feat: add collapsible reasoning/tool-call blocks, code copy, and inline diff to TUI messages
Maintainers usually reply within 1 day
A pull request for this has already been merged.
- #1361 by @avoidwork — merged
Assessment
- Difficulty
- 5/5
- Estimated time
- Over a week
- Newbie friendliness
- 12/100
- Issue type
- Feature
- Clarity
- Mostly clear
- Activity status
- Stale
- Tech stack
- javascript
- Domain
- cli
Research direction
Start in src/tui/messageBubble.js, where MessageBubbleInner handles reasoning segments (seg.type === "reasoning"), and read the tool-call rendering next to it. The [copy] affordance belongs in the component layer, reusing clipboardy from src/tui/app.js. Tests for the collapse toggles and diff rendering are also needed. This is a multi-feature design task with an open pull request (#1361) and a split recommendation, so confirm scope with the maintainers before starting.
Written by the indexing model from the issue text.
Description
Summary
Add four TUI message-rendering enhancements: collapsible reasoning blocks, collapsible tool-call blocks, code-block copy with syntax highlighting, and an inline diff view for file changes.
Motivation
The TUI currently renders reasoning, tool calls, code blocks, and file changes as flat, non-interactive text. This makes long reasoning chains and tool outputs hard to scan, and prevents users from copying code or reviewing file diffs inline. These enhancements make the message stream more navigable and actionable.
Proposed Solution
- Reasoning collapse/expand — Add a toggle to collapse a reasoning block to a single '💭 Thinking…' line, expandable on demand. The segment structure in
src/tui/messageBubble.jsalready distinguishes reasoning from message. - Collapsible tool-call blocks — Show tool name + args collapsed, expandable to the full result. Tool-call data already flows through the conversation stream.
- Code-block copy + syntax highlighting — Add a
[copy]affordance on fenced code blocks usingclipboardy(already imported insrc/tui/app.js), plus light syntax highlighting insrc/tui/markdownText.js. - Inline diff view for file changes — Render file edits as green/red diff lines in a collapsible block, pairing with the existing file/process tooling.
Alternatives Considered
- Using a full markdown renderer with built-in syntax highlighting — rejected as too heavy for the TUI's lightweight rendering.
- Rendering diffs as separate panes — rejected in favor of inline collapsible blocks that keep the message stream coherent.
Dependencies
- clipboardy (already imported in
src/tui/app.js) — used for the code-block copy affordance. - Syntax highlighting — to be determined during implementation; a lightweight highlighter (e.g.,
highlight.jsor a minimal custom tokenizer) may be added.Unknown — user to confirmfor the specific package.
Testing Strategy
- Unit tests: Verify reasoning/tool-call collapse/expand toggles, code-block copy handler, syntax highlighting output, and diff line rendering.
- Integration test: Render a message stream with reasoning, tool calls, code blocks, and file changes; verify each renders and toggles correctly.
- Edge cases: Empty reasoning block, very long tool results, code blocks with no language, diffs with no changes.
Security Considerations
- Credential storage: No new credentials introduced; clipboardy operates on the local clipboard only.
- Input validation: Validate rendered content before injecting into the DOM to prevent XSS from model output.
- OWASP: Sanitize any HTML rendered from markdown/code content; avoid injecting raw model output.
OpenSpec Note
This project uses OpenSpec for feature development. If this request is approved, I will:
- Run
/opsx:proposeto generate a full proposal with specs and tasks - Iterate on the design before any code is written
- Follow the task-driven implementation workflow
Split Recommendation
This issue bundles multiple distinct capabilities. Consider splitting into separate issues:
- Reasoning collapse/expand — Self-contained toggle on existing reasoning segments; lowest dependency.
- Collapsible tool-call blocks — Independent of reasoning; touches tool-call rendering.
- Code-block copy + syntax highlighting — Two sub-features (copy + highlighting) that could be split further.
- Inline diff view for file changes — Depends on file/process tooling; separate rendering concern.
MVP recommendation: Start with reasoning collapse/expand as it has the least dependencies and highest immediate value.
Additional Context
Split out from issue #1339.
Audit Findings (for Issue #1359)
- src/tui/messageBubble.js —
MessageBubbleInneralready distinguishes reasoning segments (seg.type === "reasoning", ~line 340) and renders them as gray text withmarginLeft: 2. No collapse/expand toggle exists. Tool calls render as flat text viatoolCallEl(active),toolDisplayEl(result), andcompletedToolCallsEl(count map). This is the primary integration point for items 1 and 2 — adduseStatecollapse state and a toggle handler here. - src/tui/markdownText.js — Syntax highlighting already exists via
cli-highlight(highlightCli) in thecode({ text, lang })renderer method (~line 155). So item 3's highlighting is largely done; only the[copy]affordance is missing.MarkdownTextis a pure renderer with no clipboard access — the copy handler must live in the component layer. - src/tui/app.js —
clipboardyis imported at line 17 and used at line 462 for selection copy. This is the existing copy mechanism to reuse for the[copy]affordance on code blocks. - src/tui/conversationArea.js — Reasoning segments are created at lines 668-716. Tool-call data flows through the conversation stream via
events(line 650-652),toolCallDisplay,activeToolCall, andcompletedToolCalls. Theeventsarray carries raw stream events including tool calls — the source for collapsible tool-call blocks. - src/tui/messageList.js — Passes
activeToolCall,toolCallDisplay,completedToolCalls,events, andshowToolResultstoMessageBubble(~line 592). No changes needed here beyond possibly forwarding new props. - Diff view (item 4) — No existing diff rendering. File/process tooling lives in
src/tools/process/index.jsandsrc/tools/code/index.js. A newdiffsegment type or file-change event renderer is needed.
Fix Steps
- Reasoning collapse/expand — In
src/tui/messageBubble.js, add auseStatetoggle (e.g.,collapsed) toMessageBubbleInner. Whenseg.type === "reasoning", render a single💭 Thinking…line when collapsed, and the full gray content when expanded. Add a click/keyboard handler to toggle. - Collapsible tool-call blocks — In
src/tui/messageBubble.js, wraptoolCallEl/toolDisplayElin a collapsible block. Show tool name + args collapsed, expandable to the full result. Source data fromevents/toolCallDisplay/completedToolCallsflowing fromconversationArea.js. - Code-block copy + syntax highlighting — Syntax highlighting already exists via
cli-highlightinsrc/tui/markdownText.js. Add a[copy]affordance on fenced code blocks. SinceMarkdownTextis a pure renderer, add the copy handler in the component layer (messageBubble.js) or pass a copy callback, reusingclipboardyfromsrc/tui/app.js. - Inline diff view — Add a diff renderer (green/red lines) in a collapsible block. Pair with file/process tooling in
src/tools/process/index.jsandsrc/tools/code/index.js. Add adiffsegment type or render file-change events. - Write tests — Add unit tests for collapse/expand toggles, the copy handler, and diff rendering.
- Verify — Run
npm run test,npm run lint, andnpm run coverageto confirm no regressions.
- Dominant language
- JavaScript
- Stars
- 2
- Forks
- 0
- Avg merge
- 1h 15m
- Merged PRs (30d)
- 237
Getting set up
- Ships a Dockerfile or Docker Compose file
- Has a pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from avoidwork/madz
-
feat: add dedicated subagent view to TUIPossibly taken @avoidwork claimed this today. Openapproved feature in progress
Difficulty 4/5 3-5 days Newbie friendliness 22/100
avoidwork/madz#1360 · 1 comment ·
Maintainers usually reply within 1 day
-
feature
Difficulty 4/5 3-5 days Newbie friendliness 22/100
avoidwork/madz#1358 · 1 comment ·
Maintainers usually reply within 1 day
-
feature
Difficulty 5/5 Over a week Newbie friendliness 15/100
avoidwork/madz#1355 · 1 comment ·
Maintainers usually reply within 1 day
-
feature
Difficulty 5/5 Over a week Newbie friendliness 35/100
Maintainers usually reply within 1 day
Similar issues
-
Progress difficulty filter lists Hard before MediumPossibly taken @Pandamachi claimed this today. Open
Difficulty 2/5 1-3 hours Newbie friendliness 86/100
sysprog21/codetrial#281 · 1 comment ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 71/100
yjh051108/dsh-routing-suite#227 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
-
needs-triage release-watch
Difficulty 1/5 Under an hour Newbie friendliness 76/100
-
Difficulty 2/5 1-3 hours Newbie friendliness 66/100
remoteintech/remote-jobs#2271 ·
Maintainers usually reply within 1 day