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,356 @@
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
+ * `index.db` utility-score + retrieval-count repository (MemRL signals).
6
+ *
7
+ * Owns the raw SQL for `utility_scores` / `utility_scores_scoped` and the
8
+ * retrieval-frequency counting over `usage_events`. The bounded-step EMA policy
9
+ * itself lives in `indexer/feedback/utility-policy`; this repo only reads/writes.
10
+ */
11
+ import path from "node:path";
12
+ import { conceptIdFromTypeName, parseRefInput } from "../../core/asset/resolve-ref.js";
13
+ import { computeNextUtility } from "../../indexer/feedback/utility-policy.js";
14
+ import { SQLITE_CHUNK_SIZE } from "./index-sql.js";
15
+ /**
16
+ * Get the utility score for an entry, or undefined if none exists.
17
+ */
18
+ export function getUtilityScore(db, entryId) {
19
+ const row = db
20
+ .prepare("SELECT entry_id, utility, show_count, search_count, select_rate, last_used_at, updated_at FROM utility_scores WHERE entry_id = ?")
21
+ .get(entryId);
22
+ if (!row)
23
+ return undefined;
24
+ return {
25
+ entryId: row.entry_id,
26
+ utility: row.utility,
27
+ showCount: row.show_count,
28
+ searchCount: row.search_count,
29
+ selectRate: row.select_rate,
30
+ lastUsedAt: row.last_used_at ?? undefined,
31
+ updatedAt: row.updated_at,
32
+ };
33
+ }
34
+ /**
35
+ * Batch-load utility scores for multiple entry IDs in a single query.
36
+ * Returns a `{ global, scoped }` pair, both Maps keyed by entry_id.
37
+ *
38
+ * When `scopeKey` is provided a second query runs against
39
+ * `utility_scores_scoped` and the result is returned as `scoped`.
40
+ * Both maps are always present; `scoped` is empty when `scopeKey` is absent.
41
+ */
42
+ export function getUtilityScoresByIds(db, ids, scopeKey) {
43
+ const global = new Map();
44
+ const scoped = new Map();
45
+ if (ids.length === 0)
46
+ return { global, scoped };
47
+ // Process in chunks to stay within SQLITE_MAX_VARIABLE_NUMBER
48
+ for (let i = 0; i < ids.length; i += SQLITE_CHUNK_SIZE) {
49
+ const chunk = ids.slice(i, i + SQLITE_CHUNK_SIZE);
50
+ const placeholders = chunk.map(() => "?").join(",");
51
+ const rows = db
52
+ .prepare(`SELECT entry_id, utility, show_count, search_count, select_rate, last_used_at, updated_at FROM utility_scores WHERE entry_id IN (${placeholders})`)
53
+ .all(...chunk);
54
+ for (const row of rows) {
55
+ global.set(row.entry_id, {
56
+ entryId: row.entry_id,
57
+ utility: row.utility,
58
+ showCount: row.show_count,
59
+ searchCount: row.search_count,
60
+ selectRate: row.select_rate,
61
+ lastUsedAt: row.last_used_at ?? undefined,
62
+ updatedAt: row.updated_at,
63
+ });
64
+ }
65
+ if (scopeKey) {
66
+ const scopedRows = db
67
+ .prepare(`SELECT entry_id, scope_key, utility, last_used_at FROM utility_scores_scoped WHERE scope_key = ? AND entry_id IN (${placeholders})`)
68
+ .all(scopeKey, ...chunk);
69
+ for (const row of scopedRows) {
70
+ scoped.set(row.entry_id, {
71
+ entryId: row.entry_id,
72
+ scopeKey: row.scope_key,
73
+ utility: row.utility,
74
+ lastUsedAt: row.last_used_at,
75
+ });
76
+ }
77
+ }
78
+ }
79
+ return { global, scoped };
80
+ }
81
+ /**
82
+ * Insert or update a utility score for an entry.
83
+ */
84
+ export function upsertUtilityScore(db, entryId, data) {
85
+ // Pre-flight FK guard (mirrors `upsertEmbedding`): when an entry is
86
+ // deleted between when its id is aggregated from usage_events and when
87
+ // this INSERT runs, the FK constraint fails and rolls back the entire
88
+ // finalize transaction. A cheap SELECT here turns the race into a
89
+ // clean skip. Returns false when the entry no longer exists.
90
+ const exists = db.prepare("SELECT 1 FROM entries WHERE id = ?").get(entryId);
91
+ if (!exists)
92
+ return false;
93
+ db.prepare(`
94
+ INSERT INTO utility_scores (entry_id, utility, show_count, search_count, select_rate, last_used_at, updated_at)
95
+ VALUES (?, ?, ?, ?, ?, ?, datetime('now'))
96
+ ON CONFLICT(entry_id) DO UPDATE SET
97
+ utility = excluded.utility,
98
+ show_count = excluded.show_count,
99
+ search_count = excluded.search_count,
100
+ select_rate = excluded.select_rate,
101
+ last_used_at = excluded.last_used_at,
102
+ updated_at = datetime('now')
103
+ `).run(entryId, data.utility, data.showCount, data.searchCount, data.selectRate, data.lastUsedAt ?? null);
104
+ return true;
105
+ }
106
+ /**
107
+ * Reduce a stored ref to its bare form, dropping any `origin//` / `bundle//`
108
+ * prefix, matching the counting SQL's `substr` after the first `//`.
109
+ */
110
+ function bareRef(ref) {
111
+ const boundary = ref.indexOf("//");
112
+ return boundary >= 0 ? ref.slice(boundary + 2) : ref;
113
+ }
114
+ /**
115
+ * The bare-form (conceptId) candidate a caller ref matches a stored
116
+ * `usage_events` row under. Post-Chunk-8 every stored row is conceptId-spelled
117
+ * (the one-time §11.4 re-key ran at the migration cutover), so only the conceptId
118
+ * candidate remains — the legacy `type:name` sibling is retired.
119
+ */
120
+ function bareRefCandidates(ref) {
121
+ const bare = bareRef(ref.trim());
122
+ const parsed = parseRefInput(bare);
123
+ return [conceptIdFromTypeName(parsed.type, parsed.name)];
124
+ }
125
+ /**
126
+ * Count retrieval events for the given entry refs.
127
+ *
128
+ * Counts `search`, `show`, and `curate` usage events. Returns a
129
+ * Map<inputRef, count> keyed by the *input* ref strings (only those with at
130
+ * least one matching event appear). Used by the improve loop's
131
+ * proactive-maintenance selector to rank zero-feedback assets by retrieval
132
+ * frequency.
133
+ *
134
+ * Source-scoped callers require either an event linked to an entry in the
135
+ * selected stash root or a detached ref qualified with the selected source
136
+ * name.
137
+ *
138
+ * `curate` events are included: their per-item rows are written with
139
+ * entry_ref populated (see logCurateEvent), so curation is a real retrieval
140
+ * signal here. Summary-only rows with a NULL entry_ref contribute nothing.
141
+ *
142
+ * Machine/eval/unattributed/extension events are excluded: this count feeds
143
+ * salience and ranking, so only explicitly attributed `user` traffic counts.
144
+ */
145
+ export function getRetrievalCounts(indexDb, stateDb, refs, options = {}) {
146
+ if (refs.length === 0)
147
+ return new Map();
148
+ if (options.sourceName || options.stashDir) {
149
+ return getSourceScopedRetrievalCounts(indexDb, stateDb, refs, options);
150
+ }
151
+ // Map each conceptId back to the input refs that produced it so DB results
152
+ // can be re-keyed onto the caller's strings.
153
+ const bareToInputs = new Map();
154
+ for (const ref of refs) {
155
+ for (const bare of bareRefCandidates(ref)) {
156
+ const existing = bareToInputs.get(bare);
157
+ if (existing)
158
+ existing.push(ref);
159
+ else
160
+ bareToInputs.set(bare, [ref]);
161
+ }
162
+ }
163
+ const bareForms = [...bareToInputs.keys()];
164
+ // Accumulate counts per bare form across chunks before re-keying.
165
+ const countsByBare = new Map();
166
+ // Chunk to stay within SQLITE_MAX_VARIABLE_NUMBER (same pattern as getUtilityScoresByIds).
167
+ for (let i = 0; i < bareForms.length; i += SQLITE_CHUNK_SIZE) {
168
+ const chunk = bareForms.slice(i, i + SQLITE_CHUNK_SIZE);
169
+ const placeholders = chunk.map(() => "?").join(", ");
170
+ // Normalize the stored entry_ref to its bare form inside SQL by stripping
171
+ // everything up to and including the last `//` separator. SQLite has no
172
+ // rfind, but stored origins never themselves contain `//`, so a stash ref
173
+ // has exactly one `//` and `substr(... instr ...)` is exact; bare refs have
174
+ // no `//` and are excluded above.
175
+ // usage_events lives in state.db (Chunk-8 WI-8.3) — this global count needs
176
+ // no entries join, so it reads state.db directly.
177
+ const rows = stateDb
178
+ .prepare(`SELECT
179
+ CASE
180
+ WHEN instr(entry_ref, '//') > 0
181
+ THEN substr(entry_ref, instr(entry_ref, '//') + 2)
182
+ ELSE entry_ref
183
+ END AS bare_ref,
184
+ COUNT(*) AS cnt
185
+ FROM usage_events
186
+ WHERE event_type IN ('search','show','curate')
187
+ AND entry_ref IS NOT NULL
188
+ AND instr(entry_ref, '//') > 0
189
+ AND source = 'user'
190
+ AND CASE
191
+ WHEN instr(entry_ref, '//') > 0
192
+ THEN substr(entry_ref, instr(entry_ref, '//') + 2)
193
+ ELSE entry_ref
194
+ END IN (${placeholders})
195
+ GROUP BY bare_ref`)
196
+ .all(...chunk);
197
+ for (const r of rows) {
198
+ countsByBare.set(r.bare_ref, (countsByBare.get(r.bare_ref) ?? 0) + r.cnt);
199
+ }
200
+ }
201
+ // Re-key bare-form counts onto every input ref that maps to that bare form.
202
+ const result = new Map();
203
+ for (const [bare, count] of countsByBare) {
204
+ for (const input of bareToInputs.get(bare) ?? []) {
205
+ result.set(input, count);
206
+ }
207
+ }
208
+ return result;
209
+ }
210
+ function getSourceScopedRetrievalCounts(indexDb, stateDb, refs, options) {
211
+ const bareToInputs = new Map();
212
+ for (const ref of refs) {
213
+ for (const bare of bareRefCandidates(ref)) {
214
+ const inputs = bareToInputs.get(bare);
215
+ if (inputs)
216
+ inputs.push(ref);
217
+ else
218
+ bareToInputs.set(bare, [ref]);
219
+ }
220
+ }
221
+ // Cross-DB (Chunk-8 WI-8.3): usage_events rows come from state.db; the
222
+ // per-row `stash_dir` (formerly a LEFT JOIN on entries) is resolved from
223
+ // index.db by entry_id. Read the usage rows first, then batch-look-up the
224
+ // stash_dir for their entry_ids and join in JS.
225
+ const entryStashDir = indexDb.prepare("SELECT stash_dir FROM entries WHERE id = ?");
226
+ const stashDirFor = (entryId) => {
227
+ if (entryId === null)
228
+ return null;
229
+ const row = entryStashDir.get(entryId);
230
+ return row?.stash_dir ?? null;
231
+ };
232
+ const countsByBare = new Map();
233
+ const bareForms = [...bareToInputs.keys()];
234
+ const selectedRoot = options.stashDir ? path.resolve(options.stashDir) : undefined;
235
+ for (let i = 0; i < bareForms.length; i += SQLITE_CHUNK_SIZE) {
236
+ const chunk = bareForms.slice(i, i + SQLITE_CHUNK_SIZE);
237
+ const placeholders = chunk.map(() => "?").join(", ");
238
+ const rawRows = stateDb
239
+ .prepare(`SELECT ue.entry_ref, ue.entry_id
240
+ FROM usage_events ue
241
+ WHERE ue.event_type IN ('search','show','curate')
242
+ AND ue.entry_ref IS NOT NULL
243
+ AND instr(ue.entry_ref, '//') > 0
244
+ AND ue.source = 'user'
245
+ AND CASE
246
+ WHEN instr(ue.entry_ref, '//') > 0
247
+ THEN substr(ue.entry_ref, instr(ue.entry_ref, '//') + 2)
248
+ ELSE ue.entry_ref
249
+ END IN (${placeholders})`)
250
+ .all(...chunk);
251
+ const rows = rawRows.map((r) => ({ ...r, stash_dir: stashDirFor(r.entry_id) }));
252
+ for (const row of rows) {
253
+ const bare = bareRef(row.entry_ref);
254
+ const linkedToSelectedRoot = row.entry_id !== null && selectedRoot !== undefined && row.stash_dir !== null
255
+ ? path.resolve(row.stash_dir) === selectedRoot
256
+ : false;
257
+ const detached = row.entry_id === null || selectedRoot === undefined;
258
+ const qualifiedForSource = detached && options.sourceName !== undefined && row.entry_ref === `${options.sourceName}//${bare}`;
259
+ if (!linkedToSelectedRoot && !qualifiedForSource)
260
+ continue;
261
+ countsByBare.set(bare, (countsByBare.get(bare) ?? 0) + 1);
262
+ }
263
+ }
264
+ const result = new Map();
265
+ for (const [bare, count] of countsByBare) {
266
+ for (const input of bareToInputs.get(bare) ?? [])
267
+ result.set(input, count);
268
+ }
269
+ return result;
270
+ }
271
+ /**
272
+ * Apply a MemRL reward signal to a batch of entries via exponential moving
273
+ * average (EMA): next = clamp(current + lr * (reward - current), 0, 1).
274
+ *
275
+ * Wrapped in a single transaction so all bumps succeed or fail together.
276
+ * The indexer (`akm index`) will overwrite these values at next reindex run;
277
+ * bumps are intentionally temporary hints between index runs, not permanent
278
+ * overrides.
279
+ *
280
+ * When `scopeKey` is provided, also writes a scoped bump to
281
+ * `utility_scores_scoped` so per-project usage signals accumulate alongside
282
+ * the global ones. The global table is always updated regardless.
283
+ */
284
+ export function bumpUtilityScoresBatch(db, entryIds, reward, lr = 0.1, scopeKey) {
285
+ if (entryIds.length === 0)
286
+ return;
287
+ db.transaction(() => {
288
+ const { global: scoreMap } = getUtilityScoresByIds(db, entryIds);
289
+ const now = new Date().toISOString();
290
+ const nowMs = Date.now();
291
+ const stmt = db.prepare(`INSERT INTO utility_scores (entry_id, utility, show_count, search_count, select_rate, last_used_at, updated_at)
292
+ VALUES (?, ?, 0, 0, 0, ?, ?)
293
+ ON CONFLICT(entry_id) DO UPDATE SET
294
+ utility = excluded.utility,
295
+ updated_at = excluded.updated_at`);
296
+ // Prepare scoped upsert once outside the loop when scopeKey is present.
297
+ const scopedStmt = scopeKey
298
+ ? db.prepare(`INSERT INTO utility_scores_scoped (entry_id, scope_key, utility, last_used_at)
299
+ VALUES (?, ?, ?, ?)
300
+ ON CONFLICT(entry_id, scope_key) DO UPDATE SET
301
+ utility = excluded.utility,
302
+ last_used_at = excluded.last_used_at`)
303
+ : null;
304
+ for (const entryId of entryIds) {
305
+ const existing = scoreMap.get(entryId);
306
+ const current = existing?.utility ?? 0;
307
+ const next = Math.max(0, Math.min(1, current + lr * (reward - current)));
308
+ stmt.run(entryId, next, now, now);
309
+ if (scopedStmt && scopeKey) {
310
+ // Retrieve the current scoped utility so we can apply the same EMA.
311
+ const scopedCurrent = getScopedUtility(db, entryId, scopeKey);
312
+ const scopedNext = Math.max(0, Math.min(1, scopedCurrent + lr * (reward - scopedCurrent)));
313
+ scopedStmt.run(entryId, scopeKey, scopedNext, nowMs);
314
+ }
315
+ }
316
+ })();
317
+ }
318
+ /**
319
+ * Return the current utility value for a single (entry_id, scope_key) pair.
320
+ * Returns 0 when no row exists yet.
321
+ */
322
+ function getScopedUtility(db, entryId, scopeKey) {
323
+ const row = db
324
+ .prepare("SELECT utility FROM utility_scores_scoped WHERE entry_id = ? AND scope_key = ?")
325
+ .get(entryId, scopeKey);
326
+ return row?.utility ?? 0;
327
+ }
328
+ /**
329
+ * Apply accumulated feedback counts to the utility score of an entry, persisting
330
+ * the result. The bounded-step EMA policy itself (MemRL, F-5 / #386,
331
+ * arXiv:2601.03192) lives in {@link computeNextUtility} (feedback/utility-policy);
332
+ * this function only reads the current utility, applies the policy, and writes
333
+ * the new value.
334
+ *
335
+ * A new entry starts at 0.5 (neutral midpoint) before the EMA step is applied.
336
+ * When there is no feedback (both counts zero) the score is left untouched — no
337
+ * DB write. Returns a {@link FeedbackUtilityResult} so the caller can detect a
338
+ * previously high-utility asset crossing below the review threshold and escalate.
339
+ */
340
+ export function applyFeedbackToUtilityScore(db, entryId, positiveCount, negativeCount) {
341
+ const existing = getUtilityScore(db, entryId);
342
+ const previousUtility = existing?.utility ?? 0.5;
343
+ const result = computeNextUtility(previousUtility, positiveCount, negativeCount);
344
+ if (positiveCount === 0 && negativeCount === 0) {
345
+ return result;
346
+ }
347
+ const now = new Date().toISOString();
348
+ db.prepare(`
349
+ INSERT INTO utility_scores (entry_id, utility, show_count, search_count, select_rate, last_used_at, updated_at)
350
+ VALUES (?, ?, 0, 0, 0, ?, ?)
351
+ ON CONFLICT(entry_id) DO UPDATE SET
352
+ utility = ?,
353
+ updated_at = ?
354
+ `).run(entryId, result.nextUtility, now, now, result.nextUtility, now);
355
+ return result;
356
+ }
@@ -0,0 +1,250 @@
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
+ * `index.db` vector + embedding repository.
6
+ *
7
+ * Owns the sqlite-vec extension load/availability probe, the BLOB `embeddings`
8
+ * table, the `entries_vec` virtual table, and the JS-cosine fallback path.
9
+ */
10
+ import { createRequire } from "node:module";
11
+ import { bestEffort } from "../../core/best-effort.js";
12
+ import { warn } from "../../core/warn.js";
13
+ import { cosineSimilarity } from "../../llm/embedders/types.js";
14
+ import { getMeta, setMeta } from "./index-meta-repository.js";
15
+ // ── sqlite-vec extension ────────────────────────────────────────────────────
16
+ const vecStatus = new WeakMap();
17
+ /**
18
+ * Attempt to load the sqlite-vec extension into `db`, recording availability.
19
+ * Exported so the connection lifecycle can arm it at open time.
20
+ */
21
+ export function loadVecExtension(db) {
22
+ try {
23
+ const esmRequire = createRequire(import.meta.url);
24
+ const sqliteVec = esmRequire("sqlite-vec");
25
+ // `db` here is the genuine underlying driver handle returned by the storage
26
+ // boundary (bun:sqlite on Bun, better-sqlite3 on Node) — only structurally
27
+ // narrowed for callers. sqlite-vec's `load()` accepts either real handle,
28
+ // so no raw-handle escape hatch is required.
29
+ sqliteVec.load(db);
30
+ vecStatus.set(db, true);
31
+ }
32
+ catch {
33
+ vecStatus.set(db, false);
34
+ }
35
+ }
36
+ export function isVecAvailable(db) {
37
+ return vecStatus.get(db) ?? false;
38
+ }
39
+ /**
40
+ * Meta key persisting whether the sqlite-vec fast-path table (`entries_vec`) is
41
+ * fully populated and trustworthy for this index. Set to "0" by the embedding
42
+ * phase when one or more vec inserts FAILED (e.g. a vec0 dimension mismatch)
43
+ * while their BLOB rows still wrote — so semantic search reads the complete
44
+ * BLOB table via the JS-cosine fallback instead of a partial/mismatched vec
45
+ * table. Absent (legacy indexes) and "1" both mean the fast path is trusted.
46
+ */
47
+ const VEC_FAST_PATH_READY_META = "vecFastPathReady";
48
+ /** Persist whether the sqlite-vec fast path is trustworthy (see the meta doc). */
49
+ export function setVecFastPathReady(db, ready) {
50
+ setMeta(db, VEC_FAST_PATH_READY_META, ready ? "1" : "0");
51
+ }
52
+ /**
53
+ * True unless the embedding phase recorded a vec insert failure. Reflects the
54
+ * ACTUAL insert outcomes recorded at index time — not an inference from how many
55
+ * BLOB rows exist — so a degraded vec table routes search to the JS fallback
56
+ * rather than silently returning partial fast-path results.
57
+ */
58
+ export function isVecFastPathReady(db) {
59
+ return getMeta(db, VEC_FAST_PATH_READY_META) !== "0";
60
+ }
61
+ /** Remove both vector representations for an entry whose embedding input changed. */
62
+ export function deleteEntryVectors(db, id) {
63
+ db.prepare("DELETE FROM embeddings WHERE id = ?").run(id);
64
+ if (isVecAvailable(db))
65
+ db.prepare("DELETE FROM entries_vec WHERE id = ?").run(id);
66
+ }
67
+ const VEC_DOCS_URL = "https://github.com/itlackey/akm/blob/main/docs/reference/configuration.md#sqlite-vec-extension";
68
+ const VEC_FALLBACK_THRESHOLD = 10_000;
69
+ // Per-database warning state: tracks which databases have already emitted the
70
+ // vec-missing warning so we don't spam on every openDatabase() call.
71
+ const vecInitWarnedDbs = new WeakSet();
72
+ /**
73
+ * Warn if sqlite-vec is unavailable and embedding count exceeds threshold.
74
+ * Called from openDatabase (once at init) and from indexer (each run).
75
+ */
76
+ export function warnIfVecMissing(db, { once } = { once: false }) {
77
+ if (isVecAvailable(db))
78
+ return;
79
+ if (once && vecInitWarnedDbs.has(db))
80
+ return;
81
+ bestEffort(() => {
82
+ const row = db.prepare("SELECT COUNT(*) AS cnt FROM embeddings").get();
83
+ const count = row?.cnt ?? 0;
84
+ if (count >= VEC_FALLBACK_THRESHOLD) {
85
+ warn("Semantic search is using JS fallback for %d entries. Install sqlite-vec for faster performance.\n See: %s", count, VEC_DOCS_URL);
86
+ if (once)
87
+ vecInitWarnedDbs.add(db);
88
+ }
89
+ }, "embeddings table may not exist yet during init");
90
+ }
91
+ /**
92
+ * Purge stored embeddings (BLOB rows in `embeddings`, plus the `entries_vec`
93
+ * virtual table) and mark the index as embedding-free. The single place that
94
+ * invalidates embeddings — used on a dimension change, a model/provider change,
95
+ * and a full rebuild.
96
+ *
97
+ * No backup: embeddings are a derived cache, fully regenerable from the markdown
98
+ * by the next `akm index`. (Recovery model decided 2026-06-25.)
99
+ *
100
+ * `dropVecTable: true` DROPs `entries_vec` — used on a DIMENSION change, where
101
+ * the vec0 table must be recreated at the new width by the caller. The default
102
+ * clears its rows in place (same dimension, stale vectors).
103
+ */
104
+ export function purgeEmbeddings(db, opts) {
105
+ bestEffort(() => db.exec("DELETE FROM embeddings"), "purge embeddings");
106
+ if (isVecAvailable(db)) {
107
+ bestEffort(() => db.exec(opts?.dropVecTable ? "DROP TABLE IF EXISTS entries_vec" : "DELETE FROM entries_vec"), "purge entries_vec");
108
+ }
109
+ setMeta(db, "hasEmbeddings", "0");
110
+ }
111
+ export function upsertEmbedding(db, entryId, embedding) {
112
+ // Pre-flight FK guard: when an entry is deleted between when its id is queued
113
+ // for embedding and when this INSERT runs (e.g. consolidation deletes during
114
+ // a concurrent improve cycle), the INSERT throws "FOREIGN KEY constraint failed"
115
+ // and rolls back the entire batch transaction in the caller, losing every
116
+ // embedding for that run. A cheap SELECT here turns the race into a clean skip.
117
+ const exists = db.prepare("SELECT 1 FROM entries WHERE id = ?").get(entryId);
118
+ if (!exists)
119
+ return { stored: false, vec: "unavailable" };
120
+ const buf = float32Buffer(embedding);
121
+ // Always write to BLOB table (works without sqlite-vec; the JS-cosine fallback
122
+ // reads it, so semantic search survives a vec fast-path failure).
123
+ db.prepare("INSERT OR REPLACE INTO embeddings (id, embedding) VALUES (?, ?)").run(entryId, buf);
124
+ if (!isVecAvailable(db))
125
+ return { stored: true, vec: "unavailable" };
126
+ // Fast path: mirror into the sqlite-vec table. Wrapped in a transaction so a
127
+ // crash between DELETE and INSERT does not leave the entry missing. A THROW
128
+ // here — previously swallowed silently by bestEffort — is now surfaced to the
129
+ // caller so the embedding phase can count it, warn, and route search to the
130
+ // (complete) BLOB table rather than a partial/mismatched vec table.
131
+ try {
132
+ db.transaction(() => {
133
+ db.prepare("DELETE FROM entries_vec WHERE id = ?").run(entryId);
134
+ db.prepare("INSERT INTO entries_vec (id, embedding) VALUES (?, ?)").run(entryId, buf);
135
+ })();
136
+ return { stored: true, vec: "ok" };
137
+ }
138
+ catch {
139
+ return { stored: true, vec: "failed" };
140
+ }
141
+ }
142
+ export function searchVec(db, queryEmbedding, k) {
143
+ // Fast path: sqlite-vec, but ONLY when the extension is loaded AND the
144
+ // embedding phase did not record a vec insert failure. A degraded fast-path
145
+ // table (partial or dimension-mismatched) would return wrong or missing
146
+ // neighbours, so we honestly fall back to the JS-cosine scan over the
147
+ // complete BLOB table instead.
148
+ if (isVecAvailable(db) && isVecFastPathReady(db)) {
149
+ const buf = float32Buffer(queryEmbedding);
150
+ try {
151
+ return db
152
+ .prepare("SELECT id, distance FROM entries_vec WHERE embedding MATCH ? AND k = ?")
153
+ .all(buf, k);
154
+ }
155
+ catch (err) {
156
+ // Log the failure so it's visible in diagnostics
157
+ warn("[db] searchVec (sqlite-vec path) failed:", err instanceof Error ? err.message : String(err));
158
+ return [];
159
+ }
160
+ }
161
+ // Fallback: JS-based cosine similarity over BLOB table
162
+ return searchBlobVec(db, queryEmbedding, k);
163
+ }
164
+ /**
165
+ * Return the k nearest neighbours of an already-indexed entry using its
166
+ * persisted embedding — no re-embedding, no network. Decodes the stored BLOB by
167
+ * byte length (dim = bytes / 4) and reuses searchVec (sqlite-vec fast path or
168
+ * JS-cosine fallback). Returns [] when the entry has no stored embedding or the
169
+ * BLOB is corrupt. The query entry itself is typically returned with distance
170
+ * ~0 — callers should filter it out by id.
171
+ */
172
+ export function getNeighborsByEntryId(db, id, k) {
173
+ const row = db.prepare("SELECT embedding FROM embeddings WHERE id = ?").get(id);
174
+ if (!row)
175
+ return [];
176
+ const queryEmbedding = bufferToFloat32(row.embedding, Math.floor(row.embedding.byteLength / 4));
177
+ if (!queryEmbedding)
178
+ return [];
179
+ return searchVec(db, queryEmbedding, k);
180
+ }
181
+ function float32Buffer(vec) {
182
+ const f32 = new Float32Array(vec);
183
+ return Buffer.from(f32.buffer);
184
+ }
185
+ /**
186
+ * Decode a stored embedding BLOB into a Float32 array of `expectedDim`
187
+ * dimensions. Returns `null` (and emits a warning) when the byte length does
188
+ * not exactly match `expectedDim * 4`, including the legacy partial-trailing
189
+ * float case the previous truncating-divide silently swallowed.
190
+ *
191
+ * BUG-M2: the previous `buf.byteLength / 4` divide would truncate any
192
+ * trailing partial float and a misaligned `byteOffset` would throw — both
193
+ * surfaced as opaque generic errors caught upstream.
194
+ */
195
+ function bufferToFloat32(buf, expectedDim) {
196
+ if (buf.byteLength !== expectedDim * 4) {
197
+ warn("[db] bufferToFloat32: skipping embedding row — expected %d bytes (%d dim x 4), got %d", expectedDim * 4, expectedDim, buf.byteLength);
198
+ return null;
199
+ }
200
+ // Copy into a fresh ArrayBuffer to sidestep any byteOffset alignment
201
+ // requirements imposed by Float32Array's typed-array view contract.
202
+ const aligned = new ArrayBuffer(buf.byteLength);
203
+ new Uint8Array(aligned).set(buf);
204
+ const f32 = new Float32Array(aligned);
205
+ return Array.from(f32);
206
+ }
207
+ function searchBlobVec(db, queryEmbedding, k) {
208
+ try {
209
+ const rows = db.prepare("SELECT id, embedding FROM embeddings").all();
210
+ if (rows.length === 0)
211
+ return [];
212
+ const expectedDim = queryEmbedding.length;
213
+ const scored = [];
214
+ for (const row of rows) {
215
+ const embedding = bufferToFloat32(row.embedding, expectedDim);
216
+ if (embedding === null)
217
+ continue;
218
+ const similarity = cosineSimilarity(queryEmbedding, embedding);
219
+ scored.push({ id: row.id, similarity });
220
+ }
221
+ scored.sort((a, b) => b.similarity - a.similarity);
222
+ // Convert cosine similarity to L2 distance for compatibility with sqlite-vec interface
223
+ // For normalized vectors: L2² = 2(1 - cos_sim)
224
+ return scored.slice(0, k).map(({ id, similarity }) => ({
225
+ id,
226
+ distance: Math.sqrt(2 * Math.max(0, 1 - similarity)),
227
+ }));
228
+ }
229
+ catch (err) {
230
+ // MD-5: Log the failure so it's visible in diagnostics
231
+ warn("[db] searchBlobVec (JS fallback) failed:", err instanceof Error ? err.message : String(err));
232
+ return [];
233
+ }
234
+ }
235
+ /**
236
+ * Return all entries that do not yet have an embedding row.
237
+ * Used by the embedding phase to determine which entries need vectors generated.
238
+ */
239
+ export function getAllEntriesForEmbedding(db) {
240
+ return db
241
+ .prepare(`
242
+ SELECT e.id, e.search_text AS searchText, e.entry_key AS entryKey, e.file_path AS filePath FROM entries e
243
+ WHERE NOT EXISTS (SELECT 1 FROM embeddings b WHERE b.id = e.id)
244
+ `)
245
+ .all();
246
+ }
247
+ export function getEmbeddingCount(db) {
248
+ const row = db.prepare("SELECT COUNT(*) AS cnt FROM embeddings").get();
249
+ return row.cnt;
250
+ }