Skip to content

Enhance context filtering and response handling with refactors - #3

Merged
DanielZhangReal merged 8 commits into
mainfrom
feat/stop-hook
Apr 17, 2026
Merged

DanielZhangReal merged 8 commits into
mainfrom
feat/stop-hook

Conversation

@DanielZhangReal

Copy link
Copy Markdown
Collaborator

No description provided.

DanielZhangReal and others added 8 commits April 17, 2026 20:36
Previous hardcoded list missed <local-command-stdout> (seen in actual
user sessions) and would miss any future tag Claude Code adds. Switch
to a pattern match for (local-)command-* and system-* so the filter
keeps working without manual additions.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Simpler than the previous pattern (command-* / system-* etc.) and
more robust to future Claude Code tag additions. Inner text is kept
so context previews still show what the user actually typed, minus
the plumbing wrappers.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Closes a race: if the user responded locally (typed new prompt, ESC'd
with transcript growth, etc.) between our last check_local_response
and ch.poll() returning a callback, we'd previously return the channel
decision and overwrite the local action.

Now we re-check immediately after the poll returns an update. If
local activity is detected, return "local" instead of the callback
data — the message resolves as "🖥️ Handled locally" on TG.

Applied to poll_callback, poll_question_answer, and the Stop hook.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- test: 2 new tests exercise the TOCTOU fix (210 total) — verify that
  poll_callback and poll_question_answer return "local" when transcript
  grows between the local-response check and ch.poll returning a callback
- CLAUDE.md Known Issues: new entry #8 documenting that ESC in Claude
  Code sends SIGKILL to pending hooks, which we can't catch — so TG
  buttons linger until the next hook runs or the user resolves on TG

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Match the concision of the other entries in the list.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Multi-line user input used to wrap awkwardly in the channel context
block. Collapse all whitespace (newlines, tabs, repeated spaces) to
single spaces so each context turn renders as one clean line. Also
applies the same collapse to assistant turns (previously we took the
first line only — same net effect but simpler code path).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Previously: Continue clicked → clear buttons → transition to "Waiting
for instruction..." → send_reply_prompt. If the prompt send failed
(transient API error), original buttons were already gone and no
prompt existed to reply to — user stuck until timeout.

Now send_reply_prompt runs FIRST. On failure the original Continue /
Dismiss buttons stay intact so the user can retry or dismiss. Only
commit to the "Waiting" transition when the prompt actually lands.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Both notification.py and stop.py previously hardcoded max_turns=1
for idle context, ignoring the configured context_turns (default 3).
Now they read from cfg — same knob affects every hook, which is what
the documented contract already suggested.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@DanielZhangReal
DanielZhangReal merged commit bbded6a into main Apr 17, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant