Migrate the run-recovery/watchdog escalation comments onto the structured
system-notice mechanism the successful-run-handoff notices already use.
- New recovery/stranded-notice.ts: per-family notice seeds (short body +
title + tone) for the no-live-execution-path / workspace-validation /
configuration-incomplete / execution-review-participant families, and
buildStrandedRecoveryEscalationNotice which assembles presentation
{kind: system_notice} plus metadata.sections (Recovery action key_value,
Recovery owner agent_link or board-escalation key_value, Next action,
Source run run_link, Failure code key_value).
- escalateStrandedAssignedIssue posts the structured notice instead of
appending the plain Recovery action/owner/Next action footer; plain
comment callers keep working via fallbackBody + cause-derived titles.
- Escalation dedupe still checks the legacy body marker for old comments
and relies on noticeMetadataReferencesRecoveryAction for new ones.
- heartbeat.ts builders replaced by the shared seeds; inline failure
fragments dropped from bodies (failure code now lives in metadata; raw
error text stays withheld from the thread).
- Shared row helpers extracted to recovery/notice-format.ts.
- Tests: unit coverage for every family seed + escalation notice shape +
metadata dedupe matcher; embedded-Postgres dedupe regressions updated to
assert the structured shape.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
System comments in the experimental chat shell now render as quiet centered
one-liners (tone icon + plain-English title + relative time + chevron) that
expand on click to the full markdown body and structured metadata sections,
instead of large gray paragraphs of raw recovery text.
- Thread presentation/metadata/createdAtIso through TaskChatMessageItem and
the comment adapter (system comments only).
- Fix authorKind ordering: authorType system now wins over a derivable
run->agent linkage, so recovery notices no longer render as agent bubbles.
- New pure classifier system-notice-humanizer.ts covering the recovery
families (claude_auth_required, configuration_incomplete, workspace
validation, no-live-execution-path with recovery-owner extraction) plus a
System update fallback with truncated first sentence.
- New TaskChatSystemNotice component; expanded state reuses the SystemNotice
metadata-section rows via a newly extracted SystemNoticeMetadataSections.
- Collapse is presentation-only; respects presentation.detailsDefaultOpen.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Chat-style task composers now keep unsent body text per task, matching the
default composer. Adds a shared ui/src/lib/composer-draft.ts (loadDraft /
saveDraft / clearDraft + DRAFT_DEBOUNCE_MS) and wires an optional draftKey
through TaskChatThread into TaskChatComposer: restore on mount/key change,
debounced save on change, explicit clear on successful send (so a
send-then-navigate within the debounce window can't resurrect the sent
message), and preserved draft on failed send.
Body text only — no attachments/mode/assignee, no server sync. The legacy
helper copies in CommentThread/IssueChatThread are intentionally left in place.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The human (blue --liveness-blue) chat bubble set text-white on its
container, but the message body renders through MarkdownBody, whose
Tailwind prose tokens (--tw-prose-body) win over the container color.
prose-invert only flips in dark mode, so light mode showed dark text
on blue while dark mode was already correct.
Add the existing paperclip-markdown-on-accent class (already used by
IssueChatThread for the same accent bubble) to the human-branch
MarkdownBody in TaskChatBubble and TaskChatDescriptionBubble. It maps
prose body/heading/etc. tokens to currentColor in both themes, so the
text follows the bubble's text-white. Agent/neutral bubbles unchanged.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Render the task identifier (e.g. ) in gray monospace between the
status glyph and the title in the breadcrumb bar. Threads an optional
identifier through Breadcrumb + breadcrumbsEqual, adds a CrumbIdentifier
helper to BreadcrumbBar (font-mono text-muted-foreground design tokens),
and wires issue?.identifier onto the task crumb in IssueDetail.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Expand button moves inside TaskChatStatusPill wrapping only the status
line (new onToggle prop); the interstitial row sits outside the hover/
click target
- Drop the Responding icon prepending the interstitial text (lead spacer
keeps column alignment)
- useHeldSelfTalk: a finished update now slides out of the 1lh viewport
after --motion-interstitial-dwell (~4s) with no successor, instead of
sitting until pushed out; same .tc-line-scroll transition, unmounts to
the reserved empty slot
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
useHeldSelfTalk reworked: a finished update stays visible, static and
truncate-ellipsized, until the next update supersedes it or the turn ends
(never fades). Swaps are paced by the new --motion-interstitial-dwell token
(4000ms; deliberately NOT zeroed under reduced motion — it is pacing, not
movement); rapid bursts collapse latest-wins via a queue of one. The
.tc-line-scroll slide now plays ONLY at swap moments (keyed remount); while
streaming, the tail-line offset applies with the transition disabled inline,
killing the per-wrap glide. Lab: responding-burst state + segmented replay
(blank-line-separated updates with gaps) to exercise dwell/swap.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A terminal run with no UI-linked reply comment fell into the unanchored
bucket and out.push(...unanchored) pinned its "Worked · Ns · N tools" row
under every new user bubble. Unanchored turns now interleave into the
backbone at meta.startedAt ?? createdAt (Infinity → tail when no meta yet);
anchored turns and live-turn-last ordering unchanged. 5 regression tests.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The interstitial row above the gerund status line is now permanently
reserved while a turn is live: text slides in/out of the always-mounted
1lh slot, so the layout above never jumps as messages appear/disappear.
On settle, a turn directly following its own agent's reply bubble
attaches to it (attachSettledTurns, after coalesceSettledTurns): the
"✓ Worked · …" summary renders appended to the bubble's timestamp line
— "2:34 PM · ✓ Worked · 38s · 2 tools" — still expandable to the tool
history. Bubble timestamps are always visible (hover-only reveal
removed). Turns without a reply bubble keep the standalone folded row.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Interstitial self-talk matches tool rows: text-xs wrapper + scoped
.tc-interstitial override (prose-sm sets its own font-size on
.paperclip-markdown, so the utility alone can't shrink it)
- tool-taxonomy: read family Book -> BookOpen, terminal SquareTerminal ->
Terminal, edit SquarePen -> Terminal (per the letter of the board ask;
the lucide link was pasted twice, flagged on the thread)
- Inline issue-reference status glyph in markdown bodies steps down
lg (20px) -> md (16px)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Mid-run agent messages are tagged interstitial by the transcript adapter and
render bubble-less/avatar-less in muted text; the run's posted reply keeps its
bubble. Settled history keeps the self-talk interleaved at its streamed
timestamp (deduped against posted comment bodies). New --motion-typewriter-*
tokens drive a CSS-only steps() clip reveal per streamed block, zeroed under
prefers-reduced-motion.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
While a run streams, the status line (whimsy/taxonomy gerund + elapsed +
tokens) is now the live turn's single visible row: TaskChatTurnItem gains
liveStatus, TaskChatTurn renders it as an expandable header (chevron, same
grammar as tool rows / the settled Worked line), and expanding nests the
chronological tool/thinking history via the existing .tc-turn-fold motion
with live append while open. On settle the header morphs in place into the
'Worked · …' summary, preserving expand state. Only tool/thinking/usage rows
nest (isNestableLiveChild); mid-run agent text, markers and interaction cards
stay in the thread. Retires the liveTurnFoldedIds window + tests.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Claude-Code whimsy pool trimmed to Brewing/Tinkering/Distilling/Deliberating
- analog-office pool drops Cataloguing/Carbon-copying/Archiving, adds Trimming,
Aligning, Combining, Whiteboarding, Diagramming, Sketching, Labeling, Sticky-noting
- Grep becomes its own informative family: Grepping + search-code icon (never whimsified)
- taxonomy icons: Search, Book, SquarePen, ChevronsLeftRightEllipsis, Network; MCP
tools now use the official MCP logo (McpIcon) instead of Plug
- Thinking/Responding statuses get Brain / MessageSquareReply glyphs in the live pill
- MDXEditor image chip: settings button removed, delete uses lucide X
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Adds ui/attachment.tsx (base-lyra registry port, @base-ui/react — the
current name of @base-ui-components/react) plus the shimmer /
scroll-fade-x / scrollbar-none utilities it expects. Composer chips get
kind icon, name, size, remove x, uploading/error states; file references
now ride as trailing [name](contentPath) lines appended at submit
(MDXEditor insertMarkdown collapses paragraph breaks, so no in-editor
insert), and an attached chip alone enables send. Posted bubbles fold
link-only reference lines back into the same chips (task-chat-attachments
extractor); prose-woven links keep their sentence. MarkdownEditor's
imperative insertMarkdown now focuses before inserting — it silently
no-oped on a never-focused editor.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Rich composer inside the v7 comp-bar chrome: @-mentions (wired through
TaskChatThread, previously dropped), data-driven /-command autocomplete via
EditorAutocompleteContext, rich lists, and inline pasted/dropped images at
the caret through the editor's image plugin -> issue attachments POST.
Non-image files keep the chip row; the round-13 object-URL thumbnail path
is superseded. Cmd/Ctrl+Enter posts natively; Shift+Tab mode-cycling is
captured on the wrapper ahead of Lexical. Motion-gate comment fix in
TaskChatStatusPill (doc said 100ms).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Live (unsettled) turns keep the most recent 3 activity rows visible; older
completed/failed tool rows and finished thinking blocks fold into an
expandable group. Each live row gets its own .tc-turn-fold wrapper so rows
entering the fold animate with the same --motion-turn-fold grid-rows motion
(zeroed under prefers-reduced-motion). In-flight tools, messages, and other
non-activity rows never fold and end the foldable prefix. Settled-turn
summary behavior unchanged.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
buildTurnSummary now dedupes tool_call entries by toolUseId (with the
parser's tool-${i} fallback) so the folded 'Worked · N tools' line matches
the expanded row count. Composer attachments carry an object-URL preview
created at attach time, rendered as a size-10 thumbnail in the chip and
revoked on clear/unmount.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
ACP emits tool_call (title "Terminal") → retitle-to-invocation → generic
tool_call_update lines that acpx fills with the literal "tool call". The
task-chat adapter replaced the whole tool item per update, so settled rows
degraded to "Tool call" + Wrench.
- transcript-adapter: merge updates instead of replacing; first real name is
the call's identity, a retitle becomes the mono target, generic names never
displace real ones (rows, status pill, tool_result upgrade path)
- tool-taxonomy: isGenericToolName() shared helper; classify multi-word ACP
titles by first word ("Read File" → read family)
- summarizeToolInput: ignore the { text, status } keys the log parser
synthesizes onto inputs
- acpx-engine emitRuntimeEvent: remember each call's first real title and
stamp it onto generic update lines so stored logs keep names durably
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Settled run turns now anchor after the run's last comment instead of
before its first, so the folded "Worked · …" line appears where the
live "Running…" pill sat — the pill reads as being replaced by the
summary in place.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- new shared tool-taxonomy.ts (family/icon/verb per raw ACP tool name,
mcp__ prefix collapse) used by the status pill, chat tool rows, and the
classic transcript's previously hardcoded Wrench sites
- deriveRunStatusLabel: tail tool_call now yields the taxonomy verb
("Searching", "Running a command") with "Tool · target" detail and
the raw toolName so the pill shows the family icon beside the pulse dot
- live status line: label/elapsed/detail/tokens share one baseline row
- TaskChatComposer: Shift+Enter posts, plain Enter inserts a newline
- tests: tool-taxonomy unit tests, deriveRunStatusLabel/toolDisplayName
tests, composer Enter-behavior tests updated
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The running/working status line now shows elapsed time directly to the
right of the label (was pushed to the far right edge) and renders it
with one decimal (24.3s) so the readout visibly moves. The pill ticks
itself every 100ms from the run's start timestamp (new startedAtMs on
TaskChatStatusItem), replacing the 1s whole-thread re-render tick in
TaskChatThread.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The Properties/Plan/Artifacts strip portaled into the pane header floated
its active underline ~6px above the header's border-b (list padding + the
bar's py-2). Move the bar's vertical padding onto the window-controls
cluster, stretch the portaled strip to the header's full height, and pin
the trigger underline to bottom-0 so it sits on the border line.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The header's Ask/Plan badge read as a task-global setting, but mode is a
per-request choice: with the redesign flag ON the badge is gone from the
issue header, and each agent reply's avatar row now shows the work mode
that was in effect when its run started, reconstructed from the activity
feed's workMode change history (issue.updated details + _previous).
Flag OFF is unchanged: the legacy header badge stays and the new
workModeChanges prop is ignored by IssueChatThread.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Revert the textless gradient capsule in TaskChatBubble to the legacy
Avatar + AgentIcon treatment: the adapter now maps the author agent's
assigned icon (agentMap icon) onto the message item, with an initials
fallback when no icon is set.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Flag-gated (enableTaskChatRedesign), flag OFF unchanged:
- Extra scrollbar: with the flag ON the page content used a fixed
calc(100dvh - 8rem) thread height inside the padded outer <main>
(overflow-auto), so main itself also scrolled. The IssueDetail root now
fills main exactly (h-full flex column) and the chain down to the thread
is flexed with min-h-0, so the thread's internal viewport is the only
scroll surface. TaskChatThread's dvh height token still applies on
mobile, where main has no fixed height (flex-basis falls back to it).
- Pane-tab underline: the portal into the pane header bar kept React
context but broke the DOM ancestry that Tailwind's
group-data-[orientation]/tabs selectors need, so the active-tab
underline never applied. A display:contents group/tabs wrapper inside
the portal restores it.
- Conditional tabs: Plan/Artifacts triggers render only when the issue
has a plan document/accepted decompositions or attachments (same query
keys as the tab bodies — shared cache). With neither, the header bar
shows a plain "Properties" title and the pane body is the plain
properties stack. Tabs are controlled with a fallback to Properties if
the selected tab's content disappears.
Verified on :3093 light+dark via Playwright: main scrollHeight ==
clientHeight (923/923) on //; underline opacity 1 on
active portaled tab; Properties|Plan on , all three on ,
title-only on ; portaled tab clicks switch content; flag-off run
scrolls the legacy page (4454px) with no redesign testids. ui tsc clean;
issue-properties/task-chat/IssueDetail/IssueChatThread tests pass (1
pre-existing TZ flake in IssueProperties monitor row, fails on base).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Flag-gated (enableTaskChatRedesign), flag OFF byte-identical:
- Properties | Plan | Artifacts tab strip portals from IssueProperties into
the pane's header bar (new slot left of the maximize/close controls).
- Center Chat/Activity/Related-work tab strip hidden — the thread is the page;
deep links that switched tabs stay on chat.
- Issue header (parent breadcrumb, title/badge block, plugin toolbars, load-
earlier button) renders INSIDE the thread scroll viewport, so it scrolls
away with the messages instead of staying pinned.
- --tc-thread-max-h reserve 21rem → 8rem: composer now sits ~26px above the
viewport bottom.
- New IssuePlanConfirmationActionBar: while a plan confirmation is pending,
its Confirm/Decline CTAs (with decline-reason flow) pin to a footer slot
below the pane's scroll area on the Plan tab.
Verified: ui tsc clean; motion gate (25 files) + token gates clean; 218 tests
across task-chat/pane/IssueDetail/IssueChatThread (1 pre-existing TZ flake in
IssueProperties monitor row, fails on base); Playwright on :3093 light+dark —
tabs in pane header, header scrolls away/returns, thread bottom 923/950, plan
bar pinned at pane bottom in footer slot, zero page errors; flag-off run shows
legacy tabs/pane title, 0 redesign testids.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- ExperimentalToggleCard for enableTaskChatRedesign in the task cluster
(after Task Plan Decomposition Panel, before Task Watchdogs), with
Experimental badge, footnote, and managed-key support
- feature-catalog copy synced to approved "Chat-Style Tasks" name +
description (key/tier/defaults unchanged)
- render + patch on/off/persist test following the Task Watchdogs pattern
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Flag-gated under enableTaskChatRedesign; flag-off byte-identical.
- TaskChatBubble: remove the tc-cursor caret from streaming message
bubbles (thinking-block caret and the blink token stay).
- PropertiesPanel (redesign variant): drop the "Properties" header
title that duplicated the tab label; header is now a right-aligned
maximize/close control row. Legacy flag-off header untouched.
- IssueDetail: flag-ON shell wrapper goes full-width and each
non-thread section re-centers itself at the 60rem cap, so the
thread's scroll viewport (which already centers its column) reaches
the properties pane; the chat tab extends under main's horizontal
padding so the scrollbar sits flush against the pane border
(gap 99-103px -> 0px light / 8px dark gutter, measured).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
All flag-gated behind enableTaskChatRedesign; flag OFF stays byte-identical.
- --tc-shell-max-w (60rem) token; IssueDetail wrapper + skeleton become
mx-auto w-full max-w-(--tc-shell-max-w) when the flag is on, and the
thread body + pinned composer caps switch to the same token
- interaction kind added to the task-chat model; TaskChatThread merges
interactions chronologically (same sort keys + same-run handoff shift
as buildIssueChatMessages) and renders them via TaskChatInteractionCard,
a v7-grammar wrapper over the shared IssueThreadInteractionCard
(expired confirmations demote to a marker row)
- useIssuePlanDocument hook (404 → null) shared by the Plan tab, which
now renders the plan document via MarkdownBody with a revision line
above the decompositions, and by the thread's Plan updated/created
marker
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Close the gaps between the flagged redesign and the accepted v7 prototype,
verified against the v7 artifact side-by-side and a REAL streaming agent run:
- Bubbles: human = --liveness-blue #2563eb (was bg-primary near-black) white
text right; agent comment = borderless gray --bubble-agent bubble (new token,
light+dark) with v7 header (capsule avatar · bold name · one capitalized
mode chip). Bubble bodies now render markdown via MarkdownBody (code chips,
links, mentions) instead of raw text.
- Composer: per-mode v7 placeholders ("Message {agent} — describe what you
want done…"), neutral focus-within ring, borderless + attach iconbtn,
full "Agent/Plan/Ask mode" label on the status-chip trigger, icon-only
32px ArrowUp send with hover scale.
- Full-page chat shell: with enableTaskChatRedesign ON, IssueDetail gates the
legacy title (compact single-line editor instead) / description / sub-tasks
table / plan decompositions / Documents (pinned plan) / Output / attachments
wall / workspace card / artifact chips — thread owns the center column,
bounded by new --tc-thread-max-h so TaskMessageScroller owns scrolling with
the composer pinned (scroll viewport = absolute inset-0; percentage heights
don't resolve against flex-sized block parents). Flag OFF proven legacy:
0 redesign testids, all legacy sections present.
- Tool rows (v7 flat grammar): [glyph · name · mono target · hover chevron ·
status]; transcript adapter now emits real tool names (toolDisplayName —
mcp__ collapse + capitalization, tool_result.toolName backfill), summarized
primary params (summarizeToolInput probes file_path/command/pattern/…),
clipped mono result detail, generic "Tool" fallback for legacy stored logs.
- Streaming states: shimmer (.shimmer-text-muted variant) on live Thinking…
header + flat pulse-dot statusline (running/working no longer card chrome);
thinking settles to "Thought for Ns" (ts-span derived) and arrives collapsed
in settled history; turn summary label + mono metrics per v7 runsum.
Verified: motion gate (24 files, seams), token gates, workspace tsc, 177 ui
tests incl. task-chat/PropertiesPanel/IssueChatThread/IssueDetail; live
streaming captured on a real claude_local run on the worktree instance
(:3093 scratch task) — thinking/text deltas, live statusline with elapsed,
auto-follow, and fold-to-summary on completion; flag-off isolation screenshot.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Auto-generated lockfile refresh after dependencies changed on master.
This PR only updates pnpm-lock.yaml.
Co-authored-by: lockfile-bot <lockfile-bot@users.noreply.github.com>