@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.
- package/.agents/skills/ci-guard/SKILL.md +104 -0
- package/.agents/skills/ci-guard/agents/openai.yaml +5 -0
- package/.agents/skills/instance-test/SKILL.md +36 -27
- package/.agents/skills/instance-test/agents/openai.yaml +1 -1
- package/.agents/skills/instance-test/references/instances.md +63 -36
- package/.agents/skills/scaffold-functional-test/SKILL.md +77 -0
- package/.agents/skills/scaffold-functional-test/agents/openai.yaml +5 -0
- package/README.md +8 -8
- package/bin/cli.js +1 -1
- package/config/proprietary.json +8 -1
- package/package.json +1 -1
- package/scripts/sync-upstream.js +1 -1
- package/template/.opencode/CONTEXT.md +2 -2
- package/template/.opencode/skills/ci-guard/SKILL.md +104 -0
- package/template/.opencode/skills/ci-guard/agents/openai.yaml +5 -0
- package/template/.opencode/skills/scaffold-functional-test/SKILL.md +77 -0
- package/template/.opencode/skills/scaffold-functional-test/agents/openai.yaml +5 -0
- package/template/.pi/CONTEXT.md +2 -2
- package/template/.pi/skills/ci-guard/SKILL.md +104 -0
- package/template/.pi/skills/ci-guard/agents/openai.yaml +5 -0
- package/template/.pi/skills/scaffold-functional-test/SKILL.md +77 -0
- package/template/.pi/skills/scaffold-functional-test/agents/openai.yaml +5 -0
- package/template/AGENTS.md +1 -2
- package/template/.opencode/skills/instance-test/SKILL.md +0 -61
- package/template/.opencode/skills/instance-test/agents/openai.yaml +0 -5
- package/template/.opencode/skills/instance-test/references/instances.md +0 -48
- package/template/.pi/skills/instance-test/SKILL.md +0 -61
- package/template/.pi/skills/instance-test/agents/openai.yaml +0 -5
- 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
|
+
```
|
|
@@ -1,61 +1,70 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: instance-test
|
|
3
3
|
disable-model-invocation: true
|
|
4
|
-
description: "
|
|
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
|
-
|
|
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
|
-
|
|
17
|
+
实例集已由生成器按**受控扩展模型**落盘于 `references/instances.md`(头部含 `spec hash` + `generatedAt`,每实例含**溯源** `spec.md` 章节/行号,`<!-- manual -->` 段受保护)。
|
|
16
18
|
|
|
17
|
-
|
|
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
|
-
|
|
21
|
+
每实例声明:`prompt/command/expected files/content/expected stdout phrases/expected exit code` 必选,`setup/env/timeout/type/teardown` 可选,默认 `type: cli`。
|
|
21
22
|
|
|
22
|
-
|
|
23
|
+
完成:实例清单已固定(含溯源与指纹),`<!-- manual -->` 段未被覆盖。
|
|
23
24
|
|
|
24
25
|
### 2. Run instances
|
|
25
26
|
|
|
26
27
|
For each **instance** in order:
|
|
27
28
|
|
|
28
|
-
1. `mktemp -d`
|
|
29
|
-
2.
|
|
30
|
-
3.
|
|
29
|
+
1. `mktemp -d` 隔离目录(或项目支持的 `git worktree` / `--dest`),单线程串行,不并行。
|
|
30
|
+
2. 执行实例的 `command` 与可选 `setup`,捕获 stdout/stderr 与 exit code。
|
|
31
|
+
3. 快照 `expected` 声明的文件与副作用。
|
|
31
32
|
|
|
32
|
-
|
|
33
|
+
一个 **instance** 一次,失败不阻断后续,产物不碰撞。
|
|
33
34
|
|
|
34
|
-
|
|
35
|
+
完成:每实例均有独立 run dir 与捕获输出。
|
|
35
36
|
|
|
36
37
|
### 3. Evaluate
|
|
37
38
|
|
|
38
|
-
|
|
39
|
+
对比每实例的 actual vs expected:
|
|
39
40
|
|
|
40
|
-
-
|
|
41
|
-
- Stdout/stderr
|
|
42
|
-
- Exit code
|
|
41
|
+
- 文件存在性/内容(`test -f`/`grep -q`/`diff`)
|
|
42
|
+
- Stdout/stderr 含预期短语
|
|
43
|
+
- Exit code 一致
|
|
44
|
+
- 扩展字段(`env`/`timeout`/`type`)行为符合声明
|
|
43
45
|
|
|
44
|
-
|
|
46
|
+
标记 `PASS`/`FAIL`,附 `expected vs actual` diff 与 run dir 证据。
|
|
45
47
|
|
|
46
|
-
|
|
48
|
+
完成:每实例均有 `PASS` 或 `FAIL` 且含证据。
|
|
47
49
|
|
|
48
50
|
### 4. Report
|
|
49
51
|
|
|
50
|
-
|
|
52
|
+
对话内汇总:
|
|
53
|
+
|
|
54
|
+
- `PASS m/n` + per-instance evidence
|
|
55
|
+
- 失败项列出 gap(expected vs actual)与 run dir 复现路径
|
|
56
|
+
- 成功默认清理临时目录、失败默认保留;`--keep` 保留全部;`--report` 显式开启才落盘报告文件
|
|
57
|
+
|
|
58
|
+
不以文件刷屏——默认输出在对话,报告文件仅显式开启才写。
|
|
51
59
|
|
|
52
|
-
|
|
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
|
-
|
|
62
|
+
- 源 spec:`.scratch/sync-merge-update/spec.md`(`spec hash` 见 `references/instances.md` 头部)
|
|
63
|
+
- 推导策略:混合推导(验收标准锚点 + 需求/接口/边界补充),每实例含溯源,无溯源视为幻觉
|
|
64
|
+
- 手工段:`<!-- manual -->` 保护
|
|
57
65
|
|
|
58
|
-
##
|
|
66
|
+
## 引用
|
|
59
67
|
|
|
60
|
-
-
|
|
61
|
-
-
|
|
68
|
+
- 生成器:`scaffold-functional-test`(读 spec 产出本 skill)
|
|
69
|
+
- 领域术语:`CONTEXT.md`
|
|
70
|
+
- 技能设计:`docs/agents/skill-design.md`
|
|
@@ -1,48 +1,75 @@
|
|
|
1
|
-
# Instances
|
|
1
|
+
# Instances for matt-skills — sync 行为功能测试(由 scaffold-functional-test 生成)
|
|
2
2
|
|
|
3
|
-
|
|
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
|
-
|
|
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
|
-
|
|
10
|
+
执行前校验:对比当前 `.scratch/sync-merge-update/spec.md` 的 hash 与本文件头部 `spec hash`,不一致时提示「spec 已变更,建议重跑 scaffold-functional-test」但不自动覆盖。
|
|
8
11
|
|
|
9
|
-
|
|
10
|
-
- Command: shell command to run in isolated dir
|
|
11
|
-
- Expected: files/content, stdout phrases, exit code
|
|
12
|
+
---
|
|
12
13
|
|
|
13
|
-
|
|
14
|
+
## 1. sync 默认 check(无参不写盘)
|
|
14
15
|
|
|
15
|
-
|
|
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
|
-
|
|
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
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
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
|
-
|
|
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
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
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
|
-
|
|
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
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
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`
|
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/
|
|
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/
|
|
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
|
|
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', '
|
|
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;
|
package/config/proprietary.json
CHANGED
package/package.json
CHANGED
package/scripts/sync-upstream.js
CHANGED
|
@@ -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', '
|
|
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
|
|
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,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`
|
package/template/.pi/CONTEXT.md
CHANGED
|
@@ -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
|
|
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,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`
|
package/template/AGENTS.md
CHANGED
|
@@ -53,7 +53,6 @@
|
|
|
53
53
|
|
|
54
54
|
仓库被 CodeGraph 索引(根目录存在 `.codegraph/`)时,理解/定位代码**优先于** grep/find/读文件——一次调用拿到相关符号源码与调用路径:
|
|
55
55
|
|
|
56
|
-
- **CLI
|
|
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,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,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.
|