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.
Child processes now have LANG/LC_ALL pinned to C.UTF-8 on every
platform, so git stderr is always English when it leaks past the
typed not_a_git_repository preflight. The 8 non-English regex
fallbacks were dead code; keep only the English pattern as a
belt-and-suspenders fallback for un-preflighted commands.
Previously LANG/LC_ALL were only set on Windows, so git stderr was
localized on macOS/Linux and substring checks for English messages
(e.g. 'unknown revision or path not in the working tree') silently
failed — empty-repo/missing-branch cases surfaced as red error
banners in the Git log panel instead of rendering as empty lists.
Reintroduce a local not-a-git-repo fallback state in the git log panel so non-repo errors still render the dedicated empty state when workspace state streaming is degraded.
Improve git repository preflight classification by distinguishing missing paths, permission issues, and non-directory targets before checking .git presence.
Add not_a_git_repository to the frontend AppErrorCode union for explicit typed handling.
Consolidate `.git` presence detection into a shared `git_repo` module used by both the workspace state watcher and the command preflight helper, replacing duplicated local definitions.
Introduce `AppErrorCode::NotAGitRepository` (HTTP 422) and preflight eleven frontend-callable git commands (log, status, list-branches, diff, diff-with-branch, show-diff, show-file, push-info, list-remotes, list-all-branches, commit-branches) so non-git folders short-circuit with a structured error instead of leaking locale-dependent git stderr.
Frontend `isNotAGitRepoError` checks the error code first and falls back to a multi-language regex list centralized in `src/i18n/git-error-patterns.ts`, covering the nine languages git actually translates into.
Wire the git log panel to `workspaceState.isGitRepo` rather than a local cached flag, so running `git init` or deleting `.git` externally propagates through the watcher and refreshes the panel automatically.
- Replace hardcoded "Claude Code" in agent_responding with each session's actual AgentType label; store agent_type on ActiveSession and populate it in both task-start and resume paths
- Remove silent ClaudeCode fallback in resolve_agent_type; /task now prompts the user to pick an agent when none is selected and the folder has no default
- Move session command strings out of session_commands.rs into i18n.rs with full 10-language coverage (en/zh-CN/zh-TW/ja/ko/es/de/fr/pt/ar)
- Fix French accent and wrap Latin agent name with Arabic bidi isolates (FSI/PDI) for consistent rendering across Telegram/Lark/WeiXin clients
- Release the bridge lock before the get_lang DB lookup in the content_delta flush path to avoid cross-session contention
- Log unknown agent_type fallback in conversation_service::parse_agent_type for observability
Reconcile the cached is_git_repo flag against the filesystem on every watch flush so `git init` or deletion of .git is reflected immediately: sync the stored flag, drop stale git_snapshot data when the repo goes away, emit a meta delta when presence flips without any data change, and mark the event as requires_resync so the frontend re-fetches the snapshot to pick up the new flag.
Replace the title-bar branch polling interval with a self-adjusting setTimeout chain that backs off to 60s when get_git_branch returns null or throws and drops back to 10s once a branch is detected, so branches created externally recover within one slow tick without hammering the backend on non-git folders.
Gate git refresh on .git presence so file churn in non-git workspaces no longer produces endless resync_hint events, and silently log tree/git refresh errors during watch flushing instead of flagging requires_resync, which turned transient failures into self-reinforcing loops.
Degrade gracefully when the filesystem watcher fails to attach (e.g. permission denied, inotify quota): keep the initial snapshot, surface a degraded flag, and expose a store-level restart that the banner uses to retry attachment after the root cause is fixed.
Propagate is_git_repo through the snapshot so the git log and changes tabs render a dedicated "Not a Git repository" empty state instead of raw git stderr with a useless retry button.
Stop polling get_git_branch from the title bar once it returns null and re-arm on visibility change.
Add translations for the new banner, empty-state, and retry keys across all ten locales.
- Persist user-supplied access token and last-used port in app_metadata, falling back to defaults when unset
- Atomically guard concurrent starts via compare_exchange with RAII rollback of the running flag
- Wrap token and port persistence in a single SeaORM transaction to prevent partial writes
- Classify bind errors (port in use, permission denied, address unavailable, invalid address) into stable i18n keys
- Localize start-failure messages across all 10 supported languages
- Codex: decouple active_agent_count decrement from close_agent target
parsing and reset counter on turn_context to prevent main assistant
messages from being swallowed when close_agent events are malformed
- Codex: use exact filename match with separator-aware fallback and
sorted candidates for deterministic subagent session file resolution
- Codex/OpenCode: truncate subagent tool call previews to 500 chars
- OpenCode: batch-load all subagent tool calls in a single SQL query
instead of per-task N+1 queries to avoid slow detail page loads
- Streaming: restrict positional child grouping fallback to in-progress
agents only, preventing top-level tool calls from being incorrectly
folded into completed Agent cards
- Tests: update Claude context window assertions to match 1M default
Refactor cleanAgentOutput to a sequential non-recursive pipeline: unwrap
JSON containers first, then strip task_id session lines, then extract
<task_result> content. Also apply cleaning to in-progress agent output
during streaming, not just completed results.
Forward the previously-dropped `locations` and `meta` fields from ACP
SDK ToolCall/ToolCallUpdate events through to the frontend. The meta
field carries `claudeCode.parentToolUseId` which enables precise
parent-child matching for concurrent Agent tool calls during streaming.
- Forward locations/meta in Rust AcpEvent types and connection handlers
- Use parentToolUseId for exact agent→child mapping, with position-based
fallback for agents that don't provide it (Codex, OpenCode)
- Replace `any` types with proper ToolCallMeta / unknown types
- Add runtime guards for meta field parsing (defensive against
unexpected shapes from different agents)
- Cache inferLiveToolName results per tool_call_id to avoid redundant
computation across Phase 1 and Phase 2
- Lazy-construct agentStats only when children exist
Support Agent card rendering during live streaming responses for Claude
Code, Codex CLI, and OpenCode. Previously Agent cards only rendered for
loaded/historical messages parsed from the DB.
- Fix tool name inference: subagent_type in input now returns "agent"
instead of "task"; add spawn_agent/wait_agent/close_agent aliases
- Group sub-agent tool calls inside parent Agent cards during streaming
using position-based heuristic (ACP SDK lacks parent_id tracking)
- Clean raw Agent output (JSON content blocks, XML task_result wrappers)
- Emit agent_stats with nested tool calls so AgentToolCallPart renders
child execution inline, matching the loaded message appearance
Transform OpenCode "task" tool calls with subagent_type into unified
Agent card display: rewrite as "Agent" tool with subagent_type, prompt,
description, and model; compute duration from time fields; query
sub-agent session parts from SQLite for nested tool call lists; extract
<task_result> content to strip preamble noise from agent output; guard
Streamdown code plugin against unsupported Shiki language identifiers
(e.g. "##", "function") in fenced code blocks from tool output.
Transform Codex spawn_agent/wait_agent/close_agent into unified Agent
card display: rewrite spawn_agent as "Agent" tool with subagent_type,
prompt, and description; correlate final results from wait_agent and
close_agent outputs; parse sub-agent session JSONL files for nested
tool call lists; suppress intermediate status messages during agent
execution; clean exec_command output to show only the command and its
result.
Render Agent/Explore/Plan tool calls in a visually distinct collapsible
container with colored left border, replacing the generic tool card. Parse
subagent JSONL transcripts from {sessionId}/subagents/ to extract and
display the actual tool calls (Bash, Read, Grep, etc.) the subagent
executed, reusing the existing ToolCallPart for consistent appearance.
- Add AgentToolCallPart component with collapsible body, prompt section,
execution stats, and nested tool call list via render prop injection
- Add AgentExecutionStats and AgentToolCall types (Rust + TypeScript)
- Parse toolUseResult.agentId to locate and read subagent JSONL files
- Validate agentId against path traversal before filesystem access
- Pass agentStats through adapter for both ID-matched and positional
tool result pairing
- Strip agentStats in nested render to prevent recursive Agent expansion
- Add i18n keys for agent UI labels across all 10 languages
The upstream Codex.Color icon from @lobehub/icons renders an SVG with a
white background rectangle, which appears as a white square on dark
backgrounds. Replace it with a custom CodexColorIcon that renders only
the logo path with its original gradient fill, and adjust the viewBox to
better fit the content area.
Replace lexicographic sort with numeric (major, minor, patch) sort
across all 7 version-directory sort sites in find_node_bin_dir.
Lexicographic sort incorrectly orders v20.9 > v20.11 (because '9' > '1')
which could select an older Node.js version and cause agent preflight
failures for version-gated agents like OpenClaw (requires >=22.12.0).