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
@@ -0,0 +1,39 @@
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
+ * Shared memory-content hashing primitives, extracted from the deleted
6
+ * `dedup.ts` (#617 dedup pre-pass, removed WI-7.3) so `consolidate.ts` /
7
+ * `consolidate/chunking.ts` / `distill.ts` keep a stable, dependency-free home
8
+ * for the case-preserving stripped-body hash they use for the body-embedding
9
+ * cache and (formerly) the fidelity-check body comparison.
10
+ *
11
+ * @module content-hash
12
+ */
13
+ import { createHash } from "node:crypto";
14
+ import { parseFrontmatter } from "../../core/asset/frontmatter.js";
15
+ /**
16
+ * Strip frontmatter from raw memory content, returning the body text trimmed.
17
+ * Case and whitespace are preserved. Falls back to `raw.trim()` on
18
+ * unparseable frontmatter (consistent with the pre-existing load-time hot
19
+ * guard).
20
+ */
21
+ export function stripFrontmatterBody(raw) {
22
+ try {
23
+ return parseFrontmatter(raw).content.trim();
24
+ }
25
+ catch {
26
+ return raw.trim();
27
+ }
28
+ }
29
+ /**
30
+ * Hash used for change-detection and the body-embedding cache: case-/
31
+ * whitespace-preserving stripped body. Two memories with the same wording
32
+ * but different casing produce DIFFERENT hashes here, which is intentional —
33
+ * we embed the exact text and cache by its precise content.
34
+ *
35
+ * This is the `content_hash` stored in `body_embeddings`.
36
+ */
37
+ export function cacheHash(raw) {
38
+ return createHash("sha256").update(stripFrontmatterBody(raw), "utf8").digest("hex");
39
+ }
@@ -11,7 +11,7 @@
11
11
  * (`effectiveProposalKind !== "knowledge"`) stays in the caller; these helpers
12
12
  * assume the lesson path.
13
13
  */
14
- import { assembleAssetFromString } from "../../../core/asset/asset-serialize.js";
14
+ import { assembleAssetFromString, serializeFrontmatterQuoted } from "../../../core/asset/asset-serialize.js";
15
15
  import { parseFrontmatter } from "../../../core/asset/frontmatter.js";
16
16
  import { repairTruncatedDescription } from "../../../core/text-truncation.js";
17
17
  import { detectDoubleFrontmatter, isValidDescription, isValidWhenToUse, } from "../../proposal/validators/proposal-quality-validators.js";
@@ -82,9 +82,7 @@ export function autoRepairLessonFrontmatter(content, inputRef) {
82
82
  ...(missingDesc && descLine ? { description: descLine } : {}),
83
83
  ...(missingWtu && wtuLine ? { when_to_use: wtuLine } : {}),
84
84
  };
85
- const fmLines = Object.entries(repairedFm)
86
- .map(([k, v]) => `${k}: ${JSON.stringify(v)}`)
87
- .join("\n");
85
+ const fmLines = serializeFrontmatterQuoted(repairedFm);
88
86
  // Only rewrite content if we actually have at least one field to write.
89
87
  // Otherwise leave the original content for the lint pass to reject.
90
88
  if (Object.keys(repairedFm).length > 0) {
@@ -122,9 +120,7 @@ export function autoSwapDescriptionWhenToUse(content, inputRef) {
122
120
  description: wtuRaw,
123
121
  when_to_use: descRaw,
124
122
  };
125
- const swappedFmLines = Object.entries(swappedFm)
126
- .map(([k, v]) => `${k}: ${JSON.stringify(v)}`)
127
- .join("\n");
123
+ const swappedFmLines = serializeFrontmatterQuoted(swappedFm);
128
124
  return { content: assembleAssetFromString(swappedFmLines, parsedSwap.content), swapped: 1 };
129
125
  }
130
126
  }
@@ -146,9 +142,7 @@ export function repairLessonDescriptionTruncation(content) {
146
142
  const repaired = repairTruncatedDescription(descRepairRaw, parsedRepair.content);
147
143
  if (repaired === descRepairRaw)
148
144
  return content;
149
- const repairedFmLines = Object.entries({ ...fmRepair, description: repaired })
150
- .map(([k, v]) => `${k}: ${JSON.stringify(v)}`)
151
- .join("\n");
145
+ const repairedFmLines = serializeFrontmatterQuoted({ ...fmRepair, description: repaired });
152
146
  return assembleAssetFromString(repairedFmLines, parsedRepair.content);
153
147
  }
154
148
  /**
@@ -18,40 +18,27 @@
18
18
  */
19
19
  import fs from "node:fs";
20
20
  import { parseFrontmatter } from "../../../core/asset/frontmatter.js";
21
- import { getDefaultLlmConfig } from "../../../core/config/config.js";
22
- import { ConfigError } from "../../../core/errors.js";
23
21
  import { appendEvent } from "../../../core/events.js";
24
- import { parseEmbeddedJsonResponse } from "../../../llm/client.js";
25
- import { isLlmFeatureEnabled } from "../../../llm/feature-gate.js";
26
- import { createProposal, isProposalSkipped } from "../../proposal/repository.js";
22
+ import { parseEmbeddedJsonResponse } from "../../../core/parse.js";
23
+ import { isProposalSkipped } from "../../proposal/repository.js";
27
24
  import { assessMemoryKnowledgePromotionCandidate } from "../distill-promotion-policy.js";
25
+ import { emitProposal } from "../proposal-envelope.js";
26
+ import { durableImproveRef } from "../source-identity.js";
28
27
  import { persistOutputEncodingSalience, runLessonQualityJudge, writeQualityRejection } from "./quality-gate.js";
29
28
  /**
30
- * Run the memory→knowledge promotion branch. Returns the finished distill
31
- * result when promotion fired (all paths terminal), or `null` when the ref is
32
- * not a promotion candidate and the caller should continue to the ordinary
33
- * lesson/knowledge distillation path.
29
+ * Resolve the knowledge content to propose when a memory promotes to knowledge,
30
+ * reconciling it with any existing knowledge file at the destination (D-1 / #369).
31
+ *
32
+ * When the destination already exists and an LLM is configured, follows the
33
+ * mem0 ADD/UPDATE/NOOP pattern (arXiv:2504.19413 §3.2): ADD/UPDATE swap in the
34
+ * merged content, NOOP short-circuits with a terminal "skipped" result. Without
35
+ * an LLM the existing content is appended as reviewer-reference context so the
36
+ * merge can be done by hand. Logic is byte-identical to the prior inline block.
34
37
  */
35
- export async function promoteMemoryToKnowledge(ctx) {
36
- const { targetKind, inputRef, assetContent, config, chat, stash, lookup, fetchSimilarLessonsFn, existingRefVocabulary, outcomeWeightEnabled, eligMeta, exclusionSetSize, filteredFeedbackCount, feedbackFullyFiltered, } = ctx;
37
- const promotion = targetKind === "lesson"
38
- ? null
39
- : assessMemoryKnowledgePromotionCandidate({
40
- inputRef,
41
- assetContent,
42
- feedbackEvents: ctx.filteredEvents.map((event) => ({
43
- ...(event.metadata !== undefined ? { metadata: event.metadata } : {}),
44
- })),
45
- });
46
- if (!(promotion?.promote && promotion.content && (targetKind === "knowledge" || targetKind === "auto"))) {
47
- return null;
48
- }
49
- // D-1 / #369: When the destination knowledge file already exists, route
50
- // through the LLM for contradiction resolution instead of silently
51
- // overwriting. Follows mem0 ADD/UPDATE/DELETE/NOOP pattern (arXiv:2504.19413 §3.2)
52
- // and A-MEM dynamic linking (arXiv:2502.12110).
53
- let resolvedPromotionContent = promotion.content;
54
- const existingKnowledgePath = await lookup(promotion.knowledgeRef);
38
+ async function resolveKnowledgePromotionContent(ctx, baseContent, knowledgeRef) {
39
+ const durableInputRef = ctx.durableInputRef ?? ctx.inputRef;
40
+ let resolvedPromotionContent = baseContent;
41
+ const existingKnowledgePath = await ctx.lookup(durableImproveRef(knowledgeRef));
55
42
  const existingKnowledgeContent = existingKnowledgePath && fs.existsSync(existingKnowledgePath)
56
43
  ? (() => {
57
44
  try {
@@ -62,7 +49,7 @@ export async function promoteMemoryToKnowledge(ctx) {
62
49
  }
63
50
  })()
64
51
  : null;
65
- if (existingKnowledgeContent && config && getDefaultLlmConfig(config)) {
52
+ if (existingKnowledgeContent && ctx.llmConfig) {
66
53
  // Existing content found: call LLM for contradiction-resolution merge.
67
54
  const mergePrompt = [
68
55
  "You are merging two versions of a knowledge document.",
@@ -77,38 +64,38 @@ export async function promoteMemoryToKnowledge(ctx) {
77
64
  "",
78
65
  "## New content from distillation",
79
66
  "```",
80
- promotion.content.slice(0, 3000),
67
+ baseContent.slice(0, 3000),
81
68
  "```",
82
69
  ].join("\n");
83
70
  try {
84
- const mergeLlm = getDefaultLlmConfig(config);
85
- if (!mergeLlm) {
86
- throw new ConfigError("LLM is not configured for distillation merge.", "LLM_NOT_CONFIGURED");
87
- }
88
- const mergeResponse = await chat(mergeLlm, [
71
+ const mergeResponse = await ctx.chat(ctx.llmConfig, [
89
72
  { role: "system", content: "Return only valid JSON. No prose." },
90
73
  { role: "user", content: mergePrompt },
91
- ]);
74
+ ], ctx.signal ? { signal: ctx.signal } : undefined);
92
75
  const mergeResult = parseEmbeddedJsonResponse(mergeResponse);
93
76
  if (mergeResult?.action === "NOOP") {
94
77
  // Existing content is authoritative — no update needed.
95
78
  appendEvent({
96
79
  eventType: "distill_invoked",
97
- ref: inputRef,
80
+ // Use item_ref when resolved, otherwise the input conceptId.
81
+ ref: ctx.itemRef ?? durableInputRef,
98
82
  metadata: {
99
83
  outcome: "skipped",
100
- lessonRef: promotion.knowledgeRef,
84
+ proposalRef: knowledgeRef,
101
85
  message: "D-1: LLM resolved destination conflict as NOOP — existing content kept",
102
- ...eligMeta,
86
+ ...ctx.eligMeta,
103
87
  },
104
- });
88
+ }, ctx.eventsCtx);
105
89
  return {
106
- schemaVersion: 1,
107
- ok: true,
108
- outcome: "skipped",
109
- inputRef,
110
- lessonRef: promotion.knowledgeRef,
111
- message: "Existing knowledge content unchanged (contradiction resolution: NOOP)",
90
+ earlyResult: {
91
+ schemaVersion: 1,
92
+ ok: true,
93
+ outcome: "skipped",
94
+ inputRef: ctx.inputRef,
95
+ proposalRef: knowledgeRef,
96
+ skipReason: "conflict_noop",
97
+ message: "Existing knowledge content unchanged (contradiction resolution: NOOP)",
98
+ },
112
99
  };
113
100
  }
114
101
  if (mergeResult?.action && (mergeResult.action === "ADD" || mergeResult.action === "UPDATE")) {
@@ -122,11 +109,11 @@ export async function promoteMemoryToKnowledge(ctx) {
122
109
  // The reviewer will see both versions in the proposal diff.
123
110
  }
124
111
  }
125
- else if (existingKnowledgeContent && config && !getDefaultLlmConfig(config)) {
112
+ else if (existingKnowledgeContent) {
126
113
  // No LLM configured: include existing content as context in the proposal
127
114
  // so the reviewer can do the contradiction resolution manually.
128
115
  resolvedPromotionContent = [
129
- promotion.content,
116
+ baseContent,
130
117
  "",
131
118
  "---",
132
119
  "<!-- D-1 / #369: Existing knowledge content is shown below for reviewer reference. -->",
@@ -137,20 +124,55 @@ export async function promoteMemoryToKnowledge(ctx) {
137
124
  existingKnowledgeContent,
138
125
  ].join("\n");
139
126
  }
127
+ return { resolvedContent: resolvedPromotionContent };
128
+ }
129
+ /**
130
+ * Run the memory→knowledge promotion branch. Returns the finished distill
131
+ * result when promotion fired (all paths terminal), or `null` when the ref is
132
+ * not a promotion candidate and the caller should continue to the ordinary
133
+ * lesson/knowledge distillation path.
134
+ */
135
+ export async function promoteMemoryToKnowledge(ctx) {
136
+ const { targetKind, inputRef, assetContent, config, chat, stash, fetchSimilarLessonsFn, existingRefVocabulary, outcomeWeightEnabled, eligMeta, exclusionSetSize, filteredFeedbackCount, feedbackFullyFiltered, } = ctx;
137
+ const durableInputRef = ctx.durableInputRef ?? inputRef;
138
+ const promotion = targetKind === "lesson"
139
+ ? null
140
+ : assessMemoryKnowledgePromotionCandidate({
141
+ inputRef: durableInputRef,
142
+ assetContent,
143
+ feedbackEvents: ctx.filteredEvents.map((event) => ({
144
+ ...(event.metadata !== undefined ? { metadata: event.metadata } : {}),
145
+ })),
146
+ });
147
+ if (!(promotion?.promote && promotion.content && (targetKind === "knowledge" || targetKind === "auto"))) {
148
+ return null;
149
+ }
150
+ // D-1 / #369: When the destination knowledge file already exists, route
151
+ // through the LLM for contradiction resolution instead of silently
152
+ // overwriting. Follows mem0 ADD/UPDATE/DELETE/NOOP pattern (arXiv:2504.19413 §3.2)
153
+ // and A-MEM dynamic linking (arXiv:2502.12110).
154
+ const merged = await resolveKnowledgePromotionContent(ctx, promotion.content, promotion.knowledgeRef);
155
+ if ("earlyResult" in merged)
156
+ return merged.earlyResult;
157
+ const resolvedPromotionContent = merged.resolvedContent;
140
158
  // Apply quality gate to fast-path knowledge promotion (Risk 4 fix).
141
159
  // D-5 / #388: Three-band system — review_needed band queues to proposal
142
160
  // queue with review_needed outcome rather than auto-rejecting.
143
161
  let knowledgeJudgeConfidence;
144
- if (isLlmFeatureEnabled(config, "lesson_quality_gate")) {
162
+ if (ctx.strategy?.processes?.distill?.qualityGate?.enabled ?? true) {
145
163
  // D-4 / #390: retrieve top-3 similar lessons for dedup check in judge.
146
164
  const similarLessons = await fetchSimilarLessonsFn(resolvedPromotionContent.slice(0, 500), 3);
147
- const judgeResult = await runLessonQualityJudge(config, resolvedPromotionContent, assetContent ?? "", chat, similarLessons.length > 0 ? similarLessons : undefined);
165
+ const judgeResult = await runLessonQualityJudge(config, resolvedPromotionContent, assetContent ?? "", chat, {
166
+ ...(similarLessons.length > 0 ? { similarLessons } : {}),
167
+ ...(ctx.llmConfig ? { llmConfig: ctx.llmConfig } : {}),
168
+ ...(ctx.signal ? { signal: ctx.signal } : {}),
169
+ });
148
170
  if (!judgeResult.pass) {
149
171
  if (judgeResult.reviewNeeded) {
150
172
  // Uncertainty band (2.5–3.5): queue as review_needed instead of rejecting.
151
- return writeQualityRejection(stash, inputRef, promotion.knowledgeRef, resolvedPromotionContent, judgeResult.score, judgeResult.reason, { reviewNeeded: true }, ctx.eligibilitySource);
173
+ return writeQualityRejection(stash, inputRef, promotion.knowledgeRef, resolvedPromotionContent, judgeResult.score, judgeResult.reason, { reviewNeeded: true }, ctx.eligibilitySource, ctx.eventsCtx);
152
174
  }
153
- return writeQualityRejection(stash, inputRef, promotion.knowledgeRef, resolvedPromotionContent, judgeResult.score, judgeResult.reason, {}, ctx.eligibilitySource);
175
+ return writeQualityRejection(stash, inputRef, promotion.knowledgeRef, resolvedPromotionContent, judgeResult.score, judgeResult.reason, {}, ctx.eligibilitySource, ctx.eventsCtx);
154
176
  }
155
177
  // Normalize 1-5 judge score to [0, 1]. Only a real passing verdict reaches
156
178
  // here (07 P0-2: the judge now fails CLOSED on no-LLM / timeout / parse
@@ -160,9 +182,11 @@ export async function promoteMemoryToKnowledge(ctx) {
160
182
  knowledgeJudgeConfidence = judgeResult.score / 5;
161
183
  }
162
184
  const knowledgeParsed = parseFrontmatter(resolvedPromotionContent);
163
- const proposalResult = createProposal(stash, {
185
+ const proposalResult = emitProposal({ stashDir: stash, proposalsCtx: ctx.proposalsCtx }, {
164
186
  ref: promotion.knowledgeRef,
165
187
  source: "distill",
188
+ // §23.6 fingerprint model-id term (WI-6.4).
189
+ ...(ctx.llmConfig?.model ? { modelId: ctx.llmConfig.model } : {}),
166
190
  ...(ctx.sourceRun !== undefined ? { sourceRun: ctx.sourceRun } : {}),
167
191
  payload: {
168
192
  content: resolvedPromotionContent,
@@ -171,38 +195,40 @@ export async function promoteMemoryToKnowledge(ctx) {
171
195
  ...(knowledgeJudgeConfidence !== undefined ? { confidence: knowledgeJudgeConfidence } : {}),
172
196
  // Attribution tagging: persist the eligibility lane on the proposal.
173
197
  ...(ctx.eligibilitySource ? { eligibilitySource: ctx.eligibilitySource } : {}),
174
- }, ctx.proposalsCtx);
198
+ });
175
199
  if (isProposalSkipped(proposalResult)) {
176
200
  appendEvent({
177
201
  eventType: "distill_invoked",
178
- ref: inputRef,
202
+ // Use item_ref when resolved, otherwise the input conceptId.
203
+ ref: ctx.itemRef ?? durableInputRef,
179
204
  metadata: {
180
205
  outcome: "skipped",
181
- lessonRef: promotion.knowledgeRef,
206
+ proposalRef: promotion.knowledgeRef,
182
207
  message: proposalResult.message,
183
208
  skipReason: proposalResult.reason,
184
209
  ...eligMeta,
185
210
  },
186
- });
211
+ }, ctx.eventsCtx);
187
212
  return {
188
213
  schemaVersion: 1,
189
214
  ok: true,
190
215
  outcome: "skipped",
191
216
  inputRef,
192
- lessonRef: promotion.knowledgeRef,
217
+ proposalRef: promotion.knowledgeRef,
218
+ skipReason: proposalResult.reason,
193
219
  message: proposalResult.message,
194
220
  };
195
221
  }
196
222
  const proposal = proposalResult;
197
223
  // G4: content-score the distilled OUTPUT so it carries a real encoding
198
224
  // salience (encoding_source='content') from creation.
199
- persistOutputEncodingSalience(promotion.knowledgeRef, resolvedPromotionContent, existingRefVocabulary, outcomeWeightEnabled);
225
+ persistOutputEncodingSalience(durableImproveRef(promotion.knowledgeRef), resolvedPromotionContent, existingRefVocabulary, outcomeWeightEnabled);
200
226
  appendEvent({
201
227
  eventType: "distill_invoked",
202
- ref: inputRef,
228
+ // Use item_ref when resolved, otherwise the input conceptId.
229
+ ref: ctx.itemRef ?? durableInputRef,
203
230
  metadata: {
204
231
  outcome: "queued",
205
- lessonRef: promotion.knowledgeRef,
206
232
  proposalRef: promotion.knowledgeRef,
207
233
  proposalKind: "knowledge",
208
234
  proposalId: proposal.id,
@@ -213,13 +239,12 @@ export async function promoteMemoryToKnowledge(ctx) {
213
239
  ...(exclusionSetSize > 0 ? { filteredFeedbackCount } : {}),
214
240
  ...eligMeta,
215
241
  },
216
- });
242
+ }, ctx.eventsCtx);
217
243
  return {
218
244
  schemaVersion: 1,
219
245
  ok: true,
220
246
  outcome: "queued",
221
247
  inputRef,
222
- lessonRef: promotion.knowledgeRef,
223
248
  proposalRef: promotion.knowledgeRef,
224
249
  proposalKind: "knowledge",
225
250
  proposalId: proposal.id,
@@ -10,12 +10,13 @@
10
10
  */
11
11
  import fs from "node:fs";
12
12
  import path from "node:path";
13
- import { parseAssetRef } from "../../../core/asset/asset-ref.js";
13
+ import { parseRefInput } from "../../../core/asset/resolve-ref.js";
14
14
  import { timestampForFilename } from "../../../core/common.js";
15
- import { getDefaultLlmConfig } from "../../../core/config/config.js";
16
15
  import { appendEvent } from "../../../core/events.js";
16
+ import { parseEmbeddedJsonResponse } from "../../../core/parse.js";
17
17
  import { withStateDb } from "../../../core/state-db.js";
18
- import { parseEmbeddedJsonResponse } from "../../../llm/client.js";
18
+ import { getDefaultLlmConfig } from "../../../integrations/agent/engine-resolution.js";
19
+ import { callStructured } from "../../../llm/structured-call.js";
19
20
  import { akmSearch } from "../../read/search.js";
20
21
  import { scoreEncodingSalience } from "../encoding-salience.js";
21
22
  import { computeSalience, upsertAssetSalience } from "../salience.js";
@@ -98,39 +99,97 @@ export function buildJudgePrompt(lessonContent, sourceContent, similarLessons) {
98
99
  lines.push('Return ONLY valid JSON, no prose: {"score": <average score 1-5 as float>, "reason": "<one sentence>"}');
99
100
  return lines.join("\n");
100
101
  }
101
- /**
102
- * Run the LLM-as-judge quality gate on a proposal's content.
103
- *
104
- * Exported so reflect.ts can apply the same gate to reflect proposals (R-5 / #374).
105
- * Gated by the flag name `lesson_quality_gate` (or its alias
106
- * `proposal_quality_gate`) via {@link isLlmFeatureEnabled} — which reads
107
- * `profiles.improve.default.processes.distill.qualityGate.enabled` (and the
108
- * corresponding `.reflect.qualityGate.enabled` for proposals).
109
- *
110
- * Fail-CLOSED (07 P0-2): returns `pass: false` (score -1) on timeout, parse
111
- * failure, or missing LLM. Minted content that cannot be judged is rejected,
112
- * not passed through — an unverifiable judge must never wave content into the
113
- * stash. The rejection is `quality_rejected`, not `review_needed`.
114
- */
115
- export async function runLessonQualityJudge(config, lessonContent, sourceContent, chat,
116
- /** D-4 / #390: top-3 similar existing lessons for dedup check. */
117
- similarLessons) {
118
- const llmConfig = getDefaultLlmConfig(config);
102
+ function boundedDocument(content, maxChars = 6000) {
103
+ if (content.length <= maxChars)
104
+ return content;
105
+ const half = Math.floor((maxChars - 80) / 2);
106
+ return `${content.slice(0, half)}\n\n[... middle omitted for bounded judge context ...]\n\n${content.slice(-half)}`;
107
+ }
108
+ function buildChangedRegion(sourceContent, candidateContent) {
109
+ const source = sourceContent.split("\n");
110
+ const candidate = candidateContent.split("\n");
111
+ let prefix = 0;
112
+ while (prefix < source.length && prefix < candidate.length && source[prefix] === candidate[prefix])
113
+ prefix++;
114
+ let suffix = 0;
115
+ while (suffix < source.length - prefix &&
116
+ suffix < candidate.length - prefix &&
117
+ source[source.length - 1 - suffix] === candidate[candidate.length - 1 - suffix]) {
118
+ suffix++;
119
+ }
120
+ const removed = source.slice(prefix, source.length - suffix).join("\n");
121
+ const added = candidate.slice(prefix, candidate.length - suffix).join("\n");
122
+ return boundedDocument(`Removed or replaced:\n${removed || "(none)"}\n\nAdded or replacement:\n${added || "(none)"}`);
123
+ }
124
+ /** Build quality criteria for revising an existing asset in place. */
125
+ export function buildReflectJudgePrompt(candidateContent, sourceContent, feedback) {
126
+ return [
127
+ "You are evaluating a proposed revision to an existing akm asset.",
128
+ "",
129
+ "Score this revision on each criterion from 1 (poor) to 5 (excellent):",
130
+ "1. FEEDBACK ALIGNMENT: Does the revision address the supplied feedback or improve retrieval and clarity?",
131
+ "2. PRESERVATION: Does it retain the source's concrete facts, code, commands, examples, and structure without truncation?",
132
+ "3. QUALITY: Is the revision coherent, actionable, complete, and free of unsupported claims?",
133
+ "",
134
+ "Overlap with the source is expected and must not lower the score by itself; this is an in-place revision, not a new lesson.",
135
+ "",
136
+ "Feedback:",
137
+ "```",
138
+ (feedback.length > 0 ? feedback.join("\n") : "No explicit feedback supplied.").slice(0, 1000),
139
+ "```",
140
+ "",
141
+ "Source asset content:",
142
+ "```",
143
+ boundedDocument(sourceContent),
144
+ "```",
145
+ "",
146
+ "Proposed revision:",
147
+ "```",
148
+ boundedDocument(candidateContent),
149
+ "```",
150
+ "",
151
+ "Changed region:",
152
+ "```",
153
+ buildChangedRegion(sourceContent, candidateContent),
154
+ "```",
155
+ "",
156
+ 'Return ONLY valid JSON, no prose: {"score": <average score 1-5 as float>, "reason": "<one sentence>"}',
157
+ ].join("\n");
158
+ }
159
+ async function runQualityJudge(feature, config, prompt, chat, options = {}) {
160
+ const llmConfig = options.llmConfig ?? getDefaultLlmConfig(config);
119
161
  if (!llmConfig) {
120
162
  return { pass: false, score: -1, reason: "no LLM configured — cannot judge, failing closed" };
121
163
  }
122
- const judgeLlmConfig = llmConfig.judgeModel ? { ...llmConfig, model: llmConfig.judgeModel } : llmConfig;
123
- const JUDGE_TIMEOUT_MS = 8_000;
124
164
  try {
125
- const raw = await Promise.race([
126
- chat(judgeLlmConfig, [
165
+ // UNGATED at the seam (no akmConfig): the quality gates' enablement is
166
+ // resolved by the caller before this function runs, and a transport throw
167
+ // propagates into the fail-closed catch below. `feature` labels the call.
168
+ const raw = await callStructured({
169
+ feature,
170
+ config: llmConfig,
171
+ messages: [
127
172
  { role: "system", content: "Return only valid JSON. No prose." },
128
- { role: "user", content: buildJudgePrompt(lessonContent, sourceContent, similarLessons) },
129
- ]),
130
- new Promise((_, reject) => setTimeout(() => reject(new Error("judge timeout")), JUDGE_TIMEOUT_MS)),
131
- ]);
173
+ { role: "user", content: prompt },
174
+ ],
175
+ request: {
176
+ enableThinking: false,
177
+ ...(Object.hasOwn(options, "timeoutMs") ? { timeoutMs: options.timeoutMs } : {}),
178
+ ...(options.signal ? { signal: options.signal } : {}),
179
+ ...(chat ? { chat } : {}),
180
+ },
181
+ parse: (rawResponse) => rawResponse ?? "",
182
+ // Unreachable on the ungated path (errors propagate); fail closed anyway.
183
+ onError: () => "",
184
+ fallback: "",
185
+ });
132
186
  const parsed = parseEmbeddedJsonResponse(raw);
133
- if (!parsed || typeof parsed.score !== "number") {
187
+ if (!parsed ||
188
+ typeof parsed.score !== "number" ||
189
+ !Number.isFinite(parsed.score) ||
190
+ parsed.score < 1 ||
191
+ parsed.score > 5 ||
192
+ typeof parsed.reason !== "string") {
134
193
  return { pass: false, score: -1, reason: "judge parse failed — cannot judge, failing closed" };
135
194
  }
136
195
  // D-5 / #388: Three-band system (MT-Bench arXiv:2306.05685 — ~±0.5 judge variance).
@@ -139,19 +198,35 @@ similarLessons) {
139
198
  // < 2.5: auto-reject (pass: false)
140
199
  const score = parsed.score;
141
200
  const reason = parsed.reason ?? "";
142
- if (score >= 3.5) {
201
+ if (score >= 3.5)
143
202
  return { pass: true, score, reason };
144
- }
145
- if (score >= 2.5) {
146
- // Uncertainty band: treat as failed for auto-queuing but flag for review.
203
+ if (score >= 2.5)
147
204
  return { pass: false, score, reason, reviewNeeded: true };
148
- }
149
205
  return { pass: false, score, reason };
150
206
  }
151
207
  catch {
152
208
  return { pass: false, score: -1, reason: "judge timeout/error — cannot judge, failing closed" };
153
209
  }
154
210
  }
211
+ /**
212
+ * Run the LLM-as-judge quality gate on a proposal's content.
213
+ *
214
+ * Exported so reflect.ts can apply the same gate to reflect proposals (R-5 / #374).
215
+ * The selected strategy's distill/reflect quality-gate setting is resolved by
216
+ * the caller before this function runs.
217
+ *
218
+ * Fail-CLOSED (07 P0-2): returns `pass: false` (score -1) on timeout, parse
219
+ * failure, or missing LLM. Minted content that cannot be judged is rejected,
220
+ * not passed through — an unverifiable judge must never wave content into the
221
+ * stash. The rejection is `quality_rejected`, not `review_needed`.
222
+ */
223
+ export async function runLessonQualityJudge(config, lessonContent, sourceContent, chat, options = {}) {
224
+ return runQualityJudge("lesson_quality_gate", config, buildJudgePrompt(lessonContent, sourceContent, options.similarLessons), chat, options);
225
+ }
226
+ /** Judge an in-place reflect revision without applying new-lesson novelty criteria. */
227
+ export async function runReflectQualityJudge(config, candidateContent, sourceContent, feedback, chat, options = {}) {
228
+ return runQualityJudge("proposal_quality_gate", config, buildReflectJudgePrompt(candidateContent, sourceContent, feedback), chat, options);
229
+ }
155
230
  // ── Quality-rejection helper ─────────────────────────────────────────────────
156
231
  /**
157
232
  * Write a rejected lesson to `.akm/distill-rejected/`, append a `distill_invoked`
@@ -159,25 +234,26 @@ similarLessons) {
159
234
  *
160
235
  * @param stash - Root stash directory.
161
236
  * @param inputRef - The original input ref (for the event).
162
- * @param lessonRef - The proposed lesson/knowledge ref.
237
+ * @param proposalRef - The proposed lesson/knowledge ref.
163
238
  * @param content - The raw content that failed the quality gate.
164
239
  * @param score - Quality score from the judge.
165
240
  * @param reason - Human-readable rejection reason.
166
241
  * @param extraMeta - Optional additional metadata for the event.
242
+ * @param eventsCtx - Events context so the emit takes appendEvent's fast path (R25).
167
243
  */
168
- export function writeQualityRejection(stash, inputRef, lessonRef, content, score, reason, extraMeta = {}, eligibilitySource) {
244
+ export function writeQualityRejection(stash, inputRef, proposalRef, content, score, reason, extraMeta = {}, eligibilitySource, eventsCtx) {
169
245
  // D-5 / #388: reviewNeeded flag selects "review_needed" vs "quality_rejected" outcome.
170
246
  const outcome = extraMeta.reviewNeeded ? "review_needed" : "quality_rejected";
171
247
  const rejectDir = path.join(stash, ".akm", "distill-rejected");
172
248
  fs.mkdirSync(rejectDir, { recursive: true });
173
249
  const ts = timestampForFilename();
174
- fs.writeFileSync(path.join(rejectDir, `${ts}-${lessonRef}.md`), `---\nscore: ${score}\nreason: ${reason}\noutcome: ${outcome}\n---\n\n${content}`, "utf8");
250
+ fs.writeFileSync(path.join(rejectDir, `${ts}-${proposalRef.replace(/[:/\\]/g, "-")}.md`), `---\nscore: ${score}\nreason: ${reason}\noutcome: ${outcome}\n---\n\n${content}`, "utf8");
175
251
  appendEvent({
176
252
  eventType: "distill_invoked",
177
253
  ref: inputRef,
178
254
  metadata: {
179
255
  outcome,
180
- lessonRef,
256
+ proposalRef,
181
257
  score,
182
258
  reason,
183
259
  ...extraMeta,
@@ -185,13 +261,13 @@ export function writeQualityRejection(stash, inputRef, lessonRef, content, score
185
261
  // sliced by lane downstream. See EligibilitySource.
186
262
  ...(eligibilitySource ? { eligibilitySource } : {}),
187
263
  },
188
- });
264
+ }, eventsCtx);
189
265
  return {
190
266
  schemaVersion: 1,
191
267
  ok: true,
192
268
  outcome,
193
269
  inputRef,
194
- lessonRef,
270
+ proposalRef,
195
271
  score,
196
272
  reason,
197
273
  ...extraMeta,
@@ -212,7 +288,7 @@ export function persistOutputEncodingSalience(ref, body, existingRefVocabulary,
212
288
  // preparation uses parity weights — inconsistent salience semantics.
213
289
  outcomeWeightEnabled) {
214
290
  try {
215
- const parsedRef = parseAssetRef(ref);
291
+ const parsedRef = parseRefInput(ref);
216
292
  const salienceResult = scoreEncodingSalience({
217
293
  body,
218
294
  type: parsedRef.type,
@@ -96,7 +96,7 @@ export function checkDistillFidelity(proposalBody, sourceBodies, config) {
96
96
  }
97
97
  }
98
98
  }
99
- // Also flag proposals whose source_refs are empty (broken provenance).
99
+ // Also flag proposals whose xrefs are empty (broken provenance).
100
100
  // This is a degradation signal, not a contradiction, but worth surfacing.
101
101
  return { contradictionDetected: false };
102
102
  }