Repository navigation
fix(hooks): only point widget hooks at ccstatusline's own command - #674
Open
eric-engberg wants to merge 1 commit into
Open
eric-engberg wants to merge 1 commit into
eric-engberg wants to merge 1 commit into
Conversation
Saving settings with a hook-enabled widget (Skills) syncs Claude Code hooks that run `<statusLine.command> --hook`. That happened whatever the status line command was. With ccstatusline configured but another tool installed as the status line (for example `bash ~/.claude/statusline.sh`), every ctrl+s or Save & Exit added PreToolUse(Skill) and UserPromptSubmit hooks running that script with `--hook`. The script then ran on every prompt and Skill call, and Claude Code adds UserPromptSubmit output to the conversation, so whatever it printed reached the model. Hooks are now added only when the status line command contains `ccstatusline`, the same test the legacy-hook cleanup already uses to recognize ccstatusline hook commands. npx/bunx with any version, a global or absolute-path binary, a local ccstatusline.ts checkout and shell-wrapped commands keep their hooks. For any other command the sync only removes ccstatusline-managed entries, which also cleans up hooks an earlier save pointed at another tool's script.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Saving settings no longer adds Claude Code hooks that run another tool's status line script. Widget hooks (the Skills widget's PreToolUse and UserPromptSubmit hooks) are only written when Claude's
statusLine.commandruns ccstatusline. Otherwise the sync only removes ccstatusline-managed hooks.Why
Every ctrl+s and Save & Exit syncs widget hooks into Claude's
settings.json, and each hook runs<statusLine.command> --hook. The sync never checked what that command was. With ccstatusline configured but another status line installed in Claude Code, saving a line that has the Skills widget turns this:{ "statusLine": { "type": "command", "command": "bash ~/.claude/statusline.sh" } }into this:
That script then runs on every prompt and every Skill call with an argument it doesn't know. Claude Code adds UserPromptSubmit output to the conversation, so whatever the script prints (usually a status line) reaches the model on each turn. #623 describes the same injection for a wrapped ccstatusline command; here it happens with a command that isn't ccstatusline at all.
How
syncWidgetHooksnow adds hooks only when the status line command containsccstatusline. That's the same test the existing cleanup uses to recognize ccstatusline hook commands (CCSTATUSLINE_HOOK_PATTERN), so every hook written can still be recognized as ours later.The check is deliberately looser than
isKnownCommand, which only accepts the exact commands the installer writes. These commands keep their hooks, as before:npx/bunxwith any version or none, such asbunx -y ccstatusline, which the README measures as faster per repaint than@latest;/Users/me/.bun/bin/ccstatusline);ccstatusline.tscheckout;bash -c 'head -1 | ccstatusline'.The last one is the case in #623. It still counts as ccstatusline's own, so this works alongside #641, which makes ccstatusline handle the hook payload when the wrapper drops
--hook.For any other command (or none), the sync takes the existing "no status line" path: it strips ccstatusline-managed and legacy ccstatusline hooks and writes nothing new. That also removes hooks an earlier save pointed at another tool's script. Hooks belonging to other tools are left alone, as before.
One side effect: a personal wrapper script that calls ccstatusline but doesn't have
ccstatuslinein its own command string no longer gets hooks. It can't be told apart from another tool's script, and running an unknown script on every prompt is the bug being fixed.Demo
Nothing visible changes in the TUI or the status line; only the hooks written to Claude's
settings.jsondiffer (shown above).Testing
New tests in
hooks.test.ts: withbash ~/.claude/statusline.shas the status line and the Skills widget, sync leaves only the non-ccstatusline hook and drops a managed entry pointing at the script. This test fails onmain. A shell-wrappedbash -c 'head -1 | ccstatusline'command still gets both hooks; this one passes onmaintoo and guards the wrapped case.bun test: 2784 pass, 0 fail.bun run lintpasses.Under Node 26.10.0 (Vitest):
hooks.test.ts7 pass (5 existing, 2 new). The full suite under Node gives 2609 of 2762 passing. The 153 failures are in the same 17 files that fail onmain, all from spying on Node built-ins.Built CLI under Bun 1.4.2 and Node 26.10.0: piped renders in plain and Powerline modes agree across runtimes and match
main. The TUI opens and exits cleanly under both.End to end, with the built TUI under Bun and Node, a scratch
HOMEandCLAUDE_CONFIG_DIR, and a Skills widget on the line, pressing ctrl+s:bash ~/.claude/statusline.shas the status line,mainwrites both hooks runningbash ~/.claude/statusline.sh --hook, and this branch writes none;npx -y ccstatusline@latestorbash -c 'head -1 | ccstatusline', this branch writes both hooks with that command plus--hook.In every run the other settings (
model) stayed intact.