Skip to content

Commit 27161e4

Browse files
Merge branch 'main' into configurable-file-size-limit
2 parents 49e7cb4 + 4fae990 commit 27161e4

1,712 files changed

Lines changed: 138724 additions & 65427 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.agents/skills/launch/SKILL.md

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ You're working on VS Code itself and you want to:
1414

1515
This skill provides a launcher that clones an authenticated user-data-dir to a throwaway temp folder, picks free ports for every debug surface, and prints them as JSON so you can pick them up programmatically.
1616

17-
The clone is **slim**: workspace storage, browser caches, file history, cached VSIX backups, and old logs are excluded by default. On macOS, auth tokens live in the OS keychain plus small files inside `User/globalStorage` - both of which *are* preserved.
17+
The clone is **slim**: workspace storage, browser caches, file history, cached VSIX backups, and old logs are excluded by default. On macOS, auth tokens live in the OS keychain plus small files inside `User/globalStorage` - both of which *are* preserved. On Windows the GitHub session lives in the **shared-data-dir** instead, which the launcher seeds separately (see [Windows authentication](#windows-authentication)).
1818

1919
## Prerequisites
2020

@@ -74,7 +74,20 @@ The exclude list mirrors the one used by VS Code's own perf-test skill (`.github
7474

7575
#### Windows authentication
7676

77-
Windows has no shared per-app keychain for these secrets. They live in the copied profile, notably `User/globalStorage/state.vscdb` and root `Local State`, so the launcher verifies that they (plus `machineid` and `Network`) survived the copy. If a launched instance prompts for sign-in, launch `.\scripts\code.bat --user-data-dir=<source-udd>` directly, sign in once, and close it; every later launch copies that source profile and inherits the session.
77+
Windows has no shared per-app keychain for these secrets, so they live in files on disk - but **not all in the user-data-dir**. The GitHub session is stored at `StorageScope.APPLICATION_SHARED` *only on Windows* (see `useSharedStorage` and `CROSS_APP_SHARED_SECRET_KEYS` in `src/vs/platform/secrets/common/secrets.ts`), which puts the two halves of the credential in **different directories**:
78+
79+
| Piece | Location |
80+
|---|---|
81+
| Encrypted GitHub session blob | `<shared-data-dir>/sharedStorage/state.vscdb` |
82+
| DPAPI-wrapped decryption key (`os_crypt.encrypted_key`) | `<user-data-dir>/Local State` |
83+
84+
The launcher therefore seeds **both**: it copies the source profile *and* copies the source shared-data-dir into the run's throwaway `shared-data` dir. The source resolves the same way `IEnvironmentService.appSharedDataHome` does - `$env:CODE_OSS_DEV_AUTHED_SHARED_DATA_DIR` if set, else `$env:VSCODE_PORTABLE\shared-data` when running portable, else `~/<product.sharedDataFolderName>` (i.e. `%USERPROFILE%\.vscode-oss-shared`). It also verifies `Local State`, `machineid`, and `Network` survived the profile copy, and warns on stderr if neither database holds a GitHub session.
85+
86+
> This asymmetry is invisible on macOS/Linux, where the same token lands inside the profile. A Windows-only "always signed out" symptom is a shared-data-dir problem, **not** a profile problem: signing in against the source profile writes a perfectly good session, but before this seeding existed every launch handed Code OSS an empty shared dir and threw it away.
87+
88+
To (re)establish the source session: run `.\scripts\code.bat --user-data-dir=$env:USERPROFILE\.vscode-oss-dev` directly, sign in once, and close it. That writes the blob to `%USERPROFILE%\.vscode-oss-shared` and the key to the profile's `Local State`; later launches copy both and inherit the session.
89+
90+
> Profiles that predate the `APPLICATION_SHARED` migration can still hold the secret in `User/globalStorage/state.vscdb`. `ApplicationSharedStorageMain` registers application storage as a read fallback, so those profiles authenticate even with no shared-data-dir present - which is why a missing shared dir is reported as a fact rather than assumed fatal.
7891
7992
Excluded (transient, regenerable, or known-not-needed):
8093
- `User/workspaceStorage/` - per-workspace state, **including stored chat sessions** (often multi-GB)
@@ -325,7 +338,7 @@ You can run `@playwright/cli` and `dap-cli` against the **same window simultaneo
325338
326339
Every launch picks fresh ports and a fresh temp `runDir`, so you can run as many concurrent Code OSS windows as your machine can handle. Each one's ports come back in its own JSON blob - keep them separate.
327340
328-
The launcher also passes `--shared-data-dir=<runDir>/shared-data`. This is **required** for multi-instance isolation: Code OSS keeps a fixed-path SQLite DB at `~/.<dataFolderName>-shared/sharedStorage/state.vscdb` that is *not* covered by `--user-data-dir`. Without overriding it, two concurrent instances would fight over the same file and one would die with "shared background process terminated unexpectedly". Each launch gets its own `shared-data` dir.
341+
The launcher also passes `--shared-data-dir=<runDir>/shared-data`. This is **required** for multi-instance isolation: Code OSS keeps a fixed-path SQLite DB at `~/.<dataFolderName>-shared/sharedStorage/state.vscdb` that is *not* covered by `--user-data-dir`. Without overriding it, two concurrent instances would fight over the same file and one would die with "shared background process terminated unexpectedly". Each launch gets its own `shared-data` dir, **seeded from the source shared-data-dir** so the Windows GitHub session survives - see [Windows authentication](#windows-authentication) for why that copy matters.
329342
330343
## Restart after source changes
331344
@@ -367,10 +380,11 @@ Code OSS is a full Electron app and easily eats 1-4 GB. Always clean up.
367380

368381
## Troubleshooting
369382

383+
- **`Daemon pid=...: listen EINVAL` from `@playwright/cli`** - the daemon's socket path (`TMPDIR` + a fixed ~33-char prefix + the `-s=` session name) exceeded the ~103-byte unix socket limit. macOS's default `TMPDIR` leaves only ~16 characters for the session name, so shorten `-s=` first. If you need a longer name, scope the override to the single command (`TMPDIR=/tmp npx @playwright/cli ...`) rather than `export`ing it, so the launcher keeps using your private per-user temp dir.
370384
- **"Sent env to running instance. Terminating..."** - The dynamic `--user-data-dir` should prevent this. If you see it, another Code OSS is using the same profile path; pass `--source-user-data-dir` to a different source or check that the temp copy actually happened (`ls "$(jq -r .userDataDir <<<"$INFO")"`).
371385
- **Renderer ESM errors / `import { Menu } from 'electron'`** - `ELECTRON_RUN_AS_NODE` is set in your env. The launcher unsets it for the child, but if you spawn `code.sh` yourself, do the same.
372386
- **Built-in extension fails to load (`Cannot find module .../extensions/.../out/extension.js`)** - extensions weren't compiled. Run `npm run compile` (one-shot, also rebuilds all built-in extensions) or `npm run watch` (incremental). A common cause: you ran `npm run transpile-client` to satisfy unit tests, which populated `out/` but not `extensions/*/out/`, so preLaunch's "is `out/` missing?" check skipped the compile.
373387
- **`launch.sh` exits non-zero with a log tail** - either pre-launch failed, `code.sh` died before CDP came up, or CDP never opened within 90s. The tail printed to stderr is from `runDir/code.log` - read it to diagnose.
374388
- **Snapshot shows the wrong page or no expected controls** - use `tab-list`, switch with `tab-select <index>` if needed, then re-snapshot before interacting.
375389
- **CLI typing commands complete but the input stays empty** - focus chat with the platform shortcut, use `press` or clipboard paste rather than `fill` / `type`, then verify the input state before sending.
376-
- **Auth missing in the launched window** - confirm the source profile is actually authed (`ls "$SOURCE_UDD"` should contain `User/`, and `ls "$SOURCE_UDD/User/globalStorage"` should show persisted extension state). On Windows, sign in directly against the source profile once so its copied `state.vscdb` and `Local State` contain the session.
390+
- **Auth missing in the launched window** - confirm the source profile is actually authed (`ls "$SOURCE_UDD"` should contain `User/`, and `ls "$SOURCE_UDD/User/globalStorage"` should show persisted extension state). **On Windows, check the shared-data-dir first**: the GitHub session blob lives in `%USERPROFILE%\.vscode-oss-shared\sharedStorage\state.vscdb`, not in the profile. The launcher logs `copying shared data: <src> -> <dst>` on stderr when it finds it, and warns `no shared-data-dir at <path>` when it doesn't. A missing or empty source shared-data-dir means signing in again against the source profile is what you need - see [Windows authentication](#windows-authentication).

.agents/skills/launch/scripts/launch.ps1

Lines changed: 103 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -39,22 +39,65 @@ function Get-UsableNode([string]$repoPath) {
3939
}
4040

4141
$setupMessage = "Run in PowerShell from $repoPath`: fnm env --use-on-cd --shell powershell | Out-String | Invoke-Expression; fnm use"
42-
if ($null -eq $command) {
43-
throw "Node.js $requiredVersion or newer is required on PATH. $setupMessage"
42+
if ($null -ne $command) {
43+
try {
44+
$version = & $command.Source --version 2>$null
45+
if ($LASTEXITCODE -ne 0 -or $version -notmatch '^v(?<version>\d+\.\d+\.\d+)') {
46+
throw 'could not determine its version'
47+
}
48+
if ([version]$Matches.version -lt [version]$requiredVersion) {
49+
throw "found $version"
50+
}
51+
return $command.Source
52+
} catch {
53+
# Fall through to fnm fallback
54+
}
4455
}
4556

46-
try {
47-
$version = & $command.Source --version 2>$null
48-
if ($LASTEXITCODE -ne 0 -or $version -notmatch '^v(?<version>\d+\.\d+\.\d+)') {
49-
throw 'could not determine its version'
57+
# Fallback: Check fnm directories (most recent first)
58+
$fnmBase = Join-Path $env:USERPROFILE 'AppData\Local\fnm_multishells'
59+
if (Test-Path $fnmBase) {
60+
$fnmDirs = Get-ChildItem $fnmBase -Directory -ErrorAction SilentlyContinue | Sort-Object -Property CreationTime -Descending
61+
foreach ($dir in $fnmDirs) {
62+
$nodePath = Join-Path $dir.FullName 'node.exe'
63+
if (Test-Path $nodePath) {
64+
try {
65+
$version = & $nodePath --version 2>$null
66+
if ($LASTEXITCODE -eq 0 -and $version -match '^v(?<version>\d+\.\d+\.\d+)') {
67+
if ([version]$Matches.version -ge [version]$requiredVersion) {
68+
return $nodePath
69+
}
70+
}
71+
} catch { }
72+
}
5073
}
51-
if ([version]$Matches.version -lt [version]$requiredVersion) {
52-
throw "found $version"
74+
}
75+
76+
throw "Node.js $requiredVersion or newer is required on PATH. $setupMessage"
77+
}
78+
79+
function Get-SourceSharedDataDir([string]$repoPath) {
80+
if ($env:CODE_OSS_DEV_AUTHED_SHARED_DATA_DIR) {
81+
return $env:CODE_OSS_DEV_AUTHED_SHARED_DATA_DIR
82+
}
83+
84+
# Mirrors IEnvironmentService.appSharedDataHome, minus the --shared-data-dir
85+
# branch (that one names the *destination*, not the source we copy from):
86+
# VSCODE_PORTABLE\shared-data, else ~/<product.sharedDataFolderName>.
87+
if ($env:VSCODE_PORTABLE) {
88+
return Join-Path $env:VSCODE_PORTABLE 'shared-data'
89+
}
90+
91+
$folderName = '.vscode-oss-shared'
92+
$productJson = Join-Path $repoPath 'product.json'
93+
if (Test-Path -LiteralPath $productJson -PathType Leaf) {
94+
$product = Get-Content -LiteralPath $productJson -Raw | ConvertFrom-Json
95+
if ($product.PSObject.Properties['sharedDataFolderName']) {
96+
$folderName = $product.sharedDataFolderName
5397
}
54-
return $command.Source
55-
} catch {
56-
throw "Node.js $requiredVersion or newer is required on PATH ($($_.Exception.Message)). $setupMessage"
5798
}
99+
100+
return Join-Path $env:USERPROFILE $folderName
58101
}
59102

60103
function Get-FreePort {
@@ -171,14 +214,13 @@ function Assert-AuthCriticalProfileFiles([string]$destination) {
171214
}
172215
}
173216

174-
function Test-SourceHasGitHubAuthenticationSecret([string]$node, [string]$source, [string]$temporaryDb) {
175-
$sourceDb = Join-Path $source 'User\globalStorage\state.vscdb'
176-
if (-not (Test-Path -LiteralPath $sourceDb -PathType Leaf)) {
177-
return $null
217+
function Test-DbHasGitHubAuthenticationSecret([string]$node, [string]$db, [string]$temporaryDb) {
218+
if (-not (Test-Path -LiteralPath $db -PathType Leaf)) {
219+
return $false
178220
}
179221

180222
try {
181-
[IO.File]::Copy($sourceDb, $temporaryDb, $true)
223+
[IO.File]::Copy($db, $temporaryDb, $true)
182224
$script = @'
183225
import { DatabaseSync } from 'node:sqlite';
184226
@@ -206,6 +248,33 @@ try {
206248
}
207249
}
208250

251+
function Test-SourceHasGitHubAuthenticationSecret([string]$node, [string]$source, [string]$sharedSource, [string]$temporaryDb) {
252+
# On Windows the GitHub session is APPLICATION_SHARED scoped, so it lives in
253+
# the shared-data-dir rather than the profile - see useSharedStorage in
254+
# src/vs/platform/secrets/common/secrets.ts. Older profiles may still hold it
255+
# in globalStorage, and both directories get copied, so either one counts.
256+
$databases = @(
257+
(Join-Path $sharedSource 'sharedStorage\state.vscdb'),
258+
(Join-Path $source 'User\globalStorage\state.vscdb')
259+
)
260+
261+
$undetermined = $false
262+
foreach ($db in $databases) {
263+
$result = Test-DbHasGitHubAuthenticationSecret $node $db $temporaryDb
264+
if ($result -eq $true) {
265+
return $true
266+
}
267+
if ($null -eq $result) {
268+
$undetermined = $true
269+
}
270+
}
271+
272+
if ($undetermined) {
273+
return $null
274+
}
275+
return $false
276+
}
277+
209278
function Get-JsoncCodeMask([string]$text) {
210279
# Returns a same-length copy of $text with every comment span blanked out.
211280
# Offsets are preserved so a match found in the mask can be applied to the
@@ -287,11 +356,11 @@ function Ensure-SimpleDialogSetting([string]$settingsFile) {
287356

288357
$lastBrace = $maskedText.LastIndexOf('}')
289358
if ($lastBrace -eq -1) {
290-
throw "settings.json has no closing brace refusing to clobber it: $settingsFile"
359+
throw "settings.json has no closing brace - refusing to clobber it: $settingsFile"
291360
}
292361
$firstBrace = $maskedText.IndexOf('{')
293362
if ($firstBrace -eq -1 -or $firstBrace -ge $lastBrace) {
294-
throw "settings.json has no opening brace refusing to clobber it: $settingsFile"
363+
throw "settings.json has no opening brace - refusing to clobber it: $settingsFile"
295364
}
296365

297366
# Whether a leading comma is needed depends only on real content, so decide
@@ -452,7 +521,22 @@ try {
452521
$logFile = Join-Path $runDir 'code.log'
453522
New-Item -ItemType Directory -Force -Path $runDir, $sharedDataDir | Out-Null
454523
[IO.File]::WriteAllText($logFile, '', [Text.UTF8Encoding]::new($false))
455-
$hasGitHubAuthenticationSecret = Test-SourceHasGitHubAuthenticationSecret $node $sourceUserDataDir (Join-Path $runDir 'auth-preflight.vscdb')
524+
$sourceSharedDataDir = Get-SourceSharedDataDir $repo
525+
if (Test-Path -LiteralPath $sourceSharedDataDir -PathType Container) {
526+
# On Windows the GitHub session is APPLICATION_SHARED scoped, so it lives here
527+
# and not in the profile - see useSharedStorage in
528+
# src/vs/platform/secrets/common/secrets.ts. Without this copy the launched
529+
# instance always prompts for sign-in.
530+
Write-LaunchError "[launch.ps1] copying shared data: $sourceSharedDataDir -> $sharedDataDir"
531+
Copy-ProfileDirectory $sourceSharedDataDir $sharedDataDir $false
532+
} else {
533+
# Not necessarily fatal: profiles predating the APPLICATION_SHARED migration
534+
# still hold the secret in globalStorage, and ApplicationSharedStorageMain
535+
# falls back to application storage. State the fact and let the preflight
536+
# below decide whether a sign-in is actually coming.
537+
Write-LaunchError "[launch.ps1] no shared-data-dir at $sourceSharedDataDir; nothing to seed"
538+
}
539+
$hasGitHubAuthenticationSecret = Test-SourceHasGitHubAuthenticationSecret $node $sourceUserDataDir $sourceSharedDataDir (Join-Path $runDir 'auth-preflight.vscdb')
456540
if ($hasGitHubAuthenticationSecret -eq $false) {
457541
Write-LaunchError "[launch.ps1] WARNING: source profile $sourceUserDataDir has no stored GitHub session; the launched instance will prompt you to sign in."
458542
Write-LaunchError 'To fix once and for all, launch Code OSS directly against the source profile (no copy), sign in, then close it:'

.agents/skills/launch/scripts/launch.sh

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,21 @@ MAIN_PORT=$(pick_port)
7777
AGENTHOST_PORT=$(pick_port)
7878

7979
STAMP=$(date +%Y%m%d-%H%M%S)-$$
80-
RUN_DIR="${TMPDIR:-/tmp}/code-oss-dev/$STAMP"
80+
# mktemp fills in the X's only when they trail the template; elsewhere they stay literal.
81+
RUN_NAME="code-oss-dev-$STAMP-XXXXXX"
82+
RUN_BASE="${TMPDIR:-/tmp}"
83+
# Electron's main IPC socket ("<run-dir>/user-data/<version>-main.sock") must fit
84+
# the ~103-byte unix socket limit, which macOS's default TMPDIR alone overflows.
85+
# Measure bytes, not characters, since a multibyte TMPDIR would pass a char count
86+
# and still fail to bind.
87+
if (( $(printf '%s' "$RUN_BASE/$RUN_NAME" | wc -c) + 25 > 103 )); then
88+
RUN_BASE=/tmp
89+
echo "[launch.sh] TMPDIR too long for unix sockets; using $RUN_BASE" >&2
90+
fi
91+
# mktemp -d creates the directory atomically with 0700 perms, so this copy of the
92+
# authenticated profile can't be pre-created or symlinked by another user, and its
93+
# token files aren't left world-readable when the temp base is shared (/tmp).
94+
RUN_DIR=$(mktemp -d "$RUN_BASE/$RUN_NAME")
8195
DEST_UDD="$RUN_DIR/user-data"
8296
SHARED_DATA_DIR="$RUN_DIR/shared-data"
8397
mkdir -p "$DEST_UDD" "$SHARED_DATA_DIR"

.eslint-allowed-javascript-files

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,13 @@ build/builtin/browser-main.js
1616
build/builtin/main.js
1717
build/npm/stubs/sharp/index.js
1818
build/codex/generate-protocol.mjs
19+
build/next/devTunnelsWebEntry.js
20+
build/next/devTunnelsShims/buffer.js
21+
build/next/devTunnelsShims/bufferutil.cjs
22+
build/next/devTunnelsShims/empty.cjs
23+
build/next/devTunnelsShims/process.js
24+
build/next/devTunnelsShims/utf8Validate.cjs
25+
build/next/devTunnelsShims/vscodeJsonrpc.cjs
1926
eslint.config.js
2027
extensions/copilot/.mocha-multi-reporters.js
2128
extensions/copilot/.mocharc.js

.github/CODENOTIFY

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ extensions/vscode-api-tests/src/singlefolder-tests/browser*.test.ts @kycutler @j
8383

8484
# Testing
8585
test/mcp/** @TylerLeonhardt
86+
test/scenario/** @bryanchen-d
8687
test/sanity/** @dmitrivMS
8788

8889
# Agents Workbench

.github/CODEOWNERS

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,12 @@ src/vs/workbench/services/extensions/common/extensionPoints.json @TylerLeonhardt
1818
# Adding entries here lets a new .js/.cjs/.mjs file land in the repo;
1919
# review is required to make sure TypeScript is not a better choice.
2020
.eslint-allowed-javascript-files @alexr00 @alexdima @sbatten @TylerLeonhardt
21+
22+
# Agents Window architecture specifications and their routing policy.
23+
# These files describe stable contracts and should not change for routine fixes.
24+
/src/vs/sessions/*.md @sandy081
25+
/src/vs/sessions/contrib/layout/browser/*.md @sandy081
26+
/src/vs/sessions/contrib/providers/*/*.md @sandy081
27+
/.github/instructions/sessions.instructions.md @sandy081
28+
/.github/skills/sessions/SKILL.md @sandy081
29+
/.github/skills/chat-customizations-editor/SKILL.md @sandy081

.github/dependabot.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,7 @@ updates:
1414
directory: "/extensions/markdown-language-features"
1515
schedule:
1616
interval: "daily"
17+
time: "16:00"
18+
timezone: "America/Los_Angeles"
1719
allow:
1820
- dependency-name: "@vscode/markdown-editor"

.github/instructions/agentHostTesting.instructions.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,13 @@ The sessions process is a portable, standalone server that multiple clients can
2020

2121
See the agent host protocol documentation for more details.
2222

23+
## Service Construction
24+
25+
Read `src/vs/platform/agentHost/node/serviceBootstrapping.md` before adding or
26+
moving a node Agent Host service. It is the canonical guide for service
27+
placement, static constructor arguments, activation, test overrides, and
28+
disposal ownership.
29+
2330
## End to End Testing
2431

2532
You can run `node ./scripts/code-agent-host.js` to start an agent host. If you pass `--enable-mock-agent`, then the `ScriptedMockAgent` will be used.

.github/instructions/best-practices.instructions.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ applyTo: src/vs/**
1919
- Resolve editor action arguments with `resolveCommandsContext` (`vs/workbench/browser/parts/editor/editorCommandsContext.ts`) to get the correct editor(s) instead of reading `editorService.activeEditor`.
2020
- Support multi-selection. The resolved editor actions context can contain several editors (e.g. multi-selected tabs).
2121

22+
## Context Keys
23+
24+
- Don't use context keys as a source of truth for application logic (for example, by reading `IContextKeyService.getContextKeyValue()` and branching on the result). Read the state from its owning service or model instead. Context keys are intended for declarative enablement and visibility, such as when clauses, command preconditions, and menu contributions.
25+
2226
## URI
2327

2428
- Don't hardcode URI scheme strings like `'file'`, `'untitled'`, or `'vscode-remote'`. Use the `Schemas` constants from `vs/base/common/network.ts` (e.g. `Schemas.file`, `Schemas.untitled`, `Schemas.vscodeRemote`).

0 commit comments

Comments
 (0)