baa-conductor


commit
68a85cf
parent
d8e883d
author
codex@macbookpro
date
2026-04-03 11:47:47 +0800 CST
chore: remove legacy watchdog a11y flow
11 files changed,  +90, -284
Raw patch view.
  1diff --git a/plans/A11Y_GUI_CONTROL.md b/plans/A11Y_GUI_CONTROL.md
  2index 737ec75c9eb2942b25da314e9783362d6026a3b4..dfcffbf072e5fc8ef8beeb15a2c1ad4dfb11fc27 100644
  3--- a/plans/A11Y_GUI_CONTROL.md
  4+++ b/plans/A11Y_GUI_CONTROL.md
  5@@ -1,9 +1,11 @@
  6-# A11Y GUI Control — 基于无障碍树的浏览器与操作系统控制
  7+# A11Y GUI Control — 基于无障碍树的浏览器与操作系统控制(历史归档)
  8 
  9 > 日期: 2026-03-30
 10-> 状态: 验证完成,待开发
 11+> 状态: 历史归档(探索记录,非当前需求)
 12 > 参与: Claude (验证执行) + George (架构指导)
 13 
 14+> 说明:本文保留当时对通用 a11y / GUI 控制的探索记录。基于 Safari 的 `a11y_msg.sh` / watchdog 续命脚本已于 2026-04-03 随 `T-S074` 从仓库移除;当前正式续命主线只有 conductor renewal。若未来重启通用 a11y host-ops 能力,应另开新任务,不直接把本文视为 active requirement。
 15+
 16 ---
 17 
 18 ## 核心思路
 19@@ -136,7 +138,7 @@ george@Mac Desktop % proxy_on"
 20 
 21 ---
 22 
 23-## 开发计划
 24+## 当时设想的开发计划
 25 
 26 ### Phase 1:conductor a11y 端点
 27 
 28@@ -199,7 +201,7 @@ Claude → conductor → a11y/tree(Safari, ChatGPT页面) → 读对话
 29 
 30 ---
 31 
 32-## 与现有架构的关系
 33+## 当时设想与现有架构的关系
 34 
 35 - **baa-conductor**:a11y 端点作为新的 host-ops 类端点,与 exec/files 同级
 36 - **BAA 指令系统**:a11y 工具注册为 conductor 的 tool,AI 通过 baa 代码块调用
 37@@ -219,7 +221,7 @@ Claude → conductor → a11y/tree(Safari, ChatGPT页面) → 读对话
 38 
 39 ---
 40 
 41-## 补充:续命机制与看门狗模式(2026-03-30 验证)
 42+## 补充:历史续命探索与看门狗模式(2026-03-30 记录,已废弃)
 43 
 44 ### 左右手互博验证
 45 
 46@@ -245,7 +247,7 @@ tk_conductor Claude (Safari)
 47 - 改为轻量版:直接 `keystroke "v" using command down` + `keystroke return`,不扫描元素
 48 - 发送方式统一用剪贴板粘贴 + 回车,不依赖找 Send 按钮
 49 
 50-### 轻量版 a11y_msg.sh
 51+### 当时使用的轻量版 a11y_msg.sh(脚本已删除)
 52 
 53 ```bash
 54 #!/bin/bash
 55@@ -267,7 +269,7 @@ osascript -e 'tell application "System Events" to tell process "Safari"
 56 end tell'
 57 ```
 58 
 59-### 看门狗模式(设计,待实现)
 60+### 看门狗模式(历史设计,未实现,已废弃)
 61 
 62 三个 Claude 标签页:A(主工作)、B(思考工具)、C(看门狗)
 63 
 64diff --git a/plans/STATUS_SUMMARY.md b/plans/STATUS_SUMMARY.md
 65index 655c6e8b4fe57224e73f0685c48a6dcbdf6c9917..ac2cfd4917e6716d6e6f8fc5946922b0a8b081ba 100644
 66--- a/plans/STATUS_SUMMARY.md
 67+++ b/plans/STATUS_SUMMARY.md
 68@@ -2,11 +2,11 @@
 69 
 70 ## 当前时间
 71 
 72-- `2026-04-01`
 73+- `2026-04-03`
 74 
 75 ## 当前代码基线
 76 
 77-- 当前主分支:`main@ffda03b`
 78+- 当前主分支:`main@d8e883d`
 79 - canonical local API:`http://100.71.210.78:4317`
 80 - canonical public host:`https://conductor.makefile.so`
 81 - 活跃任务文档和近期刚完成的任务文档保留在 `tasks/` 根目录;较早已完成任务归档到 [`../tasks/archive/README.md`](../tasks/archive/README.md)
 82@@ -57,6 +57,12 @@
 83   - BAA instruction policy 现在已支持默认配置与自定义 allowlist,后续 automation control 指令扩面不再依赖硬编码集合
 84   - Claude final-message 现在已补更稳的 SSE fallback,主路径字段漂移时仍能回退到稳定提取
 85   - renewal 模块公共 helper 已收口到统一 `utils`,projector / dispatcher / automation 不再重复维护同类逻辑
 86+- 当前正式续命链路只保留 conductor renewal:
 87+  - `browser.final_message` ingress
 88+  - renewal projector
 89+  - renewal dispatcher
 90+  - `browser.proxy_delivery`
 91+  - 旧 watchdog / Safari a11y 续命方案已随 `T-S074` 从仓库移除
 92 
 93 ## 当前已纠正的文档/代码不一致
 94 
 95@@ -73,17 +79,17 @@
 96 - `T-BUG-029` / `T-BUG-031` 的任务卡已完成,但旧汇总文档仍把它们写成 pending manual verification;现统一改为“建议补做浏览器复核”
 97 - Artifact 静态服务已经完成,不再把它写成“下一阶段主线”
 98 - `T-S050` 曾引入 stagit repo 静态页,但该能力已迁到 `baa-pgit`,当前仓库内残留实现已随 `T-S073` 删除
 99+- 旧 watchdog / Safari a11y 续命方案此前仍以“可继续保留/重写”的口径留在根目录计划文档中;现已随 `T-S074` 删除旧代码,并统一降级为历史方案
100 
101 ## 当前最高优先级
102 
103 **当前下一波任务:**
104 
105-- [`../tasks/T-S074.md`](../tasks/T-S074.md):删除旧版 watchdog 与 Safari a11y 续命方案
106-- Web UI 主线 `T-S070 -> T-S071 -> T-S072` 保持下一顺位
107+- Web UI 主线 `T-S070 -> T-S071 -> T-S072`
108 
109 其余没有 open bug / open opt。
110 
111-如继续推进,建议先完成 `T-S074`,之后回到 Web UI 主线,再根据新需求或代码审查结果继续拆任务。
112+如继续推进,建议直接回到 Web UI 主线;旧 watchdog / Safari a11y 续命方案已随 `T-S074` 删除,当前正式续命链路只保留 conductor renewal。
113 
114 **并行优化项:**
115 
116@@ -98,6 +104,7 @@
117 - 当前 open bug 见 [`../bugs/README.md`](../bugs/README.md)
118 - 当前没有 open `MISSING-*` blocker
119 - 其余 backlog 仍以 `OPT-*` 为主
120+- 历史文档中仍会保留 watchdog / a11y 关键词,但不代表当前 active 方案
121 
122 ## 当前活跃需求文档
123 
124@@ -113,6 +120,9 @@
125 - [`./NEXT_WAVE_REQUIREMENTS.md`](./NEXT_WAVE_REQUIREMENTS.md)(历史需求视图)
126 - [`./TONIGHT_SPRINT.md`](./TONIGHT_SPRINT.md)(历史冲刺计划)
127 - [`../HANDOFF.md`](../HANDOFF.md)(历史交接记录)
128+- [`./WATCHDOG_LOGGING_ENHANCEMENT.md`](./WATCHDOG_LOGGING_ENHANCEMENT.md)(历史 watchdog V1 需求记录,代码已删除)
129+- [`./WATCHDOG_V2_CONDUCTOR_INTEGRATED.md`](./WATCHDOG_V2_CONDUCTOR_INTEGRATED.md)(历史 watchdog V2 设计草案,未落地)
130+- [`./A11Y_GUI_CONTROL.md`](./A11Y_GUI_CONTROL.md)(历史 Safari a11y / GUI 控制探索)
131 - [`./BAA_ARTIFACT_DOWNLOAD_REQUIREMENTS.md`](./BAA_ARTIFACT_DOWNLOAD_REQUIREMENTS.md)
132 - [`./ARTIFACT_STATIC_SERVICE.md`](./ARTIFACT_STATIC_SERVICE.md)(主线已完成,保留实现参考)
133 
134@@ -125,6 +135,7 @@ Phase 1(浏览器主链)、Artifact 静态服务,以及 timed-jobs + 续
135 - 当前主线已无 open bug blocker
136 - `browser.chatgpt` / `browser.gemini` helper target 与 Gemini DOM delivery adapter 已在主线
137 - 当前这轮 backlog 已全部收口;自动化仲裁、统一浮层控制、系统级暂停、重启后风控恢复、delivery 可靠性增强和 policy 配置化均已完成
138+- 当前正式续命链路只保留 conductor renewal;旧 watchdog / Safari a11y 续命方案已删除
139 
140 之前的浏览器主链继续保持:
141 
142@@ -143,4 +154,4 @@ Phase 1(浏览器主链)、Artifact 静态服务,以及 timed-jobs + 续
143 - recent relay cache 是有限窗口;极老 replay 超出窗口后,仍会落回 conductor dedupe
144 - `status-api` 继续保留为显式 opt-in 兼容层,不是当前删除重点
145 - 远端 `baa-conductor-artifact` 已在 `2026-04-01` 应用 [`../packages/d1-client/src/d1-setup.sql`](../packages/d1-client/src/d1-setup.sql);后续如新建或重置 D1 环境,仍需执行同一 schema 初始化脚本
146-- 当前仓库内的旧 watchdog / a11y 续命方案计划由 `T-S074` 直接删除
147+- 历史文档中仍保留旧 watchdog / a11y 讨论;这是保留演进记录的有意行为,不代表仓库仍保留该方案
148diff --git a/plans/TONIGHT_SPRINT.md b/plans/TONIGHT_SPRINT.md
149index 3c36311d9df6dfabd1a3cd414bd60c5fd326dc75..8b13bf06c82296b4d5c95de1634611db34807013 100644
150--- a/plans/TONIGHT_SPRINT.md
151+++ b/plans/TONIGHT_SPRINT.md
152@@ -5,7 +5,7 @@
153 > 执行: Codex (写代码) / Claude Code (小改动/文档)
154 > 看门狗: watchdog.sh (后台,60秒间隔)
155 
156-> 状态: 历史冲刺计划。当前代码进度以 `tasks/TASK_OVERVIEW.md` 和 `plans/STATUS_SUMMARY.md` 为准。
157+> 状态: 历史冲刺计划。当前代码进度以 `tasks/TASK_OVERVIEW.md` 和 `plans/STATUS_SUMMARY.md` 为准;其中 watchdog 相关步骤已于 `T-S074` 删除,仅保留历史记录。
158 
159 ---
160 
161diff --git a/plans/WATCHDOG_LOGGING_ENHANCEMENT.md b/plans/WATCHDOG_LOGGING_ENHANCEMENT.md
162index 21c3d9fac562aef251f38dd1745c38dc1197c12b..c79d37fbfe3e7d9ec51327b2301d7db8668dd689 100644
163--- a/plans/WATCHDOG_LOGGING_ENHANCEMENT.md
164+++ b/plans/WATCHDOG_LOGGING_ENHANCEMENT.md
165@@ -1,20 +1,21 @@
166-# 看门狗日志增强需求
167+# 看门狗日志增强需求(历史归档)
168 
169 > 日期:2026-03-31
170-> 优先级:`低`(当前续命主力已切到 API 代理方式,watchdog 仅作兜底脚手架)
171-> 状态:`需求记录`
172-> 来源:原 `T-S060`,降级为需求文档
173+> 状态:`历史归档(T-S074 已移除旧实现)`
174+> 来源:原 `T-S060`,后续降级为需求文档
175 
176-## 背景
177+> 说明:本文仅保留旧版 watchdog V1 的需求记录。自 2026-04-03 起,`tools/watchdog/` 已从仓库删除;当前正式续命链路只保留 conductor renewal(`browser.final_message` ingress → renewal projector → renewal dispatcher → `browser.proxy_delivery`)。
178+
179+## 历史背景
180 
181 仓库 `tools/watchdog/` 下有两个脚本:
182 
183 - `watchdog.sh`:轮询心跳文件,判断是否需要续命
184 - `a11y_msg.sh`:通过 macOS 辅助功能 API(osascript)操控 Safari 发消息
185 
186-这是早期的 GUI 续命方案(V1),依赖 Claude 手动设心跳状态。当前续命主力已切到 conductor renewal(API 代理方式:projector + dispatcher + Firefox proxyDelivery),watchdog 降为兜底脚手架。
187+这是早期的 GUI 续命方案(V1),依赖 Claude 手动设心跳状态。该方案最终没有继续保留;当前正式续命主力已切到 conductor renewal(API 代理方式:projector + dispatcher + Firefox proxyDelivery),watchdog 也不再作为兜底脚手架存在。
188 
189-## 当前问题
190+## 当时记录的问题
191 
192 ### `a11y_msg.sh`
193 
194@@ -28,7 +29,7 @@
195 1. Python 解析心跳文件失败时(`ST="error"`),主循环没有显式 FAIL 日志
196 2. CHECK 日志已比较完整,续命后也记录了 `a11y_rc`,这部分基本到位
197 
198-## 需求
199+## 原始需求记录
200 
201 ### 1. `a11y_msg.sh` 日志增强
202 
203@@ -49,20 +50,19 @@
204 - 不清空 `wake_at` / `max_wake_at`
205 - 不引入旧版 `origin/feat/watchdog-logging` 分支的状态机回退
206 
207-## 允许修改的目录
208+## 原计划修改目录
209 
210-- `tools/watchdog/`
211+- `tools/watchdog/`(现已删除)
212 
213-## 为什么优先级低
214+## 归档说明
215 
216-- 续命主力已切到 conductor renewal(API 代理),不依赖 watchdog
217-- watchdog 仅在 conductor 链路完全断裂时作为最后保险
218-- 当前 watchdog 功能正常,只是出错时排障困难
219-- 不阻塞任何主线功能
220+- 正式续命主线已切到 conductor renewal(API 代理),不依赖 watchdog
221+- 旧 watchdog / a11y 代码已随 `T-S074` 删除
222+- 如未来需要新的 host-level 兜底续命能力,应重新立项,不延续本文方案
223 
224 ## 关联
225 
226 - 原任务卡:`T-S060`(已撤回)
227-- watchdog V1 代码:`tools/watchdog/watchdog.sh`、`tools/watchdog/a11y_msg.sh`
228-- watchdog V2 设计:[`WATCHDOG_V2_CONDUCTOR_INTEGRATED.md`](./WATCHDOG_V2_CONDUCTOR_INTEGRATED.md)(事件驱动方案,同样搁置)
229+- 原 watchdog V1 代码:`tools/watchdog/watchdog.sh`、`tools/watchdog/a11y_msg.sh`(均已删除)
230+- watchdog V2 设计:[`WATCHDOG_V2_CONDUCTOR_INTEGRATED.md`](./WATCHDOG_V2_CONDUCTOR_INTEGRATED.md)(历史事件驱动草案,未落地)
231 - 续命主力:`apps/conductor-daemon/src/renewal/`(projector + dispatcher)
232diff --git a/plans/WATCHDOG_V2_CONDUCTOR_INTEGRATED.md b/plans/WATCHDOG_V2_CONDUCTOR_INTEGRATED.md
233index 94bf2c1ed11ea2a95ebc6162946ae3ce82042a69..50decf602cc90fa2cde7f347b01056281f4eef45 100644
234--- a/plans/WATCHDOG_V2_CONDUCTOR_INTEGRATED.md
235+++ b/plans/WATCHDOG_V2_CONDUCTOR_INTEGRATED.md
236@@ -1,19 +1,21 @@
237-# Watchdog V2 — Conductor 集成方案
238+# Watchdog V2 — Conductor 集成方案(历史归档)
239 
240 > 日期: 2026-03-30
241-> 状态: 方案设计
242+> 状态: 历史归档(未落地,T-S074 已移除旧 watchdog)
243 
244-## 问题
245+> 说明:本文保留当时对事件驱动 watchdog V2 的设计草案。该方案最终没有进入当前主线;自 2026-04-03 起,仓库已删除旧版 watchdog / Safari a11y 续命实现,正式续命链路只保留 conductor renewal。
246+
247+## 当时要解决的问题
248 
249 当前看门狗依赖 Claude 手动设心跳文件状态(working → waiting),Claude 经常忘记,导致续命失效。
250 
251-## 核心洞察
252+## 当时的核心洞察
253 
254 Conductor 已拦截每个 AI 的 SSE final-message。收到 final-message = AI 回复结束 = 需要续命。
255 
256 **不需要 Claude 手动设状态,conductor 天然知道。**
257 
258-## 链路
259+## 历史链路设想
260 
261 ```
262 Claude 回复结束
263@@ -26,11 +28,11 @@ Claude 回复结束
264   → 通过 a11y 给 Safari 对话页发续命消息
265 ```
266 
267-## 实现位置
268+## 当时设想的实现位置
269 
270 `firefox-ws.ts` 的 `handleBrowserFinalMessage` 末尾,或 `ingest.ts` 的 `ingestAssistantFinalMessage` 末尾。
271 
272-## 配置
273+## 当时设想的配置
274 
275 ```typescript
276 interface WatchdogConfig {
277@@ -44,7 +46,7 @@ interface WatchdogConfig {
278 }
279 ```
280 
281-## 逻辑
282+## 当时设想的逻辑
283 
284 ```typescript
285 let lastRenewalTime = 0;
286@@ -63,14 +65,14 @@ function onFinalMessage(platform: string, conversationId: string) {
287 }
288 ```
289 
290-## 触发条件
291+## 当时设想的触发条件
292 
293 1. watchdog enabled
294 2. final-message 来自指定平台
295 3. 距上次续命超过冷却期
296 4. 可选:匹配 conversationId
297 
298-## 对比
299+## 方案对比(历史记录)
300 
301 | | V1(当前) | V2(本方案) |
302 |---|---|---|
303@@ -81,11 +83,11 @@ function onFinalMessage(platform: string, conversationId: string) {
304 | 失败模式 | 忘设状态→永不续命 | SSE 链路通就续命 |
305 | 复杂度 | 心跳+状态机+进度文件 | 一个 hook + setTimeout |
306 
307-## V1 保留为兜底
308+## 历史说明:当时曾设想 V1 作为兜底
309 
310-V2 依赖 SSE 链路(插件→WS→conductor),链路断了 V2 不工作。V1 独立于 conductor,作为最后保险。
311+该设想最终未采用。2026-04-03 起,V1 与 V2 均不再保留;当前仓库只保留 conductor renewal 主链。
312 
313-## 实现步骤
314+## 当时设想的实现步骤
315 
316 1. conductor-daemon 加 watchdog 配置读取
317 2. ingest/firefox-ws 加 final-message hook
318@@ -93,7 +95,7 @@ V2 依赖 SSE 链路(插件→WS→conductor),链路断了 V2 不工作。
319 4. 加开关端点:POST /v1/watchdog/enable, /disable
320 5. 测试验证
321 
322-## 风险
323+## 当时识别的风险
324 
325 - conductor 和 Safari 不在同一台机器时不工作(a11y 是本机操作)
326 - osascript 在 node 子进程可能有 TCC 权限问题
327diff --git a/tasks/T-S074.md b/tasks/T-S074.md
328index 1af586cbb75c5696d68400f207275940f030064e..d4010dccfdc6fb5485e4b9b965ddb97bc54cb61b 100644
329--- a/tasks/T-S074.md
330+++ b/tasks/T-S074.md
331@@ -2,7 +2,7 @@
332 
333 ## 状态
334 
335-- 当前状态:`待开始`
336+- 当前状态:`已完成`
337 - 规模预估:`S`
338 - 依赖任务:无
339 - 建议执行者:`Codex`
340@@ -152,22 +152,22 @@
341 
342 ### 开始执行
343 
344-- 执行者:
345-- 开始时间:
346-- 状态变更:
347+- 执行者:`Codex`
348+- 开始时间:`2026-04-03 11:43:07 CST`
349+- 状态变更:`待开始 -> 进行中`
350 
351 ### 完成摘要
352 
353-- 完成时间:
354-- 状态变更:
355-- 修改了哪些文件:
356-- 核心实现思路:
357-- 跑了哪些测试:
358+- 完成时间:`2026-04-03 11:46:41 CST`
359+- 状态变更:`进行中 -> 已完成`
360+- 修改了哪些文件:`tasks/TASK_OVERVIEW.md`、`plans/STATUS_SUMMARY.md`、`plans/WATCHDOG_LOGGING_ENHANCEMENT.md`、`plans/WATCHDOG_V2_CONDUCTOR_INTEGRATED.md`、`plans/A11Y_GUI_CONTROL.md`、`plans/TONIGHT_SPRINT.md`、`tasks/T-S074.md`,并删除 `tools/watchdog/` 下全部文件。
361+- 核心实现思路:删除 `tools/watchdog/` 旧脚本与说明,并把当前总览 / 状态 / 方案文档统一改成“仅保留历史记录,当前续命主线只有 conductor renewal”。
362+- 跑了哪些测试:`test ! -e /Users/george/code/baa-conductor-remove-watchdog-a11y/tools/watchdog && echo removed`、`git -C /Users/george/code/baa-conductor-remove-watchdog-a11y diff --check`、`rg -n "watchdog|a11y_msg|WATCHDOG_V2|A11Y_GUI_CONTROL" /Users/george/code/baa-conductor-remove-watchdog-a11y --glob '!HANDOFF.md'`、`git -C /Users/george/code/baa-conductor-remove-watchdog-a11y status --short`
363 
364 ### 执行过程中遇到的问题
365 
366-- 
367+- 无阻塞问题;主要工作是清理旧实现并统一文档口径。
368 
369 ### 剩余风险
370 
371-- 
372+- 历史文档中仍会保留 watchdog / a11y 关键词;这是为了保留演进记录,不代表仓库仍保留该方案。
373diff --git a/tasks/TASK_OVERVIEW.md b/tasks/TASK_OVERVIEW.md
374index f2756edcf887b3b0c862114003bcd8652b87d620..704310f5ec407bd56468c90df3690b3dac77e02d 100644
375--- a/tasks/TASK_OVERVIEW.md
376+++ b/tasks/TASK_OVERVIEW.md
377@@ -2,8 +2,8 @@
378 
379 ## 当前基线
380 
381-- 日期:`2026-04-01`
382-- 主分支基线:`main@ffda03b`
383+- 日期:`2026-04-03`
384+- 主分支基线:`main@d8e883d`
385 - canonical local API:`http://100.71.210.78:4317`
386 - canonical public host:`https://conductor.makefile.so`
387 - 当前活跃任务卡和近期刚完成的任务卡保留在本目录;较早已完成任务归档到 [`./archive/README.md`](./archive/README.md)
388@@ -55,6 +55,12 @@
389   - BAA instruction policy 现在已支持默认配置与自定义 allowlist,后续 automation control 指令扩面不再依赖硬编码集合
390   - Claude final-message 现在已补更稳的 SSE fallback,主路径字段漂移时仍能回退到稳定提取
391   - renewal 模块的公共 helper 已收口到统一 `utils`,projector / dispatcher / automation 不再重复维护同类逻辑
392+- 当前正式续命链路只保留 conductor renewal:
393+  - `browser.final_message` ingress
394+  - renewal projector
395+  - renewal dispatcher
396+  - `browser.proxy_delivery`
397+  - 旧 watchdog / Safari a11y 续命方案已随 `T-S074` 从仓库移除
398 
399 ## 当前已确认的不一致
400 
401@@ -73,6 +79,7 @@
402 - `T-BUG-029`、`T-BUG-031` 的任务卡已是 `已完成`,但旧文档仍把它们写成 pending manual verification;现统一改为“建议补做浏览器复核”
403 - Artifact 静态服务已经完成,不再把 `T-S039`~`T-S045` 写成“当前活跃主线”
404 - `T-S050` 曾引入 stagit repo 静态页,但该能力已迁到 `baa-pgit`,当前仓库内残留实现已随 `T-S073` 删除
405+- 旧 watchdog / Safari a11y 续命方案此前仍停留在根目录计划文档与任务队列中;现已随 `T-S074` 删除旧代码,并统一降级为历史方案
406 
407 ## 当前活跃任务与优先级
408 
409@@ -96,6 +103,7 @@
410 | [`T-S069`](./T-S069.md) | proxy_delivery 成功语义增强 | L | T-S060 | Codex | 已完成 |
411 | [`T-S065`](./T-S065.md) | policy 配置化 | M | 无 | Codex | 已完成 |
412 | [`T-S073`](./T-S073.md) | 移除 conductor 内的 stagit 仓库静态页能力 | M | 无 | Codex | 已完成 |
413+| [`T-S074`](./T-S074.md) | 删除旧版 watchdog 与 Safari a11y 续命方案 | S | 无 | Codex | 已完成 |
414 
415 ### 当前下一波任务
416 
417@@ -103,18 +111,17 @@
418 
419 | 任务 | 标题 | 规模 | 依赖 | 建议 AI | 状态 |
420 |---|---|---|---|---|---|
421-| [`T-S074`](./T-S074.md) | 删除旧版 watchdog 与 Safari a11y 续命方案 | S | 无 | Codex | 待开始 |
422 | [`T-S070`](./T-S070.md) | Conductor UI 基础设施:Vue 3 脚手架与 `/app` 静态托管 | M | 无 | Codex | 待开始 |
423 | [`T-S071`](./T-S071.md) | Conductor UI 会话鉴权:登录页与浏览器 session | M | T-S070 | Codex | 待开始 |
424 | [`T-S072`](./T-S072.md) | Conductor UI `Control` 工作区首版 | L | T-S070, T-S071 | Codex | 待开始 |
425 
426 当前没有 open bug / open opt。
427 
428-如继续推进,建议先完成 `T-S074`,再回到 `T-S070 -> T-S071 -> T-S072` 的 Web UI 主线。
429+如继续推进,建议直接回到 `T-S070 -> T-S071 -> T-S072` 的 Web UI 主线。
430 
431 说明:
432 
433-- `T-S073` 已完成;`T-S074` 是剩余的仓库边界收缩任务
434+- `T-S073` / `T-S074` 已完成,仓库边界收缩已结束
435 - `T-S070` / `T-S071` / `T-S072` 仍是后续正式 Web UI 主线
436 - `Channels` 工作区和正式 `channel` 域模型继续留在 `T-S072` 之后再拆下一轮
437 
438@@ -140,7 +147,8 @@
439 | T-S048 | Gemini 投递适配器 | ✅ |
440 | T-S049 | 开放 chatgpt/gemini target | ✅ |
441 | T-S050 | stagit git 静态页面 | ✅ |
442-| T-S070 | 移除 conductor 内的 stagit 仓库静态页能力 | ✅ |
443+| T-S073 | 移除 conductor 内的 stagit 仓库静态页能力 | ✅ |
444+| T-S074 | 删除旧版 watchdog 与 Safari a11y 续命方案 | ✅ |
445 | T-S052 | D1 数据库初始化 | ✅ |
446 | T-S053 | 插件诊断日志 | ✅ |
447 | T-S054 | 插件日志 WS 转发 | ✅ |
448@@ -196,18 +204,20 @@
449 - [`../plans/NEXT_WAVE_REQUIREMENTS.md`](../plans/NEXT_WAVE_REQUIREMENTS.md):历史需求视图
450 - [`../HANDOFF.md`](../HANDOFF.md):历史交接记录
451 - [`../plans/TONIGHT_SPRINT.md`](../plans/TONIGHT_SPRINT.md):历史冲刺计划
452+- [`../plans/WATCHDOG_LOGGING_ENHANCEMENT.md`](../plans/WATCHDOG_LOGGING_ENHANCEMENT.md):历史 watchdog V1 需求记录,代码已删除
453+- [`../plans/WATCHDOG_V2_CONDUCTOR_INTEGRATED.md`](../plans/WATCHDOG_V2_CONDUCTOR_INTEGRATED.md):历史 watchdog V2 设计草案,未落地
454+- [`../plans/A11Y_GUI_CONTROL.md`](../plans/A11Y_GUI_CONTROL.md):历史 Safari a11y / GUI 控制探索,不再作为当前续命方案
455 - [`../plans/BAA_ARTIFACT_DOWNLOAD_REQUIREMENTS.md`](../plans/BAA_ARTIFACT_DOWNLOAD_REQUIREMENTS.md):已废弃,保留历史决策说明
456 - [`../plans/ARTIFACT_STATIC_SERVICE.md`](../plans/ARTIFACT_STATIC_SERVICE.md):主线已完成,保留实现与验收参考
457 
458 ## 当前主线判断
459 
460-Phase 1(浏览器主链)、Artifact 静态服务,以及 timed-jobs + 续命主线都已完成收口。`T-S060`、`T-S061`、`T-S062`、`T-S063`、`T-S064`、`T-S065`、`T-S066`、`T-S067`、`T-S068`、`T-S069` 已全部落地;当前主线没有 open bug blocker,也没有 open opt,`T-S073` 已完成,剩余待开始任务是 `T-S074` 与后续 Web UI 主线。
461+Phase 1(浏览器主链)、Artifact 静态服务,以及 timed-jobs + 续命主线都已完成收口。`T-S060`、`T-S061`、`T-S062`、`T-S063`、`T-S064`、`T-S065`、`T-S066`、`T-S067`、`T-S068`、`T-S069` 已全部落地;当前主线没有 open bug blocker,也没有 open opt,`T-S073` / `T-S074` 已完成,剩余待开始任务只剩后续 Web UI 主线。
462 
463 如果继续推进,建议:
464 
465 - 远端 `baa-conductor-artifact` 已在 `2026-04-01` 应用 [`packages/d1-client/src/d1-setup.sql`](../packages/d1-client/src/d1-setup.sql) 的最新 schema;后续如新建或重置 D1 环境,仍需先执行同一脚本
466-- 再完成 `T-S074`
467-- 之后回到 `T-S070 -> T-S071 -> T-S072` 的正式 Web UI 工作台主线
468+- 直接回到 `T-S070 -> T-S071 -> T-S072` 的正式 Web UI 工作台主线
469 
470 ## 现在该读什么
471 
472diff --git a/tools/watchdog/.gitignore b/tools/watchdog/.gitignore
473deleted file mode 100644
474index 9eb2fd9a5bae8480a63fb95986ea22889282ff88..0000000000000000000000000000000000000000
475--- a/tools/watchdog/.gitignore
476+++ /dev/null
477@@ -1 +0,0 @@
478-watchdog.log
479diff --git a/tools/watchdog/README.md b/tools/watchdog/README.md
480deleted file mode 100644
481index 8e9cea8fbd39f385f24333ff6d215000bd433f93..0000000000000000000000000000000000000000
482--- a/tools/watchdog/README.md
483+++ /dev/null
484@@ -1,97 +0,0 @@
485-# Watchdog — Claude 对话续命看门狗
486-
487-## 原理
488-
489-1. Claude 写心跳文件 `/tmp/claude_heartbeat.json`
490-2. Claude 写进度文件 `/tmp/claude_progress.json`(当前任务、做到哪了)
491-3. 看门狗每 60 秒检查心跳,按条件续命
492-4. Claude 被唤醒后先读进度文件,接上之前的工作
493-
494-## 状态机
495-
496-| status | 含义 | 看门狗行为 |
497-|--------|------|------------|
498-| working | 干活中 | 不动(除非兜底超时) |
499-| waiting | 等待续命 | 按条件续命 |
500-| renewed | 已续命 | 不动 |
501-| paused | 暂停 | 跳过 |
502-| done | 完成 | 看门狗退出 |
503-
504-## 唤醒条件(三层,任一满足)
505-
506-1. **定时唤醒**:`wake_at > 0 && now >= wake_at`(我判断任务要10分钟就设10分钟后)
507-2. **空闲超时**:`wake_at == 0 && idle > timeout`(不确定多久,靠超时兜底)
508-3. **兜底上限**:`max_wake_at > 0 && now >= max_wake_at`(无论什么状态都叫醒,防止彻底卡死)
509-
510-## 心跳文件 `/tmp/claude_heartbeat.json`
511-
512-```json
513-{
514-  "ts": 1774808270,
515-  "timeout": 300,
516-  "status": "working",
517-  "wake_at": 0,
518-  "max_wake_at": 1774809870,
519-  "tab": "OpenClaw的GUI控制机制 - Claude",
520-  "renewal_msg": "watchdog续命:请继续"
521-}
522-```
523-
524-## 进度文件 `/tmp/claude_progress.json`
525-
526-被唤醒后先读这个文件,知道之前在做什么、做到哪了:
527-
528-```json
529-{
530-  "updated_at": 1774808270,
531-  "task": "conductor开发:files/read kind修复 + 日志落盘 + T-S049",
532-  "subtasks": [
533-    {"id": "fix-kind", "status": "done", "note": "一行改动已提交"},
534-    {"id": "log-ingest", "status": "in_progress", "note": "codex在写,预计5分钟"},
535-    {"id": "T-S049", "status": "pending"}
536-  ],
537-  "codex_windows": ["baa-conductor — codex"],
538-  "claude_windows": ["claude --dangerously-skip-permissions"],
539-  "next_action": "检查codex是否完成log-ingest,完成则合并并开始T-S049"
540-}
541-```
542-
543-## 工作流
544-
545-```
546-Claude 开始工作:
547-  1. 写心跳 status=working
548-  2. 写进度 task/subtasks/next_action
549-  3. 分配任务给 codex/claude
550-  4. 设心跳 status=waiting, wake_at=N分钟后, max_wake_at=30分钟后
551-  5. 停止工具调用,等看门狗唤醒
552-
553-看门狗唤醒 Claude:
554-  → Safari 发续命消息
555-
556-Claude 被唤醒:
557-  1. 读进度文件,知道之前在做什么
558-  2. 检查各 codex/claude 窗口状态
559-  3. 继续工作
560-```
561-
562-## 用法
563-
564-```bash
565-# 启动
566-nohup bash tools/watchdog/watchdog.sh 60 &
567-
568-# 发消息
569-bash tools/watchdog/a11y_msg.sh "标签页全名" "消息"
570-
571-# 停止看门狗
572-python3 -c "import json; d=json.load(open(/tmp/claude_heartbeat.json)); d[status]=done; json.dump(d,open(/tmp/claude_heartbeat.json,w))"
573-```
574-
575-## 文件
576-
577-- watchdog.sh — 看门狗主循环
578-- a11y_msg.sh — Safari 无障碍消息发送
579-- watchdog.log — 运行日志
580-- /tmp/claude_heartbeat.json — 心跳(看门狗读)
581-- /tmp/claude_progress.json — 进度(Claude 读写)
582diff --git a/tools/watchdog/a11y_msg.sh b/tools/watchdog/a11y_msg.sh
583deleted file mode 100755
584index 43ca8e610dfa2f56ab9ec1fc5e0d327aa360af4c..0000000000000000000000000000000000000000
585--- a/tools/watchdog/a11y_msg.sh
586+++ /dev/null
587@@ -1,41 +0,0 @@
588-#!/bin/bash
589-# a11y 消息发送:通过 Safari 无障碍 API 给指定标签页发消息
590-# 用法: a11y_msg.sh <标签页全名> <消息>
591-# 示例: a11y_msg.sh "OpenClaw的GUI控制机制 - Claude" "续命消息"
592-
593-TAB_NAME="$1"
594-shift
595-MSG="$*"
596-
597-if [ -z "$TAB_NAME" ] || [ -z "$MSG" ]; then
598-    echo "用法: $0 <标签页全名> <消息>"
599-    exit 1
600-fi
601-
602-# 1. 切标签页(全名匹配)
603-osascript -e "tell application \"Safari\"
604-    repeat with w in windows
605-        repeat with t in tabs of w
606-            if name of t is \"$TAB_NAME\" then
607-                set current tab of w to t
608-                set index of w to 1
609-                return \"matched\"
610-            end if
611-        end repeat
612-    end repeat
613-    return \"not found\"
614-end tell" 2>/dev/null
615-
616-sleep 1
617-
618-# 2. 设剪贴板 + 粘贴 + 回车
619-osascript -e "set the clipboard to \"$MSG\""
620-osascript -e 'tell application "System Events" to tell process "Safari"
621-    set frontmost to true
622-    delay 0.5
623-    keystroke "v" using command down
624-    delay 0.5
625-    keystroke return
626-end tell' 2>/dev/null
627-
628-echo "SENT to [$TAB_NAME]"
629diff --git a/tools/watchdog/watchdog.sh b/tools/watchdog/watchdog.sh
630deleted file mode 100755
631index 4f045ccd94a25e9bcd45056396101e296a0377a8..0000000000000000000000000000000000000000
632--- a/tools/watchdog/watchdog.sh
633+++ /dev/null
634@@ -1,80 +0,0 @@
635-#!/bin/bash
636-# 看门狗 v4:renewed 超时重试
637-
638-SCRIPT_DIR=$(cd "$(dirname "$0")" && pwd)
639-CHECK_INTERVAL=${1:-60}
640-HEARTBEAT=/tmp/claude_heartbeat.json
641-LOG="${SCRIPT_DIR}/watchdog.log"
642-
643-echo "[$(date)] watchdog v4 started, interval=${CHECK_INTERVAL}s" >> "$LOG"
644-
645-while true; do
646-    sleep $CHECK_INTERVAL
647-    [ ! -f "$HEARTBEAT" ] && continue
648-
649-    RESULT=$(python3 << PYEOF
650-import json, time
651-try:
652-    d = json.load(open("$HEARTBEAT"))
653-    now       = int(time.time())
654-    ts        = d.get("ts", 0)
655-    timeout   = d.get("timeout", 300)
656-    status    = d.get("status", "unknown")
657-    tab       = d.get("tab", "")
658-    msg       = d.get("renewal_msg", "watchdog续命")
659-    wake_at   = d.get("wake_at", 0)
660-    max_wake  = d.get("max_wake_at", 0)
661-    idle      = now - ts
662-    need      = "no"
663-    reason    = ""
664-
665-    if status in ("done", "paused"):
666-        pass
667-    elif max_wake > 0 and now >= max_wake:
668-        need = "yes"
669-        reason = f"max_wake_at reached ({now}>={max_wake})"
670-    elif status == "waiting":
671-        if wake_at > 0 and now >= wake_at:
672-            need = "yes"
673-            reason = f"wake_at reached ({now}>={wake_at})"
674-        elif wake_at == 0 and idle > timeout:
675-            need = "yes"
676-            reason = f"idle timeout ({idle}s>{timeout}s)"
677-    elif status == "renewed" and idle > timeout:
678-        need = "yes"
679-        reason = f"renewed but no response, retry ({idle}s>{timeout}s)"
680-
681-    print(f"{status}|{idle}|{timeout}|{tab}|{need}|{msg}|{reason}|{wake_at}|{max_wake}")
682-except:
683-    print("error|0|0|||no|||0|0")
684-PYEOF
685-)
686-
687-    IFS="|" read -r ST IDLE TOUT TAB NEED MSG REASON WAKE MAXW <<< "$RESULT"
688-
689-    if [ "$ST" = "done" ]; then
690-        echo "[$(date)] EXIT: done" >> "$LOG"
691-        exit 0
692-    fi
693-
694-    if [ "$ST" = "paused" ]; then
695-        echo "[$(date)] PAUSED" >> "$LOG"
696-        continue
697-    fi
698-
699-    echo "[$(date)] CHECK: status=$ST idle=${IDLE}s timeout=${TOUT}s need=$NEED wake=$WAKE max=$MAXW reason=$REASON" >> "$LOG"
700-
701-    if [ "$NEED" = "yes" ]; then
702-        echo "[$(date)] RENEWAL: $REASON" >> "$LOG"
703-        bash "${SCRIPT_DIR}/a11y_msg.sh" "$TAB" "$MSG"
704-        A11Y_RC=$?
705-        python3 << PYEOF2
706-import json, time
707-d = json.load(open("$HEARTBEAT"))
708-d["ts"] = int(time.time())
709-d["status"] = "renewed"
710-json.dump(d, open("$HEARTBEAT", "w"))
711-PYEOF2
712-        echo "[$(date)] RENEWED (a11y_rc=$A11Y_RC)" >> "$LOG"
713-    fi
714-done