@dommaker/harness 1.3.0 → 1.4.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 (517) hide show
  1. package/CHANGELOG.md +8 -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 +76 -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 +29 -214
  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 +21 -15
  53. package/dist/cli/commands/knowledge.d.ts.map +1 -1
  54. package/dist/cli/commands/knowledge.js +214 -199
  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 +2 -1
  115. package/dist/cli/commands/update-user-model.d.ts.map +1 -1
  116. package/dist/cli/commands/update-user-model.js +31 -45
  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 +64 -115
  143. package/dist/core/constraints/checker.js.map +1 -1
  144. package/dist/core/constraints/checkers/capability-sync.d.ts +4 -3
  145. package/dist/core/constraints/checkers/capability-sync.d.ts.map +1 -1
  146. package/dist/core/constraints/checkers/capability-sync.js +29 -69
  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 +37 -63
  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/no-test-simplification.d.ts.map +1 -1
  160. package/dist/core/constraints/checkers/no-test-simplification.js +4 -3
  161. package/dist/core/constraints/checkers/no-test-simplification.js.map +1 -1
  162. package/dist/core/constraints/checkers/types.d.ts +2 -2
  163. package/dist/core/constraints/context-builder.d.ts +15 -14
  164. package/dist/core/constraints/context-builder.d.ts.map +1 -1
  165. package/dist/core/constraints/context-builder.js +32 -96
  166. package/dist/core/constraints/context-builder.js.map +1 -1
  167. package/dist/core/constraints/doc-freshness/runner.d.ts.map +1 -1
  168. package/dist/core/constraints/doc-freshness/runner.js +2 -1
  169. package/dist/core/constraints/doc-freshness/runner.js.map +1 -1
  170. package/dist/core/constraints/git-evidence.d.ts +60 -0
  171. package/dist/core/constraints/git-evidence.d.ts.map +1 -0
  172. package/dist/core/constraints/git-evidence.js +88 -0
  173. package/dist/core/constraints/git-evidence.js.map +1 -0
  174. package/dist/core/constraints/injection-drift.d.ts +3 -20
  175. package/dist/core/constraints/injection-drift.d.ts.map +1 -1
  176. package/dist/core/constraints/injection-drift.js +10 -57
  177. package/dist/core/constraints/injection-drift.js.map +1 -1
  178. package/dist/core/constraints/injection-writer.d.ts +113 -0
  179. package/dist/core/constraints/injection-writer.d.ts.map +1 -0
  180. package/dist/core/constraints/injection-writer.js +228 -0
  181. package/dist/core/constraints/injection-writer.js.map +1 -0
  182. package/dist/core/constraints/usage-report.d.ts +22 -1
  183. package/dist/core/constraints/usage-report.d.ts.map +1 -1
  184. package/dist/core/constraints/usage-report.js +27 -20
  185. package/dist/core/constraints/usage-report.js.map +1 -1
  186. package/dist/core/index.d.ts +2 -2
  187. package/dist/core/index.d.ts.map +1 -1
  188. package/dist/core/index.js +4 -2
  189. package/dist/core/index.js.map +1 -1
  190. package/dist/core/project-config-loader.d.ts +32 -1
  191. package/dist/core/project-config-loader.d.ts.map +1 -1
  192. package/dist/core/project-config-loader.js +39 -9
  193. package/dist/core/project-config-loader.js.map +1 -1
  194. package/dist/core/validators/passes-gate.d.ts +15 -64
  195. package/dist/core/validators/passes-gate.d.ts.map +1 -1
  196. package/dist/core/validators/passes-gate.js +84 -222
  197. package/dist/core/validators/passes-gate.js.map +1 -1
  198. package/dist/core/validators/test-output.d.ts +58 -0
  199. package/dist/core/validators/test-output.d.ts.map +1 -0
  200. package/dist/core/validators/test-output.js +109 -0
  201. package/dist/core/validators/test-output.js.map +1 -0
  202. package/dist/failure/recorder.d.ts +6 -0
  203. package/dist/failure/recorder.d.ts.map +1 -1
  204. package/dist/failure/recorder.js +12 -8
  205. package/dist/failure/recorder.js.map +1 -1
  206. package/dist/gates/acceptance.d.ts +1 -48
  207. package/dist/gates/acceptance.d.ts.map +1 -1
  208. package/dist/gates/acceptance.js +6 -38
  209. package/dist/gates/acceptance.js.map +1 -1
  210. package/dist/gates/checker-gate.d.ts.map +1 -1
  211. package/dist/gates/checker-gate.js +6 -11
  212. package/dist/gates/checker-gate.js.map +1 -1
  213. package/dist/gates/command.d.ts.map +1 -1
  214. package/dist/gates/command.js +10 -22
  215. package/dist/gates/command.js.map +1 -1
  216. package/dist/gates/contract.d.ts.map +1 -1
  217. package/dist/gates/contract.js +22 -61
  218. package/dist/gates/contract.js.map +1 -1
  219. package/dist/gates/performance.d.ts.map +1 -1
  220. package/dist/gates/performance.js +13 -31
  221. package/dist/gates/performance.js.map +1 -1
  222. package/dist/gates/review.d.ts.map +1 -1
  223. package/dist/gates/review.js +21 -53
  224. package/dist/gates/review.js.map +1 -1
  225. package/dist/gates/security.d.ts.map +1 -1
  226. package/dist/gates/security.js +14 -32
  227. package/dist/gates/security.js.map +1 -1
  228. package/dist/gates/types.d.ts +28 -5
  229. package/dist/gates/types.d.ts.map +1 -1
  230. package/dist/gates/types.js +38 -1
  231. package/dist/gates/types.js.map +1 -1
  232. package/dist/hooks/bootstrap.d.ts +2 -0
  233. package/dist/hooks/bootstrap.d.ts.map +1 -1
  234. package/dist/hooks/bootstrap.js +5 -2
  235. package/dist/hooks/bootstrap.js.map +1 -1
  236. package/dist/index.d.ts +1 -2
  237. package/dist/index.d.ts.map +1 -1
  238. package/dist/index.js.map +1 -1
  239. package/dist/knowledge/audit.d.ts +7 -2
  240. package/dist/knowledge/audit.d.ts.map +1 -1
  241. package/dist/knowledge/audit.js +59 -79
  242. package/dist/knowledge/audit.js.map +1 -1
  243. package/dist/knowledge/flywheel-metrics.d.ts +39 -0
  244. package/dist/knowledge/flywheel-metrics.d.ts.map +1 -0
  245. package/dist/knowledge/flywheel-metrics.js +47 -0
  246. package/dist/knowledge/flywheel-metrics.js.map +1 -0
  247. package/dist/knowledge/import.d.ts.map +1 -1
  248. package/dist/knowledge/import.js +4 -14
  249. package/dist/knowledge/import.js.map +1 -1
  250. package/dist/knowledge/index-generator.d.ts.map +1 -1
  251. package/dist/knowledge/index-generator.js +17 -14
  252. package/dist/knowledge/index-generator.js.map +1 -1
  253. package/dist/knowledge/ingest.d.ts.map +1 -1
  254. package/dist/knowledge/ingest.js +9 -4
  255. package/dist/knowledge/ingest.js.map +1 -1
  256. package/dist/knowledge/migration.d.ts.map +1 -1
  257. package/dist/knowledge/migration.js +11 -8
  258. package/dist/knowledge/migration.js.map +1 -1
  259. package/dist/knowledge/reference-tracker.d.ts.map +1 -1
  260. package/dist/knowledge/reference-tracker.js +12 -9
  261. package/dist/knowledge/reference-tracker.js.map +1 -1
  262. package/dist/knowledge/store.d.ts +15 -0
  263. package/dist/knowledge/store.d.ts.map +1 -1
  264. package/dist/knowledge/store.js +59 -10
  265. package/dist/knowledge/store.js.map +1 -1
  266. package/dist/monitoring/context-tracker.d.ts.map +1 -1
  267. package/dist/monitoring/context-tracker.js +11 -20
  268. package/dist/monitoring/context-tracker.js.map +1 -1
  269. package/dist/monitoring/index.d.ts +1 -1
  270. package/dist/monitoring/index.d.ts.map +1 -1
  271. package/dist/monitoring/index.js +1 -2
  272. package/dist/monitoring/index.js.map +1 -1
  273. package/dist/monitoring/trace-analyzer.d.ts +15 -0
  274. package/dist/monitoring/trace-analyzer.d.ts.map +1 -1
  275. package/dist/monitoring/trace-analyzer.js +19 -2
  276. package/dist/monitoring/trace-analyzer.js.map +1 -1
  277. package/dist/monitoring/traces.d.ts +21 -2
  278. package/dist/monitoring/traces.d.ts.map +1 -1
  279. package/dist/monitoring/traces.js +38 -29
  280. package/dist/monitoring/traces.js.map +1 -1
  281. package/dist/release/index.d.ts +2 -2
  282. package/dist/release/index.d.ts.map +1 -1
  283. package/dist/release/index.js +1 -5
  284. package/dist/release/index.js.map +1 -1
  285. package/dist/sdd/index-generator.js +10 -11
  286. package/dist/sdd/index-generator.js.map +1 -1
  287. package/dist/test-setup/project-fixture.d.ts +48 -0
  288. package/dist/test-setup/project-fixture.d.ts.map +1 -0
  289. package/dist/test-setup/project-fixture.js +106 -0
  290. package/dist/test-setup/project-fixture.js.map +1 -0
  291. package/dist/types/constraint.d.ts +0 -18
  292. package/dist/types/constraint.d.ts.map +1 -1
  293. package/dist/types/constraint.js.map +1 -1
  294. package/dist/types/passes-gate.d.ts +10 -25
  295. package/dist/types/passes-gate.d.ts.map +1 -1
  296. package/dist/types/project-config.d.ts +1 -1
  297. package/dist/types/session.d.ts +6 -5
  298. package/dist/types/session.d.ts.map +1 -1
  299. package/dist/utils/exec.d.ts +10 -0
  300. package/dist/utils/exec.d.ts.map +1 -1
  301. package/dist/utils/exec.js +12 -0
  302. package/dist/utils/exec.js.map +1 -1
  303. package/dist/utils/file-walk.d.ts +9 -1
  304. package/dist/utils/file-walk.d.ts.map +1 -1
  305. package/dist/utils/file-walk.js +10 -1
  306. package/dist/utils/file-walk.js.map +1 -1
  307. package/dist/utils/frontmatter.d.ts +73 -0
  308. package/dist/utils/frontmatter.d.ts.map +1 -0
  309. package/dist/utils/frontmatter.js +141 -0
  310. package/dist/utils/frontmatter.js.map +1 -0
  311. package/dist/utils/jsonl.d.ts +92 -0
  312. package/dist/utils/jsonl.d.ts.map +1 -0
  313. package/dist/utils/jsonl.js +166 -0
  314. package/dist/utils/jsonl.js.map +1 -0
  315. package/dist/utils/package-version.d.ts +16 -0
  316. package/dist/utils/package-version.d.ts.map +1 -0
  317. package/dist/utils/package-version.js +63 -0
  318. package/dist/utils/package-version.js.map +1 -0
  319. package/package.json +1 -1
  320. package/src/CONTEXT.md +7 -2
  321. package/src/__tests__/acceptance-gate.test.ts +3 -1
  322. package/src/__tests__/checker-extra.test.ts +7 -1218
  323. package/src/__tests__/context-files-resolution.test.ts +116 -0
  324. package/src/__tests__/effective-constraints.test.ts +10 -13
  325. package/src/__tests__/exec.test.ts +35 -1
  326. package/src/__tests__/layering.test.ts +152 -0
  327. package/src/__tests__/passes-gate-extra.test.ts +0 -145
  328. package/src/__tests__/passes-gate.test.ts +142 -106
  329. package/src/__tests__/skip-semantics.test.ts +5 -9
  330. package/src/cli/__tests__/command-contract.test.ts +170 -0
  331. package/src/cli/command-contract.ts +108 -0
  332. package/src/cli/commands/CONTEXT.md +22 -7
  333. package/src/cli/commands/__tests__/acceptance.test.ts +40 -33
  334. package/src/cli/commands/__tests__/analyze-sessions.test.ts +35 -29
  335. package/src/cli/commands/__tests__/bin-exit-mapping.test.ts +101 -0
  336. package/src/cli/commands/__tests__/check-drift.test.ts +27 -34
  337. package/src/cli/commands/__tests__/check-skip-output.test.ts +21 -24
  338. package/src/cli/commands/__tests__/check.test.ts +378 -382
  339. package/src/cli/commands/__tests__/command.test.ts +85 -70
  340. package/src/cli/commands/__tests__/constraints-report.test.ts +100 -71
  341. package/src/cli/commands/__tests__/constraints-retire.test.ts +152 -95
  342. package/src/cli/commands/__tests__/contract.test.ts +27 -34
  343. package/src/cli/commands/__tests__/failure.test.ts +31 -34
  344. package/src/cli/commands/__tests__/init-injection.test.ts +58 -28
  345. package/src/cli/commands/__tests__/init.test.ts +77 -48
  346. package/src/cli/commands/__tests__/knowledge-flywheel-consistency.test.ts +108 -0
  347. package/src/cli/commands/__tests__/knowledge.test.ts +69 -43
  348. package/src/cli/commands/__tests__/passes-gate.test.ts +43 -45
  349. package/src/cli/commands/__tests__/performance.test.ts +22 -23
  350. package/src/cli/commands/__tests__/posteval-plan.test.ts +39 -38
  351. package/src/cli/commands/__tests__/project-path-anchoring.test.ts +157 -0
  352. package/src/cli/commands/__tests__/project-path-convention.test.ts +169 -0
  353. package/src/cli/commands/__tests__/registry.test.ts +69 -35
  354. package/src/cli/commands/__tests__/release.test.ts +209 -80
  355. package/src/cli/commands/__tests__/report-extra.test.ts +16 -16
  356. package/src/cli/commands/__tests__/report.test.ts +25 -25
  357. package/src/cli/commands/__tests__/review.test.ts +33 -31
  358. package/src/cli/commands/__tests__/security.test.ts +23 -27
  359. package/src/cli/commands/__tests__/spec-baseline-check.test.ts +20 -20
  360. package/src/cli/commands/__tests__/spec.test.ts +41 -29
  361. package/src/cli/commands/__tests__/status-extra.test.ts +18 -18
  362. package/src/cli/commands/__tests__/status-skipped-lines.test.ts +72 -0
  363. package/src/cli/commands/__tests__/status.test.ts +34 -34
  364. package/src/cli/commands/__tests__/sync-docs-agents.test.ts +77 -78
  365. package/src/cli/commands/__tests__/sync-docs.test.ts +72 -74
  366. package/src/cli/commands/__tests__/update-user-model.test.ts +62 -33
  367. package/src/cli/commands/__tests__/validate.test.ts +27 -29
  368. package/src/cli/commands/acceptance.ts +35 -24
  369. package/src/cli/commands/analyze-sessions.ts +25 -24
  370. package/src/cli/commands/check.ts +88 -65
  371. package/src/cli/commands/command.ts +30 -17
  372. package/src/cli/commands/constraints-report.ts +37 -34
  373. package/src/cli/commands/constraints-retire.ts +58 -55
  374. package/src/cli/commands/constraints.ts +10 -27
  375. package/src/cli/commands/contract.ts +51 -42
  376. package/src/cli/commands/definitions.ts +36 -222
  377. package/src/cli/commands/failure.ts +33 -26
  378. package/src/cli/commands/init.ts +166 -220
  379. package/src/cli/commands/knowledge.ts +225 -203
  380. package/src/cli/commands/passes-gate.ts +58 -68
  381. package/src/cli/commands/performance.ts +23 -18
  382. package/src/cli/commands/posteval-plan.ts +29 -15
  383. package/src/cli/commands/release.ts +70 -59
  384. package/src/cli/commands/report.ts +9 -5
  385. package/src/cli/commands/review.ts +39 -29
  386. package/src/cli/commands/sdd.ts +7 -5
  387. package/src/cli/commands/security.ts +35 -26
  388. package/src/cli/commands/spec-baseline-check.ts +16 -11
  389. package/src/cli/commands/spec.ts +66 -53
  390. package/src/cli/commands/status.ts +59 -53
  391. package/src/cli/commands/sync-docs/agents-syncer.ts +5 -2
  392. package/src/cli/commands/sync-docs/context-syncer.ts +3 -2
  393. package/src/cli/commands/sync-docs/index.ts +73 -100
  394. package/src/cli/commands/sync-docs/project-reader.ts +17 -18
  395. package/src/cli/commands/update-user-model.ts +33 -45
  396. package/src/cli/commands/validate.ts +31 -25
  397. package/src/cli/session-mining/__tests__/transcript.test.ts +118 -0
  398. package/src/cli/session-mining/transcript.ts +26 -8
  399. package/src/context/session-manager.ts +19 -33
  400. package/src/core/CONTEXT.md +9 -6
  401. package/src/core/constraints/__tests__/capabilities-reconcile.test.ts +200 -0
  402. package/src/core/constraints/__tests__/capability-counts.test.ts +94 -0
  403. package/src/core/constraints/__tests__/git-evidence.test.ts +208 -0
  404. package/src/core/constraints/__tests__/injection-drift.test.ts +3 -10
  405. package/src/core/constraints/__tests__/injection-writer.test.ts +231 -0
  406. package/src/core/constraints/__tests__/trace-injection.test.ts +71 -0
  407. package/src/core/constraints/__tests__/usage-report.test.ts +112 -0
  408. package/src/core/constraints/agent-prompt-renderer.ts +2 -6
  409. package/src/core/constraints/capabilities-parser.ts +53 -35
  410. package/src/core/constraints/capabilities-reconcile.ts +166 -0
  411. package/src/core/constraints/checker.ts +75 -130
  412. package/src/core/constraints/checkers/__tests__/capability-sync.test.ts +214 -0
  413. package/src/core/constraints/checkers/__tests__/context-doc-sync.test.ts +77 -0
  414. package/src/core/constraints/checkers/__tests__/docs-freshness.test.ts +117 -0
  415. package/src/{__tests__ → core/constraints/checkers/__tests__}/governance-presence.test.ts +83 -9
  416. package/src/core/constraints/checkers/__tests__/iron-flags.test.ts +50 -0
  417. package/src/core/constraints/checkers/__tests__/no-bypass-checkpoint.test.ts +76 -0
  418. package/src/{__tests__ → core/constraints/checkers/__tests__}/no-hardcoded-credentials.test.ts +4 -3
  419. package/src/core/constraints/checkers/__tests__/no-test-simplification.test.ts +58 -0
  420. package/src/core/constraints/checkers/__tests__/three-state-consistency.test.ts +145 -0
  421. package/src/core/constraints/checkers/capability-sync.ts +29 -88
  422. package/src/core/constraints/checkers/context-doc-sync.ts +15 -25
  423. package/src/core/constraints/checkers/docs-freshness.ts +40 -69
  424. package/src/core/constraints/checkers/governance-presence.ts +7 -25
  425. package/src/core/constraints/checkers/no-test-simplification.ts +4 -3
  426. package/src/core/constraints/checkers/types.ts +2 -2
  427. package/src/core/constraints/context-builder.ts +39 -91
  428. package/src/core/constraints/doc-freshness/runner.ts +2 -1
  429. package/src/core/constraints/git-evidence.ts +120 -0
  430. package/src/core/constraints/injection-drift.ts +13 -60
  431. package/src/core/constraints/injection-writer.ts +212 -0
  432. package/src/core/constraints/usage-report.ts +36 -17
  433. package/src/core/index.ts +4 -2
  434. package/src/core/project-config-loader.ts +49 -9
  435. package/src/core/validators/__tests__/passes-gate.test.ts +2 -56
  436. package/src/core/validators/__tests__/test-output.test.ts +372 -0
  437. package/src/core/validators/passes-gate.ts +86 -248
  438. package/src/core/validators/test-output.ts +128 -0
  439. package/src/failure/__tests__/recorder.test.ts +168 -0
  440. package/src/failure/recorder.ts +12 -10
  441. package/src/gates/CONTEXT.md +6 -3
  442. package/src/gates/__tests__/acceptance-types-single-source.test.ts +68 -0
  443. package/src/gates/__tests__/acceptance.test.ts +4 -86
  444. package/src/gates/__tests__/effective-gates.test.ts +3 -8
  445. package/src/gates/__tests__/test-verdict-consistency.test.ts +140 -0
  446. package/src/gates/acceptance.ts +19 -84
  447. package/src/gates/checker-gate.ts +8 -7
  448. package/src/gates/command.ts +10 -16
  449. package/src/gates/contract.ts +22 -61
  450. package/src/gates/performance.ts +10 -22
  451. package/src/gates/review.ts +21 -41
  452. package/src/gates/security.ts +10 -22
  453. package/src/gates/types.ts +70 -5
  454. package/src/hooks/CONTEXT.md +1 -1
  455. package/src/hooks/bootstrap.ts +5 -2
  456. package/src/index.ts +0 -4
  457. package/src/knowledge/CONTEXT.md +8 -3
  458. package/src/knowledge/__tests__/audit-labels.test.ts +44 -0
  459. package/src/knowledge/__tests__/flywheel-metrics.test.ts +135 -0
  460. package/src/knowledge/__tests__/import.test.ts +44 -0
  461. package/src/knowledge/__tests__/index-generator.test.ts +53 -0
  462. package/src/knowledge/__tests__/ingest.test.ts +85 -0
  463. package/src/knowledge/__tests__/migration.test.ts +47 -0
  464. package/src/knowledge/__tests__/reference-tracker.test.ts +16 -0
  465. package/src/knowledge/__tests__/store.test.ts +194 -0
  466. package/src/knowledge/audit.ts +67 -71
  467. package/src/knowledge/flywheel-metrics.ts +71 -0
  468. package/src/knowledge/import.ts +4 -18
  469. package/src/knowledge/index-generator.ts +19 -14
  470. package/src/knowledge/ingest.ts +9 -4
  471. package/src/knowledge/migration.ts +11 -8
  472. package/src/knowledge/reference-tracker.ts +12 -8
  473. package/src/knowledge/store.ts +64 -11
  474. package/src/monitoring/CONTEXT.md +8 -3
  475. package/src/monitoring/__tests__/skipped-lines-report.test.ts +178 -0
  476. package/src/monitoring/__tests__/traces.test.ts +57 -0
  477. package/src/monitoring/context-tracker.ts +11 -23
  478. package/src/monitoring/index.ts +1 -1
  479. package/src/monitoring/trace-analyzer.ts +21 -2
  480. package/src/monitoring/traces.ts +39 -36
  481. package/src/release/CONTEXT.md +1 -0
  482. package/src/release/__tests__/barrel.test.ts +60 -0
  483. package/src/release/index.ts +2 -13
  484. package/src/sdd/__tests__/index-generator.test.ts +71 -0
  485. package/src/sdd/index-generator.ts +9 -9
  486. package/src/test-setup/__tests__/project-fixture.test.ts +178 -0
  487. package/src/test-setup/project-fixture.ts +87 -0
  488. package/src/tools/CONTEXT.md +6 -0
  489. package/src/tools/__tests__/registry.test.ts +221 -0
  490. package/src/types/__tests__/types.test.ts +4 -5
  491. package/src/types/constraint.ts +0 -25
  492. package/src/types/passes-gate.ts +10 -30
  493. package/src/types/project-config.ts +1 -1
  494. package/src/types/session.ts +5 -5
  495. package/src/utils/__tests__/frontmatter.test.ts +206 -0
  496. package/src/utils/__tests__/jsonl-skip-disposition.test.ts +175 -0
  497. package/src/utils/__tests__/jsonl.test.ts +187 -0
  498. package/src/utils/__tests__/package-version.test.ts +97 -0
  499. package/src/utils/exec.ts +15 -0
  500. package/src/utils/file-walk.ts +11 -2
  501. package/src/utils/frontmatter.ts +121 -0
  502. package/src/utils/jsonl.ts +167 -0
  503. package/src/utils/package-version.ts +27 -0
  504. package/dist/cli/commands/doc-freshness-check.d.ts +0 -53
  505. package/dist/cli/commands/doc-freshness-check.d.ts.map +0 -1
  506. package/dist/cli/commands/doc-freshness-check.js +0 -352
  507. package/dist/cli/commands/doc-freshness-check.js.map +0 -1
  508. package/dist/types/index.d.ts +0 -14
  509. package/dist/types/index.d.ts.map +0 -1
  510. package/dist/types/index.js +0 -39
  511. package/dist/types/index.js.map +0 -1
  512. package/src/__tests__/long-running.test.ts +0 -17
  513. package/src/__tests__/passes-gate-extension.test.ts +0 -151
  514. package/src/cli/commands/__tests__/doc-freshness-check.test.ts +0 -168
  515. package/src/cli/commands/doc-freshness-check.ts +0 -386
  516. package/src/spec/CONTEXT.md +0 -11
  517. package/src/types/index.ts +0 -47
@@ -9,7 +9,9 @@ import * as fs from 'fs/promises';
9
9
  import { ConstraintChecker } from '../../core/constraints/checker';
10
10
  import { IRON_LAWS, GUIDELINES, PROMPTS } from '../../core/constraints/definitions';
11
11
  import { executeWithCollect } from '../../failure/constraint-handler';
12
+ import { getTraceCollector } from '../../monitoring/traces';
12
13
  import type { ConstraintContext } from '../../types/constraint';
14
+ import { log, processIO, type CommandIO, type CommandResult } from '../command-contract';
13
15
 
14
16
  export interface ReportOptions {
15
17
  /** 输出文件路径 */
@@ -42,11 +44,12 @@ interface ReportData {
42
44
  /**
43
45
  * 生成检查报告
44
46
  */
45
- export async function report(options: ReportOptions): Promise<void> {
46
- console.log(chalk.blue('📊 生成检查报告...'));
47
+ export async function report(options: ReportOptions, io: CommandIO = processIO): Promise<CommandResult> {
48
+ log(io, chalk.blue('📊 生成检查报告...'));
47
49
 
48
50
  const projectPath = options.projectPath || process.cwd();
49
- const checker = ConstraintChecker.getInstance();
51
+ // trace 记录器经构造参数接线(harness#88):本命令是组合根
52
+ const checker = new ConstraintChecker(getTraceCollector());
50
53
 
51
54
  const allConstraints = { ...IRON_LAWS, ...GUIDELINES, ...PROMPTS };
52
55
  const totalConstraints = Object.keys(allConstraints).length;
@@ -105,10 +108,11 @@ export async function report(options: ReportOptions): Promise<void> {
105
108
 
106
109
  if (options.output) {
107
110
  await fs.writeFile(options.output, content, 'utf-8');
108
- console.log(chalk.green(`✅ 报告已保存到: ${options.output}`));
111
+ log(io, chalk.green(`✅ 报告已保存到: ${options.output}`));
109
112
  } else {
110
- console.log(content);
113
+ log(io, content);
111
114
  }
115
+ return { kind: 'ok' };
112
116
  }
113
117
 
114
118
  function generateMarkdownReport(data: ReportData): string {
@@ -7,6 +7,7 @@
7
7
  import chalk from 'chalk';
8
8
  import { execAsync } from '../../utils/exec';
9
9
  import { ReviewGate } from '../../gates/review';
10
+ import { log, processIO, type CommandIO, type CommandResult } from '../command-contract';
10
11
 
11
12
  export interface ReviewOptions {
12
13
  /** 项目路径 */
@@ -24,8 +25,11 @@ export interface ReviewOptions {
24
25
  /**
25
26
  * 执行审查门控
26
27
  */
27
- export async function review(options: ReviewOptions): Promise<void> {
28
- console.log(chalk.blue('👀 代码审查门控检查...'));
28
+ export async function review(
29
+ options: ReviewOptions,
30
+ io: CommandIO = processIO,
31
+ ): Promise<CommandResult> {
32
+ log(io, chalk.blue('👀 代码审查门控检查...'));
29
33
 
30
34
  const projectPath = options.projectPath || process.cwd();
31
35
 
@@ -40,49 +44,53 @@ export async function review(options: ReviewOptions): Promise<void> {
40
44
 
41
45
  try {
42
46
  const { stdout: branch } = await execAsync('git rev-parse --abbrev-ref HEAD', { cwd: projectPath });
43
- console.log(chalk.gray(`当前分支: ${branch.trim()}`));
47
+ log(io, chalk.gray(`当前分支: ${branch.trim()}`));
44
48
 
45
49
  const result = await gate.check({ projectPath, projectId: 'default' });
46
50
 
47
- console.log();
51
+ log(io);
48
52
  if (result.passed) {
49
- console.log(chalk.green('✅ 代码审查门控检查通过'));
53
+ log(io, chalk.green('✅ 代码审查门控检查通过'));
50
54
  if (result.details) {
51
- console.log(chalk.gray(` 审批: ${result.details.approvals ?? 0}, 变更请求: ${result.details.changesRequested ?? 0}`));
55
+ log(io, chalk.gray(` 审批: ${result.details.approvals ?? 0}, 变更请求: ${result.details.changesRequested ?? 0}`));
52
56
  }
53
57
  } else {
54
- console.log(chalk.red('❌ 代码审查门控检查失败'));
55
- console.log(chalk.red(` ${result.message}`));
58
+ log(io, chalk.red('❌ 代码审查门控检查失败'));
59
+ log(io, chalk.red(` ${result.message}`));
56
60
  if (result.details?.suggestion) {
57
- console.log(chalk.gray(` ${result.details.suggestion}`));
61
+ log(io, chalk.gray(` ${result.details.suggestion}`));
58
62
  }
59
- process.exit(1);
63
+ return { kind: 'fail', reason: `review gate denied: ${result.message}` };
60
64
  }
65
+ return { kind: 'ok' };
61
66
  } catch (error: any) {
62
- console.log();
63
- console.log(chalk.red('❌ 代码审查门控检查出错'));
64
- console.log(chalk.red(` ${error.message}`));
67
+ log(io);
68
+ log(io, chalk.red('❌ 代码审查门控检查出错'));
69
+ log(io, chalk.red(` ${error.message}`));
65
70
 
66
71
  if (error.message.includes('not a git repository')) {
67
- console.log();
68
- console.log(chalk.gray('提示: 此命令需要在 Git 仓库中运行'));
72
+ log(io);
73
+ log(io, chalk.gray('提示: 此命令需要在 Git 仓库中运行'));
69
74
  }
70
75
 
71
- process.exit(1);
76
+ return { kind: 'fail', reason: `review gate error: ${error.message}` };
72
77
  }
73
78
  }
74
79
 
75
80
  /**
76
81
  * 显示审查状态详情
77
82
  */
78
- export async function reviewStatus(options: ReviewOptions): Promise<void> {
79
- console.log(chalk.blue('👀 代码审查状态...\n'));
83
+ export async function reviewStatus(
84
+ options: ReviewOptions,
85
+ io: CommandIO = processIO,
86
+ ): Promise<CommandResult> {
87
+ log(io, chalk.blue('👀 代码审查状态...\n'));
80
88
 
81
89
  const projectPath = options.projectPath || process.cwd();
82
90
 
83
91
  try {
84
92
  const { stdout: branch } = await execAsync('git rev-parse --abbrev-ref HEAD', { cwd: projectPath });
85
- console.log(chalk.gray(`当前分支: ${branch.trim()}`));
93
+ log(io, chalk.gray(`当前分支: ${branch.trim()}`));
86
94
 
87
95
  try {
88
96
  const { stdout: prInfo } = await execAsync('gh pr view --json number,title,state,reviewDecision,reviews', {
@@ -90,29 +98,31 @@ export async function reviewStatus(options: ReviewOptions): Promise<void> {
90
98
  });
91
99
  const pr = JSON.parse(prInfo);
92
100
 
93
- console.log();
94
- console.log(chalk.cyan(`PR #${pr.number}: ${pr.title}`));
95
- console.log(chalk.gray(`状态: ${pr.state}`));
101
+ log(io);
102
+ log(io, chalk.cyan(`PR #${pr.number}: ${pr.title}`));
103
+ log(io, chalk.gray(`状态: ${pr.state}`));
96
104
 
97
105
  if (pr.reviewDecision) {
98
106
  const decisionColor = pr.reviewDecision === 'APPROVED' ? chalk.green : chalk.yellow;
99
- console.log(decisionColor(`审查决策: ${pr.reviewDecision}`));
107
+ log(io, decisionColor(`审查决策: ${pr.reviewDecision}`));
100
108
  }
101
109
 
102
110
  if (pr.reviews && pr.reviews.length > 0) {
103
- console.log();
104
- console.log(chalk.gray('审查历史:'));
111
+ log(io);
112
+ log(io, chalk.gray('审查历史:'));
105
113
  pr.reviews.forEach((r: any) => {
106
114
  const statusColor = r.state === 'APPROVED' ? chalk.green :
107
115
  r.state === 'CHANGES_REQUESTED' ? chalk.red : chalk.gray;
108
- console.log(statusColor(` - ${r.author?.login || 'unknown'}: ${r.state}`));
116
+ log(io, statusColor(` - ${r.author?.login || 'unknown'}: ${r.state}`));
109
117
  });
110
118
  }
111
119
  } catch {
112
- console.log(chalk.yellow('\n⚠️ 未找到关联的 PR'));
113
- console.log(chalk.gray(' 使用 gh pr create 创建 PR'));
120
+ log(io, chalk.yellow('\n⚠️ 未找到关联的 PR'));
121
+ log(io, chalk.gray(' 使用 gh pr create 创建 PR'));
114
122
  }
123
+ return { kind: 'ok' };
115
124
  } catch (error: any) {
116
- console.log(chalk.red(`❌ 获取审查状态失败: ${error.message}`));
125
+ log(io, chalk.red(`❌ 获取审查状态失败: ${error.message}`));
126
+ return { kind: 'skip', reason: `获取审查状态失败: ${error.message}` };
117
127
  }
118
128
  }
@@ -2,6 +2,7 @@
2
2
  import * as fs from 'fs';
3
3
  import * as path from 'path';
4
4
  import { SDDIndexGenerator } from '../../sdd/index-generator';
5
+ import { log, processIO, type CommandIO, type CommandResult } from '../command-contract';
5
6
 
6
7
  export interface SDDOptions {
7
8
  projectPath?: string;
@@ -14,7 +15,7 @@ function getSDDDir(projectPath?: string): string {
14
15
  return base;
15
16
  }
16
17
 
17
- export function sddIndex(options: SDDOptions & { dir?: string }): void {
18
+ export function sddIndex(options: SDDOptions & { dir?: string }, io: CommandIO = processIO): CommandResult {
18
19
  const baseDir = options.dir || getSDDDir(options.projectPath);
19
20
  const gen = new SDDIndexGenerator(baseDir);
20
21
 
@@ -30,15 +31,16 @@ export function sddIndex(options: SDDOptions & { dir?: string }): void {
30
31
  );
31
32
 
32
33
  if (options.json) {
33
- console.log(JSON.stringify({
34
+ log(io, JSON.stringify({
34
35
  path: indexPath,
35
36
  entries: result.count,
36
37
  size: afterSize,
37
38
  previousSize: beforeSize,
38
39
  }));
39
40
  } else {
40
- console.log(`SDD Index regenerated: ${indexPath}`);
41
- console.log(` Entries: ${result.count}`);
42
- console.log(` Size: ${beforeSize} → ${afterSize} bytes`);
41
+ log(io, `SDD Index regenerated: ${indexPath}`);
42
+ log(io, ` Entries: ${result.count}`);
43
+ log(io, ` Size: ${beforeSize} → ${afterSize} bytes`);
43
44
  }
45
+ return { kind: 'ok' };
44
46
  }
@@ -6,6 +6,7 @@
6
6
 
7
7
  import chalk from 'chalk';
8
8
  import { SecurityGate } from '../../gates/security';
9
+ import { log, processIO, type CommandIO, type CommandResult } from '../command-contract';
9
10
 
10
11
  export interface SecurityOptions {
11
12
  /** 项目路径 */
@@ -23,8 +24,11 @@ export interface SecurityOptions {
23
24
  /**
24
25
  * 执行安全门控
25
26
  */
26
- export async function security(options: SecurityOptions): Promise<void> {
27
- console.log(chalk.blue('🔒 安全门控检查...'));
27
+ export async function security(
28
+ options: SecurityOptions,
29
+ io: CommandIO = processIO,
30
+ ): Promise<CommandResult> {
31
+ log(io, chalk.blue('🔒 安全门控检查...'));
28
32
 
29
33
  try {
30
34
  const projectPath = options.projectPath || process.cwd();
@@ -38,30 +42,31 @@ export async function security(options: SecurityOptions): Promise<void> {
38
42
 
39
43
  const result = await gate.scan({ projectPath, projectId: 'default' });
40
44
 
41
- console.log();
45
+ log(io);
42
46
  if (result.passed) {
43
- console.log(chalk.green('✅ 安全门控检查通过'));
47
+ log(io, chalk.green('✅ 安全门控检查通过'));
44
48
  if (result.details) {
45
- console.log(chalk.gray(` critical: ${result.details.critical}, high: ${result.details.high}, moderate: ${result.details.moderate}, low: ${result.details.low}`));
49
+ log(io, chalk.gray(` critical: ${result.details.critical}, high: ${result.details.high}, moderate: ${result.details.moderate}, low: ${result.details.low}`));
46
50
  }
47
51
  } else {
48
- console.log(chalk.red('❌ 安全门控检查失败'));
49
- console.log(chalk.red(` ${result.message}`));
52
+ log(io, chalk.red('❌ 安全门控检查失败'));
53
+ log(io, chalk.red(` ${result.message}`));
50
54
  if (result.details?.vulnerabilities) {
51
- console.log();
55
+ log(io);
52
56
  (result.details.vulnerabilities as Array<{ name: string; severity: string; via: string }>).forEach((v, i) => {
53
57
  const severityColor = getSeverityColor(v.severity);
54
- console.log(severityColor(` ${i + 1}. [${v.severity.toUpperCase()}] ${v.name}`));
55
- console.log(chalk.gray(` via: ${v.via}`));
58
+ log(io, severityColor(` ${i + 1}. [${v.severity.toUpperCase()}] ${v.name}`));
59
+ log(io, chalk.gray(` via: ${v.via}`));
56
60
  });
57
61
  }
58
- console.log(chalk.gray('\n 运行 harness security audit 查看详情'));
59
- process.exit(1);
62
+ log(io, chalk.gray('\n 运行 harness security audit 查看详情'));
63
+ return { kind: 'fail', reason: `security gate denied (threshold ${options.severity || 'high'}): ${result.message}` };
60
64
  }
65
+ return { kind: 'ok' };
61
66
  } catch (error) {
62
- console.log();
63
- console.log(chalk.red(`❌ 安全检查异常: ${error instanceof Error ? error.message : String(error)}`));
64
- process.exit(1);
67
+ log(io);
68
+ log(io, chalk.red(`❌ 安全检查异常: ${error instanceof Error ? error.message : String(error)}`));
69
+ return { kind: 'fail', reason: `security scan error: ${error instanceof Error ? error.message : String(error)}` };
65
70
  }
66
71
  }
67
72
 
@@ -86,8 +91,11 @@ function getSeverityColor(severity: string): (text: string) => string {
86
91
  /**
87
92
  * 运行安全审计详情
88
93
  */
89
- export async function auditDetails(options: SecurityOptions): Promise<void> {
90
- console.log(chalk.blue('🔒 安全审计详情...\n'));
94
+ export async function auditDetails(
95
+ options: SecurityOptions,
96
+ io: CommandIO = processIO,
97
+ ): Promise<CommandResult> {
98
+ log(io, chalk.blue('🔒 安全审计详情...\n'));
91
99
 
92
100
  try {
93
101
  const projectPath = options.projectPath || process.cwd();
@@ -100,23 +108,24 @@ export async function auditDetails(options: SecurityOptions): Promise<void> {
100
108
  const result = await gate.scan({ projectPath, projectId: 'default' });
101
109
 
102
110
  if (result.passed && !result.details?.total) {
103
- console.log(chalk.green('✅ 未发现安全漏洞'));
104
- return;
111
+ log(io, chalk.green('✅ 未发现安全漏洞'));
112
+ return { kind: 'ok' };
105
113
  }
106
114
 
107
115
  const details = result.details as any;
108
116
  if (details?.vulnerabilities?.length > 0) {
109
- console.log(chalk.yellow(`发现 ${details.total} 个漏洞:\n`));
117
+ log(io, chalk.yellow(`发现 ${details.total} 个漏洞:\n`));
110
118
  for (const v of details.vulnerabilities) {
111
119
  const severityColor = getSeverityColor(v.severity);
112
- console.log(severityColor(`[${v.severity.toUpperCase()}] ${v.name}`));
113
- console.log(chalk.gray(` via: ${v.via}`));
114
- console.log();
120
+ log(io, severityColor(`[${v.severity.toUpperCase()}] ${v.name}`));
121
+ log(io, chalk.gray(` via: ${v.via}`));
122
+ log(io);
115
123
  }
116
124
  }
125
+ return { kind: 'ok' };
117
126
  } catch (error) {
118
- console.log();
119
- console.log(chalk.red(`❌ 安全审计异常: ${error instanceof Error ? error.message : String(error)}`));
120
- process.exit(1);
127
+ log(io);
128
+ log(io, chalk.red(`❌ 安全审计异常: ${error instanceof Error ? error.message : String(error)}`));
129
+ return { kind: 'fail', reason: `security audit error: ${error instanceof Error ? error.message : String(error)}` };
121
130
  }
122
131
  }
@@ -8,6 +8,7 @@
8
8
  import chalk from 'chalk';
9
9
  import * as fs from 'fs';
10
10
  import * as path from 'path';
11
+ import { log, logError, processIO, type CommandIO, type CommandResult } from '../command-contract';
11
12
  import { walkFiles } from '../../utils/file-walk';
12
13
 
13
14
  export interface SpecBaselineCheckOptions {
@@ -333,13 +334,13 @@ function formatTable(results: PrerequisiteResult[]): string {
333
334
  export async function specBaselineCheck(
334
335
  specPath: string,
335
336
  options: SpecBaselineCheckOptions = {},
336
- ): Promise<void> {
337
+ io: CommandIO = processIO,
338
+ ): Promise<CommandResult> {
337
339
  // 验证文件存在
338
340
  const resolvedPath = path.resolve(specPath);
339
341
  if (!fs.existsSync(resolvedPath)) {
340
- console.error(chalk.red(`文件不存在: ${resolvedPath}`));
341
- process.exitCode = 1;
342
- return;
342
+ logError(io, chalk.red(`文件不存在: ${resolvedPath}`));
343
+ return { kind: 'usage-error', reason: `spec 文件不存在: ${resolvedPath}` };
343
344
  }
344
345
 
345
346
  const projectPath = options.projectPath || path.dirname(resolvedPath);
@@ -352,11 +353,11 @@ export async function specBaselineCheck(
352
353
 
353
354
  if (prerequisites.length === 0) {
354
355
  if (options.json) {
355
- console.log(JSON.stringify({ prerequisites: [], message: '未找到 Baseline / 前置条件 section' }, null, 2));
356
+ log(io, JSON.stringify({ prerequisites: [], message: '未找到 Baseline / 前置条件 section' }, null, 2));
356
357
  } else {
357
- console.log(chalk.yellow('未找到 ## Baseline 或 ## 前置条件 section'));
358
+ log(io, chalk.yellow('未找到 ## Baseline 或 ## 前置条件 section'));
358
359
  }
359
- return;
360
+ return { kind: 'skip', reason: '未找到 Baseline / 前置条件 section,无可判定项' };
360
361
  }
361
362
 
362
363
  // 验证每条前置条件
@@ -364,14 +365,18 @@ export async function specBaselineCheck(
364
365
 
365
366
  // 输出
366
367
  if (options.json) {
367
- console.log(JSON.stringify(results, null, 2));
368
+ log(io, JSON.stringify(results, null, 2));
368
369
  } else {
369
- console.log(formatTable(results));
370
+ log(io, formatTable(results));
370
371
  }
371
372
 
372
- // 有未满足的前置条件时 exit 1
373
+ // 有未满足的前置条件时非零退出
373
374
  const failed = results.filter(r => !r.satisfied);
374
375
  if (failed.length > 0) {
375
- process.exitCode = 1;
376
+ return {
377
+ kind: 'fail',
378
+ reason: `${failed.length} 条前置条件未满足: ${failed.map(f => f.prerequisite).join('; ')}`,
379
+ };
376
380
  }
381
+ return { kind: 'ok' };
377
382
  }
@@ -1,18 +1,22 @@
1
1
  /**
2
2
  * harness spec validate 命令
3
- *
3
+ *
4
4
  * 验证 Spec 文件格式
5
- *
5
+ *
6
6
  * 设计原则:
7
7
  * - 框架不包含具体 Schema 定义
8
8
  * - 项目需要定义自己的 Spec Schema
9
9
  * - 支持动态加载项目的 Schema
10
+ *
11
+ * 判定经返回值外溢(架构评审候选7):批量验证的失败计数译成 fail(含失败数),
12
+ * 无 Spec 文件译成 skip;单文件验证维持历史退出码面(无效仍为 0)。
10
13
  */
11
14
 
12
15
  import chalk from 'chalk';
13
16
  import * as path from 'path';
14
17
  import { SpecValidator, validateAllSpecs } from '../../core/spec/validator';
15
18
  import type { BatchSpecValidationResult, SpecValidationResult } from '../../types/spec';
19
+ import { log, processIO, type CommandIO, type CommandResult } from '../command-contract';
16
20
 
17
21
  export interface SpecValidateOptions {
18
22
  /** Schema 路径(项目定义) */
@@ -30,8 +34,11 @@ export interface SpecValidateOptions {
30
34
  /**
31
35
  * 执行 Spec 验证
32
36
  */
33
- export async function specValidate(options: SpecValidateOptions): Promise<void> {
34
- console.log(chalk.blue('📋 验证 Spec 文件...'));
37
+ export async function specValidate(
38
+ options: SpecValidateOptions,
39
+ io: CommandIO = processIO,
40
+ ): Promise<CommandResult> {
41
+ log(io, chalk.blue('📋 验证 Spec 文件...'));
35
42
 
36
43
  const projectPath = options.projectPath || process.cwd();
37
44
  const validator = SpecValidator.getInstance();
@@ -40,7 +47,7 @@ export async function specValidate(options: SpecValidateOptions): Promise<void>
40
47
  if (options.schema) {
41
48
  const absoluteSchemaPath = path.resolve(projectPath, options.schema);
42
49
  validator.setConfig({ schemaPath: absoluteSchemaPath });
43
- console.log(chalk.gray(`Schema 路径: ${absoluteSchemaPath}`));
50
+ log(io, chalk.gray(`Schema 路径: ${absoluteSchemaPath}`));
44
51
  }
45
52
 
46
53
  let result: BatchSpecValidationResult | SpecValidationResult;
@@ -48,59 +55,63 @@ export async function specValidate(options: SpecValidateOptions): Promise<void>
48
55
  // 单文件验证
49
56
  if (options.file) {
50
57
  const absoluteFilePath = path.resolve(projectPath, options.file);
51
- console.log(chalk.gray(`验证文件: ${absoluteFilePath}`));
58
+ log(io, chalk.gray(`验证文件: ${absoluteFilePath}`));
52
59
  result = await validator.validateFile(absoluteFilePath);
53
- printSingleResult(result, options.verbose);
54
- return;
60
+ printSingleResult(result, io, options.verbose);
61
+ return { kind: 'ok' };
55
62
  }
56
63
 
57
64
  // 批量验证
58
- console.log(chalk.gray(`项目路径: ${projectPath}`));
59
- console.log(chalk.gray(`仅暂存: ${options.staged ? '是' : '否'}`));
60
- console.log();
65
+ log(io, chalk.gray(`项目路径: ${projectPath}`));
66
+ log(io, chalk.gray(`仅暂存: ${options.staged ? '是' : '否'}`));
67
+ log(io);
61
68
 
62
69
  result = await validateAllSpecs(projectPath, options.staged);
63
70
 
64
71
  // 打印结果
65
- printBatchResult(result, options.verbose);
72
+ printBatchResult(result, io, options.verbose);
66
73
 
67
74
  // 根据失败级别决定退出码
68
75
  if (!options.staged && result.failed > 0) {
69
- process.exitCode = 1;
76
+ return { kind: 'fail', reason: `${result.failed} Spec 文件验证失败` };
70
77
  }
78
+ if (result.total === 0) {
79
+ return { kind: 'skip', reason: '没有找到 Spec 文件' };
80
+ }
81
+ return { kind: 'ok' };
71
82
  }
72
83
 
73
84
  /**
74
85
  * 打印单个文件验证结果
75
86
  */
76
- function printSingleResult(result: SpecValidationResult, verbose?: boolean): void {
87
+ function printSingleResult(result: SpecValidationResult, io: CommandIO, verbose?: boolean): void {
77
88
  if (result.valid) {
78
- console.log(chalk.green(`✅ ${result.file} 验证通过`));
89
+ log(io, chalk.green(`✅ ${result.file} 验证通过`));
79
90
  } else {
80
- console.log(chalk.red(`❌ ${result.file} 验证失败`));
91
+ log(io, chalk.red(`❌ ${result.file} 验证失败`));
81
92
  }
82
93
 
83
94
  if (result.errors.length > 0) {
84
- console.log();
85
- console.log(chalk.red('错误:'));
95
+ log(io);
96
+ log(io, chalk.red('错误:'));
86
97
  for (const error of result.errors) {
87
- console.log(chalk.red(` - ${error.path ? error.path + ': ' : ''}${error.message}`));
98
+ log(io, chalk.red(` - ${error.path ? error.path + ': ' : ''}${error.message}`));
88
99
  }
89
100
  }
90
101
 
91
102
  if (result.warnings.length > 0) {
92
- console.log();
93
- console.log(chalk.yellow('警告:'));
103
+ log(io);
104
+ log(io, chalk.yellow('警告:'));
94
105
  for (const warning of result.warnings) {
95
- console.log(chalk.yellow(` - ${warning.path ? warning.path + ': ' : ''}${warning.message}`));
106
+ log(io, chalk.yellow(` - ${warning.path ? warning.path + ': ' : ''}${warning.message}`));
96
107
  }
97
108
  }
98
109
 
99
110
  if (verbose && result.metrics) {
100
- console.log();
101
- console.log(chalk.gray('指标:'));
111
+ log(io);
112
+ log(io, chalk.gray('指标:'));
102
113
  for (const [key, value] of Object.entries(result.metrics)) {
103
- console.log(chalk.gray(` - ${key}: ${value}`));
114
+ log(io, chalk.gray(` - ${key}: ${value}`));
104
115
  }
105
116
  }
106
117
  }
@@ -108,51 +119,53 @@ function printSingleResult(result: SpecValidationResult, verbose?: boolean): voi
108
119
  /**
109
120
  * 打印批量验证结果
110
121
  */
111
- function printBatchResult(result: BatchSpecValidationResult, verbose?: boolean): void {
122
+ function printBatchResult(result: BatchSpecValidationResult, io: CommandIO, verbose?: boolean): void {
112
123
  // 汇总
113
- console.log(chalk.bold('验证结果:'));
114
- console.log(chalk.gray(` 总文件数: ${result.total}`));
115
- console.log(chalk.green(` 通过: ${result.passed}`));
116
- console.log(chalk.red(` 失败: ${result.failed}`));
117
- console.log(chalk.yellow(` 警告: ${result.warnings}`));
118
- console.log();
124
+ log(io, chalk.bold('验证结果:'));
125
+ log(io, chalk.gray(` 总文件数: ${result.total}`));
126
+ log(io, chalk.green(` 通过: ${result.passed}`));
127
+ log(io, chalk.red(` 失败: ${result.failed}`));
128
+ log(io, chalk.yellow(` 警告: ${result.warnings}`));
129
+ log(io);
119
130
 
120
131
  // 详细结果
121
132
  if (verbose || result.failed > 0) {
122
133
  for (const r of result.results) {
123
134
  if (!r.valid || verbose) {
124
- printSingleResult(r, verbose);
125
- console.log();
135
+ printSingleResult(r, io, verbose);
136
+ log(io);
126
137
  }
127
138
  }
128
139
  }
129
140
 
130
141
  // 成功提示
131
142
  if (result.failed === 0 && result.total > 0) {
132
- console.log(chalk.green('✅ 所有 Spec 文件验证通过'));
143
+ log(io, chalk.green('✅ 所有 Spec 文件验证通过'));
133
144
  } else if (result.total === 0) {
134
- console.log(chalk.gray('没有找到 Spec 文件,跳过验证'));
135
- console.log();
136
- console.log(chalk.gray('提示: Spec 文件包括:'));
137
- console.log(chalk.gray(' - ARCHITECTURE.md'));
138
- console.log(chalk.gray(' - specs/ 目录下的 .yml/.yaml 文件'));
139
- console.log();
140
- console.log(chalk.gray('要定义自己的 Schema,请在项目中创建:'));
141
- console.log(chalk.gray(' src/specs/schemas/index.ts'));
142
- console.log(chalk.gray(' 导出 validate 函数'));
145
+ log(io, chalk.gray('没有找到 Spec 文件,跳过验证'));
146
+ log(io);
147
+ log(io, chalk.gray('提示: Spec 文件包括:'));
148
+ log(io, chalk.gray(' - ARCHITECTURE.md'));
149
+ log(io, chalk.gray(' - specs/ 目录下的 .yml/.yaml 文件'));
150
+ log(io);
151
+ log(io, chalk.gray('要定义自己的 Schema,请在项目中创建:'));
152
+ log(io, chalk.gray(' src/specs/schemas/index.ts'));
153
+ log(io, chalk.gray(' 导出 validate 函数'));
143
154
  }
144
155
  }
145
156
 
146
157
  /**
147
158
  * 列出支持的 Spec 类型
148
159
  */
149
- export function listSpecTypes(): void {
150
- console.log(chalk.blue('📋 支持的 Spec 类型:'));
151
- console.log();
152
- console.log(' architecture - ARCHITECTURE.md 架构文档');
153
- console.log(' module - 模块定义(specs/modules/*.yml)');
154
- console.log(' api - API 定义(specs/apis/*.yml)');
155
- console.log(' custom - 自定义 Spec');
156
- console.log();
157
- console.log(chalk.gray('提示: 项目可以定义自己的 Schema 进行验证'));
160
+ /** 子命令实现一律以 (options) 调用;list 不消费验证选项,形参仅占位 */
161
+ export function listSpecTypes(_options: Partial<SpecValidateOptions> = {}, io: CommandIO = processIO): CommandResult {
162
+ log(io, chalk.blue('📋 支持的 Spec 类型:'));
163
+ log(io);
164
+ log(io, ' architecture - ARCHITECTURE.md 架构文档');
165
+ log(io, ' module - 模块定义(specs/modules/*.yml)');
166
+ log(io, ' api - API 定义(specs/apis/*.yml)');
167
+ log(io, ' custom - 自定义 Spec');
168
+ log(io);
169
+ log(io, chalk.gray('提示: 项目可以定义自己的 Schema 进行验证'));
170
+ return { kind: 'ok' };
158
171
  }