Increase the desktop session list fetch window so noisy observer sessions are less likely to hide real user sessions from the sidebar.
Tested: cd desktop && bun run test -- src/stores/sessionStore.test.ts src/components/layout/Sidebar.test.tsx
Tested: bun run check:desktop
Confidence: high
Scope-risk: narrow
Reveal-in-Explorer/Finder rejected ~-prefixed paths because no layer
expanded the tilde to the home directory. Expand it in the three path
normalization entry points: server validateOpenPath, frontend
resolveAbsolute, and Electron normalizeOpenPath. Tilde expansion is
platform-aware (~\ only on win32, where backslash is a separator).
Tested: cd desktop && bun run test -- src/components/common/OpenWithMenu.test.tsx src/components/workspace/WorkspaceFileOpenWith.test.tsx src/components/browser/BrowserSurface.test.tsx src/lib/handlePreviewLink.test.ts src/lib/openWithContextForHref.test.ts
Tested: bun run check:desktop
Confidence: high
Scope-risk: narrow
Token counts were rendered with five inconsistent formats across the
chat UI (header "181,117 t", in-progress bare "↓ 2514", background
agents "12,345 tokens", compact summary "1.5k", trace "1.2k"), and the
in-progress count was actually stale: the server never set the status
event's tokens field, so the indicator showed the previous turn's value
(hence "first message shows nothing", "sometimes appears, never moves").
- Add shared desktop lib/formatTokenCount; route header, streaming
indicator, background agents, compact summary, and trace through it.
- Header shows compact "124.3k tokens" with the exact count on hover.
- Add common.tokens i18n key (en/zh/zh-TW/jp/kr).
- Estimate the in-progress count from streamed chars (÷4, mirroring the
CLI spinner) via a new streamingResponseChars per-session field, reset
on each send; drop the dead status.tokens/elapsed fields.
- CLI spinner rows use formatTokens to drop the "1.0k" artifact.
Replace the editable MCP server heading with neutral configuration copy so the settings page does not imply an update action is running.
Fixes#763
Tested: cd desktop && bun run test -- src/__tests__/mcpSettings.test.tsx
Tested: cd desktop && bun run lint
Not-tested: full verify and coverage, scoped desktop copy/test change only
Confidence: high
Scope-risk: narrow
Allow local browser origins such as 127.0.0.1, localhost, and ::1 to use the desktop server without H5 token flow, while keeping LAN and public origins behind H5 access rules. Also make Vite SPA healthcheck fallback to the default loopback backend and document scoped verification expectations.
Tested: bun test src/server/__tests__/h5-access-policy.test.ts
Tested: bun test src/server/__tests__/h5-access-auth.test.ts
Tested: bun test src/server/middleware/cors.test.ts
Tested: cd desktop && bun run test -- src/lib/desktopRuntime.test.ts --run
Tested: git diff --check
Not-tested: bun run verify and coverage were intentionally skipped for this scoped local-dev fix.
Scope-risk: moderate
Strip the rotating billing attribution line before converting system
prompts to OpenAI Chat/Responses requests, forward a stable
prompt_cache_key derived from the client session, request stream usage
explicitly on Chat streams, and map cached_tokens back to Anthropic
cache_read_input_tokens with exclusive input accounting.
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
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
Expose the existing CLI Auto-dream switch in General settings with an explicit opt-in confirmation before enabling background memory consolidation.
Tested: bun run check:desktop
Tested: ./bin/claude-haha --help
Tested: CLAUDE_CONFIG_DIR temp settings true/false autoDreamEnabled check
Tested: real provider Auto-dream trigger against temporary memory copy
Scope-risk: narrow
Confidence: high
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
Add historical tool and skill aggregation to activity stats, compact the token summary, and show Codex-style activity insights with plugin/skill ranking.
Tested: bun test src/utils/__tests__/stats.test.ts
Tested: bun run check:persistence-upgrade
Tested: bun run check:desktop
Not-tested: bun run check:server (previous full run exposed unrelated conversations WebSocket timeouts; focused stats and persistence checks passed)
Confidence: medium
Scope-risk: moderate
Remove the Windows renderer-side drag delta fallback and keep frameless window movement on Electron app-region handling. Reject drag movement payloads on the legacy IPC channel so window drags cannot mutate bounds through repeated setPosition calls.
Tested: cd desktop && bun run test --run src/hooks/useElectronWindowDragRegions.test.tsx electron/ipc/capabilities.test.ts src/lib/desktopHost/electronHost.test.ts
Tested: bun run check:desktop
Tested: bun run check:native
Confidence: high
Scope-risk: narrow
Prevent stale same-version update metadata from surfacing another install prompt, avoid showing a fake desktop version fallback, and configure the Windows NSIS installer to expose install directory selection.
Fixes#801
Tested: bun run verify
Confidence: high
Scope-risk: moderate
Ensure Electron sidecar launch and Windows taskkill calls hide console windows, and pass the same hidden-window spawn option through desktop CLI and scheduled-task subprocess launches.
Tested: cd desktop && bun test ./electron/services/sidecarManager.test.ts
Tested: bun test src/server/__tests__/conversation-service.test.ts src/server/__tests__/cron-scheduler-launcher.test.ts
Tested: bun run check:native
Tested: bun run check:server
Not-tested: Windows GUI quit smoke
Confidence: medium
Scope-risk: narrow
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
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
Mapped Windows drives can resolve to UNC paths before the CLI starts. Treat the UNC prefix as safe only after the target has already been proven to be inside the allowed working directory, while keeping sensitive paths and out-of-workspace UNC writes behind safety checks.
Tested: bun test src\\utils\\permissions\\filesystem.test.ts
Tested: real local app server/WebSocket session with deepseek-v4-pro and --dangerously-skip-permissions wrote through X:\\project without a permission_request.
Not-tested: full check:server is still red on this Windows checkout due pre-existing unrelated failures in shell env, H5/local-file, MCP, FileRead CJK, and a darwin-only expectation.
Confidence: high
Scope-risk: narrow
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
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
Restore visual-selection prompts from persisted transcript history as annotated screenshot attachments instead of exposing the model-facing selector prompt after reopening a session.
Tested: cd desktop && bun run test -- --run src/stores/chatStore.test.ts -t "restores visual selection history" --reporter verbose
Tested: bun run check:desktop
Confidence: high
Scope-risk: narrow
WhatsApp always closes the pairing socket with DisconnectReason.restartRequired
(515) right after a successful QR scan, so the login flow treated every
successful scan as "connection closed". Recreate the socket with the saved
credentials and keep waiting for the open event instead, matching the openclaw
reference behavior. Also restart on QR rotation timeout (408) to serve a fresh
QR, bounded by a restart limit.
Tested:
- cd adapters && bun test (397 pass)
- cd adapters && bunx tsc --noEmit -p tsconfig.json
- bun test src/server/__tests__/adapters.test.ts
Put Telegram first in the IM adapter settings, add a single documentation link in the setup copy, and keep per-platform settings focused on configuration.
Tested: cd desktop && bun run test AdapterSettings.test.tsx
Tested: bun run check:desktop
Scope-risk: narrow
Confidence: high
Persist permission mode changes immediately, but defer restart-only permission transitions until the active desktop turn emits its terminal result.
Tested:
- bun test src/server/__tests__/conversations.test.ts -t "should defer bypass permission restarts until the active turn completes"
- bun test src/server/__tests__/conversations.test.ts -t "permission"
- bun run check:server
Scope-risk: narrow
Tested: cd desktop && bun run test -- src/__tests__/memorySettings.test.tsx --run --reporter=verbose --pool=forks --maxWorkers=1 --minWorkers=1
Tested: bun run check:desktop
Tested: bun run check:coverage
Tested: Chrome CDP smoke confirmed the memory editor textarea expands to 592px tall
Confidence: high
Scope-risk: narrow
Use Electron WebContentsView capturePage for browser preview screenshots and selection annotations so captured images match the rendered preview.
Tested:
- cd desktop && bun run test -- electron/services/preview.test.ts src/lib/previewEvents.test.ts src/components/browser/BrowserSurface.test.tsx src/preview-agent/screenshot.test.ts src/preview-agent/picker.test.ts src/preview-agent/editBubble.test.ts
- cd desktop && bun run lint
- cd desktop && bun run build
- bun run check:desktop
- bun run check:electron
- bun run check:native
Not-tested:
- Real GUI click-through for Screenshot / Select Element; Electron runtime launch was blocked in this shell and packaged build did not enter the smoke path.
Constraint: GUI click-through smoke was blocked by local Electron launch behavior; package smoke passed but does not launch the app.
Confidence: medium
Scope-risk: narrow
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
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
Ensure custom OpenAI-compatible provider tests explicitly request non-stream responses for both direct connectivity checks and the proxy pipeline. This avoids default SSE responses being parsed as empty JSON by provider validation.
Tested: bun test src/server/__tests__/providers.test.ts --test-name-pattern "requests non-stream OpenAI Chat responses during provider tests"
Tested: bun test src/server/__tests__/providers.test.ts
Tested: bun test src/server/__tests__/proxy-transform.test.ts
Tested: bun run check:server
Confidence: high
Scope-risk: narrow
Prevent desktop prewarm launches from inheriting interrupted-turn resume state, while leaving explicit user-message startup unchanged. Also stop server-side background schedulers during shutdown so app quit cannot leave scheduled task runners alive.
Tested:
- bun test src/server/__tests__/conversation-service.test.ts
- bun test src/server/__tests__/conversations.test.ts -t "prewarm"
- bun test src/server/__tests__/conversations.test.ts -t "permission"
- bun test src/server/__tests__/diagnostics-service.test.ts -t "keeps fatal startup errors visible on stderr while recording diagnostics"
- bun test desktop/electron/services/windows.test.ts desktop/electron/services/tray.test.ts desktop/electron/services/sidecarManager.test.ts src/server/__tests__/server-shutdown.test.ts
- bun run check:server
Add a WhatsApp adapter backed by Baileys linked-device auth, plus desktop QR binding UI, server config endpoints, sidecar startup wiring, tests, and documentation.
Constraint: Uses WhatsApp Web linked-device auth, not Meta WhatsApp Business Cloud API.
Tested:
- cd adapters && bun run check:adapters
- bun test src/server/__tests__/adapters.test.ts
- cd desktop && bun run check:desktop
- bun run check:native
- bun run check:persistence-upgrade
- bun run check:docs
Not-tested:
- Live WhatsApp QR pairing, because no WhatsApp account/device was exercised here.
- bun run check:server, because the existing src/server/__tests__/conversations.test.ts timeout still fails independently.
Confidence: medium
Scope-risk: moderate
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
Avoid killing an in-flight desktop SDK turn when runtime config changes during tool execution. Persist the requested runtime immediately, then restart after the turn emits its terminal result.
Tested:
- bun run check:server
- real provider tool-turn model switch smoke
- bun run check:coverage (changed-line coverage passed; unrelated global lanes still fail)
Scope-risk: narrow
Add Telegram command-menu sync plus /resume, /provider, /model, and /skills command handling with paginated inline selections.
Expose the adapter HTTP calls needed by those commands and harden stale WebSocket session cleanup during Telegram resume/reset flows.
Tested:
- cd adapters && bun test telegram/__tests__/commands.test.ts telegram/__tests__/menu.test.ts
- cd adapters && bunx tsc --noEmit -p tsconfig.json
- bun run check:adapters
- bun run check:persistence-upgrade
- bun run check:native
- bun run verify (coverage lane failed on existing root WebSocket Chat Integration timeout)
Not-tested:
- Live Telegram bot smoke, no bot token/session available.
Confidence: medium
Scope-risk: moderate
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
Git writes upstream branch config when a worktree starts from origin/main. Use the already-resolved base SHA as the worktree start point so parallel agent worktrees do not race on shared .git/config.
Tested: bun test src/utils/__tests__/worktree.test.ts
Tested: real gpt-5.5 Sub2API run with four worktree-isolated agents
Not-tested: bun run check:server currently fails unrelated WebSocket restart/timeouts
Confidence: high
Scope-risk: narrow
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>
Main added two TranslationKeys after this branch's base — 'thinking.labelDone'
(the "Thought" label shown after thinking completes) and
'slashCmd.agent.description' — which the jp/kr/zh-TW locale files did not yet
cover, so the Record<TranslationKey, string> contract failed tsc after merging
main. Add both keys to each new locale:
- jp: '思考完了' / '選択した Agent でプロンプトを実行'
- kr: '사고 완료' / '선택한 Agent로 프롬프트 실행'
- zh-TW: '已思考' / '使用指定 Agent 執行提示'
en/zh are unchanged. `tsc --noEmit` is now clean and the i18n + timestamp
suites pass.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Guard OpenAI-compatible proxy streaming bodies with the configured AI request timeout so a provider that emits partial SSE and then idles cannot leave proxy consumers waiting forever.
This is a proxy-level fix found while investigating #548; it does not claim to close the broader desktop interruption issue.
Tested: bun test src/server/__tests__/proxy-network-settings.test.ts
Tested: bun run check:server
Confidence: medium
Scope-risk: narrow