v1.0.96
变更 / Changes
Fixed
- 自动部署不再在活着的后台 claude 会话之下重启 actd——roster 上有活会话就整轮延后(CONTRACT §56.3 会话闸门,状态
deferred):2026-09-07T05:35Z live,v1.0.72 的自动部署在 P-029 派发 17 分钟后 bootout+bootstrap 了 actd,owner 正在终端里 attach 着那个会话,终端打出[worker crashed (exit 143) — respawning…] Session f40f2001 has exited(143 = SIGTERM);三天里 25 次 actd 重启,多张卡在部署时刻附近被「中断收割」。修法:scripts/auto-deploy.sh在 CI 闸门与脏树检查之后、merge --ff-only之前(以及 install_incomplete 的 install.sh 修补重跑之前)问一次 roster——新act.executor.live_session_count(),与 actd 同一个 reader、同一个 §55 稳定副本 claude(agents --json --all,不另造 parser),数kind != interactive且带pid的条目(pid = 进程活着 = 重启会打断;done 但 owner attach 着的 worker 一样算)。N > 0 →status=deferred+ add-only 键deferred_reason=sessions_running/deferred_sessions=N/deferred_since=<首次>,日志一行、不通知、HEAD 不动、exit 0,下个 interval 再问;没有时间上限(永不结束的会话是 §46/#119 收割机制的事),但连续满 6 h 日志 WARN、doctorauto-deploy行由 OK 转 WARN「更新已就绪,等待 N 个会话结束已 X 小时」、web 顶栏由次级色「新版本已就绪,等待 N 个会话结束后更新」切警告色并追加「(已 X 小时)」。roster 读不到(claude 缺失 / 超时 / 非零 / 坏 JSON)= fail closed:deferred_reason=roster_unknown,镜像私账roster_unknown_ticks计连续未知,满 3 轮后下一轮让行并在日志说明——既不静默杀会话,也不让坏掉的 roster 查询永远挡住部署。--force跳过闸门并记下会被打断的会话数;回滚不延后但日志点名它打断了几个会话。实证:launchctl bootout只 SIGTERM 该 job 自己 process group 里的进程(setsid / double-fork 的子进程都活着),live 机器上 claude worker 挂在claude daemon run之下、不在 actd 的进程组里——bootout 不是直接的信号源,法条不依赖那个机制。判例tests/integration/test_auto_deploy_session_gate.py(8 轮真 bash+git,复用既有夹具的AutoDeployFixture)、tests/test_executor_live_session_count.py、tests/test_deploy_state_deferred.py、HeaderBar.test.tsx。 - 会话闸门 review 修订(#284 review):(a)
deferred_since与roster_unknown_ticks只属于连续deferred的 episode——夹在中间的任何别的结果(refused_dirty / ci_pending / 一次跳过闸门并回滚了的--force……)都关掉它,--force的「忘掉」写入也清这四个键(修前:几秒钟前才开始的延后继承一天前的 stamp → 假「已 7 小时」WARN;--force+回滚后陈旧的 ticks 让下一个 unknown 直接算第 3 次);(b) 写明「活着」= 带pid、不看state的代价:done 但进程还在的 worker(每张待验收卡)同样挡住部署,直到 claude 回收它 / owner 验收或打回那张卡 /claude stop <id>——doctor WARN 的 fix 与顶栏文案改点名这些真实出口(顶栏「等待 N 个会话结束或验收后更新」),不再说「卡住的会话由 §46/#119 收割」;(c) 被延后的 install.sh 修补重跑保留 install_incomplete 的 token(reason=<失配 token> sessions_running)、detail 带失配说明,doctor 行与顶栏从第一轮起就是 WARN「安装未完成,修补等待 N 个会话结束」而不是 OK「更新已就绪」;actd 死了修补同样受闸(规矩没有例外),fix 写明那时只有 claude 自己回收、claude stop或--force能结束会话;(d) doctor OK 行由「vX ready」(X 是正在跑的版本)改为「deferred on v (waiting for …): 」;(e)deferred下last_incident同判(#135 规则):doctor WARN、顶栏警告色 +「上次回滚判决待处理」;(f) 6 h 阈值只剩一个真源act/lib/deploy_state.py DEFER_WARN_AFTER_S(脚本读它,env 旋钮AUTODEPLOY_DEFER_WARN_AFTER退役);(g) CONTRACT 记录闸门作答到 install.sh bootout 之间的残余窗口(不关)。判例tests/integration/test_auto_deploy_defer_episode.py(5 条 / 13 轮真 bash+git)、tests/test_deploy_state_deferred_visibility.py、HeaderBar.test.tsx新 case。
安装 / Install
macOS
下载下方的 ZelinAIAssistant-*.pkg 双击安装。装完后菜单栏会自动出现小图标(首启弹权限设置页)。
这个安装包目前没有 Apple 开发者签名,所以 macOS 第一次会拦下它说"无法打开"。这不是故障,也不是恶意软件——用 3 步绕过(只需做这一次):
- 在 Finder 里右键点击 .pkg 文件 → 选「打开」;
- 弹窗里再点一次「打开」;
- 如果 macOS Sequoia 仍然拒绝:打开 系统设置 → 隐私与安全性,拉到底部,点「仍要打开」,输一次密码。
Download ZelinAIAssistant-*.pkg below and double-click it. The build is not yet signed with an Apple Developer ID, so macOS blocks the first open — expected, not malware. Bypass it once: right-click the .pkg in Finder → Open → Open; if macOS Sequoia still refuses, go to System Settings → Privacy & Security, scroll to the bottom, click Open Anyway and enter your password.
Windows / Linux
Windows 和 Linux 是纯 Python(无需编译)。下载对应的源码包,解压,然后从解压出的目录里运行安装脚本:
- Windows:下载
ZelinAIAssistant-*-windows.zip,解压后运行install.ps1(指南:docs/WINDOWS.md)。 - Linux:下载
ZelinAIAssistant-*-linux.tar.gz,解压后运行bash install-linux.sh(指南:docs/LINUX.md)。
Windows and Linux are pure Python (no build step). Download the matching source bundle, unpack it, and run the install script from the extracted folder:
- Windows: download
ZelinAIAssistant-*-windows.zip, extract, runinstall.ps1— see docs/WINDOWS.md. - Linux: download
ZelinAIAssistant-*-linux.tar.gz, unpack, runbash install-linux.sh— see docs/LINUX.md.
完整安装指南 / full install guide: docs/INSTALL.md · 卸载 / uninstall: bash uninstall.sh
What's Changed
Other changes
- fix(deploy): defer the deploy while background claude sessions are live (§56.3 session gate) by @Wan-ZL in #284
Full Changelog: v1.0.95...v1.0.96