Windows packaging: CRLF makes every packaged Workflow unrunnable, and fp-check's Stop hook deadlocks the session (#205's fix never merged)
Two packaging defects hit on Windows today, both in plugins whose skills worked well. Reporting them together because the fix for one is a one-line .gitattributes and the other is a reopen.
Environment: Claude Code on Windows 11, Git Bash, core.autocrlf=true (the Git for Windows default), marketplace at d1f1575.
1. Every packaged Workflow is unrunnable on Windows — CRLF
Workflow invocation is refused before the script runs:
script contains control characters that would be hidden in the approval dialog
It is not the caller's arguments. It is the plugin file: with core.autocrlf=true the checkout writes workflows/*.js with CRLF, and \r is a control character to the permission handler.
$ git ls-files --eol plugins/insecure-defaults/workflows/audit.js
i/lf w/crlf attr/ plugins/insecure-defaults/workflows/audit.js
$ python -c "d=open('audit.js','rb').read(); print(d.count(b'\r\n'))"
713
Confirmed on insecure-defaults:audit-pipeline and variant-analysis:variants. Both are unusable as shipped — variant-analysis had to be run by hand before the cause was found, and insecure-defaults only ran after copying the script and replacing \r\n with \n (content otherwise byte-identical, and it then completed normally: 11 agents, 1448 files, 6 candidates, all refuted).
Fix: add a .gitattributes at the repo root. The repo has none today.
*.js text eol=lf
*.mjs text eol=lf
Worth considering * text=auto eol=lf for anything else a permission handler or shebang might read.
2. fp-check's Stop hook deadlocks the session — and #205's fix never landed
The hook re-blocks the end of every turn until Claude Code's consecutive-block cap (9 here) trips and force-ends it. Once triggered, the session cannot end normally no matter what the agent says, and the repeated checklist reads as an agent failure rather than a plugin one.
Two causes:
(a) No stop_hook_active clause. The prompt has no rule releasing the turn after it has already blocked once, so it fires indefinitely. This is not covered by #205.
(b) Scope, which #205 already diagnosed — the prompt demands all 7 phases "for EVERY bug that was being verified", with no path for a user who asked to verify one finding out of a set. In my session the user asked for exactly one candidate (V2) out of 13 from a variant-analysis sweep; that verification was complete, with all 6 gates and a TRUE POSITIVE verdict, and the hook still blocked 9 times.
#205 was closed on the assumption that #188 would land, and #188 was closed unmerged (mergedAt: null). plugins/fp-check/hooks/hooks.json still carries the Stop block at HEAD, unchanged. So the fix that justified closing #205 is not in the tree.
Local workaround: delete the Stop block, keep SubagentStop. That lives in cache/ and is lost on the next plugin update.
Suggested fix, on top of what @GotenJBZ proposed in #190/#205:
- Return
{"ok": true}whenstop_hook_activeis set — a completeness gate should state its case once, not trap the session. - Skip when the conversation is not fp-check.
- Skip when work was delegated to subagents/workflows (they have their own per-agent checks).
- Check only the phases the path actually used (standard vs deep).
- Scope to the findings the user asked about, not to every candidate that appeared earlier in the conversation.
Rule 0 is the one that turns this from noisy into blocking.
The skills themselves were good, which is why the packaging is worth fixing: fp-check corrected an overstated impact claim twice in three rounds — including downgrading an alleged cross-tenant leak to same-tenant, and refuting an RSA-SHA1 finding by tracing that the value never reaches the accept/reject decision.
Source: trailofbits/skills