- 变更规模:新增 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/ 知识文件,按口径入库)
22 KiB
会话机制合并技能包 · 方案(2026-10-01)
状态:正式方案(任务 0 产出) · 补
接续包_会话机制合并技能包_20261001.md §2 任务 0的后半段 落点:$WS/交付物/会话机制合并技能包-方案-20261001.md定位:本文件是任务 1–4 的唯一设计依据;与接续包 §3.4 冲突时以本文件为准(本文件是 §3.4 的展开,⛔ 未改其任何已定项) ⚠️ 本文件只写本轮实测到的计数与字节;⛔ 不报未经实测的系数。
一、目标(用户原话拆解 · 不可改动)
「整合 会话机制相关技能为一个 skill 包,再将多会话协作机制也整合到这个技能包,要求换一台电脑的 workbuddy 上运行也能自动完成配置,让所有会话遵循会话机制,并且可独立使用多会话协作」
| # | 硬要求 | 判据(怎么算达成) |
|---|---|---|
| 1 | 一个技能包装下「会话机制」相关技能 | 目标目录存在,SKILL.md 能分别加载两段 |
| 2 | 多会话协作机制并入同一个包 | 协作本体脚本在包内,且包内可独立跑起来 |
| 3 | 换一台电脑 ⇒ 自动完成配置 | 拷目录 → 跑一次 install.py → 钩子全通,⛔ 不手改绝对路径 |
| 4 | 所有会话遵循会话机制 + 多会话协作可独立使用 | 全局注入面生效;包内自包含,⛔ 不依赖旁件 |
二、现状(2026-10-01 实测 · 定向复核)
2.1 家当散在三处(这是要解决的第一性问题)
| 落点 | 装什么 | 实测规模 |
|---|---|---|
~/.workbuddy/skills/multi-session-collab/ |
协作本体 | 14 个文件(其中 2 份是 .bak-*,⛔ 不属机制) |
D:/github/dsh_shenxian/dsh-server-docs/07-scripts/ |
宿主钩子 + 锁 | 目录内 29 个脚本 / 配置文件,其中属机制 9 份 |
$WS/.workbuddy/ |
运行态 | 分两个子目录:collab/(协作程序与配置,9 个文件 + 4 个子目录)+ tools/(监控 / 成本 / 会话查找等辅助,23 个条目) |
2.2 精确拷贝源清单(任务 1 直接照抄这张表)
① 协作本体 → 包 scripts/collab/
源(~/.workbuddy/skills/multi-session-collab/) |
说明 |
|---|---|
scripts/collabd.py |
协作主程序(177 KB 级) |
scripts/board.py |
看板 |
scripts/guard.py |
守卫 |
scripts/selftest.py |
自检 |
scripts/collabd.config.example.json |
配置模板(install.py 的输入) |
references/{architecture,deploy,pitfalls,taskgraph}.md |
4 份 references |
assets/{board.html,design-tokens.css} |
2 份前端资产 |
SKILL.md |
改造为包内两段式总入口(⛔ 不是原样拷) |
⛔ 不拷:scripts/collabd.py.bak-digest-20261001、scripts/collabd.py.bak-ledger-first-20261001(历史备份,非机制)。
② 宿主钩子 + 锁 → 包 scripts/hooks/ 与 scripts/lock/(源 DOC/07-scripts/)
| 源文件 | 归入 | 钩子事件(见 2.3) |
|---|---|---|
session-log-guard.py |
scripts/hooks/ |
PostToolUse + UserPromptSubmit |
lock-guard-hook.py |
scripts/hooks/ |
PreToolUse(Write|Edit) + SessionStart |
bash-output-guard.py |
scripts/hooks/ |
PreToolUse(Bash|Read) |
stop-dialog-guard.py |
scripts/hooks/ |
UserPromptSubmit |
skill-load-guard.py |
scripts/hooks/ |
UserPromptSubmit |
handoff-guard.sh |
scripts/lock/ |
锁(手工调用,非钩子) |
preflight-lock.sh |
scripts/lock/ |
开工前置(手工调用) |
handoff-status.py |
scripts/lock/ |
锁状态(手工调用) |
op-lock.sh |
scripts/lock/ |
操作锁(手工调用) |
③ 运行态 → 包 scripts/collab/ 与 scripts/forensics/
源($WS/.workbuddy/) |
归入 |
|---|---|
collab/goalctl.py |
scripts/collab/ |
collab/board_ext.py |
scripts/collab/ |
collab/wake-session.py |
scripts/collab/ |
collab/stop-collab.py |
scripts/collab/ |
collab/deliver-gateway-token.py |
scripts/collab/(超 §3.4 明列清单的补充,理由:属协作投递链、要求 4「可独立使用」) |
collab/collabd.config.json |
scripts/collab/,改名 collabd.config.json.bak-live-20261001(本机活配置留存,供 install.py 比对;⛔ 不作为分发模板) |
tools/wb-result-hook.py |
scripts/hooks/ |
~/.workbuddy/skills/workbuddy-session-forensics/scripts/proc-parent.py |
scripts/forensics/ |
2.3 宿主钩子接线现状(settings.json 实测 · 14 处 · 指向 3 个不同目录)
| 事件 | matcher | 指向 |
|---|---|---|
| PostToolUse | (空) | 07-scripts/session-log-guard.py(-S) |
| PreToolUse | ^AskUserQuestion$ |
ai1net-decision-laya/bridge/decision_bridge.py |
| PreToolUse | ^Bash$ |
$WS/.workbuddy/tools/wb-result-hook.py |
| PreToolUse | Write|Edit |
07-scripts/lock-guard-hook.py |
| PreToolUse | Bash|Read |
07-scripts/bash-output-guard.py |
| SessionEnd | (空)×2 | decision_bridge.py / wb-result-hook.py |
| SessionStart | startup|resume |
07-scripts/lock-guard-hook.py |
| SessionStart | (空) | decision_bridge.py |
| UserPromptSubmit | (空)×5 | decision_bridge.py / wb-result-hook.py / stop-dialog-guard.py / skill-load-guard.py / session-log-guard.py(-S) |
🔴 两条硬事实:
- 14 处全部硬编码 python 绝对路径(
E:\ProgramData\.workbuddy\binaries\python\versions\3.13.12\python.exe)⇒ 换机器必碎,正是要求 3 要治的。 decision_bridge.py出现 4 处,但它属另一条线(ai1net-decision-laya)⇒ ⛔ 不并入本包、⛔ 不改它的 4 条接线。本包只接管其余 10 处。
2.4 引用面(搬动前 blast radius · 实测)
handoff-guard 被引用:文档库 5 / 工作区 2;preflight-lock 2/1;op-lock 3/0;lock-guard-hook 3/0;session-log-guard 3/0;stop-dialog-guard 6/0;skill-load-guard 4/0;bash-output-guard 5/1。
⇒ 合计约 37 处引用(不含 decision_bridge)。⛔ 不能 mv 走:任一漏改 = 静默失效(pitfalls 明写「同名两份实现是最难查的故障」)。
2.5 🔴 任务 1 执行后回填(以本节为最终实测值)
⚠️ 起草本文件时曾出现一处误判(把 collab/ 记为「空」)—— 起因是 ls -1 目录A 目录B | sort 把两个目录的输出合并排序了,误读成同一目录 ⇒ 已按分开列目录更正。教训:多目录用一条 ls 会被合并排序,必须分开列。 本节即为更正后的实测值。
| 项 | §3 原文 | 最终实测 | 处置 |
|---|---|---|---|
$WS/.workbuddy/collab/ |
列为一个落点 | 9 个文件:board_ext.py collabd.config.json deliver-gateway-token.py gateway-schedules.json goalctl.py stop-collab.py wake-pulse.sh wake-session.py + 1 份 goalctl.py.bak-*;另有 4 个子目录 |
运行态源取自此目录,不是 tools/ |
$WS/.workbuddy/tools/ |
列为一个落点 | 23 个条目,全为监控 / 成本 / 常驻类(cost_model.py keepalive.py thin-consumer.py wb-supervisor-watch.py 等)+ wb-result-hook.py |
只取 wb-result-hook.py(钩子);其余暂不纳入 |
multi-session-collab/scripts/ |
「14 文件」 | 14 中含 2 份 .bak-* |
实际机制 = 12 份,⛔ bak 不拷 |
references/{collab,rules,forensics}.md |
列在目录表 | 无源,属本包新写 | 任务 4 写 |
manifest.md |
列在目录表 | 任务 1 已生成 | ✅ 已完成 |
三、方案对比(≥2 项 · 利弊 · 建议)
方案 A · 单一实现源 + 原位转发壳 ✅ 建议采用
包内 = 唯一实现(cp 拷入);07-scripts/<同名> 与 $WS/.workbuddy/tools/<同名> 改成 3 行转发壳(exec 包内那份),⛔ 不删原件、不动物流。
- 优点:① 零 blast radius —— 既有 37 处引用一个字都不用改,全部继续可用;② 换机器只需搬一个目录(正是要求 3);③ **消灭「同名两份实现」**这个最难查的故障模式(读数为准的只有一份);④ 可灰度:先拷壳 → 验壳 → 再切,每一步都能停;⑤ 回滚只需还原壳文件与
settings.json备份。 - 缺点:① 文档库排错时多一层间接(看 shell 才知道真身在哪);② 若用户日后删掉整个包,转发壳会指向不存在的目标 ⇒ 需在
install.py --uninstall里先还原壳再让用户删;③ 需要一次「改壳」动作(9 个脚本),本轮必须放在最后做(有 blast radius)。
方案 B · 直接 mv 到包内 + 全量改引用 ❌ 淘汰
- 优点:结构最干净,读代码只有一处;无转发跳数。
- 缺点:必须一次性改完约 37 处引用,任一漏改 ⇒ 静默失效(无报错、只在关键时刻掉链子);无法灰度;回滚要把 37 处反向改回来。风险与收益不匹配 ⇒ 不可接受。
方案 C · 只做「配置器」包,机制脚本原地不动 ❌ 淘汰(不满足需求)
- 优点:改动最小、风险最低;
install.py只做钩子接线与工作区初始化。 - 缺点:直接违反要求 1、2、3 —— 没有「一个包」、没有整合、换机器仍要搬三处。需求未达 ⇒ 淘汰。
方案 D · 硬链接 / junction 把三处指到一个包 ❌ 淘汰
- 优点:零拷贝、单一实现、引用不用改。
- 缺点:Windows 下 junction 需管理员或开发者模式,跨盘符不支持硬链接(本机 C: 与 E: 并存);换机器必碎(恰恰是要解决的问题);R11「交互 / 便利性」净变差。淘汰。
🔴 建议
采用方案 A。 它是唯一同时满足「零 blast radius」「换机器只搬一处」「消灭双实现」三项的候选;B 的干净结构以 37 处引用的一次性正确率为代价,不值得;C 不满足需求;D 与「换机器」目标直接冲突。
四、推荐方案的落地设计(任务 1–4 照此执行)
4.1 包内目录(照 §3.4 第 2 条 · 已定项)
~/.workbuddy/skills/session-mechanism/
SKILL.md # 总入口;两段可分别加载:「会话机制」/「多会话协作」
install.py # 🔴 自动配置(本包核心交付物)
references/
architecture.md deploy.md pitfalls.md taskgraph.md # ← 拷自 multi-session-collab
collab.md rules.md forensics.md manifest.md # ← 🆕 本包新写(任务 4)
scripts/
hooks/ session-log-guard.py lock-guard-hook.py bash-output-guard.py
stop-dialog-guard.py skill-load-guard.py wb-result-hook.py
lock/ handoff-guard.sh preflight-lock.sh handoff-status.py op-lock.sh
collab/ collabd.py board.py board_ext.py goalctl.py wake-session.py
guard.py selftest.py stop-collab.py deliver-gateway-token.py
collabd.config.example.json collabd.config.json.bak-live-20261001
forensics/ proc-parent.py
assets/ board.html design-tokens.css
✅ 任务 1 已完成:上述 27 个文件已 cp 拷入,逐文件 py_compile / Git-Bash bash -n / json.loads 全通过(失败 0),并与源逐字节 md5 一致;清单见包内 references/manifest.md(含 provenance 与「暂未纳入」清单)。
⚠️ references/ 中 collab / rules / forensics / manifest 四份当前没有源,属新写(任务 4);⛔ 不要去找现成文件。
4.2 install.py 五项职责(照 §3.4 第 5 条 · 已定项)
| # | 职责 | 关键约束 |
|---|---|---|
| ① | 自解析 | 解释器一律 sys.executable(⛔ 不硬编码 python 路径);配置目录按 CODEBUDDY_CONFIG_DIR 推导(⛔ 不硬编码盘符) |
| ② | 钩子接线 | 声明表驱动(14 处 → 一张表,decision_bridge 的 4 条排除在外);先删自己旧条目再插(幂等);写前备份;支持 --dry-run;--uninstall 逐字节还原 |
| ③ | 工作区初始化 | --workspace <path> ⇒ 由 collabd.config.example.json 生成 collabd.config.json(路径按本机推导)+ 写工作区规则锚 |
| ④ | --verify |
每个钩子跑空载荷须 rc=0 + collabd.py --where + selftest.py(PASS / FAIL 0) |
| ⑤ | 日志 | 全部写操作写 install.log |
4.3 「所有会话遵循」的注入面(照 §3.4 第 6 条)
- ✅ 已确认可用:① 全局钩子(
settings.json全局生效)② 技能全局可见 ③~/.workbuddy/MEMORY.md(用户级记忆,跨会话注入)。 - ⚠️ 未取证:WorkBuddy 是否读
~/.workbuddy/AGENTS.md。 ⇒ 🔴 任务 2 开工前必须先只读取证(线索:app.asar.unpacked/cli/dist/codebuddy-headless.js、codebuddy-lite-wb.mjs里出现AGENTS.md字样)。⛔ 不许猜、不许跳过。 若读 ⇒ 本包多一个全局注入点(写在install.py里落一份锚文件);若不读 ⇒ 注入面收敛为上述三条,方案不动。
4.4 转发壳(照 §3.4 第 4 条 · 🔴 放最后做)
DOC/07-scripts/<同名> 与 $WS/.workbuddy/tools/<同名> 改为 3 行壳:定位包内真身 → exec 之。
- ⛔ 不删原件:先把原件改名
*.orig-<日期>还是先用.bak-forwarder-<日期>备份 ⇒ 必须备份,再覆盖(R7)。 - ⛔ 不带
--domains的独占锁期间才能做(改的是全平台共用脚本 ⇒ 机制层)。 - 验收:
handoff-guard.sh --status行为与改前一致。
五、红线 R1–R11 逐条自查
| # | 是否命中 | 自查结论 |
|---|---|---|
| R1 不自动升级 dsh | ⛔ 不命中 | 本方案只动 ~/.workbuddy/skills/、settings.json、文档库脚本与工作区 tools/,不碰任何 dsh 升级链路 |
| R2 不改官方 dsh 主程序与缓存 | ⛔ 不命中 | ⛔ 全程不写 @deepseek-ai/dsh 及其缓存;扩展只走 profile 层既定机制 |
R3 client bundle 禁 exports.default |
⛔ 不命中 | 不改任何 client bundle |
| R4 不用真实账号测登录 | ⛔ 不命中 | 本轮无登录类验证 |
| R5 权限只准收窄 | ⛔ 不命中 ⇒ 附权限影响评估(见 5.1) | 无新挂载 / 无放开遮蔽 / 无暴露平台目录或 env / 无放宽 nft / 无提档位;钩子不新增事件类型(已存在的 5 类) |
| R6 先查已有资产再动手 | ✅ 已履行 | 已读接续包 §3 盘点 + 本轮定向复核三处源目录(见 2.1 / 2.2 / 2.5);未装任何新东西 |
| R7 禁未经确认的批量写入 | ✅ 已履行 | 拷贝涉及 27 个文件(>10)⇒ 已在 2.2 表列出完整前置清单,包内 manifest.md 亦有逐文件 provenance;均为 cp 新增到新建目录,⛔ 无覆盖、⛔ 无 cp -r 覆盖、⛔ 无全库遍历、⛔ 无 git add -A;本包正是用户明确要求(原话「整合…为一个 skill 包」)⇒ 属本 lane 内(R7-边界) |
| R8 生产变更直接做 | ⛔ 不命中 | 本方案全在本机,不触 47.77.182.89 |
| R9 禁人工删锁 / 接管 | ✅ 已履行 | 本会话已 --claim-exec 抢到全局独占锁;⛔ 不删 交接单/.exec-lock、⛔ 不接管、⛔ 不以「疑似已死」为由删锁;完工反序释放;抢不到即停手(本轮已抢到) |
| R10 禁 root / 禁非该实例 uid | ⛔ 不命中 | 全程当前 Windows 用户,无实例、无 root、无 profile |
| R11 只做正向迭代 | ✅ 已自查 | 见 5.2,十维无净变差 |
5.1 R5 · 权限影响评估(按 §1.5 B 阶段 2 附)
| 维度 | 结论 |
|---|---|
| 新增挂载 / 放开遮蔽 | 无。包落在 ~/.workbuddy/skills/(用户级技能目录,已有大量同类技能),沿用既有可见性,⛔ 不新增目录层级 |
| 暴露平台目录或 env | 无。install.py 只读自身所在路径与 CODEBUDDY_CONFIG_DIR,⛔ 不外传、⛔ 不写平台 env |
| 放宽 nft / 提档位 | 无 |
| 钩子能力变化 | 不扩大。14 处接线的事件类型(PostToolUse / PreToolUse / SessionStart / SessionEnd / UserPromptSubmit)全部是已有的;本包只做指向改写(绝对路径 → 包内路径),⛔ 不新增 matcher、⛔ 不扩大拦截面 |
| 写入面 | 唯一新增写动作 = settings.json(写前备份);其余均为用户级技能目录内新增文件,等价于「装一个技能」 |
| 净结论 | 权限不扩大 ⇒ 无需权限类确认;本节为履行流程留痕 |
5.2 R11 · 十维自查
| 维度 | 判断 | 说明 |
|---|---|---|
| 目标 | ↑ | 「一个包 + 自动配置」直接达成 |
| 方向 | ↑ | 与用户原话完全一致 |
| 架构 | ↑ | 三处合一;消除「同名两份实现」这一已实测到过的故障模式 |
| 功能 | → | 全为 cp,行为等价;decision_bridge 那 4 条原样不动 |
| 性能 | → | 转发壳会多一次进程启动(脚本本身是短进程)⇒ 量级可忽略;⚠️ 本轮未实测耗时系数,⛔ 不报具体毫秒数 |
| 安全 | → | 权限不扩大(见 5.1) |
| 交互 | → | 对使用者无感知变化 |
| UI | → | 不涉及 |
| 便利性 | ↑↑ | 换机器:从「搬三处 + 手改 14 处绝对路径」→「跑一次 install.py」 |
| 扩展性 | ↑ | 新增机制脚本从此有唯一落点,不再三处扩散 |
| 结论 | 无净变差 | 唯一潜在劣化 = 转发壳一跳(可忽略)+「包被删后壳悬空」(🈯 用约束堵住:--uninstall 先还原壳,再让用户删包) |
六、执行顺序与验收
顺序(一次只做一件事,做完即停)
- 任务 1 · 建骨架 —— 建
~/.workbuddy/skills/session-mechanism/;按 2.2 表cp拷入(⛔ 不mv);逐个py_compile/bash -n;算 md5 记进references/manifest.md。 - 任务 2 · 写
install.py—— 🔴 开工前先只读取证 §4.3 的未取证项;然后按 4.2 五项职责实现。 - 任务 3 · 本机实测 —— 见下验收判据,⛔ 不许只测 happy path。
- 任务 4 · 文档与收口 ——
SKILL.md(两段式)+references/deploy.md(换机器)+ 最后才做 4.4 转发壳 + 三层沉淀 + 反序释放锁。
验收判据(照接续包 §5,逐条打钩)
| # | 判据 | 状态 |
|---|---|---|
| 1 | install.py --dry-run diff 与预期一致;真装后再跑一遍 ⇒ 零改动(幂等) |
⬜ 待任务 3 |
| 2 | 装机后 --verify:钩子空载荷全 rc=0;collabd.py --where 正确;selftest.py PASS / FAIL 0 |
⬜ 待任务 3 |
| 3 | --uninstall 后 settings.json 与装前备份逐字节相同(cmp) |
⬜ 待任务 3 |
| 4 | 包拷到另一个目录再跑 install.py ⇒ 钩子指向新路径且 --verify 全绿(=「换电脑」最小可复现) |
⬜ 待任务 3 |
| 5 | 07-scripts/ 转发壳:handoff-guard.sh --status 行为与原型一致 |
⬜ 待任务 4 |
七、风险与回滚
| 风险 | 触发条件 | 处置 |
|---|---|---|
| 改壳后既有引用失效 | 转发壳写错、路径推导错 | 改壳前逐个备份 *.bak-forwarder-20261001;验收 5 必做;异常 ⇒ 立刻还原备份 |
settings.json 被写坏 |
install.py 逻辑错 |
写前备份 settings.json.bak-<用途>-20261001(沿用本目录 6 份先例的命名);--uninstall 须 cmp 逐字节相同 |
| 包被删后壳悬空 | 用户手工删包 | --uninstall 先还原壳、后允许删;install.log 留痕 |
| 拷贝把历史备份当机制 | 误拷 .bak-* |
2.2 表已注明 ⛔ 不拷 collabd.py.bak-* |
动了 decision_bridge 那条线 |
表驱动误包含 | install.py 的声明表显式排除 ai1net-decision-laya 的 4 条,并在 --dry-run 输出里打印被排除项以便目视核对 |
回滚三件:① 还原 settings.json 备份 ② 还原 9 个转发壳备份 ③ 删除包目录。三步互不依赖,可单独回。
八、留给后棒的两件事
- §3.4 第 3 条(并入范围)可一句话推翻 —— 现值 = 并入
multi-session-collab(机制本体)+workbuddy-session-forensics(2 个文件:SKILL.md+scripts/proc-parent.py);不并agent-operating-rules(跨项目「作业总规矩 / 说话方式」层,被大量模板引用,只在包内 SKILL.md 声明依赖)。推翻成本低(多拷 4 个 references)。本轮按现值执行。 - 文档库
04-调整方案/占号建档未做 —— 本轮按用户指定落点写在$WS/交付物/。若要求并入文档库正式方案序列,可在任务 4 收尾时补一次原子占号(届时仍须持锁)。
附 · 本轮改动边界(零改动既有机制文件)
新增(3 处)
- 本文件(
$WS/交付物/会话机制合并技能包-方案-20261001.md) - 新包
~/.workbuddy/skills/session-mechanism/(27 个文件,全部cp,含新生成的references/manifest.md) $WS/tmp/inv-20261001/build-manifest.py(一次性脚本,⛔ 不入库)+ 今日日志一段
⛔ 零改动:settings.json / DOC/07-scripts/ 下任何文件 / $WS/.workbuddy/ 下任何文件 / multi-session-collab 下任何文件 / workbuddy-session-forensics 下任何文件 / 自动化排期。
⇒ 旧路径全部原样可用,decision_bridge 那条线未触碰 ⇒ 无回滚负担(回滚 = 删掉新包目录即可)。
本机踩坑记录(供后棒省时)
ls -1 目录A 目录B | sort会把两目录输出合并排序 ⇒ 误判collab/为空。多目录必须分开列。- Python
subprocess.run(["bash", …])在本机落到 WSL 启动器 ⇒bash -n假阴性(乱码 + 路径被吃)。必须显式用E:/ProgramData/.workbuddy/binaries/PortableGit/versions/1.2.0/usr/bin/bash.exe。