Repository navigation
feat: session transcript calm-surface redesign - #271
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
WalkthroughThis PR adds reusable UI primitives, refactors session transcript and decision surfaces, introduces goal strips and actions, updates tool rendering and runtime selection, adds runtime speed requests, and moves skill discovery into bounded filesystem scanners. ChangesSession UI and runtime interactions
Estimated code review effort: 5 (Critical) | ~120 minutes 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
React Doctor found no new issues. 🎉 Reviewed by React Doctor for commit |
There was a problem hiding this comment.
Actionable comments posted: 19
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
web/src/components/assistant-ui/session-composer.tsx (1)
59-74: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
onSteerPromptis declared and passed through but never used.
SessionComposerProps.onSteerPrompt(line 26) is passed bySessionThread(onSteerPrompt={onSteerPrompt}), butSessionComposer's destructuring at Line 59-74 never picks it up, and no Steer control exists in the busy-controls block (only Queue/Interrupt/Stop are rendered). The busy-input "Steer" action is silently non-functional even though its sibling handlers (onQueuePrompt,onInterruptPrompt) are fully wired.🐛 Suggested fix
export function SessionComposer({ composerState, contentInset, canPrompt, onCancelPrompt, onQueuePrompt, onInterruptPrompt, + onSteerPrompt, isBusyInputPending = false,…and add a Steer button alongside Queue/Interrupt using
handleBusyInputAction(onSteerPrompt, "Couldn't steer prompt."), mirroring the existing pattern.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@web/src/components/assistant-ui/session-composer.tsx` around lines 59 - 74, Wire the existing onSteerPrompt prop into SessionComposer by destructuring it and adding a Steer control in the busy-controls block alongside Queue and Interrupt. Invoke it through handleBusyInputAction with the error message "Couldn't steer prompt.", matching the existing sibling-handler pattern.web/src/components/assistant-ui/session-working-row.tsx (1)
56-67: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winReduced motion drops the elapsed-time information, not just the animation.
The motion branch surfaces "Working for Xs"; the reduced-motion branch shows only "Working…". Reduced-motion users lose a factual runtime signal rather than just the movement. Rendering the timer without the dots (and, if the 1s tick is the concern, at a coarser interval) preserves parity.
♿ Suggested change
<div role="status" aria-label="Working" data-testid="session-working-row" className="flex min-h-[22px] items-center gap-2 px-1 py-0.5 text-[11.5px] text-subtle" > - <span>Working…</span> + <span className="tabular-nums"> + {startedAt !== undefined ? ( + <> + Working for <WorkingTimer startedAt={startedAt} /> + </> + ) : ( + "Working…" + )} + </span> </div>🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@web/src/components/assistant-ui/session-working-row.tsx` around lines 56 - 67, Update the reducedMotion branch in SessionWorkingRow to retain the elapsed-time display shown by the animated branch, rendering “Working for Xs” without the animation dots. Preserve the existing reduced-motion layout and accessibility attributes; only adjust the displayed status and timer update behavior as needed.
🧹 Nitpick comments (20)
web/src/systems/session/components/thinking-block.tsx (2)
101-102: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueCustom comparator is now equivalent to the default. With
updateCountgone, the props are exactlythinkingandthinkingComplete, so plainmemo(...)gives the same behavior with less to maintain.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@web/src/systems/session/components/thinking-block.tsx` around lines 101 - 102, Remove the redundant custom comparator from the memoized thinking block component, identified by the comparator comparing prev.thinking and next.thinkingComplete. Use plain memo(...) now that the component only receives thinking and thinkingComplete props.
41-87: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueThe two trigger branches duplicate the same button contract.
Both branches share
type,data-testid,aria-expanded, and the sameonClick; only the inner content and classes differ. Extracting a single button with a conditional body would keep the two states from drifting (e.g. one branch gaining a handler the other lacks).🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@web/src/systems/session/components/thinking-block.tsx` around lines 41 - 87, The live and non-live branches in the thinking trigger duplicate the same button contract. Refactor the conditional around a single button element, keeping type, data-testid, aria-expanded, onClick, and shared structural behavior on that button; conditionally render the existing live or completed inner content and retain each state’s distinct classes.web/src/systems/session/components/__tests__/tool-call-card.test.tsx (1)
151-164: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valuePrefer the
data-status/aria-labelcontract over class-literal assertions.
getAttribute("class")).toContain("text-subtle")couples the suite to a Tailwind literal that any token rename breaks, while the row already exposesdata-statusand the accessible label as the real contract. If "no signal hue" must be gated, consider asserting the absence oftext-success/text-dangerinstead of the presence of a specific utility.As per coding guidelines, "Avoid CSS-literal, snapshot, generated, or prose tests unless they are the product contract and no stronger gate exists."
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@web/src/systems/session/components/__tests__/tool-call-card.test.tsx` around lines 151 - 164, Update the assertions in the running and success cases of the tool-call card tests to rely on the existing data-status and aria-label contract instead of asserting the text-subtle CSS class. If verifying the absence of a signal hue is necessary, assert that text-success and text-danger are not present while preserving the current status and accessible-label checks.Source: Coding guidelines
web/src/systems/session/components/__tests__/thinking-block.test.tsx (1)
81-96: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueAlignment test pins Tailwind literals rather than a behavioral invariant.
ml-[25px]/pl-[11px]will break on any rail retune even when the layout stays correct. If the 25px rail is the contract, consider expressing it as a token/utility class (or adata-*rail marker) that the test can assert stably.As per coding guidelines, "Avoid CSS-literal, snapshot, generated, or prose tests unless they are the product contract and no stronger gate exists."
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@web/src/systems/session/components/__tests__/thinking-block.test.tsx` around lines 81 - 96, Update the ThinkingBlock alignment test around the “Should align the reasoning body…” case to assert a stable rail token, utility class, or data attribute instead of the literal ml-[25px] and pl-[11px] Tailwind values. Add or reuse the corresponding semantic marker in ThinkingBlock so the test verifies the shared detail-rail alignment contract while retaining the existing border and visual-style assertions.Source: Coding guidelines
web/src/systems/session/components/session-resume-failure.tsx (1)
46-66: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueTwo copies of the same session-level danger banner. Both files hand-roll an identical shell (
border-danger/28 bg-danger/4, icon + bold title +text-[12px] text-mutedbody) with the same ad-hoc font size instead of a token, so any retune must be applied twice.
web/src/systems/session/components/session-resume-failure.tsx#L46-L66: extract the banner shell (icon, title, body slot) into a reusable component and replacetext-[12px]with the matching typography token.web/src/systems/session/components/goal/session-goal-header.tsx#L25-L39: render that shared banner instead of re-declaring the wrapper/icon/title/body markup.As per coding guidelines, "Use design tokens from
packages/ui/src/tokens.cssand generatedDESIGN.md".🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@web/src/systems/session/components/session-resume-failure.tsx` around lines 46 - 66, The session-level danger banner is duplicated and uses an ad-hoc body font size. In web/src/systems/session/components/session-resume-failure.tsx#L46-L66, extract the shared icon, title, and body banner shell into a reusable component and replace text-[12px] with the matching typography token from the design system; in web/src/systems/session/components/goal/session-goal-header.tsx#L25-L39, render that shared component instead of duplicating the wrapper markup.Source: Coding guidelines
web/src/systems/session/components/runtime-activity-notice.tsx (1)
214-219: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winUse
toneinstead ofdata-marker-tonefor the progress marker.
Markerexposesdata-tone={tone}and its icon styling is keyed onMarkerTone, whose union isneutral | danger | warning | info. The progress branch is leavingtoneat"neutral"while setting a non-contractdata-marker-tone="progress", so the glyph will render as neutral; pass a validtonevalue if this is meant to affect styling.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@web/src/systems/session/components/runtime-activity-notice.tsx` around lines 214 - 219, Update the progress Marker in the runtime activity notice to use its supported tone prop instead of data-marker-tone. Pass a valid MarkerTone value, such as info, so the marker and Activity icon receive the intended styling; leave the existing role, test ID, and icon unchanged.web/src/systems/runtime/components/runtime-selector/provider-chips.tsx (1)
62-70: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueHome/End rely on wrap-around instead of moving directly.
Homepasses the last chip and steps forward,Endpasses the first and steps back, so both depend on the modulo wrap to land on the intended edge. A direct edge move is easier to read and cannot break if wrapping ever changes.♻️ Optional: explicit edge focus
+ const focusChip = (target: RailFilter) => { + onRail(target); + groupRef.current + ?.querySelector<HTMLButtonElement>(`[data-rail="${CSS.escape(String(target))}"]`) + ?.focus(); + }; + const handleKeyDown = (event: KeyboardEvent<HTMLDivElement>) => { if (searching) return; if (event.key === "ArrowRight" || event.key === "ArrowDown") { event.preventDefault(); moveFocus(railFilter, 1); } else if (event.key === "ArrowLeft" || event.key === "ArrowUp") { event.preventDefault(); moveFocus(railFilter, -1); } else if (event.key === "Home") { event.preventDefault(); - const order = getChipOrder(providers); - moveFocus(order[order.length - 1] ?? railFilter, 1); + const order = getChipOrder(providers); + if (order[0] !== undefined) focusChip(order[0]); } else if (event.key === "End") { event.preventDefault(); - const order = getChipOrder(providers); - moveFocus(order[0] ?? railFilter, -1); + const order = getChipOrder(providers); + const last = order[order.length - 1]; + if (last !== undefined) focusChip(last); } };🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@web/src/systems/runtime/components/runtime-selector/provider-chips.tsx` around lines 62 - 70, Update the Home and End handlers in the provider-chips keyboard navigation logic to move directly to the corresponding edge: Home should focus the first chip and End should focus the last chip, using the appropriate non-wrapping direction or edge-focus behavior. Preserve the railFilter fallback when no providers exist.web/src/systems/runtime/components/runtime-selector/selector-footer.tsx (1)
26-34: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueTighten
modeto the reasoning-mode union.
mode: stringlets any value reachdata-reasoning-mode, which tests and CSS treat as a contract.♻️ Optional typing tweak
- mode: string; + mode: RuntimeReasoningState["mode"];🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@web/src/systems/runtime/components/runtime-selector/selector-footer.tsx` around lines 26 - 34, Update the FooterNote mode prop to use the existing reasoning-mode union type instead of string, ensuring only supported values reach data-reasoning-mode. Reuse the established union symbol from the surrounding runtime selector types and preserve the component’s existing behavior.web/src/components/assistant-ui/session-composer-queued-prompts.tsx (1)
15-98: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winNative
<button>s replace the sharedButtonprimitive.The Steer/Edit/Remove controls were previously built on
@compozy/ui'sButtonand are now hand-rolled<button>elements with a bespokeICON_BUTTON_CLASS, duplicating hover/focus/disabled treatment that the shared primitive already centralizes.♻️ Suggested direction
-import { CornerDownRight, ListPlus, Pencil, Trash2 } from "lucide-react"; +import { Button } from "`@compozy/ui`"; +import { CornerDownRight, ListPlus, Pencil, Trash2 } from "lucide-react";Then reintroduce
Button(with an icon-only size/variant if one doesn't already exist) for Edit/Remove/Steer instead of raw<button>+ manual class strings.As per coding guidelines, "Reuse primitives exported by
packages/ui/src/index.tsand import them from@compozy/ui; generic primitives belong inpackages/ui, while domain composites belong inweb/src/systems/<domain>/."🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@web/src/components/assistant-ui/session-composer-queued-prompts.tsx` around lines 15 - 98, The SessionComposerQueuedPrompts controls currently duplicate shared button styling with native buttons and ICON_BUTTON_CLASS. Reintroduce the Button primitive from `@compozy/ui` for the Steer, Edit, and Remove actions, using existing icon-only sizing and variants where available; remove the bespoke class-based button styling while preserving their labels, icons, disabled state, test IDs, and callbacks.Source: Coding guidelines
web/src/components/assistant-ui/session-message-parts.tsx (1)
21-27: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueStale name and dead
dataprop.The component no longer renders a card (it renders a one-line
Marker) anddatais now required-but-unread while both callers (session-timeline-render.tsxLine 69,session-user-message.tsxLine 22) still pass it. Renaming toSessionDataEventMarkerand droppingdatain the same change keeps the contract honest.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@web/src/components/assistant-ui/session-message-parts.tsx` around lines 21 - 27, The component name and props no longer match its marker-only implementation. Rename SessionDataEventCard to SessionDataEventMarker, remove the unused required data prop from its parameter type, and update both callers in the session timeline and user message components to use the renamed component without passing data.web/src/components/assistant-ui/__tests__/session-timeline.logic.test.ts (1)
650-658: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAdd coverage for the turn-boundary split of marker clusters.
deriveBaseRowssplits marker clusters on either akindchange or aturnIdchange (session-timeline.logic.tsLine 271), but only the kind-change branch is exercised. A same-kind pair across two turns is a cheap extra case.♻️ Suggested extra test
it("Should split marker clusters when the kind changes", () => { const rows = deriveSessionRows([ markerEvent("m1", "provider-retry"), markerEvent("m2", "compaction"), ]); expect(rows).toHaveLength(2); expect(rows.map(row => (row.kind === "data" ? row.count : row.kind))).toEqual([1, 1]); }); + + it("Should split same-kind markers that belong to different turns", () => { + const first = markerEvent("m1", "provider-retry"); + const second = { ...markerEvent("m2", "provider-retry"), turnId: "turn-2" }; + const rows = deriveSessionRows([first, second]); + + expect(rows).toHaveLength(2); + expect(rows.map(row => (row.kind === "data" ? row.count : row.kind))).toEqual([1, 1]); + });🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@web/src/components/assistant-ui/__tests__/session-timeline.logic.test.ts` around lines 650 - 658, Add a test alongside the existing “Should split marker clusters when the kind changes” case that passes two same-kind marker events with different turnId values to deriveSessionRows, then assert they produce two separate single-item rows. This should exercise the turnId-change boundary in deriveBaseRows while preserving the existing kind-change coverage.web/src/components/assistant-ui/session-timeline-render.tsx (1)
122-172: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winOne disclosure grammar, three copies. The summary row, the changed-files roll-up, and the turn fold each hand-roll the same button shell plus rotating chevron; the shared root cause is that no disclosure component owns this shape, so the calm-surface grammar now has to be kept in sync by hand.
web/src/components/assistant-ui/session-timeline-render.tsx#L122-L172: extract the button shell + chevron into a localTranscriptDisclosure(props:expanded,onToggle,icon,label,trailing) and use it forSessionWorkSummaryRowandSessionTurnFoldRowView.web/src/components/assistant-ui/session-changed-files-row.tsx#L63-L107: replace the inline button/chevron markup with the sameTranscriptDisclosure, keepingDiffStatas thetrailingslot.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@web/src/components/assistant-ui/session-timeline-render.tsx` around lines 122 - 172, The disclosure button and rotating chevron are duplicated across three transcript surfaces. In web/src/components/assistant-ui/session-timeline-render.tsx:122-172, add a local TranscriptDisclosure component accepting expanded, onToggle, icon, label, and trailing, then use it in SessionWorkSummaryRow and SessionTurnFoldRowView; in web/src/components/assistant-ui/session-changed-files-row.tsx:63-107, replace the inline disclosure markup with TranscriptDisclosure while passing DiffStat as trailing.web/src/components/assistant-ui/session-changed-files-row.tsx (1)
63-107: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚖️ Poor tradeoffAd-hoc typography and spacing literals instead of design tokens. These rows introduce a new family of hand-picked values (
text-[11.5px],text-[13.5px],text-[12px],gap-[7px],min-h-[22px],ml-[25px],pl-[11px],size-[18px]) rather than tokens; the shared root cause is that the calm-surface transcript scale was never added topackages/ui/src/tokens.css. As per coding guidelines, "Use design values frompackages/ui/src/tokens.cssandDESIGN.md; do not invent colors, typography, radius, spacing, or motion values."
web/src/components/assistant-ui/session-changed-files-row.tsx#L63-L107: replace thetext-[11px]/text-[11.5px]/gap-[7px]/ml-[25px]/pl-[11px]literals with the transcript scale tokens.web/src/components/assistant-ui/session-timeline-render.tsx#L103-L172: replace thetext-[11.5px],text-[12px],gap-[7px],size-[18px],ml-[25px]literals with the same tokens.web/src/components/assistant-ui/session-working-row.tsx#L62-L83: replacetext-[11.5px],min-h-[22px],gap-[3px]with tokens.web/src/components/assistant-ui/session-user-message.tsx#L51-L74: replacetext-[13.5px],text-[11px],py-[7px]with tokens, and alignUSER_CLAMP_MAX_PXwith themax-h-44token rather than two parallel constants.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@web/src/components/assistant-ui/session-changed-files-row.tsx` around lines 63 - 107, Replace the ad-hoc typography and spacing values with shared calm-surface transcript tokens, adding the missing scale to packages/ui/src/tokens.css as needed. In web/src/components/assistant-ui/session-changed-files-row.tsx lines 63-107, update the ChangedFiles row layout; in web/src/components/assistant-ui/session-timeline-render.tsx lines 103-172, update the timeline row styles; and in web/src/components/assistant-ui/session-working-row.tsx lines 62-83, update the working row styles. In web/src/components/assistant-ui/session-user-message.tsx lines 51-74, replace the listed text and padding literals and align USER_CLAMP_MAX_PX with the max-h-44 token.Source: Coding guidelines
web/src/components/assistant-ui/session-working-row.tsx (1)
34-38: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winReuse
TypingDotsinstead of forking the dot animation here.
TypingDotsis still exported from@compozy/ui, but this component renders three working dots with local.session-working-dotstyling and custom delay delays. Use the shared primitive, or extendTypingDotswith the required styling/delay props instead of duplicating the pattern.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@web/src/components/assistant-ui/session-working-row.tsx` around lines 34 - 38, Replace the locally defined WORKING_DOT_DELAYS and duplicated working-dot rendering in the session working row with the exported TypingDots component from `@compozy/ui`. Reuse TypingDots directly, or extend it with the required styling and animation-delay props so the existing appearance is preserved without local dot-animation logic.Source: Coding guidelines
web/src/systems/session/lib/pending-permissions.ts (2)
33-49: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick winRecomputed over the whole transcript on every render.
SessionDecisionDockcalls this unmemoized (session-decision-dock.tsxLine 33), so every render walks all messages and all parts. On a long live-tailing transcript this is avoidable work; wrap the call inuseMemokeyed onmessagesat the call site.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@web/src/systems/session/lib/pending-permissions.ts` around lines 33 - 49, The derivePendingPermissions call in SessionDecisionDock should be memoized with useMemo, using messages as its dependency so permission derivation only reruns when the transcript changes. Keep derivePendingPermissions unchanged and update the call site in SessionDecisionDock.
66-82: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueDuplicated subject derivation.
permissionReceiptSubjectinweb/src/systems/session/components/permission-data-part.tsx(Lines 22-29) repeats the command→resource branches verbatim, differing only by omitting the JSON fallback. Extract a shared helper with a flag/variant so the two stay in sync.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@web/src/systems/session/lib/pending-permissions.ts` around lines 66 - 82, Extract the duplicated command→resource subject derivation from permissionSubject and permissionReceiptSubject into a shared helper, supporting the JSON fallback only where needed. Update both functions to use this helper so their subject-selection logic remains synchronized.web/src/systems/session/hooks/use-session-goal-header.ts (1)
31-39: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueFourth positional parameter forces
undefinedplaceholders at call sites.
useSessionGoalHeader(WORKSPACE_ID, SESSION_ID, undefined, { stream: false })(seeweb/src/systems/session/components/__tests__/session-goal-header.test.tsxLine 118) shows the cost. FoldingonPrefillComposerinto the options object keeps the signature stable as more flags appear.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@web/src/systems/session/hooks/use-session-goal-header.ts` around lines 31 - 39, Update the useSessionGoalHeader hook signature to move onPrefillComposer into the existing options object, alongside stream, and adjust all call sites and related tests to pass it by name without undefined positional placeholders. Preserve the current callback behavior and stream option semantics.web/src/systems/session/components/goal/session-goal-strip.tsx (1)
119-128: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winScope
aria-liveto the status facts, not the whole disclosure.The section wraps both the trigger and the expandable body, so every expand/collapse announces the full body (contract, run, context, node rows) as a live update. Move
aria-live="polite"onto the facts span (Line 149-154) so only the changing state text is announced.♻️ Proposed change
aria-label="Goal status" - aria-live="polite" data-testid="session-goal-strip"<span data-testid="goal-strip-facts" + aria-live="polite" className="shrink-0 font-mono text-badge text-subtle tabular-nums" >🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@web/src/systems/session/components/goal/session-goal-strip.tsx` around lines 119 - 128, Move aria-live="polite" from the section element to the facts span around the status text (the span near lines 149-154). Keep the section’s existing data attributes and disclosure structure unchanged so only changing status facts are announced, not expandable content.web/src/systems/session/components/__tests__/session-decision-dock.test.tsx (1)
154-155: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winReplace the arbitrary
setTimeout(10)waits with a deterministic flush.Both negative assertions (Lines 154-155 and 181-182) rely on a 10 ms sleep, which is flaky on loaded CI and adds real wall time. Awaiting a microtask flush (
await Promise.resolve()) or anawait waitForon an observable post-condition is deterministic.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@web/src/systems/session/components/__tests__/session-decision-dock.test.tsx` around lines 154 - 155, Replace the arbitrary 10 ms setTimeout waits in the negative assertion cases with deterministic synchronization, such as awaiting Promise.resolve() or waitFor on an observable post-condition. Update both assertion blocks involving approveSession while preserving their existing not.toHaveBeenCalled expectations.web/src/systems/session/components/__tests__/session-goal-strip.test.tsx (1)
128-141: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winOnly the
draftaffordance is covered; thereplacebranch is untested.
prefillCommand's replace path builds/goal replace <expectedRunId> <objective>— a format regression there silently stages a wrong command. Add a case asserting the replace string and the "Draft replacement" label.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@web/src/systems/session/components/__tests__/session-goal-strip.test.tsx` around lines 128 - 141, The session goal strip tests only cover the draft affordance; add a test for the replace branch in SessionGoalStrip. Render with a replace composerAffordance containing an expectedRunId and objective, assert the button is labeled “Draft replacement,” and verify clicking it calls onPrefillComposer with `/goal replace <expectedRunId> <objective>`.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/ui/src/components/custom/__tests__/tool-call-row.test.tsx`:
- Around line 91-106: Update the “Should render the per-file diff stat slot
between text and trailing glyphs” test to provide preview content and locate the
preview, stat slot, and trailing status glyph in the rendered DOM. Assert their
document order is preview before stat before status glyph, while retaining the
existing stat text assertion.
- Around line 8-13: Update the status tone assertions driven by GLYPH_STATUSES
to inspect the element returned by statusGlyph(container) for each status,
rather than using the aggregate classesOf helper on the whole container;
preserve the existing expected tone values.
In `@packages/ui/src/components/custom/choice.tsx`:
- Around line 108-116: Add colocated stories demonstrating the new public
primitives: create a Choice story for
packages/ui/src/components/custom/choice.tsx:108-116, a Dock story for
packages/ui/src/components/custom/dock.tsx:183-197, a Marker story for
packages/ui/src/components/custom/marker.tsx:78-78, and a Receipt story for
packages/ui/src/components/custom/receipt.tsx:64-64. Use each component’s
existing story conventions and keep the current exports and tests intact.
- Around line 13-105: Update ChoiceList, ChoiceRow, ChoiceKey, ChoiceHint,
ChoiceFree, ChoiceFreeTextarea, and ChoiceFreeBar in
packages/ui/src/components/custom/choice.tsx (lines 13-105) to use
React.forwardRef with refs matching each wrapped DOM element, while preserving
intrinsic props, className merging, and prop spreading. Apply the same
forwarded-ref wrapper contract to DockRoot and its DOM-backed subcomponents in
packages/ui/src/components/custom/dock.tsx (lines 18-181), Marker and MarkerMeta
in packages/ui/src/components/custom/marker.tsx (lines 30-76), and the Receipt
root in packages/ui/src/components/custom/receipt.tsx (lines 29-62); no other
behavior should change.
In `@web/src/components/assistant-ui/timeline-row-estimates.ts`:
- Around line 49-51: Update the changed-files branch in the row estimate logic
to use the shared exported CHANGED_FILES_VISIBLE_CAP, matching
SessionChangedFilesRowView’s maximum of eight visible files plus one “+N more”
line when additional files exist. Replace the full row.files.length-based
calculation while preserving the collapsed estimate and normal behavior for
collections within the cap.
In `@web/src/styles.css`:
- Around line 65-79: Update the gradient in .session-shimmer to replace the
hardcoded rgba(246, 246, 248, 0.9) highlight with the existing design-token
variable that best matches the intended shine color, using tokens defined in
packages/ui/src/tokens.css.
In `@web/src/systems/runtime/components/runtime-selector/model-row.tsx`:
- Around line 126-146: Update the favorite indicator styling in the model-row
component so the unfavorited star is visible for coarse pointers without
changing its current desktop hover/highlight behavior. Adjust the conditional
opacity classes in the `data-favorite-indicator` span while preserving its
existing click handling and 24px hit target.
In `@web/src/systems/session/components/clarification-dock.tsx`:
- Around line 62-77: Update the ChoiceRow key in the dock.choices.map rendering
within the clarification dock to use the choice index instead of the
server-supplied choice label, preserving the existing row behavior and
rendering.
In `@web/src/systems/session/components/permission-dock.tsx`:
- Around line 129-138: Add disabled={isSubmitting} to the reject-always button
in the permission decision menu, alongside the existing decision buttons, so
repeated clicks cannot trigger another submission while the current decision is
in flight.
- Around line 158-160: Update the isSubmitting branch in the permission dock to
pass an explicit live-region role to Dock.Status: use role="status" for normal
submissions and role="alert" when the submitting state represents a retryable
danger status, reusing the existing danger-state condition.
In `@web/src/systems/session/components/session-decision-dock.tsx`:
- Around line 22-38: Update the session decision dock’s clarifications query
handling around useSessionClarifications to explicitly render a quiet
Dock.Status error state when clarifications.error is present, while preserving
the existing pending clarification and permission rendering for successful
responses.
In `@web/src/systems/session/components/session-resume-failure.tsx`:
- Around line 36-44: Scope the Escape handling in handleEscape so the
session-resume failure banner only dismisses when the event has not already been
handled by another UI control, preserving Escape behavior for dialogs, popovers,
and the runtime selector. Keep the existing document listener lifecycle
unchanged.
In `@web/src/systems/session/components/thinking-block.tsx`:
- Around line 88-98: Update the expanded thinking-content div in the thinking
block to be keyboard focusable and accessible, adding an appropriate tabindex
and accessible label while preserving its existing scrolling behavior and
styling.
In `@web/src/systems/session/components/tool-call-card.tsx`:
- Around line 65-85: Update previewFor to always return a non-empty preview for
failed tool calls, including failures where toolResult.error is absent. For Bash
failures, prefer the first line of stderr and otherwise fall back to stderr; for
other failed tools, use available stderr before the generic "Tool call failed"
message, while preserving the existing error and success-summary behavior.
In `@web/src/systems/session/components/tool-renderers/bash-content.tsx`:
- Around line 36-39: Update the bash content renderer’s errorText handling
alongside output and stderr: apply clampLines to result.error before rendering,
include its line count in totalLines, and ensure overflow reflects combined
output, stderr, and error lines so the “Show full output” count and truncation
behavior are accurate.
In `@web/src/systems/session/components/tool-renderers/generic-content.tsx`:
- Around line 28-41: Update GenericContent’s hasResult check to recognize every
non-empty field covered by toolResultIsEmpty, including preview, artifacts,
stderr, filePath, and structuredPatch, while preserving the existing stdout,
content, and error checks. Ensure GenericContent renders formatResult(result)
whenever tool-call-card.tsx mounts the expanded body via hasOutput, preventing
blank expanded content.
In `@web/src/systems/session/components/tool-renderers/todo-content.tsx`:
- Around line 71-87: Update the todo list rendering in the todos.map callback to
use a unique, stable key for each item instead of item.content alone, preventing
collisions when multiple todos share the same text. Prefer an existing unique
todo identifier or the item’s stable position if no identifier is available;
leave the displayed content unchanged.
In `@web/src/systems/session/hooks/use-permission-dock.ts`:
- Around line 61-70: Complete the reject split menu dismissal and keyboard
behavior: in web/src/systems/session/hooks/use-permission-dock.ts lines 61-70,
register touchstart alongside mousedown and add a menuOpen-gated keydown
listener that closes on Escape; in
web/src/systems/session/components/permission-dock.tsx lines 123-140, move focus
to the menuitem when opening and restore focus to the trigger when closing,
preserving the existing menu/menuitem roles.
In `@web/src/systems/session/lib/pending-permissions.ts`:
- Around line 60-62: Update the supported-decision filtering logic near
FALLBACK_PERMISSION_DECISIONS so an explicitly advertised, non-empty set with no
recognized canonical decisions returns an empty list rather than all fallback
decisions. Preserve the fallback-to-all behavior only when
permission.supportedDecisions is absent or empty, ensuring the UI never renders
decisions unsupported by the runtime.
---
Outside diff comments:
In `@web/src/components/assistant-ui/session-composer.tsx`:
- Around line 59-74: Wire the existing onSteerPrompt prop into SessionComposer
by destructuring it and adding a Steer control in the busy-controls block
alongside Queue and Interrupt. Invoke it through handleBusyInputAction with the
error message "Couldn't steer prompt.", matching the existing sibling-handler
pattern.
In `@web/src/components/assistant-ui/session-working-row.tsx`:
- Around line 56-67: Update the reducedMotion branch in SessionWorkingRow to
retain the elapsed-time display shown by the animated branch, rendering “Working
for Xs” without the animation dots. Preserve the existing reduced-motion layout
and accessibility attributes; only adjust the displayed status and timer update
behavior as needed.
---
Nitpick comments:
In `@web/src/components/assistant-ui/__tests__/session-timeline.logic.test.ts`:
- Around line 650-658: Add a test alongside the existing “Should split marker
clusters when the kind changes” case that passes two same-kind marker events
with different turnId values to deriveSessionRows, then assert they produce two
separate single-item rows. This should exercise the turnId-change boundary in
deriveBaseRows while preserving the existing kind-change coverage.
In `@web/src/components/assistant-ui/session-changed-files-row.tsx`:
- Around line 63-107: Replace the ad-hoc typography and spacing values with
shared calm-surface transcript tokens, adding the missing scale to
packages/ui/src/tokens.css as needed. In
web/src/components/assistant-ui/session-changed-files-row.tsx lines 63-107,
update the ChangedFiles row layout; in
web/src/components/assistant-ui/session-timeline-render.tsx lines 103-172,
update the timeline row styles; and in
web/src/components/assistant-ui/session-working-row.tsx lines 62-83, update the
working row styles. In web/src/components/assistant-ui/session-user-message.tsx
lines 51-74, replace the listed text and padding literals and align
USER_CLAMP_MAX_PX with the max-h-44 token.
In `@web/src/components/assistant-ui/session-composer-queued-prompts.tsx`:
- Around line 15-98: The SessionComposerQueuedPrompts controls currently
duplicate shared button styling with native buttons and ICON_BUTTON_CLASS.
Reintroduce the Button primitive from `@compozy/ui` for the Steer, Edit, and
Remove actions, using existing icon-only sizing and variants where available;
remove the bespoke class-based button styling while preserving their labels,
icons, disabled state, test IDs, and callbacks.
In `@web/src/components/assistant-ui/session-message-parts.tsx`:
- Around line 21-27: The component name and props no longer match its
marker-only implementation. Rename SessionDataEventCard to
SessionDataEventMarker, remove the unused required data prop from its parameter
type, and update both callers in the session timeline and user message
components to use the renamed component without passing data.
In `@web/src/components/assistant-ui/session-timeline-render.tsx`:
- Around line 122-172: The disclosure button and rotating chevron are duplicated
across three transcript surfaces. In
web/src/components/assistant-ui/session-timeline-render.tsx:122-172, add a local
TranscriptDisclosure component accepting expanded, onToggle, icon, label, and
trailing, then use it in SessionWorkSummaryRow and SessionTurnFoldRowView; in
web/src/components/assistant-ui/session-changed-files-row.tsx:63-107, replace
the inline disclosure markup with TranscriptDisclosure while passing DiffStat as
trailing.
In `@web/src/components/assistant-ui/session-working-row.tsx`:
- Around line 34-38: Replace the locally defined WORKING_DOT_DELAYS and
duplicated working-dot rendering in the session working row with the exported
TypingDots component from `@compozy/ui`. Reuse TypingDots directly, or extend it
with the required styling and animation-delay props so the existing appearance
is preserved without local dot-animation logic.
In `@web/src/systems/runtime/components/runtime-selector/provider-chips.tsx`:
- Around line 62-70: Update the Home and End handlers in the provider-chips
keyboard navigation logic to move directly to the corresponding edge: Home
should focus the first chip and End should focus the last chip, using the
appropriate non-wrapping direction or edge-focus behavior. Preserve the
railFilter fallback when no providers exist.
In `@web/src/systems/runtime/components/runtime-selector/selector-footer.tsx`:
- Around line 26-34: Update the FooterNote mode prop to use the existing
reasoning-mode union type instead of string, ensuring only supported values
reach data-reasoning-mode. Reuse the established union symbol from the
surrounding runtime selector types and preserve the component’s existing
behavior.
In `@web/src/systems/session/components/__tests__/session-decision-dock.test.tsx`:
- Around line 154-155: Replace the arbitrary 10 ms setTimeout waits in the
negative assertion cases with deterministic synchronization, such as awaiting
Promise.resolve() or waitFor on an observable post-condition. Update both
assertion blocks involving approveSession while preserving their existing
not.toHaveBeenCalled expectations.
In `@web/src/systems/session/components/__tests__/session-goal-strip.test.tsx`:
- Around line 128-141: The session goal strip tests only cover the draft
affordance; add a test for the replace branch in SessionGoalStrip. Render with a
replace composerAffordance containing an expectedRunId and objective, assert the
button is labeled “Draft replacement,” and verify clicking it calls
onPrefillComposer with `/goal replace <expectedRunId> <objective>`.
In `@web/src/systems/session/components/__tests__/thinking-block.test.tsx`:
- Around line 81-96: Update the ThinkingBlock alignment test around the “Should
align the reasoning body…” case to assert a stable rail token, utility class, or
data attribute instead of the literal ml-[25px] and pl-[11px] Tailwind values.
Add or reuse the corresponding semantic marker in ThinkingBlock so the test
verifies the shared detail-rail alignment contract while retaining the existing
border and visual-style assertions.
In `@web/src/systems/session/components/__tests__/tool-call-card.test.tsx`:
- Around line 151-164: Update the assertions in the running and success cases of
the tool-call card tests to rely on the existing data-status and aria-label
contract instead of asserting the text-subtle CSS class. If verifying the
absence of a signal hue is necessary, assert that text-success and text-danger
are not present while preserving the current status and accessible-label checks.
In `@web/src/systems/session/components/goal/session-goal-strip.tsx`:
- Around line 119-128: Move aria-live="polite" from the section element to the
facts span around the status text (the span near lines 149-154). Keep the
section’s existing data attributes and disclosure structure unchanged so only
changing status facts are announced, not expandable content.
In `@web/src/systems/session/components/runtime-activity-notice.tsx`:
- Around line 214-219: Update the progress Marker in the runtime activity notice
to use its supported tone prop instead of data-marker-tone. Pass a valid
MarkerTone value, such as info, so the marker and Activity icon receive the
intended styling; leave the existing role, test ID, and icon unchanged.
In `@web/src/systems/session/components/session-resume-failure.tsx`:
- Around line 46-66: The session-level danger banner is duplicated and uses an
ad-hoc body font size. In
web/src/systems/session/components/session-resume-failure.tsx#L46-L66, extract
the shared icon, title, and body banner shell into a reusable component and
replace text-[12px] with the matching typography token from the design system;
in web/src/systems/session/components/goal/session-goal-header.tsx#L25-L39,
render that shared component instead of duplicating the wrapper markup.
In `@web/src/systems/session/components/thinking-block.tsx`:
- Around line 101-102: Remove the redundant custom comparator from the memoized
thinking block component, identified by the comparator comparing prev.thinking
and next.thinkingComplete. Use plain memo(...) now that the component only
receives thinking and thinkingComplete props.
- Around line 41-87: The live and non-live branches in the thinking trigger
duplicate the same button contract. Refactor the conditional around a single
button element, keeping type, data-testid, aria-expanded, onClick, and shared
structural behavior on that button; conditionally render the existing live or
completed inner content and retain each state’s distinct classes.
In `@web/src/systems/session/hooks/use-session-goal-header.ts`:
- Around line 31-39: Update the useSessionGoalHeader hook signature to move
onPrefillComposer into the existing options object, alongside stream, and adjust
all call sites and related tests to pass it by name without undefined positional
placeholders. Preserve the current callback behavior and stream option
semantics.
In `@web/src/systems/session/lib/pending-permissions.ts`:
- Around line 33-49: The derivePendingPermissions call in SessionDecisionDock
should be memoized with useMemo, using messages as its dependency so permission
derivation only reruns when the transcript changes. Keep
derivePendingPermissions unchanged and update the call site in
SessionDecisionDock.
- Around line 66-82: Extract the duplicated command→resource subject derivation
from permissionSubject and permissionReceiptSubject into a shared helper,
supporting the JSON fallback only where needed. Update both functions to use
this helper so their subject-selection logic remains synchronized.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: 0cddedbb-5563-429b-936b-2b6d2127dd83
⛔ Files ignored due to path filters (32)
.codex/hooks.jsonis excluded by!**/*.jsonDESIGN.mdis excluded by!**/*.mddocs/design/opendesign/session/SESSION-REDESIGN-SPEC.mdis excluded by!docs/design/**/*,!**/*.mddocs/design/opendesign/session/_vc-capture-fast.htmlis excluded by!docs/design/**/*docs/design/opendesign/session/_vc-capture-normal.htmlis excluded by!docs/design/**/*docs/design/opendesign/session/runtime-selector-variations.htmlis excluded by!docs/design/**/*docs/design/opendesign/session/runtime-selector-variations.html.artifact.jsonis excluded by!docs/design/**/*,!**/*.jsondocs/design/opendesign/session/session-chat.htmlis excluded by!docs/design/**/*docs/design/opendesign/session/session-design-system.htmlis excluded by!docs/design/**/*docs/design/opendesign/session/session.cssis excluded by!docs/design/**/*docs/qa/scenarios/ET-web-session-goal-strip.mdis excluded by!**/*.mddocs/qa/scenarios/ET-web-session-permission-dock.mdis excluded by!**/*.mddocs/qa/scenarios/ET-web-session-transcript-calm-grammar.mdis excluded by!**/*.mddocs/qa/scenarios/GL-001.mdis excluded by!**/*.mddocs/qa/scenarios/GL-005.mdis excluded by!**/*.mddocs/qa/scenarios/GL-006.mdis excluded by!**/*.mddocs/qa/scenarios/GL-008.mdis excluded by!**/*.mddocs/qa/scenarios/GL-use-response-as-goal.mdis excluded by!**/*.mdpackages/ui/src/components/custom/stories/choice.stories.tsxis excluded by!**/*.stories.tsxpackages/ui/src/components/custom/stories/code-block.stories.tsxis excluded by!**/*.stories.tsxpackages/ui/src/components/custom/stories/dock.stories.tsxis excluded by!**/*.stories.tsxpackages/ui/src/components/custom/stories/marker.stories.tsxis excluded by!**/*.stories.tsxpackages/ui/src/components/custom/stories/receipt.stories.tsxis excluded by!**/*.stories.tsxweb/src/systems/runtime/components/stories/runtime-selector.stories.tsxis excluded by!**/*.stories.tsxweb/src/systems/session/components/goal/stories/goal-status-chip.stories.tsxis excluded by!**/*.stories.tsxweb/src/systems/session/components/goal/stories/session-goal-strip.stories.tsxis excluded by!**/*.stories.tsxweb/src/systems/session/components/stories/clarification-card.stories.tsxis excluded by!**/*.stories.tsxweb/src/systems/session/components/stories/clarification-data-part.stories.tsxis excluded by!**/*.stories.tsxweb/src/systems/session/components/stories/clarification-dock.stories.tsxis excluded by!**/*.stories.tsxweb/src/systems/session/components/stories/permission-dock.stories.tsxis excluded by!**/*.stories.tsxweb/src/systems/session/components/stories/permission-prompt.stories.tsxis excluded by!**/*.stories.tsxweb/src/systems/session/components/stories/thinking-block.stories.tsxis excluded by!**/*.stories.tsx
📒 Files selected for processing (105)
packages/ui/src/components/custom/__tests__/choice.test.tsxpackages/ui/src/components/custom/__tests__/code-block.test.tsxpackages/ui/src/components/custom/__tests__/dock.test.tsxpackages/ui/src/components/custom/__tests__/marker.test.tsxpackages/ui/src/components/custom/__tests__/receipt.test.tsxpackages/ui/src/components/custom/__tests__/tool-call-row.test.tsxpackages/ui/src/components/custom/choice.tsxpackages/ui/src/components/custom/code-block.tsxpackages/ui/src/components/custom/dock.tsxpackages/ui/src/components/custom/marker.tsxpackages/ui/src/components/custom/receipt.tsxpackages/ui/src/components/custom/tool-call-row.tsxpackages/ui/src/components/custom/tool-call-status-icon.tsxpackages/ui/src/index.tspackages/ui/src/tokens.cssweb/src/components/assistant-ui/__tests__/session-thread.test.tsxweb/src/components/assistant-ui/__tests__/session-timeline.logic.test.tsweb/src/components/assistant-ui/session-changed-files-row.tsxweb/src/components/assistant-ui/session-composer-queued-prompts.tsxweb/src/components/assistant-ui/session-composer.tsxweb/src/components/assistant-ui/session-message-parts.tsxweb/src/components/assistant-ui/session-thread.tsxweb/src/components/assistant-ui/session-timeline-changed-files.tsweb/src/components/assistant-ui/session-timeline-fold.tsweb/src/components/assistant-ui/session-timeline-markers.tsweb/src/components/assistant-ui/session-timeline-render.tsxweb/src/components/assistant-ui/session-timeline-stable.tsweb/src/components/assistant-ui/session-timeline-summary.tsweb/src/components/assistant-ui/session-timeline.logic.tsweb/src/components/assistant-ui/session-user-message.tsxweb/src/components/assistant-ui/session-working-row.tsxweb/src/components/assistant-ui/timeline-row-estimates.tsweb/src/lib/api-contract.tsweb/src/styles.cssweb/src/systems/os/apps/session/use-session-window-controller.tsxweb/src/systems/runtime/components/runtime-selector/__tests__/runtime-selector.test.tsxweb/src/systems/runtime/components/runtime-selector/model-list.tsxweb/src/systems/runtime/components/runtime-selector/model-row.tsxweb/src/systems/runtime/components/runtime-selector/provider-chips.tsxweb/src/systems/runtime/components/runtime-selector/reasoning-bar.tsxweb/src/systems/runtime/components/runtime-selector/reasoning-slider.tsxweb/src/systems/runtime/components/runtime-selector/runtime-selector.tsxweb/src/systems/runtime/components/runtime-selector/selector-footer.tsxweb/src/systems/runtime/components/runtime-selector/speed-switch.tsxweb/src/systems/runtime/components/runtime-selector/trigger.tsxweb/src/systems/runtime/components/runtime-selector/use-runtime-selector.tsweb/src/systems/session/components/__tests__/clarification-card.test.tsxweb/src/systems/session/components/__tests__/goal-head-action.test.tsxweb/src/systems/session/components/__tests__/goal-status-chip.test.tsxweb/src/systems/session/components/__tests__/permission-data-part.test.tsxweb/src/systems/session/components/__tests__/permission-prompt.test.tsxweb/src/systems/session/components/__tests__/runtime-activity-notice.test.tsxweb/src/systems/session/components/__tests__/session-chat-runtime-provider.test.tsxweb/src/systems/session/components/__tests__/session-create-dialog.test.tsxweb/src/systems/session/components/__tests__/session-decision-dock.test.tsxweb/src/systems/session/components/__tests__/session-goal-header.test.tsxweb/src/systems/session/components/__tests__/session-goal-strip.test.tsxweb/src/systems/session/components/__tests__/session-resume-failure.test.tsxweb/src/systems/session/components/__tests__/thinking-block.test.tsxweb/src/systems/session/components/__tests__/tool-call-card.test.tsxweb/src/systems/session/components/clarification-card.tsxweb/src/systems/session/components/clarification-data-part.tsxweb/src/systems/session/components/clarification-dock.tsxweb/src/systems/session/components/clarification-receipt.tsxweb/src/systems/session/components/goal/goal-head-action.tsxweb/src/systems/session/components/goal/goal-status-chip.tsxweb/src/systems/session/components/goal/goal-status-controls.tsxweb/src/systems/session/components/goal/goal-status-meters.tsxweb/src/systems/session/components/goal/goal-status-types.tsweb/src/systems/session/components/goal/session-goal-header.tsxweb/src/systems/session/components/goal/session-goal-strip.tsxweb/src/systems/session/components/permission-data-part.tsxweb/src/systems/session/components/permission-dock.tsxweb/src/systems/session/components/permission-prompt.tsxweb/src/systems/session/components/runtime-activity-notice.tsxweb/src/systems/session/components/session-create-dialog-host.tsxweb/src/systems/session/components/session-create-dialog.tsxweb/src/systems/session/components/session-decision-dock.tsxweb/src/systems/session/components/session-resume-failure.tsxweb/src/systems/session/components/thinking-block.tsxweb/src/systems/session/components/tool-call-card.tsxweb/src/systems/session/components/tool-renderers/__tests__/renderers.test.tsxweb/src/systems/session/components/tool-renderers/bash-content.tsxweb/src/systems/session/components/tool-renderers/detail-pre.tsxweb/src/systems/session/components/tool-renderers/edit-content.tsxweb/src/systems/session/components/tool-renderers/expanded-tool-content.tsxweb/src/systems/session/components/tool-renderers/generic-content.tsxweb/src/systems/session/components/tool-renderers/search-content.tsxweb/src/systems/session/components/tool-renderers/todo-content.tsxweb/src/systems/session/components/tool-renderers/write-content.tsxweb/src/systems/session/components/tool-result-artifact.tsxweb/src/systems/session/hooks/__tests__/use-session-create-dialog.test.tsxweb/src/systems/session/hooks/use-clarification-dock.tsweb/src/systems/session/hooks/use-permission-dock.tsweb/src/systems/session/hooks/use-session-create-dialog.tsweb/src/systems/session/hooks/use-session-goal-header.tsweb/src/systems/session/hooks/use-session-topbar-slot.tsxweb/src/systems/session/index.tsweb/src/systems/session/lib/editable-target.tsweb/src/systems/session/lib/message-parts.tsweb/src/systems/session/lib/pending-permissions.tsweb/src/systems/session/lib/session-create-draft.tsweb/src/systems/session/lib/session-data-renderers.tsxweb/src/systems/session/lib/tool-diff-stat.tsweb/src/systems/session/stores/session-create-store.ts
💤 Files with no reviewable changes (11)
- web/src/systems/session/components/tests/clarification-card.test.tsx
- web/src/systems/session/components/goal/goal-status-meters.tsx
- web/src/systems/runtime/components/runtime-selector/reasoning-bar.tsx
- web/src/systems/session/components/clarification-card.tsx
- web/src/systems/session/components/goal/goal-status-chip.tsx
- web/src/systems/session/components/tests/permission-prompt.test.tsx
- web/src/systems/session/components/permission-prompt.tsx
- web/src/systems/session/components/goal/goal-status-types.ts
- web/src/systems/session/components/goal/goal-status-controls.tsx
- web/src/systems/session/components/tests/goal-status-chip.test.tsx
- packages/ui/src/components/custom/code-block.tsx
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@web/src/components/assistant-ui/scroll-to-bottom-pill.tsx`:
- Around line 24-39: Update the button in the scroll-to-bottom pill component to
set its disabled state whenever visible is false, alongside the existing
tabIndex and pointer-events handling. Preserve normal click and keyboard
behavior when visible is true, and ensure hidden pills cannot retain an active
focus target.
In `@web/src/components/assistant-ui/session-thread-messages.tsx`:
- Around line 77-103: Update the messageCount === 0 path in
session-thread-messages.tsx and ThreadStatePane so isSessionRunning is passed
through and an active session renders the active/loading surface instead of
resolving successful empty data to ThreadEmpty. Preserve the existing error,
retry, and inactive empty-transcript behavior; do not rely on the
threadEmptyWhileActive telemetry as the user-facing fallback.
In `@web/src/components/assistant-ui/session-thread.tsx`:
- Around line 27-30: Add a Compozy Cross-Surface Impact Audit near the session
surface composition documentation, explicitly checking the web transcript and
session-decision surfaces, packages/site documentation impact, workspace scope,
and cross-workspace leakage; provide evidence supporting each no-impact
conclusion and document any required impacts.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: a96a4fe6-9768-4a08-a844-779706781b76
⛔ Files ignored due to path filters (1)
web/src/systems/session/components/assistant-ui/stories/session-thread.stories.tsxis excluded by!**/*.stories.tsx
📒 Files selected for processing (5)
web/src/components/assistant-ui/scroll-to-bottom-pill.tsxweb/src/components/assistant-ui/session-assistant-message.tsxweb/src/components/assistant-ui/session-thread-messages.tsxweb/src/components/assistant-ui/session-thread-viewport.tsxweb/src/components/assistant-ui/session-thread.tsx
|
Review remediation batch published in ae4f28c. Resolved and verified:
Verified skips:
Fresh evidence:
|
|
@greptile-apps review the latest head ae4f28c, including the remediation batch. |
|
| Filename | Overview |
|---|---|
| web/src/components/assistant-ui/session-timeline.logic.ts | Refactors transcript derivation into specialized summary, marker, stable-row, folding, and changed-file helpers. |
| web/src/systems/session/components/session-decision-dock.tsx | Coordinates the permission-first queue and clarification fallback above the session composer. |
| web/src/systems/session/hooks/use-permission-dock.ts | Implements offered-decision gating, submission state, and digit-key permission shortcuts. |
| web/src/systems/session/hooks/use-clarification-dock.ts | Implements bounded-choice shortcuts and free-text clarification submission behavior. |
| web/src/systems/session/hooks/use-session-goal-header.ts | Reconciles goal stream state through the shared query cache and exposes state-gated goal commands. |
| web/src/systems/session/components/goal/session-goal-strip.tsx | Replaces legacy goal controls and meters with expandable state, context, verdict, and command-staging details. |
| packages/ui/src/components/custom/dock.tsx | Introduces the compound dock primitive used by session decision surfaces. |
| web/src/systems/runtime/components/runtime-selector/runtime-selector.tsx | Expands the create-time runtime selector anatomy with provider, reasoning, and speed controls. |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart TD
Events[Session messages and runtime events] --> Timeline[Timeline derivation]
Timeline --> Transcript[Collapsed transcript rows and markers]
Events --> Pending{Pending decision?}
Pending -->|Permission| PermissionDock[Permission dock]
Pending -->|Clarification| ClarificationDock[Clarification dock]
PermissionDock --> Composer[Composer zone]
ClarificationDock --> Composer
Goal[Goal query and loop stream] --> GoalStrip[Session goal strip]
Goal --> HeadAction[Single window-head action]
Reviews (6): Last reviewed commit: "fix: repair session UI integration contr..." | Re-trigger Greptile
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
web/src/components/assistant-ui/session-composer.tsx (1)
269-282: 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick winUse the shared
Buttonprimitive for Stop.This generic control bypasses
@compozy/uiwhile the same component already usesButtonfor adjacent actions. Preserve the behavior and styling throughButtonprops/classes instead.Proposed fix
- <button + <Button type="button" + variant="ghost" + size="sm" onClick={onCancelPrompt} aria-label="Stop generation" data-testid="composer-stop-button" className={cn( "inline-flex size-7 items-center justify-center rounded-full", @@ > <Square className="size-3 fill-current" /> - </button> + </Button>As per coding guidelines, “Reuse primitives exported by
packages/ui/src/index.tsand import them from@compozy/ui.”🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@web/src/components/assistant-ui/session-composer.tsx` around lines 269 - 282, Replace the native button used for the Stop action in the session composer with the shared Button primitive imported from `@compozy/ui`. Preserve onCancelPrompt, type, aria-label, data-testid, the Square icon, and equivalent styling by transferring the existing classes and appropriate Button props.Source: Coding guidelines
🧹 Nitpick comments (3)
packages/ui/src/components/custom/dock-key.tsx (1)
10-13: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winReplace the ad-hoc spacing and typography values.
ml-[3px]andtext-[9px]bypass the shared design system in this public primitive. Use documented token-backed utilities instead.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/ui/src/components/custom/dock-key.tsx` around lines 10 - 13, Update the kbd element in the dock-key primitive to replace the arbitrary ml-[3px] and text-[9px] utilities with documented, token-backed spacing and typography utilities from the shared design system, while preserving the existing className composition and props.Source: Coding guidelines
packages/ui/src/components/custom/dock-actions.tsx (1)
7-15: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winReplace arbitrary pixel utilities with shared design tokens.
The new Dock primitives encode spacing, typography, and sizing directly in arbitrary Tailwind values instead of using the repository’s token system.
packages/ui/src/components/custom/dock-actions.tsx#L7-L15: replacegap-[7px].packages/ui/src/components/custom/dock-count.tsx#L7-L16: replacetext-[10px].packages/ui/src/components/custom/dock-deadline.tsx#L7-L16: replacetext-[10px].packages/ui/src/components/custom/dock-meta.tsx#L7-L19: replacemt-[5px]andtext-[11px].packages/ui/src/components/custom/dock-pre.tsx#L7-L21: replacemax-h-[130px]andtext-[11px].packages/ui/src/components/custom/dock-status.tsx#L13-L26: replacemt-[7px]andtext-[11px].As per coding guidelines, design values must come from
packages/ui/src/tokens.cssandDESIGN.md.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/ui/src/components/custom/dock-actions.tsx` around lines 7 - 15, Replace the arbitrary Tailwind values in DockActions, DockCount, DockDeadline, DockMeta, DockPre, and DockStatus with the corresponding shared design-token utilities defined by tokens.css and DESIGN.md: gap-[7px], text-[10px], mt-[5px], text-[11px], max-h-[130px], and mt-[7px]. Apply the required changes in packages/ui/src/components/custom/dock-actions.tsx (lines 7-15), dock-count.tsx (7-16), dock-deadline.tsx (7-16), dock-meta.tsx (7-19), dock-pre.tsx (7-21), and dock-status.tsx (13-26), preserving each component’s existing layout and behavior.Source: Coding guidelines
web/src/components/assistant-ui/transcript-disclosure.tsx (1)
49-56: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueArbitrary size value instead of a scale/token step.
size-[11px]doesn't correspond to a spacing/size scale step (nearest aresize-2.5/size-3). Coding guidelines call for using tokens/scale values rather than inventing sizing values, though similar bracketed pixel values already exist elsewhere in the codebase.♻️ Suggested tweak
- className={cn( - "size-[11px] shrink-0 text-faint transition-transform duration-slow ease-out motion-reduce:transition-none", - expanded ? "rotate-90" : null - )} + className={cn( + "size-3 shrink-0 text-faint transition-transform duration-slow ease-out motion-reduce:transition-none", + expanded ? "rotate-90" : null + )}Based on coding guidelines: "Use design values from
packages/ui/src/tokens.cssandDESIGN.md; do not invent colors, typography, radius, spacing, or motion values."🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@web/src/components/assistant-ui/transcript-disclosure.tsx` around lines 49 - 56, Replace the arbitrary `size-[11px]` class on the `ChevronRight` in the transcript disclosure with the nearest approved size token, using `size-2.5` or `size-3` according to the intended icon dimensions; leave the remaining classes and rotation behavior unchanged.Source: Coding guidelines
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@web/src/systems/session/mocks/handlers.ts`:
- Around line 253-260: Update the clarification-response handler using
sessionById to validate that the fixture session’s workspace_id matches
params.workspace_id before returning 200. Return the existing 404 response for
missing or cross-workspace sessions, while preserving the empty clarifications
payload for valid matches. Add a regression test covering an existing session
requested with a different workspace_id and assert it returns 404.
---
Outside diff comments:
In `@web/src/components/assistant-ui/session-composer.tsx`:
- Around line 269-282: Replace the native button used for the Stop action in the
session composer with the shared Button primitive imported from `@compozy/ui`.
Preserve onCancelPrompt, type, aria-label, data-testid, the Square icon, and
equivalent styling by transferring the existing classes and appropriate Button
props.
---
Nitpick comments:
In `@packages/ui/src/components/custom/dock-actions.tsx`:
- Around line 7-15: Replace the arbitrary Tailwind values in DockActions,
DockCount, DockDeadline, DockMeta, DockPre, and DockStatus with the
corresponding shared design-token utilities defined by tokens.css and DESIGN.md:
gap-[7px], text-[10px], mt-[5px], text-[11px], max-h-[130px], and mt-[7px].
Apply the required changes in packages/ui/src/components/custom/dock-actions.tsx
(lines 7-15), dock-count.tsx (7-16), dock-deadline.tsx (7-16), dock-meta.tsx
(7-19), dock-pre.tsx (7-21), and dock-status.tsx (13-26), preserving each
component’s existing layout and behavior.
In `@packages/ui/src/components/custom/dock-key.tsx`:
- Around line 10-13: Update the kbd element in the dock-key primitive to replace
the arbitrary ml-[3px] and text-[9px] utilities with documented, token-backed
spacing and typography utilities from the shared design system, while preserving
the existing className composition and props.
In `@web/src/components/assistant-ui/transcript-disclosure.tsx`:
- Around line 49-56: Replace the arbitrary `size-[11px]` class on the
`ChevronRight` in the transcript disclosure with the nearest approved size
token, using `size-2.5` or `size-3` according to the intended icon dimensions;
leave the remaining classes and rotation behavior unchanged.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: e49b4fd0-66aa-4281-9ce7-6dd9766eae2f
⛔ Files ignored due to path filters (1)
DESIGN.mdis excluded by!**/*.md
📒 Files selected for processing (70)
packages/ui/src/components/custom/__tests__/tool-call-row.test.tsxpackages/ui/src/components/custom/dock-actions.tsxpackages/ui/src/components/custom/dock-body.tsxpackages/ui/src/components/custom/dock-count.tsxpackages/ui/src/components/custom/dock-deadline.tsxpackages/ui/src/components/custom/dock-eyebrow.tsxpackages/ui/src/components/custom/dock-head.tsxpackages/ui/src/components/custom/dock-key.tsxpackages/ui/src/components/custom/dock-meta.tsxpackages/ui/src/components/custom/dock-pre.tsxpackages/ui/src/components/custom/dock-status.tsxpackages/ui/src/components/custom/dock-title.tsxpackages/ui/src/components/custom/dock.tsxpackages/ui/src/tokens.cssweb/src/components/assistant-ui/__tests__/session-thread.test.tsxweb/src/components/assistant-ui/__tests__/session-timeline.logic.test.tsweb/src/components/assistant-ui/scroll-to-bottom-pill.tsxweb/src/components/assistant-ui/session-changed-files-row.tsxweb/src/components/assistant-ui/session-composer-queued-prompts.tsxweb/src/components/assistant-ui/session-composer.tsxweb/src/components/assistant-ui/session-message-parts.tsxweb/src/components/assistant-ui/session-thread-messages.tsxweb/src/components/assistant-ui/session-thread-states.tsxweb/src/components/assistant-ui/session-timeline-changed-files.tsweb/src/components/assistant-ui/session-timeline-render.tsxweb/src/components/assistant-ui/session-user-message.tsxweb/src/components/assistant-ui/session-working-row.tsxweb/src/components/assistant-ui/timeline-row-estimates.tsweb/src/components/assistant-ui/transcript-disclosure.tsxweb/src/styles.cssweb/src/systems/os/apps/session/use-session-window-controller.tsxweb/src/systems/runtime/components/runtime-selector/__tests__/runtime-selector.test.tsxweb/src/systems/runtime/components/runtime-selector/model-row.tsxweb/src/systems/runtime/components/runtime-selector/provider-chips.tsxweb/src/systems/runtime/components/runtime-selector/selector-footer.tsxweb/src/systems/session/components/__tests__/runtime-activity-notice.test.tsxweb/src/systems/session/components/__tests__/session-decision-dock.test.tsxweb/src/systems/session/components/__tests__/session-goal-header.test.tsxweb/src/systems/session/components/__tests__/session-goal-strip.test.tsxweb/src/systems/session/components/__tests__/session-resume-failure.test.tsxweb/src/systems/session/components/__tests__/thinking-block.test.tsxweb/src/systems/session/components/__tests__/tool-call-card.test.tsxweb/src/systems/session/components/clarification-dock.tsxweb/src/systems/session/components/goal/session-goal-header-container.tsxweb/src/systems/session/components/goal/session-goal-header.tsxweb/src/systems/session/components/goal/session-goal-strip.tsxweb/src/systems/session/components/permission-data-part.tsxweb/src/systems/session/components/permission-dock.tsxweb/src/systems/session/components/runtime-activity-notice.tsxweb/src/systems/session/components/session-danger-banner.tsxweb/src/systems/session/components/session-decision-dock.tsxweb/src/systems/session/components/session-resume-failure.tsxweb/src/systems/session/components/thinking-block.tsxweb/src/systems/session/components/tool-call-card.tsxweb/src/systems/session/components/tool-renderers/__tests__/renderers.test.tsxweb/src/systems/session/components/tool-renderers/bash-content.tsxweb/src/systems/session/components/tool-renderers/generic-content.tsxweb/src/systems/session/components/tool-renderers/todo-content.tsxweb/src/systems/session/hooks/use-permission-dock.tsweb/src/systems/session/hooks/use-reject-menu-elements.tsweb/src/systems/session/hooks/use-session-goal-header.tsweb/src/systems/session/lib/message-parts.tsweb/src/systems/session/lib/message-schemas.tsweb/src/systems/session/lib/pending-permissions.tsweb/src/systems/session/lib/permission-subject.tsweb/src/systems/session/lib/session-thread-repository.tsweb/src/systems/session/lib/tool-part-error.tsweb/src/systems/session/mocks/__tests__/handlers.test.tsweb/src/systems/session/mocks/handlers.tsweb/src/systems/session/types.ts
💤 Files with no reviewable changes (1)
- web/src/systems/session/components/tests/runtime-activity-notice.test.tsx
🚧 Files skipped from review as they are similar to previous changes (28)
- web/src/systems/session/components/tests/session-resume-failure.test.tsx
- web/src/systems/session/components/permission-data-part.tsx
- web/src/systems/os/apps/session/use-session-window-controller.tsx
- web/src/components/assistant-ui/session-user-message.tsx
- web/src/systems/session/components/tests/session-goal-strip.test.tsx
- web/src/systems/session/lib/pending-permissions.ts
- web/src/systems/session/hooks/use-session-goal-header.ts
- web/src/components/assistant-ui/scroll-to-bottom-pill.tsx
- web/src/systems/session/components/session-resume-failure.tsx
- web/src/systems/session/components/tests/thinking-block.test.tsx
- packages/ui/src/components/custom/tests/tool-call-row.test.tsx
- web/src/components/assistant-ui/session-thread-messages.tsx
- web/src/styles.css
- web/src/systems/session/components/session-decision-dock.tsx
- web/src/systems/session/components/goal/session-goal-strip.tsx
- web/src/systems/session/components/tests/tool-call-card.test.tsx
- web/src/systems/session/components/clarification-dock.tsx
- web/src/systems/session/components/tool-renderers/todo-content.tsx
- web/src/systems/runtime/components/runtime-selector/model-row.tsx
- web/src/systems/runtime/components/runtime-selector/selector-footer.tsx
- web/src/components/assistant-ui/timeline-row-estimates.ts
- web/src/systems/session/components/tool-call-card.tsx
- web/src/systems/session/components/goal/session-goal-header.tsx
- web/src/components/assistant-ui/tests/session-timeline.logic.test.ts
- web/src/components/assistant-ui/session-timeline-changed-files.ts
- web/src/systems/session/components/permission-dock.tsx
- web/src/components/assistant-ui/session-timeline-render.tsx
- web/src/systems/runtime/components/runtime-selector/tests/runtime-selector.test.tsx
|
@greptile-apps review the latest head a0edbad, including the workspace-scoping follow-up. |
Implements
SESSION-REDESIGN-SPEC.mdentirely — the session transcript disappears behind the conversation: one neutral ramp, status as glyphs, collapse as the resting state, decisions docked to the composer. All 7 build-order phases (§11) landed; the §8 coverage matrix was re-checked row by row.What changed
1 · Timeline derivation (
web/src/components/assistant-ui/)"Ran 2 commands · Edited 3 files", fixed category order, distinct-file counts), ported from the synaratoolCallGroupengine ontoSessionTimelineToolPart.+N previous tool callstoggle above the visible tail (ACTIVE_WORK_VISIBLE_LIMIT = 4;SETTLED_WORK_VISIBLE_LIMITdeleted).×Ncount (keyed ontype:kind; clarifications/permissions/goal prompts never cluster).session-timeline-summary.ts,session-timeline-stable.ts,session-timeline-markers.ts; row estimates retuned (trow ≈26px, marker ≈24px).2 · packages/ui primitives (story + test each)
Marker/MarkerMeta,Receipt,Dock(compound: Head/Eyebrow/Title/Count/Deadline/Body/Pre/Meta/Actions/Status/Key),Choice*(rows with key chips + free-text form).runtimeErrordanger heading deleted; newstatslot for per-file+a −d; success check and running spinner are grey — only the failure × carries a hue.tonerecolor path deleted (ring/tint/full-text recolor); density/copy kept.--color-chat-fill-user(4.5% ink) +--color-chat-fill-codeadded totokens.css;DESIGN.mdregenerated viamake codegen.3 · Transcript components
Thoughtrow with first-line preview (updates eyebrow deleted).Working for Ns(text-node mutation, no per-second React commits).SessionDataEventCardpayload-preview card deleted; message errors → danger marker.Edited N files +A −Dline expanding to bare mono file lines (cap 8 ++N more)..trow__detailrail grammar: unified±text diffs (Edit/Write), stderr as danger text (Bash), bare mono result lines (Grep/Glob), plain JSON (generic), new TodoWrite plan renderer (done/active/pending glyphs, never JSON).--info"Open full result" with faint byte meta; pages load in place; load failure is a danger text line + Retry (fetch/pagination semantics verbatim).4 · Decisions dock to the composer
1/Nqueue counter — permissions first.decisionOptionsthe runtime offers; keys 1–4 map to the four ACP decisions; reject-always rides the reject split menu and key 4 fires with the menu closed; digit shortcuts ignore focused inputs.PermissionPrompt,ClarificationCard(+ their stories/tests); replaced bypermission-data-part.tsx, dock components + hooks, and canonical suites (session-decision-dock.test.tsx,permission-data-part.test.tsx).5 · Goal strip + window-head actions
GoalStatusChip/meters/controls deleted →SessionGoalStrip: state dot (accent pulse active · warning blocked/paused · success done · faint moved) + GOAL kicker + objective +turn 3/20 · ctx 41%mono facts, expanding to quiet key/value rows (Contract · Run link · Context tokens + nudge · Last verdict · Node/cause · moved-session link · Draft goal command / Draft replacement staging/goal …into the composer, never auto-sending). Progress bars dropped — the number is the information; pending/unknown context readsctx —, never an invented %.useSessionGoalHeader(head instance reads the shared cache; the strip owns loop-stream reconciliation).6 · Composer + queued strip
.composergrammar: no zone top border, hairline →line-strongon hover →accent-dimon focus, elevated fill, 28px accent send disc, ghost circular stop, quiet⏎ send/⏎ queuehint. Queue/Interrupt/steer logic verbatim.Authorized deltas (spec updated in-diff, §11.7)
SessionPayloadcarries no model/reasoning/speed;speedexists only oncreateSession). The variation-A selector ships on the create-contract surfaces (session create dialog / agent settings — carried branch WIP in this PR). Spec §3/§6 updated.SessionThread's composer zone (where the composer actually lives); capability intact..liferulestays vocabulary-only — no runtime lifecycle data source exists beyond markers.Eyebrowcontract (11/600/-0.005em, L-022) instead of the prototype's.14emtracking.Carried branch WIP (pre-existing on
session-ui)Variation-A runtime selector anatomy (provider chips, reasoning slider, speed switch + PR #267 session-create
speed), session-create dialog wiring, and the opendesign prototype refresh.Verification
make verifygreen on this exact tree — all 12 stages (codegen-check, installer-check, source-size, Bun lint/typecheck/test, web build, Go fmt/lint/test/build, boundaries). Web: 516/516 test files; packages/ui: 632 tests.QA impact (flagged, not retested)
untestedscenarios:ET-web-session-transcript-calm-grammar,ET-web-session-permission-dock,ET-web-session-goal-strip.untestedwith impact notes:GL-001,GL-005,GL-006,GL-008,GL-use-response-as-goal(goal controls relocated to the window head; Clear now terminal-gated).Compozy Impact Audit
tool-labels.ts,toTimelinePartschecked).session-data-rendererschecked).🤖 Generated with Claude Code
Summary by CodeRabbit