@heihei0299/matt-skills 1.5.4 → 1.6.0
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.
|
@@ -17,6 +17,7 @@ description: "Run the pre-commit gate before any commit: verify docs match the i
|
|
|
17
17
|
- 发现不一致 → 先修文档(或更新实现),再进入下一步
|
|
18
18
|
- 改动涉及项目结构、分发文件、技能/命令清单时,检查 README 中对应的结构说明、映射表、清单是否同步
|
|
19
19
|
- 改动涉及用法/CLI/配置/示例时,检查 README 对应描述与实际一致
|
|
20
|
+
- **重点聚焦(README + matt-skills 流程)**:本次门禁优先对齐 `README.md` 与 matt-skills 流程相关文件——`AGENTS.md`(路由)、`CONTEXT.md`(术语)、`docs/agents/*`(`skill-design.md`/`runtime-discipline.md`/`issue-tracker.md`/`triage-labels.md`/`domain.md`)、`template/` 镜像(含 `.agents/skills` 全量、`AGENTS.md`、`CONTEXT.md`、`docs/agents`)、`.agents/skills/*`(技能正文与 `references/`)、`config/*` 与 `scripts/build-template.js`;改动触及上述任一文件时,逐项核对 README 的结构说明/清单/映射表与模板镜像是否同步,未同步先修复再 commit
|
|
20
21
|
- 存在模板镜像/分发副本时,确认源文件与副本同步(如有守护测试,跑一遍确认)
|
|
21
22
|
- **特例**:`AGENTS.md` 的 `tdd-implement ↔ implement` 路由行 + 技能文件 + `.gitignore` 的 `.pi/` 忽略,且存在 `AGENTS.md.bak` 时,视为模板同步预期增量,不回滚
|
|
22
23
|
### ② 保持目录卫生
|
package/bin/cli.js
CHANGED
|
@@ -32,37 +32,83 @@ process.stdout.on('error', (err) => {
|
|
|
32
32
|
throw err;
|
|
33
33
|
});
|
|
34
34
|
|
|
35
|
-
const
|
|
35
|
+
const HELP_GLOBAL = `matt-skills — install and manage this skill collection
|
|
36
36
|
|
|
37
37
|
Usage:
|
|
38
38
|
matt-skills init [options] Initialize a project: template + skills (.agents/skills)
|
|
39
|
-
matt-skills sync [--
|
|
39
|
+
matt-skills sync [--all|--force|--dry-run] [--dest <path>] Sync existing project to latest template + skills
|
|
40
40
|
matt-skills list [--all] [--json] List available skills and their descriptions
|
|
41
41
|
matt-skills install [options] Install skills (interactive by default)
|
|
42
42
|
matt-skills check [--all] [--json] [--upstream <url>] [--ref <ref>]
|
|
43
43
|
Check if upstream skills are up to date (read-only)
|
|
44
|
-
matt-skills --help
|
|
44
|
+
matt-skills --help | -h Show this help
|
|
45
|
+
matt-skills --version | -v Show version
|
|
46
|
+
`;
|
|
47
|
+
|
|
48
|
+
const HELP_INIT = `matt-skills init [options] — Initialize a project: template + skills (.agents/skills)
|
|
49
|
+
|
|
50
|
+
Usage:
|
|
51
|
+
matt-skills init [options]
|
|
45
52
|
|
|
46
53
|
Init options:
|
|
47
54
|
--dest <path> Target directory (default: current directory)
|
|
48
55
|
--force Overwrite existing files
|
|
49
56
|
--all Include non-programming skills (productivity) and optional proprietary; default only core programming (engineering 18 + default proprietary 4 → 22)
|
|
57
|
+
--help, -h Show this help
|
|
58
|
+
|
|
59
|
+
提示:matt-skills --help 查看全量
|
|
60
|
+
`;
|
|
61
|
+
|
|
62
|
+
const HELP_SYNC = `matt-skills sync — Sync existing project to latest template + skills
|
|
63
|
+
|
|
64
|
+
Usage:
|
|
65
|
+
matt-skills sync [--all|--force|--dry-run] [--dest <path>]
|
|
66
|
+
|
|
50
67
|
Sync options:
|
|
51
|
-
--
|
|
52
|
-
--force
|
|
53
|
-
--
|
|
68
|
+
--all 范围:含非编程与可选独有(默认仅编程 22)
|
|
69
|
+
--force 力度:硬盖(备份 .bak + 删多余,全量 add/update/remove)
|
|
70
|
+
--dry-run 预演:只比对不写盘
|
|
54
71
|
--dest <path> Target directory (default: current directory)
|
|
55
|
-
--
|
|
56
|
-
|
|
72
|
+
--help, -h Show this help
|
|
73
|
+
|
|
74
|
+
说明:默认不带参即安全增量同步默认技能(22);--all 与 --force 互斥。
|
|
75
|
+
|
|
76
|
+
提示:matt-skills --help 查看全量
|
|
77
|
+
`;
|
|
78
|
+
|
|
79
|
+
const HELP_LIST = `matt-skills list — List available skills
|
|
80
|
+
|
|
81
|
+
Usage:
|
|
82
|
+
matt-skills list [--all] [--json]
|
|
83
|
+
|
|
84
|
+
List options:
|
|
85
|
+
--all List all skills (default only core programming 22)
|
|
57
86
|
--json Output as JSON
|
|
87
|
+
--help, -h Show this help
|
|
88
|
+
|
|
89
|
+
提示:matt-skills --help 查看全量
|
|
90
|
+
`;
|
|
91
|
+
|
|
92
|
+
const HELP_CHECK = `matt-skills check — Check if upstream skills are up to date (read-only)
|
|
93
|
+
|
|
94
|
+
Usage:
|
|
95
|
+
matt-skills check [--all] [--json] [--upstream <url>] [--ref <ref>]
|
|
96
|
+
|
|
58
97
|
Check options:
|
|
59
98
|
--all Include non-programming and optional proprietary; default only core programming (22)
|
|
60
99
|
--json Output as JSON
|
|
61
100
|
--upstream <url> Upstream repo URL (default: https://github.com/mattpocock/skills.git)
|
|
62
101
|
--ref <ref> Upstream ref (default: HEAD)
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
102
|
+
--help, -h Show this help
|
|
103
|
+
|
|
104
|
+
提示:matt-skills --help 查看全量
|
|
105
|
+
`;
|
|
106
|
+
|
|
107
|
+
const HELP_INSTALL = `matt-skills install — Install skills (interactive by default)
|
|
108
|
+
|
|
109
|
+
Usage:
|
|
110
|
+
matt-skills install [options]
|
|
111
|
+
|
|
66
112
|
Install options:
|
|
67
113
|
--tools <a,b> Install for the given tools (codex, pi, opencode, claude); skips tool selection — 共享技能统一指向 .agents/skills,.pi/skills/.opencode/skills 仅用于项目自定义
|
|
68
114
|
--all Install all skills (default only core programming 22); skips skill selection
|
|
@@ -70,8 +116,13 @@ Install options:
|
|
|
70
116
|
--global Install to the user's global skill directories
|
|
71
117
|
--project Install to project skill directories (default)
|
|
72
118
|
--dest <path> Install everything into a single custom directory (overrides --tools)
|
|
119
|
+
--help, -h Show this help
|
|
120
|
+
|
|
121
|
+
提示:matt-skills --help 查看全量
|
|
73
122
|
`;
|
|
74
123
|
|
|
124
|
+
const HELP = HELP_GLOBAL;
|
|
125
|
+
|
|
75
126
|
function parseFrontmatter(text) {
|
|
76
127
|
const match = text.match(/^---\r?\n([\s\S]*?)\r?\n---/);
|
|
77
128
|
if (!match) return {};
|
|
@@ -280,25 +331,22 @@ async function initCommand({ dest, force, all }) {
|
|
|
280
331
|
}
|
|
281
332
|
process.stdout.write(`目标路径:${target}\n`);
|
|
282
333
|
}
|
|
283
|
-
async function syncCommand({ dest, force,
|
|
334
|
+
async function syncCommand({ dest, force, all, dryRun, json, upstreamUrl, ref }) {
|
|
284
335
|
const onlyProgramming = !all;
|
|
285
|
-
|
|
286
|
-
const doApply = apply || force;
|
|
287
|
-
if (!doApply) {
|
|
336
|
+
if (dryRun) {
|
|
288
337
|
const { compare } = await import('../scripts/sync-upstream.js');
|
|
289
338
|
const cmp = await compare({ upstreamUrl, ref, onlyProgramming });
|
|
290
339
|
if (json) {
|
|
291
340
|
process.stdout.write(JSON.stringify({ head: cmp.head, counts: cmp.counts, result: cmp.result, onlyProgramming }, null, 2) + '\n');
|
|
292
341
|
} else {
|
|
342
|
+
const modeHint = onlyProgramming ? '(仅编程)' : '(全量)';
|
|
293
343
|
const lines = [];
|
|
294
344
|
lines.push(`上游 HEAD: ${cmp.head}`);
|
|
295
|
-
const modeHint = onlyProgramming ? '(仅编程)' : '(全量)';
|
|
296
345
|
lines.push(`本地非独有: ${cmp.counts.local} 上游: ${cmp.counts.upstream} ${modeHint}`);
|
|
297
346
|
lines.push('');
|
|
298
347
|
const totalDiff = cmp.result.added.length + cmp.result.updated.length + cmp.result.removed.length + cmp.result.renamed.length;
|
|
299
|
-
if (totalDiff === 0)
|
|
300
|
-
|
|
301
|
-
} else {
|
|
348
|
+
if (totalDiff === 0) lines.push('✅ 已是最新,无差异');
|
|
349
|
+
else {
|
|
302
350
|
if (cmp.result.added.length) lines.push(`新增 (${cmp.result.added.length}): ${cmp.result.added.join(', ')}`);
|
|
303
351
|
if (cmp.result.updated.length) lines.push(`更新 (${cmp.result.updated.length}): ${cmp.result.updated.join(', ')}`);
|
|
304
352
|
if (cmp.result.renamed.length) lines.push(`重命名 (${cmp.result.renamed.length}): ${cmp.result.renamed.map((r) => `${r.from}→${r.to}`).join(', ')}`);
|
|
@@ -309,8 +357,8 @@ async function syncCommand({ dest, force, apply, upstreamUrl, ref, json, all })
|
|
|
309
357
|
}
|
|
310
358
|
const { rm } = await import('node:fs/promises');
|
|
311
359
|
await rm(cmp.dest, { recursive: true, force: true });
|
|
312
|
-
const
|
|
313
|
-
if (
|
|
360
|
+
const totalDiff = cmp.result.added.length + cmp.result.updated.length + cmp.result.removed.length + cmp.result.renamed.length;
|
|
361
|
+
if (totalDiff > 0) process.exitCode = 1;
|
|
314
362
|
return;
|
|
315
363
|
}
|
|
316
364
|
|
|
@@ -341,22 +389,16 @@ async function syncCommand({ dest, force, apply, upstreamUrl, ref, json, all })
|
|
|
341
389
|
}
|
|
342
390
|
if (!(await pathExists(marker))) {
|
|
343
391
|
process.stdout.write('未检测到现有项目(AGENTS.md 不存在),将执行全新初始化\n');
|
|
344
|
-
if (onlyProgramming)
|
|
345
|
-
|
|
346
|
-
} else {
|
|
347
|
-
await cp(TEMPLATE_DIR, target, { recursive: true, force: true });
|
|
348
|
-
}
|
|
392
|
+
if (onlyProgramming) await copyTemplateFiltered();
|
|
393
|
+
else await cp(TEMPLATE_DIR, target, { recursive: true, force: true });
|
|
349
394
|
process.stdout.write('模板:已复制(AGENTS.md、.agents/skills、.opencode/、.pi/)\n');
|
|
350
395
|
} else if (force) {
|
|
351
396
|
process.stdout.write('同步:检测到现有项目,将增量更新\n');
|
|
352
397
|
await backupIfExists(path.join(target, 'AGENTS.md'));
|
|
353
|
-
if (onlyProgramming)
|
|
354
|
-
|
|
355
|
-
} else {
|
|
356
|
-
await cp(TEMPLATE_DIR, target, { recursive: true, force: true });
|
|
357
|
-
}
|
|
398
|
+
if (onlyProgramming) await copyTemplateFiltered();
|
|
399
|
+
else await cp(TEMPLATE_DIR, target, { recursive: true, force: true });
|
|
358
400
|
process.stdout.write('模板:已覆盖(AGENTS.md、.agents/skills、.opencode/、.pi/)\n');
|
|
359
|
-
} else
|
|
401
|
+
} else {
|
|
360
402
|
process.stdout.write('同步:检测到现有项目,将增量更新\n');
|
|
361
403
|
let skipAgents = false;
|
|
362
404
|
try {
|
|
@@ -382,21 +424,10 @@ async function syncCommand({ dest, force, apply, upstreamUrl, ref, json, all })
|
|
|
382
424
|
}
|
|
383
425
|
process.stdout.write('模板:已同步(AGENTS.md 跳过,已含定制)\n');
|
|
384
426
|
} else {
|
|
385
|
-
if (onlyProgramming)
|
|
386
|
-
|
|
387
|
-
} else {
|
|
388
|
-
await cp(TEMPLATE_DIR, target, { recursive: true, force: true });
|
|
389
|
-
}
|
|
427
|
+
if (onlyProgramming) await copyTemplateFiltered();
|
|
428
|
+
else await cp(TEMPLATE_DIR, target, { recursive: true, force: true });
|
|
390
429
|
process.stdout.write('模板:已同步(AGENTS.md、.agents/skills、.opencode/、.pi/)\n');
|
|
391
430
|
}
|
|
392
|
-
} else {
|
|
393
|
-
process.stdout.write('同步:检测到现有项目,将增量更新\n');
|
|
394
|
-
if (onlyProgramming) {
|
|
395
|
-
await copyTemplateFiltered();
|
|
396
|
-
} else {
|
|
397
|
-
await cp(TEMPLATE_DIR, target, { recursive: true, force: true });
|
|
398
|
-
}
|
|
399
|
-
process.stdout.write('模板:已同步(AGENTS.md、.agents/skills、.opencode/、.pi/)\n');
|
|
400
431
|
}
|
|
401
432
|
// 技能同步:按编程过滤(默认仅编程,--all 全量)
|
|
402
433
|
const entries = await readdir(SKILLS_DIR, { withFileTypes: true });
|
|
@@ -428,7 +459,7 @@ async function syncCommand({ dest, force, apply, upstreamUrl, ref, json, all })
|
|
|
428
459
|
}
|
|
429
460
|
}
|
|
430
461
|
// --force 时删除多余;仅编程模式下多余指不在编程集合中的,--all 模式下多余指不在全量中的
|
|
431
|
-
//
|
|
462
|
+
// 默认安全增量保留多余(不删除),符合“默认保留、--force 删除”
|
|
432
463
|
if (force) {
|
|
433
464
|
let localEntries = [];
|
|
434
465
|
try {
|
|
@@ -478,25 +509,55 @@ async function syncCommand({ dest, force, apply, upstreamUrl, ref, json, all })
|
|
|
478
509
|
function parseInitArgs(args) {
|
|
479
510
|
let dest;
|
|
480
511
|
let force = false;
|
|
481
|
-
let apply = false;
|
|
482
|
-
let json = false;
|
|
483
512
|
let all = false;
|
|
513
|
+
for (let i = 0; i < args.length; i++) {
|
|
514
|
+
const arg = args[i];
|
|
515
|
+
if (arg === '--dest') {
|
|
516
|
+
if (i + 1 >= args.length || args[i + 1].startsWith('-')) throw new Error(`unknown option '--dest' requires a value`);
|
|
517
|
+
dest = args[++i];
|
|
518
|
+
} else if (arg.startsWith('--dest=')) dest = arg.slice('--dest='.length);
|
|
519
|
+
else if (arg === '--force') force = true;
|
|
520
|
+
else if (arg === '--all') all = true;
|
|
521
|
+
else if (arg === '--help' || arg === '-h') {} // handled at main level, ignore here
|
|
522
|
+
else if (arg.startsWith('-')) throw new Error(`unknown option '${arg}' for command 'init'`);
|
|
523
|
+
else throw new Error(`unknown argument '${arg}' for command 'init'`);
|
|
524
|
+
}
|
|
525
|
+
return { dest, force, all };
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
function parseSyncArgs(args) {
|
|
529
|
+
let dest;
|
|
530
|
+
let force = false;
|
|
531
|
+
let all = false;
|
|
532
|
+
let dryRun = false;
|
|
533
|
+
let json = false;
|
|
484
534
|
let upstreamUrl;
|
|
485
535
|
let ref;
|
|
486
536
|
for (let i = 0; i < args.length; i++) {
|
|
487
537
|
const arg = args[i];
|
|
488
|
-
if (arg === '--dest')
|
|
489
|
-
|
|
538
|
+
if (arg === '--dest') {
|
|
539
|
+
if (i + 1 >= args.length || args[i + 1].startsWith('-')) throw new Error(`unknown option '--dest' requires a value`);
|
|
540
|
+
dest = args[++i];
|
|
541
|
+
} else if (arg.startsWith('--dest=')) dest = arg.slice('--dest='.length);
|
|
490
542
|
else if (arg === '--force') force = true;
|
|
491
|
-
else if (arg === '--apply') apply = true;
|
|
492
543
|
else if (arg === '--all') all = true;
|
|
544
|
+
else if (arg === '--dry-run') dryRun = true;
|
|
493
545
|
else if (arg === '--json') json = true;
|
|
494
|
-
else if (arg === '--upstream')
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
else if (arg.startsWith('--
|
|
546
|
+
else if (arg === '--upstream') {
|
|
547
|
+
if (i + 1 >= args.length || args[i + 1].startsWith('-')) throw new Error(`unknown option '--upstream' requires a value`);
|
|
548
|
+
upstreamUrl = args[++i];
|
|
549
|
+
} else if (arg.startsWith('--upstream=')) upstreamUrl = arg.slice('--upstream='.length);
|
|
550
|
+
else if (arg === '--ref') {
|
|
551
|
+
if (i + 1 >= args.length || args[i + 1].startsWith('-')) throw new Error(`unknown option '--ref' requires a value`);
|
|
552
|
+
ref = args[++i];
|
|
553
|
+
} else if (arg.startsWith('--ref=')) ref = arg.slice('--ref='.length);
|
|
554
|
+
else if (arg === '--help' || arg === '-h') {} // handled at main
|
|
555
|
+
else if (arg === '--apply') {} // deprecated alias, same as default safe incremental
|
|
556
|
+
else if (arg.startsWith('-')) throw new Error(`unknown option '${arg}' for command 'sync'`);
|
|
557
|
+
else throw new Error(`unknown argument '${arg}' for command 'sync'`);
|
|
498
558
|
}
|
|
499
|
-
|
|
559
|
+
if (all && force) throw new Error(`--all and --force are mutually exclusive, choose one`);
|
|
560
|
+
return { dest, force, all, dryRun, json, upstreamUrl, ref };
|
|
500
561
|
}
|
|
501
562
|
|
|
502
563
|
function parseInstallArgs(args) {
|
|
@@ -507,14 +568,21 @@ function parseInstallArgs(args) {
|
|
|
507
568
|
let toolsArg;
|
|
508
569
|
for (let i = 0; i < args.length; i++) {
|
|
509
570
|
const arg = args[i];
|
|
510
|
-
if (arg === '--dest')
|
|
511
|
-
|
|
571
|
+
if (arg === '--dest') {
|
|
572
|
+
if (i + 1 >= args.length || args[i + 1].startsWith('-')) throw new Error(`unknown option '--dest' requires a value`);
|
|
573
|
+
dest = args[++i];
|
|
574
|
+
} else if (arg.startsWith('--dest=')) dest = arg.slice('--dest='.length);
|
|
512
575
|
else if (arg === '--all') all = true;
|
|
513
576
|
else if (arg === '--force') force = true;
|
|
514
|
-
else if (arg === '--tools')
|
|
515
|
-
|
|
577
|
+
else if (arg === '--tools') {
|
|
578
|
+
if (i + 1 >= args.length || args[i + 1].startsWith('-')) throw new Error(`unknown option '--tools' requires a value`);
|
|
579
|
+
toolsArg = args[++i];
|
|
580
|
+
} else if (arg.startsWith('--tools=')) toolsArg = arg.slice('--tools='.length);
|
|
516
581
|
else if (arg === '--global') global = true;
|
|
517
582
|
else if (arg === '--project') global = false;
|
|
583
|
+
else if (arg === '--help' || arg === '-h') {} // handled at main
|
|
584
|
+
else if (arg.startsWith('-')) throw new Error(`unknown option '${arg}' for command 'install'`);
|
|
585
|
+
else throw new Error(`unknown argument '${arg}' for command 'install'`);
|
|
518
586
|
}
|
|
519
587
|
const tools = toolsArg
|
|
520
588
|
? toolsArg.split(',').map((t) => t.trim()).filter(Boolean)
|
|
@@ -559,12 +627,49 @@ async function checkCommand(args) {
|
|
|
559
627
|
|
|
560
628
|
async function main() {
|
|
561
629
|
const args = process.argv.slice(2);
|
|
562
|
-
|
|
563
|
-
|
|
630
|
+
// -v/--version highest priority, anywhere
|
|
631
|
+
if (args.includes('-v') || args.includes('--version')) {
|
|
632
|
+
try {
|
|
633
|
+
const pkgRaw = await readFile(path.join(path.dirname(fileURLToPath(import.meta.url)), '..', 'package.json'), 'utf8');
|
|
634
|
+
const pkg = JSON.parse(pkgRaw);
|
|
635
|
+
process.stdout.write(`${pkg.version}\n`);
|
|
636
|
+
} catch {
|
|
637
|
+
process.stdout.write('unknown\n');
|
|
638
|
+
}
|
|
639
|
+
return;
|
|
640
|
+
}
|
|
641
|
+
// -h/--help suffix handling (global vs per-command)
|
|
642
|
+
if (args.includes('-h') || args.includes('--help')) {
|
|
643
|
+
const known = ['init', 'sync', 'list', 'install', 'check'];
|
|
644
|
+
const first = args[0];
|
|
645
|
+
const cmd = known.includes(first) ? first : null;
|
|
646
|
+
if (cmd === 'init') { process.stdout.write(HELP_INIT); return; }
|
|
647
|
+
if (cmd === 'sync') { process.stdout.write(HELP_SYNC); return; }
|
|
648
|
+
if (cmd === 'list') { process.stdout.write(HELP_LIST); return; }
|
|
649
|
+
if (cmd === 'check') { process.stdout.write(HELP_CHECK); return; }
|
|
650
|
+
if (cmd === 'install') { process.stdout.write(HELP_INSTALL); return; }
|
|
651
|
+
process.stdout.write(HELP_GLOBAL);
|
|
652
|
+
return;
|
|
653
|
+
}
|
|
654
|
+
if (args.length === 0) {
|
|
655
|
+
process.stdout.write(HELP_GLOBAL);
|
|
564
656
|
return;
|
|
565
657
|
}
|
|
566
658
|
const [command, ...rest] = args;
|
|
659
|
+
const knownCommands = new Set(['list', 'init', 'sync', 'install', 'check', 'update']);
|
|
660
|
+
if (!knownCommands.has(command)) {
|
|
661
|
+
process.stderr.write(`error: unknown command '${command}'\n`);
|
|
662
|
+
process.stderr.write(`Run 'matt-skills --help' for usage.\n`);
|
|
663
|
+
process.exitCode = 1;
|
|
664
|
+
return;
|
|
665
|
+
}
|
|
567
666
|
if (command === 'list') {
|
|
667
|
+
// list strict: only --all/--json/--help allowed, rest handled via parse but we keep simple
|
|
668
|
+
for (const a of rest) {
|
|
669
|
+
if (a === '--all' || a === '--json' || a === '--help' || a === '-h') continue;
|
|
670
|
+
if (a.startsWith('-')) { process.stderr.write(`error: unknown option '${a}' for command 'list'\n`); process.stderr.write(`Run 'matt-skills list --help' for usage.\n`); process.exitCode = 1; return; }
|
|
671
|
+
process.stderr.write(`error: unknown argument '${a}' for command 'list'\n`); process.stderr.write(`Run 'matt-skills list --help' for usage.\n`); process.exitCode = 1; return;
|
|
672
|
+
}
|
|
568
673
|
const onlyProgramming = !rest.includes('--all');
|
|
569
674
|
const skills = await listSkills({ onlyProgramming });
|
|
570
675
|
if (rest.includes('--json')) {
|
|
@@ -581,7 +686,7 @@ async function main() {
|
|
|
581
686
|
return;
|
|
582
687
|
}
|
|
583
688
|
if (command === 'sync') {
|
|
584
|
-
await syncCommand(
|
|
689
|
+
await syncCommand(parseSyncArgs(rest));
|
|
585
690
|
return;
|
|
586
691
|
}
|
|
587
692
|
if (command === 'install') {
|
|
@@ -589,16 +694,22 @@ async function main() {
|
|
|
589
694
|
return;
|
|
590
695
|
}
|
|
591
696
|
if (command === 'check') {
|
|
697
|
+
// check strict: allow --all/--json/--upstream/--ref/--help
|
|
698
|
+
for (const a of rest) {
|
|
699
|
+
if (a === '--all' || a === '--json' || a === '--help' || a === '-h') continue;
|
|
700
|
+
if (a === '--upstream' || a.startsWith('--upstream=')) continue;
|
|
701
|
+
if (a === '--ref' || a.startsWith('--ref=')) continue;
|
|
702
|
+
if (a.startsWith('-')) { process.stderr.write(`error: unknown option '${a}' for command 'check'\n`); process.stderr.write(`Run 'matt-skills check --help' for usage.\n`); process.exitCode = 1; return; }
|
|
703
|
+
process.stderr.write(`error: unknown argument '${a}' for command 'check'\n`); process.stderr.write(`Run 'matt-skills check --help' for usage.\n`); process.exitCode = 1; return;
|
|
704
|
+
}
|
|
592
705
|
await checkCommand(rest);
|
|
593
706
|
return;
|
|
594
707
|
}
|
|
595
708
|
if (command === 'update') {
|
|
596
|
-
process.stderr.write('update 已合并到 sync
|
|
709
|
+
process.stderr.write('update 已合并到 sync(默认即增量同步)\n');
|
|
597
710
|
process.exitCode = 1;
|
|
598
711
|
return;
|
|
599
712
|
}
|
|
600
|
-
process.stderr.write(HELP);
|
|
601
|
-
process.exitCode = 1;
|
|
602
713
|
}
|
|
603
714
|
main().catch((error) => {
|
|
604
715
|
process.stderr.write(`error: ${error.message}\n`);
|
package/package.json
CHANGED
|
@@ -17,6 +17,7 @@ description: "Run the pre-commit gate before any commit: verify docs match the i
|
|
|
17
17
|
- 发现不一致 → 先修文档(或更新实现),再进入下一步
|
|
18
18
|
- 改动涉及项目结构、分发文件、技能/命令清单时,检查 README 中对应的结构说明、映射表、清单是否同步
|
|
19
19
|
- 改动涉及用法/CLI/配置/示例时,检查 README 对应描述与实际一致
|
|
20
|
+
- **重点聚焦(README + matt-skills 流程)**:本次门禁优先对齐 `README.md` 与 matt-skills 流程相关文件——`AGENTS.md`(路由)、`CONTEXT.md`(术语)、`docs/agents/*`(`skill-design.md`/`runtime-discipline.md`/`issue-tracker.md`/`triage-labels.md`/`domain.md`)、`template/` 镜像(含 `.agents/skills` 全量、`AGENTS.md`、`CONTEXT.md`、`docs/agents`)、`.agents/skills/*`(技能正文与 `references/`)、`config/*` 与 `scripts/build-template.js`;改动触及上述任一文件时,逐项核对 README 的结构说明/清单/映射表与模板镜像是否同步,未同步先修复再 commit
|
|
20
21
|
- 存在模板镜像/分发副本时,确认源文件与副本同步(如有守护测试,跑一遍确认)
|
|
21
22
|
- **特例**:`AGENTS.md` 的 `tdd-implement ↔ implement` 路由行 + 技能文件 + `.gitignore` 的 `.pi/` 忽略,且存在 `AGENTS.md.bak` 时,视为模板同步预期增量,不回滚
|
|
22
23
|
### ② 保持目录卫生
|