@dommaker/harness 0.19.0 → 1.0.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 (348) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/bin/harness.js +136 -557
  3. package/dist/cli/commands/check.d.ts.map +1 -1
  4. package/dist/cli/commands/check.js +2 -13
  5. package/dist/cli/commands/check.js.map +1 -1
  6. package/dist/cli/commands/definitions.d.ts +90 -0
  7. package/dist/cli/commands/definitions.d.ts.map +1 -0
  8. package/dist/cli/commands/definitions.js +519 -0
  9. package/dist/cli/commands/definitions.js.map +1 -0
  10. package/dist/cli/commands/knowledge.js.map +1 -1
  11. package/dist/cli/commands/sync-docs/capabilities-syncer.d.ts +3 -25
  12. package/dist/cli/commands/sync-docs/capabilities-syncer.d.ts.map +1 -1
  13. package/dist/cli/commands/sync-docs/capabilities-syncer.js +3 -93
  14. package/dist/cli/commands/sync-docs/capabilities-syncer.js.map +1 -1
  15. package/dist/cli/commands/sync-docs/index.d.ts +1 -1
  16. package/dist/cli/commands/sync-docs/index.d.ts.map +1 -1
  17. package/dist/cli/commands/sync-docs/index.js +4 -4
  18. package/dist/cli/commands/sync-docs/index.js.map +1 -1
  19. package/dist/context/index.d.ts +1 -5
  20. package/dist/context/index.d.ts.map +1 -1
  21. package/dist/context/index.js +1 -5
  22. package/dist/context/index.js.map +1 -1
  23. package/dist/context/knowledge-injector.d.ts +3 -3
  24. package/dist/context/knowledge-injector.d.ts.map +1 -1
  25. package/dist/context/knowledge-injector.js +1 -1
  26. package/dist/context/session-manager.d.ts +1 -12
  27. package/dist/context/session-manager.d.ts.map +1 -1
  28. package/dist/context/session-manager.js +0 -63
  29. package/dist/context/session-manager.js.map +1 -1
  30. package/dist/context/types.d.ts +1 -39
  31. package/dist/context/types.d.ts.map +1 -1
  32. package/dist/context/types.js +2 -15
  33. package/dist/context/types.js.map +1 -1
  34. package/dist/core/constraints/agent-prompt-renderer.d.ts +1 -1
  35. package/dist/core/constraints/agent-prompt-renderer.js +1 -1
  36. package/dist/core/constraints/capabilities-parser.d.ts +17 -2
  37. package/dist/core/constraints/capabilities-parser.d.ts.map +1 -1
  38. package/dist/core/constraints/capabilities-parser.js +84 -2
  39. package/dist/core/constraints/capabilities-parser.js.map +1 -1
  40. package/dist/core/constraints/checker.d.ts +3 -17
  41. package/dist/core/constraints/checker.d.ts.map +1 -1
  42. package/dist/core/constraints/checker.js +7 -47
  43. package/dist/core/constraints/checker.js.map +1 -1
  44. package/dist/core/constraints/definitions.d.ts +0 -7
  45. package/dist/core/constraints/definitions.d.ts.map +1 -1
  46. package/dist/core/constraints/definitions.js +1 -8
  47. package/dist/core/constraints/definitions.js.map +1 -1
  48. package/dist/core/constraints/doc-freshness/runner.d.ts +0 -2
  49. package/dist/core/constraints/doc-freshness/runner.d.ts.map +1 -1
  50. package/dist/core/constraints/doc-freshness/runner.js.map +1 -1
  51. package/dist/core/constraints/index.d.ts +1 -1
  52. package/dist/core/constraints/index.d.ts.map +1 -1
  53. package/dist/core/constraints/index.js +2 -3
  54. package/dist/core/constraints/index.js.map +1 -1
  55. package/dist/core/constraints/interceptor.d.ts.map +1 -1
  56. package/dist/core/constraints/interceptor.js +1 -5
  57. package/dist/core/constraints/interceptor.js.map +1 -1
  58. package/dist/core/effective-constraints.d.ts.map +1 -1
  59. package/dist/core/effective-constraints.js +0 -1
  60. package/dist/core/effective-constraints.js.map +1 -1
  61. package/dist/core/project-config-loader.d.ts.map +1 -1
  62. package/dist/core/project-config-loader.js +1 -8
  63. package/dist/core/project-config-loader.js.map +1 -1
  64. package/dist/dashboard/stats.d.ts.map +1 -1
  65. package/dist/dashboard/stats.js.map +1 -1
  66. package/dist/dashboard/types.d.ts +2 -2
  67. package/dist/dashboard/types.d.ts.map +1 -1
  68. package/dist/failure/constraint-handler.d.ts.map +1 -1
  69. package/dist/failure/constraint-handler.js +0 -2
  70. package/dist/failure/constraint-handler.js.map +1 -1
  71. package/dist/gates/acceptance.d.ts +9 -1
  72. package/dist/gates/acceptance.d.ts.map +1 -1
  73. package/dist/gates/acceptance.js +21 -0
  74. package/dist/gates/acceptance.js.map +1 -1
  75. package/dist/gates/checker-gate.d.ts +23 -0
  76. package/dist/gates/checker-gate.d.ts.map +1 -0
  77. package/dist/gates/checker-gate.js +53 -0
  78. package/dist/gates/checker-gate.js.map +1 -0
  79. package/dist/gates/command.d.ts +9 -2
  80. package/dist/gates/command.d.ts.map +1 -1
  81. package/dist/gates/command.js +10 -0
  82. package/dist/gates/command.js.map +1 -1
  83. package/dist/gates/contract.d.ts +8 -2
  84. package/dist/gates/contract.d.ts.map +1 -1
  85. package/dist/gates/contract.js +9 -0
  86. package/dist/gates/contract.js.map +1 -1
  87. package/dist/gates/decision.d.ts +17 -0
  88. package/dist/gates/decision.d.ts.map +1 -0
  89. package/dist/gates/decision.js +25 -0
  90. package/dist/gates/decision.js.map +1 -0
  91. package/dist/gates/definitions.d.ts +63 -0
  92. package/dist/gates/definitions.d.ts.map +1 -0
  93. package/dist/gates/definitions.js +160 -0
  94. package/dist/gates/definitions.js.map +1 -0
  95. package/dist/gates/effective-gates.d.ts +30 -0
  96. package/dist/gates/effective-gates.d.ts.map +1 -0
  97. package/dist/gates/effective-gates.js +85 -0
  98. package/dist/gates/effective-gates.js.map +1 -0
  99. package/dist/gates/index.d.ts +25 -1
  100. package/dist/gates/index.d.ts.map +1 -1
  101. package/dist/gates/index.js +37 -1
  102. package/dist/gates/index.js.map +1 -1
  103. package/dist/gates/performance.d.ts +8 -2
  104. package/dist/gates/performance.d.ts.map +1 -1
  105. package/dist/gates/performance.js +9 -0
  106. package/dist/gates/performance.js.map +1 -1
  107. package/dist/gates/registry.d.ts +32 -0
  108. package/dist/gates/registry.d.ts.map +1 -0
  109. package/dist/gates/registry.js +90 -0
  110. package/dist/gates/registry.js.map +1 -0
  111. package/dist/gates/review.d.ts +8 -2
  112. package/dist/gates/review.d.ts.map +1 -1
  113. package/dist/gates/review.js +9 -0
  114. package/dist/gates/review.js.map +1 -1
  115. package/dist/gates/runner.d.ts +30 -0
  116. package/dist/gates/runner.d.ts.map +1 -0
  117. package/dist/gates/runner.js +38 -0
  118. package/dist/gates/runner.js.map +1 -0
  119. package/dist/gates/security.d.ts +8 -2
  120. package/dist/gates/security.d.ts.map +1 -1
  121. package/dist/gates/security.js +9 -0
  122. package/dist/gates/security.js.map +1 -1
  123. package/dist/gates/types.d.ts +41 -1
  124. package/dist/gates/types.d.ts.map +1 -1
  125. package/dist/hooks/bootstrap.d.ts.map +1 -1
  126. package/dist/hooks/bootstrap.js +0 -2
  127. package/dist/hooks/bootstrap.js.map +1 -1
  128. package/dist/hooks/config.d.ts +26 -0
  129. package/dist/hooks/config.d.ts.map +1 -0
  130. package/dist/hooks/config.js +30 -0
  131. package/dist/hooks/config.js.map +1 -0
  132. package/dist/hooks/index.d.ts +2 -1
  133. package/dist/hooks/index.d.ts.map +1 -1
  134. package/dist/hooks/index.js +4 -1
  135. package/dist/hooks/index.js.map +1 -1
  136. package/dist/hooks/registry.d.ts +18 -1
  137. package/dist/hooks/registry.d.ts.map +1 -1
  138. package/dist/hooks/registry.js +45 -0
  139. package/dist/hooks/registry.js.map +1 -1
  140. package/dist/hooks/types.d.ts +20 -0
  141. package/dist/hooks/types.d.ts.map +1 -1
  142. package/dist/index.d.ts +4 -8
  143. package/dist/index.d.ts.map +1 -1
  144. package/dist/index.js +5 -20
  145. package/dist/index.js.map +1 -1
  146. package/dist/knowledge/import.d.ts +2 -2
  147. package/dist/knowledge/import.d.ts.map +1 -1
  148. package/dist/knowledge/ingest.js.map +1 -1
  149. package/dist/knowledge/lifecycle-hooks.d.ts +2 -2
  150. package/dist/knowledge/lifecycle-hooks.d.ts.map +1 -1
  151. package/dist/knowledge/types.d.ts +5 -7
  152. package/dist/knowledge/types.d.ts.map +1 -1
  153. package/dist/knowledge/types.js +1 -1
  154. package/dist/knowledge/types.js.map +1 -1
  155. package/dist/monitoring/constraint-doctor.d.ts +4 -22
  156. package/dist/monitoring/constraint-doctor.d.ts.map +1 -1
  157. package/dist/monitoring/constraint-doctor.js +7 -94
  158. package/dist/monitoring/constraint-doctor.js.map +1 -1
  159. package/dist/presets/standard.d.ts +1 -1
  160. package/dist/presets/standard.d.ts.map +1 -1
  161. package/dist/presets/standard.js +1 -2
  162. package/dist/presets/standard.js.map +1 -1
  163. package/dist/spec/annotation-checker.d.ts.map +1 -1
  164. package/dist/spec/annotation-checker.js +6 -26
  165. package/dist/spec/annotation-checker.js.map +1 -1
  166. package/dist/tools/index.d.ts +0 -4
  167. package/dist/tools/index.d.ts.map +1 -1
  168. package/dist/tools/index.js +0 -4
  169. package/dist/tools/index.js.map +1 -1
  170. package/dist/types/constraint.d.ts +1 -12
  171. package/dist/types/constraint.d.ts.map +1 -1
  172. package/dist/types/constraint.js +0 -3
  173. package/dist/types/constraint.js.map +1 -1
  174. package/dist/types/project-config.d.ts +0 -2
  175. package/dist/types/project-config.d.ts.map +1 -1
  176. package/dist/utils/file-walk.d.ts +2 -2
  177. package/dist/utils/file-walk.js +2 -2
  178. package/package.json +6 -1
  179. package/src/CONTEXT.md +14 -0
  180. package/src/__tests__/checker-extra.test.ts +2 -59
  181. package/src/__tests__/constraint-doctor.test.ts +1 -140
  182. package/src/__tests__/constraint-handler.test.ts +0 -4
  183. package/src/__tests__/project-config-loader-extra.test.ts +0 -20
  184. package/src/__tests__/project-config-loader.test.ts +0 -1
  185. package/src/cli/commands/CONTEXT.md +15 -7
  186. package/src/cli/commands/__tests__/check-drift.test.ts +0 -3
  187. package/src/cli/commands/__tests__/check-skip-output.test.ts +0 -5
  188. package/src/cli/commands/__tests__/check.test.ts +7 -75
  189. package/src/cli/commands/__tests__/registry.test.ts +201 -0
  190. package/src/cli/commands/check.ts +2 -14
  191. package/src/cli/commands/definitions.ts +593 -0
  192. package/src/cli/commands/knowledge.ts +3 -3
  193. package/src/cli/commands/sync-docs/capabilities-syncer.ts +4 -110
  194. package/src/cli/commands/sync-docs/index.ts +8 -5
  195. package/src/context/CONTEXT.md +2 -7
  196. package/src/context/__tests__/session-manager.test.ts +0 -91
  197. package/src/context/index.ts +1 -5
  198. package/src/context/knowledge-injector.ts +3 -3
  199. package/src/context/session-manager.ts +0 -74
  200. package/src/context/types.ts +2 -63
  201. package/src/core/constraints/__tests__/interceptor.test.ts +0 -2
  202. package/src/core/constraints/agent-prompt-renderer.ts +1 -1
  203. package/src/core/constraints/capabilities-parser.ts +95 -2
  204. package/src/core/constraints/checker.ts +8 -53
  205. package/src/core/constraints/definitions.ts +0 -8
  206. package/src/core/constraints/doc-freshness/runner.ts +1 -2
  207. package/src/core/constraints/index.ts +1 -2
  208. package/src/core/constraints/interceptor.ts +1 -6
  209. package/src/core/effective-constraints.ts +0 -1
  210. package/src/core/project-config-loader.ts +1 -7
  211. package/src/dashboard/stats.ts +2 -2
  212. package/src/dashboard/types.ts +2 -2
  213. package/src/failure/constraint-handler.ts +0 -2
  214. package/src/gates/CONTEXT.md +16 -13
  215. package/src/gates/__tests__/checker-gate.test.ts +45 -0
  216. package/src/gates/__tests__/contract.test.ts +73 -0
  217. package/src/gates/__tests__/effective-gates.test.ts +82 -0
  218. package/src/gates/__tests__/gate-interface.test.ts +202 -0
  219. package/src/gates/__tests__/registry.test.ts +87 -0
  220. package/src/gates/__tests__/runner.test.ts +81 -0
  221. package/src/gates/acceptance.ts +24 -1
  222. package/src/gates/checker-gate.ts +54 -0
  223. package/src/gates/command.ts +13 -2
  224. package/src/gates/contract.ts +12 -2
  225. package/src/gates/decision.ts +27 -0
  226. package/src/gates/definitions.ts +207 -0
  227. package/src/gates/effective-gates.ts +106 -0
  228. package/src/gates/index.ts +38 -0
  229. package/src/gates/performance.ts +12 -2
  230. package/src/gates/registry.ts +107 -0
  231. package/src/gates/review.ts +12 -2
  232. package/src/gates/runner.ts +57 -0
  233. package/src/gates/security.ts +12 -2
  234. package/src/gates/types.ts +48 -1
  235. package/src/hooks/CONTEXT.md +12 -2
  236. package/src/hooks/__tests__/bootstrap.test.ts +0 -1
  237. package/src/hooks/__tests__/config.test.ts +19 -0
  238. package/src/hooks/__tests__/pipeline.test.ts +79 -0
  239. package/src/hooks/__tests__/registry.test.ts +67 -0
  240. package/src/hooks/bootstrap.ts +0 -2
  241. package/src/hooks/config.ts +29 -0
  242. package/src/hooks/index.ts +2 -1
  243. package/src/hooks/registry.ts +60 -1
  244. package/src/hooks/types.ts +21 -0
  245. package/src/index.ts +5 -22
  246. package/src/knowledge/import.ts +3 -3
  247. package/src/knowledge/ingest.ts +4 -4
  248. package/src/knowledge/lifecycle-hooks.ts +3 -3
  249. package/src/knowledge/types.ts +5 -8
  250. package/src/monitoring/constraint-doctor.ts +7 -106
  251. package/src/presets/__tests__/standard.test.ts +0 -2
  252. package/src/presets/standard.ts +1 -2
  253. package/src/spec/__tests__/annotation-checker.test.ts +9 -3
  254. package/src/spec/annotation-checker.ts +7 -29
  255. package/src/tools/CONTEXT.md +7 -14
  256. package/src/tools/index.ts +0 -4
  257. package/src/types/constraint.ts +1 -14
  258. package/src/types/project-config.ts +0 -3
  259. package/src/utils/file-walk.ts +2 -2
  260. package/dist/architecture/constraint-engine.d.ts +0 -67
  261. package/dist/architecture/constraint-engine.d.ts.map +0 -1
  262. package/dist/architecture/constraint-engine.js +0 -295
  263. package/dist/architecture/constraint-engine.js.map +0 -1
  264. package/dist/architecture/cross-project-checker.d.ts +0 -54
  265. package/dist/architecture/cross-project-checker.d.ts.map +0 -1
  266. package/dist/architecture/cross-project-checker.js +0 -467
  267. package/dist/architecture/cross-project-checker.js.map +0 -1
  268. package/dist/cli/commands/index.d.ts +0 -30
  269. package/dist/cli/commands/index.d.ts.map +0 -1
  270. package/dist/cli/commands/index.js +0 -91
  271. package/dist/cli/commands/index.js.map +0 -1
  272. package/dist/context/file-budget.d.ts +0 -40
  273. package/dist/context/file-budget.d.ts.map +0 -1
  274. package/dist/context/file-budget.js +0 -147
  275. package/dist/context/file-budget.js.map +0 -1
  276. package/dist/context/progressive-loader.d.ts +0 -109
  277. package/dist/context/progressive-loader.d.ts.map +0 -1
  278. package/dist/context/progressive-loader.js +0 -166
  279. package/dist/context/progressive-loader.js.map +0 -1
  280. package/dist/context/token-pipeline.d.ts +0 -55
  281. package/dist/context/token-pipeline.d.ts.map +0 -1
  282. package/dist/context/token-pipeline.js +0 -220
  283. package/dist/context/token-pipeline.js.map +0 -1
  284. package/dist/context/tool-output-budget.d.ts +0 -59
  285. package/dist/context/tool-output-budget.d.ts.map +0 -1
  286. package/dist/context/tool-output-budget.js +0 -177
  287. package/dist/context/tool-output-budget.js.map +0 -1
  288. package/dist/core/constraints/default-executors.d.ts +0 -10
  289. package/dist/core/constraints/default-executors.d.ts.map +0 -1
  290. package/dist/core/constraints/default-executors.js +0 -120
  291. package/dist/core/constraints/default-executors.js.map +0 -1
  292. package/dist/llm/adapter.d.ts +0 -36
  293. package/dist/llm/adapter.d.ts.map +0 -1
  294. package/dist/llm/adapter.js +0 -118
  295. package/dist/llm/adapter.js.map +0 -1
  296. package/dist/llm/index.d.ts +0 -3
  297. package/dist/llm/index.d.ts.map +0 -1
  298. package/dist/llm/index.js +0 -19
  299. package/dist/llm/index.js.map +0 -1
  300. package/dist/llm/types.d.ts +0 -62
  301. package/dist/llm/types.d.ts.map +0 -1
  302. package/dist/llm/types.js +0 -8
  303. package/dist/llm/types.js.map +0 -1
  304. package/dist/tools/core/index.d.ts +0 -13
  305. package/dist/tools/core/index.d.ts.map +0 -1
  306. package/dist/tools/core/index.js +0 -198
  307. package/dist/tools/core/index.js.map +0 -1
  308. package/dist/tools/loader.d.ts +0 -21
  309. package/dist/tools/loader.d.ts.map +0 -1
  310. package/dist/tools/loader.js +0 -199
  311. package/dist/tools/loader.js.map +0 -1
  312. package/dist/tools/registry.d.ts +0 -59
  313. package/dist/tools/registry.d.ts.map +0 -1
  314. package/dist/tools/registry.js +0 -115
  315. package/dist/tools/registry.js.map +0 -1
  316. package/dist/tools/types.d.ts +0 -38
  317. package/dist/tools/types.d.ts.map +0 -1
  318. package/dist/tools/types.js +0 -6
  319. package/dist/tools/types.js.map +0 -1
  320. package/src/__tests__/architecture-engine.test.ts +0 -619
  321. package/src/__tests__/context/progressive-loader.test.ts +0 -131
  322. package/src/__tests__/cross-project-checker.test.ts +0 -318
  323. package/src/architecture/CONTEXT.md +0 -22
  324. package/src/architecture/constraint-engine.ts +0 -351
  325. package/src/architecture/cross-project-checker.ts +0 -545
  326. package/src/cli/commands/index.ts +0 -30
  327. package/src/context/__tests__/file-budget.test.ts +0 -142
  328. package/src/context/__tests__/progressive-loader.test.ts +0 -264
  329. package/src/context/__tests__/token-pipeline.test.ts +0 -178
  330. package/src/context/__tests__/tool-output-budget.test.ts +0 -95
  331. package/src/context/file-budget.ts +0 -142
  332. package/src/context/progressive-loader.ts +0 -260
  333. package/src/context/token-pipeline.ts +0 -265
  334. package/src/context/tool-output-budget.ts +0 -178
  335. package/src/core/constraints/__tests__/default-executors.test.ts +0 -57
  336. package/src/core/constraints/default-executors.ts +0 -92
  337. package/src/llm/CONTEXT.md +0 -21
  338. package/src/llm/__tests__/adapter.test.ts +0 -172
  339. package/src/llm/adapter.ts +0 -149
  340. package/src/llm/index.ts +0 -2
  341. package/src/llm/types.ts +0 -81
  342. package/src/tools/__tests__/loader.test.ts +0 -252
  343. package/src/tools/__tests__/registry.test.ts +0 -157
  344. package/src/tools/core/__tests__/core.test.ts +0 -122
  345. package/src/tools/core/index.ts +0 -201
  346. package/src/tools/loader.ts +0 -216
  347. package/src/tools/registry.ts +0 -128
  348. package/src/tools/types.ts +0 -46
@@ -1,10 +1,16 @@
1
1
  # cli/commands/
2
2
 
3
3
  ## 职责
4
- CLI 子命令实现:24 个顶层命令 + constraints 治理子命令 report/retire(共 26 个命令文件),覆盖约束检查/门禁验证/文档同步/知识管理/失败诊断/发布/会话分析等。
4
+ CLI 子命令实现:24 个顶层命令 + constraints 治理子命令 report/retire,覆盖约束检查/门禁验证/文档同步/知识管理/失败诊断/发布/会话分析等。
5
5
 
6
- ## 核心导出(24 顶层命令)
7
- check / validate / passes-gate / init / report / status / spec / acceptance / performance / security / contract / review / command / sync-docs / knowledge / sdd / failure / posteval-plan / release / analyze-sessions / update-user-model / constraints / doc-freshness-check / spec-baseline-check
6
+ H5(#44)起:
7
+ - **命令定义即注册**:`definitions.ts` `COMMAND_DEFINITIONS` 是命令形状(名称/别名/位置参数/选项/子命令/实现引用)的单一来源;bin/harness.js 遍历本表注册表驱动生成,不再手写 commander 命令块,不再有 index.ts barrel 两处同步(R6)
8
+ - **per-command 懒加载**(O2):定义表存实现引用 `{ module, export }`,bin 只在 action 执行时 require 对应命令模块,任一命令执行不再加载全部命令实现
9
+
10
+ ## 核心导出
11
+ - `COMMAND_DEFINITIONS`(definitions.ts)— 全部非门禁命令定义(纯数据模块,禁止 import 命令实现)
12
+ - 各命令文件:check / validate / passes-gate / init / report / status / spec / sync-docs / knowledge / sdd / failure / posteval-plan / release / analyze-sessions / update-user-model / constraints / doc-freshness-check / spec-baseline-check
13
+ - 6 门禁命令实现在 `acceptance` / `command` / `contract` / `performance` / `review` / `security`(其 CLI 元数据在 `src/gates/definitions.ts`)
8
14
 
9
15
  `constraints` 下挂治理子命令:`constraints report`(使用统计 + 退役候选诊断 + 配置健康 + 注入漂移,`--export` 脱敏)、`constraints retire`(交互选择 + 人确认退役;带 id 直达需显式 `--yes`(#24 人确认闸门),无 `--yes` 报错 + 非零退出码且不落盘;内置落 config.yml retired 元数据,custom 落 custom-constraints.yml 条目 retired 段(#82 D6 一处真相)+ KnowledgeStore 沉淀 + CLAUDE.md 注入段同步)。
10
16
 
@@ -14,13 +20,15 @@ check / validate / passes-gate / init / report / status / spec / acceptance / pe
14
20
  - 依赖 `src/monitoring/` 追踪/诊断
15
21
  - 依赖 `src/knowledge/` 知识引擎
16
22
  - 依赖 `src/failure/` 失败记录
17
- - 被 `bin/harness.js` CLI 入口注册
23
+ - 被 `bin/harness.js` CLI 入口按定义表驱动生成
18
24
 
19
25
  ## 约定
20
- - 每个命令一个文件,命名与命令名一致
21
- - 命令必须在 index.ts 中注册导出
26
+ - 每个命令一个实现文件,命名与命令名一致(sync-docs 为模块族目录)
27
+ - **新增命令 = 命令实现文件 + definitions.ts 一条定义(含 CLI 元数据与实现引用)+ 测试**,不再改 bin/harness.js
28
+ - **definitions.ts 是纯数据模块**:禁止 import 任何命令实现/运行时依赖(保 --help/--version 懒加载);实现引用可解析性由 `__tests__/registry.test.ts` 构建/测试期断言
22
29
  - 命令选项类型命名规范:XxxOptions
23
30
 
24
31
  ## 注意事项
25
32
  - 新增命令需同步更新 CLAUDE.md / CAPABILITIES.md / src/CONTEXT.md
26
- - knowledge 命令包含 9 个子操作(list/search/import/decay/stats/upsert/sync-status/sync-rag)
33
+ - knowledge 命令包含 13 个子操作(list/search/import/decay/stats/upsert/sync-status/sync-rag/audit/snapshot/migrate/index/health)
34
+ - 特殊路由(选项条件、子命令兜底、退出码处理)表达在定义表的 optionRoutes / subcommands / afterRun 字段,bin 是纯通用引擎、不含单命令知识
@@ -16,7 +16,6 @@ import { getEffectiveConstraints } from '../../../core/effective-constraints';
16
16
 
17
17
  jest.mock('../../../core/constraints/checker', () => ({
18
18
  constraintChecker: {
19
- setCustomConfig: jest.fn(),
20
19
  setTraceRecorder: jest.fn(),
21
20
  checkConstraints: jest.fn(),
22
21
  },
@@ -58,9 +57,7 @@ describe('check 命令注入漂移警告', () => {
58
57
  passed: true,
59
58
  ironLaws: [],
60
59
  guidelines: [],
61
- tips: [],
62
60
  warningCount: 0,
63
- tipCount: 0,
64
61
  });
65
62
  });
66
63
 
@@ -29,7 +29,6 @@ jest.mock('child_process', () => ({
29
29
  // Mock constraintChecker
30
30
  jest.mock('../../../core/constraints/checker', () => ({
31
31
  constraintChecker: {
32
- setCustomConfig: jest.fn(),
33
32
  setTraceRecorder: jest.fn(),
34
33
  checkConstraints: jest.fn(),
35
34
  },
@@ -89,9 +88,7 @@ describe('check 命令 skip 输出', () => {
89
88
  { id: 'law_skip', level: 'iron_law', satisfied: true, skipped: true, checkedAt: new Date(), constraint: fakeConstraint('law_skip', 'iron_law') },
90
89
  ],
91
90
  guidelines: [],
92
- tips: [],
93
91
  warningCount: 0,
94
- tipCount: 0,
95
92
  });
96
93
 
97
94
  await check({ preset: 'default', staged: false });
@@ -113,9 +110,7 @@ describe('check 命令 skip 输出', () => {
113
110
  { id: 'g_pass', level: 'guideline', satisfied: true, checkedAt: new Date(), constraint: fakeConstraint('g_pass', 'guideline') },
114
111
  { id: 'g_skip', level: 'guideline', satisfied: true, skipped: true, checkedAt: new Date(), constraint: fakeConstraint('g_skip', 'guideline') },
115
112
  ],
116
- tips: [],
117
113
  warningCount: 0,
118
- tipCount: 0,
119
114
  });
120
115
 
121
116
  await check({ preset: 'default', staged: false });
@@ -40,7 +40,6 @@ jest.mock('child_process', () => ({
40
40
  // Mock constraintChecker
41
41
  jest.mock('../../../core/constraints/checker', () => ({
42
42
  constraintChecker: {
43
- setCustomConfig: jest.fn(),
44
43
  setTraceRecorder: jest.fn(),
45
44
  checkConstraints: jest.fn(),
46
45
  },
@@ -89,9 +88,7 @@ describe('check command', () => {
89
88
  passed: true,
90
89
  ironLaws: [{ id: 'test', level: 'iron_law', satisfied: true, checkedAt: new Date(), constraint: { kind: 'check' as const, id: 'test', rule: 'test', message: 'test', level: 'iron_law', trigger: 'code_implementation', enforcement: 'checkpoint-required' } }],
91
90
  guidelines: [],
92
- tips: [],
93
91
  warningCount: 0,
94
- tipCount: 0,
95
92
  });
96
93
 
97
94
  await check({ preset: 'default', staged: false });
@@ -103,9 +100,7 @@ describe('check command', () => {
103
100
  passed: false,
104
101
  ironLaws: [{ id: 'no_bypass_checkpoint', level: 'iron_law', satisfied: false, checkedAt: new Date(), constraint: { kind: 'check' as const, id: 'no_bypass_checkpoint', rule: 'test', message: 'test', level: 'iron_law', trigger: 'code_implementation', enforcement: 'checkpoint-required' } }],
105
102
  guidelines: [],
106
- tips: [],
107
103
  warningCount: 0,
108
- tipCount: 0,
109
104
  });
110
105
 
111
106
  const mockExit = jest.spyOn(process, 'exit').mockImplementation(() => undefined as never);
@@ -120,9 +115,7 @@ describe('check command', () => {
120
115
  passed: false,
121
116
  ironLaws: [],
122
117
  guidelines: [{ id: 'test_guideline', level: 'guideline', satisfied: false, checkedAt: new Date(), constraint: { kind: 'check' as const, id: 'test_guideline', rule: 'test', message: 'test', level: 'guideline', trigger: 'code_implementation', enforcement: 'warning' } }],
123
- tips: [],
124
118
  warningCount: 1,
125
- tipCount: 0,
126
119
  });
127
120
 
128
121
  await check({ preset: 'default', staged: false });
@@ -141,38 +134,23 @@ describe('check command', () => {
141
134
  passed: true,
142
135
  ironLaws: [],
143
136
  guidelines: [],
144
- tips: [],
145
137
  warningCount: 0,
146
- tipCount: 0,
147
138
  });
148
139
 
149
140
  await check({ preset: 'default', staged: false, projectPath: '/project' });
150
- expect(mockChecker.setCustomConfig).toHaveBeenCalled();
141
+ expect(mockChecker.checkConstraints).toHaveBeenCalledWith(
142
+ expect.anything(),
143
+ expect.objectContaining({ disabled: ['disabled_constraint'] })
144
+ );
151
145
  expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining('已禁用约束'));
152
146
  });
153
147
 
154
- it('应该显示提示信息', async () => {
155
- mockChecker.checkConstraints.mockResolvedValue({
156
- passed: true,
157
- ironLaws: [],
158
- guidelines: [],
159
- tips: [{ id: 'test_tip', level: 'tip', satisfied: false, checkedAt: new Date(), constraint: { kind: 'check' as const, id: 'test_tip', rule: 'test', message: 'test tip', level: 'tip', trigger: 'code_implementation', enforcement: 'info' } }],
160
- warningCount: 0,
161
- tipCount: 1,
162
- });
163
-
164
- await check({ preset: 'default', staged: false });
165
- expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining('提示'));
166
- });
167
-
168
148
  it('应该显示通过的指导原则', async () => {
169
149
  mockChecker.checkConstraints.mockResolvedValue({
170
150
  passed: true,
171
151
  ironLaws: [],
172
152
  guidelines: [{ id: 'test_guideline', level: 'guideline', satisfied: true, checkedAt: new Date(), constraint: { kind: 'check' as const, id: 'test_guideline', rule: 'test', message: 'test', level: 'guideline', trigger: 'code_implementation', enforcement: 'warning' } }],
173
- tips: [],
174
153
  warningCount: 0,
175
- tipCount: 0,
176
154
  });
177
155
 
178
156
  await check({ preset: 'default', staged: false });
@@ -186,9 +164,7 @@ describe('check command', () => {
186
164
  passed: true,
187
165
  ironLaws: [],
188
166
  guidelines: [],
189
- tips: [],
190
167
  warningCount: 0,
191
- tipCount: 0,
192
168
  });
193
169
 
194
170
  await check({ preset: 'default', staged: true });
@@ -201,9 +177,7 @@ describe('check command', () => {
201
177
  passed: true,
202
178
  ironLaws: [],
203
179
  guidelines: [],
204
- tips: [],
205
180
  warningCount: 0,
206
- tipCount: 0,
207
181
  });
208
182
 
209
183
  await check({ preset: 'default', staged: false });
@@ -216,9 +190,7 @@ describe('check command', () => {
216
190
  passed: true,
217
191
  ironLaws: [],
218
192
  guidelines: [],
219
- tips: [],
220
193
  warningCount: 0,
221
- tipCount: 0,
222
194
  });
223
195
 
224
196
  await check({ preset: 'default', staged: true });
@@ -231,9 +203,7 @@ describe('check command', () => {
231
203
  passed: true,
232
204
  ironLaws: [],
233
205
  guidelines: [],
234
- tips: [],
235
206
  warningCount: 0,
236
- tipCount: 0,
237
207
  });
238
208
 
239
209
  await check({ preset: 'default', staged: false });
@@ -244,7 +214,7 @@ describe('check command', () => {
244
214
  it('应该检测 module_modification 触发条件(.ts 文件)', async () => {
245
215
  mockExecAsync.mockResolvedValue({ stdout: 'src/foo.ts\nsrc/bar.tsx\n', stderr: '' });
246
216
  mockChecker.checkConstraints.mockResolvedValue({
247
- passed: true, ironLaws: [], guidelines: [], tips: [], warningCount: 0, tipCount: 0,
217
+ passed: true, ironLaws: [], guidelines: [], warningCount: 0,
248
218
  });
249
219
 
250
220
  // Mock filesystem so detectSourceRoots finds src/ as a source root
@@ -267,7 +237,7 @@ describe('check command', () => {
267
237
  it('应该检测 module_modification 触发条件(.js 文件)', async () => {
268
238
  mockExecAsync.mockResolvedValue({ stdout: 'src/foo.js\nsrc/bar.jsx\n', stderr: '' });
269
239
  mockChecker.checkConstraints.mockResolvedValue({
270
- passed: true, ironLaws: [], guidelines: [], tips: [], warningCount: 0, tipCount: 0,
240
+ passed: true, ironLaws: [], guidelines: [], warningCount: 0,
271
241
  });
272
242
 
273
243
  // Mock filesystem so detectSourceRoots finds src/ as a source root
@@ -290,7 +260,7 @@ describe('check command', () => {
290
260
  it('应该检测 file_modification 触发条件(非 src/ 目录)', async () => {
291
261
  mockExecAsync.mockResolvedValue({ stdout: 'docs/bar.md\n', stderr: '' });
292
262
  mockChecker.checkConstraints.mockResolvedValue({
293
- passed: true, ironLaws: [], guidelines: [], tips: [], warningCount: 0, tipCount: 0,
263
+ passed: true, ironLaws: [], guidelines: [], warningCount: 0,
294
264
  });
295
265
 
296
266
  await check({ preset: 'default', staged: false });
@@ -304,9 +274,7 @@ describe('check command', () => {
304
274
  passed: true,
305
275
  ironLaws: [],
306
276
  guidelines: [],
307
- tips: [],
308
277
  warningCount: 0,
309
- tipCount: 0,
310
278
  });
311
279
 
312
280
  // Mock filesystem so detectSourceRoots finds src/ as a source root
@@ -332,9 +300,7 @@ describe('check command', () => {
332
300
  passed: true,
333
301
  ironLaws: [],
334
302
  guidelines: [],
335
- tips: [],
336
303
  warningCount: 0,
337
- tipCount: 0,
338
304
  });
339
305
 
340
306
  await check({ preset: 'default', staged: false, trigger: 'code_implementation' });
@@ -361,9 +327,7 @@ describe('check command', () => {
361
327
  },
362
328
  }],
363
329
  guidelines: [],
364
- tips: [],
365
330
  warningCount: 0,
366
- tipCount: 0,
367
331
  });
368
332
 
369
333
  const mockExit = jest.spyOn(process, 'exit').mockImplementation(() => undefined as never);
@@ -393,43 +357,13 @@ describe('check command', () => {
393
357
  enforcement: 'warning',
394
358
  },
395
359
  }],
396
- tips: [],
397
360
  warningCount: 1,
398
- tipCount: 0,
399
361
  });
400
362
 
401
363
  await check({ preset: 'default', staged: false });
402
364
  expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining('prefer_composition'));
403
365
  });
404
366
 
405
- it('应该显示提示的约束详情', async () => {
406
- mockExecAsync.mockResolvedValue({ stdout: '', stderr: '' });
407
- mockChecker.checkConstraints.mockResolvedValue({
408
- passed: true,
409
- ironLaws: [],
410
- guidelines: [],
411
- tips: [{
412
- id: 'consider_reuse',
413
- level: 'tip',
414
- satisfied: false,
415
- checkedAt: new Date(),
416
- constraint: {
417
- kind: 'check' as const,
418
- id: 'consider_reuse',
419
- rule: 'CONSIDER REUSE',
420
- message: '考虑复用',
421
- level: 'tip',
422
- trigger: 'code_implementation',
423
- enforcement: 'info',
424
- },
425
- }],
426
- warningCount: 0,
427
- tipCount: 1,
428
- });
429
-
430
- await check({ preset: 'default', staged: false });
431
- expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining('consider_reuse'));
432
- });
433
367
  });
434
368
 
435
369
  describe('getSmartHint (通过 check 间接测试)', () => {
@@ -439,9 +373,7 @@ describe('check command', () => {
439
373
  passed: true,
440
374
  ironLaws: [],
441
375
  guidelines: [],
442
- tips: [],
443
376
  warningCount: 0,
444
- tipCount: 0,
445
377
  });
446
378
  });
447
379
 
@@ -0,0 +1,201 @@
1
+ /**
2
+ * 命令注册表闭环测试(H5:命令定义即注册 + per-command 懒加载)
3
+ *
4
+ * - 定义表内每个实现引用(module+export)都必须可解析(构建/测试期断言,
5
+ * 取代 commands barrel 的编译期保护——R6 消灭手工同步后的闭环兜底)
6
+ * - definitions 是纯数据模块:require 它不加载任何命令实现(保 --help/--version 懒加载)
7
+ * - 命令面与 CAPABILITIES.md 的 24 顶层命令一致(防误删回归)
8
+ * - bin/harness.js 端到端冒烟(dist 存在时):--version/--help 零命令实现模块,
9
+ * 单命令执行只加载该命令模块(O2 per-command 懒加载)
10
+ */
11
+
12
+ import * as fs from 'fs';
13
+ import * as os from 'os';
14
+ import * as path from 'path';
15
+ import { spawnSync } from 'child_process';
16
+ import { COMMAND_DEFINITIONS, type CommandDefinition, type CommandImplRef } from '../definitions';
17
+ import { GATE_DEFINITIONS } from '../../../gates/definitions';
18
+
19
+ function collectRefs(defs: CommandDefinition[]): CommandImplRef[] {
20
+ const refs: CommandImplRef[] = [];
21
+ const walk = (def: CommandDefinition) => {
22
+ if (def.action) refs.push(def.action);
23
+ if (def.subcommands) {
24
+ for (const entry of Object.values(def.subcommands)) refs.push(entry.impl);
25
+ }
26
+ if (def.optionRoutes) {
27
+ for (const route of def.optionRoutes) refs.push(route.impl);
28
+ }
29
+ for (const child of def.children || []) walk(child);
30
+ };
31
+ for (const def of defs) walk(def);
32
+ return refs;
33
+ }
34
+
35
+ const EXPECTED_TOP_LEVEL_COMMANDS = [
36
+ 'check', 'validate', 'passes-gate', 'init', 'report', 'status', 'spec',
37
+ 'sync-docs', 'knowledge', 'sdd', 'failure', 'posteval-plan',
38
+ 'update-user-model', 'release', 'analyze-sessions', 'constraints',
39
+ 'doc-freshness-check', 'spec-baseline-check',
40
+ // 6 门禁命令(GATE_DEFINITIONS 驱动)
41
+ 'acceptance', 'command', 'contract', 'performance', 'review', 'security',
42
+ ];
43
+
44
+ describe('命令注册表闭环', () => {
45
+ it('definitions 是纯数据模块:加载时不引入任何命令实现', () => {
46
+ const loaded = Object.keys(require.cache)
47
+ .filter(k => k.includes('/cli/commands/') && k.endsWith('.ts') && !k.includes('__tests__'));
48
+ expect(loaded).toEqual([
49
+ expect.stringContaining('/cli/commands/definitions.ts'),
50
+ ]);
51
+ });
52
+
53
+ it('全部实现引用可解析(module 存在且 export 是函数)', () => {
54
+ const refs = collectRefs(COMMAND_DEFINITIONS);
55
+ for (const def of GATE_DEFINITIONS) {
56
+ refs.push(def.cli.action);
57
+ for (const entry of Object.values(def.cli.subcommands || {})) refs.push(entry);
58
+ }
59
+ expect(refs.length).toBeGreaterThan(0);
60
+
61
+ for (const ref of refs) {
62
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
63
+ const mod = require('../' + ref.module);
64
+ if (typeof mod[ref.export] !== 'function') {
65
+ throw new Error(`实现引用 ${ref.module}.${ref.export} 不存在或不是函数`);
66
+ }
67
+ }
68
+ });
69
+
70
+ it('顶层命令面与预期 24 命令一致(含 6 门禁)', () => {
71
+ const names = [
72
+ ...COMMAND_DEFINITIONS.map(d => d.command.split(' ')[0]),
73
+ ...GATE_DEFINITIONS.map(d => d.cli.command.split(' ')[0]),
74
+ ];
75
+ expect(new Set(names).size).toBe(names.length);
76
+ expect(names.sort()).toEqual([...EXPECTED_TOP_LEVEL_COMMANDS].sort());
77
+ });
78
+
79
+ it('命令定义无重复注册名', () => {
80
+ const names = COMMAND_DEFINITIONS.map(d => d.command);
81
+ expect(new Set(names).size).toBe(names.length);
82
+ });
83
+
84
+ it('全部命令定义的路由构造可执行(mapActionArgs/subcommands.args/optionRoutes.args/afterRun 冒烟)', () => {
85
+ const exitSpy = jest.spyOn(process, 'exit').mockImplementation(() => undefined as never);
86
+ try {
87
+ const walk = (def: CommandDefinition) => {
88
+ if (def.mapActionArgs) {
89
+ def.mapActionArgs(['positional'], {});
90
+ def.mapActionArgs([], {});
91
+ }
92
+ for (const entry of Object.values(def.subcommands || {})) {
93
+ if (entry.args) {
94
+ entry.args(['positional'], {});
95
+ entry.args([], {});
96
+ }
97
+ }
98
+ for (const route of def.optionRoutes || []) {
99
+ if (route.args) {
100
+ route.args([], {});
101
+ route.args(['positional'], {});
102
+ }
103
+ }
104
+ if (def.afterRun) {
105
+ def.afterRun(true, {});
106
+ def.afterRun(false, { check: true });
107
+ }
108
+ for (const child of def.children || []) walk(child);
109
+ };
110
+ for (const def of COMMAND_DEFINITIONS) walk(def);
111
+ // sync-docs --check 失败路径确实会请求退出
112
+ expect(exitSpy).toHaveBeenCalled();
113
+ } finally {
114
+ exitSpy.mockRestore();
115
+ }
116
+ });
117
+ });
118
+
119
+ const repoRoot = path.join(__dirname, '..', '..', '..', '..');
120
+ const distBin = path.join(repoRoot, 'bin', 'harness.js');
121
+ const distCommands = path.join(repoRoot, 'dist', 'cli', 'commands');
122
+ const hasDist = fs.existsSync(distCommands);
123
+
124
+ /**
125
+ * 经 NODE_OPTIONS=--require 预加载探针 spawn bin(进程退出时打印加载的
126
+ * 命令实现模块清单)。不用 node -e(commander 在 -e 下走 eval 分支,
127
+ * argv 解析不同,会误判位置参数)。
128
+ */
129
+ function runWithModuleProbe(argv: string[]): { status: number | null; implModules: string[]; stdout: string; stderr: string } {
130
+ const probeDir = fs.mkdtempSync(path.join(os.tmpdir(), 'harness-lazy-probe-'));
131
+ const probeFile = path.join(probeDir, 'probe.js');
132
+ fs.writeFileSync(probeFile, [
133
+ `process.on('exit', () => {`,
134
+ ` const impls = Object.keys(require.cache).filter(k => /dist[\\\\/]cli[\\\\/]commands[\\\\/]/.test(k) && !/definitions\\.js/.test(k)).sort();`,
135
+ ` console.error('IMPL_MODULES=' + impls.join(','));`,
136
+ `});`,
137
+ ].join('\n'));
138
+ try {
139
+ const r = spawnSync(process.execPath, [distBin, ...argv], {
140
+ cwd: repoRoot,
141
+ encoding: 'utf-8',
142
+ timeout: 30000,
143
+ env: { ...process.env, NODE_OPTIONS: `--require ${probeFile}` },
144
+ });
145
+ const match = r.stderr.match(/IMPL_MODULES=(.*)/);
146
+ return {
147
+ status: r.status,
148
+ implModules: match && match[1] ? match[1].split(',').filter(Boolean) : [],
149
+ stdout: r.stdout,
150
+ stderr: r.stderr,
151
+ };
152
+ } finally {
153
+ fs.rmSync(probeDir, { recursive: true, force: true });
154
+ }
155
+ }
156
+
157
+ const smoke = hasDist ? describe : describe.skip;
158
+
159
+ smoke('bin/harness.js 端到端(dist 存在时)', () => {
160
+ it('--version:退出 0,零命令实现模块加载', () => {
161
+ const r = runWithModuleProbe(['--version']);
162
+ expect(r.status).toBe(0);
163
+ expect(r.implModules).toEqual([]);
164
+ });
165
+
166
+ it('--help:退出 0,零命令实现模块加载', () => {
167
+ const r = runWithModuleProbe(['--help']);
168
+ expect(r.status).toBe(0);
169
+ expect(r.implModules).toEqual([]);
170
+ });
171
+
172
+ it('harness constraints --json:只加载 constraints 命令模块', () => {
173
+ const r = runWithModuleProbe(['constraints', '--json']);
174
+ expect(r.status).toBe(0);
175
+ expect(r.implModules).toEqual([
176
+ expect.stringContaining('/dist/cli/commands/constraints.js'),
177
+ ]);
178
+ });
179
+
180
+ it('harness check --list:只加载 check 命令模块(optionRoutes)', () => {
181
+ const r = runWithModuleProbe(['check', '--list']);
182
+ expect(r.status).toBe(0);
183
+ expect(r.implModules).toEqual([
184
+ expect.stringContaining('/dist/cli/commands/check.js'),
185
+ ]);
186
+ });
187
+
188
+ it('harness acceptance:只加载 acceptance 命令模块(门禁注册表)', () => {
189
+ const r = runWithModuleProbe(['acceptance', '--check-all']);
190
+ expect(r.status).toBe(0);
191
+ expect(r.implModules).toEqual([
192
+ expect.stringContaining('/dist/cli/commands/acceptance.js'),
193
+ ]);
194
+ });
195
+
196
+ it('未知子命令报错退出(knowledge 兜底行为保留)', () => {
197
+ const r = runWithModuleProbe(['knowledge', 'bogus']);
198
+ expect(r.status).toBe(1);
199
+ expect(r.stderr).toContain('未知子命令: bogus');
200
+ });
201
+ });
@@ -49,7 +49,6 @@ export async function check(options: CheckOptions): Promise<void> {
49
49
  const merged = configLoader.hasCustomConfig()
50
50
  ? configLoader.mergeConstraints()
51
51
  : configLoader.mergeConstraints({ preset: options.preset || 'standard' });
52
- constraintChecker.setCustomConfig(merged);
53
52
  if (merged.custom.length > 0) {
54
53
  console.log(chalk.gray(`自定义约束: ${merged.custom.length} 条`));
55
54
  }
@@ -73,8 +72,8 @@ export async function check(options: CheckOptions): Promise<void> {
73
72
  }
74
73
  console.log(chalk.gray(`触发条件: ${[context.operation, ...(context.extraTriggers ?? [])].join(', ')}`));
75
74
 
76
- // 执行三层检查
77
- const result = await constraintChecker.checkConstraints(context);
75
+ // 执行三层检查(per-request 传 customConfig,避免单例状态污染)
76
+ const result = await constraintChecker.checkConstraints(context, merged);
78
77
 
79
78
  // 输出结果
80
79
  console.log();
@@ -83,7 +82,6 @@ export async function check(options: CheckOptions): Promise<void> {
83
82
  const skippedResults = [
84
83
  ...result.ironLaws,
85
84
  ...result.guidelines,
86
- ...result.tips,
87
85
  ].filter(r => r.skipped);
88
86
 
89
87
  // Iron Laws
@@ -118,16 +116,6 @@ export async function check(options: CheckOptions): Promise<void> {
118
116
  console.log(chalk.green(`✅ 指导原则: ${passedGuidelines}/${evaluatedGuidelines.length} 通过`));
119
117
  }
120
118
 
121
- // Tips
122
- if (result.tipCount > 0) {
123
- console.log(chalk.blue(`💡 提示: ${result.tipCount} 条`));
124
- result.tips.filter(r => !r.satisfied).forEach(r => {
125
- if (r.constraint) {
126
- console.log(chalk.blue(` - ${r.constraint.id}: ${r.constraint.message}`));
127
- }
128
- });
129
- }
130
-
131
119
  // Skipped:约定未采用 / 证据未接线,未评估(不计通过/失败)
132
120
  if (skippedResults.length > 0) {
133
121
  console.log(chalk.gray(`⏭️ 跳过评估: ${skippedResults.length} 条(约定未采用或证据未接线,不计通过/失败)`));