diff --git a/eslint-rules/no-adhoc-timeout-literal.allowlist.json b/eslint-rules/no-adhoc-timeout-literal.allowlist.json index 00acade09..7ae12bc80 100644 --- a/eslint-rules/no-adhoc-timeout-literal.allowlist.json +++ b/eslint-rules/no-adhoc-timeout-literal.allowlist.json @@ -3,12 +3,10 @@ "tests/adr-612-bracket-read-tolerance.test.cjs", "tests/adr-index-gate.test.cjs", "tests/adr857-core-without-capabilities.test.cjs", - "tests/antigravity-upgrades.test.cjs", "tests/api-coverage-gate-e2e.test.cjs", "tests/api-coverage.test.cjs", "tests/assumption-delta-checkpoint-e2e.test.cjs", "tests/assumption-delta.test.cjs", - "tests/augment-upgrades.test.cjs", "tests/capability-cli.test.cjs", "tests/capability-probe-fallback.test.cjs", "tests/capability-state.test.cjs", @@ -26,18 +24,14 @@ "tests/code-review.test.cjs", "tests/commands.test.cjs", "tests/config-get-default.test.cjs", - "tests/cursor-hook-workspace-roots.test.cjs", - "tests/cursor-hooks.test.cjs", "tests/dispatcher.test.cjs", "tests/effort-surface-axis.test.cjs", - "tests/effort-sync-installed-runtime.test.cjs", "tests/emitted-ack-trailer.test.cjs", "tests/emitted-attribution.test.cjs", "tests/execute-wave-post-gate-pipeline-e2e.test.cjs", "tests/feat-2483-review-claude-mds-guard.test.cjs", "tests/federated-config.test.cjs", "tests/gate-predicate-evaluator.test.cjs", - "tests/gemini-runtime-removed.test.cjs", "tests/gen-context-index.test.cjs", "tests/gen-health-docs.test.cjs", "tests/gen-section-manifest.test.cjs", @@ -49,12 +43,8 @@ "tests/gsd-statusline.test.cjs", "tests/gsd-write-guard.test.cjs", "tests/health-validation.test.cjs", - "tests/hooks-commonjs-marker.test.cjs", "tests/hooks-crash-policy.test.cjs", "tests/init.test.cjs", - "tests/kilo-upgrades.test.cjs", - "tests/kimi-upgrades.test.cjs", - "tests/kimi-variant-disambiguation.test.cjs", "tests/lint-docs-command-form.test.cjs", "tests/locking-bugs-1909-1916-1925-1927.test.cjs", "tests/loop-hooks-empty-points-e2e.test.cjs", @@ -64,7 +54,6 @@ "tests/loop-walk.qa.test.cjs", "tests/milestone-lock.test.cjs", "tests/no-pending-3212-markers.test.cjs", - "tests/opencode-plugin-adapter.test.cjs", "tests/pattern.test.cjs", "tests/perf-316-state-lock-buffer-alloc.test.cjs", "tests/perf-317-context-monitor-fs.test.cjs", @@ -91,13 +80,11 @@ "tests/security-prompt-injection.security.test.cjs", "tests/security-scan.security.test.cjs", "tests/security.test.cjs", - "tests/shared-hooks-dir-resolution.test.cjs", "tests/shell-command-projection-dispatch.test.cjs", "tests/state-document.test.cjs", "tests/state-todos-render.test.cjs", "tests/task-command-router-resolve-content.test.cjs", "tests/task-content-resolution.test.cjs", "tests/task-content-resolver-grammar-parity.test.cjs", - "tests/teams-status.test.cjs", - "tests/windsurf-hooks-bridge.test.cjs" + "tests/teams-status.test.cjs" ] diff --git a/tests/antigravity-upgrades.test.cjs b/tests/antigravity-upgrades.test.cjs index 8de414f67..df2af40be 100644 --- a/tests/antigravity-upgrades.test.cjs +++ b/tests/antigravity-upgrades.test.cjs @@ -37,6 +37,7 @@ const { runNode } = require('./helpers/process-seam.cjs'); const { runMinimalInstall, installerEnv, INSTALL_SCRIPT } = require('./helpers/install-shared.cjs'); const { cleanup } = require('./helpers.cjs'); +const { PROBE_TIMEOUT_MS, INSTALL_TIMEOUT_MS } = require('./helpers/timeouts.cjs'); const { toTildePosixPath, buildAntigravityAllowRules, @@ -225,7 +226,7 @@ test('UPGRADE 2: gsd-mcp-server companion is reachable — spawn, initialize, to const res = spawnSync(process.execPath, [MCP_SERVER_BIN], { input: stdin, encoding: 'utf-8', - timeout: 15000, + timeout: PROBE_TIMEOUT_MS, env: { ...process.env, GSD_TEST_MODE: '1' }, }); @@ -252,7 +253,7 @@ test('antigravity --global uninstall removes only GSD-owned permissions.allow ru const args = [INSTALL_SCRIPT, '--antigravity', '--global', '--config-dir', root]; const installResult = runNode(args, { env: installerEnv({ HOME: root, USERPROFILE: root }), - timeoutMs: 120000, + timeoutMs: INSTALL_TIMEOUT_MS, }); assert.strictEqual(installResult.exitCode, 0, `install failed: ${installResult.stderr}`); @@ -271,7 +272,7 @@ test('antigravity --global uninstall removes only GSD-owned permissions.allow ru const uninstallArgs = [INSTALL_SCRIPT, '--antigravity', '--global', '--config-dir', root, '--uninstall']; const uninstallResult = runNode(uninstallArgs, { env: installerEnv({ HOME: root, USERPROFILE: root }), - timeoutMs: 120000, + timeoutMs: INSTALL_TIMEOUT_MS, }); assert.strictEqual(uninstallResult.exitCode, 0, `uninstall failed: ${uninstallResult.stderr}`); diff --git a/tests/augment-upgrades.test.cjs b/tests/augment-upgrades.test.cjs index d82eac73b..707114d20 100644 --- a/tests/augment-upgrades.test.cjs +++ b/tests/augment-upgrades.test.cjs @@ -25,6 +25,7 @@ const { runNode } = require('./helpers/process-seam.cjs'); const { runMinimalInstall, installerEnv, INSTALL_SCRIPT } = require('./helpers/install-shared.cjs'); const { cleanup } = require('./helpers.cjs'); +const { INSTALL_TIMEOUT_MS } = require('./helpers/timeouts.cjs'); const { mergeGsdMcpServerIntoSettings, } = require('../bin/install.js'); @@ -169,7 +170,7 @@ test('augment --global: reinstalling does not duplicate or clobber the gsd MCP c const args = [INSTALL_SCRIPT, '--augment', '--global', '--config-dir', root]; const env = installerEnv({ HOME: root, USERPROFILE: root }); - const first = runNode(args, { env, timeoutMs: 120000 }); + const first = runNode(args, { env, timeoutMs: INSTALL_TIMEOUT_MS }); assert.strictEqual(first.exitCode, 0, `first install failed: ${first.stderr}`); const settingsPath = path.join(root, 'settings.json'); @@ -179,7 +180,7 @@ test('augment --global: reinstalling does not duplicate or clobber the gsd MCP c afterFirst.mcpServers.gsd.args.push('--custom-flag'); fs.writeFileSync(settingsPath, JSON.stringify(afterFirst, null, 2) + '\n'); - const second = runNode(args, { env, timeoutMs: 120000 }); + const second = runNode(args, { env, timeoutMs: INSTALL_TIMEOUT_MS }); assert.strictEqual(second.exitCode, 0, `second install failed: ${second.stderr}`); const afterSecond = JSON.parse(fs.readFileSync(settingsPath, 'utf8')); @@ -203,7 +204,7 @@ test('augment --global: installing preserves a pre-existing unrelated mcpServers const args = [INSTALL_SCRIPT, '--augment', '--global', '--config-dir', root]; const result = runNode(args, { env: installerEnv({ HOME: root, USERPROFILE: root }), - timeoutMs: 120000, + timeoutMs: INSTALL_TIMEOUT_MS, }); assert.strictEqual(result.exitCode, 0, `install failed: ${result.stderr}`); @@ -223,7 +224,7 @@ test('augment --global uninstall removes only the GSD-owned mcpServers.gsd entry const env = installerEnv({ HOME: root, USERPROFILE: root }); const installArgs = [INSTALL_SCRIPT, '--augment', '--global', '--config-dir', root]; - const installResult = runNode(installArgs, { env, timeoutMs: 120000 }); + const installResult = runNode(installArgs, { env, timeoutMs: INSTALL_TIMEOUT_MS }); assert.strictEqual(installResult.exitCode, 0, `install failed: ${installResult.stderr}`); // Seed user-owned data alongside GSD's contributions, post-install. @@ -233,7 +234,7 @@ test('augment --global uninstall removes only the GSD-owned mcpServers.gsd entry fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + '\n'); const uninstallArgs = [INSTALL_SCRIPT, '--augment', '--global', '--config-dir', root, '--uninstall']; - const uninstallResult = runNode(uninstallArgs, { env, timeoutMs: 120000 }); + const uninstallResult = runNode(uninstallArgs, { env, timeoutMs: INSTALL_TIMEOUT_MS }); assert.strictEqual(uninstallResult.exitCode, 0, `uninstall failed: ${uninstallResult.stderr}`); const settingsAfter = JSON.parse(fs.readFileSync(settingsPath, 'utf8')); diff --git a/tests/cursor-hook-workspace-roots.test.cjs b/tests/cursor-hook-workspace-roots.test.cjs index 9c0a61149..4a818ca1e 100644 --- a/tests/cursor-hook-workspace-roots.test.cjs +++ b/tests/cursor-hook-workspace-roots.test.cjs @@ -33,6 +33,7 @@ const { execFileSync } = require('node:child_process'); const { createTempDir, cleanup } = require('./helpers.cjs'); const { runHook: runHookSeam } = require('./helpers/process-seam.cjs'); const { escapeRegex } = require('../gsd-core/bin/lib/pattern.cjs'); +const { STAGED_HOOK_SCRIPT_TIMEOUT_MS } = require('./helpers/timeouts.cjs'); const HOOKS = path.join(__dirname, '..', 'hooks'); const SESSION_START = path.join(HOOKS, 'gsd-cursor-session-start.js'); @@ -54,7 +55,7 @@ function runHook(script, { cwd, payload }) { const r = runHookSeam(script, [], { cwd, input: typeof payload === 'string' ? payload : JSON.stringify(payload), - timeoutMs: 20000, + timeoutMs: STAGED_HOOK_SCRIPT_TIMEOUT_MS, }); return JSON.parse(r.stdout || '{}'); } @@ -343,7 +344,7 @@ describe('#2587: cursor hooks resolve the workspace from workspace_roots, not cw cwd: root, input: JSON.stringify({ workspace_roots: [ws] }), encoding: 'utf8', - timeout: 20000, + timeout: STAGED_HOOK_SCRIPT_TIMEOUT_MS, }) || '{}'); assert.ok( (out.additional_context || '').includes('STATE.md is present'), diff --git a/tests/cursor-hooks.test.cjs b/tests/cursor-hooks.test.cjs index 72df72b3a..ed9443f18 100644 --- a/tests/cursor-hooks.test.cjs +++ b/tests/cursor-hooks.test.cjs @@ -41,6 +41,7 @@ const fs = require('node:fs'); const path = require('node:path'); const os = require('node:os'); const { createTempDir, cleanup } = require('./helpers.cjs'); +const { QUICK_SPAWN_TIMEOUT_MS } = require('./helpers/timeouts.cjs'); const { GSD_CURSOR_HOOK_MARKER, @@ -401,7 +402,7 @@ test('T17: gsd-cursor-session-start.js emits JSON with additional_context', (t, const input = JSON.stringify({ session_id: 'test-123', composer_mode: 'agent' }); const child = execFile(process.execPath, [scriptPath], { - timeout: 10000, + timeout: QUICK_SPAWN_TIMEOUT_MS, cwd: os.tmpdir(), // no .planning/ dir here — should get MSG_ABSENT }, (err, stdout) => { if (err && !stdout) { done(err); return; } @@ -432,7 +433,7 @@ test('T18: gsd-cursor-post-tool.js emits {} for non-write tool names', (t, done) }); const child = execFile(process.execPath, [scriptPath], { - timeout: 10000, + timeout: QUICK_SPAWN_TIMEOUT_MS, cwd: os.tmpdir(), }, (err, stdout) => { if (err && !stdout) { done(err); return; } diff --git a/tests/effort-sync-installed-runtime.test.cjs b/tests/effort-sync-installed-runtime.test.cjs index 88dc88795..3a602bd84 100644 --- a/tests/effort-sync-installed-runtime.test.cjs +++ b/tests/effort-sync-installed-runtime.test.cjs @@ -26,6 +26,7 @@ const { runNode } = require('./helpers/process-seam.cjs'); const { runMinimalInstall } = require('./helpers/install-shared.cjs'); const { cleanup } = require('./helpers.cjs'); +const { PROBE_TIMEOUT_MS } = require('./helpers/timeouts.cjs'); // Absolute path to the built module, spawned in a child process below so the // JSON `cmdEffortSync` writes straight to fd 1 (via io.cjs's writeAllSync) can @@ -53,7 +54,7 @@ describe('#2071: effort sync runs in an installed runtime (no package-root bin/i const gsdTools = path.join(configDir, 'gsd-core', 'bin', 'gsd-tools.cjs'); const result = runNode( [gsdTools, 'effort', 'sync', '--config-dir', configDir], - { cwd: root, env: { ...process.env, HOME: root }, timeoutMs: 15000 }, + { cwd: root, env: { ...process.env, HOME: root }, timeoutMs: PROBE_TIMEOUT_MS }, ); const combined = `${result.stdout || ''}${result.stderr || ''}`; diff --git a/tests/gemini-runtime-removed.test.cjs b/tests/gemini-runtime-removed.test.cjs index b61889836..816235d93 100644 --- a/tests/gemini-runtime-removed.test.cjs +++ b/tests/gemini-runtime-removed.test.cjs @@ -33,7 +33,7 @@ const ROOT = path.join(__dirname, '..'); const INSTALL_JS = path.join(ROOT, 'bin', 'install.js'); // #3145: class-norm timeout, not a per-suite value — see helpers/timeouts.cjs. -const { BUILD_TIMEOUT_MS: BUILD_HOOKS_TIMEOUT_MS } = require('./helpers/timeouts.cjs'); +const { BUILD_TIMEOUT_MS: BUILD_HOOKS_TIMEOUT_MS, INSTALL_TIMEOUT_MS } = require('./helpers/timeouts.cjs'); // hooks/dist is gitignored + built; build it idempotently so a real install // emits hooks (mirrors golden-install-parity / install-minimal-hooks). @@ -64,7 +64,7 @@ function runInstaller(args, homeDir) { 'XDG_CONFIG_HOME', 'CODEX_CONFIG_DIR', 'OPENCODE_CONFIG_DIR', 'KILO_CONFIG_DIR', ]) delete env[k]; return spawnSync(process.execPath, [INSTALL_JS, ...args], { - cwd: homeDir, env, encoding: 'utf8', timeout: 120000, + cwd: homeDir, env, encoding: 'utf8', timeout: INSTALL_TIMEOUT_MS, }); } @@ -127,7 +127,7 @@ describe('#1928 --gemini CLI deprecation redirect', () => { delete env.GSD_TEST_MODE; delete env.CLAUDE_CONFIG_DIR; const r = spawnSync(process.execPath, [INSTALL_JS, '--gemini', '--uninstall', '--global'], { - cwd: home, env, encoding: 'utf8', timeout: 120000, + cwd: home, env, encoding: 'utf8', timeout: INSTALL_TIMEOUT_MS, }); assert.strictEqual(r.status, 1, 'must exit 1, not fall through to the uninstall dispatch'); diff --git a/tests/helpers/timeouts.cjs b/tests/helpers/timeouts.cjs index f5b1b40fa..04c66b666 100644 --- a/tests/helpers/timeouts.cjs +++ b/tests/helpers/timeouts.cjs @@ -141,6 +141,24 @@ const QUICK_SPAWN_TIMEOUT_MS = 10000; */ const FIXTURE_HOOK_TIMEOUT_SECONDS = 5; +/** + * Spawning ONE already-staged or already-bundled hook script directly -- + * never the full installer, never a fan-out across several hooks -- where + * the script does a modest amount of real work: a git-root check, a + * version-cache read/write, or an ESM-vs-CommonJS module load probe under a + * hostile config root. This is a distinct, heavier class than + * `QUICK_SPAWN_TIMEOUT_MS` (10000ms, trivial invocations with no real + * git/network work), since every site using this constant measurably does + * more than that. It is also distinct from `HOOK_FANOUT_TIMEOUT_MS`, which + * bounds a different class -- nested shell fan-out across MULTIPLE hooks, + * not a single script. + * + * Shared across 3 files in batch #4516 of the ad hoc timeout literal + * migration, epic #4445 -- that is why it lives here rather than as a + * file-local constant. + */ +const STAGED_HOOK_SCRIPT_TIMEOUT_MS = 20000; + module.exports = { PROBE_TIMEOUT_MS, HOOK_FANOUT_TIMEOUT_MS, @@ -151,4 +169,5 @@ module.exports = { SEAM_DEFAULT_TIMEOUT_MS, QUICK_SPAWN_TIMEOUT_MS, FIXTURE_HOOK_TIMEOUT_SECONDS, + STAGED_HOOK_SCRIPT_TIMEOUT_MS, }; diff --git a/tests/hooks-commonjs-marker.test.cjs b/tests/hooks-commonjs-marker.test.cjs index 2721b127f..bae618a10 100644 --- a/tests/hooks-commonjs-marker.test.cjs +++ b/tests/hooks-commonjs-marker.test.cjs @@ -19,6 +19,7 @@ const path = require('node:path'); const { execFileSync } = require('node:child_process'); const { createTempDir, cleanup } = require('./helpers.cjs'); const { runMinimalInstall } = require('./helpers/install-shared.cjs'); +const { STAGED_HOOK_SCRIPT_TIMEOUT_MS } = require('./helpers/timeouts.cjs'); const COMMONJS_MARKER = '{"type":"commonjs"}\n'; @@ -82,7 +83,7 @@ describe('#2717 CommonJS marker for staged .js hooks', () => { cwd: root, input: stdinPayload, encoding: 'utf8', - timeout: 20000, + timeout: STAGED_HOOK_SCRIPT_TIMEOUT_MS, stdio: ['pipe', 'pipe', 'pipe'], }); } catch (e) { diff --git a/tests/kilo-upgrades.test.cjs b/tests/kilo-upgrades.test.cjs index fe76bd648..6c7d6560e 100644 --- a/tests/kilo-upgrades.test.cjs +++ b/tests/kilo-upgrades.test.cjs @@ -33,6 +33,7 @@ const os = require('node:os'); const path = require('node:path'); const { spawnSync } = require('node:child_process'); const { runNode, runGit } = require('./helpers/process-seam.cjs'); +const { PROBE_TIMEOUT_MS } = require('./helpers/timeouts.cjs'); const { runMinimalInstall, BUILD_SCRIPT } = require('./helpers/install-shared.cjs'); const { cleanup } = require('./helpers.cjs'); @@ -206,7 +207,7 @@ test('UPGRADE 3: gsd-mcp-server companion is reachable — spawn, initialize, to const res = spawnSync(process.execPath, [MCP_SERVER_BIN], { input: stdin, encoding: 'utf-8', - timeout: 15000, + timeout: PROBE_TIMEOUT_MS, env: { ...process.env, GSD_TEST_MODE: '1' }, }); diff --git a/tests/kimi-upgrades.test.cjs b/tests/kimi-upgrades.test.cjs index 4b7fffb5a..feb396a06 100644 --- a/tests/kimi-upgrades.test.cjs +++ b/tests/kimi-upgrades.test.cjs @@ -40,6 +40,7 @@ const fs = require('node:fs'); const os = require('node:os'); const path = require('node:path'); const { runNode } = require('./helpers/process-seam.cjs'); +const { INSTALL_TIMEOUT_MS } = require('./helpers/timeouts.cjs'); const { runMinimalInstall, INSTALL_SCRIPT, installerEnv } = require('./helpers/install-shared.cjs'); const { cleanup, createTempDir, toPosixPath } = require('./helpers.cjs'); @@ -148,7 +149,7 @@ test('kimi --global: reinstalling is idempotent — the GSD [[hooks]] block is n const reinstall = runNode([INSTALL_SCRIPT, '--kimi', '--global', '--config-dir', root], { cwd: process.cwd(), env: installerEnv({ HOME: root, USERPROFILE: root }), - timeoutMs: 120000, + timeoutMs: INSTALL_TIMEOUT_MS, }); assert.strictEqual(reinstall.exitCode, 0, `reinstall exited with status ${reinstall.exitCode}\nstdout: ${reinstall.stdout}\nstderr: ${reinstall.stderr}`); diff --git a/tests/kimi-variant-disambiguation.test.cjs b/tests/kimi-variant-disambiguation.test.cjs index b3e813925..00e6a1b82 100644 --- a/tests/kimi-variant-disambiguation.test.cjs +++ b/tests/kimi-variant-disambiguation.test.cjs @@ -12,6 +12,7 @@ const fs = require('node:fs'); const os = require('node:os'); const path = require('node:path'); const { cleanup } = require('./helpers.cjs'); +const { PROBE_TIMEOUT_MS } = require('./helpers/timeouts.cjs'); const INSTALL_JS = path.join(__dirname, '..', 'bin', 'install.js'); @@ -29,7 +30,7 @@ function runInstall(args, home) { const r = spawnSync('node', [INSTALL_JS, ...args], { env: { ...process.env, HOME: home, USERPROFILE: home, GSD_TEST_MODE: '1' }, encoding: 'utf8', - timeout: 15000, + timeout: PROBE_TIMEOUT_MS, }); return { stdout: r.stdout || '', stderr: r.stderr || '', exit: r.status }; } diff --git a/tests/opencode-plugin-adapter.test.cjs b/tests/opencode-plugin-adapter.test.cjs index 3ac5a9c55..c7733bc15 100644 --- a/tests/opencode-plugin-adapter.test.cjs +++ b/tests/opencode-plugin-adapter.test.cjs @@ -26,6 +26,7 @@ const fs = require('node:fs'); const path = require('node:path'); const os = require('os'); const { cleanup } = require('./helpers.cjs'); +const { INSTALL_TIMEOUT_MS } = require('./helpers/timeouts.cjs'); const ADAPTER_SRC = path.join(__dirname, '..', '.opencode', 'plugins', 'gsd-core.js'); @@ -436,7 +437,7 @@ test('installer copies plugin as .js, records it in the manifest, and removes it const run = (args) => { const result = runNode([installer, '--opencode', '--global', '--config-dir', cfg, ...args], { - timeoutMs: 120000, + timeoutMs: INSTALL_TIMEOUT_MS, // #3156: sandbox HOME — the installer writes /.gsd/defaults.json via // os.homedir() directly, which no env scrub can reach. See installSpawnEnv. env: require('./helpers.cjs').installSpawnEnv(), diff --git a/tests/shared-hooks-dir-resolution.test.cjs b/tests/shared-hooks-dir-resolution.test.cjs index a9e615ca2..5f5e7473b 100644 --- a/tests/shared-hooks-dir-resolution.test.cjs +++ b/tests/shared-hooks-dir-resolution.test.cjs @@ -41,9 +41,17 @@ const path = require('node:path'); const { runNode, OUTCOME } = require('./helpers/process-seam.cjs'); const { createTempDir, cleanup } = require('./helpers.cjs'); const { copyScriptWithDeps } = require('./helpers/copy-script-fixture.cjs'); +const { STAGED_HOOK_SCRIPT_TIMEOUT_MS, QUICK_SPAWN_TIMEOUT_MS } = require('./helpers/timeouts.cjs'); const REPO_ROOT = path.join(__dirname, '..'); +// Bounds a single `driver.cjs` process sweeping many fast-check +// property-based cases in-process against a stubbed registry; digits +// coincide with the shared HOOK_FANOUT_TIMEOUT_MS/SEAM_DEFAULT_TIMEOUT_MS +// constants but this is neither a hook fan-out nor an omitted-default seam +// call, so kept as its own constant. +const PROPERTY_DRIVER_TIMEOUT_MS = 60000; + // Requiring the installer (not as main) never runs the CLI — matches the // existing tests/claude-imperative-reference.test.cjs convention. const installMod = require('../bin/install.js'); @@ -282,7 +290,7 @@ describe('GROUP A.2: resolveSharedHooksDirName — malformed/hostile values + pr UNDEFINED_SENTINEL, CASES_JSON: JSON.stringify(ALL_SINGLE_CASES), }, - timeoutMs: 60000, + timeoutMs: PROPERTY_DRIVER_TIMEOUT_MS, }); assert.equal(result.outcome, OUTCOME.EXITED, `driver did not exit cleanly: ${JSON.stringify(result)}`); @@ -567,7 +575,7 @@ describe('GROUP C: bundle-directory-name-agnostic hook scripts', () => { GSD_GLOBAL_VERSION_FILE: '', GSD_CACHE_FILE: cacheFile, }, - timeoutMs: 20000, + timeoutMs: STAGED_HOOK_SCRIPT_TIMEOUT_MS, }, ); @@ -632,7 +640,7 @@ describe('GROUP C: bundle-directory-name-agnostic hook scripts', () => { tool_response: { content: injectionContent }, }); - const excludedResult = runNode([scannerPath], { input: excludedPayload, timeoutMs: 10000 }); + const excludedResult = runNode([scannerPath], { input: excludedPayload, timeoutMs: QUICK_SPAWN_TIMEOUT_MS }); assert.equal(excludedResult.outcome, OUTCOME.EXITED); assert.equal(excludedResult.exitCode, 0); assert.equal( @@ -641,7 +649,7 @@ describe('GROUP C: bundle-directory-name-agnostic hook scripts', () => { "a path under the scanner's own bundle directory must be excluded (no PostToolUse output at all)", ); - const controlResult = runNode([scannerPath], { input: controlPayload, timeoutMs: 10000 }); + const controlResult = runNode([scannerPath], { input: controlPayload, timeoutMs: QUICK_SPAWN_TIMEOUT_MS }); assert.equal(controlResult.outcome, OUTCOME.EXITED); assert.equal(controlResult.exitCode, 0); assert.notEqual( diff --git a/tests/windsurf-hooks-bridge.test.cjs b/tests/windsurf-hooks-bridge.test.cjs index fa9b693f0..427e96c59 100644 --- a/tests/windsurf-hooks-bridge.test.cjs +++ b/tests/windsurf-hooks-bridge.test.cjs @@ -46,6 +46,7 @@ const path = require('node:path'); const os = require('node:os'); const { runHook: runHookSeam } = require('./helpers/process-seam.cjs'); const { gitOrThrow } = require('./helpers/git-fixture.cjs'); +const { QUICK_SPAWN_TIMEOUT_MS } = require('./helpers/timeouts.cjs'); const { createTempDir, cleanup } = require('./helpers.cjs'); @@ -69,7 +70,7 @@ function runHook(scriptPath, payload, opts = {}) { const input = payload === undefined ? '' : (typeof payload === 'string' ? payload : JSON.stringify(payload)); const r = runHookSeam(scriptPath, [], { input, - timeoutMs: 10000, + timeoutMs: QUICK_SPAWN_TIMEOUT_MS, cwd: opts.cwd || os.tmpdir(), }); return { status: r.exitCode, stdout: r.stdout, stderr: r.stderr, signal: r.signal };