Electron 迁移任务清单
For agentic workers: 按任务顺序执行。每个任务完成后先跑该任务列出的核对命令,再进入下一任务。不要跳过打包壳 smoke,也不要把浏览器/Vite smoke 当作 Electron 壳验收。
目标: 将桌面端 host runtime 从 Tauri 2 迁移到 Electron,同时保持 React 层、server/sidecar、自动更新、系统交互、通知、构建发布和 Computer Use 能力可用。 架构: 先抽象 desktopHost contract,再并行实现 Tauri 与 Electron,最后切换构建发布链路。保留本地 Bun server + REST/WebSocket 边界,不把会话、聊天、workspace、team 业务协议改成 Electron IPC。 技术栈: React 18、Vite、Zustand、Bun、Electron、electron-builder/electron-updater、现有 sidecar、现有质量门禁。
当前同步状态
执行记录(2026-06-01):
- 已按本地
main重新同步当前迁移工作区:当前分支feat/electron-migration-main-sync-2392已快进到本地main的最新提交后再恢复 Electron 迁移改动。 - 已在当前工作区内解决同步冲突,重点文件包括
desktop/package.json、desktop/scripts/build-macos-arm64.sh、desktop/src-tauri/resources/preview-agent.js、desktop/src/components/workspace/WorkspaceFileOpenWith.test.tsx、desktop/src/lib/previewEvents.ts和desktop/src/lib/previewEvents.test.ts。 - 冲突解决后已重建 preview agent,并运行 targeted tests 与 Electron package dir 构建;后续迭代均基于同步后的本地
main。 - packaged Electron renderer 使用
file://.../app.asar/dist/index.html,真实模型 smoke 暴露出 H5 token mode 下 WebSocket 会因Origin: file://被拒绝;已在 server CORS/H5 access policy 中把file://纳入本地桌面可信来源,并补回归测试。
Phase 0:迁移前基线
1. 冻结当前 Tauri 行为基线
涉及文件:
- 只读:
desktop/src/** - 只读:
desktop/src-tauri/** - 只读:
scripts/quality-gate/**
步骤:
- [x] 运行
git status --short,确认当前工作区是否有无关改动。 - [x] 运行
bun run check:policy。 - [x] 运行
bun run check:desktop。 - [x] 运行
bun run check:server。 - [x] 运行
bun run check:coverage。 - [ ] 有 live provider 时运行
bun run quality:gate --mode baseline --allow-live --provider-model <provider:model[:label]>。 - [x] 记录 quality report 路径和失败项;失败时先修现有基线,不进入迁移。
执行记录(2026-05-31):
bun run check:policy通过。bun run check:desktop通过;首次缺少 desktop 依赖,已在desktop/执行bun install后复跑通过。bun run check:server通过。bun run check:coverage初次运行未通过;归因后在adapters/执行bun install修复grammy缺包环境问题,并补足 changed-line 覆盖率。- 后续
bun run check:coverage复跑曾因本机 WeChat 占用随机端口24023导致src/server/__tests__/h5-access-auth.test.ts超时;已把该测试的随机端口选择改为先探测可绑定端口。 - 最新
bun run check:coverage通过;report 为artifacts/coverage/2026-05-31T13-15-40-522Z/coverage-report.md,summary 为passed=5 failed=0,changed-lines coverage 为90.67% (204/225)。
通过标准: 现有 Tauri 主干的 desktop/server/coverage/baseline 状态可复现。 阻断条件: 当前主干已有红灯且未归因。
Phase 1:Host Adapter Contract
2. 新增 host adapter 类型与 browser fallback
创建:
desktop/src/lib/desktopHost/types.tsdesktop/src/lib/desktopHost/browserHost.tsdesktop/src/lib/desktopHost/index.tsdesktop/src/lib/desktopHost/contract.test.ts
步骤:
- [x] 定义
DesktopHost接口,至少覆盖runtime/server URL、updates、notifications、dialogs、shell、window、terminal、preview、appMode。 - [x] 在
browserHost中保留 H5/browser fallback:没有桌面能力时返回明确错误或 no-op。 - [x] 在 contract test 中固定每个方法的 payload 和错误语义。
- [x] 运行
cd desktop && bun run test -- src/lib/desktopHost/contract.test.ts --run。
执行记录(2026-05-31):
- 新增
desktop/src/lib/desktopHost/types.ts、browserHost.ts、index.ts、contract.test.ts。 - 先运行 contract test 得到预期红灯(缺少
browserHost模块),补实现后desktopHost/contract.test.ts6 tests 通过。
通过标准: host adapter 类型能表达当前所有 Tauri command/plugin 能力。 阻断条件: 仍需要 renderer 直接 import Tauri API 才能表达某个能力。
3. 实现 Tauri host adapter
创建:
desktop/src/lib/desktopHost/tauriHost.ts
修改:
desktop/src/lib/desktopRuntime.tsdesktop/src/api/terminal.tsdesktop/src/stores/updateStore.tsdesktop/src/lib/desktopNotifications.tsdesktop/src/lib/previewBridge.tsdesktop/src/lib/previewEvents.tsdesktop/src/lib/appZoom.tsdesktop/src/stores/adapterStore.tsdesktop/src/stores/settingsStore.ts- dialog/shell 调用组件:
DirectoryPicker.tsx、Sidebar.tsx、Settings.tsx、TerminalSettings.tsx、ComputerUseSettings.tsx、WorkspaceFileOpenWith.tsx、聊天链接打开组件
步骤:
- [x] 把
@tauri-apps/api/core.invoke包进tauriHost.commands.invoke或具体方法。 - [x] 把 Tauri
listen包进desktopHost.events。 - [x] 把 dialog/shell/window/update/notification 调用全部迁到
tauriHost。 - [x] 运行
rg "@tauri-apps|__TAURI_INTERNALS__|window\\.__TAURI__|from '@tauri" desktop/src。 - [x] 确认生产代码只在
desktop/src/lib/desktopHost/tauriHost.ts命中。 - [x] 运行
bun run check:desktop。
通过标准: renderer 业务文件不再知道 Tauri API。 阻断条件: 任一 store/component 仍直接动态 import @tauri-apps/*。
当前进度(2026-05-31):
- 新增
desktop/src/lib/desktopHost/tauriHost.ts,先迁入get_server_url运行时调用。 desktop/src/lib/desktopRuntime.ts已改为通过desktopHost选择 Electron preload host、Tauri host 或 browser fallback;新增回归测试确保window.desktopHost优先于 H5/browser fallback。- 已迁移
desktop/src/api/terminal.ts、desktop/src/lib/previewBridge.ts、desktop/src/lib/previewEvents.ts、desktop/src/lib/appZoom.ts、desktop/src/lib/desktopNotifications.ts、desktop/src/stores/updateStore.ts、desktop/src/stores/adapterStore.ts、desktop/src/stores/settingsStore.ts的 runtime/terminal/preview/zoom/notification/update/adapter restart/app mode 调用到desktopHost。 desktopHost现在覆盖app.getVersion、commands.invoke、events.listen、webview.onDragDropEvent、dialogs.open/save、shell.open、notifications.permission/request/send/onAction、window.minimize/toggleMaximize/close/startDragging/focus/requestAttention/isMaximized/onResized/onNativeMenuNavigate、updates.check/prepare/cancel/relaunch等 Tauri 能力。- 已运行 focused tests:
desktopRuntime.test.ts、desktopHost/contract.test.ts、terminal.test.ts、previewBridge.test.ts、previewEvents.test.ts、appZoom.test.ts、desktopNotifications.test.ts、updateStore.test.ts、adapterStore.test.ts、settingsStore.test.ts、AppShell.test.tsx、WindowControls.test.tsx、ComputerUseSettings.test.tsx全部通过。 - 继续迁移了 dialog/shell/window/menu 组件层、file drop webview、official login/open-with 等打开路径:
DirectoryPicker、composerAttachments、TerminalSettings、ComputerUseSettings、Settings、Sidebar、TabBar、WindowControls、AppShell、WorkspaceFileOpenWith、AssistantMessage、AssistantOutputTargetCard、CurrentTurnChangeCard。 - 2026-05-31 扫描结果:业务 renderer 生产代码不再直接 import
@tauri-apps/*;剩余 Tauri 命中为desktopHost自身、runtime detection 类型声明和测试 mock。生产路径排除desktopHost后扫描为空:rg -n "@tauri-apps|__TAURI_INTERNALS__|window\\.__TAURI__|from '@tauri" desktop/src --glob '!**/*.test.ts' --glob '!**/*.test.tsx' --glob '!**/lib/desktopHost/**' --glob '!src-tauri/**'。 bun run check:desktop通过:desktoptsc --noEmit、Vitest 全量 146 test files / 1127 tests passed,production build 成功;现有 Reactact(...)warnings 仍为非阻断输出。
Phase 2:Electron 最小壳
4. 新增 Electron main/preload 骨架
创建:
desktop/electron/main.tsdesktop/electron/preload.tsdesktop/electron/ipc/channels.tsdesktop/electron/ipc/capabilities.tsdesktop/electron/tsconfig.json
修改:
desktop/package.json- 根
package.json
步骤:
- [x] 新增
electron:dev、electron:build、check:electron脚本。 - [x]
BrowserWindow使用 preload,保持contextIsolation,不启用 renderer Node。 - [x] preload 暴露
window.desktopHost,不暴露通用ipcRenderer。 - [x]
capabilities.ts枚举允许的 IPC channel 和 payload validator。 - [x] 运行
bun run check:electron。
执行记录(2026-05-31):
- 新增
desktop/electron/main.ts、preload.ts、ipc/channels.ts、ipc/capabilities.ts、ipc/capabilities.test.ts、electron/tsconfig.json、scripts/electron-dev.ts。 BrowserWindow配置为preload + contextIsolation: true + nodeIntegration: false + sandbox: true;preload 只通过contextBridge.exposeInMainWorld('desktopHost', ...)暴露 typed host contract。check:electron通过:Electron IPC validator 测试 3/3 通过,electron-dist/main.cjs与electron-dist/preload.cjs构建成功。electron:build通过:rendererdesktop/dist和 Electron CJS entrypoints 均构建成功。- 短时 Electron 启动 smoke 已尝试;当前机器首次运行
electron会触发 Electron binary 下载,下载未在本轮完成,因此真实窗口启动验证保留到下一轮 runtime/server bridge smoke。
通过标准: Electron 壳能启动并加载 Vite/dev 或 desktop/dist。 阻断条件: renderer 需要 Node API 或 Electron API 才能工作。
5. 实现 Electron runtime/server bridge
创建:
desktop/electron/services/sidecarManager.tsdesktop/electron/services/serverRuntime.ts
步骤:
- [x] 复刻
start_server_sidecar:保留动态端口、host、config、startup log、超时错误。 - [x] 复刻 adapter sidecar 启动和
restart_adapters_sidecar。 - [x] 保留
CLAUDE_CONFIG_DIR、CC_HAHA_APP_PORTABLE_DIR、ADAPTER_SERVER_URL注入。 - [x] 提供
get_server_url等价 IPC。 - [x] 确认 renderer 仍通过
desktop/src/api/client.ts和 WebSocket manager 访问会话/聊天/workspace/team,不新增这些业务的 IPC handler。 - [x] 运行
bun run check:electron。 - [x] 打开 Electron dev app,确认首页能连上 local server。
执行记录(2026-05-31):
- 新增
desktop/electron/services/sidecarManager.ts和serverRuntime.ts;Electron main 在 ready 阶段启动 server sidecar,runtime.getServerUrl()通过 IPC 返回动态 loopback URL。 sidecarManager复用现有desktop/src-tauri/binaries/claude-sidecar-<triple>,server 参数保持server --app-root <path> --host 0.0.0.0 --port <dynamic>,adapter 参数保持adapters --app-root <path> --feishu/--telegram/--wechat/--dingtalk。- 环境变量保留
CLAUDE_CONFIG_DIR、XDG_CACHE_HOME、CLAUDE_H5_AUTO_PUBLIC_URL、CLAUDE_H5_DIST_DIR;adapter 注入ADAPTER_SERVER_URL=ws://<dynamic>。 - headless smoke 通过:
bun run build:sidecars后用ElectronServerRuntime启动 server,GET /health返回 200,随后stopAll()停止 server/adapters 子进程。 - 2026-06-01 Electron dev 壳已由 Computer Use 多轮复测:renderer 加载
localhost:1420/,main process 自动启动 local server/sidecar,首页、设置页和会话页均可通过 server API/WebSocket 工作。
通过标准: Electron app 不依赖外部手动启动 server。 阻断条件: 需要用户先运行 SERVER_PORT=... bun run src/server/index.ts 才能使用桌面端,或迁移方案开始绕过 local server 直接重写 session/chat IPC。
Phase 3:系统能力迁移
6. 迁移文件选择、保存、外链打开
创建/修改:
desktop/electron/services/dialogs.tsdesktop/electron/services/shell.tsdesktop/src/lib/desktopHost/electronHost.ts
步骤:
- [x]
openFile、openDirectory、saveFile映射到 Electron dialog。 - [x]
openExternal限制 URL scheme,openPath限制为明确来自文件选择或 workspace 的路径。 - [x] 更新 adapter contract tests。
- [x] 运行
bun run check:desktop && bun run check:electron。 - [x] 手动 smoke:选择工作目录、选择附件、选择 Python 路径、打开外链。
执行记录(2026-05-31):
- 新增
desktop/electron/services/dialogs.ts与shell.ts;dialog options 映射到 ElectronshowOpenDialog/showSaveDialog,shell URL 只允许http: / https: / mailto:。 DesktopHost.shell拆分为open(url)与openPath(path);workspace/open-with 本地文件路径改走openPath,普通网页/OAuth/通知设置等外链继续走open。- 新增
desktop/src/lib/desktopHost/electronHost.ts,preload 改为复用该 typed host factory;IPC payload 在 preload 进入ipcRenderer.invoke前先校验。 - Focused tests 通过:
electron/services/shell.test.ts、dialogs.test.ts、electronHost.test.ts、desktopHost/contract.test.ts、WorkspaceFileOpenWith.test.tsx。 bun run check:electron通过:16 tests passed,Electron main/preload 构建成功。bun run check:desktop通过,现有 React/Tauri 主干未被openPathcontract 破坏。- 2026-06-01 Electron dev 壳 Computer Use 复测附件选择:点击 composer
添加文件或图片打开 macOS 原生打开面板,选择/Users/nanmi/cc-haha-cua-attachment-smoke.txt后回到应用,composer 显示cc-haha-cua-attachment-smoke.txt附件 chip。 - 2026-06-01 Electron dev 壳 Computer Use 复测 Python 路径选择:在 Computer Use 设置中点击
选择打开 macOS 原生选择 Python 解释器面板,选择/Users/nanmi/cc-haha-cua-python3-smoke后应用解析并保存为/opt/homebrew/Cellar/python@3.14/3.14.5/Frameworks/Python.framework/Versions/3.14/bin/python3.14;随后恢复自动检测,/api/computer-use/authorized-apps返回pythonPath: null。 - 2026-06-01 Electron dev 壳 Computer Use 复测外链:点击关于页 GitHub 项目卡片后,系统浏览器 Google Chrome 被拉到前台,地址栏为
github.com/NanmiCoder/cc-haha;Electron renderer 仍停留在localhost:1420/,未在应用内导航外链。
通过标准: 所有原 plugin-dialog 和 plugin-shell 用户路径可用。 阻断条件: 任一路径绕过 preload 或接受未校验目标。
7. 迁移窗口、托盘、菜单和单实例
创建/修改:
desktop/electron/services/windows.tsdesktop/electron/services/tray.tsdesktop/electron/services/menu.tsdesktop/electron/services/singleInstance.ts
步骤:
- [x] 实现 minimize/toggleMaximize/close/startDragging。
- [x] 实现关闭隐藏到托盘、托盘 show/quit。
- [x] 实现 macOS About/Settings 菜单并发送
native-menu-navigate等价事件。 - [x] 实现窗口位置/尺寸持久化和 monitor 可见性保护。
- [x] 实现
app.requestSingleInstanceLock(),第二实例显示主窗口。 - [x] 运行
bun run check:electron。 - [ ] 打包 app smoke:关闭窗口、托盘恢复、菜单打开设置页、重启后窗口仍可见。
执行记录(2026-05-31):
- 新增
desktop/electron/services/windows.ts、tray.ts、menu.ts、singleInstance.ts。 - Electron main 现在启动前申请 single-instance lock;重复启动会 show/focus 主窗口。
- 主窗口关闭默认隐藏到托盘,托盘菜单提供
Show Claude Code Haha和Quit Claude Code Haha;显式 quit 才停止 sidecar 并退出。 - 窗口位置/尺寸/maximized 状态写入
window-state.json,优先使用CLAUDE_CONFIG_DIR,恢复前会验证尺寸和 display/workArea 可见性。 - 原生菜单发送
desktop:window:native-menu-navigate,保持 renderer 现有 settings/about 路由入口。 - Electron 先不声明自定义 Windows chrome 能力:
windowControls=false,renderer 不渲染自定义窗口按钮,也不会把空白 tab/sidebar 区当成可拖拽窗口区域;后续若启用 frameless window,需要同时实现真实拖拽。 bun run check:electron通过:26 tests passed,Electron main/preload 构建成功。- 2026-06-01 Electron dev 壳 Computer Use 复测窗口关闭/恢复:点击 macOS 关闭按钮后 Electron 进程仍在
list_apps中保持 running,主窗口消失;通过 macOS app activation 路径重新激活同一 Electron app 后,Computer Use 再次看到Claude Code Companion主窗口和localhost:1420/renderer。Computer Use 当前不能稳定枚举 Dock,因此本轮验证的是与 Dock 点击等价的 app activation/show 主窗口路径。 - 2026-06-01 packaged app Computer Use 复测菜单与窗口生命周期:在
desktop/build-artifacts/electron/mac-arm64/Claude Code Haha.app隔离实例中,通过 macOS app menu 点击Settings...后 renderer 打开设置页;点击关闭按钮后 Computer Use 返回noWindowsAvailable,System Events 显示同一 PIDcount=0且进程仍存活;随后用 app activation 恢复,Computer Use 再次读取到Claude Code Companion设置页窗口。继续通过 app menuQuit退出后,隔离配置写入window-state.json;用同一CLAUDE_CONFIG_DIR和--user-data-dir重启,Computer Use 成功读取新 PID 的 packagedfile://.../app.asar/dist/index.html主窗口,System Events 显示count=1 names=Claude Code Companion。该轮覆盖 packaged 菜单打开设置、关闭隐藏、activation 恢复和重启后窗口仍可见;真实 tray 图标点击仍需后续实机/可枚举 tray 环境复验。
通过标准: macOS/Windows/Linux 主窗口生命周期等价。 阻断条件: 关闭行为会误退出或窗口状态可能恢复到屏幕外。
8. 迁移通知
创建/修改:
desktop/electron/services/notifications.tsdesktop/src/lib/desktopNotifications.tsdesktop/src/lib/desktopHost/contract.test.ts
步骤:
- [x] 实现权限状态、请求权限、发送通知。
- [x] 实现通知点击回跳并传递 target。
- [x] Windows 保留打开系统通知设置入口。
- [x] macOS 若 Electron
Notification无法满足权限/点击语义,保留 native bridge 或补原生模块。 - [x] 运行
bun run check:electron。 - [x] 运行
bun run check:desktop。 - [ ] 打包 app smoke:发送通知、点击通知、跳回目标 session。
执行记录(2026-05-31):
- 新增
desktop/electron/services/notifications.ts,使用 Electron main-processNotification发送系统通知并监听click。 - 通知点击通过
desktop:notification:action发送{ id, extra, target, action: 'click' },renderer 继续复用现有installDesktopNotificationClickListenertarget 解析和导航。 - Electron
commandInvoke兼容现有 renderer 的 legacy 通知入口:macos_notification_permission_state、macos_request_notification_permission、macos_send_notification、plugin:notification|is_permission_granted、plugin:notification|request_permission。 - Windows 通知设置入口通过 allowlisted
ms-settings:notifications打开;macOS 系统通知设置 URL 仍限制在 allowlist。 - 参考 Electron 官方 Notification 文档:main process 使用
new Notification(...).show(),点击通过notification.on('click', ...)处理;Electron 没有独立的桌面通知 request-permission API,因此 Electron host 将Notification.isSupported()映射为 host permission state。 bun run check:electron通过:32 tests passed,Electron main/preload 构建成功。bun run check:desktop通过:141 test files / 1103 tests passed,production build 成功;现有 Reactact(...)warnings 仍为非阻断输出。
执行记录(2026-06-01):
- 新增
desktop/electron/services/notificationSmoke.ts,提供显式环境变量触发的 Electron 通知 smoke hook:设置CC_HAHA_ELECTRON_NOTIFICATION_SMOKE_SESSION_ID=<session-id>后,main process 会延迟发送带{ type: 'session', sessionId }target 的真实 ElectronNotification。默认不启用,不影响正常启动和生产行为。 - 新增
desktop/electron/services/notificationSmoke.test.ts,锁定默认不发送、target payload 透传和 delay clamp;cd desktop && bun test electron/services/notificationSmoke.test.ts electron/services/notifications.test.ts electron/services/windows.test.ts通过:16 tests passed。 - Computer Use 真实 OS 点击复测:带 smoke env 启动 Electron dev 壳并关闭主窗口后,Electron 仍 running;但本机 Computer Use 对
/System/Library/CoreServices/NotificationCenter.app和SystemUIServer均返回timeoutReached,无法稳定枚举或点击 macOS 通知横幅。重新get_app_state(Electron)会触发 app activation 并恢复窗口,因此不能作为“点击通知回跳”的证据。该项保持未完成,需在可操作 Notification Center/横幅的 macOS 会话或签名 packaged app 上复验。 - 2026-06-01 通知点击二次复测:用
CC_HAHA_ELECTRON_NOTIFICATION_SMOKE_DELAY_MS=30000启动 Electron dev 壳,Computer Use 确认主窗口可见后点击 macOS close button,Electron 无主窗口且进程保持 running;等待通知触发后,Computer Use 对SystemUIServer与 Notification Center 仍timeoutReached,前台 Chrome 截图/AX 树也没有出现可点击通知横幅。真实 OS 通知点击回跳仍未验收通过。 - 2026-06-01 通知 smoke 可审计化:新增
CC_HAHA_ELECTRON_NOTIFICATION_SMOKE_LOG=<path>,仅在显式 smoke env 下把 scheduled/sent/action/send_failed 写入 JSONL,方便真实 macOS/Windows runner 点击通知后确认 Electron main 是否收到 OS click。cd desktop && bun test electron/services/notificationSmoke.test.ts electron/services/notifications.test.ts electron/services/windows.test.ts通过 17 tests,cd desktop && bun run check:electron通过 85 tests。 - 2026-06-01 packaged 通知 smoke 复测:重新运行
CSC_IDENTITY_AUTO_DISCOVERY=false bun run electron:package:dir后,用隔离配置启动 packaged app,并设置CC_HAHA_ELECTRON_NOTIFICATION_SMOKE_LOG=/tmp/.../notification-smoke.jsonl。Computer Use 确认 packagedfile://.../app.asar/dist/index.html主窗口可见;JSONL 记录scheduled与sent:true,证明 Electron main 已向系统发出真实通知。但 Computer Use 仍无法读取SystemUIServer或NotificationCenter.app(均timeoutReached),日志也未出现action,所以“点击通知回到目标 session”仍未完成。 - 2026-06-01 通知点击当前态再复测:用 canonical packaged app 启动隔离通知 smoke,设置
CC_HAHA_ELECTRON_NOTIFICATION_SMOKE_SESSION_ID=notification-click-smoke-session、CC_HAHA_ELECTRON_NOTIFICATION_SMOKE_DELAY_MS=8000和 JSONL log;Computer Use 关闭主窗口后 app 留在后台,JSONL 记录scheduled与sent:true。Computer Use 对/System/Library/CoreServices/UserNotificationCenter.app/返回安全策略拒绝,对NotificationCenter.app仍timeoutReached,所以仍无法执行真实 OS 通知点击。为后续实机复验,通知 smoke 日志已扩展记录lifecycle: close|failed,可区分通知发出后被系统关闭、发送失败和用户点击;cd desktop && bun test electron/services/notificationSmoke.test.ts electron/services/notifications.test.ts通过 10 tests,cd desktop && bun run check:electron通过 90 tests。
通过标准: 通知提示、权限、点击回跳都能在真实打包 app 里证明。 阻断条件: 只在 unit test 中 mock 成功,未走系统通知。
9. 迁移自动更新
创建/修改:
desktop/electron/services/updater.tsdesktop/src/stores/updateStore.tsdesktop/package.json.github/workflows/release-desktop.yml
步骤:
- [x] 选定
electron-builder+electron-updater,不要用 Electron 内置 updater 覆盖 Linux。 - [x] 保留
check -> download -> progress -> install -> relaunch状态机。 - [x]
install前调用 sidecar manager 停止 server/adapters,失败后恢复可重试状态。 - [x] 建立 mock update feed 测试。
- [x] macOS 签名/zip metadata、Windows NSIS metadata、Linux AppImage/deb update 策略写入 Electron build metadata。
- [x] 运行
bun run check:electron。 - [x] 运行
bun run check:desktop。 - [x] release workflow 切换到 Electron builder,并在打包前验证签名/notarization/update metadata secrets 是否配置齐全。
通过标准: 自动更新全链路有 unit、mock feed、打包产物证据。 阻断条件: 只能检查到新版本,不能安全安装并 relaunch。
执行记录(2026-05-31):
- 新增运行时依赖
electron-updater@6.8.3和打包依赖electron-builder@26.8.1。 - 新增
desktop/electron/services/updater.ts;autoDownload=false,checkForUpdates()只返回 metadata,downloadUpdate()将 electron-updaterdownload-progress转成现有DesktopUpdateDownloadEvent,relaunch()阶段调用quitAndInstall(false, true)。 - 扩展 Electron IPC:
desktop:update:download、desktop:update:install和desktop:update:download-event。 desktop/src/lib/desktopHost/electronHost.ts将 Electron update metadata 包装成现有DesktopUpdate对象,rendererupdateStore不需要改状态机。desktop/package.json已加入 Electron builder metadata:appId=com.claude-code-haha.desktop、GitHub publish 到NanmiCoder/cc-haha、macOSdmg/zip、Windowsnsis、LinuxAppImage/deb;packaged runtime 使用asar=true,并通过asarUnpack保留node-pty与 sidecar binaries。bun run check:electron通过:36 tests passed,Electron main/preload 构建成功。bun run check:desktop通过:desktoptsc --noEmit、Vitest 全量 146 test files / 1127 tests passed,production build 成功。
执行记录(2026-06-01):
- 完整 macOS Electron Builder release packaging 暴露出两个自动更新发布问题:平台级
publish: ["github"]会在 worktree/CI 中触发 git remote 自动探测并导致 update info 生成崩溃;默认含空格 artifact name 会让latest-mac.yml指向Claude-Code-Haha-...,但实际上传文件是Claude Code Haha-...。 - 已修复
desktop/package.json:保留顶层显式 GitHub publish 元数据,并移除 mac/win/linux 平台级 publish 覆盖;新增统一无空格artifactName,避免 update metadata 与上传 asset 文件名漂移。 - 已增强
scripts/quality-gate/package-smoke/index.ts:当存在latest-mac.yml/latest.yml/latest-linux.yml时,会解析url/path并确认引用的 artifact 文件实际存在;当发布 archive 存在但 update metadata 缺失时会失败。 - 已新增回归测试:
scripts/pr/release-workflow.test.ts防止 Electron Builder 再依赖 git remote autodetection;scripts/quality-gate/package-smoke/index.test.ts会捕获latest-mac.yml指向缺失 asset 的情况。 - 2026-06-01 packaged app updater 缺失 channel metadata 修复:本地打包 app 启动后 electron-updater 可访问 GitHub release,但当前 release 缺少
latest-mac.yml时会抛ERR_UPDATER_CHANNEL_FILE_NOT_FOUND。该错误现在仅在 message 指向latest*.yml时降级为“无更新”,继续保留其它 updater 错误抛出;cd desktop && bun test electron/services/updater.test.ts通过 7 tests,cd desktop && bun run check:electron通过 84 tests。 - 2026-06-01 packaged app 当前态复验:重新运行
cd desktop && CSC_IDENTITY_AUTO_DISCOVERY=false bun run electron:package:dir后,从desktop/build-artifacts/electron/mac-arm64/Claude Code Haha.app以隔离CLAUDE_CONFIG_DIR/--user-data-dir启动;Computer Use 确认主窗口加载file://.../app.asar/dist/index.html,sidecar 自动启动,未出现 Safe Storage 钥匙串弹窗,日志未再出现ERR_UPDATER_CHANNEL_FILE_NOT_FOUNDIPC handler 崩错。纯--dir包缺少app-update.yml的提示仍按无更新处理,不代表 signed release update feed 已验收。 - 当前本机
.dmg构建仍受 macOS DiskImages/hdiutil 状态阻塞:hdiutil: create failed - 操作超时,且当前 worktree 下残留的临时读写 disk image 无法正常 detach;这属于本机磁盘镜像服务阻塞,不应被 package-smoke 或浏览器 smoke 替代为发布通过。
10. 迁移 PTY 终端
创建/修改:
desktop/electron/services/terminal.tsdesktop/src/api/terminal.ts
步骤:
- [x] 明确 PTY 实现:保留 Rust sidecar command 或引入 Node PTY 方案。
- [x] 实现 spawn/write/resize/kill 和 output/exit event。
- [x] 保留 terminal shell 配置读写语义。
- [x] 运行
bun run check:desktop && bun run check:electron。 - [x] 打包 app smoke:打开终端、输入命令;resize/kill 需随完整 packaged smoke 继续复验。
通过标准: 终端交互和事件流等价。 阻断条件: Windows shell 或自定义 shell path 行为不明确。
执行记录(2026-05-31):
- 已选择 Node PTY 方案:新增运行时依赖
node-pty@1.1.0,Electron main process 负责pty.spawn(),renderer 只通过 preload IPC 发送 spawn/write/resize/kill。Context7/microsoft/node-pty文档确认主进程集成方式为spawn+onData/onExit+write/resize/kill。 - 新增
desktop/electron/services/terminal.ts,保留 Tauri 终端语义:CLAUDE_CONFIG_DIR/terminal-config.json优先,其次 ElectronuserData/terminal-config.json;继续读取~/.claude/settings.json的desktopTerminalWindows shell 配置;保留 Windowsbash_path、COMSPEC、POSIXSHELL、/bin/zsh//bin/bash默认 shell 选择。 terminal_spawn等价实现最小尺寸限制:cols >= 20、rows >= 8;默认 cwd 仍按cwd -> CLAUDE_CONFIG_DIR -> HOME/USERPROFILE -> process.cwd();环境变量合并 login shell env,并强制 UTF-8 locale,补充TERM=xterm-256color与COLORTERM=truecolor。desktop/electron/main.ts已注册desktop:terminal:*IPC:spawn/write/resize/kill/get-bash-path/set-bash-path,并通过desktop:terminal:output、desktop:terminal:exit事件回传现有 renderer payload。desktop/electron/ipc/capabilities.ts收紧terminalSpawnpayload 校验,避免 renderer 传入非数字尺寸或非字符串 cwd/shell。- 新增
desktop/electron/services/terminal.test.ts,覆盖配置路径、bash path 持久化、Windows shell 解析、UTF-8 env、spawn event 转发、write/resize/kill、exit 后 session 清理。 - packaged macOS
node-pty直接从.app/Contents/Resources/app.asar.unpacked执行会在spawn-helper上触发posix_spawnp failed;已改为打包时先执行prepare:node-pty修正 helper executable bit,并在 packaged macOS runtime 将node-pty复制到 ElectronuserData/native/node-pty-<platform>-<arch>-<version>后加载,避免嵌套 app bundle 资源执行限制。 bun run check:electron通过:58 tests passed,Electron main/preload/preview-preload 构建成功。bun run check:desktop通过:desktoptsc --noEmit、Vitest 全量 146 test files / 1127 tests passed,production build 成功。CSC_IDENTITY_AUTO_DISCOVERY=false bun run electron:package:dir通过并产出 unpacked macOS.app;Computer Use packaged smoke 通过:启动Claude Code Haha.app,点击“打开终端”后显示运行中 /bin/zsh,在终端输入printf electron-terminal-ok并看到输出electron-terminal-ok。终端 resize/close kill 仍需在完整 packaged smoke 中补齐。
11. 迁移预览面板
创建/修改:
desktop/electron/services/preview.tsdesktop/src/lib/previewBridge.tsdesktop/src/lib/previewEvents.ts
步骤:
- [x] 使用
WebContentsView,不要用已弃用的BrowserView。 - [x] 保留
http/httpsURL 白名单。 - [x] 保留 preview agent 注入和 JSON 消息校验。
- [x] 实现 open/navigate/setBounds/setVisible/close/eval/message。
- [x] 运行
bun run check:desktop && bun run check:electron。 - [x] 打包 app smoke:打开 workbench/browser panel,导航 URL,完成 preview/screenshot 回填 smoke。
通过标准: 预览面板功能等价且安全边界保留。 阻断条件: 允许 file: 或 javascript: URL 进入 preview。
执行记录(2026-05-31):
- Context7
/electron/electron文档确认当前 API 使用WebContentsView+contentView.addChildView()+setBounds()+webContents.loadURL(),不再新增BrowserView。 - 新增
desktop/electron/services/preview.ts,使用WebContentsView实现open/navigate/setBounds/setVisible/close/eval,继续拒绝空 URL、file:、javascript:等非http/httpsURL。 - 新增
desktop/electron/preview-preload.ts,只暴露window.__DESKTOP_PREVIEW_POST__(raw);外部页面无法拿到 Node/Electron API,只能把 JSON 字符串发回 main process。 desktop/src/preview-agent/index.ts改为调用通用__DESKTOP_PREVIEW_POST__;Tauri 端在desktop/src-tauri/src/webview_panel.rs创建 child webview 时先注入该函数,再注入 preview agent;Electron 端由 preview preload 注入同名函数。- Electron main process 增加内部 channel
desktop:preview:message-from-view,只接受当前 previewwebContents发出的 raw JSON;校验 JSON 后通过desktop:preview:event转发给 React。 desktop/package.json的build:electron增加preview-preload.cjs构建,Electron builder files 增加src-tauri/resources/preview-agent.js,保证 packaged app 能读取注入脚本。- 新增
desktop/electron/services/preview.test.ts,覆盖 URL 白名单、bounds 规范化、child view 复用、load 后注入 preview agent、JSON event 转发、close 清理。 bun run build:preview-agent已重建desktop/src-tauri/resources/preview-agent.js。bun run check:electron通过:49 tests passed,Electron main/preload/preview-preload 构建成功。bun run check:desktop通过:desktoptsc --noEmit、Vitest 全量 146 test files / 1127 tests passed,production build 成功。- 2026-06-01 Computer Use packaged smoke 覆盖 preview/workbench:临时 packaged app 中打开 browser panel,导航
https://example.com/成功,并完成 screenshot 回填 composer;完整 preview event 回归继续由desktop/electron/services/preview.test.ts覆盖。
12. 迁移 app mode、portable config 和 zoom
创建/修改:
desktop/electron/services/appMode.tsdesktop/electron/services/zoom.tsdesktop/src/stores/settingsStore.tsdesktop/src/lib/appZoom.ts
步骤:
- [x] 保留
get_app_mode、set_app_mode、detect_portable_dir返回形状。 - [x] 保留同时写系统默认配置目录和 portable 目录的语义。
- [x] zoom 继续 clamp 到
0.5..2.0。 - [x] 运行
bun run check:persistence-upgrade。 - [x] 运行
bun run check:desktop && bun run check:electron。
通过标准: 老配置可升级,unknown fields 保留。 阻断条件: 写入 ~/.claude/settings.json 或受保护配置路径。
执行记录(2026-05-31):
- 新增
desktop/electron/services/appMode.ts,复刻 Tauriapp-mode.json语义:启动时按external CLAUDE_CONFIG_DIR -> default portable app-mode.json -> system app-mode.json -> default portable data auto-detect判定是否设置CLAUDE_CONFIG_DIR。 - Electron
app.whenReady()后、server sidecar 启动前调用applyStartupPortableMode(app),保证 sidecar、window state、terminal config 都能看到 portable env;同时设置CC_HAHA_APP_PORTABLE_DIR=1与WEBVIEW2_USER_DATA_FOLDER=<portable>/EBWebView。 desktop:app-mode:get返回现有 renderer 形状:mode、portableDir、defaultPortableDir、activeConfigDir、configDirSource;configDirSource区分system、外部环境变量environment、应用切换产生的portable。desktop:app-mode:set在当前 active config、目标 portable dir、系统默认userData三处写入app-mode.json,不写~/.claude/settings.json,也不移动/删除已有数据。desktop:app-mode:restart现在relaunch()后立即quit(),与设置页“切换后重启”的语义一致;prepareRestart继续先停止 server/adapters。- 新增
desktop/electron/services/zoom.ts,native zoom 统一 clamp 到0.5..2.0,避免 Electron IPC 绕过 renderer 侧限制。 - 新增
appMode.test.ts与zoom.test.ts,覆盖 portable 数据探测、启动模式解析、env 设置、返回形状、三处 app-mode 写入、zoom clamp。 bun run check:electron通过:56 tests passed,Electron main/preload/preview-preload 构建成功。bun run check:persistence-upgrade通过:server persistence 6 tests passed,desktop localStorage migration 8 tests passed。bun run check:desktop通过:desktoptsc --noEmit、Vitest 全量 146 test files / 1127 tests passed,production build 成功。
Phase 4:Build、CI、Release
13. 替换本地构建脚本
修改:
desktop/package.jsonpackage.jsondesktop/scripts/build-macos-arm64.shdesktop/scripts/build-windows-x64.ps1
步骤:
- [x] 保留
desktop build作为 renderer build。 - [x] 保留
build:sidecars。 - [x] 新增 Electron package 脚本,输出到
desktop/build-artifacts/<platform>。 - [x]
check:native替换为 Electron main/preload/package config check,或新增check:electron并让quality:gate使用它。 - [x] 运行
bun run check:desktop && bun run check:electron。
通过标准: 本地 macOS/Windows 构建命令产出可启动 app。 阻断条件: sidecar 没有被打进产物或产物启动后仍读开发路径。
执行记录(2026-05-31):
desktop/package.json保留build为 renderer build,新增/调整electron:build、electron:package、electron:package:dir,并将build:electron扩展为 main/preload/preview-preload 三个 bundle。- Electron builder 配置包含
dist/**、electron-dist/**、src-tauri/binaries/**、src-tauri/resources/preview-agent.js和node_modules/node-pty/**;electron-updater已打进 main bundle,node-pty保持外部原生模块并通过asarUnpack解包。 check:native已从 Tauricargo check改为build:sidecars + check:electron;quality:gatenative lane 描述同步为 Electron host/package checks。desktop/scripts/build-macos-arm64.sh改为 Electron Builder:构建 sidecar、renderer、Electron bundles,执行electron-builder --mac dmg zip --arm64 --publish never,输出复制到desktop/build-artifacts/macos-arm64。desktop/scripts/build-windows-x64.ps1改为 Electron Builder:导入 MSVC 环境,构建 sidecar、renderer、Electron bundles,执行electron-builder --win nsis --x64 --publish never,输出复制到desktop/build-artifacts/windows-x64。desktop/scripts/build-macos-arm64.sh支持MAC_TARGETS覆盖 Electron Builder macOS target,默认仍为dmg zip;本机 DiskImages 异常时可用MAC_TARGETS=zip单独验证 zip/update metadata 链路。脚本会对当前 worktree 的 stale Electron Builder 临时 DMG 挂载 fail fast,成功复制 canonical artifacts 后默认运行 package-smoke。desktop/scripts/build-windows-x64.ps1会把 installer、update metadata、blockmap 和win-unpacked复制到 canonicaldesktop/build-artifacts/windows-x64;成功复制后默认运行bun run test:package-smoke --platform windows --package-kind release --artifacts-dir desktop/build-artifacts/windows-x64,可用SKIP_PACKAGE_SMOKE=1跳过静态验包。desktop/scripts/build-linux.sh支持LINUX_ARCH=x64|arm64和LINUX_TARGETS覆盖,默认构建 AppImage/deb x64;脚本会复制.AppImage、.deb、latest-linux.yml、blockmap 和linux-unpacked到 canonicaldesktop/build-artifacts/linux-<arch>,并默认运行bun run test:package-smoke --platform linux --package-kind release --artifacts-dir desktop/build-artifacts/linux-<arch>。node-pty原生模块验证:bunx electron ./tmp-electron-node-pty-smoke.cjs在 Electron 42.3.0 runtime 下成功输出node-pty spawn type: function。electron-builder install-app-deps在本机@electron/rebuildnode-gyp worker 上空转无输出;由于node-ptyElectron runtime smoke 已通过,默认配置设为npmRebuild=false,脚本保留REBUILD_NATIVE=1作为 runner/调试开关。- packaged
.app首轮 smoke 暴露两个打包差异:Vite 默认绝对/assets/...在file://下加载失败,已通过vite.config.ts base: './'、publicAssetPath()和字体 URL 改造修复;asar=false的全量 unpacked resources 会触发 macOS assessmentToo many open files,已切换为asar=true+asarUnpack。 CSC_IDENTITY_AUTO_DISCOVERY=false bun run electron:package:dir通过并产出desktop/build-artifacts/electron/mac-arm64/Claude Code Haha.app;codesign --verify --deep --strict --verbose=2通过;packaged app 启动后 sidecar 从app.asar.unpacked/src-tauri/binaries/claude-sidecar-aarch64-apple-darwin运行,renderer 从app.asar/dist/index.html加载。bun run check:native通过:sidecar build 成功,Electron host 56 tests passed,main/preload/preview-preload 构建成功。- 2026-06-01 已把
check:native扩展为build:sidecars + check:electron + electron:package:dir + test:package-smoke:current;最新复跑通过:Electron 77 tests passed,Electron--dir产出desktop/build-artifacts/electron/mac-arm64/Claude Code Haha.app,当前平台 macOS package-smoke PASS。 bun run check:desktop通过:desktoptsc --noEmit、Vitest 全量 146 test files / 1127 tests passed,production build 成功。- 生产 React 直接 Tauri 扫描无输出:
rg -n "@tauri-apps|__TAURI_INTERNALS__|window\\.__TAURI__|from '@tauri" desktop/src --glob '!**/*.test.ts' --glob '!**/*.test.tsx' --glob '!**/lib/desktopHost/**' --glob '!src-tauri/**'。
14. 替换 CI workflow
修改:
.github/workflows/build-desktop-dev.yml.github/workflows/release-desktop.yml.github/workflows/pr-quality.ymlscripts/quality-gate/modes.tsscripts/pr/change-policy.tsscripts/pr/check-pr.ts
步骤:
- [x] 移除
tauri-apps/tauri-action@v0。 - [x] 移除 Linux WebKitGTK/Rust/Tauri 专用依赖,保留 Electron/Linux 打包需要的依赖。
- [x] 配置 macOS arm64/x64、Windows x64、Linux x64/arm64 matrix。
- [x] 配置 signing/notarization/update metadata secrets。
- [x] 让 PR/change policy 识别
desktop/electron/**和 Electron build config。 - [x] 运行
bun run check:policy。
通过标准: CI lane 名称、触发条件和产物路径都更新为 Electron。 阻断条件: PR 改 Electron host 文件但不会触发桌面/原生检查。
执行记录(2026-05-31):
.github/workflows/build-desktop-dev.yml改为 Electron Builder matrix:macOS arm64/x64、Windows x64、Linux x64/arm64;每个 job 安装 Bun/Node、构建 sidecars、构建 renderer/Electron bundles、运行electron-builder并上传desktop/build-artifacts/electron产物。.github/workflows/release-desktop.yml移除tauri-apps/tauri-action@v0,改为electron-builder --publish never生成产物,再用softprops/action-gh-release@v2上传 release assets。- Linux CI 依赖删除 WebKitGTK/Rust/Tauri 专用包,仅保留 Electron packaging 与 AppImage 需要的基础构建工具和
libfuse2。 - PR
desktop-native-checks不再安装 Rust toolchain 或 Rust cache;desktop/scripts/build-sidecars.ts改为用process.platform/process.arch推导 host triple,避免 Electroncheck:native继续依赖rustc -vV。 - sidecar build target env 已改为
SIDECAR_TARGET_TRIPLE;build-sidecars.ts暂时兼容旧TAURI_ENV_TARGET_TRIPLE,但 CI 和平台脚本不再使用 Tauri 命名。 scripts/pr/change-policy.ts将desktop/electron/tsconfig.json、Electron macOS/Windows build scripts 纳入 native/release paths;scripts/quality-gate/modes.ts和scripts/pr/impact-report.ts文案从 Tauri native 改为 Electron host/package。bun run check:policy通过:64 tests passed,quarantine review 0 expired。
15. 替换 release 脚本
修改:
scripts/release.tsscripts/pr/release-workflow.test.ts
步骤:
- [x] 版本来源从
desktop/src-tauri/tauri.conf.json改为 Electron package/build config。 - [x] 删除
Cargo.toml/Cargo.lockrelease 更新。 - [x] 保留 release note 校验、commit、tag 流程。
- [x] 运行
bun run scripts/release.ts <next-version> --dry。 - [x] 运行
bun test scripts/pr/release-workflow.test.ts。
通过标准: dry run 显示的版本文件全部属于 Electron 发布链。 阻断条件: release 仍依赖 Tauri 版本文件。
执行记录(2026-05-31):
scripts/release.ts当前版本来源改为desktop/package.json,版本更新文件只保留desktop/package.json。- release 脚本不再更新
desktop/src-tauri/tauri.conf.json、Cargo.toml或Cargo.lock,也不再运行cargo generate-lockfile。 - Git commit/tag 流程仍保留 release notes 校验、
git add desktop/package.json release-notes/vX.Y.Z.md、commit、annotated tag。 bun run scripts/release.ts patch --dry通过,显示0.3.1 -> 0.3.2,只会更新desktop/package.json和release-notes/v0.3.2.md。bun test scripts/pr/release-workflow.test.ts scripts/pr/change-policy.test.ts通过:11 tests passed。
Phase 5:最终验收
16. Electron packaged smoke
步骤:
- [ ] macOS:构建
.app/.dmg,启动 app,验证聊天、附件、通知、托盘、更新 mock、终端、预览面板。 - [ ] Windows:构建 NSIS 安装器,安装后启动 app,验证 sidecar 文件锁和更新前停进程。
- [ ] Linux:构建 deb/AppImage,验证启动、tray、通知、更新策略。
- [x] 运行
bun run test:package-smoke --platform macos作为包结构预检;Windows/Linux 待对应平台产物。
通过标准: 每个平台至少一个真实发布格式完成 smoke。 阻断条件: 只有 dev build 或 Vite 页面通过。
执行记录(2026-05-31):
- macOS unpacked
.appsmoke 已完成一部分:CSC_IDENTITY_AUTO_DISCOVERY=false bun run electron:package:dir成功,Computer Use 启动 packaged app 后主界面正常渲染,server sidecar 正常启动,终端面板可打开并执行printf electron-terminal-ok。 - Review 后重新运行
cd desktop && CSC_IDENTITY_AUTO_DISCOVERY=false bun run electron:package:dir成功;bun run test:package-smoke --platform macos通过,确认当前.app结构、app.asar、unpacked sidecar、unpackednode-ptynative module 和spawn-helper存在。 - 因本机已有正式
/Applications/Claude Code Haha.app实例持有单实例锁,Computer Use 最终 smoke 使用同一构建输出重新打包临时Claude Code Haha Smoke.app(仅临时 appId/productName 不同)执行:packaged renderer 从app.asar/dist/index.html加载,sidecar 自动启动,终端执行electron-terminal-ok,系统目录选择器可打开,preview WebContentsView 可导航https://example.com/,截图可回填 composer。 - 注意:
test:package-smoke是 bundle-structure/static-artifact preflight,不启动 GUI,也不替代 Computer Use 或实机 smoke。 - 2026-06-01 同步本地
main后重新运行cd desktop && CSC_IDENTITY_AUTO_DISCOVERY=false bun run electron:package:dir成功,产出desktop/build-artifacts/electron/mac-arm64/Claude Code Haha.app。 - 2026-06-01 使用 Computer Use 操作真实 packaged app,并把本机 cc-haha provider/model 配置复制到隔离临时
CLAUDE_CONFIG_DIR:模型选择器显示gpt-5.5 Sub2API-ChatGPT,系统目录选择器选中/private/tmp/cc-haha-electron-real-fixed-sRFUeO/project。 - 真实模型 smoke 会话
e0d7abc2-27db-4ff1-9954-7923f6c3385e通过:packaged renderer 从file://.../app.asar/dist/index.html加载,server sidecar 建立 WebSocket,CLI subprocess 使用--model gpt-5.5启动,模型读取package.json与src/greeting.ts后经权限审批执行bun test,结果为1 pass / 0 fail,最终回复“测试通过。”。 - 2026-06-01 重跑
SKIP_INSTALL=1 SIGN_BUILD=0 desktop/scripts/build-macos-arm64.sh:修复平台级 publish 后曾产出.app/.zip/.dmg/latest-mac.yml,但latest-mac.yml与实际含空格 asset 文件名不一致;加入稳定artifactName后,清理旧 disk image 挂载前本机 DiskImages/hdiutil 在.dmg创建阶段超时,zip-only Electron Builder 也曾在本机 7za 子进程处失败。 - 2026-06-01 清理旧 Tauri/Electron disk image 挂载后,
MAC_TARGETS=zip SKIP_INSTALL=1 SIGN_BUILD=0 desktop/scripts/build-macos-arm64.sh通过,canonicaldesktop/build-artifacts/macos-arm64产出.app、Claude-Code-Haha-0.3.2-arm64.zip、.zip.blockmap和latest-mac.yml;脚本自动运行bun run test:package-smoke --platform macos --artifacts-dir desktop/build-artifacts/macos-arm64并 PASS,确认latest-mac.yml引用真实 zip 且 packaged resources 含app-update.yml。 - 2026-06-01
.dmgtarget 最新复验通过:后续默认SKIP_INSTALL=1 SIGN_BUILD=0 desktop/scripts/build-macos-arm64.sh已完成dmg ziptarget,canonicaldesktop/build-artifacts/macos-arm64包含.app、.dmg、.zip、blockmap 和latest-mac.yml,脚本自动 release package-smoke PASS。Gatekeeper/signed/notarized launch 仍保持 release blocker。 - 2026-06-01 macOS build script hardening:默认
dmg ziptarget 在当前 worktree 检测到 stale Electron Builder.temp...dmg挂载时会提前失败并给出MAC_TARGETS=zip替代路径,避免继续进入会卡死的 DiskImages detach/create 分支。 - 2026-06-01 Windows build script hardening:canonical 输出现在保留
win-unpacked供 package-smoke 检查app.asar、app-update.yml、unpacked sidecar 和node-pty原生模块;脚本默认在 Windows runner 上执行 canonical package-smoke,但本机 macOS 未执行 NSIS 真实构建/安装。 - 2026-06-01 Linux build script hardening:新增
desktop/scripts/build-linux.sh与build:linux-x64/build:linux-arm64scripts,canonical 输出现在保留 AppImage/deb、latest-linux.yml和linux-unpacked供 package-smoke 检查;本机 macOS 不能执行 Linux 真实构建/安装。 - 2026-06-01 Linux package-smoke 区分开发目录包和发布包:
electron-builder --dir只产出linux-unpacked时仍检查app.asar、sidecar 和node-pty并通过check:native;AppImage/deb 发布产物存在时继续要求latest-linux.yml和app-update.yml。 - 2026-06-01 Linux arm64 updater metadata 修复:
build-linux.sh现在复制latest-linux*.yml,避免 arm64 Electron Builder 产出latest-linux-arm64.yml时 canonicallinux-arm64目录丢失 update metadata;package-smoke同步识别latest-linux.yml和latest-linux-arm64.yml,并检查 metadata 引用的 AppImage/deb artifact 是否真实存在。 - 2026-06-01 package-smoke 增加显式
--package-kind dir|release:check:native使用dir + desktop/build-artifacts/electron,发布/dev packaging workflow 和平台 release 脚本使用release + 精确 artifacts-dir,避免旧 installer/metadata 污染本轮验包。 - 2026-06-01 Gatekeeper 诊断加固:
--require-macos-gatekeeper的spctl失败时,package-smoke 会同时记录codesign --verify --deep --strict --verbose=2、codesign -dv --verbose=4与xcrun stapler validate摘要,方便区分未签名、签名链、bundle 格式和 notarization ticket 问题。 - 2026-06-01 SubAgent Review 修复:release workflow 在打包矩阵前新增
bun run verify非 live 预检;quality:gate --mode release会包含 PR checks,并把desktop-package-smoke:<platform>改为--package-kind release --artifacts-dir desktop/build-artifacts/<platform-arch>,避免验到旧的--dir包。 - 2026-06-01 多架构 metadata 风险收敛:release workflow 上传前会把
latest*.yml改名为带 matrix label 后缀的唯一 asset,避免 GitHub Release 中同名 metadata 互相覆盖或上传失败;matrix 全部通过后由scripts/release-update-metadata.ts重新发布标准 updater channel metadata。macOS 会把 x64/arm64 zip entries 合并回latest-mac.yml,Linux 会恢复latest-linux.yml/latest-linux-arm64.yml,Windows 会恢复latest.yml。完整自动更新 release 仍需在 signed/notarized artifact 上复验。 - 2026-06-01 signing/notarization secrets preflight:release workflow 新增非 matrix
signing-preflightjob,在任何平台 artifact 上传前检查MACOS_CERTIFICATE、MACOS_CERTIFICATE_PASSWORD、APPLE_ID、APPLE_APP_SPECIFIC_PASSWORD、APPLE_TEAM_ID、WINDOWS_CERTIFICATE和WINDOWS_CERTIFICATE_PASSWORD。缺失时用 GitHub Actions error 早停,避免部分 matrix leg 先发布 partial release。真实 Developer ID signing/notarization 仍需在 CI secrets 存在时复验。 - 2026-06-01 native/package 当前态复验:
bun run check:native通过,完成 sidecar 构建和 ad-hoc signing、check:electron83 tests、desktop production build、electron-builder --dir,并运行bun run test:package-smoke --platform macos --package-kind dir --artifacts-dir desktop/build-artifacts/electronPASS。该证据只覆盖 directory-only unpacked app bundle 结构、app.asar、sidecar、node-pty和spawn-helper,不替代.dmg、Gatekeeper 或 signed release smoke。 - 2026-06-01 DMG 当前态复验:默认
SKIP_INSTALL=1 SIGN_BUILD=0 desktop/scripts/build-macos-arm64.sh已通过,canonicaldesktop/build-artifacts/macos-arm64恢复.app、.dmg、.dmg.blockmap、.zip、.zip.blockmap、latest-mac.yml,并由 release package-smoke PASS。 - 2026-06-01 跨平台 package-smoke 当前态复验:
bun test scripts/quality-gate/package-smoke/index.test.ts scripts/pr/release-workflow.test.ts scripts/release-update-metadata.test.ts通过 26 tests,覆盖 Windows canonical output、Linux x64/arm64 update metadata、release workflow Gatekeeper/signing preflight 和 metadata republish;bun run test:package-smoke --platform macos --package-kind release --artifacts-dir desktop/build-artifacts/macos-arm64PASS,确认当前 macOS zip/update canonical artifact set 仍完整。 - 本轮尚未完成
.dmg安装包、通知点击、signed/notarized Gatekeeper launch、Windows NSIS 和 Linux AppImage/deb 的真实发布格式 smoke,因此本阶段保持未完成。附件选择、目录选择、外链、终端和 preview 已有 dev 或 unpacked packaged Computer Use 证据,但还不能替代最终 signed release artifact 的全量验收。
17. Release gate
步骤:
- [x] 运行
bun run verify。 - [x] 有 live provider 时运行
bun run quality:gate --mode release --allow-live --provider-model <provider:model[:label]>。 - [x] 检查 quality report 的 pass/fail/skip。
- [x] 记录 coverage report 路径。
通过标准: PR/release 门禁通过,coverage 未退化。 阻断条件: 任一 release 必需 lane 失败。
执行记录(2026-06-01):
bun run verify通过:最新为artifacts/quality-runs/2026-05-31T21-42-57-279Z/report.md,passed=9 failed=0 skipped=1。- 首次重跑完整
release --allow-live后,旧 agent-browser/Vite blocker 已消失;唯一失败为 coverage 中h5-access-auth.test.ts随机端口撞到本机 WeChat 的127.0.0.1:24023。 - 已把
h5-access-auth.test.ts端口选择改成 OS 分配 ephemeral port;focusedbun test src/server/__tests__/h5-access-auth.test.ts通过,bun run check:coverage最新通过:artifacts/coverage/2026-05-31T21-46-15-873Z/coverage-report.md,passed=5 failed=0。 - 历史
bun run quality:gate --mode release --allow-live --provider-model sub2api-chatgpt:main:sub2api-chatgpt-main曾通过:artifacts/quality-runs/2026-05-31T20-29-45-758Z/report.md,passed=15 failed=0 skipped=0。SubAgent Review 后 release gate 已收窄为必须检查 canonical release artifact,当前仍需在 signed/notarized artifact 与可用 Computer Use 桌面会话上重新跑完整 release gate。
18. Computer Use 全面测试
步骤:
- [x] 用真实打包 app 运行 Computer Use 设置流程。
- [x] 验证 Python 路径选择、权限授权、屏幕录制/辅助功能授权提示、授权应用列表。
- [x] 验证点击、输入、滚动、系统快捷键、剪贴板。
- [ ] 验证通知点击回到目标会话。
- [ ] macOS 和 Windows 至少各完成一次;Linux 如能力降级,写入 release note 和已知限制。
通过标准: Computer Use 在真实 Electron app 中完成端到端操作。 阻断条件: 只用浏览器/Vite 或 mock 路径证明。
验证清单: 迁移收口使用 docs/desktop/09-electron-migration-validation-checklist.md,其中区分自动化证据、macOS Computer Use smoke、Windows 待实机和 Linux 待实机。
执行记录(2026-06-01):
- 尝试继续 Computer Use GUI 验收时,Computer Use 工具层对
list_apps和get_app_state(Finder)均返回NSOSStatusErrorDomain Code=-600 procNotFound。该结果说明当前 macOS 自动化桥未拿到可用进程,不是 Electron app 单点问题;剩余附件、Python 路径、外链、Dock/tray、通知点击和完整 update feed 验收保持未完成。 - 2026-06-01 后续复测 Computer Use 仍返回同一
procNotFound,这是连续第二个 goal turn 复现;目标仍可在代码和发布门禁层继续推进,因此暂不标记 goal blocked。 - 2026-06-01 再次复测后 Computer Use
list_apps已恢复,但get_app_state(Electron)对 Electron dev 壳超时,get_app_state(Finder)为cgWindowNotFound;系统screencapture同时返回could not create image from display。这说明当前桌面会话没有可用截图/窗口捕获能力,Computer Use 交互验收仍不能推进。 - 2026-06-01 continuation 复测:Computer Use
list_apps仍可列应用,get_app_state(Finder)仍为cgWindowNotFound,screencapture仍失败为could not create image from display;当前仍不能完成附件、Python 路径、外链、Dock/tray、通知点击等 GUI 验收。 - 2026-06-01 packaged app 启动被 macOS
AppleSystemPolicy拦截:spctl -a -t execute desktop/build-artifacts/electron/mac-arm64/Claude Code Haha.app报bundle format unrecognized, invalid, or unsuitable,系统日志显示 ad-hoc/unknown-chain app 被终止。本轮已新增bun run test:package-smoke --platform macos --require-macos-gatekeeper作为可选 release-readiness 检查;当前该检查失败,release-ready 需要 Developer ID signing/notarization 或真实签名产物复验。 - 2026-06-01 release workflow 已补强:macOS release artifact 上传前强制运行
bun run test:package-smoke --platform macos --require-macos-gatekeeper,防止未通过 macOS 启动策略的.app/.dmg/.zip被发布;dev build 仍保留结构型 package-smoke。 - 2026-06-01 修复 Electron dev launcher 代理问题:
electron:dev默认 renderer URL 改为http://localhost:1420,并对当前进程、Vite 与 Electron 子进程补齐NO_PROXY/no_proxy=localhost,127.0.0.1,::1,避免本机代理把 localhost renderer 等待请求打成 502。 - 2026-06-01 主窗口显示逻辑加固:创建
BrowserWindow后立即show/focus,renderer load 完成后再次show/focus,避免隐藏窗口在 load 等待期间被托盘/单实例/Computer Use 路径视为无窗口。 - 2026-06-01 SubAgent gap follow-up:renderer 生产代码不再用
isTauriRuntime()判断通用桌面能力,新增isDesktopRuntime(),更新弹窗、附件 native picker、设置 app mode、移动布局分支均识别 Electron/Tauri desktop host。 - 2026-06-01 Electron updater proxy contract 已补齐:renderer 传入的
{ proxy }会进入 Electron main,检查更新前应用到 Electronapp/sessionproxy;切回系统代理时会清理手动代理,避免更新检查继续沿用旧 proxy。 - 2026-06-01 package-smoke 增加发布型包的 installed updater metadata 检查:当 artifact set 含
.zip/.dmg/latest-mac.yml、Windows installer/latest.yml 或 Linux package/latest-linux.yml 时,安装后 resources 目录必须包含app-update.yml;纯--dir开发包会记录 note 但不失败。 - 2026-06-01 真实 provider smoke 使用本机
~/.claude/cc-haha/providers.jsonselectorsub2api-chatgpt:main:sub2api-chatgpt-main通过:artifacts/quality-runs/2026-05-31T21-28-07-154Z/report.md,passed=1 failed=0 skipped=0。该路径复用 cc-haha provider 配置,不走QUALITY_GATE_PROVIDER_*明文 env-only 分支。 - 2026-06-01
check:native已补上打包后验包:根脚本现在会在 Electron--dir打包后运行test:package-smoke:current。最新bun run check:native通过,package-smoke notes 明确当前纯--dirmacOS artifact set 不强制app-update.yml,也不代表 GUI 启动或 Gatekeeper approval。 - 2026-06-01 final-definition 复测:Computer Use
list_apps正常,但get_app_state(Finder)仍返回cgWindowNotFound;系统screencapture -x /tmp/cc-haha-cua-retake-final.png仍失败为could not create image from display。当前机器继续不能承载真实 GUI 操作验收。 - 2026-06-01 cross-platform-script 复测:Computer Use
list_apps正常且可见/Applications/Claude Code Haha.app,get_app_state(Finder)仍为cgWindowNotFound,get_app_state(Claude Code Haha)返回remoteConnection,系统screencapture -x /tmp/cc-haha-computer-use-check.png仍失败为could not create image from display。当前仍不能完成点击、输入、附件选择、托盘恢复、通知点击等 GUI 验收。 - 2026-06-01 package-kind 复测:Computer Use
list_apps正常且显示/Applications/Claude Code Haha.app正在运行,get_app_state(Claude Code Haha)和get_app_state(Finder)均返回cgWindowNotFound,系统screencapture -x /tmp/cc-haha-computer-use-check-2.png仍失败为could not create image from display。当前机器仍不能承载真实 GUI 操作验收。 - 2026-06-01 Gatekeeper 诊断加固:release-readiness package-smoke 在
spctl失败时会补充codesignverify/details 摘要,后续 signed/notarized artifact 的失败可以直接从 quality log 判断是签名链、bundle 格式还是 notarization policy 问题。 - 2026-06-01 Gatekeeper 诊断复验:当前 ad-hoc
.app仍被spctl拒绝为bundle format unrecognized, invalid, or unsuitable,但 package-smoke 已输出codesign verification exited with status 0与 bundle identifier/signature detail 摘要,证明诊断链路可用;release blocker 仍是 Developer ID signing/notarization 或真实签名产物复验。 - 2026-06-01 Gatekeeper 诊断后 Computer Use 复测:
list_apps可见运行中的/Applications/Claude Code Haha.app,但get_app_state(Claude Code Haha)和get_app_state(Finder)均仍为cgWindowNotFound,系统screencapture -x /tmp/cc-haha-computer-use-check-3.png仍失败为could not create image from display。当前机器继续无法执行点击、输入、文件选择器、托盘/通知等 GUI 验收。 - 2026-06-01 Security/Runtime Review 修复:Electron 移除了 renderer 可调用的
previewEval任意 JS 注入通道,预览截图/元素选择改走结构化preview.message;shell.openPath改为只允许已存在的普通文件/目录,并拒绝.app、脚本/安装器/Windows 可执行扩展和 POSIX executable 文件;Electron 暂不声明自定义 window controls,避免 Windows 原生标题栏与自定义标题栏双渲染。 - 2026-06-01 release metadata 合并后 Computer Use 复测:
list_apps可见运行中的/Applications/Claude Code Haha.app,但get_app_state(Claude Code Haha)和get_app_state(Finder)均仍为cgWindowNotFound,系统screencapture -x /tmp/cc-haha-computer-use-check-4.png仍失败为could not create image from display。当前机器继续无法执行点击、输入、文件选择器、托盘/通知等 GUI 验收。 - 2026-06-01 mock update feed UI 流程补强:
UpdateChecker集成测试通过 ElectrondesktopHostmock update feed 驱动真实updateStore,覆盖 check/download/install/relaunch 状态流、下载完成弹窗、点击安装后 prompt 退出。signed/release feed 仍需真实 signed/notarized artifact 复验。 - 2026-06-01 mock update feed UI 补强后 Computer Use 复测:
list_apps可见运行中的/Applications/Claude Code Haha.app,但get_app_state(Claude Code Haha)和get_app_state(Finder)均仍为cgWindowNotFound,系统screencapture -x /tmp/cc-haha-computer-use-check-5.png仍失败为could not create image from display。当前机器继续无法执行点击、输入、文件选择器、托盘/通知等 GUI 验收。 - 2026-06-01 macOS Keychain 弹窗修复:用户截图显示 Electron/Chromium 反复请求
claude-code-desktop Safe Storage。原因是 Chromium profile safe storage 会访问 macOS Keychain;本项目 OAuth token 已走 sidecar file-backed storage,不依赖 Chromium cookie/password store。Electron main 现在在启动早期对 macOS 设置use-mock-keychain,并把ModelSelector的官方 OAuth status 从挂载即请求改为 runtime 下拉打开时按需请求一次,避免启动/重渲染时反复触发敏感存储路径。验证:cd desktop && bun run test -- --run src/components/controls/ModelSelector.test.tsx electron/services/keychain.test.ts12 tests passed;cd desktop && bun run check:electron80 tests passed 并完成 main/preload bundle。 - 2026-06-01 Keychain 修复后 Computer Use 复测:
bun run electron:dev启动当前 Electron dev 壳,get_app_state(Electron)成功返回localhost:1420/主界面和模型选择器gpt-5.5 Sub2API-ChatGPT;截图/AX 树中未再出现claude-code-desktop Safe Storage钥匙串授权弹窗。随后已终止 dev Electron/Vite 进程。 - 2026-06-01 Keychain 当前态复验:
cd desktop && bun run test -- --run electron/services/keychain.test.ts src/components/controls/ModelSelector.test.tsx通过 12 tests;cd desktop && bun run check:electron通过 83 tests 并完成 Electron main/preload/preview-preload bundle。Computer Useget_app_state(Electron)返回Claude Code Companion主窗口和localhost:1420/renderer,未出现 Safe Storage 钥匙串授权弹窗。 - 2026-06-01 原生附件文件选择补强:Electron dialog IPC 改为使用当前
BrowserWindow作为 parent window,composer 打开原生选择器前先关闭 plus 菜单,避免无 owner sheet 返回后菜单状态残留。验证:bun test electron/services/dialogs.test.ts3 tests passed;bun run test -- --run src/lib/composerAttachments.test.ts src/components/chat/ChatInput.test.tsx src/pages/EmptySession.test.tsx33 tests passed;bun run check:electron80 tests passed;Computer Use 在 Electron dev 壳中成功选择/Users/nanmi/cc-haha-cua-attachment-smoke.txt并显示附件 chip,未出现 Safe Storage 弹窗。 - 2026-06-01 packaged updater 噪音修复:Electron updater service 在 packaged
app-update.yml缺失时直接返回“无更新”,并将 electron-updater 内置 logger 设为null,避免目录包或 GitHub release 暂缺latest-mac.yml时在启动日志里打印 404 stack;非 metadata 错误仍会抛出。验证:cd desktop && bun test electron/services/updater.test.ts electron/services/singleInstance.test.ts13 tests passed;cd desktop && bun run check:electron89 tests passed。 - 2026-06-01 single-instance 验证绕过:新增显式
CC_HAHA_ELECTRON_DISABLE_SINGLE_INSTANCE_LOCK=1供本地验证启动同 bundle 的 worktree/canonical app,不影响默认生产单实例行为,避免需要杀掉用户正在使用的/Applications/Claude Code Haha.app。 - 2026-06-01 canonical macOS release Computer Use 复测:
SKIP_INSTALL=1 SIGN_BUILD=0 desktop/scripts/build-macos-arm64.sh通过默认dmg zip,release package-smoke PASS;用隔离配置和CC_HAHA_ELECTRON_DISABLE_SINGLE_INSTANCE_LOCK=1启动desktop/build-artifacts/macos-arm64/Claude Code Haha.app,server sidecar 启动,Computer Useget_app_state成功读取Claude Code Companion主窗口和 packaged renderer。启动日志没有app-update.yml或latest-mac.ymlupdater stack。 - 2026-06-01 canonical packaged 系统交互复测:在同一个
desktop/build-artifacts/macos-arm64/Claude Code Haha.app隔离实例中,Computer Use 确认项目选择器已选中系统原生目录选择结果/private/tmp/cc-haha-electron-real-fixed-sRFUeO/project;点击打开终端后终端面板显示运行中 /bin/zsh / /tmp/cc-haha-canonical-cua-flow.xTxSmt/claude-config,输入printf 'canonical-terminal-ok\n'; pwd后画面可见canonical-terminal-ok和实际工作目录输出。该轮未出现claude-code-desktop Safe Storage钥匙串弹窗。 - 2026-06-01 canonical packaged Computer Use 设置流程复测:用隔离
CLAUDE_CONFIG_DIR启动desktop/build-artifacts/macos-arm64/Claude Code Haha.app,Computer Use 打开设置页后进入Computer Usetab。首次状态请求曾因 30s timeout 显示Failed to check status,点击重试后页面正常显示 Python 3.14.5、venv 未创建、依赖未安装。通过页面安装环境按钮完成真实 server/setup 链路,随后 UI 显示 venv 已就绪、依赖包已安装、辅助功能权限已授权、屏幕录制权限未授权;curl /api/computer-use/status返回venv.created=true、dependencies.installed=true、permissions.accessibility=true、permissions.screenRecording=false。点击打开屏幕录制设置后 Computer Use 成功读取 macOS 系统设置窗口录屏与系统录音,并看到Claude Code Haha权限项。 - 2026-06-01 canonical packaged Computer Use 授权应用复测:复用隔离 packaged app,Computer Use 在设置页搜索
Terminal,应用列表返回Terminal / com.apple.Terminal;点击该项后 UI 显示 check 状态,隔离配置cc-haha/computer-use-config.json与GET /api/computer-use/authorized-apps均返回authorizedApps[0].bundleId=com.apple.Terminal,grantFlags.clipboardRead=true、grantFlags.clipboardWrite=true、grantFlags.systemKeyCombos=true。该轮覆盖了真实 UI 点击、输入、滚动、应用枚举和授权配置持久化。 - 2026-06-01 notarization 诊断复验:
bun test scripts/quality-gate/package-smoke/index.test.ts15 tests passed;bun run test:package-smoke --platform macos --package-kind release --artifacts-dir desktop/build-artifacts/macos-arm64 --require-macos-gatekeeper预期失败,但输出现在同时包含spctl、codesign和notarization ticket validation诊断,当前 ad-hoc app 被分类为没有 stapled notarization ticket。 - 2026-06-01 Gatekeeper 当前态复跑:
bun run test:package-smoke --platform macos --package-kind release --artifacts-dir desktop/build-artifacts/macos-arm64通过,确认 release artifact 结构、latest-mac.yml引用 zip、app-update.yml、sidecar 和node-pty完整;追加--require-macos-gatekeeper后仍失败,codesignverify/details 通过但spctl返回bundle format unrecognized, invalid, or unsuitable,stapler返回does not have a ticket stapled to it。package-smoke 现已在spctl报Too many open files时用 raised file descriptor limit 自动重试,避免该临时诊断掩盖真实 Gatekeeper 结果。release-ready 仍需要 Developer ID signing/notarization 或真实签名产物复验。 - 2026-06-01 Gatekeeper 诊断补强后 Computer Use 复测:用隔离
CLAUDE_CONFIG_DIR和--user-data-dir启动desktop/build-artifacts/electron/mac-arm64/Claude Code Haha.app,Computer Use 成功读取Claude Code Companion主窗口和 packagedfile://.../app.asar/dist/index.htmlrenderer,证明 package-smoke 诊断补强未破坏 packaged app 运行路径。 - 2026-06-01 release gate 口径收紧:
quality:gate --mode release的当前平台desktop-package-smoke:macoslane 现在会追加--require-macos-gatekeeper,与 GitHub release workflow 上传前 Gatekeeper 检查保持一致。验证:bun test scripts/quality-gate/runner.test.ts scripts/quality-gate/package-smoke/index.test.ts scripts/pr/release-workflow.test.ts通过 39 tests;bun run quality:gate --mode release --dry-run --only 'desktop-package-smoke:*'报告命令包含--require-macos-gatekeeper;实际运行bun run quality:gate --mode release --only 'desktop-package-smoke:*'失败于 Gatekeeper,报告为artifacts/quality-runs/2026-06-01T12-16-06-442Z/report.md。 - 2026-06-01 当前 release provider smoke 复验:
bun run quality:gate --mode release --allow-live --only 'provider-smoke:*' --provider-model sub2api-chatgpt:main:sub2api-chatgpt-main通过,报告为artifacts/quality-runs/2026-06-01T12-18-47-144Z/report.md;随后用 Computer Use 启动隔离 packaged app,成功读取Claude Code Companion主窗口和 packagedfile://.../app.asar/dist/index.htmlrenderer。 - 2026-06-01 governance gate 复验:
bun run check:policy通过 77 tests,并执行check:quarantine,覆盖 release workflow、quality gate runner、provider/desktop smoke、change policy、quality contract 和 quarantine governance。随后用 Computer Use 再次启动隔离 packaged app;首次读取遇到 ScreenCaptureKit stream error,但 System Events 显示同一 PID 有Claude Code Companion窗口,重试后 Computer Use 成功读取 packagedfile://.../app.asar/dist/index.htmlrenderer。 - 2026-06-01 本地
main同步后复验:已把本地main最近 10 个提交的非重叠改动应用到当前迁移工作区,并手动合并ChatInput.tsx/previewEvents.ts/previewEvents.test.ts中的 append prefill 与 ElectrondesktopHost.preview改造。验证:cd desktop && bun run test -- --run src/components/chat/ChatInput.test.tsx src/lib/previewEvents.test.ts通过 24 tests;bun test src/cli/__tests__/structuredIO.test.ts src/services/api/withRetry.test.ts src/utils/__tests__/imageResizer.test.ts src/utils/shell/powershellDetection.test.ts src/server/__tests__/providers.test.ts src/server/__tests__/conversation-service.test.ts src/server/__tests__/conversation-attachments.test.ts src/server/__tests__/websocket-handler.test.ts通过 124 tests;cd adapters && bun test feishu/__tests__/streaming-card.test.ts通过 36 tests;cd desktop && bun run check:electron通过 94 tests;CSC_IDENTITY_AUTO_DISCOVERY=false bun run electron:package:dir重新生成 packaged dir;bun run test:package-smoke --platform macos --package-kind dir --artifacts-dir desktop/build-artifacts/electron通过;Computer Use 成功读取新打包的desktop/build-artifacts/electron/mac-arm64/Claude Code Haha.app主窗口和 packaged renderer。 - 2026-06-01 release update blockmap 验证补强:
package-smoke的 release 模式现在强制检查 macOS.zip/.dmg.blockmap、Windows.exe.blockmap和 Linux.AppImage.blockmap,避免只有 channel metadata 和安装包但缺少 electron-updater 差分更新文件。验证:bun test scripts/quality-gate/package-smoke/index.test.ts通过 17 tests;bun run test:package-smoke --platform macos --package-kind release --artifacts-dir desktop/build-artifacts/macos-arm64通过,并确认当前 macOS release artifact set 含.dmg.blockmap和.zip.blockmap。 - 2026-06-01 packaged update smoke 补强:新增
CC_HAHA_ELECTRON_UPDATE_SMOKE_VERSION驱动的 Electron main updater stub,仅在显式 smoke env 下启用;app-update.yml缺失不会阻断该 smoke stub,生产electron-updater仍保持缺失 metadata 时 no-op。验证:cd desktop && bun run check:electron通过 94 tests;CSC_IDENTITY_AUTO_DISCOVERY=false bun run electron:package:dir生成新的 packaged dir;复制为唯一 bundle id 的 smoke app 后,packaged rendererfile://.../app.asar/dist/index.html通过 preload 调用desktopHost.updates.check/download/prepareInstall/install/relaunch,JSONL 记录check、download-start、download-finish、quit-and-install。同轮 Computer Uselist_apps可见唯一 smoke app,但get_app_state对该 app 仍超时,故真实“点击安装”仍不能声明通过。 - 2026-06-01 packaged window smoke 诊断:新增
CC_HAHA_ELECTRON_WINDOW_SMOKE_LOG,main process 在after-create、after-initial-show、did-finish-load和after-final-show写入窗口快照。早前同一 packaged dir 启动日志显示 ElectronBrowserWindow已visible:true,bounds 为1280x820,URL 为 packagedfile://.../app.asar/dist/index.html,但 System Events 曾读取到windows count=0且 Computer Useget_app_state超时;随后用完整.app路径复测,Computer Use 成功读取Claude Code Companion主窗口和 packaged renderer,System Events 返回front=true count=1 names=Claude Code Companion。当前结论是之前的卡点在 macOS AX/窗口捕获状态波动,不是 renderer、server、更新 preload smoke 或关闭智能体流程。 - 2026-06-01 packaged notification click 复测:直接执行 app binary 时 smoke env 未进入最终 Electron app 进程,改用
launchctl setenv+open -n ... --args --user-data-dir=<tmp>后,packaged app 的CC_HAHA_ELECTRON_NOTIFICATION_SMOKE_LOG正常写入scheduled和sent:true。Computer Use 对/System/Library/CoreServices/NotificationCenter.app和SystemUIServer仍返回timeoutReached,Finder 状态读取返回 ScreenCaptureKit stream error,JSONL 未出现action;因此“点击通知回到目标 session”仍保持未完成。 - 2026-06-01 通知点击再次复测:用
launchctl setenv启动 worktree packaged app 后,JSONL 正常写入scheduled和sent:true,但 Computer Use 对该 worktree app 连续返回 ScreenCaptureKit stream error;list_apps能看到 worktree app running。随后复制当前 packaged app 为唯一 bundle id smoke app 并 ad-hoc 重签名,LaunchServices 能注册该 smoke app,但应用立即退出,系统日志显示 appDeath;因此本轮仍不能把真实 OS 通知点击回跳勾选为完成。 - 2026-06-01 当前全量桌面/服务端门禁复验:
cd desktop && bun run check:desktop通过 desktop lint、151 个 Vitest 文件、1199 个测试和 production build;bun run check:server通过 88 files / 969 tests。通知真实点击、signed/notarized Gatekeeper、Windows/Linux 实机 release smoke 仍保持未完成项。 - 2026-06-01 通知点击 renderer ack 补强:新增 Electron
desktop:notification:action-ackIPC,renderer 处理通知 action 并打开目标 session 后,会把{ target, payload }写入CC_HAHA_ELECTRON_NOTIFICATION_SMOKE_LOG的renderer_ack事件。该补强不模拟 OS 点击,只让后续可点击通知的 macOS/Windows runner 能证明 main action 已进入 UI 导航链路。验证:focused notification/desktopHost tests 42 passed;cd desktop && bun run check:electron通过 97 tests;CSC_IDENTITY_AUTO_DISCOVERY=false bun run electron:package:dir重新生成 packaged dir;bun run test:package-smoke --platform macos --package-kind dir --artifacts-dir desktop/build-artifacts/electronPASS。 - 2026-06-01 renderer ack 补强后 Computer Use 复测:用隔离
CLAUDE_CONFIG_DIR、隔离--user-data-dir和 notification smoke env 启动当前 worktree packaged app 时,Computer Use 首次get_app_state返回timeoutReached,直接执行也曾退出 137。随后用隔离CLAUDE_CONFIG_DIR/--user-data-dir重新直接运行同一.app后保持运行,Computer Use 成功读取Claude Code Companion主窗口,renderer URL 为当前 worktree 的 packagedfile://.../app.asar/dist/index.html;点击设置入口后进入 packaged 设置页。该轮确认当前 Electron build 可被 Computer Use 读取和交互;spctl -a -t execute desktop/build-artifacts/electron/mac-arm64/Claude Code Haha.app仍返回bundle format unrecognized, invalid, or unsuitable,codesign --verify --deep --strict通过,因此真实 OS 通知点击和 signed/notarized launch 仍未完成。 - 2026-06-01 packaged synthetic notification action 复测:新增显式 smoke-only 开关
CC_HAHA_ELECTRON_NOTIFICATION_SMOKE_TRIGGER_ACTION=1,只在测试环境中由 main process 对刚发送的通知 action 触发同一条 renderer ack 链路。用launchctl setenv+open -n desktop/build-artifacts/electron/mac-arm64/Claude Code Haha.app --args --user-data-dir=<tmp>启动当前 worktree packaged app 后,Computer Use 成功读取Claude Code Companion,renderer URL 为file:///Users/nanmi/.codex/worktrees/2392/claude-code-haha/desktop/build-artifacts/electron/mac-arm64/Claude%20Code%20Haha.app/Contents/Resources/app.asar/dist/index.html;JSONL 记录scheduled、sent:true、synthetic_action和renderer_ack。该 synthetic action 仅证明 packaged main -> renderer action -> ack 链路,不替代真实 OS 通知点击;真实“点击通知后回到目标 session”仍未完成。
Review 收口记录
2026-05-31 SubAgent Review
- [x] Security Review:收紧 packaged renderer entry,packaged app 不再接受
ELECTRON_RENDERER_URL;dev 模式只允许 local HTTP renderer。 - [x] Security Review:preview bridge 增加大小上限、事件 allowlist、字段 schema、
data:image/*校验,外部页面不能向 host 注入无限大或未知事件。 - [x] Security Review:packaged macOS
node-ptyruntime cache 增加 manifest 校验、tamper 后重建、cache/helper 权限收紧。 - [x] Code Review:macOS “打开通知设置”改走 native command 和 allowlisted system settings URL。
- [x] Code Review:Electron
preview.message()改为转发到 injected preview bridge,不再 silent no-op。 - [x] Code Review:dev/release desktop workflows 在 Electron builder 后运行
test:package-smoke,避免上传缺少 sidecar 或node-pty关键资源的产物。 - [x] Verification Review:新增
docs/desktop/09-electron-migration-validation-checklist.md,明确package-smoke只是结构预检,最终完成仍需要真实 packaged app + Computer Use/实机 smoke。 - [x] Release gate follow-up:
desktop-smoke:agent-browser-chat:*保留为 baseline/browser confidence lane,不再作为 release 必需 lane;release mode 新增desktop-package-smoke:<platform>,用当前平台 Electron packaged artifact 结构检查配合 Computer Use 真实 app 验收,避免用浏览器/Vite open 结果代表桌面构建可用性。
最终完成定义
- [x]
desktop/src生产代码不再直接依赖@tauri-apps/*。 - [x] Electron main/preload IPC 有 capability registry 和 payload validation。
- [x] 本地 Bun server + REST/WebSocket contract 保留,renderer 没有把 session/chat/workspace/team 主链改成 IPC。
- [x] 自动更新、通知、文件选择、外链打开、窗口/托盘/菜单、sidecar、terminal、preview、app mode、zoom 全部有测试或 smoke 证据。
- [ ] macOS、Windows、Linux 发布产物可构建并启动。
- [x]
bun run verify通过。 - [x] release gate 通过,或 live provider blocker 被明确记录。
- [ ] Computer Use 对真实打包 app 完成全面测试。
最终定义复核(2026-06-01):
- 生产 Tauri 边界扫描通过:
rg -n "@tauri-apps|__TAURI_INTERNALS__|window\\.__TAURI__|from ['\\\"]@tauri" desktop/src --glob '!**/*.test.ts' --glob '!**/*.test.tsx' --glob '!**/lib/desktopHost/**' --glob '!src-tauri/**'无输出。 - Electron IPC 复核通过:
desktop/electron/ipc/capabilities.ts为每个ELECTRON_IPC_CHANNELSchannel 定义 validator,desktop/electron/main.ts的registerHandler()在进入 handler 前执行isElectronIpcChannel()和validateElectronIpcPayload();rendererelectronHost也在 preload bridge 调用前执行相同 payload validation。 - REST/WebSocket 主干复核通过:session/workspace/team 仍在
desktop/src/api/sessions.ts、desktop/src/api/teams.ts、desktop/src/api/websocket.ts调用/api/**和/ws/:sessionId;Electron IPC 命中仅覆盖 host/system 能力、terminal 和 preview,不承载 chat/session/workspace/team 主业务。 - 系统能力证据复核通过:Electron service/API tests 覆盖 updater、notifications、dialogs、shell、windows/tray/menu/single-instance、sidecar、terminal、preview、app mode、zoom;macOS
.dmg/.zip/latest-mac.ymlcanonical release artifact set 已通过package-smoke,canonical.app已通过 Computer Use 窗口可见性 smoke;完整完成仍受 signed/notarized Gatekeeper、通知真实点击、Windows/Linux 实机发布格式 smoke 阻塞。