agentic-flow-kit 1.7.0 → 1.7.16

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 (162) hide show
  1. package/README.md +81 -9
  2. package/modules/gates/README.md +1 -0
  3. package/modules/gates/test-protect/README.md +23 -0
  4. package/modules/gates/test-protect/check-test-protect.mjs +64 -0
  5. package/modules/gates/test-protect/local-pre-commit.line +1 -0
  6. package/modules/hosts/README.md +57 -0
  7. package/modules/hosts/claude/commands/wf-build.md +5 -24
  8. package/modules/hosts/claude/commands/wf-deploy.md +1 -0
  9. package/modules/hosts/claude/commands/wf-design.md +7 -6
  10. package/modules/hosts/claude/commands/wf-gate-checklist.md +1 -3
  11. package/modules/hosts/claude/commands/wf-new-task.md +42 -21
  12. package/modules/hosts/claude/commands/wf-plan.md +1 -1
  13. package/modules/hosts/claude/commands/wf-review.md +1 -1
  14. package/modules/hosts/claude/commands/wf-sync-hosts.md +8 -16
  15. package/modules/hosts/claude/commands/wf-test.md +5 -4
  16. package/modules/hosts/codex/commands/wf-build.md +5 -24
  17. package/modules/hosts/codex/commands/wf-deploy.md +1 -0
  18. package/modules/hosts/codex/commands/wf-design.md +7 -6
  19. package/modules/hosts/codex/commands/wf-gate-checklist.md +1 -3
  20. package/modules/hosts/codex/commands/wf-new-task.md +42 -21
  21. package/modules/hosts/codex/commands/wf-plan.md +1 -1
  22. package/modules/hosts/codex/commands/wf-review.md +1 -1
  23. package/modules/hosts/codex/commands/wf-sync-hosts.md +8 -16
  24. package/modules/hosts/codex/commands/wf-test.md +5 -4
  25. package/modules/hosts/cursor/commands/wf-build.md +5 -24
  26. package/modules/hosts/cursor/commands/wf-deploy.md +1 -0
  27. package/modules/hosts/cursor/commands/wf-design.md +7 -6
  28. package/modules/hosts/cursor/commands/wf-gate-checklist.md +1 -3
  29. package/modules/hosts/cursor/commands/wf-new-task.md +42 -21
  30. package/modules/hosts/cursor/commands/wf-plan.md +1 -1
  31. package/modules/hosts/cursor/commands/wf-review.md +1 -1
  32. package/modules/hosts/cursor/commands/wf-sync-hosts.md +8 -16
  33. package/modules/hosts/cursor/commands/wf-test.md +5 -4
  34. package/modules/hosts/opencode/commands/wf-build.md +5 -24
  35. package/modules/hosts/opencode/commands/wf-deploy.md +1 -0
  36. package/modules/hosts/opencode/commands/wf-design.md +7 -6
  37. package/modules/hosts/opencode/commands/wf-gate-checklist.md +1 -3
  38. package/modules/hosts/opencode/commands/wf-new-task.md +42 -21
  39. package/modules/hosts/opencode/commands/wf-plan.md +1 -1
  40. package/modules/hosts/opencode/commands/wf-review.md +1 -1
  41. package/modules/hosts/opencode/commands/wf-sync-hosts.md +8 -16
  42. package/modules/hosts/opencode/commands/wf-test.md +5 -4
  43. package/modules/hosts/trae/commands/wf-build.md +5 -24
  44. package/modules/hosts/trae/commands/wf-deploy.md +1 -0
  45. package/modules/hosts/trae/commands/wf-design.md +7 -6
  46. package/modules/hosts/trae/commands/wf-gate-checklist.md +1 -3
  47. package/modules/hosts/trae/commands/wf-new-task.md +42 -21
  48. package/modules/hosts/trae/commands/wf-plan.md +1 -1
  49. package/modules/hosts/trae/commands/wf-review.md +1 -1
  50. package/modules/hosts/trae/commands/wf-sync-hosts.md +8 -16
  51. package/modules/hosts/trae/commands/wf-test.md +5 -4
  52. package/package.json +2 -2
  53. package/src/add-gate.mjs +25 -1
  54. package/src/add-gate.test.mjs +103 -0
  55. package/src/cli.mjs +59 -5
  56. package/src/doctor.mjs +136 -12
  57. package/src/executor.mjs +245 -0
  58. package/src/executor.test.mjs +292 -0
  59. package/src/gates.test.mjs +17 -0
  60. package/src/init.mjs +14 -1
  61. package/src/init.test.mjs +19 -0
  62. package/src/instance-ref.test.mjs +62 -0
  63. package/src/jscpd-drift.test.mjs +144 -0
  64. package/src/profiles.mjs +3 -0
  65. package/src/render.mjs +6 -1
  66. package/src/rule-budget.test.mjs +103 -0
  67. package/src/sync-hosts.mjs +41 -45
  68. package/src/sync-hosts.test.mjs +67 -56
  69. package/src/trae-hooks.test.mjs +15 -3
  70. package/src/validate.mjs +72 -0
  71. package/src/validate.test.mjs +95 -0
  72. package/templates/.gitattributes +8 -0
  73. package/templates/AGENTS.md +2 -1
  74. package/templates/_agents/commands/build.md +5 -24
  75. package/templates/_agents/commands/deploy.md +1 -0
  76. package/templates/_agents/commands/design.md +7 -6
  77. package/templates/_agents/commands/gate-checklist.md +1 -3
  78. package/templates/_agents/commands/new-task.md +42 -21
  79. package/templates/_agents/commands/plan.md +1 -1
  80. package/templates/_agents/commands/review.md +1 -1
  81. package/templates/_agents/commands/sync-hosts.md +8 -16
  82. package/templates/_agents/commands/test.md +5 -4
  83. package/templates/_agents/control-surfaces.txt +53 -0
  84. package/templates/_agents/engine-lock.json +246 -0
  85. package/templates/_agents/lane-surfaces.txt +1 -1
  86. package/templates/_agents/level-hints.txt +30 -0
  87. package/templates/_agents/scripts/agg-delegations.cjs +51 -6
  88. package/templates/_agents/scripts/agg-delegations.test.mjs +84 -4
  89. package/templates/_agents/scripts/check-engine-integrity.mjs +217 -0
  90. package/templates/_agents/scripts/check-engine-integrity.test.mjs +215 -0
  91. package/templates/_agents/scripts/check-lane-surface.mjs +78 -24
  92. package/templates/_agents/scripts/check-lane-surface.test.mjs +66 -0
  93. package/templates/_agents/scripts/check-ledger-invariant.mjs +112 -14
  94. package/templates/_agents/scripts/check-ledger-invariant.test.mjs +5 -1
  95. package/templates/_agents/scripts/check-loop-rev.test.mjs +6 -4
  96. package/templates/_agents/scripts/check-loop.mjs +255 -45
  97. package/templates/_agents/scripts/check-loop.test.mjs +330 -15
  98. package/templates/_agents/scripts/check-metric-claims.mjs +4 -2
  99. package/templates/_agents/scripts/compact-ledgers.mjs +97 -0
  100. package/templates/_agents/scripts/compact-ledgers.test.mjs +162 -0
  101. package/templates/_agents/scripts/confirm-doc.mjs +54 -12
  102. package/templates/_agents/scripts/confirm-doc.test.mjs +59 -0
  103. package/templates/_agents/scripts/doctor.test.mjs +294 -1
  104. package/templates/_agents/scripts/draft-sediment.mjs +178 -0
  105. package/templates/_agents/scripts/draft-sediment.test.mjs +272 -0
  106. package/templates/_agents/scripts/edit-face-check.test.mjs +5 -4
  107. package/templates/_agents/scripts/fill-intent.mjs +2 -2
  108. package/templates/_agents/scripts/fixture-scripts.mjs +153 -0
  109. package/templates/_agents/scripts/fixture-scripts.test.mjs +107 -0
  110. package/templates/_agents/scripts/gate-checklist.mjs +6 -3
  111. package/templates/_agents/scripts/gate-checklist.test.mjs +2 -5
  112. package/templates/_agents/scripts/gen-wiki-board.mjs +61 -6
  113. package/templates/_agents/scripts/gen-wiki-board.test.mjs +74 -1
  114. package/templates/_agents/scripts/gen-workflow-dashboard.mjs +10 -13
  115. package/templates/_agents/scripts/gen-workflow-metrics.mjs +12 -30
  116. package/templates/_agents/scripts/git-merge-jsonl.mjs +63 -0
  117. package/templates/_agents/scripts/git-merge-jsonl.test.mjs +125 -0
  118. package/templates/_agents/scripts/kb-search.mjs +87 -12
  119. package/templates/_agents/scripts/kb-search.test.mjs +83 -0
  120. package/templates/_agents/scripts/ledger-doc-chain.test.mjs +166 -0
  121. package/templates/_agents/scripts/ledger-loader.mjs +108 -0
  122. package/templates/_agents/scripts/ledger-loader.test.mjs +131 -0
  123. package/templates/_agents/scripts/ledger-prune.mjs +96 -0
  124. package/templates/_agents/scripts/ledger-prune.test.mjs +120 -0
  125. package/templates/_agents/scripts/ledger-ts-monotonic.test.mjs +135 -0
  126. package/templates/_agents/scripts/level-criteria.mjs +232 -0
  127. package/templates/_agents/scripts/level-criteria.test.mjs +279 -0
  128. package/templates/_agents/scripts/pipeline-run.mjs +5 -3
  129. package/templates/_agents/scripts/policy.mjs +47 -0
  130. package/templates/_agents/scripts/solidify-task.mjs +1 -1
  131. package/templates/_agents/scripts/stage-gates.mjs +52 -10
  132. package/templates/_agents/scripts/stage-gates.test.mjs +105 -0
  133. package/templates/_agents/scripts/verify-wiki-consistency.mjs +34 -0
  134. package/templates/_agents/scripts/verify-wiki-consistency.test.mjs +44 -2
  135. package/templates/_agents/scripts/verify.mjs +1 -1
  136. package/templates/_agents/scripts/wf-journal.test.mjs +1 -1
  137. package/templates/_agents/scripts/wiki-search.test.mjs +5 -6
  138. package/templates/_agents/scripts/workflows-check.mjs +1 -1
  139. package/templates/_agents/scripts-test-exempt.txt +3 -1
  140. package/templates/_agents/skills/wiki/SKILL.md +5 -3
  141. package/templates/_agents/workflows/pipeline-closing.md +4 -5
  142. package/templates/_githooks/pre-commit +3 -34
  143. package/templates/_githooks/pre-push +3 -3
  144. package/templates/wiki/INDEX.md +44 -1
  145. package/templates/wiki//347/237/245/350/257/206/346/262/211/346/267/200/346/200/273/350/247/210.html +22 -1
  146. package/templates/workflow/README.md +11 -0
  147. package/templates/workflow/delegations.md +5 -4
  148. package/templates/workflow/incidents/_TEMPLATE.md +2 -0
  149. package/templates/workflow/intents/_TEMPLATE.md +3 -0
  150. package/templates/workflow/plans/_TEMPLATE.md +4 -0
  151. package/templates/workflow/specs/_TEMPLATE.md +23 -0
  152. package/modules/hosts/claude/commands/wf-source-sync-check.md +0 -91
  153. package/modules/hosts/codex/commands/wf-source-sync-check.md +0 -91
  154. package/modules/hosts/cursor/commands/wf-source-sync-check.md +0 -91
  155. package/modules/hosts/opencode/commands/wf-source-sync-check.md +0 -91
  156. package/modules/hosts/trae/commands/wf-source-sync-check.md +0 -92
  157. package/templates/_agents/commands/source-sync-check.md +0 -105
  158. package/templates/_agents/scripts/check-ledger.mjs +0 -109
  159. package/templates/_agents/scripts/check-ledger.test.mjs +0 -197
  160. package/templates/_agents/scripts/source-sync-check.mjs +0 -156
  161. package/templates/_agents/scripts/source-sync-check.test.mjs +0 -281
  162. package/templates/_agents/workflows/source-sync-repair.md +0 -30
@@ -21,7 +21,21 @@ description: 闭环总入口 · 路由判断(新需求 → wf-plan / 修复
21
21
 
22
22
  ## 2. 风险定级(第 0 步,先定级再路由)
23
23
 
24
- 动工前先按下表定风险级 L0-L3(就高不就低;判据细则见下节「级别判断」),级别即风险级,决定走哪条泳道——确认放事前,还是审计补事后:
24
+ **第 0 步先取机器面下界(必跑,不是可选提示)**:
25
+
26
+ ```bash
27
+ flow-kit route --files <预计改动面…> --kind require|fix|verify|review|deploy
28
+ ```
29
+
30
+ - **不给 `--files` 就拿不到路径下限**——机器面此时只能按 L1 起步并在降级栏点名,等于白跑;
31
+ 故定级前先把**预计改动面**列出来(不必精确到最终 diff,给到目录/文件前缀即可)。
32
+ - 跑完**再**按 §4 逐条语义判级:机器只给「就高不就低 + 路径下限」,「一处定义、多处消费」仍要你判。
33
+ - **确实跳过**时必须写明理由(入口文档备注或当场告知用户)——判低的后果由两道门兜:
34
+ 起草面 `check-lane-surface` 命中路径下限无合格入口即拦,提交面同门再拦一次。
35
+ **诚实边界**:机器**无法**发现你没跑 route——定级发生在改动面确定之前,没有可比对的记录面,
36
+ 详见 [ARCHITECTURE §5](../ARCHITECTURE.md) 与 CHANGELOG 1.7.16 B3 条。
37
+
38
+ 动工前按下表定风险级 L0-L3(就高不就低;判据细则见下节「级别判断」),级别即风险级,决定走哪条泳道——确认放事前,还是审计补事后:
25
39
 
26
40
  | 泳道 | 级别 | 确认与审计口径 |
27
41
  |------|------|---------------|
@@ -34,6 +48,10 @@ description: 闭环总入口 · 路由判断(新需求 → wf-plan / 修复
34
48
 
35
49
  ## 3. 路由判断
36
50
 
51
+ <!-- route-kinds: require=plan.md | fix=maintain.md | verify=test.md | review=review.md | deploy=deploy.md -->
52
+ <!-- ↑ 本行是 kind→入口指令的**机器单源**:`flow-kit route` 读它得出「该读哪个 md」,不再在包内自带一份映射。
53
+ 增删 kind 或改入口文件名只改这一行(判据单源 level-criteria.mjs 的纪律同源)。 -->
54
+
37
55
  - **自动化驱动(并列入口,可选)**:一句话全程走 [pipeline-run.md](pipeline-run.md)——状态机驱动+工单协议+原话代录,与下述手动路由二选一,同一任务不混用
38
56
  - **新需求 / 功能**:从 `plan.md` 进,立 **intent**(`workflow/intents/`)
39
57
  - **修复类任务 / 事故**:从 `maintain.md` 进,立 **incident**(`workflow/incidents/`);incident 在 L1+ 即 **intent 等价物**(check-loop 认 incident≡intent),不必另立 intent。先检索同类历史(`node .agents/scripts/kb-search.mjs "<关键词>" --scope workflow --type incidents,plans`),有同类先读其历史三件套;再按级别走:
@@ -46,28 +64,31 @@ description: 闭环总入口 · 路由判断(新需求 → wf-plan / 修复
46
64
 
47
65
  ## 4. 级别判断(AGENTS.md 第 3 条)
48
66
 
49
- | 级别 | 改什么 | 流程 |
50
- |------|--------|------|
51
- | L0 | 文档/样式微调(无行为影响) | 直接 commit,豁免 intent |
52
- | L1 | **实现级改动**(未命中 L2/L3) | 快车道:液态草稿(.zcode/drafts) → 实现 → 固化(`solidify-task.mjs`)——用户确认后带 `--delegated "<原话>"` 执行;无确认来源只迁移不落账 |
53
- | L2 | **规则 / 契约**(一处改、多处依赖) | 入口文档(intent / incident) + spec + plan 三件套 |
54
- | L3 | **数据与运行时结构**(schema / 迁移 SQL / DI 链 / 认证与中间件管线) | 同 L2 + spec 新会话独立复核 |
55
-
56
- > 级别判定同上表"改什么"列;混合改动按最高档定级。
57
-
58
- **L2 触达面**(闭集,命中任一即 L2;本体不改但改其输入域 / 调用点校验同样命中):
59
-
60
- 1. **编码权威**:项目内「一处生成、多处消费」的编码 / 命名 / 取号规则(编码模板、序列发生器、命名空间与去重约束——具体清单按项目 AGENTS.md)
61
- 2. **共享契约**:跨模块共享的基类 / DTO 形状、跨模块公共接口签名
62
- 3. **既有接口语义**:既有参数或端点的行为变化(由失效变生效、默认值或钳制口径改变)
63
- 4. **全局横切口径**:错误响应出口、分页与校验口径、聚合投影键
67
+ > **判据单源 = [`.agents/scripts/level-criteria.mjs`](../scripts/level-criteria.mjs)**,本节**不复述判据**。
68
+ > 要看判据全文,或要机器可判的部分(路径下限 / 就高不就低 / 混档取高),直接:
69
+ >
70
+ > ```bash
71
+ > flow-kit route --files <改动文件…> # 定级 + 下一阶段 + 该读哪个 md
72
+ > ```
73
+ >
74
+ > 单源导出:`LEVELS` `LEVEL_MEANING`(档位语义) / `L2_SURFACES`(四类触达面闭集) / `L3_SURFACES`(结构面) /
75
+ > `L1_NEGATIVES`(判低红线) / `SELF_CHECK`(自查句) / `assessLevel` `hintLevelFor` `parseLevelHints` `routeAdvice`。
76
+ >
77
+ > 路径下限清单(装户 owned,默认空):`.agents/level-hints.txt`,每行 `L2 <ERE>` / `L3 <ERE>`,登记「哪些路径一碰就至少是此档」。
64
78
 
65
- > **负例(落 L1)**:纯页面表现 / 文案 / 布局 / 交互实现;纯新增端点或参数且既有行为不变;单模块内部重构且无对外契约变化。
66
- > **自查句**:能否列出 ≥2 个受影响的消费方(模块 / 端点 / 页面)?能 → L2。
67
- > 先例:本仓 `workflow/specs/`、`workflow/intents/` 下同类历史(kb 检索主题词)。
79
+ **本表只承载流程**(「改什么」判据以单源为准,别在本表增删判据):
68
80
 
69
- > **L1 是默认档**:红线全不勾即 L1,无需正列举——判级只回答「是否命中 L2 四类或 L3 结构面」。
70
- > **L3 的「DI 链」按组合根与运行时管线理解**:DI 注册、中间件/认证管线、服务构造器依赖变更(先例:本仓 workflow/ 留痕中无 schema 变更仍定 L3 的同类历史)。
81
+ | 级别 | 单源语义(摘要) | 流程 |
82
+ |------|-----------------|------|
83
+ | L0 | 文档/样式微调(无行为影响) | 直接 commit,豁免 intent |
84
+ | L1 | 实现级改动(未命中 L2/L3) | 快车道:液态草稿(.zcode/drafts) → 实现 → 固化(`solidify-task.mjs`)——用户确认后带 `--delegated "<原话>"` 执行;无确认来源只迁移不落账 |
85
+ | L2 | 规则 / 契约(一处改、多处依赖) | 入口文档(intent / incident) + spec + plan 三件套 |
86
+ | L3 | 数据与运行时结构(结构面闭集见单源 `L3_SURFACES`) | 同 L2 + spec 新会话独立复核 |
87
+
88
+ > 混合改动按最高档定级(就高不就低);**L1 是默认档**——判级只回答「是否命中单源 `L2_SURFACES` 或
89
+ > `L3_SURFACES`」,负例(`L1_NEGATIVES`)命中即不得升档;自查句:`SELF_CHECK`。
90
+ > 机器兜得住的只有「就高不就低」与路径下限;「一处定义、多处消费」是**语义**判定,由你按单源逐条判,
91
+ > 漏判由 lane-surface 触达面门在提交面兜。先例:`workflow/specs/`、`workflow/intents/` 下同类历史(kb 检索主题词)。
71
92
 
72
93
  ## 5. intent 豁免(避免小改动也走完整闭环)
73
94
 
@@ -21,7 +21,7 @@ description: Plan 阶段 · 立 intent(AI 起草、用户确认;本阶段不
21
21
  - 红线勾选对照根 `AGENTS.md` 红线/约束相关节(如「项目适配区」「门禁与提交」)+ 改动域目录级 `AGENTS.md`(如有);**没触及就全不勾**,不要硬填
22
22
  3. 写不出可测试判据 = 还没想清楚 → 反问澄清,不要硬填。
23
23
  4. 起草后停下,输出草稿全文给用户过目,一句"可以"即确认。
24
- **确认落态**:唯一入口 `node .agents/scripts/confirm-doc.mjs <path>`(draft→approved / approved→done;TTY 两形态 / 逐件调用+逐件原话 / 台账对质全口径见根 `AGENTS.md` §1.3 确认门)。
24
+ **确认落态**:唯一入口 `node .agents/scripts/confirm-doc.mjs <path>`(draft→approved / approved→done;TTY 两形态 / 逐件代录(摘要可复用——分辨力由 scope+指纹承担)/ 台账对质全口径见根 `AGENTS.md` §1.3 确认门)。
25
25
 
26
26
  ## 2. 技能辅助(可选,宿主级 skills)
27
27
 
@@ -33,7 +33,7 @@ description: Review · 代码评审(横切,合入前使用;P0/P1/P2 分级
33
33
  - **Create/Update 校验同口径**:Create 已有校验 Update 必须同口径;被引用的标识符字段禁改
34
34
  - **查询分页与状态语义**:分页参数范围校验 + 服务层钳制;非法状态与不存在分离(按项目统一错误口径,如 400 / 404)
35
35
  - **spec 承诺的断言落地**:spec §测试列出的用例 / 断言须真落到测试或验证脚本;「写进 spec」不等于「跑得起来」,且常驻断言禁写成随时间增长的行数常量
36
- - **跨宿主薄适配正文漂移**:改 `templates/_agents/{commands,roles}/*.md` 后必须跑 `flow-kit sync-hosts --apply` 单向同步注册表内全部宿主薄适配(`modules/hosts/<h>/{agents,commands}/*.md`);装户视角由 `flow-kit doctor` §6.7 检查(包源环境 §6.7 skipped)
36
+ - **跨宿主薄适配正文漂移**:包源仓改 `templates/_agents/{commands,roles}/*.md` 后跑 `flow-kit sync-hosts --apply`,单向同步 `modules/hosts/<h>/{agents,commands}/*.md`。装户由 `flow-kit doctor` §6.7 检查(包源环境跳过);装户刷新宿主文件用 `flow-kit add-host <宿主> --force`(`sync` 不更新宿主适配,`sync-hosts` 不在装户根运行)
37
37
 
38
38
  ## 3. P2 建议(提醒,不拦合入)
39
39
 
@@ -7,27 +7,22 @@ description: 跨宿主适配层同步(正文段 sha 比对 + 用户拍板 +
7
7
 
8
8
  # Sync-Hosts · 跨宿主适配层正文段同步
9
9
 
10
- > 改权威源(`templates/_agents/{commands,roles}/*.md`)后薄适配(`modules/hosts/<h>/{agents,commands}/*.md`)要同步——薄适配正文 = 权威源正文,frontmatter 各自保留宿主特化(commands 层文件名 = 宿主命令名,opencode / trae 同用 `wf-` 前缀,单源见 `src/profiles.mjs#HOSTS.commandPrefix`;trae 另有 `name: wf-X`,zcode/omp 各自原描述)。
11
- > 装户视角:`flow-kit doctor` §7.x 跑同名检查(仅装户,包源环境跳过——包源下永远是 drift);**修漂移用同一条命令**
12
- > `flow-kit sync-hosts --apply`——2026-10-07 起按**目标根**自动判布局(含 `templates/_agents` + `modules/hosts` → 包源:
13
- > 比 `templates/_agents` ↔ `modules/hosts/<宿主键>/`;含 `.agents` → 装户:比 `.agents` ↔ 项目根下 `<宿主点目录>/`),
14
- > 目标根取 `--dir <目录>` > 当前目录。
10
+ > 本命令只在包源仓运行(需要 `templates/_agents` 与 `modules/hosts`)。改权威源(`templates/_agents/{commands,roles}/*.md`)后薄适配(`modules/hosts/<h>/{agents,commands}/*.md`)要同步——薄适配正文 = 权威源正文,frontmatter 各自保留宿主特化(commands 层文件名 = 宿主命令名,opencode / trae 同用 `wf-` 前缀,单源见 `src/profiles.mjs#HOSTS.commandPrefix`;trae 另有 `name: wf-X`,zcode/omp 各自原描述)。
11
+ > 装户的宿主文件由 `init` / `add-host` 写入。装户漂移由 `flow-kit doctor` §6.7 报告(包源环境跳过);刷新用 `flow-kit add-host <宿主> --force`。`flow-kit sync` 不更新宿主适配。
15
12
 
16
13
  ## 1. 何时跑
17
14
 
18
15
  - 改 `templates/_agents/commands/*.md` 正文后(11 个 commands 文件)
19
16
  - 改 `templates/_agents/roles/*.md` 正文后(3 个 roles 文件)
20
- - 装户跑 `flow-kit doctor` 报"跨宿主薄适配正文漂移 N 对" WARN 时
21
- - 不跑:仅改 frontmatter;改 trae 钩子/规则;改包源其他文件
17
+ - 不跑:装户仓(本命令会拒绝);仅改 frontmatter;改 trae 钩子/规则;改包源其他文件
22
18
 
23
19
  ## 2. 怎么跑
24
20
 
25
21
  ### 2.1 默认 `--diff`(仅报告)
26
22
 
27
23
  ```
28
- node bin/flow-kit.mjs sync-hosts --diff # 包源仓(在包源根跑)
24
+ node bin/flow-kit.mjs sync-hosts --diff # 包源仓(在包源根跑,或 --dir <包源根>)
29
25
  node bin/flow-kit.mjs sync-hosts --json # 机器可读
30
- flow-kit sync-hosts --diff # 装户仓(在装户根跑;或用 --dir <项目根> 指定)
31
26
  ```
32
27
 
33
28
  输出三类:
@@ -47,9 +42,8 @@ node bin/flow-kit.mjs sync-hosts --apply
47
42
  ### 2.3 自验
48
43
 
49
44
  ```
50
- npm test # 含 sync-hosts.test.mjs 8 场景
51
- node bin/flow-kit.mjs doctor # 装户跑 §7.x PASS;包源跑 §7.x skipped
52
- sh .agents/scripts/check-loop.sh # Windows 无 sh 时 doctor 已探测分流
45
+ npm test # 含 sync-hosts.test.mjs
46
+ node bin/flow-kit.mjs doctor # 包源环境 §6.7 skipped
53
47
  ```
54
48
 
55
49
  ## 3. 边界(不要做)
@@ -64,10 +58,8 @@ sh .agents/scripts/check-loop.sh # Windows 无 sh 时 doctor 已
64
58
 
65
59
  - trae 钩子(`modules/hosts/trae/hooks/*.cjs`)— 独立演进的工程件
66
60
  - trae 规则(`modules/hosts/trae/rules/*.md`)— 同上
67
- - 包源 .agents/scripts/*.cjs(pre-commit 等钩子)— 同步由 `flow-kit sync` 走 managed 台账负责
61
+ - 门禁脚本与钩子(`templates/_agents/scripts`、`templates/_githooks`)— 由 `flow-kit sync` 按 managed 台账下发,不走 sync-hosts
68
62
 
69
63
  ## 5. 相关留痕
70
64
 
71
- - intent:`workflow/intents/2026-09-25-cross-host-sync.md`
72
- - plan:`workflow/plans/2026-09-25-cross-host-sync.md`(含 B-b 方案拍板)
73
- - incident:`workflow/incidents/2026-09-25-wf-runtime.md`(双源纪律教训,规范 §7.x 包源环境跳过)
65
+ - 立法出处:2026-09-25 cross-host-sync(intent/plan,含 B-b 方案拍板;父事件 = wf-runtime 双源纪律教训,规范 §7.x 包源环境跳过)——留痕在包源仓 git 历史与 CHANGELOG,装户径不引实例路径
@@ -17,7 +17,7 @@ description: Test 阶段 · 静态门 + 切库冒烟 + UI 实测 + L2/L3 独立
17
17
  项目测试命令 # 自动化测试
18
18
  项目类型检查命令 # 前端类型检查/构建(涉及前端时跑)
19
19
  node .agents/scripts/verify-wiki-consistency.mjs # 触及 wiki/ 时跑(exit 1 即先修台账再继续:跑 gen-wiki-board.mjs 补索引/看板;pre-commit 已按增量自动拦,此行用于改完即验)
20
- node bin/flow-kit.mjs doctor # §6.5 delegations + §6.6 owned 漂移 + §6.7 跨宿主薄适配正文漂移(装户环境;包源环境 §6.7 skipped)
20
+ npx agentic-flow-kit doctor # §6.5 delegations + §6.6 owned 漂移 + §6.7 跨宿主薄适配正文漂移(装户环境;漂移用 add-host <宿主> --force 刷新。包源环境 §6.7 skipped)
21
21
  ```
22
22
 
23
23
  > **环境注记**:本地服务占用构建产物导致编译失败、多会话并行时「谁跑静态门 / 提交谁先停服务」等约定——如有,见项目注记 `.agents/notes/runtime-env.md` §2,跑静态门前先过一眼。
@@ -56,11 +56,12 @@ node bin/flow-kit.mjs doctor # §6.5 delegations + §6.6 o
56
56
 
57
57
  - 输出测试报告(通过项 / 失败项);失败项已修复并复测通过。
58
58
  - **关单**(日常闭环点,不依赖是否上 prod):
59
- - 关单前一键过门:`node .agents/scripts/verify.mjs --doc workflow/intents/<本单>.md`(npm test + check-loop 固定编排,任一失败非零退出,非绿不关单);**`--doc` 把测试绿凭证绑到本单**——不带它落下的绿行不给任何单背书,confirm-doc 前置与检查 8 对账只认带本单 `--doc` 的绿行(仅 v6+ 生效);**装户仓**(根目录无 `package.json`,工程在子目录)默认 `npm test` 不可跑 → 脚本**显式跳过步骤 1 且不落测试绿凭证**(防假绿)并提示;此时按项目口径手工跑测试,或带 `--test-cmd "<项目测试命令>"` 指定(2026-10-07 papercut)
59
+ - 关单前一键过门:`node .agents/scripts/verify.mjs --doc workflow/intents/<本单>.md`(npm test + check-loop 固定编排,任一失败非零退出,非绿不关单);**`--doc` 把测试绿凭证绑到本单**——不带它落下的绿行不给任何单背书,confirm-doc 前置与检查 8 对账只认带本单 `--doc` 的绿行(仅 v6+ 生效);**装户仓**(根目录无 `package.json`,工程在子目录)默认 `npm test` 不可跑 → 脚本**显式跳过步骤 1 且不落测试绿凭证**(防假绿)并提示;此时按项目口径手工跑测试,或带 `--test-cmd "<项目测试命令>"` 指定
60
60
  - 新需求:逐条勾验入口 intent「验收标准」,每条补「证据:」(例如:粘贴 CI 运行结果、UI 截图路径、或具体的 commit SHA),intent → done;同名 spec/Quick-Plan(若有)仍 approved → done。**注意:勾选但缺证据会被 check-loop 拦截(hard-block)**
61
- - **approved 留痕提交**(2026-09-30 起):done 确认前确认**本次关单文档**的 approved 态已进 git 历史(越早越好——approved 后即应提交;若尚未,先补提交再 done;门为逐份校验,三件套均关单时逐份各自满足)——confirm-doc 的 done 前置门硬校验(历史未出现「状态: approved」→ 拒绝落账);done 后再提交 done 态与其余改动
62
- - **确认落态**:唯一入口 `node .agents/scripts/confirm-doc.mjs <path>`(两形态 / 逐件+逐件原话 / done 内容绑定(关单编辑先于 done 确认、confirm-doc 是最后一次写入)/ 台账对质全口径见根 `AGENTS.md` §1.3 确认门)。
61
+ - **approved 留痕提交**:done 确认前确认**本次关单文档**的 approved 态已进 git 历史(越早越好——approved 后即应提交;若尚未,先补提交再 done;门为逐份校验,三件套均关单时逐份各自满足)——confirm-doc 的 done 前置门硬校验(历史未出现「状态: approved」→ 拒绝落账);done 后再提交 done 态与其余改动
62
+ - **确认落态**:唯一入口 `node .agents/scripts/confirm-doc.mjs <path>`(两形态 / 逐件代录(摘要可复用——分辨力由 scope+指纹承担)/ done 内容绑定(关单编辑先于 done 确认、confirm-doc 是最后一次写入)/ 台账对质全口径见根 `AGENTS.md` §1.3 确认门)。
63
63
  - 修复:防复发验证已落地,incident → closed(经确认门 confirm-doc:open→fixed / fixed→closed 两跳、无单跳;2026-09-28 起 check-loop 15 对账——关单编辑先于 closed 确认,口径同 done 内容绑定)
64
+ - **沉淀草稿**:intent done / incident closed 后跑 `node .agents/scripts/draft-sediment.mjs workflow/<intents|incidents>/<本单>.md`——自动抽高价值节(intent:影响面/触达红线;incident:影响面/根因/为什么之前没拦住/复盘三件套)落 `wiki/drafts-archive/<日期-主题>/` 草稿、回写源文件 `沉淀` 字段、重跑 gen-wiki-board(归档计数随动,否则 verify-wiki-consistency 拦提交)。全占位单拒抽(正常,无沉淀价值)。`--dry-run` 先预览。草稿是**中间态**:人工读一遍归类到 `wiki/<主题>/`(补主题与用途、保留 `来源` 字段)后跑 gen-wiki-board + verify-wiki-consistency。沉淀是人工判断——机器只代抽与登记,值不值得入库由人定;不沉淀写 `沉淀: 无` 显式豁免(check-loop 的 `[WARN 未沉淀]` 随之消除)
64
65
  - **同族收尾**:入口置终态时,同名 plan 一并置 `done`(spec 见上条),不留 `approved` 孤儿(口径同看板「入口已 done,本 plan 未终态」告警)
65
66
  - 主智能体自做的 L1+ 新需求在 `workflow/delegations.md`「自做任务结果表」记一行(修复类不重复记)
66
67
  - **委派快照回写**:关单后若 `workflow/delegations.md` §月度聚合快照缺当月行或 doctor §6.5 报陈旧 → 跑 `node .agents/scripts/agg-delegations.cjs` 并回贴当月快照行
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "agentic-flow-kit",
3
- "version": "1.7.0",
4
- "description": "AI-Native 闭环工作流 + wiki 知识层脚手架——flow-kit init 一条命令为新项目装好 .agents 工作流引擎(阶段命令/角色契约/门禁钩子/kb 检索/看板/规则面预算)+ workflow 文档闭环 + wiki 知识库,装完自包含、零运行时依赖",
3
+ "version": "1.7.16",
4
+ "description": "AI-Native 闭环工作流 + wiki 知识层脚手架——flow-kit init 一条命令为新项目装好 .agents 工作流引擎(阶段命令/角色契约/门禁钩子/kb 检索/看板/规则面预算)+ workflow 文档闭环 + wiki 知识库,装完本地可跑、零运行时依赖",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "test": "node src/run-tests.mjs",
package/src/add-gate.mjs CHANGED
@@ -2,6 +2,13 @@
2
2
  // 模块约定:modules/gates/<gate>/ 下源文件拷入 .agents/hooks/(平铺,README.md 与 local-pre-commit.line 为包内元数据不拷);
3
3
  // local-pre-commit.line 内容 = 需追加进 .agents/hooks/local-pre-commit 的挂载行(存在同名行则不重复追加,幂等)。
4
4
  // 门禁装后归项目所有:入 owned 台账,sync 永不覆盖(改红线/删不适用条目自行编辑——见各模块 README)。
5
+ // gate 防改锚(2026-10-11 P3-1):逐字拷贝安装的 gate 脚本,owned 条目写 srcSha256=安装时刻包源文件
6
+ // (modules/gates/<gate>/<file>)的 LF 归一 sha。语义:sync 对 owned 的 sha256 按盘面自愈(记账不约束),
7
+ // 但 srcSha256 只按包源刷新——gate 文件在装户 sync 中 srcTemplatePath 解析不到包源模板(templates/_agents/
8
+ // hooks/ 无同名件)即提前 return,锚一经写入恒定。doctor 的 gate 安装锚校验据此让「装后手改」永久可见:
9
+ // 装户可改(不阻断),但改了会被看见。--force 重装锚随新安装刷新(即重锚路径);已存在被跳过的文件锚
10
+ // 盘面现状(盘面非逐字拷贝,锚包源会装后即误报),盘面与包源不一致时 WARN 差异。local-pre-commit 是
11
+ // 合并接线件(模板 + 各门挂载行),非逐字拷贝——不写锚(它的 srcSha256 由 init/sync 按模板语义记,含义不同)。
5
12
  import fs from 'node:fs';
6
13
  import path from 'node:path';
7
14
  import { sha256 } from './render.mjs';
@@ -77,9 +84,26 @@ export function addGate(args, pkgRoot) {
77
84
  // 记账一律 LF 归一(init-p1-batch P1-4 rider):与 doctor §6.6 / sync ownedSha 同口径,跨 checkout 字节稳定
78
85
  const shaText = (p) => sha256(Buffer.from(fs.readFileSync(p, 'utf8').replace(/\r\n/g, '\n'), 'utf8'));
79
86
  const ownedLedger = new Map((kit.owned || []).map((f) => [f.rel, f]));
87
+ // 跳过件(盘上已存在、未 --force):先出声再记账——盘面与包源不一致即本地已改,WARN 保证差异在安装输出可见。
88
+ // 无台账条目的首次见面按盘面现状建立基线与锚;已有条目则原样保留(锚停在安装时刻值,盘面手改
89
+ // 继续由 doctor gate 安装锚校验留痕——重锚会把手改吸收成「无差异」,违背防改锚初衷)。
90
+ for (const name of skipped) {
91
+ const rel = `.agents/hooks/${name}`;
92
+ const known = ownedLedger.has(rel);
93
+ if (shaText(path.join(hooksDir, name)) !== shaText(path.join(srcRoot, name))) {
94
+ console.log(known
95
+ ? ` ⚠️ ${name} 盘面与包源不一致(本地已改)——原锚保留,手改由 doctor 锚校验留痕;重装覆盖用 --force`
96
+ : ` ⚠️ ${name} 盘面与包源不一致(本地已改),锚记盘面现状——重装覆盖用 --force`);
97
+ }
98
+ if (!known) {
99
+ const diskSha = shaText(path.join(hooksDir, name));
100
+ ownedLedger.set(rel, { rel, sha256: diskSha, srcSha256: diskSha });
101
+ }
102
+ }
80
103
  for (const name of installed) {
81
104
  const rel = `.agents/hooks/${name}`;
82
- ownedLedger.set(rel, { rel, sha256: shaText(path.join(hooksDir, name)) });
105
+ // srcSha256=安装时刻包源文件 sha(gate 防改锚,见文件头注):sha256 被 sync 按盘面自愈,锚恒定
106
+ ownedLedger.set(rel, { rel, sha256: shaText(path.join(hooksDir, name)), srcSha256: shaText(path.join(srcRoot, name)) });
83
107
  }
84
108
  if (wiredLp) {
85
109
  const lpRel = '.agents/hooks/local-pre-commit';
@@ -0,0 +1,103 @@
1
+ #!/usr/bin/env node
2
+ // add-gate.test.mjs — gate 防改锚(2026-10-11 P3-1)装户端到端测试。
3
+ // 手法:真实 bin/flow-kit.mjs init 建临时装户(fresh-init.test.mjs 同款)→ CLI add-gate test-protect,
4
+ // 断言 kit.json owned:逐字拷贝的 gate 脚本带 srcSha256=安装时刻包源文件 LF 归一 sha;
5
+ // local-pre-commit(合并接线件,非逐字拷贝)不写 srcSha256。再覆盖三条锚路径——
6
+ // ①幂等重跑(盘面=包源)安静且锚不动;②盘面手改后重跑(未 --force)WARN 差异 + 原锚保留
7
+ // (doctor checkGateAnchors 端到端抓到手改);③--force 重装重锚。
8
+ // 用法:node src/add-gate.test.mjs
9
+ import { spawnSync } from 'node:child_process';
10
+ import fs from 'node:fs';
11
+ import os from 'node:os';
12
+ import path from 'node:path';
13
+ import { createHash } from 'node:crypto';
14
+ import { fileURLToPath, pathToFileURL } from 'node:url';
15
+
16
+ const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
17
+ const CLI = path.join(ROOT, 'bin', 'flow-kit.mjs');
18
+ const GATE = 'test-protect';
19
+ const GATE_REL = `.agents/hooks/check-test-protect.mjs`;
20
+ const LP_REL = '.agents/hooks/local-pre-commit';
21
+ const PKG_GATE_SRC = path.join(ROOT, 'modules', 'gates', GATE, 'check-test-protect.mjs');
22
+
23
+ // checkGateAnchors 端到端联动:add-gate 写下的锚正是 doctor 锚校验读取的判据(耦合面单独断言)
24
+ const { checkGateAnchors } = await import(pathToFileURL(path.join(ROOT, 'src', 'doctor.mjs')).href);
25
+
26
+ let pass = 0;
27
+ let fail = 0;
28
+ const check = (name, cond, detail = '') => {
29
+ if (cond) { pass++; console.log(`PASS ${name}`); }
30
+ else { fail++; console.log(`FAIL ${name}${detail ? `\n ${detail}` : ''}`); }
31
+ };
32
+ // LF 归一 sha(与 add-gate shaText / doctor checkGateAnchors 同口径,跨 checkout 字节稳定)
33
+ const shaOf = (p) => createHash('sha256').update(fs.readFileSync(p, 'utf8').replace(/\r\n/g, '\n'), 'utf8').digest('hex');
34
+ const R = (p) => fs.readFileSync(p, 'utf8');
35
+
36
+ // ---- 建临时装户:git init + 真实 CLI init(fresh-init.test.mjs 同款)----
37
+ const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'fk-addgate-'));
38
+ spawnSync(process.platform === 'win32' ? 'git.exe' : 'git', ['init', '-q'], { cwd: dir });
39
+ const init = spawnSync(process.execPath, [CLI, 'init', '--stack', 'none', '--hosts', 'claude', '--board-port', '8941', '--dir', dir], { encoding: 'utf8', timeout: 120000 });
40
+ if (init.status !== 0) {
41
+ console.error(`add-gate.test.mjs:前置 init 失败无法继续\n${(init.stdout || '') + (init.stderr || '')}`);
42
+ process.exit(1);
43
+ }
44
+ const kitOf = () => JSON.parse(R(path.join(dir, '.agents', 'kit.json')));
45
+ const gateEntry = () => kitOf().owned.find((f) => f.rel === GATE_REL);
46
+
47
+ // ---- 场景 1:首装——逐字拷贝件写锚=包源 sha;local-pre-commit 不写锚 ----
48
+ {
49
+ const r = spawnSync(process.execPath, [CLI, 'add-gate', GATE, '--dir', dir], { encoding: 'utf8' });
50
+ const out = r.stdout + r.stderr;
51
+ check('S1 add-gate exit 0', r.status === 0, `exit=${r.status}\n${out.slice(-400)}`);
52
+ const gate = gateEntry();
53
+ check('S1 gate 脚本带 srcSha256=包源文件 LF 归一 sha(安装时刻包源)', !!gate && gate.srcSha256 === shaOf(PKG_GATE_SRC), JSON.stringify(gate || null));
54
+ check('S1 gate 台账 sha256=盘面(LF 归一记账)', !!gate && gate.sha256 === shaOf(path.join(dir, GATE_REL)), JSON.stringify(gate || null));
55
+ check('S1 门禁脚本落盘且与包源一致(逐字拷贝)', R(path.join(dir, GATE_REL)) === R(PKG_GATE_SRC));
56
+ const lp = kitOf().owned.find((f) => f.rel === LP_REL);
57
+ check('S1 local-pre-commit(合并接线件)不写 srcSha256', !!lp && lp.srcSha256 === undefined, JSON.stringify(lp || null));
58
+ check('S1 local-pre-commit 台账 sha256 刷为接线后盘面', !!lp && lp.sha256 === shaOf(path.join(dir, LP_REL)), JSON.stringify(lp || null));
59
+ check('S1 首装输出无盘面/包源差异 WARN', !out.includes('盘面与包源不一致'), out);
60
+ }
61
+
62
+ // ---- 场景 2:幂等重跑(未 --force、盘面=包源)——安静,条目原样 ----
63
+ {
64
+ const before = JSON.stringify(gateEntry());
65
+ const r = spawnSync(process.execPath, [CLI, 'add-gate', GATE, '--dir', dir], { encoding: 'utf8' });
66
+ const out = r.stdout + r.stderr;
67
+ check('S2 幂等重跑 exit 0 且无差异 WARN', r.status === 0 && !out.includes('盘面与包源不一致'), out);
68
+ check('S2 锚与台账条目原样', JSON.stringify(gateEntry()) === before, `${before} → ${JSON.stringify(gateEntry())}`);
69
+ }
70
+
71
+ // ---- 场景 3:盘面手改后重跑(未 --force)——WARN 差异可见,原锚保留(手改永久留痕)----
72
+ {
73
+ fs.writeFileSync(path.join(dir, GATE_REL), `${R(PKG_GATE_SRC)}\n// 本地手改:放宽红线(测试标记)\n`);
74
+ const before = gateEntry();
75
+ const r = spawnSync(process.execPath, [CLI, 'add-gate', GATE, '--dir', dir], { encoding: 'utf8' });
76
+ const out = r.stdout + r.stderr;
77
+ const after = gateEntry();
78
+ check('S3 手改后重跑出 WARN(盘面与包源不一致,含文件名)', out.includes('盘面与包源不一致') && out.includes('check-test-protect.mjs'), out);
79
+ check('S3 已有台账条目 → WARN 指明原锚保留', out.includes('原锚保留'), out);
80
+ check('S3 原锚保留(未被盘面重锚——重锚会把手改吸收成无差异)', after.srcSha256 === before.srcSha256 && after.srcSha256 === shaOf(PKG_GATE_SRC), `${JSON.stringify(before)} → ${JSON.stringify(after)}`);
81
+ check('S3 台账 sha256 亦不被改写(未 --force 不动既有条目)', after.sha256 === before.sha256, `${JSON.stringify(before)} → ${JSON.stringify(after)}`);
82
+ check('S3 手改盘面幸存(未 --force 不覆盖)', R(path.join(dir, GATE_REL)).includes('本地手改'), R(path.join(dir, GATE_REL)).slice(-120));
83
+ const d = checkGateAnchors(dir);
84
+ check('S3 doctor 锚校验按 add-gate 写下的锚抓到手改(端到端)', d.skipped === false && d.mismatch.includes(GATE_REL), JSON.stringify(d));
85
+ }
86
+
87
+ // ---- 场景 4:--force 重装——盘面恢复包源 + 锚随新安装刷新(重锚路径)----
88
+ {
89
+ const r = spawnSync(process.execPath, [CLI, 'add-gate', GATE, '--dir', dir, '--force'], { encoding: 'utf8' });
90
+ const out = r.stdout + r.stderr;
91
+ const gate = gateEntry();
92
+ check('S4 --force 重装恢复包源内容', R(path.join(dir, GATE_REL)) === R(PKG_GATE_SRC));
93
+ check('S4 锚随新安装刷新(srcSha256=包源 sha)', !!gate && gate.srcSha256 === shaOf(PKG_GATE_SRC), JSON.stringify(gate || null));
94
+ check('S4 台账 sha256 回到包面值', !!gate && gate.sha256 === shaOf(PKG_GATE_SRC), JSON.stringify(gate || null));
95
+ check('S4 输出含安装报告', out.includes('安装到'), out);
96
+ const d = checkGateAnchors(dir);
97
+ check('S4 重锚后 doctor 锚校验回到无失配', d.skipped === false && d.mismatch.length === 0 && d.gone.length === 0 && d.total >= 1, JSON.stringify(d));
98
+ }
99
+
100
+ fs.rmSync(dir, { recursive: true, force: true });
101
+
102
+ console.log(`\n合计: PASS ${pass} / FAIL ${fail}`);
103
+ process.exit(fail ? 1 : 0);
package/src/cli.mjs CHANGED
@@ -1,11 +1,13 @@
1
1
  #!/usr/bin/env node
2
- // flow-kit CLI 入口:init(安装)/ sync(升级)/ add-host(补宿主)/ add-gate(装门禁)/ doctor(体检)/ sync-hosts(跨宿主同步)/ help
2
+ // flow-kit CLI 入口:init(安装)/ sync(升级)/ add-host(补宿主)/ add-gate(装门禁)/ doctor(体检)/ validate(只读校验)/ sync-hosts(跨宿主同步)/ help
3
3
  import { init } from './init.mjs';
4
4
  import { doctor } from './doctor.mjs';
5
+ import { validate } from './validate.mjs';
5
6
  import { sync } from './sync.mjs';
6
7
  import { syncHosts } from './sync-hosts.mjs';
7
8
  import { addHost } from './add-host.mjs';
8
9
  import { addGate } from './add-gate.mjs';
10
+ import { route, runPipeline } from './executor.mjs';
9
11
  import { existsSync, readFileSync, readdirSync } from 'node:fs';
10
12
  import { fileURLToPath } from 'node:url';
11
13
  import path from 'node:path';
@@ -37,8 +39,29 @@ export const HELP = `flow-kit — AI-Native 闭环工作流 + wiki 知识层脚
37
39
  flow-kit sync-hosts 跨宿主适配层同步:templates/_agents/{commands,roles}/*.md 权威源 vs
38
40
  modules/hosts/<h>/{agents,commands}/*.md 薄适配——默认 --diff 输出报告;
39
41
  --apply 单向同步(权威→薄适配,不反向避免污染);
42
+ --strict 漂移判红(CI 机器门用;默认 --diff 恒 exit 0,报告器语义);
40
43
  改一处权威源要同步 N 份薄适配,人工 grep 易漏
41
44
  flow-kit doctor 体检:目录布局 / git 钩子 / managed 清单 / 索引漂移 / 跨宿主漂移 / check-loop
45
+ flow-kit validate 只读校验:包内置 check-loop 引擎对装户盘面跑闭环 20 项检查(不执行装户侧脚本,
46
+ 不改文档台账);明细走 stderr,stdout 承载汇总——0/1 退出码可作 CI 独立一道门。
47
+ 与 doctor 的分工:doctor 查「装得健不健康」(含装户侧引擎校验后执行),
48
+ validate 查「盘面内容合不合规」(判定引擎随包版本走)
49
+
50
+ ── 执行面(引擎执行器:手动路由 + 自动流水线)─────────────────────────
51
+ md 指令与 md 子代理仍装在装户项目(.agents/commands、.agents/roles),
52
+ 宿主读它们;本 CLI 不复制、不改写它们的正文。执行代码亦留在装户
53
+ .agents/scripts/,包只做薄壳转发与判定面。
54
+ flow-kit route 手动路由的机器面:定级(就高不就低 + 路径下限)+ 判据清单 + 泳道 + 下一阶段
55
+ + 该读的 md 指令路径。判据单源 = .agents/scripts/level-criteria.mjs;
56
+ 路径下限清单 = .agents/level-hints.txt(装户自持、内容项目私有,默认空)。
57
+ **诚实边界**:级别是意图面的语义判定(「一处定义、多处消费」),机器判不了语义;
58
+ 未配 hints 时按 L1 起步并提示补配置,绝不假装判得出。
59
+ 选项:--kind require|fix|verify|review|deploy | --level L0|L1|L2|L3
60
+ --files "a,b"(改动文件,参与路径下限判定)| --dir <目录> | --json
61
+ flow-kit run <子命令> 自动流水线:薄壳转发装户 pipeline-run 状态机
62
+ (start / next / status / watch / abort),参数与退出码原样透传。
63
+ 驱动协议与停机点语义见 .agents/commands/pipeline-run.md(宿主面权威)。
64
+ 本命令绝不 spawn AI 会话 / 不伪造原话 / 不带 --no-verify。
42
65
 
43
66
  init 选项(全部可选,均有默认值):
44
67
  --stack <技术栈> dotnet | node(ts/js) | python | go | none(默认 none;ts/js/typescript/javascript
@@ -52,9 +75,12 @@ init 选项(全部可选,均有默认值):
52
75
  --force 覆盖已存在的同名文件(默认保守跳过)
53
76
 
54
77
  sync / add-host 选项:--dir <目录>、--force(覆盖本地已改 / 已装内容);add-gate 选项:--dir <目录>、--force。
78
+ validate 选项:--strict(advisory warning 也判红)/ --json(机器可读,stdout)/ --dir <目录>(目标项目根,默认当前目录)。
55
79
  sync-hosts 选项:--diff(默认,仅报告,不修改)/ --apply(单向同步到薄适配)/ --json(机器可读输出)/ --dir <目录>(目标项目根,默认当前目录)。
56
- sync-hosts 双布局(2026-10-07):包源仓(含 templates/_agents + modules/hosts)比对 templates/_agents ↔ modules/hosts;
57
- 装户仓(含 .agents)比对 .agents ↔ 各宿主目录(.opencode/.trae/.omp/.zcode…)——同一命令两处都可用。
80
+ sync-hosts 只在包源仓运行(需要 templates/_agents 与 modules/hosts):比对 templates/_agents ↔ modules/hosts。
81
+ 装户的宿主文件由 init / add-host 写入;刷新用 add-host <宿主> --force。
82
+ route 选项:--kind / --level / --files / --dir <目录>(目标项目根,默认当前目录)/ --json(机器可读)。
83
+ run 参数:除 --dir 外原样透传给装户 pipeline-run(--hint / --triage / --delegated / --files / --run / --json / --adopt / --to / --interval)。
58
84
 
59
85
  示例:
60
86
  npx agentic-flow-kit init # 交互模式:宿主 → 技术栈 → 端口 → 确认安装
@@ -62,10 +88,20 @@ sync-hosts 双布局(2026-10-07):包源仓(含 templates/_agents + modul
62
88
  npx agentic-flow-kit sync # 包出新版后升级(本地改过的 managed 文件会跳过并报告)
63
89
  npx agentic-flow-kit add-host opencode # 后补宿主
64
90
  npx agentic-flow-kit add-gate dotnet-ca # 装 Clean Architecture 门禁
91
+ npx agentic-flow-kit doctor # 体检
92
+ npx agentic-flow-kit validate --strict # 只读结构校验(CI 可用,0/1 退出码)
65
93
  npx agentic-flow-kit sync-hosts --diff # 看权威源 vs 薄适配漂移
66
94
  npx agentic-flow-kit sync-hosts --apply # 单向同步到薄适配
95
+ npx agentic-flow-kit route --kind require --level L1 --files "src/a.ts,src/b.ts"
96
+ npx agentic-flow-kit run start "给导入功能加审计字段"
97
+ npx agentic-flow-kit run next --delegated "可以"
98
+
99
+ 装完本地可跑:日常闭环走项目内 .agents/scripts/(零 npm 运行时依赖);升级 / 体检 / 装门禁用 npx agentic-flow-kit(sync / doctor / add-host / add-gate);AGENTS.md 生成「AI工作流 + Wiki」骨架,项目细节在「项目适配区」自填。`;
67
100
 
68
- 装完即自包含:项目不依赖本包运行;AGENTS.md 生成「AI工作流 + Wiki」骨架,项目细节在「项目适配区」自填。`;
101
+ // errText:异步命令失败的统一输出。带 code 的错误把 code 一并打出来——
102
+ // 例:flow-kit route 遇非法 level-hints 会抛 e.code = LEVEL_HINTS_INVALID,
103
+ // 只打 message 等于把机器可判的错误类别在 CLI 边界扔掉(路径与行号仍在 message 里)。
104
+ const errText = (e) => `❌ ${e?.code ? `[${e.code}] ` : ''}${e?.message || e}`;
69
105
 
70
106
  export function run(argv) {
71
107
  const cmd = argv[0];
@@ -80,7 +116,7 @@ export function run(argv) {
80
116
  }
81
117
  if (cmd === 'init') {
82
118
  init(argv.slice(1), PKG_ROOT).catch((e) => {
83
- console.error(`❌ ${e?.message || e}`);
119
+ console.error(errText(e));
84
120
  process.exit(1);
85
121
  });
86
122
  return;
@@ -106,6 +142,24 @@ export function run(argv) {
106
142
  doctor(argv.slice(1), PKG_ROOT);
107
143
  return;
108
144
  }
145
+ if (cmd === 'validate') {
146
+ validate(argv.slice(1), PKG_ROOT).catch((e) => {
147
+ console.error(errText(e));
148
+ process.exit(1);
149
+ });
150
+ return;
151
+ }
152
+ if (cmd === 'route') {
153
+ route(argv.slice(1)).catch((e) => {
154
+ console.error(errText(e));
155
+ process.exit(1);
156
+ });
157
+ return;
158
+ }
159
+ if (cmd === 'run') {
160
+ runPipeline(argv.slice(1));
161
+ return;
162
+ }
109
163
  console.error(`未知命令:${cmd}\n\n${HELP}`);
110
164
  process.exit(1);
111
165
  }