Skip to content

Support stop_task over the interactive PTY transport - #3

Merged
bddppq merged 1 commit into
mainfrom
claude/pty-claude-code-cli-57917
Jun 15, 2026
Merged

bddppq merged 1 commit into
mainfrom
claude/pty-claude-code-cli-57917

Conversation

@bddppq

@bddppq bddppq commented Jun 15, 2026

Copy link
Copy Markdown
Owner

Summary

PtyCLITransport previously rejected stop_task with an "unsupported" control error. This implements it by reconstructing the live background-task set from the transcript and driving the CLI's /tasks dialog to stop the requested task.

What changed

  1. Task registry (_track_tasks, fed from _emit_line) — reconstructs live tasks with no side channel: a spawning tool_use (Bash run_in_background / Agent / Task / Workflow / Monitor) → the tool_result whose text carries the assigned task-id → a <task-notification> whose terminal status retires it. Keyed by task-id with the task's description (for dialog matching). This complements PR Hold the PTY turn open until spawned background tasks finish #2's existing turn-hold tracker (which keys _pending_tasks by tool-use id); both now share _BACKGROUND_TASK_TOOLS / _TASK_NOTIFICATION_RE / _TERMINAL_TASK_STATUSES.
  2. /tasks dialog driver (parse_tasks_dialog / task_row_matches in pty_question.py, _stop_task) — opens the dialog via the existing pyte screen, navigates to the row matching the target, and presses x.
  3. Safety guard — the kill keystroke is sent only when the parsed selected row uniquely and verbatim matches the target; ambiguous or no-match → error, never a wrong kill. Detection is gated on the dialog-specific x to kill / x to stop footer so ordinary output (even text mentioning "kill" with an "esc to interrupt" footer, or a markdown > blockquote) is never mistaken for the dialog. On success it confirms the task left the registry (errors otherwise); if /tasks never opens, no ESC is sent (won't interrupt a turn).

The dialog layout is an undocumented TUI contract — row identification is fixture-tested and flagged for re-verification against the bundled CLI; every failure mode degrades to a clear error rather than a wrong kill.

Tests

New TestTaskRegistry / TestStopTask (transport) and parse_tasks_dialog / task_row_matches / task_label_key cases (parser), including regressions for: dialog misdetection of ordinary output, sibling-command discrimination (npm run build:prod vs :staging), ambiguity refusal, esc-in-command rows, age-column stability, navigation to a non-initial row, unconfirmed-kill error, no-ESC-on-failure, and the task-id word boundary.

ruff check/format clean, mypy src/ clean. Relevant suites green; PR #2's TestBackgroundTaskHold still passes alongside the new tracker.

https://claude.ai/code/session_01RVo5bksX7e8McFKqGbbuDH


Generated by Claude Code

Implements stop_task(task_id) for PtyCLITransport (previously an
"unsupported" control error) by reconstructing the live background-task
set from the transcript and driving the CLI's /tasks dialog.

- Task registry (task_id -> description/status), fed from _emit_line:
  a spawning tool_use -> the tool_result whose text carries the task-id
  -> a <task-notification> whose terminal status retires it.
- /tasks dialog driver (parse_tasks_dialog / task_row_matches): open the
  dialog, navigate to the uniquely-matching selected row, press x.
- Safety: detection gated on the dialog's "x to kill"/"x to stop" footer
  so ordinary output is never mistaken for it; the kill keystroke fires
  only on a unique verbatim match of the selected row (ambiguous/no-match
  -> error, never a wrong kill); confirms termination; no ESC when the
  dialog never opened (won't interrupt a turn).

The dialog layout is an undocumented TUI contract -- row identification
is fixture-tested and flagged for re-verification against the bundled CLI.

https://claude.ai/code/session_01RVo5bksX7e8McFKqGbbuDH
@bddppq
bddppq merged commit 90bc896 into main Jun 15, 2026
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.

2 participants