@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
@@ -43,12 +43,11 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
43
43
  Object.defineProperty(exports, "__esModule", { value: true });
44
44
  exports.knowledgeList = knowledgeList;
45
45
  exports.knowledgeSearch = knowledgeSearch;
46
+ exports.knowledgeSearchCommand = knowledgeSearchCommand;
46
47
  exports.knowledgeImport = knowledgeImport;
47
48
  exports.knowledgeDecay = knowledgeDecay;
48
49
  exports.knowledgeStats = knowledgeStats;
49
- exports.knowledgeUpsert = knowledgeUpsert;
50
50
  exports.knowledgeSyncRag = knowledgeSyncRag;
51
- exports.knowledgeSyncStatus = knowledgeSyncStatus;
52
51
  exports.knowledgeHealth = knowledgeHealth;
53
52
  exports.knowledgeAudit = knowledgeAudit;
54
53
  exports.knowledgeSnapshot = knowledgeSnapshot;
@@ -63,13 +62,15 @@ const query_1 = require("../../knowledge/query");
63
62
  const lifecycle_1 = require("../../knowledge/lifecycle");
64
63
  const import_1 = require("../../knowledge/import");
65
64
  const audit_1 = require("../../knowledge/audit");
65
+ const flywheel_metrics_1 = require("../../knowledge/flywheel-metrics");
66
66
  const migration_1 = require("../../knowledge/migration");
67
67
  const index_generator_1 = require("../../knowledge/index-generator");
68
+ const command_contract_1 = require("../command-contract");
68
69
  /**
69
70
  * 知识库列表
70
71
  */
71
- async function knowledgeList(options) {
72
- const store = new store_1.FileKnowledgeStore({ baseDir: getKnowledgeDir(options.projectPath) });
72
+ async function knowledgeList(options, io = command_contract_1.processIO) {
73
+ const store = new store_1.FileKnowledgeStore({ baseDir: getKnowledgeDir(options.projectPath, io) });
73
74
  const filter = { excludeArchived: false };
74
75
  if (options.type) {
75
76
  filter.types = options.type.split(',');
@@ -82,54 +83,72 @@ async function knowledgeList(options) {
82
83
  }
83
84
  const entries = store.list(filter);
84
85
  if (options.json) {
85
- console.log(JSON.stringify({ total: entries.length, entries }, null, 2));
86
- return;
86
+ (0, command_contract_1.log)(io, JSON.stringify({ total: entries.length, entries }, null, 2));
87
+ return { kind: 'ok' };
87
88
  }
88
89
  if (entries.length === 0) {
89
- console.log(chalk_1.default.yellow('知识库为空'));
90
- return;
90
+ (0, command_contract_1.log)(io, chalk_1.default.yellow('知识库为空'));
91
+ return { kind: 'ok' };
91
92
  }
92
- console.log(chalk_1.default.blue(`📚 知识库 (${entries.length} 条)\n`));
93
+ (0, command_contract_1.log)(io, chalk_1.default.blue(`📚 知识库 (${entries.length} 条)\n`));
93
94
  for (const entry of entries) {
94
95
  const maturityColor = entry.maturity === 'proven' ? chalk_1.default.green
95
96
  : entry.maturity === 'verified' ? chalk_1.default.cyan
96
97
  : entry.maturity === 'archived' ? chalk_1.default.gray
97
98
  : chalk_1.default.yellow;
98
- console.log(` ${maturityColor(`[${entry.maturity}]`)} ${chalk_1.default.bold(entry.title)}`);
99
- console.log(` ${chalk_1.default.gray(`id: ${entry.id} | type: ${entry.type} | layer: ${entry.layer}`)}`);
99
+ (0, command_contract_1.log)(io, ` ${maturityColor(`[${entry.maturity}]`)} ${chalk_1.default.bold(entry.title)}`);
100
+ (0, command_contract_1.log)(io, ` ${chalk_1.default.gray(`id: ${entry.id} | type: ${entry.type} | layer: ${entry.layer}`)}`);
100
101
  if (entry.tags.length > 0) {
101
- console.log(` ${chalk_1.default.gray(`tags: ${entry.tags.join(', ')}`)}`);
102
+ (0, command_contract_1.log)(io, ` ${chalk_1.default.gray(`tags: ${entry.tags.join(', ')}`)}`);
102
103
  }
103
104
  }
105
+ return { kind: 'ok' };
104
106
  }
105
107
  /**
106
108
  * 知识库搜索
107
109
  */
108
- async function knowledgeSearch(query, options) {
109
- const store = new store_1.FileKnowledgeStore({ baseDir: getKnowledgeDir(options.projectPath) });
110
+ async function knowledgeSearch(query, options, io = command_contract_1.processIO) {
111
+ const store = new store_1.FileKnowledgeStore({ baseDir: getKnowledgeDir(options.projectPath, io) });
110
112
  const queryEngine = new query_1.KnowledgeQuery(store);
111
113
  const matched = queryEngine.search(query, { limit: options.limit || 20 });
112
114
  if (options.json) {
113
- console.log(JSON.stringify({ query, total: matched.length, entries: matched }, null, 2));
114
- return;
115
+ (0, command_contract_1.log)(io, JSON.stringify({ query, total: matched.length, entries: matched }, null, 2));
116
+ return { kind: 'ok' };
115
117
  }
116
118
  if (matched.length === 0) {
117
- console.log(chalk_1.default.yellow(`未找到匹配 "${query}" 的知识条目`));
118
- return;
119
+ (0, command_contract_1.log)(io, chalk_1.default.yellow(`未找到匹配 "${query}" 的知识条目`));
120
+ return { kind: 'ok' };
119
121
  }
120
- console.log(chalk_1.default.blue(`🔍 搜索 "${query}" (${matched.length} 条结果)\n`));
122
+ (0, command_contract_1.log)(io, chalk_1.default.blue(`🔍 搜索 "${query}" (${matched.length} 条结果)\n`));
121
123
  for (const entry of matched) {
122
- console.log(` ${chalk_1.default.bold(entry.title)} ${chalk_1.default.gray(`[${entry.maturity}]`)}`);
124
+ (0, command_contract_1.log)(io, ` ${chalk_1.default.bold(entry.title)} ${chalk_1.default.gray(`[${entry.maturity}]`)}`);
123
125
  const preview = entry.content.slice(0, 100).replace(/\n/g, ' ');
124
- console.log(` ${chalk_1.default.gray(preview)}${entry.content.length > 100 ? '...' : ''}`);
126
+ (0, command_contract_1.log)(io, ` ${chalk_1.default.gray(preview)}${entry.content.length > 100 ? '...' : ''}`);
125
127
  }
128
+ return { kind: 'ok' };
129
+ }
130
+ /**
131
+ * knowledge search 子命令入口(候选7):缺参闸门 + limit 强转编组,
132
+ * 自 definitions.ts 的 args 复印块移回命令模块(interface/测试面所在)。
133
+ */
134
+ async function knowledgeSearchCommand(positionals, options, io = command_contract_1.processIO) {
135
+ const query = positionals[0];
136
+ if (!query) {
137
+ (0, command_contract_1.logError)(io, '请提供搜索关键词');
138
+ return { kind: 'usage-error', reason: 'knowledge search 缺少关键词位置参数' };
139
+ }
140
+ return knowledgeSearch(String(query), {
141
+ projectPath: options.projectPath,
142
+ json: options.json,
143
+ limit: parseInt(String(options.limit), 10),
144
+ });
126
145
  }
127
146
  /**
128
147
  * 知识库导入(冷启动)
129
148
  */
130
- async function knowledgeImport(options) {
149
+ async function knowledgeImport(options, io = command_contract_1.processIO) {
131
150
  const projectPath = options.projectPath || process.cwd();
132
- const store = new store_1.FileKnowledgeStore({ baseDir: getKnowledgeDir(options.projectPath) });
151
+ const store = new store_1.FileKnowledgeStore({ baseDir: getKnowledgeDir(options.projectPath, io) });
133
152
  const sources = options.sources
134
153
  ? options.sources.split(',')
135
154
  : ['code', 'git', 'docs'];
@@ -141,60 +160,62 @@ async function knowledgeImport(options) {
141
160
  if (options.reset) {
142
161
  importer.resetState();
143
162
  if (!options.json) {
144
- console.log(chalk_1.default.yellow('🔄 已重置导入状态'));
163
+ (0, command_contract_1.log)(io, chalk_1.default.yellow('🔄 已重置导入状态'));
145
164
  }
146
165
  }
147
166
  if (!options.json) {
148
- console.log(chalk_1.default.blue(`📥 开始导入知识 (源: ${sources.join(', ')})...`));
167
+ (0, command_contract_1.log)(io, chalk_1.default.blue(`📥 开始导入知识 (源: ${sources.join(', ')})...`));
149
168
  }
150
169
  const results = await importer.importAll();
151
170
  const totalImported = results.reduce((sum, r) => sum + r.entries.length, 0);
152
171
  const totalErrors = results.reduce((sum, r) => sum + r.errors.length, 0);
153
172
  if (options.json) {
154
- console.log(JSON.stringify({ totalImported, totalErrors, results }, null, 2));
155
- return;
173
+ (0, command_contract_1.log)(io, JSON.stringify({ totalImported, totalErrors, results }, null, 2));
174
+ return { kind: 'ok' };
156
175
  }
157
176
  for (const result of results) {
158
177
  if (result.entries.length > 0) {
159
- console.log(chalk_1.default.green(` ✅ ${result.source.type}: ${result.entries.length} 条`));
178
+ (0, command_contract_1.log)(io, chalk_1.default.green(` ✅ ${result.source.type}: ${result.entries.length} 条`));
160
179
  }
161
180
  if (result.errors.length > 0) {
162
181
  for (const err of result.errors) {
163
- console.log(chalk_1.default.red(` ❌ ${result.source.type}: ${err.message}`));
182
+ (0, command_contract_1.log)(io, chalk_1.default.red(` ❌ ${result.source.type}: ${err.message}`));
164
183
  }
165
184
  }
166
185
  }
167
- console.log(chalk_1.default.green(`\n✅ 导入完成: ${totalImported} 条,${totalErrors} 个错误`));
186
+ (0, command_contract_1.log)(io, chalk_1.default.green(`\n✅ 导入完成: ${totalImported} 条,${totalErrors} 个错误`));
187
+ return { kind: 'ok' };
168
188
  }
169
189
  /**
170
190
  * 知识库衰减周期
171
191
  */
172
- async function knowledgeDecay(options) {
173
- const store = new store_1.FileKnowledgeStore({ baseDir: getKnowledgeDir(options.projectPath) });
192
+ async function knowledgeDecay(options, io = command_contract_1.processIO) {
193
+ const store = new store_1.FileKnowledgeStore({ baseDir: getKnowledgeDir(options.projectPath, io) });
174
194
  const lifecycle = new lifecycle_1.KnowledgeLifecycle(store);
175
195
  if (!options.json) {
176
- console.log(chalk_1.default.blue('🔄 运行衰减周期...'));
196
+ (0, command_contract_1.log)(io, chalk_1.default.blue('🔄 运行衰减周期...'));
177
197
  }
178
198
  const changes = lifecycle.runDecayCycle();
179
199
  if (options.json) {
180
- console.log(JSON.stringify({ changes }, null, 2));
181
- return;
200
+ (0, command_contract_1.log)(io, JSON.stringify({ changes }, null, 2));
201
+ return { kind: 'ok' };
182
202
  }
183
203
  if (changes.length === 0) {
184
- console.log(chalk_1.default.green('✅ 没有需要衰减的知识条目'));
185
- return;
204
+ (0, command_contract_1.log)(io, chalk_1.default.green('✅ 没有需要衰减的知识条目'));
205
+ return { kind: 'ok' };
186
206
  }
187
- console.log(chalk_1.default.yellow(`📉 ${changes.length} 条知识发生衰减:\n`));
207
+ (0, command_contract_1.log)(io, chalk_1.default.yellow(`📉 ${changes.length} 条知识发生衰减:\n`));
188
208
  for (const change of changes) {
189
- console.log(` ${change.entryId}: ${chalk_1.default.red(change.from)} → ${chalk_1.default.green(change.to)}`);
190
- console.log(` ${chalk_1.default.gray(change.reason)}`);
209
+ (0, command_contract_1.log)(io, ` ${change.entryId}: ${chalk_1.default.red(change.from)} → ${chalk_1.default.green(change.to)}`);
210
+ (0, command_contract_1.log)(io, ` ${chalk_1.default.gray(change.reason)}`);
191
211
  }
212
+ return { kind: 'ok' };
192
213
  }
193
214
  /**
194
215
  * 知识库统计
195
216
  */
196
- async function knowledgeStats(options) {
197
- const store = new store_1.FileKnowledgeStore({ baseDir: getKnowledgeDir(options.projectPath) });
217
+ async function knowledgeStats(options, io = command_contract_1.processIO) {
218
+ const store = new store_1.FileKnowledgeStore({ baseDir: getKnowledgeDir(options.projectPath, io) });
198
219
  const entries = store.list({ excludeArchived: false });
199
220
  const active = entries.filter(e => e.maturity !== 'archived');
200
221
  const byType = {};
@@ -205,179 +226,78 @@ async function knowledgeStats(options) {
205
226
  byMaturity[entry.maturity] = (byMaturity[entry.maturity] || 0) + 1;
206
227
  byLayer[entry.layer] = (byLayer[entry.layer] || 0) + 1;
207
228
  }
208
- // D6 flywheel metrics
209
- const withRefs = active.filter(e => e.referencedBy.length > 0).length;
210
- const refCoverage = active.length > 0 ? Math.round(withRefs / active.length * 100) : 0;
211
- const avgRefs = active.length > 0
212
- ? Math.round(active.reduce((sum, e) => sum + e.referencedBy.length, 0) / active.length * 10) / 10
213
- : 0;
214
- let consumptionHitRate = 0;
229
+ // 飞轮指标:计算唯一实现在 knowledge/flywheel-metrics,此处只做 fs 读取 + 展示层单位映射
230
+ let dailyConsumptionEvents = 0;
215
231
  try {
216
232
  const statsPath = path.join(store.getBaseDir(), '.consumption-stats.json');
217
233
  if (fs.existsSync(statsPath)) {
218
234
  const stats = JSON.parse(fs.readFileSync(statsPath, 'utf-8'));
219
- const dailyEvents = stats.dailyEvents || 0;
220
- consumptionHitRate = active.length > 0 ? Math.min(Math.round(dailyEvents / active.length * 100), 100) : 0;
235
+ dailyConsumptionEvents = stats.dailyEvents || 0;
221
236
  }
222
237
  }
223
238
  catch { /* best-effort */ }
239
+ const metrics = (0, flywheel_metrics_1.evaluateFlywheel)({ entries: active, dailyConsumptionEvents });
240
+ const refCoverage = Math.round(metrics.refCoverage * 100);
241
+ const avgRefs = Math.round(metrics.avgRefs * 10) / 10;
242
+ const consumptionHitRate = Math.round(metrics.consumptionHitRate * 100);
224
243
  const flywheel = { refCoverage, avgRefs, consumptionHitRate };
225
244
  if (options.json) {
226
- console.log(JSON.stringify({ total: entries.length, byType, byMaturity, byLayer, flywheel }, null, 2));
227
- return;
245
+ (0, command_contract_1.log)(io, JSON.stringify({ total: entries.length, byType, byMaturity, byLayer, flywheel }, null, 2));
246
+ return { kind: 'ok' };
228
247
  }
229
- console.log(chalk_1.default.blue(`📊 知识库统计\n`));
230
- console.log(chalk_1.default.bold(` 总计: ${entries.length} 条 (活跃: ${active.length})\n`));
231
- console.log(chalk_1.default.bold(' 按类型:'));
248
+ (0, command_contract_1.log)(io, chalk_1.default.blue(`📊 知识库统计\n`));
249
+ (0, command_contract_1.log)(io, chalk_1.default.bold(` 总计: ${entries.length} 条 (活跃: ${active.length})\n`));
250
+ (0, command_contract_1.log)(io, chalk_1.default.bold(' 按类型:'));
232
251
  for (const [type, count] of Object.entries(byType)) {
233
- console.log(` ${type}: ${count}`);
252
+ (0, command_contract_1.log)(io, ` ${type}: ${count}`);
234
253
  }
235
- console.log(chalk_1.default.bold('\n 按成熟度:'));
254
+ (0, command_contract_1.log)(io, chalk_1.default.bold('\n 按成熟度:'));
236
255
  for (const [maturity, count] of Object.entries(byMaturity)) {
237
256
  const color = maturity === 'proven' ? chalk_1.default.green : maturity === 'archived' ? chalk_1.default.gray : chalk_1.default.yellow;
238
- console.log(` ${color(maturity)}: ${count}`);
257
+ (0, command_contract_1.log)(io, ` ${color(maturity)}: ${count}`);
239
258
  }
240
- console.log(chalk_1.default.bold('\n 按层级:'));
259
+ (0, command_contract_1.log)(io, chalk_1.default.bold('\n 按层级:'));
241
260
  for (const [layer, count] of Object.entries(byLayer)) {
242
- console.log(` ${layer}: ${count}`);
243
- }
244
- console.log(chalk_1.default.bold('\n 飞轮指标:'));
245
- console.log(` 引用覆盖: ${refCoverage}%`);
246
- console.log(` 平均引用: ${avgRefs}`);
247
- console.log(` 消费命中率: ${consumptionHitRate}%`);
248
- }
249
- /**
250
- * 设计时知识沉淀:写入 KnowledgeStore + 同步 Prisma Document(Studio UI 可见)
251
- *
252
- * 调用 Studio API POST /api/knowledge/upsert(内部端点,无 auth)
253
- */
254
- async function knowledgeUpsert(options) {
255
- const apiPort = process.env.API_PORT || '3001';
256
- const url = `http://localhost:${apiPort}/api/knowledge/upsert`;
257
- // Read content from file if --file specified
258
- let content = options.content || '';
259
- if (options.file && !content) {
260
- try {
261
- content = fs.readFileSync(options.file, 'utf-8');
262
- }
263
- catch (e) {
264
- console.error(chalk_1.default.red(`Failed to read file: ${options.file}`));
265
- console.error(chalk_1.default.red(String(e)));
266
- process.exit(1);
267
- }
268
- }
269
- if (!options.scope || !options.title || !content) {
270
- console.error(chalk_1.default.red('--scope, --title, and --content (or --file) are required'));
271
- process.exit(1);
272
- }
273
- try {
274
- const res = await fetch(url, {
275
- method: 'POST',
276
- headers: { 'Content-Type': 'application/json' },
277
- body: JSON.stringify({
278
- scope: options.scope,
279
- title: options.title,
280
- content,
281
- type: options.type || 'architecture',
282
- source: options.source || 'cli',
283
- }),
284
- });
285
- if (!res.ok) {
286
- const err = await res.json().catch(() => ({ error: res.statusText }));
287
- console.error(chalk_1.default.red(`API error ${res.status}: ${err.error || res.statusText}`));
288
- process.exit(1);
289
- }
290
- const result = await res.json();
291
- console.log(chalk_1.default.green(`✅ Knowledge upserted`));
292
- console.log(` KnowledgeStore: ${result.knowledgeStore?.action} → ${result.knowledgeStore?.entryId}`);
293
- console.log(` Studio UI: ${result.prismaDocument?.action} → ${result.prismaDocument?.docId || 'skipped'}`);
294
- }
295
- catch (e) {
296
- if (e?.code === 'ECONNREFUSED') {
297
- console.error(chalk_1.default.red(`Cannot reach Studio API at ${url}. Is the API running?`));
298
- }
299
- else {
300
- console.error(chalk_1.default.red(`Upsert failed: ${e.message}`));
301
- }
302
- process.exit(1);
261
+ (0, command_contract_1.log)(io, ` ${layer}: ${count}`);
303
262
  }
263
+ (0, command_contract_1.log)(io, chalk_1.default.bold('\n 飞轮指标:'));
264
+ (0, command_contract_1.log)(io, ` 引用覆盖: ${refCoverage}%`);
265
+ (0, command_contract_1.log)(io, ` 平均引用: ${avgRefs}`);
266
+ (0, command_contract_1.log)(io, ` 消费命中率: ${consumptionHitRate}%`);
267
+ return { kind: 'ok' };
304
268
  }
305
- /**
306
269
  /**
307
270
  * RAG 同步:扫描 .harness/knowledge-docs/ 输出需要 ingest 的文件列表
308
271
  */
309
- async function knowledgeSyncRag(options) {
272
+ async function knowledgeSyncRag(options, io = command_contract_1.processIO) {
310
273
  const projectPath = options.projectPath || process.cwd();
311
274
  const docsDir = `${projectPath}/.harness/knowledge-docs`;
312
275
  if (!fs.existsSync(docsDir)) {
313
- console.log(chalk_1.default.yellow('No .harness/knowledge-docs/ directory'));
314
- return;
276
+ (0, command_contract_1.log)(io, chalk_1.default.yellow('No .harness/knowledge-docs/ directory'));
277
+ return { kind: 'ok' };
315
278
  }
316
279
  const files = fs.readdirSync(docsDir).filter(f => f.endsWith('.md'));
317
280
  if (files.length === 0) {
318
- console.log(chalk_1.default.gray('No knowledge docs found'));
319
- return;
281
+ (0, command_contract_1.log)(io, chalk_1.default.gray('No knowledge docs found'));
282
+ return { kind: 'ok' };
320
283
  }
321
284
  if (options.json) {
322
- console.log(JSON.stringify({ directory: docsDir, files }, null, 2));
323
- return;
285
+ (0, command_contract_1.log)(io, JSON.stringify({ directory: docsDir, files }, null, 2));
286
+ return { kind: 'ok' };
324
287
  }
325
- console.log(chalk_1.default.blue(`📄 RAG sync candidates: ${files.length} files in ${docsDir}\n`));
288
+ (0, command_contract_1.log)(io, chalk_1.default.blue(`📄 RAG sync candidates: ${files.length} files in ${docsDir}\n`));
326
289
  for (const file of files) {
327
- console.log(chalk_1.default.cyan(` ${file}`));
328
- }
329
- console.log();
330
- console.log(chalk_1.default.gray('Run `mcp__local-rag__ingest_file` for each to sync to RAG'));
331
- }
332
- /**
333
- * 知识同步状态:检测所有 tracked scope 的新鲜度
334
- */
335
- async function knowledgeSyncStatus(options) {
336
- const apiPort = process.env.API_PORT || '3001';
337
- const url = `http://localhost:${apiPort}/api/knowledge/sync-status`;
338
- try {
339
- const res = await fetch(url);
340
- if (!res.ok) {
341
- const err = await res.json().catch(() => ({ error: res.statusText }));
342
- console.error(chalk_1.default.red(`API error ${res.status}: ${err.error || res.statusText}`));
343
- process.exit(1);
344
- }
345
- const data = await res.json();
346
- if (options.json) {
347
- console.log(JSON.stringify(data, null, 2));
348
- return;
349
- }
350
- console.log(chalk_1.default.blue(`🔄 KnowledgeSync Status\n`));
351
- console.log(chalk_1.default.bold(`Tracked scopes: ${data.trackedScopes?.join(', ') || 'none'}`));
352
- console.log(chalk_1.default.bold(`Stale entries: ${data.stale?.length || 0}`));
353
- if (data.stale?.length > 0) {
354
- console.log(chalk_1.default.yellow(`\n⚠️ Stale knowledge:\n`));
355
- for (const s of data.stale) {
356
- console.log(chalk_1.default.yellow(` ${s.scope} (${s.title}): ${s.stalenessHours}h old, files changed: ${s.changedFiles.join(', ')}`));
357
- }
358
- }
359
- else {
360
- console.log(chalk_1.default.green('\n✅ All knowledge fresh'));
361
- }
362
- if (data.healed?.length > 0) {
363
- console.log(chalk_1.default.cyan(`\n🩹 Auto-healed: ${data.healed.join(', ')}`));
364
- }
365
- }
366
- catch (e) {
367
- if (e?.code === 'ECONNREFUSED') {
368
- console.error(chalk_1.default.red(`Cannot reach Studio API at ${url}`));
369
- }
370
- else {
371
- console.error(chalk_1.default.red(`Sync check failed: ${e.message}`));
372
- }
373
- process.exit(1);
290
+ (0, command_contract_1.log)(io, chalk_1.default.cyan(` ${file}`));
374
291
  }
292
+ (0, command_contract_1.log)(io);
293
+ (0, command_contract_1.log)(io, chalk_1.default.gray('Run `mcp__local-rag__ingest_file` for each to sync to RAG'));
294
+ return { kind: 'ok' };
375
295
  }
376
296
  /**
377
297
  * 飞轮健康检查 — 零 token 检测知识飞轮数据流状态
378
298
  */
379
- async function knowledgeHealth(options) {
380
- const baseDir = options.dir || getKnowledgeDir(options.projectPath);
299
+ async function knowledgeHealth(options, io = command_contract_1.processIO) {
300
+ const baseDir = options.dir || getKnowledgeDir(options.projectPath, io);
381
301
  const store = new store_1.FileKnowledgeStore({ baseDir });
382
302
  const entries = store.list({ excludeArchived: true });
383
303
  const issues = [];
@@ -409,18 +329,16 @@ async function knowledgeHealth(options) {
409
329
  else {
410
330
  issues.push({ severity: 'info', entry: '-', detail: `消费追踪数据不存在(${statsPath})` });
411
331
  }
412
- // D4: 飞轮指标
413
- const withRefs = entries.filter(e => e.referencedBy.length > 0).length;
414
- const refCoverage = entries.length > 0 ? Math.round(withRefs / entries.length * 100) : 0;
415
- const avgRefs = entries.length > 0
416
- ? Math.round(entries.reduce((sum, e) => sum + e.referencedBy.length, 0) / entries.length * 10) / 10
417
- : 0;
332
+ // D4: 飞轮指标(计算唯一实现在 knowledge/flywheel-metrics;人口为本命令的 excludeArchived 切片)
333
+ const metrics = (0, flywheel_metrics_1.evaluateFlywheel)({ entries });
334
+ const refCoverage = Math.round(metrics.refCoverage * 100);
335
+ const avgRefs = Math.round(metrics.avgRefs * 10) / 10;
418
336
  // 健康分计算
419
337
  const totalIssues = issues.filter(i => i.severity === 'error').length * 3
420
338
  + issues.filter(i => i.severity === 'warn').length * 1;
421
339
  const healthScore = Math.max(0, 100 - totalIssues);
422
340
  if (options.json) {
423
- console.log(JSON.stringify({
341
+ (0, command_contract_1.log)(io, JSON.stringify({
424
342
  healthScore,
425
343
  summary: {
426
344
  total: entries.length,
@@ -432,36 +350,37 @@ async function knowledgeHealth(options) {
432
350
  },
433
351
  issues: issues.slice(0, 50),
434
352
  }, null, 2));
435
- return;
436
- }
437
- console.log(chalk_1.default.blue('🏥 飞轮健康检查\n'));
438
- console.log(chalk_1.default.bold(` 健康分: ${healthScore >= 80 ? chalk_1.default.green(healthScore) : healthScore >= 60 ? chalk_1.default.yellow(healthScore) : chalk_1.default.red(healthScore)}/100`));
439
- console.log(chalk_1.default.bold(` 活跃条目: ${entries.length}`));
440
- console.log();
441
- console.log(chalk_1.default.bold(' 数据流状态:'));
442
- console.log(` 引用密度: ${lowRefEntries === 0 ? chalk_1.default.green('✓') : chalk_1.default.yellow(`⚠ ${lowRefEntries} 个零引用 verified`)}`);
443
- console.log(` 新鲜度: ${staleEntries === 0 ? chalk_1.default.green('✓') : chalk_1.default.yellow(`⚠ ${staleEntries} 个过期 draft`)}`);
444
- console.log(` 消费追踪: ${consumptionData ? chalk_1.default.green('✓') : chalk_1.default.gray('○ 未启用')}`);
445
- console.log();
446
- console.log(chalk_1.default.bold(' 飞轮指标:'));
447
- console.log(` 引用覆盖: ${refCoverage}%`);
448
- console.log(` 平均引用: ${avgRefs}`);
449
- console.log();
353
+ return { kind: 'ok' };
354
+ }
355
+ (0, command_contract_1.log)(io, chalk_1.default.blue('🏥 飞轮健康检查\n'));
356
+ (0, command_contract_1.log)(io, chalk_1.default.bold(` 健康分: ${healthScore >= 80 ? chalk_1.default.green(healthScore) : healthScore >= 60 ? chalk_1.default.yellow(healthScore) : chalk_1.default.red(healthScore)}/100`));
357
+ (0, command_contract_1.log)(io, chalk_1.default.bold(` 活跃条目: ${entries.length}`));
358
+ (0, command_contract_1.log)(io);
359
+ (0, command_contract_1.log)(io, chalk_1.default.bold(' 数据流状态:'));
360
+ (0, command_contract_1.log)(io, ` 引用密度: ${lowRefEntries === 0 ? chalk_1.default.green('✓') : chalk_1.default.yellow(`⚠ ${lowRefEntries} 个零引用 verified`)}`);
361
+ (0, command_contract_1.log)(io, ` 新鲜度: ${staleEntries === 0 ? chalk_1.default.green('✓') : chalk_1.default.yellow(`⚠ ${staleEntries} 个过期 draft`)}`);
362
+ (0, command_contract_1.log)(io, ` 消费追踪: ${consumptionData ? chalk_1.default.green('✓') : chalk_1.default.gray('○ 未启用')}`);
363
+ (0, command_contract_1.log)(io);
364
+ (0, command_contract_1.log)(io, chalk_1.default.bold(' 飞轮指标:'));
365
+ (0, command_contract_1.log)(io, ` 引用覆盖: ${refCoverage}%`);
366
+ (0, command_contract_1.log)(io, ` 平均引用: ${avgRefs}`);
367
+ (0, command_contract_1.log)(io);
450
368
  if (issues.length > 0) {
451
- console.log(chalk_1.default.bold(` 问题 (前 20):`));
369
+ (0, command_contract_1.log)(io, chalk_1.default.bold(` 问题 (前 20):`));
452
370
  for (const issue of issues.slice(0, 20)) {
453
371
  const sevColor = issue.severity === 'error' ? chalk_1.default.red
454
372
  : issue.severity === 'warn' ? chalk_1.default.yellow
455
373
  : chalk_1.default.gray;
456
- console.log(` ${sevColor(`[${issue.severity}]`)} ${issue.entry}: ${issue.detail}`);
374
+ (0, command_contract_1.log)(io, ` ${sevColor(`[${issue.severity}]`)} ${issue.entry}: ${issue.detail}`);
457
375
  }
458
376
  if (issues.length > 20) {
459
- console.log(chalk_1.default.gray(` ... 还有 ${issues.length - 20} 条`));
377
+ (0, command_contract_1.log)(io, chalk_1.default.gray(` ... 还有 ${issues.length - 20} 条`));
460
378
  }
461
379
  }
462
380
  else {
463
- console.log(chalk_1.default.green(' ✓ 无问题'));
381
+ (0, command_contract_1.log)(io, chalk_1.default.green(' ✓ 无问题'));
464
382
  }
383
+ return { kind: 'ok' };
465
384
  }
466
385
  /** 缺省知识库数据根(相对用户 home) */
467
386
  const KNOWLEDGE_DATA_DIR = path.join('.harness', 'knowledge');
@@ -476,7 +395,7 @@ function hasKnowledgeData(dir) {
476
395
  return false;
477
396
  }
478
397
  }
479
- function getKnowledgeDir(projectPath) {
398
+ function getKnowledgeDir(projectPath, io) {
480
399
  if (projectPath)
481
400
  return `${projectPath}/.harness/knowledge`;
482
401
  if (process.env.KNOWLEDGE_BASE_DIR)
@@ -487,7 +406,7 @@ function getKnowledgeDir(projectPath) {
487
406
  if (!legacyKnowledgeDirNotified) {
488
407
  legacyKnowledgeDirNotified = true;
489
408
  // stderr:不污染 --json 的 stdout 输出
490
- console.error(chalk_1.default.yellow(`⚠ 缺省知识库根已改为 ${defaultDir};旧目录 ${legacyDir} 仍有数据,本次沿用(免迁移,可用 KNOWLEDGE_BASE_DIR 覆盖)`));
409
+ (0, command_contract_1.logError)(io, chalk_1.default.yellow(`⚠ 缺省知识库根已改为 ${defaultDir};旧目录 ${legacyDir} 仍有数据,本次沿用(免迁移,可用 KNOWLEDGE_BASE_DIR 覆盖)`));
491
410
  }
492
411
  return legacyDir;
493
412
  }
@@ -496,29 +415,29 @@ function getKnowledgeDir(projectPath) {
496
415
  /**
497
416
  * 知识库质量审计
498
417
  */
499
- async function knowledgeAudit(options) {
418
+ async function knowledgeAudit(options, io = command_contract_1.processIO) {
500
419
  const audit = new audit_1.KnowledgeAudit({
501
- baseDir: options.dir || getKnowledgeDir(options.projectPath),
420
+ baseDir: options.dir || getKnowledgeDir(options.projectPath, io),
502
421
  shortContentThreshold: options.threshold ? parseInt(options.threshold, 10) : undefined,
503
422
  });
504
423
  const isDryRun = options.dryRun && !options.fix;
505
424
  if (!options.json && !isDryRun) {
506
- console.log(chalk_1.default.blue('🔍 知识库质量审计...\n'));
425
+ (0, command_contract_1.log)(io, chalk_1.default.blue('🔍 知识库质量审计...\n'));
507
426
  }
508
427
  const report = audit.run({ autoFix: options.fix && !isDryRun });
509
428
  if (options.json) {
510
- console.log(JSON.stringify(report, null, 2));
511
- return;
429
+ (0, command_contract_1.log)(io, JSON.stringify(report, null, 2));
430
+ return { kind: 'ok' };
512
431
  }
513
432
  // Summary
514
- console.log(chalk_1.default.bold(` 总条目: ${report.totalEntries}`));
515
- console.log(chalk_1.default.bold(` 健康分: ${report.healthScore.before}/100`));
433
+ (0, command_contract_1.log)(io, chalk_1.default.bold(` 总条目: ${report.totalEntries}`));
434
+ (0, command_contract_1.log)(io, chalk_1.default.bold(` 健康分: ${report.healthScore.before}/100`));
516
435
  if (report.autoFixed > 0) {
517
- console.log(chalk_1.default.green(` 自动修复: ${report.autoFixed} 条`));
518
- console.log(chalk_1.default.bold(` 修复后: ${report.healthScore.after}/100`));
436
+ (0, command_contract_1.log)(io, chalk_1.default.green(` 自动修复: ${report.autoFixed} 条`));
437
+ (0, command_contract_1.log)(io, chalk_1.default.bold(` 修复后: ${report.healthScore.after}/100`));
519
438
  }
520
- console.log();
521
- // Dimension scores
439
+ (0, command_contract_1.log)(io);
440
+ // Dimension scores(Record 全键标注 → 编译期闭环,#109)
522
441
  const dimLabels = {
523
442
  structure: 'D1 结构完整性',
524
443
  content: 'D2 内容质量',
@@ -526,105 +445,95 @@ async function knowledgeAudit(options) {
526
445
  maturity: 'D4 成熟度健康',
527
446
  freshness: 'D5 新鲜度',
528
447
  flywheel: 'D6 飞轮验证',
448
+ incremental: 'D7 增量存活',
529
449
  };
530
- console.log(chalk_1.default.bold(' 维度评分:'));
450
+ (0, command_contract_1.log)(io, chalk_1.default.bold(' 维度评分:'));
531
451
  for (const [key, dim] of Object.entries(report.dimensions)) {
532
- const label = dimLabels[key] || key;
452
+ const label = dimLabels[key];
533
453
  const scoreColor = dim.score >= 80 ? chalk_1.default.green : dim.score >= 60 ? chalk_1.default.yellow : chalk_1.default.red;
534
- console.log(` ${label}: ${scoreColor(`${dim.score}/100`)} (${dim.issues} 问题)`);
535
- }
536
- console.log();
537
- // Issues by rule
538
- const ruleLabels = {
539
- 'frontmatter-missing': 'frontmatter 缺失',
540
- 'test-data-pollution': '测试数据污染',
541
- 'daily-audit-noise': '每日审计噪音',
542
- 'zero-content-proven': '零内容 proven',
543
- 'short-content': '短内容',
544
- 'maturity-inflation': '成熟度虚高',
545
- 'title-duplicate': '标题重复',
546
- 'source-refs-bloat': 'sourceReferences 膨胀',
547
- 'fragment-cluster': '碎片集群',
548
- 'promotion-blocked': 'promotion 受阻',
549
- 'orphan-draft': '孤儿 draft',
550
- 'stale-entry': '过期条目',
551
- };
454
+ (0, command_contract_1.log)(io, ` ${label}: ${scoreColor(`${dim.score}/100`)} (${dim.issues} 问题)`);
455
+ }
456
+ (0, command_contract_1.log)(io);
457
+ // Issues by rule(label 正本在 audit.ts 规则定义,AUDIT_RULE_LABELS 编译期闭环,#109)
552
458
  for (const [rule, count] of Object.entries(report.summary)) {
553
459
  if (count === 0)
554
460
  continue;
555
- const label = ruleLabels[rule] || rule;
556
- console.log(` ${chalk_1.default.red(`${label}: ${count}`)}`);
461
+ const label = audit_1.AUDIT_RULE_LABELS[rule];
462
+ (0, command_contract_1.log)(io, ` ${chalk_1.default.red(`${label}: ${count}`)}`);
557
463
  }
558
464
  // Detail (first 20)
559
465
  if (report.issues.length > 0) {
560
- console.log(chalk_1.default.bold(`\n 问题详情 (前 20 条):\n`));
466
+ (0, command_contract_1.log)(io, chalk_1.default.bold(`\n 问题详情 (前 20 条):\n`));
561
467
  for (const issue of report.issues.slice(0, 20)) {
562
468
  const severityColor = issue.severity === 'critical' ? chalk_1.default.red
563
469
  : issue.severity === 'high' ? chalk_1.default.yellow
564
470
  : chalk_1.default.gray;
565
- console.log(` ${severityColor(`[${issue.severity}]`)} ${issue.entryId}: ${issue.title}`);
566
- console.log(` ${chalk_1.default.gray(issue.detail)} → ${issue.action}`);
471
+ (0, command_contract_1.log)(io, ` ${severityColor(`[${issue.severity}]`)} ${issue.entryId}: ${issue.title}`);
472
+ (0, command_contract_1.log)(io, ` ${chalk_1.default.gray(issue.detail)} → ${issue.action}`);
567
473
  }
568
474
  if (report.issues.length > 20) {
569
- console.log(chalk_1.default.gray(`\n ... 还有 ${report.issues.length - 20} 条`));
475
+ (0, command_contract_1.log)(io, chalk_1.default.gray(`\n ... 还有 ${report.issues.length - 20} 条`));
570
476
  }
571
477
  }
572
478
  if (!options.fix && report.issues.length > 0) {
573
- console.log(chalk_1.default.yellow(`\n 使用 --fix 自动修复`));
479
+ (0, command_contract_1.log)(io, chalk_1.default.yellow(`\n 使用 --fix 自动修复`));
574
480
  }
575
481
  // Auto-rebuild index after audit (files may have changed)
576
- const baseDir = options.dir || getKnowledgeDir(options.projectPath);
482
+ const baseDir = options.dir || getKnowledgeDir(options.projectPath, io);
577
483
  const idxGen = new index_generator_1.KnowledgeIndexGenerator(baseDir);
578
484
  idxGen.regenerate();
579
485
  if (!options.json) {
580
- console.log(chalk_1.default.gray(` 📇 索引已重建`));
486
+ (0, command_contract_1.log)(io, chalk_1.default.gray(` 📇 索引已重建`));
581
487
  }
488
+ return { kind: 'ok' };
582
489
  }
583
490
  /**
584
491
  * 知识库快照(KR4 存活率追踪)
585
492
  */
586
- function knowledgeSnapshot(options) {
587
- const store = new store_1.FileKnowledgeStore({ baseDir: options.dir || getKnowledgeDir(options.projectPath) });
493
+ function knowledgeSnapshot(options, io = command_contract_1.processIO) {
494
+ const store = new store_1.FileKnowledgeStore({ baseDir: options.dir || getKnowledgeDir(options.projectPath, io) });
588
495
  const snapPath = store.snapshot();
589
496
  if (options.json) {
590
- console.log(JSON.stringify({ snapshotPath: snapPath }));
591
- return;
497
+ (0, command_contract_1.log)(io, JSON.stringify({ snapshotPath: snapPath }));
498
+ return { kind: 'ok' };
592
499
  }
593
- console.log(chalk_1.default.green(`✅ 快照已保存: ${snapPath}`));
500
+ (0, command_contract_1.log)(io, chalk_1.default.green(`✅ 快照已保存: ${snapPath}`));
501
+ return { kind: 'ok' };
594
502
  }
595
503
  /**
596
504
  * 知识库迁移 — 为现有条目添加 AS-021 新字段
597
505
  */
598
- function knowledgeMigrate(options) {
599
- const baseDir = options.dir || getKnowledgeDir(options.projectPath);
506
+ function knowledgeMigrate(options, io = command_contract_1.processIO) {
507
+ const baseDir = options.dir || getKnowledgeDir(options.projectPath, io);
600
508
  if (options.json) {
601
509
  const result = (0, migration_1.migrateKnowledgeEntries)(baseDir);
602
- console.log(JSON.stringify(result, null, 2));
603
- return;
510
+ (0, command_contract_1.log)(io, JSON.stringify(result, null, 2));
511
+ return { kind: 'ok' };
604
512
  }
605
- console.log(chalk_1.default.blue('🔄 迁移知识条目(添加 consumptionMode/origin 字段)\n'));
513
+ (0, command_contract_1.log)(io, chalk_1.default.blue('🔄 迁移知识条目(添加 consumptionMode/origin 字段)\n'));
606
514
  const result = (0, migration_1.migrateKnowledgeEntries)(baseDir);
607
- console.log(chalk_1.default.green(` 总计: ${result.total} 条`));
608
- console.log(chalk_1.default.green(` 已迁移: ${result.migrated} 条`));
609
- console.log(chalk_1.default.gray(` 已跳过: ${result.skipped} 条`));
515
+ (0, command_contract_1.log)(io, chalk_1.default.green(` 总计: ${result.total} 条`));
516
+ (0, command_contract_1.log)(io, chalk_1.default.green(` 已迁移: ${result.migrated} 条`));
517
+ (0, command_contract_1.log)(io, chalk_1.default.gray(` 已跳过: ${result.skipped} 条`));
610
518
  if (result.errors.length > 0) {
611
- console.log(chalk_1.default.red(`\n 错误: ${result.errors.length} 条`));
519
+ (0, command_contract_1.log)(io, chalk_1.default.red(`\n 错误: ${result.errors.length} 条`));
612
520
  for (const err of result.errors.slice(0, 5)) {
613
- console.log(chalk_1.default.red(` ${err}`));
521
+ (0, command_contract_1.log)(io, chalk_1.default.red(` ${err}`));
614
522
  }
615
523
  }
616
524
  if (result.migrated === 0 && result.errors.length === 0) {
617
- console.log(chalk_1.default.green('\n✅ 所有条目已是最新,无需迁移'));
525
+ (0, command_contract_1.log)(io, chalk_1.default.green('\n✅ 所有条目已是最新,无需迁移'));
618
526
  }
619
527
  else if (result.migrated > 0) {
620
- console.log(chalk_1.default.green(`\n✅ 迁移完成`));
528
+ (0, command_contract_1.log)(io, chalk_1.default.green(`\n✅ 迁移完成`));
621
529
  }
530
+ return { kind: 'ok' };
622
531
  }
623
532
  /**
624
533
  * 知识库索引重建 — 生成 _index.md 供 Agent grep 使用,同时同步 index.json
625
534
  */
626
- function knowledgeIndex(options) {
627
- const baseDir = options.dir || getKnowledgeDir(options.projectPath);
535
+ function knowledgeIndex(options, io = command_contract_1.processIO) {
536
+ const baseDir = options.dir || getKnowledgeDir(options.projectPath, io);
628
537
  const gen = new index_generator_1.KnowledgeIndexGenerator(baseDir);
629
538
  const beforeSize = (() => {
630
539
  const indexPath = path.join(baseDir, '_index.md');
@@ -637,20 +546,21 @@ function knowledgeIndex(options) {
637
546
  const afterSize = Buffer.byteLength(output, 'utf-8');
638
547
  const lineCount = output.split('\n').filter(l => !l.startsWith('#')).length;
639
548
  if (options.json) {
640
- console.log(JSON.stringify({
549
+ (0, command_contract_1.log)(io, JSON.stringify({
641
550
  path: path.join(baseDir, '_index.md'),
642
551
  entries: lineCount,
643
552
  size: afterSize,
644
553
  previousSize: beforeSize,
645
554
  }));
646
- return;
555
+ return { kind: 'ok' };
647
556
  }
648
- console.log(chalk_1.default.blue(`📇 索引已重建`));
649
- console.log(chalk_1.default.gray(` 路径: ${path.join(baseDir, '_index.md')}`));
650
- console.log(chalk_1.default.green(` 条目: ${lineCount}`));
651
- console.log(chalk_1.default.green(` 大小: ${(afterSize / 1024).toFixed(1)} KB`));
557
+ (0, command_contract_1.log)(io, chalk_1.default.blue(`📇 索引已重建`));
558
+ (0, command_contract_1.log)(io, chalk_1.default.gray(` 路径: ${path.join(baseDir, '_index.md')}`));
559
+ (0, command_contract_1.log)(io, chalk_1.default.green(` 条目: ${lineCount}`));
560
+ (0, command_contract_1.log)(io, chalk_1.default.green(` 大小: ${(afterSize / 1024).toFixed(1)} KB`));
652
561
  if (beforeSize > 0) {
653
- console.log(chalk_1.default.gray(` 旧大小: ${(beforeSize / 1024).toFixed(1)} KB`));
562
+ (0, command_contract_1.log)(io, chalk_1.default.gray(` 旧大小: ${(beforeSize / 1024).toFixed(1)} KB`));
654
563
  }
564
+ return { kind: 'ok' };
655
565
  }
656
566
  //# sourceMappingURL=knowledge.js.map