Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
68 commits
Select commit Hold shift + click to select a range
98c60a1
Alias # to @ in chat context references
pierceboggan Feb 12, 2026
6dffc1f
Improve chat file completion matching
pierceboggan Feb 12, 2026
d3cd52e
Address Copilot code review feedback: escape leaders in regex char cl…
pierceboggan Feb 18, 2026
632998f
Add tests for escapeForCharClass and computeCompletionRanges with @ l…
pierceboggan Mar 20, 2026
6134117
Address review: use typedLeader for insertText/label, extract utils
pierceboggan Mar 21, 2026
f944fc3
Merge branch 'main' into pierceboggan/fix-@
justschen Mar 21, 2026
da5fb11
agentHost: add session-specific metadata
connor4312 Mar 26, 2026
b0caf28
comments
connor4312 Mar 27, 2026
82136c0
Try to reduce how often LocalAgentsSessionsController fires updates
mjbvz Mar 27, 2026
834947c
Fix tests
mjbvz Mar 27, 2026
133627a
fix tests
connor4312 Mar 27, 2026
0bd9e10
Add experiment for sign in button in title bar
cwebster-99 Mar 27, 2026
cdd9c01
fix
connor4312 Mar 27, 2026
2a71559
session types changes plus /generate-run-commands, smarter chats to s…
benibenj Mar 27, 2026
9c5d733
style - update icon for `New Session` action (#305724)
bpasero Mar 27, 2026
e727b78
sessions: refine new chat empty state layout and picker styling (#304…
hawkticehurst Mar 27, 2026
676164b
fix
connor4312 Mar 27, 2026
1e69270
fix tests
benibenj Mar 27, 2026
3746fd5
fix
connor4312 Mar 27, 2026
a712e00
Merge pull request #305525 from mjbvz/dev/mjbvz/whispering-swift
mjbvz Mar 27, 2026
fc06dae
Delete pointless test
mjbvz Mar 27, 2026
00515ed
sort default question options to the top (#305696)
meganrogge Mar 27, 2026
39473a2
fix race in teardown
connor4312 Mar 27, 2026
89f90db
sessions: use proper DI for fileService and pathService in AgenticPro…
joshspicer Mar 27, 2026
dd064da
Merge pull request #305730 from microsoft/benibenj/ratty-urial
benibenj Mar 27, 2026
e55a467
last fix
connor4312 Mar 27, 2026
7466d76
fix: modernize HTML sample snippet (#304818)
yogeshwaran-c Mar 27, 2026
b8b0273
Improve badge visibility with updated styles (#305734)
mrleemurray Mar 27, 2026
2b75555
Increase font weight for session title label (#305736)
mrleemurray Mar 27, 2026
21dedfa
Merge pull request #305739 from mjbvz/dev/mjbvz/short-shark
mjbvz Mar 27, 2026
7401c12
Adjust padding for secondary action buttons in changes view (#305738)
mrleemurray Mar 27, 2026
81a487a
Don't show a terminal error when opening remote agent-host sessions (…
roblourens Mar 27, 2026
187a986
Revert "Replace child_process.exec with execFile to prevent potential…
mjbvz Mar 27, 2026
a29c4cf
Increase minimum width of AuxiliaryBarPart (#305741)
mrleemurray Mar 27, 2026
6ef843f
fix: remove persistent focus outline on walkthrough step checkbox cli…
KalashThakare Mar 27, 2026
8956984
add chat import and export icons to agent debug logs
eli-w-king Mar 27, 2026
c53d64b
Merge branch 'main' into eli/chat-export-import-icon
eli-w-king Mar 27, 2026
510195d
Sessions: Update no changed files message and adjust styles in change…
mrleemurray Mar 27, 2026
53f5495
registered in codicons.ts
eli-w-king Mar 27, 2026
0f6c3be
Merge pull request #305756 from microsoft/revert-291825-child-process
mjbvz Mar 27, 2026
402ffd2
Allow intellisense for troubleshoot skill (#305702)
pwang347 Mar 27, 2026
3fba4f2
sessions: adjust workspace picker empty state text segmentation (#305…
hawkticehurst Mar 27, 2026
fa311ec
Merge pull request #305348 from microsoft/connor4312/edit-metadata
connor4312 Mar 27, 2026
483f2ca
Add telemetry for chat todo list widget interactions (#305747)
bhavyaus Mar 27, 2026
678825d
Browser view native "add to chat" features (#305745)
kycutler Mar 27, 2026
2056bef
Don't use trusted telemetry value on model ids (#305760)
lramos15 Mar 27, 2026
9d6cdc3
Polish for experiment gating
cwebster-99 Mar 27, 2026
1d01418
Revert terminal editor regressions #298688 , #302139 (#305782)
anthonykim1 Mar 27, 2026
b7be16b
Fix customization file resolution errors for remote agent host sessio…
roblourens Mar 27, 2026
0496f93
sessions: use plus icon for Add Chat (#305791)
bpasero Mar 27, 2026
8dd3661
Merge main, remove duplicate re-export, update notebook import
pierceboggan Mar 27, 2026
36ab523
Merge branch 'main' into pierceboggan/fix-@
pierceboggan Mar 27, 2026
fea1308
polish
cwebster-99 Mar 27, 2026
e92b212
Sessions - more improvements to the changes view (#305797)
lszomoru Mar 27, 2026
2750517
Merge pull request #294777 from microsoft/pierceboggan/fix-@
pierceboggan Mar 27, 2026
44bc775
Merge pull request #305759 from microsoft/eli/chat-export-import-icon
eli-w-king Mar 27, 2026
5933225
Bump picomatch from 4.0.3 to 4.0.4 in /test/smoke (#304972)
dependabot[bot] Mar 27, 2026
fca9a78
Bump picomatch from 4.0.3 to 4.0.4 in /test/mcp (#304949)
dependabot[bot] Mar 27, 2026
e49f2d1
Bump node-forge from 1.3.2 to 1.4.0 in /extensions/vscode-api-tests (…
dependabot[bot] Mar 27, 2026
48a5303
Merge branch 'main' into open-wren
cwebster-99 Mar 27, 2026
c7de087
Bump octokit/request-action from 2.4.0 to 3.0.0 (#305135)
dependabot[bot] Mar 27, 2026
958f822
Update distro commit (main) (#305764)
vs-code-engineering[bot] Mar 27, 2026
7efa1c5
chatCustomizations: support grouping and badges for external provider…
joshspicer Mar 27, 2026
dd1cba9
Make sure main thread chat session models use overrides from live model
mjbvz Mar 27, 2026
cbc5724
Sessions - wire up the discard changes action (#305830)
lszomoru Mar 27, 2026
8d8e32f
Merge pull request #305723 from microsoft/open-wren
cwebster-99 Mar 27, 2026
cb39101
chat: fix customization provider harness deduplication, grouping, and…
joshspicer Mar 27, 2026
c171759
Merge pull request #305841 from mjbvz/dev/mjbvz/functional-shark
mjbvz Mar 27, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions .github/skills/chat-customizations-editor/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,24 @@ When changing harness descriptor interfaces or factory functions, verify both co
- **`IHarnessDescriptor`** — drives all UI behavior declaratively (hidden sections, button overrides, file filters, agent gating). See spec for full field reference.
- **`ISectionOverride`** — per-section button customization (command invocation, root file creation, type labels, file extensions).
- **`IStorageSourceFilter`** — controls which storage sources and user roots are visible per harness/type.
- **`IExternalCustomizationItemProvider`** / **`IExternalCustomizationItem`** — internal interfaces (in `customizationHarnessService.ts`) for extension-contributed providers that supply items directly. These mirror the proposed extension API types.

Principle: the UI widgets read everything from the descriptor — no harness-specific conditionals in widget code.

## Extension API (`chatSessionCustomizationProvider`)

The proposed API in `src/vscode-dts/vscode.proposed.chatSessionCustomizationProvider.d.ts` lets extensions register customization providers. Changes to `IExternalCustomizationItem` or `IExternalCustomizationItemProvider` must be kept in sync across the full chain:

| Layer | File | Type |
|-------|------|------|
| Extension API | `vscode.proposed.chatSessionCustomizationProvider.d.ts` | `ChatSessionCustomizationItem` |
| IPC DTO | `extHost.protocol.ts` | `IChatSessionCustomizationItemDto` |
| ExtHost mapping | `extHostChatAgents2.ts` | `$provideChatSessionCustomizations()` |
| MainThread mapping | `mainThreadChatAgents2.ts` | `provideChatSessionCustomizations` callback |
| Internal interface | `customizationHarnessService.ts` | `IExternalCustomizationItem` |

When adding fields to `IExternalCustomizationItem`, update all five layers. The proposed API `.d.ts` is additive-only (new optional fields are backward-compatible and do not require a version bump).

## Testing

Component explorer fixtures (see `component-fixtures` skill): `aiCustomizationListWidget.fixture.ts`, `aiCustomizationManagementEditor.fixture.ts` under `src/vs/workbench/test/browser/componentFixtures/`.
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/no-engineering-system-changes.yml
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ jobs:
echo "Copilot is not allowed to modify .github/workflows, build folder files, or package.json files."
echo "If you need to update engineering systems, please do so manually or through authorized means."
exit 1
- uses: octokit/request-action@dad4362715b7fb2ddedf9772c8670824af564f0d # v2.4.0
- uses: octokit/request-action@b91aabaa861c777dcdb14e2387e30eddf04619ae # v3.0.0
id: get_permissions
if: ${{ steps.engineering_systems_check.outputs.engineering_systems_modified == 'true' && steps.distro_exception.outputs.allowed != 'true' && github.event.pull_request.user.login != 'Copilot' }}
with:
Expand Down
115 changes: 77 additions & 38 deletions extensions/git/src/repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1369,16 +1369,47 @@ export class Repository implements Disposable {
await this.run(
Operation.Restore(!this.optimisticUpdateEnabled()),
async () => {
const resourcePaths = resources.map(r => r.fsPath);
await this.repository.restore(resourcePaths, options);
const toClean: string[] = [];
const toRestore: string[] = [];

if (options?.staged) {
// Index was modified;
this.closeDiffEditors([], resourcePaths);
} else {
// Working tree was modified;
this.closeDiffEditors(resourcePaths, []);
const resourceStates = [
...this.indexGroup.resourceStates,
...this.workingTreeGroup.resourceStates,
...this.untrackedGroup.resourceStates
];

for (const resource of resources) {
const scmResource = find(resourceStates, r => r.resourceUri.toString() === resource.toString());

if (!scmResource) {
toRestore.push(resource.fsPath);
continue;
}

switch (scmResource.type) {
case Status.UNTRACKED:
case Status.IGNORED:
toClean.push(resource.fsPath);
break;

default:
toRestore.push(resource.fsPath);
break;
}
}

if (toClean.length > 0) {
await this._clean(toClean);
}

if (toRestore.length > 0) {
await this.repository.restore(toRestore, options);
}

this.closeDiffEditors([], [...toClean, ...toRestore]);

// Clear AI contribution tracking for discarded resources
commands.executeCommand('_aiEdits.clearAiContributions', resources);
});
}

Expand Down Expand Up @@ -1511,9 +1542,6 @@ export class Repository implements Disposable {
}

async clean(resources: Uri[]): Promise<void> {
const config = workspace.getConfiguration('git');
const discardUntrackedChangesToTrash = config.get<boolean>('discardUntrackedChangesToTrash', true) && !isRemote && !isLinuxSnap;

await this.run(
Operation.Clean(!this.optimisticUpdateEnabled()),
async () => {
Expand Down Expand Up @@ -1552,33 +1580,7 @@ export class Repository implements Disposable {
});

if (toClean.length > 0) {
if (discardUntrackedChangesToTrash) {
try {
// Attempt to move the first resource to the recycle bin/trash to check
// if it is supported. If it fails, we show a confirmation dialog and
// fall back to deletion.
await workspace.fs.delete(Uri.file(toClean[0]), { useTrash: true });

const limiter = new Limiter<void>(5);
await Promise.all(toClean.slice(1).map(fsPath => limiter.queue(
async () => await workspace.fs.delete(Uri.file(fsPath), { useTrash: true }))));
} catch {
const message = isWindows
? l10n.t('Failed to delete using the Recycle Bin. Do you want to permanently delete instead?')
: l10n.t('Failed to delete using the Trash. Do you want to permanently delete instead?');
const primaryAction = toClean.length === 1
? l10n.t('Delete File')
: l10n.t('Delete All {0} Files', resources.length);

const result = await window.showWarningMessage(message, { modal: true }, primaryAction);
if (result === primaryAction) {
// Delete permanently
await this.repository.clean(toClean);
}
}
} else {
await this.repository.clean(toClean);
}
await this._clean(toClean);
}

if (toCheckout.length > 0) {
Expand Down Expand Up @@ -1615,6 +1617,43 @@ export class Repository implements Disposable {
});
}

async _clean(resources: string[]): Promise<void> {
const config = workspace.getConfiguration('git');
const discardUntrackedChangesToTrash = config.get<boolean>('discardUntrackedChangesToTrash', true) && !isRemote && !isLinuxSnap;

if (resources.length === 0) {
return;
}

if (discardUntrackedChangesToTrash) {
try {
// Attempt to move the first resource to the recycle bin/trash to check
// if it is supported. If it fails, we show a confirmation dialog and
// fall back to deletion.
await workspace.fs.delete(Uri.file(resources[0]), { useTrash: true });

const limiter = new Limiter<void>(5);
await Promise.all(resources.slice(1).map(fsPath => limiter.queue(
async () => await workspace.fs.delete(Uri.file(fsPath), { useTrash: true }))));
} catch {
const message = isWindows
? l10n.t('Failed to delete using the Recycle Bin. Do you want to permanently delete instead?')
: l10n.t('Failed to delete using the Trash. Do you want to permanently delete instead?');
const primaryAction = resources.length === 1
? l10n.t('Delete File')
: l10n.t('Delete All {0} Files', resources.length);

const result = await window.showWarningMessage(message, { modal: true }, primaryAction);
if (result === primaryAction) {
// Delete permanently
await this.repository.clean(resources);
}
}
} else {
await this.repository.clean(resources);
}
}

closeDiffEditors(indexResources: string[] | undefined, workingTreeResources: string[] | undefined, ignoreSetting = false): void {
const config = workspace.getConfiguration('git', Uri.file(this.root));
if (!config.get<boolean>('closeDiffOnOperation', false) && !ignoreSetting) { return; }
Expand Down
8 changes: 4 additions & 4 deletions extensions/grunt/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ function exists(file: string): Promise<boolean> {
});
}

function exec(command: string, args: string[], options: cp.ExecFileOptions): Promise<{ stdout: string; stderr: string }> {
function exec(command: string, options: cp.ExecOptions): Promise<{ stdout: string; stderr: string }> {
return new Promise<{ stdout: string; stderr: string }>((resolve, reject) => {
cp.execFile(command, args, options, (error, stdout, stderr) => {
cp.exec(command, options, (error, stdout, stderr) => {
if (error) {
reject({ error, stdout, stderr });
}
Expand Down Expand Up @@ -143,9 +143,9 @@ class FolderDetector {
return emptyTasks;
}

const gruntCommand = await this._gruntCommand;
const commandLine = `${await this._gruntCommand} --help --no-color`;
try {
const { stdout, stderr } = await exec(gruntCommand, ['--help', '--no-color'], { cwd: rootPath });
const { stdout, stderr } = await exec(commandLine, { cwd: rootPath });
if (stderr) {
getOutputChannel().appendLine(stderr);
showError();
Expand Down
8 changes: 3 additions & 5 deletions extensions/html-language-features/client/src/htmlClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -317,14 +317,12 @@ async function startClientWithParticipants(languageParticipants: LanguagePartici
const snippetProposal = new CompletionItem('HTML sample', CompletionItemKind.Snippet);
snippetProposal.range = range;
const content = ['<!DOCTYPE html>',
'<html>',
'<html lang=\'${1:en}\'>',
'<head>',
'\t<meta charset=\'utf-8\'>',
'\t<meta http-equiv=\'X-UA-Compatible\' content=\'IE=edge\'>',
'\t<title>${1:Page Title}</title>',
'\t<meta name=\'viewport\' content=\'width=device-width, initial-scale=1\'>',
'\t<link rel=\'stylesheet\' type=\'text/css\' media=\'screen\' href=\'${2:main.css}\'>',
'\t<script src=\'${3:main.js}\'></script>',
'\t<title>${2:Page Title}</title>',
'\t<link rel=\'stylesheet\' href=\'${3:main.css}\'>',
'</head>',
'<body>',
'\t$0',
Expand Down
8 changes: 4 additions & 4 deletions extensions/vscode-api-tests/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion extensions/vscode-api-tests/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@
"@types/mocha": "^10.0.10",
"@types/node": "22.x",
"@types/node-forge": "^1.3.11",
"node-forge": "^1.3.2",
"node-forge": "^1.4.0",
"straightforward": "^4.2.2"
},
"repository": {
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "code-oss-dev",
"version": "1.114.0",
"distro": "a305f48172def2b6e043c61177258d2d1abe7c0b",
"distro": "3431ef6bcc28695f128a7a364e73b474b103df99",
"author": {
"name": "Microsoft Corporation"
},
Expand Down
2 changes: 2 additions & 0 deletions src/vs/base/common/codicons.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ export const codiconsDerived = {
gitFetch: register('git-fetch', 0xec1d),
lightbulbSparkleAutofix: register('lightbulb-sparkle-autofix', 0xec1f),
debugBreakpointPending: register('debug-breakpoint-pending', 0xebd9),
chatImport: register('chat-import', 0xec86),
chatExport: register('chat-export', 0xec87),

} as const;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,12 @@ export class AgentHostFileSystemProvider extends Disposable implements IFileSyst
if (path === '/' || path === '') {
return { type: FileType.Directory, mtime: 0, ctime: 0, size: 0, permissions: FilePermission.Readonly };
}
const decodedPath = fromAgentHostUri(resource).path;
if (decodedPath === '/' || decodedPath === '') {
const decoded = fromAgentHostUri(resource);
if (decoded.scheme === 'session-db') {
return { type: FileType.File, mtime: 0, ctime: 0, size: 0, permissions: FilePermission.Readonly };
}

if (decoded.path === '/' || decoded.path === '') {
return { type: FileType.Directory, mtime: 0, ctime: 0, size: 0, permissions: FilePermission.Readonly };
}

Expand Down
3 changes: 2 additions & 1 deletion src/vs/platform/agentHost/common/agentHostUri.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
*--------------------------------------------------------------------------------------------*/

import { encodeBase64, VSBuffer } from '../../../base/common/buffer.js';
import { Schemas } from '../../../base/common/network.js';
import { URI } from '../../../base/common/uri.js';
import type { ResourceLabelFormatter } from '../../label/common/label.js';

Expand Down Expand Up @@ -34,7 +35,7 @@ export const AGENT_HOST_SCHEME = 'vscode-agent-host';
* the URI authority (from {@link agentHostAuthority}).
*/
export function toAgentHostUri(originalUri: URI, connectionAuthority: string): URI {
if (connectionAuthority === 'local') {
if (connectionAuthority === 'local' && originalUri.scheme === Schemas.file) {
return originalUri;
}

Expand Down
Loading
Loading