Description
Implement specialized content views for each built-in Claude Code tool. Each widget is an opinionated rendering for its tool's input and output, slotted into ToolCallCardView (D-15).
Spec: docs/architecture/dialogue-events.md §4 (tool widgets table); Epic #250 §6.
Scope
Files under MacApp/Packages/AgentChatUI/Sources/AgentChatUI/ToolCall/Widgets/:
Core widgets (must-have for MVP)
| Widget |
Tool names |
Content |
ReadWidget.swift |
Read, NotebookEdit (partial) |
path preview + line count; expanded — syntax-free monospaced content in BlockCodeContainer; binary → "{N} bytes binary". |
GrepWidget.swift |
Grep |
pattern + match count summary; expanded — grouped by file with line numbers and highlighted match spans. |
GlobWidget.swift |
Glob |
pattern + file count; expanded — file list, click → tries to open via system. |
LSWidget.swift |
LS |
dir + entry count; expanded — table (name / size / mtime / type). |
EditWidget.swift |
Edit, MultiEdit, Write |
path + ±N lines; expanded — inline unified diff (+ green, − red; monospaced). Syntax highlighting not in MVP. |
BashWidget.swift |
Bash, BashOutput, KillShell |
$ {command} pill; expanded — mini-terminal with stdout / stderr tabs + exit code + duration; run_in_background=true shows Abort button. ANSI color support via AnsiToAttributedString helper (minimal CSI subset). |
TaskWidget.swift |
Task (sub-agent) |
subagent_type + description; expanded — nested DialogueView bound to a sub-state slice (for forward compatibility with subagent routing from D-11). |
TodoWidget.swift |
TodoWrite |
"{done}/{total} · active: {activeForm}"; expanded — checklist with status pills (pending / in_progress / done) per item. |
WebFetchWidget.swift |
WebFetch |
URL pill; expanded — best-effort OG-preview (title / description / hero image via AsyncImage) + fetched content text. |
WebSearchWidget.swift |
WebSearch |
query + result count; expanded — list of title / url / snippet cards. |
SlashCommandWidget.swift |
SlashCommand, Skill |
command name; expanded — plain text output. |
GenericMCPWidget.swift |
mcp__<server>__<tool> |
"{server} / {tool}"; expanded — two tabs: Input JSON pretty-printed, Output JSON/text. |
GenericToolWidget.swift |
Any other tool name (Monitor / LSP / CronCreate / etc.) |
Tool name + collapsed raw input/output JSON. |
Dispatch
ToolCallCardContent(toolCall:) view — dispatches by toolCall.name (exact match for built-ins; prefix mcp__ for MCP; else Generic). Returns the right specialized view.
Common helpers
TruncatedText — display first 2KB / 40 lines + "Show full result" button (opens full content in modal or in Stream Inspector). For binary — summary.
AnsiToAttributedString — minimal SGR parser (8 basic colors + bold + dim); anything unknown → stripped.
DiffView — unified diff renderer for EditWidget; line-by-line AttributedString with color tint (no syntax highlight in MVP).
Constraints
- All widgets are pure views — no side effects, no async loads except
AsyncImage.
- No text selection / copy restrictions — all content should be copyable.
- A11y: every widget announces its tool name and status transitions.
Acceptance Criteria
Relationships
Description
Implement specialized content views for each built-in Claude Code tool. Each widget is an opinionated rendering for its tool's input and output, slotted into
ToolCallCardView(D-15).Spec: docs/architecture/dialogue-events.md §4 (tool widgets table); Epic #250 §6.
Scope
Files under
MacApp/Packages/AgentChatUI/Sources/AgentChatUI/ToolCall/Widgets/:Core widgets (must-have for MVP)
ReadWidget.swiftRead,NotebookEdit(partial)BlockCodeContainer; binary → "{N} bytes binary".GrepWidget.swiftGrepGlobWidget.swiftGlobLSWidget.swiftLSEditWidget.swiftEdit,MultiEdit,WriteBashWidget.swiftBash,BashOutput,KillShell$ {command}pill; expanded — mini-terminal with stdout / stderr tabs + exit code + duration;run_in_background=trueshows Abort button. ANSI color support viaAnsiToAttributedStringhelper (minimal CSI subset).TaskWidget.swiftTask(sub-agent)DialogueViewbound to a sub-state slice (for forward compatibility with subagent routing from D-11).TodoWidget.swiftTodoWriteWebFetchWidget.swiftWebFetchWebSearchWidget.swiftWebSearchSlashCommandWidget.swiftSlashCommand,SkillGenericMCPWidget.swiftmcp__<server>__<tool>GenericToolWidget.swiftDispatch
ToolCallCardContent(toolCall:)view — dispatches bytoolCall.name(exact match for built-ins; prefixmcp__for MCP; else Generic). Returns the right specialized view.Common helpers
TruncatedText— display first 2KB / 40 lines + "Show full result" button (opens full content in modal or in Stream Inspector). For binary — summary.AnsiToAttributedString— minimal SGR parser (8 basic colors + bold + dim); anything unknown → stripped.DiffView— unified diff renderer for EditWidget; line-by-line AttributedString with color tint (no syntax highlight in MVP).Constraints
AsyncImage.Acceptance Criteria
TruncatedTexttruncates large outputs with working "Show full".DiffViewrenders a realistic Edit example correctly (snapshot test).AnsiToAttributedStringhandles minimal CSI SGR; unknown sequences stripped safely.DialogueView(stubbed for MVP if child reducer not wired yet; verify slot works).Relationships