agentHost (ssh): commit-pin remote CLI on fresh start#318496
Draft
roblourens wants to merge 2 commits into
Draft
agentHost (ssh): commit-pin remote CLI on fresh start#318496roblourens wants to merge 2 commits into
roblourens wants to merge 2 commits into
Conversation
Mirrors Remote-SSH's exec-server installer for the agent-host CLI: install
at ~/<serverDataFolderName>/<archive>-<commit> (shared with Remote-SSH),
reuse on file existence, download the commit-pinned artifact on miss, and
prune old commit-keyed CLIs (keep last 5). On every fresh start we push the
CLI that matches the desktop's commit, so users stop ending up with a stale
CLI when the supervisor never self-updates.
Softer fallback than Remote-SSH: agent host has no strict commit-lock with
the desktop, so when the commit-pinned download fails we reuse any other
usable CLI on the box (other commit-keyed binary or legacy ~/.vscode-cli{,-<quality>}/<archive>)
rather than refusing to connect. The renderer<->AH handshake catches real
incompatibilities.
A live agent host found via the lockfile is still reused as-is; the install
only runs on AH cold-start. Dev/OSS builds with no productService.commit
keep the old non-pinned loose-install behaviour.
(Written by Copilot)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Contributor
There was a problem hiding this comment.
Pull request overview
This PR updates the SSH-launched agent-host flow to keep the remote VS Code CLI in sync with the desktop build by installing a commit-pinned CLI binary (when productService.commit is available), reusing it by file existence, pruning older commit-keyed installs, and introducing a soft fallback to any other usable CLI if the pinned download fails.
Changes:
- Add helper functions to derive commit-aware remote CLI paths, build commit-pinned download URLs, and generate shell snippets for pruning and fallback discovery.
- Rewrite the SSH remote agent host service’s CLI resolution/installation to prefer commit-pinned installs with tolerant fallback behavior.
- Extend/adjust unit tests to cover commit-pinned install, reuse, cleanup, and fallback scenarios.
Show a summary per file
| File | Description |
|---|---|
| src/vs/platform/agentHost/node/sshRemoteAgentHostHelpers.ts | Adds commit-aware CLI naming/path helpers and shell snippet builders for cleanup and fallback search. |
| src/vs/platform/agentHost/node/sshRemoteAgentHostService.ts | Reworks CLI installation/selection to support commit-pinned installs, cleanup, and fallback; updates start path to use a resolved CLI binary path. |
| src/vs/platform/agentHost/test/node/sshRemoteAgentHostHelpers.test.ts | Adds tests for new helpers (archive naming, install root/bin path, commit-pinned URL, cleanup/fallback commands). |
| src/vs/platform/agentHost/test/node/sshRemoteAgentHostService.test.ts | Adds commit-pinned install flow tests (cleanup invocation, reuse, pinned download URL, soft fallback, no-fallback error). |
Copilot's findings
- Files reviewed: 4/4 changed files
- Comments generated: 4
Comment on lines
+139
to
+143
| const commitGlob = '?'.repeat(40); | ||
| // `ls -1t` sorts by mtime newest-first across both Linux (coreutils) and | ||
| // macOS (BSD). `awk 'NR>5'` drops the 5 most recent entries we want to | ||
| // keep. `xargs rm -f` ignores missing files; the leading `2>/dev/null` | ||
| // suppresses "No such file" complaints when the directory is empty. |
Comment on lines
+160
to
+164
| const archive = getRemoteCLIArchiveName(quality); | ||
| const commitGlob = '?'.repeat(40); | ||
| const q = validateShellToken(quality, 'quality'); | ||
| const legacyDir = q === 'stable' ? '~/.vscode-cli' : `~/.vscode-cli-${q}`; | ||
| const legacyBin = `${legacyDir}/${archive}`; |
Comment on lines
723
to
726
| // 3. Install CLI if needed | ||
| reportProgress(localize('sshProgressInstallingCLI', "Checking remote CLI installation...")); | ||
| await this._ensureCLIInstalled(sshClient, platform, reportProgress); | ||
| cliBin = await this._ensureCLIInstalled(sshClient, platform, reportProgress); | ||
| } |
Comment on lines
+1399
to
+1403
| // Prune stale commit-keyed CLIs before the reuse check so that a long- | ||
| // running session that keeps cycling through desktop builds doesn't | ||
| // accumulate binaries forever. Best-effort: cleanup failures are | ||
| // harmless and ignored. | ||
| await sshExec(client, buildCleanupOldCLIsCommand(this._serverDataFolderName, this._quality), { ignoreExitCode: true }); |
Four fixes from the PR review (#318496): - Lazy CLI install: skip uname/install entirely when a running agent host is reused via the lockfile. Install only runs immediately before we spawn a fresh agent host (introduces an ensureCliResolved closure in connect()). - Cleanup-after-reuse in _ensureCLIInstalledPinned: test -x first, then touch the in-use binary so the keep-newest-5 prune cannot evict the CLI we're about to run. - Hex-only glob ([0-9a-f]{40}) in buildCleanupOldCLIsCommand and buildFindFallbackCLICommand, plus safer xargs -I{} rm -f -- form. - Validate _findFallbackCLI candidates through a new exported isValidFallbackCLIPath helper before invoking them; reject anything that isn't a commit-keyed path under the install root or a legacy ~/.vscode-cli{,-<quality>}/<archive> path. Tests: - New isValidFallbackCLIPath suite (7 cases). - New AH-reuse regression test asserting uname/test-x/--version/curl never run on the reuse path. - All affected service-test execResponses arrays reshaped for the new ordering; 67 service tests and 81 helper tests passing. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Mirrors Remote-SSH's exec-server installer for the agent-host CLI:
~/<serverDataFolderName>/<archive>-<commit>(shared with Remote-SSH).test -x, no--versionre-parse.update.code.visualstudio.com/commit:<sha>/cli-<os>-<arch>/<quality>), extract into a temp dir, atomic-mvinto the commit-keyed path.Every fresh agent-host start now pushes the CLI that matches the desktop's commit, so users stop ending up with a stale CLI when the supervisor never self-updates.
Why
The agent-host CLI on the remote is supposed to be kept fresh, but on the SSH-launched-AH path it never self-updates —
code updateis a manual subcommand, and the only auto self-update in the CLI lives in the tunnel path (cli/src/tunnels/control_server.rs::handle_update, gated onparams.do_update).cli/src/tunnels/agent_host.rs::run_update_looponly refreshes the server commit cache, never the CLI binary. Net result: users keep ending up with an old CLI.Easiest fix: have the desktop push the matching CLI on every fresh start, the same way Remote-SSH does for the exec-server.
Differences from Remote-SSH
Softer fallback. Agent host has no strict commit-lock with the desktop (the renderer↔AH protocol handshake catches real incompatibilities), so when the commit-pinned download fails we reuse any other usable CLI on the box rather than refusing to connect:
~/.vscode-cli{,-<quality>}/<archive>from the previous installer.Each candidate is
--version-validated; first one that works wins, with a warning logged.Scope
productService.commitkeep the old non-pinned loose-install behaviour (<root>/<archive>+latestURL +--version-based reuse), with a warning logged so it's obvious in dev.remoteAgentHostCommandoverride skips install entirely (unchanged).Files
src/vs/platform/agentHost/node/sshRemoteAgentHostHelpers.ts— new helpers (getRemoteCLIArchiveName,getRemoteCLIInstallRoot, commit-awaregetRemoteCLIBin, commit-awarebuildCLIDownloadUrl,buildCleanupOldCLIsCommand,buildFindFallbackCLICommand).src/vs/platform/agentHost/node/sshRemoteAgentHostService.ts—_ensureCLIInstalledrewritten; dispatches to pinned vs loose paths; soft fallback._startRemoteAgentHostnow takescliBin: string | undefinedinstead ofquality.commit-pinned installtests covering cleanup, reuse, commit-pinned URL, soft fallback, and no-fallback error propagation).(Written by Copilot)