Files
OthmanAdi f118ab5025 feat: answer Claude Code hook events in one Python process
hooks/claude-hook.sh answered every event by running resolve-plan-dir.sh
and inject-plan.sh, about 130 forks per UserPromptSubmit. Under Git Bash
on Windows a fork costs about 90 ms, so a prompt took 7 to 12 s against
the 10 s hook timeout and Claude Code discarded the plan context, and
PreToolUse added 5 s before every tool call. Measured on the reporting
machine: 8.1, 10.2 and 7.1 s per prompt before, 0.33 s after.

scripts/inject-plan.py is a byte-identical twin of inject-plan.sh plus
the dispatcher logic of claude-hook.sh. The launcher finds a CPython 3
with a fork-free PATH walk, runs the twin with -I -B and falls back to
the shell chain on any non-zero exit; PWF_FAST_PATH=0 forces the shell
chain; a directory without planning state exits before any fork. The
launcher hands the twin its own $PWD spelling so both routes share one
turn-marker and one progress-guard slot per plan. skill-hook.sh uses the
twin after eligibility and isolates its own two interpreter calls. Both
dispatchers run the json_string awk under LC_ALL=C so a character outside
the BMP no longer leaves as a lone surrogate on Windows. The twin ships in
every scripts directory that ships inject-plan.sh.

tests/test_inject_plan_python_parity.py runs both implementations over
the same fixtures and asserts identical stdout, including what the
second-model review found and this commit fixes: NUL bytes in
.active_plan, the awk "phases: /N" quirk for a plan with no completed
phase, the CRLF progress tail under Git for Windows sed, cache slots
shared across routes, and non-BMP characters through the JSON encoder.
2026-09-07 09:37:36 +02:00
..
2026-04-29 14:44:20 +08:00