@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
@@ -0,0 +1,207 @@
1
+ /**
2
+ * 门禁定义表(G1:定义即注册的单一定义源)
3
+ *
4
+ * - 每个门禁在此声明 id / description / 默认 order / CLI 元数据;
5
+ * registry.ts 按此表做「定义↔实现」双向闭环校验(复制 checker 闭环模式)。
6
+ * - CLI 元数据被 bin/harness.js 消费,注册表驱动生成 6 个门禁命令:
7
+ * 命令名/别名/选项/子命令路由与历史手工块完全兼容;实现引用为
8
+ * module+export(CommandImplRef),bin 按需 per-command 懒加载(H5/O2)。
9
+ * - 本模块禁止 import 任何门禁/命令实现(仅 type import,运行时零依赖)——
10
+ * bin 启动期只加载本纯数据模块(保持 --help/--version 懒加载,
11
+ * 闭环校验在 registry 加载期执行)。
12
+ */
13
+
14
+ import type { CommandImplRef } from '../cli/commands/definitions';
15
+
16
+ /**
17
+ * 门禁 CLI 选项元数据(直接映射 commander `.option()`)
18
+ */
19
+ export interface GateCliOption {
20
+ /** commander option flags,如 '-p, --project-path <path>' */
21
+ flags: string;
22
+ /** 选项描述 */
23
+ description: string;
24
+ /** commander 缺省值;negated option(如 --no-strict)不设,由 commander 默认 true */
25
+ defaultValue?: string | boolean;
26
+ }
27
+
28
+ /**
29
+ * 门禁 CLI 命令元数据(bin/harness.js 注册表驱动生成)
30
+ */
31
+ export interface GateCliDefinition {
32
+ /** 命令名(历史命令名兼容保留) */
33
+ command: string;
34
+ /** 命令别名 */
35
+ alias?: string;
36
+ /** 位置参数声明,如 '[subcommand]' / '[cmd]' */
37
+ argument?: string;
38
+ /** 命令描述 */
39
+ description: string;
40
+ /** 命令选项 */
41
+ options: GateCliOption[];
42
+ /** 子命令名 → 命令实现引用(module+export);命中后按 [options] 透传 */
43
+ subcommands?: Record<string, CommandImplRef>;
44
+ /** 默认 action 命令实现引用(module+export) */
45
+ action: CommandImplRef;
46
+ /** 默认 action 实参构造:arg = 位置参数(无位置参数时为 undefined),options = commander 选项对象 */
47
+ mapActionArgs: (arg: string | undefined, options: Record<string, unknown>) => unknown[];
48
+ }
49
+
50
+ /**
51
+ * 门禁定义
52
+ */
53
+ export interface GateDefinition {
54
+ /** 门禁 id(与实现 Gate.id 一致) */
55
+ id: string;
56
+ /** 一句话描述 */
57
+ description: string;
58
+ /** 默认顺序(config.yml `gates.order` 可覆盖),小者先执行 */
59
+ order: number;
60
+ /** CLI 元数据(bin/harness.js 注册表驱动生成) */
61
+ cli: GateCliDefinition;
62
+ }
63
+
64
+ /**
65
+ * 6 门禁定义(默认 order 按字母序,与历史 bin 块顺序一致)
66
+ */
67
+ export const GATE_DEFINITIONS: GateDefinition[] = [
68
+ {
69
+ id: 'acceptance',
70
+ description: '验收标准门控,检查任务是否满足验收标准',
71
+ order: 0,
72
+ cli: {
73
+ command: 'acceptance',
74
+ alias: 'acc',
75
+ argument: '[subcommand]',
76
+ description: '验收标准门控,检查任务是否满足验收标准',
77
+ options: [
78
+ { flags: '-t, --task-id <id>', description: '任务 ID' },
79
+ { flags: '--tasks-path <path>', description: 'tasks.yml 路径' },
80
+ { flags: '-p, --project-path <path>', description: '项目路径' },
81
+ { flags: '--check-all', description: '检查所有任务', defaultValue: false },
82
+ { flags: '--run-e2e', description: '运行 E2E 测试', defaultValue: false },
83
+ ],
84
+ subcommands: { list: { module: 'acceptance', export: 'listAcceptanceCriteria' } },
85
+ action: { module: 'acceptance', export: 'acceptance' },
86
+ mapActionArgs: (_arg, options) => [options],
87
+ },
88
+ },
89
+ {
90
+ id: 'command',
91
+ description: '命令黑名单门控,检查命令是否在禁用列表',
92
+ order: 1,
93
+ cli: {
94
+ command: 'command',
95
+ alias: 'cmd',
96
+ argument: '[cmd]',
97
+ description: '检查命令是否在黑名单中',
98
+ options: [
99
+ { flags: '-l, --level', description: '显示风险等级' },
100
+ { flags: '--list', description: '列出所有黑名单规则' },
101
+ { flags: '--json', description: 'JSON 格式输出' },
102
+ { flags: '--strict', description: '严格模式(warn 也阻止)' },
103
+ ],
104
+ action: { module: 'command', export: 'executeCommand' },
105
+ mapActionArgs: (arg, options) => [arg, options],
106
+ },
107
+ },
108
+ {
109
+ id: 'contract',
110
+ description: 'API 契约门控,检查 OpenAPI Schema',
111
+ order: 2,
112
+ cli: {
113
+ command: 'contract',
114
+ argument: '[subcommand]',
115
+ description: 'API 契约门控,检查 OpenAPI Schema',
116
+ options: [
117
+ { flags: '-p, --project-path <path>', description: '项目路径' },
118
+ { flags: '--contract-path <path>', description: '契约文件路径', defaultValue: 'openapi.yaml' },
119
+ { flags: '--no-strict', description: '关闭严格模式' },
120
+ { flags: '--allow-breaking', description: '允许破坏性变更', defaultValue: false },
121
+ ],
122
+ subcommands: { validate: { module: 'contract', export: 'validateSchema' } },
123
+ action: { module: 'contract', export: 'contract' },
124
+ mapActionArgs: (_arg, options) => [options],
125
+ },
126
+ },
127
+ {
128
+ id: 'performance',
129
+ description: '性能门控,检查性能指标',
130
+ order: 3,
131
+ cli: {
132
+ command: 'performance',
133
+ alias: 'perf',
134
+ description: '性能门控,检查性能指标',
135
+ options: [
136
+ { flags: '-p, --project-path <path>', description: '项目路径' },
137
+ { flags: '--coverage', description: '检查测试覆盖率', defaultValue: false },
138
+ { flags: '--coverage-threshold <n>', description: '覆盖率阈值', defaultValue: '80' },
139
+ { flags: '--bundle', description: '检查打包大小', defaultValue: false },
140
+ { flags: '--bundle-threshold <n>', description: '打包大小阈值 (KB)', defaultValue: '500' },
141
+ { flags: '--benchmark', description: '运行基准测试', defaultValue: false },
142
+ { flags: '--benchmark-timeout <n>', description: '基准测试超时(秒)', defaultValue: '60' },
143
+ ],
144
+ action: { module: 'performance', export: 'performance' },
145
+ mapActionArgs: (_arg, options) => [
146
+ {
147
+ projectPath: options.projectPath,
148
+ coverage: options.coverage,
149
+ coverageThreshold: parseInt(String(options.coverageThreshold), 10),
150
+ bundle: options.bundle,
151
+ bundleThreshold: parseInt(String(options.bundleThreshold), 10),
152
+ benchmark: options.benchmark,
153
+ benchmarkTimeout: parseInt(String(options.benchmarkTimeout), 10),
154
+ },
155
+ ],
156
+ },
157
+ },
158
+ {
159
+ id: 'review',
160
+ description: '代码审查门控,检查审查状态',
161
+ order: 4,
162
+ cli: {
163
+ command: 'review',
164
+ argument: '[subcommand]',
165
+ description: '代码审查门控,检查审查状态',
166
+ options: [
167
+ { flags: '-p, --project-path <path>', description: '项目路径' },
168
+ { flags: '--min-reviewers <n>', description: '最少审查人数', defaultValue: '1' },
169
+ { flags: '--no-require-approval', description: '不要求审批' },
170
+ { flags: '--no-block-on-changes', description: '不阻止变更请求' },
171
+ { flags: '--allowed-reviewers <list>', description: '允许的审查者(逗号分隔)' },
172
+ ],
173
+ subcommands: { status: { module: 'review', export: 'reviewStatus' } },
174
+ action: { module: 'review', export: 'review' },
175
+ mapActionArgs: (_arg, options) => [
176
+ {
177
+ projectPath: options.projectPath,
178
+ minReviewers: parseInt(String(options.minReviewers), 10),
179
+ requireApproval: options.requireApproval,
180
+ blockOnChangesRequested: options.blockOnChanges,
181
+ allowedReviewers: options.allowedReviewers,
182
+ },
183
+ ],
184
+ },
185
+ },
186
+ {
187
+ id: 'security',
188
+ description: '安全门控,检查安全漏洞',
189
+ order: 5,
190
+ cli: {
191
+ command: 'security',
192
+ alias: 'sec',
193
+ argument: '[subcommand]',
194
+ description: '安全门控,检查安全漏洞',
195
+ options: [
196
+ { flags: '-p, --project-path <path>', description: '项目路径' },
197
+ { flags: '--severity <level>', description: '严重性阈值 (low/moderate/high/critical)', defaultValue: 'high' },
198
+ { flags: '--ignore-warnings', description: '忽略警告', defaultValue: false },
199
+ { flags: '--ignore-dev-deps', description: '忽略开发依赖', defaultValue: false },
200
+ { flags: '--scan-command <cmd>', description: '自定义扫描命令' },
201
+ ],
202
+ subcommands: { audit: { module: 'security', export: 'auditDetails' } },
203
+ action: { module: 'security', export: 'security' },
204
+ mapActionArgs: (_arg, options) => [options],
205
+ },
206
+ },
207
+ ];
@@ -0,0 +1,106 @@
1
+ /**
2
+ * 生效门禁集(G1):对齐 getEffectiveConstraints 的 config 裁剪模式
3
+ *
4
+ * 单一来源:注册表(默认 order)→ config.yml `gates.order` 声明式重排 →
5
+ * `gates.<id>.enabled:false` 裁剪移除。
6
+ *
7
+ * 闭环:config.yml gates 配置引用了未注册的门禁 id → 抛错
8
+ * (与注册表「引用未注册」同款闭环;gates 配置段为新增面,
9
+ * 不存在历史残留配置,故不需静默忽略)。
10
+ */
11
+
12
+ import type { Gate } from './types';
13
+ import { listRegisteredGates } from './registry';
14
+ import { loadRawProjectConfig } from '../core/project-config-loader';
15
+
16
+ /**
17
+ * config.yml `gates` 段
18
+ */
19
+ export interface GatesConfig {
20
+ /** 声明式顺序(门禁 id 列表);未列出的按默认顺序排后 */
21
+ order?: string[];
22
+ /** 每个门禁的启用开关(gates.<id>.enabled: false = 裁剪) */
23
+ [gateId: string]: { enabled?: boolean } | string[] | undefined;
24
+ }
25
+
26
+ /**
27
+ * 获取项目当前生效的门禁集(按 order 升序)
28
+ *
29
+ * @param projectRoot 项目根路径(缺省 process.cwd())
30
+ * @throws config.yml gates 段引用未注册门禁 id 时抛错
31
+ */
32
+ export function getEffectiveGates(projectRoot: string = process.cwd()): Gate[] {
33
+ const raw = loadRawProjectConfig(projectRoot);
34
+ const config = raw?.gates as GatesConfig | undefined;
35
+ const gates = listRegisteredGates();
36
+ const known = new Set(gates.map(g => g.id));
37
+
38
+ if (!config) {
39
+ return sortByOrder(gates);
40
+ }
41
+
42
+ // ========================================
43
+ // 闭环校验:引用未注册 → 抛错
44
+ // ========================================
45
+ const orderIds = Array.isArray(config.order) ? (config.order as string[]) : undefined;
46
+ if (orderIds) {
47
+ const seen = new Set<string>();
48
+ for (const id of orderIds) {
49
+ if (!known.has(id)) {
50
+ throw new Error(
51
+ `[harness] config.yml gates.order 引用了未注册的门禁 "${id}"。` +
52
+ `可用门禁: ${[...known].join(', ')}。`
53
+ );
54
+ }
55
+ if (seen.has(id)) {
56
+ throw new Error(
57
+ `[harness] config.yml gates.order 中门禁 "${id}" 重复。`
58
+ );
59
+ }
60
+ seen.add(id);
61
+ }
62
+ }
63
+ for (const key of Object.keys(config)) {
64
+ if (key === 'order') continue;
65
+ if (!known.has(key)) {
66
+ throw new Error(
67
+ `[harness] config.yml gates.${key} 引用了未注册的门禁。` +
68
+ `可用门禁: ${[...known].join(', ')}。`
69
+ );
70
+ }
71
+ }
72
+
73
+ // ========================================
74
+ // enabled 裁剪(与 getEffectiveConstraints 的 enabled:false 删除同效)
75
+ // ========================================
76
+ const disabled = new Set<string>();
77
+ for (const gate of gates) {
78
+ const entry = config[gate.id];
79
+ if (
80
+ entry &&
81
+ typeof entry === 'object' &&
82
+ !Array.isArray(entry) &&
83
+ entry.enabled === false
84
+ ) {
85
+ disabled.add(gate.id);
86
+ }
87
+ }
88
+ const effective = gates.filter(g => !disabled.has(g.id));
89
+
90
+ // ========================================
91
+ // order 重排:列出的按列表顺序,未列出的按默认顺序排后
92
+ // ========================================
93
+ if (orderIds) {
94
+ const position = new Map(orderIds.map((id, i) => [id, i]));
95
+ return effective.sort((a, b) => {
96
+ const pa = position.has(a.id) ? position.get(a.id)! : orderIds.length + a.order;
97
+ const pb = position.has(b.id) ? position.get(b.id)! : orderIds.length + b.order;
98
+ return pa - pb;
99
+ });
100
+ }
101
+ return sortByOrder(effective);
102
+ }
103
+
104
+ function sortByOrder(gates: Gate[]): Gate[] {
105
+ return gates.sort((a, b) => a.order - b.order);
106
+ }
@@ -8,6 +8,9 @@
8
8
  export type {
9
9
  GateResult,
10
10
  GateContext,
11
+ Gate,
12
+ GateDecision,
13
+ GateDecisionStatus,
11
14
  PerformanceThresholds,
12
15
  ReviewGateConfig,
13
16
  SecurityGateConfig,
@@ -20,6 +23,41 @@ export type {
20
23
  CommandGateConfig,
21
24
  } from './types';
22
25
 
26
+ // ========================================
27
+ // 统一门禁协议(G1)
28
+ // ========================================
29
+
30
+ /**
31
+ * 门禁决策构造:GateResult 报告 → 三态 GateDecision(浅冻结)
32
+ */
33
+ export { decisionFromResult } from './decision';
34
+
35
+ /**
36
+ * 门禁定义表(定义即注册的单一定义源;bin/harness.js 注册表驱动生成 CLI)
37
+ */
38
+ export { GATE_DEFINITIONS, type GateDefinition, type GateCliDefinition, type GateCliOption } from './definitions';
39
+
40
+ /**
41
+ * 门禁注册表(定义↔实现双向闭环,加载期抛错)+ getGate 引用闭环
42
+ */
43
+ export { getGate, listRegisteredGates, registeredGateCount, assertGateRegistryClosed } from './registry';
44
+
45
+ /**
46
+ * 门禁执行器:deny 单调 + ask fail-closed
47
+ */
48
+ export { runGates, type GateRunResult } from './runner';
49
+
50
+ /**
51
+ * 生效门禁集:config.yml gates.order / gates.<id>.enabled 声明式裁剪
52
+ */
53
+ export { getEffectiveGates, type GatesConfig } from './effective-gates';
54
+
55
+ /**
56
+ * checker-as-guard 接线点:ConstraintCheck → Gate(studio #129 随动)
57
+ */
58
+ export { createCheckerGate } from './checker-gate';
59
+
60
+
23
61
  // 门禁类导出
24
62
  export { ReviewGate } from './review';
25
63
  export { SecurityGate } from './security';
@@ -16,7 +16,8 @@
16
16
  import { execAsync } from '../utils/exec';
17
17
  import * as fs from 'fs/promises';
18
18
  import * as path from 'path';
19
- import type { GateResult, GateContext, PerformanceGateConfig, PerformanceThresholds } from './types';
19
+ import type { GateResult, GateContext, PerformanceGateConfig, PerformanceThresholds, Gate, GateDecision } from './types';
20
+ import { decisionFromResult } from './decision';
20
21
 
21
22
  // 默认超时时间(毫秒)
22
23
  const DEFAULT_TIMEOUTS = {
@@ -38,7 +39,9 @@ export interface ExtendedPerformanceGateConfig extends PerformanceGateConfig {
38
39
  /**
39
40
  * 性能门禁
40
41
  */
41
- export class PerformanceGate {
42
+ export class PerformanceGate implements Gate {
43
+ readonly id = 'performance';
44
+ order = 0;
42
45
  private config: Required<ExtendedPerformanceGateConfig>;
43
46
 
44
47
  constructor(config: Partial<ExtendedPerformanceGateConfig> = {}) {
@@ -53,6 +56,13 @@ export class PerformanceGate {
53
56
  };
54
57
  }
55
58
 
59
+ /**
60
+ * 统一门禁接口(G1):执行细节私有,决策三态由 check() 报告推导
61
+ */
62
+ async evaluate(context: GateContext): Promise<GateDecision> {
63
+ return decisionFromResult(await this.check(context));
64
+ }
65
+
56
66
  /**
57
67
  * 检查性能
58
68
  */
@@ -0,0 +1,107 @@
1
+ /**
2
+ * 门禁注册表(G1:复制 checker 的「定义即注册 + 构建期闭环」模式)
3
+ *
4
+ * 模块加载期双向校验(任一不满足即抛错,拒绝静默缺失):
5
+ * - 定义无实现 → 抛错(definitions.ts 有定义但 registry 未注册实现)
6
+ * - 实现无定义 → 抛错(registry 注册了实现但 definitions.ts 无定义)
7
+ * - 重复 id → 抛错
8
+ *
9
+ * 引用未注册(getGate / config.yml gates 配置引用)同样抛错——
10
+ * 与 checker 注册表闭环同款故障类「定义了但没登记」由机制消灭。
11
+ */
12
+
13
+ import type { Gate } from './types';
14
+ import { GATE_DEFINITIONS, type GateDefinition } from './definitions';
15
+ import { ReviewGate } from './review';
16
+ import { SecurityGate } from './security';
17
+ import { PerformanceGate } from './performance';
18
+ import { ContractGate } from './contract';
19
+ import { SpecAcceptanceGate } from './acceptance';
20
+ import { CommandGate } from './command';
21
+
22
+ const IMPLEMENTATIONS: Gate[] = [
23
+ new SpecAcceptanceGate(),
24
+ new CommandGate(),
25
+ new ContractGate(),
26
+ new PerformanceGate(),
27
+ new ReviewGate(),
28
+ new SecurityGate(),
29
+ ];
30
+
31
+ // ========================================
32
+ // 注册表闭环校验(加载期)
33
+ // ========================================
34
+
35
+ assertGateRegistryClosed(GATE_DEFINITIONS, IMPLEMENTATIONS);
36
+
37
+ // 默认 order 以定义表为准(config.yml gates.order 在生效集层覆盖,不改注册表单例)
38
+ for (const def of GATE_DEFINITIONS) {
39
+ IMPLEMENTATIONS.find(g => g.id === def.id)!.order = def.order;
40
+ }
41
+
42
+ const registry = new Map<string, Gate>(IMPLEMENTATIONS.map(g => [g.id, g]));
43
+
44
+ /**
45
+ * 注册表闭环双向校验(加载期调用;测试用坏输入验证两个失败方向)
46
+ *
47
+ * @throws 定义无实现 / 实现无定义 / 重复 id 时抛错
48
+ */
49
+ export function assertGateRegistryClosed(
50
+ definitions: readonly GateDefinition[],
51
+ implementations: readonly Gate[]
52
+ ): void {
53
+ const implIds = new Map<string, Gate>();
54
+ for (const impl of implementations) {
55
+ if (implIds.has(impl.id)) {
56
+ throw new Error(
57
+ `[harness] 门禁注册表闭环校验失败:门禁 "${impl.id}" 重复注册。`
58
+ );
59
+ }
60
+ implIds.set(impl.id, impl);
61
+ }
62
+
63
+ for (const def of definitions) {
64
+ if (!implIds.has(def.id)) {
65
+ throw new Error(
66
+ `[harness] 门禁注册表闭环校验失败:门禁定义 "${def.id}" 未注册实现。` +
67
+ `请在 src/gates/ 中实现并注册,或删除该定义。`
68
+ );
69
+ }
70
+ }
71
+
72
+ for (const impl of implementations) {
73
+ if (!definitions.some(d => d.id === impl.id)) {
74
+ throw new Error(
75
+ `[harness] 门禁注册表闭环校验失败:门禁实现 "${impl.id}" 没有对应定义。` +
76
+ `请在 src/gates/definitions.ts 中补齐定义,或移除该实现。`
77
+ );
78
+ }
79
+ }
80
+ }
81
+
82
+ /**
83
+ * 按 id 查找已注册门禁实现;未注册抛错(闭环,拒绝静默缺失)
84
+ */
85
+ export function getGate(id: string): Gate {
86
+ const gate = registry.get(id);
87
+ if (!gate) {
88
+ throw new Error(
89
+ `[harness] 门禁 "${id}" 未注册(注册表闭环)。可用门禁: ${[...registry.keys()].join(', ')}。`
90
+ );
91
+ }
92
+ return gate;
93
+ }
94
+
95
+ /**
96
+ * 全部已注册门禁(返回副本,调用方可安全排序/过滤)
97
+ */
98
+ export function listRegisteredGates(): Gate[] {
99
+ return [...registry.values()];
100
+ }
101
+
102
+ /**
103
+ * 已注册门禁数量(诊断/测试用)
104
+ */
105
+ export function registeredGateCount(): number {
106
+ return registry.size;
107
+ }
@@ -8,12 +8,15 @@
8
8
  */
9
9
 
10
10
  import { execAsync } from '../utils/exec';
11
- import type { GateResult, GateContext, ReviewGateConfig } from './types';
11
+ import type { GateResult, GateContext, ReviewGateConfig, Gate, GateDecision } from './types';
12
+ import { decisionFromResult } from './decision';
12
13
 
13
14
  /**
14
15
  * 审查门禁
15
16
  */
16
- export class ReviewGate {
17
+ export class ReviewGate implements Gate {
18
+ readonly id = 'review';
19
+ order = 0;
17
20
  private config: Required<ReviewGateConfig>;
18
21
 
19
22
  constructor(config: Partial<ReviewGateConfig> = {}) {
@@ -25,6 +28,13 @@ export class ReviewGate {
25
28
  };
26
29
  }
27
30
 
31
+ /**
32
+ * 统一门禁接口(G1):执行细节私有,决策三态由 check() 报告推导
33
+ */
34
+ async evaluate(context: GateContext): Promise<GateDecision> {
35
+ return decisionFromResult(await this.check(context));
36
+ }
37
+
28
38
  /**
29
39
  * 检查审查状态
30
40
  */
@@ -0,0 +1,57 @@
1
+ /**
2
+ * 门禁执行器(G1)
3
+ *
4
+ * 按声明式 order 依次 evaluate,聚合语义:
5
+ * - deny 单调:deny 一旦出现即不可被下游 abstain 改回 allow(接口契约)
6
+ * - ask fail-closed:ask 枚举预留、无实现 → 聚合按 deny 计
7
+ * - 决策对象浅冻结:下游不得改写上游决策
8
+ */
9
+
10
+ import type { Gate, GateContext, GateDecision } from './types';
11
+
12
+ /**
13
+ * 一次门禁链执行的聚合结果
14
+ */
15
+ export interface GateRunResult {
16
+ /** 聚合状态:任一 deny(或 ask fail-closed)→ 'deny';否则 'abstain' */
17
+ status: 'deny' | 'abstain';
18
+ /** 按执行顺序的全部决策(浅冻结) */
19
+ decisions: GateDecision[];
20
+ /** 显式 deny 的决策(单调不可逆) */
21
+ denied: GateDecision[];
22
+ /** ask 决策(fail-closed 已计入聚合 deny,此处单独列出供报告) */
23
+ asked: GateDecision[];
24
+ }
25
+
26
+ /**
27
+ * 依次执行门禁链(按 order 升序,稳定排序)
28
+ *
29
+ * @param gates 参与执行的门禁(通常来自 getEffectiveGates)
30
+ * @param ctx 门禁上下文
31
+ */
32
+ export async function runGates(
33
+ gates: readonly Gate[],
34
+ ctx: GateContext
35
+ ): Promise<GateRunResult> {
36
+ const ordered = [...gates].sort((a, b) => a.order - b.order);
37
+ const decisions: GateDecision[] = [];
38
+ const denied: GateDecision[] = [];
39
+ const asked: GateDecision[] = [];
40
+
41
+ for (const gate of ordered) {
42
+ const decision = Object.freeze(await gate.evaluate(ctx));
43
+ decisions.push(decision);
44
+ if (decision.status === 'deny') {
45
+ denied.push(decision);
46
+ } else if (decision.status === 'ask') {
47
+ asked.push(decision);
48
+ }
49
+ }
50
+
51
+ // 单调语义:deny 一旦出现,后续 abstain 不得改回 allow;
52
+ // ask 无实现 → fail-closed = deny。
53
+ const status: GateRunResult['status'] =
54
+ denied.length > 0 || asked.length > 0 ? 'deny' : 'abstain';
55
+
56
+ return { status, decisions, denied, asked };
57
+ }
@@ -8,12 +8,15 @@
8
8
  */
9
9
 
10
10
  import { execAsync } from '../utils/exec';
11
- import type { GateResult, GateContext, SecurityGateConfig } from './types';
11
+ import type { GateResult, GateContext, SecurityGateConfig, Gate, GateDecision } from './types';
12
+ import { decisionFromResult } from './decision';
12
13
 
13
14
  /**
14
15
  * 安全门禁
15
16
  */
16
- export class SecurityGate {
17
+ export class SecurityGate implements Gate {
18
+ readonly id = 'security';
19
+ order = 0;
17
20
  private config: Required<SecurityGateConfig>;
18
21
 
19
22
  constructor(config: Partial<SecurityGateConfig> = {}) {
@@ -26,6 +29,13 @@ export class SecurityGate {
26
29
  };
27
30
  }
28
31
 
32
+ /**
33
+ * 统一门禁接口(G1):执行细节私有,决策三态由 scan() 报告推导
34
+ */
35
+ async evaluate(context: GateContext): Promise<GateDecision> {
36
+ return decisionFromResult(await this.scan(context));
37
+ }
38
+
29
39
  /**
30
40
  * 扫描安全漏洞
31
41
  */