Commit Graph

356 Commits

Author SHA1 Message Date
xintaofei
1904013dac refactor(sidebar): emphasize active-tab conversations via rail color and status icon
- 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
2026-04-22 18:39:17 +08:00
xintaofei
1d40308f52 refactor(sidebar): simplify folder header styling and fix arrow pixel alignment
- 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
2026-04-22 18:39:17 +08:00
xintaofei
3f3a325848 fix(sidebar): compute sticky folder offsets from uniform item height to avoid NaN scroll height 2026-04-22 11:08:17 +08:00
xintaofei
78caf4d827 refactor(sidebar): always render folder groups regardless of conversation count 2026-04-22 10:53:22 +08:00
xintaofei
c691fb0c07 feat(workspace): add no-folder empty states and gate folder-only actions
- 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.
2026-04-22 10:36:27 +08:00
xintaofei
14fb231dcc feat(sidebar): add conversation management dialog with filtering and bulk actions 2026-04-22 09:31:38 +08:00
xintaofei
ae88b2256f refactor(sidebar): scope folder-header menu to per-folder new/import, drop import from card and blank-area menus 2026-04-22 08:16:39 +08:00
xintaofei
fc174d8692 refactor(conversation): add horizontal scrollbar and min width to tiled tabs 2026-04-22 01:20:21 +08:00
xintaofei
72b8817bb2 refactor(sidebar): highlight expanded folder and add per-folder new-conversation button
- 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
2026-04-22 01:01:18 +08:00
xintaofei
f3bdf94723 feat(title-bar): add folder-actions menu and branch dropdown with git operations 2026-04-22 00:23:27 +08:00
xintaofei
08fb508736 refactor(branch-picker): fix popover corner radius, remove local branch delete, move new-branch to top 2026-04-21 23:14:57 +08:00
xintaofei
67c837901d refactor(workspace): remove welcome page and render conversation panel directly 2026-04-21 22:52:07 +08:00
xintaofei
eec47b3b12 refactor(title-bar): move sidebar toggle to left and swap terminal/aux-panel order 2026-04-21 22:29:51 +08:00
xintaofei
1bf2c2afce refactor(tabs): drop sidebar count and terminal-tab folder badge, show folder in tab tooltip 2026-04-21 22:23:23 +08:00
xintaofei
dd2b542df9 refactor(tabs): remove close-folder-tabs and reveal-in-sidebar menu items 2026-04-21 22:14:19 +08:00
xintaofei
b77842ee66 fix(conversation): derive ACP working dir from tab folder, not active folder 2026-04-21 22:03:57 +08:00
xintaofei
753e312c13 fix(workspace): resolve folder lookups against all folders for branch and file tree 2026-04-21 21:44:33 +08:00
xintaofei
256ebb7368 fix(sidebar): guard virtualizer itemSize against non-finite zoom level 2026-04-21 21:28:40 +08:00
xintaofei
dc75020e1c refactor(chat-input): embed conversation context bar inside input container
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.
2026-04-21 19:26:04 +08:00
xintaofei
e567181b58 fix(sidebar): center guide line under folder chevron and tighten list paddings
- 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
2026-04-21 18:44:20 +08:00
xintaofei
7a6e19097e fix(sidebar): align title/folder/item start position and stabilize status icon rendering 2026-04-21 17:47:35 +08:00
xintaofei
f0d530e1cb refactor(sidebar): streamline conversation list with completed filter and expand toggle
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.
2026-04-21 17:07:40 +08:00
xintaofei
58b48e2bfe Merge branch 'main' into one-folder 2026-04-21 09:27:55 +08:00
xintaofei
98792a696c feat(message-input): add search box to slash-command popups
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.
2026-04-21 00:26:00 +08:00
xintaofei
692b700c0d fix(file-tree): invalidate both cached target and ancestor, skip collapsed refetches
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.
2026-04-20 23:20:08 +08:00
xintaofei
baf3b6e89f fix(file-tree): keep aux-panel tree in sync with filesystem changes
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.
2026-04-20 22:57:24 +08:00
xintaofei
d9323d7399 refactor(workspace): migrate from per-folder windows to single-window workspace
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
2026-04-20 21:22:36 +08:00
xintaofei
ce289e64c5 feat(terminal): add word/line cursor shortcuts for shell line-editing
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.
2026-04-19 09:27:28 +08:00
xintaofei
0fa2a0895f feat(appearance): apply UI zoom level to terminal and Monaco editors
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.
2026-04-19 09:07:51 +08:00
xintaofei
eeeee2141c fix(settings): move content padding inside scroll areas to keep inner borders visible
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.
2026-04-19 08:45:57 +08:00
xintaofei
95a0c527c4 fix(git): restore non-repo fallback and refine repo preflight errors
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.
2026-04-18 23:49:42 +08:00
xintaofei
cc79d62b27 fix(git): surface non-git-repo as a typed error and align all panels via workspace state
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.
2026-04-18 23:07:13 +08:00
xintaofei
0048126d53 feat(settings): render update release notes as markdown 2026-04-18 18:51:09 +08:00
xintaofei
07ef376438 refactor(message): shrink agent card max height and localize running indicator with spinner 2026-04-18 18:43:04 +08:00
xintaofei
75c2dd4cc5 fix(settings): use randomUUID helper with getRandomValues fallback for non-secure contexts 2026-04-18 18:25:28 +08:00
xintaofei
ff48810603 fix(workspace-state): keep git-presence flag and branch poll in sync with runtime state
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.
2026-04-18 17:44:45 +08:00
xintaofei
7ef8d84d44 fix(workspace-state): stop resync loop on non-git folders and allow retry for degraded watcher
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.
2026-04-18 17:18:11 +08:00
xintaofei
6e477661f8 feat(status-bar): compact large token counts with K/M units in usage popover 2026-04-18 11:57:52 +08:00
xintaofei
fd10494128 feat(web-service): allow custom access token with persisted port and localized start errors
- 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
2026-04-18 10:18:34 +08:00
xintaofei
32b4c88582 feat(conversation): add copy text context menu action with preserved selection 2026-04-17 23:20:01 +08:00
xintaofei
5bb4c1cb1e feat(chat-channel): annotate Weixin channel badge with iLink reconnect hint tooltip 2026-04-17 21:52:43 +08:00
xintaofei
4f41a217c4 feat(settings): add xhigh reasoning effort level and update Claude Code model placeholders to claude-opus-4.7 2026-04-17 08:31:38 +08:00
xintaofei
488b0c2e53 feat(parser): render OpenCode task as Agent cards with nested tool calls
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.
2026-04-17 00:06:57 +08:00
xintaofei
e36ba36222 fix(ui): render Agent prompt as markdown and add max height to expanded card body 2026-04-16 21:57:58 +08:00
xintaofei
4c36da8ece fix(ui): prevent duplicate error display in Agent subagent card 2026-04-16 21:48:55 +08:00
xintaofei
9f82fdf350 feat(ui): add dedicated Agent subagent rendering with nested tool call display
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
2026-04-16 21:32:25 +08:00
xintaofei
ffdc0019fc fix(ui): replace Codex icon to remove opaque white background
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.
2026-04-16 18:03:51 +08:00
xintaofei
4abc198f44 Merge remote-tracking branch 'origin/main' 2026-04-16 09:40:31 +08:00
xintaofei
04eff14c0d fix(settings): remove ineffective max reasoning effort level for Claude Code
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 09:39:47 +08:00
xintaofei
d163e42457 feat(settings): add ChatGPT OAuth device code login for Codex CLI
Add OAuth device code flow for Codex CLI official subscription auth,
allowing users to log in with their ChatGPT account directly from the
agent settings page without using the terminal.

- Backend: two new endpoints (codex_request_device_code, codex_poll_device_code)
  that handle the OpenAI OAuth device code flow and return tokens to frontend
- Frontend: login UI with verification URL, copyable user code, polling status,
  15-minute timeout, and auto-save via existing persistEnv/persistConfig path
- Auth.json written in Codex CLI compatible format (nested tokens, account_id,
  last_refresh) so codex-acp can use OAuth tokens directly
- Show logged-in status and re-login option when tokens are present
- Remove auth.json textarea from Codex settings UI
- i18n: all 10 languages updated with new login-related keys
2026-04-16 00:29:01 +08:00