diff --git a/packages/server/src/terminal/agent-hooks/agent-hook-installer.ts b/packages/server/src/terminal/agent-hooks/agent-hook-installer.ts index bb660016c..1d1388a98 100644 --- a/packages/server/src/terminal/agent-hooks/agent-hook-installer.ts +++ b/packages/server/src/terminal/agent-hooks/agent-hook-installer.ts @@ -138,7 +138,7 @@ export function buildAgentHookShellCommand( event: AgentHookEventDefinition, ): string { const hookCommand = `"\${PASEO_HOOK_CLI:-paseo}" hooks ${shellToken(provider.id)} ${shellToken(event.event)}`; - return `[ -n "$PASEO_TERMINAL_ID" ] && ${hookCommand}`; + return `if [ -n "$PASEO_TERMINAL_ID" ]; then ${hookCommand}; fi`; } export function buildAgentHookWindowsCommand( @@ -146,7 +146,7 @@ export function buildAgentHookWindowsCommand( event: AgentHookEventDefinition, ): string { const hookArgs = `hooks ${windowsToken(provider.id)} ${windowsToken(event.event)}`; - return `if defined PASEO_TERMINAL_ID (if defined PASEO_HOOK_CLI ("%PASEO_HOOK_CLI%" ${hookArgs}) else (paseo ${hookArgs}))`; + return `if defined PASEO_TERMINAL_ID (if defined PASEO_HOOK_CLI ("%PASEO_HOOK_CLI%" ${hookArgs}) else (paseo ${hookArgs})) else (exit /b 0)`; } function installAgentHookPluginFile( diff --git a/packages/server/src/terminal/agent-hooks/claude/claude.test.ts b/packages/server/src/terminal/agent-hooks/claude/claude.test.ts index 3a6dfb40f..488b236cc 100644 --- a/packages/server/src/terminal/agent-hooks/claude/claude.test.ts +++ b/packages/server/src/terminal/agent-hooks/claude/claude.test.ts @@ -1,8 +1,10 @@ +import { spawnSync } from "node:child_process"; import { mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs"; import { tmpdir } from "node:os"; import { delimiter, dirname, join, resolve } from "node:path"; import { fileURLToPath } from "node:url"; import { afterEach, describe, expect, it } from "vitest"; +import { isPlatform } from "../../../test-utils/platform.js"; import { buildTerminalEnvironment } from "../../terminal.js"; import { buildAgentHookShellCommand } from "../agent-hook-installer.js"; import { @@ -81,7 +83,7 @@ describe("Claude terminal agent hooks", () => { ); expect(paseoCommands).toHaveLength(1); expect(paseoCommands[0]).toBe( - `[ -n "$PASEO_TERMINAL_ID" ] && "\${PASEO_HOOK_CLI:-paseo}" hooks ${provider.id} ${event.event}`, + `if [ -n "$PASEO_TERMINAL_ID" ]; then "\${PASEO_HOOK_CLI:-paseo}" hooks ${provider.id} ${event.event}; fi`, ); } expect(registeredAgentHooksAreInstalled({ configDir })).toBe(true); @@ -146,10 +148,25 @@ describe("Claude terminal agent hooks", () => { const command = buildAgentHookShellCommand(provider, provider.events[0]); expect(command).toBe( - '[ -n "$PASEO_TERMINAL_ID" ] && "${PASEO_HOOK_CLI:-paseo}" hooks claude UserPromptSubmit', + 'if [ -n "$PASEO_TERMINAL_ID" ]; then "${PASEO_HOOK_CLI:-paseo}" hooks claude UserPromptSubmit; fi', ); }); + it.skipIf(isPlatform("win32")).each(AGENT_HOOK_PROVIDERS.claude.events)( + "$event hook command exits 0 when PASEO_TERMINAL_ID is unset", + (event) => { + const provider = AGENT_HOOK_PROVIDERS.claude; + const command = buildAgentHookShellCommand(provider, event); + + const result = spawnSync("/bin/sh", ["-c", command], { + env: { PATH: process.env.PATH ?? "", PASEO_HOOK_CLI: "paseo" }, + stdio: "ignore", + }); + + expect(result.status).toBe(0); + }, + ); + it("keeps provider names out of generic CLI and bootstrap integration points", () => { const genericFiles = [ join(repositoryRoot, "packages", "cli", "src", "commands", "hooks.ts"), diff --git a/packages/server/src/terminal/agent-hooks/codex/codex.test.ts b/packages/server/src/terminal/agent-hooks/codex/codex.test.ts index 6446d51ae..64e20f69c 100644 --- a/packages/server/src/terminal/agent-hooks/codex/codex.test.ts +++ b/packages/server/src/terminal/agent-hooks/codex/codex.test.ts @@ -68,8 +68,8 @@ describe("Codex terminal agent hooks", () => { for (const event of codexAgentHookProvider.events) { expect(commandHooks(config, event.event)).toEqual([ { - command: `[ -n "$PASEO_TERMINAL_ID" ] && "\${PASEO_HOOK_CLI:-paseo}" hooks codex ${event.event}`, - commandWindows: `if defined PASEO_TERMINAL_ID (if defined PASEO_HOOK_CLI ("%PASEO_HOOK_CLI%" hooks codex ${event.event}) else (paseo hooks codex ${event.event}))`, + command: `if [ -n "$PASEO_TERMINAL_ID" ]; then "\${PASEO_HOOK_CLI:-paseo}" hooks codex ${event.event}; fi`, + commandWindows: `if defined PASEO_TERMINAL_ID (if defined PASEO_HOOK_CLI ("%PASEO_HOOK_CLI%" hooks codex ${event.event}) else (paseo hooks codex ${event.event})) else (exit /b 0)`, }, ]); } @@ -102,7 +102,7 @@ describe("Codex terminal agent hooks", () => { const stopCommands = commandHooks(readHooksFile(configDir), "Stop").map((hook) => hook.command); expect(stopCommands).toEqual([ "say codex done", - '[ -n "$PASEO_TERMINAL_ID" ] && "${PASEO_HOOK_CLI:-paseo}" hooks codex Stop', + 'if [ -n "$PASEO_TERMINAL_ID" ]; then "${PASEO_HOOK_CLI:-paseo}" hooks codex Stop; fi', ]); });