Skip to content

[pull] main from microsoft:main#1304

Merged
pull[bot] merged 24 commits into
code:mainfrom
microsoft:main
May 28, 2026
Merged

[pull] main from microsoft:main#1304
pull[bot] merged 24 commits into
code:mainfrom
microsoft:main

Conversation

@pull
Copy link
Copy Markdown

@pull pull Bot commented May 28, 2026

See Commits and Changes for more details.


Created by pull[bot] (v2.0.0-alpha.4)

Can you help keep this open source service alive? 💖 Please sponsor : )

Copilot AI and others added 24 commits May 27, 2026 19:03
Co-authored-by: eli-w-king <201316543+eli-w-king@users.noreply.github.com>
…ariationA.ts

Co-authored-by: Courtney Webster <60238438+cwebster-99@users.noreply.github.com>
…ariationA.ts

Co-authored-by: Courtney Webster <60238438+cwebster-99@users.noreply.github.com>
…ariationA.ts

Co-authored-by: Courtney Webster <60238438+cwebster-99@users.noreply.github.com>
Brings the platform and workbench code in line with the reorganized AHP customization types: containers (PluginCustomization, DirectoryCustomization) carry the children (agents, skills, prompts, rules, hooks, MCP servers) discovered inside them.

- Replaces CustomizationRef/SessionCustomization/CustomizationAgentRef with the new Customization tree, plus ClientPluginCustomization for client-published plugins. Adds a customizationId(uri, range?) helper for minting session-unique ids that disambiguate inline manifest declarations.

- Updates IAgent and IAgentPluginManager: getCustomizations/getSessionCustomizations return Customization[]; setClientCustomizations/syncCustomizations take ClientPluginCustomization[]; setCustomizationEnabled now takes the opaque id.

- Reworks copilotAgent's PluginController + SessionDiscoveredEntry around the flat Customization shape with the CustomizationLoadStatus enum and a children array; SessionCustomizationUpdated dispatches the whole entry.

- Restores the legacy plugin-only agentHostCustomizationConfigSchema so existing agent-host-config.json files keep working; entries are lifted into the new Customization container shape at read time by getAgentHostConfiguredCustomizations / toContainerCustomization.

- Renames toCustomizationAgentRefs to toAgentCustomizations; drops the redundant enabled flag on ChildCustomization (children inherit their container's enablement). customAgents.getEffectiveAgents now walks children filtered by CustomizationType.Agent.

- Updates the workbench item provider, active-client service, harnesses, custom-agent pickers, and the remote harness to the new types; toStatusString/toStatusMessage drive UI status off CustomizationLoadStatus.

- Adapts all consumer tests (reducers, agentPluginManager, agentSideEffects, copilotAgent, mockAgent, syncedCustomizationBundler, resolveCustomizationRefs, localAgentHostSessionsProvider, remoteAgentHostCustomizationHarness, agentHostAgents/AgentPicker) to the new shapes.

- Cleans up a stale URI auto-generated import in channels-session/actions.ts.

(Commit message generated by Copilot)
Decompose parsed plugins into their full set of child customizations (agents, skills, prompts/commands, rules, hooks, MCP servers) from a single point of truth in the parser, instead of synthesizing only agents ad-hoc inside the copilot agent.

- Adds protocol-level projection types to the parsed primitives: each parsed agent/skill/rule now exposes a typed customization field, and IParsedHookGroup/IMcpServerDefinition carry their HookCustomization/McpServerCustomization. parsePlugin() mints these at parse time using customizationId-based ids.

- Introduces toChildCustomizations(plugins) in copilotPluginConverters that walks all parsed primitives and emits a deduped ChildCustomization[]. The copilot agent's host/synced/session-discovered resolvers now populate Customization.children via this single helper instead of calling toAgentCustomizations(plugin.agents) ad-hoc.

- Address Copilot review feedback: customizationId now percent-encodes existing '#' and uses a reserved '#range=' suffix so ranged ids cannot collide with URI fragments.

- mockAgent.setCustomizationEnabled now records the opaque id so tests can catch id !== uri regressions.

- Updates pluginParsers / copilotPluginConverters / convertBareEnvVarsToVsCodeSyntax tests to satisfy the new customization-bearing definition shapes; adds a thin test alias for convertBareEnvVarsToVsCodeSyntax that fills in the irrelevant customization stub.

(Commit message generated by Copilot)
* Claude agent — Phase 11: customizations/plugins

Workbench-pushed customizations (setClientCustomizations /
setCustomizationEnabled) flow through IAgentPluginManager into
Options.plugins for the Claude SDK Query. Server-side
(SDK-discovered) commands / agents / MCP servers are projected as a
single "Discovered in Claude" Open Plugins-conformant on-disk bundle.

Notable design notes:

  - The SDK's Query.reloadPlugins() is parameterless and cannot
    change the plugin URI set after startup, so any client-side
    customization change triggers a yield-restart through the same
    rematerializer path used for client-tool changes. send()'s
    pre-flight runs a single rebind when either toolDiff or
    clientCustomizationsDiff is dirty.

  - SessionClientCustomizationsDiff drives dirty from the model
    state observable (not just enabledPluginPaths), so nonce bumps
    and metadata refreshes at the same URI are detected.

  - setClientCustomizations runs inside the per-session sequencer so
    a fire-and-forget call from AgentSideEffects cannot race a first
    sendMessage.

  - ClaudeSdkCustomizationBundler writes a hashed, content-addressed
    on-disk tree under the plugin manager's basePath. Repeated
    calls with the same SDK snapshot are nonce-stable and skip the
    rewrite. The on-disk tree is intentionally a cross-session warm
    cache.

Tests:
  - New customizations/ test folder mirrors the source structure:
    SessionClientCustomizationsDiff (URI list, nonce, metadata,
    enablement, dirty semantics), projector (client+server merge),
    bundler (write layout, nonce stability, name sanitisation,
    namespacing, delete-on-change).
  - claudeAgent.test.ts: sync-and-toggle dispatch, sequencer
    serialisation, rebind on customizations dirty, mid-turn race
    coverage, swallowed-SDK-snapshot fallback in
    getSessionCustomizations.

* fix: address customizations lint and review feedback

Co-authored-by: TylerLeonhardt <2644648+TylerLeonhardt@users.noreply.github.com>

* test: fix customizations enablement key mismatch

Co-authored-by: TylerLeonhardt <2644648+TylerLeonhardt@users.noreply.github.com>

* Fix Windows path assertions in Phase 11 tests

URI.file('/p/a').fsPath is '\p\a' on Windows, so the literal POSIX
string comparisons fail there. Compute expected via URI.file().fsPath
so the same path round-trip drives both sides of the assertion.

* Phase 11 docs: reflect shipped rebind-always architecture

The original plan described setCustomizationEnabled as defer-and-coalesce
via Query.reloadPlugins() with a tool-set-divergence escalation to rebind.
Council review during PR #318113 verified Query.reloadPlugins() is
parameterless in @anthropic-ai/claude-agent-sdk and cannot change the
plugin URI set captured into Options.plugins at startup, so any client-
pushed customization change ships as a yield-restart through the same
rematerializer path that client-tool changes use.

Rewrites the Phase 11 sections of roadmap.md and phase11-plan.md so the
docs match what was merged. Historical "original plan called for X"
notes preserved for context. Phase 11 marked DONE on the roadmap.

* Claude phase 11: agent picker plumbing + on-disk URIs

- Add IAgent.changeAgent for Claude: pre-materialize stash, post-materialize
  rebind via dirty bit (SDK has no working runtime control to swap agent in
  place — applyFlagSettings({ agent }) exists but doesn't actually swap).
- Thread Options.agent through buildOptions / materialize / rematerializer
  and persist selection in the per-session metadata overlay so resume
  picks it up.
- ClaudeSdkCustomizationBundler now publishes CustomizationAgentRef.uri
  as the on-disk `agents/<name>.md` path (was a synthetic
  `claude-sdk-agent:/` scheme). The workbench customization harness
  needs a real file URI to parse via promptsService.parseNew — without
  it the agents never reached the picker.
- Hide 'general-purpose' (SDK default) from the picker via shared
  CLAUDE_SDK_DEFAULT_AGENT_NAME constant.
- Tests: 3 changeAgent cases (provisional / mid-session rebind /
  clear-to-undefined), bundler agent-URI shape.

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
…-borders

Onboarding: make agent feature cards non-interactive on Build with AI Agents step
#318638)

* mcp: prefer announced server title for tool prefixes and picker labels

Reworks how MCP tool prefixes are generated and how MCP servers are labelled
in the Configure Tools picker so that the server-announced serverInfo.title
(falling back to serverInfo.name) is preferred over the mcp.json key.

- Introduces a shared McpPrefixGenerator with a 	ake(name): IReference<string>
  API that hands out collision-resolved tool prefixes and releases them on
dispose. Replaces the eager one-shot generator that used to live in
McpService.
- McpServer now derives its tool prefix from its preferred name (announced
title when known, otherwise the mcp.json label) so registry-style names like
io.github.upstash/context7 no longer end up as truncated
mcp_io_github_ups_* prefixes.
- Configure Tools picker and ToolDataSource.classify for MCP sources now
  prefer serverLabel (the announced title) over label .
- Adds unit tests for McpPrefixGenerator covering collisions, slot reuse on
dispose, bucket cleanup, and name sanitization.

Fixes #299749
Fixes #299787

(Commit message generated by Copilot)

* pr comments
…ization-refactor

# Conflicts:
#	src/vs/platform/agentHost/node/claude/claudeAgent.ts
…n-refactor

agentHost: adopt new customization protocol shape
)

* agentHost: dedupe concurrent _resumeSession calls per sessionId

Concurrent _resumeSession(id) callers (e.g. an outdated-config refresh in
sendMessage plus a getSessionMessages subscribe) each constructed a fresh
CopilotAgentSession and ran it through _createAgentSession, whose
this._sessions.set(id, …) on a DisposableMap synchronously disposed the
first entry mid-initializeSession(). The result was a tight loop of
'Trying to add a disposable to a DisposableStore that has already been
disposed' warnings (~550 in one repro) and a half-initialised session
with no event subscriptions — the chat widget opens, but sending a
message goes nowhere.

Fix:
- Add an _resumingSessions: Map<string, Promise<CopilotAgentSession>>;
  _resumeSession is now a thin wrapper that returns the in-flight promise
  when one exists, else delegates to a new _doResumeSession and memoizes
  the promise until it settles.
- Stop registering sessions in _sessions inside _createAgentSession.
  Both callers (_doResumeSession and _materializeProvisional) now set
  _sessions only after initializeSession() succeeds, and dispose the
  freshly-constructed agentSession if it throws. This removes the
  DisposableMap.set footgun that disposed an in-flight entry from under
  its own init.

Adds focused tests for the dedup contract:
- concurrent calls for the same id share one promise + one _doResumeSession
- inflight entry is cleared after resolution (next call re-invokes)
- inflight entry is cleared after rejection (next call retries)
- different ids resolve independently

(Written by Copilot)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* agentHost: guard post-init _sessions.set against shutdown race

Address Copilot review on #318636: now that _sessions.set is deferred
until after initializeSession() resolves, an in-flight _resumeSession /
_materializeProvisional whose init resolves AFTER dispose() ->
shutdown() -> super.dispose() has run would call _sessions.set(...) on
a disposed DisposableMap, leaking the session and reproducing the
'Trying to add a disposable to a DisposableStore that has already been
disposed' warning this PR exists to eliminate.

Extract a small _registerInitializedSession helper that bails (dispose
+ CancellationError) when _shutdownPromise is already set, and route
both call sites through it. The provisional path additionally still
removes its created worktree on cancel via the existing catch block.

Add a focused unit test that exercises the helper directly with a fake
session, simulating the shutdown-started state.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* launch skill: call out the transpile-client → preLaunch-skips-compile trap

When 'out/' already exists from a prior 'npm run transpile-client',
'node build/lib/preLaunch.ts' will skip 'npm run compile' and you'll
get a launched window whose built-in extensions fail to activate with
'Cannot find module .../extensions/.../out/...'. Document the trap in
both prerequisites and troubleshooting, and add a 'node_modules / npm
install' prereq.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* launch skill: tighten compile prereq + sign-in nudge

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Bump 500 mb for mac dmg
…ows (#308150)

* fix: combine URI flags to prevent Electron argument filtering on Windows

On Windows, Electron/Chromium's security layer filters out standalone
command-line arguments that look like URLs (containing "://"). This
causes --folder-uri and --file-uri to fail silently when the URI value
is not the last argument.

Combine --folder-uri and --file-uri with their values using "=" syntax
before spawning the Electron process, so Chromium treats them as flags
rather than standalone URL arguments.

Fixes #209072

* Stop rewriting --folder-uri / --file-uri past the -- end-of-options marker

---------

Co-authored-by: Dmitriy Vasyura <dmitriv@microsoft.com>
For perf work

Co-authored-by: Copilot <copilot@github.com>
@pull pull Bot locked and limited conversation to collaborators May 28, 2026
@pull pull Bot added the ⤵️ pull label May 28, 2026
@pull pull Bot merged commit 0dabf4a into code:main May 28, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.