@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
@@ -2,7 +2,7 @@
2
2
  * harness constraints retire —— 约束退役(ADR-0001 决策 2/5)
3
3
  *
4
4
  * 建议层全自动(候选诊断复用 report 数据层),执行层保留一次人确认。
5
- * 落盘形态(#82 D6 一处真相):
5
+ * 落盘形态(studio#82 D6 一处真相):
6
6
  *
7
7
  * - 内置约束 → config.yml `enabled: false` + `retired` 元数据:
8
8
  *
@@ -33,21 +33,24 @@
33
33
  import * as fs from 'fs';
34
34
  import * as path from 'path';
35
35
  import * as readline from 'readline';
36
+ import { log, logError, processIO, type CommandIO, type CommandResult } from '../command-contract';
36
37
  import * as yaml from 'js-yaml';
37
38
  import chalk from 'chalk';
38
39
  import { getConstraint } from '../../core/constraints/definitions';
39
- import { renderConstraintsSection, CONSTRAINTS_END_MARKER } from '../../core/constraints/injection-renderer';
40
- import { resolveInjectionTarget } from '../../core/constraints/injection-drift';
40
+ import { renderConstraintsSection, CONSTRAINTS_START_MARKER, CONSTRAINTS_END_MARKER } from '../../core/constraints/injection-renderer';
41
+ import { replaceStandaloneRange, resolveInjectionTarget } from '../../core/constraints/injection-writer';
41
42
  import { getEffectiveConstraints } from '../../core/effective-constraints';
42
43
  import { loadRawProjectConfig, ProjectConfigLoader } from '../../core/project-config-loader';
44
+ import { getHarnessPackageVersion } from '../../utils/package-version';
43
45
  import { FileKnowledgeStore } from '../../knowledge/store';
44
46
  import type { KnowledgeEntry } from '../../knowledge/types';
45
47
  import type { Constraint } from '../../types/constraint';
46
48
  import {
47
49
  buildConstraintsUsageReport,
50
+ CANDIDATE_KIND_LABEL,
48
51
  collectUsageByConstraint,
49
52
  readProjectTraces,
50
- type RetireCandidate,
53
+ readProjectTracesReport,
51
54
  } from '../../core/constraints/usage-report';
52
55
 
53
56
  export interface RetireExecuteOptions {
@@ -64,7 +67,7 @@ export interface RetireResult {
64
67
  status: RetireStatus;
65
68
  /** 是否 check 层 iron(交互模式据此追加确认) */
66
69
  isIronLaw: boolean;
67
- /** 退役落点:custom 约束落 custom-constraints.yml(#82 D6),内置落 config.yml */
70
+ /** 退役落点:custom 约束落 custom-constraints.yml(studio#82 D6),内置落 config.yml */
68
71
  landing: 'config.yml' | 'custom-constraints.yml';
69
72
  stats: { total: number; fail: number; failRate: number };
70
73
  /** 治理注入段(CLAUDE.md / AGENTS.md)是否已同步 */
@@ -128,18 +131,6 @@ function findRetireTarget(projectRoot: string, id: string): RetireTargetInfo | u
128
131
  return undefined;
129
132
  }
130
133
 
131
- /**
132
- * 读取 harness 版本(与 init.ts 同路径策略)
133
- */
134
- function getHarnessVersion(): string {
135
- try {
136
- const pkgPath = path.join(__dirname, '..', '..', '..', 'package.json');
137
- return JSON.parse(fs.readFileSync(pkgPath, 'utf-8')).version ?? 'unknown';
138
- } catch {
139
- return 'unknown';
140
- }
141
- }
142
-
143
134
  /**
144
135
  * 写 config.yml 退役段(ADR-0001 决策 5)
145
136
  *
@@ -174,7 +165,7 @@ function writeRetireConfig(
174
165
  }
175
166
 
176
167
  /**
177
- * 写 custom-constraints.yml 退役段(#82 D6 统一落点)
168
+ * 写 custom-constraints.yml 退役段(studio#82 D6 统一落点)
178
169
  *
179
170
  * 在 custom_constraints.<id> 条目内追加 retired 元数据,保留规则原文。
180
171
  * js-yaml 不保留注释:原文件含注释行时重写会丢失,console 说明。
@@ -280,12 +271,10 @@ function syncGovernanceInjection(projectRoot: string): { synced: boolean; file?:
280
271
  const target = resolveInjectionTarget(projectRoot);
281
272
  if (!target) return { synced: false };
282
273
 
283
- const filePath = path.join(projectRoot, target.file);
284
- const body = renderConstraintsSection(getEffectiveConstraints(projectRoot), getHarnessVersion());
285
- const after = target.content.slice(target.endIdx + CONSTRAINTS_END_MARKER.length).replace(/^\n+/, '');
286
- const newContent = target.content.slice(0, target.startIdx) + body + (after ? '\n' + after : '');
287
- if (newContent !== target.content) {
288
- fs.writeFileSync(filePath, newContent, 'utf-8');
274
+ const body = renderConstraintsSection(getEffectiveConstraints(projectRoot), getHarnessPackageVersion());
275
+ const write = replaceStandaloneRange(target.content, CONSTRAINTS_START_MARKER, CONSTRAINTS_END_MARKER, body);
276
+ if (write.kind === 'updated' && write.content !== target.content) {
277
+ fs.writeFileSync(path.join(projectRoot, target.file), write.content, 'utf-8');
289
278
  }
290
279
  return { synced: true, file: target.file };
291
280
  }
@@ -327,6 +316,9 @@ export function retireConstraint(
327
316
  }
328
317
 
329
318
  // 历史统计(来自 traces.log)
319
+ // 计数去向:兼容包装 readProjectTraces() 丢计数(harness#100)——落盘的 retire stats 只计
320
+ // 合法记录,把坏行数写进 RetireResult.stats 属形状变更不在本票;本函数按契约「纯执行无交互」
321
+ // 不打印,告知由两条命令入口各自负责(runRetireInteractive 顶部 / constraintsRetire 的 --yes 分支)
330
322
  const usage = collectUsageByConstraint(readProjectTraces(projectRoot)).get(id);
331
323
  const evaluated = usage ? usage.total - usage.skip : 0;
332
324
  const stats = {
@@ -366,29 +358,30 @@ export function retireConstraint(
366
358
  /**
367
359
  * 打印单条退役结果(含回滚语义提示)
368
360
  */
369
- export function printRetireResult(result: RetireResult): void {
361
+ export function printRetireResult(result: RetireResult, io: CommandIO = processIO): CommandResult {
370
362
  switch (result.status) {
371
363
  case 'unknown_id':
372
- console.log(chalk.red(`❌ ${result.id}: 约束不存在(既非内置也非 custom-constraints),未做任何变更`));
373
- return;
364
+ log(io, chalk.red(`❌ ${result.id}: 约束不存在(既非内置也非 custom-constraints),未做任何变更`));
365
+ return { kind: 'skip', reason: `${result.id}: 约束不存在,未做任何变更` };
374
366
  case 'already_retired':
375
- console.log(chalk.yellow(`⚠️ ${result.id}: 已处于退役状态(config.yml 中 enabled: false),跳过`));
376
- return;
367
+ log(io, chalk.yellow(`⚠️ ${result.id}: 已处于退役状态(config.yml 中 enabled: false),跳过`));
368
+ return { kind: 'skip', reason: `${result.id}: 已处于退役状态,跳过` };
377
369
  case 'retired': {
378
- console.log(chalk.green(`✅ ${result.id}: 已退役`));
379
- console.log(` 历史统计: total=${result.stats.total} fail=${result.stats.fail} fail率=${Math.round(result.stats.failRate * 100)}%`);
380
- console.log(` 知识沉淀: ${result.knowledgeEntryId}(.harness/knowledge)`);
370
+ log(io, chalk.green(`✅ ${result.id}: 已退役`));
371
+ log(io, ` 历史统计: total=${result.stats.total} fail=${result.stats.fail} fail率=${Math.round(result.stats.failRate * 100)}%`);
372
+ log(io, ` 知识沉淀: ${result.knowledgeEntryId}(.harness/knowledge)`);
381
373
  if (result.injectionSynced) {
382
- console.log(` 已同步 ${result.injectionFile ?? '治理文档'} 注入段`);
374
+ log(io, ` 已同步 ${result.injectionFile ?? '治理文档'} 注入段`);
383
375
  }
384
376
  const recovery =
385
377
  result.landing === 'custom-constraints.yml'
386
378
  ? `删除 custom-constraints.yml 中 custom_constraints.${result.id}.retired 段`
387
379
  : `删除 config.yml 中 constraints.${result.id} 段`;
388
- console.log(chalk.gray(` retire 不是删除——恢复方法:${recovery}`));
380
+ log(io, chalk.gray(` retire 不是删除——恢复方法:${recovery}`));
389
381
  break;
390
382
  }
391
383
  }
384
+ return { kind: 'ok' };
392
385
  }
393
386
 
394
387
  // ========================================
@@ -408,13 +401,6 @@ function createAsk(io: RetireIO): { ask: (q: string) => Promise<string>; close:
408
401
  };
409
402
  }
410
403
 
411
- const CANDIDATE_KIND_LABEL: Record<RetireCandidate['kind'], string> = {
412
- zero_trigger: '零触发',
413
- unevaluable: '不可评估',
414
- high_noise: '高噪',
415
- zero_intercept: '零拦截',
416
- };
417
-
418
404
  /**
419
405
  * 交互式退役(候选列表 → 编号多选 → 摘要 → 确认 → 执行)
420
406
  *
@@ -423,9 +409,16 @@ const CANDIDATE_KIND_LABEL: Record<RetireCandidate['kind'], string> = {
423
409
  export async function runRetireInteractive(
424
410
  projectRoot: string,
425
411
  io: RetireIO = { input: process.stdin, output: process.stdout }
426
- ): Promise<void> {
412
+ ): Promise<CommandResult> {
427
413
  const report = buildConstraintsUsageReport(projectRoot);
414
+ // 候选诊断是退役决策的依据:数据不完整必须先说(harness#100,与 report 同一降级维度);
415
+ // 告知行走 stderr,与 status / failure list / 直达分支同一去向(交互正文仍走 console.log)
416
+ if (report.skippedLines > 0) {
417
+ console.error(chalk.yellow(`⚠️ trace 文件有 ${report.skippedLines} 行损坏已跳过,候选只基于其余合法记录`));
418
+ }
428
419
  const { ask, close } = createAsk(io);
420
+ // 退役结果打印走注入流(与 readline 提示同一去向)
421
+ const out = { stdout: io.output, stderr: io.output } as unknown as CommandIO;
429
422
 
430
423
  try {
431
424
  let selectedIds: string[] = [];
@@ -435,7 +428,7 @@ export async function runRetireInteractive(
435
428
  const manual = await ask('可手动输入要退役的约束 id(留空取消): ');
436
429
  if (!manual) {
437
430
  console.log('已取消');
438
- return;
431
+ return { kind: 'skip', reason: '交互未确认,未做任何变更' };
439
432
  }
440
433
  selectedIds = [manual];
441
434
  } else {
@@ -447,7 +440,7 @@ export async function runRetireInteractive(
447
440
  const answer = await ask('输入编号(逗号分隔多选)或约束 id,留空取消: ');
448
441
  if (!answer) {
449
442
  console.log('已取消');
450
- return;
443
+ return { kind: 'skip', reason: '交互未确认,未做任何变更' };
451
444
  }
452
445
 
453
446
  for (const token of answer.split(',').map(s => s.trim()).filter(Boolean)) {
@@ -482,7 +475,7 @@ export async function runRetireInteractive(
482
475
 
483
476
  if (plan.length === 0) {
484
477
  console.log('无可执行项,已取消');
485
- return;
478
+ return { kind: 'skip', reason: '交互未确认,未做任何变更' };
486
479
  }
487
480
 
488
481
  // 变更摘要 → 最终确认
@@ -500,17 +493,18 @@ export async function runRetireInteractive(
500
493
  const finalConfirm = await ask('确认执行?(y/N) ');
501
494
  if (finalConfirm.toLowerCase() !== 'y' && finalConfirm.toLowerCase() !== 'yes') {
502
495
  console.log('已取消');
503
- return;
496
+ return { kind: 'skip', reason: '交互未确认,未做任何变更' };
504
497
  }
505
498
 
506
499
  console.log();
507
500
  for (const p of plan) {
508
501
  const result = retireConstraint(projectRoot, p.id, { reason: p.reason });
509
- printRetireResult(result);
502
+ printRetireResult(result, out);
510
503
  }
511
504
  } finally {
512
505
  close();
513
506
  }
507
+ return { kind: 'ok' };
514
508
  }
515
509
 
516
510
  /**
@@ -519,29 +513,38 @@ export async function runRetireInteractive(
519
513
  * 人确认闸门(#24,ADR-0001 决策 2):带 id 的直达路径必须显式 `--yes`,
520
514
  * 无 `--yes` 报错 + 非零退出码,提示改用 `--yes` 或交互模式;不落盘任何文件。
521
515
  */
522
- export async function constraintsRetire(id?: string, options: ConstraintsRetireOptions = {}): Promise<void> {
516
+ export async function constraintsRetire(
517
+ id?: string,
518
+ options: ConstraintsRetireOptions = {},
519
+ io: CommandIO = processIO,
520
+ ): Promise<CommandResult> {
523
521
  const projectRoot = options.projectPath || process.cwd();
524
522
 
525
523
  if (id) {
526
524
  // 非交互直达:执行层人确认对所有入口成立(含程序化调用方)
527
525
  if (!options.yes) {
528
- console.error(
526
+ logError(io,
529
527
  chalk.red(`❌ 直达退役需要显式人确认(ADR-0001 决策 2:执行层保留一次人确认),未做任何变更\n`) +
530
528
  ` 带 --yes 显式确认直达:harness constraints retire ${id} --yes` +
531
529
  `${options.reason ? ` --reason "${options.reason}"` : ''}\n` +
532
530
  ` 或去掉 id 走交互确认:harness constraints retire`
533
531
  );
534
- process.exitCode = 1;
535
- return;
532
+ return { kind: 'usage-error', reason: `直达退役 ${id} 缺少显式 --yes 人确认,未做任何变更` };
533
+ }
534
+
535
+ // 落盘的 retire stats 只含合法记录:依据不完整要在执行前告知(harness#100,
536
+ // 直达路径不经过 runRetireInteractive,故两处各自告知)
537
+ const { skippedLines } = readProjectTracesReport(projectRoot);
538
+ if (skippedLines > 0) {
539
+ logError(io, chalk.yellow(`⚠️ trace 文件有 ${skippedLines} 行损坏已跳过,落盘的退役统计只基于其余合法记录`));
536
540
  }
537
541
 
538
542
  const result = retireConstraint(projectRoot, id, { reason: options.reason });
539
543
  if (result.status === 'retired' && result.isIronLaw) {
540
- console.log(chalk.yellow(`⚠️ ${id} 是一条 Iron Law,已通过 --yes 直达退役(交互模式会要求二次确认)`));
544
+ log(io, chalk.yellow(`⚠️ ${id} 是一条 Iron Law,已通过 --yes 直达退役(交互模式会要求二次确认)`));
541
545
  }
542
- printRetireResult(result);
543
- return;
546
+ return printRetireResult(result, io);
544
547
  }
545
548
 
546
- await runRetireInteractive(projectRoot);
549
+ return runRetireInteractive(projectRoot);
547
550
  }
@@ -5,10 +5,10 @@
5
5
  * 供 Studio 等消费者获取约束的 hash、计数、文本大小等元数据。
6
6
  */
7
7
 
8
- import { readFileSync, existsSync } from 'fs';
9
- import { join } from 'path';
10
8
  import { createHash } from 'crypto';
11
9
  import { getAllConstraints } from '../../core/constraints/definitions';
10
+ import { getHarnessPackageVersion } from '../../utils/package-version';
11
+ import { log, processIO, type CommandIO, type CommandResult } from '../command-contract';
12
12
 
13
13
  export interface ConstraintsMeta {
14
14
  version: string;
@@ -17,24 +17,6 @@ export interface ConstraintsMeta {
17
17
  textSize: { total: number; perConstraint: number };
18
18
  }
19
19
 
20
- function getPackageVersion(): string {
21
- // Try several common locations
22
- const candidates = [
23
- join(__dirname, '..', '..', '..', 'package.json'),
24
- join(process.cwd(), 'package.json'),
25
- ];
26
- for (const p of candidates) {
27
- if (existsSync(p)) {
28
- try {
29
- return JSON.parse(readFileSync(p, 'utf-8')).version;
30
- } catch {
31
- // continue to next candidate
32
- }
33
- }
34
- }
35
- return 'unknown';
36
- }
37
-
38
20
  export function getConstraintsMeta(): ConstraintsMeta {
39
21
  const constraints = getAllConstraints();
40
22
 
@@ -56,7 +38,7 @@ export function getConstraintsMeta(): ConstraintsMeta {
56
38
  const hash = createHash('sha256').update(hashInput).digest('hex');
57
39
 
58
40
  return {
59
- version: getPackageVersion(),
41
+ version: getHarnessPackageVersion(),
60
42
  hash,
61
43
  counts: {
62
44
  ironLaws: ironLaws.length,
@@ -73,14 +55,15 @@ export function getConstraintsMeta(): ConstraintsMeta {
73
55
  /**
74
56
  * CLI handler: output --json
75
57
  */
76
- export async function constraints(options: { json?: boolean }): Promise<void> {
58
+ export async function constraints(options: { json?: boolean }, io: CommandIO = processIO): Promise<CommandResult> {
77
59
  const meta = getConstraintsMeta();
78
60
  if (options.json) {
79
- console.log(JSON.stringify(meta, null, 2));
61
+ log(io, JSON.stringify(meta, null, 2));
80
62
  } else {
81
- console.log(`version: ${meta.version}`);
82
- console.log(`hash: ${meta.hash}`);
83
- console.log(`ironLaws: ${meta.counts.ironLaws}, guidelines: ${meta.counts.guidelines}, prompts: ${meta.counts.prompts}`);
84
- console.log(`textSize: ${meta.textSize.total} chars total, ~${meta.textSize.perConstraint} chars/constraint`);
63
+ log(io, `version: ${meta.version}`);
64
+ log(io, `hash: ${meta.hash}`);
65
+ log(io, `ironLaws: ${meta.counts.ironLaws}, guidelines: ${meta.counts.guidelines}, prompts: ${meta.counts.prompts}`);
66
+ log(io, `textSize: ${meta.textSize.total} chars total, ~${meta.textSize.perConstraint} chars/constraint`);
85
67
  }
68
+ return { kind: 'ok' };
86
69
  }
@@ -8,6 +8,7 @@ import chalk from 'chalk';
8
8
  import * as fs from 'fs/promises';
9
9
  import * as path from 'path';
10
10
  import { ContractGate } from '../../gates/contract';
11
+ import { log, processIO, type CommandIO, type CommandResult } from '../command-contract';
11
12
 
12
13
  export interface ContractOptions {
13
14
  /** 项目路径 */
@@ -23,8 +24,11 @@ export interface ContractOptions {
23
24
  /**
24
25
  * 执行契约门控
25
26
  */
26
- export async function contract(options: ContractOptions): Promise<void> {
27
- console.log(chalk.blue('📜 API 契约门控检查...'));
27
+ export async function contract(
28
+ options: ContractOptions,
29
+ io: CommandIO = processIO,
30
+ ): Promise<CommandResult> {
31
+ log(io, chalk.blue('📜 API 契约门控检查...'));
28
32
 
29
33
  const projectPath = options.projectPath || process.cwd();
30
34
  const contractPath = options.contractPath || 'openapi.yaml';
@@ -34,10 +38,10 @@ export async function contract(options: ContractOptions): Promise<void> {
34
38
  try {
35
39
  await fs.access(fullPath);
36
40
  } catch {
37
- console.log();
38
- console.log(chalk.red('❌ 契约文件不存在'));
39
- console.log(chalk.red(` ${fullPath}`));
40
- process.exit(1);
41
+ log(io);
42
+ log(io, chalk.red('❌ 契约文件不存在'));
43
+ log(io, chalk.red(` ${fullPath}`));
44
+ return { kind: 'fail', reason: `contract file not found: ${fullPath}` };
41
45
  }
42
46
 
43
47
  // 创建契约门控实例
@@ -53,57 +57,61 @@ export async function contract(options: ContractOptions): Promise<void> {
53
57
  } as any);
54
58
 
55
59
  if (result.passed) {
56
- console.log();
57
- console.log(chalk.green('✅ 契约门控检查通过'));
60
+ log(io);
61
+ log(io, chalk.green('✅ 契约门控检查通过'));
58
62
 
59
63
  if (result.details) {
60
- console.log(chalk.gray(` Schema 有效: ✅`));
64
+ log(io, chalk.gray(` Schema 有效: ✅`));
61
65
  if (result.details.endpoints) {
62
- console.log(chalk.gray(` 端点数: ${result.details.endpoints}`));
66
+ log(io, chalk.gray(` 端点数: ${result.details.endpoints}`));
63
67
  }
64
68
  if (result.details.breakingChanges === false) {
65
- console.log(chalk.gray(` 破坏性变更: 无`));
69
+ log(io, chalk.gray(` 破坏性变更: 无`));
66
70
  }
67
71
  }
68
72
  } else {
69
- console.log();
70
- console.log(chalk.red('❌ 契约门控检查失败'));
71
- console.log(chalk.red(` ${result.message}`));
73
+ log(io);
74
+ log(io, chalk.red('❌ 契约门控检查失败'));
75
+ log(io, chalk.red(` ${result.message}`));
72
76
 
73
77
  if (result.details?.errors) {
74
- console.log();
75
- console.log(chalk.red('验证错误:'));
78
+ log(io);
79
+ log(io, chalk.red('验证错误:'));
76
80
  (result.details.errors as string[]).forEach((error: string) => {
77
- console.log(chalk.red(` - ${error}`));
81
+ log(io, chalk.red(` - ${error}`));
78
82
  });
79
83
  }
80
84
 
81
85
  if (result.details?.breakingChanges) {
82
- console.log();
83
- console.log(chalk.red('破坏性变更:'));
86
+ log(io);
87
+ log(io, chalk.red('破坏性变更:'));
84
88
  (result.details.breakingChanges as any[]).forEach((change: any) => {
85
- console.log(chalk.red(` - ${change.type}: ${change.path}`));
89
+ log(io, chalk.red(` - ${change.type}: ${change.path}`));
86
90
  if (change.description) {
87
- console.log(chalk.gray(` ${change.description}`));
91
+ log(io, chalk.gray(` ${change.description}`));
88
92
  }
89
93
  });
90
94
  }
91
95
 
92
- process.exit(1);
96
+ return { kind: 'fail', reason: `contract gate denied: ${result.message}` };
93
97
  }
98
+ return { kind: 'ok' };
94
99
  } catch (error: any) {
95
- console.log();
96
- console.log(chalk.red('❌ 契约门控检查出错'));
97
- console.log(chalk.red(` ${error.message}`));
98
- process.exit(1);
100
+ log(io);
101
+ log(io, chalk.red('❌ 契约门控检查出错'));
102
+ log(io, chalk.red(` ${error.message}`));
103
+ return { kind: 'fail', reason: `contract gate error: ${error.message}` };
99
104
  }
100
105
  }
101
106
 
102
107
  /**
103
108
  * 验证 OpenAPI Schema 语法
104
109
  */
105
- export async function validateSchema(options: ContractOptions): Promise<void> {
106
- console.log(chalk.blue('📜 验证 OpenAPI Schema...\n'));
110
+ export async function validateSchema(
111
+ options: ContractOptions,
112
+ io: CommandIO = processIO,
113
+ ): Promise<CommandResult> {
114
+ log(io, chalk.blue('📜 验证 OpenAPI Schema...\n'));
107
115
 
108
116
  const projectPath = options.projectPath || process.cwd();
109
117
  const contractPath = options.contractPath || 'openapi.yaml';
@@ -118,8 +126,8 @@ export async function validateSchema(options: ContractOptions): Promise<void> {
118
126
  try {
119
127
  schema = yaml.load(content);
120
128
  } catch (e: any) {
121
- console.log(chalk.red(`❌ YAML 解析错误: ${e.message}`));
122
- process.exit(1);
129
+ log(io, chalk.red(`❌ YAML 解析错误: ${e.message}`));
130
+ return { kind: 'fail', reason: `contract YAML parse error: ${e.message}` };
123
131
  }
124
132
 
125
133
  // 基本验证
@@ -143,26 +151,27 @@ export async function validateSchema(options: ContractOptions): Promise<void> {
143
151
  }
144
152
 
145
153
  if (errors.length > 0) {
146
- console.log(chalk.red('❌ Schema 验证失败:\n'));
147
- errors.forEach(err => console.log(chalk.red(` - ${err}`)));
148
- process.exit(1);
154
+ log(io, chalk.red('❌ Schema 验证失败:\n'));
155
+ errors.forEach(err => log(io, chalk.red(` - ${err}`)));
156
+ return { kind: 'fail', reason: `contract schema invalid: ${errors.join('; ')}` };
149
157
  }
150
158
 
151
- console.log(chalk.green('✅ Schema 验证通过'));
152
- console.log();
153
- console.log(chalk.gray('Schema 信息:'));
154
- console.log(chalk.gray(` 版本: ${schema.openapi}`));
155
- console.log(chalk.gray(` 标题: ${schema.info.title}`));
156
- console.log(chalk.gray(` API 版本: ${schema.info.version}`));
159
+ log(io, chalk.green('✅ Schema 验证通过'));
160
+ log(io);
161
+ log(io, chalk.gray('Schema 信息:'));
162
+ log(io, chalk.gray(` 版本: ${schema.openapi}`));
163
+ log(io, chalk.gray(` 标题: ${schema.info.title}`));
164
+ log(io, chalk.gray(` API 版本: ${schema.info.version}`));
157
165
 
158
166
  if (schema.paths) {
159
167
  const endpoints = Object.keys(schema.paths).flatMap(path =>
160
168
  Object.keys(schema.paths[path]).map(method => `${method.toUpperCase()} ${path}`)
161
169
  );
162
- console.log(chalk.gray(` 端点数: ${endpoints.length}`));
170
+ log(io, chalk.gray(` 端点数: ${endpoints.length}`));
163
171
  }
172
+ return { kind: 'ok' };
164
173
  } catch (error: any) {
165
- console.log(chalk.red(`❌ 验证失败: ${error.message}`));
166
- process.exit(1);
174
+ log(io, chalk.red(`❌ 验证失败: ${error.message}`));
175
+ return { kind: 'fail', reason: `contract schema read error: ${error.message}` };
167
176
  }
168
177
  }