@dommaker/harness 0.19.0 → 1.1.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 (398) hide show
  1. package/CHANGELOG.md +22 -9
  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/agents-syncer.d.ts.map +1 -1
  12. package/dist/cli/commands/sync-docs/agents-syncer.js +25 -4
  13. package/dist/cli/commands/sync-docs/agents-syncer.js.map +1 -1
  14. package/dist/cli/commands/sync-docs/capabilities-syncer.d.ts +3 -25
  15. package/dist/cli/commands/sync-docs/capabilities-syncer.d.ts.map +1 -1
  16. package/dist/cli/commands/sync-docs/capabilities-syncer.js +3 -93
  17. package/dist/cli/commands/sync-docs/capabilities-syncer.js.map +1 -1
  18. package/dist/cli/commands/sync-docs/index.d.ts +1 -1
  19. package/dist/cli/commands/sync-docs/index.d.ts.map +1 -1
  20. package/dist/cli/commands/sync-docs/index.js +4 -4
  21. package/dist/cli/commands/sync-docs/index.js.map +1 -1
  22. package/dist/completion-checkers/classify.d.ts +23 -0
  23. package/dist/completion-checkers/classify.d.ts.map +1 -0
  24. package/dist/completion-checkers/classify.js +37 -0
  25. package/dist/completion-checkers/classify.js.map +1 -0
  26. package/dist/completion-checkers/contract-presence.d.ts +12 -0
  27. package/dist/completion-checkers/contract-presence.d.ts.map +1 -0
  28. package/dist/completion-checkers/contract-presence.js +36 -0
  29. package/dist/completion-checkers/contract-presence.js.map +1 -0
  30. package/dist/completion-checkers/glob-match.d.ts +13 -0
  31. package/dist/completion-checkers/glob-match.d.ts.map +1 -0
  32. package/dist/completion-checkers/glob-match.js +58 -0
  33. package/dist/completion-checkers/glob-match.js.map +1 -0
  34. package/dist/completion-checkers/index.d.ts +19 -0
  35. package/dist/completion-checkers/index.d.ts.map +1 -0
  36. package/dist/completion-checkers/index.js +47 -0
  37. package/dist/completion-checkers/index.js.map +1 -0
  38. package/dist/completion-checkers/phase-format.d.ts +15 -0
  39. package/dist/completion-checkers/phase-format.d.ts.map +1 -0
  40. package/dist/completion-checkers/phase-format.js +42 -0
  41. package/dist/completion-checkers/phase-format.js.map +1 -0
  42. package/dist/completion-checkers/tdd-chain.d.ts +16 -0
  43. package/dist/completion-checkers/tdd-chain.d.ts.map +1 -0
  44. package/dist/completion-checkers/tdd-chain.js +57 -0
  45. package/dist/completion-checkers/tdd-chain.js.map +1 -0
  46. package/dist/completion-checkers/types.d.ts +77 -0
  47. package/dist/completion-checkers/types.d.ts.map +1 -0
  48. package/dist/completion-checkers/types.js +10 -0
  49. package/dist/completion-checkers/types.js.map +1 -0
  50. package/dist/context/index.d.ts +1 -5
  51. package/dist/context/index.d.ts.map +1 -1
  52. package/dist/context/index.js +1 -5
  53. package/dist/context/index.js.map +1 -1
  54. package/dist/context/knowledge-injector.d.ts +3 -3
  55. package/dist/context/knowledge-injector.d.ts.map +1 -1
  56. package/dist/context/knowledge-injector.js +1 -1
  57. package/dist/context/session-manager.d.ts +1 -12
  58. package/dist/context/session-manager.d.ts.map +1 -1
  59. package/dist/context/session-manager.js +0 -63
  60. package/dist/context/session-manager.js.map +1 -1
  61. package/dist/context/types.d.ts +1 -39
  62. package/dist/context/types.d.ts.map +1 -1
  63. package/dist/context/types.js +2 -15
  64. package/dist/context/types.js.map +1 -1
  65. package/dist/core/constraints/agent-prompt-renderer.d.ts +1 -1
  66. package/dist/core/constraints/agent-prompt-renderer.js +1 -1
  67. package/dist/core/constraints/capabilities-parser.d.ts +17 -2
  68. package/dist/core/constraints/capabilities-parser.d.ts.map +1 -1
  69. package/dist/core/constraints/capabilities-parser.js +84 -2
  70. package/dist/core/constraints/capabilities-parser.js.map +1 -1
  71. package/dist/core/constraints/checker.d.ts +3 -17
  72. package/dist/core/constraints/checker.d.ts.map +1 -1
  73. package/dist/core/constraints/checker.js +7 -47
  74. package/dist/core/constraints/checker.js.map +1 -1
  75. package/dist/core/constraints/definitions.d.ts +0 -7
  76. package/dist/core/constraints/definitions.d.ts.map +1 -1
  77. package/dist/core/constraints/definitions.js +1 -8
  78. package/dist/core/constraints/definitions.js.map +1 -1
  79. package/dist/core/constraints/doc-freshness/runner.d.ts +0 -2
  80. package/dist/core/constraints/doc-freshness/runner.d.ts.map +1 -1
  81. package/dist/core/constraints/doc-freshness/runner.js.map +1 -1
  82. package/dist/core/constraints/index.d.ts +1 -1
  83. package/dist/core/constraints/index.d.ts.map +1 -1
  84. package/dist/core/constraints/index.js +2 -3
  85. package/dist/core/constraints/index.js.map +1 -1
  86. package/dist/core/constraints/interceptor.d.ts.map +1 -1
  87. package/dist/core/constraints/interceptor.js +1 -5
  88. package/dist/core/constraints/interceptor.js.map +1 -1
  89. package/dist/core/effective-constraints.d.ts.map +1 -1
  90. package/dist/core/effective-constraints.js +0 -1
  91. package/dist/core/effective-constraints.js.map +1 -1
  92. package/dist/core/project-config-loader.d.ts.map +1 -1
  93. package/dist/core/project-config-loader.js +1 -8
  94. package/dist/core/project-config-loader.js.map +1 -1
  95. package/dist/dashboard/stats.d.ts.map +1 -1
  96. package/dist/dashboard/stats.js.map +1 -1
  97. package/dist/dashboard/types.d.ts +2 -2
  98. package/dist/dashboard/types.d.ts.map +1 -1
  99. package/dist/failure/constraint-handler.d.ts.map +1 -1
  100. package/dist/failure/constraint-handler.js +0 -2
  101. package/dist/failure/constraint-handler.js.map +1 -1
  102. package/dist/gates/acceptance.d.ts +9 -1
  103. package/dist/gates/acceptance.d.ts.map +1 -1
  104. package/dist/gates/acceptance.js +21 -0
  105. package/dist/gates/acceptance.js.map +1 -1
  106. package/dist/gates/checker-gate.d.ts +23 -0
  107. package/dist/gates/checker-gate.d.ts.map +1 -0
  108. package/dist/gates/checker-gate.js +53 -0
  109. package/dist/gates/checker-gate.js.map +1 -0
  110. package/dist/gates/command.d.ts +9 -2
  111. package/dist/gates/command.d.ts.map +1 -1
  112. package/dist/gates/command.js +10 -0
  113. package/dist/gates/command.js.map +1 -1
  114. package/dist/gates/contract.d.ts +8 -2
  115. package/dist/gates/contract.d.ts.map +1 -1
  116. package/dist/gates/contract.js +9 -0
  117. package/dist/gates/contract.js.map +1 -1
  118. package/dist/gates/decision.d.ts +17 -0
  119. package/dist/gates/decision.d.ts.map +1 -0
  120. package/dist/gates/decision.js +25 -0
  121. package/dist/gates/decision.js.map +1 -0
  122. package/dist/gates/definitions.d.ts +63 -0
  123. package/dist/gates/definitions.d.ts.map +1 -0
  124. package/dist/gates/definitions.js +160 -0
  125. package/dist/gates/definitions.js.map +1 -0
  126. package/dist/gates/effective-gates.d.ts +30 -0
  127. package/dist/gates/effective-gates.d.ts.map +1 -0
  128. package/dist/gates/effective-gates.js +85 -0
  129. package/dist/gates/effective-gates.js.map +1 -0
  130. package/dist/gates/index.d.ts +25 -1
  131. package/dist/gates/index.d.ts.map +1 -1
  132. package/dist/gates/index.js +37 -1
  133. package/dist/gates/index.js.map +1 -1
  134. package/dist/gates/performance.d.ts +8 -2
  135. package/dist/gates/performance.d.ts.map +1 -1
  136. package/dist/gates/performance.js +9 -0
  137. package/dist/gates/performance.js.map +1 -1
  138. package/dist/gates/registry.d.ts +32 -0
  139. package/dist/gates/registry.d.ts.map +1 -0
  140. package/dist/gates/registry.js +90 -0
  141. package/dist/gates/registry.js.map +1 -0
  142. package/dist/gates/review.d.ts +8 -2
  143. package/dist/gates/review.d.ts.map +1 -1
  144. package/dist/gates/review.js +9 -0
  145. package/dist/gates/review.js.map +1 -1
  146. package/dist/gates/runner.d.ts +30 -0
  147. package/dist/gates/runner.d.ts.map +1 -0
  148. package/dist/gates/runner.js +38 -0
  149. package/dist/gates/runner.js.map +1 -0
  150. package/dist/gates/security.d.ts +8 -2
  151. package/dist/gates/security.d.ts.map +1 -1
  152. package/dist/gates/security.js +9 -0
  153. package/dist/gates/security.js.map +1 -1
  154. package/dist/gates/types.d.ts +41 -1
  155. package/dist/gates/types.d.ts.map +1 -1
  156. package/dist/hooks/bootstrap.d.ts.map +1 -1
  157. package/dist/hooks/bootstrap.js +0 -2
  158. package/dist/hooks/bootstrap.js.map +1 -1
  159. package/dist/hooks/config.d.ts +26 -0
  160. package/dist/hooks/config.d.ts.map +1 -0
  161. package/dist/hooks/config.js +30 -0
  162. package/dist/hooks/config.js.map +1 -0
  163. package/dist/hooks/index.d.ts +2 -1
  164. package/dist/hooks/index.d.ts.map +1 -1
  165. package/dist/hooks/index.js +4 -1
  166. package/dist/hooks/index.js.map +1 -1
  167. package/dist/hooks/registry.d.ts +18 -1
  168. package/dist/hooks/registry.d.ts.map +1 -1
  169. package/dist/hooks/registry.js +45 -0
  170. package/dist/hooks/registry.js.map +1 -1
  171. package/dist/hooks/types.d.ts +20 -0
  172. package/dist/hooks/types.d.ts.map +1 -1
  173. package/dist/index.d.ts +5 -8
  174. package/dist/index.d.ts.map +1 -1
  175. package/dist/index.js +11 -20
  176. package/dist/index.js.map +1 -1
  177. package/dist/knowledge/import.d.ts +2 -2
  178. package/dist/knowledge/import.d.ts.map +1 -1
  179. package/dist/knowledge/ingest.js.map +1 -1
  180. package/dist/knowledge/lifecycle-hooks.d.ts +2 -2
  181. package/dist/knowledge/lifecycle-hooks.d.ts.map +1 -1
  182. package/dist/knowledge/types.d.ts +5 -7
  183. package/dist/knowledge/types.d.ts.map +1 -1
  184. package/dist/knowledge/types.js +1 -1
  185. package/dist/knowledge/types.js.map +1 -1
  186. package/dist/monitoring/constraint-doctor.d.ts +4 -22
  187. package/dist/monitoring/constraint-doctor.d.ts.map +1 -1
  188. package/dist/monitoring/constraint-doctor.js +7 -94
  189. package/dist/monitoring/constraint-doctor.js.map +1 -1
  190. package/dist/presets/standard.d.ts +1 -1
  191. package/dist/presets/standard.d.ts.map +1 -1
  192. package/dist/presets/standard.js +1 -2
  193. package/dist/presets/standard.js.map +1 -1
  194. package/dist/pretool-use-hook.d.ts +16 -0
  195. package/dist/pretool-use-hook.d.ts.map +1 -0
  196. package/dist/pretool-use-hook.js +68 -0
  197. package/dist/pretool-use-hook.js.map +1 -0
  198. package/dist/spec/annotation-checker.d.ts.map +1 -1
  199. package/dist/spec/annotation-checker.js +6 -26
  200. package/dist/spec/annotation-checker.js.map +1 -1
  201. package/dist/tools/index.d.ts +0 -4
  202. package/dist/tools/index.d.ts.map +1 -1
  203. package/dist/tools/index.js +0 -4
  204. package/dist/tools/index.js.map +1 -1
  205. package/dist/types/constraint.d.ts +1 -12
  206. package/dist/types/constraint.d.ts.map +1 -1
  207. package/dist/types/constraint.js +0 -3
  208. package/dist/types/constraint.js.map +1 -1
  209. package/dist/types/project-config.d.ts +0 -2
  210. package/dist/types/project-config.d.ts.map +1 -1
  211. package/dist/utils/file-walk.d.ts +2 -2
  212. package/dist/utils/file-walk.js +2 -2
  213. package/package.json +6 -1
  214. package/src/CONTEXT.md +15 -0
  215. package/src/__tests__/checker-extra.test.ts +2 -59
  216. package/src/__tests__/constraint-doctor.test.ts +1 -140
  217. package/src/__tests__/constraint-handler.test.ts +0 -4
  218. package/src/__tests__/pretool-use-hook.test.ts +82 -0
  219. package/src/__tests__/project-config-loader-extra.test.ts +0 -20
  220. package/src/__tests__/project-config-loader.test.ts +0 -1
  221. package/src/cli/commands/CONTEXT.md +15 -7
  222. package/src/cli/commands/__tests__/check-drift.test.ts +0 -3
  223. package/src/cli/commands/__tests__/check-skip-output.test.ts +0 -5
  224. package/src/cli/commands/__tests__/check.test.ts +7 -75
  225. package/src/cli/commands/__tests__/registry.test.ts +201 -0
  226. package/src/cli/commands/__tests__/sync-docs-agents.test.ts +55 -0
  227. package/src/cli/commands/check.ts +2 -14
  228. package/src/cli/commands/definitions.ts +593 -0
  229. package/src/cli/commands/knowledge.ts +3 -3
  230. package/src/cli/commands/sync-docs/agents-syncer.ts +26 -6
  231. package/src/cli/commands/sync-docs/capabilities-syncer.ts +4 -110
  232. package/src/cli/commands/sync-docs/index.ts +8 -5
  233. package/src/completion-checkers/CONTEXT.md +25 -0
  234. package/src/completion-checkers/__tests__/contract-presence.test.ts +44 -0
  235. package/src/completion-checkers/__tests__/phase-format.test.ts +60 -0
  236. package/src/completion-checkers/__tests__/tdd-chain.test.ts +99 -0
  237. package/src/completion-checkers/classify.ts +47 -0
  238. package/src/completion-checkers/contract-presence.ts +40 -0
  239. package/src/completion-checkers/glob-match.ts +54 -0
  240. package/src/completion-checkers/index.ts +19 -0
  241. package/src/completion-checkers/phase-format.ts +48 -0
  242. package/src/completion-checkers/tdd-chain.ts +63 -0
  243. package/src/completion-checkers/types.ts +84 -0
  244. package/src/context/CONTEXT.md +2 -7
  245. package/src/context/__tests__/session-manager.test.ts +0 -91
  246. package/src/context/index.ts +1 -5
  247. package/src/context/knowledge-injector.ts +3 -3
  248. package/src/context/session-manager.ts +0 -74
  249. package/src/context/types.ts +2 -63
  250. package/src/core/constraints/__tests__/interceptor.test.ts +0 -2
  251. package/src/core/constraints/agent-prompt-renderer.ts +1 -1
  252. package/src/core/constraints/capabilities-parser.ts +95 -2
  253. package/src/core/constraints/checker.ts +8 -53
  254. package/src/core/constraints/definitions.ts +0 -8
  255. package/src/core/constraints/doc-freshness/runner.ts +1 -2
  256. package/src/core/constraints/index.ts +1 -2
  257. package/src/core/constraints/interceptor.ts +1 -6
  258. package/src/core/effective-constraints.ts +0 -1
  259. package/src/core/project-config-loader.ts +1 -7
  260. package/src/dashboard/stats.ts +2 -2
  261. package/src/dashboard/types.ts +2 -2
  262. package/src/failure/constraint-handler.ts +0 -2
  263. package/src/gates/CONTEXT.md +16 -13
  264. package/src/gates/__tests__/checker-gate.test.ts +45 -0
  265. package/src/gates/__tests__/contract.test.ts +73 -0
  266. package/src/gates/__tests__/effective-gates.test.ts +82 -0
  267. package/src/gates/__tests__/gate-interface.test.ts +202 -0
  268. package/src/gates/__tests__/registry.test.ts +87 -0
  269. package/src/gates/__tests__/runner.test.ts +81 -0
  270. package/src/gates/acceptance.ts +24 -1
  271. package/src/gates/checker-gate.ts +54 -0
  272. package/src/gates/command.ts +13 -2
  273. package/src/gates/contract.ts +12 -2
  274. package/src/gates/decision.ts +27 -0
  275. package/src/gates/definitions.ts +207 -0
  276. package/src/gates/effective-gates.ts +106 -0
  277. package/src/gates/index.ts +38 -0
  278. package/src/gates/performance.ts +12 -2
  279. package/src/gates/registry.ts +107 -0
  280. package/src/gates/review.ts +12 -2
  281. package/src/gates/runner.ts +57 -0
  282. package/src/gates/security.ts +12 -2
  283. package/src/gates/types.ts +48 -1
  284. package/src/hooks/CONTEXT.md +12 -2
  285. package/src/hooks/__tests__/bootstrap.test.ts +0 -1
  286. package/src/hooks/__tests__/config.test.ts +19 -0
  287. package/src/hooks/__tests__/pipeline.test.ts +79 -0
  288. package/src/hooks/__tests__/registry.test.ts +67 -0
  289. package/src/hooks/bootstrap.ts +0 -2
  290. package/src/hooks/config.ts +29 -0
  291. package/src/hooks/index.ts +2 -1
  292. package/src/hooks/registry.ts +60 -1
  293. package/src/hooks/types.ts +21 -0
  294. package/src/index.ts +11 -21
  295. package/src/knowledge/import.ts +3 -3
  296. package/src/knowledge/ingest.ts +4 -4
  297. package/src/knowledge/lifecycle-hooks.ts +3 -3
  298. package/src/knowledge/types.ts +5 -8
  299. package/src/monitoring/constraint-doctor.ts +7 -106
  300. package/src/presets/__tests__/standard.test.ts +0 -2
  301. package/src/presets/standard.ts +1 -2
  302. package/src/pretool-use-hook.ts +68 -0
  303. package/src/spec/__tests__/annotation-checker.test.ts +9 -3
  304. package/src/spec/annotation-checker.ts +7 -29
  305. package/src/tools/CONTEXT.md +7 -14
  306. package/src/tools/index.ts +0 -4
  307. package/src/types/constraint.ts +1 -14
  308. package/src/types/project-config.ts +0 -3
  309. package/src/utils/file-walk.ts +2 -2
  310. package/dist/architecture/constraint-engine.d.ts +0 -67
  311. package/dist/architecture/constraint-engine.d.ts.map +0 -1
  312. package/dist/architecture/constraint-engine.js +0 -295
  313. package/dist/architecture/constraint-engine.js.map +0 -1
  314. package/dist/architecture/cross-project-checker.d.ts +0 -54
  315. package/dist/architecture/cross-project-checker.d.ts.map +0 -1
  316. package/dist/architecture/cross-project-checker.js +0 -467
  317. package/dist/architecture/cross-project-checker.js.map +0 -1
  318. package/dist/cli/commands/index.d.ts +0 -30
  319. package/dist/cli/commands/index.d.ts.map +0 -1
  320. package/dist/cli/commands/index.js +0 -91
  321. package/dist/cli/commands/index.js.map +0 -1
  322. package/dist/context/file-budget.d.ts +0 -40
  323. package/dist/context/file-budget.d.ts.map +0 -1
  324. package/dist/context/file-budget.js +0 -147
  325. package/dist/context/file-budget.js.map +0 -1
  326. package/dist/context/progressive-loader.d.ts +0 -109
  327. package/dist/context/progressive-loader.d.ts.map +0 -1
  328. package/dist/context/progressive-loader.js +0 -166
  329. package/dist/context/progressive-loader.js.map +0 -1
  330. package/dist/context/token-pipeline.d.ts +0 -55
  331. package/dist/context/token-pipeline.d.ts.map +0 -1
  332. package/dist/context/token-pipeline.js +0 -220
  333. package/dist/context/token-pipeline.js.map +0 -1
  334. package/dist/context/tool-output-budget.d.ts +0 -59
  335. package/dist/context/tool-output-budget.d.ts.map +0 -1
  336. package/dist/context/tool-output-budget.js +0 -177
  337. package/dist/context/tool-output-budget.js.map +0 -1
  338. package/dist/core/constraints/default-executors.d.ts +0 -10
  339. package/dist/core/constraints/default-executors.d.ts.map +0 -1
  340. package/dist/core/constraints/default-executors.js +0 -120
  341. package/dist/core/constraints/default-executors.js.map +0 -1
  342. package/dist/llm/adapter.d.ts +0 -36
  343. package/dist/llm/adapter.d.ts.map +0 -1
  344. package/dist/llm/adapter.js +0 -118
  345. package/dist/llm/adapter.js.map +0 -1
  346. package/dist/llm/index.d.ts +0 -3
  347. package/dist/llm/index.d.ts.map +0 -1
  348. package/dist/llm/index.js +0 -19
  349. package/dist/llm/index.js.map +0 -1
  350. package/dist/llm/types.d.ts +0 -62
  351. package/dist/llm/types.d.ts.map +0 -1
  352. package/dist/llm/types.js +0 -8
  353. package/dist/llm/types.js.map +0 -1
  354. package/dist/tools/core/index.d.ts +0 -13
  355. package/dist/tools/core/index.d.ts.map +0 -1
  356. package/dist/tools/core/index.js +0 -198
  357. package/dist/tools/core/index.js.map +0 -1
  358. package/dist/tools/loader.d.ts +0 -21
  359. package/dist/tools/loader.d.ts.map +0 -1
  360. package/dist/tools/loader.js +0 -199
  361. package/dist/tools/loader.js.map +0 -1
  362. package/dist/tools/registry.d.ts +0 -59
  363. package/dist/tools/registry.d.ts.map +0 -1
  364. package/dist/tools/registry.js +0 -115
  365. package/dist/tools/registry.js.map +0 -1
  366. package/dist/tools/types.d.ts +0 -38
  367. package/dist/tools/types.d.ts.map +0 -1
  368. package/dist/tools/types.js +0 -6
  369. package/dist/tools/types.js.map +0 -1
  370. package/src/__tests__/architecture-engine.test.ts +0 -619
  371. package/src/__tests__/context/progressive-loader.test.ts +0 -131
  372. package/src/__tests__/cross-project-checker.test.ts +0 -318
  373. package/src/architecture/CONTEXT.md +0 -22
  374. package/src/architecture/constraint-engine.ts +0 -351
  375. package/src/architecture/cross-project-checker.ts +0 -545
  376. package/src/cli/commands/index.ts +0 -30
  377. package/src/context/__tests__/file-budget.test.ts +0 -142
  378. package/src/context/__tests__/progressive-loader.test.ts +0 -264
  379. package/src/context/__tests__/token-pipeline.test.ts +0 -178
  380. package/src/context/__tests__/tool-output-budget.test.ts +0 -95
  381. package/src/context/file-budget.ts +0 -142
  382. package/src/context/progressive-loader.ts +0 -260
  383. package/src/context/token-pipeline.ts +0 -265
  384. package/src/context/tool-output-budget.ts +0 -178
  385. package/src/core/constraints/__tests__/default-executors.test.ts +0 -57
  386. package/src/core/constraints/default-executors.ts +0 -92
  387. package/src/llm/CONTEXT.md +0 -21
  388. package/src/llm/__tests__/adapter.test.ts +0 -172
  389. package/src/llm/adapter.ts +0 -149
  390. package/src/llm/index.ts +0 -2
  391. package/src/llm/types.ts +0 -81
  392. package/src/tools/__tests__/loader.test.ts +0 -252
  393. package/src/tools/__tests__/registry.test.ts +0 -157
  394. package/src/tools/core/__tests__/core.test.ts +0 -122
  395. package/src/tools/core/index.ts +0 -201
  396. package/src/tools/loader.ts +0 -216
  397. package/src/tools/registry.ts +0 -128
  398. package/src/tools/types.ts +0 -46
@@ -0,0 +1,202 @@
1
+ /**
2
+ * 6 门禁统一接口行为测试(G1)
3
+ *
4
+ * 每个门禁的 evaluate(ctx) 收敛到统一 Gate 接口:
5
+ * 执行细节私有,报告 GateResult → 三态 GateDecision(passed → abstain,失败 → deny),
6
+ * 决策浅冻结。契约门禁(contract)的测试在 contract.test.ts。
7
+ */
8
+
9
+ import { exec } from 'child_process';
10
+ import * as fs from 'fs';
11
+ import * as os from 'os';
12
+ import * as path from 'path';
13
+ import { ReviewGate } from '../review';
14
+ import { SecurityGate } from '../security';
15
+ import { PerformanceGate } from '../performance';
16
+ import { SpecAcceptanceGate } from '../acceptance';
17
+ import { CommandGate } from '../command';
18
+
19
+ // Mock exec(ReviewGate/SecurityGate 走 execAsync)
20
+ jest.mock('child_process', () => ({
21
+ exec: jest.fn(),
22
+ }));
23
+
24
+ const mockExec = exec as unknown as jest.Mock;
25
+
26
+ function callExec(cmd: string, _opts: unknown, callback: (err: unknown, res: { stdout: string }) => void): void {
27
+ callback(null, { stdout: cmd.includes('@{u}') ? '' : 'abc123 commit msg' });
28
+ }
29
+
30
+ describe('ReviewGate 统一接口', () => {
31
+ beforeEach(() => jest.clearAllMocks());
32
+
33
+ it('本地模式 requireApproval=true → deny(三态映射 + 冻结)', async () => {
34
+ mockExec.mockImplementation(callExec);
35
+ const decision = await new ReviewGate().evaluate({
36
+ projectId: 'p',
37
+ projectPath: '/test/project',
38
+ });
39
+ expect(decision.status).toBe('deny');
40
+ expect(decision.result.gate).toBe('review');
41
+ expect(decision.result.passed).toBe(false);
42
+ expect(Object.isFrozen(decision)).toBe(true);
43
+ });
44
+
45
+ it('本地模式 requireApproval=false → abstain', async () => {
46
+ mockExec.mockImplementation(callExec);
47
+ const decision = await new ReviewGate({ requireApproval: false }).evaluate({
48
+ projectId: 'p',
49
+ projectPath: '/test/project',
50
+ });
51
+ expect(decision.status).toBe('abstain');
52
+ expect(decision.result.passed).toBe(true);
53
+ });
54
+
55
+ it('id/order 字段齐备', () => {
56
+ const gate = new ReviewGate();
57
+ expect(gate.id).toBe('review');
58
+ expect(gate.order).toBe(0);
59
+ });
60
+ });
61
+
62
+ describe('SecurityGate 统一接口', () => {
63
+ beforeEach(() => jest.clearAllMocks());
64
+
65
+ it('npm audit 零漏洞 → abstain', async () => {
66
+ mockExec.mockImplementation((_cmd, _opts, callback) =>
67
+ callback(null, { stdout: JSON.stringify({ audit: { advisories: {} } }) })
68
+ );
69
+ const decision = await new SecurityGate().evaluate({
70
+ projectId: 'p',
71
+ projectPath: '/test/project',
72
+ });
73
+ expect(decision.status).toBe('abstain');
74
+ expect(decision.result.passed).toBe(true);
75
+ });
76
+
77
+ it('发现 critical 漏洞 → deny', async () => {
78
+ mockExec.mockImplementation((_cmd, _opts, callback) =>
79
+ callback(null, {
80
+ stdout: JSON.stringify({
81
+ audit: {
82
+ advisories: {
83
+ '1': { severity: 'critical', name: 'bad-lib', via: [{ title: 'RCE' }] },
84
+ },
85
+ },
86
+ }),
87
+ })
88
+ );
89
+ const decision = await new SecurityGate().evaluate({
90
+ projectId: 'p',
91
+ projectPath: '/test/project',
92
+ });
93
+ expect(decision.status).toBe('deny');
94
+ expect(decision.result.details?.critical).toBe(1);
95
+ });
96
+
97
+ it('id/order 字段齐备', () => {
98
+ const gate = new SecurityGate();
99
+ expect(gate.id).toBe('security');
100
+ expect(gate.order).toBe(0);
101
+ });
102
+ });
103
+
104
+ describe('PerformanceGate 统一接口', () => {
105
+ it('enabled=false → abstain(禁用即放行)', async () => {
106
+ const decision = await new PerformanceGate({ enabled: false }).evaluate({
107
+ projectId: 'p',
108
+ projectPath: '/test/project',
109
+ });
110
+ expect(decision.status).toBe('abstain');
111
+ expect(decision.result.passed).toBe(true);
112
+ });
113
+
114
+ it('id/order 字段齐备', () => {
115
+ const gate = new PerformanceGate();
116
+ expect(gate.id).toBe('performance');
117
+ expect(gate.order).toBe(0);
118
+ });
119
+ });
120
+
121
+ describe('SpecAcceptanceGate 统一接口', () => {
122
+ let dir: string;
123
+
124
+ beforeEach(() => {
125
+ dir = fs.mkdtempSync(path.join(os.tmpdir(), 'harness-gate-acc-'));
126
+ });
127
+
128
+ afterEach(() => {
129
+ fs.rmSync(dir, { recursive: true, force: true });
130
+ });
131
+
132
+ it('tasks.yml 不存在 → abstain(跳过)', async () => {
133
+ const decision = await new SpecAcceptanceGate().evaluate({
134
+ projectId: 'p',
135
+ projectPath: dir,
136
+ tasksPath: path.join(dir, 'no-such-tasks.yml'),
137
+ });
138
+ expect(decision.status).toBe('abstain');
139
+ expect(decision.result.passed).toBe(true);
140
+ expect(decision.result.gate).toBe('acceptance');
141
+ });
142
+
143
+ it('已完成任务验收标准未勾选 → deny', async () => {
144
+ const tasksPath = path.join(dir, 'tasks.yml');
145
+ fs.writeFileSync(
146
+ tasksPath,
147
+ [
148
+ 'tasks:',
149
+ ' - id: TASK-001',
150
+ ' status: done',
151
+ ' acceptance_criteria:',
152
+ ' - id: AC-001',
153
+ ' description: Test',
154
+ ' type: manual',
155
+ ' required: true',
156
+ ' checked: false',
157
+ ].join('\n')
158
+ );
159
+ const decision = await new SpecAcceptanceGate().evaluate({
160
+ projectId: 'p',
161
+ projectPath: dir,
162
+ tasksPath,
163
+ });
164
+ expect(decision.status).toBe('deny');
165
+ expect(decision.result.passed).toBe(false);
166
+ expect(Object.isFrozen(decision)).toBe(true);
167
+ });
168
+
169
+ it('id/order 字段齐备', () => {
170
+ const gate = new SpecAcceptanceGate();
171
+ expect(gate.id).toBe('acceptance');
172
+ expect(gate.order).toBe(0);
173
+ });
174
+ });
175
+
176
+ describe('CommandGate 统一接口', () => {
177
+ it('黑名单命令 → deny', async () => {
178
+ const decision = await new CommandGate().evaluate({
179
+ projectId: 'p',
180
+ projectPath: '/test/project',
181
+ command: 'rm -rf /',
182
+ });
183
+ expect(decision.status).toBe('deny');
184
+ expect(decision.result.passed).toBe(false);
185
+ });
186
+
187
+ it('安全命令 → abstain', async () => {
188
+ const decision = await new CommandGate().evaluate({
189
+ projectId: 'p',
190
+ projectPath: '/test/project',
191
+ command: 'echo hello',
192
+ });
193
+ expect(decision.status).toBe('abstain');
194
+ expect(decision.result.passed).toBe(true);
195
+ });
196
+
197
+ it('id/order 字段齐备', () => {
198
+ const gate = new CommandGate();
199
+ expect(gate.id).toBe('command');
200
+ expect(gate.order).toBe(0);
201
+ });
202
+ });
@@ -0,0 +1,87 @@
1
+ /**
2
+ * 门禁注册表测试(G1 闭环)
3
+ */
4
+
5
+ import { GATE_DEFINITIONS, type GateDefinition } from '../definitions';
6
+ import {
7
+ getGate,
8
+ listRegisteredGates,
9
+ registeredGateCount,
10
+ assertGateRegistryClosed,
11
+ } from '../registry';
12
+ import { decisionFromResult } from '../decision';
13
+ import type { Gate } from '../types';
14
+
15
+ function fakeGate(id: string): Gate {
16
+ return {
17
+ id,
18
+ order: 0,
19
+ evaluate: async () =>
20
+ decisionFromResult({
21
+ gate: id,
22
+ passed: true,
23
+ message: 'ok',
24
+ timestamp: new Date().toISOString(),
25
+ }),
26
+ };
27
+ }
28
+
29
+ describe('gateRegistry', () => {
30
+ it('定义即注册:6 个门禁定义全部有实现', () => {
31
+ expect(registeredGateCount()).toBe(6);
32
+ for (const def of GATE_DEFINITIONS) {
33
+ const gate = getGate(def.id);
34
+ expect(gate).toBeDefined();
35
+ expect(gate.id).toBe(def.id);
36
+ }
37
+ });
38
+
39
+ it('注册实现携带定义表默认 order 与统一 evaluate', () => {
40
+ for (const def of GATE_DEFINITIONS) {
41
+ const gate = getGate(def.id);
42
+ expect(gate.order).toBe(def.order);
43
+ expect(typeof gate.evaluate).toBe('function');
44
+ }
45
+ });
46
+
47
+ it('listRegisteredGates 返回副本且按定义序', () => {
48
+ const gates = listRegisteredGates();
49
+ expect(gates.map(g => g.id)).toEqual(GATE_DEFINITIONS.map(d => d.id));
50
+ gates.pop();
51
+ expect(listRegisteredGates()).toHaveLength(6);
52
+ });
53
+
54
+ it('定义无实现 → 抛错(闭环失败方向 1)', () => {
55
+ const definitions: GateDefinition[] = [
56
+ { id: 'orphan-def', description: 'x', order: 0, cli: { command: 'x', description: 'x', options: [], action: { module: 'x', export: 'x' }, mapActionArgs: () => [] } },
57
+ ];
58
+ const implementations = [fakeGate('other')];
59
+ expect(() => assertGateRegistryClosed(definitions, implementations)).toThrow(
60
+ /门禁定义 "orphan-def" 未注册实现/
61
+ );
62
+ });
63
+
64
+ it('实现无定义 → 抛错(闭环失败方向 2)', () => {
65
+ const definitions: GateDefinition[] = [
66
+ { id: 'defined', description: 'x', order: 0, cli: { command: 'x', description: 'x', options: [], action: { module: 'x', export: 'x' }, mapActionArgs: () => [] } },
67
+ ];
68
+ const implementations = [fakeGate('defined'), fakeGate('undocumented-impl')];
69
+ expect(() => assertGateRegistryClosed(definitions, implementations)).toThrow(
70
+ /门禁实现 "undocumented-impl" 没有对应定义/
71
+ );
72
+ });
73
+
74
+ it('重复 id → 抛错', () => {
75
+ const definitions: GateDefinition[] = [
76
+ { id: 'dup', description: 'x', order: 0, cli: { command: 'x', description: 'x', options: [], action: { module: 'x', export: 'x' }, mapActionArgs: () => [] } },
77
+ ];
78
+ const implementations = [fakeGate('dup'), fakeGate('dup')];
79
+ expect(() => assertGateRegistryClosed(definitions, implementations)).toThrow(
80
+ /门禁 "dup" 重复注册/
81
+ );
82
+ });
83
+
84
+ it('引用未注册 → getGate 抛错(闭环)', () => {
85
+ expect(() => getGate('nonexistent')).toThrow(/门禁 "nonexistent" 未注册/);
86
+ });
87
+ });
@@ -0,0 +1,81 @@
1
+ /**
2
+ * 门禁执行器测试(G1:deny 单调 + ask fail-closed + order 排序)
3
+ */
4
+
5
+ import { runGates } from '../runner';
6
+ import { decisionFromResult } from '../decision';
7
+ import type { Gate, GateContext, GateDecisionStatus } from '../types';
8
+
9
+ function fakeGate(id: string, order: number, status: GateDecisionStatus): Gate {
10
+ return {
11
+ id,
12
+ order,
13
+ evaluate: async () =>
14
+ decisionFromResult(
15
+ {
16
+ gate: id,
17
+ passed: status !== 'deny',
18
+ message: id,
19
+ timestamp: new Date().toISOString(),
20
+ },
21
+ status
22
+ ),
23
+ };
24
+ }
25
+
26
+ const ctx: GateContext = { projectId: 'p', projectPath: '/tmp/project' };
27
+
28
+ describe('runGates', () => {
29
+ it('deny 单调:先 deny 后 abstain,终态 deny(下游不得改回 allow)', async () => {
30
+ const result = await runGates(
31
+ [fakeGate('a', 0, 'deny'), fakeGate('b', 1, 'abstain')],
32
+ ctx
33
+ );
34
+ expect(result.status).toBe('deny');
35
+ expect(result.denied.map(d => d.result.gate)).toEqual(['a']);
36
+ expect(result.decisions.map(d => d.result.gate)).toEqual(['a', 'b']);
37
+ });
38
+
39
+ it('deny 单调:先 abstain 后 deny,终态 deny', async () => {
40
+ const result = await runGates(
41
+ [fakeGate('a', 0, 'abstain'), fakeGate('b', 1, 'deny')],
42
+ ctx
43
+ );
44
+ expect(result.status).toBe('deny');
45
+ expect(result.denied).toHaveLength(1);
46
+ });
47
+
48
+ it('全部 abstain → 终态 abstain', async () => {
49
+ const result = await runGates(
50
+ [fakeGate('a', 0, 'abstain'), fakeGate('b', 1, 'abstain')],
51
+ ctx
52
+ );
53
+ expect(result.status).toBe('abstain');
54
+ expect(result.denied).toHaveLength(0);
55
+ expect(result.asked).toHaveLength(0);
56
+ });
57
+
58
+ it('ask 枚举预留:无实现时 fail-closed = deny', async () => {
59
+ const result = await runGates([fakeGate('asker', 0, 'ask')], ctx);
60
+ expect(result.status).toBe('deny');
61
+ expect(result.asked).toHaveLength(1);
62
+ expect(result.asked[0].status).toBe('ask');
63
+ expect(result.denied).toHaveLength(0);
64
+ });
65
+
66
+ it('按声明式 order 升序执行(入参顺序无关)', async () => {
67
+ const result = await runGates(
68
+ [fakeGate('c', 3, 'abstain'), fakeGate('a', 1, 'abstain'), fakeGate('b', 2, 'abstain')],
69
+ ctx
70
+ );
71
+ expect(result.decisions.map(d => d.result.gate)).toEqual(['a', 'b', 'c']);
72
+ });
73
+
74
+ it('决策浅冻结:调用方/下游改写决策抛错(单调语义接口契约)', async () => {
75
+ const result = await runGates([fakeGate('a', 0, 'deny')], ctx);
76
+ expect(Object.isFrozen(result.decisions[0])).toBe(true);
77
+ expect(() => {
78
+ (result.decisions[0] as { status: GateDecisionStatus }).status = 'abstain';
79
+ }).toThrow(TypeError);
80
+ });
81
+ });
@@ -21,6 +21,8 @@ import { execAsync } from '../utils/exec';
21
21
  import * as fs from 'fs/promises';
22
22
  import * as path from 'path';
23
23
  import * as yaml from 'js-yaml';
24
+ import type { Gate, GateContext, GateDecision } from './types';
25
+ import { decisionFromResult } from './decision';
24
26
 
25
27
 
26
28
  // ==================== 类型定义 ====================
@@ -135,7 +137,9 @@ export interface E2ETestResult {
135
137
  /**
136
138
  * 验收标准门禁
137
139
  */
138
- export class SpecAcceptanceGate {
140
+ export class SpecAcceptanceGate implements Gate {
141
+ readonly id = 'acceptance';
142
+ order = 0;
139
143
  private config: SpecAcceptanceGateConfig;
140
144
 
141
145
  constructor(config?: Partial<SpecAcceptanceGateConfig>) {
@@ -148,6 +152,25 @@ export class SpecAcceptanceGate {
148
152
  };
149
153
  }
150
154
 
155
+ /**
156
+ * 统一门禁接口(G1):执行细节私有,决策三态由 check() 报告推导。
157
+ * AcceptanceGateResult 无 gate 字段,此处归一化为 GateResult 报告结构。
158
+ */
159
+ async evaluate(context: GateContext): Promise<GateDecision> {
160
+ const result = await this.check({
161
+ projectPath: context.projectPath,
162
+ taskId: context.taskId,
163
+ tasksPath: context.tasksPath,
164
+ });
165
+ return decisionFromResult({
166
+ gate: 'acceptance',
167
+ passed: result.passed,
168
+ message: result.message,
169
+ timestamp: result.timestamp,
170
+ details: result.details as Record<string, any>,
171
+ });
172
+ }
173
+
151
174
  /**
152
175
  * 检查验收标准
153
176
  */
@@ -0,0 +1,54 @@
1
+ /**
2
+ * checker-as-guard 接线点(G1 / studio #129 随动)
3
+ *
4
+ * 把已注册的 ConstraintCheck 适配为统一 Gate,供守卫链(如 studio
5
+ * runCompletionGuards)复用 runGates 的 deny 单调 / ask fail-closed 语义。
6
+ *
7
+ * 证据语义:本接线点构造的 CheckEnv 不带 git staged diff / 源码扫描证据
8
+ * (stagedDiff 空、srcScan 空)——证据 flag 未接线的 checker 按契约返回
9
+ * 'skip'(不阻断,映射为 abstain);纯上下文判断的 checker 照常判定。
10
+ * studio 侧若需 git 证据,在 #129 接线时扩展 CheckEnv 构造。
11
+ */
12
+
13
+ import type { CheckEnv, ConstraintCheck } from '../core/constraints/checkers';
14
+ import type { Gate, GateContext, GateDecision } from './types';
15
+ import { decisionFromResult } from './decision';
16
+
17
+ /**
18
+ * 将已注册 checker 适配为统一 Gate(checker-as-guard 接线点)
19
+ *
20
+ * 判定映射:false(违反)→ deny;true(满足)/ 'skip'(未评估)→ abstain。
21
+ *
22
+ * @param check 已注册的 ConstraintCheck(经 checkers 注册表取回)
23
+ * @param order 门禁顺序(供 guard 链排序)
24
+ */
25
+ export function createCheckerGate(check: ConstraintCheck, order = 0): Gate {
26
+ return {
27
+ id: check.id,
28
+ order,
29
+ async evaluate(ctx: GateContext): Promise<GateDecision> {
30
+ const startTime = Date.now();
31
+ const projectPath = ctx.projectPath || process.cwd();
32
+ const env: CheckEnv = {
33
+ context: { operation: 'manual', projectPath },
34
+ projectPath,
35
+ stagedDiff: async () => '',
36
+ stagedDiffNames: async () => '',
37
+ srcScan: () => [],
38
+ };
39
+ const outcome = await check.evaluate(env);
40
+ return decisionFromResult({
41
+ gate: check.id,
42
+ passed: outcome !== false,
43
+ message:
44
+ outcome === false
45
+ ? `checker "${check.id}" 判定违规`
46
+ : outcome === 'skip'
47
+ ? `checker "${check.id}" 跳过(证据未接线)`
48
+ : `checker "${check.id}" 通过`,
49
+ timestamp: new Date().toISOString(),
50
+ duration: Date.now() - startTime,
51
+ });
52
+ },
53
+ };
54
+ }
@@ -5,7 +5,8 @@
5
5
  * 检查命令是否安全,防止执行危险操作
6
6
  */
7
7
 
8
- import type { GateResult, CommandGateConfig, CommandBlacklistRule } from './types';
8
+ import type { GateResult, CommandGateConfig, CommandBlacklistRule, Gate, GateContext, GateDecision } from './types';
9
+ import { decisionFromResult } from './decision';
9
10
 
10
11
  /**
11
12
  * 黑名单级别
@@ -195,7 +196,9 @@ export const DEFAULT_COMMAND_BLACKLIST: CommandBlacklistRule[] = [
195
196
  /**
196
197
  * 命令门禁
197
198
  */
198
- export class CommandGate {
199
+ export class CommandGate implements Gate {
200
+ readonly id = 'command';
201
+ order = 0;
199
202
  private config: Required<CommandGateConfig>;
200
203
  private blacklist: CommandBlacklistRule[];
201
204
 
@@ -214,6 +217,14 @@ export class CommandGate {
214
217
  ];
215
218
  }
216
219
 
220
+ /**
221
+ * 统一门禁接口(G1):执行细节私有,决策三态由 check() 报告推导。
222
+ * 待检命令经 GateContext.command 传入。
223
+ */
224
+ async evaluate(context: GateContext): Promise<GateDecision> {
225
+ return decisionFromResult(await this.check(context.command ?? ''));
226
+ }
227
+
217
228
  /**
218
229
  * 检查命令
219
230
  */
@@ -9,12 +9,15 @@
9
9
 
10
10
  import * as fs from 'fs/promises';
11
11
  import * as path from 'path';
12
- import type { GateResult, GateContext, ContractGateConfig } from './types';
12
+ import type { GateResult, GateContext, ContractGateConfig, Gate, GateDecision } from './types';
13
+ import { decisionFromResult } from './decision';
13
14
 
14
15
  /**
15
16
  * 契约门禁
16
17
  */
17
- export class ContractGate {
18
+ export class ContractGate implements Gate {
19
+ readonly id = 'contract';
20
+ order = 0;
18
21
  private config: Required<ContractGateConfig>;
19
22
 
20
23
  constructor(config: Partial<ContractGateConfig> = {}) {
@@ -26,6 +29,13 @@ export class ContractGate {
26
29
  };
27
30
  }
28
31
 
32
+ /**
33
+ * 统一门禁接口(G1):执行细节私有,决策三态由 check() 报告推导
34
+ */
35
+ async evaluate(context: GateContext): Promise<GateDecision> {
36
+ return decisionFromResult(await this.check(context));
37
+ }
38
+
29
39
  /**
30
40
  * 检查契约
31
41
  */
@@ -0,0 +1,27 @@
1
+ /**
2
+ * 门禁决策构造(G1)
3
+ *
4
+ * GateResult(报告结构)→ GateDecision(三态决策)的映射点。
5
+ */
6
+
7
+ import type { GateDecision, GateDecisionStatus, GateResult } from './types';
8
+
9
+ /**
10
+ * 从报告结构构造决策。
11
+ *
12
+ * status 缺省由 `result.passed` 推导:true → 'abstain'(放行),
13
+ * false → 'deny'(阻断)。'ask' 只能显式指定(枚举预留,暂无实现)。
14
+ *
15
+ * 返回值浅冻结(Object.freeze):决策不可变是 deny 单调语义的接口契约——
16
+ * 下游门禁不得改写上游决策,deny 不可被改回 allow。
17
+ */
18
+ export function decisionFromResult(
19
+ result: GateResult,
20
+ status?: GateDecisionStatus
21
+ ): GateDecision {
22
+ const decision: GateDecision = {
23
+ status: status ?? (result.passed ? 'abstain' : 'deny'),
24
+ result: Object.freeze({ ...result }),
25
+ };
26
+ return Object.freeze(decision);
27
+ }