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
@@ -10,14 +10,26 @@
10
10
  */
11
11
  import fs from "node:fs";
12
12
  import path from "node:path";
13
+ import { parse as yamlParse } from "yaml";
14
+ import { detectAdapterId } from "../../core/adapter/detect-adapter.js";
13
15
  import { assertFlatAssetName, combineCreatePath, normalizeCreateSubPath } from "../../core/asset/asset-create.js";
14
- import { resolveAssetPathFromName } from "../../core/asset/asset-spec.js";
15
- import { isHttpUrl, isWithin, tryReadStdinText } from "../../core/common.js";
16
+ import { assetPathForName, stashDirFor } from "../../core/asset/asset-placement.js";
17
+ import { assembleAsset } from "../../core/asset/asset-serialize.js";
18
+ import { parseFrontmatter } from "../../core/asset/frontmatter.js";
19
+ import { conceptIdFromTypeName, parseRefInput } from "../../core/asset/resolve-ref.js";
20
+ import { isHttpUrl, isWithin, resolveStashDir, tryReadStdinText } from "../../core/common.js";
16
21
  import { loadConfig } from "../../core/config/config.js";
17
22
  import { UsageError } from "../../core/errors.js";
18
- import { commitWriteTargetBoundary, formatRefForMessage, resolveWriteTarget, writeAssetToSource, } from "../../core/write-source.js";
23
+ import { resolveBundleWriteTarget, resolveMutationTarget } from "../../core/mutation-target.js";
24
+ import { resolveStashStandards } from "../../core/standards/resolve-stash-standards.js";
25
+ import { warn } from "../../core/warn.js";
26
+ import { commitWriteTargetBoundary, formatRefForMessage, recordWriteTargetPath, resolveWriteTarget, writeAssetToSource, } from "../../core/write-source.js";
19
27
  import { indexWrittenAssets } from "../../indexer/index-written-assets.js";
20
- import { fetchWebsiteMarkdownSnapshot, shouldAllowPrivateWebsiteUrlForTests } from "../../sources/website-ingest.js";
28
+ import { deriveInstallations, slugForPath } from "../../indexer/installations.js";
29
+ import { resolveSourceEntries } from "../../indexer/search/search-source.js";
30
+ import { fetchWebsiteMarkdownSnapshot, shouldAllowPrivateWebsiteUrlForTests, } from "../../sources/snapshot-fetchers/website-ingest.js";
31
+ import { writeSupersededEdge } from "../improve/memory/memory-belief.js";
32
+ import { refToRelPath, resolveRefPathInStash } from "../lint/base-linter.js";
21
33
  const MAX_CAPTURED_ASSET_SLUG_LENGTH = 64;
22
34
  // ── Asset-name normalisation ─────────────────────────────────────────────────
23
35
  /**
@@ -111,6 +123,383 @@ export async function readKnowledgeInput(source, options) {
111
123
  });
112
124
  return { content: snapshot.content, preferredName: snapshot.preferredName };
113
125
  }
126
+ /**
127
+ * Parse a `--xref` / `--supersedes` value through the new-grammar input parser
128
+ * (`parseRefInput`, the `[bundle//]conceptId` grammar) so malformed values get a
129
+ * structured error instead of a misleading "did not resolve". Bundle qualifiers
130
+ * are retained for exact source membership checks.
131
+ */
132
+ function parseWriteRef(raw, flag) {
133
+ let parsed;
134
+ try {
135
+ parsed = parseRefInput(raw);
136
+ }
137
+ catch (error) {
138
+ const message = error instanceof Error ? error.message : String(error);
139
+ throw new UsageError(`${flag} "${raw}" is not a valid asset ref: ${message}`, "INVALID_FLAG_VALUE", `Refs use the conceptId form, e.g. ${flag} knowledge/auth-flow.`);
140
+ }
141
+ // Bundle qualifiers remain explicit so duplicate names resolve in the named
142
+ // source.
143
+ const conceptId = conceptIdFromTypeName(parsed.type, parsed.name);
144
+ const origin = parsed.origin;
145
+ return {
146
+ ref: origin ? `${origin}//${conceptId}` : conceptId,
147
+ type: parsed.type,
148
+ name: parsed.name,
149
+ ...(origin ? { origin } : {}),
150
+ };
151
+ }
152
+ /**
153
+ * Trim, parse, and dedupe `--xref` / `--supersedes` flag values, in argv
154
+ * order. Parsing comes before deduplication so normalized spellings collapse
155
+ * into one canonical entry.
156
+ */
157
+ function parseWriteRefs(rawRefs, flag) {
158
+ const parsedRefs = [];
159
+ for (const raw of rawRefs) {
160
+ const trimmed = raw.trim();
161
+ if (!trimmed)
162
+ continue;
163
+ const parsed = parseWriteRef(trimmed, flag);
164
+ if (!parsedRefs.some((p) => p.ref === parsed.ref))
165
+ parsedRefs.push(parsed);
166
+ }
167
+ return parsedRefs;
168
+ }
169
+ function resolveWriteRefRoots(target) {
170
+ const cfg = loadConfig();
171
+ let writeTarget;
172
+ try {
173
+ writeTarget = resolveWriteTarget(cfg, target);
174
+ }
175
+ catch (error) {
176
+ if (!target)
177
+ throw error;
178
+ try {
179
+ writeTarget = resolveBundleWriteTarget(cfg, target);
180
+ }
181
+ catch {
182
+ throw error;
183
+ }
184
+ }
185
+ const stashRoot = writeTarget.source.path;
186
+ let workingStash;
187
+ try {
188
+ workingStash = resolveStashDir();
189
+ }
190
+ catch {
191
+ // No working stash configured — the write target alone.
192
+ }
193
+ const mutableRoots = [stashRoot];
194
+ if (workingStash && path.resolve(workingStash) !== path.resolve(stashRoot))
195
+ mutableRoots.push(workingStash);
196
+ const namedSources = resolveSourceEntries(undefined, cfg);
197
+ const installations = deriveInstallations(namedSources);
198
+ const bundleByPath = new Map(namedSources.flatMap((source, index) => {
199
+ const bundleId = installations[index]?.id;
200
+ return bundleId ? [[path.resolve(source.path), bundleId]] : [];
201
+ }));
202
+ const otherSources = namedSources.filter((s) => !mutableRoots.some((m) => path.resolve(m) === path.resolve(s.path)) && fs.existsSync(s.path));
203
+ const roots = [
204
+ ...mutableRoots
205
+ .filter((p) => fs.existsSync(p))
206
+ .map((p) => {
207
+ const source = namedSources.find((candidate) => path.resolve(candidate.path) === path.resolve(p));
208
+ const mutable = path.resolve(p) === path.resolve(stashRoot)
209
+ ? writeTarget.source.adapterId === "akm"
210
+ : source?.writable === true && (source.adapterId ?? detectAdapterId(p)) === "akm";
211
+ return {
212
+ path: p,
213
+ source,
214
+ bundleId: bundleByPath.get(path.resolve(p)) ?? slugForPath(p),
215
+ mutable,
216
+ };
217
+ }),
218
+ ...otherSources.map((source) => ({
219
+ path: source.path,
220
+ source,
221
+ bundleId: bundleByPath.get(path.resolve(source.path)) ?? slugForPath(source.path),
222
+ mutable: false,
223
+ })),
224
+ ];
225
+ return { roots };
226
+ }
227
+ function rootsForWriteRef(parsed, roots) {
228
+ if (!parsed.origin)
229
+ return roots;
230
+ return roots.filter((root) => root.bundleId === parsed.origin);
231
+ }
232
+ function canonicalWriteRef(parsed, bundleId) {
233
+ return `${bundleId}//${conceptIdFromTypeName(parsed.type, parsed.name)}`;
234
+ }
235
+ /**
236
+ * True when write-time validation must FAIL OPEN for this ref type — exactly
237
+ * lint's `checkMissingRefs` policy (`if (relPath === null) continue`,
238
+ * base-linter.ts): a type the slug resolver cannot map to a path (script refs
239
+ * are contract-pinned to return null) is accepted without an existence check
240
+ * rather than being unwinnable. Workflow refs never fail open — they resolve
241
+ * stash-rooted via {@link locateWriteRefInRoot}.
242
+ */
243
+ function isFailOpenRefType(type, name) {
244
+ return type !== "workflow" && refToRelPath(type, name) === null;
245
+ }
246
+ /**
247
+ * Resolve a write-time ref to its primary on-disk file within a single stash
248
+ * root. Wraps lint's `resolveRefPathInStash` with one addition: workflow
249
+ * refs are probed against the ROOT's workflows/ dir first (every recognized
250
+ * workflow extension), because `workflowSpec.toAssetPath` inside
251
+ * `refToRelPath` probes the CWD — and write validation must not depend on the
252
+ * caller's cwd.
253
+ */
254
+ function locateWriteRefInRoot(type, name, root) {
255
+ if (type === "workflow") {
256
+ const typeRoot = path.join(root, stashDirFor("workflow") ?? "workflows");
257
+ const candidate = assetPathForName("workflow", typeRoot, name);
258
+ if (fs.existsSync(candidate))
259
+ return candidate;
260
+ }
261
+ const relPath = refToRelPath(type, name);
262
+ if (relPath === null)
263
+ return null;
264
+ return resolveRefPathInStash(relPath, type, name, root);
265
+ }
266
+ /** Build the shared exit-2 error for refs that resolved in no root. */
267
+ function unresolvedRefsError(flag, unresolved) {
268
+ const firstName = unresolved[0]?.name ?? "asset";
269
+ const firstType = unresolved[0]?.type ?? "knowledge";
270
+ return new UsageError(`${flag} ref${unresolved.length > 1 ? "s" : ""} did not resolve in the write target or any configured source: ${unresolved.map((u) => u.ref).join(", ")}`, "INVALID_FLAG_VALUE", `Find the intended asset with \`akm search "${firstName}" --type ${firstType}\`. Refs use the form [bundle//]conceptId (e.g. knowledge/guide.md).`);
271
+ }
272
+ // ── Cross-references (--xref) ────────────────────────────────────────────────
273
+ /**
274
+ * Soft cap on xrefs per asset, from the back-linking conventions' "~5" rule.
275
+ * Exceeding it warns on stderr but never blocks the write (the cap is a
276
+ * heuristic, not a validator bound).
277
+ */
278
+ export const XREF_SOFT_CAP = 5;
279
+ /**
280
+ * Validate `--xref` flag values before ANY write happens.
281
+ *
282
+ * Each `[bundle//]conceptId` must resolve to a real asset in the write-ref root
283
+ * set (write target + working stash + configured sources — see
284
+ * {@link resolveWriteRefRoots}; cross-stash provenance refs into read-only
285
+ * sources are accepted). An unresolvable ref is input validation of an
286
+ * explicitly passed flag — it throws {@link UsageError} (exit 2) naming every
287
+ * bad ref, and the caller must invoke this before writing so a failed
288
+ * validation leaves the stash untouched. Resolution reuses the lint
289
+ * ref-resolver helpers (`refToRelPath` / `resolveRefPathInStash`) — do not
290
+ * fork a second resolver — and mirrors lint's fail-open policy: a type the
291
+ * resolver cannot map to a path (for example a script concept) is accepted
292
+ * without an existence check.
293
+ *
294
+ * Returns fully-qualified durable refs, deduplicated in argv order. More than
295
+ * {@link XREF_SOFT_CAP} refs emits a stderr warning (soft cap) but still
296
+ * returns them all.
297
+ */
298
+ export function resolveXrefsForWrite(rawXrefs, target) {
299
+ const parsedRefs = parseWriteRefs(rawXrefs, "--xref");
300
+ if (parsedRefs.length === 0)
301
+ return [];
302
+ const { roots } = resolveWriteRefRoots(target);
303
+ const unresolved = [];
304
+ const xrefs = [];
305
+ for (const parsed of parsedRefs) {
306
+ const candidates = rootsForWriteRef(parsed, roots);
307
+ const resolvedRoot = isFailOpenRefType(parsed.type, parsed.name)
308
+ ? candidates[0]
309
+ : candidates.find((root) => locateWriteRefInRoot(parsed.type, parsed.name, root.path) !== null);
310
+ if (!resolvedRoot) {
311
+ unresolved.push(parsed);
312
+ continue;
313
+ }
314
+ const ref = canonicalWriteRef(parsed, resolvedRoot.bundleId);
315
+ if (!xrefs.includes(ref))
316
+ xrefs.push(ref);
317
+ }
318
+ if (unresolved.length > 0) {
319
+ throw unresolvedRefsError("--xref", unresolved);
320
+ }
321
+ if (xrefs.length > XREF_SOFT_CAP) {
322
+ warn(`Warning: ${xrefs.length} xrefs exceeds the ~${XREF_SOFT_CAP} soft cap from the back-linking conventions. ` +
323
+ "Each xref folds into this asset's search hints, so extras blur its ranking signal. Writing anyway.");
324
+ }
325
+ return xrefs;
326
+ }
327
+ /**
328
+ * Merge validated xrefs into a markdown document's frontmatter `xrefs:` list.
329
+ *
330
+ * A document without frontmatter gains a single block; a document WITH
331
+ * frontmatter keeps every existing key and gets the refs dedupe-appended to
332
+ * its `xrefs:` list — never a nested second block. Runs BEFORE the asset is
333
+ * written so write-path indexing sees the final content. Returns `content`
334
+ * unchanged when `xrefs` is empty.
335
+ *
336
+ * The merge round-trips the frontmatter through the YAML parser, so it is
337
+ * only safe when the existing block parses as a YAML mapping. Malformed YAML
338
+ * would silently fall back to `parseFrontmatter`'s lenient scalar-only
339
+ * scanner and re-serializing that lossy result would destroy list/nested
340
+ * values (`tags: [a, b]` → `tags: ""`). Rather than corrupt data the caller
341
+ * asked to preserve, a block that is not a parseable YAML mapping throws
342
+ * {@link UsageError} (exit 2, before any write). The AKM write boundary also
343
+ * rejects malformed frontmatter without `--xref` because it cannot safely add
344
+ * required type metadata. Known
345
+ * cosmetic limitation: YAML comments and anchors in a VALID block do not
346
+ * survive the round-trip (values are preserved).
347
+ */
348
+ export function mergeXrefsIntoContent(content, xrefs) {
349
+ if (xrefs.length === 0)
350
+ return content;
351
+ const parsed = parseFrontmatter(content);
352
+ if (parsed.frontmatter?.trim()) {
353
+ if (!isParseableYamlMapping(parsed.frontmatter)) {
354
+ throw new UsageError("--xref cannot merge into this document: its frontmatter is not a parseable YAML mapping, and rewriting it would drop the values the parser could not read.", "INVALID_FLAG_VALUE", "Fix the document's frontmatter (e.g. an unterminated quote) and retry.");
355
+ }
356
+ }
357
+ const existingValue = parsed.data.xrefs;
358
+ const existing = Array.isArray(existingValue)
359
+ ? existingValue.filter((v) => typeof v === "string" && v.trim().length > 0)
360
+ : typeof existingValue === "string" && existingValue.trim()
361
+ ? [existingValue.trim()]
362
+ : [];
363
+ const merged = [...existing];
364
+ for (const ref of xrefs) {
365
+ if (!merged.includes(ref))
366
+ merged.push(ref);
367
+ }
368
+ return assembleAsset({ ...parsed.data, xrefs: merged }, parsed.content);
369
+ }
370
+ /**
371
+ * True when a raw frontmatter block (the text between the `---` fences)
372
+ * parses as a YAML mapping — the precondition for any round-trip rewrite.
373
+ * Malformed YAML falls back to `parseFrontmatter`'s lossy lenient scanner
374
+ * (scalars only), and re-serializing that result destroys list/nested values
375
+ * (`tags: [a, b]` → `tags: ""`), so writers must refuse instead of rewriting.
376
+ */
377
+ function isParseableYamlMapping(frontmatter) {
378
+ try {
379
+ const fmValue = yamlParse(frontmatter);
380
+ return fmValue !== null && typeof fmValue === "object" && !Array.isArray(fmValue);
381
+ }
382
+ catch {
383
+ return false;
384
+ }
385
+ }
386
+ /** Resolve any qualified supersedes ref as the mutation target for remember/import. */
387
+ export function resolveSupersedesWriteTarget(rawRefs, target) {
388
+ const config = loadConfig();
389
+ let effectiveTarget = target;
390
+ for (const parsed of parseWriteRefs(rawRefs, "--supersedes")) {
391
+ if (!parsed.origin)
392
+ continue;
393
+ const resolved = resolveMutationTarget(config, { type: parsed.type, name: parsed.name, origin: parsed.origin }, effectiveTarget).target;
394
+ effectiveTarget = resolved.selector ?? resolved.source.name;
395
+ }
396
+ return effectiveTarget;
397
+ }
398
+ /**
399
+ * Asset types `--supersedes` must refuse to demote: the demotion writes a YAML
400
+ * frontmatter block onto the target file, and these types are RAW files whose
401
+ * bytes are the value (a secret's entire content is the credential; a task is
402
+ * pure YAML that a prepended second document breaks; scripts have arbitrary
403
+ * syntax). Prepending frontmatter corrupts them. `akm mv` excludes the same
404
+ * types as "not markdown assets" (plus `script`, unresolvable by design).
405
+ */
406
+ const SUPERSEDE_REJECTED_TYPES = new Set(["secret", "env", "task", "script"]);
407
+ /**
408
+ * Validate `--supersedes` flag values before ANY write happens.
409
+ *
410
+ * The conventions' corrections pattern needs TWO writes: the new correction
411
+ * asset (with an xref to what it corrects) and a metadata edit demoting the
412
+ * old asset (`beliefState: superseded` + `supersededBy: [<new ref>]`). This
413
+ * helper performs the validation half: each ref must resolve to a real asset
414
+ * (same resolver + root set as {@link resolveXrefsForWrite}); an unresolvable
415
+ * ref throws {@link UsageError} (exit 2) naming every bad ref, so a failed
416
+ * validation leaves the stash untouched — no partial correction.
417
+ *
418
+ * Because the demotion PREPENDS a YAML frontmatter block when the target file
419
+ * has none, only markdown assets may be demoted: refs of a raw asset type
420
+ * ({@link SUPERSEDE_REJECTED_TYPES}) and refs resolving to any non-`.md` file
421
+ * (for example a task YAML file) are rejected with {@link UsageError} BEFORE
422
+ * any write — never silently corrupted.
423
+ *
424
+ * Demotion targets must live under the resolved write target's source path or
425
+ * the working stash — honoring the "only operate on writable sources"
426
+ * constraint (and never dirtying a non-target source outside its boundary
427
+ * commit). A ref that resolves only in another configured source — read-only
428
+ * OR writable-but-not-the-target — is returned with `writable: false` and a
429
+ * reason (naming the `--target` remedy when the source is writable); the
430
+ * caller writes the correction anyway and reports the demotion as not
431
+ * applied.
432
+ *
433
+ * Returns the deduplicated plan in argv order; empty input returns [].
434
+ */
435
+ export function resolveSupersedesForWrite(rawRefs, target) {
436
+ const parsedRefs = parseWriteRefs(rawRefs, "--supersedes");
437
+ if (parsedRefs.length === 0)
438
+ return [];
439
+ const { roots } = resolveWriteRefRoots(target);
440
+ const plan = [];
441
+ const unresolved = [];
442
+ for (const parsed of parsedRefs) {
443
+ const orderedRoots = rootsForWriteRef(parsed, roots);
444
+ // Data-corruption gate (SPEC-5): demotion is a frontmatter write; a raw
445
+ // asset type must be rejected up front — resolving it and mutating the
446
+ // file would prepend a YAML block over its raw bytes.
447
+ if (SUPERSEDE_REJECTED_TYPES.has(parsed.type)) {
448
+ throw new UsageError(`--supersedes cannot demote ${parsed.ref}: asset type "${parsed.type}" uses raw files, and the demotion writes YAML frontmatter that would corrupt them.`, "INVALID_FLAG_VALUE", "Only markdown assets (e.g. memories/note, knowledge/guide, facts/team/tool-stack) can carry the beliefState/supersededBy demotion. Replace or delete the raw asset instead.");
449
+ }
450
+ let located = null;
451
+ for (const root of orderedRoots) {
452
+ const filePath = locateWriteRefInRoot(parsed.type, parsed.name, root.path);
453
+ if (filePath !== null) {
454
+ located = {
455
+ root: root.path,
456
+ source: root.source,
457
+ bundleId: root.bundleId,
458
+ mutable: root.mutable,
459
+ filePath,
460
+ };
461
+ break;
462
+ }
463
+ }
464
+ if (located === null) {
465
+ unresolved.push(parsed);
466
+ continue;
467
+ }
468
+ // Belt-and-suspenders for the same corruption class: whatever the type,
469
+ // the demotion may only touch a markdown file. Rejects, for example, a task
470
+ // YAML file reached through a malformed or stale ref.
471
+ if (!located.filePath.toLowerCase().endsWith(".md")) {
472
+ throw new UsageError(`--supersedes ${parsed.ref} resolves to a non-markdown file (${located.filePath}) — the demotion writes YAML frontmatter and would corrupt it.`, "INVALID_FLAG_VALUE", "Only markdown assets can carry the beliefState/supersededBy demotion. Replace or delete the file instead.");
473
+ }
474
+ const { root, source, bundleId, mutable: writable, filePath } = located;
475
+ // The eligibility rule is write-target-or-working-stash, NOT source
476
+ // writability: mutating a non-target writable source would leave it dirty
477
+ // outside any boundary commit. Name the remedy when one exists.
478
+ const namedWritableSource = source?.writable === true ? source.registryId : undefined;
479
+ const canonicalRef = canonicalWriteRef(parsed, bundleId);
480
+ if (plan.some((item) => item.ref === canonicalRef))
481
+ continue;
482
+ plan.push({
483
+ ref: canonicalRef,
484
+ filePath,
485
+ stashRoot: root,
486
+ writable,
487
+ ...(writable
488
+ ? {}
489
+ : {
490
+ reason: namedWritableSource
491
+ ? `resolves outside the write target and the working stash, in writable source "${namedWritableSource}" at ${root}; ` +
492
+ `re-run with --target ${namedWritableSource} to demote it there`
493
+ : `resolves outside the write target and the working stash, in a read-only source at ${root}; ` +
494
+ "demotion only applies to assets in the write target or the working stash",
495
+ }),
496
+ });
497
+ }
498
+ if (unresolved.length > 0) {
499
+ throw unresolvedRefsError("--supersedes", unresolved);
500
+ }
501
+ return plan;
502
+ }
114
503
  // ── Asset writing ────────────────────────────────────────────────────────────
115
504
  /**
116
505
  * Write a markdown asset (knowledge or memory) to the resolved write target.
@@ -122,35 +511,143 @@ export async function readKnowledgeInput(source, options) {
122
511
  */
123
512
  export async function writeMarkdownAsset(options) {
124
513
  const cfg = loadConfig();
125
- const target = resolveWriteTarget(cfg, options.target);
126
- const { source, config } = target;
127
- const typeRoot = path.join(source.path, options.type === "knowledge" ? "knowledge" : "memories");
128
514
  // `--name` is the flat asset name; `--path` is the subdirectory under the
129
515
  // type root. Combine them into the nested name the path resolver expects.
130
516
  const subPath = normalizeCreateSubPath(options.path);
131
517
  const baseName = normalizeMarkdownAssetName(options.name, inferAssetName(options.content, options.fallbackPrefix, options.preferredName));
132
518
  const normalizedName = combineCreatePath(subPath, baseName);
519
+ const resolved = resolveMutationTarget(cfg, { type: options.type, name: normalizedName }, options.target);
520
+ const { target } = resolved;
521
+ const { source, config } = target;
522
+ const typeRoot = path.join(source.path, options.type === "knowledge" ? "knowledge" : "memories");
133
523
  // Pre-flight: existence + force semantics. The helper itself overwrites
134
524
  // unconditionally; the CLI surfaces a friendlier UsageError before any
135
525
  // disk activity when --force is absent.
136
- const assetPath = resolveAssetPathFromName(options.type, typeRoot, normalizedName);
526
+ const assetPath = assetPathForName(options.type, typeRoot, normalizedName);
137
527
  if (!isWithin(assetPath, typeRoot)) {
138
528
  throw new UsageError(`Resolved ${options.type} path escapes the stash: "${normalizedName}"`);
139
529
  }
140
530
  if (fs.existsSync(assetPath) && !options.force) {
141
531
  throw new UsageError(`${options.type === "knowledge" ? "Knowledge" : "Memory"} "${normalizedName}" already exists. Re-run with --force to overwrite it.`, "RESOURCE_ALREADY_EXISTS");
142
532
  }
143
- const ref = { type: options.type, name: normalizedName };
144
- const result = await writeAssetToSource(source, config, ref, options.content);
533
+ // A correction cannot supersede ITSELF. Under `--force` the ref resolves to
534
+ // the very file this command is about to overwrite, and the demotion would
535
+ // immediately mark the fresh correction superseded (plus a self-xref) —
536
+ // silently hiding the fix from `--belief current` and capping its rank.
537
+ // Input validation: exit 2, before any write, nothing demoted.
538
+ for (const item of options.supersedes ?? []) {
539
+ if (path.resolve(item.filePath) === path.resolve(assetPath)) {
540
+ throw new UsageError(`--supersedes ${item.ref} resolves to the asset being written ("${resolved.displayRef}") — a correction cannot supersede itself.`, "INVALID_FLAG_VALUE", "Write the correction under a different --name, or drop --supersedes when overwriting an asset in place with --force.");
541
+ }
542
+ }
543
+ const result = await writeAssetToSource(source, config, resolved.ref, options.content);
544
+ const durableRef = result.ref;
545
+ result.ref = resolved.displayRef;
546
+ // SPEC-5 (--supersedes): demote each superseded asset by mutating its
547
+ // frontmatter (`beliefState: superseded` + sorted-set-append `supersededBy`;
548
+ // every other key and the body are preserved). Ordered BEFORE
549
+ // commitWriteTargetBoundary so a git target batches the correction and the
550
+ // demoted incumbent into the single boundary commit instead of leaving the
551
+ // metadata edit as dirty residue after it.
552
+ const superseded = [];
553
+ const demotedByRoot = new Map();
554
+ for (const item of options.supersedes ?? []) {
555
+ if (!item.writable) {
556
+ const reason = item.reason ?? "target is not writable";
557
+ warn(`Warning: superseded asset ${item.ref} was NOT demoted (${reason}). ` +
558
+ "The correction was written and cites it in xrefs; demote the old asset where it is writable.");
559
+ superseded.push({ ref: item.ref, applied: false, reason });
560
+ continue;
561
+ }
562
+ // The demotion round-trips the old file's frontmatter through the YAML
563
+ // parser. A malformed block would silently fall back to the lossy lenient
564
+ // scanner and re-serializing that result destroys list/nested values —
565
+ // skip instead of rewriting, mirroring mergeXrefsIntoContent's
566
+ // abort-on-malformed policy (the correction itself still writes).
567
+ let oldFrontmatter = null;
568
+ try {
569
+ oldFrontmatter = parseFrontmatter(fs.readFileSync(item.filePath, "utf8")).frontmatter;
570
+ }
571
+ catch {
572
+ // Unreadable file — let writeSupersededEdge surface the real fs error.
573
+ }
574
+ if (oldFrontmatter?.trim() && !isParseableYamlMapping(oldFrontmatter)) {
575
+ const reason = "its existing frontmatter is not a parseable YAML mapping — rewriting it would drop the values the parser could not read";
576
+ warn(`Warning: superseded asset ${item.ref} was NOT demoted (${reason}). ` +
577
+ "The correction was written and cites it in xrefs; fix the old asset's frontmatter and re-run the correction with --force.");
578
+ superseded.push({ ref: item.ref, applied: false, reason });
579
+ continue;
580
+ }
581
+ // A demotion failure (fs error, concurrent delete, malformed YAML the
582
+ // pre-check missed) must NOT abort the correction: the new asset is
583
+ // already on disk, and bailing out here would skip the boundary commit and
584
+ // the write-path indexing below — leaving the correction unindexed and,
585
+ // on a git target, uncommitted (and a re-run hits RESOURCE_ALREADY_EXISTS).
586
+ // Degrade to the same applied:false report the non-writable path uses.
587
+ try {
588
+ const sameSource = path.resolve(item.stashRoot) === path.resolve(source.path);
589
+ writeSupersededEdge(item.filePath, durableRef);
590
+ if (sameSource) {
591
+ recordWriteTargetPath(source, item.filePath);
592
+ }
593
+ }
594
+ catch (error) {
595
+ const reason = `demotion failed: ${error instanceof Error ? error.message : String(error)}`;
596
+ warn(`Warning: superseded asset ${item.ref} was NOT demoted (${reason}). ` +
597
+ "The correction was written and cites it in xrefs; demote the old asset manually or re-run the correction with --force.");
598
+ superseded.push({ ref: item.ref, applied: false, reason });
599
+ continue;
600
+ }
601
+ superseded.push({ ref: item.ref, applied: true });
602
+ const files = demotedByRoot.get(item.stashRoot) ?? [];
603
+ files.push(item.filePath);
604
+ demotedByRoot.set(item.stashRoot, files);
605
+ }
145
606
  // 0.9.0 (issue #507): single batch commit at the write boundary for git
146
607
  // targets. No-op for filesystem/primary-stash targets.
147
- commitWriteTargetBoundary(target, `Update ${formatRefForMessage(ref)}`);
608
+ commitWriteTargetBoundary(target, `Update ${formatRefForMessage(resolved.ref)}`);
148
609
  // Write-path indexing: the asset is searchable immediately. Fail-open; reads
149
- // no longer trigger reindexes, so keeping the index current is the writer's job.
150
- await indexWrittenAssets(source.path, [result.path]);
610
+ // no longer trigger reindexes, so keeping the index current is the writer's
611
+ // job. Demoted files reindex under their own containing root (usually the
612
+ // write target itself; the working stash when writing to a --target) so
613
+ // `--belief current` filtering and the beliefState ranking demotion take
614
+ // effect without waiting for the next full index.
615
+ const demotedInTargetRoot = demotedByRoot.get(source.path) ?? [];
616
+ demotedByRoot.delete(source.path);
617
+ await indexWrittenAssets(source.path, [result.path, ...demotedInTargetRoot], { bundleId: resolved.ref.origin });
618
+ const sourceEntries = resolveSourceEntries(undefined, cfg);
619
+ const sourceInstallations = deriveInstallations(sourceEntries);
620
+ for (const [root, files] of demotedByRoot) {
621
+ const sourceIndex = sourceEntries.findIndex((entry) => path.resolve(entry.path) === path.resolve(root));
622
+ await indexWrittenAssets(root, files, { bundleId: sourceInstallations[sourceIndex]?.id });
623
+ }
624
+ // Placement hint (stash-organization conventions): CLI writers never receive
625
+ // the resolveStashStandards prompt injection LLM flows get, so a type-root
626
+ // write into a stash that carries convention/meta facts points the writer at
627
+ // the placement conventions. Additive output key, advisory only — parallel
628
+ // to search's `tip`. Fail-open: the hint must never break a completed write.
629
+ let hint;
630
+ if (!subPath && !normalizedName.includes("/")) {
631
+ try {
632
+ if (resolveStashStandards(source.path).trim().length > 0) {
633
+ // Only point at the canonical organization fact when it actually
634
+ // exists — resolveStashStandards fires for ANY convention/meta fact,
635
+ // and a dead `akm show` pointer is worse than generic wording.
636
+ const orgFactPath = path.join(source.path, "facts", "conventions", "organization.md");
637
+ hint = fs.existsSync(orgFactPath)
638
+ ? `Wrote to the ${options.type} root. This stash has placement conventions — see \`akm show facts/conventions/organization\`.`
639
+ : `Wrote to the ${options.type} root. This stash has placement conventions — see the convention facts under its facts/ directory.`;
640
+ }
641
+ }
642
+ catch {
643
+ // Advisory only.
644
+ }
645
+ }
151
646
  return {
152
647
  ref: result.ref,
153
648
  path: result.path,
154
649
  stashDir: source.path,
650
+ ...(hint ? { hint } : {}),
651
+ ...(superseded.length > 0 ? { superseded } : {}),
155
652
  };
156
653
  }
@@ -4,7 +4,7 @@
4
4
  import { toErrorMessage } from "../../core/common.js";
5
5
  import { DEFAULT_CONFIG } from "../../core/config/config.js";
6
6
  import { warn } from "../../core/warn.js";
7
- import { resolveProviderFactory } from "../../registry/factory.js";
7
+ import { resolveRegistryProviderFactory } from "../../registry/factory.js";
8
8
  // ── Eagerly import providers to trigger self-registration ───────────────────
9
9
  import "../../registry/providers/index.js";
10
10
  // ── Public API ──────────────────────────────────────────────────────────────
@@ -142,7 +142,7 @@ export function resolveRegistries(configRegistries) {
142
142
  // ── Provider resolution ─────────────────────────────────────────────────────
143
143
  function createProvider(entry, warnings) {
144
144
  const providerType = entry.provider ?? "static-index";
145
- const factory = resolveProviderFactory(providerType);
145
+ const factory = resolveRegistryProviderFactory(providerType);
146
146
  if (!factory) {
147
147
  const label = entry.name ? `${entry.name} (${entry.url})` : entry.url;
148
148
  warnings.push(`Registry ${label}: unknown provider type "${providerType}"`);