Skip to content

v0.4.0

Latest

Choose a tag to compare

@Finn763 Finn763 released this 26 Oct 13:51
· 1 commit to main since this release

v0.4.0

中文 →

The guardrail is launched by a wrapper, not by a .sh path

The hook command used to be bash "$CLAUDE_PROJECT_DIR/hooks/block-destructive.sh". That
literal has two failure modes on Windows and one on Unix. Claude Code prepends bash to any
hook command containing .sh, so the host could run bash bash ... and fail; and bash only
exists on PATH when Git Bash put it there, which is not the shell the host spawns. Either way
the PreToolUse guardrail did nothing and said nothing — the matrix stayed green because it
invoked the script itself, and CI's windows-latest job uses shell: bash, so it never
exercised the host's resolution step.

hooks/run-hook.cmd is a polyglot: cmd.exe reads the batch half, sh/bash reads the Unix half.
The batch half finds bash at C:\Program Files\Git\bin\bash.exe, C:\Program Files (x86)\...,
%LOCALAPPDATA%\Programs\Git\bin\bash.exe, then falls back to where.exe $PATH:bash called by
full path with $PATH: so neither where nor bash can come from the current directory,
skipping the WSL launchers in System32, Sysnative and WindowsApps that fail without a distro.
It propagates the hook's exit code from outside any parenthesised block, where %ERRORLEVEL%
would already have been expanded. The Unix half splits $0 on its last separator instead of
shelling out to dirname.

The hook itself lost its extension — hooks/block-destructive, since the name is what the host
scans. A missing bash warns on stderr and lets the call through: blocking every Bash call would
stop the session, but a guardrail that is silently absent is worse than one that says it is.
Five new cases in the matrix run the wrapper under sh, bash and cmd, on all three OS.

Run state outlives the context

The round counter, the findings ledger and the attempts ledger lived only in context, so a
compaction erased them: the run could hand itself free rounds past --max-rounds and re-fix
what it had already fixed. They now live in <target>/.pit-stop/run.md, written before the
first fix and appended every round, with fixed line shapes (STATUS:, - LEDGER, - ATTEMPT,
- ROUND). A resumed run reads STATUS: fix <N>, keeps the rounds already spent, never
re-fixes an open finding whose fixed twin exists, and never retries a revert approach.
A fresh instruction overwrites the ledger; only compaction or an explicit continue resumes.

The ledger ships its own .pit-stop/.gitignore containing *, so it never appears in
git status --porcelain and cannot drift into the review range. Consistency check 9 pins the
template shapes and the path the skill sends the agent to.

Version

v0.3.2 → v0.4.0 (9 adapter/package manifests synced).