fix(hooks): route rtk hook check through the real decision
`rtk hook check` called `registry::rewrite_command` directly, with no permission verdict and none of the gates the hooks apply. It therefore reported a rewrite for command substitutions, file redirects and heredocs that both hook paths refuse to touch -- the diagnostic disagreed with the thing it exists to diagnose, and did so in the direction that matters, by claiming RTK would rewrite a command it deliberately leaves alone. Route it through `hooks::decision` so it answers the same question, and report a deny rule distinctly from "no rewrite" rather than collapsing both into one message. Both still exit 1. That makes the answer agent-dependent, so `--agent` stops being discarded. `AgentPath` records what actually differs between agents, which is whose permission rules their hook consults: the six that decide in-process via `rtk hook <agent>` use their own host's rules, the five whose plugin shells out to `rtk rewrite` get Claude's (that entry point cannot be told who is asking), and the six that install only a rules file have no hook and so no rules at all. Every install target resolves -- including `codex` and `openclaw`, which are install flags rather than `AgentTarget` variants -- and only a genuine typo is rejected. What does *not* differ is a rewrite that changed nothing: every agent discards it, the in-process hosts in `hook_cmd` and the others in their own plugin, since `hooks/opencode/rtk.ts`, `hooks/pi/rtk.ts` (shared with omp) and hermes' `__init__.py` all gate on `rewritten != command`. `AgentPath` suppresses it for every variant. Only the bare `rtk rewrite` CLI reports the no-op, and no agent consumes that answer raw. Consulting no rules and ignoring `--agent` is what made the diagnostic contradict every host: under a Claude deny rule for `git status` it reported `rtk git status` while `rtk hook claude` refused the command outright; it reported a rewrite for `rtk git status`, which no agent applies; and since `--agent` selected nothing, the answer described no host in particular. The expectations pinned in the characterization commit are updated here, in the same commit, so the behavior change is visible as a diff rather than as a test that quietly stopped asserting. That harness now also asserts the hook exits 0 and never panics: a crash produces empty stdout, which would let every "expect no output" assertion pass vacuously. The agent list is derived from `AgentTarget::value_variants()` so a new variant fails the test instead of silently becoming unanswerable. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
N
Nicolas Le Cam committed
6eb915bf6f2c7b13c95e188b57c654eabeb17158
Parent: d6ce8f7