@heihei0299/matt-skills 3.0.14 → 3.0.15

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/README.md CHANGED
@@ -62,7 +62,7 @@ npx @heihei0299/matt-skills sync --all # 同步全部可分发 skills
62
62
  npx @heihei0299/matt-skills sync --dry-run --json
63
63
  ```
64
64
 
65
- `init` 默认保护已有 `AGENTS.md`;需要刷新完整模板时使用 `init --all`。默认 `sync` 保留已有 `AGENTS.md` 和项目规则,`sync --all` 才将其整体刷新为当前分发模板。`sync` 不删除目标项目的额外文件或自定义 skills。
65
+ `init` 对已有 `AGENTS.md` 始终跳过;已有项目使用 `sync`。默认 `sync` 保留已有 `AGENTS.md` 和项目规则,`--all` 只扩大技能范围。需要显式刷新 `AGENTS.md` 时使用 `sync --refresh-agents`;无受管区块时会先备份为 `AGENTS.md.bak`。`sync` 不删除目标项目的额外文件或自定义 skills。
66
66
 
67
67
  默认 programming 范围中的 4 个独有 skills 是 `tdd-implement`、`diagnose-fix`、`grill-to-spec`、`show-me`。
68
68
 
@@ -72,17 +72,19 @@ npx @heihei0299/matt-skills sync --dry-run --json
72
72
  npx @heihei0299/matt-skills list [--all] [--json]
73
73
  npx @heihei0299/matt-skills install [--all] [--tools <list>] [--global] [--dest <dir>]
74
74
  npx @heihei0299/matt-skills init [--all] [--dest <dir>]
75
- npx @heihei0299/matt-skills sync [--all] [--dry-run] [--json] [--dest <dir>]
75
+ npx @heihei0299/matt-skills sync [--all] [--dry-run] [--refresh-agents] [--dest <dir>]
76
76
  npx @heihei0299/matt-skills check [--all] [--json] [--upstream <url>] [--ref <ref>]
77
77
  ```
78
78
 
79
79
  常用选项:
80
80
 
81
- - `--all`:包含全部可分发 skills,默认范围只包含 programming skills。
81
+ - `--all`:包含全部可分发 skills,默认范围只包含 programming skills;不会隐式刷新 `AGENTS.md`。
82
+ - `--refresh-agents`:显式刷新目标 `AGENTS.md`;与 `--all`、`--dry-run` 可组合。
82
83
  - `--dest <dir>`:指定目标目录。
83
84
  - `--tools <list>`:选择 `codex`、`pi`、`opencode` 或 `claude`;项目级 skills 统一写入 `.agents/skills/`,全局安装仍使用各工具目录。
84
85
  - `--global`:写入用户级 skills 目录。
85
- - `--dry-run`:只检查差异,不写入;`--json` 输出机器可读结果。
86
+ - `--dry-run`:预演目标项目差异,不写入;`sync --dry-run --json` 输出机器可读结果。
87
+ - `check --json`:输出上游比较的机器可读结果。普通 `sync --json` 不支持。
86
88
 
87
89
  ## Codex CLI 支持
88
90
 
@@ -100,9 +102,11 @@ CODEX_E2E=1 npm run codex:smoke
100
102
  非独有 skills 来自 [mattpocock/skills](https://github.com/mattpocock/skills)。
101
103
 
102
104
  ```sh
103
- npx @heihei0299/matt-skills sync --dry-run --json # 检查上游差异
104
- npx @heihei0299/matt-skills sync # 同步默认范围
105
- npx @heihei0299/matt-skills sync --all # 同步全部可分发范围
105
+ npx @heihei0299/matt-skills check --json # 检查上游差异
106
+ npx @heihei0299/matt-skills sync --dry-run --json # 预演目标项目变化
107
+ npx @heihei0299/matt-skills sync # 同步默认范围
108
+ npx @heihei0299/matt-skills sync --all # 同步全部可分发范围
109
+ npx @heihei0299/matt-skills sync --refresh-agents # 同步并刷新 AGENTS.md
106
110
  ```
107
111
 
108
112
  ## 发布
package/bin/cli.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { readdir, readFile, writeFile, cp, stat, lstat, rm, mkdir } from 'node:fs/promises';
2
+ import { readdir, readFile, writeFile, cp, stat, lstat, rm, mkdir, mkdtemp } 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';
@@ -39,7 +39,7 @@ const HELP_GLOBAL = `matt-skills — install and manage this skill collection
39
39
 
40
40
  Usage:
41
41
  matt-skills init [options] Initialize a project: template + skills (${PROJECT_SKILL_DIRS})
42
- matt-skills sync [--all|--dry-run] [--dest <path>] Sync existing project to latest template + skills
42
+ matt-skills sync [--all|--dry-run|--refresh-agents] [--dest <path>] Sync existing project to latest template + skills
43
43
  matt-skills list [--all] [--json] List available skills and their descriptions
44
44
  matt-skills install [options] Install skills (interactive by default)
45
45
  matt-skills check [--all] [--json] [--upstream <url>] [--ref <ref>]
@@ -57,7 +57,7 @@ Init options:
57
57
  --dest <path> Target directory (default: current directory)
58
58
  --all Include all distributable skills; default only default programming skills
59
59
  --help, -h Show this help
60
- 提示:已有 AGENTS.md 时普通 init 跳过;显式 init --all 刷新模板并覆盖全量可分发 skills。
60
+ 提示:已有 AGENTS.md 时 init 始终跳过;需要更新已有项目请使用 sync。
61
61
 
62
62
  提示:matt-skills --help 查看全量
63
63
  `;
@@ -65,16 +65,19 @@ Init options:
65
65
  const HELP_SYNC = `matt-skills sync — Sync existing project to latest template + skills
66
66
 
67
67
  Usage:
68
- matt-skills sync [--all|--dry-run] [--dest <path>]
68
+ matt-skills sync [--all|--dry-run|--refresh-agents] [--dest <path>]
69
69
 
70
70
  Sync options:
71
- --all 仅更新同名技能内容(存在则覆盖,不存在则新增)并更新 AGENTS.md
72
- --dry-run 预演:只比对不写盘
73
- --dest <path> Target directory (default: current directory)
74
- --help, -h Show this help
71
+ --all 同步全部可分发技能;不改变 AGENTS.md 刷新策略
72
+ --refresh-agents 显式刷新 AGENTS.md;无受管区块时先备份为 AGENTS.md.bak
73
+ --dry-run 预演目标项目变化,只比对不写盘
74
+ --json 仅与 --dry-run 一起使用,输出机器可读结果
75
+ --dest <path> Target directory (default: current directory)
76
+ --help, -h Show this help
75
77
  项目 skills:${PROJECT_SKILL_DIRS}
76
78
 
77
- 说明:默认不带 --all 增量同步默认 programming skill,并保留现有 AGENTS.md;--all 时同步全部可分发 skill 并强制刷新 AGENTS.md。
79
+ 说明:默认同步默认编程 skill 并保留现有 AGENTS.md;--all 只扩大技能范围。
80
+ --refresh-agents 与 --all、--dry-run 可组合;上游检查请使用 check。
78
81
 
79
82
  提示:matt-skills --help 查看全量
80
83
  `;
@@ -126,6 +129,8 @@ Install options:
126
129
 
127
130
  const HELP = HELP_GLOBAL;
128
131
 
132
+ const DRY_RUN_PATHS = ['AGENTS.md', 'AGENTS.md.bak', '.opencode', '.pi', '.agents/skills', '.claude/skills'];
133
+
129
134
  function parseFrontmatter(text) {
130
135
  const match = text.match(/^---\r?\n([\s\S]*?)\r?\n---/);
131
136
  if (!match) return {};
@@ -377,7 +382,7 @@ async function initCommand({ dest, all }) {
377
382
  const target = dest ? path.resolve(process.cwd(), dest) : process.cwd();
378
383
  const marker = path.join(target, 'AGENTS.md');
379
384
  const onlyProgramming = !all;
380
- if (await pathExists(marker) && !all) {
385
+ if (await pathExists(marker)) {
381
386
  process.stdout.write('模板已存在(AGENTS.md),跳过\n');
382
387
  } else {
383
388
  await cp(TEMPLATE_DIR, target, {
@@ -422,73 +427,124 @@ async function initCommand({ dest, all }) {
422
427
  }
423
428
  process.stdout.write(`目标路径:${target}\n`);
424
429
  }
425
- async function syncCommand({ dest, all, dryRun, json, upstreamUrl, ref }) {
430
+ async function copyDryRunInputs(target, stage) {
431
+ for (const relative of DRY_RUN_PATHS) {
432
+ const source = path.join(target, relative);
433
+ if (!await pathExists(source)) continue;
434
+ const destination = path.join(stage, relative);
435
+ await mkdir(path.dirname(destination), { recursive: true });
436
+ await cp(source, destination, { recursive: true, force: true });
437
+ }
438
+ }
439
+
440
+ async function compareDryRunTrees(target, stage) {
441
+ const result = { added: [], updated: [], removed: [] };
442
+ for (const relative of DRY_RUN_PATHS) {
443
+ const before = path.join(target, relative);
444
+ const after = path.join(stage, relative);
445
+ const beforeExists = await pathExists(before);
446
+ const afterExists = await pathExists(after);
447
+ if (!beforeExists && afterExists) result.added.push(relative);
448
+ else if (beforeExists && !afterExists) result.removed.push(relative);
449
+ else if (beforeExists && afterExists && !await sameTree(before, after)) result.updated.push(relative);
450
+ }
451
+ return result;
452
+ }
453
+
454
+ function formatTargetComparison({ target, result, onlyProgramming, refreshAgents }) {
455
+ const lines = [
456
+ `目标: ${target}`,
457
+ `范围: ${onlyProgramming ? '默认编程' : '全部可分发'}${refreshAgents ? ';刷新 AGENTS.md' : ''}`,
458
+ '',
459
+ ];
460
+ const totalDiff = result.added.length + result.updated.length + result.removed.length;
461
+ if (totalDiff === 0) {
462
+ lines.push('✅ 无需更新');
463
+ return lines.join('\n');
464
+ }
465
+ if (result.added.length) lines.push(`新增 (${result.added.length}): ${result.added.join(', ')}`);
466
+ if (result.updated.length) lines.push(`更新 (${result.updated.length}): ${result.updated.join(', ')}`);
467
+ if (result.removed.length) lines.push(`删除 (${result.removed.length}): ${result.removed.join(', ')}`);
468
+ return lines.join('\n');
469
+ }
470
+
471
+ async function refreshAgentsFile(targetFile) {
472
+ const templateFile = path.join(TEMPLATE_DIR, 'AGENTS.md');
473
+ const current = await readFile(targetFile, 'utf8');
474
+ const template = await readFile(templateFile, 'utf8');
475
+ const merged = mergeManagedAgents(current, template);
476
+ if (merged !== null) {
477
+ if (merged !== current) await writeFile(targetFile, merged);
478
+ return 'managed';
479
+ }
480
+ await cp(targetFile, `${targetFile}.bak`, { force: true });
481
+ await cp(templateFile, targetFile, { force: true });
482
+ return 'full';
483
+ }
484
+
485
+ async function syncCommand({ dest, all, dryRun, json, refreshAgents, quiet = false }) {
426
486
  const onlyProgramming = !all;
487
+ const output = (text) => {
488
+ if (!quiet) process.stdout.write(text);
489
+ };
490
+ if (!dryRun && json) throw new Error('--json 仅支持 sync --dry-run');
427
491
  if (dryRun) {
428
- const { compare, formatComparison } = await import('../scripts/sync-upstream.js');
429
- const cmp = await compare({ upstreamUrl, ref, onlyProgramming });
430
- if (json) {
431
- process.stdout.write(JSON.stringify({ head: cmp.head, counts: cmp.counts, result: cmp.result, onlyProgramming }, null, 2) + '\n');
432
- } else {
433
- process.stdout.write(formatComparison(cmp) + '\n');
492
+ const target = dest ? path.resolve(process.cwd(), dest) : process.cwd();
493
+ const stage = await mkdtemp(path.join(os.tmpdir(), 'matt-skills-sync-dry-run-'));
494
+ try {
495
+ await copyDryRunInputs(target, stage);
496
+ await syncCommand({ dest: stage, all, dryRun: false, json: false, refreshAgents, quiet: true });
497
+ const result = await compareDryRunTrees(target, stage);
498
+ const payload = { target, result, onlyProgramming, refreshAgents };
499
+ if (json) output(`${JSON.stringify(payload, null, 2)}\n`);
500
+ else output(`${formatTargetComparison(payload)}\n`);
501
+ const totalDiff = result.added.length + result.updated.length + result.removed.length;
502
+ if (totalDiff > 0) process.exitCode = 1;
503
+ } finally {
504
+ await rm(stage, { recursive: true, force: true });
434
505
  }
435
- const { rm } = await import('node:fs/promises');
436
- await rm(cmp.dest, { recursive: true, force: true });
437
- const totalDiff = cmp.result.added.length + cmp.result.updated.length + cmp.result.removed.length + cmp.result.renamed.length;
438
- if (totalDiff > 0) process.exitCode = 1;
439
506
  return;
440
507
  }
441
508
 
442
509
  const target = dest ? path.resolve(process.cwd(), dest) : process.cwd();
443
510
  const marker = path.join(target, 'AGENTS.md');
444
- // 模板同步:默认模式下过滤 skills,仅同步默认子集
445
511
  async function copyTemplateFiltered() {
446
- if (!onlyProgramming) {
447
- await cp(TEMPLATE_DIR, target, {
448
- recursive: true,
449
- force: true,
450
- filter: shouldCopyTemplatePath,
451
- });
452
- return;
453
- }
454
- // Skeleton only; shared Skills are copied from the canonical source below.
455
- await cp(path.join(TEMPLATE_DIR, 'AGENTS.md'), path.join(target, 'AGENTS.md'), { force: true });
456
- await cp(path.join(TEMPLATE_DIR, '.opencode'), path.join(target, '.opencode'), { recursive: true, force: true });
457
- await cp(path.join(TEMPLATE_DIR, '.pi'), path.join(target, '.pi'), { recursive: true, force: true });
458
- }
459
- if (!(await pathExists(marker))) {
460
- process.stdout.write('未检测到现有项目(AGENTS.md 不存在),将执行全新初始化\n');
461
- if (onlyProgramming) await copyTemplateFiltered();
462
- else await cp(TEMPLATE_DIR, target, {
512
+ await cp(TEMPLATE_DIR, target, {
463
513
  recursive: true,
464
514
  force: true,
465
515
  filter: shouldCopyTemplatePath,
466
516
  });
467
- process.stdout.write(`模板:已复制(AGENTS.md、skills:${PROJECT_SKILL_DIRS})\n`);
517
+ }
518
+ if (!(await pathExists(marker))) {
519
+ output('未检测到现有项目(AGENTS.md 不存在),将执行全新初始化\n');
520
+ await copyTemplateFiltered();
521
+ output(`模板:已复制(AGENTS.md、skills:${PROJECT_SKILL_DIRS})\n`);
468
522
  } else {
469
- process.stdout.write('同步:检测到现有项目,将增量更新\n');
470
- if (all) {
471
- await cp(TEMPLATE_DIR, target, {
472
- recursive: true,
473
- force: true,
474
- filter: shouldCopyTemplatePath,
475
- });
476
- process.stdout.write(`模板:已同步(AGENTS.md 整体刷新、skills:${PROJECT_SKILL_DIRS})\n`);
523
+ output('同步:检测到现有项目,将增量更新\n');
524
+ let agentsManaged = false;
525
+ let agentsRefreshed = false;
526
+ let agentsRefreshMode = null;
527
+ if (refreshAgents) {
528
+ agentsRefreshMode = await refreshAgentsFile(marker);
529
+ agentsRefreshed = true;
477
530
  } else {
478
- let agentsManaged = false;
479
531
  try {
480
532
  agentsManaged = await syncManagedAgents(marker);
481
533
  } catch {}
482
- await cp(path.join(TEMPLATE_DIR, '.opencode'), path.join(target, '.opencode'), { recursive: true, force: true });
483
- await cp(path.join(TEMPLATE_DIR, '.pi'), path.join(target, '.pi'), { recursive: true, force: true });
484
- if (agentsManaged) {
485
- process.stdout.write(`模板:已同步(AGENTS.md 受管区块已更新、skills:${PROJECT_SKILL_DIRS},项目自定义内容已保留)\n`);
486
- } else {
487
- process.stdout.write(`模板:已同步(AGENTS.md 未受管、skills:${PROJECT_SKILL_DIRS},已原样保留)\n`);
488
- }
534
+ }
535
+ await cp(path.join(TEMPLATE_DIR, '.opencode'), path.join(target, '.opencode'), { recursive: true, force: true });
536
+ await cp(path.join(TEMPLATE_DIR, '.pi'), path.join(target, '.pi'), { recursive: true, force: true });
537
+ if (agentsRefreshed && agentsRefreshMode === 'managed') {
538
+ output(`模板:已同步(AGENTS.md 受管区块已刷新、skills:${PROJECT_SKILL_DIRS},项目自定义内容已保留)\n`);
539
+ } else if (agentsRefreshed) {
540
+ output(`模板:已同步(AGENTS.md 已刷新,旧文件备份为 AGENTS.md.bak、skills:${PROJECT_SKILL_DIRS})\n`);
541
+ } else if (agentsManaged) {
542
+ output(`模板:已同步(AGENTS.md 受管区块已更新、skills:${PROJECT_SKILL_DIRS},项目自定义内容已保留)\n`);
543
+ } else {
544
+ output(`模板:已同步(AGENTS.md 未受管、skills:${PROJECT_SKILL_DIRS},已原样保留)\n`);
489
545
  }
490
546
  }
491
- // 技能同步:--all 仅更新同名可分发技能内容,存在则覆盖,不存在则新增,并更新 AGENTS.md(由上一步已处理);默认范围为默认 programming,不删多余
547
+ // --all 只扩大技能范围;同名覆盖、不存在新增,不删除目标中的额外技能。
492
548
  const allSkills = await listSkillNames({ onlyProgramming });
493
549
  const skillTargets = projectSkillTargets(target);
494
550
  const skillsDir = path.resolve(target, PROJECT_DIRS.codex);
@@ -569,20 +625,19 @@ async function syncCommand({ dest, all, dryRun, json, upstreamUrl, ref }) {
569
625
  if (await pathExists(piSettings)) {
570
626
  const txt = await readFile(piSettings, 'utf8');
571
627
  if (txt.includes('.opencode/skills') || txt.includes('../.opencode')) {
572
- const { writeFile } = await import('node:fs/promises');
573
628
  await writeFile(piSettings, '{}\n');
574
629
  }
575
630
  }
576
631
  } catch {}
577
632
  if (cleanedLegacy.length) {
578
- process.stdout.write(`迁移清理:${cleanedLegacy.join(', ')} 旧共享副本已移除\n`);
633
+ output(`迁移清理:${cleanedLegacy.join(', ')} 旧共享副本已移除\n`);
579
634
  }
580
635
  if (preservedRepoLocal.length) {
581
- process.stdout.write(`迁移提示:${preservedRepoLocal.join(', ')} 已不再分发,现有副本已保留\n`);
636
+ output(`迁移提示:${preservedRepoLocal.join(', ')} 已不再分发,现有副本已保留\n`);
582
637
  }
583
638
  const modeLabel = onlyProgramming ? '默认编程' : '全部可分发';
584
- process.stdout.write(`技能:新增 ${installed}、更新 ${updated}(${modeLabel} ${allSkills.length})\n`);
585
- process.stdout.write(`目标路径:${target}\n`);
639
+ output(`技能:新增 ${installed}、更新 ${updated}(${modeLabel} ${allSkills.length})\n`);
640
+ output(`目标路径:${target}\n`);
586
641
  }
587
642
 
588
643
  function parseInitArgs(args) {
@@ -607,8 +662,7 @@ function parseSyncArgs(args) {
607
662
  let all = false;
608
663
  let dryRun = false;
609
664
  let json = false;
610
- let upstreamUrl;
611
- let ref;
665
+ let refreshAgents = false;
612
666
  for (let i = 0; i < args.length; i++) {
613
667
  const arg = args[i];
614
668
  if (arg === '--dest') {
@@ -618,20 +672,13 @@ function parseSyncArgs(args) {
618
672
  else if (arg === '--all') all = true;
619
673
  else if (arg === '--dry-run') dryRun = true;
620
674
  else if (arg === '--json') json = true;
621
- else if (arg === '--upstream') {
622
- if (i + 1 >= args.length || args[i + 1].startsWith('-')) throw new Error(`unknown option '--upstream' requires a value`);
623
- upstreamUrl = args[++i];
624
- } else if (arg.startsWith('--upstream=')) upstreamUrl = arg.slice('--upstream='.length);
625
- else if (arg === '--ref') {
626
- if (i + 1 >= args.length || args[i + 1].startsWith('-')) throw new Error(`unknown option '--ref' requires a value`);
627
- ref = args[++i];
628
- } else if (arg.startsWith('--ref=')) ref = arg.slice('--ref='.length);
675
+ else if (arg === '--refresh-agents') refreshAgents = true;
629
676
  else if (arg === '--help' || arg === '-h') {} // handled at main
630
677
  else if (arg === '--apply') {} // deprecated alias, same as default safe incremental
631
678
  else if (arg.startsWith('-')) throw new Error(`unknown option '${arg}' for command 'sync'`);
632
679
  else throw new Error(`unknown argument '${arg}' for command 'sync'`);
633
680
  }
634
- return { dest, all, dryRun, json, upstreamUrl, ref };
681
+ return { dest, all, dryRun, json, refreshAgents };
635
682
  }
636
683
 
637
684
  function parseInstallArgs(args) {
@@ -721,15 +768,15 @@ async function main() {
721
768
  if (!knownCommands.has(command)) {
722
769
  process.stderr.write(`error: unknown command '${command}'\n`);
723
770
  process.stderr.write(`Run 'matt-skills --help' for usage.\n`);
724
- process.exitCode = 1;
771
+ process.exitCode = 2;
725
772
  return;
726
773
  }
727
774
  if (command === 'list') {
728
775
  // list strict: only --all/--json/--help allowed, rest handled via parse but we keep simple
729
776
  for (const a of rest) {
730
777
  if (a === '--all' || a === '--json' || a === '--help' || a === '-h') continue;
731
- 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; }
732
- 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;
778
+ 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 = 2; return; }
779
+ process.stderr.write(`error: unknown argument '${a}' for command 'list'\n`); process.stderr.write(`Run 'matt-skills list --help' for usage.\n`); process.exitCode = 2; return;
733
780
  }
734
781
  const onlyProgramming = !rest.includes('--all');
735
782
  const skills = await listSkills({ onlyProgramming });
@@ -759,21 +806,30 @@ async function main() {
759
806
  for (let i = 0; i < rest.length; i++) {
760
807
  const a = rest[i];
761
808
  if (a === '--all' || a === '--json' || a === '--help' || a === '-h') continue;
762
- if (a === '--upstream' || a === '--ref') { i++; continue; }
809
+ if (a === '--upstream' || a === '--ref') {
810
+ if (i + 1 >= rest.length || rest[i + 1].startsWith('-')) {
811
+ process.stderr.write(`error: option '${a}' for command 'check' requires a value\n`);
812
+ process.stderr.write(`Run 'matt-skills check --help' for usage.\n`);
813
+ process.exitCode = 2;
814
+ return;
815
+ }
816
+ i++;
817
+ continue;
818
+ }
763
819
  if (a.startsWith('--upstream=') || a.startsWith('--ref=')) continue;
764
- 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; }
765
- 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;
820
+ 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 = 2; return; }
821
+ process.stderr.write(`error: unknown argument '${a}' for command 'check'\n`); process.stderr.write(`Run 'matt-skills check --help' for usage.\n`); process.exitCode = 2; return;
766
822
  }
767
823
  await checkCommand(rest);
768
824
  return;
769
825
  }
770
826
  if (command === 'update') {
771
827
  process.stderr.write('update 已合并到 sync(默认即增量同步)\n');
772
- process.exitCode = 1;
828
+ process.exitCode = 2;
773
829
  return;
774
830
  }
775
831
  }
776
832
  main().catch((error) => {
777
833
  process.stderr.write(`error: ${error.message}\n`);
778
- process.exitCode = 1;
834
+ process.exitCode = 2;
779
835
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@heihei0299/matt-skills",
3
- "version": "3.0.14",
3
+ "version": "3.0.15",
4
4
  "description": "Agent skills + 项目配置模板:一条命令初始化 opencode / pi-agent 项目(含 mattpocock/skills 上游技能)",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,3 +1,4 @@
1
+ <!-- matt-skills:managed:start -->
1
2
  # AGENTS.md
2
3
 
3
4
  ## Workflow
@@ -75,3 +76,4 @@ codegraph node "<符号>"
75
76
  ## Completion
76
77
 
77
78
  完成时说明改动或审查结论、已执行验证、未执行验证及原因、剩余风险;如有 commit,报告 commit hash。
79
+ <!-- matt-skills:managed:end -->