agentic-flow-kit 1.7.15 → 1.8.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.
Files changed (206) hide show
  1. package/README.md +50 -8
  2. package/modules/hosts/claude/commands/wf-build.md +1 -1
  3. package/modules/hosts/claude/commands/wf-design.md +5 -4
  4. package/modules/hosts/claude/commands/wf-maintain.md +1 -1
  5. package/modules/hosts/claude/commands/wf-new-task.md +47 -25
  6. package/modules/hosts/claude/commands/wf-plan.md +1 -1
  7. package/modules/hosts/claude/commands/wf-review.md +2 -2
  8. package/modules/hosts/claude/commands/wf-sync-hosts.md +7 -13
  9. package/modules/hosts/claude/commands/wf-test.md +2 -2
  10. package/modules/hosts/codex/commands/wf-build.md +1 -1
  11. package/modules/hosts/codex/commands/wf-design.md +5 -4
  12. package/modules/hosts/codex/commands/wf-maintain.md +1 -1
  13. package/modules/hosts/codex/commands/wf-new-task.md +47 -25
  14. package/modules/hosts/codex/commands/wf-plan.md +1 -1
  15. package/modules/hosts/codex/commands/wf-review.md +2 -2
  16. package/modules/hosts/codex/commands/wf-sync-hosts.md +7 -13
  17. package/modules/hosts/codex/commands/wf-test.md +2 -2
  18. package/modules/hosts/cursor/commands/wf-build.md +1 -1
  19. package/modules/hosts/cursor/commands/wf-design.md +5 -4
  20. package/modules/hosts/cursor/commands/wf-maintain.md +1 -1
  21. package/modules/hosts/cursor/commands/wf-new-task.md +47 -25
  22. package/modules/hosts/cursor/commands/wf-plan.md +1 -1
  23. package/modules/hosts/cursor/commands/wf-review.md +2 -2
  24. package/modules/hosts/cursor/commands/wf-sync-hosts.md +7 -13
  25. package/modules/hosts/cursor/commands/wf-test.md +2 -2
  26. package/modules/hosts/opencode/commands/wf-build.md +1 -1
  27. package/modules/hosts/opencode/commands/wf-design.md +5 -4
  28. package/modules/hosts/opencode/commands/wf-maintain.md +1 -1
  29. package/modules/hosts/opencode/commands/wf-new-task.md +47 -25
  30. package/modules/hosts/opencode/commands/wf-plan.md +1 -1
  31. package/modules/hosts/opencode/commands/wf-review.md +2 -2
  32. package/modules/hosts/opencode/commands/wf-sync-hosts.md +7 -13
  33. package/modules/hosts/opencode/commands/wf-test.md +2 -2
  34. package/modules/hosts/trae/commands/wf-build.md +1 -1
  35. package/modules/hosts/trae/commands/wf-design.md +5 -4
  36. package/modules/hosts/trae/commands/wf-maintain.md +1 -1
  37. package/modules/hosts/trae/commands/wf-new-task.md +47 -25
  38. package/modules/hosts/trae/commands/wf-plan.md +1 -1
  39. package/modules/hosts/trae/commands/wf-review.md +2 -2
  40. package/modules/hosts/trae/commands/wf-sync-hosts.md +7 -13
  41. package/modules/hosts/trae/commands/wf-test.md +2 -2
  42. package/package.json +1 -1
  43. package/src/cli.mjs +47 -4
  44. package/src/doctor.mjs +48 -3
  45. package/src/executor.mjs +262 -0
  46. package/src/executor.test.mjs +295 -0
  47. package/src/fresh-init.test.mjs +1 -1
  48. package/src/init.mjs +27 -3
  49. package/src/profiles.mjs +10 -3
  50. package/src/render.mjs +3 -3
  51. package/src/rule-budget.test.mjs +2 -2
  52. package/src/stack-profile.test.mjs +6 -0
  53. package/src/sync-hosts.mjs +37 -43
  54. package/src/sync-hosts.test.mjs +67 -56
  55. package/src/validate.mjs +6 -1
  56. package/src/validate.test.mjs +1 -1
  57. package/templates/.gitattributes +12 -1
  58. package/templates/AGENTS.md +3 -3
  59. package/templates/_agents/commands/build.md +1 -1
  60. package/templates/_agents/commands/design.md +5 -4
  61. package/templates/_agents/commands/maintain.md +1 -1
  62. package/templates/_agents/commands/new-task.md +47 -25
  63. package/templates/_agents/commands/plan.md +1 -1
  64. package/templates/_agents/commands/review.md +2 -2
  65. package/templates/_agents/commands/sync-hosts.md +7 -13
  66. package/templates/_agents/commands/test.md +2 -2
  67. package/templates/_agents/control-surfaces.txt +1 -1
  68. package/templates/_agents/engine-lock.json +334 -0
  69. package/templates/_agents/hooks/check-index-incremental.mjs +48 -0
  70. package/templates/_agents/hooks/check-pairing-incremental.mjs +66 -0
  71. package/templates/_agents/hooks/check-wiki-ledger.mjs +30 -0
  72. package/templates/_agents/lane-surfaces.txt +5 -2
  73. package/templates/_agents/level-hints.txt +30 -0
  74. package/templates/_agents/loop/papercut-debt/DESIGN.md +112 -0
  75. package/templates/_agents/mechanism-registry.md +27 -0
  76. package/templates/_agents/rule-budgets.txt +2 -2
  77. package/templates/_agents/scripts/agg-delegations.cjs +21 -3
  78. package/templates/_agents/scripts/agg-delegations.test.mjs +5 -3
  79. package/templates/_agents/scripts/agg-gate-stats.mjs +3 -3
  80. package/templates/_agents/scripts/agg-judgments.mjs +80 -0
  81. package/templates/_agents/scripts/agg-judgments.test.mjs +45 -0
  82. package/templates/_agents/scripts/archive-sweep.mjs +233 -0
  83. package/templates/_agents/scripts/archive-sweep.test.mjs +129 -0
  84. package/templates/_agents/scripts/check-attribution.mjs +37 -0
  85. package/templates/_agents/scripts/check-convergence.mjs +119 -0
  86. package/templates/_agents/scripts/check-engine-integrity.mjs +59 -127
  87. package/templates/_agents/scripts/check-engine-integrity.test.mjs +33 -45
  88. package/templates/_agents/scripts/check-funnel.mjs +56 -0
  89. package/templates/_agents/scripts/check-hygiene.mjs +5 -5
  90. package/templates/_agents/scripts/check-index-incremental.test.mjs +73 -0
  91. package/templates/_agents/scripts/check-lane-surface.mjs +74 -25
  92. package/templates/_agents/scripts/check-lane-surface.test.mjs +71 -5
  93. package/templates/_agents/scripts/check-ledger-invariant.mjs +427 -78
  94. package/templates/_agents/scripts/check-ledger-invariant.test.mjs +438 -4
  95. package/templates/_agents/scripts/check-loop-rev.test.mjs +13 -8
  96. package/templates/_agents/scripts/check-loop-unit.test.mjs +8 -0
  97. package/templates/_agents/scripts/check-loop.mjs +264 -75
  98. package/templates/_agents/scripts/check-loop.test.mjs +587 -61
  99. package/templates/_agents/scripts/check-metric-claims.mjs +4 -2
  100. package/templates/_agents/scripts/check-prejudgment.mjs +59 -0
  101. package/templates/_agents/scripts/check-registry.mjs +45 -0
  102. package/templates/_agents/scripts/check-scope.mjs +96 -0
  103. package/templates/_agents/scripts/check-scope.test.mjs +96 -0
  104. package/templates/_agents/scripts/check-scripts-syntax.mjs +61 -0
  105. package/templates/_agents/scripts/check-scripts-syntax.test.mjs +72 -0
  106. package/templates/_agents/scripts/check-spec-verif.mjs +47 -0
  107. package/templates/_agents/scripts/compact-ledgers.mjs +97 -0
  108. package/templates/_agents/scripts/compact-ledgers.test.mjs +162 -0
  109. package/templates/_agents/scripts/confirm-doc.mjs +136 -31
  110. package/templates/_agents/scripts/confirm-doc.test.mjs +180 -4
  111. package/templates/_agents/scripts/doctor.test.mjs +44 -1
  112. package/templates/_agents/scripts/edit-face-check.mjs +5 -3
  113. package/templates/_agents/scripts/edit-face-check.test.mjs +5 -4
  114. package/templates/_agents/scripts/fill-intent.mjs +7 -5
  115. package/templates/_agents/scripts/fill-intent.test.mjs +19 -1
  116. package/templates/_agents/scripts/fill-plan.mjs +10 -6
  117. package/templates/_agents/scripts/fill-plan.test.mjs +19 -3
  118. package/templates/_agents/scripts/fill-spec.mjs +6 -3
  119. package/templates/_agents/scripts/fill-spec.test.mjs +12 -4
  120. package/templates/_agents/scripts/fixture-scripts.mjs +153 -0
  121. package/templates/_agents/scripts/fixture-scripts.test.mjs +112 -0
  122. package/templates/_agents/scripts/gate-checklist.mjs +10 -9
  123. package/templates/_agents/scripts/gate-checklist.test.mjs +2 -11
  124. package/templates/_agents/scripts/gate-seg.mjs +1 -1
  125. package/templates/_agents/scripts/gen-effective-policy.mjs +107 -0
  126. package/templates/_agents/scripts/gen-effective-policy.test.mjs +100 -0
  127. package/templates/_agents/scripts/gen-verify-evidence.mjs +107 -0
  128. package/templates/_agents/scripts/gen-verify-evidence.test.mjs +84 -0
  129. package/templates/_agents/scripts/gen-workflow-dashboard.mjs +16 -14
  130. package/templates/_agents/scripts/gen-workflow-dashboard.test.mjs +2 -1
  131. package/templates/_agents/scripts/gen-workflow-metrics.mjs +12 -36
  132. package/templates/_agents/scripts/git-core.mjs +45 -0
  133. package/templates/_agents/scripts/git-merge-jsonl.mjs +63 -0
  134. package/templates/_agents/scripts/git-merge-jsonl.test.mjs +125 -0
  135. package/templates/_agents/scripts/judgment-ledger.mjs +65 -0
  136. package/templates/_agents/scripts/judgment-ledger.test.mjs +129 -0
  137. package/templates/_agents/scripts/kb-search.mjs +19 -4
  138. package/templates/_agents/scripts/kb-search.test.mjs +33 -0
  139. package/templates/_agents/scripts/lane-surface-audit.mjs +143 -0
  140. package/templates/_agents/scripts/lane-surface-audit.test.mjs +93 -0
  141. package/templates/_agents/scripts/ledger-doc-chain.test.mjs +166 -0
  142. package/templates/_agents/scripts/ledger-loader.mjs +108 -0
  143. package/templates/_agents/scripts/ledger-loader.test.mjs +131 -0
  144. package/templates/_agents/scripts/ledger-prune.mjs +96 -0
  145. package/templates/_agents/scripts/ledger-prune.test.mjs +120 -0
  146. package/templates/_agents/scripts/ledger-shards.mjs +307 -0
  147. package/templates/_agents/scripts/ledger-shards.test.mjs +339 -0
  148. package/templates/_agents/scripts/ledger-ts-monotonic.test.mjs +135 -0
  149. package/templates/_agents/scripts/level-criteria.mjs +231 -0
  150. package/templates/_agents/scripts/level-criteria.test.mjs +281 -0
  151. package/templates/_agents/scripts/papercut-debt-controller.mjs +141 -0
  152. package/templates/_agents/scripts/papercut-debt-controller.test.mjs +127 -0
  153. package/templates/_agents/scripts/papercut-debt-sensor.mjs +170 -0
  154. package/templates/_agents/scripts/papercut-debt-sensor.test.mjs +146 -0
  155. package/templates/_agents/scripts/pipeline-run.mjs +10 -24
  156. package/templates/_agents/scripts/pipeline-run.test.mjs +22 -42
  157. package/templates/_agents/scripts/policy.mjs +75 -0
  158. package/templates/_agents/scripts/resolve-merge-conflicts.mjs +110 -0
  159. package/templates/_agents/scripts/resolve-merge-conflicts.test.mjs +87 -0
  160. package/templates/_agents/scripts/rewrite-file.mjs +133 -0
  161. package/templates/_agents/scripts/rewrite-file.test.mjs +148 -0
  162. package/templates/_agents/scripts/rule-budget.mjs +83 -0
  163. package/templates/_agents/scripts/run-tests.mjs +99 -0
  164. package/templates/_agents/scripts/run-tests.test.mjs +105 -0
  165. package/templates/_agents/scripts/solidify-task.test.mjs +1 -1
  166. package/templates/_agents/scripts/stage-gates.mjs +38 -21
  167. package/templates/_agents/scripts/trust-mode.mjs +4 -4
  168. package/templates/_agents/scripts/trust-mode.test.mjs +1 -1
  169. package/templates/_agents/scripts/verify.mjs +135 -58
  170. package/templates/_agents/scripts/verify.test.mjs +156 -47
  171. package/templates/_agents/scripts/wf-journal.mjs +8 -4
  172. package/templates/_agents/scripts/wf-journal.test.mjs +1 -1
  173. package/templates/_agents/scripts/wiki-search.test.mjs +5 -6
  174. package/templates/_agents/scripts/workflow-board-server.test.mjs +2 -2
  175. package/templates/_agents/scripts/workflow-enums.test.mjs +14 -5
  176. package/templates/_agents/scripts/workflows-check.mjs +1 -1
  177. package/templates/_agents/scripts-test-exempt.txt +1 -0
  178. package/templates/_agents/skills/papercut-fix/SKILL.md +60 -0
  179. package/templates/_agents/skills/papercut-fix/references/response-template.md +81 -0
  180. package/templates/_agents/workflow-enums.txt +8 -1
  181. package/templates/_agents/workflows/pipeline-closing.md +4 -5
  182. package/templates/_githooks/pre-commit +109 -120
  183. package/templates/_githooks/pre-merge-commit +27 -23
  184. package/templates/_githooks/pre-push +7 -6
  185. package/templates/_github/workflows/kit-ci.yml +4 -3
  186. package/templates/workflow/README.md +23 -5
  187. package/templates/workflow/incidents/_TEMPLATE.md +4 -1
  188. package/templates/workflow/intents/_TEMPLATE.md +4 -2
  189. package/templates/workflow/papercuts.md +2 -0
  190. package/templates/workflow/plans/_TEMPLATE.md +10 -5
  191. package/templates/workflow/regression-checklist.md +1 -0
  192. package/templates/workflow/specs/_TEMPLATE.md +17 -1
  193. package/modules/hosts/claude/commands/wf-source-sync-check.md +0 -89
  194. package/modules/hosts/codex/commands/wf-source-sync-check.md +0 -89
  195. package/modules/hosts/cursor/commands/wf-source-sync-check.md +0 -89
  196. package/modules/hosts/opencode/commands/wf-source-sync-check.md +0 -89
  197. package/modules/hosts/trae/commands/wf-source-sync-check.md +0 -90
  198. package/templates/_agents/commands/source-sync-check.md +0 -103
  199. package/templates/_agents/hooks/check-pairing-incremental.sh +0 -43
  200. package/templates/_agents/hooks/check-wiki-ledger.sh +0 -18
  201. package/templates/_agents/scripts/check-ledger.mjs +0 -109
  202. package/templates/_agents/scripts/check-ledger.test.mjs +0 -199
  203. package/templates/_agents/scripts/rule-budget.sh +0 -74
  204. package/templates/_agents/scripts/source-sync-check.mjs +0 -156
  205. package/templates/_agents/scripts/source-sync-check.test.mjs +0 -286
  206. package/templates/_agents/workflows/source-sync-repair.md +0 -30
@@ -1,286 +0,0 @@
1
- // source-sync-check.test.mjs — 装户面同步一致性检查工具测试(2026-09-25 source-sync-check)
2
- // 方法:fixture mini 包源(templates/_agents/) + 装副本(.agents/),调 sourceSyncCheck() 拿三类差异
3
- // + 实际仓库扫描做 baseline
4
- // 判据:①fixture 三类齐全 ②cache/ 排除 ③kit.json/settings.json 排除 ④sha 一致 ⑤baseline ≥ 100 ⑥JSON 可解析
5
- // 用法:node .agents/scripts/source-sync-check.test.mjs
6
- import fs from 'node:fs';
7
- import path from 'node:path';
8
- import os from 'node:os';
9
- import { spawnSync } from 'node:child_process';
10
- import { fileURLToPath } from 'node:url';
11
- import { sourceSyncCheck } from './source-sync-check.mjs';
12
-
13
- let pass = 0, failCount = 0;
14
- function check(name, cond, detail = '') {
15
- if (cond) { pass++; console.log('PASS ' + name); }
16
- else { failCount++; console.log('FAIL ' + name + (detail ? '——' + detail : '')); }
17
- }
18
-
19
- // SRC_ROOT:自测试文件位置向上探测包源(templates/_agents)——包源路径(templates/_agents/scripts/)与
20
- // 装副本路径(.agents/scripts/)直跑都解析到仓库根;无包源(装户环境)返回 null,S5/S9 baseline 记 SKIP
21
- // 不算失败(2026-09-27 gate-hardening-p2-batch:旧 `../../..` 硬编码层级从装副本直跑必 FAIL)
22
- const findSrcRoot = () => {
23
- let d = path.dirname(fileURLToPath(import.meta.url));
24
- for (let i = 0; i < 5; i++) {
25
- if (fs.existsSync(path.join(d, 'templates', '_agents'))) return d;
26
- d = path.dirname(d);
27
- }
28
- return null;
29
- };
30
- const SRC_ROOT = findSrcRoot();
31
- const SCRIPT = path.join(path.dirname(fileURLToPath(import.meta.url)), 'source-sync-check.mjs');
32
- const runGate = (args) => spawnSync(process.execPath, [SCRIPT, ...args], { encoding: 'utf8' });
33
-
34
- // ---- fixture:mini 包源 + 装副本,3 类差异各造 1 个 ----
35
- function mkFixture() {
36
- const root = fs.mkdtempSync(path.join(os.tmpdir(), 'fk-ssc-'));
37
- const pkgRoot = path.join(root, 'pkg');
38
- const target = path.join(root, 'target');
39
- const pkgBase = path.join(pkgRoot, 'templates', '_agents');
40
- const tgtBase = path.join(target, '.agents');
41
- fs.mkdirSync(path.join(pkgBase, 'commands'), { recursive: true });
42
- fs.mkdirSync(path.join(pkgBase, 'scripts'), { recursive: true });
43
- fs.mkdirSync(path.join(pkgBase, 'cache'), { recursive: true }); // 应排除
44
- fs.mkdirSync(path.join(tgtBase, 'commands'), { recursive: true });
45
- fs.mkdirSync(path.join(tgtBase, 'scripts'), { recursive: true });
46
- fs.mkdirSync(path.join(tgtBase, 'hooks'), { recursive: true }); // 孤儿
47
- fs.mkdirSync(path.join(tgtBase, 'cache'), { recursive: true }); // 装副本 cache 也应排除
48
- // 一致文件(cmdA.md):包源 + 装副本 同内容
49
- fs.writeFileSync(path.join(pkgBase, 'commands', 'cmdA.md'), '# cmdA v1\n');
50
- fs.writeFileSync(path.join(tgtBase, 'commands', 'cmdA.md'), '# cmdA v1\n');
51
- // 缺失(cmdB.md):包源有 / 装副本无
52
- fs.writeFileSync(path.join(pkgBase, 'commands', 'cmdB.md'), '# cmdB v1\n');
53
- // 孤儿(orphan-real.json):装副本 hooks/ 有 / 包源无(普通孤儿,应被报告)
54
- fs.writeFileSync(path.join(tgtBase, 'hooks', 'orphan-real.json'), '{}\n');
55
- // 白名单孤儿(commit-check.config.json):装副本 hooks/ 有 / 包源无,但 init 渲染产物不应报孤儿
56
- fs.writeFileSync(path.join(tgtBase, 'hooks', 'commit-check.config.json'), '{}\n');
57
- // 装副本独有(应排除):kit.json / settings.json
58
- fs.writeFileSync(path.join(tgtBase, 'kit.json'), '{}\n');
59
- fs.writeFileSync(path.join(tgtBase, 'settings.json'), '{}\n');
60
- // 漂移(scriptX.mjs):包源 v1 / 装副本 v2
61
- fs.writeFileSync(path.join(pkgBase, 'scripts', 'scriptX.mjs'), 'export const X = 1;\n');
62
- fs.writeFileSync(path.join(tgtBase, 'scripts', 'scriptX.mjs'), 'export const X = 2;\n');
63
- // cache/ 排除:包源 + 装副本 都有,但不应被计入
64
- fs.writeFileSync(path.join(pkgBase, 'cache', 'foo.md'), 'cache-pkg\n');
65
- fs.writeFileSync(path.join(tgtBase, 'cache', 'foo.md'), 'cache-tgt\n');
66
- return { pkgRoot, target };
67
- }
68
-
69
- // ---- 场景 1:fixture 三类差异齐全(缺失 1 / 孤儿 1 / 漂移 1)----
70
- {
71
- const { pkgRoot, target } = mkFixture();
72
- const r = sourceSyncCheck({ pkgRoot, target });
73
- check('S1 fixture 缺失 1(cmdB.md)', r.missing.length === 1 && r.missing[0].rel === 'commands/cmdB.md', JSON.stringify(r.missing));
74
- check('S1 fixture 孤儿 1(orphan-real.json)', r.orphan.length === 1 && r.orphan[0].rel === 'hooks/orphan-real.json', JSON.stringify(r.orphan));
75
- check('S1 fixture 漂移 1(scriptX.mjs)', r.drift.length === 1 && r.drift[0].rel === 'scripts/scriptX.mjs', JSON.stringify(r.drift));
76
- check('S1 fixture 白名单项(commit-check.config.json)不在孤儿', !r.orphan.some((o) => o.rel === 'hooks/commit-check.config.json'));
77
- }
78
-
79
- // ---- 场景 2:cache/ 目录排除 ----
80
- {
81
- const { pkgRoot, target } = mkFixture();
82
- const r = sourceSyncCheck({ pkgRoot, target });
83
- check('S2 cache/ 排除(缺失/孤儿/漂移不含 cache/foo.md)',
84
- !r.missing.some((m) => m.rel.includes('cache/')) &&
85
- !r.orphan.some((o) => o.rel.includes('cache/')) &&
86
- !r.drift.some((d) => d.rel.includes('cache/')));
87
- }
88
-
89
- // ---- 场景 3:装副本独有(kit.json / settings.json)排除 ----
90
- {
91
- const { pkgRoot, target } = mkFixture();
92
- const r = sourceSyncCheck({ pkgRoot, target });
93
- check('S3 装副本独有(kit.json / settings.json)排除',
94
- !r.orphan.some((o) => o.rel === 'kit.json' || o.rel === 'settings.json'));
95
- }
96
-
97
- // ---- 场景 4:sha 一致文件不出现在漂移列表 ----
98
- {
99
- const { pkgRoot, target } = mkFixture();
100
- const r = sourceSyncCheck({ pkgRoot, target });
101
- check('S4 一致文件 cmdA.md 不在漂移', !r.drift.some((d) => d.rel === 'commands/cmdA.md'));
102
- }
103
-
104
- // ---- 场景 5:实际仓库扫描 baseline(包源 ≥ 30 份 / 装副本 ≥ 30 份;装户环境无包源 → SKIP)----
105
- // 纯包源仓(装户端内容清理后)无 `.agents/` 装副本——包源侧仍扫得到,装副本侧 SKIP 不算失败。
106
- if (!SRC_ROOT) {
107
- check('S5 baseline SKIP(未探测到包源 templates/_agents——装户环境直跑,不算失败)', true);
108
- } else {
109
- const r = sourceSyncCheck({ pkgRoot: SRC_ROOT, target: SRC_ROOT });
110
- check('S5 实际仓库 包源 ≥ 30 份', r.pkgCount >= 30, '实际 ' + r.pkgCount);
111
- if (!fs.existsSync(path.join(SRC_ROOT, '.agents'))) {
112
- check('S5 装副本 SKIP(纯包源仓无 .agents/——装户端内容清理后形态,不算失败)', true);
113
- } else {
114
- check('S5 实际仓库 装副本 ≥ 30 份', r.tgtCount >= 30, '实际 ' + r.tgtCount);
115
- // 装副本 kit.json / settings.json 不应在孤儿
116
- check('S5 实际仓库 装副本独有(kit.json / settings.json)排除',
117
- !r.orphan.some((o) => o.rel === 'kit.json' || o.rel === 'settings.json'));
118
- }
119
- }
120
-
121
- // ---- 场景 6:--json 输出可解析(CLI 子流程)----
122
- {
123
- const { pkgRoot, target } = mkFixture();
124
- // 直接调 sourceSyncCheck + 序列化模拟 --json 输出
125
- const r = sourceSyncCheck({ pkgRoot, target });
126
- const jsonOut = JSON.stringify({
127
- pkgCount: r.pkgCount, tgtCount: r.tgtCount,
128
- missing: r.missing.map((m) => m.rel),
129
- orphan: r.orphan.map((o) => o.rel),
130
- drift: r.drift.map((d) => ({ rel: d.rel, pkgSha: d.pkgSha.slice(0, 8), tgtSha: d.tgtSha.slice(0, 8) })),
131
- }, null, 2);
132
- let parsed = null;
133
- try { parsed = JSON.parse(jsonOut); } catch { /* 非 JSON 输出时 parsed 保持 null,S6 判失败路径 */ }
134
- check('S6 --json 输出可解析', parsed && typeof parsed === 'object' && Array.isArray(parsed.missing));
135
- }
136
-
137
- // ---- 场景 8:白名单 RHO 文件过滤(hooks/commit-check.config.json + kit.json + settings.json 都不报孤儿)----
138
- {
139
- const root = fs.mkdtempSync(path.join(os.tmpdir(), 'fk-ssc-rho-'));
140
- const pkgRoot = path.join(root, 'pkg');
141
- const target = path.join(root, 'target');
142
- const pkgBase = path.join(pkgRoot, 'templates', '_agents');
143
- const tgtBase = path.join(target, '.agents');
144
- fs.mkdirSync(pkgBase, { recursive: true });
145
- fs.mkdirSync(path.join(tgtBase, 'hooks'), { recursive: true });
146
- fs.mkdirSync(tgtBase, { recursive: true });
147
- // 3 个白名单项都装副本独有
148
- fs.writeFileSync(path.join(tgtBase, 'hooks', 'commit-check.config.json'), '{}\n');
149
- fs.writeFileSync(path.join(tgtBase, 'kit.json'), '{}\n');
150
- fs.writeFileSync(path.join(tgtBase, 'settings.json'), '{}\n');
151
- // 1 个非白名单孤儿作对照(应被报告)
152
- fs.writeFileSync(path.join(tgtBase, 'hooks', 'real-orphan.json'), '{}\n');
153
- const r = sourceSyncCheck({ pkgRoot, target });
154
- check('S8 白名单 3 项(commit-check.config.json / kit.json / settings.json)不报孤儿',
155
- !r.orphan.some((o) => o.rel === 'hooks/commit-check.config.json' || o.rel === 'kit.json' || o.rel === 'settings.json'));
156
- check('S8 非白名单孤儿(real-orphan.json)仍报孤儿',
157
- r.orphan.length === 1 && r.orphan[0].rel === 'hooks/real-orphan.json', JSON.stringify(r.orphan));
158
- }
159
-
160
- // ---- 场景 9:实际仓库 hooks/commit-check.config.json 不在孤儿(装户环境随 S5 一并 SKIP)----
161
- if (!SRC_ROOT) {
162
- check('S9 baseline SKIP(装户环境,随 S5)', true);
163
- } else {
164
- const r = sourceSyncCheck({ pkgRoot: SRC_ROOT, target: SRC_ROOT });
165
- check('S9 实际仓库 hooks/commit-check.config.json 不在孤儿',
166
- !r.orphan.some((o) => o.rel === 'hooks/commit-check.config.json'), JSON.stringify(r.orphan));
167
- }
168
-
169
- // ---- 场景 7:空目录 / 不存在的目录不崩 ----
170
- {
171
- const empty = fs.mkdtempSync(path.join(os.tmpdir(), 'fk-ssc-empty-'));
172
- const r = sourceSyncCheck({ pkgRoot: empty, target: empty });
173
- check('S7 空目录 fixture 不崩(0/0)', r.pkgCount === 0 && r.tgtCount === 0);
174
- }
175
-
176
- // ---- 场景 10-12:--gate 门禁模式(2026-09-27 audit-gate-hardening,pre-commit 双源门禁用)----
177
- {
178
- // S10 差异 fixture(缺失 1 / 漂移 1 / 孤儿 1)→ --gate exit 1(缺失/漂移阻断)
179
- const { pkgRoot, target } = mkFixture();
180
- const r = runGate(['--gate', '--pkg-root', pkgRoot, '--target', target]);
181
- check('S10 --gate 差异 fixture(缺失+漂移)→ exit 1', r.status === 1, `exit=${r.status}\n${r.stdout || ''}${r.stderr || ''}`);
182
- }
183
- {
184
- // S11 孤儿-only fixture → --gate exit 0(孤儿只报告不计失败——装户自持内容不入机器门)
185
- const root = fs.mkdtempSync(path.join(os.tmpdir(), 'fk-ssc-gate-orphan-'));
186
- const pkgRoot = path.join(root, 'pkg');
187
- const target = path.join(root, 'target');
188
- const pkgBase = path.join(pkgRoot, 'templates', '_agents');
189
- const tgtBase = path.join(target, '.agents');
190
- fs.mkdirSync(path.join(pkgBase, 'commands'), { recursive: true });
191
- fs.mkdirSync(path.join(tgtBase, 'commands'), { recursive: true });
192
- fs.writeFileSync(path.join(pkgBase, 'commands', 'same.md'), '# v1\n');
193
- fs.writeFileSync(path.join(tgtBase, 'commands', 'same.md'), '# v1\n');
194
- fs.writeFileSync(path.join(tgtBase, 'local-only.md'), '# 装户自持\n');
195
- const r = runGate(['--gate', '--pkg-root', pkgRoot, '--target', target]);
196
- check('S11 --gate 孤儿-only → exit 0(孤儿不计失败)', r.status === 0, `exit=${r.status}\n${r.stdout || ''}${r.stderr || ''}`);
197
- }
198
- {
199
- // S12 干净 fixture --gate → exit 0;差异 fixture --diff → 仍 exit 0(B-b「只报告不修复」默认语义不变)
200
- const root = fs.mkdtempSync(path.join(os.tmpdir(), 'fk-ssc-gate-clean-'));
201
- const pkgRoot = path.join(root, 'pkg');
202
- const target = path.join(root, 'target');
203
- const pkgBase = path.join(pkgRoot, 'templates', '_agents');
204
- const tgtBase = path.join(target, '.agents');
205
- fs.mkdirSync(path.join(pkgBase, 'commands'), { recursive: true });
206
- fs.mkdirSync(path.join(tgtBase, 'commands'), { recursive: true });
207
- fs.writeFileSync(path.join(pkgBase, 'commands', 'same.md'), '# v1\n');
208
- fs.writeFileSync(path.join(tgtBase, 'commands', 'same.md'), '# v1\n');
209
- const rClean = runGate(['--gate', '--pkg-root', pkgRoot, '--target', target]);
210
- check('S12 --gate 干净 fixture → exit 0', rClean.status === 0, `exit=${rClean.status}`);
211
- const { pkgRoot: dp, target: dt } = mkFixture();
212
- const rDiff = runGate(['--diff', '--pkg-root', dp, '--target', dt]);
213
- check('S12 --diff 差异 fixture 仍 exit 0(B-b 默认语义不变)', rDiff.status === 0, `exit=${rDiff.status}`);
214
- }
215
-
216
- // ---- 场景 13-14:sha LF 归一(2026-09-27 closing-coverage)——CRLF 等价不误报 / 内容差异照常抓 ----
217
- {
218
- // S13 同内容不同行尾(包源 LF / 装副本 CRLF)→ 不报漂移
219
- const root = fs.mkdtempSync(path.join(os.tmpdir(), 'fk-ssc-crlf-'));
220
- const pkgRoot = path.join(root, 'pkg');
221
- const target = path.join(root, 'target');
222
- const pkgBase = path.join(pkgRoot, 'templates', '_agents', 'commands');
223
- const tgtBase = path.join(target, '.agents', 'commands');
224
- fs.mkdirSync(pkgBase, { recursive: true });
225
- fs.mkdirSync(tgtBase, { recursive: true });
226
- fs.writeFileSync(path.join(pkgBase, 'a.md'), '# 标题\n\n正文行\n- 项目\n');
227
- fs.writeFileSync(path.join(tgtBase, 'a.md'), '# 标题\r\n\r\n正文行\r\n- 项目\r\n');
228
- fs.writeFileSync(path.join(pkgBase, 'b.md'), '# B\n');
229
- fs.writeFileSync(path.join(tgtBase, 'b.md'), '# B\n');
230
- const r = sourceSyncCheck({ pkgRoot, target });
231
- check('S13 同内容不同行尾(LF vs CRLF)→ 0 漂移(LF 归一口径)', r.drift.length === 0, JSON.stringify(r.drift));
232
- }
233
- {
234
- // S14 内容真实差异(即使行尾也不同)→ 照常报漂移(归一不掩盖内容差异)
235
- const root = fs.mkdtempSync(path.join(os.tmpdir(), 'fk-ssc-crlf2-'));
236
- const pkgRoot = path.join(root, 'pkg');
237
- const target = path.join(root, 'target');
238
- const pkgBase = path.join(pkgRoot, 'templates', '_agents', 'commands');
239
- const tgtBase = path.join(target, '.agents', 'commands');
240
- fs.mkdirSync(pkgBase, { recursive: true });
241
- fs.mkdirSync(tgtBase, { recursive: true });
242
- fs.writeFileSync(path.join(pkgBase, 'a.md'), '# v1\n内容甲\n');
243
- fs.writeFileSync(path.join(tgtBase, 'a.md'), '# v1\r\n内容乙\r\n');
244
- const r = sourceSyncCheck({ pkgRoot, target });
245
- check('S14 内容差异(甲 vs 乙)→ 报漂移(归一只认 CRLF 不吞内容)', r.drift.length === 1 && r.drift[0].rel === 'commands/a.md', JSON.stringify(r.drift));
246
- }
247
-
248
- // ---- 场景 15-16:项目自持架子文件排除(2026-09-28 runtime-env 双源冲突)----
249
- {
250
- // S15 notes/runtime-env.md **两侧都被排除**——包源只发骨架、装户填实况,两处本就该不同。
251
- // 回归:首版只过滤装副本一侧 → 排除件变成「包源有/装副本无」的**缺失**,--gate 仍 exit 1
252
- // (实测:漂移 1 → 缺失 1)。故断言 missing/drift 皆为空。
253
- const root = fs.mkdtempSync(path.join(os.tmpdir(), 'fk-ssc-owned-'));
254
- const pkgRoot = path.join(root, 'pkg');
255
- const target = path.join(root, 'target');
256
- const pkgBase = path.join(pkgRoot, 'templates', '_agents', 'notes');
257
- const tgtBase = path.join(target, '.agents', 'notes');
258
- fs.mkdirSync(pkgBase, { recursive: true });
259
- fs.mkdirSync(tgtBase, { recursive: true });
260
- fs.writeFileSync(path.join(pkgBase, 'runtime-env.md'), '# 骨架\n> 项目按实际填写\n');
261
- fs.writeFileSync(path.join(tgtBase, 'runtime-env.md'), '# 实况\n> 本机 sh 路径已接\n');
262
- const r = sourceSyncCheck({ pkgRoot, target });
263
- check('S15 项目自持 runtime-env.md 两侧内容不同 → 既不报缺失也不报漂移(双侧排除)',
264
- r.missing.length === 0 && r.drift.length === 0,
265
- JSON.stringify({ missing: r.missing, drift: r.drift }));
266
- }
267
- {
268
- // S16 排除**只针对该文件**——同目录其他 .md 仍受双源门禁约束(防排除范围被误放大)
269
- const root = fs.mkdtempSync(path.join(os.tmpdir(), 'fk-ssc-owned2-'));
270
- const pkgRoot = path.join(root, 'pkg');
271
- const target = path.join(root, 'target');
272
- const pkgBase = path.join(pkgRoot, 'templates', '_agents', 'notes');
273
- const tgtBase = path.join(target, '.agents', 'notes');
274
- fs.mkdirSync(pkgBase, { recursive: true });
275
- fs.mkdirSync(tgtBase, { recursive: true });
276
- fs.writeFileSync(path.join(pkgBase, 'runtime-env.md'), '# 骨架\n');
277
- fs.writeFileSync(path.join(tgtBase, 'runtime-env.md'), '# 实况\n');
278
- fs.writeFileSync(path.join(pkgBase, 'other.md'), '# v1\n');
279
- fs.writeFileSync(path.join(tgtBase, 'other.md'), '# v2\n');
280
- const r = sourceSyncCheck({ pkgRoot, target });
281
- check('S16 排除不放大——同目录 other.md 内容不同仍报漂移',
282
- r.drift.length === 1 && r.drift[0].rel === 'notes/other.md', JSON.stringify(r.drift));
283
- }
284
-
285
- console.log('\n合计: PASS ' + pass + ' / FAIL ' + failCount);
286
- process.exit(failCount ? 1 : 0);
@@ -1,30 +0,0 @@
1
- ---
2
- name: source-sync-repair
3
- description: 装户面双源漂移修复专项——跑 source-sync-check 看 4 类差异(缺失 / 孤儿 / 漂移 / frontmatter-only-diff)→ 按 B-b 决策方向修齐(包源 → 装副本同步)→ 重跑确认 0 差异 → 走 pipeline-closing 标准关单。基于 F 环节真实过程沉淀
4
- concurrency: 2
5
- ---
6
- # workflow — source-sync-repair(装户面双源漂移修复)
7
-
8
- > 双源结构(`templates/_agents/` 包源 + `.agents/` 装副本)的差异修复。F 环节(2026-09-25-fix-double-source-drift)首次实测发现 5 个真实差异并闭环,本文件(custom)把修复路径固化为可复用编排。所有 stage 用 role 派单 + gate 终端两种形态——不引新 step。
9
-
10
- | id | after | role | step | task / params | files(授权) | accept(验收判据) | gate | retries |
11
- |----|-------|------|------|---------------|---------------|-------------------|------|---------|
12
- | scan-diff | — | implementer | — | 跑 source-sync-check --diff(首次摸底) | .agents/scripts/source-sync-check.mjs | 输出 4 类差异报告(缺失 / 孤儿 / 漂移 / frontmatter-only-diff),无 error | | 0 |
13
- | classify | scan-diff | implementer | — | 按差异类型分类:缺失/漂移走 repair;孤儿走白名单扩展或装副本删除;frontmatter-only-diff 走角色契约确认 | workflow/intents/<date>-fix-double-source-drift.md | intent 立 draft + 4 段改动面(漂移修复 / 白名单 / 测试 / docs)+ 9 条验收标准 | | 0 |
14
- | repair | classify | implementer | — | 按 intent 改动面修漂移:包源 → 装副本同步;白名单 RENDER_OUTPUT_FILES 扩展(含 hooks/commit-check.config.json 等 init 渲染产物);test.mjs 新增 S8/S9 场景;双源纪律(包源改了装副本手动同步) | 见 intent | source-sync-check --diff 报告漂移数减少;双源文件 sha 一致 | | 1 |
15
- | gate-rescan | repair | — | — | — | — | — | node .agents/scripts/source-sync-check.mjs --diff(必须 0 差异) | |
16
- | sync-refresh | gate-rescan | implementer | — | 跑 flow-kit sync 刷台账(owned 哈希按盘面自愈) | .agents/kit.json | sync exit 0;doctor 报 owned 漂移已自愈 | | 0 |
17
- | feat-commit | sync-refresh | implementer | — | 提交 feat commit(fix(模块名)) | 工作区所有变更文件 | pre-commit 钩子全过;commit message 含 4 段改动面 + 白名单扩展 | | 0 |
18
- | closeout | feat-commit | implementer | — | 走 pipeline-closing 标准关单(intent 8 条验收勾验 + plan → done + docs commit);如有需要新建 wiki/双源漂移修复/README.md 沉淀 | workflow/intents/, workflow/plans/, workflow/INDEX.md, wiki/双源漂移修复/README.md | intent + plan 状态均 done;9 条验收勾验含 commit SHA 证据;wiki 主题更新(如适用) | | 0 |
19
-
20
- **编排语义**:第 0 层 scan-diff → 第 1 层 classify(差异分诊)→ 第 2 层 repair(按分诊结果修漂移)→ 第 3 层 2 关静态门(gate-rescan + sync-refresh,并行 fan-out)→ 第 4 层 feat-commit → 第 5 层 closeout(复用 pipeline-closing 6 阶段闭环尾段)。失败且 retries > 0 → 重派(全新上下文);gate-rescan 非零 → 中止后续、回到 repair 重派。
21
-
22
- **与 pipeline-closing 的关系**:source-sync-repair 是 pipeline-closing 的子集(第 3-6 层复用),不重复定义 6 阶段全流程;closeout stage 引用 pipeline-closing 的关单动作。如需完整 6 阶段闭环(含 author / gate-doc / confirm / plan-commit),直接用 pipeline-closing 即可。
23
-
24
- **白名单扩展协议**(沿用 source-sync-check.mjs 的 RENDER_OUTPUT_FILES):init 渲染产物(`kit.json` / `settings.json` / `hooks/commit-check.config.json`)不属双源结构;新增白名单项必须同时加进 source-sync-check.mjs + test.mjs 新场景,且 gate-rescan 跑通 0 命中才认闭环。
25
-
26
- **纪律**(先读):
27
- - 声明随 plan 确认后方可执行;本 workflow 修复必须先立 intent + plan(用 pipeline-closing 的 author stage 起草)。
28
- - 子智能体不跨确认门、不 commit / push(派单红线行:只改授权文件;缺输入或需偏离 → `BLOCKER:` 停下)。
29
- - 留痕:每个派单 stage 完成后向 `workflow/delegations.md` 委派结果表追加一行。
30
- - 解析校验先行:role ∈ `.agents/roles/`、`after` 引用存在且无环——任一不过即拒,不执行。