@dommaker/harness 1.3.0 → 1.5.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 (532) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/README.md +0 -2
  3. package/bin/harness.js +86 -32
  4. package/dist/cli/command-contract.d.ts +83 -0
  5. package/dist/cli/command-contract.d.ts.map +1 -0
  6. package/dist/cli/command-contract.js +66 -0
  7. package/dist/cli/command-contract.js.map +1 -0
  8. package/dist/cli/commands/acceptance.d.ts +3 -2
  9. package/dist/cli/commands/acceptance.d.ts.map +1 -1
  10. package/dist/cli/commands/acceptance.js +28 -24
  11. package/dist/cli/commands/acceptance.js.map +1 -1
  12. package/dist/cli/commands/analyze-sessions.d.ts +2 -1
  13. package/dist/cli/commands/analyze-sessions.d.ts.map +1 -1
  14. package/dist/cli/commands/analyze-sessions.js +25 -24
  15. package/dist/cli/commands/analyze-sessions.js.map +1 -1
  16. package/dist/cli/commands/check.d.ts +14 -2
  17. package/dist/cli/commands/check.d.ts.map +1 -1
  18. package/dist/cli/commands/check.js +104 -61
  19. package/dist/cli/commands/check.js.map +1 -1
  20. package/dist/cli/commands/command.d.ts +5 -1
  21. package/dist/cli/commands/command.d.ts.map +1 -1
  22. package/dist/cli/commands/command.js +26 -17
  23. package/dist/cli/commands/command.js.map +1 -1
  24. package/dist/cli/commands/constraints-report.d.ts +2 -1
  25. package/dist/cli/commands/constraints-report.d.ts.map +1 -1
  26. package/dist/cli/commands/constraints-report.js +37 -33
  27. package/dist/cli/commands/constraints-report.js.map +1 -1
  28. package/dist/cli/commands/constraints-retire.d.ts +6 -5
  29. package/dist/cli/commands/constraints-retire.d.ts.map +1 -1
  30. package/dist/cli/commands/constraints-retire.js +50 -52
  31. package/dist/cli/commands/constraints-retire.js.map +1 -1
  32. package/dist/cli/commands/constraints.d.ts +2 -1
  33. package/dist/cli/commands/constraints.d.ts.map +1 -1
  34. package/dist/cli/commands/constraints.js +10 -27
  35. package/dist/cli/commands/constraints.js.map +1 -1
  36. package/dist/cli/commands/contract.d.ts +3 -2
  37. package/dist/cli/commands/contract.d.ts.map +1 -1
  38. package/dist/cli/commands/contract.js +45 -42
  39. package/dist/cli/commands/contract.js.map +1 -1
  40. package/dist/cli/commands/definitions.d.ts +11 -11
  41. package/dist/cli/commands/definitions.d.ts.map +1 -1
  42. package/dist/cli/commands/definitions.js +27 -219
  43. package/dist/cli/commands/definitions.js.map +1 -1
  44. package/dist/cli/commands/failure.d.ts +5 -4
  45. package/dist/cli/commands/failure.d.ts.map +1 -1
  46. package/dist/cli/commands/failure.js +31 -25
  47. package/dist/cli/commands/failure.js.map +1 -1
  48. package/dist/cli/commands/init.d.ts +7 -5
  49. package/dist/cli/commands/init.d.ts.map +1 -1
  50. package/dist/cli/commands/init.js +147 -211
  51. package/dist/cli/commands/init.js.map +1 -1
  52. package/dist/cli/commands/knowledge.d.ts +17 -30
  53. package/dist/cli/commands/knowledge.d.ts.map +1 -1
  54. package/dist/cli/commands/knowledge.js +183 -273
  55. package/dist/cli/commands/knowledge.js.map +1 -1
  56. package/dist/cli/commands/passes-gate.d.ts +8 -2
  57. package/dist/cli/commands/passes-gate.d.ts.map +1 -1
  58. package/dist/cli/commands/passes-gate.js +44 -66
  59. package/dist/cli/commands/passes-gate.js.map +1 -1
  60. package/dist/cli/commands/performance.d.ts +2 -1
  61. package/dist/cli/commands/performance.d.ts.map +1 -1
  62. package/dist/cli/commands/performance.js +20 -18
  63. package/dist/cli/commands/performance.js.map +1 -1
  64. package/dist/cli/commands/posteval-plan.d.ts +5 -1
  65. package/dist/cli/commands/posteval-plan.d.ts.map +1 -1
  66. package/dist/cli/commands/posteval-plan.js +26 -15
  67. package/dist/cli/commands/posteval-plan.js.map +1 -1
  68. package/dist/cli/commands/release.d.ts +6 -1
  69. package/dist/cli/commands/release.d.ts.map +1 -1
  70. package/dist/cli/commands/release.js +69 -59
  71. package/dist/cli/commands/release.js.map +1 -1
  72. package/dist/cli/commands/report.d.ts +2 -1
  73. package/dist/cli/commands/report.d.ts.map +1 -1
  74. package/dist/cli/commands/report.js +9 -5
  75. package/dist/cli/commands/report.js.map +1 -1
  76. package/dist/cli/commands/review.d.ts +3 -2
  77. package/dist/cli/commands/review.d.ts.map +1 -1
  78. package/dist/cli/commands/review.js +33 -29
  79. package/dist/cli/commands/review.js.map +1 -1
  80. package/dist/cli/commands/sdd.d.ts +2 -1
  81. package/dist/cli/commands/sdd.d.ts.map +1 -1
  82. package/dist/cli/commands/sdd.js +7 -5
  83. package/dist/cli/commands/sdd.js.map +1 -1
  84. package/dist/cli/commands/security.d.ts +3 -2
  85. package/dist/cli/commands/security.d.ts.map +1 -1
  86. package/dist/cli/commands/security.js +29 -26
  87. package/dist/cli/commands/security.js.map +1 -1
  88. package/dist/cli/commands/spec-baseline-check.d.ts +2 -1
  89. package/dist/cli/commands/spec-baseline-check.d.ts.map +1 -1
  90. package/dist/cli/commands/spec-baseline-check.js +15 -11
  91. package/dist/cli/commands/spec-baseline-check.js.map +1 -1
  92. package/dist/cli/commands/spec.d.ts +7 -2
  93. package/dist/cli/commands/spec.d.ts.map +1 -1
  94. package/dist/cli/commands/spec.js +61 -51
  95. package/dist/cli/commands/spec.js.map +1 -1
  96. package/dist/cli/commands/status.d.ts +2 -1
  97. package/dist/cli/commands/status.d.ts.map +1 -1
  98. package/dist/cli/commands/status.js +57 -53
  99. package/dist/cli/commands/status.js.map +1 -1
  100. package/dist/cli/commands/sync-docs/agents-syncer.d.ts.map +1 -1
  101. package/dist/cli/commands/sync-docs/agents-syncer.js +5 -2
  102. package/dist/cli/commands/sync-docs/agents-syncer.js.map +1 -1
  103. package/dist/cli/commands/sync-docs/context-syncer.d.ts.map +1 -1
  104. package/dist/cli/commands/sync-docs/context-syncer.js +3 -2
  105. package/dist/cli/commands/sync-docs/context-syncer.js.map +1 -1
  106. package/dist/cli/commands/sync-docs/index.d.ts +2 -1
  107. package/dist/cli/commands/sync-docs/index.d.ts.map +1 -1
  108. package/dist/cli/commands/sync-docs/index.js +68 -88
  109. package/dist/cli/commands/sync-docs/index.js.map +1 -1
  110. package/dist/cli/commands/sync-docs/project-reader.d.ts +6 -1
  111. package/dist/cli/commands/sync-docs/project-reader.d.ts.map +1 -1
  112. package/dist/cli/commands/sync-docs/project-reader.js +14 -16
  113. package/dist/cli/commands/sync-docs/project-reader.js.map +1 -1
  114. package/dist/cli/commands/update-user-model.d.ts +9 -3
  115. package/dist/cli/commands/update-user-model.d.ts.map +1 -1
  116. package/dist/cli/commands/update-user-model.js +56 -61
  117. package/dist/cli/commands/update-user-model.js.map +1 -1
  118. package/dist/cli/commands/validate.d.ts +4 -3
  119. package/dist/cli/commands/validate.d.ts.map +1 -1
  120. package/dist/cli/commands/validate.js +28 -26
  121. package/dist/cli/commands/validate.js.map +1 -1
  122. package/dist/cli/session-mining/transcript.d.ts +7 -1
  123. package/dist/cli/session-mining/transcript.d.ts.map +1 -1
  124. package/dist/cli/session-mining/transcript.js +21 -14
  125. package/dist/cli/session-mining/transcript.js.map +1 -1
  126. package/dist/context/session-manager.d.ts.map +1 -1
  127. package/dist/context/session-manager.js +19 -32
  128. package/dist/context/session-manager.js.map +1 -1
  129. package/dist/core/constraints/agent-prompt-renderer.d.ts.map +1 -1
  130. package/dist/core/constraints/agent-prompt-renderer.js +1 -4
  131. package/dist/core/constraints/agent-prompt-renderer.js.map +1 -1
  132. package/dist/core/constraints/capabilities-parser.d.ts +24 -7
  133. package/dist/core/constraints/capabilities-parser.d.ts.map +1 -1
  134. package/dist/core/constraints/capabilities-parser.js +32 -28
  135. package/dist/core/constraints/capabilities-parser.js.map +1 -1
  136. package/dist/core/constraints/capabilities-reconcile.d.ts +67 -0
  137. package/dist/core/constraints/capabilities-reconcile.d.ts.map +1 -0
  138. package/dist/core/constraints/capabilities-reconcile.js +105 -0
  139. package/dist/core/constraints/capabilities-reconcile.js.map +1 -0
  140. package/dist/core/constraints/checker.d.ts +21 -43
  141. package/dist/core/constraints/checker.d.ts.map +1 -1
  142. package/dist/core/constraints/checker.js +68 -117
  143. package/dist/core/constraints/checker.js.map +1 -1
  144. package/dist/core/constraints/checkers/capability-sync.d.ts +20 -8
  145. package/dist/core/constraints/checkers/capability-sync.d.ts.map +1 -1
  146. package/dist/core/constraints/checkers/capability-sync.js +66 -77
  147. package/dist/core/constraints/checkers/capability-sync.js.map +1 -1
  148. package/dist/core/constraints/checkers/context-doc-sync.d.ts +4 -2
  149. package/dist/core/constraints/checkers/context-doc-sync.d.ts.map +1 -1
  150. package/dist/core/constraints/checkers/context-doc-sync.js +13 -22
  151. package/dist/core/constraints/checkers/context-doc-sync.js.map +1 -1
  152. package/dist/core/constraints/checkers/docs-freshness.d.ts.map +1 -1
  153. package/dist/core/constraints/checkers/docs-freshness.js +49 -66
  154. package/dist/core/constraints/checkers/docs-freshness.js.map +1 -1
  155. package/dist/core/constraints/checkers/governance-presence.d.ts +2 -2
  156. package/dist/core/constraints/checkers/governance-presence.d.ts.map +1 -1
  157. package/dist/core/constraints/checkers/governance-presence.js +7 -28
  158. package/dist/core/constraints/checkers/governance-presence.js.map +1 -1
  159. package/dist/core/constraints/checkers/index.d.ts +2 -2
  160. package/dist/core/constraints/checkers/index.d.ts.map +1 -1
  161. package/dist/core/constraints/checkers/index.js +2 -1
  162. package/dist/core/constraints/checkers/index.js.map +1 -1
  163. package/dist/core/constraints/checkers/no-test-simplification.d.ts.map +1 -1
  164. package/dist/core/constraints/checkers/no-test-simplification.js +4 -3
  165. package/dist/core/constraints/checkers/no-test-simplification.js.map +1 -1
  166. package/dist/core/constraints/checkers/types.d.ts +43 -4
  167. package/dist/core/constraints/checkers/types.d.ts.map +1 -1
  168. package/dist/core/constraints/checkers/types.js +33 -0
  169. package/dist/core/constraints/checkers/types.js.map +1 -1
  170. package/dist/core/constraints/context-builder.d.ts +15 -14
  171. package/dist/core/constraints/context-builder.d.ts.map +1 -1
  172. package/dist/core/constraints/context-builder.js +32 -96
  173. package/dist/core/constraints/context-builder.js.map +1 -1
  174. package/dist/core/constraints/doc-freshness/runner.d.ts.map +1 -1
  175. package/dist/core/constraints/doc-freshness/runner.js +2 -1
  176. package/dist/core/constraints/doc-freshness/runner.js.map +1 -1
  177. package/dist/core/constraints/git-evidence.d.ts +60 -0
  178. package/dist/core/constraints/git-evidence.d.ts.map +1 -0
  179. package/dist/core/constraints/git-evidence.js +88 -0
  180. package/dist/core/constraints/git-evidence.js.map +1 -0
  181. package/dist/core/constraints/injection-drift.d.ts +3 -20
  182. package/dist/core/constraints/injection-drift.d.ts.map +1 -1
  183. package/dist/core/constraints/injection-drift.js +10 -57
  184. package/dist/core/constraints/injection-drift.js.map +1 -1
  185. package/dist/core/constraints/injection-writer.d.ts +113 -0
  186. package/dist/core/constraints/injection-writer.d.ts.map +1 -0
  187. package/dist/core/constraints/injection-writer.js +228 -0
  188. package/dist/core/constraints/injection-writer.js.map +1 -0
  189. package/dist/core/constraints/usage-report.d.ts +22 -1
  190. package/dist/core/constraints/usage-report.d.ts.map +1 -1
  191. package/dist/core/constraints/usage-report.js +27 -20
  192. package/dist/core/constraints/usage-report.js.map +1 -1
  193. package/dist/core/index.d.ts +2 -2
  194. package/dist/core/index.d.ts.map +1 -1
  195. package/dist/core/index.js +4 -2
  196. package/dist/core/index.js.map +1 -1
  197. package/dist/core/project-config-loader.d.ts +32 -1
  198. package/dist/core/project-config-loader.d.ts.map +1 -1
  199. package/dist/core/project-config-loader.js +39 -9
  200. package/dist/core/project-config-loader.js.map +1 -1
  201. package/dist/core/validators/passes-gate.d.ts +15 -64
  202. package/dist/core/validators/passes-gate.d.ts.map +1 -1
  203. package/dist/core/validators/passes-gate.js +84 -222
  204. package/dist/core/validators/passes-gate.js.map +1 -1
  205. package/dist/core/validators/test-output.d.ts +58 -0
  206. package/dist/core/validators/test-output.d.ts.map +1 -0
  207. package/dist/core/validators/test-output.js +109 -0
  208. package/dist/core/validators/test-output.js.map +1 -0
  209. package/dist/failure/recorder.d.ts +6 -0
  210. package/dist/failure/recorder.d.ts.map +1 -1
  211. package/dist/failure/recorder.js +12 -8
  212. package/dist/failure/recorder.js.map +1 -1
  213. package/dist/gates/acceptance.d.ts +1 -48
  214. package/dist/gates/acceptance.d.ts.map +1 -1
  215. package/dist/gates/acceptance.js +6 -38
  216. package/dist/gates/acceptance.js.map +1 -1
  217. package/dist/gates/checker-gate.d.ts +2 -1
  218. package/dist/gates/checker-gate.d.ts.map +1 -1
  219. package/dist/gates/checker-gate.js +11 -13
  220. package/dist/gates/checker-gate.js.map +1 -1
  221. package/dist/gates/command.d.ts.map +1 -1
  222. package/dist/gates/command.js +10 -22
  223. package/dist/gates/command.js.map +1 -1
  224. package/dist/gates/contract.d.ts.map +1 -1
  225. package/dist/gates/contract.js +22 -61
  226. package/dist/gates/contract.js.map +1 -1
  227. package/dist/gates/performance.d.ts.map +1 -1
  228. package/dist/gates/performance.js +13 -31
  229. package/dist/gates/performance.js.map +1 -1
  230. package/dist/gates/review.d.ts.map +1 -1
  231. package/dist/gates/review.js +21 -53
  232. package/dist/gates/review.js.map +1 -1
  233. package/dist/gates/security.d.ts.map +1 -1
  234. package/dist/gates/security.js +14 -32
  235. package/dist/gates/security.js.map +1 -1
  236. package/dist/gates/types.d.ts +28 -5
  237. package/dist/gates/types.d.ts.map +1 -1
  238. package/dist/gates/types.js +38 -1
  239. package/dist/gates/types.js.map +1 -1
  240. package/dist/hooks/bootstrap.d.ts +2 -0
  241. package/dist/hooks/bootstrap.d.ts.map +1 -1
  242. package/dist/hooks/bootstrap.js +5 -2
  243. package/dist/hooks/bootstrap.js.map +1 -1
  244. package/dist/index.d.ts +1 -2
  245. package/dist/index.d.ts.map +1 -1
  246. package/dist/index.js.map +1 -1
  247. package/dist/knowledge/audit.d.ts +7 -2
  248. package/dist/knowledge/audit.d.ts.map +1 -1
  249. package/dist/knowledge/audit.js +59 -79
  250. package/dist/knowledge/audit.js.map +1 -1
  251. package/dist/knowledge/flywheel-metrics.d.ts +39 -0
  252. package/dist/knowledge/flywheel-metrics.d.ts.map +1 -0
  253. package/dist/knowledge/flywheel-metrics.js +47 -0
  254. package/dist/knowledge/flywheel-metrics.js.map +1 -0
  255. package/dist/knowledge/import.d.ts.map +1 -1
  256. package/dist/knowledge/import.js +4 -14
  257. package/dist/knowledge/import.js.map +1 -1
  258. package/dist/knowledge/index-generator.d.ts.map +1 -1
  259. package/dist/knowledge/index-generator.js +17 -14
  260. package/dist/knowledge/index-generator.js.map +1 -1
  261. package/dist/knowledge/ingest.d.ts.map +1 -1
  262. package/dist/knowledge/ingest.js +9 -4
  263. package/dist/knowledge/ingest.js.map +1 -1
  264. package/dist/knowledge/migration.d.ts.map +1 -1
  265. package/dist/knowledge/migration.js +11 -8
  266. package/dist/knowledge/migration.js.map +1 -1
  267. package/dist/knowledge/reference-tracker.d.ts.map +1 -1
  268. package/dist/knowledge/reference-tracker.js +12 -9
  269. package/dist/knowledge/reference-tracker.js.map +1 -1
  270. package/dist/knowledge/store.d.ts +15 -0
  271. package/dist/knowledge/store.d.ts.map +1 -1
  272. package/dist/knowledge/store.js +59 -10
  273. package/dist/knowledge/store.js.map +1 -1
  274. package/dist/monitoring/context-tracker.d.ts.map +1 -1
  275. package/dist/monitoring/context-tracker.js +11 -20
  276. package/dist/monitoring/context-tracker.js.map +1 -1
  277. package/dist/monitoring/index.d.ts +1 -1
  278. package/dist/monitoring/index.d.ts.map +1 -1
  279. package/dist/monitoring/index.js +1 -2
  280. package/dist/monitoring/index.js.map +1 -1
  281. package/dist/monitoring/trace-analyzer.d.ts +15 -0
  282. package/dist/monitoring/trace-analyzer.d.ts.map +1 -1
  283. package/dist/monitoring/trace-analyzer.js +19 -2
  284. package/dist/monitoring/trace-analyzer.js.map +1 -1
  285. package/dist/monitoring/traces.d.ts +21 -2
  286. package/dist/monitoring/traces.d.ts.map +1 -1
  287. package/dist/monitoring/traces.js +38 -29
  288. package/dist/monitoring/traces.js.map +1 -1
  289. package/dist/release/index.d.ts +2 -2
  290. package/dist/release/index.d.ts.map +1 -1
  291. package/dist/release/index.js +1 -5
  292. package/dist/release/index.js.map +1 -1
  293. package/dist/sdd/index-generator.js +10 -11
  294. package/dist/sdd/index-generator.js.map +1 -1
  295. package/dist/test-setup/project-fixture.d.ts +48 -0
  296. package/dist/test-setup/project-fixture.d.ts.map +1 -0
  297. package/dist/test-setup/project-fixture.js +106 -0
  298. package/dist/test-setup/project-fixture.js.map +1 -0
  299. package/dist/types/constraint.d.ts +8 -18
  300. package/dist/types/constraint.d.ts.map +1 -1
  301. package/dist/types/constraint.js +6 -1
  302. package/dist/types/constraint.js.map +1 -1
  303. package/dist/types/passes-gate.d.ts +10 -25
  304. package/dist/types/passes-gate.d.ts.map +1 -1
  305. package/dist/types/project-config.d.ts +1 -1
  306. package/dist/types/session.d.ts +6 -5
  307. package/dist/types/session.d.ts.map +1 -1
  308. package/dist/types/trace.d.ts +9 -0
  309. package/dist/types/trace.d.ts.map +1 -1
  310. package/dist/utils/exec.d.ts +10 -0
  311. package/dist/utils/exec.d.ts.map +1 -1
  312. package/dist/utils/exec.js +12 -0
  313. package/dist/utils/exec.js.map +1 -1
  314. package/dist/utils/file-walk.d.ts +9 -1
  315. package/dist/utils/file-walk.d.ts.map +1 -1
  316. package/dist/utils/file-walk.js +10 -1
  317. package/dist/utils/file-walk.js.map +1 -1
  318. package/dist/utils/frontmatter.d.ts +73 -0
  319. package/dist/utils/frontmatter.d.ts.map +1 -0
  320. package/dist/utils/frontmatter.js +141 -0
  321. package/dist/utils/frontmatter.js.map +1 -0
  322. package/dist/utils/jsonl.d.ts +92 -0
  323. package/dist/utils/jsonl.d.ts.map +1 -0
  324. package/dist/utils/jsonl.js +166 -0
  325. package/dist/utils/jsonl.js.map +1 -0
  326. package/dist/utils/package-version.d.ts +16 -0
  327. package/dist/utils/package-version.d.ts.map +1 -0
  328. package/dist/utils/package-version.js +63 -0
  329. package/dist/utils/package-version.js.map +1 -0
  330. package/package.json +1 -1
  331. package/src/CONTEXT.md +8 -2
  332. package/src/__tests__/acceptance-gate.test.ts +3 -1
  333. package/src/__tests__/checker-extra.test.ts +7 -1218
  334. package/src/__tests__/context-files-resolution.test.ts +116 -0
  335. package/src/__tests__/effective-constraints.test.ts +10 -13
  336. package/src/__tests__/exec.test.ts +35 -1
  337. package/src/__tests__/layering.test.ts +152 -0
  338. package/src/__tests__/passes-gate-extra.test.ts +0 -145
  339. package/src/__tests__/passes-gate.test.ts +130 -101
  340. package/src/__tests__/skip-semantics.test.ts +5 -9
  341. package/src/cli/__tests__/command-contract.test.ts +170 -0
  342. package/src/cli/command-contract.ts +108 -0
  343. package/src/cli/commands/CONTEXT.md +23 -8
  344. package/src/cli/commands/__tests__/acceptance.test.ts +40 -33
  345. package/src/cli/commands/__tests__/analyze-sessions.test.ts +35 -29
  346. package/src/cli/commands/__tests__/bin-exit-mapping.test.ts +107 -0
  347. package/src/cli/commands/__tests__/check-drift.test.ts +27 -34
  348. package/src/cli/commands/__tests__/check-skip-output.test.ts +21 -24
  349. package/src/cli/commands/__tests__/check.test.ts +448 -378
  350. package/src/cli/commands/__tests__/command.test.ts +85 -70
  351. package/src/cli/commands/__tests__/constraints-report.test.ts +100 -71
  352. package/src/cli/commands/__tests__/constraints-retire.test.ts +152 -95
  353. package/src/cli/commands/__tests__/contract.test.ts +27 -34
  354. package/src/cli/commands/__tests__/failure.test.ts +31 -34
  355. package/src/cli/commands/__tests__/init-injection.test.ts +58 -28
  356. package/src/cli/commands/__tests__/init.test.ts +77 -48
  357. package/src/cli/commands/__tests__/knowledge-flywheel-consistency.test.ts +108 -0
  358. package/src/cli/commands/__tests__/knowledge.test.ts +69 -43
  359. package/src/cli/commands/__tests__/passes-gate.test.ts +43 -45
  360. package/src/cli/commands/__tests__/performance.test.ts +22 -23
  361. package/src/cli/commands/__tests__/posteval-plan.test.ts +39 -38
  362. package/src/cli/commands/__tests__/project-path-anchoring.test.ts +157 -0
  363. package/src/cli/commands/__tests__/project-path-convention.test.ts +231 -0
  364. package/src/cli/commands/__tests__/registry.test.ts +75 -35
  365. package/src/cli/commands/__tests__/release.test.ts +209 -80
  366. package/src/cli/commands/__tests__/report-extra.test.ts +16 -16
  367. package/src/cli/commands/__tests__/report.test.ts +25 -25
  368. package/src/cli/commands/__tests__/review.test.ts +33 -31
  369. package/src/cli/commands/__tests__/security.test.ts +23 -27
  370. package/src/cli/commands/__tests__/spec-baseline-check.test.ts +20 -20
  371. package/src/cli/commands/__tests__/spec.test.ts +41 -29
  372. package/src/cli/commands/__tests__/status-extra.test.ts +18 -18
  373. package/src/cli/commands/__tests__/status-skipped-lines.test.ts +72 -0
  374. package/src/cli/commands/__tests__/status.test.ts +34 -34
  375. package/src/cli/commands/__tests__/sync-docs-agents.test.ts +77 -78
  376. package/src/cli/commands/__tests__/sync-docs.test.ts +72 -74
  377. package/src/cli/commands/__tests__/update-user-model.test.ts +97 -34
  378. package/src/cli/commands/__tests__/validate.test.ts +27 -29
  379. package/src/cli/commands/acceptance.ts +35 -24
  380. package/src/cli/commands/analyze-sessions.ts +25 -24
  381. package/src/cli/commands/check.ts +127 -66
  382. package/src/cli/commands/command.ts +30 -17
  383. package/src/cli/commands/constraints-report.ts +37 -34
  384. package/src/cli/commands/constraints-retire.ts +58 -55
  385. package/src/cli/commands/constraints.ts +10 -27
  386. package/src/cli/commands/contract.ts +51 -42
  387. package/src/cli/commands/definitions.ts +34 -227
  388. package/src/cli/commands/failure.ts +33 -26
  389. package/src/cli/commands/init.ts +166 -220
  390. package/src/cli/commands/knowledge.ts +192 -289
  391. package/src/cli/commands/passes-gate.ts +58 -68
  392. package/src/cli/commands/performance.ts +23 -18
  393. package/src/cli/commands/posteval-plan.ts +29 -15
  394. package/src/cli/commands/release.ts +70 -59
  395. package/src/cli/commands/report.ts +9 -5
  396. package/src/cli/commands/review.ts +39 -29
  397. package/src/cli/commands/sdd.ts +7 -5
  398. package/src/cli/commands/security.ts +35 -26
  399. package/src/cli/commands/spec-baseline-check.ts +16 -11
  400. package/src/cli/commands/spec.ts +66 -53
  401. package/src/cli/commands/status.ts +59 -53
  402. package/src/cli/commands/sync-docs/agents-syncer.ts +5 -2
  403. package/src/cli/commands/sync-docs/context-syncer.ts +3 -2
  404. package/src/cli/commands/sync-docs/index.ts +73 -100
  405. package/src/cli/commands/sync-docs/project-reader.ts +17 -18
  406. package/src/cli/commands/update-user-model.ts +64 -61
  407. package/src/cli/commands/validate.ts +31 -25
  408. package/src/cli/session-mining/__tests__/transcript.test.ts +118 -0
  409. package/src/cli/session-mining/transcript.ts +26 -8
  410. package/src/context/session-manager.ts +19 -33
  411. package/src/core/CONTEXT.md +10 -6
  412. package/src/core/constraints/__tests__/capabilities-reconcile.test.ts +200 -0
  413. package/src/core/constraints/__tests__/capability-counts.test.ts +94 -0
  414. package/src/core/constraints/__tests__/git-evidence.test.ts +208 -0
  415. package/src/core/constraints/__tests__/injection-drift.test.ts +3 -10
  416. package/src/core/constraints/__tests__/injection-writer.test.ts +231 -0
  417. package/src/core/constraints/__tests__/trace-injection.test.ts +71 -0
  418. package/src/core/constraints/__tests__/usage-report.test.ts +112 -0
  419. package/src/core/constraints/agent-prompt-renderer.ts +2 -6
  420. package/src/core/constraints/capabilities-parser.ts +53 -35
  421. package/src/core/constraints/capabilities-reconcile.ts +166 -0
  422. package/src/core/constraints/checker.ts +82 -133
  423. package/src/core/constraints/checkers/__tests__/capability-sync.test.ts +273 -0
  424. package/src/core/constraints/checkers/__tests__/check-outcome.test.ts +176 -0
  425. package/src/core/constraints/checkers/__tests__/context-doc-sync.test.ts +77 -0
  426. package/src/core/constraints/checkers/__tests__/docs-freshness.test.ts +126 -0
  427. package/src/{__tests__ → core/constraints/checkers/__tests__}/governance-presence.test.ts +83 -9
  428. package/src/core/constraints/checkers/__tests__/iron-flags.test.ts +50 -0
  429. package/src/core/constraints/checkers/__tests__/no-bypass-checkpoint.test.ts +76 -0
  430. package/src/{__tests__ → core/constraints/checkers/__tests__}/no-hardcoded-credentials.test.ts +4 -3
  431. package/src/core/constraints/checkers/__tests__/no-test-simplification.test.ts +58 -0
  432. package/src/core/constraints/checkers/__tests__/three-state-consistency.test.ts +153 -0
  433. package/src/core/constraints/checkers/capability-sync.ts +75 -96
  434. package/src/core/constraints/checkers/context-doc-sync.ts +15 -25
  435. package/src/core/constraints/checkers/docs-freshness.ts +54 -70
  436. package/src/core/constraints/checkers/governance-presence.ts +7 -25
  437. package/src/core/constraints/checkers/index.ts +9 -2
  438. package/src/core/constraints/checkers/no-test-simplification.ts +4 -3
  439. package/src/core/constraints/checkers/types.ts +60 -4
  440. package/src/core/constraints/context-builder.ts +39 -91
  441. package/src/core/constraints/doc-freshness/runner.ts +2 -1
  442. package/src/core/constraints/git-evidence.ts +120 -0
  443. package/src/core/constraints/injection-drift.ts +13 -60
  444. package/src/core/constraints/injection-writer.ts +212 -0
  445. package/src/core/constraints/usage-report.ts +36 -17
  446. package/src/core/index.ts +4 -2
  447. package/src/core/project-config-loader.ts +49 -9
  448. package/src/core/validators/__tests__/passes-gate.test.ts +2 -56
  449. package/src/core/validators/__tests__/test-output.test.ts +372 -0
  450. package/src/core/validators/passes-gate.ts +86 -248
  451. package/src/core/validators/test-output.ts +128 -0
  452. package/src/failure/__tests__/recorder.test.ts +168 -0
  453. package/src/failure/recorder.ts +12 -10
  454. package/src/gates/CONTEXT.md +7 -4
  455. package/src/gates/__tests__/acceptance-types-single-source.test.ts +68 -0
  456. package/src/gates/__tests__/acceptance.test.ts +4 -86
  457. package/src/gates/__tests__/checker-gate.test.ts +24 -0
  458. package/src/gates/__tests__/effective-gates.test.ts +3 -8
  459. package/src/gates/__tests__/test-verdict-consistency.test.ts +140 -0
  460. package/src/gates/acceptance.ts +19 -84
  461. package/src/gates/checker-gate.ts +12 -15
  462. package/src/gates/command.ts +10 -16
  463. package/src/gates/contract.ts +22 -61
  464. package/src/gates/performance.ts +10 -22
  465. package/src/gates/review.ts +21 -41
  466. package/src/gates/security.ts +10 -22
  467. package/src/gates/types.ts +70 -5
  468. package/src/hooks/CONTEXT.md +1 -1
  469. package/src/hooks/bootstrap.ts +5 -2
  470. package/src/index.ts +0 -4
  471. package/src/knowledge/CONTEXT.md +8 -3
  472. package/src/knowledge/__tests__/audit-labels.test.ts +44 -0
  473. package/src/knowledge/__tests__/flywheel-metrics.test.ts +135 -0
  474. package/src/knowledge/__tests__/import.test.ts +44 -0
  475. package/src/knowledge/__tests__/index-generator.test.ts +53 -0
  476. package/src/knowledge/__tests__/ingest.test.ts +85 -0
  477. package/src/knowledge/__tests__/migration.test.ts +47 -0
  478. package/src/knowledge/__tests__/reference-tracker.test.ts +16 -0
  479. package/src/knowledge/__tests__/store.test.ts +194 -0
  480. package/src/knowledge/audit.ts +67 -71
  481. package/src/knowledge/flywheel-metrics.ts +71 -0
  482. package/src/knowledge/import.ts +4 -18
  483. package/src/knowledge/index-generator.ts +19 -14
  484. package/src/knowledge/ingest.ts +9 -4
  485. package/src/knowledge/migration.ts +11 -8
  486. package/src/knowledge/reference-tracker.ts +12 -8
  487. package/src/knowledge/store.ts +64 -11
  488. package/src/monitoring/CONTEXT.md +8 -3
  489. package/src/monitoring/__tests__/skipped-lines-report.test.ts +178 -0
  490. package/src/monitoring/__tests__/traces.test.ts +57 -0
  491. package/src/monitoring/context-tracker.ts +11 -23
  492. package/src/monitoring/index.ts +1 -1
  493. package/src/monitoring/trace-analyzer.ts +21 -2
  494. package/src/monitoring/traces.ts +39 -36
  495. package/src/release/CONTEXT.md +1 -0
  496. package/src/release/__tests__/barrel.test.ts +60 -0
  497. package/src/release/index.ts +2 -13
  498. package/src/sdd/__tests__/index-generator.test.ts +71 -0
  499. package/src/sdd/index-generator.ts +9 -9
  500. package/src/test-setup/__tests__/project-fixture.test.ts +178 -0
  501. package/src/test-setup/project-fixture.ts +87 -0
  502. package/src/tools/CONTEXT.md +6 -0
  503. package/src/tools/__tests__/registry.test.ts +221 -0
  504. package/src/types/__tests__/types.test.ts +4 -5
  505. package/src/types/constraint.ts +16 -27
  506. package/src/types/passes-gate.ts +10 -30
  507. package/src/types/project-config.ts +1 -1
  508. package/src/types/session.ts +5 -5
  509. package/src/types/trace.ts +10 -0
  510. package/src/utils/__tests__/frontmatter.test.ts +206 -0
  511. package/src/utils/__tests__/jsonl-skip-disposition.test.ts +175 -0
  512. package/src/utils/__tests__/jsonl.test.ts +187 -0
  513. package/src/utils/__tests__/package-version.test.ts +97 -0
  514. package/src/utils/exec.ts +15 -0
  515. package/src/utils/file-walk.ts +11 -2
  516. package/src/utils/frontmatter.ts +121 -0
  517. package/src/utils/jsonl.ts +167 -0
  518. package/src/utils/package-version.ts +27 -0
  519. package/dist/cli/commands/doc-freshness-check.d.ts +0 -53
  520. package/dist/cli/commands/doc-freshness-check.d.ts.map +0 -1
  521. package/dist/cli/commands/doc-freshness-check.js +0 -352
  522. package/dist/cli/commands/doc-freshness-check.js.map +0 -1
  523. package/dist/types/index.d.ts +0 -14
  524. package/dist/types/index.d.ts.map +0 -1
  525. package/dist/types/index.js +0 -39
  526. package/dist/types/index.js.map +0 -1
  527. package/src/__tests__/long-running.test.ts +0 -17
  528. package/src/__tests__/passes-gate-extension.test.ts +0 -151
  529. package/src/cli/commands/__tests__/doc-freshness-check.test.ts +0 -168
  530. package/src/cli/commands/doc-freshness-check.ts +0 -386
  531. package/src/spec/CONTEXT.md +0 -11
  532. package/src/types/index.ts +0 -47
@@ -4,18 +4,51 @@
4
4
  * 检查约束是否满足(check 层:Iron Laws / Guidelines;prompt 层仅注入不检查)
5
5
  * 工单 23:触发条件与证据检测迁至 core/constraints/context-builder
6
6
  * ADR-0001:约束集统一走 getMergedConstraintsConfig 生效集链路(preset/config 禁用/custom/scenes)
7
+ * harness#88:本命令是 trace 记录器的组合根——core 不上行依赖 monitoring,
8
+ * 真实收集器在此经构造参数接线
7
9
  */
8
10
 
9
11
  import chalk from 'chalk';
10
12
  import * as fs from 'fs';
11
13
  import * as path from 'path';
12
- import { constraintChecker } from '../../core/constraints/checker';
14
+ import { ConstraintChecker } from '../../core/constraints/checker';
13
15
  import { IRON_LAWS, GUIDELINES, PROMPTS } from '../../core/constraints/definitions';
14
16
  import { getMergedConstraintsConfig } from '../../core/effective-constraints';
15
17
  import { buildConstraintContext } from '../../core/constraints/context-builder';
18
+ import { createGitEvidence, type GitEvidence } from '../../core/constraints/git-evidence';
16
19
  import { detectInjectionDrift } from '../../core/constraints/injection-drift';
20
+ import { GOVERNANCE_HEADING } from '../../core/constraints/injection-writer';
21
+ import { getTraceCollector } from '../../monitoring/traces';
22
+ import { countJsonlLines } from '../../utils/jsonl';
17
23
  import { DEFAULT_TRACE_FILE } from '../../types/trace';
18
- import type { ConstraintTrigger } from '../../types/constraint';
24
+ import type { ConstraintResult, ConstraintTrigger } from '../../types/constraint';
25
+ import { log, processIO, type CommandIO, type CommandResult } from '../command-contract';
26
+
27
+ /** 证据行着色(与调用处所属结论块一致) */
28
+ const EVIDENCE_PAINT = {
29
+ red: chalk.red,
30
+ yellow: chalk.yellow,
31
+ gray: chalk.gray,
32
+ } as const;
33
+
34
+ /**
35
+ * 打印 checker 的判定证据行(harness#119)
36
+ *
37
+ * 文案由 checker 自行措辞(每行自描述),CLI 只负责缩进与着色——
38
+ * 不在这里解释内容,否则证据形状与措辞会两头漂移。
39
+ * 传 id 时首行挂上约束 id(提示块里没有父级结论行可依附)。
40
+ */
41
+ function logEvidence(
42
+ io: CommandIO,
43
+ result: ConstraintResult,
44
+ color: keyof typeof EVIDENCE_PAINT,
45
+ id?: string
46
+ ): void {
47
+ const paint = EVIDENCE_PAINT[color];
48
+ (result.evidence ?? []).forEach((line, index) => {
49
+ log(io, paint(index === 0 && id ? ` - ${id}: ${line}` : ` ${line}`));
50
+ });
51
+ }
19
52
 
20
53
  export interface CheckOptions {
21
54
  /** 预设名称 */
@@ -26,14 +59,24 @@ export interface CheckOptions {
26
59
  trigger?: ConstraintTrigger;
27
60
  /** 项目路径 */
28
61
  projectPath?: string;
62
+ /**
63
+ * git 证据 adapter(非 CLI flag;#87)
64
+ *
65
+ * 缺省 = 本 run 独占一份真 git 证据。注入则与调用方共用同一证据快照,
66
+ * 测试据此断言"同一 run 内每条 git 命令至多执行一次"。
67
+ */
68
+ evidence?: GitEvidence;
29
69
  }
30
70
 
31
71
  /**
32
72
  * 执行约束检查
33
73
  */
34
- export async function check(options: CheckOptions): Promise<void> {
35
- console.log(chalk.blue('🔍 检查约束...'));
36
- console.log(chalk.gray(`预设: ${options.preset}`));
74
+ export async function check(
75
+ options: CheckOptions,
76
+ io: CommandIO = processIO,
77
+ ): Promise<CommandResult> {
78
+ log(io, chalk.blue('🔍 检查约束...'));
79
+ log(io, chalk.gray(`预设: ${options.preset}`));
37
80
 
38
81
  try {
39
82
  const projectPath = options.projectPath || process.cwd();
@@ -43,33 +86,38 @@ export async function check(options: CheckOptions): Promise<void> {
43
86
  // 项目自定义配置优先于 CLI 预设),优先级规则收在 getMergedConstraintsConfig 一处。
44
87
  const merged = getMergedConstraintsConfig(projectPath, { preset: options.preset });
45
88
  if (merged.custom.length > 0) {
46
- console.log(chalk.gray(`自定义约束: ${merged.custom.length} 条`));
89
+ log(io, chalk.gray(`自定义约束: ${merged.custom.length} 条`));
47
90
  }
48
91
  if (merged.disabled.length > 0) {
49
- console.log(chalk.gray(`已禁用约束: ${merged.disabled.join(', ')}`));
92
+ log(io, chalk.gray(`已禁用约束: ${merged.disabled.join(', ')}`));
50
93
  }
51
94
  const unknownIds = merged.unknownIds ?? [];
52
95
  if (unknownIds.length > 0) {
53
- console.log(chalk.yellow(`⚠️ 配置中存在未知约束 id(已忽略,可清理): ${unknownIds.join(', ')}`));
96
+ log(io, chalk.yellow(`⚠️ 配置中存在未知约束 id(已忽略,可清理): ${unknownIds.join(', ')}`));
54
97
  }
55
98
 
56
99
  // 构建上下文(工单 23:触发条件与证据检测收敛至 core/constraints/context-builder)
100
+ // #87:一次 run 一份 git 证据——context-builder 与 checker 层共用同一实例
101
+ const evidence = options.evidence ?? createGitEvidence(projectPath);
57
102
  const context = await buildConstraintContext({
58
103
  projectPath: options.projectPath,
59
104
  staged: options.staged,
60
105
  trigger: options.trigger,
106
+ evidence,
61
107
  });
62
108
  const changedFiles = context.changedFiles ?? [];
63
109
  if (changedFiles.length > 0) {
64
- console.log(chalk.gray(`变更文件: ${changedFiles.length} 个`));
110
+ log(io, chalk.gray(`变更文件: ${changedFiles.length} 个`));
65
111
  }
66
- console.log(chalk.gray(`触发条件: ${[context.operation, ...(context.extraTriggers ?? [])].join(', ')}`));
112
+ log(io, chalk.gray(`触发条件: ${[context.operation, ...(context.extraTriggers ?? [])].join(', ')}`));
67
113
 
68
- // 执行三层检查(per-request 传 customConfig,避免单例状态污染)
69
- const result = await constraintChecker.checkConstraints(context, merged);
114
+ // 执行三层检查(per-request 传 customConfig,避免单例状态污染;证据同 run 同源)
115
+ // trace 记录器经构造参数接线(harness#88):一次命令一个 checker 实例
116
+ const checker = new ConstraintChecker(getTraceCollector());
117
+ const result = await checker.checkConstraints(context, merged, evidence);
70
118
 
71
119
  // 输出结果
72
- console.log();
120
+ log(io);
73
121
 
74
122
  // skipped(约定未采用/证据未接线)单独列示,不进 pass/fail 统计(ADR-0001)
75
123
  const skippedResults = [
@@ -81,39 +129,54 @@ export async function check(options: CheckOptions): Promise<void> {
81
129
  const evaluatedIronLaws = result.ironLaws.filter(r => !r.skipped);
82
130
  const ironLawViolations = evaluatedIronLaws.filter(r => !r.satisfied);
83
131
  if (ironLawViolations.length === 0 && evaluatedIronLaws.length > 0) {
84
- console.log(chalk.green(`✅ 铁律: 全部通过 (${evaluatedIronLaws.length} 条)`));
132
+ log(io, chalk.green(`✅ 铁律: 全部通过 (${evaluatedIronLaws.length} 条)`));
85
133
  } else if (ironLawViolations.length > 0) {
86
- console.log(chalk.red(`❌ 铁律违规: ${ironLawViolations.length} 条`));
134
+ log(io, chalk.red(`❌ 铁律违规: ${ironLawViolations.length} 条`));
87
135
  ironLawViolations.forEach(r => {
88
136
  if (r.constraint) {
89
- console.log(chalk.red(` - ${r.constraint.id}: ${r.constraint.message}`));
90
- console.log(chalk.red(` ${r.constraint.rule}`));
137
+ log(io, chalk.red(` - ${r.constraint.id}: ${r.constraint.message}`));
138
+ log(io, chalk.red(` ${r.constraint.rule}`));
139
+ logEvidence(io, r, 'red');
91
140
  }
92
141
  });
93
- console.log();
94
- console.log(chalk.red('🛑 铁律检查失败,请修复后再提交'));
95
- process.exit(1);
142
+ log(io);
143
+ log(io, chalk.red('🛑 铁律检查失败,请修复后再提交'));
144
+ return {
145
+ kind: 'fail',
146
+ reason: `iron law violated: ${ironLawViolations.map(r => r.constraint?.id ?? 'unknown').join(', ')}`,
147
+ };
96
148
  }
97
149
 
98
150
  // Guidelines
99
151
  if (result.warningCount > 0) {
100
- console.log(chalk.yellow(`⚠️ 指导原则警告: ${result.warningCount} 条`));
152
+ log(io, chalk.yellow(`⚠️ 指导原则警告: ${result.warningCount} 条`));
101
153
  result.guidelines.filter(r => !r.satisfied).forEach(r => {
102
154
  if (r.constraint) {
103
- console.log(chalk.yellow(` - ${r.constraint.id}: ${r.constraint.message}`));
155
+ log(io, chalk.yellow(` - ${r.constraint.id}: ${r.constraint.message}`));
156
+ logEvidence(io, r, 'yellow');
104
157
  }
105
158
  });
106
159
  } else if (result.guidelines.length > 0) {
107
160
  const evaluatedGuidelines = result.guidelines.filter(r => !r.skipped);
108
161
  const passedGuidelines = evaluatedGuidelines.filter(r => r.satisfied).length;
109
- console.log(chalk.green(`✅ 指导原则: ${passedGuidelines}/${evaluatedGuidelines.length} 通过`));
162
+ log(io, chalk.green(`✅ 指导原则: ${passedGuidelines}/${evaluatedGuidelines.length} 通过`));
163
+ }
164
+
165
+ // 提示:通过但带证据(harness#119)——与本次变更无因果的仓库级漂移在此露出,
166
+ // 不判违规、不改 exit code,只保证「看得见且能自己修」
167
+ const hints = [...result.ironLaws, ...result.guidelines].filter(
168
+ r => !r.skipped && r.satisfied && (r.evidence?.length ?? 0) > 0
169
+ );
170
+ if (hints.length > 0) {
171
+ log(io, chalk.gray(`💡 提示: ${hints.length} 条(不判违规,供参考)`));
172
+ hints.forEach(r => logEvidence(io, r, 'gray', r.id));
110
173
  }
111
174
 
112
175
  // Skipped:约定未采用 / 证据未接线,未评估(不计通过/失败)
113
176
  if (skippedResults.length > 0) {
114
- console.log(chalk.gray(`⏭️ 跳过评估: ${skippedResults.length} 条(约定未采用或证据未接线,不计通过/失败)`));
177
+ log(io, chalk.gray(`⏭️ 跳过评估: ${skippedResults.length} 条(约定未采用或证据未接线,不计通过/失败)`));
115
178
  skippedResults.forEach(r => {
116
- console.log(chalk.gray(` - ${r.id}`));
179
+ log(io, chalk.gray(` - ${r.id}`));
117
180
  });
118
181
  }
119
182
 
@@ -122,38 +185,39 @@ export async function check(options: CheckOptions): Promise<void> {
122
185
  try {
123
186
  const drift = detectInjectionDrift(projectPath);
124
187
  if (drift.hasDrift) {
125
- console.log();
126
- console.log(chalk.yellow(`⚠️ 检测到 ${drift.injectionFile ?? '治理文档'} 约束注入漂移(仅警告,不阻断):`));
188
+ log(io);
189
+ log(io, chalk.yellow(`⚠️ 检测到 ${drift.injectionFile ?? '治理文档'} 约束注入漂移(仅警告,不阻断):`));
127
190
  if (drift.versionDrift) {
128
- console.log(chalk.yellow(` ⚠️⚠️ 注入段版本 (${drift.versionDrift.actual}) ≠ 已安装 harness 版本 (${drift.versionDrift.expected}):agent 上下文中的规则与已安装 harness 版本不一致`));
191
+ log(io, chalk.yellow(` ⚠️⚠️ 注入段版本 (${drift.versionDrift.actual}) ≠ 已安装 harness 版本 (${drift.versionDrift.expected}):agent 上下文中的规则与已安装 harness 版本不一致`));
129
192
  }
130
193
  if (drift.contentDrift) {
131
- console.log(chalk.yellow(` 内容漂移: 缺失 ${drift.contentDrift.missing.length} 条 / 多余 ${drift.contentDrift.extra.length} 条(条目级差异见 harness constraints report)`));
194
+ log(io, chalk.yellow(` 内容漂移: 缺失 ${drift.contentDrift.missing.length} 条 / 多余 ${drift.contentDrift.extra.length} 条(条目级差异见 harness constraints report)`));
132
195
  }
133
196
  if (drift.duplicateHeading) {
134
- console.log(chalk.yellow(' 检测到重复的 "## Governance Rules" 章节'));
197
+ log(io, chalk.yellow(` 检测到重复的 "${GOVERNANCE_HEADING}" 章节`));
135
198
  }
136
- console.log(chalk.yellow(` 修复: ${drift.fixHint}`));
199
+ log(io, chalk.yellow(` 修复: ${drift.fixHint}`));
137
200
  }
138
201
  } catch {
139
202
  // 漂移检测失败不影响 check 结果
140
203
  }
141
204
 
142
- console.log();
143
- console.log(chalk.green('✅ 约束检查通过'));
205
+ log(io);
206
+ log(io, chalk.green('✅ 约束检查通过'));
144
207
 
145
208
  // 智能提示
146
209
  const hint = await getSmartHint(projectPath);
147
210
  if (hint) {
148
- console.log();
149
- console.log(chalk.gray('────────────────────────────────────'));
150
- console.log(hint);
151
- console.log(chalk.gray('────────────────────────────────────'));
211
+ log(io);
212
+ log(io, chalk.gray('────────────────────────────────────'));
213
+ log(io, hint);
214
+ log(io, chalk.gray('────────────────────────────────────'));
152
215
  }
216
+ return { kind: 'ok' };
153
217
  } catch (error) {
154
- console.log();
155
- console.log(chalk.red(`❌ 约束检查异常: ${error instanceof Error ? error.message : String(error)}`));
156
- process.exit(1);
218
+ log(io);
219
+ log(io, chalk.red(`❌ 约束检查异常: ${error instanceof Error ? error.message : String(error)}`));
220
+ return { kind: 'fail', reason: `check error: ${error instanceof Error ? error.message : String(error)}` };
157
221
  }
158
222
  }
159
223
 
@@ -163,17 +227,12 @@ export async function check(options: CheckOptions): Promise<void> {
163
227
  async function getSmartHint(projectPath: string): Promise<string | null> {
164
228
  const tracesPath = path.join(projectPath, DEFAULT_TRACE_FILE);
165
229
  const statePath = path.join(projectPath, '.harness', '.state.json');
166
-
167
- // 检查 trace 文件是否存在
168
- if (!fs.existsSync(tracesPath)) {
230
+
231
+ // 只数非空行数(含坏行),零 parse——原语义不变,走 jsonl 正本(harness#82)
232
+ const traceCount = countJsonlLines(tracesPath);
233
+ if (traceCount === 0) {
169
234
  return null;
170
235
  }
171
-
172
- // 读取 trace 记录数
173
- const tracesContent = fs.readFileSync(tracesPath, 'utf-8');
174
- const lines = tracesContent.trim().split('\n').filter(Boolean);
175
- const traceCount = lines.length;
176
-
177
236
  // 读取状态
178
237
  let state: {
179
238
  shownHints?: string[];
@@ -206,33 +265,35 @@ async function getSmartHint(projectPath: string): Promise<string | null> {
206
265
  /**
207
266
  * 列出所有约束
208
267
  */
209
- export function listLaws(): void {
210
- console.log(chalk.blue('\n📜 所有约束:\n'));
268
+ /** optionRoutes 一律以 (options) 调用;--list 不消费检查选项,形参仅占位 */
269
+ export function listLaws(_options: Partial<CheckOptions> = {}, io: CommandIO = processIO): CommandResult {
270
+ log(io, chalk.blue('\n📜 所有约束:\n'));
211
271
 
212
272
  // Iron Laws
213
- console.log(chalk.red('🔴 铁律 (Iron Laws) - 绝对禁止,无例外:\n'));
273
+ log(io, chalk.red('🔴 铁律 (Iron Laws) - 绝对禁止,无例外:\n'));
214
274
  Object.values(IRON_LAWS).forEach(constraint => {
215
- console.log(chalk.red(` ${constraint.id}`));
216
- console.log(chalk.gray(` ${constraint.rule}`));
217
- console.log(chalk.gray(` ${constraint.message}`));
218
- console.log();
275
+ log(io, chalk.red(` ${constraint.id}`));
276
+ log(io, chalk.gray(` ${constraint.rule}`));
277
+ log(io, chalk.gray(` ${constraint.message}`));
278
+ log(io);
219
279
  });
220
280
 
221
281
  // Guidelines
222
- console.log(chalk.yellow('🟡 指导原则 (Guidelines) - 优先建议,违背发警告但不阻止:\n'));
282
+ log(io, chalk.yellow('🟡 指导原则 (Guidelines) - 优先建议,违背发警告但不阻止:\n'));
223
283
  Object.values(GUIDELINES).forEach(constraint => {
224
- console.log(chalk.yellow(` ${constraint.id}`));
225
- console.log(chalk.gray(` ${constraint.rule}`));
226
- console.log(chalk.gray(` ${constraint.message}`));
227
- console.log();
284
+ log(io, chalk.yellow(` ${constraint.id}`));
285
+ log(io, chalk.gray(` ${constraint.rule}`));
286
+ log(io, chalk.gray(` ${constraint.message}`));
287
+ log(io);
228
288
  });
229
289
 
230
290
  // Prompts(ADR-0001:纯注入层,不执行检查)
231
- console.log(chalk.blue('🔵 提示 (Prompts) - 纯文本注入,不参与检查:\n'));
291
+ log(io, chalk.blue('🔵 提示 (Prompts) - 纯文本注入,不参与检查:\n'));
232
292
  Object.values(PROMPTS).forEach(constraint => {
233
- console.log(chalk.blue(` ${constraint.id}`));
234
- console.log(chalk.gray(` ${constraint.rule}`));
235
- console.log(chalk.gray(` ${constraint.message}`));
236
- console.log();
293
+ log(io, chalk.blue(` ${constraint.id}`));
294
+ log(io, chalk.gray(` ${constraint.rule}`));
295
+ log(io, chalk.gray(` ${constraint.message}`));
296
+ log(io);
237
297
  });
298
+ return { kind: 'ok' };
238
299
  }
@@ -5,9 +5,13 @@
5
5
  * harness command "rm -rf /"
6
6
  * harness command --level "DROP TABLE users"
7
7
  * harness command --list
8
+ *
9
+ * 判定经返回值外溢(架构评审候选7):风险等级/黑名单裁决译成 kind,
10
+ * 退出码映射收敛在 bin 一处。
8
11
  */
9
12
 
10
13
  import { createCommandGate, getCommandRiskLevel, DEFAULT_COMMAND_BLACKLIST, type CommandBlacklistRule } from '../../gates';
14
+ import { log, logError, processIO, type CommandIO, type CommandResult } from '../command-contract';
11
15
 
12
16
  export interface CommandCheckOptions {
13
17
  level?: boolean;
@@ -19,17 +23,21 @@ export interface CommandCheckOptions {
19
23
  /**
20
24
  * 执行命令黑名单检查(供 bin/harness.js 调用)
21
25
  */
22
- export async function executeCommand(cmd: string | undefined, options: CommandCheckOptions): Promise<void> {
26
+ export async function executeCommand(
27
+ cmd: string | undefined,
28
+ options: CommandCheckOptions,
29
+ io: CommandIO = processIO,
30
+ ): Promise<CommandResult> {
23
31
  if (options.list) {
24
32
  if (options.json) {
25
- console.log(JSON.stringify(DEFAULT_COMMAND_BLACKLIST.map((r: CommandBlacklistRule) => ({
33
+ log(io, JSON.stringify(DEFAULT_COMMAND_BLACKLIST.map((r: CommandBlacklistRule) => ({
26
34
  id: r.id,
27
35
  level: r.level,
28
36
  message: r.message,
29
37
  category: r.category,
30
38
  })), null, 2));
31
39
  } else {
32
- console.log('\n命令黑名单规则:\n');
40
+ log(io, '\n命令黑名单规则:\n');
33
41
 
34
42
  const byCategory = DEFAULT_COMMAND_BLACKLIST.reduce((acc: Record<string, CommandBlacklistRule[]>, rule: CommandBlacklistRule) => {
35
43
  if (!acc[rule.category]) acc[rule.category] = [];
@@ -38,23 +46,23 @@ export async function executeCommand(cmd: string | undefined, options: CommandCh
38
46
  }, {});
39
47
 
40
48
  for (const [category, rules] of Object.entries(byCategory)) {
41
- console.log(`[${category}]`);
49
+ log(io, `[${category}]`);
42
50
  for (const rule of rules as CommandBlacklistRule[]) {
43
51
  const levelIcon = rule.level === 'block' ? '🚫' : rule.level === 'warn' ? '⚠️' : '📋';
44
- console.log(` ${levelIcon} ${rule.id}: ${rule.message} (${rule.level})`);
52
+ log(io, ` ${levelIcon} ${rule.id}: ${rule.message} (${rule.level})`);
45
53
  }
46
- console.log();
54
+ log(io);
47
55
  }
48
56
 
49
- console.log(`共 ${DEFAULT_COMMAND_BLACKLIST.length} 条规则`);
57
+ log(io, `共 ${DEFAULT_COMMAND_BLACKLIST.length} 条规则`);
50
58
  }
51
- return;
59
+ return { kind: 'ok' };
52
60
  }
53
61
 
54
62
  if (!cmd) {
55
- console.error('错误:请提供要检查的命令');
56
- console.error('用法:harness command "your command"');
57
- process.exit(1);
63
+ logError(io, '错误:请提供要检查的命令');
64
+ logError(io, '用法:harness command "your command"');
65
+ return { kind: 'usage-error', reason: '缺少要检查的命令参数' };
58
66
  }
59
67
 
60
68
  const gate = createCommandGate({ strict: options.strict });
@@ -63,28 +71,33 @@ export async function executeCommand(cmd: string | undefined, options: CommandCh
63
71
  if (options.level) {
64
72
  const level = getCommandRiskLevel(cmd);
65
73
  if (options.json) {
66
- console.log(JSON.stringify({ level, command: cmd }));
74
+ log(io, JSON.stringify({ level, command: cmd }));
67
75
  } else {
68
76
  const levelColors: Record<string, string> = {
69
77
  high: '\x1b[31m',
70
78
  medium: '\x1b[33m',
71
79
  low: '\x1b[32m',
72
80
  };
73
- console.log(`${levelColors[level]}${level}\x1b[0m ${cmd}`);
81
+ log(io, `${levelColors[level]}${level}\x1b[0m ${cmd}`);
74
82
  }
75
- process.exit(level === 'high' ? 1 : 0);
83
+ // 严重级闸门(历史条件式):high 非零退出
84
+ return level === 'high'
85
+ ? { kind: 'fail', reason: `command risk level is high: ${cmd}` }
86
+ : { kind: 'ok' };
76
87
  }
77
88
 
78
89
  if (options.json) {
79
- console.log(JSON.stringify({
90
+ log(io, JSON.stringify({
80
91
  command: cmd,
81
92
  passed: result.passed,
82
93
  message: result.message,
83
94
  details: result.details,
84
95
  }, null, 2));
85
96
  } else {
86
- console.log(result.passed ? `\x1b[32m✓\x1b[0m ${result.message}` : `\x1b[31m✗\x1b[0m ${result.message}`);
97
+ log(io, result.passed ? `\x1b[32m✓\x1b[0m ${result.message}` : `\x1b[31m✗\x1b[0m ${result.message}`);
87
98
  }
88
99
 
89
- process.exit(result.passed ? 0 : 1);
100
+ return result.passed
101
+ ? { kind: 'ok' }
102
+ : { kind: 'fail', reason: `command gate denied: ${result.message}` };
90
103
  }
@@ -14,14 +14,16 @@ import * as path from 'path';
14
14
  import chalk from 'chalk';
15
15
  import {
16
16
  buildConstraintsUsageReport,
17
+ CANDIDATE_KIND_LABEL,
17
18
  DEFAULT_DIAGNOSE_THRESHOLDS,
18
19
  type ConstraintsUsageReport,
19
20
  type ConstraintUsageStats,
20
21
  type DiagnoseThresholds,
21
- type RetireCandidate,
22
22
  } from '../../core/constraints/usage-report';
23
23
  import { getConstraintsMeta } from './constraints';
24
24
  import { detectInjectionDrift, type InjectionDrift } from '../../core/constraints/injection-drift';
25
+ import { GOVERNANCE_HEADING } from '../../core/constraints/injection-writer';
26
+ import { log, processIO, type CommandIO, type CommandResult } from '../command-contract';
25
27
 
26
28
  export interface ConstraintsReportOptions {
27
29
  projectPath?: string;
@@ -36,13 +38,6 @@ export interface ConstraintsReportOptions {
36
38
  noiseMinTotal?: number;
37
39
  }
38
40
 
39
- const CANDIDATE_KIND_LABEL: Record<RetireCandidate['kind'], string> = {
40
- zero_trigger: '零触发',
41
- unevaluable: '不可评估',
42
- high_noise: '高噪',
43
- zero_intercept: '零拦截',
44
- };
45
-
46
41
  function formatTime(ts: number | undefined): string {
47
42
  return ts === undefined ? '-' : new Date(ts).toISOString().slice(0, 10);
48
43
  }
@@ -74,6 +69,10 @@ export function renderExportMarkdown(
74
69
  lines.push('');
75
70
  lines.push(`- harness 版本: ${version}`);
76
71
  lines.push(`- 日期: ${now.toISOString().slice(0, 10)}`);
72
+ if (report.skippedLines > 0) {
73
+ // 脱敏:只报条数,不报路径、不报坏行内容
74
+ lines.push(`- ⚠️ trace 文件有 ${report.skippedLines} 行损坏已跳过,下表统计只含其余合法记录`);
75
+ }
77
76
  lines.push('');
78
77
 
79
78
  lines.push('## 统计表(check 层)');
@@ -120,7 +119,7 @@ export function renderInjectionDriftLines(drift: InjectionDrift): string[] {
120
119
  if (drift.notInjected) {
121
120
  lines.push(' CLAUDE.md / AGENTS.md 均无约束注入标记段(未注入,不算漂移);可运行 npx @dommaker/harness init 注入');
122
121
  if (drift.duplicateHeading) {
123
- lines.push(' 另检测到多个 "## Governance Rules" 标题(历史遗留重复章节),建议手工清理后重跑 npx @dommaker/harness init');
122
+ lines.push(` 另检测到多个 "${GOVERNANCE_HEADING}" 标题(历史遗留重复章节),建议手工清理后重跑 npx @dommaker/harness init`);
124
123
  }
125
124
  return lines;
126
125
  }
@@ -141,7 +140,7 @@ export function renderInjectionDriftLines(drift: InjectionDrift): string[] {
141
140
  }
142
141
  }
143
142
  if (drift.duplicateHeading) {
144
- lines.push(' 重复章节: 标记段之外还存在另一个 "## Governance Rules" 标题');
143
+ lines.push(` 重复章节: 标记段之外还存在另一个 "${GOVERNANCE_HEADING}" 标题`);
145
144
  }
146
145
  lines.push(` 修复: ${drift.fixHint}`);
147
146
  return lines;
@@ -150,7 +149,7 @@ export function renderInjectionDriftLines(drift: InjectionDrift): string[] {
150
149
  /**
151
150
  * CLI handler: harness constraints report
152
151
  */
153
- export async function constraintsReport(options: ConstraintsReportOptions = {}): Promise<void> {
152
+ export async function constraintsReport(options: ConstraintsReportOptions = {}, io: CommandIO = processIO): Promise<CommandResult> {
154
153
  const projectRoot = options.projectPath || process.cwd();
155
154
  const thresholds: Partial<DiagnoseThresholds> = {};
156
155
  if (options.zeroInterceptMin !== undefined) thresholds.zeroInterceptMinEvaluated = options.zeroInterceptMin;
@@ -160,58 +159,61 @@ export async function constraintsReport(options: ConstraintsReportOptions = {}):
160
159
  const report = buildConstraintsUsageReport(projectRoot, thresholds);
161
160
 
162
161
  if (options.json) {
163
- console.log(JSON.stringify(report, null, 2));
164
- return;
162
+ log(io, JSON.stringify(report, null, 2));
163
+ return { kind: 'ok' };
165
164
  }
166
165
 
167
- console.log(chalk.blue('📊 约束使用报告'));
166
+ log(io, chalk.blue('📊 约束使用报告'));
168
167
  if (!report.traceFileExists) {
169
- console.log(chalk.gray(' (trace 文件不存在,全部按零触发统计)'));
168
+ log(io, chalk.gray(' (trace 文件不存在,全部按零触发统计)'));
169
+ }
170
+ if (report.skippedLines > 0) {
171
+ log(io, chalk.yellow(` ⚠️ trace 文件有 ${report.skippedLines} 行损坏已跳过,统计只含其余合法记录(数据不完整)`));
170
172
  }
171
- console.log();
173
+ log(io);
172
174
 
173
175
  // 统计表
174
- console.log(chalk.bold('统计表(check 层):'));
176
+ log(io, chalk.bold('统计表(check 层):'));
175
177
  for (const s of report.stats) {
176
- console.log(` ${renderStatsRow(s)}`);
178
+ log(io, ` ${renderStatsRow(s)}`);
177
179
  }
178
- console.log();
180
+ log(io);
179
181
 
180
182
  // 候选诊断
181
- console.log(chalk.bold(`退役候选(${report.candidates.length} 条,阈值: 零拦截≥${thresholds.zeroInterceptMinEvaluated ?? DEFAULT_DIAGNOSE_THRESHOLDS.zeroInterceptMinEvaluated} 次评估, 高噪 fail率>${Math.round((thresholds.highNoiseFailRate ?? DEFAULT_DIAGNOSE_THRESHOLDS.highNoiseFailRate) * 100)}% 且 ≥${thresholds.highNoiseMinEvaluated ?? DEFAULT_DIAGNOSE_THRESHOLDS.highNoiseMinEvaluated} 次评估):`));
183
+ log(io, chalk.bold(`退役候选(${report.candidates.length} 条,阈值: 零拦截≥${thresholds.zeroInterceptMinEvaluated ?? DEFAULT_DIAGNOSE_THRESHOLDS.zeroInterceptMinEvaluated} 次评估, 高噪 fail率>${Math.round((thresholds.highNoiseFailRate ?? DEFAULT_DIAGNOSE_THRESHOLDS.highNoiseFailRate) * 100)}% 且 ≥${thresholds.highNoiseMinEvaluated ?? DEFAULT_DIAGNOSE_THRESHOLDS.highNoiseMinEvaluated} 次评估):`));
182
184
  if (report.candidates.length === 0) {
183
- console.log(chalk.green(' (无候选)'));
185
+ log(io, chalk.green(' (无候选)'));
184
186
  } else {
185
187
  for (const c of report.candidates) {
186
- console.log(` [${CANDIDATE_KIND_LABEL[c.kind]}] ${c.id} — ${c.reason}`);
188
+ log(io, ` [${CANDIDATE_KIND_LABEL[c.kind]}] ${c.id} — ${c.reason}`);
187
189
  }
188
- console.log(chalk.gray(' 可运行 `harness constraints retire` 交互式处理候选'));
190
+ log(io, chalk.gray(' 可运行 `harness constraints retire` 交互式处理候选'));
189
191
  }
190
- console.log();
192
+ log(io);
191
193
 
192
194
  // 注入清单
193
- console.log(chalk.bold(`当前生效 prompt 注入(${report.activePromptIds.length} 条):`));
195
+ log(io, chalk.bold(`当前生效 prompt 注入(${report.activePromptIds.length} 条):`));
194
196
  for (const id of report.activePromptIds) {
195
- console.log(` ${id}`);
197
+ log(io, ` ${id}`);
196
198
  }
197
- console.log();
199
+ log(io);
198
200
 
199
201
  // 配置健康
200
202
  if (report.lint.unknownIds.length > 0) {
201
- console.log(chalk.yellow('⚠️ 配置健康:'));
203
+ log(io, chalk.yellow('⚠️ 配置健康:'));
202
204
  for (const id of report.lint.unknownIds) {
203
- console.log(chalk.yellow(` config.yml 中禁用了不存在/已移除的约束 id: ${id}(残留配置,建议清理)`));
205
+ log(io, chalk.yellow(` config.yml 中禁用了不存在/已移除的约束 id: ${id}(残留配置,建议清理)`));
204
206
  }
205
- console.log();
207
+ log(io);
206
208
  }
207
209
 
208
210
  // 注入漂移(ADR-0001 决策 7:条目级差异 + 修复指引;--export 摘要不含本地漂移状态)
209
- console.log(chalk.bold('注入漂移:'));
211
+ log(io, chalk.bold('注入漂移:'));
210
212
  const drift = detectInjectionDrift(projectRoot);
211
213
  for (const line of renderInjectionDriftLines(drift)) {
212
- console.log(drift.hasDrift ? chalk.yellow(line) : line);
214
+ log(io, drift.hasDrift ? chalk.yellow(line) : line);
213
215
  }
214
- console.log();
216
+ log(io);
215
217
 
216
218
  // --export
217
219
  if (options.export !== undefined && options.export !== false) {
@@ -229,6 +231,7 @@ export async function constraintsReport(options: ConstraintsReportOptions = {}):
229
231
 
230
232
  fs.mkdirSync(path.dirname(exportPath), { recursive: true });
231
233
  fs.writeFileSync(exportPath, markdown, 'utf-8');
232
- console.log(chalk.green(`✅ 脱敏报告已导出: ${exportPath}`));
234
+ log(io, chalk.green(`✅ 脱敏报告已导出: ${exportPath}`));
233
235
  }
236
+ return { kind: 'ok' };
234
237
  }