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