diff --git a/src/main/claude/hook-service.ts b/src/main/claude/hook-service.ts index 96cbe301dcf..67b66c34a93 100644 --- a/src/main/claude/hook-service.ts +++ b/src/main/claude/hook-service.ts @@ -67,10 +67,10 @@ function getManagedScript( `if not "%DEVIN_PROJECT_DIR%"=="" goto :${WINDOWS_HOOK_STDIN_DRAIN_LABEL}` ] : []), - // Why: call the endpoint file to refresh port/token — a PTY that survived an Orca restart carries stale env; falls through to PTY env if missing. + // Why: refresh endpoint coordinates for PTYs surviving an Orca restart. 'if defined ORCA_AGENT_HOOK_ENDPOINT if exist "%ORCA_AGENT_HOOK_ENDPOINT%" call "%ORCA_AGENT_HOOK_ENDPOINT%" 2>nul', ...buildWindowsHookEnvironmentGuardLines(), - // Why: post via curl.exe, not PowerShell — Claude's launcher is already encoded PowerShell, so a PS post would double interpreter startups per hook. + // Why: use curl.exe to avoid an extra PowerShell startup per hook. buildWindowsAgentHookCurlPostCommand('claude'), 'exit /b 0', ...buildWindowsHookStdinDrainEpilogue(), @@ -89,16 +89,16 @@ function getManagedScript( 'fi' ] : []), - // Why: source the endpoint file to refresh port/token — a PTY that survived an Orca restart carries stale env; falls back to PTY env if missing. - // Why: suppress stderr / || : so a stray parse error (TOCTOU or CRLF) can't leak into hook output or trip an outer set -e. + // Why: refresh endpoint coordinates for PTYs surviving an Orca restart. + // Why: suppress parse errors so they neither leak nor trip outer set -e. 'if [ -n "$ORCA_AGENT_HOOK_ENDPOINT" ] && [ -r "$ORCA_AGENT_HOOK_ENDPOINT" ]; then', ' . "$ORCA_AGENT_HOOK_ENDPOINT" 2>/dev/null || :', 'fi', 'if [ -z "$ORCA_AGENT_HOOK_PORT" ] || [ -z "$ORCA_AGENT_HOOK_TOKEN" ] || [ -z "$ORCA_PANE_KEY" ]; then', ' exit 0', 'fi', - // Why: paths can hold quotes/newlines, so hand-building JSON in shell is unsafe; post the raw payload + metadata as form fields for the receiver to parse. - // Why: pipe payload to curl stdin (`payload@-`), not an inline arg, so large tool output stays off the command line (EDR false positives). + // Why: post form fields because path-bearing payloads are unsafe in hand-built JSON. + // Why: pipe payload to curl stdin to keep large output off the command line. 'printf \'%s\' "$payload" | curl -sS -X POST "http://127.0.0.1:${ORCA_AGENT_HOOK_PORT}/hook/claude" \\', ' --connect-timeout 0.5 --max-time 1.5 \\', ' -H "Content-Type: application/x-www-form-urlencoded" \\', @@ -136,7 +136,7 @@ export class ClaudeHookService { } } - // Why: report `partial` when only some events are registered so the sidebar shows a degraded install, not a false-positive `installed`. + // Why: report partial registration instead of a false installed state. const command = getManagedCommand(scriptPath) const missing: string[] = [] let presentCount = 0 @@ -227,11 +227,11 @@ export class ClaudeHookService { // Why: install the Claude hook on the remote box (via SFTP); POSIX-only by design (Windows-remote deferred). async installRemote(sftp: SFTPWrapper, remoteHome: string): Promise { - // Why: remote-Windows is out of scope; ship POSIX paths. process.platform here is the local box, not the remote, so it can't gate this. + // Why: remote Windows is unsupported; local process.platform cannot identify the remote OS. const remoteConfigPath = getRemoteConfigPath(remoteHome, this.options.settings) const remoteScriptFileName = getPosixManagedScriptFileName(this.options.settings) const remoteScriptPath = `${remoteHome.replace(/\/$/, '')}/.orca/agent-hooks/${remoteScriptFileName}` - // Why: SFTP I/O fails often (network/EACCES/disk); wrap install so transient failures surface as structured state:'error' rather than an unhandled rejection. + // Why: surface fallible SFTP installs as structured errors. try { const config = await readHooksJsonRemote(sftp, remoteConfigPath) if (!config) { @@ -248,8 +248,8 @@ export class ClaudeHookService { const command = getRemoteManagedCommand(remoteScriptPath) const nextConfig = applyManagedHooks(config, command, remoteScriptFileName) - // Why: write script before settings — a mid-install failure then leaves a harmless orphan script, not settings.json pointing at a missing one. - // Why: SSH remotes use POSIX `.sh` paths even when Orca runs on Windows; never derive remote script syntax from the local OS. + // Why: write scripts before settings to avoid settings pointing to missing scripts. + // Why: SSH scripts always use POSIX .sh paths, regardless of the local OS. await writeManagedScriptRemote( sftp, remoteScriptPath, diff --git a/src/main/cursor/hook-service.ts b/src/main/cursor/hook-service.ts index 9ce9172f8fb..7b5f3b90dda 100644 --- a/src/main/cursor/hook-service.ts +++ b/src/main/cursor/hook-service.ts @@ -26,8 +26,8 @@ import { buildWindowsHookStdinDrainEpilogue } from '../agent-hooks/hook-stdin-contract' -// cursor-agent's declarative hooks surface (https://cursor.com/docs/hooks); subscribe to the minimum set for spinner + turn detection. -// sessionStart/sessionEnd are NOT subscribed: they fire at process (not turn) boundaries and can race/reset the just-submitted turn's prompt cache. +// Subscribe only to Cursor hooks needed for spinner and turn detection. +// Exclude process-boundary session hooks, which can reset the submitted-turn prompt cache. const CURSOR_EVENTS = [ 'beforeSubmitPrompt', 'stop', @@ -62,7 +62,7 @@ function getManagedScript(target: 'local' | 'posix' = 'local'): string { return [ '@echo off', 'setlocal', - // Why: source the endpoint file so a surviving PTY reaches the current server, not the prior Orca's coordinates (see claude/hook-service.ts). + // Why: source current endpoint coordinates for PTYs surviving an Orca restart. 'if defined ORCA_AGENT_HOOK_ENDPOINT if exist "%ORCA_AGENT_HOOK_ENDPOINT%" call "%ORCA_AGENT_HOOK_ENDPOINT%" 2>nul', ...buildWindowsHookEnvironmentGuardLines(), buildWindowsAgentHookPostCommand('cursor'), @@ -75,15 +75,15 @@ function getManagedScript(target: 'local' | 'posix' = 'local'): string { return [ '#!/bin/sh', ...buildPosixHookPayloadCapture(), - // Why: sourcing refreshes PORT/TOKEN/ENV from the current Orca so a surviving PTY keeps reporting after a restart (see claude/hook-service.ts). + // Why: refresh endpoint coordinates so surviving PTYs keep reporting. 'if [ -n "$ORCA_AGENT_HOOK_ENDPOINT" ] && [ -r "$ORCA_AGENT_HOOK_ENDPOINT" ]; then', ' . "$ORCA_AGENT_HOOK_ENDPOINT" 2>/dev/null || :', 'fi', 'if [ -z "$ORCA_AGENT_HOOK_PORT" ] || [ -z "$ORCA_AGENT_HOOK_TOKEN" ] || [ -z "$ORCA_PANE_KEY" ]; then', ' exit 0', 'fi', - // Why: worktreeId embeds a path, so hand-building JSON in shell is unsafe (quotes/newlines); post raw payload as form fields instead. - // Why: pipe payload via curl stdin (`payload@-`), not an inline arg, so large tool output stays off the command line (EDR false positives). + // Why: post form fields because path-bearing worktree IDs are unsafe in hand-built JSON. + // Why: pipe payload to curl stdin to keep large output off the command line. 'printf \'%s\' "$payload" | curl -sS -X POST "http://127.0.0.1:${ORCA_AGENT_HOOK_PORT}/hook/cursor" \\', ' --connect-timeout 0.5 --max-time 1.5 \\', ' -H "Content-Type: application/x-www-form-urlencoded" \\', @@ -167,7 +167,7 @@ export class CursorHookService { const nextHooks = { ...config.hooks } const managedEvents = new Set(CURSOR_EVENTS) - // Why: match by script filename (not exact command) so installs sweep stale entries from older builds or a different userData path. + // Why: match filenames to remove stale hooks from prior builds and user-data paths. const isManagedCommand = createManagedCommandMatcher(getManagedScriptFileName()) // Why: sweep managed entries from events we no longer subscribe to, else upgraded users keep firing stale hooks. @@ -192,7 +192,7 @@ export class CursorHookService { for (const eventName of CURSOR_EVENTS) { const current = Array.isArray(nextHooks[eventName]) ? nextHooks[eventName] : [] - // Sweep both Claude-shaped (hooks[].command) and Cursor-shaped (definition.command) variants so installs converge on one entry. + // Sweep Claude- and Cursor-shaped variants so installs converge on one entry. const cleaned = removeManagedCommands(current, isManagedCommand).filter( (definition) => !isManagedCommand(definition.command as string | undefined) ) @@ -201,7 +201,7 @@ export class CursorHookService { nextHooks[eventName] = [...cleaned, definition] } - // Why: cursor-agent's schema requires top-level `version: 1` (https://cursor.com/docs/hooks); keep any user-pinned value. + // Why: Cursor requires `version: 1`; preserve user-pinned values. const nextConfig: Record = { ...config, hooks: nextHooks } if (nextConfig.version === undefined) { nextConfig.version = 1 @@ -247,7 +247,7 @@ export class CursorHookService { } // Why: script-then-config order so a partial mid-install leaves a working script nothing points at. - // Why: SSH remotes always use POSIX `.sh` hook paths even when Orca runs on Windows; never derive from local OS. + // Why: SSH hooks always use POSIX .sh paths, regardless of the local OS. await writeManagedScriptRemote(sftp, remoteScriptPath, getManagedScript('posix')) await writeHooksJsonRemote(sftp, remoteConfigPath, nextConfig) diff --git a/src/main/memory/hydrate-local-pty-registry.ts b/src/main/memory/hydrate-local-pty-registry.ts index ec672d7e9c8..6608fd2641c 100644 --- a/src/main/memory/hydrate-local-pty-registry.ts +++ b/src/main/memory/hydrate-local-pty-registry.ts @@ -19,7 +19,7 @@ import { parsePtySessionId } from '../../shared/pty-session-id-format' import { splitWorktreeId } from '../../shared/worktree-id' import type { Store } from '../persistence' -// Why: attachMainWindowServices reruns on every macOS dock re-activation; guard against re-running git I/O + daemon RPC. +// Why: macOS dock reactivation reruns setup; avoid repeating Git I/O and daemon RPC. let hasHydrated = false /** @@ -42,7 +42,7 @@ export async function hydrateLocalPtyRegistryAtBoot(store: Pick [repo.id, repo])) // Why: verify via live git that a referenced worktree still exists, to avoid resurrecting removed ones. const liveLocalWorktreeIds = new Set() @@ -51,7 +51,7 @@ export async function hydrateLocalPtyRegistryAtBoot(store: Pick p.ptyId)) - // Why: git enumeration is slow, so re-read daemon+registry each pass to avoid resurrecting exited sessions; terminates as each pass resolves >=1 new repo. + // Why: re-read live sessions each pass to avoid resurrecting exited sessions. for (;;) { const newlyReferencedRepos = new Map[number]>() for (const info of sessionInfos) { @@ -65,7 +65,7 @@ export async function hydrateLocalPtyRegistryAtBoot(store: Pick&4 3<&- 4>&-' : '' }` - // Why: npm/nvm launchers use `#!/usr/bin/env node`; exec'ing them from plain sh loses Node's PATH and pins stale installs. + // Why: npm/nvm launchers need Node's PATH; plain sh can select stale installs. const loginShellCommand = buildWslLoginShellCommand( [setupCommands, `exec codex ${execSuffix}`].join(' && ') ) @@ -313,7 +313,7 @@ function getBackendAuthRead( if (existing) { return existing } - // Why: Node can't cancel an in-flight UNC read; keep one read per auth path so repeated refreshes don't stack them. + // Why: dedupe UNC reads because Node cannot cancel an in-flight read. const read = createAuthFilesystemOperation(authPath, () => readFile(authPath, 'utf8').then( (content) => ({ content }), @@ -528,7 +528,7 @@ async function fetchViaBackend( if (!auth || signal.aborted) { return null } - // Why: reuse Codex's own get_rate_limit_status endpoint, avoiding a hidden app-server (and WSL login shell) per refresh. + // Why: reuse Codex's endpoint to avoid an app server and WSL login shell per refresh. const response = await fetch('https://chatgpt.com/backend-api/wham/usage', { ...auth, signal @@ -538,7 +538,7 @@ async function fetchViaBackend( return null } const payload = (await response.json()) as BackendUsageResponse - // Why: plan_type is required by Codex's RateLimitStatusPayload; reject malformed JSON so the app-server fallback still runs. + // Why: reject missing plan_type so the app-server fallback runs. if (typeof payload.plan_type !== 'string') { return null } @@ -619,10 +619,10 @@ async function fetchViaRpc(options?: FetchCodexRateLimitsOptions): Promise 0 && (err as NodeJS.ErrnoException)?.code === 'EADDRINUSE') { this.portFallbackApplied = true await this.listenOn(0) @@ -151,7 +151,7 @@ export class RelayAgentHookServer { return new Promise((resolve, reject) => { const onStartupError = (err: Error): void => { this.server?.off('listening', onListening) - // Why: null the server ref on bind failure so a later start() can retry (else the early-return at top of start() wedges it). + // Why: clear failed server refs so later start() calls can retry. this.server = null reject(err) } diff --git a/src/relay/dispatcher.ts b/src/relay/dispatcher.ts index c6a1a77ec96..7149144c9a5 100644 --- a/src/relay/dispatcher.ts +++ b/src/relay/dispatcher.ts @@ -111,7 +111,7 @@ export class RelayDispatcher { } // Why: redirect outgoing frames to the reconnected socket without rebuilding the dispatcher + handler tree. - // Why: the new client's multiplexer restarts at seq=1, so reset seq/decoder state or acks stall and fire a false connection-dead signal. + // Why: a new multiplexer restarts at seq=1; reset state to avoid stalled acknowledgements. setWrite(write: RelayClientWrite, sinkOptions?: RelayClientSinkOptions): void { this.requestAborts.abortClient(this.primaryClient.id) this.primaryClient.closed = true diff --git a/src/relay/git-handler-status-ops.ts b/src/relay/git-handler-status-ops.ts index 1bd05821f50..880e690ee54 100644 --- a/src/relay/git-handler-status-ops.ts +++ b/src/relay/git-handler-status-ops.ts @@ -133,7 +133,7 @@ export async function getStatusOp( const branchName = getShortBranchName(branch) if (branchName) { try { - // Why: this probe coalesces across concurrent status reads, so one request's abort must not reject the shared in-flight promise. + // Why: one request's abort must not reject this shared status probe. upstreamStatus = await readOrProbeNoEffectiveUpstreamStatus( { worktreePath, branchName, upstreamName: upstreamStatus?.upstreamName }, (args) => git(args, worktreePath), @@ -171,7 +171,7 @@ export async function getStatusOp( // not a git repo or git not available } - // Why: skip line-stats when the limit was hit — numstat over a huge change set would reintroduce the cost the limit avoids. + // Why: skip numstat after the limit to avoid reintroducing its cost. if (!didHitLimit) { await reuseOrRecomputeGitStatusLineStats({ cacheKey: lineStatsCacheKey, diff --git a/src/relay/git-handler.ts b/src/relay/git-handler.ts index d883c742425..c574e7aaa62 100644 --- a/src/relay/git-handler.ts +++ b/src/relay/git-handler.ts @@ -112,7 +112,7 @@ function resolveRelayPath(repoPath: string, value: string): string { if (path.posix.isAbsolute(value) || path.win32.isAbsolute(value)) { return value } - // Old git ignores `--path-format=absolute`; resolve relative toplevel/git-dir against repoPath, picking the win32/posix resolver by its shape. + // Old Git ignores `--path-format=absolute`; resolve relative paths against repoPath by path shape. return isWindowsAbsolutePath(repoPath) ? path.win32.resolve(repoPath, value) : path.posix.resolve(repoPath, value) @@ -176,10 +176,10 @@ export class GitHandler { private dispatcher: RelayDispatcher private readonly gitDiffReadDedupe = new InFlightPromiseDedupe() private readonly gitCapabilities = new GitCapabilityCache() - // Why: large diff/exec responses go on the bulk lane so they don't head-of-line-block interactive pty.data echo on the shared SSH channel. + // Why: use the bulk lane so large responses do not block interactive PTY echo. private readonly responseStreams = new GitResponseStreamRegistry() - // Why: instance-level TTL cache avoids re-reading `.gitmodules` per diff click over SSH; per-instance so it can't leak across tests. + // Why: cache .gitmodules per instance to avoid SSH reads and test leakage. private submodulePathsCache: SubmodulePathsCache = createSubmodulePathsCache() // Why: RelayContext accepted for protocol back-compat (docs/relay-fs-allowlist-removal.md) but no longer consulted on git ops. @@ -360,7 +360,7 @@ export class GitHandler { }) } - // Why: parent status lists one gitlink row per submodule; fetch inner per-file changes by running status inside the submodule's own worktree. + // Why: fetch per-file submodule changes from the submodule worktree. private async getSubmoduleStatus(params: Record, context: RequestContext) { const worktreePath = params.worktreePath as string const submodulePath = params.submodulePath as string @@ -383,7 +383,7 @@ export class GitHandler { // Why: pointer/range probes are part of the same SSH request and must not outlive its cancellation. const requestGit: GitExec = (args, cwd, options) => this.git(args, cwd, { ...options, signal: context.signal }) - // Why: a moved gitlink (clean worktree) has no uncommitted rows; surface files changed between recorded and checked-out commits so it isn't empty. + // Why: moved clean gitlinks need committed changes surfaced. const { fromOid, toOid } = await resolveSubmoduleCommitRange( requestGit, worktreePath, @@ -426,7 +426,7 @@ export class GitHandler { private async getDiff(params: Record, context?: RequestContext) { const worktreePath = params.worktreePath as string const filePath = params.filePath as string - // Why: filePath is relative and joined for readWorkingFile; validate or `../../etc/passwd` traverses outside the worktree. + // Why: validate relative paths to prevent traversal outside the worktree. const resolved = path.resolve(worktreePath, filePath) const rel = path.relative(path.resolve(worktreePath), resolved) if (rel === '..' || rel.startsWith(`..${path.sep}`) || path.isAbsolute(rel)) { @@ -434,11 +434,11 @@ export class GitHandler { } const staged = params.staged as boolean const compareAgainstHead = params.compareAgainstHead as boolean | undefined - // Why: register the in-flight dedupe synchronously (before any await) so concurrent identical reads coalesce; submodule routing happens inside. + // Why: register dedupe before awaiting so identical reads coalesce. const result = await this.gitDiffReadDedupe.run( stableInFlightKey(['diff', worktreePath, filePath, staged, compareAgainstHead]), async () => { - // Why: gitlinks can't be read as blobs, so route the gitlink root to a pointer diff and inner files into the submodule's own worktree. + // Why: route gitlink roots to pointer diffs and inner files to their submodule worktree. const submodulePaths = await listSubmodulePathsCached( this.git.bind(this), worktreePath, @@ -775,13 +775,13 @@ export class GitHandler { private async branchCompare(params: Record) { const worktreePath = params.worktreePath as string const baseRef = params.baseRef as string - // Why: a baseRef starting with '-' would be read as a git rev-parse flag, potentially leaking environment variables or config. + // Why: reject flag-like base refs to prevent rev-parse option injection. if (baseRef.startsWith('-')) { throw new Error('Base ref must not start with "-"') } const gitBound = this.git.bind(this) return branchCompareOp(gitBound, worktreePath, baseRef, async (mergeBase, headOid) => { - // Why: -c core.quotePath=false keeps non-ASCII filenames as raw UTF-8; without it parseBranchDiff would get C-style octal-escaped paths. + // Why: preserve non-ASCII filenames as UTF-8 for parseBranchDiff. const [{ stdout }, { stdout: numstat }] = await Promise.all([ gitBound( ['-c', 'core.quotePath=false', 'diff', '--name-status', '-M', '-C', mergeBase, headOid], @@ -821,7 +821,7 @@ export class GitHandler { (upstreamName) => this.getBehindCommitsArePatchEquivalent(worktreePath, upstreamName) ) } catch (error) { - // Why: swallow only 'no upstream configured' (an expected state); other errors (auth, corruption, network) must surface to the user. + // Why: suppress only the expected no-upstream error; surface all others. if (isNoUpstreamError(error)) { return { hasUpstream: false, ahead: 0, behind: 0 } } @@ -1113,7 +1113,7 @@ export class GitHandler { } private async pull(params: Record) { - // Why: plain `git pull` honors the user's merge/rebase/ff policy; with none, Git's policy error is normalized with setup guidance. + // Why: plain `git pull` honors user merge/rebase/ff policy. await this.pullWithArgs(params, []) } diff --git a/src/relay/pty-handler.ts b/src/relay/pty-handler.ts index cc685389f0a..243cc758943 100644 --- a/src/relay/pty-handler.ts +++ b/src/relay/pty-handler.ts @@ -180,7 +180,7 @@ type ManagedStartupCommand = { timer: ReturnType | null } -// Why: node-pty's Windows agent throws on any signal arg (ConPTY has no signal semantics); drop it there, forward on POSIX. +// Why: Windows ConPTY rejects signals; forward them only on POSIX. function killPtyProcess(pty: IPty, signal: string): void { if (process.platform === 'win32') { pty.kill() @@ -374,7 +374,7 @@ export class PtyHandler { private exitListener: PtyExitListener | null = null private ptyPoolEmptyListener: (() => void) | null = null private ptyPoolActiveListener: (() => void) | null = null - // Why: env augmenters run on every spawn so each PTY sees live hook coords without the dispatcher knowing about agent hooks. + // Why: augment environment on every spawn so PTYs receive current hook coordinates. private envAugmenters: PtyEnvAugmenter[] = [] private readonly agentSessionOwners = new ClaimedAgentPtyOwnerRegistry() private readonly agentSessionCreateOperations = new Map< @@ -1590,7 +1590,7 @@ export class PtyHandler { throw new Error(`PTY "${id}" not found`) } - // Why: a shell can die without node-pty firing onExit (reaped out-of-band); prove liveness so attach doesn't strand a dead, lingering lease. + // Why: verify liveness because shells can exit without node-pty onExit. if (managed.pty.pid && !isProcessAlive(managed.pty.pid)) { managed.physicalExit?.markExited() this.releaseRelayIngress(managed) @@ -1603,7 +1603,7 @@ export class PtyHandler { throw new Error(`PTY "${id}" not found`) } - // Why: a relay generation reset can reuse pty-N for a different pane; reject on identity disagreement (absent identity permissive). + // Why: generation resets can reuse PTY IDs; reject conflicting identities. const mismatch = attachIdentityMismatches( { paneKey: typeof params.expectedPaneKey === 'string' ? params.expectedPaneKey : undefined, @@ -1646,8 +1646,8 @@ export class PtyHandler { } } - // Why: renderer hasn't registered replay handlers yet during spawn, so return to the caller instead of notifying too early. - // Why: buffer intentionally NOT cleared after replay (client clears xterm first) so later restarts still replay full history. + // Why: return replay during spawn before renderer handlers register. + // Why: retain replay buffers so later restarts receive full history. const replay = managed.buffered.read() if (replay) { // Why: drop pending batched bytes already in the replay buffer so attach doesn't render them twice. @@ -1715,7 +1715,7 @@ export class PtyHandler { this.releaseStartupCommand(managed) this.flushPtyOutput(id) this.requestForceKill(managed) - // Why: remote Git deletion must not race the child's native handles; on timeout keep the map entry so onExit/retry still owns it. + // Why: preserve timed-out entries so onExit/retry owns native handles. await this.waitForPhysicalExit(managed, IMMEDIATE_PTY_EXIT_TIMEOUT_MS) } else { this.releaseStartupCommand(managed) diff --git a/src/relay/relay-handshake.ts b/src/relay/relay-handshake.ts index bb61e8a08af..fbbe0283045 100644 --- a/src/relay/relay-handshake.ts +++ b/src/relay/relay-handshake.ts @@ -13,10 +13,10 @@ import { } from './protocol' import { relayLogLine } from './relay-diagnostic-log' -// Why: client maps this exit code to a non-retryable error so it skips reconnect backoff; other non-zero exits are treated as transient. +// Why: clients treat this exit code as non-retryable; other non-zero exits are transient. export const EXIT_CODE_VERSION_MISMATCH = 42 -// Why: read .version next to the resolved script path (realpathSync, not cwd) so arbitrary-cwd or symlink-launched spawns still report a coherent version. +// Why: read .version beside the resolved script path, not the arbitrary launch cwd. export function readLaunchVersion(): string { try { const entry = process.argv[1] @@ -161,7 +161,7 @@ export type ConnectHandshakeCallbacks = { onAccepted: (leftover: Buffer) => void } -// Why: bridge-side version handshake; defense-in-depth so a bad .version can't let a v2 bridge drive a v1 daemon (cf. VS Code remoteExtensionHostAgentServer.ts:340). +// Why: defense-in-depth prevents a bad .version from pairing incompatible bridge and daemon versions. export function runConnectHandshake( sock: Socket, myVersion: string,