Skip to content

fix(ui): restore green build (monaco 0.55 pin + dead css import) - #43

Merged
dvaJi merged 28 commits into
masterfrom
fix/ui-shadcn-tailwind-import
Aug 6, 2026
Merged

dvaJi merged 28 commits into
masterfrom
fix/ui-shadcn-tailwind-import

Conversation

@dvaJi

@dvaJi dvaJi commented Aug 3, 2026

Copy link
Copy Markdown
Owner

build-check has been red on master: @argos/ui build failed. Two root causes, both surfacing after the deps update (#42) once format:check was fixed.

  • style.css: removed a dead import of shadcn/tailwind.css (a file that never existed in the repo). Silently tolerated on some platforms, errored in CI.
  • monaco-editor pinned to ^0.55.1: 0.56.0 tightened its exports map and no longer exposes the deep editor.api subpath a transitive importer needs; 0.55.1 wildcard exports still allow it.
  • bun.lock updated for the pin.

Verified: @argos/ui build green (~11s), full desktop build 3/3 tasks, lint PASS.

Summary by CodeRabbit

  • New Features
    • Added an optional “Continued” indicator setting.
    • Improved ACP model and configuration menus with grouped, clearer options.
    • Added live plan updates during assistant responses.
    • Steering messages now interrupt active responses gracefully and start replacements reliably.
    • Added optimistic message display and clearer cancellation progress in chat.
    • Added collapsible assistant turn summaries for reasoning and tool activity.
    • Improved code block highlighting, copying, and line wrapping.
  • Bug Fixes
    • Improved handling of empty selections, stalled permissions, rate-limit timers, and browser-mode window controls.
  • Style
    • Updated dialogs, menus, tooltips, inputs, and other controls for a more consistent interface.

Restore a green @argos/ui build broken by the deps update (#42). style.css removed a dead shadcn/tailwind.css import to a file that never existed (silently skipped on some platforms, failed in CI). monaco-editor pinned to ^0.55.1 because 0.56.0 tightened its exports map and no longer exposes the deep editor.api subpath that a transitive importer needs; 0.55.1 wildcard exports still allow it. bun.lock updated.
Copilot AI review requested due to automatic review settings August 3, 2026 04:23
@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It 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 reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The pull request updates ACP turn streaming and steering, adds plan events and a persisted continue-indicator setting, migrates UI primitives from Radix to Base UI, and updates chat, settings, Markdown, and message rendering.

Changes

ACP execution and steering

Layer / File(s) Summary
ACP turn lifecycle and plan events
apps/daemon/src/host/acp-provider-execution.ts, apps/daemon/test/acpProviderExecution.test.ts
Active turns track completion. Streamed plans publish revisioned chat.plan.updated events. Plan blocks remain separate from regular stream blocks.
Steering interruption
apps/daemon/src/host/acp-provider-execution.ts, apps/daemon/test/daemonSessionRoutes.test.ts, packages/ui/src/pages/ChatPage.tsx
Steering interrupts local processing, cancels pending permissions, sends session/cancel, waits for completion or timeout, and then sends replacement content. The UI tracks cancellation state.

Settings and UI

Layer / File(s) Summary
Continue-indicator setting
packages/shared-contracts/src/routes/settings.routes.ts, packages/backend-core/src/dispatch/settings/settingsAdapter.ts, apps/desktop/src/main/routes/settings/settingsAdapter.ts, packages/ui/src/stores/uiSettingsStore.ts, packages/ui/settings/components/CommonSettings.tsx, packages/ui/src/components/message/MessageBlockAction.tsx
showContinueIndicator is validated, persisted, stored, exposed as a toggle, and used to control the “Continued” indicator.
Chat and message rendering
packages/ui/src/pages/ChatPage.tsx, packages/ui/src/components/chat/ChatInputBox.tsx, packages/ui/src/components/chat/ChatInputToolbar.tsx, packages/ui/src/components/message/MessageTurnFold.tsx, packages/ui/src/components/message/messageActivityGroups.ts, packages/ui/src/components/message/MessageBlockThink.tsx
Direct sends and steering add optimistic messages. Input clearing and cancellation state are exposed to the toolbar. Activity groups are replaced with turn folds. Thinking blocks use cached collapse settings and formatted durations.
Markdown rendering
packages/ui/src/components/markdown/CodeBlock.tsx, packages/ui/src/components/markdown/MarkdownRenderer.tsx, packages/ui/src/components/markdown/highlight.ts, packages/ui/src/components/markdown/code-highlight.css
Code blocks use a shared TanStack highlighter, updated token styles, wrapping controls, and custom Markdown <pre> handling.
Base UI primitives
packages/ui/shadcn/components/ui/*, packages/ui/package.json, packages/ui/components.json
Radix-based primitives are replaced with Base UI primitives. Props, positioning, rendering, styling, exports, and dependencies are updated.
Consumer compatibility updates
packages/ui/src/components/*, packages/ui/settings/components/*, packages/ui/src/pages/*
Consumers use render-based triggers, normalize cleared selector values, update tooltip composition, and adapt to the migrated primitives.

Estimated code review effort: 5 (Critical) | ~120 minutes

Possibly related PRs

  • dvaJi/argos#36: Both PRs modify shared ACP execution, chat configuration, and message activity code.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.68% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the primary UI build fixes: pinning Monaco and removing the unused CSS import.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/ui-shadcn-tailwind-import

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@greptile-apps

greptile-apps Bot commented Aug 3, 2026

Copy link
Copy Markdown

Confidence Score: 5/5

The PR appears safe to merge, with no concrete changed-code defect identified.

The Monaco range remains below 0.56 and satisfies the dependent package’s compatibility range, while the removed CSS import had no resolvable target and its required local styling remains present.

Important Files Changed

Filename Overview
packages/ui/package.json Changes Monaco Editor from the incompatible 0.56 release line to ^0.55.1, which also satisfies stream-monaco’s declared peer range.
bun.lock Resolves Monaco Editor to 0.55.1, updates its transitive packages, and deduplicates stream-monaco’s previously nested Monaco installation.
packages/ui/src/assets/style.css Removes an unresolved dead import without removing the stylesheet’s existing Tailwind scanning, shadcn theme tokens, or component styles.

Reviews (1): Last reviewed commit: "fix(ui): pin monaco 0.55, drop dead css ..." | Re-trigger Greptile

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Restores a green @argos/ui build after the dependency update by removing a failing CSS import and pinning monaco-editor to a compatible version (with corresponding lockfile updates).

Changes:

  • Removed a dead @import for shadcn/tailwind.css that doesn’t exist in the repo and can fail CI builds.
  • Pinned monaco-editor to ^0.55.1 to avoid 0.56.0 export-map / compatibility issues.
  • Updated bun.lock to reflect the pinned dependency and resolved dependency graph.

Reviewed changes

Copilot reviewed 2 out of 3 changed files in this pull request and generated no comments.

File Description
packages/ui/src/assets/style.css Removes a non-existent CSS import that can break builds.
packages/ui/package.json Pins monaco-editor to a compatible version for @argos/ui builds.
bun.lock Updates lockfile entries for the pinned monaco version and related transitive deps.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown

React Doctor found 42 new issues in 18 files · 42 warnings · score 0 / 100 (Critical) · 40 fixed · vs master

42 warnings

settings/components/AcpSettings.tsx

  • ⚠️ L151 Many related useState calls prefer-useReducer

settings/components/KnowledgeFile.tsx

  • ⚠️ L20 Many related useState calls prefer-useReducer

settings/components/ScheduledTasksSettings.tsx

  • ⚠️ L664 JSX nested too deeply jsx-max-depth

settings/components/VertexProviderSettingsDetail.tsx

  • ⚠️ L20 Many related useState calls prefer-useReducer

settings/components/VoiceAIProviderConfig.tsx

  • ⚠️ L38 Many related useState calls prefer-useReducer

src/components/WorkspaceSelector.tsx

  • ⚠️ L145 Large component is hard to read and change no-giant-component

src/components/chat/ChatInputToolbar.tsx

  • ⚠️ L24 Boolean prop combinations are hard to test no-many-boolean-props
  • ⚠️ L74 Manual memoization in compiler-managed code react-compiler-no-manual-memoization

src/components/chat/ChatStatusBar.tsx

  • ⚠️ L408 Manual memoization in compiler-managed code react-compiler-no-manual-memoization

src/components/chat/MessageList.tsx

  • ⚠️ L55 Manual memoization in compiler-managed code react-compiler-no-manual-memoization
  • ⚠️ L70 Manual memoization in compiler-managed code react-compiler-no-manual-memoization

src/components/chat/MessageListRow.tsx

  • ⚠️ L32 Boolean prop combinations are hard to test no-many-boolean-props
  • ⚠️ L158 Manual memoization in compiler-managed code react-compiler-no-manual-memoization

src/components/chat/composables/useChatStatusBarAcpConfig.ts

  • ⚠️ L327 Loading flag reset outside finally no-loading-flag-reset-outside-finally

src/components/markdown/CodeBlock.tsx

  • ⚠️ L44 Manual memoization in compiler-managed code react-compiler-no-manual-memoization
  • ⚠️ L64 Manual memoization in compiler-managed code react-compiler-no-manual-memoization

src/components/markdown/useMarkdownLinkNavigation.ts

  • ⚠️ L23 Manual memoization in compiler-managed code react-compiler-no-manual-memoization
  • ⚠️ L24 Manual memoization in compiler-managed code react-compiler-no-manual-memoization
  • ⚠️ L29 Manual memoization in compiler-managed code react-compiler-no-manual-memoization
  • ⚠️ L145 Missing effect dependencies exhaustive-deps

src/components/message/MessageBlockContent.tsx

  • ⚠️ L145 Manual memoization in compiler-managed code react-compiler-no-manual-memoization

src/components/message/MessageBlockThink.tsx

  • ⚠️ L144 React Compiler can't optimize this set-state-in-effect
  • ⚠️ L150 Missing effect dependencies exhaustive-deps
  • ⚠️ L153 React Compiler can't optimize this set-state-in-effect
  • ⚠️ L171 Manual memoization in compiler-managed code react-compiler-no-manual-memoization
  • ⚠️ L176 Manual memoization in compiler-managed code react-compiler-no-manual-memoization
  • ⚠️ L178 Manual memoization in compiler-managed code react-compiler-no-manual-memoization
  • ⚠️ L188 Manual memoization in compiler-managed code react-compiler-no-manual-memoization
  • ⚠️ L189 Manual memoization in compiler-managed code react-compiler-no-manual-memoization
  • ⚠️ L191 Manual memoization in compiler-managed code react-compiler-no-manual-memoization
  • ⚠️ L255 Manual memoization in compiler-managed code react-compiler-no-manual-memoization

src/components/message/MessageItemAssistant.tsx

  • ⚠️ L271 Manual memoization in compiler-managed code react-compiler-no-manual-memoization
  • ⚠️ L349 Manual memoization in compiler-managed code react-compiler-no-manual-memoization

src/components/message/MessageTurnFold.tsx

  • ⚠️ L171 Manual memoization in compiler-managed code react-compiler-no-manual-memoization
  • ⚠️ L186 Manual memoization in compiler-managed code react-compiler-no-manual-memoization
  • ⚠️ L187 Manual memoization in compiler-managed code react-compiler-no-manual-memoization
  • ⚠️ L192 Manual memoization in compiler-managed code react-compiler-no-manual-memoization
  • ⚠️ L243 Manual memoization in compiler-managed code react-compiler-no-manual-memoization

src/pages/ChatPage.tsx

  • ⚠️ L610 State adjusted after a prop changes no-adjust-state-on-prop-change
  • ⚠️ L610 React Compiler can't optimize this set-state-in-effect
  • ⚠️ L615 State adjusted after a prop changes no-adjust-state-on-prop-change
  • ⚠️ L615 React Compiler can't optimize this set-state-in-effect

Reviewed by React Doctor for commit e1156fd. See inline comments for fixes.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 20

Note

Due to the large number of review comments, Critical, Major severity comments were prioritized as inline comments.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
apps/daemon/test/daemonSessionRoutes.test.ts (1)

890-909: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Use the spy result for the assertion.

interruptActiveTurn is a private AcpProviderExecutionPort method, so expect(provider.interruptActiveTurn, ...) can fail TypeScript checking. Store the vi.spyOn(...) result and assert on that result instead.

Proposed fix
-    vi.spyOn(provider as any, "interruptActiveTurn").mockResolvedValue(undefined);
+    const interruptActiveTurn = vi.spyFrom(provider as any, "interruptActiveTurn").mockResolvedValue(undefined);

-    expect(provider.interruptActiveTurn).toHaveBeenCalledWith("session-1");
+    expect(interruptActiveTurn).toHaveBeenCalledWith("session-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 `@apps/daemon/test/daemonSessionRoutes.test.ts` around lines 890 - 909, Store
the vi.spyOn result for interruptActiveTurn in a local variable before
exercising steerActiveTurn, then assert that variable was called with
"session-1" instead of accessing provider.interruptActiveTurn directly. Keep the
existing mock behavior and call arguments unchanged.
packages/ui/src/components/AppBar.tsx (1)

90-119: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Render window controls in browser mode on macOS.

Lines 90, 101, and 119 use !isBrowser. This renders the controls on native macOS and hides them in browser mode. Use isBrowser in each predicate.

Proposed fix
-        {(!isMacOS || !isBrowser) && (
+        {(!isMacOS || isBrowser) && (
🤖 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/AppBar.tsx` around lines 90 - 119, Update the
three window-control render predicates in AppBar so they use isBrowser rather
than !isBrowser, ensuring the controls render in macOS browser mode while
preserving the existing non-macOS behavior.
packages/ui/src/components/message/MessageBlockAction.tsx (1)

47-60: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Stop the interval when the block crosses 180 seconds.

The age check runs only when the effect starts or its dependencies change. A block that is 179 seconds old starts progressTimer, then continues to call setCurrentTime after 180 seconds while its status remains loading or pending. This defeats the stale-block guard and can leave an interval running for the block's lifetime.

Add a timeout or check the age inside the interval and clear it at the limit.

Suggested fix
  useEffect(() => {
-    if (isRateLimitActive) {
-      if (Date.now() - block.timestamp > 180_000) return;
+    if (!isRateLimitActive) return;
+    const remainingMs = 180_000 - (Date.now() - block.timestamp);
+    if (remainingMs <= 0) return;
+
+    progressTimer.current = window.setInterval(() => {
+      setCurrentTime(Date.now());
+    }, 1000);
+
+    const stopTimer = window.setTimeout(() => {
+      if (progressTimer.current !== null) {
+        window.clearInterval(progressTimer.current);
+        progressTimer.current = null;
+      }
+    }, remainingMs);
+
+    return () => {
+      window.clearTimeout(stopTimer);
+      if (progressTimer.current !== null) {
+        window.clearInterval(progressTimer.current);
+        progressTimer.current = null;
+      }
-      progressTimer.current = window.setInterval(() => {
-        setCurrentTime(Date.now());
-      }, 1000);
-    }
-    return () => {
-      if (progressTimer.current) {
-        clearInterval(progressTimer.current);
-      }
-    };
  }, [isRateLimitActive, block.timestamp]);
🤖 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/message/MessageBlockAction.tsx` around lines 47 -
60, Update the interval created in the rate-limit branch of the
MessageBlockAction effect to check the block age on each tick and clear the
interval once it reaches 180 seconds, preventing further setCurrentTime updates.
Preserve the existing immediate stale-block guard and cleanup behavior.
🟡 Minor comments (3)
packages/ui/src/components/chat/composables/useChatStatusBarAcpConfig.ts-87-87 (1)

87-87: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Clear session loading after a pushed configuration update.

When handleAcpConfigOptionsReady accepts a session payload, it sets the configuration as loaded but does not clear isAcpSessionConfigLoading. The loading indicator remains visible until the retry request finishes, or indefinitely if that request stalls.

Set setIsAcpSessionConfigLoading(false) in the accepted conversationId branch.

🤖 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/chat/composables/useChatStatusBarAcpConfig.ts` at
line 87, Update handleAcpConfigOptionsReady so the accepted conversationId
branch clears isAcpSessionConfigLoading by calling
setIsAcpSessionConfigLoading(false) when the pushed session configuration is
applied.
.commandcode/skills/migrate-radix-to-base/menus.md-67-67 (1)

67-67: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Document data-anchor-hidden on Positioner only.

Base UI applies this hook to the positioning part, so remove Popup from these migration notes and keep the CSS workaround scoped to the Positioner.

  • .commandcode/skills/migrate-radix-to-base/menus.md#L67
  • .commandcode/skills/migrate-radix-to-base/overlays.md#L231
🤖 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 @.commandcode/skills/migrate-radix-to-base/menus.md at line 67, Update the
hideWhenDetached migration notes to document data-anchor-hidden only on
Positioner, removing Popup references and scoping the CSS workaround selector to
Positioner. Apply this change in
.commandcode/skills/migrate-radix-to-base/menus.md:67 and
.commandcode/skills/migrate-radix-to-base/overlays.md:231.

Source: MCP tools

.commandcode/skills/migrate-radix-to-base/menus.md-52-52 (1)

52-52: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Add '' to the documented focus callback interaction types.

Base UI includes the empty interaction value, so add it to the focus callback types:

  • menus.md#L52: include '' for finalFocus.
  • overlays.md#L57-L58: include '' for initialFocus and finalFocus.
🤖 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 @.commandcode/skills/migrate-radix-to-base/menus.md at line 52, Add the empty
interaction value '' to the documented focus callback types: update finalFocus
in menus.md, and both initialFocus and finalFocus in overlays.md. Preserve the
existing interaction types and callback signatures while including '' in each
relevant InteractionType union.

Source: MCP tools

🤖 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 @.agents/skills/migrate-radix-to-base/class-mapping.md:
- Around line 3-4: Restrict the class rewrites in the class-mapping guidance to
verified migrated components by requiring selector-producer verification before
changing className values, cva definitions, or cn calls; do not rewrite custom
application hooks or intentionally untouched third-party components. Apply this
same scope restriction in .agents/skills/migrate-radix-to-base/class-mapping.md
lines 3-4 and .commandcode/skills/migrate-radix-to-base/class-mapping.md lines
3-4.

In @.agents/skills/migrate-radix-to-base/display-misc.md:
- Around line 63-66: Update the nonce migration entry in both
.agents/skills/migrate-radix-to-base/display-misc.md (lines 63-66) and
.commandcode/skills/migrate-radix-to-base/display-misc.md (lines 63-66) to
document Base UI’s CSPProvider, including both nonce and disableStyleElements,
instead of stating that no CSP equivalent exists.

In @.agents/skills/migrate-radix-to-base/form-controls.md:
- Around line 70-80: The Select positioning migration guidance must state that
Base UI ignores most Positioner positioning props while alignItemWithTrigger is
active, except during automatic fallback. Add this clarification to both
.agents/skills/migrate-radix-to-base/form-controls.md lines 70-80 and
.commandcode/skills/migrate-radix-to-base/form-controls.md lines 70-80,
preserving the existing prop mappings.

In @.agents/skills/migrate-radix-to-base/menus.md:
- Around line 9-14: Update the DirectionProvider reference in the migration
table to use the current `@base-ui/react/direction-provider` package path instead
of `@base-ui-components/react/direction-provider`, keeping the skill’s Base UI
package namespace consistent.

In @.agents/skills/migrate-radix-to-base/SKILL.md:
- Around line 122-124: Expand the “Verify and report” validation sequence in
both .agents/skills/migrate-radix-to-base/SKILL.md lines 122-124 and
.commandcode/skills/migrate-radix-to-base/SKILL.md lines 122-124 to include bun
run format, bun run lint, and the repository’s test command alongside the
existing per-file typecheck, batch build, and final full-build checks.
- Around line 57-60: Replace every grep-based search in the migration
documentation with the repository-approved fff MCP search. Update the leftover
sweep in .agents/skills/migrate-radix-to-base/SKILL.md:57-60, report-template
search in .agents/skills/migrate-radix-to-base/SKILL.md:154-156, mapping sweep
in .agents/skills/migrate-radix-to-base/universal-patterns.md:57-60, and
consumer sweep in .agents/skills/migrate-radix-to-base/consumer-props.md:54-55;
apply the corresponding fff replacements at
.commandcode/skills/migrate-radix-to-base/SKILL.md:57-60 and :154-156,
.commandcode/skills/migrate-radix-to-base/universal-patterns.md:57-60, and
.commandcode/skills/migrate-radix-to-base/consumer-props.md:54-55, preserving
each search’s existing patterns and scope.
- Around line 16-21: Pin the shadcn CLI to the exact reviewed version in the
preflight command described by both
.agents/skills/migrate-radix-to-base/SKILL.md lines 16-21 and
.commandcode/skills/migrate-radix-to-base/SKILL.md lines 16-21, replacing the
`@latest` reference while continuing to use the detected package manager for
execution and installs.

In @.agents/skills/migrate-radix-to-base/universal-patterns.md:
- Around line 76-80: The individual package migration guidance must only remove
an `@radix-ui/react-`* dependency after a repository-wide import sweep confirms
zero remaining consumers. Update the corresponding instruction in both
.agents/skills/migrate-radix-to-base/universal-patterns.md (lines 76-80) and
.commandcode/skills/migrate-radix-to-base/universal-patterns.md (lines 76-80),
preserving the named-import migration while making dependency removal
conditional.

In @.commandcode/skills/migrate-radix-to-base/menus.md:
- Around line 7-17: Revise the universal rules in
.commandcode/skills/migrate-radix-to-base/menus.md lines 7-17 so asChild maps to
render only for renderable parts; document that it is dropped for non-rendering
parts such as Menu.Root and overlay Root components. Apply the same narrowed
mapping and dropped-prop guidance in
.commandcode/skills/migrate-radix-to-base/overlays.md lines 7-13, without
changing the other migration mappings.

In `@apps/daemon/src/host/acp-provider-execution.ts`:
- Around line 561-575: Update the steering interruption flow around
active.controller.abort() to resolve every pendingPermissions entry for the
session with "cancelled" before awaiting active.donePromise. Extract or reuse
the existing pending-permission resolution logic from cancelGeneration so both
cancellation paths clear stale permission overlays consistently.
- Around line 563-575: The interruptActiveTurn flow currently starts its
four-second timeout only after getRuntime and session.connection.agent.notify
complete. Restructure interruptActiveTurn so runtime lookup, cancellation
notification, and active.donePromise all race against one shared four-second
deadline, allowing steerActiveTurn to proceed even when ACP access or
cancellation stalls.

In `@build/artifact-demo/nebula-flow.html`:
- Around line 164-173: Update initParticles() so each newly created particle
receives the intended theme color for hue, saturation, and lightness instead of
zero values. Preserve the existing particle allocation and position/velocity
initialization, and ensure resetField() also produces visible theme-colored
particles through this initialization path.
- Around line 41-43: Update the range controls and their labels so each slider
has an accessible name: associate the labels with the `speed` and `turb` inputs
using matching `for` and `id` attributes, and add a visible `:focus-visible`
style for range inputs to replace the removed outline. Preserve the existing
slider appearance and apply the focus treatment to both WebKit and Firefox
controls.

In `@build/artifact-demo/neon-snake.html`:
- Around line 212-217: Update the win handling around placeFood() to call the
existing shared gameOver() end-of-round function instead of setting state and
overlay elements inline. Ensure gameOver() handles both wins and collisions by
updating best, bestVal, localStorage, newBestTag, the heading, and overlay
state, while preserving the appropriate win versus collision outcome.
- Around line 332-352: Update the render order around drawParticles,
paintBackground, drawGrid, drawFood, and drawSnake: save and apply the
screen-shake translation before rendering the scene, paint the background before
drawing particles, then render the remaining scene and death flash under the
same transform. Restore the canvas context only after all scene effects have
completed.
- Around line 129-138: Update placeFood() so it only assigns food to a
coordinate confirmed not to overlap any snake segment. Replace the bounded
random retry behavior with selection from available empty cells, or return false
when no valid cell is found; never assign the last attempted occupied coordinate
or return true for it.

In `@packages/ui/src/components/AppBar.tsx`:
- Around line 26-30: Update the welcome-route comparison in the showUpdateButton
useMemo to match the browser pathname format, using the leading slash so the
update button remains hidden on "/welcome". Preserve the existing behavior for
non-welcome routes and non-browser mode.

In `@packages/ui/src/components/chat/AcpAdvancedSettings.tsx`:
- Around line 88-97: Use a safe accumulator for ACP option groups in
packages/ui/src/components/chat/AcpAdvancedSettings.tsx lines 88-97 and
packages/ui/src/components/chat/ChatStatusBar.tsx lines 1360-1367 by replacing
the plain object with Map or Object.create(null); update the grouping access and
insertion logic in both sites so keys such as __proto__ and constructor
initialize and collect entries correctly.

In `@packages/ui/src/pages/ChatPage.tsx`:
- Around line 456-462: In packages/ui/src/pages/ChatPage.tsx, move
draft-clearing from finally blocks to the success paths of
sendMessage/queueInput and steerActiveTurn, preserving message text and
attachments when requests fail; in onCommandSubmit, call setMessage("") before
clearInput() after successful submission. Update the affected sites at lines
456-462, 496-501, and 553-558.
- Around line 620-622: Update the useEffect that resets isCancelling to also
react to sessionId changes, resetting cancellation state when navigation
switches sessions even if isGenerating remains true. Keep the existing reset
behavior for changes to isGenerating and include sessionId in the effect
dependencies.

---

Outside diff comments:
In `@apps/daemon/test/daemonSessionRoutes.test.ts`:
- Around line 890-909: Store the vi.spyOn result for interruptActiveTurn in a
local variable before exercising steerActiveTurn, then assert that variable was
called with "session-1" instead of accessing provider.interruptActiveTurn
directly. Keep the existing mock behavior and call arguments unchanged.

In `@packages/ui/src/components/AppBar.tsx`:
- Around line 90-119: Update the three window-control render predicates in
AppBar so they use isBrowser rather than !isBrowser, ensuring the controls
render in macOS browser mode while preserving the existing non-macOS behavior.

In `@packages/ui/src/components/message/MessageBlockAction.tsx`:
- Around line 47-60: Update the interval created in the rate-limit branch of the
MessageBlockAction effect to check the block age on each tick and clear the
interval once it reaches 180 seconds, preventing further setCurrentTime updates.
Preserve the existing immediate stale-block guard and cleanup behavior.

---

Minor comments:
In @.commandcode/skills/migrate-radix-to-base/menus.md:
- Line 67: Update the hideWhenDetached migration notes to document
data-anchor-hidden only on Positioner, removing Popup references and scoping the
CSS workaround selector to Positioner. Apply this change in
.commandcode/skills/migrate-radix-to-base/menus.md:67 and
.commandcode/skills/migrate-radix-to-base/overlays.md:231.
- Line 52: Add the empty interaction value '' to the documented focus callback
types: update finalFocus in menus.md, and both initialFocus and finalFocus in
overlays.md. Preserve the existing interaction types and callback signatures
while including '' in each relevant InteractionType union.

In `@packages/ui/src/components/chat/composables/useChatStatusBarAcpConfig.ts`:
- Line 87: Update handleAcpConfigOptionsReady so the accepted conversationId
branch clears isAcpSessionConfigLoading by calling
setIsAcpSessionConfigLoading(false) when the pushed session configuration is
applied.
🪄 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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: ceadea82-57f8-4e7a-896d-7b8ce336afad

📥 Commits

Reviewing files that changed from the base of the PR and between 24e5ae4 and 958726e.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (57)
  • .agents/skills/migrate-radix-to-base/SKILL.md
  • .agents/skills/migrate-radix-to-base/class-mapping.md
  • .agents/skills/migrate-radix-to-base/consumer-props.md
  • .agents/skills/migrate-radix-to-base/disclosure.md
  • .agents/skills/migrate-radix-to-base/display-misc.md
  • .agents/skills/migrate-radix-to-base/form-controls.md
  • .agents/skills/migrate-radix-to-base/menus.md
  • .agents/skills/migrate-radix-to-base/overlays.md
  • .agents/skills/migrate-radix-to-base/universal-patterns.md
  • .agents/skills/migrate-radix-to-base/wrapper-shapes.md
  • .commandcode/skills/migrate-radix-to-base/SKILL.md
  • .commandcode/skills/migrate-radix-to-base/class-mapping.md
  • .commandcode/skills/migrate-radix-to-base/consumer-props.md
  • .commandcode/skills/migrate-radix-to-base/disclosure.md
  • .commandcode/skills/migrate-radix-to-base/display-misc.md
  • .commandcode/skills/migrate-radix-to-base/form-controls.md
  • .commandcode/skills/migrate-radix-to-base/menus.md
  • .commandcode/skills/migrate-radix-to-base/overlays.md
  • .commandcode/skills/migrate-radix-to-base/universal-patterns.md
  • .commandcode/skills/migrate-radix-to-base/wrapper-shapes.md
  • apps/daemon/src/host/acp-provider-execution.ts
  • apps/daemon/test/acpProviderExecution.test.ts
  • apps/daemon/test/daemonSessionRoutes.test.ts
  • apps/desktop/components.json
  • apps/desktop/src/main/routes/settings/settingsAdapter.ts
  • build/artifact-demo/nebula-flow.html
  • build/artifact-demo/neon-snake.html
  • packages/backend-core/src/dispatch/settings/settingsAdapter.ts
  • packages/shared-contracts/src/routes/settings.routes.ts
  • packages/ui/package.json
  • packages/ui/settings/components/CommonSettings.tsx
  • packages/ui/shadcn/components/ui/badge.tsx
  • packages/ui/shadcn/components/ui/button-group.tsx
  • packages/ui/shadcn/components/ui/button.tsx
  • packages/ui/shadcn/components/ui/input.tsx
  • packages/ui/shadcn/components/ui/label.tsx
  • packages/ui/shadcn/components/ui/separator.tsx
  • packages/ui/src/assets/style.css
  • packages/ui/src/components/AppBar.tsx
  • packages/ui/src/components/chat/AcpAdvancedSettings.tsx
  • packages/ui/src/components/chat/ChatInputBox.tsx
  • packages/ui/src/components/chat/ChatInputToolbar.tsx
  • packages/ui/src/components/chat/ChatStatusBar.tsx
  • packages/ui/src/components/chat/MessageList.tsx
  • packages/ui/src/components/chat/MessageListRow.tsx
  • packages/ui/src/components/chat/composables/useChatStatusBarAcpConfig.ts
  • packages/ui/src/components/markdown/useMarkdownLinkNavigation.ts
  • packages/ui/src/components/message/MessageBlockAction.tsx
  • packages/ui/src/components/message/MessageBlockContent.tsx
  • packages/ui/src/components/message/MessageItemAssistant.tsx
  • packages/ui/src/pages/ChatPage.tsx
  • packages/ui/src/pages/NewThreadPage.tsx
  • packages/ui/src/routeTree.gen.ts
  • packages/ui/src/stores/artifact.ts
  • packages/ui/src/stores/ui/message.ts
  • packages/ui/src/stores/uiSettingsStore.ts
  • skills-lock.json
💤 Files with no reviewable changes (1)
  • packages/ui/src/assets/style.css

Comment on lines +3 to +4
Apply these across ALL class strings (className, cva definitions, cn calls),
including app code. They are safe, mechanical rewrites.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Restrict class rewrites to verified migrated components.

The global scope can rewrite custom application hooks and intentionally untouched third-party components.

  • .agents/skills/migrate-radix-to-base/class-mapping.md#L3-L4: require selector-producer verification.
  • .commandcode/skills/migrate-radix-to-base/class-mapping.md#L3-L4: apply the same scope restriction.
📍 Affects 2 files
  • .agents/skills/migrate-radix-to-base/class-mapping.md#L3-L4 (this comment)
  • .commandcode/skills/migrate-radix-to-base/class-mapping.md#L3-L4
🤖 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 @.agents/skills/migrate-radix-to-base/class-mapping.md around lines 3 - 4,
Restrict the class rewrites in the class-mapping guidance to verified migrated
components by requiring selector-producer verification before changing className
values, cva definitions, or cn calls; do not rewrite custom application hooks or
intentionally untouched third-party components. Apply this same scope
restriction in .agents/skills/migrate-radix-to-base/class-mapping.md lines 3-4
and .commandcode/skills/migrate-radix-to-base/class-mapping.md lines 3-4.

Comment thread .agents/skills/migrate-radix-to-base/display-misc.md Outdated
Comment thread .agents/skills/migrate-radix-to-base/form-controls.md Outdated
Comment on lines +9 to +14
| Radix pattern | Base UI equivalent |
| --- | --- |
| `asChild` (`boolean`, `false`) | `render` (`ReactElement \| ((props: HTMLProps, state) => ReactElement)`). No merge-onto-child boolean; pass the element or a function. |
| `dir` (`"ltr" \| "rtl"`) on roots | Dropped everywhere. Base UI reads direction from `<DirectionProvider>` (`@base-ui-components/react/direction-provider`) or the DOM `dir` attribute. |
| `forceMount` (`boolean`) | `keepMounted` (`boolean`, `false`) on `Portal` / indicator parts. Same use case (animation/SEO), presence is CSS-driven via `data-starting-style` / `data-ending-style` instead of Radix `data-state` + forced mount. |
| `onEscapeKeyDown` / `onPointerDownOutside` / `onFocusOutside` / `onInteractOutside` (content parts) | Dropped as separate props. Use `onOpenChange(open, eventDetails)` on the Root and branch on `eventDetails.reason` (`'escape-key'`, `'outside-press'`, `'focus-out'`, ...). Call `eventDetails.cancel()` to prevent the close (replaces `event.preventDefault()`). |

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Use the current Base UI package name.

@base-ui-components/react/direction-provider is the former package path. The migration guidance targets @base-ui/react@1.6.0, so this import path can fail after migration. Change it to @base-ui/react/direction-provider and use one package namespace throughout the skill. Base UI release notes document the package rename. (base-ui.com)

#!/usr/bin/env bash
set -euo pipefail
bun pm ls `@base-ui/react`
🤖 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 @.agents/skills/migrate-radix-to-base/menus.md around lines 9 - 14, Update
the DirectionProvider reference in the migration table to use the current
`@base-ui/react/direction-provider` package path instead of
`@base-ui-components/react/direction-provider`, keeping the skill’s Base UI
package namespace consistent.

Comment thread .agents/skills/migrate-radix-to-base/SKILL.md Outdated
Comment thread build/artifact-demo/neon-snake.html Outdated
Comment on lines +332 to +352
drawParticles(dt);

paintBackground(false);
drawGrid();
if (state !== "start") drawFood(tGlobal);
if (state === "playing" || state === "paused" || state === "dead") drawSnake();

// screen shake on death
if (shake > 0) {
ctx.save();
ctx.translate((Math.random() - 0.5) * shake, (Math.random() - 0.5) * shake);
shake *= 0.86;
if (shake < 0.5) shake = 0;
}
// red flash on death
if (state === "dead") {
ctx.globalCompositeOperation = "source-over";
ctx.fillStyle = `rgba(248, 60, 90, ${0.08 + Math.random() * 0.05})`;
ctx.fillRect(0, 0, W, H);
}
ctx.restore();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Correct the canvas render order.

Line 332 draws particles before Line 334 fills the canvas. The background erases every particle each frame. Lines 341-345 apply the translation after the grid, food, and snake render. Only later drawing can move, so the scene does not shake.

Save and translate the context before rendering the scene. Paint the background before drawing particles. Restore the context after all scene effects render.

🤖 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 `@build/artifact-demo/neon-snake.html` around lines 332 - 352, Update the
render order around drawParticles, paintBackground, drawGrid, drawFood, and
drawSnake: save and apply the screen-shake translation before rendering the
scene, paint the background before drawing particles, then render the remaining
scene and death flash under the same transform. Restore the canvas context only
after all scene effects have completed.

Comment thread packages/ui/src/components/AppBar.tsx Outdated
Comment on lines +88 to +97
const selectGrouped = selectEntries.reduce<
Record<string, { label: string; entries: typeof selectEntries }>
>((acc, entry) => {
const g = resolveAcpOptionGroup(entry);
if (!acc[g.key]) {
acc[g.key] = { label: g.label, entries: [] };
}
acc[g.key].entries.push(entry);
return acc;
}, {});

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Use a safe map for ACP group keys.

A group key of __proto__, constructor, or another inherited property bypasses group initialization. The subsequent entries.push then throws during rendering. ACP option metadata supplies these keys.

  • packages/ui/src/components/chat/AcpAdvancedSettings.tsx#L88-L97: replace the plain-object accumulator with Map, or initialize it with Object.create(null).
  • packages/ui/src/components/chat/ChatStatusBar.tsx#L1360-L1367: apply the same safe accumulator implementation.
📍 Affects 2 files
  • packages/ui/src/components/chat/AcpAdvancedSettings.tsx#L88-L97 (this comment)
  • packages/ui/src/components/chat/ChatStatusBar.tsx#L1360-L1367
🤖 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/chat/AcpAdvancedSettings.tsx` around lines 88 -
97, Use a safe accumulator for ACP option groups in
packages/ui/src/components/chat/AcpAdvancedSettings.tsx lines 88-97 and
packages/ui/src/components/chat/ChatStatusBar.tsx lines 1360-1367 by replacing
the plain object with Map or Object.create(null); update the grouping access and
insertion logic in both sites so keys such as __proto__ and constructor
initialize and collect entries correctly.

Comment thread packages/ui/src/pages/ChatPage.tsx Outdated
Comment on lines +456 to +462
} catch (error) {
console.error("[ChatPage] send message failed:", error);
} finally {
setMessage("");
setAttachedFiles([]);
chatInputRef.current?.clearInput();
schedulePostSubmitScrollToBottom();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Keep the draft until submission succeeds.

Each catch flows into finally, which clears typed text, attachments, and the editor after a failed request. This discards the user's draft. onCommandSubmit also suppresses the editor update without calling setMessage(""), so successful command submission leaves stale controlled input state.

  • packages/ui/src/pages/ChatPage.tsx#L456-L462: clear the draft only after sendMessage or queueInput succeeds.
  • packages/ui/src/pages/ChatPage.tsx#L496-L501: preserve the draft on failure; on success, call setMessage("") before clearInput().
  • packages/ui/src/pages/ChatPage.tsx#L553-L558: clear the draft only after steerActiveTurn succeeds.
📍 Affects 1 file
  • packages/ui/src/pages/ChatPage.tsx#L456-L462 (this comment)
  • packages/ui/src/pages/ChatPage.tsx#L496-L501
  • packages/ui/src/pages/ChatPage.tsx#L553-L558
🤖 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/pages/ChatPage.tsx` around lines 456 - 462, In
packages/ui/src/pages/ChatPage.tsx, move draft-clearing from finally blocks to
the success paths of sendMessage/queueInput and steerActiveTurn, preserving
message text and attachments when requests fail; in onCommandSubmit, call
setMessage("") before clearInput() after successful submission. Update the
affected sites at lines 456-462, 496-501, and 553-558.

Comment thread packages/ui/src/pages/ChatPage.tsx Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 7

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
packages/ui/src/components/message/MessageToolbar.tsx (1)

121-353: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Add aria-label to each icon-only Button.

The affected buttons are rendered inside TooltipTrigger and do not get an accessible name from the text that appears only in TooltipContent. Add an action-matching aria-label to each icon-only button.

🤖 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/message/MessageToolbar.tsx` around lines 121 -
353, Each icon-only Button in MessageToolbar.tsx (lines 121-353), including
save, cancel, retry, variant navigation, copy, image copy, trace, fork, edit,
and delete actions, needs an action-matching aria-label; also add the
corresponding labels to the icon-only buttons in MessageBlockImage.tsx (lines
151-164) and MessageBlockToolCallImagePreview.tsx (lines 117-130). Do not rely
on TooltipContent for accessible naming.
packages/ui/shadcn/components/ui/tabs.tsx (1)

34-44: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Preserve automatic tab activation.

Base UI Tabs.List defaults activateOnFocus to false, while the previous Radix tabs behaved automatically. Set activateOnFocus = true in TabsList and pass it to TabsPrimitive.List to keep keyboard activation consistent for consumers such as RemoteSettings and EmojiPicker.

🤖 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/shadcn/components/ui/tabs.tsx` around lines 34 - 44, Update the
TabsList component to default activateOnFocus to true and pass that prop through
to TabsPrimitive.List, preserving automatic keyboard tab activation for existing
consumers.
🧹 Nitpick comments (3)
packages/ui/tsconfig.app.json (1)

51-53: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use #-prefixed aliases for internal modules.

The new bare shadcn/* alias enables imports that violate the repository convention. Retain #shadcn/* and update all new callers.

  • packages/ui/tsconfig.app.json#L51-L53: remove shadcn/*.
  • packages/ui/shadcn/components/ui/card.tsx#L3-L3: use #shadcn/lib/utils.
  • packages/ui/shadcn/components/ui/checkbox.tsx#L3-L3: use #shadcn/lib/utils.
  • packages/ui/shadcn/components/ui/dialog.tsx#L4-L5: use #shadcn/lib/utils and #shadcn/components/ui/button.
  • packages/ui/shadcn/components/ui/scroll-area.tsx#L4-L4: use #shadcn/lib/utils.
  • packages/ui/shadcn/components/ui/select.tsx#L6-L6: use #shadcn/lib/utils.

As per coding guidelines, use #-prefixed aliases for internal modules.

🤖 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/tsconfig.app.json` around lines 51 - 53, Replace the bare
shadcn/* path alias in packages/ui/tsconfig.app.json (lines 51-53) by retaining
only the `#shadcn/`* alias, then update imports in
packages/ui/shadcn/components/ui/card.tsx (line 3), checkbox.tsx (line 3),
dialog.tsx (lines 4-5), scroll-area.tsx (line 4), and select.tsx (line 6) to use
`#shadcn/lib/utils`; in dialog.tsx, also use `#shadcn/components/ui/button`.

Source: Coding guidelines

packages/ui/shadcn/components/ui/context-menu.tsx (2)

128-129: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Merge the submenu class with cn.

props spreads after the literal className. A caller className therefore replaces "shadow-lg" instead of extending it. Merge both values.

♻️ Proposed refactor
-function ContextMenuSubContent({ ...props }: React.ComponentProps<typeof ContextMenuContent>) {
-  return <ContextMenuContent data-slot="context-menu-sub-content" className="shadow-lg" side="right" {...props} />;
+function ContextMenuSubContent({ className, ...props }: React.ComponentProps<typeof ContextMenuContent>) {
+  return (
+    <ContextMenuContent
+      data-slot="context-menu-sub-content"
+      className={cn("shadow-lg", className)}
+      side="right"
+      {...props}
+    />
+  );
 }
🤖 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/shadcn/components/ui/context-menu.tsx` around lines 128 - 129,
Update ContextMenuSubContent to merge the default "shadow-lg" class with
props.className via the existing cn utility, ensuring caller classes extend
rather than replace the submenu styling while preserving the remaining props
behavior.

4-4: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Restore the #shadcn/... alias in shadcn imports. Vite aliases both #shadcn and shadcn to shadcn, but the project guideline uses #-prefixed aliases for internal modules, while existing consumers import through #shadcn/.... Bring these primitive imports back to #shadcn/... so the internal module scheme is consistent.

🤖 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/shadcn/components/ui/context-menu.tsx` at line 4, Restore the
`#shadcn/`... alias for primitive imports in context-menu.tsx, dropdown-menu.tsx,
field.tsx, radio-group.tsx, slider.tsx, spinner.tsx, table.tsx, and textarea.tsx
at the listed import sites. Replace each unprefixed shadcn/... path with its
`#shadcn/`... equivalent while preserving the imported symbols and other imports.

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 `@packages/ui/components.json`:
- Around line 15-20: Restore the # prefix for every internal alias value in
packages/ui/components.json (lines 15-20). Update the cn imports in
packages/ui/shadcn/components/ui/accordion.tsx (line 3), popover.tsx (line 6),
skeleton.tsx (line 1), tabs.tsx (line 6), and tooltip.tsx (line 3) to use the
`#shadcn/lib/utils` convention consistently.

In `@packages/ui/shadcn/components/ui/alert-dialog.tsx`:
- Around line 6-7: Update the imports in
packages/ui/shadcn/components/ui/alert-dialog.tsx lines 6-7 to use the `#shadcn/`*
alias. Apply the same alias change to all four imports in
packages/ui/shadcn/components/ui/input-group.tsx lines 4-7 and the utility
import in packages/ui/shadcn/components/ui/kbd.tsx line 1; make no other
changes.
- Around line 125-127: Update AlertDialogAction to compose through
AlertDialogPrimitive.Close.render, matching AlertDialogCancel, while preserving
its existing Button styling, data-slot, className handling, and props. Ensure
confirmation actions notify the alert dialog close primitive so controlled
open/onOpenChange state is updated before or alongside the action handler.

In `@packages/ui/shadcn/components/ui/dropdown-menu.tsx`:
- Around line 38-45: Remove the w-(--anchor-width) utility from the class list
passed to MenuPrimitive.Popup in the dropdown menu content component, preserving
the existing min-w-32 sizing and other styles so labels do not wrap based on
trigger width.

In `@packages/ui/shadcn/components/ui/slider.tsx`:
- Around line 5-16: Update Slider to resolve scalar and array value/defaultValue
inputs into the correct thumb values, preserving a single-number input as one
thumb instead of falling back to [min, max]. Use the resolved value when
configuring SliderPrimitive.Root while retaining the existing min/max defaults
and thumbAlignment behavior.

In `@packages/ui/src/components/message/ImageActionContextMenu.tsx`:
- Line 42: Update the wrapper rendered by ContextMenuTrigger in
ImageActionContextMenu so it is layout-transparent and preserves the preview
button as the grid item, then verify other grid and flex call sites retain their
existing child structure and layout behavior.

In `@packages/ui/vite.config.ts`:
- Line 56: Use one `#-prefixed` internal alias convention: remove the bare shadcn
alias in packages/ui/vite.config.ts at lines 56-56, and update imports in
packages/ui/shadcn/components/ui/alert.tsx lines 4-4, button-group.tsx lines
5-6, empty.tsx lines 3-3, label.tsx lines 3-3, progress.tsx lines 3-3, and
sheet.tsx lines 4-5 to use `#shadcn/`* paths for cn, Separator, and Button.

---

Outside diff comments:
In `@packages/ui/shadcn/components/ui/tabs.tsx`:
- Around line 34-44: Update the TabsList component to default activateOnFocus to
true and pass that prop through to TabsPrimitive.List, preserving automatic
keyboard tab activation for existing consumers.

In `@packages/ui/src/components/message/MessageToolbar.tsx`:
- Around line 121-353: Each icon-only Button in MessageToolbar.tsx (lines
121-353), including save, cancel, retry, variant navigation, copy, image copy,
trace, fork, edit, and delete actions, needs an action-matching aria-label; also
add the corresponding labels to the icon-only buttons in MessageBlockImage.tsx
(lines 151-164) and MessageBlockToolCallImagePreview.tsx (lines 117-130). Do not
rely on TooltipContent for accessible naming.

---

Nitpick comments:
In `@packages/ui/shadcn/components/ui/context-menu.tsx`:
- Around line 128-129: Update ContextMenuSubContent to merge the default
"shadow-lg" class with props.className via the existing cn utility, ensuring
caller classes extend rather than replace the submenu styling while preserving
the remaining props behavior.
- Line 4: Restore the `#shadcn/`... alias for primitive imports in
context-menu.tsx, dropdown-menu.tsx, field.tsx, radio-group.tsx, slider.tsx,
spinner.tsx, table.tsx, and textarea.tsx at the listed import sites. Replace
each unprefixed shadcn/... path with its `#shadcn/`... equivalent while preserving
the imported symbols and other imports.

In `@packages/ui/tsconfig.app.json`:
- Around line 51-53: Replace the bare shadcn/* path alias in
packages/ui/tsconfig.app.json (lines 51-53) by retaining only the `#shadcn/`*
alias, then update imports in packages/ui/shadcn/components/ui/card.tsx (line
3), checkbox.tsx (line 3), dialog.tsx (lines 4-5), scroll-area.tsx (line 4), and
select.tsx (line 6) to use `#shadcn/lib/utils`; in dialog.tsx, also use
`#shadcn/components/ui/button`.
🪄 Autofix

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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: f4b03d56-3fa1-41d6-a40f-7bea2178fa2d

📥 Commits

Reviewing files that changed from the base of the PR and between 958726e and eb82f60.

📒 Files selected for processing (96)
  • apps/daemon/src/host/acp-provider-execution.ts
  • packages/ui/components.json
  • packages/ui/settings/components/AboutUsSettings.tsx
  • packages/ui/settings/components/AcpDiagnostics.tsx
  • packages/ui/settings/components/AcpSettings.tsx
  • packages/ui/settings/components/ArgosAgentsSettings.tsx
  • packages/ui/settings/components/BedrockProviderSettingsDetail.tsx
  • packages/ui/settings/components/BuiltinKnowledgeSettings.tsx
  • packages/ui/settings/components/DataSettings.tsx
  • packages/ui/settings/components/DifyKnowledgeSettings.tsx
  • packages/ui/settings/components/FastGptKnowledgeSettings.tsx
  • packages/ui/settings/components/GeminiSafetyConfig.tsx
  • packages/ui/settings/components/KnowledgeFile.tsx
  • packages/ui/settings/components/KnowledgeFileItem.tsx
  • packages/ui/settings/components/McpSettings.tsx
  • packages/ui/settings/components/MemoryManagerPanel.tsx
  • packages/ui/settings/components/NotificationsHooksSettings.tsx
  • packages/ui/settings/components/OllamaProviderSettingsDetail.tsx
  • packages/ui/settings/components/ProviderApiConfig.tsx
  • packages/ui/settings/components/ProviderModelList.tsx
  • packages/ui/settings/components/RagflowKnowledgeSettings.tsx
  • packages/ui/settings/components/RemoteSettings.tsx
  • packages/ui/settings/components/ScheduledTasksSettings.tsx
  • packages/ui/settings/components/VertexProviderSettingsDetail.tsx
  • packages/ui/settings/components/VoiceAIProviderConfig.tsx
  • packages/ui/settings/components/common/ProxySettingsSection.tsx
  • packages/ui/settings/components/display/FontSettingsSection.tsx
  • packages/ui/settings/components/prompt/CustomPromptSettingsSection.tsx
  • packages/ui/settings/components/prompt/SystemPromptSettingsSection.tsx
  • packages/ui/settings/main.tsx
  • packages/ui/shadcn/components/ui/accordion.tsx
  • packages/ui/shadcn/components/ui/alert-dialog.tsx
  • packages/ui/shadcn/components/ui/alert.tsx
  • packages/ui/shadcn/components/ui/badge.tsx
  • packages/ui/shadcn/components/ui/button-group.tsx
  • packages/ui/shadcn/components/ui/button.tsx
  • packages/ui/shadcn/components/ui/card.tsx
  • packages/ui/shadcn/components/ui/checkbox.tsx
  • packages/ui/shadcn/components/ui/collapsible.tsx
  • packages/ui/shadcn/components/ui/context-menu.tsx
  • packages/ui/shadcn/components/ui/dialog.tsx
  • packages/ui/shadcn/components/ui/dropdown-menu.tsx
  • packages/ui/shadcn/components/ui/empty.tsx
  • packages/ui/shadcn/components/ui/field.tsx
  • packages/ui/shadcn/components/ui/input-group.tsx
  • packages/ui/shadcn/components/ui/input.tsx
  • packages/ui/shadcn/components/ui/kbd.tsx
  • packages/ui/shadcn/components/ui/label.tsx
  • packages/ui/shadcn/components/ui/popover.tsx
  • packages/ui/shadcn/components/ui/progress.tsx
  • packages/ui/shadcn/components/ui/radio-group.tsx
  • packages/ui/shadcn/components/ui/scroll-area.tsx
  • packages/ui/shadcn/components/ui/select.tsx
  • packages/ui/shadcn/components/ui/separator.tsx
  • packages/ui/shadcn/components/ui/sheet.tsx
  • packages/ui/shadcn/components/ui/skeleton.tsx
  • packages/ui/shadcn/components/ui/slider.tsx
  • packages/ui/shadcn/components/ui/spinner.tsx
  • packages/ui/shadcn/components/ui/switch.tsx
  • packages/ui/shadcn/components/ui/table.tsx
  • packages/ui/shadcn/components/ui/tabs.tsx
  • packages/ui/shadcn/components/ui/textarea.tsx
  • packages/ui/shadcn/components/ui/tooltip.tsx
  • packages/ui/src/components/ConnectionIndicator.tsx
  • packages/ui/src/components/FolderPicker.tsx
  • packages/ui/src/components/WindowSideBar.tsx
  • packages/ui/src/components/WorkspaceSelector.tsx
  • packages/ui/src/components/chat-input/McpIndicator.tsx
  • packages/ui/src/components/chat/AcpAdvancedSettings.tsx
  • packages/ui/src/components/chat/ChatInputToolbar.tsx
  • packages/ui/src/components/chat/ChatStatusBar.tsx
  • packages/ui/src/components/chat/ChatTopBar.tsx
  • packages/ui/src/components/chat/MessageList.tsx
  • packages/ui/src/components/chat/composables/useChatStatusBarAcpConfig.ts
  • packages/ui/src/components/emoji-picker/EmojiPicker.tsx
  • packages/ui/src/components/mcp-config/components/McpPromptPanel.tsx
  • packages/ui/src/components/mcp-config/components/McpResourceViewer.tsx
  • packages/ui/src/components/mcp-config/components/McpServerCard.tsx
  • packages/ui/src/components/mcp-config/components/McpServers.tsx
  • packages/ui/src/components/mcp-config/components/McpToolPanel.tsx
  • packages/ui/src/components/mcp/McpSamplingDialog.tsx
  • packages/ui/src/components/message/ImageActionContextMenu.tsx
  • packages/ui/src/components/message/MessageBlockAction.tsx
  • packages/ui/src/components/message/MessageBlockImage.tsx
  • packages/ui/src/components/message/MessageBlockToolCallImagePreview.tsx
  • packages/ui/src/components/message/MessageItemAssistant.tsx
  • packages/ui/src/components/message/MessageToolbar.tsx
  • packages/ui/src/components/settings/ModelCheckDialog.tsx
  • packages/ui/src/components/settings/OpenAIImageGenerationSettingsFields.tsx
  • packages/ui/src/components/settings/TtsSettingsFields.tsx
  • packages/ui/src/components/workspace/WorkspaceFileNode.tsx
  • packages/ui/src/main.tsx
  • packages/ui/src/pages/ChatPage.tsx
  • packages/ui/src/pages/NewThreadPage.tsx
  • packages/ui/tsconfig.app.json
  • packages/ui/vite.config.ts
🚧 Files skipped from review as they are similar to previous changes (13)
  • packages/ui/src/components/message/MessageBlockAction.tsx
  • packages/ui/src/components/message/MessageItemAssistant.tsx
  • packages/ui/src/components/chat/MessageList.tsx
  • packages/ui/src/pages/NewThreadPage.tsx
  • packages/ui/shadcn/components/ui/button.tsx
  • packages/ui/src/components/chat/composables/useChatStatusBarAcpConfig.ts
  • packages/ui/src/components/chat/AcpAdvancedSettings.tsx
  • packages/ui/shadcn/components/ui/separator.tsx
  • apps/daemon/src/host/acp-provider-execution.ts
  • packages/ui/src/components/chat/ChatInputToolbar.tsx
  • packages/ui/shadcn/components/ui/input.tsx
  • packages/ui/src/components/chat/ChatStatusBar.tsx
  • packages/ui/shadcn/components/ui/badge.tsx

Comment thread packages/ui/components.json Outdated
Comment thread packages/ui/shadcn/components/ui/alert-dialog.tsx Outdated
Comment on lines +125 to 127
function AlertDialogAction({ className, ...props }: React.ComponentProps<typeof Button>) {
return <Button data-slot="alert-dialog-action" className={cn(className)} {...props} />;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== locate file and related files =="
fd -a 'alert-dialog\.tsx|dialog\.tsx' packages/ui/shadcn/components/ui 2>/dev/null || true

echo "== inspect target file outline =="
ast-grep outline packages/ui/shadcn/components/ui/alert-dialog.tsx || true

echo "== relevant sections =="
sed -n '1,180p' packages/ui/shadcn/components/ui/alert-dialog.tsx

echo "== usages of AlertDialogAction =="
rg -n "AlertDialogAction|AlertDialog\.(Open|Close|Cancel|Trigger|Action)" packages -g '*.tsx' -g '*.ts' | head -200

Repository: dvaJi/argos

Length of output: 10404


🌐 Web query:

@base-ui/react alert-dialog Close render property Close.Props

💡 Result:

In the @base-ui/react Alert Dialog component, AlertDialog.Close accepts a render prop that allows you to replace or compose the underlying element [1]. The render prop is defined as follows: render: ReactElement | function This prop allows you to replace the component's default HTML element (a element by default) with a different tag or compose it with another component [1]. It accepts either a ReactElement or a function that returns the element to be rendered [1]. Additionally, there is a related nativeButton prop: nativeButton: boolean (default: true) This prop specifies whether the component renders a native element when replacing it via the render prop. You should set this to false if the rendered element is not a button (for example, if you are rendering an tag) [1]. Summary of AlertDialog.Close Props: - render: Customizes the element rendering [1]. - nativeButton: Indicates if the rendered element is a native button, which helps with correct accessibility and behavior when using the render prop [1].

Citations:


🌐 Web query:

Base UI React alert-dialog primitive close component documentation

💡 Result:

In Base UI for React, the AlertDialog.Close component is a primitive used to render a button that closes the alert dialog when clicked [1][2]. Usage To implement the close functionality, include the AlertDialog.Close component within the AlertDialog.Popup [3][1]: import { AlertDialog } from '@base-ui/react/alert-dialog'; <AlertDialog.Root> <AlertDialog.Trigger /> <AlertDialog.Portal> <AlertDialog.Backdrop /> <AlertDialog.Viewport> <AlertDialog.Popup> <AlertDialog.Title /> <AlertDialog.Description /> <AlertDialog.Close>Close</AlertDialog.Close> </AlertDialog.Popup> </AlertDialog.Viewport> </AlertDialog.Portal> </AlertDialog.Root> Imperative Closing In addition to the declarative AlertDialog.Close component, you can close the dialog imperatively using the actionsRef prop on the AlertDialog.Root component [1][4]. The actionsRef object provides a close method [1][2]: const actionsRef = React.useRef(null); // Close the dialog imperatively actionsRef.current?.close; <AlertDialog.Root actionsRef={actionsRef}>... </AlertDialog.Root> When using the AlertDialog.createHandle method, you can also access a close method on the handle object, which is useful for controlling the dialog from external triggers [1].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== package versions =="
if [ -f package.json ]; then
  node -e 'const p=require("./package.json"); console.log(JSON.stringify({workspaces:p.workspaces, devDependencies:p.devDependencies, dependencies:p.dependencies}, null, 2))' | rg -n "`@base-ui/react`|bun|react" -C 2 || true
fi

echo "== lock/package manager files =="
git ls-files '*lock*' '.bun*' 'pnpm-lock.yaml' 'yarn.lock' package.json package-lock.json 2>/dev/null | head -100

echo "== inspect consumers around dismiss logic =="
for f in \
  packages/ui/settings/components/KnowledgeFileItem.tsx \
  packages/ui/settings/components/ProviderRateLimitConfig.tsx \
  packages/ui/settings/components/AcpSettings.tsx \
  packages/ui/settings/components/MemoryManagerPanel.tsx \
  packages/ui/settings/components/DataSettings.tsx \
  packages/ui/src/components/ui/MessageDialog.tsx \
  packages/ui/settings/components/BuiltinKnowledgeSettings.tsx \
  packages/ui/settings/components/skills/SkillInstallDialog.tsx \
  packages/ui/settings/components/prompt/SystemPromptSettingsSection.tsx \
  packages/ui/settings/components/prompt/CustomPromptSettingsSection.tsx
do
  if [ -f "$f" ]; then
    echo "--- $f ---"
    rg -n -A 20 -B 15 "AlertDialogAction|AlertDialogClose|AlertDialogCancel|AlertDialog|open|isOpen|handleClose|setOpen|confirm|delete|disable" "$f" || true
  fi
done

echo "== any explicit root actionsRef usage =="
rg -n "actionsRef|openState|setOpen|set\s*=[" packages/ui -g '*.tsx' -g '*.ts' | rg -n "Alert.*Dialog|AlertDialog|alert-dialog|openState|isOpen|setOpen|actionsRef" | head -200

Repository: dvaJi/argos

Length of output: 50368


🌐 Web query:

@base-ui/react alert-dialog version 1.0.0 AlertDialog.Close render prop source

💡 Result:

In @base-ui/react, the AlertDialog.Close component supports a render prop, which allows you to override the default HTML element (a button) or compose the component with custom React elements [1][2]. The render prop accepts either a ReactElement or a function [1][2]. When using a function, it provides access to the component's internal props and state, giving you complete control over how the component is rendered [2]. For implementation, Base UI components utilize an internal hook called useRender [3]. This hook manages the merging of external props with internal behavior, ensuring that event handlers are correctly merged, className and style properties are combined, and other props are applied to the underlying DOM node [2][3]. To use the render prop for AlertDialog.Close, you can provide it directly to the component: <AlertDialog.Close render={(props) => ( <button {...props} className="custom-close-button"> Close

)} /> Alternatively, for simple element replacement, you can pass a React element: <AlertDialog.Close render={} /> It is important that any custom component used with the render prop forwards the ref and spreads the received props onto its underlying DOM node to ensure proper functionality and accessibility [2].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== locate lock entries for base-ui =="
rg -n '"(`@base-ui/react`|base-ui)"|`@base-ui/react`' bun.lock package.json -S | head -100 || true

echo "== dependency files =="
git ls-files | rg '(^|/)(package\.json|bun\.lock|tsconfig|.*config\..*)$' | head -200

Repository: dvaJi/argos

Length of output: 2587


Keep confirm actions linked to the close primitive.

AlertDialogCancel uses AlertDialogPrimitive.Close.render, while AlertDialogAction calls Button directly. For controlled AlertDialog open={...}/onOpenChange={...} dialogs, use the same Close composition or update every consumer to close the dialog before handling confirmation.

🤖 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/shadcn/components/ui/alert-dialog.tsx` around lines 125 - 127,
Update AlertDialogAction to compose through AlertDialogPrimitive.Close.render,
matching AlertDialogCancel, while preserving its existing Button styling,
data-slot, className handling, and props. Ensure confirmation actions notify the
alert dialog close primitive so controlled open/onOpenChange state is updated
before or alongside the action handler.

Comment thread packages/ui/shadcn/components/ui/dropdown-menu.tsx
Comment on lines +5 to +16
function Slider({ className, defaultValue, value, min = 0, max = 100, ...props }: SliderPrimitive.Root.Props) {
const _values = Array.isArray(value) ? value : Array.isArray(defaultValue) ? defaultValue : [min, max];

return (
<SliderPrimitive.Root
className={cn("data-horizontal:w-full data-vertical:h-full", className)}
data-slot="slider"
defaultValue={defaultValue}
value={value}
min={min}
max={max}
className={cn(
"relative flex w-full touch-none items-center select-none data-disabled:opacity-50 data-vertical:h-full data-vertical:min-h-40 data-vertical:w-auto data-vertical:flex-col",
className,
)}
thumbAlignment="edge"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

Base UI React Slider Root thumbAlignment prop

💡 Result:

The thumbAlignment prop on the Base UI React Slider.Root component determines how thumbs are aligned relative to the Slider.Control element when a thumb's value is at its minimum or maximum [1][2][3]. This prop accepts the following values [1][2]: - center (default): The center of the thumb is aligned with the edge of the control [1][2]. - edge: The thumb is inset within the control, ensuring its edge is aligned with the edge of the control [1][2]. This prevents the thumb from overflowing the control's bounds [1][2]. - edge-client-only: Functions identically to "edge" but defers rendering until after React hydration on the client, which can help reduce the initial bundle size [1][2]. This functionality was introduced to enable inset positioning for slider thumbs [4]. When using "edge" or "edge-client-only", the component effectively enters an inset mode [5], often requiring adjustments such as increasing the track height to match the thumb size to achieve a desired visual effect [4].

Citations:


Handle scalar value and defaultValue.

Use the resolved value to select between array and single-number thumbs; the current Array.isArray check for a number falls back to [min, max] and renders two thumbs instead of one. thumbAlignment is available on Slider.Root.

🤖 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/shadcn/components/ui/slider.tsx` around lines 5 - 16, Update
Slider to resolve scalar and array value/defaultValue inputs into the correct
thumb values, preserving a single-number input as one thumb instead of falling
back to [min, max]. Use the resolved value when configuring SliderPrimitive.Root
while retaining the existing min/max defaults and thumbAlignment behavior.

Comment thread packages/ui/src/components/message/ImageActionContextMenu.tsx Outdated
Comment thread packages/ui/vite.config.ts Outdated
dvaJi added 5 commits August 5, 2026 00:07
…improved rendering of assistant message activities

- Introduced MessageTurnFold component to handle the rendering of assistant message activities in a collapsible format.
- Removed MessageBlockActivityGroup component and its associated logic.
- Updated MessageItemAssistant to utilize MessageTurnFold instead of the deprecated MessageBlockActivityGroup.
- Refactored messageActivityGroups to accommodate the new turn-fold structure, including changes to how activity blocks are grouped and rendered.
- Enhanced MessageBlockThink to improve performance and reduce unnecessary re-renders.
- Added a shared highlighter for code blocks in markdown rendering.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
packages/ui/src/components/message/messageActivityGroups.ts (1)

109-120: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Make the plan dedup key explicit instead of routing through stableId.

For plan blocks, stableId exists only to bypass the !stableId early return at line 110; line 114 then discards it. A plan block that carries a real id still collapses into the single "plan" key, so two distinct identified plans would merge. Handle plan blocks in one branch to state that intent directly.

♻️ Proposed refactor
   for (const block of blocks) {
-    const stableId = block.id ?? block.tool_call?.id ?? (block.type === "plan" ? "__plan__" : undefined);
-    if (!stableId) {
-      result.push(block);
-      continue;
-    }
-    const dedupKey = block.type === "plan" ? "plan" : `${block.type}:${stableId}`;
+    let dedupKey: string;
+    if (block.type === "plan") {
+      dedupKey = "plan";
+    } else {
+      const stableId = block.id ?? block.tool_call?.id;
+      if (!stableId) {
+        result.push(block);
+        continue;
+      }
+      dedupKey = `${block.type}:${stableId}`;
+    }
     const existing = keyToIndex.get(dedupKey);
🤖 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/message/messageActivityGroups.ts` around lines 109
- 120, Update the deduplication flow around stableId and dedupKey so plan blocks
are handled explicitly without deriving or discarding a synthetic stableId.
Ensure identified non-plan blocks continue using their type-and-ID key, while
plan blocks use the single plan key only when that is the intended behavior and
do not merge distinct identified plans.
🤖 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/message/MessageBlockThink.tsx`:
- Around line 64-81: Update getThinkCollapseSetting and setThinkCollapseSetting
so an in-flight getSetting("think_collapse") result cannot overwrite a value
written by a newer toggle. Apply the fetched value only while thinkCollapseCache
remains null, or invalidate the pending read when setThinkCollapseSetting writes
a value; preserve retry behavior for failed requests and ensure the mounted
block receives the latest toggle value.

In `@packages/ui/src/components/message/MessageTurnFold.tsx`:
- Around line 192-198: Update toggleExpanded so the setIsExpanded updater only
computes and returns the next boolean state; move onToggleCollapse invocation
into the event handler using the derived next value, preserving the existing
callback semantics while keeping the state updater pure.

---

Nitpick comments:
In `@packages/ui/src/components/message/messageActivityGroups.ts`:
- Around line 109-120: Update the deduplication flow around stableId and
dedupKey so plan blocks are handled explicitly without deriving or discarding a
synthetic stableId. Ensure identified non-plan blocks continue using their
type-and-ID key, while plan blocks use the single plan key only when that is the
intended behavior and do not merge distinct identified plans.
🪄 Autofix

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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: e3696122-ccdd-478d-b2ab-03a8ffde8625

📥 Commits

Reviewing files that changed from the base of the PR and between 09c1998 and 61e3e89.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (13)
  • opencode.json
  • packages/ui/package.json
  • packages/ui/src/components/chat/MessageList.tsx
  • packages/ui/src/components/markdown/CodeBlock.tsx
  • packages/ui/src/components/markdown/MarkdownRenderer.tsx
  • packages/ui/src/components/markdown/code-highlight.css
  • packages/ui/src/components/markdown/highlight.ts
  • packages/ui/src/components/message/MessageBlockAction.tsx
  • packages/ui/src/components/message/MessageBlockActivityGroup.tsx
  • packages/ui/src/components/message/MessageBlockThink.tsx
  • packages/ui/src/components/message/MessageItemAssistant.tsx
  • packages/ui/src/components/message/MessageTurnFold.tsx
  • packages/ui/src/components/message/messageActivityGroups.ts
💤 Files with no reviewable changes (1)
  • packages/ui/src/components/message/MessageBlockActivityGroup.tsx
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/ui/src/components/message/MessageBlockAction.tsx
  • packages/ui/src/components/chat/MessageList.tsx

Comment thread packages/ui/src/components/message/MessageBlockThink.tsx
Comment thread packages/ui/src/components/message/MessageTurnFold.tsx Outdated
… chat status bar grouping, and refine message handling in chat page
@@ -22,6 +23,7 @@ interface ChatInputToolbarProps {

const ChatInputToolbar: FC<ChatInputToolbarProps> = ({

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

React Doctor · react-doctor/no-many-boolean-props (warning)

Component "ChatInputToolbar" takes 7 on/off props (isGenerating, isCancelling, hasInput…), which is hard to combine & test. Split it into smaller components or named variants.

Fix → Split boolean-heavy APIs into smaller components or named variants so combinations stay testable.

Docs

@@ -70,10 +72,10 @@ const ChatInputToolbar: FC<ChatInputToolbarProps> = ({
}, [isGenerating, hasActiveInput]);

const primaryTooltip = useMemo(() => {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

React Doctor · react-doctor/react-compiler-no-manual-memoization (warning)

React Compiler can cache this value automatically. Verify that removing useMemo preserves behavior before simplifying it.

Fix → Profile compiler-managed code and remove useMemo, useCallback, or memo only when the manual cache no longer carries behavioral or performance intent.

Docs

.filter((group) => group.models.length > 0);
}, [modelSearchKeyword, modelGroups]);

const modelDisplaySections = useMemo<ModelDisplaySection[]>(() => {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

React Doctor · react-doctor/react-compiler-no-manual-memoization (warning)

React Compiler can cache this value automatically. Verify that removing useMemo preserves behavior before simplifying it.

Fix → Profile compiler-managed code and remove useMemo, useCallback, or memo only when the manual cache no longer carries behavioral or performance intent.

Docs


const resolveCaptureParentId = (messageId: string, parentId?: string): string | undefined => {
const messageItems = displayMessages;
const resolveCaptureParentId = useCallback((messageId: string, parentId?: string): string | undefined => {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

React Doctor · react-doctor/react-compiler-no-manual-memoization (warning)

React Compiler can cache this function automatically. Verify that removing useCallback preserves behavior before simplifying it.

Fix → Profile compiler-managed code and remove useMemo, useCallback, or memo only when the manual cache no longer carries behavioral or performance intent.

Docs

const resolvedParentId = resolveCaptureParentId(messageId, parentId);
await captureMessage({ messageId, parentId: resolvedParentId, fromTop, modelInfo });
};
const handleCopyImage = useCallback(

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

React Doctor · react-doctor/react-compiler-no-manual-memoization (warning)

React Compiler can cache this function automatically. Verify that removing useCallback preserves behavior before simplifying it.

Fix → Profile compiler-managed code and remove useMemo, useCallback, or memo only when the manual cache no longer carries behavioral or performance intent.

Docs

);
};

export const MessageTurnFold = memo(MessageTurnFoldBase);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

React Doctor · react-doctor/react-compiler-no-manual-memoization (warning)

React Compiler can cache this component output automatically. Verify that removing memo() preserves behavior before simplifying it.

Fix → Profile compiler-managed code and remove useMemo, useCallback, or memo only when the manual cache no longer carries behavioral or performance intent.

Docs

}, [isReadOnlySession, isGenerating, isCancelling, sessionId, chatClient]);

useEffect(() => {
if (!isGenerating) setIsCancelling(false);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

React Doctor · react-doctor/no-adjust-state-on-prop-change (warning)

This effect adjusts state after a prop changes, so users briefly see the stale value.

Fix → Remove the adjustment effect by deriving values during render, resetting the component with a key, or updating related state in the event that changes the prop. Avoid tracking the previous prop in more state, which preserves the duplication. See https://react.dev/learn/you-might-not-need-an-effect#adjusting-some-state-when-a-prop-changes

Docs

}, [isReadOnlySession, isGenerating, isCancelling, sessionId, chatClient]);

useEffect(() => {
if (!isGenerating) setIsCancelling(false);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

React Doctor · react-hooks-js/set-state-in-effect (warning)

This synchronous effect update causes an extra render: Calling setState synchronously within an effect can trigger cascading renders. Prefer deriving or initializing the value before render. If the effect must read a browser API after mount, treat this as advisory or suppress it with // react-doctor-disable-next-line react-hooks-js/set-state-in-effect.

Fix → Effects are intended to synchronize state between React and external systems such as manually updating the DOM, state management libraries, or other platform APIs. In general, the body of an effect should do one or both of the following:

  • Update external systems with the latest state from React.
  • Subscribe for updates from some external system, calling setState in a callback function when external state changes.

Calling setState synchronously within an effect body causes cascading renders that can hurt performance, and is not recommended. (https://react.dev/learn/you-might-not-need-an-effect).

Docs


useEffect(() => {
// A session change must not carry over the previous session's cancelling state.
setIsCancelling(false);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

React Doctor · react-doctor/no-adjust-state-on-prop-change (warning)

This effect adjusts state after a prop changes, so users briefly see the stale value.

Fix → Remove the adjustment effect by deriving values during render, resetting the component with a key, or updating related state in the event that changes the prop. Avoid tracking the previous prop in more state, which preserves the duplication. See https://react.dev/learn/you-might-not-need-an-effect#adjusting-some-state-when-a-prop-changes

Docs


useEffect(() => {
// A session change must not carry over the previous session's cancelling state.
setIsCancelling(false);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

React Doctor · react-hooks-js/set-state-in-effect (warning)

This synchronous effect update causes an extra render: Calling setState synchronously within an effect can trigger cascading renders. Prefer deriving or initializing the value before render. If the effect must read a browser API after mount, treat this as advisory or suppress it with // react-doctor-disable-next-line react-hooks-js/set-state-in-effect.

Fix → Effects are intended to synchronize state between React and external systems such as manually updating the DOM, state management libraries, or other platform APIs. In general, the body of an effect should do one or both of the following:

  • Update external systems with the latest state from React.
  • Subscribe for updates from some external system, calling setState in a callback function when external state changes.

Calling setState synchronously within an effect body causes cascading renders that can hurt performance, and is not recommended. (https://react.dev/learn/you-might-not-need-an-effect).

Docs

@dvaJi
dvaJi merged commit 6f817d5 into master Aug 6, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants