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
@@ -116,12 +116,15 @@ export function renderMigrationHelp(versionInput, changelogText = loadChangelog(
116
116
  if (changelogText) {
117
117
  for (const candidate of candidates) {
118
118
  const section = extractChangelogSection(changelogText, candidate);
119
- if (section) {
120
- const bundled = loadReleaseNote(candidate);
121
- if (!bundled)
122
- return `${section.trim()}\n\nFull changelog: ${CHANGELOG_URL}\n`;
119
+ const bundled = loadReleaseNote(candidate);
120
+ if (bundled) {
121
+ if (!section)
122
+ return `${bundled.trim()}\n\nFull changelog: ${CHANGELOG_URL}\n`;
123
123
  return `${bundled.trim()}\n\nRelease notes\n-------------\n${section.trim()}\n\nFull changelog: ${CHANGELOG_URL}\n`;
124
124
  }
125
+ if (section) {
126
+ return `${section.trim()}\n\nFull changelog: ${CHANGELOG_URL}\n`;
127
+ }
125
128
  }
126
129
  }
127
130
  const fallbackVersion = candidates.find((candidate) => candidate !== "latest") ?? requested;
@@ -14,15 +14,16 @@
14
14
  */
15
15
  import fs from "node:fs";
16
16
  import path from "node:path";
17
- import { parseAssetRef } from "../../core/asset/asset-ref.js";
18
17
  import { assembleAsset } from "../../core/asset/asset-serialize.js";
19
18
  import { parseFrontmatter } from "../../core/asset/frontmatter.js";
19
+ import { parseRefInput } from "../../core/asset/resolve-ref.js";
20
20
  import { authoringRulesForType } from "../../core/authoring-rules.js";
21
21
  import { appendEvent, readEvents } from "../../core/events.js";
22
+ import { parseEmbeddedJsonResponse } from "../../core/parse.js";
22
23
  import { resolveStandardsContext } from "../../core/standards/resolve-standards-context.js";
23
24
  import { info } from "../../core/warn.js";
24
25
  import { resolveAssetPath } from "../../indexer/walk/path-resolver.js";
25
- import { chatCompletion, parseEmbeddedJsonResponse } from "../../llm/client.js";
26
+ import { chatCompletion } from "../../llm/client.js";
26
27
  import { createProposal, isProposalSkipped } from "../proposal/repository.js";
27
28
  // ── Constants ────────────────────────────────────────────────────────────────
28
29
  /** Minimum gap between schema-repair attempts on the same asset. */
@@ -39,8 +40,8 @@ const SCHEMA_REPAIR_WINDOW_MS = 30 * 24 * 60 * 60 * 1000; // 30 days
39
40
  // ── Main ─────────────────────────────────────────────────────────────────────
40
41
  /**
41
42
  * Run the schema-repair loop for a batch of validation failures.
42
- * Returns a list of per-asset outcome records and the set of refs that were
43
- * successfully repaired (so the caller can exclude them from skip logic).
43
+ * Returns a list of per-asset outcome records and the set of refs whose live
44
+ * files were repaired. Queued proposals never count as live repairs.
44
45
  */
45
46
  export async function runSchemaRepairPass(failures, options) {
46
47
  const repairs = [];
@@ -55,7 +56,7 @@ export async function runSchemaRepairPass(failures, options) {
55
56
  // Cooldown: skip repair if we ran it successfully recently.
56
57
  const recentRepairs = readEvents({ type: "schema_repair_invoked", ref: failure.ref });
57
58
  const lastRepair = recentRepairs.events
58
- .filter((e) => e.metadata?.outcome === "written")
59
+ .filter((e) => e.metadata?.outcome === "queued")
59
60
  .sort((a, b) => new Date(b.ts ?? 0).getTime() - new Date(a.ts ?? 0).getTime())[0];
60
61
  if (lastRepair?.ts && Date.now() - new Date(lastRepair.ts).getTime() < SCHEMA_REPAIR_COOLDOWN_MS) {
61
62
  repairs.push({ ref: failure.ref, reason: failure.reason, outcome: "skipped" });
@@ -106,7 +107,7 @@ export async function runSchemaRepairPass(failures, options) {
106
107
  const standardsSection = standardsContext.trim()
107
108
  ? `\n\nStandards to follow (the rulebook for this target):\n${standardsContext.trim()}`
108
109
  : "";
109
- const assetType = parseAssetRef(failure.ref).type;
110
+ const assetType = parseRefInput(failure.ref).type;
110
111
  const authoringRules = authoringRulesForType(assetType);
111
112
  const authoringRulesSection = authoringRules ? `\n\n${authoringRules}` : "";
112
113
  const llmResponse = await chatFn(llmConfig, [
@@ -145,6 +146,8 @@ export async function runSchemaRepairPass(failures, options) {
145
146
  const proposalResult = createProposal(stashDir, {
146
147
  ref: failure.ref,
147
148
  source: "schema-repair",
149
+ // §23.6 fingerprint model-id term (WI-6.4).
150
+ modelId: llmConfig.model,
148
151
  payload: {
149
152
  content: newContent,
150
153
  ...(Object.keys(newFm).length > 0 ? { frontmatter: newFm } : {}),
@@ -167,8 +170,6 @@ export async function runSchemaRepairPass(failures, options) {
167
170
  outcome: "queued",
168
171
  proposalId: proposalResult.id,
169
172
  });
170
- // Mark as repaired so the caller removes it from the validation-failure set.
171
- repairedRefs.add(failure.ref);
172
173
  }
173
174
  catch (e) {
174
175
  appendEvent({
@@ -184,7 +185,7 @@ export async function runSchemaRepairPass(failures, options) {
184
185
  // ── Default seam implementations ─────────────────────────────────────────────
185
186
  function defaultIsLessonCandidate(ref) {
186
187
  try {
187
- const parsed = parseAssetRef(ref);
188
+ const parsed = parseRefInput(ref);
188
189
  return parsed.type === "lesson";
189
190
  }
190
191
  catch {
@@ -5,7 +5,8 @@ import * as childProcess from "node:child_process";
5
5
  import { createHash } from "node:crypto";
6
6
  import fs from "node:fs";
7
7
  import path from "node:path";
8
- import { fetchWithRetry, IS_WINDOWS } from "../../core/common.js";
8
+ import { fetchWithRetry, IS_WINDOWS, ResponseTooLargeError, readBodyWithByteCap } from "../../core/common.js";
9
+ import { ConfigError } from "../../core/errors.js";
9
10
  import { warn } from "../../core/warn.js";
10
11
  import { githubHeaders } from "../../integrations/github.js";
11
12
  import { getDirname, mainPath, semverOrder } from "../../runtime.js";
@@ -14,6 +15,64 @@ const DEFAULT_PACKAGE_NAME = "akm-cli";
14
15
  const NODE_MODULES_SEGMENT = "/node_modules/";
15
16
  const BUN_GLOBAL_INSTALL_PATTERN = /(^|\/)\.bun\/(?:[^/]+\/)+node_modules\//;
16
17
  const PNPM_GLOBAL_INSTALL_PATTERN = /(^|\/)(?:pnpm\/global|\.pnpm-global)(?:\/\d+)?\/node_modules\//;
18
+ const MIGRATION_CONTRACT_VERSION = "0.9.0-rc.0";
19
+ const MIGRATION_CONTRACT_BLOCKED_MESSAGE = "AKM 0.8 does not implement the migrate command or the --migration-config upgrade contract, so self-update cannot safely cross into 0.9. " +
20
+ "Prepare the 0.9 config and an independent backup, install or stage the 0.9 binary manually, then use the new binary to run: " +
21
+ "akm migrate apply --config <prepared-0.9.json>. See docs/migration/v0.8-to-v0.9.md.";
22
+ const MAX_BINARY_DOWNLOAD_BYTES = 256 * 1024 * 1024;
23
+ const MAX_CHECKSUM_METADATA_BYTES = 1024 * 1024;
24
+ export function defaultMigrationCommand(preparedConfigPath) {
25
+ const configArgs = preparedConfigPath ? ["--config", preparedConfigPath] : [];
26
+ return {
27
+ preflight: (akmBin) => runRequiredCommand(akmBin, ["migrate", "status"], "Migration preflight"),
28
+ stagedPreflight: (akmBin) => runRequiredCommand(akmBin, ["migrate", "status", ...configArgs], "Staged migration preflight"),
29
+ apply: (akmBin) => runRequiredCommand(akmBin, ["migrate", "apply", ...configArgs], "Migration apply"),
30
+ };
31
+ }
32
+ async function streamResponseToFile(response, destination, maxBytes) {
33
+ const declaredText = response.headers.get("content-length");
34
+ if (declaredText) {
35
+ const declared = Number(declaredText);
36
+ if (Number.isFinite(declared) && declared > maxBytes) {
37
+ await response.body?.cancel().catch(() => undefined);
38
+ throw new ResponseTooLargeError(response.url || "binary download", maxBytes, declared);
39
+ }
40
+ }
41
+ if (!response.body)
42
+ throw new Error("Binary download response did not provide a streaming body.");
43
+ const fd = fs.openSync(destination, "w", 0o600);
44
+ const reader = response.body.getReader();
45
+ const hash = createHash("sha256");
46
+ let byteSize = 0;
47
+ try {
48
+ while (true) {
49
+ const { done, value } = await reader.read();
50
+ if (done)
51
+ break;
52
+ if (!value)
53
+ continue;
54
+ byteSize += value.byteLength;
55
+ if (byteSize > maxBytes) {
56
+ await reader.cancel().catch(() => undefined);
57
+ throw new ResponseTooLargeError(response.url || "binary download", maxBytes, byteSize);
58
+ }
59
+ hash.update(value);
60
+ let written = 0;
61
+ while (written < value.byteLength)
62
+ written += fs.writeSync(fd, value, written, value.byteLength - written);
63
+ }
64
+ fs.fdatasyncSync(fd);
65
+ return { byteSize, sha256: hash.digest("hex") };
66
+ }
67
+ catch (error) {
68
+ removeFileBestEffort(destination);
69
+ throw error;
70
+ }
71
+ finally {
72
+ reader.releaseLock();
73
+ fs.closeSync(fd);
74
+ }
75
+ }
17
76
  /** Read live runtime signals. */
18
77
  export function getInstallSignals() {
19
78
  return {
@@ -63,7 +122,7 @@ export function getAkmBinaryName() {
63
122
  return "akm-darwin-arm64";
64
123
  if (platform === "win32" && arch === "x64")
65
124
  return "akm-windows-x64.exe";
66
- throw new Error(`Unsupported platform for binary upgrade: ${platform}/${arch}`);
125
+ throw new ConfigError(`Unsupported platform for binary upgrade: ${platform}/${arch}`, "UNSUPPORTED_PLATFORM");
67
126
  }
68
127
  export async function checkForUpdate(currentVersion) {
69
128
  const installMethod = detectInstallMethod();
@@ -72,7 +131,7 @@ export async function checkForUpdate(currentVersion) {
72
131
  if (!response.ok) {
73
132
  throw new Error(`Failed to check for updates: ${response.status} ${response.statusText}`);
74
133
  }
75
- const release = (await response.json());
134
+ const release = JSON.parse(await readBodyWithByteCap(response, MAX_CHECKSUM_METADATA_BYTES));
76
135
  const latestTag = release.tag_name ?? "";
77
136
  const latestVersion = latestTag.replace(/^v/, "");
78
137
  return {
@@ -82,10 +141,26 @@ export async function checkForUpdate(currentVersion) {
82
141
  installMethod,
83
142
  };
84
143
  }
85
- export async function performUpgrade(check, opts) {
144
+ /**
145
+ * Whether the operator has asked to bypass upgrade checksum verification.
146
+ *
147
+ * Deliberately NOT a CLI flag (C6): STABILITY.md states checksum verification
148
+ * is not optional, so the recovery hatch for a genuinely broken `checksums.txt`
149
+ * is this internal, undocumented-on-purpose env var — not something
150
+ * discoverable in `--help` or offered by tab completion.
151
+ *
152
+ * Extracted rather than read inline so `performUpgrade` stays under the
153
+ * function-size bar (`scripts/lint-src-fn-size.ts`), whose baseline only
154
+ * shrinks.
155
+ */
156
+ function checksumBypassRequested() {
157
+ return process.env.AKM_UPGRADE_SKIP_CHECKSUM === "1";
158
+ }
159
+ export async function performUpgrade(check, opts, dependencies) {
86
160
  const { currentVersion, latestVersion, installMethod } = check;
87
161
  const force = opts?.force === true;
88
162
  const skipPostUpgrade = opts?.skipPostUpgrade === true;
163
+ const migration = dependencies?.migration ?? defaultMigrationCommand(opts?.migrationConfig);
89
164
  // All install methods can short-circuit here unless the user explicitly forces an upgrade.
90
165
  if (!check.updateAvailable && !force) {
91
166
  return {
@@ -96,11 +171,17 @@ export async function performUpgrade(check, opts) {
96
171
  message: `akm v${currentVersion} is already the latest version`,
97
172
  };
98
173
  }
174
+ if (latestVersion &&
175
+ semverOrder(currentVersion, MIGRATION_CONTRACT_VERSION) < 0 &&
176
+ semverOrder(latestVersion, MIGRATION_CONTRACT_VERSION) >= 0) {
177
+ throw new ConfigError(MIGRATION_CONTRACT_BLOCKED_MESSAGE, "UPGRADE_BLOCKED");
178
+ }
99
179
  const packageManagerCommand = getPackageManagerUpgradeCommand(installMethod);
100
180
  if (packageManagerCommand) {
101
181
  if (!latestVersion) {
102
182
  throw new Error("Unable to determine latest version from GitHub releases. Check https://github.com/itlackey/akm/releases");
103
183
  }
184
+ migration.preflight("akm");
104
185
  const result = childProcess.spawnSync(packageManagerCommand.command, packageManagerCommand.args, {
105
186
  encoding: "utf8",
106
187
  env: process.env,
@@ -113,6 +194,7 @@ export async function performUpgrade(check, opts) {
113
194
  const details = (result.stderr ?? "").trim() || (result.stdout ?? "").trim() || `exit code ${result.status}`;
114
195
  throw new Error(`Failed to upgrade akm via ${installMethod}: ${details}\nRun manually: ${packageManagerCommand.displayCommand}`);
115
196
  }
197
+ migration.apply("akm");
116
198
  return {
117
199
  currentVersion,
118
200
  newVersion: latestVersion,
@@ -139,31 +221,53 @@ export async function performUpgrade(check, opts) {
139
221
  const binaryName = getAkmBinaryName();
140
222
  const binaryUrl = `https://github.com/${REPO}/releases/download/${tag}/${binaryName}`;
141
223
  const checksumsUrl = `https://github.com/${REPO}/releases/download/${tag}/checksums.txt`;
224
+ const execPath = dependencies?.execPath ?? process.execPath;
225
+ const execDir = path.dirname(execPath);
226
+ const execName = path.basename(execPath);
227
+ const stagedPath = IS_WINDOWS
228
+ ? path.join(execDir, `.${execName}.new.${process.pid}`)
229
+ : path.join(execDir, `.${execName}.tmp.${process.pid}`);
230
+ const backupPath = `${execPath}${IS_WINDOWS ? ".old" : ".bak"}`;
142
231
  // Download binary
143
232
  const binaryResponse = await fetchWithRetry(binaryUrl);
144
233
  if (!binaryResponse.ok) {
145
234
  throw new Error(`Failed to download binary: ${binaryResponse.status} ${binaryResponse.statusText}`);
146
235
  }
147
- const binaryData = new Uint8Array(await binaryResponse.arrayBuffer());
148
- // Download and verify checksum (mandatory — upgrade is blocked if checksums cannot be fetched)
236
+ let downloaded;
237
+ try {
238
+ downloaded = await streamResponseToFile(binaryResponse, stagedPath, MAX_BINARY_DOWNLOAD_BYTES);
239
+ if (!IS_WINDOWS)
240
+ fs.chmodSync(stagedPath, 0o755);
241
+ }
242
+ catch (err) {
243
+ removeFileBestEffort(stagedPath);
244
+ const code = err.code;
245
+ if (code === "EACCES" || code === "EPERM") {
246
+ throw new ConfigError(`Permission denied writing to ${execDir}.\n` +
247
+ `${IS_WINDOWS ? "Try running as Administrator." : "Run: sudo akm upgrade"}\n` +
248
+ `Or re-run the install script: curl -fsSL https://raw.githubusercontent.com/${REPO}/main/install.sh | bash`, "UPGRADE_BLOCKED");
249
+ }
250
+ throw err;
251
+ }
252
+ // Download and verify checksum (mandatory — upgrade is blocked if checksums cannot be fetched).
149
253
  let checksumVerified = false;
150
- const skipChecksum = opts?.skipChecksum === true;
254
+ const skipChecksum = checksumBypassRequested();
151
255
  try {
152
256
  const checksumsResponse = await fetchWithRetry(checksumsUrl);
153
257
  if (!checksumsResponse.ok) {
154
258
  if (skipChecksum) {
155
- warn(`WARNING: checksums.txt fetch failed (HTTP ${checksumsResponse.status}). Proceeding without verification because --skip-checksum was provided.`);
259
+ warn(`WARNING: checksums.txt fetch failed (HTTP ${checksumsResponse.status}). Proceeding without verification because AKM_UPGRADE_SKIP_CHECKSUM=1 was set.`);
156
260
  }
157
261
  else {
158
262
  throw new Error(`Checksum verification failed: could not fetch ${checksumsUrl} (HTTP ${checksumsResponse.status}). ` +
159
- `Use --skip-checksum to bypass (not recommended).`);
263
+ `Set AKM_UPGRADE_SKIP_CHECKSUM=1 to bypass (not recommended).`);
160
264
  }
161
265
  }
162
266
  else {
163
- const checksumsText = await checksumsResponse.text();
267
+ const checksumsText = await readBodyWithByteCap(checksumsResponse, MAX_CHECKSUM_METADATA_BYTES);
164
268
  const expectedHash = parseChecksumForFile(checksumsText, binaryName);
165
269
  if (expectedHash) {
166
- const actualHash = createHash("sha256").update(binaryData).digest("hex");
270
+ const actualHash = downloaded.sha256;
167
271
  if (actualHash !== expectedHash) {
168
272
  throw new Error(`Checksum mismatch for ${binaryName}.\n` + `Expected: ${expectedHash}\n` + `Got: ${actualHash}`);
169
273
  }
@@ -171,11 +275,11 @@ export async function performUpgrade(check, opts) {
171
275
  }
172
276
  else {
173
277
  if (skipChecksum) {
174
- warn(`WARNING: ${binaryName} not found in checksums.txt. Proceeding without verification because --skip-checksum was provided.`);
278
+ warn(`WARNING: ${binaryName} not found in checksums.txt. Proceeding without verification because AKM_UPGRADE_SKIP_CHECKSUM=1 was set.`);
175
279
  }
176
280
  else {
177
281
  throw new Error(`Checksum verification failed: ${binaryName} not listed in checksums.txt. ` +
178
- `Use --skip-checksum to bypass (not recommended).`);
282
+ `Set AKM_UPGRADE_SKIP_CHECKSUM=1 to bypass (not recommended).`);
179
283
  }
180
284
  }
181
285
  }
@@ -183,106 +287,54 @@ export async function performUpgrade(check, opts) {
183
287
  catch (err) {
184
288
  if (err instanceof Error &&
185
289
  (err.message.includes("Checksum mismatch") || err.message.includes("Checksum verification failed"))) {
290
+ removeFileBestEffort(stagedPath);
186
291
  throw err;
187
292
  }
188
293
  // Network or parse failure
189
294
  if (skipChecksum) {
190
- warn(`WARNING: Could not fetch or parse checksums: ${err instanceof Error ? err.message : String(err)}. Proceeding because --skip-checksum was provided.`);
295
+ warn(`WARNING: Could not fetch or parse checksums: ${err instanceof Error ? err.message : String(err)}. Proceeding because AKM_UPGRADE_SKIP_CHECKSUM=1 was set.`);
191
296
  }
192
297
  else {
298
+ removeFileBestEffort(stagedPath);
193
299
  throw new Error(`Checksum verification failed: ${err instanceof Error ? err.message : String(err)}. ` +
194
- `Use --skip-checksum to bypass (not recommended).`);
300
+ `Set AKM_UPGRADE_SKIP_CHECKSUM=1 to bypass (not recommended).`);
195
301
  }
196
302
  }
197
- const execPath = process.execPath;
198
- const execDir = path.dirname(execPath);
199
- const execName = path.basename(execPath);
200
- if (IS_WINDOWS) {
201
- // Windows: rename running exe, write new one, clean up old on success
202
- const oldPath = `${execPath}.old`;
203
- try {
204
- fs.renameSync(execPath, oldPath);
205
- }
206
- catch (err) {
207
- const code = err.code;
208
- if (code === "EPERM" || code === "EACCES") {
209
- throw new Error(`Permission denied. Cannot rename ${execPath}.\n` +
210
- `Try running as Administrator, or re-download from https://github.com/${REPO}/releases`);
211
- }
212
- const detail = err instanceof Error ? err.message : String(err);
213
- throw new Error(`Failed to rename ${execPath}: ${detail}`);
214
- }
215
- try {
216
- fs.writeFileSync(execPath, binaryData);
217
- }
218
- catch (err) {
219
- // Restore from old
220
- fs.renameSync(oldPath, execPath);
221
- throw err;
222
- }
223
- // Best-effort cleanup of .old
224
- try {
225
- fs.unlinkSync(oldPath);
226
- }
227
- catch {
228
- // Windows may lock the old exe — it will be cleaned up on next startup or manually
229
- }
303
+ try {
304
+ migration.preflight(execPath);
305
+ migration.stagedPreflight(stagedPath);
230
306
  }
231
- else {
232
- // Unix: write to temp file, chmod +x, atomic rename
233
- const tmpPath = path.join(execDir, `.${execName}.tmp.${process.pid}`);
234
- const bakPath = `${execPath}.bak`;
235
- try {
236
- fs.writeFileSync(tmpPath, binaryData);
237
- fs.chmodSync(tmpPath, 0o755);
238
- }
239
- catch (err) {
240
- // Clean up temp file on failure
241
- try {
242
- fs.unlinkSync(tmpPath);
243
- }
244
- catch {
245
- /* ignore */
246
- }
247
- const code = err.code;
248
- if (code === "EACCES" || code === "EPERM") {
249
- throw new Error(`Permission denied writing to ${execDir}.\n` +
250
- `Run: sudo akm upgrade\n` +
251
- `Or re-run the install script: curl -fsSL https://raw.githubusercontent.com/${REPO}/main/install.sh | bash`);
252
- }
253
- throw err;
254
- }
255
- // Backup current, then atomic rename
256
- try {
257
- fs.copyFileSync(execPath, bakPath);
258
- fs.renameSync(tmpPath, execPath);
259
- }
260
- catch (err) {
261
- // Restore from backup if rename failed
262
- try {
263
- fs.unlinkSync(tmpPath);
264
- }
265
- catch {
266
- /* ignore */
267
- }
268
- try {
269
- if (fs.existsSync(bakPath) && !fs.existsSync(execPath)) {
270
- fs.renameSync(bakPath, execPath);
271
- }
272
- }
273
- catch {
274
- /* ignore */
275
- }
276
- throw err;
277
- }
278
- // Cleanup backup
279
- try {
280
- fs.unlinkSync(bakPath);
281
- }
282
- catch {
283
- /* ignore */
307
+ catch (err) {
308
+ removeFileBestEffort(stagedPath);
309
+ throw err;
310
+ }
311
+ if (fs.existsSync(backupPath)) {
312
+ removeFileBestEffort(stagedPath);
313
+ throw new ConfigError(`Refusing to overwrite retained previous binary at ${backupPath}.`, "UPGRADE_BLOCKED");
314
+ }
315
+ try {
316
+ if (IS_WINDOWS)
317
+ fs.renameSync(execPath, backupPath);
318
+ else
319
+ fs.copyFileSync(execPath, backupPath);
320
+ fs.renameSync(stagedPath, execPath);
321
+ }
322
+ catch (err) {
323
+ removeFileBestEffort(stagedPath);
324
+ if (!fs.existsSync(execPath) && fs.existsSync(backupPath)) {
325
+ fs.renameSync(backupPath, execPath);
284
326
  }
327
+ throw err;
328
+ }
329
+ try {
330
+ migration.apply(execPath);
285
331
  }
332
+ catch (err) {
333
+ const detail = err instanceof Error ? err.message : String(err);
334
+ throw new Error(`Migration apply failed; the new binary remains installed and the previous binary retained at ${backupPath}: ${detail}`);
335
+ }
336
+ // Keep the previous binary available until migration apply has completed.
337
+ removeFileBestEffort(backupPath);
286
338
  return {
287
339
  currentVersion,
288
340
  newVersion: latestVersion,
@@ -290,32 +342,19 @@ export async function performUpgrade(check, opts) {
290
342
  installMethod,
291
343
  binaryPath: execPath,
292
344
  checksumVerified,
293
- // For binary installs, the new binary now lives at execPath; spawn it
294
- // directly so the post-upgrade work runs against the new code.
295
345
  postUpgrade: runPostUpgradeTasks(execPath, { skip: skipPostUpgrade }),
296
346
  };
297
347
  }
298
348
  /**
299
- * Run the post-upgrade tasks against the *new* binary as a child process.
300
- *
301
- * Why a child process: the running akm process still has the old code in
302
- * memory. Calling loadConfig()/akmIndex() in-process would use the old
303
- * implementations and miss any DB_VERSION / config-key changes the new
304
- * release introduces.
305
- *
306
- * The new binary's `akm index` does the work for us:
307
- * 1. loadConfig() runs at startup — auto-migrates legacy `stashes` →
308
- * `sources` if the on-disk config still uses the old key.
309
- * 2. ensureSchema() converges index.db forward via its idempotent baseline
310
- * schema + additive migrations (no destructive rebuild).
311
- * 3. The full reindex repopulates entries + workflow_documents + FTS.
349
+ * Rebuild the derived index after the explicit migration command succeeds.
350
+ * Migration and indexing are intentionally separate lifecycle steps.
312
351
  */
313
352
  function runPostUpgradeTasks(akmBin, opts) {
314
353
  if (opts.skip) {
315
354
  return {
316
355
  ok: true,
317
356
  skipped: true,
318
- message: "Skipped post-upgrade tasks. Run `akm index` manually to migrate config and rebuild the index.",
357
+ message: "Migration completed; skipped the index rebuild. Run `akm index` manually to rebuild the index.",
319
358
  };
320
359
  }
321
360
  try {
@@ -328,7 +367,7 @@ function runPostUpgradeTasks(akmBin, opts) {
328
367
  return {
329
368
  ok: false,
330
369
  skipped: false,
331
- message: `Post-upgrade tasks could not start: ${result.error.message}. Run \`akm index\` manually.`,
370
+ message: `Migration completed, but the index rebuild could not start: ${result.error.message}. Run \`akm index\` manually.`,
332
371
  };
333
372
  }
334
373
  if (result.status !== 0) {
@@ -337,14 +376,14 @@ function runPostUpgradeTasks(akmBin, opts) {
337
376
  ok: false,
338
377
  skipped: false,
339
378
  exitCode: result.status,
340
- message: `Post-upgrade \`akm index\` failed (${detail}). Run \`akm index\` manually.`,
379
+ message: `Migration completed, but post-upgrade \`akm index\` failed (${detail}). Run \`akm index\` manually.`,
341
380
  };
342
381
  }
343
382
  return {
344
383
  ok: true,
345
384
  skipped: false,
346
385
  exitCode: 0,
347
- message: "Config migrated (if needed) and index rebuilt against the new binary.",
386
+ message: "Migration completed and the index was rebuilt against the new binary.",
348
387
  };
349
388
  }
350
389
  catch (err) {
@@ -352,10 +391,32 @@ function runPostUpgradeTasks(akmBin, opts) {
352
391
  return {
353
392
  ok: false,
354
393
  skipped: false,
355
- message: `Post-upgrade tasks failed: ${detail}. Run \`akm index\` manually.`,
394
+ message: `Migration completed, but the index rebuild failed: ${detail}. Run \`akm index\` manually.`,
356
395
  };
357
396
  }
358
397
  }
398
+ function runRequiredCommand(akmBin, args, label) {
399
+ const result = childProcess.spawnSync(akmBin, args, {
400
+ encoding: "utf8",
401
+ env: process.env,
402
+ stdio: "pipe",
403
+ });
404
+ if (result.error) {
405
+ throw new Error(`${label} could not start: ${result.error.message}`);
406
+ }
407
+ if (result.status !== 0) {
408
+ const detail = (result.stderr ?? "").trim() || (result.stdout ?? "").trim() || `exit code ${result.status}`;
409
+ throw new Error(`${label} failed (${detail}).`);
410
+ }
411
+ }
412
+ function removeFileBestEffort(filePath) {
413
+ try {
414
+ fs.unlinkSync(filePath);
415
+ }
416
+ catch {
417
+ // Cleanup is best-effort; the primary operation determines success.
418
+ }
419
+ }
359
420
  function parseChecksumForFile(checksumsText, filename) {
360
421
  for (const line of checksumsText.split("\n")) {
361
422
  const trimmed = line.trim();