@heihei0299/matt-skills 1.3.0 → 1.3.2

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 (63) hide show
  1. package/.agents/skills/ask-matt/PHASE-BOUNDARIES.md +55 -0
  2. package/.agents/skills/ask-matt/SKILL.md +37 -25
  3. package/.agents/skills/code-review/SKILL.md +28 -35
  4. package/.agents/skills/codebase-design/DEEPENING.md +4 -4
  5. package/.agents/skills/codebase-design/DESIGN-IT-TWICE.md +10 -10
  6. package/.agents/skills/codebase-design/SKILL.md +13 -13
  7. package/.agents/skills/diagnosing-bugs/SKILL.md +34 -30
  8. package/.agents/skills/diagnosing-bugs/scripts/hitl-loop.template.sh +3 -0
  9. package/.agents/skills/domain-modeling/ADR-FORMAT.md +11 -11
  10. package/.agents/skills/domain-modeling/CONTEXT-FORMAT.md +3 -3
  11. package/.agents/skills/domain-modeling/SKILL.md +10 -10
  12. package/.agents/skills/grill-me/SKILL.md +1 -1
  13. package/.agents/skills/grill-with-docs/SKILL.md +1 -1
  14. package/.agents/skills/grilling/SKILL.md +20 -4
  15. package/.agents/skills/grilling/agents/openai.yaml +1 -1
  16. package/.agents/skills/handoff/SKILL.md +1 -1
  17. package/.agents/skills/improve-codebase-architecture/HTML-REPORT.md +19 -19
  18. package/.agents/skills/improve-codebase-architecture/SKILL.md +21 -21
  19. package/.agents/skills/prototype/LOGIC.md +30 -42
  20. package/.agents/skills/prototype/SKILL.md +7 -7
  21. package/.agents/skills/prototype/UI.md +23 -23
  22. package/.agents/skills/research/SKILL.md +1 -1
  23. package/.agents/skills/resolving-merge-conflicts/SKILL.md +1 -1
  24. package/.agents/skills/setup-matt-pocock-skills/SKILL.md +30 -30
  25. package/.agents/skills/setup-matt-pocock-skills/domain.md +4 -4
  26. package/.agents/skills/setup-matt-pocock-skills/issue-tracker-github.md +5 -5
  27. package/.agents/skills/setup-matt-pocock-skills/issue-tracker-gitlab.md +6 -6
  28. package/.agents/skills/setup-matt-pocock-skills/issue-tracker-local.md +3 -3
  29. package/.agents/skills/tdd/SKILL.md +9 -7
  30. package/.agents/skills/teach/GLOSSARY-FORMAT.md +3 -3
  31. package/.agents/skills/teach/LEARNING-RECORD-FORMAT.md +10 -10
  32. package/.agents/skills/teach/MISSION-FORMAT.md +4 -4
  33. package/.agents/skills/teach/RESOURCES-FORMAT.md +2 -2
  34. package/.agents/skills/teach/SKILL.md +4 -4
  35. package/.agents/skills/to-questionnaire/SKILL.md +54 -0
  36. package/.agents/skills/to-questionnaire/agents/openai.yaml +5 -0
  37. package/.agents/skills/to-spec/SKILL.md +4 -4
  38. package/.agents/skills/to-tickets/SKILL.md +16 -16
  39. package/.agents/skills/triage/AGENT-BRIEF.md +9 -9
  40. package/.agents/skills/triage/OUT-OF-SCOPE.md +15 -15
  41. package/.agents/skills/triage/SKILL.md +29 -29
  42. package/.agents/skills/wait-what/SKILL.md +7 -0
  43. package/.agents/skills/wait-what/agents/openai.yaml +5 -0
  44. package/.agents/skills/wayfinder/SKILL.md +37 -37
  45. package/.agents/skills/wizard/SKILL.md +44 -0
  46. package/.agents/skills/wizard/agents/openai.yaml +3 -0
  47. package/.agents/skills/wizard/template.sh +204 -0
  48. package/.agents/skills/writing-for-agents/SKILL-MECHANICS.md +22 -0
  49. package/.agents/skills/writing-for-agents/SKILL.md +81 -0
  50. package/.agents/skills/writing-for-agents/agents/openai.yaml +3 -0
  51. package/README.md +20 -16
  52. package/bin/cli.js +90 -58
  53. package/package.json +1 -1
  54. package/template/.opencode/CONTEXT.md +4 -0
  55. package/template/.opencode/commands/{writing-great-skills.md → writing-for-agents.md} +1 -1
  56. package/template/.opencode/docs/agents/skill-design.md +3 -3
  57. package/template/.pi/CONTEXT.md +55 -0
  58. package/template/.pi/docs/agents/runtime-discipline.md +3 -2
  59. package/template/.pi/docs/agents/skill-design.md +10 -5
  60. package/template/AGENTS.md +2 -2
  61. package/.agents/skills/writing-great-skills/GLOSSARY.md +0 -201
  62. package/.agents/skills/writing-great-skills/SKILL.md +0 -83
  63. package/.agents/skills/writing-great-skills/agents/openai.yaml +0 -5
package/README.md CHANGED
@@ -11,7 +11,7 @@ template/
11
11
  └── .opencode/ 分发内容(目标仓库的 opencode 项目配置)
12
12
  ├── skills/ 5 个独有技能(tdd-implement、grill-to-spec、diagnose-fix、commit-check、instance-test)
13
13
  ├── agents/ issue-audit 子代理定义
14
- ├── commands/ issue-audit + 9 个显式触发技能命令(grill-to-spec/wayfinder/to-spec/to-tickets/triage/improve-codebase-architecture/teach/handoff/writing-great-skills)
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)
16
16
  ├── CONTEXT.md 术语表
17
17
  ├── package.json 插件依赖清单
@@ -36,11 +36,13 @@ npx @heihei0299/matt-skills init
36
36
  **增量同步(已有项目)**:已有项目更新到最新模板与技能:
37
37
 
38
38
  ```sh
39
- npx @heihei0299/matt-skills sync # 增量同步,直接更新
40
- npx @heihei0299/matt-skills sync --force # 同上(直接覆盖)
39
+ npx @heihei0299/matt-skills sync # 默认仅对比不写盘(check),有差异 exit 1,--json 可解析
40
+ npx @heihei0299/matt-skills sync --apply # 安全增量:AGENTS.md 定制跳过,上游技能强制覆盖但不删
41
+ npx @heihei0299/matt-skills sync --force # 硬盖:AGENTS.md 备份后硬盖,技能与模板全量 add/update/remove
42
+ npx @heihei0299/matt-skills sync --apply --dest <path> --upstream <url> --ref <ref> --json # 选项可组合
41
43
  ```
42
44
 
43
- `sync` 专为已有项目设计:自动检测 `AGENTS.md` 是否存在,存在则增量更新模板与上游技能(直接覆盖,`AGENTS.md` 会备份),不存在则等同全新 `init`。与 `init --force` 的区别:`sync` 语义更明确,建议已有项目优先用 `sync`。
45
+ `sync` 专为已有项目设计,三档语义:默认 `check` 仅对比不写盘(打印“上游 HEAD / 本地非独有 vs 上游 / 新增/更新/删除/一致”表,`--json` 可解析,有差异 `exit 1`);`--apply` 安全增量写盘(`AGENTS.md` 若含独有路由如 `tdd-implement` 则跳过,`.agents/skills` 对上游技能 `rm+cp force` 覆盖但不 `remove`,`template/.opencode/.pi` 增量 `add/update`);`--force` 硬盖(`AGENTS.md` 备份 `.bak` 后强制覆盖,技能与模板均 `add/update/remove` 全做)。`--dest`、`--upstream`、`--ref`、`--json` 在三档均可透传。
44
46
 
45
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/`,`/命令名` 触发)。
46
48
 
@@ -115,14 +117,16 @@ pi 下对应能力以内置工具或已装扩展为准(`AGENTS.md`「能力边
115
117
  仓库内提供安装管理 CLI(`bin/cli.js`,依赖 `prompts`,见 `package.json`),同时作为 npm 包 `@heihei0299/matt-skills` 分发(`npx @heihei0299/matt-skills <command>`):
116
118
 
117
119
  ```sh
118
- node bin/cli.js init [--dest <dir>] [--force] # 初始化项目:template + 上游技能
119
- node bin/cli.js sync [--dest <dir>] [--force] # 同步已有项目到最新(直接覆盖)
120
- node bin/cli.js list [--json] # 列出 .agents/skills/ 下全部技能及描述
121
- node bin/cli.js install [选项] # 把技能复制到目标工具目录(交互式选择)
120
+ node bin/cli.js init [--dest <dir>] [--force] # 初始化项目:template + 上游技能
121
+ node bin/cli.js sync [--apply|--force] [--dest <path>] [--upstream <url>] [--ref <ref>] [--json] # 同步已有项目到最新
122
+ node bin/cli.js list [--json] # 列出 .agents/skills/ 下全部技能及描述
123
+ node bin/cli.js install [选项] # 把技能复制到目标工具目录(交互式选择)
124
+ node bin/cli.js check [--json] [--upstream <url>] [--ref <ref>] # 只读检查上游技能是否最新(等价 sync 默认)
122
125
  ```
123
126
 
124
- `init` 选项:`--dest <dir>` 指定目标目录(默认当前目录);`--force` 覆盖已存在的文件(直接覆盖,`AGENTS.md` 会备份到 `.bak`)(默认跳过),见「初始化」。
125
- `sync` 选项:`--dest <dir>` 指定目标目录;`--force` 直接覆盖(与默认一致),见「初始化」增量同步。
127
+ `init` 选项:`--dest <path>` 指定目标目录(默认当前目录);`--force` 覆盖已存在的文件(直接覆盖,`AGENTS.md` 会备份到 `.bak`)(默认跳过),见「初始化」。
128
+ `sync` 选项:`--apply` 安全增量(`AGENTS.md` 定制跳过、技能不删),`--force` 硬盖(`AGENTS.md` 备份后硬盖、技能与模板全量 `remove`);`--dest <path>` 目标目录;`--upstream <url>` 上游地址;`--ref <ref>` 上游分支;`--json` JSON 输出;默认无参等价 `check` 仅对比不写盘,`--json` 可解析,有差异 `exit 1`。
129
+ `check` 选项:`--json`、`--upstream <url>`、`--ref <ref>`(等价 `sync` 默认 `check`)。
126
130
 
127
131
  `install` 选项:
128
132
 
@@ -136,15 +140,15 @@ node bin/cli.js install [选项] # 把技能复制到目标工
136
140
 
137
141
  本仓库的 `.agents/skills/` 中 **非独有技能** 来自 `mattpocock/skills` 上游。已实现双通道自动同步:
138
142
 
139
- - **本地 CLI**:`matt-skills check`(只读比对)与 `matt-skills update`(一键覆盖本地 `.agents/skills/`,自动处理 `writing-great-skills → writing-for-agents` 重命名与增删)
143
+ - **本地 CLI**:`matt-skills sync` 三档——默认 `check` 只读比对(等价 `matt-skills check`,有差异 `exit 1`,`--json` 可解析)、`matt-skills sync --apply` 安全增量、`matt-skills sync --force` 硬盖;`matt-skills check [--json] [--upstream <url>] [--ref <ref>]` 仍保留为只读别名;`matt-skills update` 已合并到 `sync --apply`(执行提示 `update 已合并到 sync --apply` 且 `exit 1`)
140
144
  - **GitHub Actions**:`.github/workflows/sync-upstream.yml` 每周一 02:00 UTC 自动 `check`,有差异则 `apply` 并提 PR(`upstream-sync/<short-sha>`),支持 `workflow_dispatch` 手动触发(`ref`/`dry_run` 参数)
141
145
 
142
146
  ```sh
143
- npx @heihei0299/matt-skills check # 只读检查,对比本地 vs 上游 HEAD(有差异 exit 1)
144
- npx @heihei0299/matt-skills check --json # JSON 输出:{ head, counts, result: { added, updated, renamed, removed, same } }
145
- npx @heihei0299/matt-skills update --dry-run # 演练,不写文件
146
- npx @heihei0299/matt-skills update # 覆盖 .agents/skills 非独有技能
147
- node scripts/sync-upstream.js --check # 等价底层脚本(CLI check/update 的实现)
147
+ npx @heihei0299/matt-skills sync --json # 默认 check 只读检查,JSON 输出:{ head, counts, result: { added, updated, renamed, removed, same } }
148
+ npx @heihei0299/matt-skills sync --apply # 安全增量写盘
149
+ npx @heihei0299/matt-skills sync --force # 硬盖写盘
150
+ npx @heihei0299/matt-skills check --json # 等价 sync 默认 check
151
+ node scripts/sync-upstream.js --check # 等价底层脚本(CLI sync/check 的实现)
148
152
  node scripts/sync-upstream.js --apply --dry-run
149
153
  ```
150
154
 
package/bin/cli.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { readdir, readFile, cp, stat } from 'node:fs/promises';
2
+ import { readdir, readFile, cp, stat, rm, mkdir } from 'node:fs/promises';
3
3
  import os from 'node:os';
4
4
  import path from 'node:path';
5
5
  import { fileURLToPath } from 'node:url';
@@ -17,31 +17,27 @@ const HELP = `matt-skills — install and manage this skill collection
17
17
 
18
18
  Usage:
19
19
  matt-skills init [options] Initialize a project: template + upstream skills
20
- matt-skills sync [options] Sync existing project to latest template + skills
20
+ matt-skills sync [--apply|--force] [--dest <path>] [--upstream <url>] [--ref <ref>] [--json] Sync existing project to latest template + skills
21
21
  matt-skills list [--json] List available skills and their descriptions
22
22
  matt-skills install [options] Install skills (interactive by default)
23
23
  matt-skills check [--json] [--upstream <url>] [--ref <ref>]
24
24
  Check if upstream skills are up to date (read-only)
25
- matt-skills update [--dry-run] [--force] [--upstream <url>] [--ref <ref>]
26
- Update .agents/skills from upstream (auto handles renames)
27
25
  matt-skills --help Show this help
28
26
 
29
27
  Init options:
30
28
  --dest <path> Target directory (default: current directory)
31
29
  --force Overwrite existing files
32
30
  Sync options:
31
+ --apply Apply changes (safe incremental, respects custom AGENTS.md)
32
+ --force Hard overwrite (backup .bak + full sync)
33
33
  --dest <path> Target directory (default: current directory)
34
- --force Overwrite existing files
34
+ --upstream <url> Upstream repo URL (default: https://github.com/mattpocock/skills.git)
35
+ --ref <ref> Upstream ref (default: HEAD)
36
+ --json Output as JSON
35
37
  Check options:
36
38
  --json Output as JSON
37
39
  --upstream <url> Upstream repo URL (default: https://github.com/mattpocock/skills.git)
38
40
  --ref <ref> Upstream ref (default: HEAD)
39
- Update options:
40
- --dry-run Show what would change without writing files
41
- --force Force overwrite (default is to overwrite; kept for compatibility)
42
- --upstream <url> Upstream repo URL
43
- --ref <ref> Upstream ref
44
-
45
41
  Install options:
46
42
  --tools <a,b> Install for the given tools (codex, pi, opencode, claude); skips tool selection
47
43
  --all Install all skills; skips skill selection
@@ -224,22 +220,69 @@ async function initCommand({ dest, force }) {
224
220
  process.stdout.write(`目标路径:${target}\n`);
225
221
  }
226
222
 
227
- async function syncCommand({ dest, force }) {
223
+ async function syncCommand({ dest, force, apply, upstreamUrl, ref, json }) {
224
+ // 默认:仅对比不写盘 (check 模式),--apply / --force 显式写盘
225
+ const doApply = apply || force;
226
+ if (!doApply) {
227
+ const { compare } = await import('../scripts/sync-upstream.js');
228
+ const cmp = await compare({ upstreamUrl, ref });
229
+ if (json) {
230
+ process.stdout.write(JSON.stringify({ head: cmp.head, counts: cmp.counts, result: cmp.result }, null, 2) + '\n');
231
+ } else {
232
+ const lines = [];
233
+ lines.push(`上游 HEAD: ${cmp.head}`);
234
+ lines.push(`本地非独有: ${cmp.counts.local} 上游: ${cmp.counts.upstream}`);
235
+ lines.push('');
236
+ const totalDiff = cmp.result.added.length + cmp.result.updated.length + cmp.result.removed.length + cmp.result.renamed.length;
237
+ if (totalDiff === 0) {
238
+ lines.push('✅ 已是最新,无差异');
239
+ } else {
240
+ if (cmp.result.added.length) lines.push(`新增 (${cmp.result.added.length}): ${cmp.result.added.join(', ')}`);
241
+ if (cmp.result.updated.length) lines.push(`更新 (${cmp.result.updated.length}): ${cmp.result.updated.join(', ')}`);
242
+ if (cmp.result.renamed.length) lines.push(`重命名 (${cmp.result.renamed.length}): ${cmp.result.renamed.map((r) => `${r.from}→${r.to}`).join(', ')}`);
243
+ if (cmp.result.removed.length) lines.push(`删除 (${cmp.result.removed.length}): ${cmp.result.removed.join(', ')}`);
244
+ if (cmp.result.same.length) lines.push(`一致 (${cmp.result.same.length}): ${cmp.result.same.join(', ')}`);
245
+ }
246
+ process.stdout.write(lines.join('\n') + '\n');
247
+ }
248
+ const { rm } = await import('node:fs/promises');
249
+ await rm(cmp.dest, { recursive: true, force: true });
250
+ const hasDiff = cmp.result.added.length + cmp.result.updated.length + cmp.result.removed.length + cmp.result.renamed.length > 0;
251
+ if (hasDiff) process.exitCode = 1;
252
+ return;
253
+ }
254
+
228
255
  const target = dest ? path.resolve(process.cwd(), dest) : process.cwd();
229
256
  const marker = path.join(target, 'AGENTS.md');
230
- const backup = !force;
231
257
  if (!(await pathExists(marker))) {
232
258
  process.stdout.write('未检测到现有项目(AGENTS.md 不存在),将执行全新初始化\n');
233
259
  await cp(TEMPLATE_DIR, target, { recursive: true, force: true });
234
260
  process.stdout.write('模板:已复制(AGENTS.md、.opencode/、.pi/)\n');
235
- } else {
261
+ } else if (force) {
236
262
  process.stdout.write('同步:检测到现有项目,将增量更新\n');
237
- if (backup) {
238
- const cur = path.join(target, 'AGENTS.md');
239
- if (await pathExists(cur)) await backupIfExists(cur);
263
+ await backupIfExists(path.join(target, 'AGENTS.md'));
264
+ await cp(TEMPLATE_DIR, target, { recursive: true, force: true });
265
+ process.stdout.write('模板:已覆盖(AGENTS.md、.opencode/、.pi/)\n');
266
+ } else if (apply) {
267
+ process.stdout.write('同步:检测到现有项目,将增量更新\n');
268
+ let skipAgents = false;
269
+ try {
270
+ const content = await readFile(path.join(target, 'AGENTS.md'), 'utf8');
271
+ if (content.includes('tdd-implement')) skipAgents = true;
272
+ } catch {}
273
+ if (skipAgents) {
274
+ await cp(path.join(TEMPLATE_DIR, '.opencode'), path.join(target, '.opencode'), { recursive: true, force: true });
275
+ await cp(path.join(TEMPLATE_DIR, '.pi'), path.join(target, '.pi'), { recursive: true, force: true });
276
+ process.stdout.write('模板:已同步(AGENTS.md 跳过,已含定制)\n');
277
+ } else {
278
+ await cp(TEMPLATE_DIR, target, { recursive: true, force: true });
279
+ process.stdout.write('模板:已同步(AGENTS.md、.opencode/、.pi/)\n');
240
280
  }
281
+ } else {
282
+ // fallback for any other doApply case (should not reach here because !doApply already returned)
283
+ process.stdout.write('同步:检测到现有项目,将增量更新\n');
241
284
  await cp(TEMPLATE_DIR, target, { recursive: true, force: true });
242
- process.stdout.write(backup ? '模板:已同步(AGENTS.md、.opencode/、.pi/)\n' : '模板:已覆盖(AGENTS.md、.opencode/、.pi/)\n');
285
+ process.stdout.write('模板:已同步(AGENTS.md、.opencode/、.pi/)\n');
243
286
  }
244
287
  const entries = await readdir(SKILLS_DIR, { withFileTypes: true });
245
288
  const upstream = entries
@@ -247,6 +290,7 @@ async function syncCommand({ dest, force }) {
247
290
  .map((e) => e.name)
248
291
  .sort();
249
292
  const skillsDir = path.join(target, '.agents', 'skills');
293
+ await mkdir(skillsDir, { recursive: true });
250
294
  let installed = 0;
251
295
  let updated = 0;
252
296
  for (const name of upstream) {
@@ -258,6 +302,7 @@ async function syncCommand({ dest, force }) {
258
302
  }
259
303
  const exists = await pathExists(dst);
260
304
  if (exists) {
305
+ await rm(dst, { recursive: true, force: true });
261
306
  await cp(src, dst, { recursive: true, force: true });
262
307
  updated++;
263
308
  } else {
@@ -265,6 +310,20 @@ async function syncCommand({ dest, force }) {
265
310
  installed++;
266
311
  }
267
312
  }
313
+ if (force) {
314
+ let localEntries = [];
315
+ try {
316
+ localEntries = await readdir(skillsDir, { withFileTypes: true });
317
+ } catch {}
318
+ for (const e of localEntries) {
319
+ if (!e.isDirectory()) continue;
320
+ if (e.name.endsWith('.bak')) continue;
321
+ if (e.name === '.git') continue;
322
+ if (PROPRIETARY_SKILLS.has(e.name)) continue;
323
+ if (upstream.includes(e.name)) continue;
324
+ await rm(path.join(skillsDir, e.name), { recursive: true, force: true });
325
+ }
326
+ }
268
327
  process.stdout.write(`上游技能:新增 ${installed}、更新 ${updated}\n`);
269
328
  process.stdout.write(`目标路径:${target}\n`);
270
329
  }
@@ -272,13 +331,23 @@ async function syncCommand({ dest, force }) {
272
331
  function parseInitArgs(args) {
273
332
  let dest;
274
333
  let force = false;
334
+ let apply = false;
335
+ let json = false;
336
+ let upstreamUrl;
337
+ let ref;
275
338
  for (let i = 0; i < args.length; i++) {
276
339
  const arg = args[i];
277
340
  if (arg === '--dest') dest = args[++i];
278
341
  else if (arg.startsWith('--dest=')) dest = arg.slice('--dest='.length);
279
342
  else if (arg === '--force') force = true;
343
+ else if (arg === '--apply') apply = true;
344
+ else if (arg === '--json') json = true;
345
+ else if (arg === '--upstream') upstreamUrl = args[++i];
346
+ else if (arg.startsWith('--upstream=')) upstreamUrl = arg.slice('--upstream='.length);
347
+ else if (arg === '--ref') ref = args[++i];
348
+ else if (arg.startsWith('--ref=')) ref = arg.slice('--ref='.length);
280
349
  }
281
- return { dest, force };
350
+ return { dest, force, apply, json, upstreamUrl, ref };
282
351
  }
283
352
 
284
353
  function parseInstallArgs(args) {
@@ -337,44 +406,6 @@ async function checkCommand(args) {
337
406
  if (hasDiff) process.exitCode = 1;
338
407
  }
339
408
 
340
- async function updateCommand(args) {
341
- const { applySync } = await import('../scripts/sync-upstream.js');
342
- const dryRun = args.includes('--dry-run');
343
- const json = args.includes('--json');
344
- const upstreamIdx = args.indexOf('--upstream');
345
- const upstreamUrl = upstreamIdx !== -1 ? args[upstreamIdx + 1] : undefined;
346
- const refIdx = args.indexOf('--ref');
347
- const ref = refIdx !== -1 ? args[refIdx + 1] : undefined;
348
- const res = await applySync({ upstreamUrl, ref, dryRun });
349
- if (json) {
350
- process.stdout.write(JSON.stringify({ head: res.head, result: res.result, actions: res.actions, dryRun }, null, 2) + '\n');
351
- } else {
352
- const lines = [];
353
- lines.push(`上游 HEAD: ${res.head}`);
354
- lines.push(`本地非独有: ${res.counts.local} 上游: ${res.counts.upstream}`);
355
- lines.push('');
356
- const totalDiff = res.result.added.length + res.result.updated.length + res.result.removed.length + res.result.renamed.length;
357
- if (totalDiff === 0) {
358
- lines.push('✅ 已是最新,无差异');
359
- } else {
360
- if (res.result.added.length) lines.push(`新增 (${res.result.added.length}): ${res.result.added.join(', ')}`);
361
- if (res.result.updated.length) lines.push(`更新 (${res.result.updated.length}): ${res.result.updated.join(', ')}`);
362
- if (res.result.renamed.length) lines.push(`重命名 (${res.result.renamed.length}): ${res.result.renamed.map((r) => `${r.from}→${r.to}`).join(', ')}`);
363
- if (res.result.removed.length) lines.push(`删除 (${res.result.removed.length}): ${res.result.removed.join(', ')}`);
364
- if (res.result.same.length) lines.push(`一致 (${res.result.same.length}): ${res.result.same.join(', ')}`);
365
- }
366
- process.stdout.write(lines.join('\n') + '\n');
367
- if (res.actions.length) {
368
- process.stdout.write(`\n已执行 ${res.actions.length} 项:\n`);
369
- for (const a of res.actions) process.stdout.write(` - ${a}\n`);
370
- }
371
- if (dryRun) process.stdout.write('\n(dry-run,未写文件)\n');
372
- }
373
- if (!dryRun && res.actions.length) {
374
- process.stdout.write('\n提示:请运行 npm test 验证,并按需执行 npm run build:template 更新模板镜像\n');
375
- }
376
- }
377
-
378
409
  async function main() {
379
410
  const args = process.argv.slice(2);
380
411
  if (args.length === 0 || args[0] === '--help' || args[0] === '-h') {
@@ -410,7 +441,8 @@ async function main() {
410
441
  return;
411
442
  }
412
443
  if (command === 'update') {
413
- await updateCommand(rest);
444
+ process.stderr.write('update 已合并到 sync --apply\n');
445
+ process.exitCode = 1;
414
446
  return;
415
447
  }
416
448
  process.stderr.write(HELP);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@heihei0299/matt-skills",
3
- "version": "1.3.0",
3
+ "version": "1.3.2",
4
4
  "description": "Agent skills + 项目配置模板:一条命令初始化 opencode / pi-agent 项目(含 mattpocock/skills 上游技能)",
5
5
  "type": "module",
6
6
  "bin": {
@@ -32,6 +32,10 @@ _Avoid_: inheriting repo, child repo
32
32
  The one-time action of setting up a Target Repository: copying `template/` into its root (`cp -r template/. <target>/`), then fetching the 22 upstream skills from the Upstream Repository. Copying, not inheriting — no runtime relationship survives the copy.
33
33
  _Avoid_: inherit, bootstrap
34
34
 
35
+ **Sync** (同步):
36
+ `matt-skills sync` 同步 Target Repository 的模板与上游技能:默认仅对比不写盘(`check`),`--apply` 为安全增量(`AGENTS.md` 有定制如 `tdd-implement` 则跳过,上游技能直接强制覆盖 `rm+cp` 但不 `remove`,独有技能与 `template/.opencode/.pi` 增量 `add/update`)、`--force` 为硬盖(`AGENTS.md` 备份 `.bak` 后强制覆盖,技能与模板全量 `add/update/remove`)。`update` 已合并到 `sync` 并删除。
37
+ _Avoid_: update, force sync
38
+
35
39
  ## Skill Design
36
40
 
37
41
  **Turn Continuity** (回合连续性):
@@ -4,7 +4,7 @@ description: 技能写作参考——编写和编辑技能的最佳实践(词
4
4
 
5
5
  # Writing Great Skills
6
6
 
7
- 加载并执行 writing-great-skills 技能,编写/编辑技能:
7
+ 加载并执行 writing-for-agents 技能,编写/编辑技能:
8
8
 
9
9
  **主题:** $ARGUMENTS
10
10
 
@@ -7,11 +7,11 @@ This spec exists because of a real incident: a long-horizon skill run on a flash
7
7
 
8
8
  Every **Long-Horizon Skill** must carry a positive **Turn Continuity** rule of its own: the consecutive actions of a stage (red → green → typecheck → next seam) are executed serially **within one turn**, until the stage's exit condition is met. Do not end the turn at "announce the next step" points, and do not wait for the user to say "continue".
9
9
 
10
- - State it **positively** (per the negation principle in `writing-great-skills`): describe the target behaviour, never the banned one.
10
+ - State it **positively** (per the negation principle in `writing-for-agents`): describe the target behaviour, never the banned one.
11
11
  - It must be **self-contained** — the skill cannot rely on the harness `/goal` line, because no `/goal` exists when the user does not activate one.
12
12
  - Every stage ends on a checkable exit condition; reaching it is the only thing that ends the turn.
13
13
  - A sub-step going green (e.g. one seam) is not a stage exit — a stage ends only when all of its seams are complete. Progress output does not itself end the turn: output, then keep executing until one of the three endpoints (compliance checkpoint, external blocker, stage exit) is reached.
14
- - Canonical example: the 回合连续性 rule in [`.agents/skills/tdd-implement/references/stages.md`](../../skills/tdd-implement/references/stages.md) stage ③.
14
+ - Canonical example: the 回合连续性 rule in [`.agents/skills/tdd-implement/references/stages.md`](.agents/skills/tdd-implement/references/stages.md) stage ③.
15
15
 
16
16
  ## Rule 2 — Model Selection
17
17
 
@@ -31,7 +31,7 @@ Every skill that touches git must preserve history after `BASE_HEAD`: history ma
31
31
 
32
32
  To achieve "directory clean" (`git status` clean) the skill may only delete its own temporary artifacts (`[DEBUG-...]`, one-off scripts, untracked probe files) — it must never use git-level destructive commands to reach a clean state. The following are forbidden without explicit user confirmation: `git reset --hard`, `git checkout .`, `git clean -fd`, `git stash push --include-untracked` (use `--keep-index` instead and `pop` with verification), `git push --force`, `git rebase -i` and any `reset`/`checkout` that moves `HEAD` backward.
33
33
 
34
- Canonical enforcement: [`tdd-implement/references/stages.md`](../../skills/tdd-implement/references/stages.md) stage ③/⑥/⑦/A2-A4 Git 安全红线 and [`commit-check/SKILL.md`](../../skills/commit-check/SKILL.md) ③ 目录卫生.
34
+ Canonical enforcement: [`tdd-implement/references/stages.md`](.agents/skills/tdd-implement/references/stages.md) stage ③/⑥/⑦/A2-A4 Git 安全红线 and [`commit-check/SKILL.md`](.agents/skills/commit-check/SKILL.md) ③ 目录卫生.
35
35
  ## Long-horizon skills inventory
36
36
 
37
37
  Skills currently classified as Long-Horizon, to be evolved against these rules as they are touched: `tdd-implement` (fixed), `diagnose-fix` (fixed — new orchestration skill for diagnosis + TDD fix, carries its own Turn Continuity rule), `diagnosing-bugs`, `improve-codebase-architecture`, `wayfinder`, `grill-to-spec`, `to-spec`. Backfilling existing skill texts is out of scope for now — these rules bind new and edited skills going forward.
@@ -0,0 +1,55 @@
1
+ # matt-skills
2
+
3
+ The domain vocabulary for this repo — two sections: how this repository is positioned (`## Repository`) and the terms that govern how long-horizon skills are written, reviewed, and evolved (`## Skill Design`). Every term here is a single source of truth; skills and docs reference it rather than restating the definition.
4
+
5
+ ## Repository
6
+
7
+ **Template Repository** (模板仓库):
8
+ This repository's identity. It is the config repo for mattpocock/skills: it distributes project-level config (AGENTS.md behavior routing, `.opencode/docs/agents/` discipline files, `.opencode/CONTEXT.md` glossary) plus only the Proprietary Skills, not the upstream skill copies. The workspace content is mirrored into `template/` as a Template Snapshot, and initializing a Target Repository is a one-time copy of that snapshot. The workspace copy also serves this repo's own sessions.
9
+ _Avoid_: skill distribution repo
10
+
11
+ **Upstream Repository** (上游仓库):
12
+ mattpocock/skills — the source of the 22 skill bodies (skills/engineering, 17 skills; skills/productivity, 5 skills) that target repos fetch manually per the README. This repo never copies upstream skills into `template/`.
13
+ _Avoid_: source repo, skill origin
14
+
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.
17
+ _Avoid_: private skill, local skill
18
+
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/`.
21
+ _Avoid_: working copy, source repo
22
+
23
+ **Template Snapshot** (模板快照):
24
+ Everything under `template/` — the mirror of the workspace content with the path mapping above (proprietary skills land under `.opencode/skills/` and `.pi/skills/`, opencode commands under `.opencode/commands/`, the pi issue-audit command under `.pi/prompts/`, discipline files and glossary under `.opencode/`, AGENTS.md at the top level), generated by manual sync, used to initialize other repositories. There is no release pipeline; the sync direction is one-way: workspace → snapshot. `test/template-sync.test.js` guards the mirror stays in sync.
25
+ _Avoid_: release snapshot, published snapshot
26
+
27
+ **Target Repository** (目标仓库):
28
+ A repository initialized by copying `template/` into its root and then fetching the upstream skills per the README. It then loads the upstream skills from its own `.agents/skills/`, the Proprietary Skills from `.opencode/skills/` (directly under opencode) and `.pi/skills/` (auto-discovered under pi), the explicit-skill commands from `.opencode/commands/` (opencode) and the `issue-audit` command from `.pi/prompts/` (pi) / `.opencode/commands/` (opencode), and the project-level global config from `.opencode/` and `AGENTS.md`.
29
+ _Avoid_: inheriting repo, child repo
30
+
31
+ **Initialize** (初始化):
32
+ The one-time action of setting up a Target Repository: copying `template/` into its root (`cp -r template/. <target>/`), then fetching the 22 upstream skills from the Upstream Repository. Copying, not inheriting — no runtime relationship survives the copy.
33
+ _Avoid_: inherit, bootstrap
34
+
35
+ **Sync** (同步):
36
+ `matt-skills sync` 同步 Target Repository 的模板与上游技能:默认仅对比不写盘(`check`),`--apply` 为安全增量(`AGENTS.md` 有定制如 `tdd-implement` 则跳过,上游技能直接强制覆盖 `rm+cp` 但不 `remove`,独有技能与 `template/.opencode/.pi` 增量 `add/update`)、`--force` 为硬盖(`AGENTS.md` 备份 `.bak` 后强制覆盖,技能与模板全量 `add/update/remove`)。`update` 已合并到 `sync` 并删除。
37
+ _Avoid_: update, force sync
38
+
39
+ ## Skill Design
40
+
41
+ **Turn Continuity** (回合连续性):
42
+ The rule that a long-horizon skill must carry a positive instruction to keep executing within a turn — red → green → typecheck → next seam serial in one turn until the stage's exit condition is met. The stage exit is reached when all of its seams are complete — one seam going green is not an exit, and progress output does not itself end the turn. It is the skill's own guard against premature turn-end; it must not rely on the harness `/goal` line (which does not exist when no `/goal` is active).
43
+ _Avoid_: keep going, don't stop
44
+
45
+ **Chunking** (拆小步 / 进度编排):
46
+ Splitting a giant turn — one large `write` or a batch of `replace`s — into small steps that are individually verified before continuing, so the turn never hits output caps and gets truncated mid-work.
47
+ _Avoid_: step-by-step, take it slow
48
+
49
+ **Git History Preservation** (Git 历史保护):
50
+ Every git-touching skill must preserve history after `BASE_HEAD=$(git rev-parse HEAD)` recorded at stage entry — history may only be appended. Before any commit or stage exit, verify `git merge-base --is-ancestor $BASE_HEAD HEAD`; if it fails, history was rewritten and must be recovered via `git reflog` before continuing. "Directory clean" (`git status` clean) may only be achieved by deleting the skill's own temporary artifacts (`[DEBUG-...]`, one-off scripts, untracked probe files); destructive git commands `git reset --hard`, `git checkout .`, `git clean -fd`, `git stash push --include-untracked`, `git push --force`, `git rebase -i` are forbidden without explicit user confirmation.
51
+ _Avoid_: force clean, stash all
52
+
53
+ **Long-Horizon Skill** (长程多阶段技能):
54
+ A skill whose run spans multiple stages or seams executed continuously (e.g. tdd-implement, diagnosing-bugs, improve-codebase-architecture, wayfinder, grill-to-spec, to-spec). The class of skill that must carry a Turn Continuity rule.
55
+ _Avoid_: complex skill, big skill
@@ -1,6 +1,6 @@
1
1
  # Runtime Discipline
2
2
 
3
- 本仓库会话的运行时纪律,执行口径源自 `.opencode/docs/agents/skill-design.md` 的三条规则(规范正文)。术语定义见 `.opencode/CONTEXT.md`。
3
+ 本仓库会话的运行时纪律,执行口径源自 `docs/agents/skill-design.md` 的四条规则(规范正文)。术语定义见 `CONTEXT.md`。
4
4
 
5
5
  ## 回合连续性规则
6
6
 
@@ -11,7 +11,7 @@
11
11
  - 外部阻塞:权限拒绝、缺失授权、依赖不可用——明确说明所需授权或替代路径,不静默停止
12
12
  - 阶段完成:整个阶段的出口条件满足(如 seam 全绿、typecheck 通过、commit 完成)
13
13
 
14
- 预告下一步后立即执行该步骤,禁止把"分析/预告"当作回合终点。随包示例见 `.opencode/skills/tdd-implement/SKILL.md` 与 `references/stages.md` 阶段③ 3e。
14
+ 预告下一步后立即执行该步骤,禁止把"分析/预告"当作回合终点。随包示例见 `.agents/skills/tdd-implement/SKILL.md` 与 `references/stages.md` 阶段③ 3e。
15
15
 
16
16
  ## 运行纪律(长程任务)
17
17
 
@@ -20,6 +20,7 @@
20
20
  - **长程声明**:执行长程技能前,确认技能文本自带长程任务声明与回合连续性规则(Turn Continuity)——阶段内连续动作一回合内完成,不依赖 harness `/goal` 防线。tdd-implement 已内嵌(SKILL.md 声明 + references/stages.md 阶段③规则)。
21
21
  - **模型选择**:flash 级模型长程任务卡住概率显著更高;关键长任务优先强模型或 `/goal` 模式。
22
22
  - **任务分解(Chunking)**:巨型操作拆小步执行——单次 `write` 超过 ~150 行先写骨架再分批补全;批量 `replace` 超过 ~5 处分批执行,每批后立即验证。tdd-implement 已内嵌该规则(随包分发)。
23
+ - **Git 历史保护(Git History Preservation)**:任何触及 git 的操作必须追加历史、不可改写丢弃。阶段入口记录 `BASE_HEAD=$(git rev-parse HEAD)`,阶段出口与 commit 前校验 `git merge-base --is-ancestor $BASE_HEAD HEAD`,失败即经 `git reflog` 恢复后才继续。"目录卫生"仅删本次产生的 `[DEBUG-...]`/一次性脚本等未跟踪临时文件,禁止为达干净而执行 `git reset --hard`、`git checkout .`、`git clean -fd`、`git stash push --include-untracked`、`git push --force`、`git rebase -i` 等(需显式用户确认)。
23
24
 
24
25
  ## 执行原则(细则)
25
26
 
@@ -1,18 +1,17 @@
1
1
  # Skill Design Spec
2
2
 
3
- The design rules every skill in this repo must obey. Apply them when writing a new skill or editing an existing one. Terms are defined once in [`CONTEXT.md`](../../../.opencode/CONTEXT.md) — reference them there, never restate the definition.
4
-
5
- This spec exists because of a real incident: a long-horizon skill run on a flash-class model stopped its turn at "announce the next step" points four times in one session (see `DIAGNOSIS-tdd-implement-stuck.md`). The three rules below are the preventive measures that came out of that diagnosis. They are repo rules, not advice.
3
+ The design rules every skill in this repo must obey. Apply them when writing a new skill or editing an existing one. Terms are defined once in [`CONTEXT.md`](../../CONTEXT.md) — reference them there, never restate the definition.
6
4
 
5
+ This spec exists because of a real incident: a long-horizon skill run on a flash-class model stopped its turn at "announce the next step" points four times in one session (see `DIAGNOSIS-tdd-implement-stuck.md`). The four rules below are the preventive measures that came out of that diagnosis and subsequent git-history incidents (see `docs/adr/0003-git-history-preservation.md`). They are repo rules, not advice.
7
6
  ## Rule 1 — Turn Continuity
8
7
 
9
8
  Every **Long-Horizon Skill** must carry a positive **Turn Continuity** rule of its own: the consecutive actions of a stage (red → green → typecheck → next seam) are executed serially **within one turn**, until the stage's exit condition is met. Do not end the turn at "announce the next step" points, and do not wait for the user to say "continue".
10
9
 
11
- - State it **positively** (per the negation principle in `writing-great-skills`): describe the target behaviour, never the banned one.
10
+ - State it **positively** (per the negation principle in `writing-for-agents`): describe the target behaviour, never the banned one.
12
11
  - It must be **self-contained** — the skill cannot rely on the harness `/goal` line, because no `/goal` exists when the user does not activate one.
13
12
  - Every stage ends on a checkable exit condition; reaching it is the only thing that ends the turn.
14
13
  - A sub-step going green (e.g. one seam) is not a stage exit — a stage ends only when all of its seams are complete. Progress output does not itself end the turn: output, then keep executing until one of the three endpoints (compliance checkpoint, external blocker, stage exit) is reached.
15
- - Canonical example: the 回合连续性 rule in [`.agents/skills/tdd-implement/references/stages.md`](../../skills/tdd-implement/references/stages.md) stage ③.
14
+ - Canonical example: the 回合连续性 rule in [`.agents/skills/tdd-implement/references/stages.md`](.agents/skills/tdd-implement/references/stages.md) stage ③.
16
15
 
17
16
  ## Rule 2 — Model Selection
18
17
 
@@ -26,7 +25,13 @@ Giant turns — a single `write` of a large file, or a batch `replace` of a hund
26
25
  - A batch of more than ~5 `replace`s: split into batches and verify after each batch.
27
26
 
28
27
  These thresholds are experience defaults; adjust them as practice shows better values.
28
+ ## Rule 4 — Git History Preservation
29
+
30
+ Every skill that touches git must preserve history after `BASE_HEAD`: history may only be appended, never rewritten or dropped. The skill must record `BASE_HEAD=$(git rev-parse HEAD)` at stage entry, and verify `git merge-base --is-ancestor $BASE_HEAD HEAD` at every stage exit and before any commit — failure means history was rewritten and the skill must recover via `git reflog` before continuing.
31
+
32
+ To achieve "directory clean" (`git status` clean) the skill may only delete its own temporary artifacts (`[DEBUG-...]`, one-off scripts, untracked probe files) — it must never use git-level destructive commands to reach a clean state. The following are forbidden without explicit user confirmation: `git reset --hard`, `git checkout .`, `git clean -fd`, `git stash push --include-untracked` (use `--keep-index` instead and `pop` with verification), `git push --force`, `git rebase -i` and any `reset`/`checkout` that moves `HEAD` backward.
29
33
 
34
+ Canonical enforcement: [`tdd-implement/references/stages.md`](.agents/skills/tdd-implement/references/stages.md) stage ③/⑥/⑦/A2-A4 Git 安全红线 and [`commit-check/SKILL.md`](.agents/skills/commit-check/SKILL.md) ③ 目录卫生.
30
35
  ## Long-horizon skills inventory
31
36
 
32
37
  Skills currently classified as Long-Horizon, to be evolved against these rules as they are touched: `tdd-implement` (fixed), `diagnose-fix` (fixed — new orchestration skill for diagnosis + TDD fix, carries its own Turn Continuity rule), `diagnosing-bugs`, `improve-codebase-architecture`, `wayfinder`, `grill-to-spec`, `to-spec`. Backfilling existing skill texts is out of scope for now — these rules bind new and edited skills going forward.
@@ -37,10 +37,10 @@
37
37
  - 领域术语/ADR → domain-modeling;模块接口 → codebase-design;巨型规划 → wayfinder
38
38
  - 诊断 → diagnose-fix(编排 diagnosing-bugs 诊断 + tdd 修复,修复环节强制 TDD);审查 → code-review;合并冲突 → resolving-merge-conflicts;提交前 → commit-check(审查文档 + 对齐 README + 目录卫生 + commit message)
39
39
  - 分诊 → triage;架构扫描 → improve-codebase-architecture;综合 spec → to-spec;拆票 → to-tickets
40
- - 教学 → teach;交接 → handoff;技能写作 → writing-great-skills
40
+ - 教学 → teach;交接 → handoff;技能写作 → writing-for-agents
41
41
  - 兜底 → ask-matt;模板维护 → README.md
42
42
 
43
- 显式触发(须用户 `/` 发起):grill-to-spec、wayfinder、to-spec、to-tickets、triage、improve-codebase-architecture、teach、handoff、writing-great-skills
43
+ 显式触发(须用户 `/` 发起):grill-to-spec、wayfinder、to-spec、to-tickets、triage、improve-codebase-architecture、teach、handoff、writing-for-agents
44
44
 
45
45
  ## 分文件
46
46