render typed tool cards and live session status from stream-json

The conversation pane now exploits the structured stream instead of
dumping tool input as JSON. ConversationController indexes tool_use by id
so a tool_result pairs back to its call and renders the Edit/Write diff or
is_error failure in place; per-tool bodies (Bash command+output, Read/Grep
file/query) reuse the shared renderers factored out of the permission
card. SessionStatus gains cost + contextWindow + rate-limit, read straight
off the init/result/rate_limit_event events, so the in-pane status line
reflects live state without the config probe.

Partial-message streaming is wired behind --include-partial-messages but
its event shape is unverified against the live binary and degrades to a
no-op if it differs — see T-184.

T-168.

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2026-05-30 13:44:19 +02:00
co-authored by Claude
parent f6b88f503f
commit c5e58733a2
14 changed files with 722 additions and 117 deletions
@@ -2278,3 +2278,5 @@ Refinement (2026-05-30, /whats-next): pulled into the T-167/T-168 batch and sequ
INSERT INTO ticket_history (ticket_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-167', 'status', 'backlog', 'in_progress', NULL, '2026-05-30 10:48:32', '2026-05-30 10:48:32', '2026-05-30 10:48:32', NULL, '229c9cb92eb8554dbba51ca65e1eeba9', 1) ON CONFLICT(hash) DO NOTHING;
INSERT INTO ticket_history (ticket_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-168', 'status', 'backlog', 'in_progress', NULL, '2026-05-30 10:48:32', '2026-05-30 10:48:32', '2026-05-30 10:48:32', NULL, '4469254d98eba45964ca51d5855e5014', 1) ON CONFLICT(hash) DO NOTHING;
INSERT INTO ticket_history (ticket_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-160', 'status', 'backlog', 'in_progress', NULL, '2026-05-30 10:48:32', '2026-05-30 10:48:32', '2026-05-30 10:48:32', NULL, 'e410b6f78d0e4d96bc37f3a351d72767', 1) ON CONFLICT(hash) DO NOTHING;
INSERT INTO ticket_history (ticket_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-160', 'status', 'in_progress', 'done', NULL, '2026-05-30 11:05:56', '2026-05-30 11:05:56', '2026-05-30 11:05:56', NULL, '0024103be5bf0ab0653b9dbe03c52f71', 1) ON CONFLICT(hash) DO NOTHING;
INSERT INTO ticket_history (ticket_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-167', 'status', 'in_progress', 'done', NULL, '2026-05-30 11:05:56', '2026-05-30 11:05:56', '2026-05-30 11:05:56', NULL, 'fee8b67a0ad9c7c1c7ec7d9f75f42bfc', 1) ON CONFLICT(hash) DO NOTHING;
+10
View File
@@ -2816,3 +2816,13 @@ Fix direction: give the in-pane context slot a flexible/bounded width in the sta
---
Refinement (2026-05-30, /whats-next): pulled into the T-167/T-168 batch and sequenced FIRST. T-168 adds live cost / permission-mode / context / rate-limit to this same in-pane status slot; the Flexible/marquee fix here must land before T-168 lengthens the line. After this fix, T-168 can safely add fields to the slot.', 'in_progress', 'medium', NULL, NULL, NULL, '2026-05-24 09:13:42', '2026-05-30 10:48:32', NULL, 'be801b09fd2aeb3a4bb71b782499f9a7', 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
INSERT INTO tickets (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-167', 'task', 'T-164', 'P1: session persistence + /clear + /resume on stream-json (--resume)', 'Move session lifecycle onto the stream-json model. New session: --session-id <uuid>; resume an existing one: --resume <id> (T-161 confirmed --session-id refuses an existing id). Re-implement the clide-owned commands on this model: /clear = new fresh session, /resume = picker then resume the picked id. Retire the tmux session lifecycle for Claude (kill/hasSession/reap, new-session -A) and the --session-id-in-use handling once the transport no longer uses tmux. Acceptance: restart resumes the primary''s session; /clear starts empty; /resume switches to a picked session; all without tmux; tests for the new/resume argv selection and the command flows. Supersedes the mechanics of T-156/T-161. Blocked by T-165. Amends D-41 (tmux persistence → --resume).', 'done', 'high', NULL, NULL, 'D-77', '2026-05-24 16:26:30', '2026-05-30 11:05:56', NULL, '8da00e6f4b27462157ed80d908b91a6b', 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
INSERT INTO tickets (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-160', 'bug', 'T-132', 'Status bar overflows instead of marquee-scrolling the in-pane slot', 'Observed via make run (2026-05-24): the bottom status bar shows a RenderFlex ''overflowed by 77 PIXELS'' stripe after the in-pane context line (opus 4.7 · default · 21k ctx · 10 skills); the ClideMarquee never engages.
Cause: StatusbarHost (lib/app.dart ~1143) lays items in a Row [left items..., Spacer(), right items...], each at INTRINSIC width with no Flexible. PaneContextStatusItem wraps its text in ConstrainedBox(maxWidth:360) + ClideMarquee, but because the text (~280px) is under 360 the slot takes content width, so the marquee''s viewport == its content and it never scrolls. T-154 appended ''· N skills'', lengthening the line enough that git-branch + context slot + right items exceed the bar width -> the Row overflows (~77px) instead of the slot shrinking + marquee scrolling.
Fix direction: give the in-pane context slot a flexible/bounded width in the status bar (e.g. wrap it in Flexible(fit: loose), or have the bar allot it a shrinkable share) so it yields width when the bar is tight and ClideMarquee scrolls within the allotted width. Verify the interaction with the Spacer and the right-aligned items (priority>=100), and reconsider the fixed maxWidth:360. Acceptance: at narrow widths the in-pane slot marquee-scrolls and the status bar never shows an overflow stripe; widget test at a constrained width. Introduced by T-150 (marquee) + T-154 (longer line).
---
Refinement (2026-05-30, /whats-next): pulled into the T-167/T-168 batch and sequenced FIRST. T-168 adds live cost / permission-mode / context / rate-limit to this same in-pane status slot; the Flexible/marquee fix here must land before T-168 lengthens the line. After this fix, T-168 can safely add fields to the slot.', 'done', 'medium', NULL, NULL, NULL, '2026-05-24 09:13:42', '2026-05-30 11:05:56', NULL, 'c9c1801d8523ed0af1aff7da39393a0c', 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
INSERT INTO tickets (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-184', 'task', 'T-164', 'Validate partial-message wire shape from --include-partial-messages against a live capture', 'T-168 follow-up. T-168 wired --include-partial-messages into the interactive stream-json session (stream_json_session.dart) and added a partial-streaming handler that ASSUMES claude emits incremental assistant events carrying partial:true sharing one message.id. That shape is UNVERIFIED: the 2.1.150 spike (docs/spikes/cc-stream-json-control-protocol-2.1.150.md) only documents non-partial assistant events (one per content block, no partial flag), and the flag''s --help says it ''only works with --print'' while clide runs the interactive control protocol (--input-format/--output-format stream-json, not --print). The handler degrades gracefully (unmatched shapes fall through to parseTranscriptChunk and are ignored — token streaming is inert but nothing breaks), and the T-168 fixtures are synthetic so they pass regardless of reality. Do: capture a real claude turn over the interactive stream-json transport with --include-partial-messages and record the actual partial event envelope (likely a stream_event content_block_delta, not assistant+partial:true). Then either (a) fix the handler in stream_json_session.dart::_onLine to match the real shape and add a fixture from the live capture, or (b) if the flag is a true no-op in the interactive (non-print) mode, drop --include-partial-messages from the argv and the dead partial-handler branch, and pin the finding in the spike doc. Either way, update the UNVERIFIED-WIRE-SHAPE comment in stream_json_session.dart and the spike. Acceptance: the partial path is validated against a live capture, the handler matches the real shape (or is removed), a fixture derived from the capture covers it, and the spike + code comment reflect the confirmed shape.', 'backlog', 'medium', NULL, NULL, 'D-77', '2026-05-30 11:42:53', '2026-05-30 11:42:53', NULL, '38dccbc403b8ac945bd2ad01d9ac1640', 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);