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,7 +10,7 @@
10
10
  */
11
11
  import fs from "node:fs";
12
12
  import { parse as yamlParse, stringify as yamlStringify } from "yaml";
13
- import { assembleAsset } from "./asset-serialize.js";
13
+ import { assembleAsset, serializeFrontmatter } from "./asset-serialize.js";
14
14
  /**
15
15
  * Parse YAML frontmatter from a Markdown (or similar) string.
16
16
  *
@@ -51,15 +51,11 @@ export function parseFrontmatter(raw) {
51
51
  };
52
52
  }
53
53
  /**
54
- * Normalize YAML-parsed values to match expected AKM frontmatter types.
54
+ * Normalize YAML dates to match expected AKM frontmatter types.
55
55
  *
56
- * Two conversions:
57
- * 1. `Date` → YYYY-MM-DD string: the yaml "core" schema parses bare date
56
+ * `Date` → YYYY-MM-DD string: the yaml "core" schema parses bare date
58
57
  * scalars like `2026-06-18` as JS Date instances. AKM frontmatter treats
59
58
  * `updated:` and similar fields as plain strings.
60
- * 2. `null` → `""`: the yaml library parses empty-value keys (`key:` with no
61
- * value) as `null`, but AKM callers historically received `""` from the
62
- * hand-rolled parser. Convert to preserve backward compatibility.
63
59
  */
64
60
  function normalizeYamlValues(value) {
65
61
  if (value instanceof Date) {
@@ -68,11 +64,9 @@ function normalizeYamlValues(value) {
68
64
  const d = String(value.getUTCDate()).padStart(2, "0");
69
65
  return `${y}-${m}-${d}`;
70
66
  }
71
- if (value === null)
72
- return "";
73
67
  if (Array.isArray(value))
74
68
  return value.map(normalizeYamlValues);
75
- if (typeof value === "object") {
69
+ if (value !== null && typeof value === "object") {
76
70
  return Object.fromEntries(Object.entries(value).map(([k, v]) => [k, normalizeYamlValues(v)]));
77
71
  }
78
72
  return value;
@@ -118,15 +112,37 @@ function parseFrontmatterLenient(frontmatter) {
118
112
  * or `null` to skip the write entirely (e.g. for idempotent no-ops). The body
119
113
  * content is preserved from the parse.
120
114
  *
115
+ * A frontmatter mutation is a METADATA edit, not a content edit: when the file
116
+ * already has a frontmatter block, only that block is replaced and the body
117
+ * bytes are kept verbatim (routing through `assembleAsset` would strip the
118
+ * body's leading blank lines and force a trailing newline, silently reshaping
119
+ * assets whose writer used a different separator style). A file gaining its
120
+ * FIRST frontmatter block goes through the canonical `assembleAsset` shape.
121
+ *
121
122
  * @returns `true` if a write occurred, `false` if the mutator returned `null`.
122
123
  */
123
124
  export function mutateFrontmatter(filePath, mutator) {
124
125
  const raw = fs.readFileSync(filePath, "utf8");
125
126
  const parsed = parseFrontmatter(raw);
127
+ if (parsed.frontmatter?.trim()) {
128
+ let strict;
129
+ try {
130
+ strict = yamlParse(parsed.frontmatter);
131
+ }
132
+ catch {
133
+ throw new Error(`Cannot mutate malformed YAML frontmatter in ${filePath}.`);
134
+ }
135
+ if (strict === null || typeof strict !== "object" || Array.isArray(strict)) {
136
+ throw new Error(`Cannot mutate non-mapping YAML frontmatter in ${filePath}.`);
137
+ }
138
+ }
126
139
  const nextFrontmatter = mutator(parsed);
127
140
  if (nextFrontmatter === null)
128
141
  return false;
129
- fs.writeFileSync(filePath, assembleAsset(nextFrontmatter, parsed.content), "utf8");
142
+ const next = parsed.frontmatter !== null
143
+ ? `---\n${serializeFrontmatter(nextFrontmatter)}\n---\n${parsed.content}`
144
+ : assembleAsset(nextFrontmatter, parsed.content);
145
+ fs.writeFileSync(filePath, next, "utf8");
130
146
  return true;
131
147
  }
132
148
  export function parseFrontmatterBlock(raw) {
@@ -141,7 +157,7 @@ export function parseFrontmatterBlock(raw) {
141
157
  return {
142
158
  frontmatter,
143
159
  content,
144
- bodyStartLine: countLines(raw.slice(0, match[0].length - match[2].length)) + 1,
160
+ bodyStartLine: countLines(raw.slice(0, match[0].length - content.length)) + 1,
145
161
  };
146
162
  }
147
163
  // Empty frontmatter (---\n---): the content-bearing regex above requires at
@@ -2,6 +2,34 @@
2
2
  // License, v. 2.0. If a copy of the MPL was not distributed with this
3
3
  // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
4
  import { parseFrontmatter } from "./frontmatter.js";
5
+ /** Stable GitHub-style selector for a Markdown heading. */
6
+ export function markdownHeadingSlug(heading) {
7
+ return heading
8
+ .trim()
9
+ .toLowerCase()
10
+ .replace(/<[^>]*>/g, "")
11
+ .replace(/[^\p{L}\p{N}\s_-]+/gu, "-")
12
+ .replace(/[\s_]+/g, "-")
13
+ .replace(/-+/g, "-")
14
+ .replace(/^-|-$/g, "");
15
+ }
16
+ export function markdownFragmentSlugs(content) {
17
+ return uniqueHeadingSlugs(parseMarkdownToc(content).headings).filter(Boolean);
18
+ }
19
+ function uniqueHeadingSlugs(headings) {
20
+ const used = new Set();
21
+ return headings.map((heading) => {
22
+ const base = markdownHeadingSlug(heading.text);
23
+ if (!base)
24
+ return "";
25
+ let slug = base;
26
+ let suffix = 0;
27
+ while (used.has(slug))
28
+ slug = `${base}-${++suffix}`;
29
+ used.add(slug);
30
+ return slug;
31
+ });
32
+ }
5
33
  // ── Parsing ─────────────────────────────────────────────────────────────────
6
34
  export function parseMarkdownToc(content) {
7
35
  const lines = content.split(/\r?\n/);
@@ -31,61 +59,22 @@ export function parseMarkdownToc(content) {
31
59
  // ── Extraction ──────────────────────────────────────────────────────────────
32
60
  export function extractSection(content, heading) {
33
61
  const lines = content.split(/\r?\n/);
34
- const target = heading.toLowerCase();
35
- let startIdx = -1;
36
- let startLevel = 0;
37
- for (let i = 0; i < lines.length; i++) {
38
- const match = lines[i].match(/^(#{1,6})\s+(.+)$/);
39
- if (!match)
40
- continue;
41
- const text = match[2].replace(/\s+#+\s*$/, "").trim();
42
- if (text.toLowerCase() === target && startIdx === -1) {
43
- startIdx = i;
44
- startLevel = match[1].length;
45
- }
46
- else if (startIdx !== -1 && match[1].length <= startLevel) {
47
- return {
48
- content: lines.slice(startIdx, i).join("\n"),
49
- startLine: startIdx + 1,
50
- endLine: i,
51
- };
52
- }
53
- }
54
- if (startIdx === -1)
62
+ const headings = parseMarkdownToc(content).headings;
63
+ const fragment = heading.trim();
64
+ const slugIndex = uniqueHeadingSlugs(headings).indexOf(fragment);
65
+ const exact = slugIndex < 0 ? headings.find((candidate) => candidate.text.toLowerCase() === fragment.toLowerCase()) : undefined;
66
+ const selected = slugIndex >= 0 ? headings[slugIndex] : exact;
67
+ if (!selected)
55
68
  return null;
69
+ const next = headings.find((candidate) => candidate.line > selected.line && candidate.level <= selected.level);
70
+ const startIdx = selected.line - 1;
71
+ const endIdx = next ? next.line - 1 : lines.length;
56
72
  return {
57
- content: lines.slice(startIdx).join("\n"),
58
- startLine: startIdx + 1,
59
- endLine: lines.length,
73
+ content: lines.slice(startIdx, endIdx).join("\n"),
74
+ startLine: selected.line,
75
+ endLine: endIdx,
60
76
  };
61
77
  }
62
- export function extractLineRange(content, start, end) {
63
- const lines = content.split(/\r?\n/);
64
- if (end < start)
65
- return "";
66
- const s = Math.max(1, Math.min(start, lines.length));
67
- const e = Math.min(end, lines.length);
68
- return lines.slice(s - 1, e).join("\n");
69
- }
70
- export function extractFrontmatterOnly(content) {
71
- const parsed = parseFrontmatter(content);
72
- return parsed.frontmatter;
73
- }
74
- // ── Formatting ──────────────────────────────────────────────────────────────
75
- export function formatToc(toc) {
76
- if (toc.headings.length === 0) {
77
- return `(no headings found — ${toc.totalLines} lines total)`;
78
- }
79
- const lineWidth = String(toc.totalLines).length;
80
- const parts = toc.headings.map((h) => {
81
- const lineNum = `L${String(h.line).padStart(lineWidth)}`;
82
- const indent = " ".repeat(h.level - 1);
83
- const prefix = "#".repeat(h.level);
84
- return `${lineNum} ${indent}${prefix} ${h.text}`;
85
- });
86
- parts.push(`\n${toc.totalLines} lines total`);
87
- return parts.join("\n");
88
- }
89
78
  // ── Fence stripping ──────────────────────────────────────────────────────────
90
79
  /**
91
80
  * Best-effort fence stripping. Strips `<think>` reasoning blocks emitted by
@@ -0,0 +1,274 @@
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
+ * Ref RESOLUTION layer — akm 0.9.0 Chunk-5 flip, stage F1 (ref-grammar decision
6
+ * D-R1 / D-R4).
7
+ *
8
+ * The 0.9.0 ref abstraction is `parse → resolve → serialize`:
9
+ * - parse — `parseBundleRef` (`asset-ref.ts`), pure syntax, no I/O.
10
+ * - resolve — {@link resolveRef} (this module): turn a maybe-short
11
+ * {@link BundleRef} into a fully-qualified {@link ResolvedRef}
12
+ * against an injected {@link RefContext}. This is the "the short
13
+ * form is input sugar" rule (§11.1) made structural: only a
14
+ * `ResolvedRef` ever crosses a storage boundary.
15
+ * - serialize — `bundleRefToString` (`asset-ref.ts`); serializing a
16
+ * `ResolvedRef` always emits the fully-qualified form.
17
+ *
18
+ * ── Cycle-safety (HARD constraint) ──
19
+ *
20
+ * This is a PURE LEAF. It imports only sibling leaves (`asset-ref`,
21
+ * `asset-placement`) and the `core/errors` sink — nothing from the indexer-db
22
+ * SCC and no `Database`/config handle. The resolution surface is INJECTED via
23
+ * {@link RefContext}; callers build the context from their own db handle /
24
+ * installation list and hand it in. Keeping the resolver free of I/O is what
25
+ * lets it stay out of every import cycle.
26
+ *
27
+ * ── Input-boundary parser (new-grammar only) ──
28
+ *
29
+ * {@link parseRefInput} parses a RAW user/CLI/API ref in the 0.9.0
30
+ * `[bundle//]conceptId` grammar and returns an {@link AssetRef} value object via
31
+ * the permanent D-R2 reverse table {@link typeNameFromConceptId}. Post-Chunk-8
32
+ * every durable ref reaching a reader is already the new grammar, so this is the
33
+ * ONE ref parser outside the frozen migrator — there is no stored-ref dual
34
+ * grammar to bridge any more.
35
+ */
36
+ import { NotFoundError, UsageError } from "../errors.js";
37
+ import { placementSpecFor, stashDirFor, typeForStashDir } from "./asset-placement.js";
38
+ import { isBundleSlug, parseBundleRef } from "./asset-ref.js";
39
+ /**
40
+ * Resolve a maybe-short input ref to a fully-qualified {@link ResolvedRef}
41
+ * against `ctx`, implementing D-R4 exactly:
42
+ *
43
+ * 1. Already-qualified input (`bundle//…`) → that bundle (passthrough). When
44
+ * `ctx.only` is set and disagrees, that is a not-found (the ref names a
45
+ * bundle the caller scoped out).
46
+ * 2. Short input, `only` set → resolve to `only` iff it contains the concept.
47
+ * 3. Short input, no `only` → `defaultBundle` if it contains the concept,
48
+ * otherwise the FIRST bundle (priority order) that contains it.
49
+ * 4. No match → {@link NotFoundError} naming the forms tried.
50
+ *
51
+ * The `#fragment` is carried through untouched.
52
+ */
53
+ export function resolveRef(input, ctx) {
54
+ const ref = typeof input === "string" ? parseBundleRef(input) : input;
55
+ const { conceptId, fragment } = ref;
56
+ // 1. Qualified passthrough — an explicit bundle prefix wins.
57
+ if (ref.bundle !== undefined) {
58
+ if (ctx.only !== undefined && ref.bundle !== ctx.only) {
59
+ throw notFound(conceptId, [`${ref.bundle}//${conceptId}`], ctx);
60
+ }
61
+ return { bundle: ref.bundle, conceptId, fragment };
62
+ }
63
+ // `only` scoping restricts the candidate set to a single bundle.
64
+ const candidates = ctx.only !== undefined ? ctx.bundles.filter((b) => b.id === ctx.only) : ctx.bundles;
65
+ // 2/3. defaultBundle wins over priority order for a short ref (but only when
66
+ // not `only`-scoped; an `only` request never falls back to the default).
67
+ if (ctx.only === undefined && ctx.defaultBundle !== undefined) {
68
+ const def = ctx.bundles.find((b) => b.id === ctx.defaultBundle);
69
+ if (def?.hasConcept(conceptId))
70
+ return { bundle: def.id, conceptId, fragment };
71
+ }
72
+ // First candidate (priority order) that contains the concept.
73
+ for (const b of candidates) {
74
+ if (b.hasConcept(conceptId))
75
+ return { bundle: b.id, conceptId, fragment };
76
+ }
77
+ throw notFound(conceptId, [conceptId], ctx);
78
+ }
79
+ function notFound(conceptId, triedForms, ctx) {
80
+ const scope = ctx.only !== undefined ? ` in bundle "${ctx.only}"` : "";
81
+ const forms = triedForms.map((f) => `"${f}"`).join(", ");
82
+ return new NotFoundError(`No bundle contains concept "${conceptId}"${scope} (tried ${forms}).`, "ASSET_NOT_FOUND");
83
+ }
84
+ /**
85
+ * D-R2 conceptId derivation from an asset `type`/`name` pair
86
+ * (`stashDirFor(type)/name`; bare name for a foreign type with no placement
87
+ * stash-subdir). Kept self-contained so {@link displayRef} — a PERMANENT display
88
+ * rule remains independent of input parsing.
89
+ *
90
+ * Exported (Chunk-8 WI-8.5c) as the ONE conceptId derivation the improve
91
+ * correlation sites (`eligibility.ts` candidate refs, `salience.ts`
92
+ * last-use lookup, `collapse-detector.ts` canary mint/score) share with the
93
+ * display rule — the permanent successor to the retired transient
94
+ * `legacyConceptId`.
95
+ */
96
+ export function conceptIdFromTypeName(type, name) {
97
+ const stashDir = stashDirFor(type);
98
+ return stashDir !== undefined ? `${stashDir}/${name}` : name;
99
+ }
100
+ /**
101
+ * Build the USER-FACING / envelope ref string for an indexed item, applying the
102
+ * Chunk-5 flip F4b output-spelling rule (orchestrator decision; ref-grammar
103
+ * decision D-R2 / D-R3). This is the ONE place the rule lives — every emission
104
+ * site calls it instead of hand-building a ref from an entry.
105
+ *
106
+ * The rule mirrors TODAY'S origin-qualification UX, transposed to the 0.9.0
107
+ * grammar:
108
+ *
109
+ * - An item in the **default/primary bundle** (`bundleId` undefined, or equal
110
+ * to `defaultBundleId`) emits the SHORT conceptId (`knowledge/http-caching`)
111
+ * — exactly where the pre-0.9.0 output emitted an un-qualified `type:name`.
112
+ * - Any other **non-default bundle** emits the fully-qualified
113
+ * `bundle//conceptId`. Post-Chunk-8 every bundle id is a legal slug (the
114
+ * config migration assigned each source its D-R5 slug bundle key), so this
115
+ * is always the new grammar — a non-slug registryId now displays under its
116
+ * derived slug bundle id, never the retired `origin//type:name` spelling.
117
+ */
118
+ export function displayRef(item, defaultBundleId) {
119
+ const conceptId = item.conceptId ?? conceptIdFromTypeName(item.type, item.name);
120
+ const { bundleId } = item;
121
+ // Default/primary bundle → SHORT conceptId (the flip).
122
+ if (bundleId === undefined || bundleId === defaultBundleId)
123
+ return conceptId;
124
+ // Non-default bundle → the new fully-qualified `bundle//conceptId` grammar.
125
+ return `${bundleId}//${conceptId}`;
126
+ }
127
+ /**
128
+ * Split a qualified conceptId (`<stash-subdir>/<name>`) into its asset
129
+ * `type`/`name`, or `undefined` when the leading segment is not a known stash
130
+ * subdir (a bare-name conceptId from a foreign type — no legacy predicate
131
+ * applies). The PERMANENT D-R2 reverse table: the input boundary uses it to map
132
+ * a new-grammar conceptId onto today's {@link AssetRef} shape. (The migrate home
133
+ * keeps a private transient copy for stored-ref parsing.)
134
+ */
135
+ export function typeNameFromConceptId(conceptId) {
136
+ const slash = conceptId.indexOf("/");
137
+ if (slash <= 0)
138
+ return undefined;
139
+ const type = typeForStashDir(conceptId.slice(0, slash));
140
+ if (type === undefined)
141
+ return undefined;
142
+ return { type, name: conceptId.slice(slash + 1) };
143
+ }
144
+ /**
145
+ * D11 — the opaque-adapter-conceptId fallback. `typeNameFromConceptId` only
146
+ * ever answers for the PLACEMENT_SPECS stash-resident subset (D-R2); a
147
+ * conceptId whose leading segment is NOT a registered placement stashDir is
148
+ * still perfectly legal DATA per D11 — an OKF item (`tables/customers`), a
149
+ * website page, a wiki pageKind, an adapter `instruction` doc, … — and the
150
+ * ref-consuming commands must accept it rather than treat "not an AKM
151
+ * placement dir" as "malformed ref". This function draws the line: it accepts
152
+ * any well-formed `<segment>/<rest>` conceptId (so the shape is still
153
+ * anchored — a bare no-slash name stays the caller's job to pre-qualify with a
154
+ * default type, the existing env/secret/`akm mv` "bare name" convenience), and
155
+ * REJECTS anything shaped like the retired `type:name` colon grammar (Q-02):
156
+ * a `:` in the leading segment is that grammar smuggled through a conceptId
157
+ * string (e.g. `script:db/migrate/run.sh`, `workflow:release/train`), not a
158
+ * real adapter directory name, so it is refused rather than silently
159
+ * reinterpreted as opaque data.
160
+ *
161
+ * `name` deliberately carries the FULL original conceptId, not just the tail.
162
+ * This is what makes the pair round-trip through the UNCHANGED
163
+ * {@link conceptIdFromTypeName} (`stashDirFor(type)/name`, bare `name` when
164
+ * `type` has no placement stashDir): since an opaque `type` never owns a
165
+ * placement stashDir, `conceptIdFromTypeName(type, name)` falls to its bare-
166
+ * `name` branch and returns `name` verbatim — the original conceptId,
167
+ * unchanged — instead of losing the leading segment. `type` itself carries
168
+ * the leading segment (informational/behavioral use: `.type === "lesson"`
169
+ * checks correctly miss for opaque data) UNLESS that segment happens to
170
+ * collide with a real PLACEMENT_SPECS type key that merely uses a different
171
+ * stashDir spelling (e.g. a foreign top-level dir literally named "skill",
172
+ * singular) — that pathological case would make `stashDirFor` succeed on the
173
+ * "type" and corrupt the round-trip, so it falls back to the full conceptId as
174
+ * `type` too (never a placement key, since a placement key never contains
175
+ * `/`).
176
+ *
177
+ * This intentionally does NOT collapse the KNOWN_TYPES/PLACEMENT_SPECS split:
178
+ * `typeNameFromConceptId` (PLACEMENT_SPECS only) is untouched, and an opaque
179
+ * `type` returned here is never a {@link KnownType} — it is a passthrough
180
+ * label, not a claim that AKM recognizes or owns the concept.
181
+ */
182
+ function opaqueRefParts(conceptId, allowRoot = false) {
183
+ const slash = conceptId.indexOf("/");
184
+ if (slash <= 0)
185
+ return allowRoot && !conceptId.includes(":") ? { type: conceptId, name: conceptId } : undefined;
186
+ const segment = conceptId.slice(0, slash);
187
+ if (segment.includes(":"))
188
+ return undefined; // retired `type:name` grammar, not opaque data (Q-02).
189
+ const type = placementSpecFor(segment) === undefined ? segment : conceptId;
190
+ return { type, name: conceptId };
191
+ }
192
+ /**
193
+ * Parse a RAW user / CLI / API ref string in the 0.9.0 `[bundle//]conceptId`
194
+ * grammar, returning it in today's {@link AssetRef} value-object shape
195
+ * (ref-grammar decision D-R1 / D-R4). All boundaries are NEW-GRAMMAR ONLY: a
196
+ * legacy `type:name` input now fails as an unknown-conceptId not-found. Post-
197
+ * Chunk-8 every durable ref is already the new grammar, so this parser also
198
+ * serves the (formerly dual-grammar) stored-ref readers.
199
+ *
200
+ * Mapping (new grammar → {@link AssetRef}):
201
+ * - `conceptId` → `type`/`name` via {@link typeNameFromConceptId} (the D-R2
202
+ * static stash-subdir table) when the leading segment is a known AKM
203
+ * placement stashDir, else via {@link opaqueRefParts} (D11 — the ref-parser
204
+ * seam accepts opaque adapter conceptIds, e.g. OKF items, website pages,
205
+ * wiki pageKinds, adapter `instruction` docs) when it is merely a well-
206
+ * formed but foreign `<segment>/<rest>` shape. A conceptId that is neither
207
+ * — no slash at all, or a retired colon-grammar shape smuggled through —
208
+ * has no type predicate: the same not-found outcome a genuine typo
209
+ * produces today.
210
+ * - `bundle` → `origin`. A new-grammar bundle slug is a registryId-shaped
211
+ * id by construction, so it flows straight into the legacy origin channel
212
+ * that `resolveSourcesForOrigin` matches on `registryId`. The SHORT form (no
213
+ * bundle) leaves `origin` undefined = search-all-sources.
214
+ * - `#fragment` → rejected. No input boundary consumes an export fragment.
215
+ */
216
+ export function parseRefInput(raw) {
217
+ const ref = parseBundleRef(raw);
218
+ if (ref.fragment !== undefined) {
219
+ throw new UsageError(`Export fragment "#${ref.fragment}" is not accepted here — drop it from "${raw.trim()}".`, "INVALID_FLAG_VALUE");
220
+ }
221
+ const parts = typeNameFromConceptId(ref.conceptId) ?? opaqueRefParts(ref.conceptId, ref.bundle !== undefined);
222
+ if (parts === undefined) {
223
+ throw new NotFoundError(`Unrecognized asset ref "${raw.trim()}": conceptId "${ref.conceptId}" has no known asset-type prefix.`, "ASSET_NOT_FOUND");
224
+ }
225
+ return { type: parts.type, name: parts.name, origin: ref.bundle };
226
+ }
227
+ /**
228
+ * Parse a CLI/API ref that MAY be qualified by a NON-slug origin — a registry
229
+ * ref (`github:owner/repo`, `npm:@scope/pkg`, `git:host/path`), a bare path, or
230
+ * a URL — as its `origin//conceptId` prefix. Such an origin carries `:`/`.`/`/`
231
+ * so it is not a legal bundle slug and the strict {@link parseRefInput} rejects
232
+ * it; but it is still a valid SOURCE origin that `resolveSourcesForOrigin`
233
+ * matches by registry-id / path and the remote-fetch fallback can install. The
234
+ * conceptId body is parsed under the strict new grammar; the raw origin is kept
235
+ * as-is — the symmetric input side of {@link displayRef}, which likewise keeps
236
+ * `origin//…` for exactly these non-slug origins (ref-grammar decision D-R5).
237
+ *
238
+ * A short ref (no origin) or a slug-origin ref is delegated verbatim to
239
+ * {@link parseRefInput}, so this is a safe superset for origin-accepting
240
+ * commands (`show`, `clone`, `graph`, `history`).
241
+ */
242
+ export function parseQualifiedRefInput(raw) {
243
+ const trimmed = raw.trim();
244
+ const boundary = trimmed.indexOf("//");
245
+ if (boundary > 0) {
246
+ const origin = trimmed.slice(0, boundary);
247
+ if (!isBundleSlug(origin)) {
248
+ return { ...parseRefInput(trimmed.slice(boundary + 2)), origin };
249
+ }
250
+ }
251
+ return parseRefInput(trimmed);
252
+ }
253
+ /**
254
+ * Does `raw` already read as a COMPLETE new-grammar asset ref, as opposed to a
255
+ * bare asset name that a boundary would prefix with a default type (the
256
+ * `env`/`secret`/`akm mv` "bare name" convenience)?
257
+ *
258
+ * True when `raw` is a `[bundle//]conceptId` whose conceptId leads with a KNOWN
259
+ * stash subdir ({@link typeNameFromConceptId} resolves it). A bare name like
260
+ * `prod` or `projectA/new-note` is neither — its leading segment maps to no
261
+ * type — so it stays a bare name for the caller to qualify.
262
+ */
263
+ export function isFullRefInput(raw) {
264
+ const trimmed = raw.trim();
265
+ if (!trimmed)
266
+ return false;
267
+ try {
268
+ const parsed = parseBundleRef(trimmed);
269
+ return parsed.bundle !== undefined || typeNameFromConceptId(parsed.conceptId) !== undefined;
270
+ }
271
+ catch {
272
+ return false;
273
+ }
274
+ }
@@ -7,7 +7,7 @@
7
7
  * A stash may carry an optional, human-authored `.meta/` directory at its
8
8
  * root holding orientation docs for the stash as a whole: purpose, key
9
9
  * assets, conventions, maintainer info. Because `.meta/` is a dot-directory,
10
- * the indexer's walker already skips it (see `src/indexer/walker.ts`), so
10
+ * the indexer's walker already skips it (see `src/indexer/walk/walker.ts`), so
11
11
  * these files never pollute the search corpus. They are surfaced on demand
12
12
  * via `akm show [<origin>//]meta[:<name>]`, which direct-reads the file
13
13
  * rather than going through the index.
@@ -54,7 +54,7 @@ export function parseMetaRef(ref) {
54
54
  }
55
55
  /**
56
56
  * Reject meta names that would escape the `.meta/` directory. Mirrors the
57
- * traversal guards in `parseAssetRef`'s `validateName`.
57
+ * traversal guards in the ref parser's `validateName`.
58
58
  */
59
59
  function assertSafeMetaName(name) {
60
60
  if (name.includes("\0")) {
@@ -0,0 +1,51 @@
1
+ // This Source Code Form is subject to the terms of the Mozilla Public
2
+ // License, v. 2.0. If a copy of the MPL was not distributed with this
3
+ // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
+ import crypto from "node:crypto";
5
+ import path from "node:path";
6
+ import { isBundleSlug } from "./asset/asset-ref.js";
7
+ /** Deterministic, filesystem-safe bundle slug from a source path. */
8
+ export function slugForPath(sourcePath) {
9
+ const resolved = path.resolve(sourcePath);
10
+ const base = path
11
+ .basename(resolved)
12
+ .toLowerCase()
13
+ .replace(/[^a-z0-9]+/g, "-")
14
+ .replace(/^-+|-+$/g, "");
15
+ if (base.length > 0)
16
+ return base;
17
+ return `bundle-${shortHash(resolved)}`;
18
+ }
19
+ /** Derive one batch-unique bundle id. */
20
+ export function deriveBundleId(registryId, sourcePath, usedIds) {
21
+ const preferred = registryId && registryId.length > 0 && isBundleSlug(registryId) ? registryId : slugForPath(sourcePath);
22
+ const id = ensureUniqueId(preferred, sourcePath, usedIds);
23
+ usedIds.add(id);
24
+ return id;
25
+ }
26
+ /** Derive an ordered batch while reserving every explicit configured bundle id. */
27
+ export function deriveBundleIds(sources) {
28
+ const usedIds = new Set();
29
+ const reservedIds = new Set(sources.flatMap((source) => (source.registryId && isBundleSlug(source.registryId) ? [source.registryId] : [])));
30
+ return sources.map((source) => {
31
+ const id = source.registryId && isBundleSlug(source.registryId)
32
+ ? deriveBundleId(source.registryId, source.path, usedIds)
33
+ : deriveBundleId(undefined, source.path, new Set([...usedIds, ...reservedIds]));
34
+ usedIds.add(id);
35
+ return id;
36
+ });
37
+ }
38
+ function ensureUniqueId(preferred, sourcePath, used) {
39
+ if (!used.has(preferred))
40
+ return preferred;
41
+ const suffixed = `${preferred}-${shortHash(path.resolve(sourcePath))}`;
42
+ if (!used.has(suffixed))
43
+ return suffixed;
44
+ let n = 2;
45
+ while (used.has(`${suffixed}-${n}`))
46
+ n++;
47
+ return `${suffixed}-${n}`;
48
+ }
49
+ function shortHash(input) {
50
+ return crypto.createHash("sha256").update(input).digest("hex").slice(0, 8);
51
+ }