399 Commits

Author SHA1 Message Date
程序员阿江(Relakkes)
d7b8fb032c fix(desktop): preview exit plan approvals (#793)
Show ExitPlanMode approvals as a rendered plan preview in desktop chat,
forward plan feedback and requested prompt permissions through the desktop
WebSocket permission response, and keep permission-mode restoration owned by
the CLI runtime.

Tested: bun run verify
Confidence: high
Scope-risk: moderate
2026-06-12 11:16:31 +08:00
程序员阿江(Relakkes)
2f243fe920 fix(desktop): stabilize Windows settings toggles (#788, #791)
Prevent Settings General checkbox focus/reflow from using off-row sr-only inputs, close stale native preview views when leaving session pages, and avoid Windows notification enable-time smoke side effects.

Tested: cd desktop && bun run test -- src/__tests__/generalSettings.test.tsx --reporter verbose
Tested: cd desktop && bun run test -- src/components/layout/ContentRouter.test.tsx --reporter verbose
Tested: cd desktop && bun run test -- src/lib/desktopNotifications.test.ts --reporter verbose
Tested: cd desktop && bun run lint
Tested: bun run check:desktop
Confidence: medium
Scope-risk: narrow
2026-06-12 10:53:02 +08:00
程序员阿江(Relakkes)
00b4ead0ca fix(trace): show tool call durations (#799)
Compute tool spans from paired tool results, surface session wall/model/tool timing, and keep pending spans updated with elapsed time.

Tested: cd desktop && bun run test -- --run src/lib/traceViewModel.test.ts src/pages/TraceSession.test.tsx
Tested: cd desktop && bun run test -- --run src/pages/TraceList.test.tsx
Tested: bun run check:desktop
Scope-risk: narrow
2026-06-12 10:50:55 +08:00
程序员阿江(Relakkes)
dd72901ba3 fix(desktop): render generated Mermaid labels in previews (#803)
Normalize generated flowchart labels before Mermaid rendering so Markdown previews handle labels with HTML breaks, braces, and bracketed type text.

Tested: bun run check:desktop
Scope-risk: narrow
2026-06-12 09:52:30 +08:00
程序员阿江(Relakkes)
ae32599ba8 fix(trace): stabilize live trace updates
Keep live trace polling sensitive to in-place call changes, scope detail section collapse state by trace session, and expose trace rows with list/button semantics.

Tested: cd desktop && bun run test -- TraceList.test.tsx TraceSession.test.tsx
Tested: cd desktop && bun run lint
Tested: bun test src/server/__tests__/trace-capture.test.ts
Confidence: medium
Scope-risk: narrow
2026-06-12 09:22:13 +08:00
程序员阿江(Relakkes)
d9ce2f09e1 refactor(desktop): move trace entry into Settings
Trace is a low-frequency diagnostic feature, so its entry points no
longer sit in primary chrome:

- Remove the Trace nav item above the session list in the sidebar
- Remove the trace open/open-window buttons from the session header
- Add a Trace tab in Settings between Token usage and Diagnostics,
  embedding the existing TraceList page full-bleed
- Add settings.tab.trace and drop unused sidebar.traces across locales
2026-06-11 01:42:40 +08:00
程序员阿江(Relakkes)
d3d7566f0c refactor(trace): redesign trace UI with LangSmith-style two-pane layout
UI rebuild (desktop):
- TraceSession: replace 3-column layout with two panes — turn-grouped
  timeline tree (draggable splitter, search/filter, keyboard nav) and a
  section-flow detail panel (Response / Messages / System Prompt /
  Tools / Parameters / Raw), collapse state persists across spans
- Render LLM requests/responses semantically: messages as role-colored
  conversation with tool_use/tool_result pairing instead of raw JSON
  dumps; Raw fallback via CodeViewer for legacy truncated records
- TraceList: row-style list with model chips, mono metrics, hover
  actions; content-visibility rows (no virtualization, WebKit-safe)
- i18n synced across zh/en/jp/kr/zh-TW (+25/-55 keys)

Data & capture (server):
- Capture full bodies: preview cap 2048 -> 240k chars, stream cap
  256KB -> 1MB; list API trims previews to keep polling light; new
  GET /api/sessions/:id/trace/calls/:callId returns the full record
- Extract per-call token usage at read time (SSE + JSON + proxy
  wrapped); mtime-keyed read cache for the polling path
- Fix sensitive-key regex redacting *_tokens count fields, which made
  token stats always report 0

Frontend data layer:
- SSE stream reassembly (Anthropic + OpenAI chat) adapted from
  claude-tap (MIT, attribution in THIRD_PARTY_LICENSES.md), request/
  response body parsers, shared formatters, on-demand call detail
  cache; traceViewModel gains tokenUsage/isLifecycleNoise, drops
  fullRaw

Tested:
- bun run check:server (1201 pass)
- bun run check:desktop (lint + 1358 tests + build)
- Chromium walkthrough against real local traces: list, session tree,
  LLM semantic detail (new format), legacy fallback, tool detail
2026-06-11 01:02:51 +08:00
程序员阿江(Relakkes)
0d45439fbe feat(trace): add session trace monitoring (#606)
Tested:
- cd desktop && bun run test -- --run src/pages/TraceList.test.tsx
- bun test src/server/__tests__/trace-capture.test.ts
- bun run check:desktop
- bun run check:server

Scope-risk: broad
2026-06-10 17:13:27 +08:00
程序员阿江(Relakkes)
56661c7967 fix: support desktop output style config (#652)
Fixes #652.

Add desktop/server output style settings APIs and a General Settings picker
that mirrors the Claude CLI outputStyle sources.

Persist active-project choices to .claude/settings.local.json and global
choices to user settings, and route /config to the local settings UI.

Tested:
- bun test src/server/__tests__/settings.test.ts
- cd desktop && bun run test -- src/components/chat/composerUtils.test.ts src/stores/settingsStoreOutputStyle.test.ts src/pages/SettingsOutputStyle.test.tsx
- cd desktop && bun run test -- src/__tests__/generalSettings.test.tsx
- bun run check:desktop
- bun run check:server
- bun run verify

Confidence: high
Scope-risk: moderate
2026-06-10 15:24:37 +08:00
程序员阿江(Relakkes)
db631dfdfd fix(desktop): show full tool error details (#625)
Surface expanded error output for tool cards whose previews previously returned before rendering the result body. Keep successful Bash/Read/Edit/Write outputs hidden as before while exposing error details with wrapping and copy support.

Tested: cd desktop && bun run test -- src/components/chat/chatBlocks.test.tsx
Tested: bun test src/server/__tests__/conversations.test.ts -t "should switch from bypass permissions back to default without restarting" --timeout=20000
Tested: bun run verify
Confidence: high
Scope-risk: narrow
2026-06-09 21:07:45 +08:00
程序员阿江(Relakkes)
0a8f247781 feat(desktop): add plugin list bulk toggles (#527)
Tested:
- cd desktop && bun run test -- src/__tests__/pluginsSettings.test.tsx src/stores/pluginStore.test.ts --run --reporter=verbose --pool=forks --maxWorkers=1 --minWorkers=1
- bun run check:desktop
- git diff --check

Scope-risk: moderate
Confidence: high
2026-06-09 16:33:15 +08:00
程序员阿江(Relakkes)
760295dcd8 test(desktop): update chatBlocks thinking assertions to the done-state label
Commit 449ff0b0 changed completed thinking blocks to render the
'thinking.labelDone' title ("Thought"/"已思考") instead of the static
"Thinking" label, and updated ThinkingBlock.test.tsx but not
chatBlocks.test.tsx. The three inactive/default-state cases there still
queried the toggle button by /Thinking/ and failed. Match the new
done-state label (/Thought/); the active-state case is unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 23:28:11 +08:00
程序员阿江(Relakkes)
449ff0b0ff fix(desktop): show "已思考" label after thinking completes (#732)
The thinking block title always rendered the static "思考中"/"Thinking"
label; isActive only toggled the animated dots. Once thinking finished
the dots disappeared but the in-progress text stayed. Switch the label
to "已思考"/"Thought" when the block is no longer active.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 20:19:11 +08:00
程序员阿江(Relakkes)
d2a99e01c2 fix(desktop): clarify sidebar project hierarchy (#733)
Indent session rows under their project group and switch project folder icons between open and closed states when collapsed.

Tested: cd desktop && bun run test --run src/components/layout/Sidebar.test.tsx -t "groups sessions by project|collapses a project group"
Tested: cd desktop && bun run test --run src/components/layout/Sidebar.test.tsx
Tested: bun run check:desktop
Tested: Browser plugin smoke on http://127.0.0.1:3456/ confirmed first project open -> closed state, icon state, and pl-6 session indentation.
Confidence: high
Scope-risk: narrow
2026-06-04 20:05:18 +08:00
Relakkes Yang
98b79ce51a fix: restore Windows custom desktop chrome
Use frameless Electron chrome only on Windows and remove the native Windows application menu so the packaged app matches the previous Tauri-style desktop surface.

Add a Windows-only manual drag fallback for desktop drag regions, while excluding tab reorder targets and preserving macOS/Linux native chrome and menu behavior.

Tested: cd desktop && bun run test --run electron/services/menu.test.ts electron/services/windows.test.ts src/hooks/useElectronWindowDragRegions.test.tsx src/components/layout/TabBar.test.tsx src/components/layout/Sidebar.test.tsx src/lib/desktopHost/electronHost.test.ts electron/ipc/capabilities.test.ts

Tested: cd desktop && SKIP_INSTALL=1 bun run build:windows-x64

Tested: Computer Use Windows packaged app smoke verified no native menu, custom controls, drag regions, tab reorder, close-to-background, and deepseek-v4-pro provider response FINAL_WINDOWS_ELECTRON_REAL_PROVIDER_OK.

Not-tested: full bun run verify.

Constraint: keep custom frameless behavior scoped to win32 so macOS and Linux native chrome paths remain intact.

Confidence: high

Scope-risk: moderate
2026-06-03 23:24:30 +08:00
程序员阿江(Relakkes)
eaa940ab90 fix(desktop): restore sidebar titlebar dragging
The sidebar title area also needs to participate in Electron's CSS app-region chrome. Mark only the sidebar title/header region as draggable and keep the full sidebar body out of the drag region so session rows, search controls, and project actions remain normal interactions.

Constraint: Electron window dragging is driven by CSS app-region regions after the migration
Rejected: Keep the sidebar-wide startDragging mouse handler | Electron does not use that as the active drag path and it misses the left title gap
Confidence: high
Scope-risk: narrow
Directive: Keep sidebar body interactions outside the drag region unless a real titlebar affordance is added there
Tested: cd desktop && bun run test src/components/layout/Sidebar.test.tsx --run
Tested: bun run check:desktop
2026-06-03 16:38:00 +08:00
程序员阿江(Relakkes)
7e737cb4aa fix(desktop): restore tab bar window dragging
Electron handles custom draggable chrome through CSS app-region rules, not the old runtime startDragging path. Mark the tab strip and empty scroll gutter as native drag regions while keeping tab items and controls explicitly no-drag so tab reordering and close/tool buttons keep receiving pointer events.

Constraint: Electron drag regions swallow pointer events unless interactive children are marked no-drag
Rejected: Keep calling startDragging from the empty gutter | Electron desktopHost does not expose that as the active migration path
Confidence: high
Scope-risk: narrow
Directive: Do not mark tab items themselves as drag regions without revalidating tab reorder behavior
Tested: cd desktop && bun run test src/components/layout/TabBar.test.tsx --run
Tested: cd desktop && bun run lint
Tested: bun run check:desktop
2026-06-03 12:42:14 +08:00
程序员阿江(Relakkes)
54f3c00414 fix(desktop): stabilize chat selection references (#351)
The chat reference action was still tied too closely to message-local
mouseup timing, and the floating fixed-position control stayed inside
virtualized message DOM. In Electron Chromium that made multi-line ranges
race selection settlement and let transformed ancestors offset the button
away from the viewport position we calculated.

This reads settled document selections after pointerup/selectionchange,
portals the action to document.body, and prefers right-side placement for
multi-line selections.

Constraint: Electron Chromium selectionchange can settle after message-local mouse events
Rejected: Keep the popover inside the message node | transformed/virtualized ancestors offset fixed positioning in real browser layout
Confidence: high
Scope-risk: narrow
Directive: Keep chat selection actions portaled; do not reparent under virtualized message rows without browser-coordinate verification
Tested: cd desktop && bun run test -- src/components/chat/MessageList.test.tsx
Tested: bun run check:desktop
Tested: Playwright Chromium smoke for multi-line selection, single-line selection, and outside-click dismissal on local desktop harness
2026-06-03 11:39:18 +08:00
程序员阿江(Relakkes)
358b2c50be fix(desktop): restore chat selection references (#351)
Chat selection references could miss drag gestures that ended outside the
message bubble after the Electron migration. The chat transcript now tracks
selection gestures at the document pointer-up boundary and repositions the
shared selection action near the selected text with above-then-right placement.

Constraint: Electron/WebView selection ranges are not always stable during the message-local mouseup event
Rejected: Add a new selection popover system | the existing shared selection hook already covers chat and workspace dismissal behavior
Confidence: high
Scope-risk: narrow
Directive: Keep chat and workspace selection popovers on the shared positioning/dismissal hook unless their behavior intentionally diverges
Tested: bun run test -- src/components/chat/MessageList.test.tsx -t "selected-message action"
Tested: bun run test -- src/components/chat/MessageList.test.tsx
Tested: bun run check:desktop
Tested: in-app browser smoke at http://127.0.0.1:5181/ with zero console errors
Not-tested: Packaged Electron manual drag selection smoke
Related: #351
2026-06-03 09:48:23 +08:00
程序员阿江(Relakkes)
959e177cdf fix: keep agent slash selection editable before send (#653)
Selecting a concrete /agent entry from the composer suggestions should prepare the command and leave focus in the editor so the user can type the required prompt. The Enter send shortcut still applies after the suggestion menu is closed, and exact non-agent slash commands keep their existing direct execution path when they remain highlighted.

Constraint: The desktop composer supports configurable Enter vs Ctrl/Cmd+Enter sending.
Rejected: Special-case only /agent entries | the highlighted suggestion should consistently win while the menu is open.
Confidence: high
Scope-risk: narrow
Directive: Keep ChatInput and EmptySession slash-key handling aligned with shared send shortcut behavior.
Tested: cd desktop && bun run test -- --run src/components/chat/composerUtils.test.ts src/components/chat/ChatInput.test.tsx src/pages/EmptySession.test.tsx
Tested: bun run check:desktop
Not-tested: Live backend agent-list integration beyond mocked desktop composer coverage.
2026-06-03 09:30:16 +08:00
程序员阿江(Relakkes)
81845fbc49 fix: finalize Electron migration boundaries
Complete the Electron replacement boundary before merging by removing the renderer-side Tauri host fallback, tightening H5/browser access so only desktop navigation is tokenless, and moving desktop release publication to a tag-driven GitHub Actions matrix with a single final publish job.

Constraint: H5/browser capability access must not gain tokenless access through localhost or retired Tauri origins

Constraint: Desktop release artifacts must be built by GitHub Actions from version tags, not treated as local build outputs

Rejected: Keep localhost browser origins trusted for convenience | local browser contexts can access loopback services and must use the H5 token path

Rejected: Publish from each matrix job | partial releases can be created before all platforms finish

Confidence: high

Scope-risk: broad

Directive: Do not reintroduce Tauri origins or localhost browser origins into the trusted desktop origin set without a reviewed security design

Tested: bun test src/server/__tests__/h5-access-policy.test.ts src/server/__tests__/h5-access-auth.test.ts src/server/__tests__/diagnostics-service.test.ts src/server/middleware/cors.test.ts

Tested: bun test scripts/pr/release-workflow.test.ts scripts/release-update-metadata.test.ts

Tested: bun run check:desktop

Tested: bun run check:native

Tested: git diff --check

Not-tested: bun run check:server is blocked by expired quarantine entries server:cron-scheduler, server:providers-real, server:tasks, server:e2e:business-flow, server:e2e:full-flow
2026-06-02 22:42:53 +08:00
程序员阿江(Relakkes)
386a41e606 feat(desktop): enable Electron migration path
Introduce the Electron desktop shell alongside the existing React renderer and local Bun server boundary. The migration keeps the DesktopHost contract explicit across Tauri, Electron, and browser runtimes while adding Electron main/preload services for dialogs, shell, notifications, updates, tray/window lifecycle, terminal, preview WebContentsView, app mode, and release/package validation.

The commit also carries the latest local main desktop command updates, including agent slash entries and hidden-by-default markdown thinking details, so the packaged Electron build matches the current main UX surface.

Constraint: React renderer, local Bun server, REST/WebSocket, and sidecar boundaries must remain reusable during the migration
Constraint: macOS dev packages are ad-hoc signed and cannot prove Developer ID notarization or Gatekeeper release launch
Rejected: Browser-only smoke validation | it cannot exercise native dialogs, keychain prompts, notification behavior, or packaged app startup
Confidence: medium
Scope-risk: broad
Directive: Do not remove Tauri host support until signed Electron release artifacts pass native OS smoke on macOS, Windows, and Linux
Tested: bun run check:desktop
Tested: cd desktop && bun run check:electron
Tested: CSC_IDENTITY_AUTO_DISCOVERY=false bun run electron📦dir
Tested: bun run test:package-smoke --platform macos --package-kind dir --artifacts-dir desktop/build-artifacts/electron
Tested: Computer Use read packaged Electron app window at desktop/build-artifacts/electron/mac-arm64/Claude Code Haha.app
Not-tested: Developer ID signed/notarized Gatekeeper launch
Not-tested: Real OS notification click-to-session action
Not-tested: Windows and Linux packaged app smoke on real hosts
2026-06-01 22:43:16 +08:00
程序员阿江(Relakkes)
ebc78befbe fix: avoid static previews for frontend index HTML
Project entry HTML often only mounts a dev-server app, while built output can be served statically. The desktop open-with policy now only offers the in-app browser for static HTML candidates, and preview-fs rewrites built HTML root-relative assets under the workspace preview path.

Constraint: Frontend project index.html needs a dev server instead of preview-fs static serving
Rejected: Treat every .html file as browser-previewable | project entry HTML can render blank or with missing assets
Confidence: high
Scope-risk: moderate
Tested: cd desktop && bun run check:desktop
Tested: bun run check:server
Tested: git diff --check
Not-tested: bun run verify was intentionally stopped at user request
2026-06-01 03:16:52 +08:00
程序员阿江(Relakkes)
d222b47cc4 fix: keep desktop preview shutdown from orphaning tool processes
The desktop app can quit while a preview-driven Bash task is still running npm/vite. Bash commands are spawned as detached process groups, so killing only the CLI or shell process can leave descendant dev servers alive and make later app launches look stuck.

This gives the CLI enough shutdown budget to run cleanup, lets the native sidecar wait long enough for that server cleanup, kills detached Bash process groups before the existing tree-kill fallback, and closes the native preview WebView instead of hiding it on workbench unmount.

Constraint: CLI gracefulShutdown has a 5s failsafe, so outer desktop shutdown windows must not SIGKILL it after 2-3s
Rejected: Treat the browser preview as the dev-server owner | it only opens URLs and does not spawn npm/vite
Confidence: high
Scope-risk: moderate
Directive: Do not shorten desktop/server shutdown windows below the CLI cleanup budget without reproducing BashTool background-task teardown
Tested: bun test src/utils/ShellCommand.test.ts src/server/__tests__/conversation-service.test.ts
Tested: cd desktop && bun run test -- --run src/components/browser/BrowserSurface.test.tsx src/components/workbench/WorkbenchPanel.webview.test.tsx
Tested: cd desktop && bun run lint
Tested: bun run check:server
Tested: SKIP_INSTALL=1 ./desktop/scripts/build-macos-arm64.sh
Tested: Opened canonical app and generated DMG app; both showed visible/frontmost window and left no app/sidecar/vite processes after quit
Not-tested: Notarized release install path
2026-06-01 02:51:22 +08:00
程序员阿江(Relakkes)
7ca702a253 fix(desktop): simplify changed-file open-with menus
Changed-file rows are easier to scan when previewable files are grouped before source-only files, and the file open-with menu should only expose useful preview, editor, and reveal actions. Output target cards also no longer need a separate copy control now that open/open-with are the primary actions.

Constraint: Keep the existing open-with API and menu components shared across changed files, workspace context menus, and output target cards.
Rejected: Keep system-default open for files | it duplicated less predictable platform behavior and added a low-value final menu item.
Confidence: high
Scope-risk: narrow
Directive: File open-with menus should stay ordered by immediate preview/open usefulness before editor and reveal actions.
Tested: cd desktop && bun run test src/lib/openWithItems.test.ts src/components/workspace/WorkspaceFileOpenWith.test.tsx src/components/chat/AssistantOutputTargetCard.test.tsx src/components/chat/CurrentTurnChangeCard.test.tsx
Tested: cd desktop && bun run lint
Tested: cd desktop && bun run build
Tested: git diff --check
2026-06-01 01:43:36 +08:00
程序员阿江(Relakkes)
14c37d5fc1 fix: polish preview selection affordances
Preview selection turns should disclose the user's requested change on hover
or focus, while the browser capture controls should live in the address
toolbar like the referenced Codex UI. The message keeps a compact element tag
by default and exposes the note through a real tooltip instead of relying on a
native title-only hint.

Constraint: No issue number was provided for this task.
Constraint: Preserve the existing preview bridge protocol and direct-send selection flow.
Rejected: Native title-only hover text | it is too subtle and does not match the requested visible hover affordance.
Rejected: Keep a second preview action toolbar row | it contradicts the referenced right-aligned browser chrome.
Confidence: high
Scope-risk: narrow
Directive: Keep preview capture and picker actions in the browser address chrome unless the reference interaction changes.
Tested: cd desktop && bun run test --run src/components/chat/AttachmentGallery.test.tsx src/components/browser/BrowserSurface.test.tsx src/components/browser/BrowserAddressBar.test.tsx
Tested: cd desktop && bun run lint
Tested: cd desktop && bun run build
Tested: git diff --check
Not-tested: Real Tauri webview visual smoke; browser automation startup failed, local Vite HTTP smoke returned 200.
2026-06-01 01:41:54 +08:00
程序员阿江(Relakkes)
eb68791ac5 fix: send preview selections as annotated chat turns
Element selection from the local preview should preserve the visual target
the user picked and send the confirmed request directly to chat. The
screenshot now captures the visible viewport before drawing the marker, and
the selection event sends a model-facing prompt while the chat UI shows only
the annotated image and compact element label.

Constraint: No issue number was provided for this task.
Constraint: Keep the preview-agent protocol shape unchanged.
Rejected: Prefill the composer with the selection note | it keeps the old extra confirmation step and exposes implementation text in the input.
Rejected: Full-document annotation coordinates | body-relative captures drift from the viewport selection users see.
Confidence: high
Scope-risk: moderate
Directive: Do not route confirmed preview selections back through composer prefill without rechecking the Codex-style direct-send flow.
Tested: cd desktop && bun run test --run src/preview-agent/screenshot.test.ts src/lib/previewEvents.test.ts src/lib/selectionComposer.test.ts src/components/chat/AttachmentGallery.test.tsx src/stores/chatStore.test.ts
Tested: cd desktop && bun run lint
Tested: cd desktop && bun run build:preview-agent
Tested: bun run check:desktop
Tested: git diff --check
Not-tested: Real Tauri webview click-through smoke; in-app Browser automation timed out while local Vite HTTP smoke returned 200.
2026-06-01 01:07:08 +08:00
程序员阿江(Relakkes)
4f0025700f fix(desktop): scope inline image gallery hover
Inline image galleries live inside chat message shells that already use Tailwind group hover for message-level affordances. Reusing the unqualified group selector on image tiles made a parent message hover reveal every fullscreen affordance in the gallery at once. Naming the image tile group keeps the overlay state local to the hovered tile while preserving the existing layout and click behavior.

Constraint: Desktop chat message shells also use generic Tailwind group hover selectors.
Rejected: Track hovered image index in React state | unnecessary runtime state for a selector-scoping issue
Confidence: high
Scope-risk: narrow
Directive: Keep image-tile hover selectors scoped if this gallery remains nested inside message shells.
Tested: cd desktop && bun run test InlineImageGallery.test.tsx --run
Tested: bun run check:desktop
Tested: git diff --check
Not-tested: Manual desktop screenshot smoke
2026-06-01 00:44:11 +08:00
程序员阿江(Relakkes)
998e85efab fix: localize synthetic business errors
Synthetic API errors were carrying only English display text, so desktop chat could not distinguish our compatibility guidance from raw upstream failures and recovery logic depended on those English strings.

Add stable business error codes for media, PDF, request-size, prompt-length, and auto-mode errors. Desktop chat now resolves those codes through locale keys and suppresses the stale English fallback for known business errors, while normalizeMessagesForAPI still supports legacy text matching for old transcripts.

Constraint: Raw upstream provider details must remain available for diagnostics but should not drive localized business UX.

Rejected: Localize src/services/api/errors.ts strings directly | that would make persisted transcript text and media recovery depend on the active UI language.

Confidence: high

Scope-risk: moderate

Directive: Add new user-facing synthetic API errors with businessErrorCode values before localizing their display text.

Tested: bun test src/services/api/errors.test.ts tests/mediaRecoveryAndEstimation.test.ts src/server/__tests__/ws-memory-events.test.ts

Tested: cd desktop && bun run test -- run src/stores/chatStore.test.ts src/components/chat/MessageList.test.tsx

Tested: bun run check:server

Tested: bun run check:desktop

Not-tested: Manual desktop screenshot smoke for the rendered Chinese error card
2026-06-01 00:36:29 +08:00
程序员阿江(Relakkes)
8e5e86353a fix(desktop): simplify workbench open affordances
Previewable changed-file rows no longer show a redundant workspace chevron when the row already has an Open With control. The unified Workbench now owns the Browser entry point, and opening Browser mode creates a blank address bar instead of navigating to a hard-coded localhost port.

Constraint: Keep explicit preview links and localhost output cards able to open the browser directly with their target URL.
Rejected: Keep the top toolbar browser button | it duplicated the Workbench Browser tab and silently opened localhost:5173.
Rejected: Use localhost:5173 as the blank browser default | it makes arbitrary Browser mode look tied to a dev server.
Confidence: high
Scope-risk: moderate
Tested: cd desktop && /Users/nanmi/.cache/codex-runtimes/codex-primary-runtime/dependencies/node/bin/node ./node_modules/typescript/bin/tsc --noEmit
Tested: cd desktop && /Users/nanmi/.cache/codex-runtimes/codex-primary-runtime/dependencies/node/bin/node ./node_modules/vitest/vitest.mjs run src/components/chat/CurrentTurnChangeCard.test.tsx src/stores/browserPanelStore.test.ts src/components/browser/BrowserAddressBar.test.tsx src/components/workbench/WorkbenchPanel.test.tsx src/components/browser/BrowserSurface.test.tsx src/components/layout/TabBar.test.tsx --pool=forks --poolOptions.forks.singleFork=true
Tested: git diff --check -- desktop/src/components/chat/CurrentTurnChangeCard.tsx desktop/src/components/chat/CurrentTurnChangeCard.test.tsx desktop/src/components/browser/BrowserAddressBar.tsx desktop/src/components/browser/BrowserAddressBar.test.tsx desktop/src/components/browser/BrowserSurface.tsx desktop/src/components/browser/BrowserSurface.test.tsx desktop/src/components/layout/TabBar.tsx desktop/src/components/layout/TabBar.test.tsx desktop/src/components/workbench/WorkbenchPanel.tsx desktop/src/components/workbench/WorkbenchPanel.test.tsx desktop/src/stores/browserPanelStore.ts desktop/src/stores/browserPanelStore.test.ts
Not-tested: Full desktop check:desktop gate.
2026-05-31 23:18:20 +08:00
程序员阿江(Relakkes)
fac8ffb0f2 fix(desktop): reserve chat action hover space
Message actions still fade in on hover and focus, but their row now keeps a stable height so transcript content does not jump when the pointer enters or leaves a message.

Constraint: Preserve the existing hover-only visibility and copy/fork interaction model.
Rejected: Keep animating height from zero | it causes the visible transcript reflow this change is fixing.
Confidence: high
Scope-risk: narrow
Tested: cd desktop && /Users/nanmi/.cache/codex-runtimes/codex-primary-runtime/dependencies/node/bin/node ./node_modules/typescript/bin/tsc --noEmit
Tested: git diff --check -- desktop/src/components/chat/MessageActionBar.tsx desktop/src/components/chat/MessageList.test.tsx
Not-tested: Focused Vitest could not complete in this local shell because the Vitest/esbuild startup process stalled or reported esbuild service stopped.
2026-05-31 23:01:46 +08:00
程序员阿江(Relakkes)
0ab624bff4 fix(desktop): remove hidden chat action hover strip #642
The previous fix moved the hover group onto the message shell, but the action row still occupied layout space while invisible. That invisible row kept expanding the shell hit area, so moving the pointer into the empty metadata strip could still reveal copy and timestamp controls.

Collapse the action row to zero height by default and expand it only while the message shell is hovered or focused. Keep message content spacing separate from the action row so hidden controls do not create a hover target.

Constraint: Copy/fork controls must remain reachable after the bubble reveals them.
Rejected: Use display:none for the action row | would remove the keyboard focus path entirely.
Confidence: high
Scope-risk: narrow
Directive: Keep hidden message metadata rows out of normal hover hit-testing; do not reintroduce invisible layout space around chat bubbles.
Tested: cd desktop && bun run test src/components/chat/MessageList.test.tsx --run -t "keeps user actions anchored"
Tested: cd desktop && bun run test src/components/chat/MessageList.test.tsx --run
Tested: cd desktop && bun run test src/components/chat/UserMessage.test.tsx --run
Tested: bun run check:desktop
Tested: git diff --check
Not-tested: Live Tauri native hover smoke
Related: #642
2026-05-31 21:43:19 +08:00
程序员阿江(Relakkes)
9b3e58b60b perf(desktop): skip off-screen paint on non-virtualized transcript rows (WebKit)
WebKit (Tauri WKWebView) paints complex message DOM ~2x slower than Blink and stutters during scroll. Add content-visibility:auto + contain-intrinsic-size to fully-mounted (non-virtualized) rows so the engine skips off-screen rows without unmounting or re-measuring them.

Measured with Playwright WebKit on the reported laggy 79-message session (main): worst frame 279ms -> 18ms, jank 2 -> 0. Virtualization was ruled out — it made WebKit *worse* (tanstack 12-24fps) due to scroll-time measureElement/re-render cost.

Only non-virtualized rows get the class (no ResizeObserver); virtualized window items stay free of content-visibility to avoid the zero-height measurement regression. Tests guard both directions.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-31 17:42:30 +08:00
程序员阿江(Relakkes)
ed574777e3 fix(desktop): make Mermaid diagrams readable at scale #636
Large Mermaid flowcharts were still hard to inspect in the desktop chat surface because ultra-wide SVGs could be squeezed or opened at an unhelpful crop. Normalize the rendered SVG, keep edge strokes visible while preserving author styles, and add fit-first overview rendering for both inline chat cards and the preview modal.

Constraint: Mermaid emits SVG sized for generic web pages, while desktop chat needs readable SVG behavior inside constrained WebView panels.

Rejected: Replace Mermaid with a node-canvas library | it would not be a drop-in renderer for Mermaid syntax and would add unnecessary dependency and migration risk.

Confidence: high

Scope-risk: moderate

Directive: Keep SVG normalization additive; do not override explicit linkStyle or marker paint without adding a regression test.

Tested: bun run check:desktop

Tested: Real desktop frontend visual QA with complex Mermaid screenshots at Fit, 25%, 50%, 75%, 100%, and 125%.

Not-tested: Packaged Tauri WebView smoke.
2026-05-31 17:42:30 +08:00
程序员阿江(Relakkes)
8c5c2a0913 fix(desktop): narrow chat action hover area #642
Message actions were still tied to the full message row, so moving the pointer into blank space beside a short chat bubble kept copy and timestamp controls visible. Move the hover group onto the actual message shell and keep full-width behavior only for document-style assistant replies.

Constraint: Message actions still rely on group-hover and focus-within for pointer and keyboard access.
Rejected: Remove focus-within reveal | would regress keyboard users who tab to copy or fork controls.
Confidence: high
Scope-risk: narrow
Directive: Keep normal bubble hover bounds tied to the message shell; document-layout replies intentionally remain full-width.
Tested: cd desktop && bun run test src/components/chat/MessageList.test.tsx --run
Tested: cd desktop && bun run test src/components/chat/UserMessage.test.tsx --run
Tested: bun run check:desktop
Tested: git diff --check
Not-tested: Live Tauri native hover smoke
Related: #642
2026-05-31 17:42:30 +08:00
程序员阿江(Relakkes)
ef818f8d8c fix(desktop): keep dismissed task progress hidden
Dismissed completed task lists are a user visibility choice for that completed cycle, so polling the same persisted tasks during the next chat turn should not resurrect the bar. The store now keeps the dismissed completion key while the remote reset is in flight, and the markdown renderer gives default lists enough inset so bullets stay inside message cards.

Constraint: Preserve future task cycles when new TodoWrite or task updates arrive.
Rejected: Clear only the visible task array | polling can rehydrate the same completed list before remote reset finishes
Confidence: high
Scope-risk: narrow
Tested: cd desktop && bun run test -- run src/stores/cliTaskStore.test.ts src/components/markdown/MarkdownRenderer.test.tsx
Tested: bun run check:desktop
Tested: git diff --check
Not-tested: Live Tauri chat session task creation and dismissal
2026-05-31 17:42:30 +08:00
程序员阿江(Relakkes)
1f9af7e578 feat: scope desktop reasoning effort to sessions
Desktop reasoning effort now follows the selected session runtime instead of the General settings surface. Session metadata records provider, model, and effort so reconnects and prewarm restarts preserve the per-session runtime, while the default effort is max for new sessions.

Constraint: Existing transcript and localStorage runtime data must remain readable without a required migration.
Rejected: Keep effort as a General setting | it made one session change leak into every other session.
Confidence: high
Scope-risk: moderate
Directive: Do not reintroduce global desktop effort controls without proving multi-session isolation.
Tested: bun run check:server
Tested: bun run check:desktop
Tested: bun run check:native
Tested: bun run check:policy
Tested: bun run check:coverage
Tested: cd desktop && bun run test -- src/components/controls/ModelSelector.test.tsx src/stores/chatStore.test.ts
Tested: bun test src/server/__tests__/settings.test.ts --test-name-pattern "effort"
Tested: bun test src/server/__tests__/conversations.test.ts --test-name-pattern "runtime"
Not-tested: Live provider smoke for domestic providers without local credentials.
2026-05-31 17:42:30 +08:00
程序员阿江(Relakkes)
29586ce384 fix: stabilize empty agentTaskNotifications to prevent scroll re-renders
The "?? {}" fallback allocated a fresh object every render, defeating the React.memo barriers on ToolCallGroup and MessageBlock for sessions without agent task notifications, so every visible tool-call card re-rendered on each scroll frame. Reuse a module-level empty constant, mirroring EMPTY_MESSAGES.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-31 17:42:30 +08:00
程序员阿江(Relakkes)
1110e5ab30 fix: make desktop updates non-blocking
Move update downloads into the background and prompt only after the update is ready, so the global update UI no longer pins a progress panel over the app. Keep the About page as the detailed status surface and make failed downloads or installs retryable without losing the prepared update.

Constraint: Tauri updater install still needs an explicit user restart action after download
Rejected: Keep showing global download progress | it preserves the blocking top-right experience that triggered the complaint
Confidence: high
Scope-risk: moderate
Directive: Do not show the global update prompt before status is downloaded without rechecking the desktop UX complaint
Tested: bun run test -- src/stores/updateStore.test.ts src/components/shared/UpdateChecker.test.tsx --run
Tested: bun run check:desktop
Tested: bun run check:native
Tested: bun run check:coverage
Tested: bun run verify
Not-tested: Real signed release artifact update from an installed older desktop build
2026-05-31 17:42:30 +08:00
程序员阿江(Relakkes)
6ca7ee48a8 fix: unify desktop confirmation dialogs
Desktop destructive confirmations had split implementations: shared ConfirmDialog, hand-rolled modals, inline task popovers, and a diagnostics window.confirm path. This adds shared ActionDialog and ConfirmPopover primitives, keeps ConfirmDialog as the simple two-action wrapper, and migrates the known desktop confirmation flows onto those shared surfaces.

Constraint: Running-tab close needs three actions, so the two-button ConfirmDialog API was not enough.
Rejected: Force every confirmation through ConfirmDialog | would either lose the keep-running action or make ConfirmDialog too broad for inline popovers.
Confidence: high
Scope-risk: moderate
Directive: Add new desktop confirmation flows through ActionDialog, ConfirmDialog, or ConfirmPopover instead of hand-rolled overlays.
Tested: cd desktop && bun run test -- AdapterSettings.test.tsx mcpSettings.test.tsx TabBar.test.tsx PermissionModeSelector.test.tsx diagnosticsSettings.test.tsx
Tested: bun run check:desktop
Tested: git diff --check
Tested: Chrome DevTools smoke for provider delete and diagnostics clear-log confirmation dialogs
Not-tested: Agent Browser smoke because the local agent-browser CLI hung on open/snapshot/doctor/close commands.
2026-05-31 17:42:30 +08:00
程序员阿江(Relakkes)
66a0d45627 fix: hold Mermaid rendering until streams finish #636
Streaming assistant output can expose incomplete Mermaid fences before the
model has closed the diagram syntax. Keep those blocks in a generating state
until the assistant message finalizes, then render the completed diagram. Also
preserve Mermaid label content in sanitized SVG output so preview and expanded
views keep node text visible.

Constraint: marked treats unclosed fenced code as a code block during streaming
Rejected: Keep retrying Mermaid render on partial syntax | users still see parse errors while valid output is incomplete
Confidence: high
Scope-risk: narrow
Directive: Do not render parser-backed diagram components from streaming markdown without an explicit pending state
Tested: bun run check:desktop
Not-tested: live provider smoke after Codex host Crashpad renderer/utility dumps were observed
2026-05-31 17:42:09 +08:00
程序员阿江(Relakkes)
fd25e5732f fix: hide message actions after pointer clicks #642
Message action controls stay visible through focus-within for keyboard navigation, but pointer clicks left the copy/fork buttons focused after the mouse moved away. Release pointer focus on message actions so hover controls return to their quiet state while keeping Tab focus behavior intact.

Constraint: Message actions use focus-within for keyboard accessibility and should not remove that path.
Rejected: Remove focus-within reveal | would regress keyboard users who tab to copy or fork.
Confidence: high
Scope-risk: narrow
Directive: Keep pointer-only blur scoped to message action controls; do not remove focus-within without a replacement keyboard affordance.
Tested: cd desktop && bun run test src/components/chat/MessageList.test.tsx --run
Tested: bun run check:desktop
Not-tested: Live Tauri manual hover smoke
Related: #642
2026-05-31 17:42:09 +08:00
程序员阿江(Relakkes)
d9d0d20782 fix: repair desktop theme rendering for markdown #636
Dark-mode Markdown text was still inheriting Tailwind Typography's default prose color, so normal and italic text could render dark while strong text used the app theme token.

Map markdown prose variables to the desktop theme tokens, move code-viewer hover and line-number styling onto theme tokens, and make Mermaid/Diff rendering follow the active app theme. Write/Edit/tool result and workspace render paths were audited; their core code and diff surfaces already use theme tokens, with the DiffViewer theme handoff tightened here.

Constraint: Mermaid theme customization requires the base theme and concrete color values, so CSS theme tokens are resolved to hex before rendering.

Rejected: Add per-element prose utility overrides only | misses Tailwind Typography defaults for quotes, counters, tables, and future prose elements

Confidence: high

Scope-risk: moderate

Directive: Keep markdown, code, diff, and diagram colors routed through shared desktop theme tokens; do not reintroduce fixed light backgrounds in chat renderers.

Tested: cd desktop && bun run test -- --run src/theme/globals.test.ts src/components/markdown/MarkdownRenderer.test.tsx src/components/chat/CodeViewer.test.tsx src/components/chat/MermaidRenderer.test.tsx src/components/chat/DiffViewer.test.tsx src/components/chat/chatBlocks.test.tsx src/components/workspace/WorkspacePanel.test.tsx

Tested: cd desktop && bun run lint

Tested: cd desktop && bun run build

Tested: git diff --check

Not-tested: Full Tauri live desktop session with real provider output; browser broad-audit screenshot capture timed out, but computed colors were captured for all three themes.
2026-05-31 17:42:09 +08:00
程序员阿江(Relakkes)
b483a9929d fix: reveal message actions with timestamps on hover (#642)
Message rows should stay visually quiet until the user needs copy or fork controls. The action row now appears on message hover/focus, uses icon-sized controls, and shows the message timestamp beside the actions with locale-aware recent and historical formats.

Constraint: Desktop chat actions already own copy and fork affordances, so the change keeps that surface instead of adding a separate always-visible timestamp row.
Rejected: Keep text-labeled Copy buttons | the row remained too visually heavy for every message.
Confidence: high
Scope-risk: narrow
Directive: Keep copy, fork, and timestamp as one hover/focus metadata row unless the message layout is redesigned as a whole.
Tested: bun run check:desktop
Not-tested: Live Tauri native packaging
2026-05-31 17:41:43 +08:00
程序员阿江(Relakkes)
1ca29d8a4a fix(desktop): hide child webview while a fullscreen overlay (image preview) is open 2026-05-31 17:40:46 +08:00
程序员阿江(Relakkes)
144ee5a779 fix(desktop): open-with trigger toggles its menu (re-click closes; ignore trigger in outside-close) 2026-05-31 17:40:46 +08:00
程序员阿江(Relakkes)
f17b0828a0 feat(desktop): change-card row opens the workspace diff instead of an inline diff
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-31 17:40:46 +08:00
程序员阿江(Relakkes)
1d9f4c9cb7 feat(desktop): unify right panel into Workbench with file/browser mode switch
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-31 17:40:46 +08:00
程序员阿江(Relakkes)
41d1cb5c00 feat(desktop): browser loading indicator (progress bar + spinner) with timeout fallback
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-31 17:40:46 +08:00
程序员阿江(Relakkes)
d7d7cffddb feat(desktop): render AI-output videos inline as <video> (mp4/webm/mov)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-31 17:40:46 +08:00