akm-cli 0.9.0-rc.0 → 0.9.0-rc.13

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 (598) hide show
  1. package/CHANGELOG.md +1283 -22
  2. package/README.md +62 -37
  3. package/SECURITY.md +46 -31
  4. package/dist/akm +162 -38
  5. package/dist/akm-migrate +44 -0
  6. package/dist/assets/backends/schtasks-template.xml +2 -1
  7. package/dist/assets/hints/cli-hints-full.md +268 -118
  8. package/dist/assets/hints/cli-hints-short.md +87 -24
  9. package/dist/assets/{profiles → improve-strategies}/catchup.json +3 -1
  10. package/dist/assets/{profiles → improve-strategies}/consolidate.json +3 -1
  11. package/dist/assets/{profiles → improve-strategies}/default.json +6 -7
  12. package/dist/assets/improve-strategies/frequent.json +15 -0
  13. package/dist/assets/{profiles → improve-strategies}/graph-refresh.json +4 -2
  14. package/dist/assets/{profiles → improve-strategies}/memory-focus.json +4 -1
  15. package/dist/assets/{profiles → improve-strategies}/proactive-maintenance.json +5 -5
  16. package/dist/assets/{profiles → improve-strategies}/quick.json +4 -2
  17. package/dist/assets/improve-strategies/reflect-distill.json +30 -0
  18. package/dist/assets/{profiles → improve-strategies}/thorough.json +1 -1
  19. package/dist/assets/prompts/consolidate-system.md +5 -5
  20. package/dist/assets/prompts/extract-session.md +2 -6
  21. package/dist/assets/prompts/memory-infer-user.md +2 -3
  22. package/dist/assets/prompts/reflect-llm-framed-contract.md +11 -0
  23. package/dist/assets/prompts/reflect-llm-schema-contract.md +3 -0
  24. package/dist/assets/prompts/reflect-output-repair.md +3 -0
  25. package/dist/assets/prompts/workflow-unit-preamble.md +26 -0
  26. package/dist/assets/stash-skeleton/README.md +38 -10
  27. package/dist/assets/stash-skeleton/facts/conventions/assets/agent.md +8 -0
  28. package/dist/assets/stash-skeleton/facts/conventions/assets/command.md +8 -0
  29. package/dist/assets/stash-skeleton/facts/conventions/assets/fact.md +14 -1
  30. package/dist/assets/stash-skeleton/facts/conventions/assets/knowledge.md +13 -1
  31. package/dist/assets/stash-skeleton/facts/conventions/assets/lesson.md +9 -1
  32. package/dist/assets/stash-skeleton/facts/conventions/assets/memory.md +11 -0
  33. package/dist/assets/stash-skeleton/facts/conventions/assets/script.md +9 -0
  34. package/dist/assets/stash-skeleton/facts/conventions/assets/skill.md +9 -0
  35. package/dist/assets/stash-skeleton/facts/conventions/assets/workflow.md +8 -0
  36. package/dist/assets/stash-skeleton/facts/conventions/backlinks.md +100 -0
  37. package/dist/assets/stash-skeleton/facts/conventions/domains.md +64 -0
  38. package/dist/assets/stash-skeleton/facts/conventions/organization.md +136 -0
  39. package/dist/assets/tasks/core/extract.yml +3 -2
  40. package/dist/assets/tasks/core/improve.yml +2 -1
  41. package/dist/assets/tasks/core/index-refresh.yml +1 -0
  42. package/dist/assets/tasks/core/sync.yml +1 -0
  43. package/dist/assets/tasks/core/version-check.yml +2 -1
  44. package/dist/assets/tasks/improve/akm-graph-refresh-weekly.yml +5 -0
  45. package/dist/assets/tasks/improve/akm-improve-catchup.yml +8 -0
  46. package/dist/assets/tasks/improve/akm-improve-consolidate.yml +5 -0
  47. package/dist/assets/tasks/improve/akm-improve-frequent.yml +5 -0
  48. package/dist/assets/tasks/improve/akm-improve-nightly.yml +5 -0
  49. package/dist/assets/templates/html/health.html +5 -4
  50. package/dist/assets/workflows/workflow-template.md +31 -15
  51. package/dist/cli/invocation.js +279 -0
  52. package/dist/cli/parse-args.js +5 -90
  53. package/dist/cli/retired-commands.js +78 -0
  54. package/dist/cli/shared.js +158 -48
  55. package/dist/cli-node.mjs +2 -1
  56. package/dist/cli.js +747 -293
  57. package/dist/commands/agent/agent-dispatch.js +19 -18
  58. package/dist/commands/agent/agent-support.js +0 -24
  59. package/dist/commands/agent/contribute-cli.js +43 -97
  60. package/dist/commands/completions.js +80 -23
  61. package/dist/commands/config-cli.js +44 -281
  62. package/dist/commands/env/env-binding.js +99 -0
  63. package/dist/commands/env/env-cli.js +84 -224
  64. package/dist/commands/env/env.js +12 -163
  65. package/dist/commands/env/marker-path.js +6 -0
  66. package/dist/commands/env/secret-cli.js +45 -61
  67. package/dist/commands/env/secret.js +32 -62
  68. package/dist/commands/feedback-cli.js +179 -85
  69. package/dist/commands/health/accept-rate.js +58 -0
  70. package/dist/commands/health/advisories.js +7 -8
  71. package/dist/commands/health/checks.js +279 -94
  72. package/dist/commands/health/html-report.js +197 -578
  73. package/dist/commands/health/improve-metrics.js +277 -246
  74. package/dist/commands/health/llm-usage.js +19 -19
  75. package/dist/commands/health/md-report.js +16 -7
  76. package/dist/commands/health/metrics.js +67 -32
  77. package/dist/commands/health/renderers.js +47 -0
  78. package/dist/commands/health/report-view-model.js +508 -0
  79. package/dist/commands/health/stash-exposure.js +1 -1
  80. package/dist/commands/health/surfaces.js +16 -56
  81. package/dist/commands/health/task-runs.js +3 -67
  82. package/dist/{migrate-storage-node.mjs → commands/health/types-checks.js} +1 -5
  83. package/dist/commands/health/types-improve.js +29 -0
  84. package/dist/{output/text/save.js → commands/health/types-metrics.js} +1 -2
  85. package/dist/commands/health/types-result.js +7 -0
  86. package/dist/commands/health/types-runs.js +4 -0
  87. package/dist/commands/health/types-session-log.js +4 -0
  88. package/dist/commands/health/types-windows.js +4 -0
  89. package/dist/commands/health/types.js +26 -21
  90. package/dist/commands/health/windows.js +2 -3
  91. package/dist/commands/health.js +296 -167
  92. package/dist/commands/improve/anti-collapse.js +5 -5
  93. package/dist/commands/improve/autonomy-gate.js +68 -0
  94. package/dist/commands/improve/collapse-detector.js +65 -52
  95. package/dist/commands/improve/consolidate/chunking.js +9 -7
  96. package/dist/commands/improve/consolidate/eligibility.js +1 -23
  97. package/dist/commands/improve/consolidate/merge.js +4 -0
  98. package/dist/commands/improve/consolidate.js +454 -1354
  99. package/dist/commands/improve/content-hash.js +39 -0
  100. package/dist/commands/improve/distill/content-repair.js +4 -10
  101. package/dist/commands/improve/distill/promote-memory.js +89 -64
  102. package/dist/commands/improve/distill/quality-gate.js +118 -42
  103. package/dist/commands/improve/distill-guards.js +1 -1
  104. package/dist/commands/improve/distill-promotion-policy.js +33 -888
  105. package/dist/commands/improve/distill.js +607 -363
  106. package/dist/commands/improve/eligibility.js +165 -79
  107. package/dist/commands/improve/extract-cli.js +35 -126
  108. package/dist/commands/improve/extract-prompt.js +6 -35
  109. package/dist/commands/improve/extract.js +640 -391
  110. package/dist/commands/improve/feedback-valence.js +2 -12
  111. package/dist/commands/improve/improve-cli.js +134 -135
  112. package/dist/commands/improve/improve-result-file.js +30 -50
  113. package/dist/commands/improve/improve-run-types.js +4 -0
  114. package/dist/commands/improve/improve-strategies.js +135 -0
  115. package/dist/commands/improve/improve.js +904 -701
  116. package/dist/commands/improve/locks.js +64 -111
  117. package/dist/commands/improve/loop-stages.js +1110 -923
  118. package/dist/commands/improve/memory/derived-ref.js +124 -0
  119. package/dist/commands/improve/memory/memory-belief.js +79 -7
  120. package/dist/commands/improve/memory/memory-contradiction-detect.js +49 -52
  121. package/dist/commands/improve/memory/memory-improve.js +25 -37
  122. package/dist/commands/improve/outcome-loop.js +25 -88
  123. package/dist/commands/improve/preparation.js +1034 -813
  124. package/dist/commands/improve/proactive-maintenance.js +34 -9
  125. package/dist/commands/improve/proposal-envelope.js +31 -0
  126. package/dist/commands/improve/reflect.js +983 -794
  127. package/dist/commands/improve/run-context.js +119 -0
  128. package/dist/commands/improve/salience.js +24 -127
  129. package/dist/commands/improve/session-asset.js +7 -3
  130. package/dist/commands/improve/shared.js +14 -34
  131. package/dist/commands/improve/source-identity.js +28 -0
  132. package/dist/commands/improve/triage.js +20 -17
  133. package/dist/commands/lint/base-linter.js +340 -313
  134. package/dist/commands/lint/env-key-rules.js +31 -47
  135. package/dist/commands/lint/index.js +185 -30
  136. package/dist/commands/{events.js → log.js} +28 -38
  137. package/dist/commands/migrate-cli.js +54 -0
  138. package/dist/commands/migration-tool.js +55 -0
  139. package/dist/commands/observability-cli.js +70 -208
  140. package/dist/commands/proposal/diff-format.js +50 -0
  141. package/dist/commands/proposal/drain-policies.js +0 -6
  142. package/dist/commands/proposal/drain.js +91 -40
  143. package/dist/commands/proposal/proposal-cli.js +134 -132
  144. package/dist/commands/proposal/proposal-types.js +56 -0
  145. package/dist/commands/proposal/proposal.js +83 -65
  146. package/dist/commands/proposal/propose-cli.js +88 -0
  147. package/dist/commands/proposal/propose.js +105 -88
  148. package/dist/commands/proposal/repository.js +1303 -278
  149. package/dist/commands/proposal/validators/proposal-quality-validators.js +16 -6
  150. package/dist/commands/proposal/validators/proposal-validators.js +61 -12
  151. package/dist/commands/proposal/validators/proposals.js +6 -8
  152. package/dist/commands/read/curate.js +78 -73
  153. package/dist/commands/read/knowledge.js +510 -13
  154. package/dist/commands/read/registry-search.js +2 -2
  155. package/dist/commands/read/remember-cli.js +84 -15
  156. package/dist/commands/read/search-cli.js +203 -96
  157. package/dist/commands/read/search.js +126 -94
  158. package/dist/commands/read/show.js +226 -250
  159. package/dist/commands/registry-cli.js +34 -60
  160. package/dist/commands/remember.js +18 -57
  161. package/dist/commands/sources/add-cli.js +104 -49
  162. package/dist/commands/sources/bundle-cli.js +166 -0
  163. package/dist/commands/sources/bundle-config-ops.js +63 -0
  164. package/dist/commands/sources/info.js +27 -15
  165. package/dist/commands/sources/init.js +30 -40
  166. package/dist/commands/sources/installed-stashes.js +469 -172
  167. package/dist/commands/sources/migration-help.js +7 -4
  168. package/dist/commands/sources/schema-repair.js +10 -9
  169. package/dist/commands/sources/self-update.js +182 -121
  170. package/dist/commands/sources/source-add.js +169 -178
  171. package/dist/commands/sources/source-clone.js +144 -41
  172. package/dist/commands/sources/source-manage.js +94 -59
  173. package/dist/commands/sources/sources-cli.js +64 -205
  174. package/dist/commands/sources/stash-cli.js +91 -54
  175. package/dist/commands/sources/stash-skeleton.js +1 -1
  176. package/dist/commands/tasks/tasks-cli.js +106 -104
  177. package/dist/commands/tasks/tasks.js +445 -262
  178. package/dist/commands/workflow-cli.js +232 -121
  179. package/dist/core/action-contributors.js +1 -1
  180. package/dist/core/activation-policy.js +49 -0
  181. package/dist/core/adapter/adapters/agent-skills-adapter.js +181 -0
  182. package/dist/core/adapter/adapters/akm-adapter.js +528 -0
  183. package/dist/core/adapter/adapters/akm-lint.js +392 -0
  184. package/dist/core/adapter/adapters/akm-metadata.js +387 -0
  185. package/dist/core/adapter/adapters/akm-task-adapter.js +149 -0
  186. package/dist/core/adapter/adapters/akm-workflow-adapter.js +180 -0
  187. package/dist/core/adapter/adapters/claude-adapter.js +61 -0
  188. package/dist/core/adapter/adapters/dotenv-adapter.js +187 -0
  189. package/dist/core/adapter/adapters/generic-files-adapter.js +119 -0
  190. package/dist/core/adapter/adapters/index.js +80 -0
  191. package/dist/core/adapter/adapters/llm-wiki-adapter.js +419 -0
  192. package/dist/core/adapter/adapters/okf-adapter.js +391 -0
  193. package/dist/core/adapter/adapters/opencode-adapter.js +68 -0
  194. package/dist/core/adapter/adapters/shared.js +286 -0
  195. package/dist/core/adapter/adapters/tool-dir-shared.js +217 -0
  196. package/dist/core/adapter/adapters/website-snapshot-adapter.js +155 -0
  197. package/dist/core/adapter/bundle-adapter.js +4 -0
  198. package/dist/core/adapter/detect-adapter.js +17 -0
  199. package/dist/core/adapter/recognize-match.js +44 -0
  200. package/dist/core/adapter/registry.js +56 -0
  201. package/dist/core/adapter/types.js +4 -0
  202. package/dist/core/asset/akm-markdown.js +30 -0
  203. package/dist/core/asset/asset-placement.js +243 -0
  204. package/dist/core/asset/asset-ref.js +110 -79
  205. package/dist/core/asset/asset-serialize.js +20 -0
  206. package/dist/core/asset/frontmatter.js +28 -12
  207. package/dist/core/asset/markdown.js +40 -51
  208. package/dist/core/asset/resolve-ref.js +274 -0
  209. package/dist/core/asset/stash-meta.js +2 -2
  210. package/dist/core/bundle-id.js +51 -0
  211. package/dist/core/common.js +281 -86
  212. package/dist/core/config/config-io.js +42 -128
  213. package/dist/core/config/config-schema.js +233 -834
  214. package/dist/core/config/config-sources.js +162 -39
  215. package/dist/core/config/config-types.js +16 -11
  216. package/dist/core/config/config-version.js +29 -0
  217. package/dist/core/config/config-walker.js +126 -37
  218. package/dist/core/config/config.js +154 -331
  219. package/dist/core/config/deep-merge.js +41 -0
  220. package/dist/core/config/engine-semantics.js +28 -0
  221. package/dist/core/config/experimental.js +21 -0
  222. package/dist/core/config/schema/embedding.js +38 -0
  223. package/dist/core/config/schema/engines.js +116 -0
  224. package/dist/core/config/schema/experimental.js +47 -0
  225. package/dist/core/config/schema/feedback.js +31 -0
  226. package/dist/core/config/schema/improve-processes.js +389 -0
  227. package/dist/core/config/schema/improve.js +94 -0
  228. package/dist/core/config/schema/index-config.js +176 -0
  229. package/dist/core/config/schema/output.js +18 -0
  230. package/dist/core/config/schema/primitives.js +94 -0
  231. package/dist/core/config/schema/search.js +30 -0
  232. package/dist/core/config/schema/setup.js +18 -0
  233. package/dist/core/config/schema/sources-bundles.js +169 -0
  234. package/dist/core/config/schema/workflow.js +29 -0
  235. package/dist/core/env-secret-ref.js +155 -20
  236. package/dist/core/errors.js +17 -15
  237. package/dist/core/events-types.js +4 -0
  238. package/dist/core/events.js +46 -128
  239. package/dist/core/extra-params.js +62 -0
  240. package/dist/core/file-change.js +17 -0
  241. package/dist/core/file-lock.js +202 -57
  242. package/dist/core/fs-txn.js +392 -0
  243. package/dist/core/git-message.js +59 -0
  244. package/dist/core/improve-result.js +167 -0
  245. package/dist/core/json-schema.js +142 -0
  246. package/dist/core/lesson-lint.js +1 -17
  247. package/dist/core/logs-db.js +1 -1
  248. package/dist/core/maintenance-barrier.js +135 -0
  249. package/dist/core/migration-operation.js +44 -0
  250. package/dist/core/mutation-target.js +78 -0
  251. package/dist/core/paths.js +22 -25
  252. package/dist/core/platform.js +10 -0
  253. package/dist/core/recognition-util.js +128 -0
  254. package/dist/core/redaction.js +392 -0
  255. package/dist/core/standards/resolve-standards-context.js +36 -65
  256. package/dist/core/standards/resolve-stash-standards.js +2 -2
  257. package/dist/core/standards/resolve-type-conventions.js +5 -5
  258. package/dist/core/state/migrations.js +242 -11
  259. package/dist/core/state-db.js +98 -10
  260. package/dist/core/structured.js +1 -1
  261. package/dist/core/subprocess.js +303 -0
  262. package/dist/core/text-truncation.js +9 -5
  263. package/dist/core/time.js +20 -0
  264. package/dist/core/type-presentation.js +130 -0
  265. package/dist/core/warn.js +0 -3
  266. package/dist/core/write-source.js +834 -118
  267. package/dist/indexer/bundle-identity-guard.js +92 -0
  268. package/dist/indexer/db/graph-db.js +1 -25
  269. package/dist/indexer/db/llm-cache.js +1 -1
  270. package/dist/indexer/ensure-index.js +30 -9
  271. package/dist/indexer/graph/graph-boost.js +9 -30
  272. package/dist/indexer/graph/graph-extraction.js +41 -27
  273. package/dist/indexer/graph/graph-types.js +4 -0
  274. package/dist/indexer/index-writer-lock.js +93 -49
  275. package/dist/indexer/index-written-assets.js +100 -53
  276. package/dist/indexer/indexer.js +746 -329
  277. package/dist/indexer/init.js +18 -25
  278. package/dist/indexer/installations.js +142 -0
  279. package/dist/indexer/passes/dir-staleness.js +18 -10
  280. package/dist/indexer/passes/memory-inference.js +25 -15
  281. package/dist/indexer/passes/metadata.js +412 -243
  282. package/dist/indexer/scan/doc-to-entry.js +160 -0
  283. package/dist/indexer/scan/drain-dir.js +134 -0
  284. package/dist/indexer/search/db-search.js +292 -108
  285. package/dist/indexer/search/fts-query.js +64 -0
  286. package/dist/indexer/search/ranking-contributors.js +145 -25
  287. package/dist/indexer/search/ranking-types.js +4 -0
  288. package/dist/indexer/search/ranking.js +28 -71
  289. package/dist/indexer/search/search-attribution.js +67 -0
  290. package/dist/indexer/search/search-fields.js +18 -3
  291. package/dist/indexer/search/search-hit-enrichers.js +30 -40
  292. package/dist/indexer/search/search-source.js +157 -111
  293. package/dist/indexer/search/semantic-status.js +4 -1
  294. package/dist/indexer/usage/usage-events.js +10 -30
  295. package/dist/indexer/walk/file-context.js +3 -45
  296. package/dist/indexer/walk/matchers.js +42 -34
  297. package/dist/indexer/walk/path-resolver.js +11 -5
  298. package/dist/indexer/walk/walker.js +42 -14
  299. package/dist/integrations/agent/builder-shared.js +7 -0
  300. package/dist/integrations/agent/builders.js +5 -56
  301. package/dist/integrations/agent/config.js +3 -143
  302. package/dist/integrations/agent/detect.js +17 -2
  303. package/dist/integrations/agent/engine-resolution.js +231 -0
  304. package/dist/integrations/agent/index.js +1 -2
  305. package/dist/integrations/agent/model-aliases.js +16 -2
  306. package/dist/integrations/agent/profiles.js +36 -62
  307. package/dist/integrations/agent/prompts.js +46 -18
  308. package/dist/integrations/agent/runner-dispatch.js +93 -4
  309. package/dist/integrations/agent/runner.js +76 -208
  310. package/dist/integrations/agent/spawn.js +88 -196
  311. package/dist/integrations/harnesses/aider/agent-builder.js +114 -0
  312. package/dist/integrations/harnesses/aider/index.js +48 -0
  313. package/dist/integrations/harnesses/aider/result-extractor.js +53 -0
  314. package/dist/integrations/harnesses/amazonq/agent-builder.js +147 -0
  315. package/dist/integrations/harnesses/amazonq/index.js +45 -0
  316. package/dist/integrations/harnesses/amazonq/result-extractor.js +48 -0
  317. package/dist/integrations/harnesses/claude/agent-builder.js +46 -8
  318. package/dist/integrations/harnesses/claude/config-import.js +1 -3
  319. package/dist/integrations/harnesses/claude/index.js +24 -35
  320. package/dist/integrations/harnesses/claude/result-extractor.js +52 -0
  321. package/dist/integrations/harnesses/claude/session-log.js +27 -75
  322. package/dist/integrations/harnesses/codex/agent-builder.js +138 -0
  323. package/dist/integrations/harnesses/codex/index.js +52 -0
  324. package/dist/integrations/harnesses/codex/result-extractor.js +73 -0
  325. package/dist/integrations/harnesses/copilot/agent-builder.js +122 -0
  326. package/dist/integrations/harnesses/copilot/index.js +48 -0
  327. package/dist/integrations/harnesses/copilot/result-extractor.js +151 -0
  328. package/dist/integrations/harnesses/gemini/agent-builder.js +120 -0
  329. package/dist/integrations/harnesses/gemini/index.js +48 -0
  330. package/dist/integrations/harnesses/gemini/result-extractor.js +121 -0
  331. package/dist/integrations/harnesses/ids.js +24 -0
  332. package/dist/integrations/harnesses/index.js +54 -34
  333. package/dist/integrations/harnesses/opencode/agent-builder.js +23 -5
  334. package/dist/integrations/harnesses/opencode/config-import.js +1 -3
  335. package/dist/integrations/harnesses/opencode/index.js +14 -32
  336. package/dist/integrations/harnesses/opencode/session-log.js +67 -125
  337. package/dist/integrations/harnesses/opencode-sdk/harness.js +51 -0
  338. package/dist/integrations/harnesses/opencode-sdk/sdk-runner.js +681 -108
  339. package/dist/integrations/harnesses/openhands/agent-builder.js +128 -0
  340. package/dist/integrations/harnesses/openhands/index.js +48 -0
  341. package/dist/integrations/harnesses/openhands/result-extractor.js +103 -0
  342. package/dist/integrations/harnesses/pi/agent-builder.js +97 -0
  343. package/dist/integrations/harnesses/pi/index.js +45 -0
  344. package/dist/integrations/harnesses/pi/result-extractor.js +135 -0
  345. package/dist/integrations/harnesses/shared.js +17 -0
  346. package/dist/integrations/harnesses/types.js +43 -32
  347. package/dist/integrations/lockfile.js +211 -24
  348. package/dist/integrations/session-logs/index.js +36 -39
  349. package/dist/integrations/session-logs/provider-base.js +113 -0
  350. package/dist/llm/client.js +182 -110
  351. package/dist/llm/embedders/deterministic.js +2 -2
  352. package/dist/llm/embedders/remote.js +21 -9
  353. package/dist/llm/feature-gate.js +17 -57
  354. package/dist/llm/graph-extract.js +12 -13
  355. package/dist/llm/index-passes.js +8 -42
  356. package/dist/llm/memory-infer.js +144 -1
  357. package/dist/llm/metadata-enhance.js +45 -30
  358. package/dist/llm/structured-call.js +16 -8
  359. package/dist/llm/usage-persist.js +30 -5
  360. package/dist/llm/usage-telemetry.js +59 -6
  361. package/dist/output/cli-hints.js +1 -2
  362. package/dist/output/command-registry.js +27 -0
  363. package/dist/output/context.js +22 -7
  364. package/dist/output/format-exempt.js +80 -0
  365. package/dist/output/generic-render.js +251 -0
  366. package/dist/output/html-render.js +11 -16
  367. package/dist/output/render-registry.js +57 -0
  368. package/dist/output/renderers.js +14 -279
  369. package/dist/output/shapes/curate.js +10 -1
  370. package/dist/output/shapes/events.js +12 -7
  371. package/dist/output/shapes/helpers.js +58 -84
  372. package/dist/output/shapes/passthrough.js +11 -39
  373. package/dist/output/shapes/proposal/producer.js +15 -7
  374. package/dist/output/shapes/registry.js +12 -6
  375. package/dist/output/shapes.js +0 -9
  376. package/dist/output/text/{init.js → bundle-create.js} +3 -1
  377. package/dist/output/text/bundle-show.js +7 -0
  378. package/dist/output/text/command-format.js +562 -0
  379. package/dist/output/text/env.js +1 -3
  380. package/dist/output/text/events.js +8 -7
  381. package/dist/output/text/helpers.js +15 -1164
  382. package/dist/output/text/proposal/producer.js +4 -2
  383. package/dist/output/text/proposal-format.js +202 -0
  384. package/dist/output/text/registry-commands.js +1 -2
  385. package/dist/output/text/registry.js +12 -6
  386. package/dist/output/text/show-directives.js +117 -0
  387. package/dist/output/text/show-format.js +103 -0
  388. package/dist/output/text/sync.js +5 -0
  389. package/dist/output/text/workflow-format.js +332 -0
  390. package/dist/output/text/workflow.js +3 -2
  391. package/dist/output/text.js +10 -19
  392. package/dist/registry/factory.js +4 -6
  393. package/dist/registry/origin-resolve.js +16 -27
  394. package/dist/registry/providers/skills-sh.js +3 -3
  395. package/dist/registry/providers/static-index.js +15 -25
  396. package/dist/registry/resolve.js +43 -94
  397. package/dist/registry/semver.js +43 -0
  398. package/dist/runtime.js +81 -12
  399. package/dist/scripts/akm-migrate.js +35529 -0
  400. package/dist/setup/detect.js +5 -7
  401. package/dist/setup/detected-engines.js +136 -0
  402. package/dist/setup/engine-config.js +100 -0
  403. package/dist/setup/registry-stash-loader.js +3 -3
  404. package/dist/setup/semantic-assets.js +12 -9
  405. package/dist/setup/setup.js +444 -208
  406. package/dist/setup/steps/connection-shared.js +120 -0
  407. package/dist/setup/steps/connection.js +108 -305
  408. package/dist/setup/steps/platforms.js +13 -12
  409. package/dist/setup/steps/semantic.js +15 -3
  410. package/dist/setup/steps/sources.js +21 -15
  411. package/dist/setup/steps/stashdir.js +6 -4
  412. package/dist/setup/steps/tasks.js +236 -119
  413. package/dist/setup/steps.js +3 -2
  414. package/dist/sources/freshness.js +39 -0
  415. package/dist/sources/provider-factory.js +11 -17
  416. package/dist/sources/providers/filesystem.js +2 -3
  417. package/dist/sources/providers/git-install.js +278 -34
  418. package/dist/sources/providers/git-provider.js +54 -56
  419. package/dist/sources/providers/git-stash.js +420 -91
  420. package/dist/sources/providers/git.js +2 -2
  421. package/dist/sources/providers/npm.js +16 -19
  422. package/dist/sources/providers/provider-utils.js +47 -22
  423. package/dist/sources/providers/sync-from-ref.js +3 -9
  424. package/dist/sources/providers/website.js +2 -2
  425. package/dist/sources/resolve.js +11 -10
  426. package/dist/sources/snapshot-fetchers/types.js +4 -0
  427. package/dist/sources/{website-ingest.js → snapshot-fetchers/website-ingest.js} +110 -41
  428. package/dist/storage/database.js +60 -4
  429. package/dist/storage/engines/sqlite-migrations.js +156 -5
  430. package/dist/storage/locations.js +1 -2
  431. package/dist/storage/repositories/canaries-repository.js +1 -1
  432. package/dist/storage/repositories/events-repository.js +51 -11
  433. package/dist/storage/repositories/improve-runs-repository.js +6 -32
  434. package/dist/storage/repositories/index-connection.js +79 -0
  435. package/dist/storage/repositories/index-db.js +4 -3
  436. package/dist/storage/repositories/index-entries-repository.js +863 -0
  437. package/dist/{indexer/db/entry-mapper.js → storage/repositories/index-entry-mapper.js} +19 -2
  438. package/dist/storage/repositories/index-entry-types.js +4 -0
  439. package/dist/storage/repositories/index-fts-repository.js +167 -0
  440. package/dist/storage/repositories/index-llm-cache-repository.js +108 -0
  441. package/dist/storage/repositories/index-meta-repository.js +49 -0
  442. package/dist/{indexer/db/schema.js → storage/repositories/index-schema.js} +226 -100
  443. package/dist/storage/repositories/index-sql.js +12 -0
  444. package/dist/storage/repositories/index-utility-repository.js +356 -0
  445. package/dist/storage/repositories/index-vec-repository.js +250 -0
  446. package/dist/storage/repositories/outcome-repository.js +119 -0
  447. package/dist/storage/repositories/proposals-repository.js +317 -75
  448. package/dist/storage/repositories/registry-cache.js +1 -1
  449. package/dist/storage/repositories/salience-repository.js +172 -0
  450. package/dist/storage/repositories/task-history-repository.js +110 -3
  451. package/dist/storage/repositories/workflow-runs-repository.js +240 -19
  452. package/dist/tasks/backends/cron.js +169 -46
  453. package/dist/tasks/backends/exec-utils.js +76 -3
  454. package/dist/tasks/backends/index.js +6 -9
  455. package/dist/tasks/backends/launchd.js +292 -55
  456. package/dist/tasks/backends/schtasks.js +557 -70
  457. package/dist/tasks/backends/types.js +4 -0
  458. package/dist/tasks/command-executable.js +93 -0
  459. package/dist/tasks/embedded.js +56 -38
  460. package/dist/tasks/parser.js +156 -64
  461. package/dist/tasks/resolve-akm-bin.js +144 -51
  462. package/dist/tasks/runner.js +377 -209
  463. package/dist/tasks/schedule.js +108 -19
  464. package/dist/tasks/scheduler-invocation.js +296 -0
  465. package/dist/tasks/schema.js +1 -1
  466. package/dist/tasks/task-id.js +35 -0
  467. package/dist/tasks/validator.js +30 -16
  468. package/dist/text-import-hook.mjs +1 -1
  469. package/dist/workflows/authoring/authoring.js +104 -43
  470. package/dist/workflows/authoring/scope-key.js +1 -1
  471. package/dist/workflows/cli.js +0 -16
  472. package/dist/workflows/concurrency-policy.js +15 -0
  473. package/dist/workflows/exec/brief.js +450 -0
  474. package/dist/workflows/exec/frozen-judge.js +47 -0
  475. package/dist/workflows/exec/native-executor.js +1038 -0
  476. package/dist/workflows/exec/param-secrets.js +115 -0
  477. package/dist/workflows/exec/report.js +1460 -0
  478. package/dist/workflows/exec/run-workflow.js +602 -0
  479. package/dist/workflows/exec/scheduler.js +71 -0
  480. package/dist/workflows/exec/step-work.js +1190 -0
  481. package/dist/workflows/exec/unit-writer.js +23 -0
  482. package/dist/workflows/exec/workflow-engine-gate.js +67 -0
  483. package/dist/workflows/exec/worktree.js +171 -0
  484. package/dist/workflows/ir/compile.js +246 -0
  485. package/dist/workflows/ir/freeze.js +233 -0
  486. package/dist/workflows/ir/params.js +54 -0
  487. package/dist/workflows/ir/plan-hash.js +68 -0
  488. package/dist/workflows/ir/schema.js +540 -0
  489. package/dist/workflows/parser.js +878 -304
  490. package/dist/workflows/program/expressions.js +181 -0
  491. package/dist/workflows/program/schema.js +51 -0
  492. package/dist/workflows/renderer.js +100 -45
  493. package/dist/workflows/resource-limits.js +22 -0
  494. package/dist/workflows/runtime/agent-identity.js +59 -14
  495. package/dist/workflows/runtime/checkin.js +1 -1
  496. package/dist/workflows/runtime/plan-classifier.js +131 -0
  497. package/dist/workflows/runtime/runs.js +376 -119
  498. package/dist/workflows/runtime/unit-checkin.js +45 -0
  499. package/dist/workflows/runtime/unit-phases.js +20 -0
  500. package/dist/workflows/runtime/workflow-asset-loader.js +241 -40
  501. package/dist/workflows/schema.js +1 -11
  502. package/dist/workflows/validate-summary.js +2 -3
  503. package/dist/workflows/validator.js +52 -30
  504. package/docs/README.md +42 -78
  505. package/docs/migration/README.md +8 -0
  506. package/docs/migration/release-notes/0.6.0.md +1 -1
  507. package/docs/migration/release-notes/0.7.0.md +9 -8
  508. package/docs/migration/release-notes/0.9.0.md +158 -14
  509. package/docs/migration/v0.7-to-v0.8.md +46 -47
  510. package/docs/migration/v0.8-to-v0.9.md +844 -0
  511. package/docs/reference/README.md +12 -0
  512. package/docs/reference/data-and-telemetry.md +333 -0
  513. package/package.json +21 -17
  514. package/schemas/akm-asset-envelope.json +93 -0
  515. package/schemas/akm-config.json +4636 -0
  516. package/schemas/akm-task.json +87 -0
  517. package/schemas/akm-workflow.json +373 -0
  518. package/dist/akm-migrate-storage +0 -38
  519. package/dist/assets/help/help-accept.md +0 -12
  520. package/dist/assets/help/help-improve.md +0 -84
  521. package/dist/assets/help/help-proposals.md +0 -17
  522. package/dist/assets/help/help-propose.md +0 -17
  523. package/dist/assets/help/help-reject.md +0 -11
  524. package/dist/assets/profiles/frequent.json +0 -13
  525. package/dist/assets/profiles/recombine-only.json +0 -21
  526. package/dist/assets/profiles/reflect-distill.json +0 -30
  527. package/dist/assets/profiles/synthesize.json +0 -15
  528. package/dist/assets/prompts/procedural-system.md +0 -44
  529. package/dist/assets/prompts/recombine-system.md +0 -40
  530. package/dist/assets/prompts/staleness-detect-system.md +0 -6
  531. package/dist/assets/tasks/core/backup.yml +0 -4
  532. package/dist/assets/tasks/graph-refresh-weekly.yml +0 -10
  533. package/dist/assets/templates/html/default.html +0 -78
  534. package/dist/assets/templates/html/vendor/echarts.min.js +0 -45
  535. package/dist/assets/wiki/index-template.md +0 -12
  536. package/dist/assets/wiki/ingest-workflow-template.md +0 -83
  537. package/dist/assets/wiki/log-template.md +0 -8
  538. package/dist/assets/wiki/schema-template.md +0 -61
  539. package/dist/cli/config-migrate.js +0 -150
  540. package/dist/cli/config-validate.js +0 -39
  541. package/dist/commands/graph/graph-cli.js +0 -124
  542. package/dist/commands/graph/graph.js +0 -487
  543. package/dist/commands/improve/calibration.js +0 -161
  544. package/dist/commands/improve/dedup.js +0 -482
  545. package/dist/commands/improve/extract-watch.js +0 -140
  546. package/dist/commands/improve/hot-probation.js +0 -45
  547. package/dist/commands/improve/improve-auto-accept.js +0 -276
  548. package/dist/commands/improve/improve-profiles.js +0 -168
  549. package/dist/commands/improve/procedural.js +0 -398
  550. package/dist/commands/improve/recombine.js +0 -818
  551. package/dist/commands/improve/schema-similarity-gate.js +0 -168
  552. package/dist/commands/lint/agent-linter.js +0 -44
  553. package/dist/commands/lint/command-linter.js +0 -44
  554. package/dist/commands/lint/default-linter.js +0 -16
  555. package/dist/commands/lint/fact-linter.js +0 -39
  556. package/dist/commands/lint/knowledge-linter.js +0 -16
  557. package/dist/commands/lint/memory-linter.js +0 -61
  558. package/dist/commands/lint/registry.js +0 -41
  559. package/dist/commands/lint/skill-linter.js +0 -45
  560. package/dist/commands/lint/task-linter.js +0 -50
  561. package/dist/commands/lint/workflow-linter.js +0 -81
  562. package/dist/commands/proposal/legacy-import.js +0 -115
  563. package/dist/commands/sources/history.js +0 -196
  564. package/dist/commands/tasks/default-tasks.js +0 -186
  565. package/dist/commands/wiki-cli.js +0 -292
  566. package/dist/core/asset/asset-registry.js +0 -76
  567. package/dist/core/asset/asset-spec.js +0 -259
  568. package/dist/core/config/config-migration.js +0 -602
  569. package/dist/core/deep-merge.js +0 -38
  570. package/dist/core/eval/rank-metrics.js +0 -113
  571. package/dist/core/ripgrep/install.js +0 -163
  572. package/dist/core/ripgrep/resolve.js +0 -81
  573. package/dist/indexer/db/db.js +0 -1413
  574. package/dist/indexer/manifest.js +0 -170
  575. package/dist/indexer/passes/metadata-contributors.js +0 -31
  576. package/dist/indexer/usage/unmigrated-vaults-guard.js +0 -94
  577. package/dist/integrations/harnesses/opencode-sdk/index.js +0 -49
  578. package/dist/llm/call-ai.js +0 -62
  579. package/dist/llm/memory-infer-impl.js +0 -138
  580. package/dist/output/shapes/distill.js +0 -14
  581. package/dist/output/shapes/history.js +0 -11
  582. package/dist/output/text/distill.js +0 -6
  583. package/dist/output/text/enable-disable.js +0 -8
  584. package/dist/output/text/history.js +0 -6
  585. package/dist/output/text/wiki.js +0 -16
  586. package/dist/registry/build-index.js +0 -386
  587. package/dist/scripts/migrate-storage.js +0 -19108
  588. package/dist/scripts/migrations/import-fs-improve-runs-to-db.js +0 -9411
  589. package/dist/scripts/migrations/v16-to-v17.js +0 -141
  590. package/dist/setup/legacy-config.js +0 -106
  591. package/dist/storage/repositories/consolidation-repository.js +0 -38
  592. package/dist/storage/repositories/recombine-repository.js +0 -213
  593. package/dist/wiki/wiki-templates.js +0 -15
  594. package/dist/wiki/wiki.js +0 -1012
  595. package/dist/workflows/db.js +0 -215
  596. package/docs/data-and-telemetry.md +0 -226
  597. /package/dist/sources/{wiki-fetchers → snapshot-fetchers}/registry.js +0 -0
  598. /package/dist/sources/{wiki-fetchers → snapshot-fetchers}/youtube.js +0 -0
@@ -0,0 +1,508 @@
1
+ // This Source Code Form is subject to the terms of the Mozilla Public
2
+ // License, v. 2.0. If a copy of the MPL was not distributed with this
3
+ // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
+ /**
5
+ * Pure `AkmHealthResult` (+ report options) → `HealthReportViewModel`
6
+ * extractor for the health HTML report (chunk-9 WI-9.5a / H2, anchors C.6).
7
+ *
8
+ * Every computed number, string, boolean, and series the report shows is
9
+ * derived here — deltas, trends, staleness, rate/duration formatting, the
10
+ * synthesized verdict components, the summary-table rows, the action-item
11
+ * inputs. NOTHING in this module emits HTML: `html-report.ts` holds the thin
12
+ * VM→HTML fragment renderers that consume this shape (`buildEchartsTag`,
13
+ * `isoTimeTag`, the `<li>`/card builders, …).
14
+ *
15
+ * Determinism: nothing here depends on Date.now()/Math.random(). Runs are
16
+ * sorted by startedAt so the view model — and therefore the rendered report —
17
+ * is byte-identical for identical inputs.
18
+ */
19
+ import { TASK_FAIL_RATE_WARN, } from "./types.js";
20
+ /** Distill skip-reasons hidden from the breakdown chart (steady-state noise). */
21
+ const DISTILL_REASONS_HIDDEN = new Set(["no new signal since last proposal"]);
22
+ // ── Small pure formatters (ports of render.py helpers; no HTML) ─────────────
23
+ export function num(value) {
24
+ return Math.round(value).toLocaleString("en-US");
25
+ }
26
+ /** Compact token/count formatter, e.g. 127345 → "127K", 1_500_000 → "1.5M". */
27
+ export function compact(value) {
28
+ const v = Math.round(value);
29
+ if (Math.abs(v) >= 1_000_000)
30
+ return `${(v / 1_000_000).toFixed(1).replace(/\.0$/, "")}M`;
31
+ if (Math.abs(v) >= 1_000)
32
+ return `${(v / 1_000).toFixed(1).replace(/\.0$/, "")}K`;
33
+ return String(v);
34
+ }
35
+ /** Humanize a camelCase / kebab / snake enum into reader-facing text. */
36
+ export function humanize(raw) {
37
+ return raw
38
+ .replace(/[-_]/g, " ")
39
+ .replace(/([a-z])([A-Z])/g, "$1 $2")
40
+ .replace(/\s+/g, " ")
41
+ .trim()
42
+ .replace(/^./, (c) => c.toUpperCase());
43
+ }
44
+ export function fmtMs(ms) {
45
+ return ms ? `${(ms / 60000).toFixed(1)}m` : "—";
46
+ }
47
+ export function pct(rate, digits) {
48
+ return `${(rate * 100).toFixed(digits)}%`;
49
+ }
50
+ /** pctChange may be a number or an "+inf"/"-inf" sentinel (prior window was 0). */
51
+ function coercePct(raw) {
52
+ if (typeof raw === "number")
53
+ return raw;
54
+ if (typeof raw !== "string")
55
+ return undefined;
56
+ const s = raw.trim().toLowerCase();
57
+ if (s === "+inf" || s === "inf" || s === "infinity" || s === "+infinity")
58
+ return 1e9;
59
+ if (s === "-inf" || s === "-infinity")
60
+ return -1e9;
61
+ const parsed = Number.parseFloat(s.replace(/%$/, ""));
62
+ return Number.isFinite(parsed) ? parsed : undefined;
63
+ }
64
+ function reshapeRun(r) {
65
+ const cons = r.consolidation;
66
+ const mi = r.memoryInference;
67
+ const ge = r.graphExtraction;
68
+ const wall = r.wallTimeMs || 0;
69
+ const consMs = cons.durationMs || 0;
70
+ const miMs = mi.durationMs || 0;
71
+ const geMs = ge.durationMs || 0;
72
+ return {
73
+ id: r.id,
74
+ resultStatus: r.resultStatus ?? "valid",
75
+ resultComplete: r.resultComplete ?? (r.resultStatus === undefined || r.resultStatus === "valid"),
76
+ taskId: r.taskId ?? "manual",
77
+ strategy: r.strategy,
78
+ startedAt: r.startedAt,
79
+ completedAt: r.completedAt,
80
+ wallTimeMs: wall,
81
+ ok: r.ok,
82
+ mode: r.scope.mode,
83
+ consDurationMs: consMs,
84
+ miDurationMs: miMs,
85
+ geDurationMs: geMs,
86
+ otherMs: Math.max(0, wall - consMs - miMs - geMs),
87
+ consRan: cons.ran,
88
+ promoted: cons.promoted,
89
+ merged: cons.merged,
90
+ deleted: cons.deleted,
91
+ contradicted: cons.contradicted,
92
+ judgedNoAction: cons.judgedNoAction,
93
+ processed: cons.processed,
94
+ failedChunks: cons.failedChunks,
95
+ totalChunks: cons.totalChunks,
96
+ miWritten: mi.written,
97
+ miConsidered: mi.considered,
98
+ miYieldRate: mi.yieldRate,
99
+ miCacheHits: mi.cacheHits,
100
+ geEntities: ge.entities,
101
+ geRelations: ge.relations,
102
+ geCacheHitRate: ge.cacheHitRate,
103
+ geFailures: ge.failures,
104
+ distillSkipped: r.actions.distill.skipped,
105
+ distillQueued: r.actions.distill.queued,
106
+ distillLlmFailed: r.actions.distill.llmFailed,
107
+ distillByReason: r.actions.distill.skippedByReason,
108
+ reflectOk: r.actions.reflect.ok,
109
+ reflectFailed: r.actions.reflect.failed,
110
+ derived: r.memorySummary.derived,
111
+ eligible: r.memorySummary.eligible,
112
+ lintFlagged: r.lintFlagged,
113
+ lintFixed: r.lintFixed,
114
+ reflectsWithErrorContext: r.reflectsWithErrorContext,
115
+ orphansPurged: r.orphansPurged,
116
+ evalCasesWritten: r.evalCasesWritten,
117
+ };
118
+ }
119
+ function compareRuns(a, b) {
120
+ return (a.startedAt.localeCompare(b.startedAt) || a.completedAt.localeCompare(b.completedAt) || a.id.localeCompare(b.id));
121
+ }
122
+ // ── Trend classification (port of collect.py classify) ──────────────────────
123
+ function classify(deltas, metricKeys, lowerIsBetter = false) {
124
+ const changes = metricKeys
125
+ .map((key) => coercePct(deltas[key]?.pctChange))
126
+ .filter((c) => c !== undefined);
127
+ if (changes.length === 0)
128
+ return "flat";
129
+ const avg = changes.reduce((acc, c) => acc + c, 0) / changes.length;
130
+ if (Math.abs(avg) < 5)
131
+ return "flat";
132
+ const direction = avg > 0 ? "up" : "down";
133
+ if (lowerIsBetter)
134
+ return avg > 0 ? "down" : "up";
135
+ return direction;
136
+ }
137
+ function buildTrend(deltas) {
138
+ const decisionQuality = classify(deltas, ["improve.memoryInference.yieldRate", "improve.consolidation.promoted"]);
139
+ const outputVolume = classify(deltas, [
140
+ "improve.consolidation.promoted",
141
+ "improve.memoryInference.written",
142
+ "improve.sessionExtraction.proposalsCreated",
143
+ ]);
144
+ const failures = classify(deltas, ["improve.graphExtraction.failures"], true);
145
+ const latency = classify(deltas, ["improve.wallTime.medianMs", "improve.wallTime.p95Ms"], true);
146
+ const score = [decisionQuality, outputVolume, failures, latency].reduce((acc, d) => acc + (d === "up" ? 1 : d === "down" ? -1 : 0), 0);
147
+ const overall = score >= 1 ? "improving" : score <= -1 ? "degrading" : "mixed";
148
+ return { decisionQuality, outputVolume, failures, latency, overall };
149
+ }
150
+ function readSemSearch(advisories) {
151
+ const check = advisories.find((a) => a.name === "semantic-search-runtime");
152
+ if (!check)
153
+ return { blocked: false, detail: "" };
154
+ const evidence = check.evidence ?? {};
155
+ const status = String(evidence.status ?? "unknown");
156
+ const blocked = check.status !== "pass" || status.toLowerCase().includes("block");
157
+ const entries = typeof evidence.entryCount === "number" ? evidence.entryCount : 0;
158
+ const embeddings = typeof evidence.embeddingCount === "number" ? evidence.embeddingCount : 0;
159
+ return { blocked, detail: `${num(entries)} entries, ${num(embeddings)} embeddings` };
160
+ }
161
+ // ── Report-window → time-slice candidates (data only; HTML wrapping is the
162
+ // renderer's job) ─────────────────────────────────────────────────────────
163
+ /** Parse an akm window string (`24h`, `7d`, `30m`, `2w`) to milliseconds; 0 if unparseable. */
164
+ export function windowToMs(window) {
165
+ const m = /^(\d+)\s*([mhdw])$/i.exec(window.trim());
166
+ if (!m)
167
+ return 0;
168
+ const n = Number(m[1]);
169
+ const mult = { m: 60_000, h: 3_600_000, d: 86_400_000, w: 604_800_000 }[m[2].toLowerCase()] ?? 0;
170
+ return n * mult;
171
+ }
172
+ /**
173
+ * Candidate sub-window slices strictly shorter than the report window,
174
+ * largest-first, capped at 4 — the data half of the filter bar's `<option>`s
175
+ * (the "All" option and the `<option>` tags themselves are the renderer's job).
176
+ */
177
+ function computeSliceCandidates(window) {
178
+ const windowMs = windowToMs(window);
179
+ const HOUR = 3_600_000;
180
+ const DAY = 86_400_000;
181
+ const candidates = [
182
+ [6 * HOUR, "6h"],
183
+ [12 * HOUR, "12h"],
184
+ [DAY, "1d"],
185
+ [3 * DAY, "3d"],
186
+ [7 * DAY, "7d"],
187
+ [14 * DAY, "14d"],
188
+ ];
189
+ return candidates
190
+ .filter(([ms]) => windowMs > 0 && ms < windowMs)
191
+ .sort((a, b) => b[0] - a[0])
192
+ .slice(0, 4);
193
+ }
194
+ function partitionRuns(result) {
195
+ const allRuns = (result.runs ?? []).map(reshapeRun).sort(compareRuns);
196
+ return {
197
+ invalidRuns: allRuns.filter((run) => run.resultStatus === "invalid"),
198
+ runs: allRuns.filter((run) => run.resultStatus !== "invalid"),
199
+ };
200
+ }
201
+ /** Aggregates (collect.py step 6) + the WS-5 sub-rollups + their formatted-rate strings. */
202
+ function buildAggregatesPhase(result, runsPhase) {
203
+ const { runs, invalidRuns } = runsPhase;
204
+ const improve = result.improve;
205
+ const cons = improve.consolidation;
206
+ const mi = improve.memoryInference;
207
+ const ge = improve.graphExtraction;
208
+ const wallTime = improve.wallTime;
209
+ // WS-5: perf telemetry, coverage, and degradation metrics.
210
+ const perf = improve.perfTelemetry ?? {
211
+ dedupPoolSize: 0,
212
+ llmPoolSize: 0,
213
+ embedMs: 0,
214
+ embedCacheHits: 0,
215
+ embedCacheMisses: 0,
216
+ overBudgetRuns: 0,
217
+ runsWithTelemetry: 0,
218
+ };
219
+ const coverage = improve.coverage;
220
+ const degradation = improve.degradation;
221
+ const minting = improve.enrichmentMinting;
222
+ // #576: real per-stage LLM token/time accounting (replaces the GPU-time
223
+ // proxy). Optional-guarded so reports built from older health JSON without
224
+ // the aggregate still render.
225
+ const llm = result.metrics.llmUsage ?? {
226
+ calls: 0,
227
+ totalDurationMs: 0,
228
+ promptTokens: 0,
229
+ completionTokens: 0,
230
+ totalTokens: 0,
231
+ reasoningTokens: 0,
232
+ byStage: {},
233
+ byProcess: {},
234
+ byEngine: {},
235
+ };
236
+ const totalRuns = runs.length;
237
+ const failedRuns = runs.filter((r) => !r.ok).length;
238
+ const invoked = improve.invoked || totalRuns;
239
+ const completed = improve.completed || totalRuns - failedRuns;
240
+ const miWritten = mi.written;
241
+ return {
242
+ consolidation: cons,
243
+ memoryInference: mi,
244
+ graphExtraction: ge,
245
+ wallTime,
246
+ perf,
247
+ coverage,
248
+ degradation,
249
+ minting,
250
+ llm,
251
+ memorySummary: improve.memorySummary,
252
+ includedResultRows: improve.resultRows?.included ?? totalRuns,
253
+ skippedInvalidResultRows: improve.resultRows?.skipped.invalid ?? invalidRuns.length,
254
+ invoked,
255
+ completed,
256
+ miWritten,
257
+ completionRate: invoked ? `${Math.round((100 * completed) / invoked)}%` : "0%",
258
+ completionPct: invoked ? (100 * completed) / invoked : 100,
259
+ taskFailRate: pct(result.metrics.taskFailRate, 1),
260
+ agentFailRate: pct(result.metrics.agentFailureRate, 2),
261
+ miYieldRate: pct(mi.yieldRate, 1),
262
+ medianDurMin: (wallTime.medianMs / 60000).toFixed(1),
263
+ p95DurMin: (wallTime.p95Ms / 60000).toFixed(1),
264
+ avgPromoted: totalRuns ? String(Math.round(cons.promoted / totalRuns)) : "0",
265
+ chunkFail: `${num(cons.failedChunks)} / ${num(cons.totalChunks)}`,
266
+ llmTokensCompact: compact(llm.totalTokens),
267
+ totalRuns,
268
+ failedRuns,
269
+ };
270
+ }
271
+ /**
272
+ * Meta (collect.py steps 10-11) + freshness. Staleness is computed
273
+ * deterministically (no Date.now()) from the gap between the window start
274
+ * (`since`) and the newest run we have: if no run landed in the window, or
275
+ * the newest run sits in the first 25% of a window wider than the 6h
276
+ * threshold (i.e. a long idle tail), we flag stale.
277
+ */
278
+ function buildMetaPhase(result, runs) {
279
+ const sinceIso = result.since;
280
+ const reportDate = sinceIso.slice(0, 10);
281
+ const reportTitle = reportDate ? `AKM Health Report — ${reportDate}` : "AKM Health Report";
282
+ const lastRun = runs[runs.length - 1];
283
+ const generatedAt = lastRun ? lastRun.completedAt || lastRun.startedAt || sinceIso : sinceIso;
284
+ const latest = [...runs]
285
+ .filter((run) => run.resultComplete)
286
+ .sort(compareRuns)
287
+ .at(-1);
288
+ const STALE_MS = 6 * 60 * 60 * 1000;
289
+ const latestRunMs = lastRun ? Date.parse(lastRun.completedAt || lastRun.startedAt) : NaN;
290
+ const sinceMs = Date.parse(sinceIso);
291
+ const generatedMs = Date.parse(generatedAt);
292
+ const idleTailMs = Number.isFinite(latestRunMs) && Number.isFinite(generatedMs) ? Math.max(0, generatedMs - latestRunMs) : 0;
293
+ const isStale = runs.length === 0 || (Number.isFinite(latestRunMs) && Number.isFinite(sinceMs) && idleTailMs > STALE_MS);
294
+ return { sinceIso, reportDate, reportTitle, generatedAt, isStale, lastRun, latest };
295
+ }
296
+ const STATUS_LABEL = { pass: "PASS", warn: "WARN", fail: "FAIL" };
297
+ /**
298
+ * Synthesized verdict (one sentence + 2-3 drivers). The verdict WORD is the
299
+ * authoritative health status (hard checks). Concerns (failed improve runs,
300
+ * blocked search, pending proposals) are advisory and do NOT gate that word,
301
+ * so a green PASS is never paired with red "drivers" as if they were
302
+ * failures. When the status is PASS we frame concerns as "watch:" alongside
303
+ * the trend; only a degraded status (WARN/FAIL) leads with them.
304
+ */
305
+ function buildVerdictPhase(result, trend, sem, proposals, failedRuns) {
306
+ const statusLabel = STATUS_LABEL[result.status];
307
+ const failOk = result.metrics.taskFailRate < TASK_FAIL_RATE_WARN;
308
+ const concerns = [];
309
+ if (failedRuns > 0)
310
+ concerns.push(`${failedRuns} failed run${failedRuns === 1 ? "" : "s"}`);
311
+ if (sem.blocked)
312
+ concerns.push("semantic search blocked");
313
+ if (proposals.length > 0)
314
+ concerns.push(`${proposals.length} pending proposal${proposals.length === 1 ? "" : "s"}`);
315
+ const trendClause = trend.overall === "improving"
316
+ ? "throughput and latency improving"
317
+ : trend.overall === "degrading"
318
+ ? "throughput or latency degrading"
319
+ : "throughput and latency steady";
320
+ const verdictWord = statusLabel;
321
+ let verdictRest;
322
+ if (result.status === "pass") {
323
+ const watch = concerns.length > 0 ? `; watch: ${concerns.slice(0, 3).join(", ")}` : "";
324
+ verdictRest = `healthy, ${trendClause}${watch}`;
325
+ }
326
+ else {
327
+ const lead = concerns.length > 0 ? concerns.slice(0, 3).join("; ") : trendClause;
328
+ verdictRest = trend.overall === "degrading" && concerns.length > 0 ? `${lead}; ${trendClause}` : lead;
329
+ }
330
+ return { status: result.status, failOk, statusLabel, concerns, trendClause, verdictWord, verdictRest };
331
+ }
332
+ /** Distill skip-reason chart categories (collect.py chart payload step). */
333
+ function computeDistillReasons(runs) {
334
+ return [...new Set(runs.flatMap((r) => Object.keys(r.distillByReason)))]
335
+ .filter((reason) => !DISTILL_REASONS_HIDDEN.has(reason))
336
+ .sort();
337
+ }
338
+ /** Proposals grouped by `source`, sorted alphabetically (drain-proposals action item). */
339
+ function groupProposalsBySource(proposals) {
340
+ const bySource = new Map();
341
+ for (const p of proposals)
342
+ bySource.set(p.source, (bySource.get(p.source) ?? 0) + 1);
343
+ return [...bySource.entries()].sort(([a], [b]) => a.localeCompare(b));
344
+ }
345
+ /** Summary table rows: the base metric set + the WS-5 coverage/minting/perf/degradation extensions, when present. */
346
+ function buildSummaryRows(aggregates, trend) {
347
+ const { consolidation: cons, graphExtraction: ge, wallTime, llm, coverage, minting, perf, degradation } = aggregates;
348
+ const summaryRows = [
349
+ ["Task fail rate", aggregates.taskFailRate, "flat"],
350
+ ["Agent fail rate", aggregates.agentFailRate, "flat"],
351
+ ["Improve completion", `${num(aggregates.completed)} / ${num(aggregates.invoked)}`, "flat"],
352
+ [
353
+ "MI yield rate",
354
+ aggregates.miYieldRate,
355
+ trend.decisionQuality,
356
+ "Memory-inference yield: share of considered candidates that produced a written fact.",
357
+ ],
358
+ ["MI written", num(aggregates.miWritten), trend.outputVolume, "Memory-inference: facts written this window."],
359
+ ["Consolidation promoted", num(cons.promoted), trend.outputVolume],
360
+ ["Consolidation merged", num(cons.merged), "flat"],
361
+ ["Consolidation deleted", num(cons.deleted), "flat"],
362
+ ["Consolidation contradicted", num(cons.contradicted), "flat"],
363
+ [
364
+ "Consolidation judged: no action",
365
+ num(cons.judgedNoAction),
366
+ "flat",
367
+ "Candidates reviewed but intentionally left unchanged (the 'judgedNoAction' field).",
368
+ ],
369
+ ["Chunk failure", aggregates.chunkFail, "flat"],
370
+ ["Graph entities", num(ge.entities), "up"],
371
+ ["Graph relations", num(ge.relations), "up"],
372
+ [
373
+ "Stash derived",
374
+ num(aggregates.memorySummary.derived),
375
+ "up",
376
+ "Whole-bundle recount of derived assets at report time — not a per-run sum.",
377
+ ],
378
+ ["Median wall time", fmtMs(wallTime.medianMs), trend.latency],
379
+ ["P95 wall time", fmtMs(wallTime.p95Ms), trend.latency],
380
+ // #576: real LLM accounting (replaces the GPU-time proxy).
381
+ ["LLM calls", num(llm.calls), "flat"],
382
+ ["LLM total tokens", num(llm.totalTokens), "flat"],
383
+ ["LLM prompt tokens", num(llm.promptTokens), "flat"],
384
+ ["LLM completion tokens", num(llm.completionTokens), "flat"],
385
+ [
386
+ "LLM reasoning tokens",
387
+ num(llm.reasoningTokens),
388
+ "flat",
389
+ "Tokens spent on model reasoning/thinking, billed separately from prompt and completion.",
390
+ ],
391
+ ["LLM wall time", fmtMs(llm.totalDurationMs), trend.latency],
392
+ ];
393
+ // WS-5: denominator-fixed coverage rows (only when we have real data).
394
+ if (coverage && !Number.isNaN(coverage.rate)) {
395
+ summaryRows.push([
396
+ "Coverage rate",
397
+ pct(coverage.rate, 1),
398
+ "flat",
399
+ "Distinct accepted refs / total stash assets (denominator-fixed). Shows what fraction of the corpus has been touched.",
400
+ ], [
401
+ "Eligible fraction",
402
+ pct(coverage.eligibleFraction, 1),
403
+ "flat",
404
+ "Eligible assets / total stash assets. Fraction the improve pipeline actively considers.",
405
+ ], [
406
+ "Coverage accepted",
407
+ num(coverage.acceptedProposals),
408
+ "flat",
409
+ "Total accepted proposals in the window (raw volume — includes repeated rewrites of the same asset).",
410
+ ], [
411
+ "Churn ratio",
412
+ Number.isFinite(coverage.churnRatio) ? num(coverage.churnRatio) : "—",
413
+ Number.isFinite(coverage.churnRatio) && coverage.churnRatio > 1.5 ? "down" : "flat",
414
+ "Accepted proposals / distinct refs touched. >1.5 = the loop is repeatedly rewriting the same assets (churn, not coverage).",
415
+ ]);
416
+ }
417
+ // Enrichment-vs-minting policy rollup (reporting-only).
418
+ if (minting && Number.isFinite(minting.share)) {
419
+ summaryRows.push([
420
+ "Enrichment-lane minted share",
421
+ pct(minting.share, 1),
422
+ minting.share > 0.05 ? "down" : "flat",
423
+ `New assets minted by enrichment lanes / their accepted total (${minting.minted} minted vs ${minting.updated} updated). Enrichment lanes are ratified to edit existing assets only; WARN >5%, FAIL >15%.`,
424
+ ]);
425
+ }
426
+ // WS-5: perf telemetry rows (only when at least one run reported telemetry).
427
+ if (perf.runsWithTelemetry > 0) {
428
+ const embedCacheTotal = perf.embedCacheHits + perf.embedCacheMisses;
429
+ const embedCacheHitRate = embedCacheTotal > 0 ? pct(perf.embedCacheHits / embedCacheTotal, 1) : "—";
430
+ summaryRows.push([
431
+ "Embed cache hit rate",
432
+ embedCacheHitRate,
433
+ "flat",
434
+ "Fraction of embedding lookups served from cache (>95% is healthy). Aggregated across WS-5 runs.",
435
+ ], [
436
+ "Embed wall time",
437
+ fmtMs(perf.embedMs),
438
+ "flat",
439
+ "Cumulative embedding wall-clock time across consolidation runs in the window.",
440
+ ], [
441
+ "Dedup pool size",
442
+ num(perf.dedupPoolSize),
443
+ "flat",
444
+ "Memory pool size after incremental narrowing, before the limit cap. WS-5 perf telemetry.",
445
+ ], [
446
+ "Over-budget consolidation runs",
447
+ String(perf.overBudgetRuns),
448
+ perf.overBudgetRuns > 0 ? "down" : "flat",
449
+ "Runs where consolidation alone exceeded the total run budget (estimatedBudgetFractionUsed > 1.0).",
450
+ ]);
451
+ }
452
+ // WS-5: degradation metrics rows.
453
+ if (degradation) {
454
+ summaryRows.push([
455
+ "Corpus diversity (Gini)",
456
+ num(degradation.corpusCentroidDistance),
457
+ degradation.entrenchmentFlagged || degradation.salienceUniformityFlagged ? "down" : "flat",
458
+ "Gini coefficient of retrieval_salience for top-100 ranked assets. Two-tailed: >0.35 = entrenchment risk; <0.08 = collapsed toward uniform (ranking no longer discriminates).",
459
+ ], [
460
+ "Merge fidelity contradiction rate",
461
+ pct(degradation.mergeFidelityContradictionRate, 1),
462
+ "flat",
463
+ "Fraction of consolidated proposals that involved a contradiction, from consolidation result envelopes.",
464
+ ]);
465
+ }
466
+ return summaryRows;
467
+ }
468
+ /**
469
+ * Extract the health HTML report's view model from an `AkmHealthResult` +
470
+ * report options. Pure — no HTML, no I/O, no clock/RNG reads. Byte-identical
471
+ * output for identical inputs, mirroring the pre-split
472
+ * `buildHealthHtmlReplacements` arithmetic exactly. File-level decomposed
473
+ * (chunk-9 WI-9.5a) into one phase helper per section above; this function is
474
+ * the extract-then-compose glue.
475
+ */
476
+ export function buildHealthReportViewModel(result, opts) {
477
+ const deltas = opts.deltas ?? {};
478
+ const proposals = opts.proposals;
479
+ const runsPhase = partitionRuns(result);
480
+ const sem = readSemSearch(result.advisories);
481
+ const trend = buildTrend(deltas);
482
+ const aggregates = buildAggregatesPhase(result, runsPhase);
483
+ const meta = buildMetaPhase(result, runsPhase.runs);
484
+ const verdict = buildVerdictPhase(result, trend, sem, proposals, aggregates.failedRuns);
485
+ const distillReasons = computeDistillReasons(runsPhase.runs);
486
+ const proposalsBySource = groupProposalsBySource(proposals);
487
+ const summaryRows = buildSummaryRows(aggregates, trend);
488
+ return {
489
+ window: opts.window,
490
+ compare: opts.compare,
491
+ comparisonMode: opts.comparisonMode ?? "duration",
492
+ ...meta,
493
+ runs: runsPhase.runs,
494
+ invalidRuns: runsPhase.invalidRuns,
495
+ ...verdict,
496
+ ...aggregates,
497
+ trend,
498
+ deltas,
499
+ sem,
500
+ proposals,
501
+ proposalsBySource,
502
+ summaryRows,
503
+ sliceCandidates: computeSliceCandidates(opts.window),
504
+ distillReasons,
505
+ advisories: result.advisories,
506
+ sessionLogAdvisories: result.sessionLogAdvisories,
507
+ };
508
+ }
@@ -40,7 +40,7 @@ export function collectStashExposureAdvisory(stashDir, git = realGit) {
40
40
  message: `${trackedFiles.length} env/secret file(s) are git-tracked AND a remote is configured — ` +
41
41
  `a 'git push' can leak tokens/keys (${preview}). ` +
42
42
  "Run 'git rm --cached' on them (a .gitignore rule alone does NOT untrack already-tracked " +
43
- "files) and then add env/+secrets/ to .gitignore to prevent recurrence (akm init scaffolds it).",
43
+ "files) and then add env/+secrets/ to .gitignore to prevent recurrence (akm bundle create scaffolds it).",
44
44
  evidence: { trackedSecretFiles: trackedFiles },
45
45
  };
46
46
  }
@@ -4,11 +4,10 @@
4
4
  /**
5
5
  * The remaining `surfaces` advisory group for `akm health` (meta-review 08).
6
6
  * `stash-git-exposure` (08-F1) shipped first in ./stash-exposure.ts; this
7
- * module adds the other four read-only checks the adjudication approved:
7
+ * module adds the other three read-only checks the adjudication approved:
8
8
  *
9
9
  * - `secret-file-perms` — env/secret/backup files not 0600, dirs not 0700 (F4)
10
10
  * - `binary-config-skew` — config.json written by a NEWER akm than this binary (F3)
11
- * - `orphan-stores` — legacy config-backups dirs + 0-byte stash state.db decoy (F4/F7)
12
11
  * - `egress-endpoints` — the remote-destination list, for eyeball diff (surfaces 3/9)
13
12
  *
14
13
  * Every collector is a pure projection over injected paths/config (no
@@ -18,7 +17,9 @@
18
17
  */
19
18
  import fs from "node:fs";
20
19
  import path from "node:path";
21
- import { CURRENT_CONFIG_VERSION, compareConfigVersion } from "../../core/config/config-migration.js";
20
+ import { MAX_CONFIG_FILE_BYTES, readTextFileWithLimit } from "../../core/common.js";
21
+ import { CURRENT_CONFIG_VERSION } from "../../core/config/config-schema.js";
22
+ import { compareConfigVersion } from "../../core/config/config-version.js";
22
23
  const GROUP_OTHER_BITS = 0o077;
23
24
  const OFFENDER_EVIDENCE_CAP = 50;
24
25
  function modeOctal(mode) {
@@ -97,7 +98,7 @@ export function collectSecretPermsAdvisory(input, platform = process.platform) {
97
98
  export function collectConfigSkewAdvisory(configPath) {
98
99
  let raw;
99
100
  try {
100
- raw = JSON.parse(fs.readFileSync(configPath, "utf8"));
101
+ raw = JSON.parse(readTextFileWithLimit(configPath, MAX_CONFIG_FILE_BYTES, "Config file"));
101
102
  }
102
103
  catch {
103
104
  return undefined;
@@ -118,49 +119,6 @@ export function collectConfigSkewAdvisory(configPath) {
118
119
  evidence: { onDiskConfigVersion: onDisk, binaryConfigVersion: CURRENT_CONFIG_VERSION },
119
120
  };
120
121
  }
121
- /**
122
- * `orphan-stores` (08-F4/F7): stores that look load-bearing but are dead —
123
- * legacy `config-backups/` dirs in $DATA/$CONFIG (only `$CACHE/config-backups`
124
- * is written and pruned today) and a 0-byte `<stash>/.akm/state.db` decoy that
125
- * misleads debugging (the live state.db lives in the data dir). Read-only:
126
- * this advisory NAMES them; removal stays an owner-approved per-path action.
127
- */
128
- export function collectOrphanStoresAdvisory(input) {
129
- const orphans = [];
130
- for (const [label, dir] of [
131
- ["legacy data-dir backup location", path.join(input.dataDir, "config-backups")],
132
- ["legacy config-dir backup location", path.join(input.configDir, "config-backups")],
133
- ]) {
134
- try {
135
- if (fs.statSync(dir).isDirectory())
136
- orphans.push(`${dir}/ (${label}; live backups are in $CACHE/config-backups)`);
137
- }
138
- catch {
139
- // absent — fine
140
- }
141
- }
142
- const decoy = path.join(input.stashDir, ".akm", "state.db");
143
- try {
144
- const stat = fs.statSync(decoy);
145
- if (stat.isFile() && stat.size === 0) {
146
- orphans.push(`${decoy} (0-byte decoy; the live state.db is in the data dir)`);
147
- }
148
- }
149
- catch {
150
- // absent — fine
151
- }
152
- if (orphans.length === 0)
153
- return undefined;
154
- return {
155
- name: "orphan-stores",
156
- kind: "deterministic",
157
- status: "warn",
158
- confidence: "high",
159
- message: `${orphans.length} orphan store(s) found: ${orphans.join("; ")}. ` +
160
- "These are dead locations that mislead debugging/recovery — review and remove them (owner-approved, per-path).",
161
- evidence: { orphans },
162
- };
163
- }
164
122
  /**
165
123
  * `egress-endpoints` (08 surfaces 3/9): the full list of remote destinations
166
124
  * akm can talk to under the effective config — registries, remote sources,
@@ -177,15 +135,18 @@ export function collectEgressAdvisory(config) {
177
135
  continue;
178
136
  endpoints.push(`registry ${reg.name ?? "(unnamed)"}: ${reg.url}`);
179
137
  }
180
- for (const source of config.sources ?? []) {
181
- if (source.enabled === false || !source.url)
138
+ for (const [key, bundle] of Object.entries(config.bundles ?? {})) {
139
+ if (!bundle)
140
+ continue;
141
+ const url = bundle.git ?? bundle.website?.url;
142
+ if (!url)
182
143
  continue;
183
- endpoints.push(`source ${source.name ?? "(unnamed)"} (${source.type ?? "?"}): ${source.url}`);
144
+ endpoints.push(`source ${key} (${bundle.git ? "git" : "website"}): ${url}`);
184
145
  }
185
- for (const [name, profile] of Object.entries(config.profiles?.llm ?? {})) {
186
- if (!profile?.endpoint)
146
+ for (const [name, engine] of Object.entries(config.engines ?? {})) {
147
+ if (engine?.kind !== "llm" || !engine.endpoint)
187
148
  continue;
188
- endpoints.push(`llm ${name}: ${profile.endpoint}`);
149
+ endpoints.push(`llm ${name}: ${engine.endpoint}`);
189
150
  }
190
151
  if (config.embedding?.endpoint)
191
152
  endpoints.push(`embedding: ${config.embedding.endpoint}`);
@@ -202,14 +163,13 @@ export function collectEgressAdvisory(config) {
202
163
  };
203
164
  }
204
165
  /**
205
- * Aggregate the four collectors into the advisories array shape `akmHealth`
206
- * consumes. Order is fixed: perms → skew → orphans → egress.
166
+ * Aggregate the three collectors into the advisories array shape `akmHealth`
167
+ * consumes. Order is fixed: perms → skew → egress.
207
168
  */
208
169
  export function collectSurfacesAdvisories(input) {
209
170
  const results = [
210
171
  collectSecretPermsAdvisory({ stashDir: input.stashDir, cacheDir: input.cacheDir }, input.platform ?? process.platform),
211
172
  collectConfigSkewAdvisory(input.configPath),
212
- collectOrphanStoresAdvisory({ dataDir: input.dataDir, configDir: input.configDir, stashDir: input.stashDir }),
213
173
  collectEgressAdvisory(input.config),
214
174
  ];
215
175
  return results.filter((r) => r !== undefined);