Removes kilo, kimi, kimi-code, copilot, windsurf, augment, trae, qwen, hermes, cline, codebuddy and pi end to end: capability descriptors, installer branches and converters (bin/install.js 14.9k -> 11.2k lines), TypeScript converters, hook surfaces and runtime homes, review lanes qwen/kimi-code, the two pi migrations, Kimi payload normalization in the hook guards, dead hostBehaviors vocabulary, launcher home probes, fixtures, runtime-specific tests and the prose that presented them as supported. Installer output for the six kept runtimes is byte-identical to before the prune. The Kimi tool-vocabulary tests in workflow-guard, read-guard and read-injection-scanner are left in place pending a decision.
58 lines
3.2 KiB
Markdown
58 lines
3.2 KiB
Markdown
---
|
|
id: 3911
|
|
title: Hooks Declare Their Crash Policy
|
|
group: v1.7.0 Features
|
|
---
|
|
|
|
**Purpose:** Give every shipped enforcement hook (`hooks/*.js`, `hooks/*.sh`) a
|
|
named, auditable termination vocabulary instead of a bare `process.exit(N)`
|
|
scattered per file — and make a hook's fail-open/fail-closed choice a
|
|
declaration a reviewer can see, rather than an inference from which literal
|
|
integer follows `process.exit(` in its outer `catch`.
|
|
|
|
**What changed (ADR-3889 Phase 7, #3911):**
|
|
|
|
- `hooks/lib/hook-exit.js` (hand-written) exposes `allow(payload)` → exit 0,
|
|
`deny(payload, stderrPayload?)` → exit 2, and `crash(onCrash, payload)`,
|
|
which dispatches to `allow`/`deny` per a `HOOK_ON_CRASH` policy the caller
|
|
must supply — `crash()` has no default policy, so a hook cannot fail open
|
|
by omission.
|
|
- Every one of the 19 enforcement hooks under `hooks/*.js` now declares
|
|
`const ON_CRASH = HOOK_ON_CRASH.ALLOW` (or `DENY`) once, with a
|
|
hook-specific comment naming why, and calls `crash(ON_CRASH, payload)` from
|
|
its outer catch instead of a bare `process.exit(0)` / `process.exit(2)`. No
|
|
hook's effective exit code changed — this is a naming-and-declaration
|
|
migration, not a behavior change.
|
|
- `hooks/lib/cli-exit.js` and `hooks/lib/exit-code-registry.js` are new,
|
|
generated, git-tracked copies of the exit-code seam (`src/cli-exit.cts` /
|
|
`msd-core/bin/shared/exit-codes.json`), so a shipped hook can terminate
|
|
correctly on a raw, unbuilt clone without depending on `msd-core/bin/lib/`
|
|
tsc output. Generated by `scripts/gen-hooks-cli-exit.cjs` and
|
|
`scripts/gen-exit-code-registry.cjs`, both `--check`ed by
|
|
`npm run lint:generated-sync`.
|
|
- `terminateNow` gained an optional third argument, `stderrPayload`, so a
|
|
deny can send a full JSON body to stdout and a distinct plain-text reason
|
|
to stderr — needed because `msd-write-guard.js` (a host's native hook bus
|
|
may read stderr verbatim back to the model) always sent only the bare reason
|
|
string on fd 2. The two streams are now written in independent try/catch
|
|
blocks: previously a payload that failed to serialize on fd 1 aborted
|
|
before fd 2 ever wrote, producing a deny with an empty stderr reason.
|
|
- Two hooks are deliberately **not** migrated to `deny()`:
|
|
`msd-read-injection-scanner.js` (PostToolUse — its harness reads the block
|
|
decision from the JSON response body, not the exit code) and
|
|
`msd-cursor-subagent-start.js` (follows Cursor's own `subagentStart`
|
|
protocol, which reads `permission: "deny"` from the JSON body at exit 0).
|
|
Both still use `allow()`/`crash()` for their no-op and crash paths.
|
|
- `msd-phase-boundary.sh`, `msd-session-state.sh`, and
|
|
`msd-validate-commit.sh` gained `set -euo pipefail`, and
|
|
`msd-validate-commit.sh`'s three swallow-and-pass sites (the opt-in config
|
|
read, JSON command extraction, and the `isGitSubcommand` classifier) now
|
|
distinguish a genuine negative from "could not run" — on the latter they
|
|
emit a stderr diagnostic and exit 0 instead of silently allowing every
|
|
commit (#3838).
|
|
|
|
See [Declare a hook's crash policy](../how-to/declare-a-hook-crash-policy.md)
|
|
for the full how-to, and
|
|
[ADR-3889](../adr/3889-process-exit-contract.md) for the exit-code registry
|
|
this vocabulary is layered over.
|