- 变更规模:新增 514 / 修改 62 / 重命名 155 / 删除 4(归档重组与文档轮次) - .gitignore 修:`归档/**/db-cwd归一-备份-*/` —— 原规则写绝对层级(归档/db-cwd归一-…), 目录搬进 归档/配置与备份/ 后**静默失效**,43 MB 的 DB 备份又变成未跟踪 - .gitignore 补:嵌套 git 内部数据(归档/内嵌git-20261008/、归档/skills-git-旧线-20261007/dotgit-原样移出/) - .gitignore 补:运行态与部署副本(.workbuddy/collab/、.workbuddy/tools/、.workbuddy/.load-pending、.workbuddy/tmp-*) - .gitignore 补:备份件(*.bak-*) - 未跟踪文件从 2190 降到 890(其余为 归档/ 归档件与 .workbuddy/memory/ 知识文件,按口径入库)
7.6 KiB
7.6 KiB
需求统一启停控制台(2026-09-30)
起因(用户原话):「使用协作skill后 某个需求 统一管理 各种对应任务和程序的启停,包括协作程序等」 落地物:
.workbuddy/collab/goalctl.py(新)+(复用).workbuddy/collab/stop-collab.py。 全文读数均为本机实测,⛔ 无推断。
0. 结论(三行)
- 一个需求牵扯的"可启停物"只有四层(实测盘清,别再数):排期层/程序层/总开关层/服务层;钩子层不在可启停范围内(下条)。
- 🔴 一个硬事实决定了整个设计形状:钩子是全局注册、跨项目共用的 ——
E:/ProgramData/.workbuddy/settings.json里 12 个 hook,其中还混着别的工作区的ai1net-decision-laya/bridge/decision_bridge.py(×4 事件)。⇒ ⛔ 不能靠"装卸钩子"来启停某个需求(会连累所有项目)⇒ 只能 开关文件 + 入口早退。 - 入口已落地成三条命令:
goalctl.py status | start | stop(默认干跑,加--yes才真做;写前自动备份)。
1. 清单:一个需求到底牵扯哪些东西(本机实测)
| 层 | 具体物 | 本棒实测状态 | 谁能改 | 拦在哪(生效点) |
|---|---|---|---|---|
| ① 排期层 | automations 表里的周期排期 |
3 条,全 PAUSED | ⛔ 只有会话(automation_update 工具) |
不再起新会话 |
| ② 程序层 | collabd.config.json 的 wake_enable(协作程序投递总闸) |
本棒已置 false |
✅ 脚本 | 程序不再投递(=不再唤醒主会话) |
| ③ 总开关层 | goal.json 的 run 段(active/paused) |
本棒已置 paused |
✅ 脚本 | 唤醒轮/程序读到即立刻退 |
| ④ 服务层 | 看板 board.py --serve/守护 guard/网关心跳 |
全停(0 个 / 没在跑 / 登记册 0 条) | ✅ 复用 stop-collab.py |
写标志 ⇒ 对端优雅退出 |
| — 钩子层 | 全局 12 个 hook(wb-result-hook.py、lock-guard-hook.py…) |
常开、不可装卸 | ⛔ 只有全局配置能改 | 不拦 —— 零 token,且"要不要干活"全在它调的程序内部 |
剔除项(⛔ 不是启停对象):一次性棒 15 条(schedule_type='once'、next_run_at 空=已耗),它们 status 仍是 ACTIVE 但永远不会再触发。
⚠️ 判"某条排期还在不在跑"不能只看 status —— 删除是软删(deleted_at 有值、status 照旧 ACTIVE)⇒ 脚本里已按 deleted_at 过滤。
2. 三条硬约束(决定了为什么长这样)
| # | 约束 | 后果 |
|---|---|---|
| ① | 钩子全局注册、跨项目共用 | ⛔ 不装卸钩子;启停只能靠"开关文件 + 入口早退" |
| ② | 排期只能由会话改(脚本直改 workbuddy.db 的 automations = 改活库,且宿主是否重读未验) |
脚本只打印待办;⚠️ 并给降级保障:漏改时唤醒轮读到 run=paused 会立刻退(一次空跑) |
| ③ | ⛔ 不 kill 会话/worker | ⛔ 不重启宿主 | ⛔ 不改全局配置 | 停服务一律"写标志让对方自己退"(guard.stop)、或停自建看板实例 |
3. 启停语义:三层同时翻,缺一层就留缝
| 想要 | ① 排期层 | ② 程序层 | ③ 总开关 | ④ 服务层 |
|---|---|---|---|---|
| 真停 | PAUSED |
wake_enable=false |
run=paused |
stop-collab.py --yes |
| 真启 | ACTIVE(+两条相位差 ≈30 分钟) |
wake_enable=true |
run=active |
⛔ 不自启任何常驻(常驻在本机已判走不通) |
为什么三层缺一不可(各自守备范围不同):
- 排期层 管:会不会起新会话(唯一能产生新交付的通道)
- 程序闸 管:会不会投递(投递=唤醒活会话,会占主会话一轮 ⇒ 用户体感"卡")
- 总开关 管:起来了之后该不该干活(兜底 + 人/AI 都直接可读)
- 🔴 三者互补不重叠:只关程序闸 ⇒ 排期照旧起会话;只停排期 ⇒ 程序照旧投递;只有三个一起翻才是"真停"。
4. 用法
PY="E:/ProgramData/.workbuddy/binaries/python/versions/3.13.12/python.exe"
"$PY" .workbuddy/collab/goalctl.py # 状态台(只读,四层一次列清)
"$PY" .workbuddy/collab/goalctl.py stop # 干跑:列出会做什么
"$PY" .workbuddy/collab/goalctl.py stop --yes # 真停
"$PY" .workbuddy/collab/goalctl.py start --yes # 真启
"$PY" .workbuddy/collab/goalctl.py start "新目标名" --yes # 启 + 改名
驱动口径(=用户已定的那条):启停由 「执行 XXX 目标」这道口令驱动 ——
下口令 ⇒ start;目标完成或有阻碍 ⇒ stop。⛔ 唤醒轮自己不许把自己启回来。
状态台实际输出(本棒读数)
【总开关】run = paused
目标 = 本机(桌面客户端)内的多会话协作
目标状态 = 三路全过
队列 = {'done': 4}
【② 程序闸】wake_enable = False
钩子链最后唤起 = tick 2 分钟前 / once 4 分钟前
【① 排期层】周期排期 3 条(**这才是启停对象**)/一次性棒 15 条(已耗,⛔ 不是启停对象)
⚪ 1eaf45c3 PAUSED [协同监管 · 心跳……]
⚪ 16bec5ce PAUSED [本机协作]-唤醒轮B
⚪ caca9a89 PAUSED [本机协作]-唤醒轮A
⇒ 一句话:这个需求现在是 **停着**
5. 本棒实际做了什么
- 新增
.workbuddy/collab/goalctl.py(状态台 + start/stop;默认干跑、写前备份到.workbuddy/collab/bak-goalctl-<日期>/、⛔ 从不删文件)。 - 接进唤醒轮:两条提示词都加了第 0 步"先读总开关" ——
run=paused⇒ ⛔ 不派活、⛔ 不改文件、⛔ 不自启,一句话结束(="停"的兜底)。 - 按已定口径落成一致状态:A/B 从未 ACTIVE(没下过"执行 XXX 目标"口令)⇒ 正解就是停 ⇒ 执行
stop --yes:run=paused/wake_enable=false/服务层全停/排期 2 条本已 PAUSED。 - 🔴 顺手修掉一个真 bug(会致"误判完成"):原实现把任务图按"默认点"读
tmp/supervise-inbox/taskgraph.json—— 该文件根本不存在 ⇒ 三路并集少一路 ⇒ 可能把"未完成"看成"已完成"。现改为按配置taskgraph解析(交付物/任务图.json,18 节点全 done);并给读不到单独打标(⛔ 不许读不到就判完成)。
6. 已知边界(诚实说,⛔ 别当它能做到)
- ⛔ 做不到"一秒内把所有在跑的会话停下" —— 会话不可 kill(用户明令)。能做的只有「不再叫新的 + 起来了不干活」。
- ⚠️ 排期层脚本改不了 ⇒ 必须由会话执行;有
run=paused兜底,但那一轮仍会被起一次(成本=一次空会话)。 - ⚠️ 一个工作区当前只有一份
goal.json⇒ "需求"与"工作区"目前是 1:1。若将来一个工作区要并行多个需求,得把开关做成多份(本棒不做)。 - ℹ️
wake_enable=false只关投递:程序的投影、看板、台账照常(零成本),所以"关"没有副作用。 - ℹ️ ④ 服务层里网关心跳已被判死能力(桌面端硬编码
CODEBUDDY_DISABLE_CRON=1)⇒ 那一项是"名存实亡",stop只是顺手清登记册。
7. 图
见同目录 唤醒-需求统一启停-20260930-图.html(① 四层清单图:标出钩子层"不可启停";② 三层守备图:各层各拦什么)。