From 0200993462e6096600ef2daffcc6398b2ec30219 Mon Sep 17 00:00:00 2001 From: Brennan Benson <79079362+brennanb2025@users.noreply.github.com> Date: Tue, 15 Sep 2026 17:17:25 -0700 Subject: [PATCH] fix(agent-hooks): cover Auggie Windows launcher --- src/main/agent-hooks/installer-utils.ts | 5 ++-- src/main/auggie/hook-service.test.ts | 9 +++++- src/main/auggie/hook-service.ts | 40 +++++++++++++++++++++---- 3 files changed, 46 insertions(+), 8 deletions(-) diff --git a/src/main/agent-hooks/installer-utils.ts b/src/main/agent-hooks/installer-utils.ts index a53721d42fe..e18b26861c8 100644 --- a/src/main/agent-hooks/installer-utils.ts +++ b/src/main/agent-hooks/installer-utils.ts @@ -152,12 +152,13 @@ export function wrapWindowsCmdHookCommand(scriptPath: string): string { */ export function buildWindowsAgentHookPostCommand( source: AgentHookSource, - extraFormLines: readonly string[] = [] + extraFormLines: readonly string[] = [], + hookPathname = `/hook/${source}` ): string { // Why: PowerShell startup makes inline per-turn Codex hooks visibly slow, so mirror the POSIX curl path. // Why: fully-qualify curl so a repo-local curl.exe can't hijack hook payloads. return [ - `"%SystemRoot%\\System32\\curl.exe" -sS -X POST "http://127.0.0.1:%ORCA_AGENT_HOOK_PORT%/hook/${source}" ^`, + `"%SystemRoot%\\System32\\curl.exe" -sS -X POST "http://127.0.0.1:%ORCA_AGENT_HOOK_PORT%${hookPathname}" ^`, ' --connect-timeout 0.5 --max-time 1.5 ^', ' -H "Content-Type: application/x-www-form-urlencoded" ^', ' -H "X-Orca-Agent-Hook-Token: %ORCA_AGENT_HOOK_TOKEN%" ^', diff --git a/src/main/auggie/hook-service.test.ts b/src/main/auggie/hook-service.test.ts index 9de70a5bf99..4020a90ab17 100644 --- a/src/main/auggie/hook-service.test.ts +++ b/src/main/auggie/hook-service.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from 'vitest' -import { buildAuggieManagedScript } from './hook-service' +import { buildAuggieManagedScript, buildAuggieWindowsManagedScript } from './hook-service' import { wrapPosixHookCommand } from '../agent-hooks/installer-utils' describe('Auggie hook launcher contract', () => { @@ -16,4 +16,11 @@ describe('Auggie hook launcher contract', () => { expect(command).toContain('/bin/sh') expect(command).not.toContain('bash -c') }) + + it('ships a Windows command wrapper with the same guarded curl contract', () => { + const source = buildAuggieWindowsManagedScript() + expect(source).toContain('@echo off') + expect(source).toContain('/hook/aug') + expect(source).toContain('ORCA_AGENT_HOOK_TOKEN') + }) }) diff --git a/src/main/auggie/hook-service.ts b/src/main/auggie/hook-service.ts index 9e4c9171b98..c1667075dbf 100644 --- a/src/main/auggie/hook-service.ts +++ b/src/main/auggie/hook-service.ts @@ -5,12 +5,16 @@ import type { SFTPWrapper } from 'ssh2' import { buildPosixHookPayloadCapture, buildPosixHookSpoolLines, - POSIX_HOOK_BOUNDED_JSON_STDIN + POSIX_HOOK_BOUNDED_JSON_STDIN, + buildWindowsHookEnvironmentGuardLines, + buildWindowsHookStdinDrainEpilogue } from '../agent-hooks/hook-stdin-contract' import { createManagedCommandMatcher, getSharedManagedScriptPath, wrapPosixHookCommand, + wrapWindowsCmdHookCommand, + buildWindowsAgentHookPostCommand, writeHooksJson, writeManagedScript } from '../agent-hooks/installer-utils' @@ -29,6 +33,7 @@ import type { HooksConfig } from '../agent-hooks/installer-utils' import { createIntegrationHealthStore } from '../agent-hooks/integration-health' const SCRIPT_NAME = 'aug-hook.sh' +const WINDOWS_SCRIPT_NAME = 'aug-hook.cmd' const isManagedCommand = createManagedCommandMatcher(SCRIPT_NAME) export type AuggieInstallState = 'installed' | 'not_installed' | 'partial' | 'error' @@ -48,7 +53,9 @@ function getConfigPath(): string { return join(getAuggieHome(), 'settings.json') } function getScriptPath(): string { - return getSharedManagedScriptPath(SCRIPT_NAME) + return getSharedManagedScriptPath( + process.platform === 'win32' ? WINDOWS_SCRIPT_NAME : SCRIPT_NAME + ) } export function buildAuggieManagedScript(target: 'local' | 'posix' = 'local'): string { @@ -83,6 +90,19 @@ export function buildAuggieManagedScript(target: 'local' | 'posix' = 'local'): s ].join('\n') } +export function buildAuggieWindowsManagedScript(): string { + return [ + '@echo off', + 'setlocal', + 'if defined ORCA_AGENT_HOOK_ENDPOINT if exist "%ORCA_AGENT_HOOK_ENDPOINT%" call "%ORCA_AGENT_HOOK_ENDPOINT%" 2>nul', + ...buildWindowsHookEnvironmentGuardLines(), + buildWindowsAgentHookPostCommand('auggie', [], '/hook/aug'), + 'exit /b 0', + ...buildWindowsHookStdinDrainEpilogue(), + '' + ].join('\r\n') +} + function readConfig(path: string): HooksConfig | null { if (!existsSync(path)) { return {} @@ -134,8 +154,15 @@ export class AuggieHookService { if (!config) { return status(path, null) } - const command = wrapPosixHookCommand(getScriptPath()) - writeManagedScript(getScriptPath(), buildAuggieManagedScript()) + const scriptPath = getScriptPath() + const command = + process.platform === 'win32' + ? wrapWindowsCmdHookCommand(scriptPath) + : wrapPosixHookCommand(scriptPath) + writeManagedScript( + scriptPath, + process.platform === 'win32' ? buildAuggieWindowsManagedScript() : buildAuggieManagedScript() + ) writeHooksJson(path, applyAuggieManagedHooks(config, command)) createIntegrationHealthStore( join(homedir(), '.orca', 'agent-hooks', 'integration-health.json') @@ -143,7 +170,10 @@ export class AuggieHookService { integration: 'auggie', host: 'local', scope: path, - bytes: buildAuggieManagedScript(), + bytes: + process.platform === 'win32' + ? buildAuggieWindowsManagedScript() + : buildAuggieManagedScript(), version: '1' }) return this.getStatus()