From c6769fc9be0bce061b409bb6da5def31f7545e63 Mon Sep 17 00:00:00 2001 From: Neil <4138956+nwparker@users.noreply.github.com> Date: Sun, 25 Oct 2026 15:30:00 -0700 Subject: [PATCH] chore: post-merge cleanup for agent integration fixes (#33644) Post-merge cleanup after the agent-integration fixes: remove the unreachable Windows hook-script stdin drain epilogue; Windows statusline exits instead of draining outside an Orca pane; Codex CLI fork uses the \\?\-aware rollout path; WSL browser-network relay falls back to orcad's pinned Node (shared launcher revision stamp); stranded sleep records only drop for their own worktree; renames (hidden probe cwd, local Windows ConPTY helper). --- config/scripts/ci-shard-timings.json | 2 +- src/main/agent-hooks/hook-stdin-contract.ts | 5 --- .../managed-hook-stdin-lifecycle.test.ts | 2 +- src/main/agent-hooks/wsl-hook-relay-launch.ts | 16 ++------ .../ai-vault/structured-chat-cli-fork.test.ts | 38 +++++++++++++++++++ src/main/ai-vault/structured-chat-cli-fork.ts | 14 ++++--- .../wsl-browser-network-relay-launch.test.ts | 25 ++++++++++-- .../wsl-browser-network-relay-launch.ts | 11 +++++- src/main/claude/hook-script.ts | 4 +- src/main/claude/hook-service.test.ts | 4 +- src/main/claude/statusline-script.test.ts | 11 ++---- src/main/claude/statusline-script.ts | 9 +---- src/main/claude/windows-hook-files.ts | 5 ++- src/main/codex/codex-at-rest-skills-probe.ts | 4 +- src/main/codex/codex-hook-script.ts | 4 +- .../command-code-managed-script.ts | 4 +- src/main/copilot/copilot-managed-script.ts | 4 +- src/main/cursor/hook-script.ts | 4 +- src/main/devin/hook-service.ts | 4 +- src/main/droid/hook-service.ts | 4 +- src/main/dsh/hook-service.ts | 4 +- src/main/gemini/hook-service.ts | 4 +- src/main/grok/windows-grok-hook-script.ts | 6 +-- src/main/jcode/hook-service.ts | 2 - src/main/kimi/hook-service.ts | 4 +- src/main/kiro/hook-service.ts | 4 +- src/main/muse/hook-service.ts | 4 +- src/main/rate-limits/codex-fetcher.ts | 9 ++--- ...e-limit-pty-cwd.ts => hidden-probe-cwd.ts} | 15 ++++---- .../worktree-sleep-resume-records.test.ts | 9 +++-- .../stop/worktree-sleep-resume-records.ts | 3 +- .../managed-workspace-operations.ts | 2 +- src/main/wsl/wsl-guest-launcher-revision.ts | 16 ++++++++ src/main/zcode/hook-service.ts | 4 +- .../terminal-keyboard-runtime.ts | 4 +- ...erminal-pane-local-windows-conpty.test.ts} | 20 +++++----- ... => terminal-pane-local-windows-conpty.ts} | 14 +++---- 37 files changed, 161 insertions(+), 137 deletions(-) rename src/main/rate-limits/{hidden-rate-limit-pty-cwd.ts => hidden-probe-cwd.ts} (63%) create mode 100644 src/main/wsl/wsl-guest-launcher-revision.ts rename src/renderer/src/components/terminal-pane/{terminal-ctrl-arrow-conpty.test.ts => terminal-pane-local-windows-conpty.test.ts} (87%) rename src/renderer/src/components/terminal-pane/{terminal-ctrl-arrow-conpty.ts => terminal-pane-local-windows-conpty.ts} (86%) diff --git a/config/scripts/ci-shard-timings.json b/config/scripts/ci-shard-timings.json index 4393fe9ff48..9230ecedfba 100644 --- a/config/scripts/ci-shard-timings.json +++ b/config/scripts/ci-shard-timings.json @@ -9094,7 +9094,7 @@ "src/renderer/src/components/terminal-pane/terminal-context-menu-dismiss.test.ts": 33, "src/renderer/src/components/terminal-pane/terminal-copy-rejection-handling.test.ts": 44, "src/renderer/src/components/terminal-pane/terminal-copy-shortcut.test.ts": 1457, - "src/renderer/src/components/terminal-pane/terminal-ctrl-arrow-conpty.test.ts": 1372, + "src/renderer/src/components/terminal-pane/terminal-pane-local-windows-conpty.test.ts": 1372, "src/renderer/src/components/terminal-pane/terminal-ctrl-enter.test.ts": 92, "src/renderer/src/components/terminal-pane/terminal-cursor-appearance-precedence.test.ts": 296, "src/renderer/src/components/terminal-pane/terminal-cursor-inactive-style.test.ts": 337, diff --git a/src/main/agent-hooks/hook-stdin-contract.ts b/src/main/agent-hooks/hook-stdin-contract.ts index 1c881843d1f..f8c09568ad3 100644 --- a/src/main/agent-hooks/hook-stdin-contract.ts +++ b/src/main/agent-hooks/hook-stdin-contract.ts @@ -132,7 +132,6 @@ export function buildPosixHookSpoolLines(source: string, eventNameVar?: string): ] } -export const WINDOWS_HOOK_STDIN_DRAIN_LABEL = 'orca_agent_hook_drain_stdin' // Windows searches the worktree before PATH; never give hook payloads to a repo-local executable. export const WINDOWS_HOOK_STDIN_READER = '"%SystemRoot%\\System32\\more.com"' export const WINDOWS_HOOK_STDIN_DRAIN_COMMAND = `${WINDOWS_HOOK_STDIN_READER} >nul 2>nul` @@ -157,7 +156,3 @@ export const WINDOWS_GIT_BASH_HOOK_ENVIRONMENT_GUARD = `if ${WINDOWS_HOOK_ENVIRO export const WINDOWS_POWERSHELL_HOOK_ENVIRONMENT_GUARD = `if (${WINDOWS_HOOK_ENVIRONMENT_VARS.map( (name) => `-not $env:${name}` ).join(' -or ')}) { exit 0 }` - -export function buildWindowsHookStdinDrainEpilogue(): string[] { - return [`:${WINDOWS_HOOK_STDIN_DRAIN_LABEL}`, WINDOWS_HOOK_STDIN_DRAIN_COMMAND, 'exit /b 0'] -} diff --git a/src/main/agent-hooks/managed-hook-stdin-lifecycle.test.ts b/src/main/agent-hooks/managed-hook-stdin-lifecycle.test.ts index dd23ca00aed..4003f99c6ed 100644 --- a/src/main/agent-hooks/managed-hook-stdin-lifecycle.test.ts +++ b/src/main/agent-hooks/managed-hook-stdin-lifecycle.test.ts @@ -412,7 +412,7 @@ describe('Windows managed hook stdin structure', () => { : [scriptPath] const result = await runHookProcess(executable, args, hookEnvironment()) expect(result.exitCode, `${fileName} exit code`).toBe(0) - // Only missing-context Windows paths permit broken writers; in-pane hooks must drain. + // Missing-context guards exit before reading stdin, so writers may see a broken pipe. for (const error of result.stdinErrors) { expect(WRITER_BROKEN_BY_EARLY_EXIT, `${fileName} stdin error`).toContain(error.code) } diff --git a/src/main/agent-hooks/wsl-hook-relay-launch.ts b/src/main/agent-hooks/wsl-hook-relay-launch.ts index 53541e5dc49..36155fba1a3 100644 --- a/src/main/agent-hooks/wsl-hook-relay-launch.ts +++ b/src/main/agent-hooks/wsl-hook-relay-launch.ts @@ -1,8 +1,8 @@ import { spawn, type ChildProcessWithoutNullStreams } from 'node:child_process' -import { createHash } from 'node:crypto' import { existsSync, readFileSync } from 'node:fs' import { join } from 'node:path' import { relayBundleCandidates } from '../ssh/relay-bundle-paths' +import { withWslGuestLauncherRevision } from '../wsl/wsl-guest-launcher-revision' import { orcadPosixNodeRuntimeGlobs } from '../managed-server/install/orcad-node-runtime-globs' import type { MultiplexerTransport } from '../ssh/ssh-channel-multiplexer' @@ -36,7 +36,7 @@ export function resolveWslHookRelayBundle(): WslHookRelayBundle | null { const version = readFileSync(versionPath, 'utf8').trim() // Versions become shell literals and path segments; accept only a safe alphabet. if (/^[A-Za-z0-9+.-]+$/.test(version)) { - return { jsPath, version: `${version}.${guestLauncherRevision()}` } + return { jsPath, version: withWslGuestLauncherRevision(version, buildGuestLaunchScript) } } } } @@ -48,20 +48,10 @@ function guestRelayDirExpr(version: string): string { return `$HOME/${WSL_HOOK_RELAY_DIR}/${version}` } -let launcherRevision: string | undefined -// The bundle hash alone misses launcher edits; a new guest dir forces one reinstall of launch.sh. -function guestLauncherRevision(): string { - launcherRevision ??= createHash('sha256') - .update(buildGuestLaunchScript('0')) - .digest('hex') - .slice(0, 8) - return launcherRevision -} - /** Probe candidate Node versions: noninteractive sh may miss a newer nvm installation. */ export function buildGuestLaunchScript(version: string): string { const dir = guestRelayDirExpr(version) - // A WSL host distro may have no system node but always has orcad's pinned runtime. + // A WSL host distro may have no system node but usually has orcad's pinned runtime. const [orcadRuntime, orcadMachineRuntimes] = orcadPosixNodeRuntimeGlobs() return [ '#!/bin/sh', diff --git a/src/main/ai-vault/structured-chat-cli-fork.test.ts b/src/main/ai-vault/structured-chat-cli-fork.test.ts index d4e0891060b..1626c52846e 100644 --- a/src/main/ai-vault/structured-chat-cli-fork.test.ts +++ b/src/main/ai-vault/structured-chat-cli-fork.test.ts @@ -8,6 +8,7 @@ import type { AgentJournalSnapshot } from '../../shared/agent-session-journal-ty import { agentJournalSubmissionKey } from '../../shared/agent-session-journal-item-key' import { setStructuredAgentSessionHost } from '../native-chat/agent-session-wire/structured-agent-session-registry' import { prepareStructuredChatCliFork } from './structured-chat-cli-fork' +import { structuredAgentRuntimeRegistration } from '../runtime/structured-agent-runtime-registrations' import { prepareLegacySharedCodexSessionResume } from '../codex/codex-legacy-session-resume' import { AiVaultPrepareSessionResumeParams } from '../../shared/rpc-contract/ai-vault-params' @@ -98,6 +99,43 @@ it('locates the current Codex rollout in its recorded home and materializes the }) }) +it.runIf(process.platform === 'win32')( + 'maps an extended-length Windows rollout path into the prepared home (#27200)', + async () => { + root = await mkdtemp(join(tmpdir(), 'chat-cli-fork-')) + vi.stubEnv('ORCA_USER_DATA_PATH', root) + const home = join(root, 'codex-runtime-home', 'home') + const system = join(root, 'system') + const record = agentSessionRecordFixture() + record.provider = 'codex' + record.accountHome = { variable: 'CODEX_HOME', path: home } + record.providerHandleChain = [ + { + ...record.providerHandleChain[0]!, + handle: { transport: 'codex-app-server', agent: 'codex', nativeId: 'current-conversation' } + } + ] + const relative = join('2026', '10', '15', 'rollout-2026-10-15-current-conversation.jsonl') + await mkdir(join(home, 'sessions', '2026', '10', '15'), { recursive: true }) + await writeFile(join(home, 'sessions', relative), '{"saved":true}\n') + vi.spyOn( + structuredAgentRuntimeRegistration('codex')!.transcriptImport!, + 'findTranscript' + ).mockResolvedValueOnce(`\\\\?\\${join(home, 'sessions', relative)}`) + install(record) + const result = await prepareStructuredChatCliFork(request, async (args) => ({ + ...(await prepareLegacySharedCodexSessionResume(args, { + isHostSystemDefaultRealHomeSelected: () => true, + legacyCodexHomePath: home, + systemCodexHomePath: system + })), + useRealCodexHome: false, + substituteCodexHome: system + })) + expect(result.cliForkSource?.filePath).toBe(join(system, 'sessions', relative)) + } +) + it('copies OpenCode directly from the selected record and preserves its typed account and copy id', async () => { root = await mkdtemp(join(tmpdir(), 'chat-cli-fork-')) const record = agentSessionRecordFixture() diff --git a/src/main/ai-vault/structured-chat-cli-fork.ts b/src/main/ai-vault/structured-chat-cli-fork.ts index daf5c23d8cb..58151b86245 100644 --- a/src/main/ai-vault/structured-chat-cli-fork.ts +++ b/src/main/ai-vault/structured-chat-cli-fork.ts @@ -1,6 +1,7 @@ import { stat } from 'node:fs/promises' -import { isAbsolute, join, relative } from 'node:path' +import { isAbsolute, join } from 'node:path' import { getSystemCodexHomePath } from '../codex/codex-home-paths' +import { codexDatedRolloutRelativePath } from '../codex/codex-session-resume-home' import { agentForksConversations, agentForksThroughChat } from '../../shared/agent-resume-argv' import { isLegacyAgentSessionAccountHome } from '../../shared/agent-session-account-home' import { agentSessionProviderHandleChainHead } from '../../shared/agent-session-provider-handle' @@ -173,11 +174,12 @@ export async function prepareStructuredChatCliFork( }) const preparedHome = result.useRealCodexHome ? null : (result.substituteCodexHome ?? codexHome) if (codexHome && (result.useRealCodexHome || result.substituteCodexHome)) { - filePath = join( - preparedHome ?? getSystemCodexHomePath(), - 'sessions', - relative(join(codexHome, 'sessions'), filePath) - ) + // Codex canonicalizes CODEX_HOME, so Windows transcripts can carry a \\?\ prefix (#27200). + const relativePath = codexDatedRolloutRelativePath(join(codexHome, 'sessions'), filePath) + if (!relativePath) { + throw new Error('The prepared conversation is unavailable in the selected account.') + } + filePath = join(preparedHome ?? getSystemCodexHomePath(), 'sessions', relativePath) const preparedFile = await stat(filePath) if (!preparedFile.isFile() || preparedFile.size === 0) { throw new Error('The prepared conversation is unavailable in the selected account.') diff --git a/src/main/browser/wsl-browser-network-relay-launch.test.ts b/src/main/browser/wsl-browser-network-relay-launch.test.ts index cb9fe5c920a..b0e23846a4d 100644 --- a/src/main/browser/wsl-browser-network-relay-launch.test.ts +++ b/src/main/browser/wsl-browser-network-relay-launch.test.ts @@ -1,16 +1,19 @@ import { execFileSync } from 'node:child_process' -import { mkdtempSync, readFileSync, rmSync } from 'node:fs' +import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs' import { tmpdir } from 'node:os' import { join } from 'node:path' -import { afterEach, describe, expect, it } from 'vitest' +import { afterEach, describe, expect, it, vi } from 'vitest' +import { orcadPosixNodeRuntimeGlobs } from '../managed-server/install/orcad-node-runtime-globs' import { buildWslBrowserNetworkGuestInstallScript, - buildWslBrowserNetworkGuestLaunchScript + buildWslBrowserNetworkGuestLaunchScript, + resolveWslBrowserNetworkRelayBundle } from './wsl-browser-network-relay-launch' const roots: string[] = [] afterEach(() => { + vi.unstubAllEnvs() for (const root of roots.splice(0)) { rmSync(root, { recursive: true, force: true }) } @@ -29,6 +32,22 @@ describe('WSL browser network relay launch', () => { ) }) + it('falls back to orcad pinned runtimes after system node, under a launcher-stamped version', () => { + const forLine = buildWslBrowserNetworkGuestLaunchScript('0.1.0+abc') + .split('\n') + .find((line) => line.startsWith('for c in ')) + const [orcadRuntime, orcadMachineRuntimes] = orcadPosixNodeRuntimeGlobs() + expect(forLine).toContain(`"$HOME/.local/bin/node" ${orcadRuntime} ${orcadMachineRuntimes}; do`) + + const relayRoot = mkdtempSync(join(tmpdir(), 'orca-wsl-browser-network-bundle-')) + roots.push(relayRoot) + vi.stubEnv('ORCA_RELAY_PATH', relayRoot) + mkdirSync(join(relayRoot, 'wsl')) + writeFileSync(join(relayRoot, 'wsl', 'wsl-browser-network-relay.js'), '') + writeFileSync(join(relayRoot, 'wsl', '.browser-network-version'), '0.1.0+abc\n') + expect(resolveWslBrowserNetworkRelayBundle()?.version).toMatch(/^0\.1\.0\+abc\.[0-9a-f]{8}$/) + }) + it('installs exact bundle bytes and writes the version marker last', () => { const root = mkdtempSync(join(tmpdir(), 'orca-wsl-browser-network-')) roots.push(root) diff --git a/src/main/browser/wsl-browser-network-relay-launch.ts b/src/main/browser/wsl-browser-network-relay-launch.ts index a23e5237fa7..bb83e201f7e 100644 --- a/src/main/browser/wsl-browser-network-relay-launch.ts +++ b/src/main/browser/wsl-browser-network-relay-launch.ts @@ -2,6 +2,8 @@ import { spawnProcess } from '@orca/process-host' import { existsSync, readFileSync } from 'node:fs' import { join } from 'node:path' import { relayBundleCandidates } from '../ssh/relay-bundle-paths' +import { withWslGuestLauncherRevision } from '../wsl/wsl-guest-launcher-revision' +import { orcadPosixNodeRuntimeGlobs } from '../managed-server/install/orcad-node-runtime-globs' import { WSL_BROWSER_NETWORK_RELAY_BUNDLE_NAME, WSL_BROWSER_NETWORK_RELAY_DIR, @@ -33,7 +35,10 @@ export function resolveWslBrowserNetworkRelayBundle(): WslBrowserNetworkRelayBun } const version = readFileSync(versionPath, 'utf8').trim() if (/^[A-Za-z0-9+.-]+$/.test(version)) { - return { jsPath, version } + return { + jsPath, + version: withWslGuestLauncherRevision(version, buildWslBrowserNetworkGuestLaunchScript) + } } } return null @@ -48,13 +53,15 @@ function guestRelayDir(version: string): string { export function buildWslBrowserNetworkGuestLaunchScript(version: string): string { const dir = guestRelayDir(version) + // A WSL host distro may have no system node but usually has orcad's pinned runtime. + const [orcadRuntime, orcadMachineRuntimes] = orcadPosixNodeRuntimeGlobs() return [ '#!/bin/sh', `d="${dir}"`, `v="$(cat "$d/${WSL_BROWSER_NETWORK_RELAY_VERSION_FILE}" 2>/dev/null || true)"`, `[ "$v" = '${version}' ] || exit ${WSL_BROWSER_NETWORK_RELAY_STALE_EXIT_CODE}`, 'n=""', - 'for c in "$(command -v node 2>/dev/null || true)" "$HOME/.nvm/versions/node"/*/bin/node /usr/local/bin/node /usr/bin/node "$HOME/.local/bin/node"; do', + `for c in "$(command -v node 2>/dev/null || true)" "$HOME/.nvm/versions/node"/*/bin/node /usr/local/bin/node /usr/bin/node "$HOME/.local/bin/node" ${orcadRuntime} ${orcadMachineRuntimes}; do`, ' [ -n "$c" ] && [ -x "$c" ] || continue', ` if "$c" -e 'process.exit(Number(process.versions.node.split(".")[0])>=18?0:1)' 2>/dev/null; then`, ' n="$c"', diff --git a/src/main/claude/hook-script.ts b/src/main/claude/hook-script.ts index 0c233aa75ef..82e3b89c09a 100644 --- a/src/main/claude/hook-script.ts +++ b/src/main/claude/hook-script.ts @@ -17,8 +17,7 @@ import { import { buildPosixHookPayloadCapture, buildPosixHookSpoolLines, - buildWindowsHookEnvironmentGuardLines, - buildWindowsHookStdinDrainEpilogue + buildWindowsHookEnvironmentGuardLines } from '../agent-hooks/hook-stdin-contract' // Daemon workers inherit stale pane keys; exit before draining their potentially abandoned stdin. @@ -58,7 +57,6 @@ export function getManagedScript( // Avoid a PowerShell startup per hook. buildWindowsAgentHookCurlPostCommand(source), 'exit /b 0', - ...buildWindowsHookStdinDrainEpilogue(), '' ].join('\r\n') } diff --git a/src/main/claude/hook-service.test.ts b/src/main/claude/hook-service.test.ts index b0f5f9f1d9a..cb27e806750 100644 --- a/src/main/claude/hook-service.test.ts +++ b/src/main/claude/hook-service.test.ts @@ -18,7 +18,6 @@ vi.mock('../git-bash', async (importOriginal) => ({ import type { SFTPWrapper } from 'ssh2' import { createManagedCommandMatcher, WINDOWS_CMD_SAFE_PATH } from '../agent-hooks/installer-utils' -import { WINDOWS_HOOK_STDIN_DRAIN_LABEL } from '../agent-hooks/hook-stdin-contract' import { ClaudeHookService } from './hook-service' import { CLAUDE_EVENTS } from './claude-managed-hook-events' import { getWindowsManagedLifecycleHook, OPENCLAUDE_HOOK_SETTINGS } from './hook-settings' @@ -656,7 +655,7 @@ describe('backgrounded-session pane guard (#9236)', () => { expect(guard).toBeDefined() expect(script.indexOf('CLAUDE_JOB_DIR')).toBeLessThan(script.indexOf('curl')) if (target === 'win32') { - expect(guard).not.toContain(WINDOWS_HOOK_STDIN_DRAIN_LABEL) + expect(guard).toBe('if not "%CLAUDE_JOB_DIR%"=="" exit /b 0') } } finally { Object.defineProperty(process, 'platform', platform) @@ -680,7 +679,6 @@ describe('backgrounded-session pane guard (#9236)', () => { ) const guard = script.split('\r\n').find((line) => line.includes('CLAUDE_JOB_DIR')) expect(guard).toBe('if not "%CLAUDE_JOB_DIR%"=="" exit /b 0') - expect(guard).not.toContain(WINDOWS_HOOK_STDIN_DRAIN_LABEL) } finally { Object.defineProperty(process, 'platform', platform) vi.unstubAllEnvs() diff --git a/src/main/claude/statusline-script.test.ts b/src/main/claude/statusline-script.test.ts index ba2c871fe3e..8515873e23e 100644 --- a/src/main/claude/statusline-script.test.ts +++ b/src/main/claude/statusline-script.test.ts @@ -82,16 +82,13 @@ describe('getManagedStatusLineScript (win32 local)', () => { expect(script).not.toContain('"configDir=%CLAUDE_CONFIG_DIR%"') }) - it('drains stdin before exiting when the pane key is missing', () => { + it('exits without reading stdin when the pane key is missing (#24907)', () => { stubPlatform('win32') const script = getManagedStatusLineScript('local') - const paneGuardIndex = script.indexOf( - 'if "%ORCA_PANE_KEY%"=="" goto :orca_agent_hook_drain_stdin' - ) - const captureIndex = script.indexOf('more.com') + const paneGuardIndex = script.indexOf('if "%ORCA_PANE_KEY%"=="" exit /b 0') expect(paneGuardIndex).toBeGreaterThan(-1) - expect(paneGuardIndex).toBeLessThan(captureIndex) - expect(script).toContain(':orca_agent_hook_drain_stdin') + expect(paneGuardIndex).toBeLessThan(script.indexOf('more.com')) + expect(script.match(/more\.com/g)).toHaveLength(1) }) it('throttles with an all-builtin seconds-of-day stamp that fails open to posting', () => { diff --git a/src/main/claude/statusline-script.ts b/src/main/claude/statusline-script.ts index fce3d94ec19..cb8c10edc4d 100644 --- a/src/main/claude/statusline-script.ts +++ b/src/main/claude/statusline-script.ts @@ -1,9 +1,5 @@ import { posixCurlCommand } from '../agent-hooks/hook-post-command' -import { - buildWindowsHookStdinDrainEpilogue, - WINDOWS_HOOK_STDIN_DRAIN_LABEL, - WINDOWS_HOOK_STDIN_READER -} from '../agent-hooks/hook-stdin-contract' +import { WINDOWS_HOOK_STDIN_READER } from '../agent-hooks/hook-stdin-contract' import { CLAUDE_STATUSLINE_MIN_POST_INTERVAL_SECONDS, CLAUDE_STATUSLINE_PATHNAME @@ -31,7 +27,7 @@ export function getManagedStatusLineScript(target: 'local' | 'posix' = 'local'): // Daemon workers inherit stale pane keys; exit before reading their potentially abandoned stdin. 'if not "%CLAUDE_JOB_DIR%"=="" exit /b 0', // Endpoint refresh never sets the pane key, so this guard can precede stdin capture. - `if "%ORCA_PANE_KEY%"=="" goto :${WINDOWS_HOOK_STDIN_DRAIN_LABEL}`, + 'if "%ORCA_PANE_KEY%"=="" exit /b 0', // UUID suffixes and sanitized legacy delimiters keep filenames safe. 'set "ORCA_STATUSLINE_PANE_ID=%ORCA_PANE_KEY:~-36%"', 'set "ORCA_STATUSLINE_PANE_ID=%ORCA_STATUSLINE_PANE_ID::=_%"', @@ -80,7 +76,6 @@ export function getManagedStatusLineScript(target: 'local' | 'posix' = 'local'): `:${STATUSLINE_CLEANUP_LABEL}`, 'del "%ORCA_STATUSLINE_PAYLOAD_FILE%" >nul 2>nul', 'exit /b 0', - ...buildWindowsHookStdinDrainEpilogue(), '' ].join('\r\n') } diff --git a/src/main/claude/windows-hook-files.ts b/src/main/claude/windows-hook-files.ts index d841bead8d8..1b0bc158747 100644 --- a/src/main/claude/windows-hook-files.ts +++ b/src/main/claude/windows-hook-files.ts @@ -11,7 +11,7 @@ import { } from '../agent-hooks/managed-hook-script-refresh' import { buildWindowsHookEnvironmentGuardLines, - buildWindowsHookStdinDrainEpilogue + WINDOWS_HOOK_STDIN_DRAIN_COMMAND } from '../agent-hooks/hook-stdin-contract' import { resolveBundledWindowsNativeHookExecutable, @@ -85,7 +85,8 @@ export function getWindowsClaudeHookEntry(): string { 'echo {}', ...buildWindowsHookEnvironmentGuardLines(), WINDOWS_CLAUDE_BACKGROUND_JOB_GUARD, - ...buildWindowsHookStdinDrainEpilogue(), + WINDOWS_HOOK_STDIN_DRAIN_COMMAND, + 'exit /b 0', '' ].join('\r\n') } diff --git a/src/main/codex/codex-at-rest-skills-probe.ts b/src/main/codex/codex-at-rest-skills-probe.ts index fdfa9257269..93fd8021f29 100644 --- a/src/main/codex/codex-at-rest-skills-probe.ts +++ b/src/main/codex/codex-at-rest-skills-probe.ts @@ -16,7 +16,7 @@ import { import { runCodexAppServerSession } from './codex-app-server-session' import { isCodexSkillsListUnsupported, requestCodexSkillReport } from './codex-skill-list' import { supportsCodexStructuredLocation } from './codex-structured-location-support' -import { resolveHiddenRateLimitPtyCwd } from '../rate-limits/hidden-rate-limit-pty-cwd' +import { resolveHiddenProbeCwd } from '../rate-limits/hidden-probe-cwd' import { resolveCodexStructuredInvocation, type CodexStructuredInvocationDeps @@ -108,7 +108,7 @@ async function probeCodexSkills( command, args: [...args, 'app-server'], // skills/list takes the folder per request; a settling probe in it blocks Windows worktree removal (#33174). - cwd: resolveHiddenRateLimitPtyCwd(), + cwd: resolveHiddenProbeCwd(), cliPath: command, env: { ...definedEnv(environment), CODEX_HOME: accountHomePath }, envToDelete: [NATIVE_CHAT_SCRATCH_DIR_ENV, LEGACY_NATIVE_CHAT_VISUALS_DIR_ENV], diff --git a/src/main/codex/codex-hook-script.ts b/src/main/codex/codex-hook-script.ts index 173a1217874..e72b4bc7bb9 100644 --- a/src/main/codex/codex-hook-script.ts +++ b/src/main/codex/codex-hook-script.ts @@ -2,8 +2,7 @@ import { buildPosixAgentHookPostCommand } from '../agent-hooks/hook-post-command import { buildPosixHookPayloadCapture, buildPosixHookSpoolLines, - buildWindowsHookEnvironmentGuardLines, - buildWindowsHookStdinDrainEpilogue + buildWindowsHookEnvironmentGuardLines } from '../agent-hooks/hook-stdin-contract' import { buildWindowsAgentHookCurlPostCommand } from '../agent-hooks/installer-utils' @@ -17,7 +16,6 @@ export function getManagedScript(target: 'local' | 'posix' = 'local'): string { ...buildWindowsHookEnvironmentGuardLines(), buildWindowsAgentHookCurlPostCommand('codex'), 'exit /b 0', - ...buildWindowsHookStdinDrainEpilogue(), '' ].join('\r\n') } diff --git a/src/main/command-code/command-code-managed-script.ts b/src/main/command-code/command-code-managed-script.ts index c8ddf00c420..c7da611a1b8 100644 --- a/src/main/command-code/command-code-managed-script.ts +++ b/src/main/command-code/command-code-managed-script.ts @@ -3,8 +3,7 @@ import { buildWindowsAgentHookPostCommand } from '../agent-hooks/installer-utils import { buildPosixHookPayloadCapture, buildPosixHookSpoolLines, - buildWindowsHookEnvironmentGuardLines, - buildWindowsHookStdinDrainEpilogue + buildWindowsHookEnvironmentGuardLines } from '../agent-hooks/hook-stdin-contract' export type CommandCodeManagedScriptTarget = 'local' | 'posix' @@ -36,7 +35,6 @@ export function buildCommandCodeManagedScript( 'if not "%ORCA_AGENT_HOOK_TOKEN%"=="" exit /b 0', 'for /f "tokens=2 delims==" %%P in (\'findstr /b /c:"set ORCA_AGENT_HOOK_PORT=" "%~1" 2^>nul\') do if "%%P"=="%ORCA_AGENT_HOOK_PORT%" call "%~1" 2>nul', 'exit /b 0', - ...buildWindowsHookStdinDrainEpilogue(), '' ].join('\r\n') } diff --git a/src/main/copilot/copilot-managed-script.ts b/src/main/copilot/copilot-managed-script.ts index 431b9a7a0d6..8cd108d8409 100644 --- a/src/main/copilot/copilot-managed-script.ts +++ b/src/main/copilot/copilot-managed-script.ts @@ -6,8 +6,7 @@ import { import { buildPosixHookPayloadCapture, buildPosixHookSpoolLines, - buildWindowsHookEnvironmentGuardLines, - buildWindowsHookStdinDrainEpilogue + buildWindowsHookEnvironmentGuardLines } from '../agent-hooks/hook-stdin-contract' export function getManagedScriptFileName(): string { @@ -34,7 +33,6 @@ export function getManagedScript(target: 'local' | 'posix' = 'local'): string { ' --data-urlencode "hookEventName=%ORCA_COPILOT_HOOK_EVENT%" ^' ]), 'exit /b 0', - ...buildWindowsHookStdinDrainEpilogue(), '' ].join('\r\n') } diff --git a/src/main/cursor/hook-script.ts b/src/main/cursor/hook-script.ts index 24908e9c52e..3ccbd5d2a64 100644 --- a/src/main/cursor/hook-script.ts +++ b/src/main/cursor/hook-script.ts @@ -8,8 +8,7 @@ import { posixCurlCommand } from '../agent-hooks/hook-post-command' import { buildPosixHookPayloadCapture, buildPosixHookSpoolLines, - buildWindowsHookEnvironmentGuardLines, - buildWindowsHookStdinDrainEpilogue + buildWindowsHookEnvironmentGuardLines } from '../agent-hooks/hook-stdin-contract' import { buildPosixGrokReplayGuardLines, @@ -59,7 +58,6 @@ export function getManagedScript(target: 'local' | 'posix' = 'local'): string { ...buildWindowsGrokReplayGuardLines(), buildWindowsAgentHookPostCommand('cursor'), 'exit /b 0', - ...buildWindowsHookStdinDrainEpilogue(), '' ].join('\r\n') } diff --git a/src/main/devin/hook-service.ts b/src/main/devin/hook-service.ts index 08353dc4642..c9f4d3d99a7 100644 --- a/src/main/devin/hook-service.ts +++ b/src/main/devin/hook-service.ts @@ -14,8 +14,7 @@ import { import { buildPosixHookPayloadCapture, buildPosixHookSpoolLines, - buildWindowsHookEnvironmentGuardLines, - buildWindowsHookStdinDrainEpilogue + buildWindowsHookEnvironmentGuardLines } from '../agent-hooks/hook-stdin-contract' import { posixCurlCommand } from '../agent-hooks/hook-post-command' import { @@ -49,7 +48,6 @@ function getManagedScript(target: 'local' | 'posix' = 'local'): string { ...buildWindowsHookEnvironmentGuardLines(), buildWindowsAgentHookPostCommand('devin'), 'exit /b 0', - ...buildWindowsHookStdinDrainEpilogue(), '' ].join('\r\n') } diff --git a/src/main/droid/hook-service.ts b/src/main/droid/hook-service.ts index 9f0abf8e84a..a78a883e5c3 100644 --- a/src/main/droid/hook-service.ts +++ b/src/main/droid/hook-service.ts @@ -25,8 +25,7 @@ import { import { buildPosixHookPayloadCapture, buildPosixHookSpoolLines, - buildWindowsHookEnvironmentGuardLines, - buildWindowsHookStdinDrainEpilogue + buildWindowsHookEnvironmentGuardLines } from '../agent-hooks/hook-stdin-contract' import { posixCurlCommand } from '../agent-hooks/hook-post-command' @@ -81,7 +80,6 @@ function getManagedScript(target: 'local' | 'posix' = 'local'): string { ...buildWindowsHookEnvironmentGuardLines(), buildWindowsAgentHookPostCommand('droid'), 'exit /b 0', - ...buildWindowsHookStdinDrainEpilogue(), '' ].join('\r\n') } diff --git a/src/main/dsh/hook-service.ts b/src/main/dsh/hook-service.ts index 609ceed947a..25c9b109fd5 100644 --- a/src/main/dsh/hook-service.ts +++ b/src/main/dsh/hook-service.ts @@ -18,8 +18,7 @@ import { import { buildPosixHookPayloadCapture, buildPosixHookSpoolLines, - buildWindowsHookEnvironmentGuardLines, - buildWindowsHookStdinDrainEpilogue + buildWindowsHookEnvironmentGuardLines } from '../agent-hooks/hook-stdin-contract' import { buildPosixAgentHookPostCommand } from '../agent-hooks/hook-post-command' import { @@ -57,7 +56,6 @@ function getManagedScript(target: 'local' | 'posix' = 'local'): string { ...buildWindowsHookEnvironmentGuardLines(), buildWindowsAgentHookCurlPostCommand('dsh'), 'exit /b 0', - ...buildWindowsHookStdinDrainEpilogue(), '' ].join('\r\n') } diff --git a/src/main/gemini/hook-service.ts b/src/main/gemini/hook-service.ts index ee792c88a66..ece8e374156 100644 --- a/src/main/gemini/hook-service.ts +++ b/src/main/gemini/hook-service.ts @@ -25,8 +25,7 @@ import { import { buildPosixHookPayloadCapture, buildPosixHookSpoolLines, - buildWindowsHookEnvironmentGuardLines, - buildWindowsHookStdinDrainEpilogue + buildWindowsHookEnvironmentGuardLines } from '../agent-hooks/hook-stdin-contract' import { posixCurlCommand } from '../agent-hooks/hook-post-command' @@ -64,7 +63,6 @@ function getManagedScript(target: 'local' | 'posix' = 'local'): string { ...buildWindowsHookEnvironmentGuardLines(), buildWindowsAgentHookPostCommand('gemini'), 'exit /b 0', - ...buildWindowsHookStdinDrainEpilogue(), '' ].join('\r\n') } diff --git a/src/main/grok/windows-grok-hook-script.ts b/src/main/grok/windows-grok-hook-script.ts index 369c0811234..ddcbfa5e5f4 100644 --- a/src/main/grok/windows-grok-hook-script.ts +++ b/src/main/grok/windows-grok-hook-script.ts @@ -1,8 +1,5 @@ import { buildWindowsAgentHookPostCommand } from '../agent-hooks/installer-utils' -import { - buildWindowsHookEnvironmentGuardLines, - buildWindowsHookStdinDrainEpilogue -} from '../agent-hooks/hook-stdin-contract' +import { buildWindowsHookEnvironmentGuardLines } from '../agent-hooks/hook-stdin-contract' /** Matches the envelope length cap used by the POSIX grok-hook branch. */ export const GROK_HOME_ENVELOPE_MAX_LENGTH = 4096 @@ -31,7 +28,6 @@ export function buildWindowsGrokHookScript(): string { ':orca_grok_home_ready', WINDOWS_GROK_HOOK_POST_COMMAND, 'exit /b 0', - ...buildWindowsHookStdinDrainEpilogue(), '' ].join('\r\n') } diff --git a/src/main/jcode/hook-service.ts b/src/main/jcode/hook-service.ts index 9f4232a920e..67dfa60f1d3 100644 --- a/src/main/jcode/hook-service.ts +++ b/src/main/jcode/hook-service.ts @@ -16,7 +16,6 @@ import { } from '../agent-hooks/installer-utils-remote' import { buildWindowsHookEnvironmentGuardLines, - buildWindowsHookStdinDrainEpilogue, POSIX_HOOK_STDIN_DRAIN_COMMAND, WINDOWS_HOOK_STDIN_DRAIN_COMMAND } from '../agent-hooks/hook-stdin-contract' @@ -60,7 +59,6 @@ function getManagedScript(target: 'local' | 'posix' = 'local'): string { ])}`, `del "${payloadFile}" 2>nul`, 'exit /b 0', - ...buildWindowsHookStdinDrainEpilogue(), '' ].join('\r\n') } diff --git a/src/main/kimi/hook-service.ts b/src/main/kimi/hook-service.ts index 3cfb7ee6f7f..989331af4d5 100644 --- a/src/main/kimi/hook-service.ts +++ b/src/main/kimi/hook-service.ts @@ -32,8 +32,7 @@ import { import { buildPosixHookPayloadCapture, buildPosixHookSpoolLines, - buildWindowsHookEnvironmentGuardLines, - buildWindowsHookStdinDrainEpilogue + buildWindowsHookEnvironmentGuardLines } from '../agent-hooks/hook-stdin-contract' import { posixCurlCommand } from '../agent-hooks/hook-post-command' import { @@ -82,7 +81,6 @@ function getManagedScript(target: 'local' | 'posix' = 'local'): string { ...buildWindowsHookEnvironmentGuardLines(), buildWindowsAgentHookCurlPostCommand('kimi'), 'exit /b 0', - ...buildWindowsHookStdinDrainEpilogue(), '' ].join('\r\n') } diff --git a/src/main/kiro/hook-service.ts b/src/main/kiro/hook-service.ts index 6d0e7fade41..a1d5e00fb2c 100644 --- a/src/main/kiro/hook-service.ts +++ b/src/main/kiro/hook-service.ts @@ -20,8 +20,7 @@ import { refreshManagedScriptIfPresent } from '../agent-hooks/managed-hook-scrip import { buildPosixHookPayloadCapture, buildPosixHookSpoolLines, - buildWindowsHookEnvironmentGuardLines, - buildWindowsHookStdinDrainEpilogue + buildWindowsHookEnvironmentGuardLines } from '../agent-hooks/hook-stdin-contract' import { buildPosixAgentHookPostCommand } from '../agent-hooks/hook-post-command' import { @@ -50,7 +49,6 @@ function getManagedScript(target: 'local' | 'posix' = 'local'): string { ...buildWindowsHookEnvironmentGuardLines(), buildWindowsAgentHookCurlPostCommand('kiro'), 'exit /b 0', - ...buildWindowsHookStdinDrainEpilogue(), '' ].join('\r\n') } diff --git a/src/main/muse/hook-service.ts b/src/main/muse/hook-service.ts index ed2f82ec3ea..551dc59ee05 100644 --- a/src/main/muse/hook-service.ts +++ b/src/main/muse/hook-service.ts @@ -17,8 +17,7 @@ import { import { buildPosixHookPayloadCapture, buildPosixHookSpoolLines, - buildWindowsHookEnvironmentGuardLines, - buildWindowsHookStdinDrainEpilogue + buildWindowsHookEnvironmentGuardLines } from '../agent-hooks/hook-stdin-contract' import { buildPosixAgentHookPostCommand } from '../agent-hooks/hook-post-command' import { @@ -51,7 +50,6 @@ function getManagedScript(target: 'local' | 'posix' = 'local'): string { ...buildWindowsHookEnvironmentGuardLines(), buildWindowsAgentHookCurlPostCommand('muse'), 'exit /b 0', - ...buildWindowsHookStdinDrainEpilogue(), '' ].join('\r\n') } diff --git a/src/main/rate-limits/codex-fetcher.ts b/src/main/rate-limits/codex-fetcher.ts index 4c15dfee564..70d604bcffc 100644 --- a/src/main/rate-limits/codex-fetcher.ts +++ b/src/main/rate-limits/codex-fetcher.ts @@ -31,10 +31,7 @@ import { supplementCodexRateLimitResetCredits } from './codex-reset-credit-client' import { readCodexRateLimitsViaRpc } from './codex-rpc-rate-limit-probe' -import { - getHiddenRateLimitWslCwdSetupCommands, - resolveHiddenRateLimitPtyCwd -} from './hidden-rate-limit-pty-cwd' +import { getHiddenProbeWslCwdSetupCommands, resolveHiddenProbeCwd } from './hidden-probe-cwd' import { quotePosixShell } from '../../shared/shell-argument-quoting' import { resolveWslInteropSpawnCwd } from '../wsl-interop-spawn-directory' @@ -54,7 +51,7 @@ function buildWslCodexCommand( return null } const setupCommands = [ - ...getHiddenRateLimitWslCwdSetupCommands(), + ...getHiddenProbeWslCwdSetupCommands(), `export CODEX_HOME=${quotePosixShell(wslInfo.linuxPath)}` ].join(' && ') const execSuffix = `${args.map(quotePosixShell).join(' ')} <&3 >&4 3<&- 4>&-` @@ -99,7 +96,7 @@ async function fetchViaRpc(options?: CodexRateLimitFetchOptions): Promise