正式 macOS App 在安装或更新后的首次启动同步本机 Web。只有复制 App、尚未打开时,不执行安装脚本。手机和远程服务器不参与这个过程。
| 当前 Web | App 行为 |
|---|---|
| 尚未安装 | 使用 App 携带的预编译服务和 Node 安装独立后台服务 |
| 版本较旧,或同版本且提交是 App 构建的祖先 | 等待空闲后向上同步 |
| 同一构建/同一干净提交 | 直接连接 |
| 发布版本或同版本提交更新 | 保留当前 Web |
| 同版本分支关系不明、无法识别的工作区快照 | 启动页提供“使用当前 App 覆盖同版本 Web”,由用户明确选择 |
build-info.json 包含提交、构建序号、祖先提交、工作区状态和构建时间;构建序号仅用于展示,提交的先后必须有祖先关系,不能比较哈希字典序或文件时间。runtime-manifest.json 对完整服务包逐文件计算 SHA-256,并拒绝额外文件、丢失文件和符号链接。App 内置 Node 保持原签名,避免签名后改变已封存的服务包。许可证位于 web-service/NODE-LICENSE.txt。
成功后在数据目录的 updates/desktop-sync.json 记录本次 App 服务包校验值。再次打开同一构建不会重新同步,允许 Web 继续自行升级或经兼容性检查后单独回滚。该记录属于数据目录,不是全局 App 偏好。失败不写成功记录,启动页可重试。
App 与 Web 的版本号相同,即使提交来自不同历史或属于工作区快照,也可以使用当前 App 的配套服务覆盖。启动页遇到构建关系不明时显示 使用当前 App 覆盖同版本 Web;进入 Web 后也可从 macOS 的 夭夭 菜单选择同名操作。
覆盖是一次性的明确操作:它跳过构建先后判定和旧的同步成功记录,使用当前 App 自带的完整服务包。仍须校验安装包、服务归属和空闲状态,保留聊天、设置、文件及已有服务配置,并先备份;失败自动恢复。服务忙碌时延后覆盖,不中断进行中的任务。后续普通启动恢复自动同步规则,不持续强制覆盖。不同版本号不使用此入口,升级或回退沿用原有流程。
同步助手通过 force: true 传递此选择;只有受信任的原生启动页和 App 菜单可以触发,Web 页面及其他窗口不能调用覆盖 IPC。service_build_unknown 仅表示可人工处理的同版本构建冲突,包损坏、权限或身份错误不会提供强制入口。
App 同步和 Web 的更新/回滚共用 bin/lib/service-update.mjs 的事务、发布目录、SQLite 更新互斥和原有 active.lock。App 同步使用包内服务,不下载或现场运行 npm 构建;Web 的更新入口仍按发布源准备新版本。两条路径都切换同一个 current。
首次接管时核对当前用户的 LaunchAgent、数据目录、端口、监听进程、SQLite 持有者和启动入口。已有地址、TLS、上游、通知凭据文件及其他环境配置保留。不接管未知监听进程、其他数据目录或远程服务器;TLS 身份无法正常验证时在停止前退出。
新服务通过仅限本机、无 Origin、私有随机凭据的接口协商暂停。只有没有进行中的普通聊天、团队运行、Runner 操作及 HTTP 写请求时才暂停新请求;正在运行的任务继续完成。暂停租约在没有持久更新事务时 15 秒过期,避免更新器在切换前退出导致永久暂停。
旧版没有暂停协议时,检查持久任务、普通聊天未完成事件和本机服务进程的活动连接。App 发现服务忙碌时立即延后同步,核验原服务身份后继续进入现有 Web;菜单显示“Web 同步待完成”,并提供“重试同步本机 Web”。不写同步成功记录。Web 自身的更新器仍最多等待一分钟。旧客户端关闭后可重试,不强行打断任务。
/healthz、/api/status。启动或迁移失败时,恢复原程序、数据库结构、数据文件和配置。备份排除 updates、桌面浏览器数据、独立 Runner 状态及进程锁;这些内容不会被 Web 回退覆盖。中断事务由下一次 App 同步或更新器运行先行恢复。已经恢复数据但尚未启动成功的事务不会重复用旧备份覆盖数据。
成功升级后的手动回滚保留现有消息,要求升级前后及当前数据库结构一致。涉及结构变化或没有旧兼容性记录时拒绝直接降级,必须使用独立的数据恢复流程。失败更新期间的自动恢复只发生在业务请求尚未重新开放之前。
退出 App 后独立 Web 继续运行。App 自己托管的 Runner 仍按原生命周期退出;若需要退出 App 后仍执行电脑任务,应使用独立 Runner。源码开发模式默认不接管正式服务,仍使用隔离的 App 子进程。
tests/server/desktopSync.test.ts:构建选择、包篡改、互斥、忙碌延后、一次同步、数据与结构恢复、中断恢复及降级兼容性。tests/server/serviceInstance.test.ts:本机权限、空闲协商、更新期间拒绝写入、事务提交后恢复。desktop/service-sync.test.mjs:实际 Electron App、包内 Node 和隔离 LaunchAgent 的安装、健康/构建核对、Web 更新入口、退出后继续运行及保留更新的 Web。原生验收使用临时数据目录、端口、发布目录和由目录哈希派生的测试 LaunchAgent 标签;清理只作用于该测试服务,不替换正式 15300 服务。
启动页的 HTML、JavaScript、CSS 与 preload 都是必需打包资源,构建时逐一核验。desktop/startup-feedback.test.mjs 在真实 App 中制造同步助手失败,确认错误文本与“重试 / 查看日志”可见,再解除测试阻塞并点击重试进入 Web。只有 service_busy 会允许连接已验证的原服务;包校验、身份核对及其他错误继续显示在启动页。
2026-09-14 验证:25 项桌面测试及 23 项同步/服务实例/更新接口测试通过。新增真实 App 流程先安装同版本但无共同提交历史的服务,验证启动页明确提供覆盖入口,点击后构建切换成功、原文件和备份保留;Web 页面不能调用覆盖 IPC。另覆盖旧同步记录、忙碌服务、损坏包、跨版本拒绝及覆盖失败的数据恢复。
2026-09-09 验证:类型检查和生产/桌面构建通过;全量测试 787 项通过、6 项按环境跳过。原有 8 项桌面测试通过,新增真实 App/LaunchAgent 同步流程通过,覆盖退出后服务保留、较新 Web 保留、旧配置保留以及服务停止后再次打开 App 恢复独立服务。开发签名 App 的严格签名、服务包完整性及实际同步流程均已验证。此次修改不包含替换本机已安装 App 或正式 Web 服务。