fix(cli): ls 自动恢复休眠会话 - #912
Conversation
deepcoldy
left a comment
There was a problem hiding this comment.
结论:请求修改,发现 1 个阻断问题。
[P2] 为 wake 请求和 backing 轮询使用同一个有界 deadline,并保留退出能力。
当前 wakeDormantBackendForAttach() 的 15 秒预算只覆盖 await options.wake() 返回后的 probe 循环;requestDormantSessionWake() 调用 fetchDaemonIpc() 时没有 AbortSignal/超时。服务端 /wake 又会在 bot 级 withBotTurnMutation() 中等待已有 admission 排空,因此 daemon 即使已接受连接,也可能长期不返回。与此同时 picker 在 raw mode 下先用 if (deleteInFlight || wakeInFlight) return 丢弃所有按键,Ctrl-C/q/Esc 都到不了 cleanup。结果不是“最多 15 秒无法取消”,而是一次恢复可能把当前终端无限卡死。
建议用一个覆盖 wake HTTP + probe 的绝对 deadline(并将 AbortSignal 传进 IPC fetch),同时让 Ctrl-C/q/Esc 在 in-flight guard 之前生效并中止等待;补一个 wake 永不 resolve/慢 gate 时仍能按 deadline 结束或取消的测试。
其余重点复核结论:
- wake 与飞书 turn 分别经过 mutation/admission gate;任一方先到,另一方都会在状态稳定后重新检查,因此已有活 worker 时不会被 restart。
forkWorker()从入口检查到ds.worker = worker没有await,且 mutation gate 覆盖该调用;Node 单线程下这里不存在两个事件各自穿过 worker-null 检查后双 fork 的窗口。- 本地验证:
pnpm build通过;pnpm vitest run test/dashboard-ipc.test.ts test/session-list-wake.test.ts test/session-picker-responsive.test.ts test/session-list-liveness.test.ts为 163 passed / 1 skipped。
|
感谢这个 PR,把「主机重启后本地 自动评审发现 1 个建议在合入前修复的问题(liveness / 可取消性): picker 在
建议:
(这是自动评审的初步意见,最终以维护者审阅为准。) |
e42305e to
98333cc
Compare
|
已按建议修复并推送(98333cc):
已在最新 master 上 rebase 后复验:pnpm build 通过,相关 4 个测试文件共 167 项全部通过。 |
`/api/sessions/:sessionId/wake` 里的 `isRiffBackendSession(ds)` 守卫(#912)引用了 一个未导入的符号:该 import 在 #803 把 riff 判定扩成 `isRemoteBackendSession` 时被 移除,两处改动各自都对,合在一起后 `src/core/dashboard-ipc-server.ts` 少了一行 import。 结果是 master 自 #912 起 `tsc` 直接报错、`pnpm build` 退出码 2: ``` src/core/dashboard-ipc-server.ts(1277,9): error TS2552: Cannot find name 'isRiffBackendSession'. Did you mean 'isRemoteBackendSession'? ``` 按调用点的原意补 import,不改行为:该守卫返回的错误码是 `riff_wake_unsupported`, 针对的就是 riff 这一种远端后端;`isRemoteBackendSession`(riff + mojo 全家)语义更宽, 是否要把 mojo 会话也挡在本地 wake 之外属于产品判断,不在本修复范围内。 验证:`npx tsc --noEmit` 干净、`pnpm build` 通过(改动前两者均失败)。
#958 已用「补回 isRiffBackendSession import」修好了 build 编译红,但那是最小改法: 它让 /wake 继续用 riff-only 守卫,与 #803 引入的结构不变量冲突—— worker-remote-retirement-protocol.test.ts 断言 dashboard-ipc-server 里 isRiffBackendSession( 调用数为 0(远程退役守卫必须泛化到 riff+mojo,不能各自 riff-only)。 所以 master 现在 build 绿、但两个测试红: 1. worker-remote-retirement-protocol.test.ts —「still calls isRiffBackendSession: expected 1 to be 0」 2. session-picker-responsive.test.ts —「q 中止 wake」用例(见下 #3) 本提交把 /wake 守卫对齐旁边 /restart 的既有约定,从根上消掉冲突: - /wake 改用 isRemoteBackendSession,错误码 riff_wake_unsupported→remote_wake_unsupported, 并删掉 #958 补回、现已无引用的 isRiffBackendSession import。语义同步收紧:mojo 与 riff 一样持有远程血缘,本地 forkWorker 冷启动会切断/替换它,绝不能被 picker 唤醒拉起。 - 补 /wake 的 riff + mojo 拒绝回归测(此前 /wake describe 完全没覆盖远程分支, 正是守卫会从 isRemoteBackendSession 悄悄退回 riff-only 的原因)。 - 修 session-picker-responsive「q 中止 wake」用例:其 .dashboard-secret fixture 未设 0600, 被 secure-host-file 的凭证权限收紧挡在鉴权层,wake 请求发不出。显式 chmod 0600。 - 补 sessionWakeAcquireTimeoutMs clamp 单测(#912 双审记的非阻断 follow-up)。 验证:pnpm build 绿;相关 5 文件 189 测过(含两处原 master 红转绿);反向变异 3 处有牙。 Co-Authored-By: Claude <noreply@anthropic.com>
|
🚀 Released in v3.16.0 |
改动内容
问题原因
主机重启会清空 tmux/ZMX backing,但活跃会话记录和 transcript 仍然保留,可由 daemon 冷恢复。此前 list 会保留这些会话行,Enter 却只连接已经存在的 backing,因此本地入口不可用,而飞书新消息仍能触发恢复。
影响范围
验证