@dommaker/harness 1.7.0 → 1.8.1

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 (563) hide show
  1. package/CHANGELOG.md +44 -0
  2. package/bin/harness.js +17 -1
  3. package/dist/agents/index.d.ts +6 -2
  4. package/dist/agents/index.d.ts.map +1 -1
  5. package/dist/agents/index.js +6 -16
  6. package/dist/agents/index.js.map +1 -1
  7. package/dist/cli/commands/__tests__/gate-decision.d.ts +18 -0
  8. package/dist/cli/commands/__tests__/gate-decision.d.ts.map +1 -0
  9. package/dist/cli/commands/__tests__/gate-decision.js +26 -0
  10. package/dist/cli/commands/__tests__/gate-decision.js.map +1 -0
  11. package/dist/cli/commands/acceptance.d.ts.map +1 -1
  12. package/dist/cli/commands/acceptance.js +17 -28
  13. package/dist/cli/commands/acceptance.js.map +1 -1
  14. package/dist/cli/commands/check.d.ts +19 -3
  15. package/dist/cli/commands/check.d.ts.map +1 -1
  16. package/dist/cli/commands/check.js +36 -22
  17. package/dist/cli/commands/check.js.map +1 -1
  18. package/dist/cli/commands/command.d.ts +0 -1
  19. package/dist/cli/commands/command.d.ts.map +1 -1
  20. package/dist/cli/commands/command.js +8 -6
  21. package/dist/cli/commands/command.js.map +1 -1
  22. package/dist/cli/commands/constraints-retire.d.ts.map +1 -1
  23. package/dist/cli/commands/constraints-retire.js +36 -57
  24. package/dist/cli/commands/constraints-retire.js.map +1 -1
  25. package/dist/cli/commands/contract.d.ts.map +1 -1
  26. package/dist/cli/commands/contract.js +36 -42
  27. package/dist/cli/commands/contract.js.map +1 -1
  28. package/dist/cli/commands/definitions.d.ts +2 -0
  29. package/dist/cli/commands/definitions.d.ts.map +1 -1
  30. package/dist/cli/commands/definitions.js +11 -6
  31. package/dist/cli/commands/definitions.js.map +1 -1
  32. package/dist/cli/commands/failure.d.ts.map +1 -1
  33. package/dist/cli/commands/failure.js +16 -2
  34. package/dist/cli/commands/failure.js.map +1 -1
  35. package/dist/cli/commands/init.d.ts +14 -8
  36. package/dist/cli/commands/init.d.ts.map +1 -1
  37. package/dist/cli/commands/init.js +172 -364
  38. package/dist/cli/commands/init.js.map +1 -1
  39. package/dist/cli/commands/knowledge-view.d.ts +90 -0
  40. package/dist/cli/commands/knowledge-view.d.ts.map +1 -0
  41. package/dist/cli/commands/knowledge-view.js +198 -0
  42. package/dist/cli/commands/knowledge-view.js.map +1 -0
  43. package/dist/cli/commands/knowledge.d.ts +137 -52
  44. package/dist/cli/commands/knowledge.d.ts.map +1 -1
  45. package/dist/cli/commands/knowledge.js +534 -400
  46. package/dist/cli/commands/knowledge.js.map +1 -1
  47. package/dist/cli/commands/passes-gate.d.ts +4 -1
  48. package/dist/cli/commands/passes-gate.d.ts.map +1 -1
  49. package/dist/cli/commands/passes-gate.js +11 -2
  50. package/dist/cli/commands/passes-gate.js.map +1 -1
  51. package/dist/cli/commands/performance.d.ts.map +1 -1
  52. package/dist/cli/commands/performance.js +19 -31
  53. package/dist/cli/commands/performance.js.map +1 -1
  54. package/dist/cli/commands/report.d.ts.map +1 -1
  55. package/dist/cli/commands/report.js +2 -1
  56. package/dist/cli/commands/report.js.map +1 -1
  57. package/dist/cli/commands/review.d.ts.map +1 -1
  58. package/dist/cli/commands/review.js +13 -25
  59. package/dist/cli/commands/review.js.map +1 -1
  60. package/dist/cli/commands/scaffold-templates.d.ts +73 -0
  61. package/dist/cli/commands/scaffold-templates.d.ts.map +1 -0
  62. package/dist/cli/commands/scaffold-templates.js +424 -0
  63. package/dist/cli/commands/scaffold-templates.js.map +1 -0
  64. package/dist/cli/commands/scaffold.d.ts +105 -0
  65. package/dist/cli/commands/scaffold.d.ts.map +1 -0
  66. package/dist/cli/commands/scaffold.js +263 -0
  67. package/dist/cli/commands/scaffold.js.map +1 -0
  68. package/dist/cli/commands/security.d.ts.map +1 -1
  69. package/dist/cli/commands/security.js +22 -24
  70. package/dist/cli/commands/security.js.map +1 -1
  71. package/dist/cli/commands/spec-baseline-check.d.ts +43 -0
  72. package/dist/cli/commands/spec-baseline-check.d.ts.map +1 -1
  73. package/dist/cli/commands/spec-baseline-check.js +109 -34
  74. package/dist/cli/commands/spec-baseline-check.js.map +1 -1
  75. package/dist/cli/commands/status.d.ts +8 -0
  76. package/dist/cli/commands/status.d.ts.map +1 -1
  77. package/dist/cli/commands/status.js +5 -7
  78. package/dist/cli/commands/status.js.map +1 -1
  79. package/dist/cli/commands/sync-docs/context-syncer.d.ts +21 -2
  80. package/dist/cli/commands/sync-docs/context-syncer.d.ts.map +1 -1
  81. package/dist/cli/commands/sync-docs/context-syncer.js +112 -28
  82. package/dist/cli/commands/sync-docs/context-syncer.js.map +1 -1
  83. package/dist/cli/commands/sync-docs/index.d.ts +1 -1
  84. package/dist/cli/commands/sync-docs/index.d.ts.map +1 -1
  85. package/dist/cli/commands/sync-docs/index.js +86 -27
  86. package/dist/cli/commands/sync-docs/index.js.map +1 -1
  87. package/dist/cli/commands/sync-docs/project-reader.d.ts +24 -1
  88. package/dist/cli/commands/sync-docs/project-reader.d.ts.map +1 -1
  89. package/dist/cli/commands/sync-docs/project-reader.js +33 -7
  90. package/dist/cli/commands/sync-docs/project-reader.js.map +1 -1
  91. package/dist/cli/commands/validate.d.ts +0 -16
  92. package/dist/cli/commands/validate.d.ts.map +1 -1
  93. package/dist/cli/commands/validate.js +2 -97
  94. package/dist/cli/commands/validate.js.map +1 -1
  95. package/dist/cli/gate-command.d.ts +37 -0
  96. package/dist/cli/gate-command.d.ts.map +1 -0
  97. package/dist/cli/gate-command.js +64 -0
  98. package/dist/cli/gate-command.js.map +1 -0
  99. package/dist/cli/state-io.d.ts +34 -0
  100. package/dist/cli/state-io.d.ts.map +1 -0
  101. package/dist/cli/state-io.js +71 -0
  102. package/dist/cli/state-io.js.map +1 -0
  103. package/dist/completion-checkers/index.d.ts +1 -1
  104. package/dist/completion-checkers/index.d.ts.map +1 -1
  105. package/dist/completion-checkers/index.js +0 -15
  106. package/dist/completion-checkers/index.js.map +1 -1
  107. package/dist/context/knowledge-injector.d.ts +4 -2
  108. package/dist/context/knowledge-injector.d.ts.map +1 -1
  109. package/dist/context/knowledge-injector.js +13 -6
  110. package/dist/context/knowledge-injector.js.map +1 -1
  111. package/dist/core/constraints/agent-prompt-renderer.js +2 -2
  112. package/dist/core/constraints/agent-prompt-renderer.js.map +1 -1
  113. package/dist/core/constraints/capabilities-reconcile.d.ts +20 -0
  114. package/dist/core/constraints/capabilities-reconcile.d.ts.map +1 -1
  115. package/dist/core/constraints/capabilities-reconcile.js +26 -4
  116. package/dist/core/constraints/capabilities-reconcile.js.map +1 -1
  117. package/dist/core/constraints/check-cache.d.ts +1 -1
  118. package/dist/core/constraints/check-cache.js +1 -1
  119. package/dist/core/constraints/checker.d.ts +8 -3
  120. package/dist/core/constraints/checker.d.ts.map +1 -1
  121. package/dist/core/constraints/checker.js +30 -19
  122. package/dist/core/constraints/checker.js.map +1 -1
  123. package/dist/core/constraints/checkers/capability-sync.d.ts +3 -1
  124. package/dist/core/constraints/checkers/capability-sync.d.ts.map +1 -1
  125. package/dist/core/constraints/checkers/capability-sync.js +17 -24
  126. package/dist/core/constraints/checkers/capability-sync.js.map +1 -1
  127. package/dist/core/constraints/checkers/context-doc-sync.d.ts +1 -1
  128. package/dist/core/constraints/checkers/context-doc-sync.d.ts.map +1 -1
  129. package/dist/core/constraints/checkers/context-doc-sync.js +9 -6
  130. package/dist/core/constraints/checkers/context-doc-sync.js.map +1 -1
  131. package/dist/core/constraints/checkers/docs-freshness.d.ts.map +1 -1
  132. package/dist/core/constraints/checkers/docs-freshness.js +24 -30
  133. package/dist/core/constraints/checkers/docs-freshness.js.map +1 -1
  134. package/dist/core/constraints/checkers/governance-presence.d.ts.map +1 -1
  135. package/dist/core/constraints/checkers/governance-presence.js +10 -4
  136. package/dist/core/constraints/checkers/governance-presence.js.map +1 -1
  137. package/dist/core/constraints/checkers/types.d.ts +10 -6
  138. package/dist/core/constraints/checkers/types.d.ts.map +1 -1
  139. package/dist/core/constraints/checkers/types.js +7 -3
  140. package/dist/core/constraints/checkers/types.js.map +1 -1
  141. package/dist/core/constraints/context-builder.d.ts +11 -10
  142. package/dist/core/constraints/context-builder.d.ts.map +1 -1
  143. package/dist/core/constraints/context-builder.js +31 -27
  144. package/dist/core/constraints/context-builder.js.map +1 -1
  145. package/dist/core/constraints/context-reconcile.d.ts +75 -0
  146. package/dist/core/constraints/context-reconcile.d.ts.map +1 -0
  147. package/dist/core/constraints/context-reconcile.js +161 -0
  148. package/dist/core/constraints/context-reconcile.js.map +1 -0
  149. package/dist/core/constraints/doc-freshness/runner.d.ts +7 -0
  150. package/dist/core/constraints/doc-freshness/runner.d.ts.map +1 -1
  151. package/dist/core/constraints/doc-freshness/runner.js +8 -3
  152. package/dist/core/constraints/doc-freshness/runner.js.map +1 -1
  153. package/dist/core/constraints/git-evidence.js +1 -1
  154. package/dist/core/constraints/git-evidence.js.map +1 -1
  155. package/dist/core/constraints/injection-drift.d.ts +7 -2
  156. package/dist/core/constraints/injection-drift.d.ts.map +1 -1
  157. package/dist/core/constraints/injection-drift.js +13 -7
  158. package/dist/core/constraints/injection-drift.js.map +1 -1
  159. package/dist/core/constraints/run-env.d.ts +92 -0
  160. package/dist/core/constraints/run-env.d.ts.map +1 -0
  161. package/dist/core/constraints/run-env.js +175 -0
  162. package/dist/core/constraints/run-env.js.map +1 -0
  163. package/dist/core/constraints/triggers.d.ts +22 -0
  164. package/dist/core/constraints/triggers.d.ts.map +1 -0
  165. package/dist/core/constraints/triggers.js +31 -0
  166. package/dist/core/constraints/triggers.js.map +1 -0
  167. package/dist/core/effective-constraints.d.ts +13 -4
  168. package/dist/core/effective-constraints.d.ts.map +1 -1
  169. package/dist/core/effective-constraints.js +16 -6
  170. package/dist/core/effective-constraints.js.map +1 -1
  171. package/dist/core/effective-set.d.ts +8 -15
  172. package/dist/core/effective-set.d.ts.map +1 -1
  173. package/dist/core/effective-set.js +7 -12
  174. package/dist/core/effective-set.js.map +1 -1
  175. package/dist/core/index.d.ts +1 -0
  176. package/dist/core/index.d.ts.map +1 -1
  177. package/dist/core/index.js.map +1 -1
  178. package/dist/core/project-config-loader.d.ts +39 -17
  179. package/dist/core/project-config-loader.d.ts.map +1 -1
  180. package/dist/core/project-config-loader.js +51 -122
  181. package/dist/core/project-config-loader.js.map +1 -1
  182. package/dist/core/validators/check-handlers/http.d.ts +2 -2
  183. package/dist/core/validators/check-handlers/http.d.ts.map +1 -1
  184. package/dist/core/validators/check-handlers/http.js +12 -7
  185. package/dist/core/validators/check-handlers/http.js.map +1 -1
  186. package/dist/failure/classifier.d.ts +1 -1
  187. package/dist/failure/classifier.d.ts.map +1 -1
  188. package/dist/failure/classifier.js +8 -8
  189. package/dist/failure/classifier.js.map +1 -1
  190. package/dist/failure/index.d.ts +2 -1
  191. package/dist/failure/index.d.ts.map +1 -1
  192. package/dist/failure/index.js +9 -17
  193. package/dist/failure/index.js.map +1 -1
  194. package/dist/failure/recorder.d.ts +1 -1
  195. package/dist/failure/recorder.d.ts.map +1 -1
  196. package/dist/gates/checker-gate.d.ts +2 -1
  197. package/dist/gates/checker-gate.d.ts.map +1 -1
  198. package/dist/gates/checker-gate.js +3 -2
  199. package/dist/gates/checker-gate.js.map +1 -1
  200. package/dist/gates/command.d.ts +10 -4
  201. package/dist/gates/command.d.ts.map +1 -1
  202. package/dist/gates/command.js +36 -62
  203. package/dist/gates/command.js.map +1 -1
  204. package/dist/gates/contract.d.ts.map +1 -1
  205. package/dist/gates/contract.js +0 -4
  206. package/dist/gates/contract.js.map +1 -1
  207. package/dist/gates/definitions.d.ts +2 -1
  208. package/dist/gates/definitions.d.ts.map +1 -1
  209. package/dist/gates/definitions.js +6 -5
  210. package/dist/gates/definitions.js.map +1 -1
  211. package/dist/gates/index.d.ts +0 -4
  212. package/dist/gates/index.d.ts.map +1 -1
  213. package/dist/gates/index.js +1 -6
  214. package/dist/gates/index.js.map +1 -1
  215. package/dist/gates/performance.d.ts.map +1 -1
  216. package/dist/gates/performance.js +0 -4
  217. package/dist/gates/performance.js.map +1 -1
  218. package/dist/gates/runner.d.ts +1 -1
  219. package/dist/gates/runner.js +1 -1
  220. package/dist/gates/security.d.ts +1 -1
  221. package/dist/gates/security.d.ts.map +1 -1
  222. package/dist/gates/security.js +5 -6
  223. package/dist/gates/security.js.map +1 -1
  224. package/dist/gates/types.d.ts +14 -17
  225. package/dist/gates/types.d.ts.map +1 -1
  226. package/dist/gates/types.js.map +1 -1
  227. package/dist/hooks/bootstrap.d.ts +6 -4
  228. package/dist/hooks/bootstrap.d.ts.map +1 -1
  229. package/dist/hooks/bootstrap.js +25 -13
  230. package/dist/hooks/bootstrap.js.map +1 -1
  231. package/dist/hooks/config.d.ts +6 -2
  232. package/dist/hooks/config.d.ts.map +1 -1
  233. package/dist/hooks/config.js +5 -1
  234. package/dist/hooks/config.js.map +1 -1
  235. package/dist/hooks/index.d.ts +1 -1
  236. package/dist/hooks/index.d.ts.map +1 -1
  237. package/dist/hooks/index.js +0 -15
  238. package/dist/hooks/index.js.map +1 -1
  239. package/dist/hooks/pipeline.d.ts +19 -1
  240. package/dist/hooks/pipeline.d.ts.map +1 -1
  241. package/dist/hooks/pipeline.js +42 -4
  242. package/dist/hooks/pipeline.js.map +1 -1
  243. package/dist/hooks/registry.d.ts +11 -8
  244. package/dist/hooks/registry.d.ts.map +1 -1
  245. package/dist/hooks/registry.js +22 -7
  246. package/dist/hooks/registry.js.map +1 -1
  247. package/dist/hooks/types.d.ts +25 -7
  248. package/dist/hooks/types.d.ts.map +1 -1
  249. package/dist/index.d.ts +3 -3
  250. package/dist/index.d.ts.map +1 -1
  251. package/dist/index.js +3 -4
  252. package/dist/index.js.map +1 -1
  253. package/dist/knowledge/audit-scoring.d.ts +87 -0
  254. package/dist/knowledge/audit-scoring.d.ts.map +1 -0
  255. package/dist/knowledge/audit-scoring.js +470 -0
  256. package/dist/knowledge/audit-scoring.js.map +1 -0
  257. package/dist/knowledge/audit.d.ts +11 -59
  258. package/dist/knowledge/audit.d.ts.map +1 -1
  259. package/dist/knowledge/audit.js +47 -522
  260. package/dist/knowledge/audit.js.map +1 -1
  261. package/dist/knowledge/import.d.ts.map +1 -1
  262. package/dist/knowledge/import.js +2 -0
  263. package/dist/knowledge/import.js.map +1 -1
  264. package/dist/knowledge/index-generator.d.ts.map +1 -1
  265. package/dist/knowledge/index-generator.js +4 -5
  266. package/dist/knowledge/index-generator.js.map +1 -1
  267. package/dist/knowledge/index.d.ts +3 -2
  268. package/dist/knowledge/index.d.ts.map +1 -1
  269. package/dist/knowledge/index.js +3 -16
  270. package/dist/knowledge/index.js.map +1 -1
  271. package/dist/knowledge/ingest.js +1 -1
  272. package/dist/knowledge/ingest.js.map +1 -1
  273. package/dist/knowledge/lifecycle.d.ts.map +1 -1
  274. package/dist/knowledge/lifecycle.js +4 -2
  275. package/dist/knowledge/lifecycle.js.map +1 -1
  276. package/dist/knowledge/migration.d.ts +3 -0
  277. package/dist/knowledge/migration.d.ts.map +1 -1
  278. package/dist/knowledge/migration.js +8 -2
  279. package/dist/knowledge/migration.js.map +1 -1
  280. package/dist/knowledge/query.d.ts +6 -0
  281. package/dist/knowledge/query.d.ts.map +1 -1
  282. package/dist/knowledge/query.js +8 -2
  283. package/dist/knowledge/query.js.map +1 -1
  284. package/dist/knowledge/reference-tracker.d.ts.map +1 -1
  285. package/dist/knowledge/reference-tracker.js +4 -6
  286. package/dist/knowledge/reference-tracker.js.map +1 -1
  287. package/dist/knowledge/store.d.ts +22 -16
  288. package/dist/knowledge/store.d.ts.map +1 -1
  289. package/dist/knowledge/store.js +53 -12
  290. package/dist/knowledge/store.js.map +1 -1
  291. package/dist/knowledge/tree-walker.d.ts +19 -0
  292. package/dist/knowledge/tree-walker.d.ts.map +1 -0
  293. package/dist/knowledge/tree-walker.js +30 -0
  294. package/dist/knowledge/tree-walker.js.map +1 -0
  295. package/dist/knowledge/types.d.ts +16 -0
  296. package/dist/knowledge/types.d.ts.map +1 -1
  297. package/dist/monitoring/traces.d.ts +5 -3
  298. package/dist/monitoring/traces.d.ts.map +1 -1
  299. package/dist/monitoring/traces.js +19 -5
  300. package/dist/monitoring/traces.js.map +1 -1
  301. package/dist/test-setup/jsonl-fake-fs.d.ts +30 -0
  302. package/dist/test-setup/jsonl-fake-fs.d.ts.map +1 -0
  303. package/dist/test-setup/jsonl-fake-fs.js +49 -0
  304. package/dist/test-setup/jsonl-fake-fs.js.map +1 -0
  305. package/dist/tools/index.d.ts +4 -1
  306. package/dist/tools/index.d.ts.map +1 -1
  307. package/dist/tools/index.js +7 -15
  308. package/dist/tools/index.js.map +1 -1
  309. package/dist/types/checkpoint.d.ts +5 -0
  310. package/dist/types/checkpoint.d.ts.map +1 -1
  311. package/dist/types/project-config.d.ts +18 -0
  312. package/dist/types/project-config.d.ts.map +1 -1
  313. package/dist/types/trace.d.ts +13 -4
  314. package/dist/types/trace.d.ts.map +1 -1
  315. package/dist/types/trace.js +4 -3
  316. package/dist/types/trace.js.map +1 -1
  317. package/dist/utils/exec.d.ts +4 -27
  318. package/dist/utils/exec.d.ts.map +1 -1
  319. package/dist/utils/exec.js +4 -94
  320. package/dist/utils/exec.js.map +1 -1
  321. package/dist/utils/jsonl.d.ts +17 -7
  322. package/dist/utils/jsonl.d.ts.map +1 -1
  323. package/dist/utils/jsonl.js +144 -17
  324. package/dist/utils/jsonl.js.map +1 -1
  325. package/dist/utils/numeric-flag.d.ts +44 -0
  326. package/dist/utils/numeric-flag.d.ts.map +1 -0
  327. package/dist/utils/numeric-flag.js +62 -0
  328. package/dist/utils/numeric-flag.js.map +1 -0
  329. package/package.json +1 -1
  330. package/src/CONTEXT.md +5 -2
  331. package/src/__tests__/acceptance-gate.test.ts +7 -4
  332. package/src/__tests__/checker-extra.test.ts +3 -2
  333. package/src/__tests__/checker.test.ts +4 -3
  334. package/src/__tests__/checkpoint.test.ts +26 -9
  335. package/src/__tests__/context-files-resolution.test.ts +29 -15
  336. package/src/__tests__/contract-gate.test.ts +19 -40
  337. package/src/__tests__/error-classifier.test.ts +1 -1
  338. package/src/__tests__/exec.test.ts +45 -107
  339. package/src/__tests__/failure-recorder.test.ts +7 -5
  340. package/src/__tests__/hooks-pipeline.test.ts +34 -47
  341. package/src/__tests__/layering.test.ts +217 -25
  342. package/src/__tests__/passes-gate.test.ts +9 -4
  343. package/src/__tests__/performance-gate.test.ts +3 -15
  344. package/src/__tests__/project-config-loader-extra.test.ts +31 -57
  345. package/src/__tests__/project-config-loader.test.ts +6 -3
  346. package/src/__tests__/public-exports.test.ts +0 -1
  347. package/src/__tests__/public-type-surface.test.ts +5 -4
  348. package/src/__tests__/public-value-surface.test.ts +182 -0
  349. package/src/__tests__/review-gate.test.ts +4 -6
  350. package/src/__tests__/security-gate.test.ts +5 -20
  351. package/src/__tests__/skip-semantics.test.ts +5 -3
  352. package/src/__tests__/spec-validator.test.ts +3 -2
  353. package/src/__tests__/sub-barrels-explicit.test.ts +87 -0
  354. package/src/__tests__/test-fixture-hygiene.test.ts +53 -0
  355. package/src/__tests__/trace-analyzer-extra.test.ts +5 -3
  356. package/src/__tests__/trace-analyzer.test.ts +5 -3
  357. package/src/__tests__/trace-collector.test.ts +5 -3
  358. package/src/agents/index.ts +13 -2
  359. package/src/cli/__tests__/gate-command.test.ts +162 -0
  360. package/src/cli/__tests__/state-io.test.ts +50 -0
  361. package/src/cli/commands/CONTEXT.md +30 -5
  362. package/src/cli/commands/__tests__/acceptance.test.ts +24 -25
  363. package/src/cli/commands/__tests__/bin-exit-mapping.test.ts +15 -0
  364. package/src/cli/commands/__tests__/check-drift.test.ts +42 -1
  365. package/src/cli/commands/__tests__/check-read-count.test.ts +170 -0
  366. package/src/cli/commands/__tests__/check-skip-output.test.ts +4 -1
  367. package/src/cli/commands/__tests__/check.test.ts +63 -44
  368. package/src/cli/commands/__tests__/command-gate-dead-options.test.ts +60 -0
  369. package/src/cli/commands/__tests__/command.test.ts +33 -17
  370. package/src/cli/commands/__tests__/constraints-retire.test.ts +52 -0
  371. package/src/cli/commands/__tests__/context-syncer.test.ts +141 -0
  372. package/src/cli/commands/__tests__/contract.test.ts +20 -20
  373. package/src/cli/commands/__tests__/failure.test.ts +5 -4
  374. package/src/cli/commands/__tests__/gate-decision.ts +30 -0
  375. package/src/cli/commands/__tests__/init-dead-options.test.ts +50 -0
  376. package/src/cli/commands/__tests__/init-governance-io.test.ts +139 -0
  377. package/src/cli/commands/__tests__/init-injection.test.ts +3 -3
  378. package/src/cli/commands/__tests__/init-ondisk.test.ts +867 -0
  379. package/src/cli/commands/__tests__/init.test.ts +82 -6
  380. package/src/cli/commands/__tests__/knowledge-audit-threshold.test.ts +146 -0
  381. package/src/cli/commands/__tests__/knowledge-flywheel-consistency.test.ts +1 -1
  382. package/src/cli/commands/__tests__/knowledge-tone-mapping.test.ts +244 -0
  383. package/src/cli/commands/__tests__/knowledge-view.test.ts +839 -0
  384. package/src/cli/commands/__tests__/knowledge.test.ts +33 -15
  385. package/src/cli/commands/__tests__/numeric-flag-assembly.test.ts +368 -0
  386. package/src/cli/commands/__tests__/performance.test.ts +19 -21
  387. package/src/cli/commands/__tests__/posteval-plan.test.ts +5 -3
  388. package/src/cli/commands/__tests__/pre-push-hook.test.ts +181 -0
  389. package/src/cli/commands/__tests__/project-path-anchoring.test.ts +95 -2
  390. package/src/cli/commands/__tests__/project-path-convention.test.ts +103 -25
  391. package/src/cli/commands/__tests__/registry.test.ts +2 -0
  392. package/src/cli/commands/__tests__/report.test.ts +23 -1
  393. package/src/cli/commands/__tests__/review.test.ts +10 -17
  394. package/src/cli/commands/__tests__/scaffold.test.ts +505 -0
  395. package/src/cli/commands/__tests__/security-default-scan.test.ts +75 -0
  396. package/src/cli/commands/__tests__/security.test.ts +21 -24
  397. package/src/cli/commands/__tests__/spec-baseline-check.test.ts +3 -2
  398. package/src/cli/commands/__tests__/spec-baseline-index-cap.test.ts +131 -0
  399. package/src/cli/commands/__tests__/spec-baseline-read-count.test.ts +325 -0
  400. package/src/cli/commands/__tests__/status-extra.test.ts +25 -8
  401. package/src/cli/commands/__tests__/status.test.ts +46 -18
  402. package/src/cli/commands/__tests__/sync-docs-agents.test.ts +19 -4
  403. package/src/cli/commands/__tests__/sync-docs-context-drift.test.ts +232 -0
  404. package/src/cli/commands/__tests__/sync-docs-module-order.test.ts +111 -0
  405. package/src/cli/commands/__tests__/sync-docs-read-count.test.ts +192 -0
  406. package/src/cli/commands/__tests__/sync-docs.test.ts +3 -2
  407. package/src/cli/commands/__tests__/validate.test.ts +1 -48
  408. package/src/cli/commands/acceptance.ts +24 -29
  409. package/src/cli/commands/check.ts +60 -35
  410. package/src/cli/commands/command.ts +9 -8
  411. package/src/cli/commands/constraints-retire.ts +57 -70
  412. package/src/cli/commands/contract.ts +44 -47
  413. package/src/cli/commands/definitions.ts +12 -6
  414. package/src/cli/commands/failure.ts +16 -3
  415. package/src/cli/commands/init.ts +242 -389
  416. package/src/cli/commands/knowledge-view.ts +224 -0
  417. package/src/cli/commands/knowledge.ts +643 -448
  418. package/src/cli/commands/passes-gate.ts +12 -3
  419. package/src/cli/commands/performance.ts +31 -38
  420. package/src/cli/commands/report.ts +3 -2
  421. package/src/cli/commands/review.ts +22 -28
  422. package/src/cli/commands/scaffold-templates.ts +406 -0
  423. package/src/cli/commands/scaffold.ts +302 -0
  424. package/src/cli/commands/security.ts +27 -23
  425. package/src/cli/commands/spec-baseline-check.ts +158 -33
  426. package/src/cli/commands/status.ts +12 -7
  427. package/src/cli/commands/sync-docs/__tests__/context-export-surface.test.ts +102 -0
  428. package/src/cli/commands/sync-docs/__tests__/module-descriptions.test.ts +196 -0
  429. package/src/cli/commands/sync-docs/context-syncer.ts +137 -31
  430. package/src/cli/commands/sync-docs/index.ts +103 -28
  431. package/src/cli/commands/sync-docs/project-reader.ts +51 -7
  432. package/src/cli/commands/validate.ts +1 -104
  433. package/src/cli/gate-command.ts +87 -0
  434. package/src/cli/state-io.ts +53 -0
  435. package/src/completion-checkers/index.ts +10 -1
  436. package/src/context/CONTEXT.md +2 -1
  437. package/src/context/__tests__/knowledge-injector.test.ts +27 -0
  438. package/src/context/__tests__/session-manager.test.ts +19 -12
  439. package/src/context/knowledge-injector.ts +14 -7
  440. package/src/core/CONTEXT.md +10 -7
  441. package/src/core/__tests__/effective-set.test.ts +36 -60
  442. package/src/core/constraints/__tests__/context-reconcile.test.ts +246 -0
  443. package/src/core/constraints/__tests__/run-env.test.ts +377 -0
  444. package/src/core/constraints/__tests__/triggers.test.ts +70 -0
  445. package/src/core/constraints/agent-prompt-renderer.ts +1 -1
  446. package/src/core/constraints/capabilities-reconcile.ts +28 -4
  447. package/src/core/constraints/check-cache.ts +1 -1
  448. package/src/core/constraints/checker.ts +30 -14
  449. package/src/core/constraints/checkers/__tests__/context-doc-sync.test.ts +8 -3
  450. package/src/core/constraints/checkers/__tests__/governance-presence.test.ts +16 -7
  451. package/src/core/constraints/checkers/__tests__/no-hardcoded-credentials.test.ts +2 -1
  452. package/src/core/constraints/checkers/capability-sync.ts +27 -28
  453. package/src/core/constraints/checkers/context-doc-sync.ts +9 -7
  454. package/src/core/constraints/checkers/docs-freshness.ts +28 -33
  455. package/src/core/constraints/checkers/governance-presence.ts +10 -6
  456. package/src/core/constraints/checkers/types.ts +14 -8
  457. package/src/core/constraints/context-builder.ts +35 -26
  458. package/src/core/constraints/context-reconcile.ts +200 -0
  459. package/src/core/constraints/doc-freshness/__tests__/runner.test.ts +25 -0
  460. package/src/core/constraints/doc-freshness/runner.ts +18 -4
  461. package/src/core/constraints/git-evidence.ts +1 -1
  462. package/src/core/constraints/injection-drift.ts +19 -8
  463. package/src/core/constraints/run-env.ts +207 -0
  464. package/src/core/constraints/triggers.ts +33 -0
  465. package/src/core/effective-constraints.ts +17 -6
  466. package/src/core/effective-set.ts +8 -24
  467. package/src/core/index.ts +2 -0
  468. package/src/core/project-config-loader.ts +54 -102
  469. package/src/core/validators/__tests__/http-retry-sleep.test.ts +231 -0
  470. package/src/core/validators/check-handlers/http.ts +18 -7
  471. package/src/failure/CONTEXT.md +2 -1
  472. package/src/failure/classifier.ts +2 -2
  473. package/src/failure/index.ts +14 -2
  474. package/src/failure/recorder.ts +1 -1
  475. package/src/gates/CONTEXT.md +13 -7
  476. package/src/gates/__tests__/checker-gate.test.ts +1 -1
  477. package/src/gates/__tests__/command-single-predicate.test.ts +135 -0
  478. package/src/gates/__tests__/command.test.ts +8 -15
  479. package/src/gates/__tests__/contract.test.ts +5 -5
  480. package/src/gates/__tests__/gate-interface.test.ts +0 -17
  481. package/src/gates/__tests__/performance.test.ts +0 -13
  482. package/src/gates/__tests__/review.test.ts +0 -1
  483. package/src/gates/__tests__/runner.test.ts +1 -1
  484. package/src/gates/__tests__/security-default-scan.test.ts +97 -0
  485. package/src/gates/__tests__/security.test.ts +0 -13
  486. package/src/gates/checker-gate.ts +3 -2
  487. package/src/gates/command.ts +51 -74
  488. package/src/gates/contract.ts +0 -5
  489. package/src/gates/definitions.ts +6 -5
  490. package/src/gates/index.ts +0 -5
  491. package/src/gates/performance.ts +1 -6
  492. package/src/gates/runner.ts +1 -1
  493. package/src/gates/security.ts +9 -11
  494. package/src/gates/types.ts +20 -23
  495. package/src/hooks/CONTEXT.md +10 -9
  496. package/src/hooks/__tests__/bootstrap.test.ts +29 -6
  497. package/src/hooks/__tests__/pipeline.test.ts +133 -17
  498. package/src/hooks/__tests__/registry.test.ts +51 -3
  499. package/src/hooks/bootstrap.ts +35 -15
  500. package/src/hooks/config.ts +6 -2
  501. package/src/hooks/index.ts +10 -1
  502. package/src/hooks/pipeline.ts +51 -6
  503. package/src/hooks/registry.ts +31 -12
  504. package/src/hooks/types.ts +26 -7
  505. package/src/index.ts +1 -2
  506. package/src/knowledge/CONTEXT.md +14 -7
  507. package/src/knowledge/__tests__/audit-labels.test.ts +8 -5
  508. package/src/knowledge/__tests__/audit-scoring.test.ts +230 -0
  509. package/src/knowledge/__tests__/audit-write-count.test.ts +131 -0
  510. package/src/knowledge/__tests__/audit.test.ts +291 -208
  511. package/src/knowledge/__tests__/doctor.test.ts +3 -2
  512. package/src/knowledge/__tests__/ingest.test.ts +3 -2
  513. package/src/knowledge/__tests__/lifecycle.test.ts +57 -2
  514. package/src/knowledge/__tests__/migration.test.ts +35 -6
  515. package/src/knowledge/__tests__/query.test.ts +3 -2
  516. package/src/knowledge/__tests__/reference-tracker.test.ts +23 -2
  517. package/src/knowledge/__tests__/store.test.ts +149 -4
  518. package/src/knowledge/__tests__/tree-walker.test.ts +132 -0
  519. package/src/knowledge/audit-scoring.ts +589 -0
  520. package/src/knowledge/audit.ts +55 -599
  521. package/src/knowledge/import.ts +2 -0
  522. package/src/knowledge/index-generator.ts +4 -6
  523. package/src/knowledge/index.ts +27 -2
  524. package/src/knowledge/ingest.ts +1 -1
  525. package/src/knowledge/lifecycle.ts +5 -2
  526. package/src/knowledge/migration.ts +8 -2
  527. package/src/knowledge/query.ts +8 -1
  528. package/src/knowledge/reference-tracker.ts +5 -7
  529. package/src/knowledge/store.ts +75 -16
  530. package/src/knowledge/tree-walker.ts +29 -0
  531. package/src/knowledge/types.ts +19 -0
  532. package/src/monitoring/CONTEXT.md +5 -2
  533. package/src/monitoring/__tests__/context-tracker.test.ts +16 -8
  534. package/src/monitoring/__tests__/trace-file-anchoring.test.ts +80 -0
  535. package/src/monitoring/traces.ts +19 -5
  536. package/src/release/CONTEXT.md +1 -1
  537. package/src/release/__tests__/integrity.test.ts +21 -12
  538. package/src/test-setup/__tests__/jsonl-fake-fs.test.ts +98 -0
  539. package/src/test-setup/jsonl-fake-fs.ts +59 -0
  540. package/src/tools/index.ts +5 -1
  541. package/src/types/checkpoint.ts +6 -0
  542. package/src/types/project-config.ts +21 -0
  543. package/src/types/trace.ts +14 -4
  544. package/src/utils/__tests__/file-walk.test.ts +3 -2
  545. package/src/utils/__tests__/jsonl-bounded-read.test.ts +106 -0
  546. package/src/utils/__tests__/jsonl-skip-disposition.test.ts +10 -6
  547. package/src/utils/__tests__/jsonl.test.ts +61 -14
  548. package/src/utils/__tests__/numeric-flag.test.ts +80 -0
  549. package/src/utils/__tests__/package-version.test.ts +2 -2
  550. package/src/utils/exec.ts +4 -64
  551. package/src/utils/jsonl.ts +159 -20
  552. package/src/utils/numeric-flag.ts +64 -0
  553. package/dist/failure/types.d.ts +0 -9
  554. package/dist/failure/types.d.ts.map +0 -1
  555. package/dist/failure/types.js +0 -25
  556. package/dist/failure/types.js.map +0 -1
  557. package/dist/gates/effective-gates.d.ts +0 -30
  558. package/dist/gates/effective-gates.d.ts.map +0 -1
  559. package/dist/gates/effective-gates.js +0 -81
  560. package/dist/gates/effective-gates.js.map +0 -1
  561. package/src/failure/types.ts +0 -9
  562. package/src/gates/__tests__/effective-gates.test.ts +0 -77
  563. package/src/gates/effective-gates.ts +0 -99
@@ -0,0 +1,141 @@
1
+ /**
2
+ * sync-docs 的 CONTEXT.md 落点测试(harness#150)
3
+ *
4
+ * #132 把 init/validate 的脚手架三态收进 scaffold 模块,但 sync-docs 的
5
+ * `createContextMd` 是票口径外的第 9 处同形写手:自带一份 CONTEXT.md 模板正文,
6
+ * 与正本 `renderContextDoc` 已漂移。本票把它改消费正本(contextDocFile + runPlan)。
7
+ *
8
+ * 这里零真实文件系统(注入内存 fs 替身,手法照 scaffold.test.ts)钉三件事:
9
+ * 1. 对撞:同一目录经 init(contextDocFile)与 sync-docs(createContextMd)生成的
10
+ * CONTEXT.md 骨架逐字相同(两条路径归一到单一正本)。
11
+ * 2. 正本文案:并入副本独有的两行引导、四节占位取 HTML 注释形。
12
+ * 3. 只在缺失时写:present → exists 分支不覆盖,正常 contextMissing 只走 created。
13
+ */
14
+
15
+ import * as path from 'path';
16
+ import chalk from 'chalk';
17
+ import { captureIO, type CapturingIO } from '../../command-contract';
18
+ import { contextDocFile, type ScaffoldFileSystem } from '../scaffold';
19
+ import { createContextMd } from '../sync-docs/context-syncer';
20
+
21
+ jest.mock('chalk', () => ({
22
+ blue: jest.fn((s: string) => s),
23
+ yellow: jest.fn((s: string) => s),
24
+ green: jest.fn((s: string) => s),
25
+ gray: jest.fn((s: string) => s),
26
+ red: jest.fn((s: string) => s),
27
+ cyan: jest.fn((s: string) => s),
28
+ bold: jest.fn((s: string) => s),
29
+ }));
30
+
31
+ /** 内存 fs 替身:写盘内容、建过的目录可断言 */
32
+ class MemoryFs implements ScaffoldFileSystem {
33
+ readonly files = new Map<string, string>();
34
+ readonly dirs: string[] = [];
35
+
36
+ seed(target: string, content: string): void {
37
+ this.files.set(target, content);
38
+ }
39
+ async exists(target: string): Promise<boolean> {
40
+ return this.files.has(target);
41
+ }
42
+ async mkdir(dir: string): Promise<void> {
43
+ this.dirs.push(dir);
44
+ }
45
+ async writeFile(target: string, content: string): Promise<void> {
46
+ this.files.set(target, content);
47
+ }
48
+ async chmod(): Promise<void> {
49
+ /* CONTEXT.md 无权限位 */
50
+ }
51
+ }
52
+
53
+ const PROJECT = '/srv/project';
54
+ const USER_CONTENT = '# src\n\n我自己写的,不许覆盖\n';
55
+
56
+ /**
57
+ * CONTEXT.md 骨架正文的冻结字面量(harness#158):正本 `renderContextDoc('src')` 被改必红。
58
+ * 上面的对撞闸只证明「init 与 sync-docs 同源」——两侧一起漂它看不见(复审 M3:给正本
59
+ * 加一行 → 60/60 全绿)。骨架正文整体由此处逐字钉住,改骨架必须显式改这份字面量。
60
+ */
61
+ const CONTEXT_MD_SKELETON = `# src
62
+
63
+ > 此文件描述 src 目录的职责和上下文
64
+ > 请阅读本目录的源代码,然后填写以下各节。
65
+ > 如果使用 AI 编码助手,将本文件内容作为 prompt 请求它分析并填写。
66
+
67
+ ## 职责
68
+
69
+ <!-- 本目录的核心职责是什么 -->
70
+
71
+ ## 核心导出
72
+
73
+ <!-- 本目录对外暴露的主要模块/函数 -->
74
+
75
+ ## 依赖关系
76
+
77
+ <!-- 本目录依赖哪些其他模块,谁依赖本目录 -->
78
+
79
+ ## 注意事项
80
+
81
+ <!-- 开发时需要注意的约束或约定 -->
82
+ `;
83
+
84
+ let fs: MemoryFs;
85
+ let io: CapturingIO;
86
+
87
+ beforeEach(() => {
88
+ jest.clearAllMocks();
89
+ fs = new MemoryFs();
90
+ io = captureIO();
91
+ });
92
+
93
+ describe('createContextMd 消费 scaffold 正本(harness#150)', () => {
94
+ it('对撞:sync-docs 落点与 init 站点生成的骨架逐字相同', async () => {
95
+ await expect(createContextMd(PROJECT, 'src', io, fs)).resolves.toBe('created');
96
+ const written = fs.files.get(path.join(PROJECT, 'src', 'CONTEXT.md'));
97
+
98
+ // init 侧经由同一个 contextDocFile 工厂落盘(见 init.ts 的 contextDocPlan)——
99
+ // 两侧共用单一正本,任何一份偷偷漂移都会在这里撞红
100
+ expect(written).toBe(contextDocFile(PROJECT, 'src').content);
101
+ });
102
+
103
+ it('骨架正文逐字冻结:正本 renderContextDoc 被改必红(#158,M3 假闸补钉)', () => {
104
+ expect(contextDocFile(PROJECT, 'src').content).toBe(CONTEXT_MD_SKELETON);
105
+ });
106
+
107
+ it('正本文案钉住:并入的两行引导 + 注释形占位(散文式提问已消失)', async () => {
108
+ const content = contextDocFile(PROJECT, 'src').content;
109
+
110
+ expect(content).toContain('> 请阅读本目录的源代码,然后填写以下各节。');
111
+ expect(content).toContain(
112
+ '> 如果使用 AI 编码助手,将本文件内容作为 prompt 请求它分析并填写。',
113
+ );
114
+ expect(content).toContain('<!-- 本目录的核心职责是什么 -->');
115
+ expect(content).not.toContain('本目录的核心职责是?');
116
+ });
117
+
118
+ it('缺失才写:present → exists 分支,用户内容一字节不动', async () => {
119
+ const target = path.join(PROJECT, 'src', 'CONTEXT.md');
120
+ fs.seed(target, USER_CONTENT);
121
+
122
+ await expect(createContextMd(PROJECT, 'src', io, fs)).resolves.toBe('exists');
123
+
124
+ expect(fs.files.get(target)).toBe(USER_CONTENT);
125
+ expect(fs.dirs).toEqual([]);
126
+ expect(printed(io)).toEqual(['src/CONTEXT.md 已存在']);
127
+ expect(chalk.gray).toHaveBeenCalledWith('src/CONTEXT.md 已存在');
128
+ });
129
+
130
+ it('created 态:绿字文案由 runPlan 打印,与 init 落盘态同源', async () => {
131
+ await createContextMd(PROJECT, 'src', io, fs);
132
+
133
+ expect(printed(io)).toEqual(['✅ 已创建 src/CONTEXT.md']);
134
+ expect(chalk.green).toHaveBeenCalledWith('✅ 已创建 src/CONTEXT.md');
135
+ });
136
+ });
137
+
138
+ /** stdout 每次写入的文本(去掉 log 补的换行) */
139
+ function printed(capture: CapturingIO): string[] {
140
+ return capture.outRecords().map(chunk => chunk.replace(/\n$/, ''));
141
+ }
@@ -4,6 +4,7 @@
4
4
 
5
5
  import { contract, validateSchema } from '../contract';
6
6
  import { captureIO, type CapturingIO } from '../../command-contract';
7
+ import { decide, fakeGate, throwingGate } from './gate-decision';
7
8
  import * as fs from 'fs/promises';
8
9
  import { ContractGate } from '../../../gates/contract';
9
10
 
@@ -14,7 +15,7 @@ jest.mock('fs/promises', () => ({
14
15
 
15
16
  jest.mock('../../../gates/contract', () => ({
16
17
  ContractGate: jest.fn().mockImplementation(() => ({
17
- check: jest.fn(),
18
+ evaluate: jest.fn(),
18
19
  })),
19
20
  }));
20
21
 
@@ -46,16 +47,15 @@ describe('contract command', () => {
46
47
  describe('contract', () => {
47
48
  it('should print success when check passes', async () => {
48
49
  mockFs.access.mockResolvedValue(undefined);
49
- const mockCheck = jest.fn().mockResolvedValue({
50
- passed: true,
51
- message: 'ok',
52
- details: { endpoints: 10, breakingChanges: false },
53
- });
54
- MockGate.mockImplementation(() => ({ check: mockCheck }) as any);
50
+ MockGate.mockImplementation(() =>
51
+ fakeGate(decide('contract', true, 'ok', { endpoints: 10, breakingChanges: false })) as any
52
+ );
55
53
 
56
54
  const result = await contract({}, io);
57
55
 
58
56
  expect(io.outText()).toContain('契约门控检查通过');
57
+ expect(io.outText()).toContain(' 端点数: 10');
58
+ expect(io.outText()).toContain(' 破坏性变更: 无');
59
59
  expect(result.kind).toBe('ok');
60
60
  });
61
61
 
@@ -70,31 +70,31 @@ describe('contract command', () => {
70
70
 
71
71
  it('should print failure and exit 1 when check fails', async () => {
72
72
  mockFs.access.mockResolvedValue(undefined);
73
- const mockCheck = jest.fn().mockResolvedValue({
74
- passed: false,
75
- message: 'validation errors',
76
- details: {
77
- errors: ['missing field X', 'invalid type Y'],
78
- breakingChanges: [{ type: 'removed', path: '/api/v1/users' }],
79
- },
80
- });
81
- MockGate.mockImplementation(() => ({ check: mockCheck }) as any);
73
+ MockGate.mockImplementation(() =>
74
+ fakeGate(
75
+ decide('contract', false, 'validation errors', {
76
+ errors: ['missing field X', 'invalid type Y'],
77
+ breakingChanges: [{ type: 'removed', path: '/api/v1/users' }],
78
+ })
79
+ ) as any
80
+ );
82
81
 
83
82
  const result = await contract({}, io);
84
83
 
85
84
  expect(io.outText()).toContain('契约门控检查失败');
86
- expect(result.kind).toBe('fail');
85
+ expect(io.outText()).toContain(' - missing field X');
86
+ expect(io.outText()).toContain(' - removed: /api/v1/users');
87
+ expect(result).toEqual({ kind: 'fail', reason: 'contract gate denied: validation errors' });
87
88
  });
88
89
 
89
90
  it('should handle thrown errors and exit 1', async () => {
90
91
  mockFs.access.mockResolvedValue(undefined);
91
- const mockCheck = jest.fn().mockRejectedValue(new Error('gate error'));
92
- MockGate.mockImplementation(() => ({ check: mockCheck }) as any);
92
+ MockGate.mockImplementation(() => throwingGate(new Error('gate error')) as any);
93
93
 
94
94
  const result = await contract({}, io);
95
95
 
96
96
  expect(io.outText()).toContain('契约门控检查出错');
97
- expect(result.kind).toBe('fail');
97
+ expect(result).toEqual({ kind: 'fail', reason: 'contract gate error: gate error' });
98
98
  });
99
99
  });
100
100
 
@@ -5,9 +5,10 @@
5
5
  import * as fs from 'fs';
6
6
  import { captureIO, type CapturingIO } from '../../command-contract';
7
7
  import * as path from 'path';
8
+ import * as os from 'os';
8
9
  import { FailureRecorder } from '../../../failure/recorder';
9
- import { ErrorType, FailureLevel } from '../../../failure/types';
10
- import type { FailureRecord } from '../../../failure/types';
10
+ import { ErrorType, FailureLevel } from '../../../types/failure';
11
+ import type { FailureRecord } from '../../../types/failure';
11
12
 
12
13
  // Mock FailureRecorder
13
14
  jest.mock('../../../failure/recorder');
@@ -18,7 +19,7 @@ beforeEach(() => {
18
19
  });
19
20
 
20
21
  describe('failure CLI commands', () => {
21
- const tempDir = path.join(process.cwd(), 'temp-test-failure-cli');
22
+ let tempDir: string;
22
23
  let mockRecorderInstance: {
23
24
  record: jest.Mock;
24
25
  getHistory: jest.Mock;
@@ -39,7 +40,7 @@ describe('failure CLI commands', () => {
39
40
  };
40
41
 
41
42
  beforeAll(() => {
42
- fs.mkdirSync(tempDir, { recursive: true });
43
+ tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'temp-test-failure-cli-'));
43
44
  });
44
45
 
45
46
  afterAll(() => {
@@ -0,0 +1,30 @@
1
+ /**
2
+ * 门禁命令测试的决策替身
3
+ *
4
+ * 命令的唯一入口是 `evaluate()`,所以替身是「产一枚决策的假门禁」——
5
+ * 映射与报告构造器用真实现(decisionFromResult / gateResult),
6
+ * 六个命令的测试因此不需要 git、gh 或真扫描。
7
+ */
8
+
9
+ import { decisionFromResult } from '../../../gates/decision';
10
+ import { gateResult } from '../../../gates/types';
11
+ import type { GateDecision } from '../../../gates/types';
12
+
13
+ export function decide(
14
+ gateId: string,
15
+ passed: boolean,
16
+ message: string,
17
+ details?: Record<string, any>
18
+ ): GateDecision {
19
+ return decisionFromResult(gateResult(gateId, passed, message, Date.now(), details));
20
+ }
21
+
22
+ /** 恒产同一枚决策的假门禁(evaluate 记录调用参数,供断言上下文) */
23
+ export function fakeGate(decision: GateDecision): { evaluate: jest.Mock } {
24
+ return { evaluate: jest.fn().mockResolvedValue(decision) };
25
+ }
26
+
27
+ /** evaluate 直接抛出的假门禁:命令出错分支测的是门禁之外的失败(git / fs) */
28
+ export function throwingGate(error: unknown): { evaluate: jest.Mock } {
29
+ return { evaluate: jest.fn().mockRejectedValue(error) };
30
+ }
@@ -0,0 +1,50 @@
1
+ /**
2
+ * init 死选项 `-t/--type` 已删除(harness#132 grilling 落定)
3
+ *
4
+ * `-t, --type <type>` 自始只有定义表一条与 `InitOptions.type` 一个字段,全仓无读取方——
5
+ * `harness init -t nextjs-app` 恒不生效。scaffold 收口时按 ADR-0018 判据(只执法有真实现的
6
+ * 维度)连旗帜与字段一并删除。手法同 passes-gate-dead-options.test.ts:编译期
7
+ * `@ts-expect-error` 钉字段不存在 + 运行期钉定义表旗帜面。
8
+ */
9
+
10
+ import { COMMAND_DEFINITIONS } from '../definitions';
11
+ import type { InitOptions } from '../init';
12
+
13
+ const initCommand = COMMAND_DEFINITIONS.find(d => d.command === 'init');
14
+
15
+ describe('init 的 -t/--type 已删除(#132)', () => {
16
+ it('定义表已注册 init(前提)', () => {
17
+ expect(initCommand).toBeDefined();
18
+ });
19
+
20
+ it('init 旗帜面逐字冻结,不含 --type', () => {
21
+ expect((initCommand?.options || []).map(o => o.flags)).toEqual([
22
+ '-p, --preset <preset>',
23
+ '-g, --governance <level>',
24
+ '--project-path <path>',
25
+ '--no-git-hooks',
26
+ '--ci <platform>',
27
+ '--no-github-actions',
28
+ '--print-snippets',
29
+ ]);
30
+ });
31
+
32
+ it('InitOptions 的 type 字段已从类型面消失(编译期钉)', () => {
33
+ // @ts-expect-error -t/--type 无实现,随 #132 从 InitOptions 删除
34
+ const removed: InitOptions = { preset: 'standard', type: 'nextjs-app' };
35
+ expect(removed).toBeDefined();
36
+ });
37
+
38
+ it('活旗帜仍可赋值(防止删多)', () => {
39
+ const live: InitOptions = {
40
+ preset: 'strict',
41
+ governance: 'minimal',
42
+ projectPath: '/tmp/p',
43
+ gitHooks: false,
44
+ githubActions: false,
45
+ ci: 'gitlab',
46
+ printSnippets: true,
47
+ };
48
+ expect(Object.keys(live)).toHaveLength(7);
49
+ });
50
+ });
@@ -0,0 +1,139 @@
1
+ /**
2
+ * 治理链路的 io 注入不逃逸(harness#149)
3
+ *
4
+ * setupGovernance 手握 io,却在两个调用点把它丢了(`setupClaudeMdOutputStyle(projectPath)`
5
+ * / `setupGovernanceConstraints(projectPath)`),被调方一律 `io: CommandIO = processIO`
6
+ * 兜成真实 stdout。真机输出正常,但注入面的测试看不见那 14 条提示——`⚠️ …标记残缺…`
7
+ * 这类唯一提示写坏了没有测试会红。
8
+ *
9
+ * 本文件不 mock 任何 IO:在临时目录里真跑 init,断言治理段提示落在**注入面**。
10
+ * 改造前这些断言逐条为红(文本逃到了 process.stdout)。
11
+ */
12
+
13
+ import * as fs from 'fs/promises';
14
+ import * as fsSync from 'fs';
15
+ import * as os from 'os';
16
+ import * as path from 'path';
17
+ import { init, type InitOptions } from '../init';
18
+ import { captureIO, type CapturingIO } from '../../command-contract';
19
+
20
+ jest.mock('chalk', () => ({
21
+ blue: jest.fn((s: string) => s),
22
+ yellow: jest.fn((s: string) => s),
23
+ green: jest.fn((s: string) => s),
24
+ gray: jest.fn((s: string) => s),
25
+ red: jest.fn((s: string) => s),
26
+ cyan: jest.fn((s: string) => s),
27
+ bold: jest.fn((s: string) => s),
28
+ }));
29
+
30
+ const INIT_SOURCE = fsSync.readFileSync(path.join(__dirname, '..', 'init.ts'), 'utf-8');
31
+
32
+ const INIT_OPTIONS: Partial<InitOptions> = { preset: 'standard', governance: 'standard' };
33
+
34
+ /** 真临时工程根:带 .git 与 src/,让 init 走完治理链路而不必先落别的文件 */
35
+ async function makeProject(files: Record<string, string> = {}): Promise<string> {
36
+ const root = await fs.mkdtemp(path.join(os.tmpdir(), 'harness-governance-io-'));
37
+ await fs.mkdir(path.join(root, 'src'));
38
+ await fs.writeFile(path.join(root, 'src', 'index.ts'), 'export const x = 1;\n');
39
+ await fs.mkdir(path.join(root, '.git'));
40
+ for (const [rel, content] of Object.entries(files)) {
41
+ await fs.writeFile(path.join(root, rel), content, 'utf-8');
42
+ }
43
+ return root;
44
+ }
45
+
46
+ async function runInit(files: Record<string, string>): Promise<CapturingIO> {
47
+ const root = await makeProject(files);
48
+ roots.push(root);
49
+ const io = captureIO();
50
+ expect(await init({ ...INIT_OPTIONS, projectPath: root } as InitOptions, io)).toEqual({ kind: 'ok' });
51
+ return io;
52
+ }
53
+
54
+ const roots: string[] = [];
55
+
56
+ afterAll(async () => {
57
+ await Promise.all(roots.map(root => fs.rm(root, { recursive: true, force: true })));
58
+ });
59
+
60
+ describe('init 治理链路的提示落在注入面(harness#149)', () => {
61
+ it('Output Style 段(setupClaudeMdOutputStyle 调用点曾丢 io):写入提示进捕获 stdout', async () => {
62
+ const io = await runInit({ 'CLAUDE.md': '# CLAUDE.md\n\n项目说明\n' });
63
+ expect(io.outText()).toContain('✅ 已在 CLAUDE.md 顶部写入 Output Style 段');
64
+ });
65
+
66
+ it('治理契约追加到既有 AGENTS.md:`已追加治理契约` 进捕获 stdout', async () => {
67
+ const io = await runInit({ 'AGENTS.md': '# AGENTS.md\n\n既有导读\n' });
68
+ expect(io.outText()).toContain('✅ 已追加治理契约 PRESERVE:governance 段到 AGENTS.md');
69
+ });
70
+
71
+ it('标记残缺(唯一提示):`标记残缺…请人工修复` 进捕获 stdout', async () => {
72
+ const io = await runInit({ 'AGENTS.md': '# AGENTS.md\n\n<!-- PRESERVE:governance -->\n残缺段\n' });
73
+ expect(io.outText()).toContain('⚠️ AGENTS.md 中 PRESERVE:governance 标记残缺(只有单边),跳过治理契约写入,请人工修复');
74
+ });
75
+
76
+ // #158 补钉:这类提示在 init.ts 实测有四处,#149 只钉住上面一条——其余三处各补一条
77
+ // 捕获面断言。四处分支不同文件/不同段位,fixture 各自单建,不共用残缺文件。
78
+
79
+ it('标记残缺四处之二:CLAUDE.md 的 HARNESS_OUTPUT_STYLE 单边 → Output Style 注入告警', async () => {
80
+ const io = await runInit({ 'CLAUDE.md': '# CLAUDE.md\n\n<!-- HARNESS_OUTPUT_STYLE_START -->\n半残段\n' });
81
+ expect(io.outText()).toContain('⚠️ CLAUDE.md 中 HARNESS_OUTPUT_STYLE 标记残缺(单边或乱序),跳过 Output Style 注入,请人工修复');
82
+ });
83
+
84
+ it('标记残缺四处之三:AGENTS.md 的 PRESERVE 段内 HARNESS_CONSTRAINTS 单边 → 段内告警', async () => {
85
+ const broken = [
86
+ '# AGENTS.md',
87
+ '',
88
+ '<!-- PRESERVE:governance -->',
89
+ '手写契约',
90
+ '',
91
+ '<!-- HARNESS_CONSTRAINTS_START -->',
92
+ '半残注入',
93
+ '<!-- /PRESERVE:governance -->',
94
+ '',
95
+ ].join('\n');
96
+ const io = await runInit({ 'AGENTS.md': broken });
97
+ expect(io.outText()).toContain('⚠️ AGENTS.md PRESERVE:governance 段内 HARNESS_CONSTRAINTS 标记残缺(单边或乱序),跳过治理契约写入,请人工修复');
98
+ });
99
+
100
+ it('标记残缺四处之四:CLAUDE.md 的 HARNESS_CONSTRAINTS 单边 → 治理约束注入告警(旧模型仓落点)', async () => {
101
+ const io = await runInit({ 'CLAUDE.md': '# CLAUDE.md\n\n<!-- HARNESS_CONSTRAINTS_START -->\n半残段\n' });
102
+ expect(io.outText()).toContain('⚠️ CLAUDE.md 中 HARNESS_CONSTRAINTS 标记残缺(单边或乱序),跳过治理约束注入,请人工修复');
103
+ });
104
+
105
+ it('新仓创建 AGENTS.md 治理段:创建提示进捕获 stdout', async () => {
106
+ const io = await runInit({});
107
+ expect(io.outText()).toContain('✅ 已创建 AGENTS.md 并写入治理契约 PRESERVE:governance 段');
108
+ });
109
+ });
110
+
111
+ describe('writer 层 io 必传(源形状闸,防缺省兜底再回来)', () => {
112
+ it('init.ts 里 `io: CommandIO = processIO` 只剩 init() 一处(对外入口保留缺省)', () => {
113
+ const sites = INIT_SOURCE.split('\n').filter(line => line.includes('io: CommandIO = processIO'));
114
+ expect(sites).toHaveLength(1);
115
+ expect(sites[0]).toMatch(/^export async function init\(/);
116
+ });
117
+
118
+ it('三个 writer 与落点路由的 io 均为必传形参', () => {
119
+ for (const writer of [
120
+ 'setupClaudeMdOutputStyle',
121
+ 'setupAgentsMdConstraints',
122
+ 'setupClaudeMdConstraints',
123
+ 'setupGovernanceConstraints',
124
+ ]) {
125
+ expect(INIT_SOURCE).toMatch(
126
+ new RegExp(`export async function ${writer}\\(projectPath: string, io: CommandIO\\)`),
127
+ );
128
+ }
129
+ });
130
+
131
+ it('setupGovernance 的调用点逐个传 io(不留裸 projectPath 调用)', () => {
132
+ const governanceBody = INIT_SOURCE.slice(
133
+ INIT_SOURCE.indexOf('async function setupGovernance('),
134
+ INIT_SOURCE.indexOf('/**\n * 目录 CONTEXT.md 骨架的 plan'),
135
+ );
136
+ expect(governanceBody).toMatch(/await setupClaudeMdOutputStyle\(projectPath, io\)/);
137
+ expect(governanceBody).toMatch(/await setupGovernanceConstraints\(projectPath, io\)/);
138
+ });
139
+ });
@@ -422,7 +422,7 @@ describe('setupGovernanceConstraints(落点路由)', () => {
422
422
  });
423
423
 
424
424
  it('新仓(无 CLAUDE.md):治理契约写向 AGENTS.md,不创建 CLAUDE.md', async () => {
425
- await setupGovernanceConstraints(tempDir);
425
+ await setupGovernanceConstraints(tempDir, io);
426
426
 
427
427
  expect(fs.existsSync(path.join(tempDir, 'AGENTS.md'))).toBe(true);
428
428
  expect(fs.existsSync(path.join(tempDir, 'CLAUDE.md'))).toBe(false);
@@ -444,7 +444,7 @@ describe('setupGovernanceConstraints(落点路由)', () => {
444
444
  ].join('\n'));
445
445
  fs.writeFileSync(path.join(tempDir, 'AGENTS.md'), '# AGENTS.md\n\n既有导读\n');
446
446
 
447
- await setupGovernanceConstraints(tempDir);
447
+ await setupGovernanceConstraints(tempDir, io);
448
448
 
449
449
  const claude = fs.readFileSync(path.join(tempDir, 'CLAUDE.md'), 'utf-8');
450
450
  expect(claude).not.toContain('旧约束');
@@ -456,7 +456,7 @@ describe('setupGovernanceConstraints(落点路由)', () => {
456
456
  it('旧模型仓(CLAUDE.md 有无标记 Governance Rules 块):路由到 CLAUDE.md', async () => {
457
457
  fs.writeFileSync(path.join(tempDir, 'CLAUDE.md'), '# CLAUDE.md\n\n## Governance Rules\n\n手写条款\n');
458
458
 
459
- await setupGovernanceConstraints(tempDir);
459
+ await setupGovernanceConstraints(tempDir, io);
460
460
 
461
461
  const claude = fs.readFileSync(path.join(tempDir, 'CLAUDE.md'), 'utf-8');
462
462
  expect(claude).toContain('手写条款');