@heihei0299/matt-skills 1.3.2 → 1.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (29) hide show
  1. package/.agents/skills/ci-guard/SKILL.md +104 -0
  2. package/.agents/skills/ci-guard/agents/openai.yaml +5 -0
  3. package/.agents/skills/instance-test/SKILL.md +36 -27
  4. package/.agents/skills/instance-test/agents/openai.yaml +1 -1
  5. package/.agents/skills/instance-test/references/instances.md +63 -36
  6. package/.agents/skills/scaffold-functional-test/SKILL.md +77 -0
  7. package/.agents/skills/scaffold-functional-test/agents/openai.yaml +5 -0
  8. package/README.md +8 -8
  9. package/bin/cli.js +1 -1
  10. package/config/proprietary.json +8 -1
  11. package/package.json +1 -1
  12. package/scripts/sync-upstream.js +1 -1
  13. package/template/.opencode/CONTEXT.md +2 -2
  14. package/template/.opencode/skills/ci-guard/SKILL.md +104 -0
  15. package/template/.opencode/skills/ci-guard/agents/openai.yaml +5 -0
  16. package/template/.opencode/skills/scaffold-functional-test/SKILL.md +77 -0
  17. package/template/.opencode/skills/scaffold-functional-test/agents/openai.yaml +5 -0
  18. package/template/.pi/CONTEXT.md +2 -2
  19. package/template/.pi/skills/ci-guard/SKILL.md +104 -0
  20. package/template/.pi/skills/ci-guard/agents/openai.yaml +5 -0
  21. package/template/.pi/skills/scaffold-functional-test/SKILL.md +77 -0
  22. package/template/.pi/skills/scaffold-functional-test/agents/openai.yaml +5 -0
  23. package/template/AGENTS.md +1 -2
  24. package/template/.opencode/skills/instance-test/SKILL.md +0 -61
  25. package/template/.opencode/skills/instance-test/agents/openai.yaml +0 -5
  26. package/template/.opencode/skills/instance-test/references/instances.md +0 -48
  27. package/template/.pi/skills/instance-test/SKILL.md +0 -61
  28. package/template/.pi/skills/instance-test/agents/openai.yaml +0 -5
  29. package/template/.pi/skills/instance-test/references/instances.md +0 -48
@@ -0,0 +1,104 @@
1
+ ---
2
+ name: ci-guard
3
+ description: "Guard the GitHub Actions release pipeline: orchestrate workflow flow, enforce pre-release verification, and self-correct after publish. Use when CI is flaky/failing, when setting up or editing .github/workflows/ci.yml, or before tagging a release to npm."
4
+ ---
5
+
6
+ # CI Guard
7
+
8
+ **guard** 为领衔词的发布门禁技能:以一次**可复现的失败**为起点,把 `verify → build → publish` 编排成不可绕过的门,把**预发布校验**做成硬门槛,把**发布后自纠**做成闭环。本技能沉淀自 `heihei0299/pi-switch` 23 次运行中 14 次失败的复盘(见 `.scratch/research/ci-actions-调研.md`)——不替代 `diagnose-fix` 的通用诊断,只收敛 CI/发布这一条链。
9
+
10
+ ## 何时用
11
+
12
+ - Actions 持续红 / 偶发红(尤其是 `verify` 单点红而 `publish` 仍绿)
13
+ - 新建或改动 `.github/workflows/ci.yml`、调整 `cargo test` / `clippy` / `rustfmt` 参数
14
+ - 打 tag 前、发 npm 前、或发布后需要自检/回滚
15
+
16
+ ## 三段式门禁
17
+
18
+ ```
19
+ ① 编排 flows → ② 预发布 gate → ③ 发布后自纠
20
+ ```
21
+
22
+ 每段有**完成条件**(可验证),未满足不进入下一段。
23
+
24
+ ---
25
+
26
+ ### ① 编排 flows —— 让工作流不可被绕过
27
+
28
+ **做**:
29
+ - `on`:`push.tags: ["v*"]` **必须**同时配 `push.branches: [main]`(或 `master`)+ `pull_request.branches: [main]` + `workflow_dispatch`。否则直推 `main` 的修复(如 `2d68f62`)无法被 CI 验证,tag 才暴露问题
30
+ - `jobs` 依赖:`publish.needs: [build, verify]`,**禁止** `needs: build` 单依赖。门禁失效的直接原因就是 `verify` 红仍发包
31
+ - `permissions` 最小化:`verify`/`build` 只需 `contents: read`,仅 `publish` 保留 `contents: write` + `packages: write`(或 `id-token: write` 若用 OIDC)
32
+ - `concurrency`:`group: ci-${{ github.ref }}` + `cancel-in-progress: true`,避免同分支并行互踩
33
+ - `cache`:`rust-cache` 或 `actions/cache` 缓存 `~/.cargo` + `target`,`actions/setup-node` 加 `cache: npm`,避免每次 `npm install` 重装
34
+ - `find changed Rust files`:`git diff origin/main...HEAD` 在 tag 事件下为空,改为 `git diff --name-only HEAD~1...HEAD` 或直接全量 `cargo fmt --check` / `clippy`,避免误跳过
35
+
36
+ **完成条件**:
37
+ - [ ] `git diff HEAD -- .github/workflows/ci.yml` 显示 `on.push.branches` 存在
38
+ - [ ] `publish.needs` 包含 `verify`
39
+ - [ ] `workflow_dispatch` 可手动触发全量
40
+
41
+ ---
42
+
43
+ ### ② 预发布 gate —— 在写盘之前变红
44
+
45
+ 本段是**硬门槛**,顺序固定:`fmt → clippy → test → build`,任一步红即阻断 `publish`。
46
+
47
+ **fmt / clippy**:
48
+ - `rustfmt --check` 与 `cargo clippy --all-targets -- -D warnings` 必须与本地一致(`rust-toolchain.toml` 锁定 `stable` 版本)
49
+ - 允许的 `-A` 必须显式列出(如本仓 `-A clippy::manual_checked_ops` 等 4 项),不批量 `-A clippy::all`
50
+
51
+ **test(关键)**:
52
+ - 落盘测试(如 `web::tests` 直写 `config.json` / `models.json`)**必须**测试隔离:`config_dir()` / `pi_dir()` / `models_path()` 在 `#[cfg(test)]` 下重定向到 `temp/pi-switch-test-<pid>`(参考 `src-rust/proxy.rs:115 init_test_state_dir()`,`config.rs:460` 为未隔离反例;曾用 `PI_SWITCH_CONFIG_DIR` 环境覆盖后被 `20f6f86` 误删,即回归)
53
+ - 若暂未隔离,CI 侧以 `cargo test --release --lib -- --test-threads=1` 串行化为**过渡**(`2d68f62` 方案,322/322 稳定),并在代码侧记录 `TODO(ci-guard): 恢复 config_dir 测试隔离后去掉 --test-threads=1`
54
+ - `verify` 必须跑 `cargo test --lib`(或 `--release --lib` 与发布一致),不跳过;`build` 矩阵 5 目标仅验编译,不代验测试
55
+
56
+ **完成条件**:
57
+ - [ ] 本地 `cargo test --lib -- --test-threads=1` 322/322 且 `cargo test --lib`(并行)亦 322/322 或已记录隔离 TODO
58
+ - [ ] `cargo clippy --all-targets` 0 warning
59
+ - [ ] `npm run build:webui` 在 `verify` 与 `build` 均执行(本仓 WebUI 缺失会导致 `publish` 产物不一致)
60
+
61
+ ---
62
+
63
+ ### ③ 发布后自纠 —— 发出去的包自己负责
64
+
65
+ **发布时**:
66
+ - `npm publish --access public` 仅在 `if: startsWith(github.ref, 'refs/tags/v')` 且 `needs` 全绿时执行
67
+ - 发布前 `actions/download-artifact` 校验 `if-no-files-found: error`,发布后 `npm view <pkg>@<version> version` 回读确认
68
+
69
+ **自纠**:
70
+ - 失败即 **阻断**:`verify` 红 → `publish` 不执行(由 `needs` 保证);`publish` 自身失败(`409 already exists` / `401`)→ 工作流整体 `failure`,不静默
71
+ - 发布后 30s 内 `curl https://registry.npmjs.org/<pkg>/<version>` 校验可用;失败则 `gh issue create --title "chore(release): vX.Y.Z 发布后自检失败" --body "run: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"` 并 `gh release delete vX.Y.Z --yes`(或 `npm unpublish <pkg>@<version>` 在 72h 内)
72
+ - `workflow_dispatch` 支持 `inputs.rollback_version` 手动回滚
73
+
74
+ **完成条件**:
75
+ - [ ] `npm view` 回读与 tag 一致
76
+ - [ ] 失败路径有 issue/通知(非静默)
77
+ - [ ] `git tag` 与 `package.json version` 一致(`scripts/release.sh` 或 `npm version` 保证)
78
+
79
+ ---
80
+
81
+ ## 反模式
82
+
83
+ - **单依赖 publish**:`needs: build` 是本仓 7 次带病发布的根因
84
+ - **仅 tag 触发**:`push.branches` 缺失导致主干修复无 CI
85
+ - **真实落盘并行测试**:无 `#[cfg(test)]` 隔离的 `config_dir` 直写是偶发红的根因,`--test-threads=1` 只是止血
86
+ - **静默发布**:`publish` 失败不建 issue / 不删 tag,下次 `409` 叠加
87
+ - **`-A clippy::all`**:掩盖真实告警
88
+
89
+ ## 引用
90
+
91
+ - 调研:`.scratch/research/ci-actions-调研.md`(23 次运行全量、`proxy.rs:115` vs `config.rs:460` 对比)
92
+ - 修复:`2d68f62 fix(ci): gate publish on verify and serialize Rust tests`
93
+ - 关联技能:`diagnose-fix`(通用诊断)、`commit-check`(提交前门禁)、`tdd`(测试隔离后的回归)
94
+
95
+ ## 执行清单(粘贴即用)
96
+
97
+ ```markdown
98
+ - [ ] .github/workflows/ci.yml: on.push.branches: [main] 已加
99
+ - [ ] publish.needs: [build, verify]
100
+ - [ ] verify: cargo test --release --lib -- --test-threads=1(或已隔离则去掉该 flag)
101
+ - [ ] config.rs: #[cfg(test)] config_dir/pi_dir → temp(或 TODO 已记录)
102
+ - [ ] workflow_dispatch 可手动触发
103
+ - [ ] npm view 回读 + 失败建 issue
104
+ ```
@@ -0,0 +1,5 @@
1
+ interface:
2
+ display_name: "CI Guard"
3
+ short_description: "Guard release pipeline: orchestrate flows, enforce verify gate, self-correct after publish"
4
+ policy:
5
+ allow_implicit_invocation: false
@@ -1,61 +1,70 @@
1
1
  ---
2
2
  name: instance-test
3
3
  disable-model-invocation: true
4
- description: "Verify project meets expected goals by running prompt instances in isolated temp dirs"
4
+ description: "matt-skills 专属功能测试示范(由 scaffold-functional-test spec 生成)— 验证 sync 合并 update 后的行为;仅显式调用"
5
5
  ---
6
6
 
7
- # Instance Test
7
+ # Instance Test — matt-skills 专属示范
8
8
 
9
- Run **instance** prompts to verify project meets expected goals via actual functional tests. Each **instance** is a prompt + expected outcome, executed in an isolated temp dir — no mocks, no stubs.
9
+ skill **matt-skills 专属**的功能测试示范,由 `scaffold-functional-test` `.scratch/sync-merge-update/spec.md` 生成(见 `references/instances.md` 头部 `spec hash` + `generatedAt`)。它是生成器产出形态的示例,不随 Template Snapshot 分发,仅保留于 Workspace。旧通用执行器文案已废弃。
10
+
11
+ 兼容别名:`instance-test` 保留原名以兼容历史调用,实际为 `matt-functional-test` 的示范实现。
10
12
 
11
13
  ## Steps
12
14
 
13
15
  ### 1. Gather instances
14
16
 
15
- Collect the **instance** set to run:
17
+ 实例集已由生成器按**受控扩展模型**落盘于 `references/instances.md`(头部含 `spec hash` + `generatedAt`,每实例含**溯源** `spec.md` 章节/行号,`<!-- manual -->` 段受保护)。
16
18
 
17
- - User-provided instances (prompt, command, expected files/stdout/exit code), or
18
- - Derived from `spec.md`/`README` acceptance criteria — extract each verifiable behavior as one instance, then confirm the list with the user before running.
19
+ 执行前校验指纹:若当前 spec `spec hash` `references/instances.md` 头部不一致,提示「spec 已变更,建议重跑 scaffold-functional-test」但不自动覆盖,需用户显式确认才 regenerate(AI 先给 diff 建议)。
19
20
 
20
- Each **instance** must declare: command to run, expected files/content, expected stdout phrases, expected exit code.
21
+ 每实例声明:`prompt/command/expected files/content/expected stdout phrases/expected exit code` 必选,`setup/env/timeout/type/teardown` 可选,默认 `type: cli`。
21
22
 
22
- Completion: instance list is fixed (prompt, expected outcome, verification command) — no instance is added mid-run.
23
+ 完成:实例清单已固定(含溯源与指纹),`<!-- manual -->` 段未被覆盖。
23
24
 
24
25
  ### 2. Run instances
25
26
 
26
27
  For each **instance** in order:
27
28
 
28
- 1. `mktemp -d` isolated dir (or `git worktree` / `--dest` if the project supports it).
29
- 2. Execute the instance's command capture stdout/stderr and exit code.
30
- 3. Snapshot result files and side effects declared in expected.
29
+ 1. `mktemp -d` 隔离目录(或项目支持的 `git worktree` / `--dest`),单线程串行,不并行。
30
+ 2. 执行实例的 `command` 与可选 `setup`,捕获 stdout/stderr exit code
31
+ 3. 快照 `expected` 声明的文件与副作用。
31
32
 
32
- Do not run instances in parallel — one **instance** at a time, so failures are isolated and artifacts do not collide.
33
+ 一个 **instance** 一次,失败不阻断后续,产物不碰撞。
33
34
 
34
- Completion: every **instance** has a run dir with captured output and file snapshot.
35
+ 完成:每实例均有独立 run dir 与捕获输出。
35
36
 
36
37
  ### 3. Evaluate
37
38
 
38
- Compare each **instance**'s actual vs expected:
39
+ 对比每实例的 actual vs expected
39
40
 
40
- - File existence/content (`test -f`, `grep -q`, `diff`).
41
- - Stdout/stderr contains expected phrases.
42
- - Exit code matches expected.
41
+ - 文件存在性/内容(`test -f`/`grep -q`/`diff`)
42
+ - Stdout/stderr 含预期短语
43
+ - Exit code 一致
44
+ - 扩展字段(`env`/`timeout`/`type`)行为符合声明
43
45
 
44
- Mark `PASS`/`FAIL` per **instance** with evidence (file path, stdout line, or diff).
46
+ 标记 `PASS`/`FAIL`,附 `expected vs actual` diff run dir 证据。
45
47
 
46
- Completion: every **instance** has a `PASS` or `FAIL` with evidence — no unevaluated instance.
48
+ 完成:每实例均有 `PASS` `FAIL` 且含证据。
47
49
 
48
50
  ### 4. Report
49
51
 
50
- Summarize in conversation:
52
+ 对话内汇总:
53
+
54
+ - `PASS m/n` + per-instance evidence
55
+ - 失败项列出 gap(expected vs actual)与 run dir 复现路径
56
+ - 成功默认清理临时目录、失败默认保留;`--keep` 保留全部;`--report` 显式开启才落盘报告文件
57
+
58
+ 不以文件刷屏——默认输出在对话,报告文件仅显式开启才写。
51
59
 
52
- - `PASS m/n` with per-instance evidence.
53
- - Failures list the gap (expected vs actual) and the run dir for reproduction.
54
- - Clean up temp dirs unless `--keep` is requested.
60
+ ## 实例来源
55
61
 
56
- Do not write a report file (`report-*.md`) — output stays in conversation. Keep temp dirs only on failure for debugging.
62
+ - spec:`.scratch/sync-merge-update/spec.md`(`spec hash` `references/instances.md` 头部)
63
+ - 推导策略:混合推导(验收标准锚点 + 需求/接口/边界补充),每实例含溯源,无溯源视为幻觉
64
+ - 手工段:`<!-- manual -->` 保护
57
65
 
58
- ## References
66
+ ## 引用
59
67
 
60
- - Instance definitions (if any): `references/instances.md` — example set, auto-loaded only when present, not required.
61
- - Project expected behavior: `spec.md`/`README`/`--help` — the source of truth for what to verify.
68
+ - 生成器:`scaffold-functional-test`(读 spec 产出本 skill)
69
+ - 领域术语:`CONTEXT.md`
70
+ - 技能设计:`docs/agents/skill-design.md`
@@ -1,5 +1,5 @@
1
1
  interface:
2
2
  display_name: "Instance Test"
3
- short_description: "Verify project via prompt instances in isolated temp projects"
3
+ short_description: "matt-skills 专属功能测试示范 验证 sync 合并 update 后行为"
4
4
  policy:
5
5
  allow_implicit_invocation: false
@@ -1,48 +1,75 @@
1
- # Instances template
1
+ # Instances for matt-skills — sync 行为功能测试(由 scaffold-functional-test 生成)
2
2
 
3
- Generic template for **instance** functional tests. Each **instance** is a prompt + command + expected outcome. Copy and adapt for your project; the example below is for `matt-skills`.
3
+ > spec:`.scratch/sync-merge-update/spec.md`
4
+ > spec hash: `062a76fc872d` # .scratch/sync-merge-update/spec.md 的 sha256 前 12 位
5
+ > generatedAt: 2026-05-11
6
+ > 推导策略:混合推导(验收标准锚点 + 需求/行为补充),每实例含溯源,无溯源视为幻觉
4
7
 
5
- ## Format
8
+ 本文件由 `scaffold-functional-test` 按**受控扩展模型**生成:必选 `prompt/command/expected files/content/expected stdout phrases/expected exit code`,可选 `setup/env/timeout/type/teardown`,默认 `type: cli`。执行语义:`mktemp -d` 隔离、单线程串行、`PASS m/n` 汇总、证据含 `expected vs actual` diff + `run dir`。
6
9
 
7
- Each instance declares:
10
+ 执行前校验:对比当前 `.scratch/sync-merge-update/spec.md` 的 hash 与本文件头部 `spec hash`,不一致时提示「spec 已变更,建议重跑 scaffold-functional-test」但不自动覆盖。
8
11
 
9
- - Prompt: human intent (what to verify)
10
- - Command: shell command to run in isolated dir
11
- - Expected: files/content, stdout phrases, exit code
12
+ ---
12
13
 
13
- Verification commands are in `SKILL.md` steps.
14
+ ## 1. sync 默认 check(无参不写盘)
14
15
 
15
- ## Example: matt-skills functional behavior
16
+ - Prompt: 验证 `matt-skills sync` 无参等价 check,打印表且不改 AGENTS.md
17
+ - 溯源: spec.md — 需求/行为「`matt-skills sync` 无参:等价 `check`」+ 验收标准「`sync` 无参在已定制的 `pi-switch` 仓库上不改 `AGENTS.md`」
18
+ - type: cli
19
+ - setup: `node bin/cli.js init --dest <tmp>` 后手工改 `AGENTS.md` 加入 `tdd-implement` 定制行
20
+ - Command: `node bin/cli.js sync --dest <tmp>`(无参)
21
+ - Expected:
22
+ - `git diff HEAD -- AGENTS.md` 为空(`AGENTS.md` 未被覆盖)
23
+ - stdout 含 `上游 HEAD` 与 `新增/更新/删除/一致` 表头
24
+ - stdout 含 `--json` 可解析提示或表格行
25
+ - exit 0 或 1(有差异时 exit 1,判 exit code 符合 check 语义)
26
+ - Expected files/content: `AGENTS.md` 保留定制行,无 `AGENTS.md.bak` 新增
27
+ - Expected stdout phrases: `上游 HEAD`, `一致`
28
+ - Expected exit code: 1(有差异时)/ 0(无差异时)— 按实现定义,测试以实际 check 语义为准
16
29
 
17
- ### 1. Fresh init
18
- Prompt: verify fresh project initialization
19
- Command: `node bin/cli.js init --dest <tmp>`
20
- Expected: `AGENTS.md`, `.opencode/skills/tdd-implement/SKILL.md`, `.pi/skills/tdd-implement/SKILL.md`, `.agents/skills/tdd` (22 upstream) exist; stdout `模板:已复制` + `上游技能:已装 22`; no `.bak`; exit 0.
30
+ ## 2. sync --apply 安全增量(AGENTS.md 跳过、上游强制覆盖不删)
21
31
 
22
- ### 2. Init skip on existing
23
- Prompt: verify idempotent init without --force
24
- Command: `init` twice without `--force`, second with local edit to `AGENTS.md`
25
- Expected: second stdout `模板已存在.*跳过`, `上游技能:已装 0、跳过 22`; local edit preserved; exit 0.
32
+ - Prompt: 验证 `sync --apply` 为安全增量,`AGENTS.md` 定制跳过、上游技能被覆盖但 remove 列表不删
33
+ - 溯源: spec.md 需求/行为「`sync --apply`:安全增量写盘。`AGENTS.md` 若含独有路由则跳过;上游技能 `rm+cp force` 覆盖,跳过 `PROPRIETARY`,不执行 `remove`」+ 验收标准「`sync --apply` 后上游技能被强制更新为上游 `HEAD`,`remove` 列表的技能仍保留」
34
+ - type: cli
35
+ - setup: `<tmp>` 放置旧版上游技能 `test-skill` 过期文件,并手工改 `AGENTS.md`
36
+ - Command: `node bin/cli.js sync --apply --dest <tmp>`
37
+ - Expected:
38
+ - `AGENTS.md` 仍含定制行(未被模板覆盖)
39
+ - 上游技能文件已更新为上游 HEAD 内容(`diff` 无旧版残留)
40
+ - `remove` 列表中的技能目录仍存在(未被删除)
41
+ - Expected files/content: `AGENTS.md` 定制行存在;`test-skill` 被覆盖为新版;无 `AGENTS.md.bak`(安全档不备份)或按实现保留但不覆盖
42
+ - Expected stdout phrases: `已同步` 或 `已更新` 或 `同步`
43
+ - Expected exit code: 0
44
+ - timeout: 30000
26
45
 
27
- ### 3. Init --force with direct overwrite
28
- Prompt: verify forced init directly overwrites
29
- Command: `init --force --dest <tmp>` after local edit
30
- Expected: stdout `已覆盖` + `已装 22`; `AGENTS.md.bak` exists with local edit; `AGENTS.md` restored from template; no `.agents/skills/*.bak`; no `.opencode.bak`/`.pi.bak`; exit 0.
46
+ ## 3. sync --force 硬盖(AGENTS.md 备份后覆盖、全量 add/update/remove)
31
47
 
32
- ### 4. Sync on existing
33
- Prompt: verify sync directly updates existing project
34
- Command: `sync --dest <tmp>` after local edit
35
- Expected: stdout `同步` + `已同步`/`已更新`; `AGENTS.md.bak` exists; `.agents/skills/tdd` updated; exit 0.
36
- Prompt: verify sync backs up existing project
37
- Command: `sync --dest <tmp>` after local edit
38
- Expected: stdout `同步` + `已备份`; `AGENTS.md.bak` exists; exit 0.
48
+ - Prompt: 验证 `sync --force` 硬盖,`AGENTS.md` 备份后被模板覆盖、技能与模板全量同步含删除
49
+ - 溯源: spec.md — 需求/行为「`sync --force`:硬盖。`AGENTS.md` `backupIfExists → .bak` 再 `cp -r force`;技能与模板均 `add/update/remove` 全做」+ 验收标准「`sync --force` 后 `AGENTS.md` 变为模板且 `AGENTS.md.bak` 存在,`remove` 列表的技能被删除」
50
+ - type: cli
51
+ - setup: `<tmp>` 放置 `AGENTS.md` 定制行 + 一个上游已删的本地技能 `obsolete-skill/`
52
+ - Command: `node bin/cli.js sync --force --dest <tmp>`
53
+ - Expected:
54
+ - `AGENTS.md` 已被模板覆盖(定制行消失,与 `template/AGENTS.md` 一致)
55
+ - `AGENTS.md.bak` 存在且含定制行备份
56
+ - `obsolete-skill/` 已被删除
57
+ - Expected files/content: `AGENTS.md` 内容等于 `template/AGENTS.md`;`AGENTS.md.bak` 存在
58
+ - Expected stdout phrases: `已覆盖` 或 `硬盖`
59
+ - Expected exit code: 0
39
60
 
40
- ### 5. Sync --force without backup
41
- Prompt: verify sync --force does not backup
42
- Command: `sync --force --dest <tmp>`
43
- Expected: stdout `已覆盖` without new `.bak`; exit 0.
61
+ ## 4. update 已合并到 sync --apply(删除分支、提示已合并)
44
62
 
45
- ### 6. List
46
- Prompt: verify skill listing
47
- Command: `list` and `list --json`
48
- Expected: 27 skills, includes `tdd` with correct description; `--json` is valid JSON array; exit 0.
63
+ - Prompt: 验证 `matt-skills update` 已删除,执行后报错提示已合并到 `sync --apply`,且 `--help` 不再列 `update`
64
+ - 溯源: spec.md — 需求/行为「`matt-skills update`:删除该分支,`main` 中 `command === 'update'` 改为 `stderr: 'update 已合并到 sync --apply'` 且 `exit 1`,`--help` 不再列 `update`」+ 验收标准「`matt-skills update` 执行后报错提示已合并,`--help` 无 `update`」
65
+ - type: cli
66
+ - Command: `node bin/cli.js update 2>&1; echo "exit:$?"` `node bin/cli.js --help`
67
+ - Expected:
68
+ - `update` 命令 stdout/stderr 含 `已合并到 sync --apply` 且 exit 1
69
+ - `--help` 输出不含独立的 `update` 子命令行(不匹配 `^\s*update`)
70
+ - Expected stdout phrases: `已合并到 sync --apply`
71
+ - Expected exit code: 1(`update` 分支)
72
+ - env: {}
73
+
74
+ <!-- manual -->
75
+ <!-- 以下为人工定制实例保护段:由开发者手写,scaffold-functional-test 重生成时不覆盖此段以上的内容。如需新增手工实例,请在此段后追加。 -->
@@ -0,0 +1,77 @@
1
+ ---
2
+ name: scaffold-functional-test
3
+ disable-model-invocation: false
4
+ description: "Scaffold a repo-specific functional-test skill from spec — use when the user wants to generate a customized functional-test suite/skill from a spec/README/help; not for running tests (use instance-test) nor for TDD (use tdd-implement)"
5
+ ---
6
+
7
+ # Scaffold Functional Test
8
+
9
+ 从本仓库的 spec 自动脚手架出**仓库专属的功能测试 skill**。本技能为**非 Long-Horizon 轻量 skill**(一次性 scaffold,不做多 seam 红绿循环),一次性完成「读 spec → 推导实例 → 落盘 skill → 自验证」闭环。术语定义见 `CONTEXT.md`。
10
+
11
+ ## 产出物
12
+
13
+ - 定制 skill 目录:`.agents/skills/<repo>-functional-test/`(含 `SKILL.md` + `references/instances.md` + 可选 `scripts/run.sh`)
14
+ - 指纹:`spec hash` + `generatedAt` 写入生成物头部,用于后续执行前校验
15
+ - 保护:`<!-- manual -->` 标记段不被覆盖
16
+
17
+ 生成物纳入 git,可回归复用,不进入 `template/` 再分发(生成器本身才随 Template Snapshot 分发)。
18
+
19
+ ## Steps
20
+
21
+ ### ① 采集 Spec
22
+
23
+ 解析用户传入的 spec 路径,默认 `.scratch/<feature>/spec.md`。
24
+
25
+ - 若 spec 存在:读取 `CONTEXT.md`/`docs/adr/` 相关术语与决策,提取待覆盖行为清单(以验收标准为锚点)。
26
+ - 若 spec 不存在:回退到 `README` + `--help` 输出倒推行为清单,但必须进入 Step ② 的清单确认关卡,不静默臆测。
27
+
28
+ 完成:待覆盖行为清单已固定,无未澄清歧义。
29
+
30
+ ### ② 推导实例
31
+
32
+ 按混合推导策略生成实例草案:
33
+
34
+ - 以验收标准为锚点,需求/接口/边界为补充,可为 spec 未显式写的隐含行为(如 `--help` 文案、错误码、幂等性)补实例,但每条实例必须标注**溯源**(spec 章节/行号或 `README/--help` 来源),无溯源的实例视为幻觉需删除。
35
+ - 每实例声明**受控扩展模型**:必选 `prompt/command/expected files/content/expected stdout phrases/expected exit code`,可选 `setup/env/timeout/type/teardown`,默认 `type: cli`。
36
+ - **强制门禁**:实例清单必须与用户确认后才进入 Step ③;无确认不落盘。
37
+
38
+ 完成:实例清单已获用户确认,每实例含溯源与完整四元组。
39
+
40
+ ### ③ 脚手架落盘
41
+
42
+ 按受控扩展模型写入定制 skill 目录:
43
+
44
+ - `SKILL.md`:执行语义(见下节「执行语义」)
45
+ - `references/instances.md`:实例集(含溯源、必选+可选字段、头部 `spec hash` + `generatedAt`)
46
+ - 不覆盖 `<!-- manual -->` 保护段;覆盖式更新需经用户确认;重生成时先给出 diff 建议,用户确认后才应用。
47
+
48
+ 完成:定制 skill 目录已落盘,指纹正确,人工段受保护。
49
+
50
+ ### ④ 自验证
51
+
52
+ 落盘后立即按实例执行语义串行执行一轮实例集作自验证:
53
+
54
+ - `mktemp -d` 隔离(或项目支持的 `git worktree` / `--dest`),单线程串行,不并行。
55
+ - 每实例捕获 stdout/stderr 与 exit code,按 `test -f`/`grep -q`/`diff` 对比判定 `PASS`/`FAIL`,单 FAIL 不阻断后续。
56
+ - 对话内输出 `PASS m/n` + per-instance evidence(`expected vs actual diff` + `run dir`),失败不回滚生成物但给出 gap 供迭代 `regenerate`。
57
+ - 成功默认清理临时目录、失败默认保留(`--keep` 保留全部);`--report` 显式开启才落盘报告文件。
58
+
59
+ 完成:自验证已执行,对话内汇总完成,证据可复现。
60
+
61
+ ## 执行语义(生成物复用)
62
+
63
+ 生成物本身的执行语义与 `instance-test` 一致:`mktemp -d` 串行、`PASS m/n` 汇总、证据含 `expected vs actual diff` + `run dir`。执行前校验 `spec hash` 指纹:若当前 spec 已变更,提示「spec 已变更,建议重跑 scaffold-functional-test」但不自动覆盖,需用户显式确认才 regenerate。
64
+
65
+ ## 不做什么
66
+
67
+ - 不替代 `tdd`/`tdd-implement` 的红绿循环与 `commit-check` 门禁
68
+ - 不自动织入每次 `tdd-implement` 或 `commit-check`;仅 `tdd-implement --with-functional` 显式 opt-in
69
+ - 不支持并行执行与 `docker` 隔离
70
+ - 不处理超出混合推导锚点范围的源码静态分析隐式行为挖掘
71
+
72
+ ## 引用
73
+
74
+ - 领域术语:`CONTEXT.md`
75
+ - 技能设计规则:`docs/agents/skill-design.md`
76
+ - 示范产物:`.agents/skills/instance-test/`(本仓库专属,见其 SKILL.md)
77
+ - Issue tracker:`docs/agents/issue-tracker.md`
@@ -0,0 +1,5 @@
1
+ interface:
2
+ display_name: "Scaffold Functional Test"
3
+ short_description: "Scaffold a repo-specific functional-test skill from spec — not for running tests nor TDD"
4
+ policy:
5
+ allow_implicit_invocation: true
package/README.md CHANGED
@@ -9,7 +9,7 @@ template/
9
9
  ├── AGENTS.md 项目级全局配置(行为路由 + 分文件指针)
10
10
  ├── .pi/ pi-agent 项目配置(pi 标准结构:`.pi/skills/` 直放独有技能,自动发现)
11
11
  └── .opencode/ 分发内容(目标仓库的 opencode 项目配置)
12
- ├── skills/ 5 个独有技能(tdd-implement、grill-to-spec、diagnose-fix、commit-check、instance-test)
12
+ ├── skills/ 6 个独有技能(ci-guard、tdd-implement、grill-to-spec、diagnose-fix、commit-check、scaffold-functional-test)
13
13
  ├── agents/ issue-audit 子代理定义
14
14
  ├── commands/ issue-audit + 9 个显式触发技能命令(grill-to-spec/wayfinder/to-spec/to-tickets/triage/improve-codebase-architecture/teach/handoff/writing-for-agents)
15
15
  ├── docs/agents/ 5 个分文件(运行时纪律 / 技能设计 / issue tracker / triage labels / domain)
@@ -46,7 +46,7 @@ npx @heihei0299/matt-skills sync --apply --dest <path> --upstream <url> --ref <r
46
46
 
47
47
  上游没有 `tdd-implement`、`grill-to-spec`、`diagnose-fix`、`commit-check`,复制天然不冲突。目标仓库会话即自动加载全部技能(上游在 `.agents/skills/`、独有在 `.opencode/skills/`;pi 侧独有在 `.pi/skills/`)与项目级全局配置(行为路由表、分文件约定);`issue-audit` 以子代理 + 命令形式分发(`.opencode/agents/`、`.opencode/commands/`);9 个显式触发技能注册为 opencode 命令(`.opencode/commands/`,`/命令名` 触发)。
48
48
 
49
- **pi-agent 用户**:初始化命令完全相同。pi 从 `.pi/skills/` 自动发现独有技能(tdd-implement、grill-to-spec、diagnose-fix、commit-check),无需任何指向配置;首次在目标仓库交互启动时 pi 会询问项目信任,用 `/trust` 保存即可。
49
+ **pi-agent 用户**:初始化命令完全相同。pi 从 `.pi/skills/` 自动发现独有技能(ci-guard、tdd-implement、grill-to-spec、diagnose-fix、commit-check、scaffold-functional-test),无需任何指向配置;首次在目标仓库交互启动时 pi 会询问项目信任,用 `/trust` 保存即可。
50
50
 
51
51
  **手动方式(备选)**:无 npx 环境时,将 `template/` 整个文件夹复制到目标仓库根目录,再拉取上游技能:
52
52
 
@@ -60,7 +60,7 @@ rm -rf /tmp/mattpocock-skills
60
60
 
61
61
  上游没有 `tdd-implement`、`grill-to-spec`、`diagnose-fix`、`commit-check`,复制天然不冲突。目标仓库会话即自动加载全部技能(上游在 `.agents/skills/`、独有在 `.opencode/skills/`;pi 侧独有在 `.pi/skills/`)与项目级全局配置(行为路由表、分文件约定);`issue-audit` 以子代理 + 命令形式分发(`.opencode/agents/`、`.opencode/commands/`);9 个显式触发技能注册为 opencode 命令(`.opencode/commands/`,`/命令名` 触发)。
62
62
 
63
- **pi-agent 用户**:初始化命令完全相同。pi 从 `.pi/skills/` 自动发现独有技能(tdd-implement、grill-to-spec、diagnose-fix、commit-check),无需任何指向配置;首次在目标仓库交互启动时 pi 会询问项目信任,用 `/trust` 保存即可。
63
+ **pi-agent 用户**:初始化命令完全相同。pi 从 `.pi/skills/` 自动发现独有技能(ci-guard、tdd-implement、grill-to-spec、diagnose-fix、commit-check、scaffold-functional-test),无需任何指向配置;首次在目标仓库交互启动时 pi 会询问项目信任,用 `/trust` 保存即可。
64
64
 
65
65
  ## 维护约定
66
66
 
@@ -68,8 +68,8 @@ rm -rf /tmp/mattpocock-skills
68
68
 
69
69
  | 工作区 | 模板 |
70
70
  |--------|------|
71
- | `.agents/skills/{tdd-implement,grill-to-spec,diagnose-fix,commit-check}/` | `template/.opencode/skills/{tdd-implement,grill-to-spec,diagnose-fix,commit-check}/` |
72
- | `.agents/skills/{tdd-implement,grill-to-spec,diagnose-fix,commit-check}/` | `template/.pi/skills/{tdd-implement,grill-to-spec,diagnose-fix,commit-check}/` |
71
+ | `.agents/skills/{ci-guard,tdd-implement,grill-to-spec,diagnose-fix,commit-check,scaffold-functional-test}/` | `template/.opencode/skills/{ci-guard,tdd-implement,grill-to-spec,diagnose-fix,commit-check,scaffold-functional-test}/` |
72
+ | `.agents/skills/{ci-guard,tdd-implement,grill-to-spec,diagnose-fix,commit-check,scaffold-functional-test}/` | `template/.pi/skills/{ci-guard,tdd-implement,grill-to-spec,diagnose-fix,commit-check,scaffold-functional-test}/` |
73
73
  | `.opencode/agents/issue-audit.md`、`commands/*.md`(issue-audit + 9 个显式技能命令)、`.gitignore`、`package.json`、`package-lock.json` | `template/.opencode/` 同名 |
74
74
  | `.pi/prompts/issue-audit.md`(pi 命令:opencode 版适配,去 subagent frontmatter) | `template/.pi/prompts/issue-audit.md` |
75
75
  | `AGENTS.md` | `template/AGENTS.md`(引用映射为 `.opencode/` 路径) |
@@ -79,7 +79,7 @@ rm -rf /tmp/mattpocock-skills
79
79
  独有技能需同步**双份**:`.opencode/skills/`(opencode 分发)与 `.pi/skills/`(pi 标准分发)。
80
80
  `test/template-sync.test.js` 守护同步(含路径映射),漏同步测试即红。
81
81
 
82
- 新增技能前先查上游 `mattpocock/skills` 是否已存在;仅上游没有的技能才作为独有技能落在本仓库(当前独有:tdd-implement、grill-to-spec、diagnose-fix、commit-check),上游技能一律不进 `template/`。
82
+ 新增技能前先查上游 `mattpocock/skills` 是否已存在;仅上游没有的技能才作为独有技能落在本仓库(当前独有:ci-guard、tdd-implement、grill-to-spec、diagnose-fix、commit-check、scaffold-functional-test),上游技能一律不进 `template/`。
83
83
 
84
84
  ## harness 支持
85
85
 
@@ -156,7 +156,7 @@ node scripts/sync-upstream.js --apply --dry-run
156
156
  上游重命名映射:`RENAMES = { "writing-great-skills": "writing-for-agents" }`,Actions/CLI 均会删除旧目录并复制新目录。
157
157
  ## 发布
158
158
 
159
- 推送 `v*` 标签自动发布到 npm(GitHub Actions,见 `.github/workflows/publish.yml`):
159
+ 推送 `v*` 标签自动发布到 npm(GitHub Actions,见 `.github/workflows/ci.yml`):
160
160
 
161
161
  ```sh
162
162
  # 1. 确保 main 分支为最新且测试全绿
@@ -189,5 +189,5 @@ npm run build:template # 从单源生成 template/.opencode/.pi(con
189
189
 
190
190
  交互模式依赖 `prompts`(见 `package.json`);测试见 `test/cli.test.js`、`test/cli-init.test.js`、`test/template-sync.test.js`。
191
191
 
192
- 用户手动触发的功能测试:`/instance-test`(见 `.agents/skills/instance-test/SKILL.md`)——在隔离 `temp dir` prompt 实例验实际功能,`references/instances.md` 为通用模板。
192
+ 用户手动触发的功能测试:`/instance-test`(matt-skills 专属示范,见 `.agents/skills/instance-test/SKILL.md`)——验证 sync 合并 update 后的行为,`references/instances.md` 由 `scaffold-functional-test` 从 spec 生成;通用模板已废弃。新增生成器 `/scaffold-functional-test`(见 `.agents/skills/scaffold-functional-test/SKILL.md`)——读 spec 生成定制化功能测试 skill。
193
193
 
package/bin/cli.js CHANGED
@@ -7,7 +7,7 @@ import prompts from 'prompts';
7
7
 
8
8
  const SKILLS_DIR = path.join(path.dirname(fileURLToPath(import.meta.url)), '..', '.agents', 'skills');
9
9
  const TEMPLATE_DIR = path.join(path.dirname(fileURLToPath(import.meta.url)), '..', 'template');
10
- const PROPRIETARY_SKILLS = new Set(['tdd-implement', 'grill-to-spec', 'diagnose-fix', 'commit-check', 'instance-test']);
10
+ const PROPRIETARY_SKILLS = new Set(['ci-guard', 'tdd-implement', 'grill-to-spec', 'diagnose-fix', 'commit-check', 'scaffold-functional-test']);
11
11
  process.stdout.on('error', (err) => {
12
12
  if (err.code === 'EPIPE') process.exit(0);
13
13
  throw err;
@@ -1 +1,8 @@
1
- ["tdd-implement", "grill-to-spec", "diagnose-fix", "commit-check", "instance-test"]
1
+ [
2
+ "ci-guard",
3
+ "tdd-implement",
4
+ "grill-to-spec",
5
+ "diagnose-fix",
6
+ "commit-check",
7
+ "scaffold-functional-test"
8
+ ]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@heihei0299/matt-skills",
3
- "version": "1.3.2",
3
+ "version": "1.3.3",
4
4
  "description": "Agent skills + 项目配置模板:一条命令初始化 opencode / pi-agent 项目(含 mattpocock/skills 上游技能)",
5
5
  "type": "module",
6
6
  "bin": {
@@ -21,7 +21,7 @@ async function loadProprietary() {
21
21
  const raw = await readFile(PROPRIETARY_PATH, 'utf8');
22
22
  return new Set(JSON.parse(raw));
23
23
  } catch {
24
- return new Set(['tdd-implement', 'grill-to-spec', 'diagnose-fix', 'commit-check', 'instance-test']);
24
+ return new Set(['ci-guard', 'tdd-implement', 'grill-to-spec', 'diagnose-fix', 'commit-check', 'scaffold-functional-test']);
25
25
  }
26
26
  }
27
27
 
@@ -13,11 +13,11 @@ mattpocock/skills — the source of the 22 skill bodies (skills/engineering, 17
13
13
  _Avoid_: source repo, skill origin
14
14
 
15
15
  **Proprietary Skill** (独有技能):
16
- A skill that does not exist upstream and lives only in this repo (currently tdd-implement, grill-to-spec, diagnose-fix and commit-check). Before adding a new skill, check the Upstream Repository first; only skills absent there qualify as proprietary. The issue-audit subagent is NOT a skill: it ships as a subagent + command under `.opencode/` and is distributed through the Template Snapshot without a skill directory.
16
+ A skill that does not exist upstream and lives only in this repo (currently ci-guard, tdd-implement, grill-to-spec, diagnose-fix, commit-check and scaffold-functional-test). Before adding a new skill, check the Upstream Repository first; only skills absent there qualify as proprietary. The issue-audit subagent is NOT a skill: it ships as a subagent + command under `.opencode/` and is distributed through the Template Snapshot without a skill directory.
17
17
  _Avoid_: private skill, local skill
18
18
 
19
19
  **Workspace** (工作区):
20
- The root-level working copies of the template content — `.agents/skills/` (proprietary skill sources), `.opencode/` (issue-audit agent, explicit-skill commands, plugin manifests), `.pi/` (pi-agent project config: `.pi/skills/` + `.pi/prompts/` issue-audit command), `AGENTS.md`, `CONTEXT.md`, `docs/`. Where this repo's own sessions load, modify, and test the content. The template paths mirror them with a path mapping: `.agents/skills/{tdd-implement,grill-to-spec,diagnose-fix,commit-check}` → `template/.opencode/skills/` and `template/.pi/skills/` (dual mirror), `.opencode/commands/*.md` → `template/.opencode/commands/`, `.pi/prompts/issue-audit.md` → `template/.pi/prompts/issue-audit.md`, root-level `CONTEXT.md` and `docs/agents/` → `template/.opencode/`.
20
+ The root-level working copies of the template content — `.agents/skills/` (proprietary skill sources), `.opencode/` (issue-audit agent, explicit-skill commands, plugin manifests), `.pi/` (pi-agent project config: `.pi/skills/` + `.pi/prompts/` issue-audit command), `AGENTS.md`, `CONTEXT.md`, `docs/`. Where this repo's own sessions load, modify, and test the content. The template paths mirror them with a path mapping: `.agents/skills/{ci-guard,tdd-implement,grill-to-spec,diagnose-fix,commit-check,scaffold-functional-test}` → `template/.opencode/skills/` and `template/.pi/skills/` (dual mirror), `.opencode/commands/*.md` → `template/.opencode/commands/`, `.pi/prompts/issue-audit.md` → `template/.pi/prompts/issue-audit.md`, root-level `CONTEXT.md` and `docs/agents/` → `template/.opencode/`.
21
21
  _Avoid_: working copy, source repo
22
22
 
23
23
  **Template Snapshot** (模板快照):
@@ -0,0 +1,104 @@
1
+ ---
2
+ name: ci-guard
3
+ description: "Guard the GitHub Actions release pipeline: orchestrate workflow flow, enforce pre-release verification, and self-correct after publish. Use when CI is flaky/failing, when setting up or editing .github/workflows/ci.yml, or before tagging a release to npm."
4
+ ---
5
+
6
+ # CI Guard
7
+
8
+ **guard** 为领衔词的发布门禁技能:以一次**可复现的失败**为起点,把 `verify → build → publish` 编排成不可绕过的门,把**预发布校验**做成硬门槛,把**发布后自纠**做成闭环。本技能沉淀自 `heihei0299/pi-switch` 23 次运行中 14 次失败的复盘(见 `.scratch/research/ci-actions-调研.md`)——不替代 `diagnose-fix` 的通用诊断,只收敛 CI/发布这一条链。
9
+
10
+ ## 何时用
11
+
12
+ - Actions 持续红 / 偶发红(尤其是 `verify` 单点红而 `publish` 仍绿)
13
+ - 新建或改动 `.github/workflows/ci.yml`、调整 `cargo test` / `clippy` / `rustfmt` 参数
14
+ - 打 tag 前、发 npm 前、或发布后需要自检/回滚
15
+
16
+ ## 三段式门禁
17
+
18
+ ```
19
+ ① 编排 flows → ② 预发布 gate → ③ 发布后自纠
20
+ ```
21
+
22
+ 每段有**完成条件**(可验证),未满足不进入下一段。
23
+
24
+ ---
25
+
26
+ ### ① 编排 flows —— 让工作流不可被绕过
27
+
28
+ **做**:
29
+ - `on`:`push.tags: ["v*"]` **必须**同时配 `push.branches: [main]`(或 `master`)+ `pull_request.branches: [main]` + `workflow_dispatch`。否则直推 `main` 的修复(如 `2d68f62`)无法被 CI 验证,tag 才暴露问题
30
+ - `jobs` 依赖:`publish.needs: [build, verify]`,**禁止** `needs: build` 单依赖。门禁失效的直接原因就是 `verify` 红仍发包
31
+ - `permissions` 最小化:`verify`/`build` 只需 `contents: read`,仅 `publish` 保留 `contents: write` + `packages: write`(或 `id-token: write` 若用 OIDC)
32
+ - `concurrency`:`group: ci-${{ github.ref }}` + `cancel-in-progress: true`,避免同分支并行互踩
33
+ - `cache`:`rust-cache` 或 `actions/cache` 缓存 `~/.cargo` + `target`,`actions/setup-node` 加 `cache: npm`,避免每次 `npm install` 重装
34
+ - `find changed Rust files`:`git diff origin/main...HEAD` 在 tag 事件下为空,改为 `git diff --name-only HEAD~1...HEAD` 或直接全量 `cargo fmt --check` / `clippy`,避免误跳过
35
+
36
+ **完成条件**:
37
+ - [ ] `git diff HEAD -- .github/workflows/ci.yml` 显示 `on.push.branches` 存在
38
+ - [ ] `publish.needs` 包含 `verify`
39
+ - [ ] `workflow_dispatch` 可手动触发全量
40
+
41
+ ---
42
+
43
+ ### ② 预发布 gate —— 在写盘之前变红
44
+
45
+ 本段是**硬门槛**,顺序固定:`fmt → clippy → test → build`,任一步红即阻断 `publish`。
46
+
47
+ **fmt / clippy**:
48
+ - `rustfmt --check` 与 `cargo clippy --all-targets -- -D warnings` 必须与本地一致(`rust-toolchain.toml` 锁定 `stable` 版本)
49
+ - 允许的 `-A` 必须显式列出(如本仓 `-A clippy::manual_checked_ops` 等 4 项),不批量 `-A clippy::all`
50
+
51
+ **test(关键)**:
52
+ - 落盘测试(如 `web::tests` 直写 `config.json` / `models.json`)**必须**测试隔离:`config_dir()` / `pi_dir()` / `models_path()` 在 `#[cfg(test)]` 下重定向到 `temp/pi-switch-test-<pid>`(参考 `src-rust/proxy.rs:115 init_test_state_dir()`,`config.rs:460` 为未隔离反例;曾用 `PI_SWITCH_CONFIG_DIR` 环境覆盖后被 `20f6f86` 误删,即回归)
53
+ - 若暂未隔离,CI 侧以 `cargo test --release --lib -- --test-threads=1` 串行化为**过渡**(`2d68f62` 方案,322/322 稳定),并在代码侧记录 `TODO(ci-guard): 恢复 config_dir 测试隔离后去掉 --test-threads=1`
54
+ - `verify` 必须跑 `cargo test --lib`(或 `--release --lib` 与发布一致),不跳过;`build` 矩阵 5 目标仅验编译,不代验测试
55
+
56
+ **完成条件**:
57
+ - [ ] 本地 `cargo test --lib -- --test-threads=1` 322/322 且 `cargo test --lib`(并行)亦 322/322 或已记录隔离 TODO
58
+ - [ ] `cargo clippy --all-targets` 0 warning
59
+ - [ ] `npm run build:webui` 在 `verify` 与 `build` 均执行(本仓 WebUI 缺失会导致 `publish` 产物不一致)
60
+
61
+ ---
62
+
63
+ ### ③ 发布后自纠 —— 发出去的包自己负责
64
+
65
+ **发布时**:
66
+ - `npm publish --access public` 仅在 `if: startsWith(github.ref, 'refs/tags/v')` 且 `needs` 全绿时执行
67
+ - 发布前 `actions/download-artifact` 校验 `if-no-files-found: error`,发布后 `npm view <pkg>@<version> version` 回读确认
68
+
69
+ **自纠**:
70
+ - 失败即 **阻断**:`verify` 红 → `publish` 不执行(由 `needs` 保证);`publish` 自身失败(`409 already exists` / `401`)→ 工作流整体 `failure`,不静默
71
+ - 发布后 30s 内 `curl https://registry.npmjs.org/<pkg>/<version>` 校验可用;失败则 `gh issue create --title "chore(release): vX.Y.Z 发布后自检失败" --body "run: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"` 并 `gh release delete vX.Y.Z --yes`(或 `npm unpublish <pkg>@<version>` 在 72h 内)
72
+ - `workflow_dispatch` 支持 `inputs.rollback_version` 手动回滚
73
+
74
+ **完成条件**:
75
+ - [ ] `npm view` 回读与 tag 一致
76
+ - [ ] 失败路径有 issue/通知(非静默)
77
+ - [ ] `git tag` 与 `package.json version` 一致(`scripts/release.sh` 或 `npm version` 保证)
78
+
79
+ ---
80
+
81
+ ## 反模式
82
+
83
+ - **单依赖 publish**:`needs: build` 是本仓 7 次带病发布的根因
84
+ - **仅 tag 触发**:`push.branches` 缺失导致主干修复无 CI
85
+ - **真实落盘并行测试**:无 `#[cfg(test)]` 隔离的 `config_dir` 直写是偶发红的根因,`--test-threads=1` 只是止血
86
+ - **静默发布**:`publish` 失败不建 issue / 不删 tag,下次 `409` 叠加
87
+ - **`-A clippy::all`**:掩盖真实告警
88
+
89
+ ## 引用
90
+
91
+ - 调研:`.scratch/research/ci-actions-调研.md`(23 次运行全量、`proxy.rs:115` vs `config.rs:460` 对比)
92
+ - 修复:`2d68f62 fix(ci): gate publish on verify and serialize Rust tests`
93
+ - 关联技能:`diagnose-fix`(通用诊断)、`commit-check`(提交前门禁)、`tdd`(测试隔离后的回归)
94
+
95
+ ## 执行清单(粘贴即用)
96
+
97
+ ```markdown
98
+ - [ ] .github/workflows/ci.yml: on.push.branches: [main] 已加
99
+ - [ ] publish.needs: [build, verify]
100
+ - [ ] verify: cargo test --release --lib -- --test-threads=1(或已隔离则去掉该 flag)
101
+ - [ ] config.rs: #[cfg(test)] config_dir/pi_dir → temp(或 TODO 已记录)
102
+ - [ ] workflow_dispatch 可手动触发
103
+ - [ ] npm view 回读 + 失败建 issue
104
+ ```
@@ -0,0 +1,5 @@
1
+ interface:
2
+ display_name: "CI Guard"
3
+ short_description: "Guard release pipeline: orchestrate flows, enforce verify gate, self-correct after publish"
4
+ policy:
5
+ allow_implicit_invocation: false
@@ -0,0 +1,77 @@
1
+ ---
2
+ name: scaffold-functional-test
3
+ disable-model-invocation: false
4
+ description: "Scaffold a repo-specific functional-test skill from spec — use when the user wants to generate a customized functional-test suite/skill from a spec/README/help; not for running tests (use instance-test) nor for TDD (use tdd-implement)"
5
+ ---
6
+
7
+ # Scaffold Functional Test
8
+
9
+ 从本仓库的 spec 自动脚手架出**仓库专属的功能测试 skill**。本技能为**非 Long-Horizon 轻量 skill**(一次性 scaffold,不做多 seam 红绿循环),一次性完成「读 spec → 推导实例 → 落盘 skill → 自验证」闭环。术语定义见 `CONTEXT.md`。
10
+
11
+ ## 产出物
12
+
13
+ - 定制 skill 目录:`.agents/skills/<repo>-functional-test/`(含 `SKILL.md` + `references/instances.md` + 可选 `scripts/run.sh`)
14
+ - 指纹:`spec hash` + `generatedAt` 写入生成物头部,用于后续执行前校验
15
+ - 保护:`<!-- manual -->` 标记段不被覆盖
16
+
17
+ 生成物纳入 git,可回归复用,不进入 `template/` 再分发(生成器本身才随 Template Snapshot 分发)。
18
+
19
+ ## Steps
20
+
21
+ ### ① 采集 Spec
22
+
23
+ 解析用户传入的 spec 路径,默认 `.scratch/<feature>/spec.md`。
24
+
25
+ - 若 spec 存在:读取 `CONTEXT.md`/`docs/adr/` 相关术语与决策,提取待覆盖行为清单(以验收标准为锚点)。
26
+ - 若 spec 不存在:回退到 `README` + `--help` 输出倒推行为清单,但必须进入 Step ② 的清单确认关卡,不静默臆测。
27
+
28
+ 完成:待覆盖行为清单已固定,无未澄清歧义。
29
+
30
+ ### ② 推导实例
31
+
32
+ 按混合推导策略生成实例草案:
33
+
34
+ - 以验收标准为锚点,需求/接口/边界为补充,可为 spec 未显式写的隐含行为(如 `--help` 文案、错误码、幂等性)补实例,但每条实例必须标注**溯源**(spec 章节/行号或 `README/--help` 来源),无溯源的实例视为幻觉需删除。
35
+ - 每实例声明**受控扩展模型**:必选 `prompt/command/expected files/content/expected stdout phrases/expected exit code`,可选 `setup/env/timeout/type/teardown`,默认 `type: cli`。
36
+ - **强制门禁**:实例清单必须与用户确认后才进入 Step ③;无确认不落盘。
37
+
38
+ 完成:实例清单已获用户确认,每实例含溯源与完整四元组。
39
+
40
+ ### ③ 脚手架落盘
41
+
42
+ 按受控扩展模型写入定制 skill 目录:
43
+
44
+ - `SKILL.md`:执行语义(见下节「执行语义」)
45
+ - `references/instances.md`:实例集(含溯源、必选+可选字段、头部 `spec hash` + `generatedAt`)
46
+ - 不覆盖 `<!-- manual -->` 保护段;覆盖式更新需经用户确认;重生成时先给出 diff 建议,用户确认后才应用。
47
+
48
+ 完成:定制 skill 目录已落盘,指纹正确,人工段受保护。
49
+
50
+ ### ④ 自验证
51
+
52
+ 落盘后立即按实例执行语义串行执行一轮实例集作自验证:
53
+
54
+ - `mktemp -d` 隔离(或项目支持的 `git worktree` / `--dest`),单线程串行,不并行。
55
+ - 每实例捕获 stdout/stderr 与 exit code,按 `test -f`/`grep -q`/`diff` 对比判定 `PASS`/`FAIL`,单 FAIL 不阻断后续。
56
+ - 对话内输出 `PASS m/n` + per-instance evidence(`expected vs actual diff` + `run dir`),失败不回滚生成物但给出 gap 供迭代 `regenerate`。
57
+ - 成功默认清理临时目录、失败默认保留(`--keep` 保留全部);`--report` 显式开启才落盘报告文件。
58
+
59
+ 完成:自验证已执行,对话内汇总完成,证据可复现。
60
+
61
+ ## 执行语义(生成物复用)
62
+
63
+ 生成物本身的执行语义与 `instance-test` 一致:`mktemp -d` 串行、`PASS m/n` 汇总、证据含 `expected vs actual diff` + `run dir`。执行前校验 `spec hash` 指纹:若当前 spec 已变更,提示「spec 已变更,建议重跑 scaffold-functional-test」但不自动覆盖,需用户显式确认才 regenerate。
64
+
65
+ ## 不做什么
66
+
67
+ - 不替代 `tdd`/`tdd-implement` 的红绿循环与 `commit-check` 门禁
68
+ - 不自动织入每次 `tdd-implement` 或 `commit-check`;仅 `tdd-implement --with-functional` 显式 opt-in
69
+ - 不支持并行执行与 `docker` 隔离
70
+ - 不处理超出混合推导锚点范围的源码静态分析隐式行为挖掘
71
+
72
+ ## 引用
73
+
74
+ - 领域术语:`CONTEXT.md`
75
+ - 技能设计规则:`docs/agents/skill-design.md`
76
+ - 示范产物:`.agents/skills/instance-test/`(本仓库专属,见其 SKILL.md)
77
+ - Issue tracker:`docs/agents/issue-tracker.md`
@@ -0,0 +1,5 @@
1
+ interface:
2
+ display_name: "Scaffold Functional Test"
3
+ short_description: "Scaffold a repo-specific functional-test skill from spec — not for running tests nor TDD"
4
+ policy:
5
+ allow_implicit_invocation: true
@@ -13,11 +13,11 @@ mattpocock/skills — the source of the 22 skill bodies (skills/engineering, 17
13
13
  _Avoid_: source repo, skill origin
14
14
 
15
15
  **Proprietary Skill** (独有技能):
16
- A skill that does not exist upstream and lives only in this repo (currently tdd-implement, grill-to-spec, diagnose-fix and commit-check). Before adding a new skill, check the Upstream Repository first; only skills absent there qualify as proprietary. The issue-audit subagent is NOT a skill: it ships as a subagent + command under `.opencode/` and is distributed through the Template Snapshot without a skill directory.
16
+ A skill that does not exist upstream and lives only in this repo (currently ci-guard, tdd-implement, grill-to-spec, diagnose-fix, commit-check and scaffold-functional-test). Before adding a new skill, check the Upstream Repository first; only skills absent there qualify as proprietary. The issue-audit subagent is NOT a skill: it ships as a subagent + command under `.opencode/` and is distributed through the Template Snapshot without a skill directory.
17
17
  _Avoid_: private skill, local skill
18
18
 
19
19
  **Workspace** (工作区):
20
- The root-level working copies of the template content — `.agents/skills/` (proprietary skill sources), `.opencode/` (issue-audit agent, explicit-skill commands, plugin manifests), `.pi/` (pi-agent project config: `.pi/skills/` + `.pi/prompts/` issue-audit command), `AGENTS.md`, `CONTEXT.md`, `docs/`. Where this repo's own sessions load, modify, and test the content. The template paths mirror them with a path mapping: `.agents/skills/{tdd-implement,grill-to-spec,diagnose-fix,commit-check}` → `template/.opencode/skills/` and `template/.pi/skills/` (dual mirror), `.opencode/commands/*.md` → `template/.opencode/commands/`, `.pi/prompts/issue-audit.md` → `template/.pi/prompts/issue-audit.md`, root-level `CONTEXT.md` and `docs/agents/` → `template/.opencode/`.
20
+ The root-level working copies of the template content — `.agents/skills/` (proprietary skill sources), `.opencode/` (issue-audit agent, explicit-skill commands, plugin manifests), `.pi/` (pi-agent project config: `.pi/skills/` + `.pi/prompts/` issue-audit command), `AGENTS.md`, `CONTEXT.md`, `docs/`. Where this repo's own sessions load, modify, and test the content. The template paths mirror them with a path mapping: `.agents/skills/{ci-guard,tdd-implement,grill-to-spec,diagnose-fix,commit-check,scaffold-functional-test}` → `template/.opencode/skills/` and `template/.pi/skills/` (dual mirror), `.opencode/commands/*.md` → `template/.opencode/commands/`, `.pi/prompts/issue-audit.md` → `template/.pi/prompts/issue-audit.md`, root-level `CONTEXT.md` and `docs/agents/` → `template/.opencode/`.
21
21
  _Avoid_: working copy, source repo
22
22
 
23
23
  **Template Snapshot** (模板快照):
@@ -0,0 +1,104 @@
1
+ ---
2
+ name: ci-guard
3
+ description: "Guard the GitHub Actions release pipeline: orchestrate workflow flow, enforce pre-release verification, and self-correct after publish. Use when CI is flaky/failing, when setting up or editing .github/workflows/ci.yml, or before tagging a release to npm."
4
+ ---
5
+
6
+ # CI Guard
7
+
8
+ **guard** 为领衔词的发布门禁技能:以一次**可复现的失败**为起点,把 `verify → build → publish` 编排成不可绕过的门,把**预发布校验**做成硬门槛,把**发布后自纠**做成闭环。本技能沉淀自 `heihei0299/pi-switch` 23 次运行中 14 次失败的复盘(见 `.scratch/research/ci-actions-调研.md`)——不替代 `diagnose-fix` 的通用诊断,只收敛 CI/发布这一条链。
9
+
10
+ ## 何时用
11
+
12
+ - Actions 持续红 / 偶发红(尤其是 `verify` 单点红而 `publish` 仍绿)
13
+ - 新建或改动 `.github/workflows/ci.yml`、调整 `cargo test` / `clippy` / `rustfmt` 参数
14
+ - 打 tag 前、发 npm 前、或发布后需要自检/回滚
15
+
16
+ ## 三段式门禁
17
+
18
+ ```
19
+ ① 编排 flows → ② 预发布 gate → ③ 发布后自纠
20
+ ```
21
+
22
+ 每段有**完成条件**(可验证),未满足不进入下一段。
23
+
24
+ ---
25
+
26
+ ### ① 编排 flows —— 让工作流不可被绕过
27
+
28
+ **做**:
29
+ - `on`:`push.tags: ["v*"]` **必须**同时配 `push.branches: [main]`(或 `master`)+ `pull_request.branches: [main]` + `workflow_dispatch`。否则直推 `main` 的修复(如 `2d68f62`)无法被 CI 验证,tag 才暴露问题
30
+ - `jobs` 依赖:`publish.needs: [build, verify]`,**禁止** `needs: build` 单依赖。门禁失效的直接原因就是 `verify` 红仍发包
31
+ - `permissions` 最小化:`verify`/`build` 只需 `contents: read`,仅 `publish` 保留 `contents: write` + `packages: write`(或 `id-token: write` 若用 OIDC)
32
+ - `concurrency`:`group: ci-${{ github.ref }}` + `cancel-in-progress: true`,避免同分支并行互踩
33
+ - `cache`:`rust-cache` 或 `actions/cache` 缓存 `~/.cargo` + `target`,`actions/setup-node` 加 `cache: npm`,避免每次 `npm install` 重装
34
+ - `find changed Rust files`:`git diff origin/main...HEAD` 在 tag 事件下为空,改为 `git diff --name-only HEAD~1...HEAD` 或直接全量 `cargo fmt --check` / `clippy`,避免误跳过
35
+
36
+ **完成条件**:
37
+ - [ ] `git diff HEAD -- .github/workflows/ci.yml` 显示 `on.push.branches` 存在
38
+ - [ ] `publish.needs` 包含 `verify`
39
+ - [ ] `workflow_dispatch` 可手动触发全量
40
+
41
+ ---
42
+
43
+ ### ② 预发布 gate —— 在写盘之前变红
44
+
45
+ 本段是**硬门槛**,顺序固定:`fmt → clippy → test → build`,任一步红即阻断 `publish`。
46
+
47
+ **fmt / clippy**:
48
+ - `rustfmt --check` 与 `cargo clippy --all-targets -- -D warnings` 必须与本地一致(`rust-toolchain.toml` 锁定 `stable` 版本)
49
+ - 允许的 `-A` 必须显式列出(如本仓 `-A clippy::manual_checked_ops` 等 4 项),不批量 `-A clippy::all`
50
+
51
+ **test(关键)**:
52
+ - 落盘测试(如 `web::tests` 直写 `config.json` / `models.json`)**必须**测试隔离:`config_dir()` / `pi_dir()` / `models_path()` 在 `#[cfg(test)]` 下重定向到 `temp/pi-switch-test-<pid>`(参考 `src-rust/proxy.rs:115 init_test_state_dir()`,`config.rs:460` 为未隔离反例;曾用 `PI_SWITCH_CONFIG_DIR` 环境覆盖后被 `20f6f86` 误删,即回归)
53
+ - 若暂未隔离,CI 侧以 `cargo test --release --lib -- --test-threads=1` 串行化为**过渡**(`2d68f62` 方案,322/322 稳定),并在代码侧记录 `TODO(ci-guard): 恢复 config_dir 测试隔离后去掉 --test-threads=1`
54
+ - `verify` 必须跑 `cargo test --lib`(或 `--release --lib` 与发布一致),不跳过;`build` 矩阵 5 目标仅验编译,不代验测试
55
+
56
+ **完成条件**:
57
+ - [ ] 本地 `cargo test --lib -- --test-threads=1` 322/322 且 `cargo test --lib`(并行)亦 322/322 或已记录隔离 TODO
58
+ - [ ] `cargo clippy --all-targets` 0 warning
59
+ - [ ] `npm run build:webui` 在 `verify` 与 `build` 均执行(本仓 WebUI 缺失会导致 `publish` 产物不一致)
60
+
61
+ ---
62
+
63
+ ### ③ 发布后自纠 —— 发出去的包自己负责
64
+
65
+ **发布时**:
66
+ - `npm publish --access public` 仅在 `if: startsWith(github.ref, 'refs/tags/v')` 且 `needs` 全绿时执行
67
+ - 发布前 `actions/download-artifact` 校验 `if-no-files-found: error`,发布后 `npm view <pkg>@<version> version` 回读确认
68
+
69
+ **自纠**:
70
+ - 失败即 **阻断**:`verify` 红 → `publish` 不执行(由 `needs` 保证);`publish` 自身失败(`409 already exists` / `401`)→ 工作流整体 `failure`,不静默
71
+ - 发布后 30s 内 `curl https://registry.npmjs.org/<pkg>/<version>` 校验可用;失败则 `gh issue create --title "chore(release): vX.Y.Z 发布后自检失败" --body "run: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"` 并 `gh release delete vX.Y.Z --yes`(或 `npm unpublish <pkg>@<version>` 在 72h 内)
72
+ - `workflow_dispatch` 支持 `inputs.rollback_version` 手动回滚
73
+
74
+ **完成条件**:
75
+ - [ ] `npm view` 回读与 tag 一致
76
+ - [ ] 失败路径有 issue/通知(非静默)
77
+ - [ ] `git tag` 与 `package.json version` 一致(`scripts/release.sh` 或 `npm version` 保证)
78
+
79
+ ---
80
+
81
+ ## 反模式
82
+
83
+ - **单依赖 publish**:`needs: build` 是本仓 7 次带病发布的根因
84
+ - **仅 tag 触发**:`push.branches` 缺失导致主干修复无 CI
85
+ - **真实落盘并行测试**:无 `#[cfg(test)]` 隔离的 `config_dir` 直写是偶发红的根因,`--test-threads=1` 只是止血
86
+ - **静默发布**:`publish` 失败不建 issue / 不删 tag,下次 `409` 叠加
87
+ - **`-A clippy::all`**:掩盖真实告警
88
+
89
+ ## 引用
90
+
91
+ - 调研:`.scratch/research/ci-actions-调研.md`(23 次运行全量、`proxy.rs:115` vs `config.rs:460` 对比)
92
+ - 修复:`2d68f62 fix(ci): gate publish on verify and serialize Rust tests`
93
+ - 关联技能:`diagnose-fix`(通用诊断)、`commit-check`(提交前门禁)、`tdd`(测试隔离后的回归)
94
+
95
+ ## 执行清单(粘贴即用)
96
+
97
+ ```markdown
98
+ - [ ] .github/workflows/ci.yml: on.push.branches: [main] 已加
99
+ - [ ] publish.needs: [build, verify]
100
+ - [ ] verify: cargo test --release --lib -- --test-threads=1(或已隔离则去掉该 flag)
101
+ - [ ] config.rs: #[cfg(test)] config_dir/pi_dir → temp(或 TODO 已记录)
102
+ - [ ] workflow_dispatch 可手动触发
103
+ - [ ] npm view 回读 + 失败建 issue
104
+ ```
@@ -0,0 +1,5 @@
1
+ interface:
2
+ display_name: "CI Guard"
3
+ short_description: "Guard release pipeline: orchestrate flows, enforce verify gate, self-correct after publish"
4
+ policy:
5
+ allow_implicit_invocation: false
@@ -0,0 +1,77 @@
1
+ ---
2
+ name: scaffold-functional-test
3
+ disable-model-invocation: false
4
+ description: "Scaffold a repo-specific functional-test skill from spec — use when the user wants to generate a customized functional-test suite/skill from a spec/README/help; not for running tests (use instance-test) nor for TDD (use tdd-implement)"
5
+ ---
6
+
7
+ # Scaffold Functional Test
8
+
9
+ 从本仓库的 spec 自动脚手架出**仓库专属的功能测试 skill**。本技能为**非 Long-Horizon 轻量 skill**(一次性 scaffold,不做多 seam 红绿循环),一次性完成「读 spec → 推导实例 → 落盘 skill → 自验证」闭环。术语定义见 `CONTEXT.md`。
10
+
11
+ ## 产出物
12
+
13
+ - 定制 skill 目录:`.agents/skills/<repo>-functional-test/`(含 `SKILL.md` + `references/instances.md` + 可选 `scripts/run.sh`)
14
+ - 指纹:`spec hash` + `generatedAt` 写入生成物头部,用于后续执行前校验
15
+ - 保护:`<!-- manual -->` 标记段不被覆盖
16
+
17
+ 生成物纳入 git,可回归复用,不进入 `template/` 再分发(生成器本身才随 Template Snapshot 分发)。
18
+
19
+ ## Steps
20
+
21
+ ### ① 采集 Spec
22
+
23
+ 解析用户传入的 spec 路径,默认 `.scratch/<feature>/spec.md`。
24
+
25
+ - 若 spec 存在:读取 `CONTEXT.md`/`docs/adr/` 相关术语与决策,提取待覆盖行为清单(以验收标准为锚点)。
26
+ - 若 spec 不存在:回退到 `README` + `--help` 输出倒推行为清单,但必须进入 Step ② 的清单确认关卡,不静默臆测。
27
+
28
+ 完成:待覆盖行为清单已固定,无未澄清歧义。
29
+
30
+ ### ② 推导实例
31
+
32
+ 按混合推导策略生成实例草案:
33
+
34
+ - 以验收标准为锚点,需求/接口/边界为补充,可为 spec 未显式写的隐含行为(如 `--help` 文案、错误码、幂等性)补实例,但每条实例必须标注**溯源**(spec 章节/行号或 `README/--help` 来源),无溯源的实例视为幻觉需删除。
35
+ - 每实例声明**受控扩展模型**:必选 `prompt/command/expected files/content/expected stdout phrases/expected exit code`,可选 `setup/env/timeout/type/teardown`,默认 `type: cli`。
36
+ - **强制门禁**:实例清单必须与用户确认后才进入 Step ③;无确认不落盘。
37
+
38
+ 完成:实例清单已获用户确认,每实例含溯源与完整四元组。
39
+
40
+ ### ③ 脚手架落盘
41
+
42
+ 按受控扩展模型写入定制 skill 目录:
43
+
44
+ - `SKILL.md`:执行语义(见下节「执行语义」)
45
+ - `references/instances.md`:实例集(含溯源、必选+可选字段、头部 `spec hash` + `generatedAt`)
46
+ - 不覆盖 `<!-- manual -->` 保护段;覆盖式更新需经用户确认;重生成时先给出 diff 建议,用户确认后才应用。
47
+
48
+ 完成:定制 skill 目录已落盘,指纹正确,人工段受保护。
49
+
50
+ ### ④ 自验证
51
+
52
+ 落盘后立即按实例执行语义串行执行一轮实例集作自验证:
53
+
54
+ - `mktemp -d` 隔离(或项目支持的 `git worktree` / `--dest`),单线程串行,不并行。
55
+ - 每实例捕获 stdout/stderr 与 exit code,按 `test -f`/`grep -q`/`diff` 对比判定 `PASS`/`FAIL`,单 FAIL 不阻断后续。
56
+ - 对话内输出 `PASS m/n` + per-instance evidence(`expected vs actual diff` + `run dir`),失败不回滚生成物但给出 gap 供迭代 `regenerate`。
57
+ - 成功默认清理临时目录、失败默认保留(`--keep` 保留全部);`--report` 显式开启才落盘报告文件。
58
+
59
+ 完成:自验证已执行,对话内汇总完成,证据可复现。
60
+
61
+ ## 执行语义(生成物复用)
62
+
63
+ 生成物本身的执行语义与 `instance-test` 一致:`mktemp -d` 串行、`PASS m/n` 汇总、证据含 `expected vs actual diff` + `run dir`。执行前校验 `spec hash` 指纹:若当前 spec 已变更,提示「spec 已变更,建议重跑 scaffold-functional-test」但不自动覆盖,需用户显式确认才 regenerate。
64
+
65
+ ## 不做什么
66
+
67
+ - 不替代 `tdd`/`tdd-implement` 的红绿循环与 `commit-check` 门禁
68
+ - 不自动织入每次 `tdd-implement` 或 `commit-check`;仅 `tdd-implement --with-functional` 显式 opt-in
69
+ - 不支持并行执行与 `docker` 隔离
70
+ - 不处理超出混合推导锚点范围的源码静态分析隐式行为挖掘
71
+
72
+ ## 引用
73
+
74
+ - 领域术语:`CONTEXT.md`
75
+ - 技能设计规则:`docs/agents/skill-design.md`
76
+ - 示范产物:`.agents/skills/instance-test/`(本仓库专属,见其 SKILL.md)
77
+ - Issue tracker:`docs/agents/issue-tracker.md`
@@ -0,0 +1,5 @@
1
+ interface:
2
+ display_name: "Scaffold Functional Test"
3
+ short_description: "Scaffold a repo-specific functional-test skill from spec — not for running tests nor TDD"
4
+ policy:
5
+ allow_implicit_invocation: true
@@ -53,7 +53,6 @@
53
53
 
54
54
  仓库被 CodeGraph 索引(根目录存在 `.codegraph/`)时,理解/定位代码**优先于** grep/find/读文件——一次调用拿到相关符号源码与调用路径:
55
55
 
56
- - **CLI**(首选):`codegraph explore "<符号名或问题>"` 一次回答大部分代码问题——相关符号的逐字源码 + 调用路径(含 grep 追不上的动态分派跳转)。在 query 中指名文件/符号即可读取其带行号的当前源码。
57
- - **MCP 工具**(可用时补充):`codegraph_explore` 输出与 CLI 相同;若列出但延迟加载,用工具搜索按名加载。
56
+ - **CLI**:`codegraph explore "<符号名或问题>"` 一次回答大部分代码问题——相关符号的逐字源码 + 调用路径(含 grep 追不上的动态分派跳转)。在 query 中指名文件/符号即可读取其带行号的当前源码。
58
57
 
59
58
  没有 `.codegraph/` 目录则完全跳过 CodeGraph——是否建立索引由用户决定。
@@ -1,61 +0,0 @@
1
- ---
2
- name: instance-test
3
- disable-model-invocation: true
4
- description: "Verify project meets expected goals by running prompt instances in isolated temp dirs"
5
- ---
6
-
7
- # Instance Test
8
-
9
- Run **instance** prompts to verify project meets expected goals via actual functional tests. Each **instance** is a prompt + expected outcome, executed in an isolated temp dir — no mocks, no stubs.
10
-
11
- ## Steps
12
-
13
- ### 1. Gather instances
14
-
15
- Collect the **instance** set to run:
16
-
17
- - User-provided instances (prompt, command, expected files/stdout/exit code), or
18
- - Derived from `spec.md`/`README` acceptance criteria — extract each verifiable behavior as one instance, then confirm the list with the user before running.
19
-
20
- Each **instance** must declare: command to run, expected files/content, expected stdout phrases, expected exit code.
21
-
22
- Completion: instance list is fixed (prompt, expected outcome, verification command) — no instance is added mid-run.
23
-
24
- ### 2. Run instances
25
-
26
- For each **instance** in order:
27
-
28
- 1. `mktemp -d` isolated dir (or `git worktree` / `--dest` if the project supports it).
29
- 2. Execute the instance's command — capture stdout/stderr and exit code.
30
- 3. Snapshot result files and side effects declared in expected.
31
-
32
- Do not run instances in parallel — one **instance** at a time, so failures are isolated and artifacts do not collide.
33
-
34
- Completion: every **instance** has a run dir with captured output and file snapshot.
35
-
36
- ### 3. Evaluate
37
-
38
- Compare each **instance**'s actual vs expected:
39
-
40
- - File existence/content (`test -f`, `grep -q`, `diff`).
41
- - Stdout/stderr contains expected phrases.
42
- - Exit code matches expected.
43
-
44
- Mark `PASS`/`FAIL` per **instance** with evidence (file path, stdout line, or diff).
45
-
46
- Completion: every **instance** has a `PASS` or `FAIL` with evidence — no unevaluated instance.
47
-
48
- ### 4. Report
49
-
50
- Summarize in conversation:
51
-
52
- - `PASS m/n` with per-instance evidence.
53
- - Failures list the gap (expected vs actual) and the run dir for reproduction.
54
- - Clean up temp dirs unless `--keep` is requested.
55
-
56
- Do not write a report file (`report-*.md`) — output stays in conversation. Keep temp dirs only on failure for debugging.
57
-
58
- ## References
59
-
60
- - Instance definitions (if any): `references/instances.md` — example set, auto-loaded only when present, not required.
61
- - Project expected behavior: `spec.md`/`README`/`--help` — the source of truth for what to verify.
@@ -1,5 +0,0 @@
1
- interface:
2
- display_name: "Instance Test"
3
- short_description: "Verify project via prompt instances in isolated temp projects"
4
- policy:
5
- allow_implicit_invocation: false
@@ -1,48 +0,0 @@
1
- # Instances template
2
-
3
- Generic template for **instance** functional tests. Each **instance** is a prompt + command + expected outcome. Copy and adapt for your project; the example below is for `matt-skills`.
4
-
5
- ## Format
6
-
7
- Each instance declares:
8
-
9
- - Prompt: human intent (what to verify)
10
- - Command: shell command to run in isolated dir
11
- - Expected: files/content, stdout phrases, exit code
12
-
13
- Verification commands are in `SKILL.md` steps.
14
-
15
- ## Example: matt-skills functional behavior
16
-
17
- ### 1. Fresh init
18
- Prompt: verify fresh project initialization
19
- Command: `node bin/cli.js init --dest <tmp>`
20
- Expected: `AGENTS.md`, `.opencode/skills/tdd-implement/SKILL.md`, `.pi/skills/tdd-implement/SKILL.md`, `.agents/skills/tdd` (22 upstream) exist; stdout `模板:已复制` + `上游技能:已装 22`; no `.bak`; exit 0.
21
-
22
- ### 2. Init skip on existing
23
- Prompt: verify idempotent init without --force
24
- Command: `init` twice without `--force`, second with local edit to `AGENTS.md`
25
- Expected: second stdout `模板已存在.*跳过`, `上游技能:已装 0、跳过 22`; local edit preserved; exit 0.
26
-
27
- ### 3. Init --force with direct overwrite
28
- Prompt: verify forced init directly overwrites
29
- Command: `init --force --dest <tmp>` after local edit
30
- Expected: stdout `已覆盖` + `已装 22`; `AGENTS.md.bak` exists with local edit; `AGENTS.md` restored from template; no `.agents/skills/*.bak`; no `.opencode.bak`/`.pi.bak`; exit 0.
31
-
32
- ### 4. Sync on existing
33
- Prompt: verify sync directly updates existing project
34
- Command: `sync --dest <tmp>` after local edit
35
- Expected: stdout `同步` + `已同步`/`已更新`; `AGENTS.md.bak` exists; `.agents/skills/tdd` updated; exit 0.
36
- Prompt: verify sync backs up existing project
37
- Command: `sync --dest <tmp>` after local edit
38
- Expected: stdout `同步` + `已备份`; `AGENTS.md.bak` exists; exit 0.
39
-
40
- ### 5. Sync --force without backup
41
- Prompt: verify sync --force does not backup
42
- Command: `sync --force --dest <tmp>`
43
- Expected: stdout `已覆盖` without new `.bak`; exit 0.
44
-
45
- ### 6. List
46
- Prompt: verify skill listing
47
- Command: `list` and `list --json`
48
- Expected: 27 skills, includes `tdd` with correct description; `--json` is valid JSON array; exit 0.
@@ -1,61 +0,0 @@
1
- ---
2
- name: instance-test
3
- disable-model-invocation: true
4
- description: "Verify project meets expected goals by running prompt instances in isolated temp dirs"
5
- ---
6
-
7
- # Instance Test
8
-
9
- Run **instance** prompts to verify project meets expected goals via actual functional tests. Each **instance** is a prompt + expected outcome, executed in an isolated temp dir — no mocks, no stubs.
10
-
11
- ## Steps
12
-
13
- ### 1. Gather instances
14
-
15
- Collect the **instance** set to run:
16
-
17
- - User-provided instances (prompt, command, expected files/stdout/exit code), or
18
- - Derived from `spec.md`/`README` acceptance criteria — extract each verifiable behavior as one instance, then confirm the list with the user before running.
19
-
20
- Each **instance** must declare: command to run, expected files/content, expected stdout phrases, expected exit code.
21
-
22
- Completion: instance list is fixed (prompt, expected outcome, verification command) — no instance is added mid-run.
23
-
24
- ### 2. Run instances
25
-
26
- For each **instance** in order:
27
-
28
- 1. `mktemp -d` isolated dir (or `git worktree` / `--dest` if the project supports it).
29
- 2. Execute the instance's command — capture stdout/stderr and exit code.
30
- 3. Snapshot result files and side effects declared in expected.
31
-
32
- Do not run instances in parallel — one **instance** at a time, so failures are isolated and artifacts do not collide.
33
-
34
- Completion: every **instance** has a run dir with captured output and file snapshot.
35
-
36
- ### 3. Evaluate
37
-
38
- Compare each **instance**'s actual vs expected:
39
-
40
- - File existence/content (`test -f`, `grep -q`, `diff`).
41
- - Stdout/stderr contains expected phrases.
42
- - Exit code matches expected.
43
-
44
- Mark `PASS`/`FAIL` per **instance** with evidence (file path, stdout line, or diff).
45
-
46
- Completion: every **instance** has a `PASS` or `FAIL` with evidence — no unevaluated instance.
47
-
48
- ### 4. Report
49
-
50
- Summarize in conversation:
51
-
52
- - `PASS m/n` with per-instance evidence.
53
- - Failures list the gap (expected vs actual) and the run dir for reproduction.
54
- - Clean up temp dirs unless `--keep` is requested.
55
-
56
- Do not write a report file (`report-*.md`) — output stays in conversation. Keep temp dirs only on failure for debugging.
57
-
58
- ## References
59
-
60
- - Instance definitions (if any): `references/instances.md` — example set, auto-loaded only when present, not required.
61
- - Project expected behavior: `spec.md`/`README`/`--help` — the source of truth for what to verify.
@@ -1,5 +0,0 @@
1
- interface:
2
- display_name: "Instance Test"
3
- short_description: "Verify project via prompt instances in isolated temp projects"
4
- policy:
5
- allow_implicit_invocation: false
@@ -1,48 +0,0 @@
1
- # Instances template
2
-
3
- Generic template for **instance** functional tests. Each **instance** is a prompt + command + expected outcome. Copy and adapt for your project; the example below is for `matt-skills`.
4
-
5
- ## Format
6
-
7
- Each instance declares:
8
-
9
- - Prompt: human intent (what to verify)
10
- - Command: shell command to run in isolated dir
11
- - Expected: files/content, stdout phrases, exit code
12
-
13
- Verification commands are in `SKILL.md` steps.
14
-
15
- ## Example: matt-skills functional behavior
16
-
17
- ### 1. Fresh init
18
- Prompt: verify fresh project initialization
19
- Command: `node bin/cli.js init --dest <tmp>`
20
- Expected: `AGENTS.md`, `.opencode/skills/tdd-implement/SKILL.md`, `.pi/skills/tdd-implement/SKILL.md`, `.agents/skills/tdd` (22 upstream) exist; stdout `模板:已复制` + `上游技能:已装 22`; no `.bak`; exit 0.
21
-
22
- ### 2. Init skip on existing
23
- Prompt: verify idempotent init without --force
24
- Command: `init` twice without `--force`, second with local edit to `AGENTS.md`
25
- Expected: second stdout `模板已存在.*跳过`, `上游技能:已装 0、跳过 22`; local edit preserved; exit 0.
26
-
27
- ### 3. Init --force with direct overwrite
28
- Prompt: verify forced init directly overwrites
29
- Command: `init --force --dest <tmp>` after local edit
30
- Expected: stdout `已覆盖` + `已装 22`; `AGENTS.md.bak` exists with local edit; `AGENTS.md` restored from template; no `.agents/skills/*.bak`; no `.opencode.bak`/`.pi.bak`; exit 0.
31
-
32
- ### 4. Sync on existing
33
- Prompt: verify sync directly updates existing project
34
- Command: `sync --dest <tmp>` after local edit
35
- Expected: stdout `同步` + `已同步`/`已更新`; `AGENTS.md.bak` exists; `.agents/skills/tdd` updated; exit 0.
36
- Prompt: verify sync backs up existing project
37
- Command: `sync --dest <tmp>` after local edit
38
- Expected: stdout `同步` + `已备份`; `AGENTS.md.bak` exists; exit 0.
39
-
40
- ### 5. Sync --force without backup
41
- Prompt: verify sync --force does not backup
42
- Command: `sync --force --dest <tmp>`
43
- Expected: stdout `已覆盖` without new `.bak`; exit 0.
44
-
45
- ### 6. List
46
- Prompt: verify skill listing
47
- Command: `list` and `list --json`
48
- Expected: 27 skills, includes `tdd` with correct description; `--json` is valid JSON array; exit 0.