Skip to content

Refactor CSS to Tailwind & Fix Vibrancy#7

Merged
zvadaadam merged 78 commits into
mainfrom
arc-vibrancy-design
Oct 19, 2025
Merged

Refactor CSS to Tailwind & Fix Vibrancy#7
zvadaadam merged 78 commits into
mainfrom
arc-vibrancy-design

Conversation

@zvadaadam

@zvadaadam zvadaadam commented Oct 19, 2025

Copy link
Copy Markdown
Owner

Background

The project was using anti-pattern CSS files like App.css and WorkspaceDetail.css. This PR refactors all custom CSS into inline Tailwind utilities and defines reusable vibrancy effects in styles.css for a cleaner, more maintainable, and Tailwind-first codebase. Additionally, it addresses several visual inconsistencies to achieve the Arc browser aesthetic.

Changes

  • Deleted CSS Files: App.css, WorkspaceDetail.css, Settings.css, TerminalPanel.css (approx. 1653 lines of CSS removed).
  • Unified Vibrancy Utilities: Created/refined classes in styles.css for:
    • .vibrancy-root: Universal background on #root (transparent for desktop, bg-background for web)
    • .vibrancy-card: Main content panel (bg-white/70, backdrop-blur-[20px])
    • .vibrancy-panel: Headers and subtle sections (bg-background/30, backdrop-blur-sm)
    • .vibrancy-shadow: Custom complex shadows for depth
    • .scrollbar-vibrancy: Refined subtle scrollbar styling
  • Refactored Components:
    • Dashboard.tsx:
      • Removed all custom CSS classes.
      • Applied vibrancy-root to SidebarProvider (now transparent on desktop).
      • Applied vibrancy-card to PanelGroup.
      • Adjusted spacing and shadows for tighter integration.
      • Added proper sidebar variant and icon-only collapse logic.
    • Sidebar.tsx:
      • Removed all custom CSS classes and applied Tailwind utilities.
      • Standardized sidebar variants and states for better consistency.
    • WorkspaceDetail.tsx:
      • Removed all custom CSS.
      • Applied vibrancy classes to diff views and message containers.
    • Settings.tsx:
      • Removed all custom CSS.
      • Integrated theme switching using useTheme hook.
    • TerminalPanel.tsx:
      • Removed all custom CSS.
      • Styled tabs and panels with vibrancy utilities.
    • App.tsx: Removed App.css import.
  • Typography:
    • Moved font definitions to tailwind.config.js for IntelliSense and semantic usage.
    • Applied semantic typography scale (text-body, text-caption, etc.) throughout the sidebar for clear hierarchy.
  • Color System:
    • Implemented semantic HSL color tokens (success, warning, info) in tailwind.config.js and styles.css.
    • Refactored all hardcoded colors to use these semantic tokens for theme-awareness.
    • Added theme switching (light, dark, system) via useTheme hook and ThemeProvider.
  • Tauri Configuration:
    • Enabled macOS vibrancy (macosPrivateApi: true, transparent: true, underWindowBackground) in tauri.conf.json.
    • Ensured #root background is transparent to allow vibrancy to show through.
  • Accessibility & Polish:
    • Added subtle hover states and transitions (200ms).
    • Improved empty states with proper icons and structure.
    • Added aria-labels and keyboard navigation where appropriate (ongoing).

Testing

  • Verify Arc browser-style frosted glass effect in desktop Tauri app.
  • Test sidebar transparency and scrolling.
  • Check theme switching (Light, Dark, System) in Settings.
  • Verify semantic color tokens adapt correctly to themes.
  • Ensure all components use pure Tailwind utilities or essential CSS abstractions.
  • Test app functionality across all main views (Dashboard, Settings).

Greptile Overview

Updated On: 2025-10-19 16:19:21 UTC

Greptile Summary

This PR executes a comprehensive refactoring from anti-pattern CSS files to a pure Tailwind-first architecture, removing approximately 1,653 lines of custom CSS across App.css, WorkspaceDetail.css, Settings.css, and TerminalPanel.css. The refactor introduces a unified vibrancy design system inspired by Arc browser's frosted-glass aesthetic, enabling macOS native transparency effects via Tauri's private APIs. Key architectural changes include: (1) consolidating all styling into reusable vibrancy utilities (.vibrancy-root, .vibrancy-card, .vibrancy-panel) defined in styles.css, (2) implementing semantic HSL color tokens (success, warning, info, destructive) in tailwind.config.js for theme-aware light/dark mode switching, (3) establishing a semantic typography scale (text-display, text-heading, text-body, text-caption) with IntelliSense support, (4) enabling macOS window vibrancy through Tauri configuration (transparent: true, underWindowBackground, macosPrivateApi: true), and (5) introducing a theme provider with system-aware theme switching. The refactor touches42 files, migrating all hardcoded colors, font sizes, and spacing to centralized Tailwind tokens while maintaining existing functionality across Dashboard, Settings, Workspace, Browser, and Terminal features.

Important Files Changed

Changed Files
Filename Score Overview
.mcp.json 0/5 CRITICAL SECURITY ISSUE: Hardcoded API key 64d127d2-c680-47d8-bf81-54b7052dd6aa exposed in version control for Exa search service.
src/hooks/useTheme.tsx 1.5/5 New theme provider with three critical bugs: initial system theme never applied to DOM, flash of wrong theme on first render, unsafe localStorage casting.
src-tauri/tauri.conf.json 2/5 Enabled macOS vibrancy correctly but beforeDevCommand inline shell may block instead of forking, preventing dev server from starting.
src/fonts.css 4/5 Added custom font-face declarations for Helvetica Neue and Ioskeley Mono; depends on font files in /public/fonts/ that may not exist.
src/App.css 4/5 Deleted entire file (250 lines) removing critical viewport constraints and panel layout—must verify inline Tailwind replicates these.
tailwind.config.js.bak 4/5 Backup file committed with duplicate object keys in sidebar color definitions; should be in .gitignore.
src/styles.css 4/5 Major refactor consolidating vibrancy utilities and semantic tokens; universal * scrollbar override may conflict with OS accessibility settings.
src/components/ui/button.tsx 4/5 Refactored with vibrancy tokens and elevation-* classes; will silently fail if elevation utilities are not defined in global CSS.
src/components/ui/sidebar.tsx 4/5 Sidebar now transparent for vibrancy; inline cubic-bezier easing deviates from CLAUDE.md guideline to use Tailwind tokens.
src/components/app-sidebar.tsx 4/5 Removed collapse buttons from header and refactored all colors to semantic tokens; may impact usability if no alternative toggle exists.
tailwind.config.js 4/5 Added semantic color tokens, typography scale, and animations; duplicate property keys on lines 93-94 will silently overwrite values.
src/Dashboard.tsx 4/5 Removed all custom CSS, applied vibrancy classes, and replaced emoji icons with Lucide; complex pseudo-element resize handle could be extracted.
src/features/workspace/components/MessageItem.tsx 4/5 Refactored to semantic tokens with backdrop-blur-sm; uses border-l-green-500 instead of semantic success token (inconsistent).
src/Settings.tsx 4/5 Removed Settings.css, added theme switcher; hardcoded success colors on line 485 (bg-success-100, border-success-200) instead of semantic tokens.
src/WorkspaceDetail.tsx 4/5 Removed WorkspaceDetail.css and refactored to vibrancy utilities; two instances hardcode backdrop-blur-[20px] instead of using .vibrancy-card.
src/components/ui/EmptyState.tsx 4/5 Refactored to pure Tailwind; fixed icon dimensions (16x16) may constrain icons needing different sizes; animate-fade-in-up must be defined elsewhere.
src/features/workspace/components/MessageList.tsx 4/5 Refactored status indicator with vibrancy tokens; increased message gap from 3 to 6 may impact layout on small screens.
src/components/ui/card.tsx 4/5 Card now uses bg-sidebar-accent/30 which may cause insufficient contrast or visual confusion when rendered inside/adjacent to sidebars.
src/features/workspace/components/FileChangesPanel.tsx 4/5 Removed bg-background to allow vibrancy; primary-50 and primary-100 may not adapt to dark mode if not defined as CSS variables.
src/Settings.css 4/5 Deleted 393 lines of Settings-specific CSS; verify all visual states (active nav, toggle switches, form focus) preserved in component.
src/TerminalPanel.tsx 4/5 Removed TerminalPanel.css import; line 196 uses group-hover:text-primary without group class on parent, so hover won't trigger.
VIBRANCY_DEBUG.md 3/5 Debug documentation with architectural inconsistency: "ROOT CAUSE" says #root should be transparent, but "Architecture" diagram shows bg-background.
src/WorkspaceDetail.css 5/5 Deleted 757 lines of custom CSS; styles migrated to inline Tailwind and vibrancy utilities in WorkspaceDetail.tsx.
src-tauri/Cargo.toml 5/5 Added macos-private-api feature flag to enable macOS vibrancy effects; safe for development/direct distribution.
src/types/settings.types.ts 5/5 Added optional theme field to Settings interface for theme persistence; non-breaking additive change.
src/features/dashboard/components/RepoGroup.tsx 5/5 Replaced hardcoded text sizes with semantic typography tokens (text-body-sm, text-caption) for consistency.
src/components/BranchName.tsx 5/5 Replaced hardcoded text-green-500 with semantic text-success token for theme-awareness.
src/App.tsx 5/5 Removed App.css import and wrapped app in ThemeProvider for theme context.
src/features/workspace/components/MessageInput.tsx 5/5 Removed explicit bg-background from container to allow parent vibrancy; Create PR button uses semantic color tokens.
COLOR_SYSTEM_GUIDE.md 5/5 Comprehensive documentation for 3-layer semantic color system; formalizes migration from hardcoded to semantic tokens.
CLAUDE.md 5/5 Updated design philosophy with explicit product vision and mandate to use Tailwind tokens for colors/fonts.
TYPOGRAPHY.md 5/5 New documentation establishing semantic typography scale with usage examples and migration guidance.
src/TerminalPanel.css 5/5 Deleted 249 lines of terminal-specific CSS; styles migrated to inline Tailwind in TerminalPanel.tsx.
src/components/ui/tabs.tsx 5/5 Removed bg-muted from TabsList, changed active tab to bg-sidebar-accent/40 for vibrancy consistency.
src/components/ui/badge.tsx 5/5 All badge variants now use semi-transparent backgrounds with backdrop-blur-sm for frosted-glass aesthetic.
src/features/dashboard/components/WorkspaceItem.tsx 5/5 Refactored hardcoded sizes/colors to semantic tokens (text-body-sm, text-caption, text-success, bg-success/10).
TAILWIND_AUDIT.md 5/5 Audit documentation tracking CSS refactoring; keeps both 'before' (CRITICAL) and 'after' (UPDATE) states for clarity.
SIDEBAR_TYPOGRAPHY.md 5/5 Documents semantic typography system applied to sidebar with three-tier size/weight hierarchy.
src/features/browser/components/BrowserPanel.tsx 5/5 Removed all hardcoded colors, replaced with semantic tokens and vibrancy utilities; no functional logic changed.

Confidence score: 1/5

  • This PR has critical security and runtime issues that make it unsafe to merge in its current state.
  • Score reflects three blocking issues: (1) exposed API key in .mcp.json will leak credentials to version control/public repos, (2) useTheme.tsx has three bugs causing incorrect theme application on initial render and potential memory leaks, and (3) tauri.conf.json inline shell command may block dev server startup. Additional concerns include missing font files, unsafe localStorage casting, duplicate Tailwind config keys, and hardcoded backdrop-blur values inconsistent with the vibrancy system.
  • Pay close attention to .mcp.json (must use environment variable), src/hooks/useTheme.tsx (must fix DOM sync and cleanup), src-tauri/tauri.conf.json (revert to dev.sh script), src/fonts.css (verify font files exist), and tailwind.config.js (remove duplicate keys on lines 93-94).

Sequence Diagram

sequenceDiagram
    participant User
    participant App
    participant ThemeProvider
    participant Dashboard
    participant Sidebar
    participant Settings
    participant Tauri
    participant Browser

    User->>App: Launch Application
    App->>ThemeProvider: Initialize with localStorage theme
    ThemeProvider->>Browser: Check system preference
    Browser-->>ThemeProvider: Return dark/light preference
    ThemeProvider->>Browser: Apply theme class to root
    ThemeProvider->>App: Provide theme context

    User->>Dashboard: Navigate to Dashboard
    Dashboard->>Sidebar: Render SidebarProvider
    Note over Dashboard,Sidebar: No custom CSS classes<br/>All Tailwind utilities
    Dashboard->>Browser: Apply vibrancy-root to #root
    Note over Browser: Transparent for Tauri desktop<br/>bg-background for web
    Dashboard->>Browser: Apply vibrancy-card to PanelGroup
    Note over Browser: bg-white/70 + backdrop-blur-[20px]

    User->>Sidebar: Collapse/Expand Sidebar
    Sidebar->>Sidebar: Toggle state (expanded/collapsed)
    Sidebar->>Browser: Update width with transition
    Note over Sidebar,Browser: All styling via<br/>Tailwind semantic tokens

    User->>Settings: Navigate to Settings
    Settings->>ThemeProvider: Request current theme
    ThemeProvider-->>Settings: Return theme state
    Settings->>Browser: Render theme selector
    
    User->>Settings: Select "Dark" theme
    Settings->>ThemeProvider: setTheme("dark")
    ThemeProvider->>Browser: localStorage.setItem("theme", "dark")
    ThemeProvider->>Browser: root.classList.add("dark")
    ThemeProvider->>Browser: root.classList.remove("light")
    Note over Browser: CSS variables switch automatically<br/>--background, --foreground, etc.
    Browser->>Dashboard: Re-render with dark theme
    Browser->>Sidebar: Re-render with dark theme
    Browser->>Settings: Re-render with dark theme

    User->>Settings: Select "System" theme
    Settings->>ThemeProvider: setTheme("system")
    ThemeProvider->>Browser: Listen to prefers-color-scheme
    Browser-->>ThemeProvider: Notify on system theme change
    ThemeProvider->>Browser: Apply matching theme class
    Note over Browser: Automatically syncs with OS

    User->>Dashboard: View workspace with vibrancy
    Dashboard->>Tauri: Request window effects
    Note over Tauri: macOSPrivateApi: true<br/>transparent: true<br/>underWindowBackground
    Tauri-->>Dashboard: Enable native vibrancy
    Dashboard->>Browser: Render with vibrancy-shadow
    Note over Browser: Multi-layer shadow for depth<br/>Arc browser aesthetic
Loading

Context used:

  • Context from dashboard - CLAUDE.md (source)

Summary by CodeRabbit

  • New Features

    • Theme selector (light/dark/system) and new MCP server entry support
    • Desktop window effects: transparency, overlay title bar, and under-window vibrancy
  • UI/UX Improvements

    • Redesigned dashboard, Settings, Terminal panel, Workspace detail, and sidebar
    • Enhanced empty states, tabs, badges, message rendering, and repo/workspace lists
  • Design & Styling

    • New semantic color tokens, updated typography scale, added fonts, vibrancy system, scrollbars, and animations
  • Documentation

    • Added color system, typography, Tailwind audit, and vibrancy debugging guides

@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

Caution

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

⚠️ Outside diff range comments (8)
src/features/workspace/components/MessageItem.tsx (2)

10-25: Remove redundant key prop from returned div.

The key prop on line 13 is redundant because this element is wrapped in a keyed div at line 95. React will use the outer key for reconciliation, making the inner key unnecessary and potentially confusing.

Apply this diff to remove the redundant key:

   function renderToolUse(toolUse: any) {
     return (
       <div
-        key={toolUse.id}
         className="bg-sidebar-accent/30 rounded-md p-2 border border-border/40 mt-1 text-[0.85rem] border-l-2 border-l-primary backdrop-blur-sm"
       >

Alternatively, if you prefer to keep the key inside the function, remove the wrapper div at line 95:

-            return <div key={`tool-use-${index}`}>{renderToolUse(block)}</div>;
+            return renderToolUse(block);

and update the function to accept index:

-  function renderToolUse(toolUse: any) {
+  function renderToolUse(toolUse: any, index: number) {
     return (
       <div
-        key={toolUse.id}
+        key={`tool-use-${index}`}
         className="bg-sidebar-accent/30 rounded-md p-2 border border-border/40 mt-1 text-[0.85rem] border-l-2 border-l-primary backdrop-blur-sm"
       >

27-57: Remove redundant key prop from returned div.

Same issue as renderToolUse: the key prop on line 39 is redundant because this element is wrapped in a keyed div at line 97.

Apply this diff to remove the redundant key:

   function renderToolResult(toolResult: any) {
     let content = toolResult.content || "";
     
     // If content is an array or object, stringify it
     if (typeof content === 'object') {
       content = JSON.stringify(content, null, 2);
     }
     
     const isError = toolResult.is_error;
     
     return (
       <div
-        key={toolResult.tool_use_id}
         className={cn(
           "bg-sidebar-accent/30 rounded-md p-2 border border-border/40 mt-1 text-[0.85rem] border-l-2 backdrop-blur-sm",
           isError ? "border-l-destructive bg-destructive/10" : "border-l-green-500"
         )}
       >

Or follow the same alternative approach as suggested for renderToolUse.

src/components/app-sidebar.tsx (1)

313-316: Narrowing: avoid possibly-undefined diffStats access.

TypeScript can’t infer diffStats is defined inside the hasChanges block. Precompute counts and use them downstream.

-  const hasChanges = diffStats && (diffStats.additions > 0 || diffStats.deletions > 0);
+  const additions = diffStats?.additions ?? 0;
+  const deletions = diffStats?.deletions ?? 0;
+  const hasChanges = additions > 0 || deletions > 0;
@@
-            {diffStats.additions > 0 && (
+            {additions > 0 && (
-              <span className="inline-flex items-center px-1 py-0.5 rounded text-[10px] font-medium border border-success/30 bg-success/10 text-success whitespace-nowrap">
-                +{diffStats.additions}
+              <span className="inline-flex items-center px-1 py-0.5 rounded text-[10px] font-medium border border-success/30 bg-success/10 text-success whitespace-nowrap">
+                +{additions}
               </span>
             )}
@@
-            {diffStats.deletions > 0 && (
+            {deletions > 0 && (
-              <span className="inline-flex items-center px-1 py-0.5 rounded text-[10px] font-medium border border-destructive/30 bg-destructive/10 text-destructive whitespace-nowrap">
-                -{diffStats.deletions}
+              <span className="inline-flex items-center px-1 py-0.5 rounded text-[10px] font-medium border border-destructive/30 bg-destructive/10 text-destructive whitespace-nowrap">
+                -{deletions}
               </span>
             )}

Also applies to: 379-386

src/Settings.tsx (5)

178-189: Coerce Checkbox value to boolean before saving.

shadcn Checkbox onCheckedChange emits CheckedState. Persist strictly boolean.

- onCheckedChange={(checked) => saveSetting('notifications_enabled', checked)}
+ onCheckedChange={(checked) => saveSetting('notifications_enabled', checked === true)}
@@
- onCheckedChange={(checked) => saveSetting('sound_effects_enabled', checked)}
+ onCheckedChange={(checked) => saveSetting('sound_effects_enabled', checked === true)}
@@
- onCheckedChange={(checked) => saveSetting('right_panel_visible', checked)}
+ onCheckedChange={(checked) => saveSetting('right_panel_visible', checked === true)}
@@
- onCheckedChange={(checked) => saveSetting('using_split_view', checked)}
+ onCheckedChange={(checked) => saveSetting('using_split_view', checked === true)}

Also applies to: 192-203, 675-686, 689-700


283-292: Don’t POST API key on every keystroke. Save on blur; avoid noisy writes.

Minimize exposure and traffic; update local state onChange and persist onBlur.

- <Input
+ <Input
   id="api-key"
   type="password"
   value={settings.anthropic_api_key ?? ''}
-  onChange={(e) => saveSetting('anthropic_api_key', e.target.value)}
+  onChange={(e) =>
+    setSettings(prev => ({ ...prev, anthropic_api_key: e.target.value }))
+  }
+  onBlur={(e) => saveSetting('anthropic_api_key', e.currentTarget.value)}
+  autoComplete="off" spellCheck={false} autoCapitalize="off"
   placeholder="sk-ant-api03-..."
 />

80-89: Handle non-2xx responses in saveSetting.

Check response.ok and surface HTTP errors.

-  await fetch(`${baseURL}/settings`, {
+  const res = await fetch(`${baseURL}/settings`, {
     method: 'POST',
     headers: { 'Content-Type': 'application/json' },
     body: JSON.stringify({ key, value })
   });
+  if (!res.ok) {
+    throw new Error(`Failed to save: ${res.status}`);
+  }

309-314: Guard against NaN when parsing font size.

Avoid persisting NaN if input is cleared.

- onChange={(e) => saveSetting('terminal_font_size', parseInt(e.target.value, 10))}
+ onChange={(e) => {
+   const next = parseInt(e.target.value, 10);
+   saveSetting('terminal_font_size', Number.isFinite(next) ? next : 12);
+ }}

132-146: Fix changelog link—anthropics/claude-code has no releases published.

The link at line 142 points to https://github.com/anthropics/claude-code/releases, but the repository has no published releases. Consider linking to the official Claude Code changelog in Anthropic's documentation instead, or verify that a different repository with releases is more appropriate.

🧹 Nitpick comments (8)
src/features/workspace/components/MessageItem.tsx (2)

100-104: Consider removing or conditionally disabling console.warn in production.

While the warning is helpful during development, it will run in production and may clutter logs. Consider one of these approaches:

  1. Remove it entirely if unknown blocks should be silently ignored
  2. Add a development-only check: if (import.meta.env.DEV) console.warn(...)
  3. Replace with proper error boundary or logging service

Example using development-only check:

           } else if (typeof block === 'object') {
             // Handle unknown object types - don't try to render them directly
-            console.warn('Unknown block type:', block);
+            if (import.meta.env.DEV) {
+              console.warn('Unknown block type:', block);
+            }
             return null;
           }

20-20: Consider applying vibrancy scrollbar styling.

The scrollable pre elements could benefit from the .scrollbar-vibrancy utility mentioned in the PR summary to maintain visual consistency with the frosted-glass aesthetic.

Apply this diff to add scrollbar styling:

-        <pre className="bg-sidebar-accent/40 p-2 rounded font-mono text-xs leading-snug overflow-x-auto m-0 whitespace-pre-wrap break-words text-foreground border-none max-h-[150px] overflow-y-auto">
+        <pre className="bg-sidebar-accent/40 p-2 rounded font-mono text-xs leading-snug overflow-x-auto m-0 whitespace-pre-wrap break-words text-foreground border-none max-h-[150px] overflow-y-auto scrollbar-vibrancy">
           {JSON.stringify(toolUse.input, null, 2)}
         </pre>

And similarly for the pre element in renderToolResult:

         <pre className={cn(
           "p-2 rounded font-mono text-xs leading-snug overflow-x-auto m-0 whitespace-pre-wrap break-words border-none max-h-[150px] overflow-y-auto",
+          "scrollbar-vibrancy",
           isError ? "bg-destructive/10 text-destructive" : "bg-sidebar-accent/40 text-foreground"
         )}>

Also applies to: 50-51

src/components/app-sidebar.tsx (2)

206-208: Respect reduced motion for the ping indicator.

Add a motion-reduce fallback to avoid continuous animation.

-  <span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-primary opacity-75"></span>
+  <span className="animate-ping motion-reduce:hidden absolute inline-flex h-full w-full rounded-full bg-primary opacity-75"></span>

As per coding guidelines.


358-360: Use semantic tokens instead of hard-coded blue/yellow in shimmer.

Avoid brand hue coupling; prefer primary/warning tokens. Either extend a numeric ramp for warning in tailwind.config.js or adapt TextShimmer to accept token names and compute tints.

If you add a warning ramp, switch to:

-  ? "[--base-color:theme(colors.blue.700)] [--base-gradient-color:theme(colors.blue.300)] ..."
-  : "[--base-color:theme(colors.yellow.600)] [--base-gradient-color:theme(colors.yellow.200)] ..."
+  ? "[--base-color:theme(colors.primary.700)] [--base-gradient-color:theme(colors.primary.300)] ..."
+  : "[--base-color:theme(colors.warning.600)] [--base-gradient-color:theme(colors.warning.300)] ..."

As per coding guidelines (use design tokens).

src/Settings.tsx (2)

751-754: Reduce motion for “Saving…” pulse.

Disable animation for users preferring reduced motion.

- <span className="text-sm text-muted-foreground animate-pulse">
+ <span className="text-sm text-muted-foreground animate-pulse motion-reduce:animate-none">

As per coding guidelines.


112-148: Add navigation landmark label.

Improve a11y by labeling the nav region.

- <nav className="w-[250px] bg-muted/30 border-r border-border py-5 overflow-y-auto flex flex-col gap-1 p-2">
+ <nav aria-label="Settings navigation" className="w-[250px] bg-muted/30 border-r border-border py-5 overflow-y-auto flex flex-col gap-1 p-2">
src/hooks/useTheme.tsx (1)

14-32: Solid fix for validation and initial system theme; add SSR guards to avoid crashes.

Accessing window/localStorage in initializers breaks SSR/pre-render. Guard with isBrowser.

+ const isBrowser = typeof window !== 'undefined';
@@
- const [theme, setThemeState] = useState<Theme>(() => {
+ const [theme, setThemeState] = useState<Theme>(() => {
   // Load theme from localStorage or default to 'system'
-  const stored = localStorage.getItem('theme');
+  const stored = isBrowser ? localStorage.getItem('theme') : null;
   ...
 });
@@
- const [actualTheme, setActualTheme] = useState<'light' | 'dark'>(() => {
+ const [actualTheme, setActualTheme] = useState<'light' | 'dark'>(() => {
   // Resolve initial theme synchronously to avoid flicker
-  const stored = localStorage.getItem('theme');
+  const stored = isBrowser ? localStorage.getItem('theme') : null;
-  return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
+  return isBrowser && window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
 });
@@
- useEffect(() => {
+ useEffect(() => {
+   if (!isBrowser) return;
   const root = window.document.documentElement;
   ...
 }, [theme]);
@@
- const setTheme = (newTheme: Theme) => {
-   localStorage.setItem('theme', newTheme);
+ const setTheme = (newTheme: Theme) => {
+   if (isBrowser) localStorage.setItem('theme', newTheme);
   setThemeState(newTheme);
 };

Optional: to eliminate first-paint flash entirely, add a tiny inline script in index.html that applies the stored/system class before React mounts.

Also applies to: 34-69

tailwind.config.js (1)

112-119: Mono font name looks off; consider a safer default stack.

“Ioskeley Mono” may be a typo. Prefer a broadly available stack.

- mono: ['Ioskeley Mono','SF Mono','Monaco','Cascadia Code','Consolas','monospace']
+ mono: ['ui-monospace','SFMono-Regular','SF Mono','Menlo','Monaco','Cascadia Code','Consolas','Liberation Mono','monospace']
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Lite

📥 Commits

Reviewing files that changed from the base of the PR and between 2806f38 and 470e351.

📒 Files selected for processing (10)
  • .gitignore (1 hunks)
  • src-tauri/tauri.conf.json (3 hunks)
  • src/Settings.tsx (13 hunks)
  • src/TerminalPanel.tsx (3 hunks)
  • src/components/app-sidebar.tsx (7 hunks)
  • src/components/ui/badge.tsx (1 hunks)
  • src/components/ui/sidebar.tsx (9 hunks)
  • src/features/workspace/components/MessageItem.tsx (6 hunks)
  • src/hooks/useTheme.tsx (1 hunks)
  • tailwind.config.js (5 hunks)
✅ Files skipped from review due to trivial changes (1)
  • .gitignore
🚧 Files skipped from review as they are similar to previous changes (4)
  • src/components/ui/badge.tsx
  • src/TerminalPanel.tsx
  • src-tauri/tauri.conf.json
  • src/components/ui/sidebar.tsx
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx,js,jsx}: Use Zustand for state management
When using Framer Motion and needing hardware acceleration, animate via transform instead of x/y
Default to spring animations when using Framer Motion
Avoid bouncy spring animations except for drag gestures in Framer Motion

Files:

  • src/components/app-sidebar.tsx
  • src/Settings.tsx
  • src/features/workspace/components/MessageItem.tsx
  • tailwind.config.js
  • src/hooks/useTheme.tsx
**/*.{tsx,jsx,html}

📄 CodeRabbit inference engine (CLAUDE.md)

Use Tailwind for styling (prefer utility classes over custom CSS)

Files:

  • src/components/app-sidebar.tsx
  • src/Settings.tsx
  • src/features/workspace/components/MessageItem.tsx
  • src/hooks/useTheme.tsx
**/*.{css,scss,less,tsx,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{css,scss,less,tsx,jsx}: Default paddings to 16px for denser layout
Use consistent font sizes (stick to design scale)
Use consistent colors and avoid hardcoding colors; use design tokens/Tailwind variables
Default to ease-out for most animations; durations ~0.2s–0.3s and never exceed 1s unless illustrative
Avoid built-in easings except ease or linear; otherwise use the specified cubic-bezier variants for ease-in/out/in-out
For simple hover transitions (color, background-color, opacity), use ease 200ms
Respect prefers-reduced-motion: disable transform animations when reduced motion is requested
Animate from the trigger (set transform-origin based on trigger position)
Prefer animating opacity and transform; avoid animating top/left for movement
Do not animate drag gestures using CSS variables
Do not animate blur values higher than 20px

Files:

  • src/components/app-sidebar.tsx
  • src/Settings.tsx
  • src/features/workspace/components/MessageItem.tsx
  • src/hooks/useTheme.tsx
**/*.{tsx,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Base UI on shadcn/ui components

Files:

  • src/components/app-sidebar.tsx
  • src/Settings.tsx
  • src/features/workspace/components/MessageItem.tsx
  • src/hooks/useTheme.tsx
🧠 Learnings (3)
📚 Learning: 2025-10-17T23:39:42.966Z
Learnt from: CR
PR: zvadaadam/box-ide#0
File: CLAUDE.md:0-0
Timestamp: 2025-10-17T23:39:42.966Z
Learning: Applies to **/*.{css,scss,less,tsx,jsx} : Prefer animating opacity and transform; avoid animating top/left for movement

Applied to files:

  • tailwind.config.js
📚 Learning: 2025-10-17T23:39:42.966Z
Learnt from: CR
PR: zvadaadam/box-ide#0
File: CLAUDE.md:0-0
Timestamp: 2025-10-17T23:39:42.966Z
Learning: Applies to **/*.{css,scss,less,tsx,jsx} : Default to ease-out for most animations; durations ~0.2s–0.3s and never exceed 1s unless illustrative

Applied to files:

  • tailwind.config.js
📚 Learning: 2025-10-17T23:39:42.966Z
Learnt from: CR
PR: zvadaadam/box-ide#0
File: CLAUDE.md:0-0
Timestamp: 2025-10-17T23:39:42.966Z
Learning: Applies to **/*.{css,scss,less,tsx,jsx} : For simple hover transitions (color, background-color, opacity), use ease 200ms

Applied to files:

  • tailwind.config.js
🧬 Code graph analysis (1)
src/Settings.tsx (1)
src/hooks/useTheme.tsx (1)
  • useTheme (83-89)
🔇 Additional comments (6)
src/features/workspace/components/MessageItem.tsx (2)

59-66: LGTM! Key generation improved.

Good refactor removing the random key generation. The stable index-based keys from the wrapper (line 99) provide better React reconciliation.


72-88: Verify color contrast with new opacity values.

The styling updates look good and align with the vibrancy design system. However, the low opacity values (e.g., bg-primary/10, bg-sidebar-accent/40) may affect text readability depending on the underlying background.

Please verify that text within these message blocks maintains sufficient contrast (WCAG AA: 4.5:1 for normal text, 3:1 for large text) across both light and dark themes, especially for the user messages with bg-primary/10.

src/components/app-sidebar.tsx (1)

220-223: Chevron transition looks good.

Duration/easing and motion-reduce handling match guidelines.

src/Settings.tsx (1)

158-173: Theme selector wiring LGTM.

Correctly binds useTheme with light/dark/system.

src/hooks/useTheme.tsx (1)

76-81: Context/provider and hook look correct.

API is clear; error on missing provider is appropriate.

Also applies to: 83-89

tailwind.config.js (1)

56-67: CSS variables are properly defined for all themes.

All six semantic color variables (--success, --success-foreground, --warning, --warning-foreground, --info, --info-foreground) are defined in src/styles.css with appropriate HSL values for both light and dark themes. No runtime "transparent" fallbacks will occur.

Comment thread src/components/app-sidebar.tsx
Comment thread tailwind.config.js

@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: 3

♻️ Duplicate comments (1)
tailwind.config.js (1)

182-201: slideInRight/Left directions — corrected.
Directions now match names (Right: +X, Left: −X). Resolves prior feedback.

🧹 Nitpick comments (11)
src/Settings.tsx (1)

319-322: Consider simplifying the validation logic.

The current implementation works correctly, but could be more explicit about the validation rules.

Apply this diff for clearer validation:

-              onChange={(e) => {
-                const next = parseInt(e.target.value, 10);
-                saveSetting('terminal_font_size', Number.isFinite(next) ? next : 12);
-              }}
+              onChange={(e) => {
+                const value = parseInt(e.target.value, 10);
+                const fontSize = isNaN(value) || value < 8 || value > 24 ? 12 : value;
+                saveSetting('terminal_font_size', fontSize);
+              }}

This makes the min/max bounds (already specified in the input attributes) explicit in the validation logic.

tailwind.config.js (2)

92-92: Sidebar ring token added — consider adoption sweep.
Recommend updating components that use ring utilities to prefer ring-sidebar where appropriate for consistency.


120-136: Custom fontSize scale: avoid relying on fontWeight here.
Tailwind’s text-* utilities won’t apply fontWeight from the fontSize config. Use explicit font-* classes in components (as you already do with font-medium, etc.). Keep lineHeight/letterSpacing here; move weight decisions to components.

src/components/app-sidebar.tsx (1)

121-121: Footer padding is tighter than default.
Guidelines default to 16px. Consider p-4 for consistency unless intentionally compact.

-      <SidebarFooter className="p-2">
+      <SidebarFooter className="p-4">
src/features/workspace/components/MessageItem.tsx (7)

10-10: Replace any with precise block types for safety and DX.

Strongly type tool/text blocks and update function signatures accordingly. This prevents silent shape drift and improves autocomplete.

@@
-import type { Message } from "../../../types";
+import type { Message } from "../../../types";
+
+type ToolUseBlock = { type: "tool_use"; name: string; input: unknown };
+type ToolResultBlock = { type: "tool_result"; is_error?: boolean; content: unknown };
+type TextBlock = { type: "text"; text: string };
@@
-export function MessageItem({ message, parseContent }: MessageItemProps) {
-  function renderToolUse(toolUse: any, index: number) {
+export function MessageItem({ message, parseContent }: MessageItemProps) {
+  function renderToolUse(toolUse: ToolUseBlock, index: number) {
@@
-  function renderToolResult(toolResult: any, index: number) {
+  function renderToolResult(toolResult: ToolResultBlock, index: number) {
@@
-  function renderText(text: any) {
+  function renderText(text: TextBlock | string) {

As per coding guidelines.

Also applies to: 27-27, 59-59


13-15: Use semantic text sizes; avoid arbitrary font-size values.

Replace text-[0.85rem] with the configured scale (e.g., text-sm) to stay on the design system.

-        className="bg-sidebar-accent/30 rounded-md p-2 border border-border/40 mt-1 text-[0.85rem] border-l-2 border-l-primary backdrop-blur-sm"
+        className="bg-sidebar-accent/30 rounded-md p-2 border border-border/40 mt-1 text-sm border-l-2 border-l-primary backdrop-blur-sm"

Also consider changing header instances of text-[0.8rem]/text-[0.95rem] to text-xs/text-sm for consistency. As per coding guidelines.


20-20: Add accessible labelling for the code block.

Expose the region to AT and label the content.

-        <pre className="bg-sidebar-accent/40 p-2 rounded font-mono text-xs leading-snug overflow-x-auto m-0 whitespace-pre-wrap break-words text-foreground border-none max-h-[150px] overflow-y-auto scrollbar-vibrancy">
+        <pre role="region" aria-label="Tool input"
+          className="bg-sidebar-accent/40 p-2 rounded font-mono text-xs leading-snug overflow-x-auto m-0 whitespace-pre-wrap break-words text-foreground border-none max-h-[150px] overflow-y-auto scrollbar-vibrancy">

Tip: mark decorative emoji as aria-hidden="true" and add visually-hidden text for screen readers. As per coding guidelines.


39-43: Replace hard-coded green-500 with a semantic success token.

This PR moves to tokens; keep consistency by not using palette literals.

-          isError ? "border-l-destructive bg-destructive/10" : "border-l-green-500"
+          isError ? "border-l-destructive bg-destructive/10" : "border-l-success"

If border-l-success isn’t available, fall back to an arbitrary value tied to the token:

-          ... : "border-l-green-500"
+          ... : "border-l-[hsl(var(--success))]"

As per coding guidelines and PR objectives.


50-52: A11y for result block + consider shadcn/ui ScrollArea.

Label the region and optionally use ScrollArea for consistent scrollbars instead of a custom class.

-        <pre className={cn(
+        <pre role="region" aria-label={isError ? "Tool error" : "Tool result"} className={cn(
           "p-2 rounded font-mono text-xs leading-snug overflow-x-auto m-0 whitespace-pre-wrap break-words border-none max-h-[150px] overflow-y-auto scrollbar-vibrancy",
           isError ? "bg-destructive/10 text-destructive" : "bg-sidebar-accent/40 text-foreground"
         )}>

Optional:

// import { ScrollArea } from "@/components/ui/scroll-area"
<ScrollArea className="max-h-[150px]">
  <pre ...>{content}</pre>
</ScrollArea>

As per coding guidelines.


76-79: Tighten transitions, add easing and reduced-motion guard; align padding to 16px.

Avoid transition-all, add ease-out, and prefer default 16px padding.

-        "max-w-[85%] rounded-xl p-5 flex flex-col gap-3 shadow-sm transition-all duration-200 overflow-hidden backdrop-blur-sm",
+        "max-w-[85%] rounded-xl p-4 flex flex-col gap-3 shadow-sm transition-colors duration-200 ease-out overflow-hidden backdrop-blur-sm motion-reduce:transition-none",

Note: If this renders server-side anywhere, consider suppressHydrationWarning on the timestamp to avoid SSR mismatch. As per coding guidelines.


100-103: Gate console warnings to dev to avoid leaking data.

Prevent noisy logs and potential PII in production builds.

-              console.warn('Unknown block type:', block);
+              if (import.meta.env.DEV) console.warn('Unknown block type:', block);

As per coding guidelines.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Lite

📥 Commits

Reviewing files that changed from the base of the PR and between 470e351 and eca8276.

📒 Files selected for processing (4)
  • src/Settings.tsx (19 hunks)
  • src/components/app-sidebar.tsx (6 hunks)
  • src/features/workspace/components/MessageItem.tsx (5 hunks)
  • tailwind.config.js (5 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx,js,jsx}: Use Zustand for state management
When using Framer Motion and needing hardware acceleration, animate via transform instead of x/y
Default to spring animations when using Framer Motion
Avoid bouncy spring animations except for drag gestures in Framer Motion

Files:

  • tailwind.config.js
  • src/components/app-sidebar.tsx
  • src/features/workspace/components/MessageItem.tsx
  • src/Settings.tsx
**/*.{tsx,jsx,html}

📄 CodeRabbit inference engine (CLAUDE.md)

Use Tailwind for styling (prefer utility classes over custom CSS)

Files:

  • src/components/app-sidebar.tsx
  • src/features/workspace/components/MessageItem.tsx
  • src/Settings.tsx
**/*.{css,scss,less,tsx,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{css,scss,less,tsx,jsx}: Default paddings to 16px for denser layout
Use consistent font sizes (stick to design scale)
Use consistent colors and avoid hardcoding colors; use design tokens/Tailwind variables
Default to ease-out for most animations; durations ~0.2s–0.3s and never exceed 1s unless illustrative
Avoid built-in easings except ease or linear; otherwise use the specified cubic-bezier variants for ease-in/out/in-out
For simple hover transitions (color, background-color, opacity), use ease 200ms
Respect prefers-reduced-motion: disable transform animations when reduced motion is requested
Animate from the trigger (set transform-origin based on trigger position)
Prefer animating opacity and transform; avoid animating top/left for movement
Do not animate drag gestures using CSS variables
Do not animate blur values higher than 20px

Files:

  • src/components/app-sidebar.tsx
  • src/features/workspace/components/MessageItem.tsx
  • src/Settings.tsx
**/*.{tsx,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Base UI on shadcn/ui components

Files:

  • src/components/app-sidebar.tsx
  • src/features/workspace/components/MessageItem.tsx
  • src/Settings.tsx
🧠 Learnings (3)
📚 Learning: 2025-10-17T23:39:42.966Z
Learnt from: CR
PR: zvadaadam/box-ide#0
File: CLAUDE.md:0-0
Timestamp: 2025-10-17T23:39:42.966Z
Learning: Applies to **/*.{css,scss,less,tsx,jsx} : Prefer animating opacity and transform; avoid animating top/left for movement

Applied to files:

  • tailwind.config.js
📚 Learning: 2025-10-17T23:39:42.966Z
Learnt from: CR
PR: zvadaadam/box-ide#0
File: CLAUDE.md:0-0
Timestamp: 2025-10-17T23:39:42.966Z
Learning: Applies to **/*.{css,scss,less,tsx,jsx} : Default to ease-out for most animations; durations ~0.2s–0.3s and never exceed 1s unless illustrative

Applied to files:

  • tailwind.config.js
📚 Learning: 2025-10-17T23:39:42.966Z
Learnt from: CR
PR: zvadaadam/box-ide#0
File: CLAUDE.md:0-0
Timestamp: 2025-10-17T23:39:42.966Z
Learning: Applies to **/*.{css,scss,less,tsx,jsx} : For simple hover transitions (color, background-color, opacity), use ease 200ms

Applied to files:

  • tailwind.config.js
🧬 Code graph analysis (2)
src/components/app-sidebar.tsx (4)
src/components/ui/sidebar.tsx (7)
  • Sidebar (746-746)
  • SidebarHeader (753-753)
  • SidebarFooter (748-748)
  • SidebarMenu (756-756)
  • SidebarMenuItem (760-760)
  • SidebarMenuButton (759-759)
  • SidebarMenuSubItem (764-764)
src/components/ui/index.ts (9)
  • Sidebar (28-28)
  • SidebarHeader (35-35)
  • Avatar (56-56)
  • AvatarFallback (56-56)
  • SidebarFooter (30-30)
  • SidebarMenu (38-38)
  • SidebarMenuItem (42-42)
  • SidebarMenuButton (41-41)
  • SidebarMenuSubItem (46-46)
src/components/ui/avatar.tsx (2)
  • Avatar (46-46)
  • AvatarFallback (46-46)
src/lib/utils.ts (1)
  • cn (4-6)
src/Settings.tsx (1)
src/hooks/useTheme.tsx (1)
  • useTheme (83-89)
🔇 Additional comments (24)
src/Settings.tsx (12)

17-17: LGTM! Theme hook integration looks correct.

The useTheme import and usage follow the correct pattern. The hook will throw a clear error if the ThemeProvider is missing from the component tree.

Also applies to: 29-29


83-90: Good improvement to error handling.

Adding response status validation ensures failed saves are properly detected and reported to the user.


160-176: LGTM! Theme selector properly integrated.

The theme selection control correctly binds to the useTheme hook and provides clear options for light/dark/system preferences.


184-184: Good defensive boolean coercion.

The checked === true pattern ensures only boolean values are persisted, preventing the 'indeterminate' state from being accidentally saved.

Also applies to: 198-198, 688-688, 702-702


291-295: Excellent API key input handling.

The onChange/onBlur pattern provides immediate visual feedback while deferring the server save until blur, reducing unnecessary API calls. The additional attributes (autoComplete, spellCheck, autoCapitalize) appropriately disable browser features that would interfere with API key entry.


115-115: Good accessibility addition.

The aria-label on the navigation element improves screen reader support.


362-367: Excellent empty state improvements.

The refactored empty states provide clear, consistent guidance with helpful code snippets showing users exactly where to add configurations. The visual design is cohesive across all sections.

Also applies to: 432-438, 477-483, 575-581


370-396: Clean, consistent card styling.

The MCP server cards use appropriate spacing, semantic design tokens, and handle overflow correctly for long commands.


493-499: Excellent use of semantic color tokens.

The agent tool badges correctly use the success semantic token with appropriate opacity levels, following the new design system introduced in this PR.

As per coding guidelines.


761-764: Great accessibility consideration.

The saving indicator properly respects user motion preferences with motion-reduce:animate-none, following accessibility best practices.

As per coding guidelines.


747-773: Solid layout structure with vibrancy effects.

The layout correctly implements full-height flexbox with proper scroll containment, and the backdrop-blur-sm on the header aligns with the Arc-style vibrancy design system.


400-415: Well-designed guidance blocks.

The contextual help sections provide clear instructions with properly styled links (including secure external link attributes) and code snippets. The hover transitions follow the coding guidelines with ease and 200ms duration.

Also applies to: 452-460, 506-511, 596-606

tailwind.config.js (4)

68-71: Muted token placement — OK.
No issues; consistent with existing token strategy.


172-181: fadeInDown keyframes — compliant.
Uses opacity+transform with a small offset; aligns with motion guidelines.


202-211: scaleIn keyframes — conservative and smooth.
Scale 0.9→1 with opacity; good default.


56-67: CSS variables for semantic tokens are properly defined.

All required variables (--success, --success-foreground, --warning, --warning-foreground, --info, --info-foreground) exist in src/styles.css for both light and dark themes. The tailwind.config.js correctly references them via hsl(var(...)) syntax, so utility classes like bg-success/10 will resolve properly.

src/components/app-sidebar.tsx (8)

76-97: Sidebar variant/header refactor — LGTM.
Clean expanded/collapsed header logic; uses semantic text sizes.


129-129: Semantic type scale usage — OK.
text-body-sm aligns with the new fontSize tokens.


206-208: Running ping honors reduced motion — nice.
motion-reduce:hidden on the ping + solid dot fallback is accessible.


220-220: Chevron transitions — compliant.
transition-transform duration-200 ease-out + motion-reduce:transition-none matches motion rules.


313-316: Diff stats defaults — safe.
Null-safe coalescing to 0 avoids runtime issues.


332-332: Loader honors reduced motion — good.
motion-reduce:animate-none covers accessibility.


385-393: Change badges use semantic tokens — LGTM.
bg-success/10 and bg-destructive/10 with borders read well on both themes.


321-325: The elevation-* utilities are properly defined and this review comment is incorrect.

The shell script confirms that both elevation-1 and elevation-2 are custom utilities defined in src/styles.css (lines 254–260) with explicit box-shadow values. These utilities are actively used throughout the codebase in multiple components. The code in app-sidebar.tsx is correct as-written; no changes are required.

Likely an incorrect or invalid review comment.

Comment thread src/components/app-sidebar.tsx Outdated
Comment thread src/features/workspace/components/MessageItem.tsx
Comment thread tailwind.config.js

@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: 0

♻️ Duplicate comments (1)
src/components/app-sidebar.tsx (1)

299-306: Status color mapping fix looks good

Explicit mapping (working/warning/destructive, muted idle) resolves prior truthy bug and aligns icon/text.

🧹 Nitpick comments (7)
src/Settings.tsx (2)

319-323: Consider debouncing the font size save.

The validation logic is solid, but calling saveSetting on every keystroke could create excessive API calls. Consider debouncing the save operation or switching to an onBlur pattern similar to the API key input.

Example with debounced save:

// Add debounce utility or use a library
const debouncedSaveSetting = useMemo(
  () => debounce((key: string, value: any) => saveSetting(key, value), 500),
  []
);

// Then in the onChange:
onChange={(e) => {
  const value = parseInt(e.target.value, 10);
  const fontSize = isNaN(value) || value < 8 || value > 24 ? 12 : value;
  setSettings(prev => ({ ...prev, terminal_font_size: fontSize }));
  debouncedSaveSetting('terminal_font_size', fontSize);
}}

408-408: Refine transition properties per guidelines.

The transition should specify which properties animate and include an easing function. For hover color changes, use ease with 200ms duration.

As per coding guidelines

Apply this change:

-              className="text-primary hover:underline transition-all duration-200"
+              className="text-primary hover:underline transition-colors duration-200 ease"
src/components/app-sidebar.tsx (5)

121-130: Add aria-label for icon-only “New Workspace”

When collapsed, rely on an explicit aria-label (tooltips aren’t read by AT).

Apply:

-            <SidebarMenuButton
-              onClick={() => onNewWorkspace()}
-              tooltip={!isExpanded ? "New Workspace" : undefined}
-            >
+            <SidebarMenuButton
+              onClick={() => onNewWorkspace()}
+              tooltip={!isExpanded ? "New Workspace" : undefined}
+              aria-label={!isExpanded ? "New Workspace" : undefined}
+            >

As per coding guidelines.


206-208: Mark decorative ping as aria-hidden

The status ping is purely decorative—hide from screen readers.

Apply:

-                  {hasRunningWorkspace && (
-                    <span className="absolute -bottom-0.5 -right-0.5 flex h-3 w-3 z-10">
+                  {hasRunningWorkspace && (
+                    <span className="absolute -bottom-0.5 -right-0.5 flex h-3 w-3 z-10" aria-hidden="true">
                       <span className="animate-ping motion-reduce:hidden absolute inline-flex h-full w-full rounded-full bg-primary opacity-75"></span>
                       <span className="relative inline-flex rounded-full h-3 w-3 bg-primary"></span>
                     </span>
                   )}

321-325: Align paddings to 16px default

The item uses px-2.5/py-3 (~10/12px). Prefer 16px (px-4, py-4) per guidelines; adjust if spacing permits.

Apply:

-          "grid grid-cols-[1fr_auto] items-center gap-2 py-3 px-2.5 min-h-[56px] rounded-lg cursor-pointer transition-all duration-200",
+          "grid grid-cols-[1fr_auto] items-center gap-2 py-4 px-4 min-h-[56px] rounded-lg cursor-pointer transition-all duration-200",

As per coding guidelines.


332-340: Hide decorative icons from AT

Spinner and branch glyph duplicate adjacent status text. Mark them aria-hidden to reduce verbosity.

Apply:

-            <Loader2
-              className="h-4 w-4 flex-shrink-0 text-primary/80 animate-spin motion-reduce:animate-none"
-            />
+            <Loader2
+              className="h-4 w-4 flex-shrink-0 text-primary/80 animate-spin motion-reduce:animate-none"
+              aria-hidden="true"
+              focusable="false"
+            />
...
-            <GitBranch
+            <GitBranch
               className={cn(
                 "h-4 w-4 flex-shrink-0",
                 getStatusTextColor(workspace.session_status)
               )}
+              aria-hidden="true"
+              focusable="false"
             />

381-389: Improve badge accessibility with labels

Add aria-labels so AT announces “X additions/deletions” instead of “plus/minus number”.

Apply:

-              <span className="inline-flex items-center px-1 py-0.5 rounded text-[10px] font-medium border border-success/30 bg-success/10 text-success whitespace-nowrap">
+              <span className="inline-flex items-center px-1 py-0.5 rounded text-[10px] font-medium border border-success/30 bg-success/10 text-success whitespace-nowrap" aria-label={`${additions} additions`}>
                 +{additions}
               </span>
...
-              <span className="inline-flex items-center px-1 py-0.5 rounded text-[10px] font-medium border border-destructive/30 bg-destructive/10 text-destructive whitespace-nowrap">
+              <span className="inline-flex items-center px-1 py-0.5 rounded text-[10px] font-medium border border-destructive/30 bg-destructive/10 text-destructive whitespace-nowrap" aria-label={`${deletions} deletions`}>
                 -{deletions}
               </span>
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Lite

📥 Commits

Reviewing files that changed from the base of the PR and between eca8276 and b1ad19c.

📒 Files selected for processing (4)
  • src/Settings.tsx (19 hunks)
  • src/components/app-sidebar.tsx (6 hunks)
  • src/components/ui/EmptyState.tsx (1 hunks)
  • src/features/workspace/components/MessageItem.tsx (5 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/components/ui/EmptyState.tsx
  • src/features/workspace/components/MessageItem.tsx
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx,js,jsx}: Use Zustand for state management
When using Framer Motion and needing hardware acceleration, animate via transform instead of x/y
Default to spring animations when using Framer Motion
Avoid bouncy spring animations except for drag gestures in Framer Motion

Files:

  • src/components/app-sidebar.tsx
  • src/Settings.tsx
**/*.{tsx,jsx,html}

📄 CodeRabbit inference engine (CLAUDE.md)

Use Tailwind for styling (prefer utility classes over custom CSS)

Files:

  • src/components/app-sidebar.tsx
  • src/Settings.tsx
**/*.{css,scss,less,tsx,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{css,scss,less,tsx,jsx}: Default paddings to 16px for denser layout
Use consistent font sizes (stick to design scale)
Use consistent colors and avoid hardcoding colors; use design tokens/Tailwind variables
Default to ease-out for most animations; durations ~0.2s–0.3s and never exceed 1s unless illustrative
Avoid built-in easings except ease or linear; otherwise use the specified cubic-bezier variants for ease-in/out/in-out
For simple hover transitions (color, background-color, opacity), use ease 200ms
Respect prefers-reduced-motion: disable transform animations when reduced motion is requested
Animate from the trigger (set transform-origin based on trigger position)
Prefer animating opacity and transform; avoid animating top/left for movement
Do not animate drag gestures using CSS variables
Do not animate blur values higher than 20px

Files:

  • src/components/app-sidebar.tsx
  • src/Settings.tsx
**/*.{tsx,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Base UI on shadcn/ui components

Files:

  • src/components/app-sidebar.tsx
  • src/Settings.tsx
🧬 Code graph analysis (2)
src/components/app-sidebar.tsx (5)
src/components/ui/sidebar.tsx (7)
  • Sidebar (746-746)
  • SidebarHeader (753-753)
  • SidebarFooter (748-748)
  • SidebarMenu (756-756)
  • SidebarMenuItem (760-760)
  • SidebarMenuButton (759-759)
  • SidebarMenuSubItem (764-764)
src/components/ui/index.ts (9)
  • Sidebar (28-28)
  • SidebarHeader (35-35)
  • Avatar (56-56)
  • AvatarFallback (56-56)
  • SidebarFooter (30-30)
  • SidebarMenu (38-38)
  • SidebarMenuItem (42-42)
  • SidebarMenuButton (41-41)
  • SidebarMenuSubItem (46-46)
src/components/ui/avatar.tsx (2)
  • Avatar (46-46)
  • AvatarFallback (46-46)
backend/server.cjs (1)
  • deletions (367-367)
src/lib/utils.ts (1)
  • cn (4-6)
src/Settings.tsx (1)
src/hooks/useTheme.tsx (1)
  • useTheme (83-89)
🔇 Additional comments (13)
src/Settings.tsx (10)

83-90: Good addition of response validation.

The error handling now properly validates the response status before updating state, preventing silent failures.


160-176: Theme selector looks good.

The implementation correctly integrates with the new theme system. The type annotations ensure type safety, and the UI follows the established patterns.


184-184: Consistent boolean normalization.

The pattern checked === true ensures only boolean values are persisted, which is good defensive programming given that onCheckedChange can return boolean | "indeterminate".

Also applies to: 198-198, 689-689, 703-703


287-295: API key deferred save is reasonable, but note the trade-off.

The pattern of updating local state on change and saving on blur reduces API calls and is appropriate for password fields. However, be aware that changes could be lost if the user navigates away before the field loses focus.

The autoComplete, spellCheck, and autoCapitalize attributes are good additions for API key input.

Consider whether this trade-off is acceptable for your UX requirements. If data loss is a concern, you might want to add a prompt before navigation or use a debounced auto-save.


115-115: Excellent accessibility considerations.

The aria-label on the navigation provides helpful context for screen readers, and the motion-reduce:animate-none utility respects user preferences for reduced motion.

Also applies to: 762-762


363-368: Consistent and helpful empty states.

The empty states across all sections now provide clear visual feedback and helpful guidance. The consistent styling and use of semantic color tokens aligns well with the design system.

Also applies to: 433-439, 478-484, 576-582


371-396: Well-structured card layouts.

The consistent card-based layout across all configuration sections provides excellent visual hierarchy and readability. The code blocks are properly styled with monospace fonts and overflow handling.

Also applies to: 442-448, 487-502, 585-592


401-416: Helpful documentation sections.

The info boxes at the end of each section provide valuable context and links to external documentation. The consistent styling makes them easily identifiable as supplementary information.

Also applies to: 453-461, 507-512, 597-607


749-766: Effective header with vibrancy effects.

The header successfully implements the frosted-glass aesthetic with backdrop blur and appropriate opacity values. The saving indicator with motion-reduce support provides good user feedback while respecting accessibility preferences.


1-776: Excellent Tailwind migration.

The complete refactor from custom CSS to Tailwind utilities is well-executed. The consistent use of semantic color tokens, proper spacing, and design patterns throughout the file creates a maintainable and cohesive UI. The integration of the new theme system is seamless.

src/components/app-sidebar.tsx (3)

76-97: Header + variant switch LGTM

Variant="sidebar" and the expanded/collapsed profile rendering look consistent with tokens and motion-reduce.


220-223: Verify aria-expanded is forwarded

CollapsibleTrigger asChild should attach aria-expanded to SidebarMenuButton. Please confirm it appears in the DOM for the trigger.


313-315: Safe defaults for diff stats

Nullish coalescing avoids undefined access—good.

@zvadaadam zvadaadam merged commit c9305da into main Oct 19, 2025
1 check passed
zvadaadam added a commit that referenced this pull request Feb 6, 2026
…mentation

Fixes 9 out of 10 code review issues (#1-5, #7, #9-10):
- Remove dead Claude transformer accumulation (Issue #1)
- Add graceful fallback for full_message column detection (Issue #2)
- Use process.argv[1] for bundle-safe vendor path resolution (Issue #3)
- Static import of execSync instead of dynamic require (Issue #4)
- Add platform support guard instead of silently mapping to Linux (Issue #5)
- Add null check on child.stdout before readline (Issue #7)
- Add identity check in finally block to prevent race condition (Issue #9)
- Capture thread_id for Codex message correlation (Issue #10)

The in-place mutation in codex-adapter.ts (Issue #6) is verified safe because blocks
are JSON-serialized before reaching the frontend, making the mutation internal to
adapter lifecycle and invisible to consumers.

All 193 sidecar tests pass. Zero type errors.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
zvadaadam added a commit that referenced this pull request Feb 8, 2026
…mentation

Fixes 9 out of 10 code review issues (#1-5, #7, #9-10):
- Remove dead Claude transformer accumulation (Issue #1)
- Add graceful fallback for full_message column detection (Issue #2)
- Use process.argv[1] for bundle-safe vendor path resolution (Issue #3)
- Static import of execSync instead of dynamic require (Issue #4)
- Add platform support guard instead of silently mapping to Linux (Issue #5)
- Add null check on child.stdout before readline (Issue #7)
- Add identity check in finally block to prevent race condition (Issue #9)
- Capture thread_id for Codex message correlation (Issue #10)

The in-place mutation in codex-adapter.ts (Issue #6) is verified safe because blocks
are JSON-serialized before reaching the frontend, making the mutation internal to
adapter lifecycle and invisible to consumers.

All 193 sidecar tests pass. Zero type errors.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
zvadaadam added a commit that referenced this pull request Feb 8, 2026
…mentation

Fixes 9 out of 10 code review issues (#1-5, #7, #9-10):
- Remove dead Claude transformer accumulation (Issue #1)
- Add graceful fallback for full_message column detection (Issue #2)
- Use process.argv[1] for bundle-safe vendor path resolution (Issue #3)
- Static import of execSync instead of dynamic require (Issue #4)
- Add platform support guard instead of silently mapping to Linux (Issue #5)
- Add null check on child.stdout before readline (Issue #7)
- Add identity check in finally block to prevent race condition (Issue #9)
- Capture thread_id for Codex message correlation (Issue #10)

The in-place mutation in codex-adapter.ts (Issue #6) is verified safe because blocks
are JSON-serialized before reaching the frontend, making the mutation internal to
adapter lifecycle and invisible to consumers.

All 193 sidecar tests pass. Zero type errors.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
zvadaadam added a commit that referenced this pull request Feb 23, 2026
## Changes

### 1. Fix DevTools Expansion Bug (Tauri Native Layer)
When clicking the DevTools button, the browser view would unexpectedly expand.
Root cause: `_inspector.show()` docks by splitting WKWebView's superview, resizing
the webview. After `detach()` moves inspector to floating window, frame isn't restored.
**Fix:** Save WKWebView frame before show(), restore after detach().
- Modified: src-tauri/src/commands/webview.rs (lines 570-582)

### 2. Fix Cursor Animation Attribute Mismatch (Issue #1 - HIGH)
Cursor visual effects (move, ripple, pin) were silently failing because they searched
for `data-cursor-ref` but elements were marked with `data-hive-ref`.
**Fix:** Replace all `data-cursor-ref` references with `data-hive-ref` to match
the actual attribute used in inject-mode.ts.
- Modified: src/features/browser/automation/visual-effects.ts
  - Line 18: JSDoc comment
  - Line 25: buildMoveCursorAndRippleJs()
  - Line 45: buildPinCursorJs()
  - Line 96: buildHighlightElementJs()

### 3. Add IME Composition Guard to MessageInput (Issue #2 - MEDIUM)
CJK (Chinese, Japanese, Korean) users using Input Method Editors (IME) would lose
their input when pressing Enter during composition, since the handler didn't check
if composition was in progress.
**Fix:** Add `!e.nativeEvent.isComposing` guard to Enter key handler to prevent
message send during active IME composition.
- Modified: src/features/session/ui/MessageInput.tsx (line 286)

### 4. Fix Element Selector Injection Exception Handling (Issue #3 - MEDIUM)
When `verify_injection` script threw an exception, the catch block didn't return,
causing exception object to fall through to `eval_browser_webview_with_result`,
which would parse it as a result string instead of error.
**Fix:** Add explicit `return;` in catch block to prevent fall-through.
- Modified: src/features/browser/ui/BrowserTab.tsx (line 521)

### 5. Fix Selector Toggle State on Eval Failure (Issue #4 - MEDIUM)
When element selector injection failed, `selectorActive` was set in the UI store
but outside the try block, so errors during injection were silently swallowed.
**Fix:** Move state update inside try block to fail-fast on injection errors.
- Modified: src/features/browser/ui/BrowserTab.tsx (line 563)

### 6. Add Polling Guard to Inspect Event Drain (Issue #5 - MEDIUM)
Inspect event drain was polling unconditionally every 200ms, consuming ~5 IPC
calls/second unnecessarily. With multiple tabs this compounds quickly.
**Fix:** Only poll when selector is active. Add `!tab.selectorActive` guard and
add to dependency array.
- Modified: src/features/browser/ui/BrowserTab.tsx (lines 396-458)

### 7. Replace if/else with ts-pattern (Issue #6 - LOW)
Long if/else chain for event type dispatch violates CLAUDE.md requirement to use
ts-pattern for discriminated union dispatch.
**Fix:** Import ts-pattern and use `.with()` / `.otherwise()` for event type matching.
- Modified: src/features/browser/ui/BrowserTab.tsx (lines 26, 427-444)

### 8. Fix Hover Animation Timing (Issue #7 - LOW)
InspectedElementCard hover transition was `duration-150` instead of `duration-200`,
violating CLAUDE.md animation standard of 200-300ms default duration.
**Fix:** Update to `duration-200 ease` to match project animation guidelines.
- Modified: src/features/session/ui/InspectedElementCard.tsx (line 48)

## Verification
- TypeScript compilation: ✓ (pre-existing Lucide icon issue unrelated to changes)
- All fixes verified and applied by parallel code-reviewer agents
- Changes preserve existing functionality while fixing correctness issues
- Performance improvement: Eliminates ~5 IPC calls/second from unconditional polling

## Impact
- **Bug fixes:** 3 (DevTools expansion, cursor animations, IME composition)
- **Correctness improvements:** 2 (exception handling, state sync)
- **Performance:** Reduced IPC quota consumption from inspect event drain
- **Code quality:** Full CLAUDE.md compliance (ts-pattern, animation timing)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
zvadaadam added a commit that referenced this pull request Feb 23, 2026
1. **inject-mode.ts: var() scan now covers padding/gap (#3)**
   Renamed colorProps → varScanProps, added padding/gap so
   getMatchedVarDeclarations captures var() tokens for spacing props.

2. **inject-mode.ts: font-weight fallback added (#10)**
   Added font-weight to the fallback conditional alongside font-size
   and border-radius. Filters out 'normal' (CSS default) as noise.

3. **BrowserPanel.tsx: DevTools state races with async invoke (#4)**
   Moved handleUpdateTab into .then() so devtoolsOpen only updates
   after the Rust command succeeds. Prevents UI desync on failure.

4. **BrowserTab.tsx: safeListen missing .catch() (#5)**
   Added .catch() to the listen() promise chain to prevent unhandled
   rejections if Tauri listener registration fails.

5. **BrowserTab.tsx: injectionFailed not cleared on success (#7)**
   Changed onUpdateTab to also set injectionFailed: false after
   successful injection, clearing stale error indicators.

6. **webview.rs: eprintln! gated for release builds (#8)**
   All 4 eprintln! calls in eval_browser_webview_with_result wrapped
   with cfg!(debug_assertions). Prevents leaking JS content, URLs,
   tokens, or page console data in production.

7. **webview.rs: DevTools error propagation (#9)**
   open/close_browser_devtools now use Arc<Mutex<Option<String>>> to
   propagate null-pointer errors out of with_webview closures. Frontend
   receives Err() instead of silent Ok(()) when DevTools unavailable.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
zvadaadam added a commit that referenced this pull request Feb 23, 2026
* feat: Fix browser inspect element pills with code quality improvements

## Changes

### 1. Fix DevTools Expansion Bug (Tauri Native Layer)
When clicking the DevTools button, the browser view would unexpectedly expand.
Root cause: `_inspector.show()` docks by splitting WKWebView's superview, resizing
the webview. After `detach()` moves inspector to floating window, frame isn't restored.
**Fix:** Save WKWebView frame before show(), restore after detach().
- Modified: src-tauri/src/commands/webview.rs (lines 570-582)

### 2. Fix Cursor Animation Attribute Mismatch (Issue #1 - HIGH)
Cursor visual effects (move, ripple, pin) were silently failing because they searched
for `data-cursor-ref` but elements were marked with `data-hive-ref`.
**Fix:** Replace all `data-cursor-ref` references with `data-hive-ref` to match
the actual attribute used in inject-mode.ts.
- Modified: src/features/browser/automation/visual-effects.ts
  - Line 18: JSDoc comment
  - Line 25: buildMoveCursorAndRippleJs()
  - Line 45: buildPinCursorJs()
  - Line 96: buildHighlightElementJs()

### 3. Add IME Composition Guard to MessageInput (Issue #2 - MEDIUM)
CJK (Chinese, Japanese, Korean) users using Input Method Editors (IME) would lose
their input when pressing Enter during composition, since the handler didn't check
if composition was in progress.
**Fix:** Add `!e.nativeEvent.isComposing` guard to Enter key handler to prevent
message send during active IME composition.
- Modified: src/features/session/ui/MessageInput.tsx (line 286)

### 4. Fix Element Selector Injection Exception Handling (Issue #3 - MEDIUM)
When `verify_injection` script threw an exception, the catch block didn't return,
causing exception object to fall through to `eval_browser_webview_with_result`,
which would parse it as a result string instead of error.
**Fix:** Add explicit `return;` in catch block to prevent fall-through.
- Modified: src/features/browser/ui/BrowserTab.tsx (line 521)

### 5. Fix Selector Toggle State on Eval Failure (Issue #4 - MEDIUM)
When element selector injection failed, `selectorActive` was set in the UI store
but outside the try block, so errors during injection were silently swallowed.
**Fix:** Move state update inside try block to fail-fast on injection errors.
- Modified: src/features/browser/ui/BrowserTab.tsx (line 563)

### 6. Add Polling Guard to Inspect Event Drain (Issue #5 - MEDIUM)
Inspect event drain was polling unconditionally every 200ms, consuming ~5 IPC
calls/second unnecessarily. With multiple tabs this compounds quickly.
**Fix:** Only poll when selector is active. Add `!tab.selectorActive` guard and
add to dependency array.
- Modified: src/features/browser/ui/BrowserTab.tsx (lines 396-458)

### 7. Replace if/else with ts-pattern (Issue #6 - LOW)
Long if/else chain for event type dispatch violates CLAUDE.md requirement to use
ts-pattern for discriminated union dispatch.
**Fix:** Import ts-pattern and use `.with()` / `.otherwise()` for event type matching.
- Modified: src/features/browser/ui/BrowserTab.tsx (lines 26, 427-444)

### 8. Fix Hover Animation Timing (Issue #7 - LOW)
InspectedElementCard hover transition was `duration-150` instead of `duration-200`,
violating CLAUDE.md animation standard of 200-300ms default duration.
**Fix:** Update to `duration-200 ease` to match project animation guidelines.
- Modified: src/features/session/ui/InspectedElementCard.tsx (line 48)

## Verification
- TypeScript compilation: ✓ (pre-existing Lucide icon issue unrelated to changes)
- All fixes verified and applied by parallel code-reviewer agents
- Changes preserve existing functionality while fixing correctness issues
- Performance improvement: Eliminates ~5 IPC calls/second from unconditional polling

## Impact
- **Bug fixes:** 3 (DevTools expansion, cursor animations, IME composition)
- **Correctness improvements:** 2 (exception handling, state sync)
- **Performance:** Reduced IPC quota consumption from inspect event drain
- **Code quality:** Full CLAUDE.md compliance (ts-pattern, animation timing)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: Address PR review — ts-pattern console dispatch + comment consistency

1. Replace nested ternary on log.l with ts-pattern match() in console
   drain loop (BrowserTab.tsx:365). Consistent with inspect event drain
   at line 428 which already uses match(). CLAUDE.md requires ts-pattern
   for all discriminator field dispatch.

2. Fix contradictory architecture comments across 3 files:
   - inject/inspect-mode.ts: Remove "DUAL mechanism: PRIMARY title-channel"
     language and phantom serialization queue details. Buffer+drain via
     eval_browser_webview_with_result is the sole path.
   - BrowserTab.tsx: Change "FALLBACK path" to "sole delivery path".
   - webview.rs: Remove reference to non-existent sendViaTitle(), mark
     title-channel handler as backward-compat only.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: Address PR review — 7 issues across 4 files

1. **inject-mode.ts: var() scan now covers padding/gap (#3)**
   Renamed colorProps → varScanProps, added padding/gap so
   getMatchedVarDeclarations captures var() tokens for spacing props.

2. **inject-mode.ts: font-weight fallback added (#10)**
   Added font-weight to the fallback conditional alongside font-size
   and border-radius. Filters out 'normal' (CSS default) as noise.

3. **BrowserPanel.tsx: DevTools state races with async invoke (#4)**
   Moved handleUpdateTab into .then() so devtoolsOpen only updates
   after the Rust command succeeds. Prevents UI desync on failure.

4. **BrowserTab.tsx: safeListen missing .catch() (#5)**
   Added .catch() to the listen() promise chain to prevent unhandled
   rejections if Tauri listener registration fails.

5. **BrowserTab.tsx: injectionFailed not cleared on success (#7)**
   Changed onUpdateTab to also set injectionFailed: false after
   successful injection, clearing stale error indicators.

6. **webview.rs: eprintln! gated for release builds (#8)**
   All 4 eprintln! calls in eval_browser_webview_with_result wrapped
   with cfg!(debug_assertions). Prevents leaking JS content, URLs,
   tokens, or page console data in production.

7. **webview.rs: DevTools error propagation (#9)**
   open/close_browser_devtools now use Arc<Mutex<Option<String>>> to
   propagate null-pointer errors out of with_webview closures. Frontend
   receives Err() instead of silent Ok(()) when DevTools unavailable.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(ci): build inject scripts before sidecar unit tests

browser-templates.test.ts imports browser-utils.ts which reads
dist-inject/browser-utils.js via ?raw import. The dist-inject/
directory is gitignored and must be built first.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(test): update browser-templates tests for inject refactor

- Remove dead BROWSER_UTILS import (renamed to BROWSER_UTILS_SETUP)
- Remove incorrect buildPressKeyJs BROWSER_UTILS test (it intentionally
  doesn't use browser utils — operates on document.activeElement directly)
- Update assertIsIIFE to accept both classic IIFEs (function(){...})()
  and arrow IIFEs (() => {...})() — esbuild format: "iife" emits the
  latter for compiled inject scripts like VISUAL_EFFECTS_SETUP

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: address code review round 3 — security, a11y, concurrency

- Gate getReactProps() and getShallowInnerHTML() to local context only;
  external sites can leak PII/tokens via React fiber props and innerHTML
- Remove 'value' from ATTR_WHITELIST (can contain passwords)
- Add in-flight guards to console and inspect drain intervals to prevent
  overlapping async invokes when eval_browser_webview is slow
- Add aria-hidden + sr-only text for injection failure indicator
- Add aria-label to screenshot button
- Remove duplicate comment blocks in inject-mode.ts
- Fix stale "title-channel" comment in BrowserTab.tsx

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat(browser): add screenshot button + mobile viewport toggle

Add two new browser panel toolbar features:

1. Screenshot button (Camera icon): captures WKWebView as JPEG via Rust
   IPC and attaches to chat input via CustomEvent bridge.

2. Mobile/Desktop viewport toggle (Smartphone/Monitor icon): constrains
   browser area to 390px (iPhone 14 logical width) centered with mx-auto.

The mobile view required replacing the tab stacking strategy — absolute
positioning (inset-0) didn't reliably inherit width constraints during
parent restructuring, causing getBoundingClientRect() to return stale
full-width values. Tabs now stack via CSS Grid ([grid-area:1/1]) which
keeps them in normal document flow. A useLayoutEffect with hide →
setBounds → show cycle ensures the native WKWebView repositions
synchronously on toggle.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
zvadaadam added a commit that referenced this pull request Mar 12, 2026
- #3: Log query:invalidate emit errors in backend.rs (was silent `let _ =`)
- #5: Guard malformed payload in useQueryInvalidation with `?.` fallback
- #6: Update CLAUDE.md — useSession is event-driven, not polled
- #7: Move misplaced ChatInsert JSDoc to correct position above its schema

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
zvadaadam added a commit that referenced this pull request Mar 12, 2026
* feat(events): centralized event catalog with Zod runtime validation

Implement a single source of truth for all Tauri/sidecar events with compile-time type safety and runtime validation:

- Add shared/events.ts with 17 event constants, 13 Zod schemas, 3 domain arrays (QUERY_RESOURCES, MUTATION_NAMES, SIDECAR_NOTIFY_EVENTS), and AppEventMap/AppEventName types
- Wire Zod validation into listen() wrapper — validates payloads at Rust→TS boundary, logs drift, still delivers on failure
- Fix 3 raw string emit() calls to use BROWSER_WORKSPACE_CHANGE and CHAT_INSERT constants
- Consolidate message-writing to writeUserMessage() service to eliminate duplication
- Remove web polling fallback code (getWorkspacesByRepoRefetchInterval, getStatsRefetchInterval) — desktop-only app
- Fix type narrowing for INVALIDATION_MAP in notify route
- Tighten ChatInsertSchema element variant with proper InspectElement Zod schema
- Add 32 tests: events schema validation (19), listen() Zod validation (5), notify route (8)
- All 286 backend + 131 frontend + 442 sidecar tests pass

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>

* docs(CLAUDE.md): document event catalog pattern and update polling guidance

- Add Event Catalog section explaining shared/events.ts, AppEventMap,
  Zod validation, createListenerGroup, and how to add new events
- Update request volume table to reflect event-driven invalidation
  (workspaces/stats no longer polled)
- Update polling discipline to reference push-first invalidation pipeline
- Update read-layer migration priorities (no longer referenced as "polled every 2s")

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: address code review feedback (#3, #5, #6, #7)

- #3: Log query:invalidate emit errors in backend.rs (was silent `let _ =`)
- #5: Guard malformed payload in useQueryInvalidation with `?.` fallback
- #6: Update CLAUDE.md — useSession is event-driven, not polled
- #7: Move misplaced ChatInsert JSDoc to correct position above its schema

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: tighten QueryInvalidateSchema and clear error fields on retry (#2, #5)

- #2: Clear error_message/error_category in writeUserMessage() to align
  with sidecar's saveUserMessage() — prevents stale error fields on retry
- #5: Tighten QueryInvalidateSchema resources to z.enum(QUERY_RESOURCES)
  instead of z.string() — catches misspelled resource names at runtime

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Haiku 4.5 <noreply@anthropic.com>
zvadaadam added a commit that referenced this pull request Mar 22, 2026
PairGatePage:
- Remove last "relay" jargon from error message (#3)
- PulsingDots respects prefers-reduced-motion via `reduced` prop (#4)
- Add sr-only label, aria-invalid, aria-describedby, role=alert for a11y (#5)
- Store success timeout in ref + cleanup on unmount (#6)
- Cancel paste auto-submit timer on type and explicit submit (#8)

AccessSection:
- Use onOpenChangeRef to prevent stale closure in success setTimeout (#7)
- Detect new devices by ID set comparison instead of count (#9)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 089f8af05d92
zvadaadam added a commit that referenced this pull request Mar 22, 2026
)

* feat: redesign device pairing UX with two-word codes, QR dialog, and animated gate page

Replaces WORD-NNNN pairing codes with two uppercase words (e.g. SOFT TIGER) from a 250-word list
for better dictation and mobile typing. Consolidates the split two-field input into a single field
with smart paste handling. Adds a centered dialog with QR code hero for desktop pairing flow, and
redesigns the remote PairGatePage with three animated states (auto-connecting, success, manual entry).
Codes are now reusable within their 15-minute TTL for multi-device sharing.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: replace hardcoded color classes with semantic tokens

Use bg-success, text-success, text-warning, bg-warning, bg-destructive
instead of bg-emerald-500, text-emerald-500, text-amber-500, bg-red-400.
These semantic tokens are already defined in global.css and adapt to
light/dark mode via OKLCH values.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 9ffb5ff87432

* fix: update integration tests for two-word codes and reusable TTL

The integration test still expected the old WORD-NNNN format regex and
one-time-use code behavior. Updated to match two-word format and verify
that codes are reusable within their TTL for multi-device sharing.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 36c4f0b6f8fc

* fix: address code review findings for pairing UX

PairGatePage:
- Remove last "relay" jargon from error message (#3)
- PulsingDots respects prefers-reduced-motion via `reduced` prop (#4)
- Add sr-only label, aria-invalid, aria-describedby, role=alert for a11y (#5)
- Store success timeout in ref + cleanup on unmount (#6)
- Cancel paste auto-submit timer on type and explicit submit (#8)

AccessSection:
- Use onOpenChangeRef to prevent stale closure in success setTimeout (#7)
- Detect new devices by ID set comparison instead of count (#9)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 089f8af05d92

* fix: gate device success detection on query resolution

Pass isDevicesLoaded (from devicesQuery.isFetched) to ConnectDeviceDialog.
When the query hasn't resolved yet, just update the baseline IDs without
triggering success detection. This prevents false positives when the dialog
opens while devices are still loading ([] → existing devices).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: f34b15c1a77e

* fix: differentiate QR placeholder states in connect dialog

Show "Generating..." only when the relay URL is available but the code
is still being created. Show "Waiting for connection..." when the relay
itself hasn't connected yet (no accessUrl). Previously both states showed
"Generating..." which was misleading.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 43c76b5ad359

* fix: await clipboard writes and use curated error messages

- Await navigator.clipboard.writeText() and show error toast on failure
  instead of assuming success (all 3 clipboard call sites)
- Replace raw backend error messages in toasts with curated user-facing
  copy ("Couldn't generate a code", "Couldn't remove device")
- Remove unused getErrorMessage import

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 60d8c8e60b18

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
zvadaadam added a commit that referenced this pull request Apr 2, 2026
…mentation

Fixes 9 out of 10 code review issues (#1-5, #7, #9-10):
- Remove dead Claude transformer accumulation (Issue #1)
- Add graceful fallback for full_message column detection (Issue #2)
- Use process.argv[1] for bundle-safe vendor path resolution (Issue #3)
- Static import of execSync instead of dynamic require (Issue #4)
- Add platform support guard instead of silently mapping to Linux (Issue #5)
- Add null check on child.stdout before readline (Issue #7)
- Add identity check in finally block to prevent race condition (Issue #9)
- Capture thread_id for Codex message correlation (Issue #10)

The in-place mutation in codex-adapter.ts (Issue #6) is verified safe because blocks
are JSON-serialized before reaching the frontend, making the mutation internal to
adapter lifecycle and invisible to consumers.

All 193 sidecar tests pass. Zero type errors.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
zvadaadam added a commit that referenced this pull request Apr 2, 2026
- #3: Log query:invalidate emit errors in backend.rs (was silent `let _ =`)
- #5: Guard malformed payload in useQueryInvalidation with `?.` fallback
- #6: Update CLAUDE.md — useSession is event-driven, not polled
- #7: Move misplaced ChatInsert JSDoc to correct position above its schema

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
zvadaadam added a commit that referenced this pull request Apr 2, 2026
## Changes

### 1. Fix DevTools Expansion Bug (Tauri Native Layer)
When clicking the DevTools button, the browser view would unexpectedly expand.
Root cause: `_inspector.show()` docks by splitting WKWebView's superview, resizing
the webview. After `detach()` moves inspector to floating window, frame isn't restored.
**Fix:** Save WKWebView frame before show(), restore after detach().
- Modified: src-tauri/src/commands/webview.rs (lines 570-582)

### 2. Fix Cursor Animation Attribute Mismatch (Issue #1 - HIGH)
Cursor visual effects (move, ripple, pin) were silently failing because they searched
for `data-cursor-ref` but elements were marked with `data-hive-ref`.
**Fix:** Replace all `data-cursor-ref` references with `data-hive-ref` to match
the actual attribute used in inject-mode.ts.
- Modified: src/features/browser/automation/visual-effects.ts
  - Line 18: JSDoc comment
  - Line 25: buildMoveCursorAndRippleJs()
  - Line 45: buildPinCursorJs()
  - Line 96: buildHighlightElementJs()

### 3. Add IME Composition Guard to MessageInput (Issue #2 - MEDIUM)
CJK (Chinese, Japanese, Korean) users using Input Method Editors (IME) would lose
their input when pressing Enter during composition, since the handler didn't check
if composition was in progress.
**Fix:** Add `!e.nativeEvent.isComposing` guard to Enter key handler to prevent
message send during active IME composition.
- Modified: src/features/session/ui/MessageInput.tsx (line 286)

### 4. Fix Element Selector Injection Exception Handling (Issue #3 - MEDIUM)
When `verify_injection` script threw an exception, the catch block didn't return,
causing exception object to fall through to `eval_browser_webview_with_result`,
which would parse it as a result string instead of error.
**Fix:** Add explicit `return;` in catch block to prevent fall-through.
- Modified: src/features/browser/ui/BrowserTab.tsx (line 521)

### 5. Fix Selector Toggle State on Eval Failure (Issue #4 - MEDIUM)
When element selector injection failed, `selectorActive` was set in the UI store
but outside the try block, so errors during injection were silently swallowed.
**Fix:** Move state update inside try block to fail-fast on injection errors.
- Modified: src/features/browser/ui/BrowserTab.tsx (line 563)

### 6. Add Polling Guard to Inspect Event Drain (Issue #5 - MEDIUM)
Inspect event drain was polling unconditionally every 200ms, consuming ~5 IPC
calls/second unnecessarily. With multiple tabs this compounds quickly.
**Fix:** Only poll when selector is active. Add `!tab.selectorActive` guard and
add to dependency array.
- Modified: src/features/browser/ui/BrowserTab.tsx (lines 396-458)

### 7. Replace if/else with ts-pattern (Issue #6 - LOW)
Long if/else chain for event type dispatch violates CLAUDE.md requirement to use
ts-pattern for discriminated union dispatch.
**Fix:** Import ts-pattern and use `.with()` / `.otherwise()` for event type matching.
- Modified: src/features/browser/ui/BrowserTab.tsx (lines 26, 427-444)

### 8. Fix Hover Animation Timing (Issue #7 - LOW)
InspectedElementCard hover transition was `duration-150` instead of `duration-200`,
violating CLAUDE.md animation standard of 200-300ms default duration.
**Fix:** Update to `duration-200 ease` to match project animation guidelines.
- Modified: src/features/session/ui/InspectedElementCard.tsx (line 48)

## Verification
- TypeScript compilation: ✓ (pre-existing Lucide icon issue unrelated to changes)
- All fixes verified and applied by parallel code-reviewer agents
- Changes preserve existing functionality while fixing correctness issues
- Performance improvement: Eliminates ~5 IPC calls/second from unconditional polling

## Impact
- **Bug fixes:** 3 (DevTools expansion, cursor animations, IME composition)
- **Correctness improvements:** 2 (exception handling, state sync)
- **Performance:** Reduced IPC quota consumption from inspect event drain
- **Code quality:** Full CLAUDE.md compliance (ts-pattern, animation timing)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
zvadaadam added a commit that referenced this pull request Apr 2, 2026
1. **inject-mode.ts: var() scan now covers padding/gap (#3)**
   Renamed colorProps → varScanProps, added padding/gap so
   getMatchedVarDeclarations captures var() tokens for spacing props.

2. **inject-mode.ts: font-weight fallback added (#10)**
   Added font-weight to the fallback conditional alongside font-size
   and border-radius. Filters out 'normal' (CSS default) as noise.

3. **BrowserPanel.tsx: DevTools state races with async invoke (#4)**
   Moved handleUpdateTab into .then() so devtoolsOpen only updates
   after the Rust command succeeds. Prevents UI desync on failure.

4. **BrowserTab.tsx: safeListen missing .catch() (#5)**
   Added .catch() to the listen() promise chain to prevent unhandled
   rejections if Tauri listener registration fails.

5. **BrowserTab.tsx: injectionFailed not cleared on success (#7)**
   Changed onUpdateTab to also set injectionFailed: false after
   successful injection, clearing stale error indicators.

6. **webview.rs: eprintln! gated for release builds (#8)**
   All 4 eprintln! calls in eval_browser_webview_with_result wrapped
   with cfg!(debug_assertions). Prevents leaking JS content, URLs,
   tokens, or page console data in production.

7. **webview.rs: DevTools error propagation (#9)**
   open/close_browser_devtools now use Arc<Mutex<Option<String>>> to
   propagate null-pointer errors out of with_webview closures. Frontend
   receives Err() instead of silent Ok(()) when DevTools unavailable.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
zvadaadam added a commit that referenced this pull request Apr 2, 2026
PairGatePage:
- Remove last "relay" jargon from error message (#3)
- PulsingDots respects prefers-reduced-motion via `reduced` prop (#4)
- Add sr-only label, aria-invalid, aria-describedby, role=alert for a11y (#5)
- Store success timeout in ref + cleanup on unmount (#6)
- Cancel paste auto-submit timer on type and explicit submit (#8)

AccessSection:
- Use onOpenChangeRef to prevent stale closure in success setTimeout (#7)
- Detect new devices by ID set comparison instead of count (#9)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 089f8af05d92
zvadaadam added a commit that referenced this pull request Apr 14, 2026
…ptyState 39 lines), removed 3 dead API type definitions (ApiResponse, PaginatedResponse, WorkspaceQueryParams) from shared/types/api.ts, removed 4 dead session type aliases (SessionMessageEvent, SessionErrorEvent, SessionEnterPlanModeEvent, SessionStatusEvent) from shared/types/session.ts, and cleaned up 3 barrel re-export files — net reduction of 330 lines across 7 files with all 825 tests passing.
zvadaadam added a commit that referenced this pull request Apr 14, 2026
* gnhf #1: Extracted two helper methods in claude-adapter.ts (closeActiveParts, accumulateStreamDelta) to eliminate 5 repeated close-text/close-thinking call sites and 2 duplicate 25-line streaming delta handlers; also replaced a duplicate 15-line formatTime function in WorkspaceItem.tsx with the existing shared formatTimeAgo utility — net reduction of 49 lines with all 375 agent-server tests passing.

* gnhf #2: Extracted duplicate workspace-grouping logic (85 lines across query-engine.ts and workspaces.ts route) into shared lib/workspace-grouping.ts, and consolidated duplicate parameter-reading helpers (readString/readNumber across query-engine.ts and commands.ts) into shared lib/query-params.ts — net reduction of 41 lines with all 825 tests passing.

* gnhf #3: Removed unused  parameter from cancellation functions across both agent handlers, extracted  helper replacing 5 identical repo-lookup patterns in repos.ts, unified duplicate git progress push functions, and removed dead  export — net reduction of 23 lines across 7 files with all 825 tests passing.

* gnhf #4: Removed 5 dead exports/functions and un-exported 2 internal-only functions across 6 files — net reduction of 112 lines with all 825 tests passing.

* gnhf #5: Removed 2 dead exported functions (getRepoInitials, getRepoColor), un-exported 3 internal-only symbols (RECENT_PROJECT_LIMIT, resolveGitProjectRoot, setLastOpenInAppId), and replaced duplicate timeAgo in AccessSection.tsx with shared formatTimeAgo — net reduction of 41 lines across 5 files with all 825 tests passing.

* gnhf #6: Un-exported 14 dead Zod schema validators (6 from shared/events.ts, 8 from shared/agent-events.ts), un-exported 6 dead type aliases from shared/events.ts, and consolidated duplicate parseGitHubRepo function from gh.service.ts and deus-import.ts into shared/lib/github.ts — reducing public API surface by 20 exports and eliminating 1 duplicate function across 5 files with all 825 tests passing.

* gnhf #7: Deleted 2 dead component files (OpenInDropdown 214 lines, EmptyState 39 lines), removed 3 dead API type definitions (ApiResponse, PaginatedResponse, WorkspaceQueryParams) from shared/types/api.ts, removed 4 dead session type aliases (SessionMessageEvent, SessionErrorEvent, SessionEnterPlanModeEvent, SessionStatusEvent) from shared/types/session.ts, and cleaned up 3 barrel re-export files — net reduction of 330 lines across 7 files with all 825 tests passing.

* gnhf #8: Deleted 2 dead platform files (updates.ts 31 lines, listenerGroup.ts 38 lines), removed dead  function from dialog.ts, removed the entire dead StatusChanged notification pipeline across 5 files (method, schema, type, constant, test builder, union), un-exported  from electron barrel, and cleaned up 3 barrel re-export files — net reduction of 121 lines across 11 files with all 825 tests passing.

* gnhf #9: Removed 3 dead query hooks (useStats, useUncommittedFiles, useLastTurnFiles) with their stub service methods and query keys, removed 4 dead type definitions (ChangedFilesResult, BranchInfo, PaginationParams, DevServer) and their barrel re-exports, un-exported internal-only connectToRelay function, and cleaned up 2 dead barrel re-exports (clearToken, ConnectionIllustration) — net reduction of 121 lines across 12 files with all 825 tests passing and clean tsc.

* gnhf #10: Removed 6 dead visual effect builder functions (98 lines) from visual-effects.ts, un-exported 5 internal-only symbols (resolveClaudeDir, getAgentConfig, StatusPriority, StatusConfig, WorkflowStatusConfig), and removed dead barrel re-exports (createAgentEventHandler, AgentEventHandler) from agent/index.ts — net reduction of 98 lines across 5 files with all 825 tests passing and clean tsc.

* gnhf #11: Consolidated inline path validation in files.ts to use shared resolveWorkspaceRelativePath from git.service.ts, and replaced 10 hand-rolled readString+throw param validation patterns in commands.ts with the existing requireParam utility — net reduction of 17 lines across 2 files with all 825 tests passing and clean tsc.

* gnhf #12: Removed 211 lines of dead CSS from global.css: the entire glitch-swap effect system (6 classes, 6 @Keyframes, 2 media queries) and the empty tool-use-enter class — none referenced by any component, with all 825 tests passing.

* gnhf #13: Deleted 2 dead component files (RepoGroup.tsx 102 lines, WorkspaceItem.tsx 123 lines) from repository/ui that were never rendered anywhere, removed 14 dead barrel re-exports across 4 barrel files (repository/ui, sidebar/ui, sidebar feature, session/ui/blocks), and cleaned up knip.json — net reduction of 242 lines across 7 files with all 825 tests passing and clean tsc.

* gnhf #14: Deleted the dead agent-server/messages/index.ts barrel (30 lines), removed 4 dead type exports from shared/messages/types.ts (ToolLocation, ToolOutputContent, PartType, PartTypeSchema), removed dead ToolResultMap type from chat-types.ts, and cleaned up 15 dead barrel re-exports across 4 barrel files (session/hooks, session/ui, workspace/ui, shared/hooks) — net reduction of 51 lines across 8 files with all 825 tests passing and clean tsc.

* gnhf #15: Removed 10 dead type aliases from shared/agent-events.ts, un-exported 2 dead Zod schemas from shared/enums.ts, removed the dead useWindowFocus hook and its useSyncExternalStore infrastructure (50 lines) from useWindowFocus.ts, and removed dead BaseToolRendererProps barrel re-export — net reduction of 62 lines across 4 files with all 825 tests passing and clean tsc.

* refactor: extract backend helpers and fix typecheck

* Address CodeRabbit review feedback

* Fix Claude adapter message handoff
zvadaadam added a commit that referenced this pull request May 31, 2026
…ptyState 39 lines), removed 3 dead API type definitions (ApiResponse, PaginatedResponse, WorkspaceQueryParams) from shared/types/api.ts, removed 4 dead session type aliases (SessionMessageEvent, SessionErrorEvent, SessionEnterPlanModeEvent, SessionStatusEvent) from shared/types/session.ts, and cleaned up 3 barrel re-export files — net reduction of 330 lines across 7 files with all 825 tests passing.
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.

1 participant