- commit
- 96f5a82
- parent
- 7c8558f
- author
- im_wower
- date
- 2026-03-30 08:44:45 +0800 CST
docs: watchdog v2 conductor-integrated plan
1 files changed,
+100,
-0
+100,
-0
1@@ -0,0 +1,100 @@
2+# Watchdog V2 — Conductor 集成方案
3+
4+> 日期: 2026-03-30
5+> 状态: 方案设计
6+
7+## 问题
8+
9+当前看门狗依赖 Claude 手动设心跳文件状态(working → waiting),Claude 经常忘记,导致续命失效。
10+
11+## 核心洞察
12+
13+Conductor 已拦截每个 AI 的 SSE final-message。收到 final-message = AI 回复结束 = 需要续命。
14+
15+**不需要 Claude 手动设状态,conductor 天然知道。**
16+
17+## 链路
18+
19+```
20+Claude 回复结束
21+ → 浏览器 SSE 流结束
22+ → Firefox 插件拦截 final-message
23+ → WS 发给 conductor
24+ → conductor ingest 处理
25+ → ingest 末尾触发续命 hook
26+ → 延迟 N 秒
27+ → 通过 a11y 给 Safari 对话页发续命消息
28+```
29+
30+## 实现位置
31+
32+`firefox-ws.ts` 的 `handleBrowserFinalMessage` 末尾,或 `ingest.ts` 的 `ingestAssistantFinalMessage` 末尾。
33+
34+## 配置
35+
36+```typescript
37+interface WatchdogConfig {
38+ enabled: boolean; // 开关
39+ targetTab: string; // Safari 标签页全名
40+ platform: string; // 监控哪个平台,如 "claude"
41+ delayMs: number; // final-message 后延迟多久(默认 5000ms)
42+ renewalMessage: string; // 续命消息
43+ cooldownMs: number; // 冷却期,避免连续续命(默认 30000ms)
44+ conversationId?: string; // 可选:只监控特定对话
45+}
46+```
47+
48+## 逻辑
49+
50+```typescript
51+let lastRenewalTime = 0;
52+
53+function onFinalMessage(platform: string, conversationId: string) {
54+ if (!config.enabled) return;
55+ if (platform !== config.platform) return;
56+ if (config.conversationId && conversationId !== config.conversationId) return;
57+ const now = Date.now();
58+ if (now - lastRenewalTime < config.cooldownMs) return;
59+
60+ setTimeout(() => {
61+ exec(`bash tools/watchdog/a11y_msg.sh "${config.targetTab}" "${config.renewalMessage}"`);
62+ lastRenewalTime = Date.now();
63+ }, config.delayMs);
64+}
65+```
66+
67+## 触发条件
68+
69+1. watchdog enabled
70+2. final-message 来自指定平台
71+3. 距上次续命超过冷却期
72+4. 可选:匹配 conversationId
73+
74+## 对比
75+
76+| | V1(当前) | V2(本方案) |
77+|---|---|---|
78+| 触发 | 心跳文件 + 定时轮询 | 事件驱动 |
79+| 依赖手动操作 | 是 | 否 |
80+| 延迟 | 最多 60 秒 | 5 秒 |
81+| 进程管理 | launchd 独立进程 | conductor 内置 |
82+| 失败模式 | 忘设状态→永不续命 | SSE 链路通就续命 |
83+| 复杂度 | 心跳+状态机+进度文件 | 一个 hook + setTimeout |
84+
85+## V1 保留为兜底
86+
87+V2 依赖 SSE 链路(插件→WS→conductor),链路断了 V2 不工作。V1 独立于 conductor,作为最后保险。
88+
89+## 实现步骤
90+
91+1. conductor-daemon 加 watchdog 配置读取
92+2. ingest/firefox-ws 加 final-message hook
93+3. hook 调 a11y_msg.sh 或直接 osascript
94+4. 加开关端点:POST /v1/watchdog/enable, /disable
95+5. 测试验证
96+
97+## 风险
98+
99+- conductor 和 Safari 不在同一台机器时不工作(a11y 是本机操作)
100+- osascript 在 node 子进程可能有 TCC 权限问题
101+- final-message 漏掉(SSE 异常中断)→ V1 兜底