Skip to content

fix(mac): richer tool panels, settled tool status, markdown blocks, composer polish - #16

Merged
SergeSerb2 merged 2 commits into
mainfrom
sergecode/mac-app-ux-fixes
Jul 5, 2026
Merged

fix(mac): richer tool panels, settled tool status, markdown blocks, composer polish#16
SergeSerb2 merged 2 commits into
mainfrom
sergecode/mac-app-ux-fixes

Conversation

@SergeSerb2

Copy link
Copy Markdown
Owner

Five chat-surface fixes for the native macOS app.

Tool-call panels are now visual

  • Wire itemType flows through ActivityRowsTimelineItem.toolEvent(kind:).
  • New ParsedToolDetail parser (T3Kit) turns server detail strings into structure: Edit/Write/MultiEdit: {json} → file path + old/new strings, Bash: cmd → command line.
  • File-change rows expand into a real diff body: path header with +/− counts, colored added/removed lines (capped at 60 — the Diff inspector remains the full view).
  • Command rows show the command inline (collapsed) and monospaced (expanded); rows gain per-kind glyphs (terminal / pencil / globe / wrench / …).
  • Truncated detail JSON (server caps at 400 chars) degrades to plain text, never a garbage command line.

Stuck "pending" command rows

  • upsertTimelineItem now folds uncorrelated completion events into their running row across interleaved reasoning rows (previously only when strictly adjacent — anything in between left the row spinning forever).
  • Rows still marked running render as settled once the thread stops (idle/archived → check, error → x), mirroring the web client's turn-settled indicator rule for providers that never close a tool's lifecycle.

Assistant text formatting

  • SwiftUI Text ignores PresentationIntent, so full-markdown parsing collapsed paragraphs/headings/lists into one blob.
  • Prose is now split into block-level pieces (paragraphs, headings, bullet/ordered lists, quotes, rules), each rendered as its own view with inline-only markdown per block.
  • Position-keyed ForEach ids (content hashes collide on repeated blocks); blocks parsed once per view value, not per body evaluation.

Composer spacing + placeholder

  • Composer gets 16pt side margins and 14pt bottom clearance instead of touching window edges; timeline gains matching horizontal padding.
  • Placeholder overlay aligns with the NSTextView text origin (was 8pt low).

Verification

  • swift build clean; 103 tests pass (11 new: ToolDetailParsingTests, updated ActivityRowTests).
  • Mock-mode app launch clean.
  • Pre-commit Opus diff review: 4 findings (duplicate block ids, per-token re-parse, per-frame JSON parse, truncated-command rendering) — all fixed; tool-event arity migration and Swift 6 isolation verified clean.

🤖 Generated with Claude Code

…omposer polish

Five chat-surface fixes:

- Tool rows now carry the wire itemType through ActivityRows into
  TimelineItem.toolEvent(kind:). Rows show a kind glyph plus an inline
  preview (the command, the file path), and the disclosure body renders
  structure: a real diff (path header, +/- counted colored lines) for
  file changes parsed from Edit/Write/MultiEdit detail JSON, a clean
  command line for shell runs. New ParsedToolDetail parser in T3Kit
  degrades truncated/unrecognized detail to plain text.

- Stuck "pending" tool rows: upsertTimelineItem folds uncorrelated
  completions into a running row across interleaved reasoning rows
  (previously only when adjacent), and rows still marked running render
  as done once the thread settles (idle/archived -> check, error -> x),
  mirroring the web client's turn-settled rule.

- Assistant text no longer renders as a blob: SwiftUI Text ignores
  PresentationIntent, so prose is now split into block-level pieces
  (paragraphs, headings, bullet/ordered lists, quotes, rules) each laid
  out as its own view with inline-only markdown per block.

- Composer gets breathing room from the window edges and bottom;
  timeline gains matching horizontal padding.

- Composer placeholder aligns with the typed-text origin (NSTextView
  has no top inset) instead of sitting 8pt low.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@github-actions github-actions Bot added size:XL Release-system, architecture, or ecosystem-scale change vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. labels Jul 5, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6668d67e3f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread apps/mac/Sources/SergeCodeMac/UI/Chat/ChatTimelineRow.swift Outdated
Comment thread apps/mac/Sources/SergeCodeMac/Model/Entities.swift Outdated
Comment thread apps/mac/Sources/T3Kit/ToolDetailParsing.swift
Comment thread apps/mac/Sources/T3Kit/ToolDetailParsing.swift
- Settled fallback no longer claims success: a row still running when the
  thread stops (which includes interrupted/stopped turns folded into idle)
  now renders a neutral outline check in secondary tint instead of the
  green success fill; error threads get the same neutral mark rather than
  a fabricated failure.

- Completion coalescing is bounded to the current turn: the backward
  search folding uncorrelated completions into a running row stops at a
  user message or checkpoint, so a same-name/same-detail invocation in a
  later turn can no longer merge into a stale stuck row.

- Diff parsing is gated by item type: fileChange conversion requires
  itemType == "file_change" (or a known edit tool name when no item type
  arrived), and command extraction requires command_execution — an MCP
  tool whose input happens to contain path/content or command fields
  stays plain text.

- File edits and commands parse from the untruncated payload.data
  ({toolName, input} passes through ingestion verbatim) instead of the
  ~180-char-truncated payload.detail, so real-world edits actually get
  the diff body instead of falling back to a clipped blob.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@github-actions github-actions Bot added size:XXL and removed size:XL Release-system, architecture, or ecosystem-scale change labels Jul 5, 2026
@SergeSerb2
SergeSerb2 merged commit cd1cdc0 into main Jul 5, 2026
11 of 15 checks passed
SergeSerb2 added a commit that referenced this pull request Jul 5, 2026
Main's tool-row rework (PR #16) already ships a richer header preview
(kind-aware font, parse cache, middle truncation), so its version wins
and this branch's simpler detailPreview is dropped. Scroll logic keeps
this branch's phase-gated pinning; the changeToken signature it
replaced is removed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant