Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
953f23e
Default external sessions to recent (#332195)
benibenj Aug 23, 2026
fd811a4
sessions: keep chat input above mobile keyboard (#332148)
amunger Aug 23, 2026
9ef731c
Float chat pills above the chat input (#332196)
benibenj Aug 23, 2026
19a1b50
Rename leftover respectAutoSaveConfig variable to isRefactoring (#160…
a-stewart Aug 23, 2026
9ef9bc9
Fix typo in selectionHighlightMaxLength description (#296427)
jainampatel27 Aug 23, 2026
1ad94e2
Launch skill: Poll CDP readiness more frequently (#332190)
jruales Aug 23, 2026
493f812
agentHost: Map resources through owning connection (#332088)
roblourens Aug 23, 2026
310a3f5
Launch skill: Optimize launch debug port allocation (#332208)
jruales Aug 24, 2026
07d1762
docs: remove dead Gitter badge (service shut down June 2023) (#322702)
jachinsamuel Aug 24, 2026
8bb368a
Launch skill: Report startup timing phases (#332211)
jruales Aug 24, 2026
6037262
subagent ux: fix border, better confirmation, show subagent type (#33…
justschen Aug 24, 2026
a3397f6
agentHost: Clarify Markdown file link formatting (#332213)
roblourens Aug 24, 2026
f2180ea
Fix agent sessions midnight test flake (Written by Copilot) (#332216)
roblourens Aug 24, 2026
84aa315
Launch skill: Add prepared-build fast path (#332214)
jruales Aug 24, 2026
b41c9d8
De-flake response selection browser tests (Written by Copilot) (#332217)
roblourens Aug 24, 2026
ee6d34f
Rename auto tiers display names to "Optimize for" (#332005)
lramos15 Aug 24, 2026
d0686fe
Remove unused code (#332219)
roblourens Aug 24, 2026
af0071d
agentHost: add tool invocation telemetry (#332218)
roblourens Aug 24, 2026
b8e7c56
Agent Host: Export debug logs for the active chat (#332067)
roblourens Aug 24, 2026
6a7ab60
Fix typo in Settings UI description for editor.selectionHighlightMaxL…
TheRealAlexxx Aug 24, 2026
0052619
Add harness context to chat telemetry (#332100)
jruales Aug 24, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions .agents/skills/launch/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ The clone is **slim**: workspace storage, browser caches, file history, cached V
## Prerequisites

- macOS, Linux, or Windows.
- **macOS / Linux**: the launcher is a bash script (`scripts/launch.sh`) and depends on `rsync`, `curl`, `nohup`, and Node on `PATH`. The example caller snippets below also use `jq` (parse the JSON output) and `lsof` (kill-by-port fallback) — install those if you plan to use them, but the launcher itself does not require them.
- **macOS / Linux**: the launcher is a bash script (`scripts/launch.sh`) and depends on `rsync`, `nohup`, and Node on `PATH`. The example caller snippets below also use `jq` (parse the JSON output) and `lsof` (kill-by-port fallback) — install those if you plan to use them, but the launcher itself does not require them.
- **Windows**: use `scripts\launch.ps1` instead. It needs no extra tooling beyond Node on `PATH`, and works on both Windows PowerShell 5.1 and PowerShell 7+. `jq` is not needed — parse the JSON with `ConvertFrom-Json`. If Node is managed with [fnm](https://github.com/Schniz/fnm), put it on `PATH` first:
```powershell
fnm env --use-on-cd --shell powershell | Out-String | Invoke-Expression
Expand Down Expand Up @@ -50,6 +50,7 @@ The launcher script lives next to this SKILL.md at `scripts/launch.sh` (macOS/Li
"$LAUNCH" --repo <vscode-repo-root> # if not run from the repo
"$LAUNCH" --clone-extensions # start with a copy of the source extensions/ (~few seconds)
"$LAUNCH" --full # skip slim excludes; copy everything
"$LAUNCH" --skip-prelaunch # reuse already-current build outputs
```

On Windows, invoke the PowerShell launcher with the same flags:
Expand All @@ -64,6 +65,7 @@ $launch = Join-Path $skillDir 'scripts\launch.ps1'
& $launch --repo C:\path\to\vscode
& $launch --clone-extensions
& $launch --full
& $launch --skip-prelaunch
```

If the local execution policy blocks scripts, invoke it with `powershell -ExecutionPolicy Bypass -File <path-to-launch.ps1>`. The Windows implementation has the same profile isolation, slim-copy excludes, settings merge, port allocation, foreground pre-launch, and CDP-ready contract as the bash launcher; only the shell commands and path syntax differ.
Expand Down Expand Up @@ -106,10 +108,14 @@ Excluded (transient, regenerable, or known-not-needed):

The script runs pre-launch (electron download, compile-if-missing, built-in extensions) **in the foreground**, then starts Code OSS detached and **blocks until the renderer's CDP endpoint is responding** (up to ~90s) before printing the JSON line on stdout. If anything fails — preLaunch errors, code.sh exits early, CDP never opens — the script exits non-zero and dumps the relevant log tail to stderr.

For repeated launches of the same prepared build, pass `--skip-prelaunch` after one successful normal launch. Only use it while a watch task keeps all output current or neither sources nor build outputs have changed; otherwise the new instance may run stale or incomplete code.

```json
{"pid":12345,"cdpPort":53111,"extHostPort":53112,"mainPort":53113,"agentHostPort":53114,"userDataDir":".../user-data","extensionsDir":".../extensions","sharedDataDir":".../shared-data","runDir":"...","logFile":".../code.log","repo":"...","agents":false}
{"pid":12345,"cdpPort":53111,"extHostPort":53112,"mainPort":53113,"agentHostPort":53114,"userDataDir":".../user-data","extensionsDir":".../extensions","sharedDataDir":".../shared-data","runDir":"...","logFile":".../code.log","repo":"...","agents":false,"timings":{"profileMs":231,"preLaunchMs":251,"cdpReadyMs":459,"totalMs":941}}
```

The additive `timings` object uses monotonic elapsed time to identify time spent preparing the isolated profile, running pre-launch, and starting Code OSS through CDP readiness. `totalMs` covers the complete launcher operation through readiness.

Capture it with `jq` — no retry loop needed, CDP is already up when the JSON is printed:

```bash
Expand Down Expand Up @@ -354,7 +360,7 @@ npx @playwright/cli -s=$PW_SESSION tab-list
npx @playwright/cli -s=$PW_SESSION snapshot
```

If you are iterating frequently, keep the repo build/watch task running separately so relaunches pick up already-generated output.
If you are iterating frequently, keep the repo build/watch task running separately so relaunches pick up already-generated output. After one successful normal launch, `--skip-prelaunch` avoids repeating the preparation while those outputs remain current.

## Cleanup

Expand Down
74 changes: 41 additions & 33 deletions .agents/skills/launch/scripts/launch.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ $sourceUserDataDir = ''
$repo = ''
$cloneExtensions = $false
$full = $false
$skipPreLaunch = $false
if ($null -eq $cliArgs) {
$cliArgs = @()
}
Expand Down Expand Up @@ -464,6 +465,10 @@ for ($index = 0; $index -lt $cliArgs.Count; $index++) {
$full = $true
continue
}
'--skip-prelaunch' {
$skipPreLaunch = $true
continue
}
'--' {
for ($forwardIndex = $index + 1; $forwardIndex -lt $cliArgs.Count; $forwardIndex++) {
$extraArgs.Add($cliArgs[$forwardIndex])
Expand All @@ -478,6 +483,7 @@ for ($index = 0; $index -lt $cliArgs.Count; $index++) {
}

try {
$launchStopwatch = [Diagnostics.Stopwatch]::StartNew()
if ([string]::IsNullOrWhiteSpace($repo)) {
$candidateRepo = (Get-Location).Path
if (Test-Path -LiteralPath (Join-Path $candidateRepo 'scripts\code.bat') -PathType Leaf) {
Expand Down Expand Up @@ -563,6 +569,7 @@ try {
$settingsFile = Join-Path $destinationUdd 'User\settings.json'
Ensure-SimpleDialogSetting $settingsFile
Write-LaunchError "[launch.ps1] ensured files.simpleDialog.enable=true in $settingsFile"
$profileReadyMs = $launchStopwatch.ElapsedMilliseconds

$launchArgs = [System.Collections.Generic.List[string]]::new()
if ($agents) {
Expand All @@ -581,47 +588,42 @@ try {

Write-LaunchError "[launch.ps1] launching: $codeBat $($launchArgs -join ' ')"
Write-LaunchError "[launch.ps1] logs: $logFile"
Write-LaunchError '[launch.ps1] running pre-launch (ensures electron + compiled output + built-ins)...'
Push-Location -LiteralPath $repo
try {
& $node 'build/lib/preLaunch.ts' *>> $logFile
$preLaunchExitCode = $LASTEXITCODE
} finally {
Pop-Location
}
if ($preLaunchExitCode -ne 0) {
Write-LaunchError '[launch.ps1] pre-launch FAILED. Log tail:'
Write-LogTail $logFile
exit 1
}

$process = Start-Code $codeBat $launchArgs.ToArray() $logFile
Write-LaunchError "[launch.ps1] waiting for CDP on port $cdpPort (timeout 90s)..."
$ready = $false
for ($second = 1; $second -le 90; $second++) {
if ($process.HasExited) {
Write-LaunchError "[launch.ps1] code.bat (PID $($process.Id)) exited before CDP came up. Log tail:"
if ($skipPreLaunch) {
Write-LaunchError '[launch.ps1] skipping pre-launch by request'
} else {
Write-LaunchError '[launch.ps1] running pre-launch (ensures electron + compiled output + built-ins)...'
Push-Location -LiteralPath $repo
try {
& $node 'build/lib/preLaunch.ts' *>> $logFile
$preLaunchExitCode = $LASTEXITCODE
} finally {
Pop-Location
}
if ($preLaunchExitCode -ne 0) {
Write-LaunchError '[launch.ps1] pre-launch FAILED. Log tail:'
Write-LogTail $logFile
exit 1
}
}
$preLaunchReadyMs = $launchStopwatch.ElapsedMilliseconds

try {
$request = [Net.WebRequest]::Create("http://127.0.0.1:$cdpPort/json/version")
$request.Timeout = 1000
$response = $request.GetResponse()
$response.Close()
$ready = $true
Write-LaunchError "[launch.ps1] CDP ready after ${second}s"
break
} catch {
Start-Sleep -Seconds 1
$process = Start-Code $codeBat $launchArgs.ToArray() $logFile
Write-LaunchError "[launch.ps1] waiting for CDP on port $cdpPort (timeout 90s)..."
$waitForCdp = Join-Path $PSScriptRoot 'waitForCdp.ts'
$readyMs = & $node $waitForCdp $process.Id $cdpPort
$readyStatus = $LASTEXITCODE
if ($readyStatus -eq 0) {
Write-LaunchError "[launch.ps1] CDP ready after ${readyMs}ms"
} else {
switch ($readyStatus) {
1 { Write-LaunchError "[launch.ps1] timed out waiting for CDP on port $cdpPort. Log tail:" }
2 { Write-LaunchError "[launch.ps1] code.bat (PID $($process.Id)) exited before CDP came up. Log tail:" }
default { Write-LaunchError "[launch.ps1] failed while waiting for CDP on port $cdpPort. Log tail:" }
}
}
if (-not $ready) {
Write-LaunchError "[launch.ps1] timed out waiting for CDP on port $cdpPort. Log tail:"
Write-LogTail $logFile
exit 1
}
$launchReadyMs = $launchStopwatch.ElapsedMilliseconds

[PSCustomObject]@{
pid = $process.Id
Expand All @@ -636,6 +638,12 @@ try {
logFile = $logFile
repo = $repo
agents = [bool]$agents
timings = [PSCustomObject]@{
profileMs = $profileReadyMs
preLaunchMs = $preLaunchReadyMs - $profileReadyMs
cdpReadyMs = $launchReadyMs - $preLaunchReadyMs
totalMs = $launchReadyMs
}
} | ConvertTo-Json -Compress
} catch {
Write-LaunchError "[launch.ps1] $($_.Exception.Message)"
Expand Down
95 changes: 61 additions & 34 deletions .agents/skills/launch/scripts/launch.sh
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,16 @@
#
# Usage:
# launch.sh [--agents] [--source-user-data-dir <path>] [--repo <vscode-repo-root>]
# [--clone-extensions] [--full] [-- <extra code.sh args>]
# [--clone-extensions] [--full] [--skip-prelaunch] [-- <extra code.sh args>]
#
# Flags:
# --clone-extensions Copy the source extensions/ into the new profile (~10s).
# Default: start with an EMPTY extensions/ dir - fastest
# and conflict-free, but no third-party extensions.
# --full Copy the entire profile (incl. extensions). Use if the
# slim copy is missing something you need.
# --skip-prelaunch Skip build/lib/preLaunch.ts after a successful prepared
# launch while build outputs remain current.
#
# Defaults:
# --source-user-data-dir $CODE_OSS_DEV_AUTHED_USER_DATA_DIR (else ~/.vscode-oss-dev)
Expand All @@ -35,6 +37,7 @@ REPO=""
EXTRA_ARGS=()
CLONE_EXTENSIONS=0
FULL=0
SKIP_PRELAUNCH=0

while [[ $# -gt 0 ]]; do
case "$1" in
Expand All @@ -43,11 +46,18 @@ while [[ $# -gt 0 ]]; do
--repo) REPO="$2"; shift 2 ;;
--clone-extensions|--copy-extensions) CLONE_EXTENSIONS=1; shift ;;
--full) FULL=1; shift ;;
--skip-prelaunch) SKIP_PRELAUNCH=1; shift ;;
--) shift; EXTRA_ARGS=("$@"); break ;;
*) echo "Unknown arg: $1" >&2; exit 2 ;;
esac
done

monotonic_ms() {
node -e 'process.stdout.write(String(process.hrtime.bigint() / 1_000_000n))'
}

LAUNCH_START_MS=$(monotonic_ms)

if [[ -z "$REPO" ]]; then
if [[ -x "$PWD/scripts/code.sh" ]]; then
REPO="$PWD"
Expand All @@ -63,18 +73,25 @@ if [[ ! -d "$SOURCE_UDD" ]]; then
exit 2
fi

pick_port() {
node -e '
const net = require("net");
const s = net.createServer();
s.listen(0, "127.0.0.1", () => { const p = s.address().port; s.close(() => console.log(p)); });
'
}
PORTS=$(node <<'NODE'
const net = require('net');

CDP_PORT=$(pick_port)
EXTHOST_PORT=$(pick_port)
MAIN_PORT=$(pick_port)
AGENTHOST_PORT=$(pick_port)
const fail = error => {
console.error('[launch.sh] failed to allocate debug ports:', error);
process.exit(1);
};
const servers = Array.from({ length: 4 }, () => net.createServer().on('error', fail));
(async () => {
await Promise.all(servers.map(server => new Promise(resolve => server.listen(0, '127.0.0.1', resolve))));
const ports = servers.map(server => server.address().port);
await Promise.all(servers.map(server => new Promise((resolve, reject) => {
server.close(error => error ? reject(error) : resolve());
})));
console.log(ports.join(' '));
})().catch(fail);
NODE
)
read -r CDP_PORT EXTHOST_PORT MAIN_PORT AGENTHOST_PORT <<< "$PORTS"

STAMP=$(date +%Y%m%d-%H%M%S)-$$
# mktemp fills in the X's only when they trail the template; elsewhere they stay literal.
Expand Down Expand Up @@ -205,6 +222,7 @@ then
exit 1
fi
echo "[launch.sh] ensured files.simpleDialog.enable=true in $SETTINGS_FILE" >&2
PROFILE_READY_MS=$(monotonic_ms)

# Strip ELECTRON_RUN_AS_NODE, commonly inherited from VS Code's integrated
# terminal / agent runtimes; it breaks ./scripts/code.sh.
Expand Down Expand Up @@ -238,12 +256,17 @@ echo "[launch.sh] logs: $LOG_FILE" >&2

# Run pre-launch (electron download, compile-if-missing, built-in extensions) in the
# foreground so any errors surface synchronously. Then skip code.sh's own pre-launch.
echo "[launch.sh] running pre-launch (ensures electron + compiled output + built-ins)..." >&2
if ! ( cd "$REPO" && node build/lib/preLaunch.ts ) >>"$LOG_FILE" 2>&1; then
echo "[launch.sh] pre-launch FAILED. Log tail:" >&2
tail -n 80 "$LOG_FILE" >&2
exit 1
if [[ "$SKIP_PRELAUNCH" == "1" ]]; then
echo "[launch.sh] skipping pre-launch by request" >&2
else
echo "[launch.sh] running pre-launch (ensures electron + compiled output + built-ins)..." >&2
if ! ( cd "$REPO" && node build/lib/preLaunch.ts ) >>"$LOG_FILE" 2>&1; then
echo "[launch.sh] pre-launch FAILED. Log tail:" >&2
tail -n 80 "$LOG_FILE" >&2
exit 1
fi
fi
PRELAUNCH_READY_MS=$(monotonic_ms)

# Launch code.sh in the background. Detaching with `nohup ... & disown` is
# sufficient: by the time we return below, CDP is up and Electron is fully
Expand All @@ -259,27 +282,25 @@ disown $PID 2>/dev/null || true
# immediately. If code.sh dies or we time out, dump the log so the failure is
# visible.
echo "[launch.sh] waiting for CDP on port $CDP_PORT (timeout 90s)..." >&2
READY=0
for i in $(seq 1 90); do
if ! kill -0 "$PID" 2>/dev/null; then
echo "[launch.sh] code.sh (PID $PID) exited before CDP came up. Log tail:" >&2
tail -n 80 "$LOG_FILE" >&2
exit 1
fi
if curl -sf -o /dev/null --max-time 1 "http://127.0.0.1:$CDP_PORT/json/version" 2>/dev/null; then
READY=1
echo "[launch.sh] CDP ready after ${i}s" >&2
break
fi
sleep 1
done
if [[ "$READY" != "1" ]]; then
echo "[launch.sh] timed out waiting for CDP on port $CDP_PORT. Log tail:" >&2
WAIT_FOR_CDP="$(cd "$(dirname "$0")" && pwd)/waitForCdp.ts"
if READY_MS=$(node "$WAIT_FOR_CDP" "$PID" "$CDP_PORT"); then
echo "[launch.sh] CDP ready after ${READY_MS}ms" >&2
else
READY_STATUS=$?
case "$READY_STATUS" in
1) echo "[launch.sh] timed out waiting for CDP on port $CDP_PORT. Log tail:" >&2 ;;
2) echo "[launch.sh] code.sh (PID $PID) exited before CDP came up. Log tail:" >&2 ;;
*) echo "[launch.sh] failed while waiting for CDP on port $CDP_PORT. Log tail:" >&2 ;;
esac
tail -n 80 "$LOG_FILE" >&2
exit 1
fi

node -e '
const finishedAt = Number(process.hrtime.bigint() / 1_000_000n);
const startedAt = Number(process.argv[7]);
const profileReadyAt = Number(process.argv[8]);
const preLaunchReadyAt = Number(process.argv[9]);
console.log(JSON.stringify({
pid: '"$PID"',
cdpPort: '"$CDP_PORT"',
Expand All @@ -293,5 +314,11 @@ node -e '
logFile: process.argv[5],
repo: process.argv[6],
agents: '"$AGENTS"' === 1,
timings: {
profileMs: profileReadyAt - startedAt,
preLaunchMs: preLaunchReadyAt - profileReadyAt,
cdpReadyMs: finishedAt - preLaunchReadyAt,
totalMs: finishedAt - startedAt,
},
}));
' "$DEST_UDD" "$EXT_DIR" "$SHARED_DATA_DIR" "$RUN_DIR" "$LOG_FILE" "$REPO"
' "$DEST_UDD" "$EXT_DIR" "$SHARED_DATA_DIR" "$RUN_DIR" "$LOG_FILE" "$REPO" "$LAUNCH_START_MS" "$PROFILE_READY_MS" "$PRELAUNCH_READY_MS"
Loading
Loading