Repository navigation
fix(hooks): dispatch wrapped hook payloads without rendering - #641
Open
vishnujayvel wants to merge 1 commit into
Open
vishnujayvel wants to merge 1 commit into
vishnujayvel wants to merge 1 commit into
Conversation
When a configured statusLine command is wrapped (e.g. bash -c '...'), syncWidgetHooks() appends --hook outside the wrapper's quotes, so the inner ccstatusline never sees the flag. The hook JSON then arrives on the piped-stdin path and renders as status output. Detect supported hook envelopes (PreToolUse / UserPromptSubmit with a non-empty session_id) before StatusJSONSchema validation and route them through the existing handleHookInput, without rendering. Explicit --hook mode is unchanged. Refs sirmalloc#623 Co-Authored-By: Claude Sonnet 5 <[email protected]>
This was referenced Oct 7, 2026
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.
fix(hooks): dispatch wrapped hook payloads without rendering
Closes #623. Thanks to the reporter of #623 for the reproduction.
When a configured
statusLinecommand is wrapped (e.g.bash -c '...'),syncWidgetHooks()appends--hookoutside the wrapper's quotes, so the innerccstatuslinenever sees the flag. Its hook payload then arrives on the piped-stdin path and renders as status output instead of being recorded as a skill-usage event. This change detects supported hook envelopes on that path and dispatches them through the existing hook handler without rendering. Command construction is unchanged.Type: bug fix · Risk: low — only payloads with
hook_event_namePreToolUseorUserPromptSubmitand a non-emptysession_idare diverted; everything else takes the existing path.src/ccstatusline.tsisDispatchableHookPayload(); in piped-input handling, dispatches matching payloads viahandleHookInputand returns beforeStatusJSONSchemavalidationsrc/__tests__/ccstatusline-hook-dispatch.test.ts--hookregression, status rendering, non-dispatchableStop, and malformed JSONHow verified:
bun install --frozen-lockfile→ exit 0 (lockfile unchanged), darwin.bun test src/__tests__/ccstatusline-hook-dispatch.test.ts→ 6 pass, 0 fail, 17 expect() calls, 0 skipped on darwin.bun run lint, typecheck, build, and Windows (the file is skipped onwin32, so Windows is untested).Evidence & notes for reviewers
Root cause.
syncWidgetHooks()insrc/utils/hooks.tsbuilds the hook command as`${statusCommand} --hook`. For a wrapped command such asbash -c '<cmd> ccstatusline', the appended--hookbecomes an argument tobash, not to the wrappedccstatusline.StatusJSONSchemais a loose object with all fields optional, so the hook payload validates as status JSON and renders.Approach. Route the payload on its content, not on argv or the environment:
hook_event_namemust bePreToolUseorUserPromptSubmitandsession_ida non-empty string. The check runs beforeStatusJSONSchema.safeParse. The explicit--hookbranch is still checked first and is unchanged. No shell parsing, no new environment contract, and no change tosrc/utils/hooks.ts,src/utils/hook-handler.ts, orsrc/types/StatusJSON.ts.Alternatives not taken. Setting an env var such as
CCSTATUSLINE_HOOK=1in the hook command was rejected: it breakscmd.exe/PowerShell quoting and fails wrappers that clear the environment. Fixing command construction is a separate problem; open PR #502 touches construction but still appends--hookoutside the wrapper quotes, so it does not cover this payload path.Test design.
ccstatusline.tscallsvoid main()at module load (reads stdin, may launch the TUI), so the test spawns the real entry viabunand redirectsHOME/USERPROFILEto a temp dir per test. Assertions for dispatch check that the skill event is written to~/.cache/ccstatusline/skills/, not only that stdout is empty. The suite is skipped onwin32as a precaution: it runsbunviaexecFileSyncwithoutshell: true, and no Windows runtime was available to confirm that resolves the same way. This is not a claim that the fix is POSIX-only.Verification identity. Committed blobs:
src/ccstatusline.ts3dfe9c56, test file3eebecfd. The focused verification ran on the same staged content; the verification logs do not record file hashes, so identity rests on the files being unchanged since that run, which the packaging step did not modify.Logs. Verification logs and before/after resource records are in the local artifact directory for this candidate (
occ-5u5-verify-*), not attached to the PR.Out of scope. No
CURRENT_VERSIONor settings-migration bump, since theSettingsschema is untouched.🤖 Drafted with Claude Code (Claude Sonnet 5). The focused test run above was executed locally by the agent; the draft has not been reviewed by a human maintainer and has not been submitted.