GitNexus/gitnexus/test
haimingZZ ae4965899c fix(cursor-hook): self-test the guard, size npx budget from the real host window
Four fixes to the Cursor postToolUse hook's npx fallback.

F1 — Homebrew installs `gtimeout`, not `timeout`. The builtin candidate
list named `/opt/homebrew/bin/timeout` and `/usr/local/bin/timeout`, which
exist on no Homebrew install, so on Apple Silicon the `-s KILL`
orphan-containment wrap silently never engaged. Adopt the canonical list:
`/usr/bin/timeout`, `/bin/timeout`, `/opt/homebrew/bin/gtimeout`,
`/usr/local/bin/gtimeout`.

F2 — candidates were adopted on mere existence. `GITNEXUS_HOOK_TIMEOUT_PATH`
pointing at an always-exit-0 binary passed `existsSync`, and the wrapped
spawn then exited 0 without ever running npx — status 0 and empty stderr
satisfy main()'s success check, so the hook emitted no augmentation at all.
Port `passesGuardSelfTest` from hook-db-lock-probe.cjs: a candidate is
adopted only when `timeout -k 1 1 /bin/sh -c 'exit 42'` exits 42, i.e. it
both runs the wrapped command and propagates its status. This also rejects
busybox <1.34 / toybox, which lack `-k`. The override is resolved with
`path.resolve` because runGitNexusCli spawns it with the tool request's cwd.
Resolution is memoized per hook process.

F3 — `Math.max(1000, ...)` handed the guard 1000ms of an already-expired
host window (3000ms with the spawnSync allowance), so the host killed the
hook before the guard returned or the final stdout write landed. Skip the
npx spawn when no usable budget remains; return the same shape main()
already handles so the hook slot is still released.

F4 — `timeout + 5000` capped every npx fallback at 12s (main passes 7000),
defeating the 60s hooks.json manifest that exists to accommodate the cold
`npx -y gitnexus` install. Size the npx arm from the remaining host budget
instead, clamped by a documented max so one slow install cannot hold a
per-repo hook slot for the whole window.

Tests: pin the Homebrew gtimeout candidates, the always-exit-0 stub
rejection, the exhausted-budget skip, and the uncapped budget. The budget
arithmetic and the guard resolver are now exported so the tests exercise
them directly instead of matching substrings.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-10-06 01:48:18 +08:00
..
fixtures fix(embeddings): reuse completed vectors after interrupted analyze (#3463) 2026-10-04 09:26:02 +01:00
helpers fix(test): align fixtures and mocks with current types (#3471) 2026-10-05 04:47:37 +01:00
integration fix(search): reject incomplete FTS repairs and verify worktree lookup (#3475) 2026-10-05 13:19:10 +00:00
unit fix(cursor-hook): self-test the guard, size npx budget from the real host window 2026-10-06 01:48:18 +08:00
utils feat(storage): add configurable index storage and content retention tiers (#3060) 2026-09-12 20:31:55 +00:00