Plain `npm install -g <pkg>@<version>` over an existing install does not
reliably re-resolve platform-specific optionalDependencies, leaving the
native CLI binary missing or stale (e.g. 'Native CLI binary for darwin-x64
not found' after the claude-agent-sdk upgrade). The Upgrade button now
runs npm uninstall -g first as a best-effort step, forcing npm to rebuild
the dependency graph from scratch on the subsequent install. If the clean
upgrade fails midway, the DB and the Settings UI resync to the actual
on-disk state instead of showing a phantom version.
- fix(chat-input): raise toolbar collapse threshold to 34rem so selectors stay visible at wider input widths.
- fix(acp): prevent Windows terminal hangs caused by orphaned pipes and .cmd shims.
- fix(acp): fix context loss when resuming a historical conversation by deferring auto-connect until the session id resolves.
- fix(sidebar): clarify empty state when completed conversations are hidden.
- chore(acp): bump claude-code to 0.31.0, codex to 0.12.0, opencode to 1.14.23, gemini to 0.39.1.
-----------------------------
# 发布版本 0.10.3
- 修复(聊天输入):将工具栏折叠阈值提升到 34rem,更宽的输入区仍能保留选择器;
- 修复(ACP):修复 Windows 下因管道残留与 .cmd shim 导致的终端挂起;
- 修复(ACP):修复在历史会话中继续对话时偶发的上下文丢失问题,自动连接会等待历史会话 id 解析完成后再发起;
- 修复(侧边栏):在隐藏已完成会话时显示更清晰的空态提示;
- 杂项(ACP):升级 claude-code 至 0.31.0、codex 至 0.12.0、opencode 至 1.14.23、gemini 至 0.39.1。
When reopening a historical conversation, the ACP auto-connect fired before
the detail fetch resolved external_id, so the backend fell back to
session/new and the agent lost prior context. Gate both the auto-connect
effect and the focus-triggered reconnect on the session id being ready.
On Windows the expert enable-status check compared `fs::read_link` output
against the central path, which silently failed for junctions: the link
state fell back to Broken/LinkedElsewhere, so enabled experts kept
reappearing as disabled and disappeared from the message-input expert
list. Switch the link verification to canonicalize both sides (which
transparently follows junctions and symlinks) and add a case-insensitive
path comparison on Windows. Also prefer `junction::get_target` for the
displayed target path.
Large raw_output snapshots from tool_call_update notifications caused
O(N²) traffic through the event pipeline, multi-GB transient allocations
and WKWebView crashes. The fix turns cumulative snapshots into bounded
incremental deltas and removes redundant payload copies.
- Add ToolCallOutputCache keyed by tool_call_id with a 8KB tail
fingerprint and total length. Detects cumulative extensions by
matching the cached tail at the expected offset in the incoming
snapshot, so it works even when the full output grows into the MB
range. Emits suffix deltas with raw_output_append=true; falls back
to a truncated replacement when content diverges.
- Cap any single emitted raw_output chunk at 64KB (MAX_SINGLE_EMIT_BYTES)
with a UTF-8 char-boundary-safe tail and ANSI-sequence-safe trimming.
Apply the same cap to emit_terminal_output_update.
- Bound the cache at 256 entries with FIFO eviction, and clear entries
when the tool call reaches completed / failed / cancelled / error.
- Seed the cache via a dedicated seed() method on SessionUpdate::ToolCall
so the initial event never emits an accidental append.
- Share emit payloads as Arc<serde_json::Value> across broadcast
receivers and skip the Tauri-side clone: serialize once and hand the
same Arc to both the webview emit and the WebSocket broadcaster.
- Add 14 unit tests covering boundary cases: identity, prefix extension
past the cached tail, divergence, oversized deltas, multibyte UTF-8
truncation, final-status cleanup, FIFO eviction, seed semantics, and
ANSI-safe trimming.
Scan ~/.codex/skills/.system so Codex CLI's bundled skills (imagegen,
skill-creator, etc.) appear in the $ autocomplete and Skills settings.
Mark them read_only on the API; the save/delete handlers refuse writes
to that path, and the UI shows a system badge with a tooltip and
disables edit/delete/save for those entries.
Adds a new "Quick Messages" settings page below Experts for managing reusable title/content snippets, backed by SQLite via SeaORM and exposed through both Tauri commands and the Axum web router. The list supports drag-to-reorder using the same motion/react Reorder pattern as the agent list, with translations provided across all 10 supported locales.
- Pin folder/branch selectors to the left with a subtle divider so they stay visible while scrolling
- Redirect vertical wheel input to horizontal scroll within the bar
- Auto-scroll to the end when new attachments are appended
- Add `color` column to folder table with migration backfill and hash-based assignment on folder creation
- Expose `update_folder_color` via Tauri command and `/update_folder_color` HTTP route
- Render a color swatch before each folder name in the sidebar header; offer a 10-color palette (9 hues plus a theme-aware foreground sentinel) through the folder context menu
- Show the folder header "new conversation" button only on hover
- Drop the expanded-state tint on folder name and count badge; use a fixed neutral rail color for conversation items
Remove the parent-branch button shown beside the branch selector along
with its supporting API, command, service, model, and i18n strings.
Add migration m20260423 to drop the now-unused folder.parent_branch
column.
- Match popover corner styling of folder picker with branch picker
- Drop 'open folder from disk' entry from folder picker
- Drop 'new branch' entry and dialog from branch picker
- Highlight the vertical rail on conversations open in tabs with a darker primary tint and bleed 1px at both ends to stay continuous across cards
- Add emphasized state to SidebarStatusIcon mirroring the rail, deepening color when the conversation is open in a tab
- Redesign done icon as outlined circle + check, unify all status icons to sidebar-primary with consistent 0.75rem size and sidebar-tinted backdrop so they mask the rail
- Drop the expanded-state background and border on folder headers; keep the unified hover background
- Swap the arrow to a ChevronRight/ChevronDown toggle and remove the rotation animation to avoid subpixel rendering drift
- Size the arrow icon at 11px so its vertical center lands on an integer pixel
- Round the sticky overlay's top offset so it stays pixel-aligned with the virtual list items
Call plugin:event|listen/unlisten directly and guard the client-side listener
registry cleanup, so unsubscribe always reaches the backend even when the
registration eval has not yet populated window.__TAURI_EVENT_LISTENERS__.
Prevents the intermittent `listeners[eventId].handlerId` TypeError and the
resulting leaked listener.
- Sidebar: replace the "no conversations" placeholder with Open Folder, Clone Repository, and Project Boot buttons when the workspace has no open folders.
- Title bar: disable the terminal and auxiliary-panel toggle buttons while no folder is active.
- Aux panel: show a shared localized "no folder open" prompt in the file tree, git changes, and git log tabs when no folder is active.
- Add auxPanel.noFolderTitle / noFolderHint translations across all ten supported locales.
- Replace the branch badge with a compact count badge; recolor the
folder name and badge to sidebar-primary on a tinted row background
when expanded
- Lighten the selected conversation item background so the expanded
folder row stays the strongest signal
- Add a "+" button on each folder header that reuses a single new-
conversation tab across folders, disconnecting the old ACP session
so the connection lifecycle reconnects against the target folder's
working directory
Folder/branch pickers now render at the top of the input's rounded box
instead of a separate strip above it. Restyled as xs outlined buttons
matching the config selectors, always rendering the folder picker
chevron (dimmed when not editable). Removed the right-side commit/push
git action buttons and their unused imports. Scoped the bar to its
owning tab via a tabId prop so tile mode shows each tab's own folder
and disabled state independent of which tab is globally active.
- Align conversation guide line and status icon to the folder chevron center (left: 0.875rem)
- Use fixed 1px guide line with darker shade (sidebar-primary/15) for better visibility
- Add bottom border to sidebar title and a top gap above the folder list
- Tighten list horizontal padding to px-2 with matching pt-2 for consistency
- Fill the done status icon frame directly to avoid sub-pixel off-centering
Replace flat/grouped view toggle with a show-completed filter dropdown,
add expand/collapse-all control, extract status icon component, and
simplify the sidebar header.
Both the inline autocomplete (triggered by `/` in the textarea) and the
dropdown popup (triggered by the slash-command button) now show a search
field at the top. Matching uses substring on name and description, and
ranks name matches above description/id-only matches.
When a deep directory was renamed or deleted externally and both the
directory itself and a parent directory were cached, only the self entry
was cleared — leaving the parent's children list holding a ghost reference
to the old child. Walk up to the nearest cached ancestor in addition to
the direct hit so both stale entries are dropped together.
Also gate the follow-up getFileTree refetch on the directory still being
expanded. Collapsed branches only need their cache cleared; they will
re-hydrate naturally on the next expansion, which avoids unnecessary IPC
traffic during FS event bursts.
Deep directories (beyond the workspace snapshot's depth limit) relied on
a lazy-loaded override cache that was never invalidated, so agent-created
files, in-app deletes / renames / rollbacks, and external changes inside
expanded deep folders stayed invisible until the folder was reopened.
Propagate watcher `changed_paths` through the delta envelope and fire a
Meta event whenever FS activity doesn't alter the tree/git snapshots, so
the frontend can surgically invalidate affected cache entries and
re-fetch. Manual refresh (Reload from disk) clears the cache and
re-hydrates still-expanded deep dirs through the same path. Replayed
deltas after reconnect are forwarded to the same listeners.
Also split the combined workspace-state effect into tree / git / status
slices so unrelated state transitions (e.g. the 'resyncing' flip during
a refresh) no longer rebuild the entire node tree and cause a flash.
Replace the legacy folder + welcome routes with a unified /workspace route
that hosts all folders, conversations, tabs, and terminals in one window.
- Persist opened tabs to the database (opened_tabs entity + migration)
so tab layout survives restarts and deep-link bootstrap restores state
- Replace FolderContext shim with AppWorkspaceProvider, ActiveFolderProvider,
and TabProvider; expose both opened (folders) and full DB (allFolders)
listings via list_all_folder_details
- Return conversations across all non-deleted folders from list_all when
no folder filter is given, so the sidebar can show every folder's history
- Add ConversationContextBar above the chat input with folder picker
(auto-opens unopened folders on select), branch picker, and commit /
push / merge / stash entries to restore BranchDropdown functionality
- Rework sidebar with stats header, search, flat / folder-grouped view
modes (localStorage-persisted), reveal-in-sidebar event subscriber,
and per-folder context menu (focus, close tabs, remove from workspace);
indent conversations under folder headers in grouped mode
- Gate terminal creation on active folder and show folder context
- Remove deprecated BranchDropdown, FolderNameDropdown, welcome route,
and per-folder window commands
- Localize all new strings across 10 locales
Intercept keyboard events via xterm's custom key handler and emit
readline/zle escape sequences so bindings work regardless of terminfo:
- Alt/Option + Left/Right: word-wise cursor move
- Alt/Option + Backspace: delete previous word
- macOS Cmd + Left/Right: jump to line start/end
- macOS Cmd + Backspace: clear to line start
Uses `e.code` to stay correct on dead-key layouts, skips IME
composition, and excludes AltGr (ctrl+alt) on Windows/Linux.
Extend the existing appearance zoom setting so it also scales xterm.js
terminals and Monaco editors (diff viewer, three-pane merge editor, file
workspace editor), which previously rendered at a hard-coded 13px
regardless of zoom.
- Terminals read zoom at init and update term.options.fontSize live on
zoom change, refitting after a double rAF so xterm's renderer has
recomputed cell metrics. Font size is rounded to an integer to avoid
subpixel blur in the canvas renderer.
- Monaco editors derive fontSize from zoomLevel; three-pane merge
editor memoizes its options object to avoid redundant updateOptions
calls on unrelated re-renders.
The settings shell wrapped children in an outer section with p-3/p-4 padding.
With OverlayScrollbars replacing native scroll, the overlay scrollbar sat at
the viewport's right edge and covered the right border of inner cards.
Drop the outer padding (and the now-redundant overflow-auto) from the shell
and apply p-3 md:p-4 inside each settings page instead, so the scrollbar
aligns with the column edge while inner sections stay within the padded area.