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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (598) hide show
  1. package/CHANGELOG.md +1283 -22
  2. package/README.md +62 -37
  3. package/SECURITY.md +46 -31
  4. package/dist/akm +162 -38
  5. package/dist/akm-migrate +44 -0
  6. package/dist/assets/backends/schtasks-template.xml +2 -1
  7. package/dist/assets/hints/cli-hints-full.md +268 -118
  8. package/dist/assets/hints/cli-hints-short.md +87 -24
  9. package/dist/assets/{profiles → improve-strategies}/catchup.json +3 -1
  10. package/dist/assets/{profiles → improve-strategies}/consolidate.json +3 -1
  11. package/dist/assets/{profiles → improve-strategies}/default.json +6 -7
  12. package/dist/assets/improve-strategies/frequent.json +15 -0
  13. package/dist/assets/{profiles → improve-strategies}/graph-refresh.json +4 -2
  14. package/dist/assets/{profiles → improve-strategies}/memory-focus.json +4 -1
  15. package/dist/assets/{profiles → improve-strategies}/proactive-maintenance.json +5 -5
  16. package/dist/assets/{profiles → improve-strategies}/quick.json +4 -2
  17. package/dist/assets/improve-strategies/reflect-distill.json +30 -0
  18. package/dist/assets/{profiles → improve-strategies}/thorough.json +1 -1
  19. package/dist/assets/prompts/consolidate-system.md +5 -5
  20. package/dist/assets/prompts/extract-session.md +2 -6
  21. package/dist/assets/prompts/memory-infer-user.md +2 -3
  22. package/dist/assets/prompts/reflect-llm-framed-contract.md +11 -0
  23. package/dist/assets/prompts/reflect-llm-schema-contract.md +3 -0
  24. package/dist/assets/prompts/reflect-output-repair.md +3 -0
  25. package/dist/assets/prompts/workflow-unit-preamble.md +26 -0
  26. package/dist/assets/stash-skeleton/README.md +38 -10
  27. package/dist/assets/stash-skeleton/facts/conventions/assets/agent.md +8 -0
  28. package/dist/assets/stash-skeleton/facts/conventions/assets/command.md +8 -0
  29. package/dist/assets/stash-skeleton/facts/conventions/assets/fact.md +14 -1
  30. package/dist/assets/stash-skeleton/facts/conventions/assets/knowledge.md +13 -1
  31. package/dist/assets/stash-skeleton/facts/conventions/assets/lesson.md +9 -1
  32. package/dist/assets/stash-skeleton/facts/conventions/assets/memory.md +11 -0
  33. package/dist/assets/stash-skeleton/facts/conventions/assets/script.md +9 -0
  34. package/dist/assets/stash-skeleton/facts/conventions/assets/skill.md +9 -0
  35. package/dist/assets/stash-skeleton/facts/conventions/assets/workflow.md +8 -0
  36. package/dist/assets/stash-skeleton/facts/conventions/backlinks.md +100 -0
  37. package/dist/assets/stash-skeleton/facts/conventions/domains.md +64 -0
  38. package/dist/assets/stash-skeleton/facts/conventions/organization.md +136 -0
  39. package/dist/assets/tasks/core/extract.yml +3 -2
  40. package/dist/assets/tasks/core/improve.yml +2 -1
  41. package/dist/assets/tasks/core/index-refresh.yml +1 -0
  42. package/dist/assets/tasks/core/sync.yml +1 -0
  43. package/dist/assets/tasks/core/version-check.yml +2 -1
  44. package/dist/assets/tasks/improve/akm-graph-refresh-weekly.yml +5 -0
  45. package/dist/assets/tasks/improve/akm-improve-catchup.yml +8 -0
  46. package/dist/assets/tasks/improve/akm-improve-consolidate.yml +5 -0
  47. package/dist/assets/tasks/improve/akm-improve-frequent.yml +5 -0
  48. package/dist/assets/tasks/improve/akm-improve-nightly.yml +5 -0
  49. package/dist/assets/templates/html/health.html +5 -4
  50. package/dist/assets/workflows/workflow-template.md +31 -15
  51. package/dist/cli/invocation.js +279 -0
  52. package/dist/cli/parse-args.js +5 -90
  53. package/dist/cli/retired-commands.js +78 -0
  54. package/dist/cli/shared.js +158 -48
  55. package/dist/cli-node.mjs +2 -1
  56. package/dist/cli.js +747 -293
  57. package/dist/commands/agent/agent-dispatch.js +19 -18
  58. package/dist/commands/agent/agent-support.js +0 -24
  59. package/dist/commands/agent/contribute-cli.js +43 -97
  60. package/dist/commands/completions.js +80 -23
  61. package/dist/commands/config-cli.js +44 -281
  62. package/dist/commands/env/env-binding.js +99 -0
  63. package/dist/commands/env/env-cli.js +84 -224
  64. package/dist/commands/env/env.js +12 -163
  65. package/dist/commands/env/marker-path.js +6 -0
  66. package/dist/commands/env/secret-cli.js +45 -61
  67. package/dist/commands/env/secret.js +32 -62
  68. package/dist/commands/feedback-cli.js +179 -85
  69. package/dist/commands/health/accept-rate.js +58 -0
  70. package/dist/commands/health/advisories.js +7 -8
  71. package/dist/commands/health/checks.js +279 -94
  72. package/dist/commands/health/html-report.js +197 -578
  73. package/dist/commands/health/improve-metrics.js +277 -246
  74. package/dist/commands/health/llm-usage.js +19 -19
  75. package/dist/commands/health/md-report.js +16 -7
  76. package/dist/commands/health/metrics.js +67 -32
  77. package/dist/commands/health/renderers.js +47 -0
  78. package/dist/commands/health/report-view-model.js +508 -0
  79. package/dist/commands/health/stash-exposure.js +1 -1
  80. package/dist/commands/health/surfaces.js +16 -56
  81. package/dist/commands/health/task-runs.js +3 -67
  82. package/dist/{migrate-storage-node.mjs → commands/health/types-checks.js} +1 -5
  83. package/dist/commands/health/types-improve.js +29 -0
  84. package/dist/{output/text/save.js → commands/health/types-metrics.js} +1 -2
  85. package/dist/commands/health/types-result.js +7 -0
  86. package/dist/commands/health/types-runs.js +4 -0
  87. package/dist/commands/health/types-session-log.js +4 -0
  88. package/dist/commands/health/types-windows.js +4 -0
  89. package/dist/commands/health/types.js +26 -21
  90. package/dist/commands/health/windows.js +2 -3
  91. package/dist/commands/health.js +296 -167
  92. package/dist/commands/improve/anti-collapse.js +5 -5
  93. package/dist/commands/improve/autonomy-gate.js +68 -0
  94. package/dist/commands/improve/collapse-detector.js +65 -52
  95. package/dist/commands/improve/consolidate/chunking.js +9 -7
  96. package/dist/commands/improve/consolidate/eligibility.js +1 -23
  97. package/dist/commands/improve/consolidate/merge.js +4 -0
  98. package/dist/commands/improve/consolidate.js +454 -1354
  99. package/dist/commands/improve/content-hash.js +39 -0
  100. package/dist/commands/improve/distill/content-repair.js +4 -10
  101. package/dist/commands/improve/distill/promote-memory.js +89 -64
  102. package/dist/commands/improve/distill/quality-gate.js +118 -42
  103. package/dist/commands/improve/distill-guards.js +1 -1
  104. package/dist/commands/improve/distill-promotion-policy.js +33 -888
  105. package/dist/commands/improve/distill.js +607 -363
  106. package/dist/commands/improve/eligibility.js +165 -79
  107. package/dist/commands/improve/extract-cli.js +35 -126
  108. package/dist/commands/improve/extract-prompt.js +6 -35
  109. package/dist/commands/improve/extract.js +640 -391
  110. package/dist/commands/improve/feedback-valence.js +2 -12
  111. package/dist/commands/improve/improve-cli.js +134 -135
  112. package/dist/commands/improve/improve-result-file.js +30 -50
  113. package/dist/commands/improve/improve-run-types.js +4 -0
  114. package/dist/commands/improve/improve-strategies.js +135 -0
  115. package/dist/commands/improve/improve.js +904 -701
  116. package/dist/commands/improve/locks.js +64 -111
  117. package/dist/commands/improve/loop-stages.js +1110 -923
  118. package/dist/commands/improve/memory/derived-ref.js +124 -0
  119. package/dist/commands/improve/memory/memory-belief.js +79 -7
  120. package/dist/commands/improve/memory/memory-contradiction-detect.js +49 -52
  121. package/dist/commands/improve/memory/memory-improve.js +25 -37
  122. package/dist/commands/improve/outcome-loop.js +25 -88
  123. package/dist/commands/improve/preparation.js +1034 -813
  124. package/dist/commands/improve/proactive-maintenance.js +34 -9
  125. package/dist/commands/improve/proposal-envelope.js +31 -0
  126. package/dist/commands/improve/reflect.js +983 -794
  127. package/dist/commands/improve/run-context.js +119 -0
  128. package/dist/commands/improve/salience.js +24 -127
  129. package/dist/commands/improve/session-asset.js +7 -3
  130. package/dist/commands/improve/shared.js +14 -34
  131. package/dist/commands/improve/source-identity.js +28 -0
  132. package/dist/commands/improve/triage.js +20 -17
  133. package/dist/commands/lint/base-linter.js +340 -313
  134. package/dist/commands/lint/env-key-rules.js +31 -47
  135. package/dist/commands/lint/index.js +185 -30
  136. package/dist/commands/{events.js → log.js} +28 -38
  137. package/dist/commands/migrate-cli.js +54 -0
  138. package/dist/commands/migration-tool.js +55 -0
  139. package/dist/commands/observability-cli.js +70 -208
  140. package/dist/commands/proposal/diff-format.js +50 -0
  141. package/dist/commands/proposal/drain-policies.js +0 -6
  142. package/dist/commands/proposal/drain.js +91 -40
  143. package/dist/commands/proposal/proposal-cli.js +134 -132
  144. package/dist/commands/proposal/proposal-types.js +56 -0
  145. package/dist/commands/proposal/proposal.js +83 -65
  146. package/dist/commands/proposal/propose-cli.js +88 -0
  147. package/dist/commands/proposal/propose.js +105 -88
  148. package/dist/commands/proposal/repository.js +1303 -278
  149. package/dist/commands/proposal/validators/proposal-quality-validators.js +16 -6
  150. package/dist/commands/proposal/validators/proposal-validators.js +61 -12
  151. package/dist/commands/proposal/validators/proposals.js +6 -8
  152. package/dist/commands/read/curate.js +78 -73
  153. package/dist/commands/read/knowledge.js +510 -13
  154. package/dist/commands/read/registry-search.js +2 -2
  155. package/dist/commands/read/remember-cli.js +84 -15
  156. package/dist/commands/read/search-cli.js +203 -96
  157. package/dist/commands/read/search.js +126 -94
  158. package/dist/commands/read/show.js +226 -250
  159. package/dist/commands/registry-cli.js +34 -60
  160. package/dist/commands/remember.js +18 -57
  161. package/dist/commands/sources/add-cli.js +104 -49
  162. package/dist/commands/sources/bundle-cli.js +166 -0
  163. package/dist/commands/sources/bundle-config-ops.js +63 -0
  164. package/dist/commands/sources/info.js +27 -15
  165. package/dist/commands/sources/init.js +30 -40
  166. package/dist/commands/sources/installed-stashes.js +469 -172
  167. package/dist/commands/sources/migration-help.js +7 -4
  168. package/dist/commands/sources/schema-repair.js +10 -9
  169. package/dist/commands/sources/self-update.js +182 -121
  170. package/dist/commands/sources/source-add.js +169 -178
  171. package/dist/commands/sources/source-clone.js +144 -41
  172. package/dist/commands/sources/source-manage.js +94 -59
  173. package/dist/commands/sources/sources-cli.js +64 -205
  174. package/dist/commands/sources/stash-cli.js +91 -54
  175. package/dist/commands/sources/stash-skeleton.js +1 -1
  176. package/dist/commands/tasks/tasks-cli.js +106 -104
  177. package/dist/commands/tasks/tasks.js +445 -262
  178. package/dist/commands/workflow-cli.js +232 -121
  179. package/dist/core/action-contributors.js +1 -1
  180. package/dist/core/activation-policy.js +49 -0
  181. package/dist/core/adapter/adapters/agent-skills-adapter.js +181 -0
  182. package/dist/core/adapter/adapters/akm-adapter.js +528 -0
  183. package/dist/core/adapter/adapters/akm-lint.js +392 -0
  184. package/dist/core/adapter/adapters/akm-metadata.js +387 -0
  185. package/dist/core/adapter/adapters/akm-task-adapter.js +149 -0
  186. package/dist/core/adapter/adapters/akm-workflow-adapter.js +180 -0
  187. package/dist/core/adapter/adapters/claude-adapter.js +61 -0
  188. package/dist/core/adapter/adapters/dotenv-adapter.js +187 -0
  189. package/dist/core/adapter/adapters/generic-files-adapter.js +119 -0
  190. package/dist/core/adapter/adapters/index.js +80 -0
  191. package/dist/core/adapter/adapters/llm-wiki-adapter.js +419 -0
  192. package/dist/core/adapter/adapters/okf-adapter.js +391 -0
  193. package/dist/core/adapter/adapters/opencode-adapter.js +68 -0
  194. package/dist/core/adapter/adapters/shared.js +286 -0
  195. package/dist/core/adapter/adapters/tool-dir-shared.js +217 -0
  196. package/dist/core/adapter/adapters/website-snapshot-adapter.js +155 -0
  197. package/dist/core/adapter/bundle-adapter.js +4 -0
  198. package/dist/core/adapter/detect-adapter.js +17 -0
  199. package/dist/core/adapter/recognize-match.js +44 -0
  200. package/dist/core/adapter/registry.js +56 -0
  201. package/dist/core/adapter/types.js +4 -0
  202. package/dist/core/asset/akm-markdown.js +30 -0
  203. package/dist/core/asset/asset-placement.js +243 -0
  204. package/dist/core/asset/asset-ref.js +110 -79
  205. package/dist/core/asset/asset-serialize.js +20 -0
  206. package/dist/core/asset/frontmatter.js +28 -12
  207. package/dist/core/asset/markdown.js +40 -51
  208. package/dist/core/asset/resolve-ref.js +274 -0
  209. package/dist/core/asset/stash-meta.js +2 -2
  210. package/dist/core/bundle-id.js +51 -0
  211. package/dist/core/common.js +281 -86
  212. package/dist/core/config/config-io.js +42 -128
  213. package/dist/core/config/config-schema.js +233 -834
  214. package/dist/core/config/config-sources.js +162 -39
  215. package/dist/core/config/config-types.js +16 -11
  216. package/dist/core/config/config-version.js +29 -0
  217. package/dist/core/config/config-walker.js +126 -37
  218. package/dist/core/config/config.js +154 -331
  219. package/dist/core/config/deep-merge.js +41 -0
  220. package/dist/core/config/engine-semantics.js +28 -0
  221. package/dist/core/config/experimental.js +21 -0
  222. package/dist/core/config/schema/embedding.js +38 -0
  223. package/dist/core/config/schema/engines.js +116 -0
  224. package/dist/core/config/schema/experimental.js +47 -0
  225. package/dist/core/config/schema/feedback.js +31 -0
  226. package/dist/core/config/schema/improve-processes.js +389 -0
  227. package/dist/core/config/schema/improve.js +94 -0
  228. package/dist/core/config/schema/index-config.js +176 -0
  229. package/dist/core/config/schema/output.js +18 -0
  230. package/dist/core/config/schema/primitives.js +94 -0
  231. package/dist/core/config/schema/search.js +30 -0
  232. package/dist/core/config/schema/setup.js +18 -0
  233. package/dist/core/config/schema/sources-bundles.js +169 -0
  234. package/dist/core/config/schema/workflow.js +29 -0
  235. package/dist/core/env-secret-ref.js +155 -20
  236. package/dist/core/errors.js +17 -15
  237. package/dist/core/events-types.js +4 -0
  238. package/dist/core/events.js +46 -128
  239. package/dist/core/extra-params.js +62 -0
  240. package/dist/core/file-change.js +17 -0
  241. package/dist/core/file-lock.js +202 -57
  242. package/dist/core/fs-txn.js +392 -0
  243. package/dist/core/git-message.js +59 -0
  244. package/dist/core/improve-result.js +167 -0
  245. package/dist/core/json-schema.js +142 -0
  246. package/dist/core/lesson-lint.js +1 -17
  247. package/dist/core/logs-db.js +1 -1
  248. package/dist/core/maintenance-barrier.js +135 -0
  249. package/dist/core/migration-operation.js +44 -0
  250. package/dist/core/mutation-target.js +78 -0
  251. package/dist/core/paths.js +22 -25
  252. package/dist/core/platform.js +10 -0
  253. package/dist/core/recognition-util.js +128 -0
  254. package/dist/core/redaction.js +392 -0
  255. package/dist/core/standards/resolve-standards-context.js +36 -65
  256. package/dist/core/standards/resolve-stash-standards.js +2 -2
  257. package/dist/core/standards/resolve-type-conventions.js +5 -5
  258. package/dist/core/state/migrations.js +242 -11
  259. package/dist/core/state-db.js +98 -10
  260. package/dist/core/structured.js +1 -1
  261. package/dist/core/subprocess.js +303 -0
  262. package/dist/core/text-truncation.js +9 -5
  263. package/dist/core/time.js +20 -0
  264. package/dist/core/type-presentation.js +130 -0
  265. package/dist/core/warn.js +0 -3
  266. package/dist/core/write-source.js +834 -118
  267. package/dist/indexer/bundle-identity-guard.js +92 -0
  268. package/dist/indexer/db/graph-db.js +1 -25
  269. package/dist/indexer/db/llm-cache.js +1 -1
  270. package/dist/indexer/ensure-index.js +30 -9
  271. package/dist/indexer/graph/graph-boost.js +9 -30
  272. package/dist/indexer/graph/graph-extraction.js +41 -27
  273. package/dist/indexer/graph/graph-types.js +4 -0
  274. package/dist/indexer/index-writer-lock.js +93 -49
  275. package/dist/indexer/index-written-assets.js +100 -53
  276. package/dist/indexer/indexer.js +746 -329
  277. package/dist/indexer/init.js +18 -25
  278. package/dist/indexer/installations.js +142 -0
  279. package/dist/indexer/passes/dir-staleness.js +18 -10
  280. package/dist/indexer/passes/memory-inference.js +25 -15
  281. package/dist/indexer/passes/metadata.js +412 -243
  282. package/dist/indexer/scan/doc-to-entry.js +160 -0
  283. package/dist/indexer/scan/drain-dir.js +134 -0
  284. package/dist/indexer/search/db-search.js +292 -108
  285. package/dist/indexer/search/fts-query.js +64 -0
  286. package/dist/indexer/search/ranking-contributors.js +145 -25
  287. package/dist/indexer/search/ranking-types.js +4 -0
  288. package/dist/indexer/search/ranking.js +28 -71
  289. package/dist/indexer/search/search-attribution.js +67 -0
  290. package/dist/indexer/search/search-fields.js +18 -3
  291. package/dist/indexer/search/search-hit-enrichers.js +30 -40
  292. package/dist/indexer/search/search-source.js +157 -111
  293. package/dist/indexer/search/semantic-status.js +4 -1
  294. package/dist/indexer/usage/usage-events.js +10 -30
  295. package/dist/indexer/walk/file-context.js +3 -45
  296. package/dist/indexer/walk/matchers.js +42 -34
  297. package/dist/indexer/walk/path-resolver.js +11 -5
  298. package/dist/indexer/walk/walker.js +42 -14
  299. package/dist/integrations/agent/builder-shared.js +7 -0
  300. package/dist/integrations/agent/builders.js +5 -56
  301. package/dist/integrations/agent/config.js +3 -143
  302. package/dist/integrations/agent/detect.js +17 -2
  303. package/dist/integrations/agent/engine-resolution.js +231 -0
  304. package/dist/integrations/agent/index.js +1 -2
  305. package/dist/integrations/agent/model-aliases.js +16 -2
  306. package/dist/integrations/agent/profiles.js +36 -62
  307. package/dist/integrations/agent/prompts.js +46 -18
  308. package/dist/integrations/agent/runner-dispatch.js +93 -4
  309. package/dist/integrations/agent/runner.js +76 -208
  310. package/dist/integrations/agent/spawn.js +88 -196
  311. package/dist/integrations/harnesses/aider/agent-builder.js +114 -0
  312. package/dist/integrations/harnesses/aider/index.js +48 -0
  313. package/dist/integrations/harnesses/aider/result-extractor.js +53 -0
  314. package/dist/integrations/harnesses/amazonq/agent-builder.js +147 -0
  315. package/dist/integrations/harnesses/amazonq/index.js +45 -0
  316. package/dist/integrations/harnesses/amazonq/result-extractor.js +48 -0
  317. package/dist/integrations/harnesses/claude/agent-builder.js +46 -8
  318. package/dist/integrations/harnesses/claude/config-import.js +1 -3
  319. package/dist/integrations/harnesses/claude/index.js +24 -35
  320. package/dist/integrations/harnesses/claude/result-extractor.js +52 -0
  321. package/dist/integrations/harnesses/claude/session-log.js +27 -75
  322. package/dist/integrations/harnesses/codex/agent-builder.js +138 -0
  323. package/dist/integrations/harnesses/codex/index.js +52 -0
  324. package/dist/integrations/harnesses/codex/result-extractor.js +73 -0
  325. package/dist/integrations/harnesses/copilot/agent-builder.js +122 -0
  326. package/dist/integrations/harnesses/copilot/index.js +48 -0
  327. package/dist/integrations/harnesses/copilot/result-extractor.js +151 -0
  328. package/dist/integrations/harnesses/gemini/agent-builder.js +120 -0
  329. package/dist/integrations/harnesses/gemini/index.js +48 -0
  330. package/dist/integrations/harnesses/gemini/result-extractor.js +121 -0
  331. package/dist/integrations/harnesses/ids.js +24 -0
  332. package/dist/integrations/harnesses/index.js +54 -34
  333. package/dist/integrations/harnesses/opencode/agent-builder.js +23 -5
  334. package/dist/integrations/harnesses/opencode/config-import.js +1 -3
  335. package/dist/integrations/harnesses/opencode/index.js +14 -32
  336. package/dist/integrations/harnesses/opencode/session-log.js +67 -125
  337. package/dist/integrations/harnesses/opencode-sdk/harness.js +51 -0
  338. package/dist/integrations/harnesses/opencode-sdk/sdk-runner.js +681 -108
  339. package/dist/integrations/harnesses/openhands/agent-builder.js +128 -0
  340. package/dist/integrations/harnesses/openhands/index.js +48 -0
  341. package/dist/integrations/harnesses/openhands/result-extractor.js +103 -0
  342. package/dist/integrations/harnesses/pi/agent-builder.js +97 -0
  343. package/dist/integrations/harnesses/pi/index.js +45 -0
  344. package/dist/integrations/harnesses/pi/result-extractor.js +135 -0
  345. package/dist/integrations/harnesses/shared.js +17 -0
  346. package/dist/integrations/harnesses/types.js +43 -32
  347. package/dist/integrations/lockfile.js +211 -24
  348. package/dist/integrations/session-logs/index.js +36 -39
  349. package/dist/integrations/session-logs/provider-base.js +113 -0
  350. package/dist/llm/client.js +182 -110
  351. package/dist/llm/embedders/deterministic.js +2 -2
  352. package/dist/llm/embedders/remote.js +21 -9
  353. package/dist/llm/feature-gate.js +17 -57
  354. package/dist/llm/graph-extract.js +12 -13
  355. package/dist/llm/index-passes.js +8 -42
  356. package/dist/llm/memory-infer.js +144 -1
  357. package/dist/llm/metadata-enhance.js +45 -30
  358. package/dist/llm/structured-call.js +16 -8
  359. package/dist/llm/usage-persist.js +30 -5
  360. package/dist/llm/usage-telemetry.js +59 -6
  361. package/dist/output/cli-hints.js +1 -2
  362. package/dist/output/command-registry.js +27 -0
  363. package/dist/output/context.js +22 -7
  364. package/dist/output/format-exempt.js +80 -0
  365. package/dist/output/generic-render.js +251 -0
  366. package/dist/output/html-render.js +11 -16
  367. package/dist/output/render-registry.js +57 -0
  368. package/dist/output/renderers.js +14 -279
  369. package/dist/output/shapes/curate.js +10 -1
  370. package/dist/output/shapes/events.js +12 -7
  371. package/dist/output/shapes/helpers.js +58 -84
  372. package/dist/output/shapes/passthrough.js +11 -39
  373. package/dist/output/shapes/proposal/producer.js +15 -7
  374. package/dist/output/shapes/registry.js +12 -6
  375. package/dist/output/shapes.js +0 -9
  376. package/dist/output/text/{init.js → bundle-create.js} +3 -1
  377. package/dist/output/text/bundle-show.js +7 -0
  378. package/dist/output/text/command-format.js +562 -0
  379. package/dist/output/text/env.js +1 -3
  380. package/dist/output/text/events.js +8 -7
  381. package/dist/output/text/helpers.js +15 -1164
  382. package/dist/output/text/proposal/producer.js +4 -2
  383. package/dist/output/text/proposal-format.js +202 -0
  384. package/dist/output/text/registry-commands.js +1 -2
  385. package/dist/output/text/registry.js +12 -6
  386. package/dist/output/text/show-directives.js +117 -0
  387. package/dist/output/text/show-format.js +103 -0
  388. package/dist/output/text/sync.js +5 -0
  389. package/dist/output/text/workflow-format.js +332 -0
  390. package/dist/output/text/workflow.js +3 -2
  391. package/dist/output/text.js +10 -19
  392. package/dist/registry/factory.js +4 -6
  393. package/dist/registry/origin-resolve.js +16 -27
  394. package/dist/registry/providers/skills-sh.js +3 -3
  395. package/dist/registry/providers/static-index.js +15 -25
  396. package/dist/registry/resolve.js +43 -94
  397. package/dist/registry/semver.js +43 -0
  398. package/dist/runtime.js +81 -12
  399. package/dist/scripts/akm-migrate.js +35529 -0
  400. package/dist/setup/detect.js +5 -7
  401. package/dist/setup/detected-engines.js +136 -0
  402. package/dist/setup/engine-config.js +100 -0
  403. package/dist/setup/registry-stash-loader.js +3 -3
  404. package/dist/setup/semantic-assets.js +12 -9
  405. package/dist/setup/setup.js +444 -208
  406. package/dist/setup/steps/connection-shared.js +120 -0
  407. package/dist/setup/steps/connection.js +108 -305
  408. package/dist/setup/steps/platforms.js +13 -12
  409. package/dist/setup/steps/semantic.js +15 -3
  410. package/dist/setup/steps/sources.js +21 -15
  411. package/dist/setup/steps/stashdir.js +6 -4
  412. package/dist/setup/steps/tasks.js +236 -119
  413. package/dist/setup/steps.js +3 -2
  414. package/dist/sources/freshness.js +39 -0
  415. package/dist/sources/provider-factory.js +11 -17
  416. package/dist/sources/providers/filesystem.js +2 -3
  417. package/dist/sources/providers/git-install.js +278 -34
  418. package/dist/sources/providers/git-provider.js +54 -56
  419. package/dist/sources/providers/git-stash.js +420 -91
  420. package/dist/sources/providers/git.js +2 -2
  421. package/dist/sources/providers/npm.js +16 -19
  422. package/dist/sources/providers/provider-utils.js +47 -22
  423. package/dist/sources/providers/sync-from-ref.js +3 -9
  424. package/dist/sources/providers/website.js +2 -2
  425. package/dist/sources/resolve.js +11 -10
  426. package/dist/sources/snapshot-fetchers/types.js +4 -0
  427. package/dist/sources/{website-ingest.js → snapshot-fetchers/website-ingest.js} +110 -41
  428. package/dist/storage/database.js +60 -4
  429. package/dist/storage/engines/sqlite-migrations.js +156 -5
  430. package/dist/storage/locations.js +1 -2
  431. package/dist/storage/repositories/canaries-repository.js +1 -1
  432. package/dist/storage/repositories/events-repository.js +51 -11
  433. package/dist/storage/repositories/improve-runs-repository.js +6 -32
  434. package/dist/storage/repositories/index-connection.js +79 -0
  435. package/dist/storage/repositories/index-db.js +4 -3
  436. package/dist/storage/repositories/index-entries-repository.js +863 -0
  437. package/dist/{indexer/db/entry-mapper.js → storage/repositories/index-entry-mapper.js} +19 -2
  438. package/dist/storage/repositories/index-entry-types.js +4 -0
  439. package/dist/storage/repositories/index-fts-repository.js +167 -0
  440. package/dist/storage/repositories/index-llm-cache-repository.js +108 -0
  441. package/dist/storage/repositories/index-meta-repository.js +49 -0
  442. package/dist/{indexer/db/schema.js → storage/repositories/index-schema.js} +226 -100
  443. package/dist/storage/repositories/index-sql.js +12 -0
  444. package/dist/storage/repositories/index-utility-repository.js +356 -0
  445. package/dist/storage/repositories/index-vec-repository.js +250 -0
  446. package/dist/storage/repositories/outcome-repository.js +119 -0
  447. package/dist/storage/repositories/proposals-repository.js +317 -75
  448. package/dist/storage/repositories/registry-cache.js +1 -1
  449. package/dist/storage/repositories/salience-repository.js +172 -0
  450. package/dist/storage/repositories/task-history-repository.js +110 -3
  451. package/dist/storage/repositories/workflow-runs-repository.js +240 -19
  452. package/dist/tasks/backends/cron.js +169 -46
  453. package/dist/tasks/backends/exec-utils.js +76 -3
  454. package/dist/tasks/backends/index.js +6 -9
  455. package/dist/tasks/backends/launchd.js +292 -55
  456. package/dist/tasks/backends/schtasks.js +557 -70
  457. package/dist/tasks/backends/types.js +4 -0
  458. package/dist/tasks/command-executable.js +93 -0
  459. package/dist/tasks/embedded.js +56 -38
  460. package/dist/tasks/parser.js +156 -64
  461. package/dist/tasks/resolve-akm-bin.js +144 -51
  462. package/dist/tasks/runner.js +377 -209
  463. package/dist/tasks/schedule.js +108 -19
  464. package/dist/tasks/scheduler-invocation.js +296 -0
  465. package/dist/tasks/schema.js +1 -1
  466. package/dist/tasks/task-id.js +35 -0
  467. package/dist/tasks/validator.js +30 -16
  468. package/dist/text-import-hook.mjs +1 -1
  469. package/dist/workflows/authoring/authoring.js +104 -43
  470. package/dist/workflows/authoring/scope-key.js +1 -1
  471. package/dist/workflows/cli.js +0 -16
  472. package/dist/workflows/concurrency-policy.js +15 -0
  473. package/dist/workflows/exec/brief.js +450 -0
  474. package/dist/workflows/exec/frozen-judge.js +47 -0
  475. package/dist/workflows/exec/native-executor.js +1038 -0
  476. package/dist/workflows/exec/param-secrets.js +115 -0
  477. package/dist/workflows/exec/report.js +1460 -0
  478. package/dist/workflows/exec/run-workflow.js +602 -0
  479. package/dist/workflows/exec/scheduler.js +71 -0
  480. package/dist/workflows/exec/step-work.js +1190 -0
  481. package/dist/workflows/exec/unit-writer.js +23 -0
  482. package/dist/workflows/exec/workflow-engine-gate.js +67 -0
  483. package/dist/workflows/exec/worktree.js +171 -0
  484. package/dist/workflows/ir/compile.js +246 -0
  485. package/dist/workflows/ir/freeze.js +233 -0
  486. package/dist/workflows/ir/params.js +54 -0
  487. package/dist/workflows/ir/plan-hash.js +68 -0
  488. package/dist/workflows/ir/schema.js +540 -0
  489. package/dist/workflows/parser.js +878 -304
  490. package/dist/workflows/program/expressions.js +181 -0
  491. package/dist/workflows/program/schema.js +51 -0
  492. package/dist/workflows/renderer.js +100 -45
  493. package/dist/workflows/resource-limits.js +22 -0
  494. package/dist/workflows/runtime/agent-identity.js +59 -14
  495. package/dist/workflows/runtime/checkin.js +1 -1
  496. package/dist/workflows/runtime/plan-classifier.js +131 -0
  497. package/dist/workflows/runtime/runs.js +376 -119
  498. package/dist/workflows/runtime/unit-checkin.js +45 -0
  499. package/dist/workflows/runtime/unit-phases.js +20 -0
  500. package/dist/workflows/runtime/workflow-asset-loader.js +241 -40
  501. package/dist/workflows/schema.js +1 -11
  502. package/dist/workflows/validate-summary.js +2 -3
  503. package/dist/workflows/validator.js +52 -30
  504. package/docs/README.md +42 -78
  505. package/docs/migration/README.md +8 -0
  506. package/docs/migration/release-notes/0.6.0.md +1 -1
  507. package/docs/migration/release-notes/0.7.0.md +9 -8
  508. package/docs/migration/release-notes/0.9.0.md +158 -14
  509. package/docs/migration/v0.7-to-v0.8.md +46 -47
  510. package/docs/migration/v0.8-to-v0.9.md +844 -0
  511. package/docs/reference/README.md +12 -0
  512. package/docs/reference/data-and-telemetry.md +333 -0
  513. package/package.json +21 -17
  514. package/schemas/akm-asset-envelope.json +93 -0
  515. package/schemas/akm-config.json +4636 -0
  516. package/schemas/akm-task.json +87 -0
  517. package/schemas/akm-workflow.json +373 -0
  518. package/dist/akm-migrate-storage +0 -38
  519. package/dist/assets/help/help-accept.md +0 -12
  520. package/dist/assets/help/help-improve.md +0 -84
  521. package/dist/assets/help/help-proposals.md +0 -17
  522. package/dist/assets/help/help-propose.md +0 -17
  523. package/dist/assets/help/help-reject.md +0 -11
  524. package/dist/assets/profiles/frequent.json +0 -13
  525. package/dist/assets/profiles/recombine-only.json +0 -21
  526. package/dist/assets/profiles/reflect-distill.json +0 -30
  527. package/dist/assets/profiles/synthesize.json +0 -15
  528. package/dist/assets/prompts/procedural-system.md +0 -44
  529. package/dist/assets/prompts/recombine-system.md +0 -40
  530. package/dist/assets/prompts/staleness-detect-system.md +0 -6
  531. package/dist/assets/tasks/core/backup.yml +0 -4
  532. package/dist/assets/tasks/graph-refresh-weekly.yml +0 -10
  533. package/dist/assets/templates/html/default.html +0 -78
  534. package/dist/assets/templates/html/vendor/echarts.min.js +0 -45
  535. package/dist/assets/wiki/index-template.md +0 -12
  536. package/dist/assets/wiki/ingest-workflow-template.md +0 -83
  537. package/dist/assets/wiki/log-template.md +0 -8
  538. package/dist/assets/wiki/schema-template.md +0 -61
  539. package/dist/cli/config-migrate.js +0 -150
  540. package/dist/cli/config-validate.js +0 -39
  541. package/dist/commands/graph/graph-cli.js +0 -124
  542. package/dist/commands/graph/graph.js +0 -487
  543. package/dist/commands/improve/calibration.js +0 -161
  544. package/dist/commands/improve/dedup.js +0 -482
  545. package/dist/commands/improve/extract-watch.js +0 -140
  546. package/dist/commands/improve/hot-probation.js +0 -45
  547. package/dist/commands/improve/improve-auto-accept.js +0 -276
  548. package/dist/commands/improve/improve-profiles.js +0 -168
  549. package/dist/commands/improve/procedural.js +0 -398
  550. package/dist/commands/improve/recombine.js +0 -818
  551. package/dist/commands/improve/schema-similarity-gate.js +0 -168
  552. package/dist/commands/lint/agent-linter.js +0 -44
  553. package/dist/commands/lint/command-linter.js +0 -44
  554. package/dist/commands/lint/default-linter.js +0 -16
  555. package/dist/commands/lint/fact-linter.js +0 -39
  556. package/dist/commands/lint/knowledge-linter.js +0 -16
  557. package/dist/commands/lint/memory-linter.js +0 -61
  558. package/dist/commands/lint/registry.js +0 -41
  559. package/dist/commands/lint/skill-linter.js +0 -45
  560. package/dist/commands/lint/task-linter.js +0 -50
  561. package/dist/commands/lint/workflow-linter.js +0 -81
  562. package/dist/commands/proposal/legacy-import.js +0 -115
  563. package/dist/commands/sources/history.js +0 -196
  564. package/dist/commands/tasks/default-tasks.js +0 -186
  565. package/dist/commands/wiki-cli.js +0 -292
  566. package/dist/core/asset/asset-registry.js +0 -76
  567. package/dist/core/asset/asset-spec.js +0 -259
  568. package/dist/core/config/config-migration.js +0 -602
  569. package/dist/core/deep-merge.js +0 -38
  570. package/dist/core/eval/rank-metrics.js +0 -113
  571. package/dist/core/ripgrep/install.js +0 -163
  572. package/dist/core/ripgrep/resolve.js +0 -81
  573. package/dist/indexer/db/db.js +0 -1413
  574. package/dist/indexer/manifest.js +0 -170
  575. package/dist/indexer/passes/metadata-contributors.js +0 -31
  576. package/dist/indexer/usage/unmigrated-vaults-guard.js +0 -94
  577. package/dist/integrations/harnesses/opencode-sdk/index.js +0 -49
  578. package/dist/llm/call-ai.js +0 -62
  579. package/dist/llm/memory-infer-impl.js +0 -138
  580. package/dist/output/shapes/distill.js +0 -14
  581. package/dist/output/shapes/history.js +0 -11
  582. package/dist/output/text/distill.js +0 -6
  583. package/dist/output/text/enable-disable.js +0 -8
  584. package/dist/output/text/history.js +0 -6
  585. package/dist/output/text/wiki.js +0 -16
  586. package/dist/registry/build-index.js +0 -386
  587. package/dist/scripts/migrate-storage.js +0 -19108
  588. package/dist/scripts/migrations/import-fs-improve-runs-to-db.js +0 -9411
  589. package/dist/scripts/migrations/v16-to-v17.js +0 -141
  590. package/dist/setup/legacy-config.js +0 -106
  591. package/dist/storage/repositories/consolidation-repository.js +0 -38
  592. package/dist/storage/repositories/recombine-repository.js +0 -213
  593. package/dist/wiki/wiki-templates.js +0 -15
  594. package/dist/wiki/wiki.js +0 -1012
  595. package/dist/workflows/db.js +0 -215
  596. package/docs/data-and-telemetry.md +0 -226
  597. /package/dist/sources/{wiki-fetchers → snapshot-fetchers}/registry.js +0 -0
  598. /package/dist/sources/{wiki-fetchers → snapshot-fetchers}/youtube.js +0 -0
@@ -0,0 +1,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
  }