Introduce the Electron desktop shell alongside the existing React renderer and local Bun server boundary. The migration keeps the DesktopHost contract explicit across Tauri, Electron, and browser runtimes while adding Electron main/preload services for dialogs, shell, notifications, updates, tray/window lifecycle, terminal, preview WebContentsView, app mode, and release/package validation.
The commit also carries the latest local main desktop command updates, including agent slash entries and hidden-by-default markdown thinking details, so the packaged Electron build matches the current main UX surface.
Constraint: React renderer, local Bun server, REST/WebSocket, and sidecar boundaries must remain reusable during the migration
Constraint: macOS dev packages are ad-hoc signed and cannot prove Developer ID notarization or Gatekeeper release launch
Rejected: Browser-only smoke validation | it cannot exercise native dialogs, keychain prompts, notification behavior, or packaged app startup
Confidence: medium
Scope-risk: broad
Directive: Do not remove Tauri host support until signed Electron release artifacts pass native OS smoke on macOS, Windows, and Linux
Tested: bun run check:desktop
Tested: cd desktop && bun run check:electron
Tested: CSC_IDENTITY_AUTO_DISCOVERY=false bun run electron📦dir
Tested: bun run test:package-smoke --platform macos --package-kind dir --artifacts-dir desktop/build-artifacts/electron
Tested: Computer Use read packaged Electron app window at desktop/build-artifacts/electron/mac-arm64/Claude Code Haha.app
Not-tested: Developer ID signed/notarized Gatekeeper launch
Not-tested: Real OS notification click-to-session action
Not-tested: Windows and Linux packaged app smoke on real hosts
84 KiB
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/**
步骤:
- 运行
git status --short,确认当前工作区是否有无关改动。 - 运行
bun run check:policy。 - 运行
bun run check:desktop。 - 运行
bun run check:server。 - 运行
bun run check:coverage。 - 有 live provider 时运行
bun run quality:gate --mode baseline --allow-live --provider-model <provider:model[:label]>。 - 记录 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
步骤:
- 定义
DesktopHost接口,至少覆盖runtime/server URL、updates、notifications、dialogs、shell、window、terminal、preview、appMode。 - 在
browserHost中保留 H5/browser fallback:没有桌面能力时返回明确错误或 no-op。 - 在 contract test 中固定每个方法的 payload 和错误语义。
- 运行
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、聊天链接打开组件
步骤:
- 把
@tauri-apps/api/core.invoke包进tauriHost.commands.invoke或具体方法。 - 把 Tauri
listen包进desktopHost.events。 - 把 dialog/shell/window/update/notification 调用全部迁到
tauriHost。 - 运行
rg "@tauri-apps|__TAURI_INTERNALS__|window\\.__TAURI__|from '@tauri" desktop/src。 - 确认生产代码只在
desktop/src/lib/desktopHost/tauriHost.ts命中。 - 运行
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
步骤:
- 新增
electron:dev、electron:build、check:electron脚本。 BrowserWindow使用 preload,保持contextIsolation,不启用 renderer Node。- preload 暴露
window.desktopHost,不暴露通用ipcRenderer。 capabilities.ts枚举允许的 IPC channel 和 payload validator。- 运行
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
步骤:
- 复刻
start_server_sidecar:保留动态端口、host、config、startup log、超时错误。 - 复刻 adapter sidecar 启动和
restart_adapters_sidecar。 - 保留
CLAUDE_CONFIG_DIR、CC_HAHA_APP_PORTABLE_DIR、ADAPTER_SERVER_URL注入。 - 提供
get_server_url等价 IPC。 - 确认 renderer 仍通过
desktop/src/api/client.ts和 WebSocket manager 访问会话/聊天/workspace/team,不新增这些业务的 IPC handler。 - 运行
bun run check:electron。 - 打开 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
步骤:
openFile、openDirectory、saveFile映射到 Electron dialog。openExternal限制 URL scheme,openPath限制为明确来自文件选择或 workspace 的路径。- 更新 adapter contract tests。
- 运行
bun run check:desktop && bun run check:electron。 - 手动 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
步骤:
- 实现 minimize/toggleMaximize/close/startDragging。
- 实现关闭隐藏到托盘、托盘 show/quit。
- 实现 macOS About/Settings 菜单并发送
native-menu-navigate等价事件。 - 实现窗口位置/尺寸持久化和 monitor 可见性保护。
- 实现
app.requestSingleInstanceLock(),第二实例显示主窗口。 - 运行
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
步骤:
- 实现权限状态、请求权限、发送通知。
- 实现通知点击回跳并传递 target。
- Windows 保留打开系统通知设置入口。
- macOS 若 Electron
Notification无法满足权限/点击语义,保留 native bridge 或补原生模块。 - 运行
bun run check:electron。 - 运行
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
步骤:
- 选定
electron-builder+electron-updater,不要用 Electron 内置 updater 覆盖 Linux。 - 保留
check -> download -> progress -> install -> relaunch状态机。 install前调用 sidecar manager 停止 server/adapters,失败后恢复可重试状态。- 建立 mock update feed 测试。
- macOS 签名/zip metadata、Windows NSIS metadata、Linux AppImage/deb update 策略写入 Electron build metadata。
- 运行
bun run check:electron。 - 运行
bun run check:desktop。 - 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
步骤:
- 明确 PTY 实现:保留 Rust sidecar command 或引入 Node PTY 方案。
- 实现 spawn/write/resize/kill 和 output/exit event。
- 保留 terminal shell 配置读写语义。
- 运行
bun run check:desktop && bun run check:electron。 - 打包 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
步骤:
- 使用
WebContentsView,不要用已弃用的BrowserView。 - 保留
http/httpsURL 白名单。 - 保留 preview agent 注入和 JSON 消息校验。
- 实现 open/navigate/setBounds/setVisible/close/eval/message。
- 运行
bun run check:desktop && bun run check:electron。 - 打包 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
步骤:
- 保留
get_app_mode、set_app_mode、detect_portable_dir返回形状。 - 保留同时写系统默认配置目录和 portable 目录的语义。
- zoom 继续 clamp 到
0.5..2.0。 - 运行
bun run check:persistence-upgrade。 - 运行
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
步骤:
- 保留
desktop build作为 renderer build。 - 保留
build:sidecars。 - 新增 Electron package 脚本,输出到
desktop/build-artifacts/<platform>。 check:native替换为 Electron main/preload/package config check,或新增check:electron并让quality:gate使用它。- 运行
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
步骤:
- 移除
tauri-apps/tauri-action@v0。 - 移除 Linux WebKitGTK/Rust/Tauri 专用依赖,保留 Electron/Linux 打包需要的依赖。
- 配置 macOS arm64/x64、Windows x64、Linux x64/arm64 matrix。
- 配置 signing/notarization/update metadata secrets。
- 让 PR/change policy 识别
desktop/electron/**和 Electron build config。 - 运行
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
步骤:
- 版本来源从
desktop/src-tauri/tauri.conf.json改为 Electron package/build config。 - 删除
Cargo.toml/Cargo.lockrelease 更新。 - 保留 release note 校验、commit、tag 流程。
- 运行
bun run scripts/release.ts <next-version> --dry。 - 运行
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、通知、更新策略。
- 运行
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
步骤:
- 运行
bun run verify。 - 有 live provider 时运行
bun run quality:gate --mode release --allow-live --provider-model <provider:model[:label]>。 - 检查 quality report 的 pass/fail/skip。
- 记录 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 全面测试
步骤:
- 用真实打包 app 运行 Computer Use 设置流程。
- 验证 Python 路径选择、权限授权、屏幕录制/辅助功能授权提示、授权应用列表。
- 验证点击、输入、滚动、系统快捷键、剪贴板。
- 验证通知点击回到目标会话。
- 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
- Security Review:收紧 packaged renderer entry,packaged app 不再接受
ELECTRON_RENDERER_URL;dev 模式只允许 local HTTP renderer。 - Security Review:preview bridge 增加大小上限、事件 allowlist、字段 schema、
data:image/*校验,外部页面不能向 host 注入无限大或未知事件。 - Security Review:packaged macOS
node-ptyruntime cache 增加 manifest 校验、tamper 后重建、cache/helper 权限收紧。 - Code Review:macOS “打开通知设置”改走 native command 和 allowlisted system settings URL。
- Code Review:Electron
preview.message()改为转发到 injected preview bridge,不再 silent no-op。 - Code Review:dev/release desktop workflows 在 Electron builder 后运行
test:package-smoke,避免上传缺少 sidecar 或node-pty关键资源的产物。 - Verification Review:新增
docs/desktop/09-electron-migration-validation-checklist.md,明确package-smoke只是结构预检,最终完成仍需要真实 packaged app + Computer Use/实机 smoke。 - 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 结果代表桌面构建可用性。
最终完成定义
desktop/src生产代码不再直接依赖@tauri-apps/*。- Electron main/preload IPC 有 capability registry 和 payload validation。
- 本地 Bun server + REST/WebSocket contract 保留,renderer 没有把 session/chat/workspace/team 主链改成 IPC。
- 自动更新、通知、文件选择、外链打开、窗口/托盘/菜单、sidecar、terminal、preview、app mode、zoom 全部有测试或 smoke 证据。
- macOS、Windows、Linux 发布产物可构建并启动。
bun run verify通过。- 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 阻塞。