127 Commits

Author SHA1 Message Date
程序员阿江(Relakkes)
49e1367659 fix: avoid blocking MCP list on live health checks
Desktop MCP settings was synchronously probing every configured server from /api/mcp, which made the list page scale with connection latency and surface brittle behavior as installs accumulated more MCPs. Return lightweight snapshot rows from the list API, keep explicit status checks separate, and let the desktop UI refresh status in a constrained background lane while preserving project-aware server identity.

Constraint: MCP list must stay responsive even with many configured servers
Rejected: Probe all servers from the list view without limits | still fans out with server count and can overload slow installs
Rejected: Keep servers permanently unchecked until detail view | misses the desired loading feedback when the MCP page opens
Confidence: high
Scope-risk: moderate
Reversibility: clean
Directive: Keep /api/mcp as a configuration snapshot endpoint; do not reintroduce per-row live connect work on list load
Tested: bun test src/server/__tests__/mcp.test.ts; cd desktop && bun run test -- mcpSettings.test.tsx; cd desktop && bun x tsc --noEmit --ignoreDeprecations 5.0
Not-tested: Real desktop interaction against an environment with dozens of live MCP servers
2026-04-22 15:34:36 +08:00
Relakkes Yang
4bc6e135dd fix: restore computer use setup for python 3.8 2026-04-22 14:28:36 +08:00
程序员阿江(Relakkes)
de736c49f7 Unify plugin capabilities with the desktop management views
Desktop plugin details now route into the shared Skills, Agents, and MCP management surfaces instead of maintaining separate read-only drilldowns. This also extends the desktop/server skill aggregation so plugin-provided skills appear in the shared list, groups MCP entries by source, and preserves detail-view back navigation based on where the user entered the page.

The implementation keeps plugin detail as the high-level capability hub while pushing real inspection into the existing management pages. Disabled plugins no longer expose false navigation paths into shared views, and the agent-browser regression script was expanded to exercise the new end-to-end flows.

Constraint: Shared Agents data only includes enabled plugin agents, so disabled plugins cannot deep-link into agent detail
Rejected: Keep duplicating full Skills/Agents/MCP detail inside Plugin detail | creates divergent UI flows and stale data paths
Confidence: high
Scope-risk: moderate
Reversibility: clean
Directive: If a detail view can be opened from multiple entry points, keep the return target in store state rather than hardcoding a single back destination
Tested: desktop vitest for plugins/skills/agents/mcp; desktop tsc --noEmit; desktop vite build; server skills API test; agent-browser web regression on plugin->skill/mcp and plugin->agent back navigation
Not-tested: packaged desktop app regression after rebuilding the Tauri bundle
2026-04-22 12:31:57 +08:00
程序员阿江(Relakkes)
6c02904e58 Keep slash-command entry surfaces aligned with MCP desktop management
Merged the desktop MCP management work into local main and retained
existing plugin settings affordances while resolving router and settings-tab
conflicts. The resulting flow keeps MCP settings global-only for speed and
uses slash-command cards to route users into concrete MCP or skill targets.

Constraint: local main already had plugin settings and API routes that had to remain available
Rejected: Favor the worktree version wholesale during merge | would have dropped local plugin tab and router support on main
Confidence: medium
Scope-risk: moderate
Reversibility: clean
Directive: Keep slash-command entry flows and settings tabs additive during future merges; do not collapse MCP and plugin navigation into one another
Tested: Conflict resolution review during merge; source commit 66edded validated with bun test src/server/__tests__/mcp.test.ts; cd desktop && bun run test -- pages.test.tsx mcpSettings.test.tsx; cd desktop && bun x tsc --noEmit --ignoreDeprecations 5.0
Not-tested: Re-running full desktop/manual verification from the merged main worktree after merge completion
Related: 66edded
2026-04-21 23:29:11 +08:00
程序员阿江(Relakkes)
66edded2d7 Make desktop MCP management and slash entry points directly operable
Desktop MCP management now has a working server API, a global-only settings surface,
and slash-command entry points that surface MCP and skills from the composer before
routing users into the right settings view.

Constraint: Project-scoped MCP browsing in settings was too slow and noisy because it scanned multiple workdirs
Rejected: Keep project MCP aggregation on the settings homepage | duplicated entries and poor responsiveness
Rejected: Route /mcp directly on Enter without an intermediate card | removed the user's ability to choose a specific target first
Confidence: medium
Scope-risk: moderate
Reversibility: clean
Directive: Keep settings focused on global MCP; add project-scoped MCP affordances in the chat-context slash surfaces instead of re-expanding the settings homepage
Tested: bun test src/server/__tests__/mcp.test.ts; cd desktop && bun run test -- pages.test.tsx mcpSettings.test.tsx; cd desktop && bun x tsc --noEmit --ignoreDeprecations 5.0
Not-tested: Manual IAB verification after this final commit/merge cycle
2026-04-21 23:28:06 +08:00
程序员阿江(Relakkes)
89911bd6bf Merge commit '375d587' 2026-04-21 23:21:25 +08:00
程序员阿江(Relakkes)
375d587ed1 Expose desktop plugin management through first-class APIs
The desktop app could read plugin-produced skills and agents, but it had no
plugin control plane of its own. This adds a dedicated Settings tab backed by
server-side plugin APIs so installed plugins can be inspected, enabled,
disabled, updated, reloaded, and uninstalled from the WebUI.

The implementation also teaches browser-based desktop dev sessions to honor a
custom backend URL, which made it possible to run isolated worktree ports for
real UI automation. During verification, the long-lived desktop server kept a
stale installed-plugin snapshot after external CLI mutations, so cache clearing
now resets that session-level plugin installation state as well.

Constraint: Desktop WebUI needed an isolated backend URL instead of the hard-coded 127.0.0.1:3456 fallback
Constraint: Reuse existing plugin operations and loaders instead of rebuilding plugin lifecycle logic in the desktop layer
Rejected: Fold plugin management into Skills or Adapters | mixed unrelated lifecycles and hid plugin-specific health/actions
Rejected: Expose only read-only plugin status in desktop | did not satisfy enable-disable-reload-uninstall verification needs
Confidence: high
Scope-risk: moderate
Reversibility: clean
Directive: Keep desktop plugin actions routed through the shared plugin operation layer and clear installed-plugin session caches when plugin state changes externally
Tested: cd desktop && bun run lint
Tested: cd desktop && bun run test -- src/__tests__/pluginsSettings.test.tsx
Tested: bun test src/server/__tests__/plugins.test.ts src/server/__tests__/skills.test.ts
Tested: Browser automation against isolated ports 15120/38456 covering discord plugin list/detail/disable/apply/enable/update/uninstall flows
Not-tested: Full desktop session runtime parity with CLI /reload-plugins AppState refresh beyond the new desktop API path
2026-04-21 23:21:16 +08:00
程序员阿江(Relakkes)
044e9b6cc8 Make desktop rewind restore both transcript state and file checkpoints
The desktop client already had a conversation-level rewind UI concept on the
CLI side, but the web/desktop surface lacked the protocol, session trimming,
and file checkpoint restore path needed to make rewind trustworthy. This change
adds a desktop-specific rewind API, wires the message-level UI affordance and
confirmation modal, enables SDK file checkpointing for desktop sessions, and
covers the restore path with service tests plus a real agent-browser workflow.

Constraint: Desktop sessions run the CLI in SDK/print mode, so file checkpointing had to be enabled explicitly for that path
Constraint: main branch is checked out in a separate worktree, so merge-back must happen from the primary worktree after commit
Rejected: UI-only rewind that only trims local state | would leave persisted transcript and disk state inconsistent after refresh
Rejected: Reuse getLastSessionLog as the sole snapshot source | active rewind must read file-history metadata directly from the session file
Confidence: high
Scope-risk: moderate
Reversibility: clean
Directive: Keep desktop rewind keyed to persisted user-message order unless the UI model starts carrying stable transcript UUIDs end-to-end
Tested: bun test src/server/__tests__/conversation-service.test.ts src/server/__tests__/sessions.test.ts; desktop MessageList vitest; desktop tsc no-emit; live agent-browser E2E on isolated ports with file edit then rewind
Not-tested: Browser E2E matrix for multi-file and second-edit scenarios is still covered at service-test level rather than full UI level
2026-04-21 21:34:41 +08:00
程序员阿江(Relakkes)
5377eb596f Keep desktop session history and reconnect recovery trustworthy
Desktop session interruptions were leaving two different classes of stale UI
artifacts behind: reconnects could silently lose in-flight output, and history
reloads could replay synthetic interruption or internal command breadcrumbs as
if they were user-facing transcript content. This change rebinds active session
output to the latest client websocket on reconnect, preserves queued outbound
messages across transient disconnects, and filters synthetic transcript entries
before they reach the desktop history API so reloads reconstruct only the
messages users should actually see.

Constraint: Desktop transcript history is shared with CLI JSONL files and must stay compatible with persisted message shapes
Rejected: Hide these artifacts only in React renderers | other transcript consumers would still receive polluted history
Confidence: high
Scope-risk: moderate
Reversibility: clean
Directive: Keep transcript filtering aligned with real synthetic/internal message shapes before adding new hidden message types
Tested: bun test src/server/__tests__/sessions.test.ts
Tested: bun test src/server/__tests__/conversations.test.ts
Tested: cd /Users/nanmi/.codex/worktrees/e7ac/claude-code-haha/desktop && bun run test -- websocket.test.ts
Tested: cd /Users/nanmi/.codex/worktrees/e7ac/claude-code-haha/desktop && bun run lint
Not-tested: Manual browser verification of the refreshed session transcript after interrupt on this exact session
2026-04-21 17:55:15 +08:00
程序员阿江(Relakkes)
16d716e773 fix: keep completed task lists from leaking into the next turn
Completed desktop task bars were only being dismissed locally, which let the
persisted task list resurface on refresh or bleed into the next user turn.
This wires the existing server-side reset path into the desktop stores and
session flow so a finished task cycle is summarized once, cleared locally,
and removed remotely before the next round starts.

Constraint: Existing task persistence already lives behind the server task-list API and must stay compatible with persisted JSON task files
Rejected: Only hide the completed task bar in UI state | left stale persisted tasks behind and reintroduced them on reload
Rejected: Clear desktop state without a task summary | dropped useful completion context from the chat transcript
Confidence: high
Scope-risk: moderate
Reversibility: clean
Directive: Keep desktop task dismissal and task-list persistence behavior aligned; do not reintroduce local-only clearing without covering reload and next-turn flows
Tested: `cd desktop && bun run lint`
Tested: `cd desktop && bun run test src/stores/cliTaskStore.test.ts src/stores/chatStore.test.ts src/components/chat/SessionTaskBar.test.tsx src/components/chat/ComputerUsePermissionModal.test.tsx`
Tested: `bun test src/server/__tests__/e2e/business-flow.test.ts --test-name-pattern "Task Lists API"`
Not-tested: Full `bun test src/server/__tests__/e2e/business-flow.test.ts` suite still has unrelated pre-existing failures in Models and Sessions sections
2026-04-21 00:46:29 +08:00
程序员阿江(Relakkes)
7651b24a50 Reduce desktop first-token latency in sdk-url sessions
Desktop-managed sessions were blocking the first visible token on slow or failing
regular MCP connections, which made the UI feel much slower than direct bin runs.
This keeps partial assistant streaming enabled for desktop sessions and moves
regular MCP connection work off the critical path only for sdk-url startup.

Constraint: Desktop sdk-url sessions must preserve chat responsiveness even when local MCP endpoints fail or hang
Rejected: Leave MCP startup fully blocking in sdk-url mode | first visible token stayed several seconds behind direct CLI runs
Confidence: high
Scope-risk: moderate
Reversibility: clean
Directive: Keep blocking MCP startup for plain -p sessions unless you re-measure first-turn latency and tool availability tradeoffs
Tested: bun test src/server/__tests__/conversation-service.test.ts src/server/__tests__/conversations.test.ts; same-prompt timing comparison for direct bin vs sdk-url session path
Not-tested: Immediate first-turn availability of slow regular MCP tools in desktop sdk-url sessions
2026-04-21 00:41:02 +08:00
程序员阿江(Relakkes)
e78b973e8c Restore sidebar project filter metadata and dropdown layering
The sidebar project filter had regressed to lossy projectPath strings, so the
UI showed broken folder-name fragments and the dropdown could not match the
richer project chooser used in session creation. This switches the sidebar back
to recent-project metadata, renders the filter menu through a portal, and keeps
session filtering behavior unchanged while restoring readable labels and paths.

Constraint: Sidebar filtering still needs to target existing session projectPath values without migrating store shape
Constraint: The desktop sidebar dropdown must escape local stacking and overflow constraints to render reliably
Rejected: Keep deriving labels from sanitized projectPath strings | lost repo names and full paths, causing misleading project choices
Rejected: Rebuild sessionStore around recent-project objects in this fix | broader state migration than needed for the regression
Confidence: high
Scope-risk: moderate
Reversibility: clean
Directive: Keep sidebar project displays aligned with /api/sessions/recent-projects metadata instead of reintroducing string-splitting fallbacks
Tested: cd desktop && bunx vitest run src/components/layout/ProjectFilter.test.tsx src/components/layout/Sidebar.test.tsx
Tested: cd desktop && bun run lint
Tested: cd desktop && bun run build
Not-tested: Manual desktop visual pass of the repaired dropdown in a live Tauri window
2026-04-20 23:45:53 +08:00
程序员阿江(Relakkes)
9fdbfafd4d Prevent settings races and stale session teardown in local services
Concurrent writes to the same settings file could interleave and leave user
preferences in a partially updated state, and a restarted conversation session
could still be torn down by an older process exit callback. This serializes
per-file settings writes, hardens temp-file handling, adds regression coverage
for both service behaviors, and drops an unused sidecar external from the
build exclude list.

Constraint: Settings writes must remain atomic while allowing multiple service entry points to update the same JSON file
Rejected: Keep fire-and-forget writes with unique temp names only | still allows stale reads and last-writer races between callers
Confidence: high
Scope-risk: moderate
Reversibility: clean
Directive: Preserve the per-file write lock when adding new settings mutation paths so concurrent writes keep one serialization point
Tested: bun test src/server/__tests__/settings.test.ts src/server/__tests__/conversations.test.ts (new settings/conversation cases passed)
Not-tested: Root lint script is unavailable; Models API tests in src/server/__tests__/settings.test.ts still fail in this checkout with changed default model/effort expectations
2026-04-20 23:13:45 +08:00
程序员阿江(Relakkes)
0f7494006f Prevent misleading empty @-file menus when filesystem access fails
Desktop @-mentions were collapsing filesystem browse failures into an empty
state, which made /private/tmp aliases on macOS look like real empty
directories. The server now treats /private/tmp as the same temp root as
/tmp on Darwin, and the menu surfaces explicit access/load errors instead of
pretending the directory has no files.

Constraint: Desktop browse/file APIs must stay restricted to approved roots
Constraint: Native macOS pickers and realpath() may canonicalize /tmp to /private/tmp
Rejected: Expanding filesystem access to arbitrary system paths | too broad for this targeted fix
Rejected: Keeping silent empty-state fallback | hides permission and path bugs from users
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Keep filesystem error states visible in the composer; do not collapse API failures back into empty-directory messaging
Tested: bun test src/server/__tests__/filesystem.test.ts
Tested: cd desktop && bun run test -- FileSearchMenu.test.tsx
Tested: cd desktop && bun run lint
Not-tested: Manual desktop packaging or end-to-end Tauri app run after this patch
2026-04-20 23:07:15 +08:00
程序员阿江(Relakkes)
0d3933c2c9 Keep desktop AskUserQuestion flows from stalling in plan mode
Desktop chat was rendering AskUserQuestion twice: once as an inline question card and again as a generic permission request. That split also dropped the structured answers on the floor because the websocket permission_response shape only carried allow/deny state.

This change keeps AskUserQuestion on the permission pipeline end-to-end. The desktop websocket contract now carries toolUseId and updatedInput, AskUserQuestion submits answers through permission_response, and the generic permission card is suppressed for that tool so the user sees a single question flow.

Constraint: AskUserQuestion answers must round-trip through updatedInput.answers for the CLI tool contract to complete
Rejected: Leave AskUserQuestion as a plain chat reply in desktop | the tool never receives structured answers and the pending approval UI remains stuck
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Keep AskUserQuestion bound to the permission-response path unless the desktop protocol grows a separate structured elicitation channel
Tested: desktop lint; vitest src/components/chat/AskUserQuestion.test.tsx src/stores/chatStore.test.ts; bun test src/server/__tests__/conversations.test.ts
Not-tested: Manual desktop click-through against a live plan-mode session after bundling
2026-04-20 23:07:15 +08:00
Relakkes Yang
4b513271ee fix: improve windows computer use and desktop rendering 2026-04-20 17:59:42 +08:00
程序员阿江(Relakkes)
921a352517 Integrate desktop skill discovery and empty-session composer fixes into main
This merges the detached-worktree desktop fixes back into main, preserving the
existing Computer Use modal changes on main while bringing over the project
skill discovery fallback, skills settings cwd-awareness, sidebar tab cleanup,
and the empty-session hero composer styling.

Constraint: Main already carried newer desktop session UI changes that had to be preserved during merge resolution
Rejected: Abort the merge and cherry-pick individual files | unnecessary once the only conflict was isolated to ActiveSession.tsx
Confidence: high
Scope-risk: moderate
Reversibility: clean
Directive: When merging detached-worktree desktop branches into main, keep ActiveSession conflict resolution additive so session overlays and composer variants survive together
Tested: bun test src/server/__tests__/sessions.test.ts; cd desktop && bun run test -- --run src/__tests__/skillsSettings.test.tsx src/components/layout/Sidebar.test.tsx src/__tests__/pages.test.tsx src/pages/ActiveSession.test.tsx; cd desktop && bun run lint
Not-tested: Manual post-merge GUI verification in the local main worktree app bundle
2026-04-20 13:37:57 +08:00
程序员阿江(Relakkes)
261a85ab76 Restore desktop project-skill discovery and align empty-session composer
The desktop app previously lost project-level skills in two places: the
settings browser only queried user skills, and the slash-command picker for a
fresh session depended on CLI init state that does not exist before the first
turn. This change makes the skills APIs cwd-aware, falls back to project skill
loading before CLI init, syncs sidebar session deletion with open tabs, and
aligns the empty-session composer styling so the pre-message session UI stays
consistent.

Constraint: Fresh desktop sessions need slash-command discovery before the CLI websocket emits system/init
Constraint: Only repository code should be committed; build artifacts, installs, and /tmp smoke fixtures stay out of git
Rejected: Rebuild slash-command listings from full getCommands() in the sessions API | introduced auth-gated command dependencies unrelated to local skill discovery
Rejected: Unify EmptySession and ChatInput into one full component now | higher regression risk for normal chat interactions than a visual-only hero variant
Confidence: high
Scope-risk: moderate
Reversibility: clean
Directive: Keep pre-message skill discovery keyed to session workDir so project-level .claude/skills remain visible before the first turn
Tested: bun test src/server/__tests__/sessions.test.ts; cd desktop && bun run test -- --run src/__tests__/skillsSettings.test.tsx src/components/layout/Sidebar.test.tsx src/__tests__/pages.test.tsx src/pages/ActiveSession.test.tsx; cd desktop && bun run lint
Not-tested: Manual desktop smoke test against the rebuilt .app bundle in the local GUI
2026-04-20 13:36:19 +08:00
程序员阿江(Relakkes)
5cd6b5d07b Prevent desktop Computer Use from stalling on missing approvals and unstable text input
Desktop sessions were missing a visible request_access approval path and could
mis-detect their own app window as an unapproved frontmost target, which caused
Computer Use clicks to fail even after opening the intended app. On macOS, text
entry was also split across inconsistent clipboard and keystroke paths, making
Electron inputs unreliable for Chinese and short strings.

This change adds a desktop approval bridge over the existing session websocket,
renders a dedicated desktop approval modal, threads the real desktop bundle id
into the Computer Use executor, and switches macOS clipboard typing onto the
native pasteboard plus system paste shortcut path. It also makes tool error
results expandable in the desktop chat UI so frontmost-gate failures are fully
visible during debugging.

Constraint: Desktop sessions run the CLI over the SDK websocket path, so Ink tool JSX dialogs are not visible there
Constraint: macOS IME and Electron text inputs are unreliable with pyautogui.write and generic hotkey synthesis
Rejected: Reuse CLI setToolJSX dialogs in desktop mode | no transport for mid-call Ink UI over the SDK bridge
Rejected: Keep shell pbcopy/pbpaste for clipboard typing | inconsistent with NSPasteboard path and less reliable for Chinese text
Confidence: medium
Scope-risk: moderate
Reversibility: clean
Directive: Keep desktop Computer Use approvals and macOS text-entry behavior on a single bridge/path; avoid reintroducing separate CLI-only and desktop-only codepaths for the same action
Tested: python3 -m unittest runtime/test_helpers.py
Tested: bun test src/utils/computerUse/permissions.test.ts src/server/__tests__/conversation-service.test.ts
Tested: cd desktop && bun run test ComputerUsePermissionModal chatStore
Tested: cd desktop && bun run test chatBlocks
Tested: cd desktop && bun run lint
Not-tested: End-to-end manual Computer Use interaction against a live Electron target app on macOS
2026-04-20 12:12:02 +08:00
程序员阿江(Relakkes)
20806f406f chore: update cluade model name 2026-04-18 20:34:56 +08:00
程序员阿江(Relakkes)
9d29d8e32c Keep desktop replies stable across turns and fix OAuth callback routing
The desktop chat store was dropping the previous assistant draft when a new user turn began because streaming text was cleared before it was flushed into message history. At the same time, the desktop OAuth flow was using an unregistered /api/haha-oauth/callback redirect URI, which caused provider authorization failures. This change flushes visible assistant drafts before starting a new turn, restores the OAuth redirect to the registered localhost callback, and adds a root callback handler while keeping the legacy API callback path compatible.

Constraint: The OAuth provider only accepts the registered localhost /callback redirect URI
Rejected: Keep the desktop-specific /api/haha-oauth/callback path | provider rejects unsupported redirect URIs
Rejected: Rely on message_complete to persist visible assistant text | next user turn can begin before that event arrives
Confidence: high
Scope-risk: moderate
Directive: Any UI-visible assistant draft must be flushed into messages before a new user turn resets streaming state
Tested: bun test src/server/__tests__/haha-oauth-service.test.ts src/server/__tests__/haha-oauth-api.test.ts src/server/__tests__/conversation-service.test.ts
Tested: cd desktop && bun run test src/stores/chatStore.test.ts
Tested: cd desktop && bun run lint
Not-tested: Manual end-to-end desktop OAuth login after reinstall
2026-04-18 17:01:53 +08:00
程序员阿江(Relakkes)
d83efc1b04 Prevent desktop OAuth sessions from drifting out of sync
Desktop auth was reporting stale local token files as logged in, could inherit a parent OAuth token after logout, and kept polling even when browser launch failed. This change validates stored tokens through the refresh path, clears inherited OAuth env before spawning the CLI, fetches subscription metadata on initial login, and moves polling start until after the browser opens. Regression tests cover the server and desktop store paths.

Constraint: Desktop CLI must bypass macOS Keychain by injecting env OAuth when available
Rejected: Keep status endpoint file-based only | reports expired sessions as logged in
Confidence: high
Scope-risk: moderate
Directive: Official desktop auth state must be derived from ensureFreshTokens rather than oauth.json presence alone
Tested: bun test src/server/__tests__/conversation-service.test.ts src/server/__tests__/haha-oauth-service.test.ts src/server/__tests__/haha-oauth-api.test.ts
Tested: cd desktop && bun run lint
Tested: cd desktop && bun run test
Not-tested: Manual end-to-end desktop OAuth flow against the live provider
2026-04-18 01:45:18 +08:00
程序员阿江(Relakkes)
669be1fbc6 fix(desktop): align conversationService log format + document deferred import
Code review follow-up on 94b445c:
- console.error 改用 err instanceof Error ? err.message : err (跟 hahaOAuthService 一致)
- dynamic import hahaOAuthService 加注释说明 defer 目的

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 20:19:31 +08:00
程序员阿江(Relakkes)
94b445cd06 feat(desktop): inject CLAUDE_CODE_OAUTH_TOKEN from haha oauth.json
在 buildChildEnv 官方模式分支下,调 hahaOAuthService.ensureFreshAccessToken()
(自动 refresh),成功则通过 env 注入给 CLI 子进程。

CLI 的 src/utils/auth.ts:1260 优先读 CLAUDE_CODE_OAUTH_TOKEN env,完全
不碰 Keychain —— DMG 装的 .app 在 macOS 下也能正常用官方 Claude,不再 403。

buildChildEnv 签名改为 async, 所有 caller 加 await。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 20:12:43 +08:00
程序员阿江(Relakkes)
7421db2857 fix(desktop): align haha-oauth handler with sibling error-handling convention
Code review follow-up on 142eb9cd:
- 加 outer try/catch + errorResponse wrapper (parity with providers.ts)
- 400 响应改用 ApiError.badRequest (shape 跟其他 handler 一致: {error: 'BAD_REQUEST', message})
- test 加上对 error shape 的断言

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 20:06:22 +08:00
程序员阿江(Relakkes)
142eb9cd11 feat(desktop): add /api/haha-oauth REST endpoints
Endpoints:
- POST   /api/haha-oauth/start    — 生成 PKCE,返回 authorize URL
- GET    /api/haha-oauth/callback — 浏览器 redirect 到此,完成 token exchange,
                                    渲染 success/fail HTML 页(自动关闭)
- GET    /api/haha-oauth          — 查询登录状态(不回传 token 本体)
- DELETE /api/haha-oauth          — 登出,清除 token 文件

前端用 start 拿到 authorizeUrl → shell.open(浏览器) → 浏览器走 OAuth → redirect
到 callback → callback 完成后显示 '登录成功,可关闭窗口' 页面。前端并行轮询
/api/haha-oauth 检测 loggedIn=true 后刷新 UI。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 19:59:42 +08:00
程序员阿江(Relakkes)
a1b2530fab fix(desktop): cleanup HahaOAuthService — 删除 dead code、加 fetch timeout、log refresh errors
Code review follow-ups on b0ca5861:
- 删除 dead code exchangeFn/setExchangeFn (completeSession 总走 exchangeWithCustomCallback)
- exchangeWithCustomCallback fetch 加 15s AbortController timeout (parity with client.ts)
- ensureFreshAccessToken refresh 失败时 console.error,不再静默吞异常
- test 删除未用的 mock import
- getOauthConfig 改为 static import
- saveTokens 加注释说明 atomic write 意图

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 19:55:12 +08:00
程序员阿江(Relakkes)
b0ca586190 feat(desktop): add HahaOAuthService for self-managed Claude OAuth
新增 service 层管理桌面端自己的 OAuth token 生命周期:
- PKCE + state 生成(复用 oauth/crypto.ts)
- Token 存 ~/.claude/cc-haha/oauth.json, 权限 0600
- In-memory session map (5min TTL)
- ensureFreshAccessToken: 自动 refresh (5min buffer)

目的: 绕开 macOS Keychain ACL 对未公证 .app 的静默拒绝,
让 DMG 装的 .app 也能正常走官方 Claude OAuth。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 19:38:31 +08:00
程序员阿江(Relakkes)
05cbc0119e fix(desktop): 激活官方时把 CLI 标记为 managed-OAuth 避免 403
桌面端激活"官方"后请求被服务端返回 403 "Request not allowed":
CLI 继承到的 env 里只要残留 ANTHROPIC_API_KEY / ANTHROPIC_AUTH_TOKEN /
apiKeyHelper, isAnthropicAuthEnabled() 就会静默禁用 OAuth, 请求缺
oauth-2025 beta header。

conversationService.buildChildEnv 新增 shouldMarkManagedOAuth(): 只有
cc-haha/settings.json 没写 provider env (即"官方"模式) 时,才给子进程设
CLAUDE_CODE_ENTRYPOINT=claude-desktop, 让 CLI 忽略外部凭据强制走 OAuth。
自定义 provider 场景下不设, 避免 CLI 把 provider 的 AUTH_TOKEN 当作需忽略
的残留、错走 OAuth 打到第三方 endpoint。

详见 src/utils/auth.ts isManagedOAuthContext()。

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 19:44:54 +08:00
程序员阿江(Relakkes)
0b4c742d55 fix(desktop): 修复桌面端多个渲染和权限问题
1. 修复 Tauri CSP 导致 Emotion CSS-in-JS 样式失效的问题
   - Tauri 编译时自动给 style-src 添加 nonce,使 unsafe-inline 失效
   - 添加 dangerousDisableAssetCspModification 阻止 Tauri 修改 style-src
   - 解决 DiffViewer 背景色/缩进等样式丢失

2. 修复 CodeViewer 代码块内容不显示的问题
   - react-shiki 异步加载 WASM 期间返回 null,代码区域空白
   - 添加 CodeArea 组件,纯文本 fallback + MutationObserver 检测加载完成

3. 修复 Bypass 权限模式切换不生效的问题
   - CLI 的 bypassPermissions 需要启动时带 --dangerously-skip-permissions
   - 运行中切换被 CLI 静默拒绝,前端不知情
   - 改为重启 CLI 子进程以正确的参数启动

4. 修复 stream_event tool input JSON 解析失败时 DiffViewer 不渲染
   - content_block_stop 的 JSON parse 失败时暂存到 pendingToolBlocks
   - 由后续 assistant 消息补发完整的 tool input
2026-04-16 10:50:02 +08:00
程序员阿江(Relakkes)
ec436986c5 feat(computer-use): 添加 Windows 平台支持
Computer Use 原本仅限 macOS,现在扩展支持 Windows:
- 新增 win_helper.py,用 win32gui/psutil/pyperclip/screeninfo 替代 macOS 专有 API
- 服务端按平台选择 helper 脚本、venv 路径 (bin→Scripts)、Python 命令 (python3→python)
- 前端权限区域仅在 macOS 上显示,Windows 无需 TCC 权限
- 跨平台测试验证两个 helper 的命令集和协议一致性

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 10:03:27 +08:00
Relakkes Yang
5d243b657a feat(desktop): Windows 自定义标题栏 & 服务端改进
- Windows 上隐藏原生菜单栏和窗口装饰,前端渲染自定义窗口控制按钮(最小化/最大化/关闭)
- macOS 保持原生菜单栏不变(条件编译)
- Sidebar 在 Windows 上不再添加 macOS 红绿灯的额外顶部间距
- 新增 Windows 构建脚本和 NSIS 安装钩子
- 服务端 CORS、会话服务、对话服务改进及测试补充

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-15 21:29:35 +08:00
程序员阿江(Relakkes)
5fdf50436c test: 更新测试用例适配 provider 隔离与新 API
- providers-real.test.ts 重写适配 ModelMapping 对象格式
- e2e 测试适配 cc-haha/settings.json 路径
- settings.test.ts 验证写入隔离
- models.ts 小调整
2026-04-15 14:19:04 +08:00
程序员阿江(Relakkes)
651ab936b7 fix: 停止生成不再显示错误提示 & GrowthBook clientKey 检查
- ws/handler.ts 增加 sessionStopRequested 追踪,用户主动停止时返回 message_complete 而非 error
- growthbook.ts 在 isGrowthBookEnabled() 中先检查 clientKey 是否存在
2026-04-15 14:18:46 +08:00
程序员阿江(Relakkes)
166fe5b676 fix: Computer Use 点击功能修复
- ensureRuntimeFiles() 改为始终同步源文件而非仅缺失时复制
- pre-authorized apps 增加 tier: 'full',与现有 allowedApps 合并而非替换
- normalizeOsPermissions() 将 screenRecording: null 视为非阻塞
- config 路径改为 cc-haha/computer-use-config.json
- mac_helper.py 改进鼠标点击与坐标处理
2026-04-15 14:18:37 +08:00
程序员阿江(Relakkes)
b002447436 fix: provider 隔离与 Claude 官方认证修复
- provider 配置写入 ~/.claude/cc-haha/settings.json,不再污染原版 settings.json
- 子进程 env 剥离 PROVIDER_ENV_KEYS,防止残留 key 传递
- bin/claude-haha 在 CC_HAHA_SKIP_DOTENV=1 时用 --env-file=/dev/null 阻止 Bun 自动加载 .env
- managedEnv.ts 增加 getCcHahaSettingsEnv() 读取隔离配置
- 新增 /api/providers/auth-status 端点,启动时检测认证状态
- AppShell 启动时无认证则跳转 provider 设置页
2026-04-15 14:18:25 +08:00
程序员阿江(Relakkes)
23b31b397a Prevent local team sessions from dropping members and stalling adapters
This bundles the pending desktop/server team-session fixes with the local adapter recovery changes already in the worktree. The team path now keeps teammate membership stable under concurrent spawns, surfaces real teammate identities in the desktop UI, and allows direct interaction with member transcripts. The adapter changes recover automatically when stale thinking signatures invalidate an existing session.

Constraint: Team config writes can happen concurrently while multiple reviewers spawn in parallel

Constraint: Desktop member views must follow mailbox/transcript semantics rather than hijacking teammate runtime sessions

Rejected: Keep relying on config.json alone for member discovery | in-process teammates can be lost after concurrent writes

Rejected: Open teammate sessionIds as normal desktop sessions | would attach a second CLI instead of the running teammate

Confidence: medium

Scope-risk: moderate

Reversibility: clean

Directive: Preserve locked team-file mutation for any future teammate registration path and keep teammate labels sourced from member names before agent types

Tested: bun test src/server/__tests__/teams.test.ts src/server/__tests__/team-watcher.test.ts

Tested: cd desktop && bun run test --run src/stores/chatStore.test.ts src/pages/ActiveSession.test.tsx

Tested: cd desktop && bun run lint

Tested: cd desktop && bun run build

Not-tested: Manual end-to-end validation against a live Agent Teams run in the desktop app
2026-04-14 17:27:07 +08:00
程序员阿江(Relakkes)
9eb3be4b11 perf: optimize recent projects loading with parallel git queries and caching
目录选择器每次打开都串行执行大量 git 子进程导致卡顿,现改为并行查询 + 前后端双层 30s 缓存,选择新目录时自动失效缓存。

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 16:02:35 +08:00
程序员阿江(Relakkes)
8888e1c3fb chore: comprehensive code review fixes — security, perf, leaks, quality, docs
- security: XSS sanitization with DOMPurify in Markdown/Mermaid/PermissionDialog;
  path whitelist in filesystem API; fake keys in test/config files
- perf: fine-grained Zustand selectors in Sidebar/StatusBar/ContentRouter;
  50ms throttle on streaming deltas; React.memo + useMemo in MessageList;
  useRef for frequent keyboard shortcut state; AbortController 30s timeout
- leaks: WS session TTL timers (5-min cleanup on close); batch splice for
  sdkMessages/stderrLines; folderPath validation in cronScheduler
- quality: optimistic update rollback in settingsStore; error state in
  providerStore/teamStore; i18n for all hardcoded English strings
- docs: desktop architecture and features docs updated; VitePress nav fixed

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 22:27:17 +08:00
程序员阿江(Relakkes)
8617a4b9c9 feat: scheduled task IM notification + UI fixes
- Add notification config to CronTask (enabled + channels)
- New notificationService: push task results to Feishu/Telegram on completion
- Feishu uses Schema 2.0 interactive card for proper Markdown rendering
- Telegram uses Bot API sendMessage with Markdown parse mode
- NewTaskModal: notification toggle + channel checkboxes with config validation
- Fix: API layer now passes notification field through on task creation
- Fix: View conversation button uses tabStore instead of legacy setActiveView
- Fix: bypass permission dialog shows selected folder path instead of ~

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 15:42:44 +08:00
程序员阿江(Relakkes)
bfafd26fb6 fix: batch resolve 5 issues from Feishu bug tracker
- fix(desktop): Settings Agents/Skills page layout overflow at narrow widths
  Shift header grid breakpoint md→xl, summary cards sm→3col, add min-w-0/truncate

- fix(desktop): TabBar tab style — remove border-r separators, use bg-only active state
  Drop ::after indicator and inter-tab borders; active tab distinguished by surface bg

- feat(desktop): IM Adapters page — horizontal tabs with Feishu first, Telegram second
  Replace vertical stack with tablist; add ImTabButton with aria-selected + focus-visible

- fix(server): bundled IM session cwd resolves to / instead of selected project
  Root cause: preload.ts chdir(CALLER_DIR) inherits '/' from Tauri-spawned sidecar.
  Fix: pin CALLER_DIR and PWD to session workDir in conversationService spawn env.
  Add diagnostic logs at sessionService, ws/handler, and conversationService.

- fix(feishu): StreamingCard shows duplicate "thinking" indicators
  Merge static loading element into streaming_content; renderedText() controls state.

- test(adapters): add 5 ImageBlockWatcher edge-case unit tests (reset, relative path,
  multi-image chunk, malformed data URI)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 13:36:14 +08:00
程序员阿江(Relakkes)
3c5549e221 experiment(desktop): merge server + cli into one sidecar binary
Replaces the two ~65MB bun-compiled sidecar binaries with a single
~66MB merged binary. The bun runtime + shared dependency code (anthropic
SDK, MCP SDK, ws, undici, etc) was previously duplicated across both —
merging eliminates that duplication entirely.

Combined with the previous P0 commit (static-import inlining + drop
src/ + node_modules/ from Resources), this brings the macOS .app from
the original 435MB baseline down to 87MB (-80%), and the DMG from 113MB
to 37MB (-67%).

Final breakdown of the 87MB .app:
  Contents/MacOS/claude-sidecar         66MB   (was 57+57=114MB)
  Contents/MacOS/claude-code-desktop    18MB   (Tauri Rust main)
  Contents/Resources/icon.icns           2MB
  + plist + frameworks                  ~1MB

This is essentially the floor — bun runtime + Tauri main + minimum
overhead. Going lower would require swapping toolchains.

Implementation
==============

* desktop/sidecars/claude-sidecar.ts (new): single entrypoint that
  takes a positional mode argument ("server" or "cli") then dispatches
  via `await import('../../src/server/index.ts').startServer()` or
  `await import('../../src/entrypoints/cli.tsx')`. Same env / argv setup
  pattern as the old launchers.
* desktop/sidecars/server-launcher.ts + cli-launcher.ts: deleted.
* desktop/scripts/build-sidecars.ts: compiles only claude-sidecar now.
* desktop/src-tauri/tauri.conf.json: externalBin → ["binaries/claude-sidecar"]
* desktop/src-tauri/src/lib.rs: spawns sidecar with leading "server"
  positional arg.
* src/server/services/conversationService.ts resolveBundledCliPath /
  resolveCliArgs: when current process is claude-sidecar, reuses the
  same exe and spawns it with leading "cli" positional arg. Backward
  compat path for old claude-server / claude-cli pair preserved for the
  bin/claude-haha dev mode.

Verification
============

* claude-sidecar cli --version → 999.0.0-local (Claude Code) ✓
* claude-sidecar cli --help → full Commander spec ✓
* claude-sidecar server --port N → HTTP listening, CronScheduler running ✓
* All three above run in /tmp with no src/ or node_modules/ on disk
* bun test on src/ → 358 pass / 45 fail / 1 error, identical to baseline
  (44 fails are pre-existing on main, unrelated to this change)
* Full DMG round-trip via build-macos-arm64.sh succeeds; new .app
  installs cleanly in /Volumes/

Bundle size summary (vs original baseline)
==========================================

  metric              baseline   final      delta
  .app total          435 MB     87 MB      -348 MB (-80%)
  .dmg                113 MB     37 MB      -76 MB  (-67%)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 00:10:47 +08:00
程序员阿江(Relakkes)
662485c3eb experiment(desktop): static-import sidecars + drop src/ + node_modules/ from bundle
Cuts the macOS .app from 435MB → 152MB (-65%) and the DMG from 113MB → 60MB
(-47%) by inlining src/server and src/entrypoints/cli into the bun-compiled
sidecar binaries instead of dynamic-importing them from disk at runtime.

Architectural change
====================

Before:
  desktop/sidecars/server-launcher.ts → bun build --compile (≈57MB shell)
    └─ at runtime: dynamic file:// import of <appRoot>/src/server/index.ts
       which transitively requires ALL of src/ + the entire root node_modules/
       to be shipped as Resource. tauri.conf.json copied 254M of node_modules
       and 47M of src/ into Contents/Resources/app/ on every build.

After:
  desktop/sidecars/server-launcher.ts → bun build --compile (≈65MB)
    └─ uses `await import('../../src/server/index.ts')` with a literal
       specifier so bun's bundler walks the whole graph statically and
       inlines everything into the binary.

  Same treatment for cli-launcher.ts → src/entrypoints/cli.tsx.

Resolver gymnastics
===================

This fork carries dozens of ant-internal feature() gated require/import
calls referencing modules that simply don't exist on disk
(cachedMicrocompact, devtools, proactive, coordinator, etc). Bun's resolver
walks the static dep graph BEFORE bun:bundle macro DCE, so even though
the dead branches never execute at runtime, they still fail to resolve
at compile time.

Two complementary mechanisms:

1. desktop/scripts/scan-missing-imports.ts walks src/, regex-greps every
   relative import / require / type-import specifier, and writes a Proxy
   noop stub for any target that doesn't exist on disk. Stubs are tagged
   with "@generated stub from scan-missing-imports" for idempotency. Text
   resources (.md / .txt / .json) get appropriate format-specific stubs.
   Runs as a pre-step inside build:sidecars.

2. desktop/scripts/build-sidecars.ts adds an `external: [...]` list for
   bare-package optional deps not in package.json (OTLP exporters,
   @aws-sdk/*, @anthropic-ai/{bedrock,vertex,foundry,mcpb}-sdk,
   @azure/identity, fflate, turndown, sharp, react-devtools-core).
   These remain runtime imports, fail benignly when their gating env
   var or feature flag is off.

Tauri side
==========

- desktop/src-tauri/tauri.conf.json: dropped all `resources` entries.
  Was 7 entries totaling ≈301MB. Now `{}`.
- desktop/src-tauri/src/lib.rs `resolve_app_root` no longer calls
  BaseDirectory::Resource (the app/ resource dir doesn't exist anymore);
  instead returns the directory of the current sidecar exe. The launchers
  still accept --app-root for backward compat with conversationService's
  CLI subprocess spawn.

Optimisations
=============

- bun build now uses minify whitespace+identifiers+syntax. Saved another
  ≈16MB across both binaries (server: 72MB→65MB, cli: 75MB→66MB).

Bonus fix
=========

src/services/remoteManagedSettings/index.ts had a typo importing
'./securityCheck.jsx' instead of '.js'. Bun's runtime resolver tolerated
it; bun build didn't.

Verification
============

- Both binaries boot successfully in /tmp with no src/ or node_modules/
  on disk. Verified `claude-cli --version` returns the build version,
  `claude-cli --help` prints the full Commander spec, and claude-server
  starts CronScheduler + listens on the requested port.
- bun test on src/ shows 358 pass / 45 fail / 2 errors vs main baseline
  of 359 / 44 / 2 — net 0 new failures (1 different flake direction).
  All 44 baseline failures pre-exist on main and are unrelated.
- Full DMG round-trip via build-macos-arm64.sh succeeds; new bundle
  installs cleanly in /Volumes/.

Bundle size summary
===================

  metric              baseline   after P0   delta
  Resources/app/      301 MB     0 MB       -301 MB
  MacOS/claude-server  57 MB     65 MB      +8 MB
  MacOS/claude-cli     57 MB     66 MB      +9 MB
  MacOS/claude-code-desktop  18 MB  18 MB   —
  ─────────────────────────────────────────────
  .app total          435 MB     152 MB     -283 MB (-65%)
  .dmg                113 MB     60 MB      -53 MB (-47%)

Generated stub files (173 of them under src/) are committed for
reproducibility — the scanner is idempotent and will re-create them
identically on every build, but tracking them avoids dirty working trees
on first compile.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 00:05:39 +08:00
程序员阿江(Relakkes)
635a966c3e fix(desktop): unblock rollout with reliable session and IM flows
This folds together the desktop-side fixes needed before broader rollout.
Session resume no longer deadlocks waiting on init, Mermaid and inline image
output render inside chat, task and sub-agent state stay visible during
execution, local build/release paths are safer, and Feishu/Telegram now expose
lightweight mobile commands (/help, /status, /clear) without adding a new
adapter-specific protocol.

Constraint: Desktop releases must publish updater artifacts from non-draft GitHub releases
Constraint: IM commands need short, phone-friendly responses and low operational complexity
Rejected: Add a dedicated IM command API surface | re-used existing slash commands and session/task REST endpoints to keep adapters thin
Rejected: Wait for task_update push events in WebUI | added low-risk polling because the current frontend ignores that event path
Confidence: medium
Scope-risk: broad
Reversibility: clean
Directive: Keep IM command replies terse and mobile-first, and merge local fallback slash commands when server-provided lists are partial
Tested: cd desktop && bun x vitest run src/components/chat/MermaidRenderer.test.tsx src/components/markdown/MarkdownRenderer.test.tsx
Tested: cd desktop && bun x vitest run src/components/chat/composerUtils.test.ts src/pages/ActiveSession.test.tsx src/stores/chatStore.test.ts
Tested: cd desktop && bun run lint
Tested: bun test src/server/__tests__/conversations.test.ts --test-name-pattern "SDK init arrives only after the first user turn" --timeout 60000
Tested: cd adapters && bun test common/ feishu/ telegram/
Tested: cd adapters && bunx tsc --noEmit
Not-tested: Full GitHub Actions release run on all three desktop platforms
Not-tested: Local DMG packaging end-to-end on Apple Silicon
Not-tested: Real Feishu/Telegram device sessions against a live adapter process
2026-04-10 16:41:59 +08:00
程序员阿江(Relakkes)
98a24f99b4 feat(proxy): add multi-protocol proxy for OpenAI-compatible providers
Add a protocol-translating reverse proxy that allows using OpenAI-compatible
API providers (DeepSeek, OpenRouter, Groq, etc.) with Claude Code.

The proxy intercepts Anthropic Messages API requests from the CLI, transforms
them to OpenAI Chat Completions or Responses API format, forwards to the
upstream provider, and transforms streaming/non-streaming responses back.

Key features:
- Request transform: Anthropic Messages → OpenAI Chat/Responses
- Response transform: OpenAI → Anthropic (streaming SSE + non-streaming)
- Provider-agnostic reasoning support (reasoning_content, thinking_blocks,
  reasoning fields from DeepSeek, OpenAI o-series, GLM-5, Groq, etc.)
- Event queue pattern for correct Anthropic SSE event ordering
- Two-step test: ① connectivity check ② full proxy pipeline validation
- Desktop UI: API format selector, two-step test results display
- License attribution for cc-switch (MIT, Jason Young)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 00:33:26 +08:00
程序员阿江(Relakkes)
824b1967ff fix(adapters): fix IM message delivery issues and improve UX
- Fix WebSocket race condition: wait for connection to open before
  sending first message, preventing silent message loss after pairing
  or project selection
- Fix response text appearing above tool calls: finalize placeholder
  before tool_use blocks so post-tool text gets a new message
- Remove noisy tool_use and tool_result messages from IM output;
  thinking indicator is preserved, details visible in Desktop
- Fix /new command using default project dir instead of always showing
  project picker
- Fix duplicate projects in list by deduping on realPath instead of
  projectPath
- Improve formatToolUse with human-readable summaries for common tools
- Add send failure feedback to users

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 20:40:07 +08:00
程序员阿江(Relakkes)
211226c7a1 feat(agents): update API types, store, i18n, and tests for new agent model
- Update AgentDefinition type with agentType, source, isActive, modelDisplay fields
- Refactor agentStore to support activeAgents/allAgents with cwd parameter
- Add i18n strings for agent browser UI (source labels, summary, status)
- Update server agents API with serialization helpers and override resolution
- Update tests to match new agent data structure

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 16:45:51 +08:00
程序员阿江(Relakkes)
5911388626 fix(skills): polish desktop browser layout and rendering
Improve the desktop Skills browser so SKILL.md metadata renders cleanly and the settings view uses space like a real document browser. Add coverage for the new detail, markdown, and i18n behavior.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-09 14:59:33 +08:00
程序员阿江(Relakkes)
039ad8afd7 feat(skills): add server API, types, client, store, and i18n
- Server: GET /api/skills (list) and GET /api/skills/detail (tree + files)
- Desktop: type definitions, API client, Zustand store
- i18n: EN/ZH translation keys for Skills tab

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 11:30:16 +08:00
程序员阿江(Relakkes)
91b4d16dc5 Restore sub-agent context in the desktop chat transcript
The desktop chat view flattened Agent tool activity, which made sub-agent work
hard to follow and separated key evidence from the main conversation. This
change threads parent tool linkage through the server bridge and desktop store,
renders dispatched sub-agents as grouped cards with nested tool activity, and
moves long final outputs into a markdown preview dialog so the main transcript
stays readable on narrow layouts.

Constraint: Existing sessions and live websocket events both needed to preserve parent-child relationships
Rejected: Add brand-new subagent websocket event types | unnecessary protocol expansion when parent linkage already existed upstream
Rejected: Inline full sub-agent markdown in the card body | too cramped for narrow desktop chat layouts
Confidence: medium
Scope-risk: moderate
Reversibility: clean
Directive: Keep Agent card summaries compact; route long-form sub-agent output through the preview dialog unless the main chat layout is widened substantially
Tested: cd desktop && bun run test -- MessageList.test.tsx chatStore.test.ts
Tested: cd desktop && bun run lint
Tested: bun test src/server/__tests__/sessions.test.ts -t should\ reconstruct\ parent\ agent\ tool\ linkage\ from\ parentUuid\ chains
Not-tested: Full end-to-end visual verification against live CLI sessions with sub-agent text/thinking nested inline
2026-04-09 00:04:40 +08:00