Files
orca/src/cli
Brennan Benson 2c86d2a3bd fix(agent-hooks): stop test runs and secondary profiles deleting the user's agent hooks (STA-5679) (#16980)
* fix(agent-hooks): stop startup from deleting another instance's managed hooks (STA-5679)

Startup reconciliation removed the managed agent hooks whenever THIS profile had
the agent-status-hooks off switch set. The hook files it removes are user-global
(~/.claude/settings.json, ~/.cursor/hooks.json), so a second Orca profile with the
switch off deleted the hooks every other running instance depends on.

Cursor is the only agent with no title-derived status fallback: its native title is
deliberately parsed as status-less, so a hookless Cursor pane is floored at 'idle'
rather than showing a spinner. A global hook wipe therefore surfaces as "Cursor
loading status missing from the sidebar" while Claude and Codex still paint status
from their own titles, which is why this reads as a Cursor-only bug. Codex is
unaffected either way because its hooks live in an Orca-owned runtime home.

Honoring the off switch only requires skipping the install; removal stays on the
explicit Settings toggle, which is the user-initiated path that should own it.

Regression from #2778, which restored the destructive startup branch.

* fix(cli-tests): stop the deferral suite deleting the developer's real agent hooks

runtime-client-deferral.test.ts runs the REAL `main()` and feeds it
`agent hooks off`. It mocks only ./runtime/environments and ./runtime-client, so
the production handler ran end to end: updateEnabledOnDisk() wrote its state file
and applyAgentStatusHooksEnabled(false) called removeManagedAgentHooks() against
the developer's OWN ~/.claude/settings.json and ~/.cursor/hooks.json.

A green test run therefore deleted every Orca-managed hook on the machine. Agent
status then stopped reporting until the next Orca restart reinstalled them —
silently, because the hook POSTs still return 204 and Cursor has no title-derived
status fallback at all.

The byte-for-byte equivalence twin already refuses these exact tokens, commented
"MUTATING — writes outside ORCA_USER_DATA_PATH (`agent hooks off` parks the real
~/.claude hooks)". The vitest twin never got that guard.

Stub the hook-controls module rather than dropping the row: `agent hooks off` is
the only case in the table that reads ctx.client, so it carries the
null-vs-undefined coverage the other four cannot. All 23 tests still pass, and a
sandboxed HOME now keeps its hooks (5 -> 5) where it previously lost them (5 -> 0).

* fix(cli-tests): ratchet agent hook deferral safety

* fix(agent-hooks): keep startup reconciliation install-only
2026-08-28 11:33:14 -07:00
..
2026-08-26 09:50:12 -07:00
2026-08-26 09:50:12 -07:00