* Run Agents App in transient mode when VS Code is launched with --transient
When VS Code is launched with --transient, the Agents App now also runs
in transient mode with its own dedicated temporary user data and
extensions directories created under the same temp parent folder.
- Add `--agents-user-data-dir` and `--agents-extensions-dir` CLI args
- In --transient handling, create `agents-data/` and `agents-extensions/`
subdirs alongside existing temp dirs and pass them via the new args
- In `launchSiblingApp`, forward transient agents dirs as
`--user-data-dir` and `--extensions-dir` to the sibling Agents process
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Also forward --shared-data-dir and --agent-plugins-dir to sibling Agents app
To ensure the sibling Agents process is fully isolated in transient mode,
forward shared-data-dir and agent-plugins-dir in addition to user-data-dir
and extensions-dir.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Share secrets between Code and Agents app via macOS Keychain
Add a shared keychain service that stores secrets directly in the macOS
Keychain, allowing Code and its embedded Agents app to share auth tokens
without re-authentication.
Architecture:
- ISharedKeychainService (common interface) with ISharedKeychainMainService
running in the Electron main process, exposed to renderer via IPC
- SharedKeychainMainService wraps @vscode/macos-keychain native addon
- NativeSecretStorageService now writes to both the shared keychain and
the legacy safeStorage+SQLite pipeline (for rollback safety)
- On read, shared keychain is tried first, falling back to legacy
Product configuration:
- darwinSharedKeychainServiceName: per-flavor service name for data
isolation between Stable/Insiders/Exploration
- Access group auto-detected from entitlements by the native addon
Key design decisions:
- Shared keychain only used when type is 'persisted' (not in-memory)
- BaseSecretStorageService refactored to expose protected _doGet/_doSet/
_doDelete/_doGetKeys for use by subclasses within sequencer tasks
- Native addon is an optional dependency (macOS-only)
Files:
- build/azure-pipelines/darwin/app-entitlements.plist (keychain-access-groups)
- src/vs/platform/secrets/common/sharedKeychainService.ts (interface)
- src/vs/platform/secrets/electron-main/sharedKeychainMainService.ts (impl)
- src/vs/workbench/services/secrets/electron-browser/sharedKeychainService.ts (IPC proxy)
- src/vs/workbench/services/secrets/electron-browser/secretStorageService.ts (wiring)
Issue: #308028
* Address review feedback
* Add one-time migration of legacy secrets to shared keychain
On first secret operation, migrate all existing secrets from the legacy
safeStorage+SQLite pipeline into the shared macOS Keychain. This ensures
the Agents app can read secrets that were stored before the shared
keychain was introduced.
- Migration is lazy (triggered on first get/set/delete/keys)
- Guarded by a 'sharedKeychain.migrationDone' storage flag
- Idempotent: keychain writes are upserts, re-running is safe
- Best-effort per key: individual failures don't block the rest
- Skipped when type is 'in-memory'
- Also: make set() in SharedKeychainMainService best-effort (log, don't throw)
* update the current implementation
* restrict shared keychain to CROSS_APP_SHARED_SECRET_KEYS
* kick off shared keychain migration eagerly in constructor
* update @vscode/macos-keychain to 0.0.1
* Use provisioning profile for keychain access groups when available
During signing, check for build/darwin/distribution.provisionprofile.
If present, use it as the provisioning profile and keep the
keychain-access-groups entitlement in app-entitlements.plist.
If not present (e.g. OSS builds), strip the keychain-access-groups
section from a temp copy of the entitlements plist to avoid signing
failures. The shared keychain still works via the app's default
keychain without access-group isolation.
* Add entitlements diagnostic dump after signing
Dump the actual entitlements from the signed binary to validate
whether $(TeamIdentifierPrefix) is being expanded by codesign.
Hypothesis: the variable is passed literally to the entitlements
plist without expansion, causing a mismatch with the provisioning
profile and resulting in Killed: 9 on launch.
* Exclude provisioning profile from unicode hygiene check
* update package-lock.json
* Adopt multiple provision profiles
* fix: expand teamidentifier in the entitlement
* Re-sign without provisioning profile for tests
Run the entitlements step twice in CI:
1. First with provisioning profile (keychain-access-groups) for codesign/notarize
2. Then without provisioning profile for tests (in parallel with codesign)
This avoids making codesign sequential with tests while still
supporting the keychain-access-groups entitlement that requires
a provisioning profile.
- Add --skip-provisioning-profile flag to sign.ts
- Add 'Set Hardened Entitlements (for tests)' pipeline step
* Skip plist modifications when re-signing for tests
The plutil -insert calls fail on the second sign pass because the
keys already exist from the first pass. Skip plist modifications
when --skip-provisioning-profile is set since they are not needed.
* Move shared keychain migration from renderer to main process
Replace crossAppIPC-based secret handshake with direct shared keychain
writes in the main process:
- MacOSCrossAppSecretSharing now reads safeStorage+SQLite and writes to
shared keychain via SharedKeychainMainService (no crossAppIPC needed)
- Code.app migrates on startup; Agents app spawns Code.app once if
keychain is incomplete
- NativeSecretStorageService no longer does migration — just reads/writes
shared keychain for cross-app keys
* Add isMacintosh guards before using the shared keychain service
Co-authored-by: Copilot <copilot@github.com>
* Remove spec
* Tweak comments
---------
Co-authored-by: deepak1556 <hop2deep@gmail.com>
Co-authored-by: Copilot <copilot@github.com>
* Move agentPluginsHome to IUserDataProfile and IEnvironmentService
- Add agentPluginsHome to IEnvironmentService (platform level)
- Add agentPluginsHome to IUserDataProfile (same value for all profiles)
- Remove agentPluginsHome from IWorkbenchEnvironmentService
- Remove agentPluginsHome getter from NativeWorkbenchEnvironmentService
- Update AgentPluginRepositoryService to read from IUserDataProfileService
- Update toUserDataProfile signature with new agentPluginsHome parameter
- Update all test files and consumers
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Address review feedback
- Remove redundant agentPluginsHome override in embedded app
(already correct from environment service since dataFolderName is shared)
- Add agentPluginsHome to isUserDataProfile type guard
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Add --agent-plugins-dir to --transient feature
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Derive agentPluginsPath from extensions parent directory
Agent plugins are now stored as a sibling of the extensions directory
(e.g., ~/.vscode-insiders/agent-plugins/ next to ~/.vscode-insiders/extensions/).
This means --extensions-dir and --transient automatically co-locate
agent plugins without needing a separate --agent-plugins-dir flag.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Fix test: only co-locate agent-plugins when extensions-dir is explicitly set
Avoid calling this.extensionsPath in the default agentPluginsPath
fallback, which breaks tests where environment args are empty objects.
Instead, check args['extensions-dir'] directly and only co-locate
when it is explicitly overridden.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Revert env service change; only co-locate agent-plugins in --transient
Keep agentPluginsPath original logic in environment service. The
--transient handler in cli.ts passes --agent-plugins-dir explicitly
to co-locate agent plugins under the same temp parent directory.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Compute host agent-plugins path for embedded Agents app
Extract getAgentPluginsPath as a shared function. In the embedded
Agents app, compute the host VS Code's agent-plugins directory using
quality-specific dataFolderName, matching the hostUserRoamingDataHome
pattern. Add --agent-plugins-dir to --transient feature.
Add agentPluginsHome to isUserDataProfile type guard.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix warnings
* simplify
Co-authored-by: Copilot <copilot@github.com>
* fix
Co-authored-by: Copilot <copilot@github.com>
* fix
Co-authored-by: Copilot <copilot@github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <copilot@github.com>
Restore agents application support on Linux
Remove the Linux platform check that was added in 683373f3, re-enabling
the agents window on Linux for non-stable builds.
- Restore `ProductQualityContext.notEqualsTo('stable')` in the command
precondition instead of the Linux-specific context key expression
- Clean up unused `isLinux`/`IsLinuxContext` imports
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Replace crossAppIPC-based secret handshake with direct shared keychain
writes in the main process:
- MacOSCrossAppSecretSharing now reads safeStorage+SQLite and writes to
shared keychain via SharedKeychainMainService (no crossAppIPC needed)
- Code.app migrates on startup; Agents app spawns Code.app once if
keychain is incomplete
- NativeSecretStorageService no longer does migration — just reads/writes
shared keychain for cross-app keys
* agentHost: resolve user shell environment for agent host process
Spawn the agent host with the user's resolved shell environment merged
in (PATH and friends from the login shell), matching what other VS Code
processes do via getResolvedShellEnv. Without this, tools and terminals
launched by the agent host on macOS/Linux GUI launches don't see the
user's PATH.
Both ElectronAgentHostStarter and NodeAgentHostStarter now resolve the
shell env before spawning. IAgentHostStarter.start() is now async; the
process managers await it and guard against being disposed mid-await.
In the Electron starter, the renderer's createMessageChannel request
could race ahead of the now-async start() and call utilityProcess.connect()
before utilityProcess.start() had run, silently dropping the MessagePort
and leaving the renderer with no agents. _onWindowConnection now awaits
a DeferredPromise that completes once the utility process has actually
been spawned.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* agentHost: address Copilot review feedback
- ElectronAgentHostStarter: spread shellEnv after process.env so the
resolved login shell PATH actually wins over the GUI-launched env.
(NodeAgentHostStarter is fine as-is: ipc.cp.Client merges process.env
before the options env, so shellEnv there already wins.)
- AgentHostProcessManager._start / ServerAgentHostManager._start: wrap
the body in try/catch so a rejection from starter.start() doesn't
surface as an unhandled promise rejection. Reset state on failure so
future starts can retry. Server manager applies the same MaxRestarts
policy as the unexpected-exit path.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* shared application storage
* add tests
* fix tests
Co-authored-by: Copilot <copilot@github.com>
* add logging and address feedback
* Add application shared storage scope
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Add fallback migration for APPLICATION_SHARED storage
VS Code: AbstractStorageService.get() falls back from
APPLICATION_SHARED to APPLICATION scope transparently,
enabling lazy per-key migration without a registry.
Agents App: SharedSQLiteStorageDatabase reads the host
(VS Code) app's application storage DB as a fallback
during getItems(), merging missing keys so shared data
is available even before VS Code runs with new scope code.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Move storage fallback into Storage class with auto-migration
Move the APPLICATION → APPLICATION_SHARED fallback logic from
AbstractStorageService into the base Storage class via the new
fallbackStorage property on IStorage. When a key is not found,
the fallback is checked and the value is automatically written
through to persist the migration.
This eliminates duplicated fallback code in get/getBoolean/
getNumber and ensures write-through happens for all access
patterns.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Make fallbackStorage an implementation detail of Storage
Remove fallbackStorage from IStorage interface. It is now a
property on the Storage class only, set directly by callers
that have access to the concrete type.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Pass fallback storage via ApplicationSharedStorageMain constructor
Wire up the application storage as fallback during doCreate()
instead of post-init. The ApplicationStorageMain is created
first and passed to ApplicationSharedStorageMain's constructor.
The fallback is set on the Storage instance when the shared
database is created, so it's ready by the time reads happen.
Removes setFallbackStorage() method and post-init wiring.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Remove fallbackDatabasePath - use fallbackStorage only
The in-memory fallbackStorage (application storage) makes the
DB-level fallback (reading VS Code's DB from disk) redundant.
Both VS Code and Agents App now use the same mechanism: the
Storage.fallbackStorage property that reads from application
storage and auto-migrates on hit.
Removes getHostUserDataPath, IProductService dependency, and
INativeEnvironmentService from StorageMainService.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Add MigratingStorage with persisted migration tracking
Introduce MigratingStorage that migrates keys from a fallback
storage on first access. Migrated keys are tracked via a
persisted marker key (__$__migratedStorageMarker) in the DB
so deleted keys are never resurrected from the fallback.
- VS Code windows: MigratingStorage falls back to own
APPLICATION storage for transparent key migration
- Sessions windows: MigratingStorage falls back to host
(VS Code) application storage loaded via IPC
- Main process: ApplicationSharedStorageMain uses
HostApplicationStorageMain for embedded app fallback
- sharedDataFolderName added to product configuration
- Workspace trust migration simplified (handled by
MigratingStorage automatically)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix compilation
* minimise changes
* some fixes
Co-authored-by: Copilot <copilot@github.com>
* fixes
* fix
* delete migrated key
* fix removing migrated key
* update distro
* feedback
* Fix MigratingStorage: persist marker only on actual migration
Add key to migratedKeys immediately before checking fallback
to prevent redundant lookups. Only persist the MIGRATED_KEY
marker when a value was actually found and migrated, avoiding
unnecessary writes when the key doesn't exist in the fallback.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* feedback
* fix tests
Co-authored-by: Copilot <copilot@github.com>
* fix application storage path
* fix compilation
---------
Co-authored-by: Copilot <copilot@github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
When Code.app is spawned with --share-secrets-with-agents-app and no
other file/folder args, skip opening any windows in openFirstWindow().
This prevents the app from flashing windows open during the background
secret migration handshake.
Introduce demand-driven one-time secret migration from VS Code to the
agents app using Electron's crossAppIPC (Mach port based, code-signature
verified).
When the agents app starts and detects that `github.auth` has not been
migrated yet, it:
1. Creates a crossAppIPC connection and starts listening.
2. Spawns Code.app with `--share-secrets-with-agents-app`.
3. Code.app connects, receives a SecretRequest, reads the secret from
its safeStorage, and sends it back in a SecretResponse.
4. The agents app stores the secret in its own safeStorage and sends
a SecretAck so both sides record the migration as done.
5. If Code.app was launched solely for this purpose, it quits.
If Code.app is already running, the second instance forwards the arg
via the node IPC socket to the running instance's LaunchMainService.
Also extracts shared utilities (`readEncryptedSecret`, `writeEncryptedSecret`,
`secretStorageKey`, `SECRET_STORAGE_PREFIX`) from BaseSecretStorageService
into reusable functions in `secrets.ts` to avoid code duplication between
the renderer-side secret service and the main-process secret sharing.
* feat: use crossAppIPC to coordinate update ownership between apps
Introduce CrossAppUpdateCoordinator that uses Electron's crossAppIPC
module to ensure only one update client runs at a time. Whichever app
(VS Code or Agents) launches first becomes the IPC server and owns the
update client. The second app becomes the IPC client, suspends its local
update service, and proxies all update operations to the server.
When the server app quits, the client detects the disconnect, resumes
its local update service, and takes over update ownership. Both apps
show synchronized update UI at all times. "Restart to Update" signals
the peer to quit before applying the update.
- Add crossAppIPC type definitions for custom Electron build
- Add CrossAppUpdateCoordinator (symmetric, role-based coordination)
- Add suspend()/resume() to AbstractUpdateService
- Simplify Agents update UI to use direct update actions
* chore: use temp build
* fix: address review feedback for cross-app update coordination
- Dynamically register/dispose the local state change listener instead
of filtering by mode, avoids unnecessary event handling
while in client mode
- Clarify that suspend() blocks all update checks (automatic and manual)
since the coordinator proxies everything to the server in client mode
- Replace fire-and-forget quit with a proper handshake protocol:
server sends PrepareForQuit, client responds with QuitConfirmed or
QuitVetoed, server only proceeds with quitAndInstall on confirmation.
This prevents one side from quitting while the other's quit is vetoed.
* temp: update build
* fix: disable the crossapp coordinator for stable
* fix: don't restart ipc for client disconnection over quit request
* fix: use proxy exe mutex to detect and relaunch app
* temp: workaround for reconnect on macOS
* chore: move noisy updating state to trace level
* fix: compile error on windows
* fix: ready mutex when running as embedded app
* fix: don't open host app when proxy app is the only client
* chore: only enable cross app updater on windows
macOS needs additional work in the squirrel client.
* chore: revert to upstream electron
* fix: compile error
* fix: lazy resolve custom module
Add a shared keychain service that stores secrets directly in the macOS
Keychain, allowing Code and its embedded Agents app to share auth tokens
without re-authentication.
Architecture:
- ISharedKeychainService (common interface) with ISharedKeychainMainService
running in the Electron main process, exposed to renderer via IPC
- SharedKeychainMainService wraps @vscode/macos-keychain native addon
- NativeSecretStorageService now writes to both the shared keychain and
the legacy safeStorage+SQLite pipeline (for rollback safety)
- On read, shared keychain is tried first, falling back to legacy
Product configuration:
- darwinSharedKeychainServiceName: per-flavor service name for data
isolation between Stable/Insiders/Exploration
- Access group auto-detected from entitlements by the native addon
Key design decisions:
- Shared keychain only used when type is 'persisted' (not in-memory)
- BaseSecretStorageService refactored to expose protected _doGet/_doSet/
_doDelete/_doGetKeys for use by subclasses within sequencer tasks
- Native addon is an optional dependency (macOS-only)
Files:
- build/azure-pipelines/darwin/app-entitlements.plist (keychain-access-groups)
- src/vs/platform/secrets/common/sharedKeychainService.ts (interface)
- src/vs/platform/secrets/electron-main/sharedKeychainMainService.ts (impl)
- src/vs/workbench/services/secrets/electron-browser/sharedKeychainService.ts (IPC proxy)
- src/vs/workbench/services/secrets/electron-browser/secretStorageService.ts (wiring)
Issue: #308028
* polish: improve policy-blocked overlay with agents icon, button fixes, and product names
* feat: add AgentsAppEnabled enterprise policy with parent policy identity propagation
- Register chat.agentsApp.enabled configuration with policy support
- Add agents_app_enabled to IPolicyData for account-level policy
- Save parent VS Code policy identity (win32RegValueName/darwinBundleIdentifier)
in bootstrap-meta before product.sub.json merge so the agents sub-app reads
policies from the parent VS Code's registry/plist domain
- Use parentPolicyConfig in main.ts when creating NativePolicyService
- Improve policy-blocked overlay: agents icon, button width fix, keyboard fix,
hardcoded 'Agents' name, Open VS Code scheme fix
* chore: regenerate policyData.jsonc with AgentsAppEnabled policy
* refactor: use existing ChatAgentMode policy instead of separate AgentsAppEnabled
Piggyback on chat.agent.enabled (ChatAgentMode) policy to show the
policy-blocked splash screen in the agents app, rather than introducing
a separate AgentsAppEnabled policy.
* polish: use sessions logo SVG, save parent urlProtocol, update overlay text
- Replace codicon with sessions logo SVG (theme-aware light/dark)
- Save parent urlProtocol in parentPolicyConfig for correct Open VS Code link
- Update overlay title to 'Agents Disabled by Policy'
- Update description to 'Your organization has disabled Agents via policy.'
* fix: update Learn more link to agents docs
* refactor: move sessions logo SVGs to shared location, update title
* Revert "agentHost: Hook up isRead/isDone (#308107)"
This reverts commit a3d69b7767.
* Revert "agentHost: support connections over tunnels (#307948)"
This reverts commit 75f21d0a8d.
* agentPlugins: clone locally when in a remote
The git extension runs on the remote side, so it's not suitable to use to clone. This just does it directly.
I would kind of like to just take this path in all cases since I previously had to add some internal commands in the git extension. But for now going into next release this only affects the remote case which was previously broken.
Closes#298701
* cleanup
* comments
* Add SSH remote agent host bootstrap
Adds a new ISSHRemoteAgentHostService that automates connecting to a
remote machine via SSH, installing the VS Code CLI, starting
'code agent-host', and forwarding the agent host port back through
the SSH tunnel.
- New service interface and types in common/sshRemoteAgentHost.ts
- Full implementation using ssh2 in electron-browser/ with dynamic
imports to respect layering rules
- Multi-step quick input flow for SSH connection details integrated
into the remote agent host picker
- 'Connect via SSH' command registered in contributions
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Address PR review feedback
- Strip password/privateKeyPath from ISSHAgentHostConnection.config
so secrets are not exposed to consumers after connect
- Redact connection tokens (?tkn=...) in all log output and error
messages to prevent credential leakage
- Parse user@host:port format in SSH host input with proper validation
for port range and missing components
- Guard onDidClose with a closed flag to prevent double-fire when
dispose and SSH close/error events overlap
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* SSH working through main process
Co-authored-by: Copilot <copilot@github.com>
* Resolve ssh configs
Co-authored-by: Copilot <copilot@github.com>
* progress
* Granular connect progress, test fix
Co-authored-by: Copilot <copilot@github.com>
* Test, refactor
Co-authored-by: Copilot <copilot@github.com>
* Resolve comments
Co-authored-by: Copilot <copilot@github.com>
* Get rid of cpu-features
* Move to shared process
Co-authored-by: Copilot <copilot@github.com>
* fixes
Co-authored-by: Copilot <copilot@github.com>
* add ssh2 to remote/package.json
* Cleanup and fixes
Co-authored-by: Copilot <copilot@github.com>
* fix
Co-authored-by: Copilot <copilot@github.com>
* fix
Co-authored-by: Copilot <copilot@github.com>
* resolve comments
Co-authored-by: Copilot <copilot@github.com>
* comments
Co-authored-by: Copilot <copilot@github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Raymond Zhao <7199958+rzhao271@users.noreply.github.com>
Co-authored-by: Copilot <copilot@github.com>
* updating tests
* sandbox dependencies check for linux
* sandbox dependencies check for linux
* review comment
* Injecting sandboxhelperservice for web