@dommaker/harness 1.6.0 → 1.8.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 (560) hide show
  1. package/CHANGELOG.md +52 -0
  2. package/bin/harness.js +17 -1
  3. package/dist/agents/index.d.ts +6 -2
  4. package/dist/agents/index.d.ts.map +1 -1
  5. package/dist/agents/index.js +6 -16
  6. package/dist/agents/index.js.map +1 -1
  7. package/dist/cli/commands/__tests__/gate-decision.d.ts +18 -0
  8. package/dist/cli/commands/__tests__/gate-decision.d.ts.map +1 -0
  9. package/dist/cli/commands/__tests__/gate-decision.js +26 -0
  10. package/dist/cli/commands/__tests__/gate-decision.js.map +1 -0
  11. package/dist/cli/commands/acceptance.d.ts.map +1 -1
  12. package/dist/cli/commands/acceptance.js +17 -28
  13. package/dist/cli/commands/acceptance.js.map +1 -1
  14. package/dist/cli/commands/check.d.ts +11 -3
  15. package/dist/cli/commands/check.d.ts.map +1 -1
  16. package/dist/cli/commands/check.js +26 -11
  17. package/dist/cli/commands/check.js.map +1 -1
  18. package/dist/cli/commands/command.d.ts +0 -1
  19. package/dist/cli/commands/command.d.ts.map +1 -1
  20. package/dist/cli/commands/command.js +8 -6
  21. package/dist/cli/commands/command.js.map +1 -1
  22. package/dist/cli/commands/constraints-retire.d.ts.map +1 -1
  23. package/dist/cli/commands/constraints-retire.js +36 -57
  24. package/dist/cli/commands/constraints-retire.js.map +1 -1
  25. package/dist/cli/commands/contract.d.ts.map +1 -1
  26. package/dist/cli/commands/contract.js +36 -42
  27. package/dist/cli/commands/contract.js.map +1 -1
  28. package/dist/cli/commands/definitions.d.ts +2 -0
  29. package/dist/cli/commands/definitions.d.ts.map +1 -1
  30. package/dist/cli/commands/definitions.js +11 -6
  31. package/dist/cli/commands/definitions.js.map +1 -1
  32. package/dist/cli/commands/failure.d.ts.map +1 -1
  33. package/dist/cli/commands/failure.js +16 -2
  34. package/dist/cli/commands/failure.js.map +1 -1
  35. package/dist/cli/commands/init.d.ts +14 -8
  36. package/dist/cli/commands/init.d.ts.map +1 -1
  37. package/dist/cli/commands/init.js +172 -364
  38. package/dist/cli/commands/init.js.map +1 -1
  39. package/dist/cli/commands/knowledge-view.d.ts +90 -0
  40. package/dist/cli/commands/knowledge-view.d.ts.map +1 -0
  41. package/dist/cli/commands/knowledge-view.js +198 -0
  42. package/dist/cli/commands/knowledge-view.js.map +1 -0
  43. package/dist/cli/commands/knowledge.d.ts +137 -52
  44. package/dist/cli/commands/knowledge.d.ts.map +1 -1
  45. package/dist/cli/commands/knowledge.js +534 -400
  46. package/dist/cli/commands/knowledge.js.map +1 -1
  47. package/dist/cli/commands/passes-gate.d.ts +4 -1
  48. package/dist/cli/commands/passes-gate.d.ts.map +1 -1
  49. package/dist/cli/commands/passes-gate.js +11 -2
  50. package/dist/cli/commands/passes-gate.js.map +1 -1
  51. package/dist/cli/commands/performance.d.ts.map +1 -1
  52. package/dist/cli/commands/performance.js +19 -31
  53. package/dist/cli/commands/performance.js.map +1 -1
  54. package/dist/cli/commands/report.d.ts.map +1 -1
  55. package/dist/cli/commands/report.js +2 -1
  56. package/dist/cli/commands/report.js.map +1 -1
  57. package/dist/cli/commands/review.d.ts.map +1 -1
  58. package/dist/cli/commands/review.js +13 -25
  59. package/dist/cli/commands/review.js.map +1 -1
  60. package/dist/cli/commands/scaffold-templates.d.ts +73 -0
  61. package/dist/cli/commands/scaffold-templates.d.ts.map +1 -0
  62. package/dist/cli/commands/scaffold-templates.js +424 -0
  63. package/dist/cli/commands/scaffold-templates.js.map +1 -0
  64. package/dist/cli/commands/scaffold.d.ts +105 -0
  65. package/dist/cli/commands/scaffold.d.ts.map +1 -0
  66. package/dist/cli/commands/scaffold.js +263 -0
  67. package/dist/cli/commands/scaffold.js.map +1 -0
  68. package/dist/cli/commands/security.d.ts.map +1 -1
  69. package/dist/cli/commands/security.js +22 -24
  70. package/dist/cli/commands/security.js.map +1 -1
  71. package/dist/cli/commands/spec-baseline-check.d.ts +43 -0
  72. package/dist/cli/commands/spec-baseline-check.d.ts.map +1 -1
  73. package/dist/cli/commands/spec-baseline-check.js +109 -34
  74. package/dist/cli/commands/spec-baseline-check.js.map +1 -1
  75. package/dist/cli/commands/sync-docs/context-syncer.d.ts +21 -2
  76. package/dist/cli/commands/sync-docs/context-syncer.d.ts.map +1 -1
  77. package/dist/cli/commands/sync-docs/context-syncer.js +112 -28
  78. package/dist/cli/commands/sync-docs/context-syncer.js.map +1 -1
  79. package/dist/cli/commands/sync-docs/index.d.ts +1 -1
  80. package/dist/cli/commands/sync-docs/index.d.ts.map +1 -1
  81. package/dist/cli/commands/sync-docs/index.js +86 -27
  82. package/dist/cli/commands/sync-docs/index.js.map +1 -1
  83. package/dist/cli/commands/sync-docs/project-reader.d.ts +24 -1
  84. package/dist/cli/commands/sync-docs/project-reader.d.ts.map +1 -1
  85. package/dist/cli/commands/sync-docs/project-reader.js +33 -7
  86. package/dist/cli/commands/sync-docs/project-reader.js.map +1 -1
  87. package/dist/cli/commands/validate.d.ts +0 -16
  88. package/dist/cli/commands/validate.d.ts.map +1 -1
  89. package/dist/cli/commands/validate.js +2 -97
  90. package/dist/cli/commands/validate.js.map +1 -1
  91. package/dist/cli/gate-command.d.ts +37 -0
  92. package/dist/cli/gate-command.d.ts.map +1 -0
  93. package/dist/cli/gate-command.js +64 -0
  94. package/dist/cli/gate-command.js.map +1 -0
  95. package/dist/completion-checkers/index.d.ts +1 -1
  96. package/dist/completion-checkers/index.d.ts.map +1 -1
  97. package/dist/completion-checkers/index.js +0 -15
  98. package/dist/completion-checkers/index.js.map +1 -1
  99. package/dist/context/knowledge-injector.d.ts +4 -2
  100. package/dist/context/knowledge-injector.d.ts.map +1 -1
  101. package/dist/context/knowledge-injector.js +13 -6
  102. package/dist/context/knowledge-injector.js.map +1 -1
  103. package/dist/core/constraints/agent-prompt-renderer.js +2 -2
  104. package/dist/core/constraints/agent-prompt-renderer.js.map +1 -1
  105. package/dist/core/constraints/capabilities-reconcile.d.ts +20 -0
  106. package/dist/core/constraints/capabilities-reconcile.d.ts.map +1 -1
  107. package/dist/core/constraints/capabilities-reconcile.js +26 -4
  108. package/dist/core/constraints/capabilities-reconcile.js.map +1 -1
  109. package/dist/core/constraints/check-cache.d.ts +1 -1
  110. package/dist/core/constraints/check-cache.js +1 -1
  111. package/dist/core/constraints/checker.d.ts +8 -3
  112. package/dist/core/constraints/checker.d.ts.map +1 -1
  113. package/dist/core/constraints/checker.js +30 -19
  114. package/dist/core/constraints/checker.js.map +1 -1
  115. package/dist/core/constraints/checkers/capability-sync.d.ts +3 -1
  116. package/dist/core/constraints/checkers/capability-sync.d.ts.map +1 -1
  117. package/dist/core/constraints/checkers/capability-sync.js +17 -24
  118. package/dist/core/constraints/checkers/capability-sync.js.map +1 -1
  119. package/dist/core/constraints/checkers/context-doc-sync.d.ts +1 -1
  120. package/dist/core/constraints/checkers/context-doc-sync.d.ts.map +1 -1
  121. package/dist/core/constraints/checkers/context-doc-sync.js +9 -6
  122. package/dist/core/constraints/checkers/context-doc-sync.js.map +1 -1
  123. package/dist/core/constraints/checkers/docs-freshness.d.ts.map +1 -1
  124. package/dist/core/constraints/checkers/docs-freshness.js +24 -30
  125. package/dist/core/constraints/checkers/docs-freshness.js.map +1 -1
  126. package/dist/core/constraints/checkers/governance-presence.d.ts.map +1 -1
  127. package/dist/core/constraints/checkers/governance-presence.js +10 -4
  128. package/dist/core/constraints/checkers/governance-presence.js.map +1 -1
  129. package/dist/core/constraints/checkers/types.d.ts +10 -6
  130. package/dist/core/constraints/checkers/types.d.ts.map +1 -1
  131. package/dist/core/constraints/checkers/types.js +7 -3
  132. package/dist/core/constraints/checkers/types.js.map +1 -1
  133. package/dist/core/constraints/context-builder.d.ts +11 -10
  134. package/dist/core/constraints/context-builder.d.ts.map +1 -1
  135. package/dist/core/constraints/context-builder.js +31 -27
  136. package/dist/core/constraints/context-builder.js.map +1 -1
  137. package/dist/core/constraints/context-reconcile.d.ts +75 -0
  138. package/dist/core/constraints/context-reconcile.d.ts.map +1 -0
  139. package/dist/core/constraints/context-reconcile.js +161 -0
  140. package/dist/core/constraints/context-reconcile.js.map +1 -0
  141. package/dist/core/constraints/doc-freshness/runner.d.ts +7 -0
  142. package/dist/core/constraints/doc-freshness/runner.d.ts.map +1 -1
  143. package/dist/core/constraints/doc-freshness/runner.js +8 -3
  144. package/dist/core/constraints/doc-freshness/runner.js.map +1 -1
  145. package/dist/core/constraints/git-evidence.js +1 -1
  146. package/dist/core/constraints/git-evidence.js.map +1 -1
  147. package/dist/core/constraints/injection-drift.d.ts +7 -2
  148. package/dist/core/constraints/injection-drift.d.ts.map +1 -1
  149. package/dist/core/constraints/injection-drift.js +13 -7
  150. package/dist/core/constraints/injection-drift.js.map +1 -1
  151. package/dist/core/constraints/run-env.d.ts +92 -0
  152. package/dist/core/constraints/run-env.d.ts.map +1 -0
  153. package/dist/core/constraints/run-env.js +175 -0
  154. package/dist/core/constraints/run-env.js.map +1 -0
  155. package/dist/core/constraints/triggers.d.ts +22 -0
  156. package/dist/core/constraints/triggers.d.ts.map +1 -0
  157. package/dist/core/constraints/triggers.js +31 -0
  158. package/dist/core/constraints/triggers.js.map +1 -0
  159. package/dist/core/effective-constraints.d.ts +13 -4
  160. package/dist/core/effective-constraints.d.ts.map +1 -1
  161. package/dist/core/effective-constraints.js +16 -6
  162. package/dist/core/effective-constraints.js.map +1 -1
  163. package/dist/core/effective-set.d.ts +8 -15
  164. package/dist/core/effective-set.d.ts.map +1 -1
  165. package/dist/core/effective-set.js +7 -12
  166. package/dist/core/effective-set.js.map +1 -1
  167. package/dist/core/index.d.ts +2 -1
  168. package/dist/core/index.d.ts.map +1 -1
  169. package/dist/core/index.js.map +1 -1
  170. package/dist/core/project-config-loader.d.ts +39 -17
  171. package/dist/core/project-config-loader.d.ts.map +1 -1
  172. package/dist/core/project-config-loader.js +51 -122
  173. package/dist/core/project-config-loader.js.map +1 -1
  174. package/dist/core/validators/check-handlers/http.d.ts +2 -2
  175. package/dist/core/validators/check-handlers/http.d.ts.map +1 -1
  176. package/dist/core/validators/check-handlers/http.js +12 -7
  177. package/dist/core/validators/check-handlers/http.js.map +1 -1
  178. package/dist/core/validators/index.d.ts +1 -1
  179. package/dist/core/validators/index.d.ts.map +1 -1
  180. package/dist/core/validators/passes-gate.d.ts.map +1 -1
  181. package/dist/core/validators/passes-gate.js +2 -2
  182. package/dist/core/validators/passes-gate.js.map +1 -1
  183. package/dist/failure/classifier.d.ts +1 -1
  184. package/dist/failure/classifier.d.ts.map +1 -1
  185. package/dist/failure/classifier.js +8 -8
  186. package/dist/failure/classifier.js.map +1 -1
  187. package/dist/failure/index.d.ts +2 -1
  188. package/dist/failure/index.d.ts.map +1 -1
  189. package/dist/failure/index.js +9 -17
  190. package/dist/failure/index.js.map +1 -1
  191. package/dist/failure/recorder.d.ts +1 -1
  192. package/dist/failure/recorder.d.ts.map +1 -1
  193. package/dist/gates/checker-gate.d.ts +2 -1
  194. package/dist/gates/checker-gate.d.ts.map +1 -1
  195. package/dist/gates/checker-gate.js +3 -2
  196. package/dist/gates/checker-gate.js.map +1 -1
  197. package/dist/gates/command.d.ts +10 -4
  198. package/dist/gates/command.d.ts.map +1 -1
  199. package/dist/gates/command.js +36 -62
  200. package/dist/gates/command.js.map +1 -1
  201. package/dist/gates/contract.d.ts.map +1 -1
  202. package/dist/gates/contract.js +0 -4
  203. package/dist/gates/contract.js.map +1 -1
  204. package/dist/gates/definitions.d.ts +2 -1
  205. package/dist/gates/definitions.d.ts.map +1 -1
  206. package/dist/gates/definitions.js +6 -5
  207. package/dist/gates/definitions.js.map +1 -1
  208. package/dist/gates/index.d.ts +0 -4
  209. package/dist/gates/index.d.ts.map +1 -1
  210. package/dist/gates/index.js +1 -6
  211. package/dist/gates/index.js.map +1 -1
  212. package/dist/gates/performance.d.ts.map +1 -1
  213. package/dist/gates/performance.js +0 -4
  214. package/dist/gates/performance.js.map +1 -1
  215. package/dist/gates/runner.d.ts +1 -1
  216. package/dist/gates/runner.js +1 -1
  217. package/dist/gates/security.d.ts +1 -1
  218. package/dist/gates/security.d.ts.map +1 -1
  219. package/dist/gates/security.js +5 -6
  220. package/dist/gates/security.js.map +1 -1
  221. package/dist/gates/types.d.ts +14 -17
  222. package/dist/gates/types.d.ts.map +1 -1
  223. package/dist/gates/types.js.map +1 -1
  224. package/dist/hooks/bootstrap.d.ts +6 -4
  225. package/dist/hooks/bootstrap.d.ts.map +1 -1
  226. package/dist/hooks/bootstrap.js +25 -13
  227. package/dist/hooks/bootstrap.js.map +1 -1
  228. package/dist/hooks/config.d.ts +6 -2
  229. package/dist/hooks/config.d.ts.map +1 -1
  230. package/dist/hooks/config.js +5 -1
  231. package/dist/hooks/config.js.map +1 -1
  232. package/dist/hooks/index.d.ts +1 -1
  233. package/dist/hooks/index.d.ts.map +1 -1
  234. package/dist/hooks/index.js +0 -15
  235. package/dist/hooks/index.js.map +1 -1
  236. package/dist/hooks/pipeline.d.ts.map +1 -1
  237. package/dist/hooks/pipeline.js +2 -4
  238. package/dist/hooks/pipeline.js.map +1 -1
  239. package/dist/hooks/registry.d.ts +11 -8
  240. package/dist/hooks/registry.d.ts.map +1 -1
  241. package/dist/hooks/registry.js +22 -7
  242. package/dist/hooks/registry.js.map +1 -1
  243. package/dist/hooks/types.d.ts +23 -7
  244. package/dist/hooks/types.d.ts.map +1 -1
  245. package/dist/index.d.ts +4 -4
  246. package/dist/index.d.ts.map +1 -1
  247. package/dist/index.js +3 -4
  248. package/dist/index.js.map +1 -1
  249. package/dist/knowledge/audit-scoring.d.ts +87 -0
  250. package/dist/knowledge/audit-scoring.d.ts.map +1 -0
  251. package/dist/knowledge/audit-scoring.js +470 -0
  252. package/dist/knowledge/audit-scoring.js.map +1 -0
  253. package/dist/knowledge/audit.d.ts +11 -59
  254. package/dist/knowledge/audit.d.ts.map +1 -1
  255. package/dist/knowledge/audit.js +47 -522
  256. package/dist/knowledge/audit.js.map +1 -1
  257. package/dist/knowledge/import.d.ts.map +1 -1
  258. package/dist/knowledge/import.js +2 -0
  259. package/dist/knowledge/import.js.map +1 -1
  260. package/dist/knowledge/index-generator.d.ts.map +1 -1
  261. package/dist/knowledge/index-generator.js +4 -5
  262. package/dist/knowledge/index-generator.js.map +1 -1
  263. package/dist/knowledge/index.d.ts +3 -2
  264. package/dist/knowledge/index.d.ts.map +1 -1
  265. package/dist/knowledge/index.js +3 -16
  266. package/dist/knowledge/index.js.map +1 -1
  267. package/dist/knowledge/ingest.js +1 -1
  268. package/dist/knowledge/ingest.js.map +1 -1
  269. package/dist/knowledge/lifecycle.d.ts.map +1 -1
  270. package/dist/knowledge/lifecycle.js +4 -2
  271. package/dist/knowledge/lifecycle.js.map +1 -1
  272. package/dist/knowledge/migration.d.ts +3 -0
  273. package/dist/knowledge/migration.d.ts.map +1 -1
  274. package/dist/knowledge/migration.js +8 -2
  275. package/dist/knowledge/migration.js.map +1 -1
  276. package/dist/knowledge/query.d.ts +6 -0
  277. package/dist/knowledge/query.d.ts.map +1 -1
  278. package/dist/knowledge/query.js +8 -2
  279. package/dist/knowledge/query.js.map +1 -1
  280. package/dist/knowledge/reference-tracker.d.ts.map +1 -1
  281. package/dist/knowledge/reference-tracker.js +4 -6
  282. package/dist/knowledge/reference-tracker.js.map +1 -1
  283. package/dist/knowledge/store.d.ts +22 -16
  284. package/dist/knowledge/store.d.ts.map +1 -1
  285. package/dist/knowledge/store.js +53 -12
  286. package/dist/knowledge/store.js.map +1 -1
  287. package/dist/knowledge/tree-walker.d.ts +19 -0
  288. package/dist/knowledge/tree-walker.d.ts.map +1 -0
  289. package/dist/knowledge/tree-walker.js +30 -0
  290. package/dist/knowledge/tree-walker.js.map +1 -0
  291. package/dist/knowledge/types.d.ts +16 -0
  292. package/dist/knowledge/types.d.ts.map +1 -1
  293. package/dist/monitoring/traces.d.ts +5 -3
  294. package/dist/monitoring/traces.d.ts.map +1 -1
  295. package/dist/monitoring/traces.js +19 -5
  296. package/dist/monitoring/traces.js.map +1 -1
  297. package/dist/test-setup/jsonl-fake-fs.d.ts +30 -0
  298. package/dist/test-setup/jsonl-fake-fs.d.ts.map +1 -0
  299. package/dist/test-setup/jsonl-fake-fs.js +49 -0
  300. package/dist/test-setup/jsonl-fake-fs.js.map +1 -0
  301. package/dist/tools/index.d.ts +4 -1
  302. package/dist/tools/index.d.ts.map +1 -1
  303. package/dist/tools/index.js +7 -15
  304. package/dist/tools/index.js.map +1 -1
  305. package/dist/types/checkpoint.d.ts +5 -0
  306. package/dist/types/checkpoint.d.ts.map +1 -1
  307. package/dist/types/passes-gate.d.ts +0 -13
  308. package/dist/types/passes-gate.d.ts.map +1 -1
  309. package/dist/types/project-config.d.ts +18 -0
  310. package/dist/types/project-config.d.ts.map +1 -1
  311. package/dist/types/trace.d.ts +13 -4
  312. package/dist/types/trace.d.ts.map +1 -1
  313. package/dist/types/trace.js +4 -3
  314. package/dist/types/trace.js.map +1 -1
  315. package/dist/utils/exec.d.ts +4 -27
  316. package/dist/utils/exec.d.ts.map +1 -1
  317. package/dist/utils/exec.js +4 -94
  318. package/dist/utils/exec.js.map +1 -1
  319. package/dist/utils/jsonl.d.ts +17 -7
  320. package/dist/utils/jsonl.d.ts.map +1 -1
  321. package/dist/utils/jsonl.js +144 -17
  322. package/dist/utils/jsonl.js.map +1 -1
  323. package/dist/utils/numeric-flag.d.ts +44 -0
  324. package/dist/utils/numeric-flag.d.ts.map +1 -0
  325. package/dist/utils/numeric-flag.js +62 -0
  326. package/dist/utils/numeric-flag.js.map +1 -0
  327. package/package.json +1 -1
  328. package/src/CONTEXT.md +5 -2
  329. package/src/__tests__/acceptance-gate.test.ts +7 -4
  330. package/src/__tests__/checker-extra.test.ts +3 -2
  331. package/src/__tests__/checker.test.ts +4 -3
  332. package/src/__tests__/checkpoint.test.ts +26 -9
  333. package/src/__tests__/context-files-resolution.test.ts +29 -15
  334. package/src/__tests__/contract-gate.test.ts +19 -40
  335. package/src/__tests__/error-classifier.test.ts +1 -1
  336. package/src/__tests__/exec.test.ts +45 -107
  337. package/src/__tests__/failure-recorder.test.ts +7 -5
  338. package/src/__tests__/hooks-pipeline.test.ts +34 -47
  339. package/src/__tests__/layering.test.ts +217 -25
  340. package/src/__tests__/passes-gate.test.ts +9 -4
  341. package/src/__tests__/performance-gate.test.ts +3 -15
  342. package/src/__tests__/project-config-loader-extra.test.ts +31 -57
  343. package/src/__tests__/project-config-loader.test.ts +6 -3
  344. package/src/__tests__/public-exports.test.ts +27 -6
  345. package/src/__tests__/public-type-surface.test.ts +360 -0
  346. package/src/__tests__/public-value-surface.test.ts +182 -0
  347. package/src/__tests__/review-gate.test.ts +4 -6
  348. package/src/__tests__/security-gate.test.ts +5 -20
  349. package/src/__tests__/skip-semantics.test.ts +5 -3
  350. package/src/__tests__/spec-validator.test.ts +3 -2
  351. package/src/__tests__/sub-barrels-explicit.test.ts +87 -0
  352. package/src/__tests__/test-fixture-hygiene.test.ts +53 -0
  353. package/src/__tests__/trace-analyzer-extra.test.ts +5 -3
  354. package/src/__tests__/trace-analyzer.test.ts +5 -3
  355. package/src/__tests__/trace-collector.test.ts +5 -3
  356. package/src/agents/index.ts +13 -2
  357. package/src/cli/__tests__/gate-command.test.ts +162 -0
  358. package/src/cli/commands/CONTEXT.md +29 -5
  359. package/src/cli/commands/__tests__/acceptance.test.ts +24 -25
  360. package/src/cli/commands/__tests__/bin-exit-mapping.test.ts +15 -0
  361. package/src/cli/commands/__tests__/check-drift.test.ts +42 -1
  362. package/src/cli/commands/__tests__/check-read-count.test.ts +167 -0
  363. package/src/cli/commands/__tests__/check-skip-output.test.ts +4 -1
  364. package/src/cli/commands/__tests__/check.test.ts +43 -36
  365. package/src/cli/commands/__tests__/command-gate-dead-options.test.ts +60 -0
  366. package/src/cli/commands/__tests__/command.test.ts +33 -17
  367. package/src/cli/commands/__tests__/constraints-retire.test.ts +52 -0
  368. package/src/cli/commands/__tests__/context-syncer.test.ts +141 -0
  369. package/src/cli/commands/__tests__/contract.test.ts +20 -20
  370. package/src/cli/commands/__tests__/failure.test.ts +5 -4
  371. package/src/cli/commands/__tests__/gate-decision.ts +30 -0
  372. package/src/cli/commands/__tests__/init-dead-options.test.ts +50 -0
  373. package/src/cli/commands/__tests__/init-governance-io.test.ts +139 -0
  374. package/src/cli/commands/__tests__/init-injection.test.ts +3 -3
  375. package/src/cli/commands/__tests__/init-ondisk.test.ts +867 -0
  376. package/src/cli/commands/__tests__/init.test.ts +82 -6
  377. package/src/cli/commands/__tests__/knowledge-audit-threshold.test.ts +146 -0
  378. package/src/cli/commands/__tests__/knowledge-flywheel-consistency.test.ts +1 -1
  379. package/src/cli/commands/__tests__/knowledge-tone-mapping.test.ts +244 -0
  380. package/src/cli/commands/__tests__/knowledge-view.test.ts +839 -0
  381. package/src/cli/commands/__tests__/knowledge.test.ts +33 -15
  382. package/src/cli/commands/__tests__/numeric-flag-assembly.test.ts +368 -0
  383. package/src/cli/commands/__tests__/passes-gate-dead-options.test.ts +89 -1
  384. package/src/cli/commands/__tests__/performance.test.ts +19 -21
  385. package/src/cli/commands/__tests__/posteval-plan.test.ts +5 -3
  386. package/src/cli/commands/__tests__/pre-push-hook.test.ts +181 -0
  387. package/src/cli/commands/__tests__/project-path-anchoring.test.ts +95 -2
  388. package/src/cli/commands/__tests__/project-path-convention.test.ts +103 -25
  389. package/src/cli/commands/__tests__/registry.test.ts +2 -0
  390. package/src/cli/commands/__tests__/report.test.ts +23 -1
  391. package/src/cli/commands/__tests__/review.test.ts +10 -17
  392. package/src/cli/commands/__tests__/scaffold.test.ts +505 -0
  393. package/src/cli/commands/__tests__/security-default-scan.test.ts +75 -0
  394. package/src/cli/commands/__tests__/security.test.ts +21 -24
  395. package/src/cli/commands/__tests__/spec-baseline-check.test.ts +3 -2
  396. package/src/cli/commands/__tests__/spec-baseline-index-cap.test.ts +131 -0
  397. package/src/cli/commands/__tests__/spec-baseline-read-count.test.ts +325 -0
  398. package/src/cli/commands/__tests__/sync-docs-agents.test.ts +19 -4
  399. package/src/cli/commands/__tests__/sync-docs-context-drift.test.ts +232 -0
  400. package/src/cli/commands/__tests__/sync-docs-module-order.test.ts +111 -0
  401. package/src/cli/commands/__tests__/sync-docs-read-count.test.ts +192 -0
  402. package/src/cli/commands/__tests__/sync-docs.test.ts +3 -2
  403. package/src/cli/commands/__tests__/validate.test.ts +1 -48
  404. package/src/cli/commands/acceptance.ts +24 -29
  405. package/src/cli/commands/check.ts +40 -17
  406. package/src/cli/commands/command.ts +9 -8
  407. package/src/cli/commands/constraints-retire.ts +57 -70
  408. package/src/cli/commands/contract.ts +44 -47
  409. package/src/cli/commands/definitions.ts +12 -6
  410. package/src/cli/commands/failure.ts +16 -3
  411. package/src/cli/commands/init.ts +242 -389
  412. package/src/cli/commands/knowledge-view.ts +224 -0
  413. package/src/cli/commands/knowledge.ts +643 -448
  414. package/src/cli/commands/passes-gate.ts +12 -3
  415. package/src/cli/commands/performance.ts +31 -38
  416. package/src/cli/commands/report.ts +3 -2
  417. package/src/cli/commands/review.ts +22 -28
  418. package/src/cli/commands/scaffold-templates.ts +406 -0
  419. package/src/cli/commands/scaffold.ts +302 -0
  420. package/src/cli/commands/security.ts +27 -23
  421. package/src/cli/commands/spec-baseline-check.ts +158 -33
  422. package/src/cli/commands/sync-docs/__tests__/context-export-surface.test.ts +102 -0
  423. package/src/cli/commands/sync-docs/__tests__/module-descriptions.test.ts +196 -0
  424. package/src/cli/commands/sync-docs/context-syncer.ts +137 -31
  425. package/src/cli/commands/sync-docs/index.ts +103 -28
  426. package/src/cli/commands/sync-docs/project-reader.ts +51 -7
  427. package/src/cli/commands/validate.ts +1 -104
  428. package/src/cli/gate-command.ts +87 -0
  429. package/src/completion-checkers/index.ts +10 -1
  430. package/src/context/CONTEXT.md +2 -1
  431. package/src/context/__tests__/knowledge-injector.test.ts +27 -0
  432. package/src/context/__tests__/session-manager.test.ts +19 -12
  433. package/src/context/knowledge-injector.ts +14 -7
  434. package/src/core/CONTEXT.md +10 -7
  435. package/src/core/__tests__/effective-set.test.ts +36 -60
  436. package/src/core/constraints/__tests__/context-reconcile.test.ts +246 -0
  437. package/src/core/constraints/__tests__/run-env.test.ts +377 -0
  438. package/src/core/constraints/__tests__/triggers.test.ts +70 -0
  439. package/src/core/constraints/agent-prompt-renderer.ts +1 -1
  440. package/src/core/constraints/capabilities-reconcile.ts +28 -4
  441. package/src/core/constraints/check-cache.ts +1 -1
  442. package/src/core/constraints/checker.ts +30 -14
  443. package/src/core/constraints/checkers/__tests__/context-doc-sync.test.ts +8 -3
  444. package/src/core/constraints/checkers/__tests__/governance-presence.test.ts +16 -7
  445. package/src/core/constraints/checkers/__tests__/no-hardcoded-credentials.test.ts +2 -1
  446. package/src/core/constraints/checkers/capability-sync.ts +27 -28
  447. package/src/core/constraints/checkers/context-doc-sync.ts +9 -7
  448. package/src/core/constraints/checkers/docs-freshness.ts +28 -33
  449. package/src/core/constraints/checkers/governance-presence.ts +10 -6
  450. package/src/core/constraints/checkers/types.ts +14 -8
  451. package/src/core/constraints/context-builder.ts +35 -26
  452. package/src/core/constraints/context-reconcile.ts +200 -0
  453. package/src/core/constraints/doc-freshness/__tests__/runner.test.ts +25 -0
  454. package/src/core/constraints/doc-freshness/runner.ts +18 -4
  455. package/src/core/constraints/git-evidence.ts +1 -1
  456. package/src/core/constraints/injection-drift.ts +19 -8
  457. package/src/core/constraints/run-env.ts +207 -0
  458. package/src/core/constraints/triggers.ts +33 -0
  459. package/src/core/effective-constraints.ts +17 -6
  460. package/src/core/effective-set.ts +8 -24
  461. package/src/core/index.ts +2 -1
  462. package/src/core/project-config-loader.ts +54 -102
  463. package/src/core/validators/__tests__/http-retry-sleep.test.ts +231 -0
  464. package/src/core/validators/check-handlers/http.ts +18 -7
  465. package/src/core/validators/index.ts +0 -1
  466. package/src/core/validators/passes-gate.ts +2 -3
  467. package/src/failure/CONTEXT.md +2 -1
  468. package/src/failure/classifier.ts +2 -2
  469. package/src/failure/index.ts +14 -2
  470. package/src/failure/recorder.ts +1 -1
  471. package/src/gates/CONTEXT.md +13 -7
  472. package/src/gates/__tests__/checker-gate.test.ts +1 -1
  473. package/src/gates/__tests__/command-single-predicate.test.ts +135 -0
  474. package/src/gates/__tests__/command.test.ts +8 -15
  475. package/src/gates/__tests__/contract.test.ts +5 -5
  476. package/src/gates/__tests__/gate-interface.test.ts +0 -17
  477. package/src/gates/__tests__/performance.test.ts +0 -13
  478. package/src/gates/__tests__/review.test.ts +0 -1
  479. package/src/gates/__tests__/runner.test.ts +1 -1
  480. package/src/gates/__tests__/security-default-scan.test.ts +97 -0
  481. package/src/gates/__tests__/security.test.ts +0 -13
  482. package/src/gates/checker-gate.ts +3 -2
  483. package/src/gates/command.ts +51 -74
  484. package/src/gates/contract.ts +0 -5
  485. package/src/gates/definitions.ts +6 -5
  486. package/src/gates/index.ts +0 -5
  487. package/src/gates/performance.ts +1 -6
  488. package/src/gates/runner.ts +1 -1
  489. package/src/gates/security.ts +9 -11
  490. package/src/gates/types.ts +20 -23
  491. package/src/hooks/CONTEXT.md +10 -9
  492. package/src/hooks/__tests__/bootstrap.test.ts +29 -6
  493. package/src/hooks/__tests__/pipeline.test.ts +28 -17
  494. package/src/hooks/__tests__/registry.test.ts +51 -3
  495. package/src/hooks/bootstrap.ts +35 -15
  496. package/src/hooks/config.ts +6 -2
  497. package/src/hooks/index.ts +10 -1
  498. package/src/hooks/pipeline.ts +4 -6
  499. package/src/hooks/registry.ts +31 -12
  500. package/src/hooks/types.ts +24 -7
  501. package/src/index.ts +1 -3
  502. package/src/knowledge/CONTEXT.md +14 -7
  503. package/src/knowledge/__tests__/audit-labels.test.ts +8 -5
  504. package/src/knowledge/__tests__/audit-scoring.test.ts +230 -0
  505. package/src/knowledge/__tests__/audit-write-count.test.ts +131 -0
  506. package/src/knowledge/__tests__/audit.test.ts +291 -208
  507. package/src/knowledge/__tests__/doctor.test.ts +3 -2
  508. package/src/knowledge/__tests__/ingest.test.ts +3 -2
  509. package/src/knowledge/__tests__/lifecycle.test.ts +57 -2
  510. package/src/knowledge/__tests__/migration.test.ts +35 -6
  511. package/src/knowledge/__tests__/query.test.ts +3 -2
  512. package/src/knowledge/__tests__/reference-tracker.test.ts +23 -2
  513. package/src/knowledge/__tests__/store.test.ts +149 -4
  514. package/src/knowledge/__tests__/tree-walker.test.ts +132 -0
  515. package/src/knowledge/audit-scoring.ts +589 -0
  516. package/src/knowledge/audit.ts +55 -599
  517. package/src/knowledge/import.ts +2 -0
  518. package/src/knowledge/index-generator.ts +4 -6
  519. package/src/knowledge/index.ts +27 -2
  520. package/src/knowledge/ingest.ts +1 -1
  521. package/src/knowledge/lifecycle.ts +5 -2
  522. package/src/knowledge/migration.ts +8 -2
  523. package/src/knowledge/query.ts +8 -1
  524. package/src/knowledge/reference-tracker.ts +5 -7
  525. package/src/knowledge/store.ts +75 -16
  526. package/src/knowledge/tree-walker.ts +29 -0
  527. package/src/knowledge/types.ts +19 -0
  528. package/src/monitoring/CONTEXT.md +5 -2
  529. package/src/monitoring/__tests__/context-tracker.test.ts +16 -8
  530. package/src/monitoring/__tests__/trace-file-anchoring.test.ts +80 -0
  531. package/src/monitoring/traces.ts +19 -5
  532. package/src/release/CONTEXT.md +1 -1
  533. package/src/release/__tests__/integrity.test.ts +21 -12
  534. package/src/test-setup/__tests__/jsonl-fake-fs.test.ts +98 -0
  535. package/src/test-setup/jsonl-fake-fs.ts +59 -0
  536. package/src/tools/index.ts +5 -1
  537. package/src/types/checkpoint.ts +6 -0
  538. package/src/types/passes-gate.ts +0 -17
  539. package/src/types/project-config.ts +21 -0
  540. package/src/types/trace.ts +14 -4
  541. package/src/utils/__tests__/file-walk.test.ts +3 -2
  542. package/src/utils/__tests__/jsonl-bounded-read.test.ts +106 -0
  543. package/src/utils/__tests__/jsonl-skip-disposition.test.ts +10 -6
  544. package/src/utils/__tests__/jsonl.test.ts +61 -14
  545. package/src/utils/__tests__/numeric-flag.test.ts +80 -0
  546. package/src/utils/__tests__/package-version.test.ts +2 -2
  547. package/src/utils/exec.ts +4 -64
  548. package/src/utils/jsonl.ts +159 -20
  549. package/src/utils/numeric-flag.ts +64 -0
  550. package/dist/failure/types.d.ts +0 -9
  551. package/dist/failure/types.d.ts.map +0 -1
  552. package/dist/failure/types.js +0 -25
  553. package/dist/failure/types.js.map +0 -1
  554. package/dist/gates/effective-gates.d.ts +0 -30
  555. package/dist/gates/effective-gates.d.ts.map +0 -1
  556. package/dist/gates/effective-gates.js +0 -81
  557. package/dist/gates/effective-gates.js.map +0 -1
  558. package/src/failure/types.ts +0 -9
  559. package/src/gates/__tests__/effective-gates.test.ts +0 -77
  560. package/src/gates/effective-gates.ts +0 -99
@@ -2,7 +2,10 @@
2
2
  /**
3
3
  * harness knowledge 命令
4
4
  *
5
- * 知识库管理:listsearchimportdecaystats
5
+ * 知识库管理 11 子操作(list/search/import/decay/stats/sync-rag/audit/snapshot/migrate/index/health)。
6
+ * 本文件只做「取数 + 声明两投影」:json 面正本在 `data`,人读排版在 `human()` 的
7
+ * display model。上色、label 映射、json/人读分派、退出码、路径解析与 store 构造
8
+ * 统一在 knowledge-view.ts(harness#133,架构评审候选4)。
6
9
  */
7
10
  var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
8
11
  if (k2 === undefined) k2 = k;
@@ -37,27 +40,32 @@ var __importStar = (this && this.__importStar) || (function () {
37
40
  return result;
38
41
  };
39
42
  })();
40
- var __importDefault = (this && this.__importDefault) || function (mod) {
41
- return (mod && mod.__esModule) ? mod : { "default": mod };
42
- };
43
43
  Object.defineProperty(exports, "__esModule", { value: true });
44
+ exports.knowledgeListView = knowledgeListView;
44
45
  exports.knowledgeList = knowledgeList;
46
+ exports.knowledgeSearchView = knowledgeSearchView;
45
47
  exports.knowledgeSearch = knowledgeSearch;
46
48
  exports.knowledgeSearchCommand = knowledgeSearchCommand;
49
+ exports.knowledgeImportView = knowledgeImportView;
47
50
  exports.knowledgeImport = knowledgeImport;
51
+ exports.knowledgeDecayView = knowledgeDecayView;
48
52
  exports.knowledgeDecay = knowledgeDecay;
53
+ exports.knowledgeStatsView = knowledgeStatsView;
49
54
  exports.knowledgeStats = knowledgeStats;
55
+ exports.knowledgeSyncRagView = knowledgeSyncRagView;
50
56
  exports.knowledgeSyncRag = knowledgeSyncRag;
51
- exports.knowledgeHealth = knowledgeHealth;
57
+ exports.knowledgeAuditView = knowledgeAuditView;
52
58
  exports.knowledgeAudit = knowledgeAudit;
59
+ exports.knowledgeSnapshotView = knowledgeSnapshotView;
53
60
  exports.knowledgeSnapshot = knowledgeSnapshot;
61
+ exports.knowledgeMigrateView = knowledgeMigrateView;
54
62
  exports.knowledgeMigrate = knowledgeMigrate;
63
+ exports.knowledgeIndexView = knowledgeIndexView;
55
64
  exports.knowledgeIndex = knowledgeIndex;
56
- const chalk_1 = __importDefault(require("chalk"));
65
+ exports.knowledgeHealthView = knowledgeHealthView;
66
+ exports.knowledgeHealth = knowledgeHealth;
57
67
  const fs = __importStar(require("fs"));
58
- const os = __importStar(require("os"));
59
68
  const path = __importStar(require("path"));
60
- const store_1 = require("../../knowledge/store");
61
69
  const query_1 = require("../../knowledge/query");
62
70
  const lifecycle_1 = require("../../knowledge/lifecycle");
63
71
  const import_1 = require("../../knowledge/import");
@@ -66,70 +74,98 @@ const flywheel_metrics_1 = require("../../knowledge/flywheel-metrics");
66
74
  const migration_1 = require("../../knowledge/migration");
67
75
  const index_generator_1 = require("../../knowledge/index-generator");
68
76
  const command_contract_1 = require("../command-contract");
69
- /**
70
- * 知识库列表
71
- */
72
- async function knowledgeList(options, io = command_contract_1.processIO) {
73
- const store = new store_1.FileKnowledgeStore({ baseDir: getKnowledgeDir(options.projectPath, io) });
77
+ const numeric_flag_1 = require("../../utils/numeric-flag");
78
+ const knowledge_view_1 = require("./knowledge-view");
79
+ // ========================================
80
+ // list
81
+ // ========================================
82
+ function listFilter(options) {
74
83
  const filter = { excludeArchived: false };
75
- if (options.type) {
84
+ if (options.type)
76
85
  filter.types = options.type.split(',');
77
- }
78
- if (options.maturity) {
86
+ if (options.maturity)
79
87
  filter.maturity = options.maturity.split(',');
80
- }
81
- if (options.tag) {
88
+ if (options.tag)
82
89
  filter.tags = options.tag.split(',');
83
- }
84
- const entries = store.list(filter);
85
- if (options.json) {
86
- (0, command_contract_1.log)(io, JSON.stringify({ total: entries.length, entries }, null, 2));
87
- return { kind: 'ok' };
88
- }
90
+ return filter;
91
+ }
92
+ function knowledgeListView(options, io) {
93
+ const entries = (0, knowledge_view_1.openKnowledgeStore)(options, io).list(listFilter(options));
94
+ const data = { total: entries.length, entries };
95
+ return { data, human: () => ({ sections: [{ rows: listRows(entries) }] }) };
96
+ }
97
+ function listRows(entries) {
89
98
  if (entries.length === 0) {
90
- (0, command_contract_1.log)(io, chalk_1.default.yellow('知识库为空'));
91
- return { kind: 'ok' };
92
- }
93
- (0, command_contract_1.log)(io, chalk_1.default.blue(`📚 知识库 (${entries.length} 条)\n`));
94
- for (const entry of entries) {
95
- const maturityColor = entry.maturity === 'proven' ? chalk_1.default.green
96
- : entry.maturity === 'verified' ? chalk_1.default.cyan
97
- : entry.maturity === 'archived' ? chalk_1.default.gray
98
- : chalk_1.default.yellow;
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}`)}`);
99
+ return [{ cells: [{ label: '知识库为空', tone: 'warn' }] }];
100
+ }
101
+ const rows = [
102
+ { cells: [
103
+ { label: '📚 知识库 (', tone: 'heading' },
104
+ { field: 'total', text: String(entries.length), tone: 'heading' },
105
+ { label: ' 条)', tone: 'heading' },
106
+ ] },
107
+ (0, knowledge_view_1.blankLine)(),
108
+ ];
109
+ entries.forEach((entry, i) => {
110
+ rows.push({ cells: [
111
+ { field: `entries.${i}.maturity`, text: ` [${entry.maturity}]`, tone: (0, knowledge_view_1.toneForMaturity)(entry.maturity) },
112
+ { field: `entries.${i}.title`, text: ` ${entry.title}`, tone: 'emph' },
113
+ ] });
114
+ rows.push({ cells: [
115
+ { field: `entries.${i}.id`, text: ` id: ${entry.id}`, tone: 'muted' },
116
+ { field: `entries.${i}.type`, text: ` | type: ${entry.type}`, tone: 'muted' },
117
+ { field: `entries.${i}.layer`, text: ` | layer: ${entry.layer}`, tone: 'muted' },
118
+ ] });
101
119
  if (entry.tags.length > 0) {
102
- (0, command_contract_1.log)(io, ` ${chalk_1.default.gray(`tags: ${entry.tags.join(', ')}`)}`);
120
+ rows.push({ cells: [{ field: `entries.${i}.tags`, text: ` tags: ${entry.tags.join(', ')}`, tone: 'muted' }] });
103
121
  }
104
- }
105
- return { kind: 'ok' };
122
+ });
123
+ return rows;
106
124
  }
107
- /**
108
- * 知识库搜索
109
- */
110
- async function knowledgeSearch(query, options, io = command_contract_1.processIO) {
111
- const store = new store_1.FileKnowledgeStore({ baseDir: getKnowledgeDir(options.projectPath, io) });
112
- const queryEngine = new query_1.KnowledgeQuery(store);
113
- const matched = queryEngine.search(query, { limit: options.limit || 20 });
114
- if (options.json) {
115
- (0, command_contract_1.log)(io, JSON.stringify({ query, total: matched.length, entries: matched }, null, 2));
116
- return { kind: 'ok' };
117
- }
125
+ async function knowledgeList(options, io = command_contract_1.processIO) {
126
+ return (0, knowledge_view_1.emitKnowledgeView)(io, options, knowledgeListView(options, io));
127
+ }
128
+ // ========================================
129
+ // search
130
+ // ========================================
131
+ function knowledgeSearchView(query, options, io) {
132
+ const store = (0, knowledge_view_1.openKnowledgeStore)(options, io);
133
+ const matched = new query_1.KnowledgeQuery(store).search(query, { limit: options.limit ?? 20 });
134
+ const data = { query, total: matched.length, entries: matched };
135
+ return { data, human: () => ({ sections: [{ rows: searchRows(query, matched) }] }) };
136
+ }
137
+ function searchRows(query, matched) {
118
138
  if (matched.length === 0) {
119
- (0, command_contract_1.log)(io, chalk_1.default.yellow(`未找到匹配 "${query}" 的知识条目`));
120
- return { kind: 'ok' };
121
- }
122
- (0, command_contract_1.log)(io, chalk_1.default.blue(`🔍 搜索 "${query}" (${matched.length} 条结果)\n`));
123
- for (const entry of matched) {
124
- (0, command_contract_1.log)(io, ` ${chalk_1.default.bold(entry.title)} ${chalk_1.default.gray(`[${entry.maturity}]`)}`);
125
- const preview = entry.content.slice(0, 100).replace(/\n/g, ' ');
126
- (0, command_contract_1.log)(io, ` ${chalk_1.default.gray(preview)}${entry.content.length > 100 ? '...' : ''}`);
127
- }
128
- return { kind: 'ok' };
139
+ return [{ cells: [{ label: `未找到匹配 "${query}" 的知识条目`, tone: 'warn' }] }];
140
+ }
141
+ const rows = [
142
+ { cells: [
143
+ { label: '🔍 搜索 "', tone: 'heading' },
144
+ { field: 'query', text: query, tone: 'heading' },
145
+ { label: '" (', tone: 'heading' },
146
+ { field: 'total', text: String(matched.length), tone: 'heading' },
147
+ { label: ' 条结果)', tone: 'heading' },
148
+ ] },
149
+ (0, knowledge_view_1.blankLine)(),
150
+ ];
151
+ matched.forEach((entry, i) => {
152
+ const preview = entry.content.slice(0, 100).replace(/\n/g, ' ') + (entry.content.length > 100 ? '...' : '');
153
+ rows.push({ cells: [
154
+ { field: `entries.${i}.title`, text: ` ${entry.title}`, tone: 'emph' },
155
+ { field: `entries.${i}.maturity`, text: ` [${entry.maturity}]`, tone: 'muted' },
156
+ ] });
157
+ rows.push({ cells: [{ field: `entries.${i}.content`, text: ` ${preview}`, tone: 'muted' }] });
158
+ });
159
+ return rows;
160
+ }
161
+ async function knowledgeSearch(query, options, io = command_contract_1.processIO) {
162
+ return (0, knowledge_view_1.emitKnowledgeView)(io, options, knowledgeSearchView(query, options, io));
129
163
  }
130
164
  /**
131
- * knowledge search 子命令入口(候选7):缺参闸门 + limit 强转编组,
165
+ * knowledge search 子命令入口(候选7):缺参闸门 + limit 装配窄化,
132
166
  * 自 definitions.ts 的 args 复印块移回命令模块(interface/测试面所在)。
167
+ * `--limit` 给到的恒是字符串(缺省 '20' 也是),脏输入 fail-loud(harness#154,
168
+ * 原先 parseInt 出 NaN 被下游 `|| 20` 静默兜成缺省量)。
133
169
  */
134
170
  async function knowledgeSearchCommand(positionals, options, io = command_contract_1.processIO) {
135
171
  const query = positionals[0];
@@ -137,85 +173,109 @@ async function knowledgeSearchCommand(positionals, options, io = command_contrac
137
173
  (0, command_contract_1.logError)(io, '请提供搜索关键词');
138
174
  return { kind: 'usage-error', reason: 'knowledge search 缺少关键词位置参数' };
139
175
  }
176
+ const limit = (0, numeric_flag_1.parseNumericFlag)(options.limit, 'int');
177
+ if (!limit.ok) {
178
+ (0, command_contract_1.logError)(io, (0, numeric_flag_1.numericFlagMessage)('--limit', limit.raw, 'int'));
179
+ return { kind: 'usage-error', reason: `knowledge search --limit 非法限制: "${limit.raw}"` };
180
+ }
140
181
  return knowledgeSearch(String(query), {
141
182
  projectPath: options.projectPath,
142
183
  json: options.json,
143
- limit: parseInt(String(options.limit), 10),
144
- });
184
+ limit: limit.value,
185
+ }, io);
145
186
  }
146
- /**
147
- * 知识库导入(冷启动)
148
- */
149
- async function knowledgeImport(options, io = command_contract_1.processIO) {
187
+ // ========================================
188
+ // import(冷启动)
189
+ // ========================================
190
+ async function knowledgeImportView(options, io) {
150
191
  const projectPath = options.projectPath || process.cwd();
151
- const store = new store_1.FileKnowledgeStore({ baseDir: getKnowledgeDir(options.projectPath, io) });
192
+ const store = (0, knowledge_view_1.openKnowledgeStore)(options, io);
152
193
  const sources = options.sources
153
194
  ? options.sources.split(',')
154
195
  : ['code', 'git', 'docs'];
155
- const importer = new import_1.ColdStartImporter({
156
- projectRoot: projectPath,
157
- store,
158
- sources,
159
- });
196
+ const importer = new import_1.ColdStartImporter({ projectRoot: projectPath, store, sources });
160
197
  if (options.reset) {
161
198
  importer.resetState();
162
- if (!options.json) {
163
- (0, command_contract_1.log)(io, chalk_1.default.yellow('🔄 已重置导入状态'));
164
- }
165
- }
166
- if (!options.json) {
167
- (0, command_contract_1.log)(io, chalk_1.default.blue(`📥 开始导入知识 (源: ${sources.join(', ')})...`));
199
+ (0, knowledge_view_1.announce)(io, options.json, '🔄 已重置导入状态', 'warn');
168
200
  }
201
+ (0, knowledge_view_1.announce)(io, options.json, `📥 开始导入知识 (源: ${sources.join(', ')})...`);
169
202
  const results = await importer.importAll();
170
- const totalImported = results.reduce((sum, r) => sum + r.entries.length, 0);
171
- const totalErrors = results.reduce((sum, r) => sum + r.errors.length, 0);
172
- if (options.json) {
173
- (0, command_contract_1.log)(io, JSON.stringify({ totalImported, totalErrors, results }, null, 2));
174
- return { kind: 'ok' };
175
- }
176
- for (const result of results) {
203
+ const data = {
204
+ totalImported: results.reduce((sum, r) => sum + r.entries.length, 0),
205
+ totalErrors: results.reduce((sum, r) => sum + r.errors.length, 0),
206
+ results,
207
+ };
208
+ return { data, human: () => ({ sections: [{ rows: importRows(data) }] }) };
209
+ }
210
+ function importRows(data) {
211
+ const rows = [];
212
+ data.results.forEach((result, i) => {
177
213
  if (result.entries.length > 0) {
178
- (0, command_contract_1.log)(io, chalk_1.default.green(` ✅ ${result.source.type}: ${result.entries.length} 条`));
214
+ rows.push({ cells: [
215
+ { field: `results.${i}.source.type`, text: ` ✅ ${result.source.type}: `, tone: 'ok' },
216
+ { field: `results.${i}.entries.length`, text: `${result.entries.length} 条`, tone: 'ok' },
217
+ ] });
179
218
  }
180
- if (result.errors.length > 0) {
181
- for (const err of result.errors) {
182
- (0, command_contract_1.log)(io, chalk_1.default.red(` ❌ ${result.source.type}: ${err.message}`));
183
- }
184
- }
185
- }
186
- (0, command_contract_1.log)(io, chalk_1.default.green(`\n✅ 导入完成: ${totalImported} 条,${totalErrors} 个错误`));
187
- return { kind: 'ok' };
219
+ result.errors.forEach((err, j) => {
220
+ rows.push({ cells: [
221
+ { field: `results.${i}.source.type`, text: ` ❌ ${result.source.type}: `, tone: 'error' },
222
+ { field: `results.${i}.errors.${j}.message`, text: err.message, tone: 'error' },
223
+ ] });
224
+ });
225
+ });
226
+ rows.push((0, knowledge_view_1.blankLine)(), { cells: [
227
+ { label: '✅ 导入完成: ', tone: 'ok' },
228
+ { field: 'totalImported', text: String(data.totalImported), tone: 'ok' },
229
+ { label: ' 条,', tone: 'ok' },
230
+ { field: 'totalErrors', text: String(data.totalErrors), tone: 'ok' },
231
+ { label: ' 个错误', tone: 'ok' },
232
+ ] });
233
+ return rows;
188
234
  }
189
- /**
190
- * 知识库衰减周期
191
- */
192
- async function knowledgeDecay(options, io = command_contract_1.processIO) {
193
- const store = new store_1.FileKnowledgeStore({ baseDir: getKnowledgeDir(options.projectPath, io) });
194
- const lifecycle = new lifecycle_1.KnowledgeLifecycle(store);
195
- if (!options.json) {
196
- (0, command_contract_1.log)(io, chalk_1.default.blue('🔄 运行衰减周期...'));
197
- }
235
+ async function knowledgeImport(options, io = command_contract_1.processIO) {
236
+ return (0, knowledge_view_1.emitKnowledgeView)(io, options, await knowledgeImportView(options, io));
237
+ }
238
+ // ========================================
239
+ // decay
240
+ // ========================================
241
+ function knowledgeDecayView(options, io) {
242
+ const lifecycle = new lifecycle_1.KnowledgeLifecycle((0, knowledge_view_1.openKnowledgeStore)(options, io));
243
+ (0, knowledge_view_1.announce)(io, options.json, '🔄 运行衰减周期...');
198
244
  const changes = lifecycle.runDecayCycle();
199
- if (options.json) {
200
- (0, command_contract_1.log)(io, JSON.stringify({ changes }, null, 2));
201
- return { kind: 'ok' };
202
- }
245
+ const data = { changes };
246
+ return { data, human: () => ({ sections: [{ rows: decayRows(changes) }] }) };
247
+ }
248
+ function decayRows(changes) {
203
249
  if (changes.length === 0) {
204
- (0, command_contract_1.log)(io, chalk_1.default.green('✅ 没有需要衰减的知识条目'));
205
- return { kind: 'ok' };
206
- }
207
- (0, command_contract_1.log)(io, chalk_1.default.yellow(`📉 ${changes.length} 条知识发生衰减:\n`));
208
- for (const change of changes) {
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)}`);
211
- }
212
- return { kind: 'ok' };
250
+ return [{ cells: [{ label: '✅ 没有需要衰减的知识条目', tone: 'ok' }] }];
251
+ }
252
+ const rows = [
253
+ { cells: [
254
+ { label: '📉 ', tone: 'warn' },
255
+ { field: 'changes.length', text: String(changes.length), tone: 'warn' },
256
+ { label: ' 条知识发生衰减:', tone: 'warn' },
257
+ ] },
258
+ (0, knowledge_view_1.blankLine)(),
259
+ ];
260
+ changes.forEach((change, i) => {
261
+ rows.push({ cells: [
262
+ { field: `changes.${i}.entryId`, text: ` ${change.entryId}: ` },
263
+ { field: `changes.${i}.from`, text: change.from, tone: 'error' },
264
+ { label: ' → ' },
265
+ { field: `changes.${i}.to`, text: change.to, tone: 'ok' },
266
+ ] });
267
+ rows.push({ cells: [{ field: `changes.${i}.reason`, text: ` ${change.reason}`, tone: 'muted' }] });
268
+ });
269
+ return rows;
213
270
  }
214
- /**
215
- * 知识库统计
216
- */
217
- async function knowledgeStats(options, io = command_contract_1.processIO) {
218
- const store = new store_1.FileKnowledgeStore({ baseDir: getKnowledgeDir(options.projectPath, io) });
271
+ async function knowledgeDecay(options, io = command_contract_1.processIO) {
272
+ return (0, knowledge_view_1.emitKnowledgeView)(io, options, knowledgeDecayView(options, io));
273
+ }
274
+ // ========================================
275
+ // stats
276
+ // ========================================
277
+ function knowledgeStatsView(options, io) {
278
+ const store = (0, knowledge_view_1.openKnowledgeStore)(options, io);
219
279
  const entries = store.list({ excludeArchived: false });
220
280
  const active = entries.filter(e => e.maturity !== 'archived');
221
281
  const byType = {};
@@ -237,68 +297,288 @@ async function knowledgeStats(options, io = command_contract_1.processIO) {
237
297
  }
238
298
  catch { /* best-effort */ }
239
299
  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);
243
- const flywheel = { refCoverage, avgRefs, consumptionHitRate };
244
- if (options.json) {
245
- (0, command_contract_1.log)(io, JSON.stringify({ total: entries.length, byType, byMaturity, byLayer, flywheel }, null, 2));
246
- return { kind: 'ok' };
300
+ const flywheel = {
301
+ refCoverage: Math.round(metrics.refCoverage * 100),
302
+ avgRefs: Math.round(metrics.avgRefs * 10) / 10,
303
+ consumptionHitRate: Math.round(metrics.consumptionHitRate * 100),
304
+ };
305
+ const data = { total: entries.length, byType, byMaturity, byLayer, flywheel };
306
+ const activeCount = active.length;
307
+ return {
308
+ data,
309
+ human: () => ({
310
+ sections: [
311
+ {
312
+ rows: [
313
+ { cells: [{ label: '📊 知识库统计', tone: 'heading' }] },
314
+ (0, knowledge_view_1.blankLine)(),
315
+ {
316
+ cells: [
317
+ { label: ' 总计: ', tone: 'emph' },
318
+ { field: 'total', text: String(data.total), tone: 'emph' },
319
+ { label: ' 条 (活跃: ', tone: 'emph' },
320
+ { derived: 'activeCount', text: String(activeCount), tone: 'emph' },
321
+ { label: ')', tone: 'emph' },
322
+ ],
323
+ },
324
+ (0, knowledge_view_1.blankLine)(),
325
+ ],
326
+ },
327
+ { title: ' 按类型:', rows: [...countRows('byType', byType), (0, knowledge_view_1.blankLine)()] },
328
+ {
329
+ title: ' 按成熟度:',
330
+ rows: [...Object.entries(byMaturity).map(([maturity, count]) => ({
331
+ cells: [
332
+ { field: `byMaturity.${maturity}`, text: ` ${maturity}`, tone: (0, knowledge_view_1.toneForMaturity)(maturity) },
333
+ { field: `byMaturity.${maturity}`, text: `: ${count}` },
334
+ ],
335
+ })), (0, knowledge_view_1.blankLine)()],
336
+ },
337
+ { title: ' 按层级:', rows: [...countRows('byLayer', byLayer), (0, knowledge_view_1.blankLine)()] },
338
+ {
339
+ title: ' 飞轮指标:',
340
+ rows: [
341
+ { cells: [{ label: ' 引用覆盖: ' }, { field: 'flywheel.refCoverage', text: `${flywheel.refCoverage}%` }] },
342
+ { cells: [{ label: ' 平均引用: ' }, { field: 'flywheel.avgRefs', text: String(flywheel.avgRefs) }] },
343
+ { cells: [{ label: ' 消费命中率: ' }, { field: 'flywheel.consumptionHitRate', text: `${flywheel.consumptionHitRate}%` }] },
344
+ ],
345
+ },
346
+ ],
347
+ }),
348
+ };
349
+ }
350
+ function countRows(field, counts) {
351
+ return Object.entries(counts).map(([key, count]) => ({
352
+ cells: [
353
+ { label: ' ' },
354
+ { field: `${field}.${key}`, text: `${key}: ${count}` },
355
+ ],
356
+ }));
357
+ }
358
+ async function knowledgeStats(options, io = command_contract_1.processIO) {
359
+ return (0, knowledge_view_1.emitKnowledgeView)(io, options, knowledgeStatsView(options, io));
360
+ }
361
+ // ========================================
362
+ // sync-rag
363
+ // ========================================
364
+ function knowledgeSyncRagView(options) {
365
+ const projectPath = options.projectPath || process.cwd();
366
+ const docsDir = `${projectPath}/.harness/knowledge-docs`;
367
+ const docsPresent = fs.existsSync(docsDir);
368
+ const files = docsPresent ? fs.readdirSync(docsDir).filter(f => f.endsWith('.md')) : [];
369
+ const data = { directory: docsDir, files };
370
+ return { data, human: () => ({ sections: [{ rows: syncRagRows(docsPresent, docsDir, files) }] }) };
371
+ }
372
+ function syncRagRows(docsPresent, docsDir, files) {
373
+ if (!docsPresent)
374
+ return [{ cells: [{ label: 'No .harness/knowledge-docs/ directory', tone: 'warn' }] }];
375
+ if (files.length === 0)
376
+ return [{ cells: [{ label: 'No knowledge docs found', tone: 'muted' }] }];
377
+ return [
378
+ { cells: [
379
+ { label: '📄 RAG sync candidates: ', tone: 'heading' },
380
+ { field: 'files.length', text: String(files.length), tone: 'heading' },
381
+ { label: ' files in ', tone: 'heading' },
382
+ { field: 'directory', text: docsDir, tone: 'heading' },
383
+ ] },
384
+ (0, knowledge_view_1.blankLine)(),
385
+ ...files.map((file, i) => ({ cells: [{ field: `files.${i}`, text: ` ${file}`, tone: 'accent' }] })),
386
+ (0, knowledge_view_1.blankLine)(),
387
+ { cells: [{ label: 'Run `mcp__local-rag__ingest_file` for each to sync to RAG', tone: 'muted' }] },
388
+ ];
389
+ }
390
+ async function knowledgeSyncRag(options, io = command_contract_1.processIO) {
391
+ return (0, knowledge_view_1.emitKnowledgeView)(io, options, knowledgeSyncRagView(options));
392
+ }
393
+ /**
394
+ * `--threshold` 的装配点窄化(harness#152):非负整数字符串 → 数值,转不出来即脏输入。
395
+ * `undefined` = 未传,落引擎缺省(50);`'0'` 是显式零值,不当「未传」兜掉。
396
+ * 判定规则正本是 `parseNumericFlag`(harness#154 统一解析器),此处保留 #152 的
397
+ * 函数面与报错文案(冻结测试钉死),只做委派。
398
+ */
399
+ function assembleShortContentThreshold(raw) {
400
+ return (0, numeric_flag_1.parseNumericFlag)(raw, 'int');
401
+ }
402
+ function knowledgeAuditView(options, io) {
403
+ const audit = new audit_1.KnowledgeAudit((0, knowledge_view_1.openKnowledgeStore)(options, io), {
404
+ shortContentThreshold: options.threshold,
405
+ });
406
+ const isDryRun = options.dryRun && !options.fix;
407
+ if (!isDryRun)
408
+ (0, knowledge_view_1.announce)(io, options.json, '🔍 知识库质量审计...\n');
409
+ const report = audit.run({ autoFix: options.fix && !isDryRun });
410
+ const showFixHint = !options.fix && report.issues.length > 0;
411
+ return {
412
+ data: report,
413
+ human: () => ({ sections: auditSections(report, showFixHint) }),
414
+ };
415
+ }
416
+ function auditSections(report, showFixHint) {
417
+ const sections = [{
418
+ rows: [
419
+ { cells: [{ label: ' 总条目: ', tone: 'emph' }, { field: 'totalEntries', text: String(report.totalEntries), tone: 'emph' }] },
420
+ { cells: [{ label: ' 健康分: ', tone: 'emph' }, { field: 'healthScore.before', text: `${report.healthScore.before}/100`, tone: 'emph' }] },
421
+ ],
422
+ }];
423
+ if (report.autoFixed > 0) {
424
+ sections[0].rows.push({ cells: [{ label: ' 自动修复: ', tone: 'ok' }, { field: 'autoFixed', text: String(report.autoFixed), tone: 'ok' }] }, { cells: [{ label: ' 修复后: ', tone: 'emph' }, { field: 'healthScore.after', text: `${report.healthScore.after}/100`, tone: 'emph' }] });
247
425
  }
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(' 按类型:'));
251
- for (const [type, count] of Object.entries(byType)) {
252
- (0, command_contract_1.log)(io, ` ${type}: ${count}`);
426
+ sections[0].rows.push((0, knowledge_view_1.blankLine)());
427
+ const dimensions = [];
428
+ for (const [key, dim] of Object.entries(report.dimensions)) {
429
+ dimensions.push({ cells: [
430
+ { field: `dimensions.${key}`, text: ` ${(0, knowledge_view_1.dimensionLabel)(key)}: ` },
431
+ { field: `dimensions.${key}.score`, text: `${dim.score}/100`, tone: (0, knowledge_view_1.toneForScore)(dim.score) },
432
+ { field: `dimensions.${key}.issues`, text: ` (${dim.issues} 问题)` },
433
+ ] });
434
+ }
435
+ dimensions.push((0, knowledge_view_1.blankLine)());
436
+ sections.push({ title: ' 维度评分:', rows: dimensions });
437
+ // 规则 label 正本在 audit.ts 的规则定义上(#109 编译期闭环经 ruleLabel 转发)
438
+ const rules = [];
439
+ for (const [rule, count] of Object.entries(report.summary)) {
440
+ if (count === 0)
441
+ continue;
442
+ rules.push({ cells: [{ field: `summary.${rule}`, text: ` ${(0, knowledge_view_1.ruleLabel)(rule)}: ${count}`, tone: 'error' }] });
253
443
  }
254
- (0, command_contract_1.log)(io, chalk_1.default.bold('\n 按成熟度:'));
255
- for (const [maturity, count] of Object.entries(byMaturity)) {
256
- const color = maturity === 'proven' ? chalk_1.default.green : maturity === 'archived' ? chalk_1.default.gray : chalk_1.default.yellow;
257
- (0, command_contract_1.log)(io, ` ${color(maturity)}: ${count}`);
444
+ if (report.issues.length > 0) {
445
+ rules.push((0, knowledge_view_1.blankLine)()); // 「问题详情」标题前的空行(原排版是 `\n` 前缀)
258
446
  }
259
- (0, command_contract_1.log)(io, chalk_1.default.bold('\n 按层级:'));
260
- for (const [layer, count] of Object.entries(byLayer)) {
261
- (0, command_contract_1.log)(io, ` ${layer}: ${count}`);
447
+ sections.push({ rows: rules });
448
+ if (report.issues.length > 0) {
449
+ const issues = [(0, knowledge_view_1.blankLine)()];
450
+ for (const [i, issue] of report.issues.slice(0, 20).entries()) {
451
+ issues.push({ cells: [
452
+ { field: `issues.${i}.severity`, text: ` [${issue.severity}]`, tone: (0, knowledge_view_1.toneForSeverity)(issue.severity) },
453
+ { field: `issues.${i}.entryId`, text: ` ${issue.entryId}: ` },
454
+ { field: `issues.${i}.title`, text: issue.title },
455
+ ] });
456
+ issues.push({ cells: [
457
+ { field: `issues.${i}.detail`, text: ` ${issue.detail}`, tone: 'muted' },
458
+ { label: ' → ' },
459
+ { field: `issues.${i}.action`, text: issue.action },
460
+ ] });
461
+ }
462
+ if (report.issues.length > 20) {
463
+ issues.push((0, knowledge_view_1.blankLine)(), { cells: [
464
+ { label: ' ... 还有 ', tone: 'muted' },
465
+ { field: 'issues.length', text: String(report.issues.length - 20), tone: 'muted' },
466
+ { label: ' 条', tone: 'muted' },
467
+ ] });
468
+ }
469
+ sections.push({ title: ' 问题详情 (前 20 条):', rows: issues });
262
470
  }
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' };
471
+ if (showFixHint) {
472
+ sections.push({ rows: [(0, knowledge_view_1.blankLine)(), { cells: [{ label: ' 使用 --fix 自动修复', tone: 'warn' }] }] });
473
+ }
474
+ return sections;
268
475
  }
269
- /**
270
- * RAG 同步:扫描 .harness/knowledge-docs/ 输出需要 ingest 的文件列表
271
- */
272
- async function knowledgeSyncRag(options, io = command_contract_1.processIO) {
273
- const projectPath = options.projectPath || process.cwd();
274
- const docsDir = `${projectPath}/.harness/knowledge-docs`;
275
- if (!fs.existsSync(docsDir)) {
276
- (0, command_contract_1.log)(io, chalk_1.default.yellow('No .harness/knowledge-docs/ directory'));
277
- return { kind: 'ok' };
476
+ async function knowledgeAudit(options, io = command_contract_1.processIO) {
477
+ const threshold = assembleShortContentThreshold(options.threshold);
478
+ if (!threshold.ok) {
479
+ (0, command_contract_1.logError)(io, `错误:--threshold 需要非负整数阈值(字符数),收到 "${threshold.raw}";短内容判定未执行`);
480
+ return { kind: 'usage-error', reason: `knowledge audit --threshold 非法阈值: "${threshold.raw}"` };
278
481
  }
279
- const files = fs.readdirSync(docsDir).filter(f => f.endsWith('.md'));
280
- if (files.length === 0) {
281
- (0, command_contract_1.log)(io, chalk_1.default.gray('No knowledge docs found'));
282
- return { kind: 'ok' };
482
+ const result = (0, knowledge_view_1.emitKnowledgeView)(io, options, knowledgeAuditView({ ...options, threshold: threshold.value }, io));
483
+ // 审计可能改文件,人读路径收尾重建索引;--json 保持不写盘(现状冻结,#133 不动这条策略)
484
+ if (!options.json) {
485
+ new index_generator_1.KnowledgeIndexGenerator((0, knowledge_view_1.resolveKnowledgeBaseDir)(options, io)).regenerate();
486
+ (0, knowledge_view_1.announce)(io, options.json, ' 📇 索引已重建', 'muted');
283
487
  }
284
- if (options.json) {
285
- (0, command_contract_1.log)(io, JSON.stringify({ directory: docsDir, files }, null, 2));
286
- return { kind: 'ok' };
488
+ return result;
489
+ }
490
+ // ========================================
491
+ // snapshot(KR4 存活率追踪)
492
+ // ========================================
493
+ function knowledgeSnapshotView(options, io) {
494
+ const snapshotPath = (0, knowledge_view_1.openKnowledgeStore)(options, io).snapshot();
495
+ const data = { snapshotPath };
496
+ return {
497
+ data,
498
+ human: () => ({
499
+ sections: [{
500
+ rows: [{
501
+ cells: [
502
+ { label: '✅ 快照已保存: ', tone: 'ok' },
503
+ { field: 'snapshotPath', text: snapshotPath, tone: 'ok' },
504
+ ],
505
+ }],
506
+ }],
507
+ }),
508
+ };
509
+ }
510
+ function knowledgeSnapshot(options, io = command_contract_1.processIO) {
511
+ return (0, knowledge_view_1.emitKnowledgeView)(io, options, knowledgeSnapshotView(options, io));
512
+ }
513
+ function knowledgeMigrateView(options, io) {
514
+ const result = (0, migration_1.migrateKnowledgeEntries)((0, knowledge_view_1.resolveKnowledgeBaseDir)(options, io));
515
+ return {
516
+ data: result,
517
+ human: () => ({ sections: [{ rows: migrateRows(result) }] }),
518
+ };
519
+ }
520
+ function migrateRows(result) {
521
+ const rows = [
522
+ { cells: [{ label: '🔄 迁移知识条目(添加 consumptionMode/origin 字段)', tone: 'heading' }] },
523
+ (0, knowledge_view_1.blankLine)(),
524
+ { cells: [{ label: ' 总计: ', tone: 'ok' }, { field: 'total', text: String(result.total), tone: 'ok' }, { label: ' 条', tone: 'ok' }] },
525
+ { cells: [{ label: ' 已迁移: ', tone: 'ok' }, { field: 'migrated', text: String(result.migrated), tone: 'ok' }, { label: ' 条', tone: 'ok' }] },
526
+ { cells: [{ label: ' 已跳过: ', tone: 'muted' }, { field: 'skipped', text: String(result.skipped), tone: 'muted' }, { label: ' 条', tone: 'muted' }] },
527
+ ];
528
+ if (result.errors.length > 0) {
529
+ rows.push((0, knowledge_view_1.blankLine)(), { cells: [{ label: ' 错误: ', tone: 'error' }, { field: 'errors.length', text: String(result.errors.length), tone: 'error' }, { label: ' 条', tone: 'error' }] });
530
+ result.errors.slice(0, 5).forEach((err, i) => {
531
+ rows.push({ cells: [{ label: ' ' }, { field: `errors.${i}`, text: err, tone: 'error' }] });
532
+ });
533
+ }
534
+ // 两种收尾语各自带一个前导空行;migrated=0 且有错误时历史上两句都不打
535
+ if (result.migrated === 0 && result.errors.length === 0) {
536
+ rows.push((0, knowledge_view_1.blankLine)(), { cells: [{ label: '✅ 所有条目已是最新,无需迁移', tone: 'ok' }] });
287
537
  }
288
- (0, command_contract_1.log)(io, chalk_1.default.blue(`📄 RAG sync candidates: ${files.length} files in ${docsDir}\n`));
289
- for (const file of files) {
290
- (0, command_contract_1.log)(io, chalk_1.default.cyan(` ${file}`));
538
+ else if (result.migrated > 0) {
539
+ rows.push((0, knowledge_view_1.blankLine)(), { cells: [{ label: '✅ 迁移完成', tone: 'ok' }] });
291
540
  }
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' };
541
+ return rows;
295
542
  }
296
- /**
297
- * 飞轮健康检查 token 检测知识飞轮数据流状态
298
- */
299
- async function knowledgeHealth(options, io = command_contract_1.processIO) {
300
- const baseDir = options.dir || getKnowledgeDir(options.projectPath, io);
301
- const store = new store_1.FileKnowledgeStore({ baseDir });
543
+ function knowledgeMigrate(options, io = command_contract_1.processIO) {
544
+ return (0, knowledge_view_1.emitKnowledgeView)(io, options, knowledgeMigrateView(options, io));
545
+ }
546
+ // ========================================
547
+ // index(重建 _index.md Agent grep,并同步 index.json)
548
+ // ========================================
549
+ function knowledgeIndexView(options, io) {
550
+ const baseDir = (0, knowledge_view_1.resolveKnowledgeBaseDir)(options, io);
551
+ const indexPath = path.join(baseDir, '_index.md');
552
+ const beforeSize = fs.existsSync(indexPath) ? fs.statSync(indexPath).size : 0;
553
+ const output = new index_generator_1.KnowledgeIndexGenerator(baseDir).regenerate();
554
+ // Sync index.json from disk files (removes ghost entries from manual mv/rm)
555
+ (0, knowledge_view_1.openKnowledgeStore)({ dir: baseDir }, io).rebuildIndex();
556
+ const afterSize = Buffer.byteLength(output, 'utf-8');
557
+ const lineCount = output.split('\n').filter(l => !l.startsWith('#')).length;
558
+ const data = { path: indexPath, entries: lineCount, size: afterSize, previousSize: beforeSize };
559
+ return {
560
+ data,
561
+ human: () => ({ sections: [{ rows: indexRows({ indexPath, afterSize, lineCount, beforeSize }) }] }),
562
+ };
563
+ }
564
+ function indexRows(shape) {
565
+ const rows = [
566
+ { cells: [{ label: '📇 索引已重建', tone: 'heading' }] },
567
+ { cells: [{ label: ' 路径: ', tone: 'muted' }, { field: 'path', text: shape.indexPath, tone: 'muted' }] },
568
+ { cells: [{ label: ' 条目: ', tone: 'ok' }, { field: 'entries', text: String(shape.lineCount), tone: 'ok' }] },
569
+ { cells: [{ label: ' 大小: ', tone: 'ok' }, { field: 'size', text: `${(shape.afterSize / 1024).toFixed(1)} KB`, tone: 'ok' }] },
570
+ ];
571
+ if (shape.beforeSize > 0) {
572
+ rows.push({ cells: [{ label: ' 旧大小: ', tone: 'muted' }, { field: 'previousSize', text: `${(shape.beforeSize / 1024).toFixed(1)} KB`, tone: 'muted' }] });
573
+ }
574
+ return rows;
575
+ }
576
+ function knowledgeIndex(options, io = command_contract_1.processIO) {
577
+ return (0, knowledge_view_1.emitKnowledgeView)(io, options, knowledgeIndexView(options, io));
578
+ }
579
+ function knowledgeHealthView(options, io) {
580
+ const store = (0, knowledge_view_1.openKnowledgeStore)(options, io);
581
+ const baseDir = store.getBaseDir();
302
582
  const entries = store.list({ excludeArchived: true });
303
583
  const issues = [];
304
584
  // D1: 引用密度检查(低引用 = 可能孤立)
@@ -321,246 +601,100 @@ async function knowledgeHealth(options, io = command_contract_1.processIO) {
321
601
  }
322
602
  }
323
603
  // D3: 消费数据检查
324
- let consumptionData = false;
325
604
  const statsPath = path.join(baseDir, '.consumption-stats.json');
326
- if (fs.existsSync(statsPath)) {
327
- consumptionData = true;
328
- }
329
- else {
605
+ const consumptionData = fs.existsSync(statsPath);
606
+ if (!consumptionData) {
330
607
  issues.push({ severity: 'info', entry: '-', detail: `消费追踪数据不存在(${statsPath})` });
331
608
  }
332
609
  // D4: 飞轮指标(计算唯一实现在 knowledge/flywheel-metrics;人口为本命令的 excludeArchived 切片)
333
610
  const metrics = (0, flywheel_metrics_1.evaluateFlywheel)({ entries });
334
611
  const refCoverage = Math.round(metrics.refCoverage * 100);
335
612
  const avgRefs = Math.round(metrics.avgRefs * 10) / 10;
336
- // 健康分计算
337
613
  const totalIssues = issues.filter(i => i.severity === 'error').length * 3
338
614
  + issues.filter(i => i.severity === 'warn').length * 1;
339
615
  const healthScore = Math.max(0, 100 - totalIssues);
340
- if (options.json) {
341
- (0, command_contract_1.log)(io, JSON.stringify({
342
- healthScore,
343
- summary: {
344
- total: entries.length,
345
- lowRefEntries,
346
- staleEntries,
347
- consumptionData,
348
- refCoverage,
349
- avgRefs,
350
- },
351
- issues: issues.slice(0, 50),
352
- }, null, 2));
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);
368
- if (issues.length > 0) {
369
- (0, command_contract_1.log)(io, chalk_1.default.bold(` 问题 (前 20):`));
370
- for (const issue of issues.slice(0, 20)) {
371
- const sevColor = issue.severity === 'error' ? chalk_1.default.red
372
- : issue.severity === 'warn' ? chalk_1.default.yellow
373
- : chalk_1.default.gray;
374
- (0, command_contract_1.log)(io, ` ${sevColor(`[${issue.severity}]`)} ${issue.entry}: ${issue.detail}`);
375
- }
376
- if (issues.length > 20) {
377
- (0, command_contract_1.log)(io, chalk_1.default.gray(` ... 还有 ${issues.length - 20} 条`));
378
- }
379
- }
380
- else {
381
- (0, command_contract_1.log)(io, chalk_1.default.green(' ✓ 无问题'));
382
- }
383
- return { kind: 'ok' };
384
- }
385
- /** 缺省知识库数据根(相对用户 home) */
386
- const KNOWLEDGE_DATA_DIR = path.join('.harness', 'knowledge');
387
- /** 旧缺省数据根(曾寄居 studio home),仍有数据时兼容沿用,免迁移 */
388
- const LEGACY_KNOWLEDGE_DATA_DIR = path.join('.studio', 'knowledge');
389
- let legacyKnowledgeDirNotified = false;
390
- function hasKnowledgeData(dir) {
391
- try {
392
- return fs.existsSync(dir) && fs.readdirSync(dir).length > 0;
393
- }
394
- catch {
395
- return false;
396
- }
397
- }
398
- function getKnowledgeDir(projectPath, io) {
399
- if (projectPath)
400
- return `${projectPath}/.harness/knowledge`;
401
- if (process.env.KNOWLEDGE_BASE_DIR)
402
- return process.env.KNOWLEDGE_BASE_DIR;
403
- const defaultDir = path.join(os.homedir(), KNOWLEDGE_DATA_DIR);
404
- const legacyDir = path.join(os.homedir(), LEGACY_KNOWLEDGE_DATA_DIR);
405
- if (hasKnowledgeData(legacyDir)) {
406
- if (!legacyKnowledgeDirNotified) {
407
- legacyKnowledgeDirNotified = true;
408
- // stderr:不污染 --json 的 stdout 输出
409
- (0, command_contract_1.logError)(io, chalk_1.default.yellow(`⚠ 缺省知识库根已改为 ${defaultDir};旧目录 ${legacyDir} 仍有数据,本次沿用(免迁移,可用 KNOWLEDGE_BASE_DIR 覆盖)`));
410
- }
411
- return legacyDir;
412
- }
413
- return defaultDir;
414
- }
415
- /**
416
- * 知识库质量审计
417
- */
418
- async function knowledgeAudit(options, io = command_contract_1.processIO) {
419
- const audit = new audit_1.KnowledgeAudit({
420
- baseDir: options.dir || getKnowledgeDir(options.projectPath, io),
421
- shortContentThreshold: options.threshold ? parseInt(options.threshold, 10) : undefined,
422
- });
423
- const isDryRun = options.dryRun && !options.fix;
424
- if (!options.json && !isDryRun) {
425
- (0, command_contract_1.log)(io, chalk_1.default.blue('🔍 知识库质量审计...\n'));
426
- }
427
- const report = audit.run({ autoFix: options.fix && !isDryRun });
428
- if (options.json) {
429
- (0, command_contract_1.log)(io, JSON.stringify(report, null, 2));
430
- return { kind: 'ok' };
431
- }
432
- // Summary
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`));
435
- if (report.autoFixed > 0) {
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`));
438
- }
439
- (0, command_contract_1.log)(io);
440
- // Dimension scores(Record 全键标注 → 编译期闭环,#109)
441
- const dimLabels = {
442
- structure: 'D1 结构完整性',
443
- content: 'D2 内容质量',
444
- dedup: 'D3 去重有效性',
445
- maturity: 'D4 成熟度健康',
446
- freshness: 'D5 新鲜度',
447
- flywheel: 'D6 飞轮验证',
448
- incremental: 'D7 增量存活',
616
+ const data = {
617
+ healthScore,
618
+ summary: { total: entries.length, lowRefEntries, staleEntries, consumptionData, refCoverage, avgRefs },
619
+ issues: issues.slice(0, 50),
449
620
  };
450
- (0, command_contract_1.log)(io, chalk_1.default.bold(' 维度评分:'));
451
- for (const [key, dim] of Object.entries(report.dimensions)) {
452
- const label = dimLabels[key];
453
- const scoreColor = dim.score >= 80 ? chalk_1.default.green : dim.score >= 60 ? chalk_1.default.yellow : chalk_1.default.red;
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)
458
- for (const [rule, count] of Object.entries(report.summary)) {
459
- if (count === 0)
460
- continue;
461
- const label = audit_1.AUDIT_RULE_LABELS[rule];
462
- (0, command_contract_1.log)(io, ` ${chalk_1.default.red(`${label}: ${count}`)}`);
463
- }
464
- // Detail (first 20)
465
- if (report.issues.length > 0) {
466
- (0, command_contract_1.log)(io, chalk_1.default.bold(`\n 问题详情 (前 20 条):\n`));
467
- for (const issue of report.issues.slice(0, 20)) {
468
- const severityColor = issue.severity === 'critical' ? chalk_1.default.red
469
- : issue.severity === 'high' ? chalk_1.default.yellow
470
- : chalk_1.default.gray;
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}`);
473
- }
474
- if (report.issues.length > 20) {
475
- (0, command_contract_1.log)(io, chalk_1.default.gray(`\n ... 还有 ${report.issues.length - 20} 条`));
476
- }
477
- }
478
- if (!options.fix && report.issues.length > 0) {
479
- (0, command_contract_1.log)(io, chalk_1.default.yellow(`\n 使用 --fix 自动修复`));
480
- }
481
- // Auto-rebuild index after audit (files may have changed)
482
- const baseDir = options.dir || getKnowledgeDir(options.projectPath, io);
483
- const idxGen = new index_generator_1.KnowledgeIndexGenerator(baseDir);
484
- idxGen.regenerate();
485
- if (!options.json) {
486
- (0, command_contract_1.log)(io, chalk_1.default.gray(` 📇 索引已重建`));
487
- }
488
- return { kind: 'ok' };
621
+ return { data, human: () => ({ sections: healthSections(data) }) };
489
622
  }
490
- /**
491
- * 知识库快照(KR4 存活率追踪)
492
- */
493
- function knowledgeSnapshot(options, io = command_contract_1.processIO) {
494
- const store = new store_1.FileKnowledgeStore({ baseDir: options.dir || getKnowledgeDir(options.projectPath, io) });
495
- const snapPath = store.snapshot();
496
- if (options.json) {
497
- (0, command_contract_1.log)(io, JSON.stringify({ snapshotPath: snapPath }));
498
- return { kind: 'ok' };
499
- }
500
- (0, command_contract_1.log)(io, chalk_1.default.green(`✅ 快照已保存: ${snapPath}`));
501
- return { kind: 'ok' };
623
+ function healthSections(data) {
624
+ const { healthScore, summary, issues } = data;
625
+ const scoreTone = (0, knowledge_view_1.toneForScore)(healthScore);
626
+ return [
627
+ {
628
+ rows: [
629
+ { cells: [{ label: '🏥 飞轮健康检查', tone: 'heading' }] },
630
+ (0, knowledge_view_1.blankLine)(),
631
+ { cells: [
632
+ { label: ' 健康分: ', tone: 'emph' },
633
+ { field: 'healthScore', text: String(healthScore), tone: scoreTone },
634
+ { label: '/100', tone: 'emph' },
635
+ ] },
636
+ { cells: [
637
+ { label: ' 活跃条目: ', tone: 'emph' },
638
+ { field: 'summary.total', text: String(summary.total), tone: 'emph' },
639
+ ] },
640
+ (0, knowledge_view_1.blankLine)(),
641
+ ],
642
+ },
643
+ {
644
+ title: ' 数据流状态:',
645
+ rows: [
646
+ densityRow(' 引用密度: ', 'summary.lowRefEntries', summary.lowRefEntries, ' 个零引用 verified'),
647
+ densityRow(' 新鲜度: ', 'summary.staleEntries', summary.staleEntries, ' 个过期 draft'),
648
+ { cells: [
649
+ { label: ' 消费追踪: ' },
650
+ summary.consumptionData
651
+ ? { label: '✓', tone: 'ok' }
652
+ : { field: 'summary.consumptionData', text: '○ 未启用', tone: 'muted' },
653
+ ] },
654
+ (0, knowledge_view_1.blankLine)(),
655
+ ],
656
+ },
657
+ {
658
+ title: ' 飞轮指标:',
659
+ rows: [
660
+ { cells: [{ label: ' 引用覆盖: ' }, { field: 'summary.refCoverage', text: `${summary.refCoverage}%` }] },
661
+ { cells: [{ label: ' 平均引用: ' }, { field: 'summary.avgRefs', text: String(summary.avgRefs) }] },
662
+ (0, knowledge_view_1.blankLine)(),
663
+ ],
664
+ },
665
+ {
666
+ title: ' 问题 (前 20):',
667
+ rows: issues.length === 0
668
+ ? [{ cells: [{ label: ' ✓ 无问题', tone: 'ok' }] }]
669
+ : [
670
+ ...issues.slice(0, 20).map((issue, i) => ({
671
+ cells: [
672
+ { field: `issues.${i}.severity`, text: ` [${issue.severity}]`, tone: (0, knowledge_view_1.toneForSeverity)(issue.severity) },
673
+ { field: `issues.${i}.entry`, text: ` ${issue.entry}: ` },
674
+ { field: `issues.${i}.detail`, text: issue.detail },
675
+ ],
676
+ })),
677
+ // 溢出计数取全量数组,而 json 面的 issues 已截 50 条 → 无字段可锚,登记派生量
678
+ ...(issues.length > 20
679
+ ? [{ cells: [{ derived: 'healthIssuesOverflow', text: ` ... 还有 ${issues.length - 20} 条`, tone: 'muted' }] }]
680
+ : []),
681
+ ],
682
+ },
683
+ ];
502
684
  }
503
- /**
504
- * 知识库迁移 — 为现有条目添加 AS-021 新字段
505
- */
506
- function knowledgeMigrate(options, io = command_contract_1.processIO) {
507
- const baseDir = options.dir || getKnowledgeDir(options.projectPath, io);
508
- if (options.json) {
509
- const result = (0, migration_1.migrateKnowledgeEntries)(baseDir);
510
- (0, command_contract_1.log)(io, JSON.stringify(result, null, 2));
511
- return { kind: 'ok' };
512
- }
513
- (0, command_contract_1.log)(io, chalk_1.default.blue('🔄 迁移知识条目(添加 consumptionMode/origin 字段)\n'));
514
- const result = (0, migration_1.migrateKnowledgeEntries)(baseDir);
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} 条`));
518
- if (result.errors.length > 0) {
519
- (0, command_contract_1.log)(io, chalk_1.default.red(`\n 错误: ${result.errors.length} 条`));
520
- for (const err of result.errors.slice(0, 5)) {
521
- (0, command_contract_1.log)(io, chalk_1.default.red(` ${err}`));
522
- }
523
- }
524
- if (result.migrated === 0 && result.errors.length === 0) {
525
- (0, command_contract_1.log)(io, chalk_1.default.green('\n✅ 所有条目已是最新,无需迁移'));
526
- }
527
- else if (result.migrated > 0) {
528
- (0, command_contract_1.log)(io, chalk_1.default.green(`\n✅ 迁移完成`));
529
- }
530
- return { kind: 'ok' };
685
+ function densityRow(prefix, field, count, suffix) {
686
+ if (count === 0)
687
+ return { cells: [{ label: prefix }, { label: '✓', tone: 'ok' }] };
688
+ return {
689
+ cells: [
690
+ { label: prefix },
691
+ { label: '⚠ ', tone: 'warn' },
692
+ { field, text: String(count), tone: 'warn' },
693
+ { label: suffix, tone: 'warn' },
694
+ ],
695
+ };
531
696
  }
532
- /**
533
- * 知识库索引重建 — 生成 _index.md Agent grep 使用,同时同步 index.json
534
- */
535
- function knowledgeIndex(options, io = command_contract_1.processIO) {
536
- const baseDir = options.dir || getKnowledgeDir(options.projectPath, io);
537
- const gen = new index_generator_1.KnowledgeIndexGenerator(baseDir);
538
- const beforeSize = (() => {
539
- const indexPath = path.join(baseDir, '_index.md');
540
- return fs.existsSync(indexPath) ? fs.statSync(indexPath).size : 0;
541
- })();
542
- const output = gen.regenerate();
543
- // Sync index.json from disk files (removes ghost entries from manual mv/rm)
544
- const store = new store_1.FileKnowledgeStore({ baseDir });
545
- store.rebuildIndex();
546
- const afterSize = Buffer.byteLength(output, 'utf-8');
547
- const lineCount = output.split('\n').filter(l => !l.startsWith('#')).length;
548
- if (options.json) {
549
- (0, command_contract_1.log)(io, JSON.stringify({
550
- path: path.join(baseDir, '_index.md'),
551
- entries: lineCount,
552
- size: afterSize,
553
- previousSize: beforeSize,
554
- }));
555
- return { kind: 'ok' };
556
- }
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`));
561
- if (beforeSize > 0) {
562
- (0, command_contract_1.log)(io, chalk_1.default.gray(` 旧大小: ${(beforeSize / 1024).toFixed(1)} KB`));
563
- }
564
- return { kind: 'ok' };
697
+ async function knowledgeHealth(options, io = command_contract_1.processIO) {
698
+ return (0, knowledge_view_1.emitKnowledgeView)(io, options, knowledgeHealthView(options, io));
565
699
  }
566
700
  //# sourceMappingURL=knowledge.js.map