Repository navigation
Conversation
- Model selector popover: match chat input box bg/border/shadow - Dropdown menus: same bg-gray-1 + white border treatment - Context window hover card: consistent styling - Input mode, model selector, effort, image buttons: pill shape - Worktree path: use GitBranch icon, pill shape - Coming Soon box: match model button corner radius - Update docs and add release guide
- Add NSVisualEffectView frost layer (decorum plugin) replacing CSS backdrop-filter which caused white glow at macOS window rounded corners - Add AI-powered session titles using Haiku via query() for fast ~1-2s title generation after first conversation turn, with smart fallback truncation and pending-title flush on system:init - Persist custom titles to JSONL via custom-title convention (matching Claude Code CLI), with POSIX-safe atomic appends - Unify tool widget borders and backgrounds across all tool widgets - Polish light-mode popover shadows, sidebar selection opacity, and rounded corner consistency (rounded-[9px]) - Fix Immer nested mutation in updateConversationTitle (whole-object replace) - Bump claude-agent-sdk to 0.2.50 and claude-code to 2.1.50
Remove HeaderBranchSelector from chat-header and content-top-bar — branch switching now lives in the WorktreeItem sidebar badge using a Select dropdown with checkout, status refresh, and UIStore update. Branches are prefetched on badge hover and only fetched once on open (prevents async setBranches from triggering Radix item-aligned repositioning while the dropdown is visible).
Switch from .run(context) to .build(context) + .run(callback) to hook into RunEvent::Exit. Explicitly calls SessionManager::shutdown() before the process terminates, preventing orphan agent-bridge processes.
Move StatusBar from ContentCard to ActivityPanel so it only shows when a file is open in the editor. Remove all git-related info (branch, ahead/behind, changes) from the status bar. Add pb-2 to chat input container for bottom spacing.
Two bugs combined to silently drop manual renames: 1. remapConversation used .find() + direct property mutation (Immer nested mutation bug) — sessionId remap could be silently dropped, causing persistTitle to look for a non-existent frontend UUID JSONL. 2. update_title() used conversation_path() (single workspace) instead of find_conversation_path() (searches all workspaces like delete() does) — workspace path mismatches caused silent skips.
…verlay The NSVisualEffectView frost appeared as solid grey in light mode because blurring the desktop wallpaper produces inherently grey output. CSS overlays covered the blur pattern entirely. Added a native screen-blend tint overlay (NSView with CIScreenBlendMode compositing filter) between the frost and webview. Screen blend lightens per-pixel proportionally — preserving blur texture contrast unlike alpha blending. Also added runtime theme configuration (material, appearance, emphasis) and removed all CSS ::before tint hacks.
Reduce frost alpha to 0.2 for more desktop see-through, switch to Clear liquid glass variant with stronger white tint (#FFFFFF80) from below to lighten the grey, and use .titlebar material (lightest) instead of .menu for the NSVisualEffectView.
- Apply CALayer corner radius to browser child window (macOS) so it clips flush inside the activity card, replacing the old bottom-inset workaround - Add react-grab element selection: intercept orbit-eval:// URL callbacks from the embedded browser and bridge to frontend via Tauri events - Add browser_focus command for immediate input after activating selection - Unify element context chips and file/skill chips into a single row - Round the browser URL bar (rounded-full) and empty-state card (rounded-2xl) - Update decorum plugin with set_child_windows_corner_radius API - Add docs: browser corner radius decision, navigation history & worktree sync plans
ESLint's projectService cannot resolve Claude Agent SDK types (SDKMessage, BetaMessage, MessageParam) across the agent-bridge tsconfig boundary. tsc --noEmit passes — this is a known tooling limitation matching the existing Vitest globals and agent-bridge test overrides.
…olution" This reverts commit 1d1ab37.
Create shared LocalSDKMessage types in agent-bridge/src/common/types/ that ESLint can resolve (matching the pattern session-manager.ts uses). Cast SDK messages at the for-await iteration boundary so all property access is type-safe for both TypeScript and ESLint. Files changed: - New: common/types/claude-sdk.ts — local mirror of SDK message union - agent/core/agent.ts — use LocalSDKMessage, remove unsafe casts - agent/session/session-manager.ts — use typed result narrowing - canvas/core/canvas-agent.ts — use LocalSDKMessage with exhaustive switch - canvas/orchestrator/agents/base-agent.ts — same pattern - Tests updated to use typed property access
… crash SDK user messages have content: string (text) or content: ContentBlock[] (tool results). The local mirror type incorrectly assumed always unknown[], causing .every() crash on strings. Also documents the agent-bridge SDK type workaround and risks in CLAUDE.md.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f91e1a72ec
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| )) | ||
| })?; | ||
|
|
||
| writeln!(file, "{line}").map_err(|e| { |
There was a problem hiding this comment.
Serialize custom-title append as one atomic write
This append path can run while the Claude sidecar is simultaneously appending session events to the same JSONL, but writeln!(file, "{line}") formats and writes in multiple chunks, so only per-chunk append is atomic. In that concurrent case, bytes from two writers can interleave and produce malformed JSONL lines, which then breaks conversation parsing/loading for that session.
Useful? React with 👍 / 👎.
| const gitStore = useGitStore.getState(); | ||
| gitStore.setStatus(newStatus); | ||
| gitStore.setBranches(newBranches); |
There was a problem hiding this comment.
Scope git store updates to the active worktree
After a badge checkout, this always pushes newStatus/newBranches into the global useGitStore even when the user switched a non-active worktree (the badge click explicitly stops row selection). That overwrites source-control/file-status state for the currently active repo with data from a different worktree until another refresh corrects it.
Useful? React with 👍 / 👎.
…evel files Root CLAUDE.md trimmed from 45k to ~30k by moving area-specific content to sub-level CLAUDE.md files. CLAUDE-CONTINUOUS.md eliminated entirely. Created 3 new sub-level docs: - crates/common/CLAUDE.md (11 Rust crates reference) - packages/shared-schemas/CLAUDE.md (Zod schema domains) - apps/common/CLAUDE.md (shared frontend exports) Updated existing sub-level docs: - agent-bridge/CLAUDE.md (+SDK type workaround, testing philosophy, Zod patterns, CVE) - apps/agent/CLAUDE.md (+WKWebView blur workaround, barrel pattern) - src-tauri/CLAUDE.md (+Rust module organization)
Replace bracket opacity notation (bg-black/[0.08]) with shorthand (bg-black/8) and move important modifier from prefix (!border) to postfix (border!) per Tailwind v4 canonical form.
- Retry title generation on subsequent turns if first attempt failed - Pick first non-empty assistant message for title context - Preserve in-memory AI titles when disk reads race ahead of persist
…ion button - Convert ArrowLeft, ArrowRight, SidebarLeft, SquareAndPencil from SVG stroke paths to base64 PNG mask-image technique for pixel-identical macOS SF Symbol rendering - Wire the "new session" button in ContentTopBar with handleNewSession (previously had no onClick handler) - Export conversationBelongsToWorktree for reuse in content-top-bar - Add audited LINE-ANNOTATION-FEATURE plan with inline review findings
Sidebar: replace two-property transition (width + margin-left) with single margin-left slide mirroring the activity panel pattern. Keeps wrapper at fixed expanded width during collapse — eliminates desync jank on rapid open/close. Header: replace conditional render of nav controls with always-rendered overflow-hidden container animated via max-width + opacity in sync with sidebar timing — prevents layout shift flash on project/session title.
…decisions Add WORKTREE-AS-WORKSPACE-PLAN.md revised per combined audit (Claude + Codex) — addresses 4 critical issues: empty conversation list handling, CreateWorktreeDialog/removeWorktree repo targeting, file tree null-main sync gap, and startup reconciliation. Plan grew from 5 to 8 sections. Also adds PIERRE-DIFFS-MIGRATION-PLAN.md and SIDEBAR-ANIMATION-SINGLE-PROPERTY.md decision doc. Updates docs/CLAUDE.md index to reflect new files.
Split setWorkspace into initializeWorkspace (full project reset) and transitional shim. Add clearActiveSession cross-store handoff on worktree switch/remove. Complete call site inventory (8 + tests).
Worktree-as-workspace logic: initializeWorkspace, switchToWorktree, repoRootPath, clearActiveSession, scoped file tree and conversations. UI: context menu for worktree removal, folder icon → chevron on hover, fading timeline line, consistent gap spacing, remove misleading expanded background on non-active worktrees.
…ions - Enforce 400px minimum width for chat panel via CSS min-width + dynamic getActivityMax constraint (replaces static PANEL_SIZES.review.max=800) - Auto-collapse sidebar when window becomes too narrow for all open panels - Lower INPUT_CONTROLS.collapseBreakpoint from 400 to 340 (fewer buttons) - Add gradient fade overlay on header when project/chat name overflows - Animate conversation list and Powers section expand/collapse using CSS Grid row transition (grid-template-rows 0fr↔1fr) with asymmetric enter/exit easing curves and opacity fade - Add fading vertical timeline line to Powers section (matches conversations) - Unify WorktreeItem border-radius to rounded-[9px] (matches Powers button)
…insight block parser Replace @tanstack/react-virtual with normal document flow — CSS containment (contain: paint, content-visibility: auto) causes block-level selection highlights in WKWebView instead of proper text-following selection. Messages now render in natural flow with stick-to-bottom handling auto-scroll via ResizeObserver. Also make rehype-insight-blocks more robust: support plain-text openers (no backticks), multiple dash characters (─ — – -), and titles appended after the opener pattern. Add stripInsightMarkers safety net to prevent leaked patterns in insight body content.
…nd transition-all
- Change sidebar toggle from Cmd+/ to Cmd+S, remove save file shortcut - Add Cmd+N for new session with ⌘N badge on sidebar button - Add Cmd+T for projects dialog with ⌘T badge on sidebar button - Add Shift+Tab to cycle input modes (default/plan/accept) with kbd in tooltip - Unify input control buttons to rounded-[9px] (mode picker, model selector, effort level, image, context buttons)
Replace folder icons with Facehash identity avatars in the projects dialog tiles and sidebar recent project rows. Adds facehash dependency.
…inements Replace custom Shiki-based diff rendering with @pierre/diffs across all tool widgets (edit, write, bash, glob, grep, etc.) for unified syntax-highlighted diffs. Add file explorer context menu with Reveal in Finder and Open in Default App actions backed by cross-platform Rust commands. Extend git crate with get_file_at_ref() for reading files at any git ref or index. Add liquid glass button-primary and textarea CSS styles. Clean up legacy diff-line and diff-viewer components.
…cts dialog button styling
Move file watcher setup from tauri-provider into use-file-tree hook and add debounced directory refresh (scheduleDirectoryRefresh) for create and delete events instead of clearing parent cache. Introduce case-insensitive path comparison throughout file-store for macOS where FSEvents can report paths with different casing than what's cached. Extract toFileNodes mapper from file-handlers to shared mappers module.
…ity guard macOS FSEvents can misreport file deletions as 'modified' events. This change removes the created/deleted filter so all file:changed events trigger directory refresh, with structural equality checks to prevent unnecessary re-renders from benign modified events. Adds concurrency limiting (max 5 concurrent listDirectory calls), sticky structural intent across debounce windows, dirty markers for collapsed folders, and workspace-switch cleanup.
…tor tests - Gate BROWSER_CORNER_RADIUS with #[cfg(target_os = "macos")] to match its usage - Escape [warning] in rustdoc comment to prevent unresolved link error - Update BranchSelector tests for dialog-based create flow (no longer CommandItem)
- Add lerp-based smooth scroll hook with external scroll coexistence (passive listener syncs with useStickToBottom, onScrollAway callback) - Apply useSmoothScroll + overscroll-y-contain across all scrollable panels (chat, file explorer, sidebar, source control, settings, diagnostics, diffs) - Style Streamdown table wrappers with border-radius and overflow hidden - Disable table copy/download controls in chat, plan, and task widgets - Use resize: 'smooth' + overflow-anchor: none for chat scroll container
…styling Replace Streamdown's built-in MarkdownTable (which hardcodes w-full and adds copy/download controls) with a custom component that wraps <table> in a .table-wrapper div. Strip padding/background from inline code inside table cells to prevent pill-shaped selections extending beyond text glyphs.
…switching Replace the centered ThinkingDots spinner with a ChatSkeleton component that mimics the visual rhythm of user/assistant message blocks. Adds a minimum display time (500ms) to prevent the skeleton from flashing on fast loads. Animation uses scale(0.98→1) + opacity with custom easing, respects prefers-reduced-motion.
Show copy/rewind actions only on assistant message hover for a cleaner chat interface. Add bottom padding to user bubbles and increase the bottom spacer for better scroll ergonomics.
…ze tool widget padding - Delay clearing isAgentRunning by 1.5s after tool-using turns so the loader persists through intermediate SDK result messages instead of flashing the action bar between every tool execution - Add isLastMessage prop to hide action bar only on the actively streaming message while preserving it on previous completed turns - Migrate delayed-clear timers across session ID remaps - Cancel stale timers on permission:request to avoid race conditions - Remove inner px-2.5 from all tool widget headers, gutters, and status rows to unify horizontal spacing at the parent level - Update spring spacer plan with dedicated SpringSpacer component design - Add tests for action bar visibility and agent running timer logic
Replace the centered ThinkingDots fallback in settings tab switching with a SettingsSkeleton that mimics the SectionHeader + SettingItem layout. Uses bg-foreground/[0.06] for subtle contrast on the darker sidebar background. Adds lazyWithMinDelay (500ms) to prevent the skeleton from flashing on fast chunk loads.
…on resume The rewindFiles flow creates a temporary SDK query with `prompt: ''` that writes an empty user message (`text: ""`) to the parent JSONL. On resume, the API rejects this with 400 "text content blocks must be non-empty". Defense layers: - Rewind lock (rewindingSessionIds) blocks sendMessage during rewind - Strip-on-resume in createSession scrubs before startSession - Strip-on-send in sendMessage scrubs before queueMessage (primary fix) - One-time startup repair via repairPollutedJsonls (flag-gated) Only empty user messages are stripped. All other JSONL entries are preserved: interrupt markers, queue-ops, titles, system metadata. Also fixes dangling parentUuid chain in Rust conversation parser — when a stripped message leaves an orphaned reference, fall back to unfiltered parsing instead of returning an empty conversation. Includes session-storage init mapping fix and tests from prior work.
…inux CI Bun's jest.spyOn(os, 'homedir') doesn't reliably intercept calls across module boundaries on Linux. Added getHomeDir() wrapper with _setHomeDirForTest() override so session-storage tests work on both macOS and Linux CI.
Implement a phase-based launch animation (wallpaper fade → ASCII reveal → sidebar slide) with runId cancellation tokens, watchdog fallbacks, and a settings toggle to disable it. Hide back/forward/new-session buttons on the welcome page header.
…s styling Extract BranchPickerContent from BranchSelector into a reusable component with searchable branch list (cmdk) and create-branch dialog. Sidebar WorktreeItem now shows the full popover when source control is closed, falling back to simple Select when open. Sidebar branch badge syncs with GitStore for real-time updates after source control checkouts. Unify popover/dropdown styling across branch selector, model selector, and context hover card: frosted glass bg (bg-white/70 + backdrop-blur-sm in light, bg-lg-control/80 + backdrop-blur-xl in dark), directional shadows without white ring, and lg-control buttons for source control Fetch/Refresh.
…wind stripRewindPollution() was removing empty user messages without re-parenting their children, breaking the parentUuid linked-list chain. When build_active_uuid_set() in Rust walked the chain, it couldn't reach entries before the break — so Claude saw the OG session as empty after a rewind+fork. Changes: - Rewrite stripRewindPollution() as two-pass: identify removals, then re-parent children to nearest surviving ancestor (chain-safe) - Thread sessionId through error pipeline (bridge → Rust → frontend) so errors reach the correct session instead of being silently dropped - Remove pre-send stripRewindPollution from sendMessage (race-prone; createSession and startup repair already cover all cases) - Bump rewind pollution repair flag v3→v4 to heal corrupted JONLs - Preserve fork records during session-storage repair (v1→v2 flag) - Fix migration test flag mismatch (was checking v1, code uses v2)
Remove transition-[background-color] and transition-[color] from recent project list items (Frequency Principle). The 100ms fade caused ghost highlights when sweeping the cursor quickly across items. Also tune ASCII logo animation durations for snappier launch sequence.
Adds VS Code-style source/preview switching for .md/.mdx files using the existing Streamdown infrastructure from chat. Includes three-tier link routing (fragment → relative → absolute), path normalization, large-file threshold guard (10K lines), and derived isPreviewRendered hook as single source of truth for effective preview state across rendering, search guards, and keyboard shortcuts.
- Add drag-and-drop from file explorer to chat input (enqueues file chips) - Add "Add to Chat" context menu item in file explorer - Render @file tokens as clickable blue links in user message bubbles - Resolve @filename to absolute path via attachedFiles or workspacePath - Redesign context chips: borderless tinted pills with subtle hover - Fix code block styling: wrap long lines, match line number font size, reduce header padding, 9px rounded copy button
…ility Extract CreateBranchDialog from BranchPickerContent so it renders outside the Popover tree — prevents Radix unmount when popover closes from killing the dialog. Also fix sidebar branch picker showing Select instead of Popover when activity panel is closed but activityTab is still 'source' (now checks reviewPanelOpen too).
…, symlink safety 11 fixes from independent code reviews (Claude + Codex): - updateActiveDocPath derives all identity fields (id, name, relativePath, extension) - saveDocument captures content before await, re-checks after to avoid losing edits - initializeVault only sets initializedWorkspace on success (retry no longer blocked) - VaultActions shows Reload/Overwrite buttons when conflicted - openDocument clears stale content on error - CSS table overflow-x: auto no longer clobbered by overflow shorthand - deleteVaultEntry re-reads state after await, handles directory descendants - VaultCreateDialog resets mode to 'file' on close - File watcher: conflict detection before markdown filter, ref for currentPath - Rust: dead double-check removed in vault_search_all_docs - Rust: recursive walkers skip symlinks via symlink_metadata - Rust: clippy absolute_paths and map_unwrap_or warnings resolved
Replace verbose arbitrary value syntax with theme utilities: bg-[var(--lg-control-bg)] → bg-lg-control, bg-[var(--lg-control-bg-hover)] → bg-lg-control-hover, [mask-image:...] → mask-[...]
Unify settings pages (slash commands, subagents, feedback, git) to use bg-lg-control backgrounds instead of borders, consistent rounded corners, and segmented edit/delete button groups. Fix light mode DiffFileCard and code block colors in pierre-adapter. Skip XDG_CONFIG_HOME/APPDATA env vars in agent-bridge test mode for proper storage isolation.
…hancements - Enhanced DiffFileCard with expanded diff view and folder-level git status - Improved ChangesList with folder grouping and status indicators - Polished edit/write tool widgets with better UX - Updated sidebar with scroll fade and layout refinements - Extended Rust git backend with additional diff/status commands - Added tests for source control hooks and ChangesList component
…inking box polish - Refactor all tool widgets to remove gutter/connector lines, simplify expand/collapse animations with separate enter/exit transitions - Add folder-level git status propagation (selectDirectoryStatus) with colored dots in file explorer - Restyle tooltips to solid bg matching chat input area, rounded-[9px], remove backdrop-blur - Simplify thinking-box by removing gutter lines and completed status row - Replace actions-bar AI disclaimer tooltip with CSS-only chat bubble - Polish message-actions: rounded-[9px], tooltip on top, remove scale transforms - Add git store tests for buildStatusMaps and directory status propagation
…ary polish - Add branch deletion option to worktree remove flow with granular toast feedback (success/warning/error) and double-click guard - Migrate clone repo, SSH connection, delete worktree, onboarding, and vault create dialogs to liquid glass design system - Restyle root error boundary fallback with liquid glass components - Add integration tests for handleRemoveWorktree in useSidebarActions - Return WorktreeRemoveResult from Rust backend with branchDeleteFailed field - Extract delete_branch_after_worktree_remove helper to reduce cognitive complexity
Issues attributed to commits in this pull requestThis pull request was merged and Sentry observed the following issues:
|
Summary
CIScreenBlendModetint overlay, tuned for light/dark mode transparencyno-unsafe-*false positives with local SDK mirror types (LocalSDKMessage) instead of rule suppression; fixed runtime crash fromstring | unknown[]user message contentChanges (91 files, +3200 / -1019)
Native / Rust
NSVisualEffectView+ screen blend tint overlayWKWebViewcorner radius and element selection handlersFrontend
Agent Bridge
LocalSDKMessagediscriminated union types (replaces unsafe casts)Array.isArray()guard for user message content (string | unknown[])Test plan
J.everycrash in logs