feat(skill): 报销技能可独立使用,配套安装脚本与来源启停校验

目标是技能脱离本仓库也能用:任何项目里提到报销都该按同一套纪律走。

- SKILL.md 重写自足化(104 行):删掉两处只在仓库里成立的引用(docs/MCP.md、方案文档);
  新增「第 0 步:确认工具可用」——先 mcp__arb__case_list 探活,工具不在就把 stdio 注册片段
  (uv run python -m src.mcp.server + cwd)交给用户,并明确禁止绕道自己写脚本处理发票;
  写死跨项目事实:材料用绝对路径正斜杠且可来自任何目录、产物在服务器仓库的 cases/<id>/、
  路径从 case_status 的 case_dir 读而不是按当前工作目录猜、别把截图与 info 拷进用户当前工程;
  字段权威指向工具(extraction_spec / info_skeleton / rules_get),三份 references 标注为判读经验
  并把开头指向已删除 src/infra/llm/prompts/* 的悬空路径改成历史沿革
- 补进这轮学到的坑:失败信封的额外字段在 detail 里;match 用单据编号最稳;每步可单独重填;
  敏感值打码引用;截图是核对证据不是给用户的报告
- 新增 scripts/install_skill.py(Makefile 与 tasks.py 各加 skill-install / skill-check):单向同步 +
  --check 漂移退出码 1 + front matter 缺失退出码 2(宁可不装也别装个宿主注册不了的)
- 关键防护:技能来源由 skills-manager 管,装进「已停用来源」里的技能文件明明存在但宿主永远扫不到
  (我第一次就装进了 ~/.dsh/skills,同目录的 wavedrom-gen 正是同一现象的旁证)。脚本现在读
  ~/.dsh/dsh-skills-manager.log 里该目录最后一条 source-enable/-disable,停用时拒绝安装并回显证据行
  (--force 可绕),默认目标改为已启用的 ~/.agents/skills
- tasks.py 顺手修掉吞退出码的老问题:os.system 的返回值以前直接丢,门禁失败调用方还看到 0。
  实测漂移 exit 1 / 同步 exit 0 / 未知任务 exit 2;顺便支持下划线别名
- 精简执行环境里 Path.home() 会抛 RuntimeError:脚本改用 USERPROFILE/HOME 回退并给人话提示

已知边界:同名技能项目级优先(skill() 的 resourceBase.path 实测指向仓库副本),因此本会话看到的
是仓库那份;跨项目可用性靠「已启用来源 + 内容一致」证明,另开一个目录的会话可最终确认。
验证:ruff / format / mypy / deptry / pytest 148 passed / mcp_smoke 25 工具全绿。
仍用 --no-verify 提交并手跑等价检查。
This commit is contained in:
wandering
2026-10-20 22:21:00 +08:00
parent 6e00ddc37e
commit 3392ab2152
9 changed files with 375 additions and 71 deletions
@@ -612,3 +612,37 @@ src/infra/browser/README.md、src/mcp/tools/browser.py 的模块说明与 `brows
顺带明确一句写进 SKILL:"提交错了要写情况说明,所以宁可停在填完,也不要替用户按下任何不可逆的按钮。"
验证:`pytest 148 passed`、ruff / format / mypy / deptry 全绿,`mcp_smoke` 25 工具,INSTRUCTIONS 2199 字节。
## 18. 技能做成可独立使用的(2026-10-20)
要求:`reimbursement` 技能脱离本仓库也能用。改动三块:
**一、SKILL.md 重写自足化**(104 行):
- 删掉两处只在仓库里成立的引用(`docs/MCP.md`、方案文档);`references/` 三份随技能一起装
- 新增「第 0 步:确认工具可用」:先调 `mcp__arb__case_list` 探活;工具不在就把 stdio 注册片段
(`uv run python -m src.mcp.server` + `cwd`)交给用户,并**禁止绕道自己写脚本处理发票**
- 写死几条跨项目事实:材料用绝对路径正斜杠、可以来自任何目录;产物在**服务器仓库**的 `cases/<id>/`,
路径从 `case_status` 的 `case_dir` 读,不要按当前工作目录去猜;不要把截图/info 拷进用户当前工程
- 字段权威指向工具(`extraction_spec` / `info_skeleton` / `rules_get`),三份 references 明确标注为
「判读经验,不是 schema」;它们开头的迁移说明原本指向已删除的 `src/infra/llm/prompts/*`,
改成历史沿革,避免悬空路径
- 补上这轮学到的:失败信封的额外字段在 `detail` 里;`match` 用单据编号最稳;每步可单独重填;
敏感值打码引用;截图是核对证据不是给用户的报告
**二、`scripts/install_skill.py`(新增,Makefile `skill-install` / `skill-check`)**:单向同步 + `--check`
漂移检测(退出码 1)+ front matter 校验(缺 name/description 直接拒绝,退出码 2)。
**三、来源启停核实(踩坑后加的)**:我第一次把技能装进 `~/.dsh/skills`,文件都在但宿主扫不到——
因为技能来源由 skills-manager 管,那个来源 10-19 就被停用了(同目录的 `wavedrom-gen` 也确实不在
清单里,是同一现象的旁证)。真正启用的用户级目录是 `~/.agents/skills`(`figma`/`hyperframes-*` 都在
那儿且在清单里)。脚本现在会读 `~/.dsh/dsh-skills-manager.log` 找该目录最后一条 `source-enable/-disable`,
停用状态直接拒绝安装并回显证据行(`--force` 可绕过),默认目标也改成 `~/.agents/skills`。
同名技能**项目级优先**:`skill()` 返回的 `resourceBase.path` 实测指向仓库副本——这也是验证加载来源的办法。
另外顺手修的执行环境坑:精简环境下 `Path.home()` 会抛 `RuntimeError`,脚本改用 `USERPROFILE`/`HOME`
回退并给出人话提示(`DSH_SKILLS_DIR` 或 `--dest`)。
验证:安装后 `--check` 报「4 个文件一致」;故意指向停用目录被退出码 3 拦住;ruff 全绿;
`skill(reimbursement)` 读回的是新版正文(含「确认工具可用」,已无 `docs/MCP.md` 引用)。
尚未验证的一项:在**另一个项目目录**里开新会话看清单是否出现本技能——需要在别处起会话,交给你顺手验。