akm-cli 0.9.0-rc.1 → 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 (587) hide show
  1. package/CHANGELOG.md +1190 -52
  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/stash-skeleton/README.md +38 -10
  26. package/dist/assets/stash-skeleton/facts/conventions/assets/agent.md +8 -0
  27. package/dist/assets/stash-skeleton/facts/conventions/assets/command.md +8 -0
  28. package/dist/assets/stash-skeleton/facts/conventions/assets/fact.md +14 -1
  29. package/dist/assets/stash-skeleton/facts/conventions/assets/knowledge.md +13 -1
  30. package/dist/assets/stash-skeleton/facts/conventions/assets/lesson.md +9 -1
  31. package/dist/assets/stash-skeleton/facts/conventions/assets/memory.md +11 -0
  32. package/dist/assets/stash-skeleton/facts/conventions/assets/script.md +9 -0
  33. package/dist/assets/stash-skeleton/facts/conventions/assets/skill.md +9 -0
  34. package/dist/assets/stash-skeleton/facts/conventions/assets/workflow.md +8 -0
  35. package/dist/assets/stash-skeleton/facts/conventions/backlinks.md +100 -0
  36. package/dist/assets/stash-skeleton/facts/conventions/domains.md +64 -0
  37. package/dist/assets/stash-skeleton/facts/conventions/organization.md +136 -0
  38. package/dist/assets/tasks/core/extract.yml +3 -2
  39. package/dist/assets/tasks/core/improve.yml +2 -1
  40. package/dist/assets/tasks/core/index-refresh.yml +1 -0
  41. package/dist/assets/tasks/core/sync.yml +1 -0
  42. package/dist/assets/tasks/core/version-check.yml +2 -1
  43. package/dist/assets/tasks/improve/akm-graph-refresh-weekly.yml +5 -0
  44. package/dist/assets/tasks/improve/akm-improve-catchup.yml +8 -0
  45. package/dist/assets/tasks/improve/akm-improve-consolidate.yml +5 -0
  46. package/dist/assets/tasks/improve/akm-improve-frequent.yml +5 -0
  47. package/dist/assets/tasks/improve/akm-improve-nightly.yml +5 -0
  48. package/dist/assets/templates/html/health.html +5 -4
  49. package/dist/assets/workflows/workflow-template.md +31 -15
  50. package/dist/cli/invocation.js +279 -0
  51. package/dist/cli/parse-args.js +5 -90
  52. package/dist/cli/retired-commands.js +78 -0
  53. package/dist/cli/shared.js +158 -48
  54. package/dist/cli-node.mjs +2 -1
  55. package/dist/cli.js +747 -293
  56. package/dist/commands/agent/agent-dispatch.js +19 -18
  57. package/dist/commands/agent/agent-support.js +0 -24
  58. package/dist/commands/agent/contribute-cli.js +43 -97
  59. package/dist/commands/completions.js +80 -23
  60. package/dist/commands/config-cli.js +44 -281
  61. package/dist/commands/env/env-binding.js +13 -9
  62. package/dist/commands/env/env-cli.js +76 -159
  63. package/dist/commands/env/env.js +12 -163
  64. package/dist/commands/env/marker-path.js +6 -0
  65. package/dist/commands/env/secret-cli.js +45 -61
  66. package/dist/commands/env/secret.js +32 -62
  67. package/dist/commands/feedback-cli.js +179 -85
  68. package/dist/commands/health/accept-rate.js +58 -0
  69. package/dist/commands/health/advisories.js +7 -8
  70. package/dist/commands/health/checks.js +279 -94
  71. package/dist/commands/health/html-report.js +197 -578
  72. package/dist/commands/health/improve-metrics.js +277 -246
  73. package/dist/commands/health/llm-usage.js +19 -19
  74. package/dist/commands/health/md-report.js +16 -7
  75. package/dist/commands/health/metrics.js +67 -32
  76. package/dist/commands/health/renderers.js +47 -0
  77. package/dist/commands/health/report-view-model.js +508 -0
  78. package/dist/commands/health/stash-exposure.js +1 -1
  79. package/dist/commands/health/surfaces.js +16 -56
  80. package/dist/commands/health/task-runs.js +3 -67
  81. package/dist/{migrate-storage-node.mjs → commands/health/types-checks.js} +1 -5
  82. package/dist/commands/health/types-improve.js +29 -0
  83. package/dist/{output/text/save.js → commands/health/types-metrics.js} +1 -2
  84. package/dist/commands/health/types-result.js +7 -0
  85. package/dist/commands/health/types-runs.js +4 -0
  86. package/dist/commands/health/types-session-log.js +4 -0
  87. package/dist/commands/health/types-windows.js +4 -0
  88. package/dist/commands/health/types.js +26 -21
  89. package/dist/commands/health/windows.js +2 -3
  90. package/dist/commands/health.js +296 -167
  91. package/dist/commands/improve/anti-collapse.js +5 -5
  92. package/dist/commands/improve/autonomy-gate.js +68 -0
  93. package/dist/commands/improve/collapse-detector.js +65 -52
  94. package/dist/commands/improve/consolidate/chunking.js +9 -7
  95. package/dist/commands/improve/consolidate/eligibility.js +1 -23
  96. package/dist/commands/improve/consolidate/merge.js +4 -0
  97. package/dist/commands/improve/consolidate.js +454 -1354
  98. package/dist/commands/improve/content-hash.js +39 -0
  99. package/dist/commands/improve/distill/content-repair.js +4 -10
  100. package/dist/commands/improve/distill/promote-memory.js +89 -64
  101. package/dist/commands/improve/distill/quality-gate.js +118 -42
  102. package/dist/commands/improve/distill-guards.js +1 -1
  103. package/dist/commands/improve/distill-promotion-policy.js +33 -888
  104. package/dist/commands/improve/distill.js +607 -363
  105. package/dist/commands/improve/eligibility.js +165 -79
  106. package/dist/commands/improve/extract-cli.js +35 -126
  107. package/dist/commands/improve/extract-prompt.js +6 -35
  108. package/dist/commands/improve/extract.js +640 -391
  109. package/dist/commands/improve/feedback-valence.js +2 -12
  110. package/dist/commands/improve/improve-cli.js +134 -135
  111. package/dist/commands/improve/improve-result-file.js +30 -50
  112. package/dist/commands/improve/improve-run-types.js +4 -0
  113. package/dist/commands/improve/improve-strategies.js +135 -0
  114. package/dist/commands/improve/improve.js +904 -701
  115. package/dist/commands/improve/locks.js +64 -111
  116. package/dist/commands/improve/loop-stages.js +1110 -923
  117. package/dist/commands/improve/memory/derived-ref.js +124 -0
  118. package/dist/commands/improve/memory/memory-belief.js +79 -7
  119. package/dist/commands/improve/memory/memory-contradiction-detect.js +49 -52
  120. package/dist/commands/improve/memory/memory-improve.js +25 -37
  121. package/dist/commands/improve/outcome-loop.js +25 -88
  122. package/dist/commands/improve/preparation.js +1034 -813
  123. package/dist/commands/improve/proactive-maintenance.js +34 -9
  124. package/dist/commands/improve/proposal-envelope.js +31 -0
  125. package/dist/commands/improve/reflect.js +983 -794
  126. package/dist/commands/improve/run-context.js +119 -0
  127. package/dist/commands/improve/salience.js +24 -127
  128. package/dist/commands/improve/session-asset.js +7 -3
  129. package/dist/commands/improve/shared.js +14 -34
  130. package/dist/commands/improve/source-identity.js +28 -0
  131. package/dist/commands/improve/triage.js +20 -17
  132. package/dist/commands/lint/base-linter.js +340 -313
  133. package/dist/commands/lint/env-key-rules.js +31 -47
  134. package/dist/commands/lint/index.js +185 -30
  135. package/dist/commands/{events.js → log.js} +28 -38
  136. package/dist/commands/migrate-cli.js +54 -0
  137. package/dist/commands/migration-tool.js +55 -0
  138. package/dist/commands/observability-cli.js +70 -208
  139. package/dist/commands/proposal/diff-format.js +50 -0
  140. package/dist/commands/proposal/drain-policies.js +0 -6
  141. package/dist/commands/proposal/drain.js +91 -40
  142. package/dist/commands/proposal/proposal-cli.js +134 -132
  143. package/dist/commands/proposal/proposal-types.js +56 -0
  144. package/dist/commands/proposal/proposal.js +83 -65
  145. package/dist/commands/proposal/propose-cli.js +88 -0
  146. package/dist/commands/proposal/propose.js +105 -88
  147. package/dist/commands/proposal/repository.js +1303 -278
  148. package/dist/commands/proposal/validators/proposal-quality-validators.js +16 -6
  149. package/dist/commands/proposal/validators/proposal-validators.js +61 -12
  150. package/dist/commands/proposal/validators/proposals.js +6 -8
  151. package/dist/commands/read/curate.js +78 -73
  152. package/dist/commands/read/knowledge.js +510 -13
  153. package/dist/commands/read/registry-search.js +2 -2
  154. package/dist/commands/read/remember-cli.js +84 -15
  155. package/dist/commands/read/search-cli.js +203 -96
  156. package/dist/commands/read/search.js +126 -94
  157. package/dist/commands/read/show.js +226 -250
  158. package/dist/commands/registry-cli.js +34 -60
  159. package/dist/commands/remember.js +18 -57
  160. package/dist/commands/sources/add-cli.js +104 -49
  161. package/dist/commands/sources/bundle-cli.js +166 -0
  162. package/dist/commands/sources/bundle-config-ops.js +63 -0
  163. package/dist/commands/sources/info.js +27 -15
  164. package/dist/commands/sources/init.js +30 -40
  165. package/dist/commands/sources/installed-stashes.js +469 -172
  166. package/dist/commands/sources/schema-repair.js +10 -9
  167. package/dist/commands/sources/self-update.js +182 -121
  168. package/dist/commands/sources/source-add.js +169 -178
  169. package/dist/commands/sources/source-clone.js +144 -41
  170. package/dist/commands/sources/source-manage.js +94 -59
  171. package/dist/commands/sources/sources-cli.js +64 -205
  172. package/dist/commands/sources/stash-cli.js +91 -54
  173. package/dist/commands/sources/stash-skeleton.js +1 -1
  174. package/dist/commands/tasks/tasks-cli.js +106 -104
  175. package/dist/commands/tasks/tasks.js +445 -262
  176. package/dist/commands/workflow-cli.js +75 -228
  177. package/dist/core/action-contributors.js +1 -1
  178. package/dist/core/activation-policy.js +49 -0
  179. package/dist/core/adapter/adapters/agent-skills-adapter.js +181 -0
  180. package/dist/core/adapter/adapters/akm-adapter.js +528 -0
  181. package/dist/core/adapter/adapters/akm-lint.js +392 -0
  182. package/dist/core/adapter/adapters/akm-metadata.js +387 -0
  183. package/dist/core/adapter/adapters/akm-task-adapter.js +149 -0
  184. package/dist/core/adapter/adapters/akm-workflow-adapter.js +180 -0
  185. package/dist/core/adapter/adapters/claude-adapter.js +61 -0
  186. package/dist/core/adapter/adapters/dotenv-adapter.js +187 -0
  187. package/dist/core/adapter/adapters/generic-files-adapter.js +119 -0
  188. package/dist/core/adapter/adapters/index.js +80 -0
  189. package/dist/core/adapter/adapters/llm-wiki-adapter.js +419 -0
  190. package/dist/core/adapter/adapters/okf-adapter.js +391 -0
  191. package/dist/core/adapter/adapters/opencode-adapter.js +68 -0
  192. package/dist/core/adapter/adapters/shared.js +286 -0
  193. package/dist/core/adapter/adapters/tool-dir-shared.js +217 -0
  194. package/dist/core/adapter/adapters/website-snapshot-adapter.js +155 -0
  195. package/dist/core/adapter/bundle-adapter.js +4 -0
  196. package/dist/core/adapter/detect-adapter.js +17 -0
  197. package/dist/core/adapter/recognize-match.js +44 -0
  198. package/dist/core/adapter/registry.js +56 -0
  199. package/dist/core/adapter/types.js +4 -0
  200. package/dist/core/asset/akm-markdown.js +30 -0
  201. package/dist/core/asset/asset-placement.js +243 -0
  202. package/dist/core/asset/asset-ref.js +110 -79
  203. package/dist/core/asset/asset-serialize.js +20 -0
  204. package/dist/core/asset/frontmatter.js +28 -12
  205. package/dist/core/asset/markdown.js +40 -51
  206. package/dist/core/asset/resolve-ref.js +274 -0
  207. package/dist/core/asset/stash-meta.js +2 -2
  208. package/dist/core/bundle-id.js +51 -0
  209. package/dist/core/common.js +281 -86
  210. package/dist/core/config/config-io.js +42 -128
  211. package/dist/core/config/config-schema.js +233 -855
  212. package/dist/core/config/config-sources.js +162 -39
  213. package/dist/core/config/config-types.js +16 -11
  214. package/dist/core/config/config-version.js +29 -0
  215. package/dist/core/config/config-walker.js +126 -37
  216. package/dist/core/config/config.js +154 -331
  217. package/dist/core/config/deep-merge.js +41 -0
  218. package/dist/core/config/engine-semantics.js +28 -0
  219. package/dist/core/config/experimental.js +21 -0
  220. package/dist/core/config/schema/embedding.js +38 -0
  221. package/dist/core/config/schema/engines.js +116 -0
  222. package/dist/core/config/schema/experimental.js +47 -0
  223. package/dist/core/config/schema/feedback.js +31 -0
  224. package/dist/core/config/schema/improve-processes.js +389 -0
  225. package/dist/core/config/schema/improve.js +94 -0
  226. package/dist/core/config/schema/index-config.js +176 -0
  227. package/dist/core/config/schema/output.js +18 -0
  228. package/dist/core/config/schema/primitives.js +94 -0
  229. package/dist/core/config/schema/search.js +30 -0
  230. package/dist/core/config/schema/setup.js +18 -0
  231. package/dist/core/config/schema/sources-bundles.js +169 -0
  232. package/dist/core/config/schema/workflow.js +29 -0
  233. package/dist/core/env-secret-ref.js +155 -20
  234. package/dist/core/errors.js +17 -15
  235. package/dist/core/events-types.js +4 -0
  236. package/dist/core/events.js +46 -128
  237. package/dist/core/extra-params.js +62 -0
  238. package/dist/core/file-change.js +17 -0
  239. package/dist/core/file-lock.js +202 -57
  240. package/dist/core/fs-txn.js +392 -0
  241. package/dist/core/git-message.js +59 -0
  242. package/dist/core/improve-result.js +167 -0
  243. package/dist/core/lesson-lint.js +1 -17
  244. package/dist/core/logs-db.js +1 -1
  245. package/dist/core/maintenance-barrier.js +135 -0
  246. package/dist/core/migration-operation.js +44 -0
  247. package/dist/core/mutation-target.js +78 -0
  248. package/dist/core/paths.js +22 -25
  249. package/dist/core/platform.js +10 -0
  250. package/dist/core/recognition-util.js +128 -0
  251. package/dist/core/redaction.js +392 -0
  252. package/dist/core/standards/resolve-standards-context.js +36 -65
  253. package/dist/core/standards/resolve-stash-standards.js +2 -2
  254. package/dist/core/standards/resolve-type-conventions.js +5 -5
  255. package/dist/core/state/migrations.js +242 -11
  256. package/dist/core/state-db.js +98 -10
  257. package/dist/core/structured.js +1 -1
  258. package/dist/core/subprocess.js +303 -0
  259. package/dist/core/text-truncation.js +9 -5
  260. package/dist/core/time.js +20 -0
  261. package/dist/core/type-presentation.js +130 -0
  262. package/dist/core/warn.js +0 -3
  263. package/dist/core/write-source.js +834 -118
  264. package/dist/indexer/bundle-identity-guard.js +92 -0
  265. package/dist/indexer/db/graph-db.js +1 -25
  266. package/dist/indexer/db/llm-cache.js +1 -1
  267. package/dist/indexer/ensure-index.js +30 -9
  268. package/dist/indexer/graph/graph-boost.js +9 -30
  269. package/dist/indexer/graph/graph-extraction.js +41 -27
  270. package/dist/indexer/graph/graph-types.js +4 -0
  271. package/dist/indexer/index-writer-lock.js +93 -49
  272. package/dist/indexer/index-written-assets.js +100 -53
  273. package/dist/indexer/indexer.js +746 -329
  274. package/dist/indexer/init.js +18 -25
  275. package/dist/indexer/installations.js +142 -0
  276. package/dist/indexer/passes/dir-staleness.js +18 -10
  277. package/dist/indexer/passes/memory-inference.js +25 -15
  278. package/dist/indexer/passes/metadata.js +412 -243
  279. package/dist/indexer/scan/doc-to-entry.js +160 -0
  280. package/dist/indexer/scan/drain-dir.js +134 -0
  281. package/dist/indexer/search/db-search.js +292 -108
  282. package/dist/indexer/search/fts-query.js +64 -0
  283. package/dist/indexer/search/ranking-contributors.js +145 -25
  284. package/dist/indexer/search/ranking-types.js +4 -0
  285. package/dist/indexer/search/ranking.js +28 -71
  286. package/dist/indexer/search/search-attribution.js +67 -0
  287. package/dist/indexer/search/search-fields.js +18 -3
  288. package/dist/indexer/search/search-hit-enrichers.js +30 -40
  289. package/dist/indexer/search/search-source.js +157 -111
  290. package/dist/indexer/search/semantic-status.js +4 -1
  291. package/dist/indexer/usage/usage-events.js +10 -30
  292. package/dist/indexer/walk/file-context.js +3 -45
  293. package/dist/indexer/walk/matchers.js +42 -73
  294. package/dist/indexer/walk/path-resolver.js +11 -5
  295. package/dist/indexer/walk/walker.js +42 -14
  296. package/dist/integrations/agent/builder-shared.js +7 -0
  297. package/dist/integrations/agent/builders.js +5 -58
  298. package/dist/integrations/agent/config.js +3 -143
  299. package/dist/integrations/agent/detect.js +17 -2
  300. package/dist/integrations/agent/engine-resolution.js +231 -0
  301. package/dist/integrations/agent/index.js +1 -2
  302. package/dist/integrations/agent/model-aliases.js +8 -3
  303. package/dist/integrations/agent/profiles.js +6 -99
  304. package/dist/integrations/agent/prompts.js +46 -18
  305. package/dist/integrations/agent/runner-dispatch.js +78 -13
  306. package/dist/integrations/agent/runner.js +76 -208
  307. package/dist/integrations/agent/spawn.js +48 -279
  308. package/dist/integrations/harnesses/aider/agent-builder.js +9 -8
  309. package/dist/integrations/harnesses/aider/index.js +2 -12
  310. package/dist/integrations/harnesses/amazonq/agent-builder.js +10 -16
  311. package/dist/integrations/harnesses/amazonq/index.js +3 -17
  312. package/dist/integrations/harnesses/claude/agent-builder.js +2 -3
  313. package/dist/integrations/harnesses/claude/config-import.js +1 -3
  314. package/dist/integrations/harnesses/claude/index.js +1 -14
  315. package/dist/integrations/harnesses/claude/session-log.js +27 -75
  316. package/dist/integrations/harnesses/codex/agent-builder.js +8 -7
  317. package/dist/integrations/harnesses/codex/index.js +2 -13
  318. package/dist/integrations/harnesses/copilot/agent-builder.js +9 -9
  319. package/dist/integrations/harnesses/copilot/index.js +1 -13
  320. package/dist/integrations/harnesses/gemini/agent-builder.js +8 -9
  321. package/dist/integrations/harnesses/gemini/index.js +1 -13
  322. package/dist/integrations/harnesses/ids.js +24 -0
  323. package/dist/integrations/harnesses/index.js +31 -33
  324. package/dist/integrations/harnesses/opencode/agent-builder.js +23 -5
  325. package/dist/integrations/harnesses/opencode/config-import.js +1 -3
  326. package/dist/integrations/harnesses/opencode/index.js +1 -18
  327. package/dist/integrations/harnesses/opencode/session-log.js +67 -125
  328. package/dist/integrations/harnesses/opencode-sdk/harness.js +3 -17
  329. package/dist/integrations/harnesses/opencode-sdk/sdk-runner.js +274 -191
  330. package/dist/integrations/harnesses/openhands/agent-builder.js +12 -10
  331. package/dist/integrations/harnesses/openhands/index.js +2 -12
  332. package/dist/integrations/harnesses/pi/agent-builder.js +11 -18
  333. package/dist/integrations/harnesses/pi/index.js +3 -16
  334. package/dist/integrations/harnesses/shared.js +17 -0
  335. package/dist/integrations/harnesses/types.js +38 -34
  336. package/dist/integrations/lockfile.js +211 -24
  337. package/dist/integrations/session-logs/index.js +24 -40
  338. package/dist/integrations/session-logs/provider-base.js +113 -0
  339. package/dist/llm/client.js +182 -110
  340. package/dist/llm/embedders/deterministic.js +2 -2
  341. package/dist/llm/embedders/remote.js +21 -9
  342. package/dist/llm/feature-gate.js +17 -57
  343. package/dist/llm/graph-extract.js +12 -13
  344. package/dist/llm/index-passes.js +8 -42
  345. package/dist/llm/memory-infer.js +144 -1
  346. package/dist/llm/metadata-enhance.js +45 -30
  347. package/dist/llm/structured-call.js +16 -8
  348. package/dist/llm/usage-persist.js +30 -5
  349. package/dist/llm/usage-telemetry.js +59 -6
  350. package/dist/output/cli-hints.js +1 -2
  351. package/dist/output/command-registry.js +27 -0
  352. package/dist/output/context.js +22 -7
  353. package/dist/output/format-exempt.js +80 -0
  354. package/dist/output/generic-render.js +251 -0
  355. package/dist/output/html-render.js +11 -16
  356. package/dist/output/render-registry.js +57 -0
  357. package/dist/output/renderers.js +15 -281
  358. package/dist/output/shapes/curate.js +10 -1
  359. package/dist/output/shapes/events.js +12 -7
  360. package/dist/output/shapes/helpers.js +58 -84
  361. package/dist/output/shapes/passthrough.js +8 -40
  362. package/dist/output/shapes/proposal/producer.js +15 -7
  363. package/dist/output/shapes/registry.js +12 -6
  364. package/dist/output/shapes.js +0 -9
  365. package/dist/output/text/{init.js → bundle-create.js} +3 -1
  366. package/dist/output/text/bundle-show.js +7 -0
  367. package/dist/output/text/command-format.js +562 -0
  368. package/dist/output/text/env.js +1 -3
  369. package/dist/output/text/events.js +8 -7
  370. package/dist/output/text/helpers.js +15 -1375
  371. package/dist/output/text/proposal/producer.js +4 -2
  372. package/dist/output/text/proposal-format.js +202 -0
  373. package/dist/output/text/registry-commands.js +1 -2
  374. package/dist/output/text/registry.js +12 -6
  375. package/dist/output/text/show-directives.js +117 -0
  376. package/dist/output/text/show-format.js +103 -0
  377. package/dist/output/text/sync.js +5 -0
  378. package/dist/output/text/workflow-format.js +332 -0
  379. package/dist/output/text/workflow.js +1 -2
  380. package/dist/output/text.js +10 -19
  381. package/dist/registry/factory.js +4 -6
  382. package/dist/registry/origin-resolve.js +16 -27
  383. package/dist/registry/providers/skills-sh.js +3 -3
  384. package/dist/registry/providers/static-index.js +15 -25
  385. package/dist/registry/resolve.js +43 -94
  386. package/dist/registry/semver.js +43 -0
  387. package/dist/runtime.js +81 -12
  388. package/dist/scripts/akm-migrate.js +35529 -0
  389. package/dist/setup/detect.js +5 -7
  390. package/dist/setup/detected-engines.js +136 -0
  391. package/dist/setup/engine-config.js +100 -0
  392. package/dist/setup/registry-stash-loader.js +3 -3
  393. package/dist/setup/semantic-assets.js +12 -9
  394. package/dist/setup/setup.js +444 -208
  395. package/dist/setup/steps/connection-shared.js +120 -0
  396. package/dist/setup/steps/connection.js +108 -305
  397. package/dist/setup/steps/platforms.js +13 -12
  398. package/dist/setup/steps/semantic.js +15 -3
  399. package/dist/setup/steps/sources.js +21 -15
  400. package/dist/setup/steps/stashdir.js +6 -4
  401. package/dist/setup/steps/tasks.js +236 -119
  402. package/dist/setup/steps.js +3 -2
  403. package/dist/sources/freshness.js +39 -0
  404. package/dist/sources/provider-factory.js +11 -17
  405. package/dist/sources/providers/filesystem.js +2 -3
  406. package/dist/sources/providers/git-install.js +278 -34
  407. package/dist/sources/providers/git-provider.js +54 -56
  408. package/dist/sources/providers/git-stash.js +420 -91
  409. package/dist/sources/providers/git.js +2 -2
  410. package/dist/sources/providers/npm.js +16 -19
  411. package/dist/sources/providers/provider-utils.js +47 -22
  412. package/dist/sources/providers/sync-from-ref.js +3 -9
  413. package/dist/sources/providers/website.js +2 -2
  414. package/dist/sources/resolve.js +11 -10
  415. package/dist/sources/snapshot-fetchers/types.js +4 -0
  416. package/dist/sources/{website-ingest.js → snapshot-fetchers/website-ingest.js} +110 -41
  417. package/dist/storage/database.js +60 -4
  418. package/dist/storage/engines/sqlite-migrations.js +156 -5
  419. package/dist/storage/locations.js +1 -2
  420. package/dist/storage/repositories/canaries-repository.js +1 -1
  421. package/dist/storage/repositories/events-repository.js +51 -11
  422. package/dist/storage/repositories/improve-runs-repository.js +6 -32
  423. package/dist/storage/repositories/index-connection.js +79 -0
  424. package/dist/storage/repositories/index-db.js +4 -3
  425. package/dist/storage/repositories/index-entries-repository.js +863 -0
  426. package/dist/{indexer/db/entry-mapper.js → storage/repositories/index-entry-mapper.js} +19 -2
  427. package/dist/storage/repositories/index-entry-types.js +4 -0
  428. package/dist/storage/repositories/index-fts-repository.js +167 -0
  429. package/dist/storage/repositories/index-llm-cache-repository.js +108 -0
  430. package/dist/storage/repositories/index-meta-repository.js +49 -0
  431. package/dist/{indexer/db/schema.js → storage/repositories/index-schema.js} +226 -100
  432. package/dist/storage/repositories/index-sql.js +12 -0
  433. package/dist/storage/repositories/index-utility-repository.js +356 -0
  434. package/dist/storage/repositories/index-vec-repository.js +250 -0
  435. package/dist/storage/repositories/outcome-repository.js +119 -0
  436. package/dist/storage/repositories/proposals-repository.js +317 -75
  437. package/dist/storage/repositories/registry-cache.js +1 -1
  438. package/dist/storage/repositories/salience-repository.js +172 -0
  439. package/dist/storage/repositories/task-history-repository.js +110 -3
  440. package/dist/storage/repositories/workflow-runs-repository.js +68 -35
  441. package/dist/tasks/backends/cron.js +169 -46
  442. package/dist/tasks/backends/exec-utils.js +76 -3
  443. package/dist/tasks/backends/index.js +6 -9
  444. package/dist/tasks/backends/launchd.js +292 -55
  445. package/dist/tasks/backends/schtasks.js +557 -70
  446. package/dist/tasks/backends/types.js +4 -0
  447. package/dist/tasks/command-executable.js +93 -0
  448. package/dist/tasks/embedded.js +56 -38
  449. package/dist/tasks/parser.js +156 -64
  450. package/dist/tasks/resolve-akm-bin.js +144 -51
  451. package/dist/tasks/runner.js +377 -209
  452. package/dist/tasks/schedule.js +108 -19
  453. package/dist/tasks/scheduler-invocation.js +296 -0
  454. package/dist/tasks/schema.js +1 -1
  455. package/dist/tasks/task-id.js +35 -0
  456. package/dist/tasks/validator.js +30 -16
  457. package/dist/workflows/authoring/authoring.js +96 -148
  458. package/dist/workflows/authoring/scope-key.js +1 -1
  459. package/dist/workflows/cli.js +0 -20
  460. package/dist/workflows/concurrency-policy.js +15 -0
  461. package/dist/workflows/exec/brief.js +25 -59
  462. package/dist/workflows/exec/frozen-judge.js +47 -0
  463. package/dist/workflows/exec/native-executor.js +157 -94
  464. package/dist/workflows/exec/report.js +365 -200
  465. package/dist/workflows/exec/run-workflow.js +46 -40
  466. package/dist/workflows/exec/scheduler.js +12 -41
  467. package/dist/workflows/exec/step-work.js +239 -205
  468. package/dist/workflows/exec/workflow-engine-gate.js +67 -0
  469. package/dist/workflows/ir/compile.js +141 -283
  470. package/dist/workflows/ir/freeze.js +233 -0
  471. package/dist/workflows/ir/plan-hash.js +40 -5
  472. package/dist/workflows/ir/schema.js +537 -1
  473. package/dist/workflows/parser.js +878 -306
  474. package/dist/workflows/program/expressions.js +20 -208
  475. package/dist/workflows/program/schema.js +7 -10
  476. package/dist/workflows/renderer.js +99 -121
  477. package/dist/workflows/resource-limits.js +22 -0
  478. package/dist/workflows/runtime/checkin.js +1 -1
  479. package/dist/workflows/runtime/plan-classifier.js +131 -0
  480. package/dist/workflows/runtime/runs.js +200 -113
  481. package/dist/workflows/runtime/unit-checkin.js +1 -1
  482. package/dist/workflows/runtime/unit-phases.js +20 -0
  483. package/dist/workflows/runtime/workflow-asset-loader.js +235 -97
  484. package/dist/workflows/schema.js +1 -11
  485. package/dist/workflows/validate-summary.js +4 -26
  486. package/dist/workflows/validator.js +52 -30
  487. package/docs/README.md +42 -78
  488. package/docs/migration/README.md +8 -0
  489. package/docs/migration/release-notes/0.6.0.md +1 -1
  490. package/docs/migration/release-notes/0.7.0.md +9 -8
  491. package/docs/migration/release-notes/0.9.0.md +158 -14
  492. package/docs/migration/v0.7-to-v0.8.md +46 -47
  493. package/docs/migration/v0.8-to-v0.9.md +844 -0
  494. package/docs/reference/README.md +12 -0
  495. package/docs/reference/data-and-telemetry.md +333 -0
  496. package/package.json +21 -17
  497. package/schemas/akm-asset-envelope.json +93 -0
  498. package/schemas/akm-config.json +4636 -0
  499. package/schemas/akm-task.json +87 -0
  500. package/{dist/schemas → schemas}/akm-workflow.json +127 -82
  501. package/dist/akm-migrate-storage +0 -38
  502. package/dist/assets/help/help-accept.md +0 -12
  503. package/dist/assets/help/help-improve.md +0 -84
  504. package/dist/assets/help/help-proposals.md +0 -17
  505. package/dist/assets/help/help-propose.md +0 -17
  506. package/dist/assets/help/help-reject.md +0 -11
  507. package/dist/assets/profiles/frequent.json +0 -13
  508. package/dist/assets/profiles/recombine-only.json +0 -21
  509. package/dist/assets/profiles/reflect-distill.json +0 -30
  510. package/dist/assets/profiles/synthesize.json +0 -15
  511. package/dist/assets/prompts/procedural-system.md +0 -44
  512. package/dist/assets/prompts/recombine-system.md +0 -40
  513. package/dist/assets/prompts/staleness-detect-system.md +0 -6
  514. package/dist/assets/tasks/core/backup.yml +0 -4
  515. package/dist/assets/tasks/graph-refresh-weekly.yml +0 -10
  516. package/dist/assets/templates/html/default.html +0 -78
  517. package/dist/assets/templates/html/vendor/echarts.min.js +0 -45
  518. package/dist/assets/wiki/index-template.md +0 -12
  519. package/dist/assets/wiki/ingest-workflow-template.md +0 -83
  520. package/dist/assets/wiki/log-template.md +0 -8
  521. package/dist/assets/wiki/schema-template.md +0 -61
  522. package/dist/cli/config-migrate.js +0 -150
  523. package/dist/cli/config-validate.js +0 -39
  524. package/dist/commands/graph/graph-cli.js +0 -124
  525. package/dist/commands/graph/graph.js +0 -487
  526. package/dist/commands/improve/calibration.js +0 -161
  527. package/dist/commands/improve/dedup.js +0 -482
  528. package/dist/commands/improve/extract-watch.js +0 -140
  529. package/dist/commands/improve/hot-probation.js +0 -45
  530. package/dist/commands/improve/improve-auto-accept.js +0 -276
  531. package/dist/commands/improve/improve-profiles.js +0 -168
  532. package/dist/commands/improve/procedural.js +0 -398
  533. package/dist/commands/improve/recombine.js +0 -818
  534. package/dist/commands/improve/schema-similarity-gate.js +0 -168
  535. package/dist/commands/lint/agent-linter.js +0 -44
  536. package/dist/commands/lint/command-linter.js +0 -44
  537. package/dist/commands/lint/default-linter.js +0 -16
  538. package/dist/commands/lint/fact-linter.js +0 -39
  539. package/dist/commands/lint/knowledge-linter.js +0 -16
  540. package/dist/commands/lint/memory-linter.js +0 -61
  541. package/dist/commands/lint/registry.js +0 -41
  542. package/dist/commands/lint/skill-linter.js +0 -45
  543. package/dist/commands/lint/task-linter.js +0 -50
  544. package/dist/commands/lint/workflow-linter.js +0 -81
  545. package/dist/commands/proposal/legacy-import.js +0 -115
  546. package/dist/commands/sources/history.js +0 -196
  547. package/dist/commands/tasks/default-tasks.js +0 -186
  548. package/dist/commands/wiki-cli.js +0 -292
  549. package/dist/core/asset/asset-registry.js +0 -76
  550. package/dist/core/asset/asset-spec.js +0 -316
  551. package/dist/core/config/config-migration.js +0 -602
  552. package/dist/core/deep-merge.js +0 -38
  553. package/dist/core/eval/rank-metrics.js +0 -113
  554. package/dist/core/ripgrep/install.js +0 -163
  555. package/dist/core/ripgrep/resolve.js +0 -81
  556. package/dist/indexer/db/db.js +0 -1414
  557. package/dist/indexer/manifest.js +0 -170
  558. package/dist/indexer/passes/metadata-contributors.js +0 -31
  559. package/dist/indexer/usage/unmigrated-vaults-guard.js +0 -94
  560. package/dist/integrations/harnesses/opencode-sdk/index.js +0 -25
  561. package/dist/llm/call-ai.js +0 -62
  562. package/dist/llm/memory-infer-impl.js +0 -138
  563. package/dist/output/shapes/distill.js +0 -14
  564. package/dist/output/shapes/history.js +0 -11
  565. package/dist/output/text/distill.js +0 -6
  566. package/dist/output/text/enable-disable.js +0 -8
  567. package/dist/output/text/history.js +0 -6
  568. package/dist/output/text/wiki.js +0 -16
  569. package/dist/registry/build-index.js +0 -386
  570. package/dist/schemas/akm-config.json +0 -14225
  571. package/dist/scripts/migrate-storage.js +0 -13169
  572. package/dist/scripts/migrations/import-fs-improve-runs-to-db.js +0 -10169
  573. package/dist/scripts/migrations/v16-to-v17.js +0 -141
  574. package/dist/setup/legacy-config.js +0 -106
  575. package/dist/storage/repositories/consolidation-repository.js +0 -38
  576. package/dist/storage/repositories/recombine-repository.js +0 -213
  577. package/dist/wiki/wiki-templates.js +0 -15
  578. package/dist/wiki/wiki.js +0 -1012
  579. package/dist/workflows/authoring/workflow-program-template.yaml +0 -31
  580. package/dist/workflows/db.js +0 -350
  581. package/dist/workflows/exec/watch.js +0 -116
  582. package/dist/workflows/program/parser.js +0 -760
  583. package/dist/workflows/program/project.js +0 -105
  584. package/docs/data-and-telemetry.md +0 -227
  585. package/docs/migration/release-notes/0.9.0-beta.60.md +0 -19
  586. /package/dist/sources/{wiki-fetchers → snapshot-fetchers}/registry.js +0 -0
  587. /package/dist/sources/{wiki-fetchers → snapshot-fetchers}/youtube.js +0 -0
@@ -1,482 +0,0 @@
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
- // ── Deterministic near-duplicate MEMORY dedup (#617) ─────────────────────────
5
- //
6
- // A CHEAP, DETERMINISTIC fast path that collapses the obvious duplicates with
7
- // NO LLM call, run in front of the embedding-clustered LLM consolidation pass
8
- // (see consolidate.ts). The working stash accumulates near-duplicates faster
9
- // than the capped/rotating LLM consolidate pass can merge them; this pre-pass
10
- // clears the unambiguous twins so the (expensive) LLM only ever sees genuinely
11
- // distinct-but-related memories.
12
- //
13
- // Two collapse classes, both safe and reversible (archive + backup at the call
14
- // site in consolidate.ts; this module only computes the plan and applies the
15
- // file writes/deletes):
16
- //
17
- // 1. `.derived` ↔ origin pairs — a memory-inference `<parent>.derived` child
18
- // whose normalized body is identical to (or, with embeddings, ≥ the strict
19
- // cosine threshold of) its origin. Keep the canonical (non-derived) origin;
20
- // drop the derived variant; preserve the variant's provenance on the
21
- // canonical (`dedupedFrom`).
22
- //
23
- // 2. Content twins — two non-derived memories with identical normalized body
24
- // hash, or ≥ the strict cosine threshold. Keep the deterministic canonical
25
- // (lexicographically smallest name); merge the other into it, preserving
26
- // provenance.
27
- //
28
- // Determinism: the plan is a pure function of the on-disk memory set + config.
29
- // Nothing here reads Date.now()/Math.random(); ordering is by memory name so the
30
- // canonical choice and op order are stable across runs.
31
- //
32
- // Gating: DEFAULT OFF. The pre-pass only runs when `dedup.enabled === true`. The
33
- // cosine path additionally requires an embedding config; absent embeddings the
34
- // pass still collapses exact normalized-hash twins. `cosineThreshold` defaults
35
- // to 0.97 — a strict floor chosen so distinct-but-related memories fall through
36
- // untouched to the LLM consolidation.
37
- import { createHash } from "node:crypto";
38
- import fs from "node:fs";
39
- import path from "node:path";
40
- import { parseAssetRef } from "../../core/asset/asset-ref.js";
41
- import { assembleAssetFromString, serializeFrontmatter } from "../../core/asset/asset-serialize.js";
42
- import { parseFrontmatter } from "../../core/asset/frontmatter.js";
43
- import { warn } from "../../core/warn.js";
44
- import { cosineSimilarity, embedBatch, resolveEmbeddingModelId } from "../../llm/embedder.js";
45
- import { getBodyEmbeddings, upsertBodyEmbeddings } from "../../storage/repositories/embeddings-repository.js";
46
- /** Default strict cosine floor — high enough to skip distinct-but-related memories. */
47
- export const DEFAULT_DEDUP_COSINE_THRESHOLD = 0.97;
48
- /**
49
- * Strip frontmatter from raw memory content, returning the body text trimmed.
50
- * Case and whitespace are preserved — this is the shared primitive used by
51
- * both hash wrappers below. Falls back to `raw.trim()` on unparseable
52
- * frontmatter (consistent with the pre-existing load-time hot guard).
53
- */
54
- export function stripFrontmatterBody(raw) {
55
- try {
56
- return parseFrontmatter(raw).content.trim();
57
- }
58
- catch {
59
- return raw.trim();
60
- }
61
- }
62
- /**
63
- * Normalize a memory body for content-twin equality. Strips frontmatter,
64
- * lowercases, trims, and collapses all runs of whitespace to a single space so
65
- * trivial reformatting (extra blank lines, trailing spaces, case) does not
66
- * defeat the hash. Deterministic and pure.
67
- *
68
- * Use this for the DEDUP path only (exact-twin detection). For the change-
69
- * detection / embedding-cache path use `cacheHash` instead.
70
- */
71
- export function normalizeMemoryBody(raw) {
72
- return stripFrontmatterBody(raw).toLowerCase().replace(/\s+/g, " ");
73
- }
74
- /**
75
- * Hash used for content-twin detection: lowercase + whitespace-collapsed body.
76
- * Two memories that differ only in case or whitespace produce the same hash
77
- * and are considered identical twins. Use this key for the dedup buckets.
78
- */
79
- export function dedupHash(raw) {
80
- return createHash("sha256").update(normalizeMemoryBody(raw), "utf8").digest("hex");
81
- }
82
- /**
83
- * Hash used for change-detection and the body-embedding cache: case-/whitespace-
84
- * preserving stripped body. Two memories with the same wording but different
85
- * casing produce DIFFERENT hashes here, which is intentional — we embed the
86
- * exact text and cache by its precise content.
87
- *
88
- * This is the `content_hash` stored in `body_embeddings` and
89
- * `consolidation_judged`. Do NOT reuse the `dedupHash` for those tables.
90
- */
91
- export function cacheHash(raw) {
92
- return createHash("sha256").update(stripFrontmatterBody(raw), "utf8").digest("hex");
93
- }
94
- /**
95
- * Load every memory `.md` file (including `.derived` children) from the stash
96
- * memories directory. Unlike the consolidate loader, this DOES include derived
97
- * children — the whole point of class 1 is to collapse a derived child into its
98
- * origin, so both must be visible here.
99
- */
100
- export function loadDedupMemories(stashDir) {
101
- const memoriesDir = path.join(stashDir, "memories");
102
- if (!fs.existsSync(memoriesDir))
103
- return [];
104
- const out = [];
105
- for (const fname of fs.readdirSync(memoriesDir).sort()) {
106
- if (!fname.endsWith(".md"))
107
- continue;
108
- const name = fname.replace(/\.md$/, "");
109
- const filePath = path.join(memoriesDir, fname);
110
- let raw;
111
- try {
112
- raw = fs.readFileSync(filePath, "utf8");
113
- }
114
- catch {
115
- continue;
116
- }
117
- let fm = {};
118
- try {
119
- fm = parseFrontmatter(raw).data ?? {};
120
- }
121
- catch {
122
- fm = {};
123
- }
124
- const normalizedBody = normalizeMemoryBody(raw);
125
- out.push({
126
- name,
127
- filePath,
128
- derived: name.endsWith(".derived"),
129
- derivedFrom: typeof fm.derivedFrom === "string" ? fm.derivedFrom : undefined,
130
- raw,
131
- normalizedBody,
132
- bodyHash: dedupHash(raw),
133
- hot: fm.captureMode === "hot",
134
- });
135
- }
136
- return out;
137
- }
138
- /** Default cap on the O(n²) cosine-compare pool size. */
139
- export const DEFAULT_COSINE_CANDIDATE_LIMIT = 500;
140
- /**
141
- * Build the deterministic collapse plan. Pure over (memories, similarities,
142
- * threshold) — `embeddings` is optional; when absent only exact normalized-hash
143
- * twins are matched.
144
- *
145
- * Pass invariants:
146
- * - A memory is consumed (collapsed) at most once.
147
- * - Hot (captureMode: hot) memories are never collapsed, as canonical OR
148
- * variant — user-explicit, only the user retires them.
149
- * - Class 1 (`.derived` ↔ origin) is matched first so a derived child is
150
- * always folded into its origin (never the reverse, never twin-matched).
151
- */
152
- export function planDedup(memories, opts) {
153
- const collapses = [];
154
- const warnings = [];
155
- const consumed = new Set();
156
- const threshold = opts.cosineThreshold;
157
- const byName = new Map();
158
- for (const m of memories)
159
- byName.set(m.name, m);
160
- const sim = (a, b) => {
161
- if (!opts.embeddings)
162
- return undefined;
163
- const ea = opts.embeddings.get(a.name);
164
- const eb = opts.embeddings.get(b.name);
165
- if (!ea || !eb)
166
- return undefined;
167
- return cosineSimilarity(ea, eb);
168
- };
169
- // ── Class 1: `.derived` children ↔ their origin ────────────────────────────
170
- // Iterate derived children in sorted order (loadDedupMemories sorts), folding
171
- // each into its origin when near-identical.
172
- const derived = memories.filter((m) => m.derived).sort((a, b) => a.name.localeCompare(b.name));
173
- for (const child of derived) {
174
- if (consumed.has(child.name))
175
- continue;
176
- if (child.hot)
177
- continue;
178
- const originName = child.derivedFrom ?? child.name.replace(/\.derived$/, "");
179
- const origin = byName.get(originName);
180
- if (!origin || consumed.has(origin.name) || origin.derived || origin.hot)
181
- continue;
182
- let via;
183
- let similarity;
184
- if (child.bodyHash === origin.bodyHash) {
185
- via = "derived-hash";
186
- }
187
- else {
188
- const s = sim(child, origin);
189
- if (s !== undefined && s >= threshold) {
190
- via = "derived-cosine";
191
- similarity = s;
192
- }
193
- }
194
- if (!via)
195
- continue;
196
- collapses.push({ canonical: origin.name, variant: child.name, via, similarity });
197
- consumed.add(child.name);
198
- }
199
- // ── Class 2: content twins among non-derived memories ──────────────────────
200
- // Bucket by exact normalized-hash first (cheap, transitive, deterministic).
201
- const remaining = memories
202
- .filter((m) => !m.derived && !m.hot && !consumed.has(m.name))
203
- .sort((a, b) => a.name.localeCompare(b.name));
204
- const hashBuckets = new Map();
205
- for (const m of remaining) {
206
- const list = hashBuckets.get(m.bodyHash);
207
- if (list)
208
- list.push(m);
209
- else
210
- hashBuckets.set(m.bodyHash, [m]);
211
- }
212
- for (const bucket of hashBuckets.values()) {
213
- if (bucket.length < 2)
214
- continue;
215
- // Canonical = lexicographically smallest name (already sorted).
216
- const canonical = bucket[0];
217
- for (let i = 1; i < bucket.length; i++) {
218
- const variant = bucket[i];
219
- if (consumed.has(variant.name))
220
- continue;
221
- collapses.push({ canonical: canonical.name, variant: variant.name, via: "twin-hash" });
222
- consumed.add(variant.name);
223
- }
224
- consumed.add(canonical.name); // canonical kept but no longer a twin candidate
225
- }
226
- // Cosine twins (only when embeddings are available). O(n²) over the still-
227
- // unconsumed non-derived pool; deterministic greedy: for each canonical in
228
- // sorted order, claim every unconsumed later memory whose similarity ≥ floor.
229
- // The pool is capped at `cosineCandidateLimit` (default 500) to bound the
230
- // O(n²) cost (~0.1 s at 500; ~3 s at 2.6 k; ~85 s at 13 k). Exact-hash
231
- // matches above always run over the full pool and are unaffected.
232
- if (opts.embeddings) {
233
- const limit = opts.cosineCandidateLimit ?? DEFAULT_COSINE_CANDIDATE_LIMIT;
234
- const fullPool = remaining.filter((m) => !consumed.has(m.name));
235
- const pool = fullPool.length > limit ? fullPool.slice(0, limit) : fullPool;
236
- if (fullPool.length > limit) {
237
- warnings.push(`dedup: cosine compare pool (${fullPool.length}) exceeds cosineCandidateLimit (${limit}); capping to first ${limit} memories (exact-hash matches unaffected).`);
238
- }
239
- for (let i = 0; i < pool.length; i++) {
240
- const canonical = pool[i];
241
- if (consumed.has(canonical.name))
242
- continue;
243
- for (let j = i + 1; j < pool.length; j++) {
244
- const variant = pool[j];
245
- if (consumed.has(variant.name))
246
- continue;
247
- const s = sim(canonical, variant);
248
- if (s !== undefined && s >= threshold) {
249
- collapses.push({ canonical: canonical.name, variant: variant.name, via: "twin-cosine", similarity: s });
250
- consumed.add(variant.name);
251
- }
252
- }
253
- consumed.add(canonical.name);
254
- }
255
- }
256
- return { collapses, warnings };
257
- }
258
- /**
259
- * Fold a dropped variant's provenance into the canonical's frontmatter. Appends
260
- * the variant ref to a `dedupedFrom` list (deduplicated, sorted) and carries
261
- * any `source`/`sources` references the variant held that the canonical lacks.
262
- * Pure string→string; never invents timestamps.
263
- */
264
- export function applyProvenance(canonicalRaw, variant) {
265
- let parsed;
266
- try {
267
- parsed = parseFrontmatter(canonicalRaw);
268
- }
269
- catch {
270
- // Canonical frontmatter unparseable — leave content untouched (the file is
271
- // never collapsed AS a canonical when hot/unparseable is the variant, but
272
- // the canonical itself can still be odd; preserve bytes).
273
- return canonicalRaw;
274
- }
275
- const fm = { ...parsed.data };
276
- const variantRef = `memory:${variant.name}`;
277
- const existing = Array.isArray(fm.dedupedFrom)
278
- ? fm.dedupedFrom.filter((v) => typeof v === "string")
279
- : typeof fm.dedupedFrom === "string"
280
- ? [fm.dedupedFrom]
281
- : [];
282
- const next = Array.from(new Set([...existing, variantRef])).sort();
283
- fm.dedupedFrom = next;
284
- return assembleAssetFromString(serializeFrontmatter(fm), parsed.content);
285
- }
286
- /**
287
- * Apply a collapse plan to disk: rewrite each canonical with merged provenance,
288
- * delete each variant. Returns counts + consumed refs so the consolidate pass
289
- * can prune them from the LLM pool. NO LLM call.
290
- *
291
- * `onArchive` (optional) is invoked with the variant file path before deletion
292
- * so the caller can archive/back up exactly as it does for LLM merges.
293
- */
294
- export function applyDedupPlan(plan, memories, onArchive) {
295
- const byName = new Map();
296
- for (const m of memories)
297
- byName.set(m.name, m);
298
- const warnings = [...plan.warnings];
299
- const consumedRefs = [];
300
- let collapsed = 0;
301
- // Accumulate provenance per canonical so multiple variants folding into the
302
- // same canonical produce a single rewrite.
303
- const provByCanonical = new Map();
304
- for (const c of plan.collapses) {
305
- const list = provByCanonical.get(c.canonical);
306
- if (list)
307
- list.push(byName.get(c.variant));
308
- else
309
- provByCanonical.set(c.canonical, [byName.get(c.variant)]);
310
- }
311
- // 1. Rewrite canonicals with merged provenance.
312
- for (const [canonicalName, variants] of provByCanonical) {
313
- const canonical = byName.get(canonicalName);
314
- if (!canonical)
315
- continue;
316
- let content = canonical.raw;
317
- for (const v of variants.filter((x) => x).sort((a, b) => a.name.localeCompare(b.name))) {
318
- content = applyProvenance(content, v);
319
- }
320
- try {
321
- fs.writeFileSync(canonical.filePath, content.endsWith("\n") ? content : `${content}\n`, "utf8");
322
- }
323
- catch (e) {
324
- warnings.push(`dedup: failed to rewrite canonical ${canonicalName}: ${String(e)}`);
325
- }
326
- }
327
- // 2. Delete variants (archive first if requested).
328
- for (const c of plan.collapses) {
329
- const variant = byName.get(c.variant);
330
- if (!variant)
331
- continue;
332
- if (!fs.existsSync(variant.filePath)) {
333
- warnings.push(`dedup: variant ${c.variant} already absent — skipping delete.`);
334
- continue;
335
- }
336
- if (onArchive) {
337
- try {
338
- onArchive(variant);
339
- }
340
- catch {
341
- // best-effort archival; deletion proceeds
342
- }
343
- }
344
- try {
345
- fs.unlinkSync(variant.filePath);
346
- collapsed++;
347
- consumedRefs.push(`memory:${variant.name}`);
348
- }
349
- catch (e) {
350
- warnings.push(`dedup: failed to delete variant ${c.variant}: ${String(e)}`);
351
- }
352
- }
353
- return { collapsed, consumedRefs, warnings };
354
- }
355
- /**
356
- * Top-level entry point for the consolidate pre-pass. Loads memories, optionally
357
- * embeds them (only when a cosine path is reachable), plans, and applies the
358
- * collapse. DEFAULT OFF — returns a no-op result when `config.enabled !== true`.
359
- *
360
- * `onArchive` lets the caller archive/back up each dropped variant before
361
- * deletion (consolidate.ts wires this to its existing archive helper).
362
- *
363
- * `signal` (optional): an AbortSignal forwarded from the caller's budget
364
- * controller. When aborted before the embedding call the function returns a
365
- * no-op result immediately; the signal is also forwarded into `embedBatch`
366
- * so a mid-embedding abort is handled cleanly.
367
- */
368
- export async function runDeterministicDedup(stashDir, dedupConfig, akmConfig, onArchive, signal,
369
- /** Optional open state.db handle for the body-embedding cache (WS-3a). */
370
- stateDb) {
371
- if (!dedupConfig?.enabled) {
372
- return { collapsed: 0, consumedRefs: [], warnings: [] };
373
- }
374
- if (signal?.aborted) {
375
- return { collapsed: 0, consumedRefs: [], warnings: ["dedup: aborted before start"] };
376
- }
377
- const threshold = dedupConfig.cosineThreshold ?? DEFAULT_DEDUP_COSINE_THRESHOLD;
378
- const candidateLimit = dedupConfig.cosineCandidateLimit ?? DEFAULT_COSINE_CANDIDATE_LIMIT;
379
- const memories = loadDedupMemories(stashDir);
380
- if (memories.length === 0) {
381
- return { collapsed: 0, consumedRefs: [], warnings: [] };
382
- }
383
- // Embed only when embeddings are configured — exact-hash collapse still works
384
- // without them. Fail-open: any embedding error degrades to hash-only matching.
385
- // NOTE: embedBatch embeds the case-preserving stripped body (cacheHash domain),
386
- // not the lowercase dedupHash body, so dedup cosine and the body_embeddings
387
- // cache share the same canonical embedding input.
388
- let embeddings;
389
- if (akmConfig.embedding) {
390
- try {
391
- const eligible = memories.filter((m) => !m.hot);
392
- // Use the case-preserving stripped body for embeddings (matching cacheHash
393
- // canonical input) so the embedding cache can be shared with consolidate.
394
- const modelId = resolveEmbeddingModelId(akmConfig.embedding);
395
- // WS-3a: body-embedding cache — look up all content_hashes in one query,
396
- // embed only the misses, then upsert the new vectors in one transaction.
397
- const contentHashes = eligible.map((m) => cacheHash(m.raw));
398
- const hashToName = new Map();
399
- for (let i = 0; i < eligible.length; i++) {
400
- hashToName.set(contentHashes[i], eligible[i].name);
401
- }
402
- let cachedVecs = new Map();
403
- if (stateDb) {
404
- try {
405
- cachedVecs = getBodyEmbeddings(stateDb, contentHashes, modelId);
406
- }
407
- catch {
408
- // Fail open: cache read errors degrade to full embed.
409
- cachedVecs = new Map();
410
- }
411
- }
412
- const missIndices = [];
413
- const missTexts = [];
414
- for (let i = 0; i < eligible.length; i++) {
415
- const hash = contentHashes[i];
416
- if (!cachedVecs.has(hash)) {
417
- missIndices.push(i);
418
- missTexts.push(stripFrontmatterBody(eligible[i].raw) || eligible[i].name);
419
- }
420
- }
421
- let missVecs = [];
422
- if (missTexts.length > 0) {
423
- missVecs = await embedBatch(missTexts, akmConfig.embedding, signal);
424
- // Upsert new vectors into cache.
425
- if (stateDb && missVecs.length === missTexts.length) {
426
- try {
427
- const toUpsert = missIndices.map((idx, pos) => ({
428
- contentHash: contentHashes[idx],
429
- embedding: missVecs[pos],
430
- modelId,
431
- }));
432
- upsertBodyEmbeddings(stateDb, toUpsert);
433
- }
434
- catch {
435
- // Fail open: cache write errors are non-fatal.
436
- }
437
- }
438
- }
439
- // Assemble the full embeddings map (cache hits + freshly embedded misses).
440
- if (missVecs.length === missTexts.length || cachedVecs.size > 0) {
441
- embeddings = new Map();
442
- // Add cache hits.
443
- for (let i = 0; i < eligible.length; i++) {
444
- const hash = contentHashes[i];
445
- const cached = cachedVecs.get(hash);
446
- if (cached)
447
- embeddings.set(eligible[i].name, cached);
448
- }
449
- // Add freshly embedded misses.
450
- for (let pos = 0; pos < missIndices.length; pos++) {
451
- const idx = missIndices[pos];
452
- const vec = missVecs[pos];
453
- if (vec)
454
- embeddings.set(eligible[idx].name, vec);
455
- }
456
- }
457
- }
458
- catch {
459
- embeddings = undefined;
460
- }
461
- }
462
- const plan = planDedup(memories, { cosineThreshold: threshold, embeddings, cosineCandidateLimit: candidateLimit });
463
- if (plan.collapses.length === 0) {
464
- return { collapsed: 0, consumedRefs: [], warnings: plan.warnings };
465
- }
466
- // Sanity: every variant ref must be a parseable memory ref before we touch
467
- // disk (defends against a malformed name slipping through).
468
- for (const c of plan.collapses) {
469
- try {
470
- parseAssetRef(`memory:${c.variant}`);
471
- parseAssetRef(`memory:${c.canonical}`);
472
- }
473
- catch {
474
- plan.warnings.push(`dedup: unparseable ref in collapse ${c.canonical} ← ${c.variant} — dropping op.`);
475
- }
476
- }
477
- const result = applyDedupPlan(plan, memories, (v) => onArchive?.(v.filePath, v.name));
478
- if (result.collapsed > 0) {
479
- warn(`[consolidate] deterministic dedup collapsed ${result.collapsed} near-duplicate memor${result.collapsed === 1 ? "y" : "ies"} (no LLM).`);
480
- }
481
- return result;
482
- }
@@ -1,140 +0,0 @@
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
- import { akmExtract } from "./extract.js";
5
- const DEFAULT_DEBOUNCE_MS = 2000;
6
- /** Small look-back window for the default trigger's `akmExtract` call. */
7
- const DEFAULT_TRIGGER_SINCE = "10m";
8
- /**
9
- * Does `filePath` look like a real session file under one of the configured
10
- * roots? True only when the path is under a root AND matches that harness's
11
- * on-disk session-file shape:
12
- * - claude-code: `<root>/<project>/<id>.jsonl`
13
- * - opencode: `<root>/<project>/<id>.json`
14
- * Anything out-of-root, or in-root with the wrong extension, returns false.
15
- */
16
- export function isSessionFile(filePath, roots) {
17
- return matchHarness(filePath, roots) !== undefined;
18
- }
19
- /** Normalize a path for prefix comparison (ensure a trailing separator). */
20
- function withSep(dir) {
21
- return dir.endsWith("/") ? dir : `${dir}/`;
22
- }
23
- /**
24
- * Resolve which harness a path belongs to by longest-prefix match against the
25
- * configured roots, then validate the file shape for that harness. Returns the
26
- * harness name, or `undefined` when the path is out-of-root or not a session
27
- * file. Longest-prefix match guards against the (in practice impossible) case
28
- * of nested roots.
29
- */
30
- export function matchHarness(filePath, roots) {
31
- let best;
32
- let bestLen = -1;
33
- for (const target of roots) {
34
- for (const root of target.roots) {
35
- const prefix = withSep(root);
36
- if (filePath.startsWith(prefix) && prefix.length > bestLen) {
37
- best = { harnessName: target.harnessName };
38
- bestLen = prefix.length;
39
- }
40
- }
41
- }
42
- if (!best)
43
- return undefined;
44
- // Validate the file shape for the resolved harness.
45
- if (best.harnessName === "claude-code") {
46
- return filePath.endsWith(".jsonl") ? best.harnessName : undefined;
47
- }
48
- if (best.harnessName === "opencode") {
49
- return filePath.endsWith(".json") ? best.harnessName : undefined;
50
- }
51
- // Unknown harness: accept any file under its root.
52
- return best.harnessName;
53
- }
54
- /**
55
- * Start the watch-mode core. Returns a handle whose `stop()` tears everything
56
- * down. The event source is injected, so this never touches the real
57
- * filesystem itself.
58
- */
59
- export function akmExtractWatch(options) {
60
- const { roots, eventSource, debounceMs = DEFAULT_DEBOUNCE_MS, setTimeoutFn = setTimeout, clearTimeoutFn = clearTimeout, isSessionFile: isSessionFileFn = isSessionFile, } = options;
61
- const onTrigger = options.onTrigger ??
62
- (async (harnessName) => {
63
- await akmExtract({ type: harnessName, since: DEFAULT_TRIGGER_SINCE, force: false });
64
- });
65
- let stopped = false;
66
- // Pending debounce timers, keyed by harness name.
67
- const pendingTimers = new Map();
68
- // Harnesses with an in-flight trigger, and whether a re-run is queued.
69
- const inFlight = new Set();
70
- const rerunPending = new Set();
71
- function runTrigger(harnessName) {
72
- if (stopped)
73
- return;
74
- if (inFlight.has(harnessName)) {
75
- // A trigger is already running for this harness; coalesce into a single
76
- // re-run after it resolves rather than launching a concurrent extract.
77
- rerunPending.add(harnessName);
78
- return;
79
- }
80
- inFlight.add(harnessName);
81
- // Invoke synchronously so a synchronous `onTrigger` observes its effect
82
- // before control returns (tests advance the clock then assert inline).
83
- // Wrap the (possibly async) result in a promise to drive the in-flight
84
- // guard's release without forcing the trigger itself into a microtask.
85
- let result;
86
- try {
87
- result = onTrigger(harnessName);
88
- }
89
- catch (err) {
90
- // One failed extract must never kill the watcher (mirrors the non-fatal
91
- // handling in collectSessionEvents).
92
- console.error(`[akm] extract --watch trigger for "${harnessName}" failed:`, err);
93
- inFlight.delete(harnessName);
94
- if (rerunPending.delete(harnessName) && !stopped)
95
- runTrigger(harnessName);
96
- return;
97
- }
98
- Promise.resolve(result)
99
- .catch((err) => {
100
- console.error(`[akm] extract --watch trigger for "${harnessName}" failed:`, err);
101
- })
102
- .finally(() => {
103
- inFlight.delete(harnessName);
104
- if (rerunPending.delete(harnessName) && !stopped) {
105
- runTrigger(harnessName);
106
- }
107
- });
108
- }
109
- function onEvent(e) {
110
- if (stopped)
111
- return;
112
- if (!isSessionFileFn(e.path, roots))
113
- return;
114
- const harnessName = matchHarness(e.path, roots);
115
- if (!harnessName)
116
- return;
117
- const existing = pendingTimers.get(harnessName);
118
- if (existing !== undefined)
119
- clearTimeoutFn(existing);
120
- const timer = setTimeoutFn(() => {
121
- pendingTimers.delete(harnessName);
122
- if (!stopped)
123
- runTrigger(harnessName);
124
- }, debounceMs);
125
- pendingTimers.set(harnessName, timer);
126
- }
127
- const unsubscribe = eventSource.subscribe(onEvent);
128
- return {
129
- stop() {
130
- if (stopped)
131
- return;
132
- stopped = true;
133
- unsubscribe();
134
- for (const timer of pendingTimers.values())
135
- clearTimeoutFn(timer);
136
- pendingTimers.clear();
137
- rerunPending.clear();
138
- },
139
- };
140
- }
@@ -1,45 +0,0 @@
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
- * WS-3b Step 0c — Hot-probation intake buffer (#604).
6
- *
7
- * New system-generated extractions enter `captureMode: hot-probation` and spend
8
- * ONE consolidation cycle in probation before promotion to the main stash;
9
- * dedup + quality second-pass runs against them. Stops noisy extractions from
10
- * polluting the stash at the source. Reuses shared dedupHash + body_embeddings.
11
- * Default OFF.
12
- *
13
- * @module hot-probation
14
- */
15
- /**
16
- * captureMode value for system-generated extractions in probation.
17
- * Automatic counterpart to the user-explicit `captureMode: hot`.
18
- */
19
- export const CAPTURE_MODE_HOT_PROBATION = "hot-probation";
20
- /**
21
- * Returns true when an asset is in hot-probation (system-generated, not yet
22
- * graduated from the intake dedup+quality pass).
23
- */
24
- export function isHotProbation(captureModeValue) {
25
- return captureModeValue === CAPTURE_MODE_HOT_PROBATION;
26
- }
27
- /**
28
- * Returns true when an asset should be skipped by the consolidation LLM
29
- * because it's still in hot-probation (hasn't completed the intake pass yet).
30
- *
31
- * Hot-probation assets are processed by the consolidation dedup pre-pass
32
- * (runDeterministicDedup) but excluded from the LLM merge clustering, so
33
- * noisy extractions can't pollute the LLM context.
34
- */
35
- export function shouldSkipHotProbationInLlm(frontmatterData) {
36
- return isHotProbation(frontmatterData.captureMode);
37
- }
38
- /**
39
- * Build frontmatter fields to inject when creating a hot-probation proposal.
40
- * The proposal will carry `captureMode: hot-probation` so downstream logic
41
- * knows to run the intake dedup pass before graduating it.
42
- */
43
- export function buildHotProbationFrontmatter() {
44
- return { captureMode: CAPTURE_MODE_HOT_PROBATION };
45
- }