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
@@ -7,7 +7,7 @@
7
7
  * Given a single asset body (typically a `memory:` or `knowledge:` file),
8
8
  * asks the configured LLM to surface the entities mentioned in it and the
9
9
  * relations between them. The pass itself
10
- * (`src/indexer/graph-extraction.ts`) is responsible for deciding which
10
+ * (`src/indexer/graph/graph-extraction.ts`) is responsible for deciding which
11
11
  * files to extract, persisting the resulting nodes/edges to the index DB,
12
12
  * and feeding the graph data into the FTS5+boosts
13
13
  * search pipeline as a single boost component.
@@ -15,16 +15,15 @@
15
15
  * This module is intentionally tiny and stateless so tests can stub it via
16
16
  * `mock.module("../src/llm/graph-extract", ...)` without hitting a network.
17
17
  *
18
- * Locked v1 contract (#208): the LLM connection always comes from the
19
- * shared `akm.llm` block — never from a per-pass override. Callers obtain
20
- * the connection via `resolveIndexPassLLM("graph", config)` and pass it
21
- * straight through.
18
+ * The LLM connection comes from the selected named engine. Callers obtain it
19
+ * via `resolveIndexPassLLM("graph", config)` and pass it straight through.
22
20
  */
23
21
  import systemPromptTemplate from "../assets/prompts/graph-extract-system.md" with { type: "text" };
24
22
  import userPromptTemplate from "../assets/prompts/graph-extract-user-prompt.md" with { type: "text" };
25
23
  import { toErrorMessage } from "../core/common.js";
24
+ import { parseEmbeddedJsonResponse } from "../core/parse.js";
26
25
  import { warn, warnVerbose } from "../core/warn.js";
27
- import { chatCompletion, isContextSizeError, parseEmbeddedJsonResponse } from "./client.js";
26
+ import { chatCompletion, isContextSizeError } from "./client.js";
28
27
  import { tryLlmFeature } from "./feature-gate.js";
29
28
  import { callStructured } from "./structured-call.js";
30
29
  /**
@@ -47,11 +46,6 @@ const SYSTEM_PROMPT = systemPromptTemplate;
47
46
  const USER_PROMPT_PREFIX = userPromptTemplate
48
47
  .replace("{{MAX_ENTITIES}}", String(MAX_ENTITIES_PER_ASSET))
49
48
  .replace("{{MAX_RELATIONS}}", String(MAX_RELATIONS_PER_ASSET));
50
- // `isContextSizeError` is defined in `./client` and re-exported here so the
51
- // graph extractor and the retry classifier (`isRetryable`) share one
52
- // definition (#496). Re-exported (not just imported) to preserve existing
53
- // importers of this module — including its unit test.
54
- export { isContextSizeError } from "./client.js";
55
49
  const GENERIC_ENTITIES = new Set([
56
50
  "agent",
57
51
  "application",
@@ -749,5 +743,10 @@ export async function extractGraphFromBody(llmConfig, body, signal, akmConfig, o
749
743
  onFallback,
750
744
  });
751
745
  }
752
- // deduplicateGraph moved to src/indexer/graph-dedup.ts (pure utility, no LLM calls).
753
- export { deduplicateGraph } from "../indexer/graph/graph-dedup.js";
746
+ // deduplicateGraph lives in src/indexer/graph/graph-dedup.ts (pure utility, no
747
+ // LLM calls) — import it from there directly. The re-export that used to live
748
+ // here created a value edge back to graph-dedup.ts, which (via its type-only
749
+ // import of GraphExtraction/GraphRelation below) formed a 2-file import cycle
750
+ // (chunk 9 WI-9.8 KILL 4 sever). No src or test consumer used this re-export
751
+ // (graph-extraction.ts and the test suite already import graph-dedup.ts
752
+ // directly), so it is deleted outright rather than repointed.
@@ -1,50 +1,16 @@
1
1
  // This Source Code Form is subject to the terms of the Mozilla Public
2
2
  // License, v. 2.0. If a copy of the MPL was not distributed with this
3
3
  // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
- import { getDefaultLlmConfig, getIndexPassConfig } from "../core/config/config.js";
4
+ import { materializeLlmConnection, resolveLlmEngineUse } from "../integrations/agent/engine-resolution.js";
5
5
  /**
6
- * Map a pass name (as used by callers — "memory", "graph", etc.) to the
7
- * matching key under `profiles.improve.default.processes`. Pass names with
8
- * no improve-profile counterpart return undefined and resolve via the
9
- * default LLM only.
6
+ * Resolve standalone index passes from the index section only. Improve
7
+ * strategies own improve-triggered calls and are intentionally not consulted.
10
8
  */
11
- function improveProcessKeyForPass(passName) {
12
- switch (passName) {
13
- case "memory":
14
- return "memoryInference";
15
- case "graph":
16
- return "graphExtraction";
17
- default:
18
- return undefined;
19
- }
20
- }
21
9
  export function resolveIndexPassLLM(passName, config) {
22
- // Gate 1 — explicit opt-out via the index-config block stays authoritative.
23
- const passConfig = getIndexPassConfig(config.index, passName);
24
- if (passConfig?.llm === false)
10
+ const pass = config.index?.[passName];
11
+ if (pass?.enabled === false)
25
12
  return undefined;
26
- // Gate 2 — per-process profile from the improve profile, when present.
27
- // This is the path that lets
28
- // profiles.improve.default.processes.graphExtraction.profile = "ministral-3b"
29
- // actually take effect on the graph pass instead of being silently
30
- // ignored.
31
- const processKey = improveProcessKeyForPass(passName);
32
- if (processKey) {
33
- const processConfig = config.profiles?.improve?.default?.processes?.[processKey];
34
- // Honor enabled === false here too — an explicit disable wins.
35
- if (processConfig?.enabled === false)
36
- return undefined;
37
- const profileName = processConfig?.profile;
38
- if (profileName) {
39
- const profile = config.profiles?.llm?.[profileName];
40
- if (profile)
41
- return profile;
42
- // A named-but-missing profile is a configuration error in spirit, but
43
- // we fall through to default rather than throwing — callers gracefully
44
- // treat `undefined` as "pass disabled" and emitting a hard throw here
45
- // would take the whole improve run down on a typo.
46
- }
47
- }
48
- // Gate 3 — fall back to the default LLM profile.
49
- return getDefaultLlmConfig(config);
13
+ const defaults = config.index?.defaults;
14
+ const resolved = resolveLlmEngineUse(config, [defaults ?? {}, pass ?? {}], { optional: true });
15
+ return resolved ? materializeLlmConnection(resolved) : undefined;
50
16
  }
@@ -1,4 +1,147 @@
1
1
  // This Source Code Form is subject to the terms of the Mozilla Public
2
2
  // License, v. 2.0. If a copy of the MPL was not distributed with this
3
3
  // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
- export { compressMemoryToDerivedMemory, } from "./memory-infer-impl.js";
4
+ /**
5
+ * LLM helper for the `akm index` memory-inference pass (#201).
6
+ *
7
+ * Compresses a single memory body into one higher-signal derived memory. The
8
+ * pass itself (in `src/indexer/passes/memory-inference.ts`) is responsible for
9
+ * deciding which memories are pending, persisting the derived memory with the
10
+ * correct frontmatter (`inferred: true`, `source: <parent-ref>`), and marking
11
+ * the parent as processed for idempotency.
12
+ *
13
+ * This module is intentionally tiny and stateless so tests can stub it via
14
+ * `mock.module("../src/llm/memory-infer", ...)` without hitting a network.
15
+ *
16
+ * The LLM connection comes from the selected named engine. Callers obtain it
17
+ * via `resolveIndexPassLLM("memory", config)` and pass it straight through.
18
+ */
19
+ import memoryInferSystemPrompt from "../assets/prompts/memory-infer-system.md" with { type: "text" };
20
+ import memoryInferUserPrompt from "../assets/prompts/memory-infer-user.md" with { type: "text" };
21
+ import { toErrorMessage } from "../core/common.js";
22
+ import { parseEmbeddedJsonResponse } from "../core/parse.js";
23
+ import { warn } from "../core/warn.js";
24
+ import { callStructured } from "./structured-call.js";
25
+ /** Hard cap on body chars sent to the model — pragmatic and matches `runLlmEnrich`. */
26
+ const MAX_BODY_CHARS = 4000;
27
+ const SYSTEM_PROMPT = memoryInferSystemPrompt;
28
+ const USER_PROMPT_PREFIX = memoryInferUserPrompt;
29
+ const PROMPT_PLACEHOLDERS = new Set([
30
+ "short title string",
31
+ "one sentence summary string",
32
+ "tag1",
33
+ "tag2",
34
+ "search phrase 1",
35
+ "search phrase 2",
36
+ "2-3 sentence compressed body preserving key facts verbatim",
37
+ ]);
38
+ /**
39
+ * Strict JSON Schema for the derived-memory payload. Sent to providers that
40
+ * opt in via `ChatCompletionConfig.supportsJsonSchema = true`; the client
41
+ * silently drops the schema for providers that don't.
42
+ *
43
+ * Extends the responseSchema lift (PR 1, asset-writers-investigation §5) to
44
+ * the memory-inference path. Mirrors the validation gate below
45
+ * (title/description/content + non-empty tags/searchHints) so a
46
+ * schema-compliant response is guaranteed to pass the downstream check
47
+ * — no more "incomplete derived memory payload from LLM; skipping memory"
48
+ * for shape-only failures.
49
+ */
50
+ const DERIVED_MEMORY_JSON_SCHEMA = {
51
+ type: "object",
52
+ properties: {
53
+ title: { type: "string", minLength: 1 },
54
+ description: { type: "string", minLength: 1 },
55
+ content: { type: "string", minLength: 1 },
56
+ tags: { type: "array", items: { type: "string" }, minItems: 1, maxItems: 8 },
57
+ searchHints: { type: "array", items: { type: "string" }, minItems: 1, maxItems: 6 },
58
+ },
59
+ required: ["title", "description", "content", "tags", "searchHints"],
60
+ additionalProperties: false,
61
+ };
62
+ /**
63
+ * Compress a single memory body into one derived memory via the configured LLM.
64
+ *
65
+ * Returns `undefined` on any failure (timeout, invalid JSON, empty response).
66
+ * Errors are logged via `warn()` but never thrown — a failed split for one memory
67
+ * must not abort the rest of the index pass.
68
+ *
69
+ * Routes through `callStructured({ feature: "memory_inference", ... })` so the
70
+ * feature gate, error classification, and onFallback hook are honoured uniformly
71
+ * (Fix C5).
72
+ */
73
+ export async function compressMemoryToDerivedMemory(llmConfig, body, signal, akmConfig, onFallback, telemetry, onRetryAttempt) {
74
+ const trimmedBody = body.trim();
75
+ if (!trimmedBody)
76
+ return undefined;
77
+ const userPrompt = `${USER_PROMPT_PREFIX}${trimmedBody.slice(0, MAX_BODY_CHARS)}`;
78
+ // Memory inference is always gated: no config closes the gate instead of
79
+ // taking callStructured's ungated path for direct callers.
80
+ if (!akmConfig) {
81
+ onFallback?.({ feature: "memory_inference", reason: "disabled" });
82
+ return undefined;
83
+ }
84
+ return callStructured({
85
+ feature: "memory_inference",
86
+ akmConfig,
87
+ config: llmConfig,
88
+ messages: [
89
+ { role: "system", content: SYSTEM_PROMPT },
90
+ { role: "user", content: userPrompt },
91
+ ],
92
+ request: {
93
+ temperature: 0.1,
94
+ timeoutMs: llmConfig.timeoutMs,
95
+ signal,
96
+ responseSchema: DERIVED_MEMORY_JSON_SCHEMA,
97
+ onRetryAttempt,
98
+ },
99
+ parse: (raw) => {
100
+ if (!raw)
101
+ return undefined;
102
+ const parsed = parseEmbeddedJsonResponse(raw);
103
+ if (!parsed) {
104
+ warn("memory inference: invalid JSON response from LLM; skipping memory.");
105
+ return undefined;
106
+ }
107
+ const title = typeof parsed.title === "string" ? parsed.title.trim() : "";
108
+ const description = typeof parsed.description === "string" ? parsed.description.trim() : "";
109
+ const content = typeof parsed.content === "string" ? parsed.content.trim() : "";
110
+ const tags = Array.isArray(parsed.tags)
111
+ ? parsed.tags
112
+ .filter((t) => typeof t === "string")
113
+ .map((t) => t.trim())
114
+ .filter(Boolean)
115
+ .slice(0, 8)
116
+ : [];
117
+ const searchHints = Array.isArray(parsed.searchHints)
118
+ ? parsed.searchHints
119
+ .filter((h) => typeof h === "string")
120
+ .map((h) => h.trim())
121
+ .filter(Boolean)
122
+ .slice(0, 6)
123
+ : [];
124
+ if (!title || !description || !content || tags.length === 0 || searchHints.length === 0) {
125
+ warn("memory inference: incomplete derived memory payload from LLM; skipping memory.");
126
+ return undefined;
127
+ }
128
+ if ([title, description, content, ...tags, ...searchHints].some((value) => PROMPT_PLACEHOLDERS.has(value.toLowerCase()))) {
129
+ warn("memory inference: prompt placeholder response from LLM; skipping memory.");
130
+ return undefined;
131
+ }
132
+ return { title, description, tags, searchHints, content };
133
+ },
134
+ onError: (cls, err) => {
135
+ if (cls === "html") {
136
+ if (telemetry)
137
+ telemetry.htmlErrorCount = (telemetry.htmlErrorCount ?? 0) + 1;
138
+ warn(`memory inference: provider returned HTML instead of JSON; skipping memory: ${toErrorMessage(err)}`);
139
+ return undefined;
140
+ }
141
+ warn(`memory inference failed: ${toErrorMessage(err)}`);
142
+ return undefined;
143
+ },
144
+ fallback: undefined,
145
+ onFallback,
146
+ });
147
+ }
@@ -4,12 +4,11 @@
4
4
  /**
5
5
  * LLM-driven metadata enhancement for stash entries.
6
6
  *
7
- * Split out of `llm.ts` so the higher-level workflow (prompting the LLM to
8
- * improve descriptions/tags/searchHints) lives separately from the low-level
9
- * transport client in `client.ts`.
7
+ * Keeps the higher-level workflow for improving descriptions, tags, and search
8
+ * hints separate from the low-level transport client.
10
9
  */
11
10
  import metadataEnhanceSystemPrompt from "../assets/prompts/metadata-enhance-system.md" with { type: "text" };
12
- import { parseJsonResponse } from "./client.js";
11
+ import { parseJsonResponse } from "../core/parse.js";
13
12
  import { callStructured } from "./structured-call.js";
14
13
  const SYSTEM_PROMPT = metadataEnhanceSystemPrompt;
15
14
  /**
@@ -17,10 +16,11 @@ const SYSTEM_PROMPT = metadataEnhanceSystemPrompt;
17
16
  * generate searchHints, and suggest tags.
18
17
  *
19
18
  * When `akmConfig` is provided, routes through
20
- * `tryLlmFeature("metadata_enhance", ...)` so the feature gate is honoured and
21
- * errors are swallowed to `{}`. When `akmConfig` is `undefined` the gate is
22
- * bypassed entirely — the LLM call runs unconditionally and errors propagate to
23
- * the caller (pre-gate behaviour, used by direct callers such as tests).
19
+ * `tryLlmFeature("metadata_enhance", ...)` so the feature gate is honoured: a
20
+ * closed gate yields `{ status: "skipped" }` and a thrown/timed-out call yields
21
+ * `{ status: "failed" }` — neither is reported as an enrichment. When
22
+ * `akmConfig` is `undefined` the gate is bypassed entirely: the LLM call runs
23
+ * unconditionally and errors propagate to direct callers such as tests.
24
24
  */
25
25
  export async function enhanceMetadata(config, entry, fileContent, signal, akmConfig) {
26
26
  const contextParts = [`Name: ${entry.name}`, `Type: ${entry.type}`];
@@ -41,12 +41,14 @@ Generate improved metadata for this ${entry.type}. Return JSON with these fields
41
41
  - "tags": an array of 3-8 relevant keyword tags
42
42
 
43
43
  Return ONLY the JSON object, no explanation.`;
44
- // `parse` owns the raw response: the `!raw`/unparseable case ⇒ `{}`, plus the
45
- // description/searchHints/tags shaping. `enhanceMetadata` never warns and
46
- // never bumps telemetry, so `onError` (gated path only) just swallows to `{}`
47
- // — identical to the surrounding control flow's pre-migration behaviour. The
48
- // ungated path (akmConfig === undefined) propagates errors via callStructured.
49
- return callStructured({
44
+ // `parse` owns the raw response: the `!raw`/unparseable case ⇒ empty metadata
45
+ // (still a genuine success), plus the description/searchHints/tags shaping.
46
+ // `enhanceMetadata` never warns and never bumps telemetry — `onError` (gated
47
+ // path only) reports `failed` WITHOUT warning, carrying the message so the
48
+ // caller can surface it. The ungated path (akmConfig === undefined) propagates
49
+ // errors via callStructured.
50
+ let timedOut = false;
51
+ const outcome = await callStructured({
50
52
  feature: "metadata_enhance",
51
53
  akmConfig,
52
54
  config,
@@ -57,23 +59,36 @@ Return ONLY the JSON object, no explanation.`;
57
59
  request: { signal, timeoutMs: config.timeoutMs },
58
60
  parse: (raw) => {
59
61
  const parsed = raw ? parseJsonResponse(raw) : undefined;
60
- if (!parsed)
61
- return {};
62
- const result = {};
63
- if (typeof parsed.description === "string" && parsed.description) {
64
- result.description = parsed.description;
62
+ const metadata = {};
63
+ if (parsed) {
64
+ if (typeof parsed.description === "string" && parsed.description) {
65
+ metadata.description = parsed.description;
66
+ }
67
+ if (Array.isArray(parsed.searchHints)) {
68
+ metadata.searchHints = parsed.searchHints
69
+ .filter((s) => typeof s === "string" && s.trim().length > 0)
70
+ .slice(0, 8);
71
+ }
72
+ if (Array.isArray(parsed.tags)) {
73
+ metadata.tags = parsed.tags
74
+ .filter((s) => typeof s === "string" && s.trim().length > 0)
75
+ .slice(0, 10);
76
+ }
65
77
  }
66
- if (Array.isArray(parsed.searchHints)) {
67
- result.searchHints = parsed.searchHints
68
- .filter((s) => typeof s === "string" && s.trim().length > 0)
69
- .slice(0, 8);
70
- }
71
- if (Array.isArray(parsed.tags)) {
72
- result.tags = parsed.tags.filter((s) => typeof s === "string" && s.trim().length > 0).slice(0, 10);
73
- }
74
- return result;
78
+ return { status: "enriched", metadata };
79
+ },
80
+ onError: (_cls, err) => ({ status: "failed", error: err instanceof Error ? err.message : String(err) }),
81
+ fallback: { status: "skipped" },
82
+ // The seam returns the `skipped` fallback for a closed gate AND for a
83
+ // wrapper-level timeout. Record the timeout so we can reclassify it below —
84
+ // a timed-out call is a failure, not a silent skip.
85
+ onFallback: (event) => {
86
+ if (event.reason === "timeout")
87
+ timedOut = true;
75
88
  },
76
- onError: () => ({}),
77
- fallback: {},
78
89
  });
90
+ if (outcome.status === "skipped" && timedOut) {
91
+ return { status: "failed", error: "metadata_enhance timed out" };
92
+ }
93
+ return outcome;
79
94
  }
@@ -1,7 +1,7 @@
1
1
  // This Source Code Form is subject to the terms of the Mozilla Public
2
2
  // License, v. 2.0. If a copy of the MPL was not distributed with this
3
3
  // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
- import { chatCompletion, isContextSizeError, LlmCallError } from "./client.js";
4
+ import { chatCompletion, isContextSizeError, LlmCallError, } from "./client.js";
5
5
  import { tryLlmFeature } from "./feature-gate.js";
6
6
  /**
7
7
  * Classify a thrown LLM error into one of the three buckets. This is the single
@@ -17,14 +17,21 @@ export function classifyLlmError(err) {
17
17
  return "other";
18
18
  }
19
19
  export async function callStructured(opts) {
20
- const { feature, akmConfig, config, messages, request, parse, onError, fallback, onFallback } = opts;
20
+ const { feature, akmConfig, enabled, config, messages, request, parse, onError, fallback, onFallback } = opts;
21
21
  const chat = request?.chat ?? chatCompletion;
22
+ // Forward each option key ONLY when present on `request` — see the
23
+ // key-presence semantics note on CallStructuredRequest: for `timeoutMs`,
24
+ // present-but-undefined means "explicitly disabled" while absent means
25
+ // "use the default", both in the feature-gate wrapper and the transport.
26
+ const has = (key) => request !== undefined && Object.hasOwn(request, key);
22
27
  const chatOptions = {
23
- temperature: request?.temperature,
24
- timeoutMs: request?.timeoutMs,
25
- signal: request?.signal,
26
- responseSchema: request?.responseSchema,
27
- onRetryAttempt: request?.onRetryAttempt,
28
+ ...(has("temperature") ? { temperature: request?.temperature } : {}),
29
+ ...(has("timeoutMs") ? { timeoutMs: request?.timeoutMs } : {}),
30
+ ...(has("signal") ? { signal: request?.signal } : {}),
31
+ ...(has("responseSchema") ? { responseSchema: request?.responseSchema } : {}),
32
+ ...(has("maxTokens") ? { maxTokens: request?.maxTokens } : {}),
33
+ ...(has("enableThinking") ? { enableThinking: request?.enableThinking } : {}),
34
+ ...(has("onRetryAttempt") ? { onRetryAttempt: request?.onRetryAttempt } : {}),
28
35
  };
29
36
  // UNGATED: run the chat+parse directly. Errors propagate — no `onError`
30
37
  // funnel — matching the pre-gate behaviour of direct callers.
@@ -43,7 +50,8 @@ export async function callStructured(opts) {
43
50
  return onError(classifyLlmError(err), err);
44
51
  }
45
52
  }, fallback, {
46
- timeoutMs: request?.timeoutMs,
53
+ ...(has("timeoutMs") ? { timeoutMs: request?.timeoutMs } : {}),
54
+ ...(enabled !== undefined ? { enabled } : {}),
47
55
  onFallback,
48
56
  });
49
57
  }
@@ -23,14 +23,24 @@ import { appendEvent } from "../core/events.js";
23
23
  import { clearLlmUsageSink, hasLlmUsageSink, setLlmUsageSink } from "./usage-telemetry.js";
24
24
  /** Event type for persisted per-call LLM usage telemetry. */
25
25
  export const LLM_USAGE_EVENT = "llm_usage";
26
+ /** Event type for the owning sink's terminal-record count marker. */
27
+ export const LLM_USAGE_SUMMARY_EVENT = "llm_usage_summary";
26
28
  /**
27
29
  * Project a usage record into event metadata, dropping `undefined` token
28
30
  * fields so an absent-usage call records only `{stage, model, durationMs}`.
29
31
  */
30
32
  function toEventMetadata(record) {
31
- const metadata = { durationMs: record.durationMs };
33
+ const metadata = {
34
+ durationMs: record.durationMs,
35
+ outcome: record.outcome,
36
+ modelSource: record.modelSource,
37
+ };
32
38
  if (record.stage !== undefined)
33
39
  metadata.stage = record.stage;
40
+ if (record.engine !== undefined)
41
+ metadata.engine = record.engine;
42
+ if (record.process !== undefined)
43
+ metadata.process = record.process;
34
44
  if (record.model !== undefined)
35
45
  metadata.model = record.model;
36
46
  if (record.finishReason !== undefined)
@@ -43,6 +53,8 @@ function toEventMetadata(record) {
43
53
  metadata.totalTokens = record.totalTokens;
44
54
  if (record.reasoningTokens !== undefined)
45
55
  metadata.reasoningTokens = record.reasoningTokens;
56
+ if (record.errorCode !== undefined)
57
+ metadata.errorCode = record.errorCode;
46
58
  return metadata;
47
59
  }
48
60
  /**
@@ -52,20 +64,33 @@ function toEventMetadata(record) {
52
64
  * test-isolation harness sees a clean sink between tests).
53
65
  *
54
66
  * `ctx` should carry the same long-lived `state.db` handle the caller already
55
- * opened for its other events; when omitted, `appendEvent` falls back to its
56
- * default open-insert-close path.
67
+ * opened for its other events. A getter is resolved for every append so a
68
+ * caller can replace its context binding without replacing this owning sink.
69
+ * When omitted, `appendEvent` falls back to its default open-insert-close path.
57
70
  */
58
71
  export function installLlmUsagePersistence(ctx) {
72
+ let expectedTerminalRecords = 0;
73
+ let disposed = false;
59
74
  setLlmUsageSink((record) => {
60
- appendEvent({ eventType: LLM_USAGE_EVENT, metadata: toEventMetadata(record) }, ctx);
75
+ expectedTerminalRecords += 1;
76
+ appendEvent({ eventType: LLM_USAGE_EVENT, metadata: toEventMetadata(record) }, typeof ctx === "function" ? ctx() : ctx);
61
77
  });
62
78
  return () => {
79
+ if (disposed)
80
+ return;
81
+ disposed = true;
63
82
  clearLlmUsageSink();
83
+ try {
84
+ appendEvent({ eventType: LLM_USAGE_SUMMARY_EVENT, metadata: { expectedTerminalRecords } }, typeof ctx === "function" ? ctx() : ctx);
85
+ }
86
+ catch {
87
+ // Persistence remains best-effort even during run teardown.
88
+ }
64
89
  };
65
90
  }
66
91
  /**
67
92
  * Like {@link installLlmUsagePersistence}, but a no-op when a sink is already
68
- * installed — used by standalone entry points (`akm consolidate`, `akm drain`)
93
+ * installed — used by standalone entry points (`akm proposal drain`)
69
94
  * that may also run as a sub-step of `akm improve`. When invoked inside an
70
95
  * enclosing run the existing per-run sink keeps ownership; the returned
71
96
  * disposer then does nothing, so the enclosing run's `finally` still clears it.
@@ -5,7 +5,8 @@
5
5
  * Per-call LLM usage telemetry (#576).
6
6
  *
7
7
  * `chatCompletion` captures usage + model + finish_reason + wall-time for
8
- * EVERY OpenAI-compatible call and emits one {@link LlmUsageRecord} through a
8
+ * EVERY OpenAI-compatible HTTP attempt and emits one terminal
9
+ * {@link LlmUsageRecord} through a
9
10
  * module-level sink. The sink indirection keeps `client.ts` free of any
10
11
  * dependency on the events/db layer: the application wires the sink to
11
12
  * persistence at startup / per improve run, and tests can inspect records in
@@ -24,7 +25,7 @@
24
25
  * `undefined` outside any `withLlmStage` scope.
25
26
  */
26
27
  import { AsyncLocalStorage } from "node:async_hooks";
27
- const stageStorage = new AsyncLocalStorage();
28
+ const attributionStorage = new AsyncLocalStorage();
28
29
  let usageSink;
29
30
  /**
30
31
  * Run `fn` with `stage` as the ambient LLM stage. Any `chatCompletion` call
@@ -32,12 +33,12 @@ let usageSink;
32
33
  * helpers and nested `withLlmStage` calls — the innermost wins) is attributed
33
34
  * to `stage`. Returns whatever `fn` returns; never alters control flow.
34
35
  */
35
- export function withLlmStage(stage, fn) {
36
- return stageStorage.run(stage, fn);
36
+ export function withLlmStage(stage, fn, attribution = {}) {
37
+ return attributionStorage.run({ ...attributionStorage.getStore(), ...attribution, stage }, fn);
37
38
  }
38
39
  /** The ambient LLM stage for the current async context, or `undefined` outside any {@link withLlmStage} scope. */
39
40
  export function currentLlmStage() {
40
- return stageStorage.getStore();
41
+ return attributionStorage.getStore()?.stage;
41
42
  }
42
43
  /**
43
44
  * Install the process-wide usage sink. Replaces any previously installed sink.
@@ -69,7 +70,13 @@ export function emitLlmUsage(record) {
69
70
  if (!sink)
70
71
  return;
71
72
  try {
72
- sink({ ...record, stage: record.stage ?? currentLlmStage() });
73
+ const ambient = attributionStorage.getStore();
74
+ sink({
75
+ ...record,
76
+ stage: record.stage ?? ambient?.stage,
77
+ engine: record.engine ?? ambient?.engine,
78
+ process: record.process ?? ambient?.process,
79
+ });
73
80
  }
74
81
  catch {
75
82
  // Telemetry must never break a real run.
@@ -78,6 +85,52 @@ export function emitLlmUsage(record) {
78
85
  function asFiniteNonNegative(value) {
79
86
  return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : undefined;
80
87
  }
88
+ function asNonEmptyString(value) {
89
+ return typeof value === "string" && value.length > 0 ? value : undefined;
90
+ }
91
+ function asLlmUsageErrorCode(value) {
92
+ switch (value) {
93
+ case "rate_limited":
94
+ case "provider_error":
95
+ case "provider_html_error":
96
+ case "network_error":
97
+ case "parse_error":
98
+ case "timeout":
99
+ case "unknown_error":
100
+ return value;
101
+ default:
102
+ return undefined;
103
+ }
104
+ }
105
+ /** Decode durable event metadata with the same validation used by health aggregation. */
106
+ export function decodeLlmUsageRecord(value) {
107
+ if (!value || typeof value !== "object")
108
+ return undefined;
109
+ const raw = value;
110
+ const durationMs = asFiniteNonNegative(raw.durationMs);
111
+ if (durationMs === undefined)
112
+ return undefined;
113
+ // Historical rows predate terminal provenance. Keep health aggregation
114
+ // backward-compatible while conservatively treating their model as configured,
115
+ // never response-observed.
116
+ const outcome = raw.outcome === "success" || raw.outcome === "error" ? raw.outcome : "success";
117
+ const modelSource = raw.modelSource === "response" || raw.modelSource === "configured" ? raw.modelSource : "configured";
118
+ const record = { durationMs, outcome, modelSource };
119
+ for (const key of ["stage", "engine", "process", "model", "finishReason"]) {
120
+ const decoded = asNonEmptyString(raw[key]);
121
+ if (decoded !== undefined)
122
+ record[key] = decoded;
123
+ }
124
+ for (const key of ["promptTokens", "completionTokens", "totalTokens", "reasoningTokens"]) {
125
+ const decoded = asFiniteNonNegative(raw[key]);
126
+ if (decoded !== undefined)
127
+ record[key] = decoded;
128
+ }
129
+ const errorCode = asLlmUsageErrorCode(raw.errorCode);
130
+ if (errorCode !== undefined)
131
+ record.errorCode = errorCode;
132
+ return record;
133
+ }
81
134
  /**
82
135
  * Project a provider `usage` block into the token fields of an
83
136
  * {@link LlmUsageRecord}. Missing or garbled values are omitted (not zeroed)
@@ -2,8 +2,7 @@
2
2
  // License, v. 2.0. If a copy of the MPL was not distributed with this
3
3
  // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
4
  /**
5
- * Embedded "agent CLI hints" rendered by `akm hints` when no other source
6
- * is available.
5
+ * Embedded agent CLI guide rendered by `akm hints` and `akm help agents`.
7
6
  *
8
7
  * Extracted from `src/cli.ts` so it does not bloat the CLI module and so
9
8
  * docs/CI tooling can re-use the same constants. Two flavors:
@@ -0,0 +1,27 @@
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
+ * Create a fresh, independent {@link CommandRegistry} backed by its own
6
+ * `Map`. Each call returns a distinct registry — call once per registry
7
+ * module and hold the result in a module-level `const`.
8
+ */
9
+ export function createCommandRegistry() {
10
+ const handlers = new Map();
11
+ return {
12
+ register(command, handler) {
13
+ handlers.set(command, handler);
14
+ },
15
+ registerAll(entries) {
16
+ for (const { command, handler } of entries) {
17
+ handlers.set(command, handler);
18
+ }
19
+ },
20
+ deregister(command) {
21
+ handlers.delete(command);
22
+ },
23
+ get(command) {
24
+ return handlers.get(command);
25
+ },
26
+ };
27
+ }