# 开机自动启动功能复制计划 ## 1. 目标与结论 目标是在 `zn-ai/src/pages/Setting/components/GeneralSettingsPanel.tsx` 中复制 `ClawX` 的“开机自动启动”能力,并把视觉位置排在“语言设置”后面、“网关设置”前面。 先给结论: - `ClawX` 的“开机自动启动”不是单纯的前端 `Switch`,而是“设置持久化 + 主进程 OS 级生效 + 启动时回放同步”的完整链路。 - `zn-ai` 已经具备可复用的设置基础设施:`settingsStore`、`config-service`、`SET_CONFIG/GET_CONFIG` IPC、`/api/settings` 本地路由。 - `zn-ai` 当前没有 `launchAtStartup` 配置键,也没有任何 OS 级自启动应用逻辑。 - 这次复制不需要新增复杂的状态 hook、也不需要新增 preload 专用桥接;最小可行方案是复用现有设置存取链路,只补 `launchAtStartup` 配置模型和主进程副作用。 ## 2. ClawX 现有实现拆解 ### 2.1 渲染层 UI 结构 `ClawX/src/pages/Settings/index.tsx` 中,“开机自动启动”位于通用设置区块内,紧跟在语言设置后面,位于 Gateway 区块前: - 主题按钮组 - 语言按钮组 - `launchAtStartup` 开关 - `Separator` - Gateway 区块 对应 UI 代码位置: - `ClawX/src/pages/Settings/index.tsx:528` - `ClawX/src/pages/Settings/index.tsx:545` 交互特征: - 左侧是标题和说明文案。 - 右侧是一个 `Switch`。 - 没有额外保存按钮,属于“切换即保存”。 - 没有单独 loading/error 状态,也没有回滚提示。 ### 2.2 渲染层状态链路 `ClawX` 渲染层把 `launchAtStartup` 放在 `settings` store 中统一管理: - 字段定义:`ClawX/src/stores/settings.ts:19` - 默认值:`ClawX/src/stores/settings.ts:72` - 初始化从 `/api/settings` 拉取:`ClawX/src/stores/settings.ts:86` - setter 里直接调用 `/api/settings/launchAtStartup`:`ClawX/src/stores/settings.ts:132` 实现特征: - 先本地 `set({ launchAtStartup })`,再异步请求主进程。 - 请求失败时静默吞掉,没有回滚。 - 这和 `gatewayAutoStart`、`theme`、`language` 是同一类“轻量即改即存”模式。 ### 2.3 i18n 文案 `ClawX` 使用 `settings.appearance` 下的两个键: - `launchAtStartup` - `launchAtStartupDesc` 对应位置: - 中文:`ClawX/src/i18n/locales/zh/settings.json:12` - 英文:`ClawX/src/i18n/locales/en/settings.json:12` - 日文:`ClawX/src/i18n/locales/ja/settings.json:12` ### 2.4 主进程与 Host API 链路 `ClawX` 的主进程实现分成 4 层: 1. 持久化配置 - `ClawX/electron/utils/store.ts:24` - `launchAtStartup` 被定义为 `AppSettings` 字段,默认值为 `false` 2. 设置路由 - `ClawX/electron/api/routes/settings.ts:27` - `PUT /api/settings` - `PUT /api/settings/launchAtStartup` - `POST /api/settings/reset` - 只要 patch/key 触达 `launchAtStartup`,都会执行 `syncLaunchAtStartupSettingFromStore()` 3. OS 级应用逻辑 - `ClawX/electron/main/launch-at-startup.ts:1` - Windows/macOS:`app.setLoginItemSettings({ openAtLogin, openAsHidden: false })` - Linux:写入或删除 `~/.config/autostart/clawx.desktop` - 错误只记录日志,不向上抛出 4. 启动时同步 - `ClawX/electron/main/index.ts:298` - 应用启动后会从 store 读取 `launchAtStartup`,再回放到操作系统 ### 2.5 测试覆盖 `ClawX` 已经对 OS 级逻辑做了单元测试: - `ClawX/tests/unit/launch-at-startup.test.ts` 覆盖点: - Windows `setLoginItemSettings` - macOS `setLoginItemSettings` - Linux `.desktop` 文件创建/删除 - 非支持平台不抛异常 ## 3. zn-ai 当前现状 ### 3.1 已有可复用能力 `zn-ai` 已经具备以下基础: - 通用设置 UI:`zn-ai/src/pages/Setting/components/GeneralSettingsPanel.tsx` - 设置页容器:`zn-ai/src/pages/Setting/index.tsx` - 自定义开关组件:`zn-ai/src/pages/Setting/components/ToggleSwitch.tsx` - 全局设置 store:`zn-ai/src/stores/settings.ts` - 配置持久化:`zn-ai/electron/service/config-service.ts` - 通用设置本地路由:`zn-ai/electron/api/routes/settings.ts` - 主进程初始化入口:`zn-ai/electron/main.ts` ### 3.2 关键差异 和 `ClawX` 相比,`zn-ai` 当前的关键差异有 5 个: 1. `launchAtStartup` 不在 `ConfigValueMap` 中 - `zn-ai/src/types/runtime.ts` - `zn-ai/runtime-shared/lib/constants.ts` - `zn-ai/runtime-shared/lib/types.ts` 2. `settingsStore` 只管理 `gatewayAutoStart`,没有 `launchAtStartup` - `zn-ai/src/stores/settings.ts` 3. `config-service` 默认配置里没有 `launchAtStartup` - `zn-ai/electron/service/config-service.ts` 4. 主进程没有 OS 级开机自启动服务 - `zn-ai/electron` 下目前不存在 `launch-at-startup` 模块 5. `zn-ai` 的设置主写路径不是 Host API,而是 `SET_CONFIG` IPC - `zn-ai/src/stores/settings.ts` - `zn-ai/electron/service/config-service.ts` 这意味着: - 不能只在 `/api/settings` 路由里补副作用。 - 必须覆盖到 `SET_CONFIG` 这条实际写入通路,否则 UI 开关会“写进配置但不生效到系统”。 ## 4. 复制范围与非目标 ### 4.1 本次复制范围 只复制 `ClawX` 的这一项能力: - “开机自动启动”开关 - 配套说明文案 - 配置持久化 - 主进程 OS 级应用 - 应用启动时回放同步 ### 4.2 明确不做的内容 这次不要把以下内容一起带进来: - `startMinimized` - `minimizeToTray` - Gateway 自动启动 - 代理设置 - 日志目录打开 - 开发者模式 - Telemetry 原因: - 这些不是 `ClawX`“开机自动启动”功能的必要组成。 - 一起迁移会把范围从“复制单一功能”扩大成“重新设计通用设置”。 ## 5. zn-ai 的最小复制方案 ### 5.1 UI 方案 在 `zn-ai/src/pages/Setting/components/GeneralSettingsPanel.tsx` 中,把新行插在语言设置后面: - 保持和现有设置页一致的 `border-b` 行布局 - 左侧:标题 + 描述 - 右侧:复用 `ToggleSwitch` 建议结构: 1. 主题设置 2. 语言设置 3. 开机自动启动 4. Gateway 5. 更新 说明: - 不需要新建卡片。 - 不需要新建 section header。 - 不需要新建独立 hook。 - 这项功能足够简单,沿用 `themeMode/language` 的 props 传递模式即可。 ### 5.2 状态与设置层方案 推荐在 `zn-ai/src/stores/settings.ts` 中新增: - `launchAtStartup: boolean` - `updateLaunchAtStartup(launchAtStartup: boolean, persist = true)` 并在 `SettingsState`、`createInitialState()`、`hydrate()` 中补齐: - 读取 `CONFIG_KEYS.LAUNCH_AT_STARTUP` - 默认值 `false` `GeneralSettingsPanel` 通过 props 收到: - `launchAtStartup` - `onLaunchAtStartupChange` `Setting/index.tsx` 负责从 `useSettingsStore` 取值并透传。 ### 5.3 配置模型方案 需要同时修改以下位置,保证 key 一致: - `zn-ai/runtime-shared/lib/constants.ts` - `zn-ai/runtime-shared/lib/types.ts` - `zn-ai/src/types/runtime.ts` - `zn-ai/electron/service/config-service.ts` 建议新增 key: - `launchAtStartup` 默认值建议: - `false` 原因: - 与 `ClawX` 保持一致。 - 对桌面应用更保守,避免首次启动时直接注册系统自启动。 ### 5.4 主进程方案 建议新增模块: - `zn-ai/electron/service/launch-at-startup.ts` 职责直接对齐 `ClawX`,但把应用标识替换为 `zn-ai` 当前产品信息: - Windows/macOS - `app.setLoginItemSettings({ openAtLogin: enabled, openAsHidden: false })` - Linux - 写入或删除 `~/.config/autostart/*.desktop` - 不能直接照搬 `clawx.desktop` - `Name`、`Comment`、桌面文件名需要改成 zn-ai 当前产品名 建议暴露两个函数: - `applyLaunchAtStartupSetting(enabled: boolean)` - `syncLaunchAtStartupSettingFromStore()` ### 5.5 副作用挂载位置 这是本次复制里最关键的实现点。 因为 `zn-ai` 当前 renderer 主要通过 `SET_CONFIG` IPC 写设置,所以副作用至少要覆盖两条路径: 1. `SET_CONFIG` / `UPDATE_CONFIG` - 位置:`zn-ai/electron/service/config-service.ts` - 当 key 或 patch 触达 `launchAtStartup` 时,调用 `applyLaunchAtStartupSetting(...)` 2. 应用启动回放 - 位置:`zn-ai/electron/main.ts` - `await configManager.init()` 之后调用 `syncLaunchAtStartupSettingFromStore()` 一致性建议: - `zn-ai/electron/api/routes/settings.ts` 也补齐同样的副作用。 - 虽然当前 UI 主通路不是走这个 route,但本地 Host API 应该与 IPC 行为一致。 ## 6. 文件级改动清单 ### 6.1 渲染层 - `zn-ai/src/pages/Setting/components/GeneralSettingsPanel.tsx` - `zn-ai/src/pages/Setting/index.tsx` - `zn-ai/src/stores/settings.ts` - `zn-ai/src/i18n/messages.ts` - `zn-ai/src/types/runtime.ts` ### 6.2 共享常量与类型 - `zn-ai/runtime-shared/lib/constants.ts` - `zn-ai/runtime-shared/lib/types.ts` ### 6.3 主进程 - `zn-ai/electron/service/config-service.ts` - `zn-ai/electron/service/launch-at-startup.ts`(新增) - `zn-ai/electron/api/routes/settings.ts` - `zn-ai/electron/main.ts` ### 6.4 测试 - `zn-ai/tests/launch-at-startup.test.ts`(建议新增) ## 7. 关键风险与处理建议 ### 7.1 双写路径风险 风险: - `SET_CONFIG` IPC 和 `/api/settings` route 都能改配置。 - 如果只给其中一条路径挂副作用,会出现“配置值正确但系统登录项没同步”的假成功。 处理: - 两条路径都挂同一个 helper。 ### 7.2 Linux 桌面文件元数据风险 风险: - 直接复制 `ClawX` 的 `clawx.desktop`、`Name=ClawX` 会导致 Linux 桌面环境识别错误。 处理: - 使用 zn-ai 当前产品名、可执行路径和桌面文件名。 - 优先通过 `app.getName()` / `process.execPath` 生成,而不是写死 ClawX 文案。 ### 7.3 产品名文案不一致风险 风险: - `package.json` 中 `productName` 是 `NIANXX`,但前端文案里大量使用 `ZN-AI`。 处理: - 本次设置说明文案优先使用“应用”或“系统登录后自动启动”这种泛化表达。 - 不在这次迁移里额外引入品牌命名统一改造。 ### 7.4 静默失败体验风险 风险: - `ClawX` 的写法对失败是静默吞掉,用户可能看不出 OS 级注册失败。 处理: - 第一版可以保持与 `ClawX` 相同的轻量体验。 - 如果后续需要提高可观测性,再补 toast 或错误文案,但这不属于这次最小复制范围。 ## 8. 推荐实施顺序 ### Phase 1:主进程能力补齐 1. 新增 `launchAtStartup` config key 2. 新增 `launch-at-startup` 服务 3. 在 `config-service` 和 `/api/settings` 中挂副作用 4. 在 `electron/main.ts` 启动时回放同步 ### Phase 2:渲染层接入 1. `settingsStore` 增加 `launchAtStartup` 2. `Setting/index.tsx` 透传 prop 3. `GeneralSettingsPanel.tsx` 在语言设置后插入 UI 4. `messages.ts` 补三语文案 ### Phase 3:验证 1. `typecheck` 2. `launch-at-startup` 单元测试 3. 手动验证设置页切换 4. 手动验证 Windows/macOS/Linux 的系统登录项行为 ## 9. 最小测试集合 建议至少覆盖以下 4 类验证: 1. 单元测试 - Windows/macOS 调用 `app.setLoginItemSettings` - Linux `.desktop` 创建/删除 2. 配置链路测试 - 改写 `launchAtStartup` 后,`configManager` 中值已更新 3. 渲染层回归 - 设置页中开关显示在语言设置后面 - 开关值能和 store 状态联动 4. 启动同步验证 - 应用启动后能读取持久化值并重新应用 OS 级自启动 ## 10. sub-agent 估算与分工 ### 10.1 推荐数量 推荐 `3` 个 sub-agent。 理由: - 这次复制的改动面天然分成“渲染层”“配置/状态链路”“主进程 OS 级服务”三块。 - 三块之间耦合度低,适合并行推进。 - 再往上拆会让协同成本高于收益。 ### 10.2 分工建议 #### Worker 1:渲染层与 i18n 负责文件: - `zn-ai/src/pages/Setting/components/GeneralSettingsPanel.tsx` - `zn-ai/src/pages/Setting/index.tsx` - `zn-ai/src/i18n/messages.ts` 职责: - 在语言设置后插入 UI - 接入 `launchAtStartup` prop - 补齐中英日文案 - 确保视觉风格与现有设置页一致 #### Worker 2:设置模型与配置链路 负责文件: - `zn-ai/src/stores/settings.ts` - `zn-ai/src/types/runtime.ts` - `zn-ai/runtime-shared/lib/constants.ts` - `zn-ai/runtime-shared/lib/types.ts` 职责: - 新增 `launchAtStartup` 配置键和类型 - 在 store 中完成读取、更新、对外导出 - 保证 renderer 能通过现有设置链路读写该值 #### Worker 3:主进程自启动服务与测试 负责文件: - `zn-ai/electron/service/launch-at-startup.ts` - `zn-ai/electron/service/config-service.ts` - `zn-ai/electron/api/routes/settings.ts` - `zn-ai/electron/main.ts` - `zn-ai/tests/launch-at-startup.test.ts` 职责: - 实现跨平台 OS 级自启动逻辑 - 把副作用挂到配置写入与启动同步节点 - 补齐最小单元测试 ## 11. 最终建议 这次复制应严格控制在“ClawX 的 launchAtStartup 单功能迁移”范围内推进。 建议落地原则: - UI 只加一行,不做新的设置分组。 - 状态层只加一个布尔配置,不新建复杂 hook。 - 主进程只加一个独立服务,不顺手扩散到别的系统设置功能。 - 测试优先覆盖 OS 级副作用,而不是先写大量 UI 测试。 按这个方案推进,能以最小代价把 `ClawX` 的成熟能力复制到 `zn-ai`,同时避免出现“只做了开关外观、没有真正接到系统登录项”的伪完成状态。