A plain 'npm run export-policy-data' loads dev-profile extensions, injecting
referencedSettings the fixture-based PolicyExport integration test won't
produce — failing CI in a way that is not reproducible locally. Document the
isolated regeneration command.
Move turn state and tool confirmations onto AHP chat channels so peer chats and subagents do not cross-talk. Persist draft/config metadata through side effects, harden malformed chat-channel handling, and keep subscription hydration from hanging on errors.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Store chat drafts in the per-session database and restore draft text, attachments, model, and agent selection into the chat input. Rebuild restored Copilot turns with best-effort model and attachment metadata while avoiding unresolved subagent names as agent URIs.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Symbolizing the intermittent Electron-startup SIGSEGV crash dumps (Ubuntu debug
symbols + frame-pointer walk) shows the fault is an upstream Pango concurrency
bug, not a VS Code bug:
pango: fc_thread_func -> init_in_thread -> FcInit() (pangofc-fontmap.c)
fontconfig: FcInit -> FcConfigParseAndLoadFromMemory -> _FcConfigParse
libexpat: XML_ParseBuffer -> libc (NULL deref, SIGSEGV)
Pango >= 1.52's pango_fc_font_map_init() unconditionally spawns a
"[pango] fontconfig" thread that runs FcInit(); that races with the
Electron/Chromium main thread's own fontconfig use during startup and corrupts
fontconfig's global config while it is being parsed. The threaded design is a
known-bad area upstream (pango#784 "single fontconfig thread introduces a hang
... seems to be due to a race condition", pango#872), and there is no env var to
disable it (still present in Pango 1.56).
It only manifests in our CI because the race window is microscopic: it needs a
cold process, two threads hitting first-time FcInit() simultaneously, and a slow
machine. Our smoke job is a near-perfect trigger — fresh contended runners, a
wiped fontconfig cache + custom FONTCONFIG_FILE (so FcInit re-parses cold), and
~25 cold Electron starts per run. (This also explains why the expat version was
irrelevant and why dropping the config DOCTYPE made it worse: it is pure timing,
not parser/content.)
Fix: initialize fontconfig once, single-threaded, from an ELF constructor that
runs before main() (and thus before any thread exists), via a tiny LD_PRELOAD
shim. Pango's later threaded FcInit() then finds fontconfig already initialized
and returns immediately, so the concurrent parse never happens and the race is
eliminated.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The Linux smoke-test job works around the expat 2.6.1 fontconfig NULL-deref
CVEs by pointing FONTCONFIG_FILE at a minimal config with <include> removed.
However that config still declared an external DTD:
<!DOCTYPE fontconfig SYSTEM "urn:fontconfig:fonts.dtd">
fontconfig feeds that DTD to expat as an external *parameter* entity, which
still hits the not-yet-backported CVE-2026-32776 / CVE-2026-32778 crash paths
on expat 2.6.1 even with <include> gone. This was observed in CI as a SIGSEGV
inside libexpat (called from libfontconfig) during Chromium browser-process
font initialization, which crashed Electron at startup. Because the smoke-test
launch used no timeout, that crash surfaced only as an opaque 120s Mocha
"before all" hook timeout.
fontconfig does not require the DOCTYPE, so drop it to remove the last
external-entity codepath. The full workaround can be removed once the runner
ships libexpat >= 2.7.5 (the step already auto-disables itself in that case).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add a file-based managed-settings delivery channel that reads
managed-settings.json from a well-known per-OS disk path in the main
process and exposes it to renderer windows over IPC. Mirrors the
existing Copilot managed-settings (server / native MDM) channels.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
On a narrow Agents window, auto-hide the sessions sidebar while both the
editor and the side panel (auxiliary bar) are open, and show it again once
either closes or the window grows wide. A manual close suppresses auto-show
until the user opens it again; suspended while the editor is maximized or
multiple sessions are visible. Gated by the experimental setting
`sessions.layout.autoCollapseSessionsSidebar` (default on in non-stable builds).
Session navigation never auto-hides the sidebar: a base-controller restore
epoch (`_withSessionLayoutRestore` / `_isRestoringSessionLayout`) wraps both
the aux-bar restore and the editor working-set apply (`_applyWorkingSet`, which
reveals the editor part after an await). The D7 autorun re-baselines instead of
reacting while a restore is in flight. The epoch is a depth counter so the
guard stays up across overlapping/independently-settling restores, and it
decrements synchronously for void work so it never leaks for no-op restores.
Layout-controller registration moves to a new
`sessions.layout.contribution.ts` that picks the desktop or mobile controller
per platform and registers the experimental setting.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Cutover ThirdPartyNotices to CG-generated NOTICE
Add downloadNotice.ts: pulls the CG-generated NOTICE from the parallel Quality stage notice_output artifact and overwrites repo-root ThirdPartyNotices.txt before gulp packages it, on the desktop-client platform stages (win32, linux, darwin). Clones the copilot VSIX background-download harness (deemon detach/attach) so added wall-clock is near-zero when the artifact is ready in time. Non-fatal with legacy fallback; gated on VSCODE_OVERWRITE_TPN. Alpine/Web (server/REH only) are out of scope.
* Fix notice_output race: wait for Quality job completion before accepting artifact
The notice_output artifact is populated in two phases (generated.txt+meta, then the shipping ThirdPartyNotices.new.txt seconds later). Build 450466 showed the downloader grabbing the artifact after phase 1 but before .new.txt landed, falling back to legacy. Gate acceptance on the Quality job being completed so both upload phases are done. Bump poll budget to 7.5min.
* Bump notice poll budget to 20 attempts (10 min)
Observed acceptance at ~attempt 10 (~4.5min) in builds 450470/450477; 20 attempts gives ~2x margin while staying well under copilot's 30min. Clarify in comments that this outer poll is distinct from retry.ts's inner per-API-call retry.
* Accept CG NOTICE as soon as .new.txt lands in artifact
Change the E-lite acceptance gate from a Quality-job-completed proxy to a
direct check that ThirdPartyNotices.new.txt is present inside the notice_output
container artifact. Container file uploads are atomic per file, so the file
appears in the listing only after its upload finishes -- a race-free, earlier
readiness signal. Observed ~80s wasted in build 450470 waiting for the whole
Quality job after .new.txt was already available.
Backstops kept: (a) if Quality completes and .new.txt is still absent, give up
and fall back to legacy (do not burn the full poll budget); (b) post-download
>1KB size guard on .new.txt. POLL_ATTEMPTS stays 20 (10 min budget).
* Fix cache artifact mismatch: use DownloadBuildArtifacts + guard upload
The cache download steps used DownloadPipelineArtifact@2 but the upload
uses ##vso[artifact.upload] (which creates build artifacts, not pipeline
artifacts). These are different storage systems in ADO -- the download
was looking in the wrong store, which is why cache misses on both branch
and main.
Changes:
- Switch cache downloads to DownloadBuildArtifacts@1 (matches the upload)
- Update file paths to include notice_output/ subfolder (task behavior)
- Guard upload with condition eq(CG_NOTICE_OK, 'true') -- never upload
a cached copy, only fresh CG output
- Remove NOTICE_FROM_CACHE branching in upload (redundant with guard)
- Always write notice-meta.txt sidecar when uploading (step only runs
on fresh generation now)
* Validate extracted NOTICE content before accepting, re-poll on mid-upload miss
The accept-gate decided based on the container LISTING showing ThirdPartyNotices.new.txt, but a listing entry can appear before the file's content has finished committing. The consumer then downloaded+extracted and, when .new.txt was not yet in the extract, terminally fell back to the legacy notice. On a fast-compiling platform (e.g. linux armhf) this raced and shipped MIXED notices across architectures in a single build.
Move download+extract+validation into the poll loop: accept only when .new.txt is present AND non-empty (>1KB) in the extracted output. A listing-hit that does not yet yield a valid extracted file is treated as still-uploading and re-polls (consuming an attempt) rather than falling back. Fallback now only triggers on genuine budget exhaustion, or when .new.txt never appears in the listing and the Quality job has completed. Size guard, non-fatal exit 0, and the fresh/fallback/disabled RESULT markers are unchanged.
* Add "Use legacy OSS Tool" pipeline parameter to bypass CG notice
Surfaces a queue-time checkbox (default off) that, when checked, keeps the
legacy mixin ThirdPartyNotices.txt instead of overwriting it with the
Component Governance notice. Mirrors the VSCODE_STEP_ON_IT plumbing andderives VSCODE_OVERWRITE_TPN as an explicit lowercase string literal so
downloadNotice.ts's case-sensitive check matches. The derived variable is
threaded into the detached Pull CG NOTICE step env on win32/linux/darwin.
* Use 'definition' input alias for DownloadBuildArtifacts@1 NOTICE cache download
* Guard notice unzip against zip-slip and handle write-stream errors
Validate each extracted entry path stays within the output directory before
writing, and reject on write-stream errors so extraction failures surface
instead of hanging the poll.
* Rename legacy notice param displayName to 'Use legacy OSS Notice'
* Harden CG NOTICE feature flag plumbing
Make the VSCODE_OVERWRITE_TPN check case-insensitive and empty-safe so
YAML casing can't silently disable the rollback lever, and pass the flag
to the Apply (--attach) steps as well as Pull (--detach) so the legacy
notice is honored even if the script ever runs from the attach step.
* sessions: fork into a new chat for multi-chat agent host sessions
Forking a conversation in an agent host session that supports multiple
chats now creates a new peer chat in the same session instead of a brand
new session. Single-chat and non-agent-host sessions keep the existing
fork-into-a-new-session behavior.
- Add a `fork` option to chat creation and plumb it through the AHP
protocol, state manager, agent service and the Copilot agent SDK fork.
- Add required `forkChat`/`forkChatInSession` operations (return the new
chat or throw; never return undefined). Capability gating happens in
the caller before invoking the service.
- Fork before the selected request (turnId is the last turn to keep),
matching the new-session fork boundary.
- Drop the fork when the requested turn is unknown so the provider does
not inherit the whole backend conversation while the UI is seeded with
no turns.
- Generate a content-derived title for forked chats/sessions via the
utility model, with a short framing note that the conversation was
branched from the source chat.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* sessions: use isEqual for chat/session URI comparison
Address CCR feedback: compare URIs with the standard `isEqual` helper
instead of `toString()` so equality is robust to normalization.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* sessions: support background send for a new chat in an existing session
Add background-send (Alt+Enter) support for a new chat created inside an
existing multi-chat session, mirroring the new-session composer behavior.
- Plumb a `background` flag and `forceNew` option through the new-chat
composer, sessions service, and management service so a background send
resets the composer before dispatching (avoiding a shared chat-session
state race) and runs fire-and-forget without navigating the visible slot.
- Keep tab order in the renderer: move in-composer `Untitled` chats to the
end so a just-completed background chat never jumps last.
- Agent host: present a freshly created peer chat as `Untitled` until its
first request is sent (the host commits it eagerly as `Completed`), so the
sessions view shows the composer that owns the Alt+Enter handler. Add a
committed-chat branch to `sendRequest` and revert the chat to its real
status once sent.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* sessions: update remote provider not-found assertion
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* sessions: partition chat tabs instead of sort for stable status tracking
Address CCR feedback: read each chat status exactly once inside the autorun
so dependency tracking is complete, and preserve provider order by partition.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* sessions: resolve ${workspaceFolder} in agent-host tasks via IConfigurationResolverService
Agent-host worktree sessions build their task command line through
AgentHostSessionTaskRunner/resolveTaskCommand, which bypassed variable
resolution and sent ${workspaceFolder} to the terminal verbatim (causing
EROFS errors writing to a literal "${workspaceFolder}" path).
Expand variables using the workbench IConfigurationResolverService (already
registered in the Agents window), passing the session's worktree folder so
${workspaceFolder} resolves to the worktree rather than the Agents window's
own workspace. The resolver API is async, so the resolveTaskCommand pipeline
is now async; the hook is attached only when a cwd is known so variables are
left untouched otherwise.
Also adds the Agents-window worktree dev tasks (Install & Watch Client,
Run Client, Install & Watch) to .vscode/tasks.json, and tightens the
over-commenting guidance in the coding guidelines and sessions skill.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* sessions: address CCR feedback on agent-host variable resolution
- Resolve ${workspaceFolder} for remote hosts using the POSIX URI path
instead of IConfigurationResolverService.resolveAsync (whose fsPath uses
renderer-OS separators, wrong for a differently-OS'd remote host).
- Wrap the local resolveAsync call in try/catch so an unresolvable variable
(e.g. ${command:}/${input:}) leaves the string unchanged rather than
failing task dispatch.
- Fix the _getCwd comment to reference the real scheme (vscode-agent-host).
- Add a remote-host test asserting POSIX-path expansion and that the
renderer resolver is not consulted.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* sessions: make agent-host task runner test platform-independent
The expansion test asserted against the resolver substituting URI.fsPath,
which on Windows yields backslash separators. Backslash is in
POSIX_NEEDS_QUOTING, so the expanded arg was strong-quoted on Windows and
the unquoted assertion failed. Substitute the POSIX URI path instead so the
test is deterministic across platforms.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Refactor Copilot managed-settings for maintainability
Centralize structured (object/array) managed-setting handling behind a
single descriptor table so adding a key touches one place, consolidate the
duplicated equality helpers onto `equals`, and add shared
`hasManagedSettingsDefinitions` and `managedSettingValue` helpers. Strictly
behavior-preserving.
Incorporates a 3-model maintainability review:
- `adaptManagedSettings` builds the scalar remainder via `{ ...response }`
plus delete (CopyDataProperties) instead of for..in + assignment, so a
server-sent own `__proto__` key cannot trigger the inherited setter. This
matches the original `...rest` semantics; adds a regression test.
- `managedSettingValue` is memoized per key so its policy-definition
reference identity is real rather than incidental to the call site.
- Corrected JSDoc and skill docs that overstated `responseField` as
compiler-checked; it is a hand-maintained union backstopped by tests.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Clarify why structured managed-settings keys must declare type: 'string'
The bag-carrying `type` is load-bearing, not cosmetic: `projectManagedSettings`
gates each value with `typeof value === type` and drops mismatches, and the
native MDM watcher reads the registry/plist value as that type. Spell out that
omitting it (or declaring the object/array type) makes a structured key fail
projection and silently never apply.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Address PR review: allocation-free empty check, __proto__ test, doc accuracy
- hasManagedSettingsDefinitions: reuse the allocation-free isEmptyObject
helper instead of Object.keys(...).length (the bot's only valid nit).
- Add a primitive `__proto__` regression test proving a server-sent
`{"__proto__": true}` scalar is dropped, never pollutes the result
(disproves the reviewer's prototype-pollution concern).
- Fix github-managed-settings.md: omitting `type` or declaring
`'object'`/`'array'` is a compile error (the field is required and
constrained to `'string' | 'number' | 'boolean'`), not a runtime drop;
only `'number'`/`'boolean'` compile-but-drop-at-runtime.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Surface managed-settings source in Policy Diagnostics
Centralize the server-over-MDM precedence into a shared selectManagedSettings
helper (plus a ManagedSettingsSource union) and reuse it in both
AccountPolicyService and the Policy Diagnostics report, so the report can never
drift from the source that policy evaluation actually applies.
Rewrite the diagnostics "Managed Settings" section to:
- show the Active source (GitHub Server API / Native MDM / None)
- break down each channel (server fetch status + raw response, native MDM bag)
- label the raw response as the last *successful* fetch, so a later failed
fetch (e.g. a 404) no longer looks like it contradicts an empty effective bag
- compute the true effective bag via the shared projectManagedSettings
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Fix mock policy server "Generate example" not persisting
The "Generate example" button filled the editor and the localStorage draft but
never called debouncedSave(), so the generated body was never POSTed to
/api/state and the endpoint kept serving the empty preset. Add the missing
debouncedSave() to match applyPreset() and the editor input handler.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Strip prose from Policy Diagnostics and collect managed-settings parse errors
The Developer: Policy Diagnostics "Managed Settings" section now renders
data only (tables and JSON blocks, no explanatory paragraphs).
It also collects non-fatal parsing/normalization warnings from every stage
of the managed-settings pipeline, jsonc-style (accumulate, never throw), and
surfaces them in a new "Parse Errors" section:
- adapt: re-runs adaptManagedSettings on the raw server response
- project: re-runs projectManagedSettings against the declared policy keys
- parse: re-parses JSON-payload string values with the jsonc parser
This explains why a key is silently dropped. For example a server
extraKnownMarketplaces entry with source "github" but no "repo" now shows
the "requires \"repo\"" warning instead of just vanishing from the bag.
Adds a focused test for that github-without-repo normalization case.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Tighten Policy Diagnostics managed-settings rendering (review follow-up)
Code-quality pass on the managed-settings diagnostics section:
- Extract a jsonBlock() helper for the repeated fenced-JSON rendering
(4 call sites collapsed).
- Parse only the known JSON-payload keys (enabledPlugins,
strictKnownMarketplaces, extraKnownMarketplaces) instead of a
leading-brace heuristic. This mirrors what PolicyConfiguration actually
parses, avoids mis-sniffing scalar values, and catches malformed payloads
that don't start with a brace.
- Unify the raw-response guard on isObject() so the printed raw response and
the adapt-stage warning harvest use one predicate.
- Drop the defensive object copy in projectManagedSettings(); it is read-only,
so normalize undefined with `?? {}` instead of spreading.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Fix native MDM availability in Policy Diagnostics; tidy table headers
The diagnostics report showed "Native MDM | Available | no (desktop only)"
even on desktop. ICopilotManagedSettingsService was registered only in the
electron-main process and hand-plumbed into AccountPolicyService, but never
placed in the renderer service collection, so the report's
accessor.get(ICopilotManagedSettingsService) always threw and mislabeled the
channel as unavailable.
Register the CopilotManagedSettingsChannelClient (the renderer's handle to the
main-process service) in the service collection in both desktop.main.ts and
sessions.main.ts. The diagnostics now resolves it on desktop and Agents windows
and reports real native MDM availability and values; web still has no native
channel and correctly reports unavailable.
Also tidy the report builder: extract a PROPERTY_VALUE_TABLE_HEADER constant for
the five repeated two-column table headers, and drop the now-misleading
"(desktop only)" annotation on the availability row.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agent host: fix custom agent selection and per-chat agent/model changes
Two fixes for Copilot CLI agent-host sessions:
- The selected custom agent (e.g. a plugin/extension agent like "Inbox")
failed with "Custom agent '<name>' not found". The SDK validates the
session-start `agent:` option against `customAgents` by name and does not
consult `pluginDirectories`, but file-dir plugin agents were excluded from
`customAgents`. The new `toSdkSessionCustomAgents` helper force-includes the
resolved selected agent while other file-dir agents still load via
`pluginDirectories`.
- An additional (peer) chat in a session did not respect agent/model changes.
`SessionAgentChanged`/`SessionModelChanged` were dispatched to the session
URI (the default chat) instead of the per-chat turn channel, and the
`chatChannel` was dropped before reaching `changeAgent`/`changeModel`. These
now route to the peer chat's backend conversation in `_chatSessions`.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* sessions: address Copilot code review feedback
- Trim SDK custom-agent names to match parseAgentFile so a whitespace-padded
frontmatter name still matches the resolved selected agent (CCR finding 3).
- Dedup peer-chat agent/model side-channel dispatch against the last value
sent for that chat (tracked on AgentHostChatSession) instead of the session
summary, which only exists for the default chat (CCR findings 1 & 2).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* ci: split Electron test jobs into unit/integration and smoke
The Linux, Windows and macOS Electron PR test jobs are the slowest in CI,
dominated by the smoke test run. Split each into two parallel jobs - one
running unit + integration tests, the other running smoke tests - to cut
wall-clock time.
Done via two new parameters on the reusable workflows
(unit_and_integration_tests and smoke_tests, both defaulting to true) so
Browser and Remote jobs are unchanged. Artifact names get a -smoke suffix
on the smoke-only job to avoid upload collisions.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* ci: gate build and diagnostics to correct Electron test phase
Follow-up to the Electron job split. Ensure each half only does the work
it needs:
- Gate "Build integration tests" on unit_and_integration_tests so the
smoke-only job skips it.
- Scope the before/after diagnostics steps to their phase (combined with
always()) so they don't run in the wrong job.
- Move the Copilot extension build into the smoke phase (gated on
smoke_tests) instead of compiling it unconditionally; align Linux,
Windows and macOS on the same ordering.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* ci: drop space and parens from Electron-Smoke job name
The Windows 1ES runner builds its JobId label from job_name, producing
"windows-test-Electron (Smoke)-...". The space and parentheses prevented
the runner from picking up the job. Rename the smoke job to Electron-Smoke
on all three platforms so the JobId is a plain slug.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Fixes
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
refactor: update restore-node-modules action to support lookup-only functionality
- Replaced 'extract' input with 'lookup-only' to allow cache entry checks without downloading or extracting.
- Updated action logic to conditionally extract node_modules based on the new 'lookup-only' input.
- Adjusted workflow files to utilize 'lookup-only' for cache-warming jobs on Linux, macOS, and Windows.
* CI: speed up node_modules cache with zstd + shared scripts
Switch the Linux/macOS node_modules cache from single-threaded gzip
(tar -czf) to multi-threaded zstd. The "Create node_modules archive"
step was spending ~5min of single-core gzip on a multi-GB tree on every
cache miss; zstd -T0 uses all cores and decompresses much faster, so
cache-hit jobs benefit too. Windows stays on 7-Zip (already threaded).
Extract the archive/extract commands into shared per-platform scripts
under .github/workflows/node_modules_cache/ (cache.sh / cache.ps1, each
dispatching on an archive|extract argument) so the format and flags live
in one place instead of being duplicated across ~8 workflows. Bump
build/.cachesalt to invalidate existing gzip caches.
Also remove the obsolete extensions/copilot CI workflows
(copilot-setup-steps.yml, ensure-node-modules-cache.yml, pr.yml) and the
unused build/listBuildCacheFiles.js, and drop their now-stale entries
(plus lit-html and signals-core) from .eslint-allowed-javascript-files.
* ci: seed copilot node_modules cache on main and rename cache keys
Add copilot-linux and copilot-windows jobs to pr-node-modules.yml so the
copilot node_modules cache is populated on main. Rename the copilot cache
keys to copilot-node_modules-linux / copilot-node_modules-windows in pr.yml.
* ci: extract node_modules cache into composite actions
Factor the repeated node_modules cache plumbing into two local composite
actions, restore-node-modules and save-node-modules, and migrate all
workflows that used the cache.sh/cache.ps1 archive flow (pr, pr-node-modules,
pr-{linux,darwin,win32}-test, copilot-setup-steps, component-fixtures,
css-order-scan).
- restore-node-modules computes the key, restores the cache, optionally
extracts on a hit, and exports the resolved key via $GITHUB_ENV.
- save-node-modules archives node_modules and saves it to the cache, reusing
the key exported by restore so callers don't repeat the prefix.
- Bespoke install steps stay in the workflows, so per-job env/secrets never
cross the action boundary.
- Only seed the cache on branch pushes (component-fixtures skips PRs, whose
caches aren't shared).
* save the node_modules cache for now to test it
* ci: fix node_modules cache save dropping the archive
cache.sh wrote its archive as cache.tzst, but actions/cache reserves that
name for its own tarball and passes --exclude cache.tzst, so our archive was
excluded and an empty (~200 B) cache was saved on Linux/macOS. Rename the
archive to node-modules.tzst and bump build/.cachesalt to invalidate the
broken cache entries.
* empty commit
* Remove again saving to the node modules cache from PR steps
* policy: add dev mock server for copilot_internal policy endpoints
Adds scripts/mock-policy-server, a standalone dev tool (npm run
mock-policy-server) that mocks the Copilot policy endpoints
DefaultAccountService calls: entitlements (/copilot_internal/user), token
(/copilot_internal/v2/token), MCP registry (/copilot/mcp_registry) and
managed settings (/copilot_internal/managed_settings).
A small web GUI lets devs pick presets or edit each JSON response, and
Wire/Unwire buttons point product.overrides.json at the local server
(preserving the rest of defaultChatAgent, since bootstrap-meta merges
overrides shallowly). The managed-settings JSON schema is loaded from
--schema/MANAGED_SETTINGS_SCHEMA, defaulting to
./copilot-agent-runtime/schema/managed-settings-schema.json relative to
the app cwd; web URLs and file URIs are accepted, and the GUI warns about
keys not declared in the schema.
The three browser/shared .js files are added to
.eslint-allowed-javascript-files since the GUI loads them directly.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* policy: address mock-policy-server review feedback
- Scope permissive CORS to the mocked GET endpoints only; keep /api/*
same-origin so a website can't drive /api/wire and rewrite
product.overrides.json (CSRF).
- Coerce an empty editor body to {} instead of "" so mocked responses
stay JSON objects.
- Build the endpoint meta line with textContent/DOM nodes instead of
innerHTML.
- Drop the misused tablist/tab ARIA roles; the nav now has an aria-label
and the active item uses aria-current.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* policy: document mock policy server in add-policy skill
Add local-testing.md to the add-policy skill with basic steps for using
the mock policy server (scripts/mock-policy-server) to exercise the
account/managed-settings flow locally, and link it from SKILL.md and
github-managed-settings.md.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* policy: polish mock server GUI — schema validation, wiring backup, localStorage persistence
* policy: auto-save, rename wiring to product.overrides.json, copy path button
* mock-policy-server: convert server.js to TypeScript; add raw response diagnostics
- Convert server.js → server.ts (runs via --experimental-strip-types)
- Add endpoints.d.ts type declarations for the UMD endpoints module
- Add managedSettingsRawResponse to IDefaultAccountProvider/IDefaultAccountService
- Show raw response in Developer: Sync Account Policy output
- Remove server.js from eslint allowed-javascript-files
* mock-policy-server: convert all JS to TypeScript
- endpoints.js → endpoints.ts with proper interfaces (replaces .d.ts)
- public/app.js → public/app.ts with full type annotations
- Server uses module.stripTypeScriptTypes() to serve .ts as plain JS
to the browser — no build step needed
- Remove all mock-policy-server entries from .eslint-allowed-javascript-files
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* policy: server-delivered managed settings win over native MDM
Managed settings can arrive from two channels: the server `managed_settings`
endpoint and native MDM (Windows registry / macOS plist). Previously the two
were merged with native MDM winning. This changes the precedence so the two
layers are never merged: at any point in time there is a single authoritative
source. The server is harder to bypass than local MDM/file policies, so when
the server delivers managed settings it wins outright and native MDM is ignored
entirely. Native MDM applies only when the server provides no managed settings.
Client-side merging still happens within the winning layer (e.g. enabledPlugins,
extraKnownMarketplaces).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* policy: move managed-settings precedence rationale into add-policy skill
Trim the verbose inline comment in AccountPolicyService.getPolicyData() down to
a one-line pointer; the full precedence rationale lives in the managed-settings
section of the add-policy skill doc.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* policy: drop code snippet from managed-settings precedence doc
Keep the precedence explanation as prose; the code lives in
AccountPolicyService.getPolicyData().
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* policy: add skill learning — prefer behavior/contract prose over copy-pasted code
Skills should document behavior and business-logic expectations and reserve
code blocks for the author-facing API contract, rather than reproducing
internal implementation that rots when the source changes.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Implement multi-chat session support for Copilot CLI in Local Agent Host Provider
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Address CCR feedback: session-rename telemetry, createChat race, observable read
- Add dedicated onDidRenameSession event + agents/sessionRenamed telemetry
so session-title renames are no longer misclassified as chat renames
- Re-check chat existence inside the per-session sequencer in createChat to
avoid a race overwriting/disposing an already-registered conversation
- Cache mainChat.title read in chatCompositeBar autorun
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: dispatch default-chat turn lifecycle on session URI
After merging origin/main's default-chat compat layer, turn-lifecycle
actions (turnStarted, truncated, turnCancelled) must target the session
URI for the default chat (and the peer chat URI for peer chats), so the
server routes them to the default chat and subagent session URIs derive
correctly. Conversation side-channel actions and tool-call observation
keep using the resolved chat URI.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Document GitHub Copilot managed settings in add-policy skill
Add a github-managed-settings.md sub-file covering the new enterprise
managed-settings modality (native MDM / file / GitHub server -> the
canonical IPolicyData.managedSettings bag) and the policyReference
mechanism (one policy governing many settings). Update SKILL.md to link
the sub-file and refresh the policy-sources and key-files tables.
Grounded in PRs #318623, #320991, #321218, #321515.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Tighten managed-settings skill after council fact-check
Cross-checked every claim against the source and the four PRs:
- Correct the channel count: VS Code feeds the bag from native MDM +
server endpoint only; managed-settings.json is external-schema-only and
not read by VS Code.
- Fix "JSON.parse" -> PolicyConfiguration.parse() (lenient JSONC visitor).
- Quote ManagedSettingValue verbatim (= PolicyValue).
- Clarify native MDM is a separate input merged in getPolicyData, not on
policyData; document MDM-wins merge order precisely.
- Note schema is nested vs the flattened bag key; add the
extraKnownMarketplaces github/git-only divergence alongside the strict
boolean one.
- Soften the catalog claim: referencedSettings only captures references
loaded at export time (sessions Claude ref absent from policyData.jsonc).
- Fix example file path (chat.shared.contribution.ts) and restore the
chat_preview_features_enabled OR in the ChatToolsAutoApprove sample.
- Make the main.ts wiring snippet match the real two-step structure.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Address PR review: annotate example minimumVersion values
Mark the concrete minimumVersion values in example blocks as historical
values transcribed from existing policies, with an inline note that new
policies derive minimumVersion from package.json major.minor (Step 1).
The file-based-channel and JSON.parse review comments were already
resolved in the prior council-fix commit.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Clarify policy multiplexing in add-policy skill
After another pass through the policy wiring, clarify that
MultiplexPolicyService is used in two places: main-process OS/file policy
reader multiplexing, and renderer/session multiplexing of the main policy
channel with AccountPolicyService.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Promote policyReference guidance to main add-policy skill
policyReference is a general policy mechanism, not specific to Copilot
managed settings. Make the main SKILL.md section self-contained with the
owner/reference model, validation rules, export behavior, IPC-safe
serialization, and diagnostics notes. Keep the managed-settings sub-file
as a cross-reference only for managed-settings-specific examples.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* chat: delegate agent-host sessions
- Pass transcript handoff as an attachment so the prompt stays user-authored.
- Route agent-host delegation through the correct session-opening path in VS Code and Agents Window.
- Preserve attachment round-tripping and existing Agents Window behavior while matching the updated SDK behavior.
Fixes#319819
(Commit message generated by Copilot)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* chat: preserve paste attachment rendering
- Keeps normal pasted chat context as opaque simple attachments so existing paste chips render as before.
- Uses delegation transcript metadata, not display kind, to restore transcript handoff attachments.
- Updates attachment restore coverage to distinguish tagged transcripts from display-kind-only paste attachments.
(Commit message generated by Copilot)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Potential fix for pull request finding
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
* chat: remove generic attachment tooltip
- Avoids changing generic restored attachment UI while preserving metadata-based delegation transcript restore.
- Keeps normal simple attachment rendering behavior narrowly scoped to the existing generic path.
(Commit message generated by Copilot)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* chat: remove delegation diagnostic logging
- Removes temporary attachment and delegation trace logging added while diagnosing transcript handoff.
- Restores the Copilot attachment log to its previous low-detail trace shape.
- Reverts the unintended API proposal type change so proposal versions remain supported.
(Commit message generated by Copilot)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* chat: fix agent host paste attachment test
- Completes the paste attachment request test with the chat turn completion event used by the state-driven test helper.
- Keeps the assertion that normal paste variables stay simple attachments without paste display kind.
(Commit message generated by Copilot)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* chat: skip unused repo lookup for agents delegation
- Avoids computing chat initial session options for the Agents Window agent-host delegation path where they are not consumed.
- Keeps repository options for paths that pass them through workbench chat session creation.
(Commit message generated by Copilot)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Revert "chat: skip unused repo lookup for agents delegation"
This reverts commit b67d77c920.
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
We've had this enabled for watch for many months. Let's finish the move by switching this over now too
Also gives a better name to the typecheck script
* ci: restore chat pipeline to windows-latest
* chore: remove node-gyp override
* chore: restore node-gyp override with comment
* refactor: rm dependency on key:sqlite
The module locks the node-gyp dependency to 8.x due to
its transitive sqlite3 native module dependency this in turn
blocks using newer windows CI, refs https://github.com/microsoft/vscode/issues/321267
The module can be replaced with built-in sqlite support
from Node.js without losing the on-disk cache format has
already been committed.
* chore: restore minimist
* chore: set sqlite busy timeout
* fix: decode json-buffer values for keyv cache compat
* sessions: inline rename for chats in the chat composite bar
Support renaming a chat directly inside its tab in the chat composite
bar, mirroring the inline rename of the session title. Double-click a
tab (or use the context menu "Rename") to reveal a themed InputBox
pre-filled with the chat title; Enter commits via renameChat, Escape or
blur cancels.
The rename input lives in a stable, empty per-tab container that is
toggled via the tab's `editing` CSS class; the InputBox is created lazily
only while editing and disposed when done, so no DOM is inserted/removed
on demand and unused tabs carry no widget overhead.
Also adds a component fixture (chatCompositeBar.fixture.ts) covering the
two-tab, mixed-status, long-title and renaming states for screenshot
testing.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* sessions: switch tabs via click, keep rename blur a pure cancel
Address PR review: the tab click handler bailed out while editing and the
input blur handler switched tabs via relatedTarget. Because blur clears
the editing state before the trailing click fires, this could switch
twice (extra openChat/flicker) and was order-sensitive.
Now blur only cancels the rename, and the tab click handler cancels any
in-progress edit before switching, so tab switching follows the normal
click path.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Document two antipatterns fixed in #320913 so AI agents avoid them and
Copilot Code Reviews flag them:
- `.monaco-editor-background` must be opaque (never transparent), otherwise
the reverse-rounded selection corners break and performance suffers.
- Editor highlights should use regular decorations with inlineClassName/className;
registerDecorationType/setDecorationsByType is reserved for the ext host API.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The "chat-lib tests (windows-latest)" job started failing at the
"Extract chat-lib" step (npm ci in extensions/copilot). npm ci builds
the native sqlite3@5.1.7 module — a transitive dependency of the
@keyv/sqlite devDependency — via `prebuild-install -r napi || node-gyp
rebuild`. prebuild-install finds no matching prebuilt, so it falls back
to node-gyp, which fails on the runner because the GitHub-hosted
windows-latest label now resolves to the Windows Server 2025 + Visual
Studio 2026 image, whose VS 18 toolchain the bundled node-gyp cannot
detect ("unknown version undefined ... could not find a version of
Visual Studio 2017 or newer").
This was the only npm ci job exposed to the new image: every other
Windows npm ci job runs on self-hosted pools pinned to windows-2022
(still VS 2022), and all other copilot npm ci jobs run on Linux/macOS.
Pin this matrix entry to windows-2022 to match, as recommended by the
runner-images migration notice (actions/runner-images#14017).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>