akm-cli 0.10.261012-beta → 0.10.261014-beta

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 (518) hide show
  1. package/CHANGELOG.md +710 -3
  2. package/README.md +15 -0
  3. package/SECURITY.md +11 -10
  4. package/STABILITY.md +47 -51
  5. package/dist/assets/hints/cli-hints-full.md +21 -19
  6. package/dist/assets/hints/cli-hints-short.md +3 -4
  7. package/dist/assets/opencode/akm-plugin.js +177 -0
  8. package/dist/assets/stash-skeleton/README.md +1 -1
  9. package/dist/assets/tasks/core/improve.yml +1 -1
  10. package/dist/assets/tasks/improve/akm-improve-consolidate.yml +1 -1
  11. package/dist/assets/ui/config.js +27 -10
  12. package/dist/assets/workflows/workflow-template.md +2 -2
  13. package/dist/cli/clack.js +3 -1
  14. package/dist/cli/selection.js +33 -0
  15. package/dist/cli/shared.js +14 -1
  16. package/dist/cli/unknown-flags.js +6 -37
  17. package/dist/cli.js +69 -48
  18. package/dist/commands/agent/agent-dispatch.js +17 -25
  19. package/dist/commands/agent/contribute-cli.js +9 -8
  20. package/dist/commands/command/command-cli.js +4 -8
  21. package/dist/commands/command/command-execution.js +25 -39
  22. package/dist/commands/command/execution-source-loader.js +10 -14
  23. package/dist/commands/completions.js +1 -1
  24. package/dist/commands/config-cli.js +14 -5
  25. package/dist/commands/env/child-env.js +12 -14
  26. package/dist/commands/env/env-binding.js +47 -58
  27. package/dist/commands/env/env-cli.js +22 -24
  28. package/dist/commands/env/env.js +10 -58
  29. package/dist/commands/env/secret-cli.js +11 -29
  30. package/dist/commands/env/secret.js +3 -10
  31. package/dist/commands/health/checks.js +10 -849
  32. package/dist/commands/health/connections-and-harnesses-check.js +109 -0
  33. package/dist/commands/health/egress.js +3 -3
  34. package/dist/commands/health/html-report.js +9 -10
  35. package/dist/commands/health/plugin-staleness.js +18 -11
  36. package/dist/commands/health/report-view-model.js +16 -12
  37. package/dist/commands/health/scheduler-binary.js +1 -1
  38. package/dist/commands/health/semantic-search-check.js +85 -0
  39. package/dist/commands/health/type-directory-check.js +0 -3
  40. package/dist/commands/health.js +30 -42
  41. package/dist/commands/improve/consolidate/pair-pass.js +10 -25
  42. package/dist/commands/improve/consolidate.js +10 -15
  43. package/dist/commands/improve/distill.js +5 -17
  44. package/dist/commands/improve/eligibility.js +1 -3
  45. package/dist/commands/improve/execution.js +37 -40
  46. package/dist/commands/improve/extract-cli.js +6 -11
  47. package/dist/commands/improve/extract-prompt.js +2 -2
  48. package/dist/commands/improve/extract.js +67 -97
  49. package/dist/commands/improve/improve-cli.js +22 -128
  50. package/dist/commands/improve/improve-report.js +1 -1
  51. package/dist/commands/improve/improve-strategies.js +25 -108
  52. package/dist/commands/improve/improve.js +10 -14
  53. package/dist/commands/improve/loop-stages.js +3 -0
  54. package/dist/commands/improve/memory/memory-improve.js +1 -1
  55. package/dist/commands/improve/preparation.js +8 -13
  56. package/dist/commands/improve/reflect.js +203 -332
  57. package/dist/commands/improve/retrieval-scope.js +1 -1
  58. package/dist/commands/improve/session-asset.js +3 -2
  59. package/dist/commands/improve/stage.js +87 -115
  60. package/dist/commands/lint/base-linter.js +3 -3
  61. package/dist/commands/lint/env-key-rules.js +7 -6
  62. package/dist/commands/lint/index.js +3 -3
  63. package/dist/commands/models-cli.js +103 -63
  64. package/dist/commands/proposal/drain.js +26 -39
  65. package/dist/commands/proposal/proposal-cli.js +14 -18
  66. package/dist/commands/proposal/propose-cli.js +4 -2
  67. package/dist/commands/proposal/propose.js +37 -64
  68. package/dist/commands/proposal/repository.js +17 -17
  69. package/dist/commands/proposal/validators/proposal-validators.js +3 -6
  70. package/dist/commands/read/curate.js +10 -6
  71. package/dist/commands/read/registry-search.js +2 -48
  72. package/dist/commands/read/search-cli.js +1 -8
  73. package/dist/commands/read/search.js +5 -6
  74. package/dist/commands/read/show.js +6 -29
  75. package/dist/commands/remember.js +25 -40
  76. package/dist/commands/sources/add-cli.js +8 -63
  77. package/dist/commands/sources/bundle-cli.js +8 -9
  78. package/dist/commands/sources/bundle-config-ops.js +2 -2
  79. package/dist/commands/sources/info.js +12 -1
  80. package/dist/commands/sources/init.js +1 -1
  81. package/dist/commands/sources/installed-stashes.js +119 -63
  82. package/dist/commands/sources/migration-help.js +1 -1
  83. package/dist/commands/sources/plugin-upgrade.js +8 -15
  84. package/dist/commands/sources/schema-repair.js +4 -10
  85. package/dist/commands/sources/source-add.js +2 -2
  86. package/dist/commands/sources/source-clone.js +31 -7
  87. package/dist/commands/sources/source-manage.js +4 -4
  88. package/dist/commands/targets.js +175 -0
  89. package/dist/commands/tasks/explain.js +104 -69
  90. package/dist/commands/tasks/tasks-cli.js +9 -11
  91. package/dist/commands/tasks/tasks.js +75 -97
  92. package/dist/commands/ui/api.js +11 -3
  93. package/dist/commands/ui/redact.js +5 -31
  94. package/dist/commands/ui/workspace-actions.js +1 -1
  95. package/dist/commands/workflow/plan.js +48 -9
  96. package/dist/commands/workflow-cli.js +40 -45
  97. package/dist/core/adapter/adapters/agent-skills-adapter.js +10 -11
  98. package/dist/core/adapter/adapters/akm-adapter.js +36 -41
  99. package/dist/core/adapter/adapters/akm-lint.js +10 -12
  100. package/dist/core/adapter/adapters/akm-metadata.js +2 -2
  101. package/dist/core/adapter/adapters/akm-task-adapter.js +8 -9
  102. package/dist/core/adapter/adapters/akm-workflow-adapter.js +5 -5
  103. package/dist/core/adapter/adapters/claude-adapter.js +1 -1
  104. package/dist/core/adapter/adapters/dotenv-adapter.js +7 -6
  105. package/dist/core/adapter/adapters/generic-files-adapter.js +5 -5
  106. package/dist/core/adapter/adapters/index.js +3 -4
  107. package/dist/core/adapter/adapters/llm-wiki-adapter.js +12 -14
  108. package/dist/core/adapter/adapters/okf-adapter.js +8 -10
  109. package/dist/core/adapter/adapters/opencode-adapter.js +1 -1
  110. package/dist/core/adapter/adapters/shared.js +3 -3
  111. package/dist/core/adapter/adapters/tool-dir-shared.js +7 -25
  112. package/dist/core/adapter/adapters/website-snapshot-adapter.js +3 -3
  113. package/dist/core/adapter/detect-adapter.js +1 -1
  114. package/dist/core/adapter/execution-source.js +13 -35
  115. package/dist/core/adapter/registry.js +1 -1
  116. package/dist/core/adapter/validate-context.js +2 -4
  117. package/dist/core/asset/asset-placement.js +1 -1
  118. package/dist/core/asset/asset-ref.js +3 -3
  119. package/dist/core/asset/resolve-ref.js +5 -0
  120. package/dist/core/bundle-rename.js +12 -4
  121. package/dist/core/closest-match.js +37 -0
  122. package/dist/core/common.js +37 -57
  123. package/dist/core/config/config-io.js +26 -18
  124. package/dist/core/config/config-schema.js +19 -106
  125. package/dist/core/config/config-sources.js +3 -3
  126. package/dist/core/config/config-types.js +4 -4
  127. package/dist/core/config/config-walker.js +50 -77
  128. package/dist/core/config/config.js +438 -109
  129. package/dist/core/config/convert-engine-references.js +114 -0
  130. package/dist/core/config/convert-engines-shared.js +40 -0
  131. package/dist/core/config/convert-engines.js +300 -0
  132. package/dist/core/config/convert-models-overlay.js +137 -0
  133. package/dist/core/config/credentials.js +304 -0
  134. package/dist/core/config/engine-semantics.js +3 -3
  135. package/dist/core/config/migrate-keys.js +222 -0
  136. package/dist/core/config/model-aliases.js +37 -0
  137. package/dist/core/config/models-file.js +34 -0
  138. package/dist/core/config/retired-engines.js +53 -0
  139. package/dist/core/config/schema/connections.js +41 -0
  140. package/dist/core/config/schema/embedding.js +2 -2
  141. package/dist/core/config/schema/harnesses.js +41 -0
  142. package/dist/core/config/schema/improve-processes.js +9 -28
  143. package/dist/core/config/schema/improve.js +36 -1
  144. package/dist/core/config/schema/index-config.js +18 -20
  145. package/dist/core/config/schema/primitives.js +42 -17
  146. package/dist/core/config/schema/search.js +6 -11
  147. package/dist/core/config/schema/sources-bundles.js +9 -9
  148. package/dist/core/config/schema/workflow.js +2 -6
  149. package/dist/core/config/unusable-entries.js +66 -0
  150. package/dist/core/content-safety.js +3 -6
  151. package/dist/core/endpoint-url.js +47 -0
  152. package/dist/core/env-secret-ref.js +84 -73
  153. package/dist/core/errors.js +10 -16
  154. package/dist/core/extra-params.js +3 -3
  155. package/dist/core/improve-result.js +8 -9
  156. package/dist/core/json-schema.js +1 -1
  157. package/dist/core/lesson-lint.js +1 -1
  158. package/dist/core/llm-inference.js +80 -0
  159. package/dist/core/parse.js +2 -2
  160. package/dist/core/paths.js +33 -10
  161. package/dist/core/recognition-util.js +8 -10
  162. package/dist/core/redaction.js +94 -55
  163. package/dist/core/ref-token.js +82 -0
  164. package/dist/core/secret-value.js +14 -0
  165. package/dist/core/state/migrations.js +17 -22
  166. package/dist/core/structured.js +2 -68
  167. package/dist/core/subprocess.js +63 -22
  168. package/dist/core/type-presentation.js +10 -14
  169. package/dist/core/write-source.js +20 -4
  170. package/dist/execution/input-contract.js +3 -6
  171. package/dist/execution/notices.js +49 -0
  172. package/dist/execution/resolved-request.js +24 -40
  173. package/dist/execution/source.js +21 -45
  174. package/dist/execution/target-ref.js +2 -2
  175. package/dist/indexer/bundle-identity-guard.js +6 -5
  176. package/dist/indexer/ensure-index.js +1 -1
  177. package/dist/indexer/index-writer-lock.js +1 -1
  178. package/dist/indexer/indexer.js +46 -42
  179. package/dist/indexer/installations.js +12 -22
  180. package/dist/indexer/lookup/adapter-concept-owner.js +40 -14
  181. package/dist/indexer/materialize-embeddings.js +20 -16
  182. package/dist/indexer/passes/memory-inference.js +21 -50
  183. package/dist/indexer/passes/metadata.js +5 -5
  184. package/dist/indexer/scan/doc-to-entry.js +1 -1
  185. package/dist/indexer/scan/drain-dir.js +9 -11
  186. package/dist/indexer/search/db-search.js +9 -7
  187. package/dist/indexer/search/search-source.js +42 -22
  188. package/dist/indexer/usage/usage-events.js +2 -3
  189. package/dist/indexer/walk/index-context.js +2 -1
  190. package/dist/indexer/walk/matchers.js +3 -11
  191. package/dist/indexer/walk/path-resolver.js +13 -68
  192. package/dist/indexer/walk/walker.js +32 -26
  193. package/dist/integrations/agent/akm-read-tools.js +81 -0
  194. package/dist/integrations/agent/config.js +1 -1
  195. package/dist/integrations/agent/detect.js +32 -36
  196. package/dist/integrations/agent/execution.js +130 -428
  197. package/dist/integrations/agent/index.js +1 -1
  198. package/dist/integrations/agent/profiles.js +24 -28
  199. package/dist/integrations/agent/prompts.js +17 -30
  200. package/dist/integrations/agent/request-lowering.js +67 -101
  201. package/dist/integrations/agent/resolution.js +332 -0
  202. package/dist/integrations/agent/runner-dispatch.js +156 -181
  203. package/dist/integrations/agent/runner.js +20 -70
  204. package/dist/integrations/agent/runtime-port.js +4 -0
  205. package/dist/integrations/agent/runtime.js +10 -0
  206. package/dist/integrations/agent/spawn.js +65 -190
  207. package/dist/integrations/harnesses/aider/index.js +19 -39
  208. package/dist/integrations/harnesses/amazonq/index.js +17 -32
  209. package/dist/integrations/harnesses/claude/index.js +59 -28
  210. package/dist/integrations/harnesses/claude/session-log.js +7 -5
  211. package/dist/integrations/harnesses/codex/index.js +19 -31
  212. package/dist/integrations/harnesses/copilot/index.js +17 -35
  213. package/dist/integrations/harnesses/gemini/index.js +18 -34
  214. package/dist/integrations/harnesses/harness.js +36 -0
  215. package/dist/integrations/harnesses/index.js +20 -51
  216. package/dist/integrations/harnesses/opencode/agent-builder.js +132 -100
  217. package/dist/integrations/harnesses/opencode/index.js +11 -33
  218. package/dist/integrations/harnesses/opencode/roots.js +50 -0
  219. package/dist/integrations/harnesses/opencode/runtime/binary.js +206 -0
  220. package/dist/integrations/harnesses/opencode/runtime/command.js +152 -0
  221. package/dist/integrations/harnesses/opencode/runtime/index.js +177 -0
  222. package/dist/integrations/harnesses/opencode/runtime/tar.js +107 -0
  223. package/dist/integrations/harnesses/opencode/session-log-v1.js +15 -7
  224. package/dist/integrations/harnesses/opencode/session-log-v2.js +72 -48
  225. package/dist/integrations/harnesses/opencode/session-log.js +58 -137
  226. package/dist/integrations/harnesses/opencode/version.js +34 -53
  227. package/dist/integrations/harnesses/openhands/index.js +13 -37
  228. package/dist/integrations/harnesses/pi/index.js +21 -32
  229. package/dist/integrations/lockfile.js +1 -1
  230. package/dist/integrations/session-logs/index.js +11 -31
  231. package/dist/llm/client.js +93 -111
  232. package/dist/llm/embedder.js +19 -34
  233. package/dist/llm/embedders/connection.js +31 -0
  234. package/dist/llm/embedders/local-model-files.js +56 -0
  235. package/dist/llm/embedders/local.js +146 -115
  236. package/dist/llm/embedders/remote.js +26 -23
  237. package/dist/llm/embedders/types.js +1 -1
  238. package/dist/llm/index-passes.js +33 -39
  239. package/dist/llm/memory-infer.js +67 -77
  240. package/dist/llm/model-list.js +35 -0
  241. package/dist/llm/rerank-client.js +8 -14
  242. package/dist/llm/structured-call.js +45 -99
  243. package/dist/llm/structured.js +60 -0
  244. package/dist/output/renderers.js +2 -8
  245. package/dist/output/shapes/helpers.js +18 -44
  246. package/dist/output/shapes/passthrough.js +1 -0
  247. package/dist/output/shapes.js +1 -7
  248. package/dist/output/text/command-format.js +41 -39
  249. package/dist/output/text/health-format.js +8 -2
  250. package/dist/output/text/helpers.js +1 -1
  251. package/dist/output/text/migrate.js +12 -0
  252. package/dist/output/text/models.js +3 -2
  253. package/dist/output/text/registry-commands.js +1 -2
  254. package/dist/output/text/show-directives.js +16 -28
  255. package/dist/output/text/show-format.js +0 -2
  256. package/dist/output/text/targets-table.js +70 -0
  257. package/dist/output/text/workflow-format.js +44 -15
  258. package/dist/output/text.js +1 -1
  259. package/dist/registry/providers/skills-sh.js +1 -28
  260. package/dist/registry/providers/static-index.js +1 -71
  261. package/dist/runtime.js +6 -2
  262. package/dist/scripts/akm-migrate-node.js +47095 -44905
  263. package/dist/scripts/akm-migrate.js +46946 -44755
  264. package/dist/setup/detect.js +28 -273
  265. package/dist/setup/endpoint.js +36 -0
  266. package/dist/setup/semantic-assets.js +13 -19
  267. package/dist/setup/setup-flags.js +77 -0
  268. package/dist/setup/setup-plan.js +144 -0
  269. package/dist/setup/setup.js +134 -358
  270. package/dist/setup/steps/connection-shared.js +49 -101
  271. package/dist/setup/steps/connection.js +121 -524
  272. package/dist/setup/steps/embeddings.js +151 -0
  273. package/dist/setup/steps/harnesses.js +118 -0
  274. package/dist/setup/steps/platforms.js +2 -81
  275. package/dist/setup/steps/tasks.js +1 -2
  276. package/dist/setup/steps.js +10 -0
  277. package/dist/setup/summary.js +67 -0
  278. package/dist/sources/freshness.js +16 -21
  279. package/dist/sources/providers/git-provider.js +2 -9
  280. package/dist/sources/providers/provider-utils.js +13 -5
  281. package/dist/sources/resolve.js +12 -16
  282. package/dist/sources/snapshot-fetchers/robots.js +11 -12
  283. package/dist/sources/snapshot-fetchers/secret-seam.js +2 -4
  284. package/dist/sources/snapshot-fetchers/website-ingest.js +8 -15
  285. package/dist/sources/snapshot-fetchers/x.js +1 -1
  286. package/dist/standalone/onnxruntime-library.js +52 -0
  287. package/dist/storage/repositories/improve-ledger-repository.js +1 -1
  288. package/dist/storage/repositories/improve-runs-repository.js +0 -13
  289. package/dist/storage/repositories/index-entries-repository.js +2 -2
  290. package/dist/storage/repositories/proposals-repository.js +2 -2
  291. package/dist/storage/repositories/task-history-repository.js +2 -2
  292. package/dist/storage/repositories/workflow-runs-repository.js +44 -129
  293. package/dist/storage/sqlite-read-snapshot.js +33 -29
  294. package/dist/tasks/embedded.js +1 -1
  295. package/dist/tasks/log-redaction.js +7 -119
  296. package/dist/tasks/prepare/prepare-support.js +8 -7
  297. package/dist/tasks/prepare/prepare.js +8 -9
  298. package/dist/tasks/prepare/script-capture.js +9 -25
  299. package/dist/tasks/run/attempt-lifecycle.js +17 -35
  300. package/dist/tasks/run/load-task.js +54 -27
  301. package/dist/tasks/run/run-command-task.js +15 -10
  302. package/dist/tasks/run/run-native-task.js +8 -21
  303. package/dist/tasks/run/run-task.js +5 -8
  304. package/dist/tasks/run/run-workflow-task.js +14 -21
  305. package/dist/tasks/run/task-history.js +9 -17
  306. package/dist/tasks/run/task-log.js +1 -5
  307. package/dist/tasks/scheduler-invocation.js +13 -18
  308. package/dist/tasks/scheduler-sync.js +0 -1
  309. package/dist/tasks/source/bounded-document.js +31 -117
  310. package/dist/tasks/source/parse-task-source.js +0 -1
  311. package/dist/tasks/source/project-v4.js +5 -3
  312. package/dist/tasks/source/task-input-diagnostics.js +3 -4
  313. package/dist/tasks/source/task-source-v4.js +48 -72
  314. package/dist/tasks/source-v3.js +2 -5
  315. package/dist/tasks/task-run-reserved-flags.js +1 -2
  316. package/dist/workflows/authoring/authoring.js +2 -7
  317. package/dist/workflows/compile.js +1 -15
  318. package/dist/workflows/concurrency-policy.js +4 -4
  319. package/dist/workflows/exec/child-workflow.js +1 -4
  320. package/dist/workflows/exec/dispatch-redaction.js +35 -86
  321. package/dist/workflows/exec/environment.js +13 -77
  322. package/dist/workflows/exec/exec-unit.js +14 -55
  323. package/dist/workflows/exec/frozen-judge.js +26 -28
  324. package/dist/workflows/exec/native-executor.js +126 -71
  325. package/dist/workflows/exec/run-workflow.js +38 -42
  326. package/dist/workflows/exec/step-work.js +13 -17
  327. package/dist/workflows/exec/unit-dispatch.js +7 -21
  328. package/dist/workflows/freeze/environment.js +14 -119
  329. package/dist/workflows/freeze/freeze.js +14 -33
  330. package/dist/workflows/freeze/step-values.js +6 -13
  331. package/dist/workflows/freeze/targets/child-workflow.js +3 -5
  332. package/dist/workflows/freeze/targets/command.js +9 -15
  333. package/dist/workflows/freeze/targets/shell.js +0 -3
  334. package/dist/workflows/freeze/task-bindings.js +0 -1
  335. package/dist/workflows/parser.js +50 -59
  336. package/dist/workflows/plan.js +8 -2
  337. package/dist/workflows/renderer.js +83 -9
  338. package/dist/workflows/resource-limits.js +2 -2
  339. package/dist/workflows/runtime/run-plan.js +38 -23
  340. package/dist/workflows/runtime/runs.js +55 -93
  341. package/dist/workflows/runtime/workflow-asset-loader.js +55 -86
  342. package/dist/workflows/source-files.js +7 -19
  343. package/docs/README.md +10 -16
  344. package/docs/architecture/README.md +2 -37
  345. package/docs/architecture/adapters.md +2 -2
  346. package/docs/architecture/akm-core-principles.md +256 -118
  347. package/docs/architecture/architecture.md +283 -99
  348. package/docs/architecture/improvement.md +8 -2
  349. package/docs/architecture/internals/classification.md +1 -3
  350. package/docs/architecture/internals/fresh-host-rebuild-runbook.md +7 -6
  351. package/docs/architecture/internals/health-advisories.md +35 -74
  352. package/docs/architecture/internals/improve-workflow.md +27 -26
  353. package/docs/architecture/internals/indexing.md +3 -3
  354. package/docs/architecture/internals/storage-locations.md +48 -15
  355. package/docs/architecture/persisted-data-compat.md +10 -6
  356. package/docs/architecture/specs/okf-support.md +9 -11
  357. package/docs/architecture/specs/ref.md +7 -9
  358. package/docs/architecture/testing/testing-workflow.md +172 -52
  359. package/docs/architecture/workflow-engine.md +51 -34
  360. package/docs/guides/README.md +0 -1
  361. package/docs/guides/author-bundles.md +15 -20
  362. package/docs/guides/author-workflows.md +93 -71
  363. package/docs/guides/bundles.md +20 -16
  364. package/docs/guides/discover-and-load.md +1 -1
  365. package/docs/guides/getting-started.md +49 -3
  366. package/docs/guides/improve-the-library.md +10 -4
  367. package/docs/guides/recipes/headless-install.md +11 -16
  368. package/docs/guides/run-workflows.md +29 -20
  369. package/docs/guides/scheduling.md +2 -2
  370. package/docs/guides/use-with-any-agent.md +20 -22
  371. package/docs/integration/bundling-akm.md +19 -9
  372. package/docs/maintainers/README.md +2 -6
  373. package/docs/maintainers/release-checklist.md +73 -126
  374. package/docs/migration/README.md +10 -3
  375. package/docs/migration/release-notes/0.10.0.md +81 -16
  376. package/docs/migration/release-notes/0.6.0.md +1 -1
  377. package/docs/migration/release-notes/0.7.0.md +1 -1
  378. package/docs/migration/release-notes/0.9.0.md +1 -1
  379. package/docs/migration/release-notes/README.md +1 -1
  380. package/docs/migration/v0.9-to-v0.10.md +300 -60
  381. package/docs/migration/v0.9.1-to-v0.9.2.md +6 -5
  382. package/docs/posts/config-v2-lessons-16.md +1 -1
  383. package/docs/posts/llm-mode-reflect-13.md +1 -1
  384. package/docs/posts/release-0.6.0.md +11 -11
  385. package/docs/posts/release-0.8.0.md +4 -4
  386. package/docs/posts/workflows-vaults-09.md +1 -1
  387. package/docs/reference/README.md +1 -1
  388. package/docs/reference/asset-types.md +2 -2
  389. package/docs/reference/cli.md +477 -388
  390. package/docs/reference/configuration.md +569 -550
  391. package/docs/reference/data-and-telemetry.md +9 -6
  392. package/docs/reference/env-and-secrets.md +72 -15
  393. package/docs/reference/refs.md +3 -20
  394. package/docs/reference/registry.md +12 -38
  395. package/docs/reference/supported-formats.md +1 -1
  396. package/docs/reference/tasks.md +22 -11
  397. package/docs/reference/ui-api.md +14 -9
  398. package/docs/reference/workflow-schema.md +199 -154
  399. package/docs/reference/workflows.md +4 -6
  400. package/package.json +9 -11
  401. package/schemas/akm-config.json +1696 -2922
  402. package/schemas/akm-task.json +4 -4
  403. package/schemas/akm-workflow.json +36 -9
  404. package/ROADMAP.md +0 -112
  405. package/dist/assets/models.json +0 -35
  406. package/dist/commands/health/engine-usage.js +0 -45
  407. package/dist/commands/sources/dangerous-env-audit.js +0 -134
  408. package/dist/core/activation-policy.js +0 -67
  409. package/dist/core/config/schema/engines.js +0 -160
  410. package/dist/core/config/schema/execution.js +0 -23
  411. package/dist/core/spawn-env.js +0 -268
  412. package/dist/execution/directory-identity.js +0 -78
  413. package/dist/integrations/agent/builder-shared.js +0 -33
  414. package/dist/integrations/agent/builders.js +0 -43
  415. package/dist/integrations/agent/engine-fallback.js +0 -59
  416. package/dist/integrations/agent/engine-resolution.js +0 -333
  417. package/dist/integrations/agent/model-map.js +0 -475
  418. package/dist/integrations/harnesses/aider/agent-builder.js +0 -107
  419. package/dist/integrations/harnesses/aider/result-extractor.js +0 -53
  420. package/dist/integrations/harnesses/amazonq/agent-builder.js +0 -138
  421. package/dist/integrations/harnesses/amazonq/result-extractor.js +0 -48
  422. package/dist/integrations/harnesses/claude/agent-builder.js +0 -106
  423. package/dist/integrations/harnesses/claude/config-import.js +0 -67
  424. package/dist/integrations/harnesses/claude/result-extractor.js +0 -67
  425. package/dist/integrations/harnesses/codex/agent-builder.js +0 -150
  426. package/dist/integrations/harnesses/codex/result-extractor.js +0 -110
  427. package/dist/integrations/harnesses/copilot/agent-builder.js +0 -117
  428. package/dist/integrations/harnesses/copilot/result-extractor.js +0 -178
  429. package/dist/integrations/harnesses/gemini/agent-builder.js +0 -114
  430. package/dist/integrations/harnesses/gemini/result-extractor.js +0 -149
  431. package/dist/integrations/harnesses/opencode/config-import.js +0 -149
  432. package/dist/integrations/harnesses/opencode/model-config.js +0 -33
  433. package/dist/integrations/harnesses/opencode/model-work-agent.js +0 -115
  434. package/dist/integrations/harnesses/opencode/session-log-types.js +0 -12
  435. package/dist/integrations/harnesses/opencode-sdk/index.js +0 -44
  436. package/dist/integrations/harnesses/opencode-sdk/sdk-runner.js +0 -1052
  437. package/dist/integrations/harnesses/opencode-sdk/v1-adapter.js +0 -199
  438. package/dist/integrations/harnesses/opencode-sdk/v2-adapter.js +0 -254
  439. package/dist/integrations/harnesses/opencode-sdk/wire.js +0 -66
  440. package/dist/integrations/harnesses/openhands/agent-builder.js +0 -120
  441. package/dist/integrations/harnesses/openhands/result-extractor.js +0 -135
  442. package/dist/integrations/harnesses/pi/agent-builder.js +0 -89
  443. package/dist/integrations/harnesses/pi/result-extractor.js +0 -168
  444. package/dist/integrations/harnesses/shared.js +0 -18
  445. package/dist/integrations/harnesses/types.js +0 -55
  446. package/dist/llm/feature-gate.js +0 -115
  447. package/dist/output/shapes/models-list.js +0 -16
  448. package/dist/output/shapes/registry-search.js +0 -10
  449. package/dist/setup/detected-engines.js +0 -136
  450. package/dist/setup/engine-config.js +0 -97
  451. package/dist/setup/harness-config-import.js +0 -47
  452. package/dist/setup/providers.js +0 -14
  453. package/dist/setup/steps/semantic.js +0 -39
  454. package/dist/workflows/authoring/scope-key.js +0 -79
  455. package/dist/workflows/exec/lowering-notices.js +0 -23
  456. package/dist/workflows/source-semantics.js +0 -110
  457. package/docs/architecture/0.10-process-rules.md +0 -832
  458. package/docs/architecture/akm-architecture-decision-history.md +0 -2055
  459. package/docs/architecture/comparisons/claude-code-vs-akm-workflows-full.md +0 -550
  460. package/docs/architecture/decisions/0001-no-interpolation-attached-structured-context.md +0 -72
  461. package/docs/architecture/decisions/0002-unit-reuse-and-input-hash-scope.md +0 -142
  462. package/docs/architecture/decisions/0003-child-env-allowlist-and-provenance.md +0 -189
  463. package/docs/architecture/decisions/0004-task-input-contract-and-flag-coercion.md +0 -97
  464. package/docs/architecture/decisions/0005-task-result-vocabulary-and-legacy-read-mapping.md +0 -108
  465. package/docs/architecture/decisions/0006-task-source-version-routing.md +0 -124
  466. package/docs/architecture/decisions/0007-workflow-composition-bounds.md +0 -83
  467. package/docs/architecture/decisions/0008-task-binding-normalization.md +0 -88
  468. package/docs/architecture/decisions/0009-child-run-publication-column-parity.md +0 -80
  469. package/docs/architecture/decisions/0010-driver-protocol-cut.md +0 -36
  470. package/docs/architecture/decisions/0011-engine-run-loop-invariants.md +0 -125
  471. package/docs/architecture/decisions/README.md +0 -62
  472. package/docs/architecture/internals/functional-contract-patterns.md +0 -340
  473. package/docs/architecture/internals/registry-network-boundary.md +0 -57
  474. package/docs/architecture/internals/search.md +0 -248
  475. package/docs/architecture/reviews/env-secret-access.md +0 -319
  476. package/docs/architecture/runtime-boundary-design.md +0 -153
  477. package/docs/architecture/specs/0.9.0-close-out-plan.md +0 -361
  478. package/docs/architecture/specs/0.9.0-decisions.md +0 -532
  479. package/docs/architecture/specs/0.9.0-docs-code-drift-register.md +0 -745
  480. package/docs/architecture/specs/0.9.0-open-items-register.md +0 -135
  481. package/docs/architecture/specs/0.9.0-public-api-issue-backlog.md +0 -740
  482. package/docs/architecture/specs/0.9.0-release-surface-review.md +0 -636
  483. package/docs/architecture/specs/agent-command-engine-model-design.md +0 -513
  484. package/docs/architecture/specs/akm-0.9.0-bundle-adapter-spec.md +0 -501
  485. package/docs/architecture/specs/akm-0.9.0-ref-grammar-decision.md +0 -291
  486. package/docs/architecture/specs/akm-format-neutral-bundle-workspace-spec.md +0 -2059
  487. package/docs/architecture/specs/di-seams-plan.md +0 -539
  488. package/docs/architecture/specs/driver-protocol-keep-or-cut.md +0 -275
  489. package/docs/architecture/specs/fact-asset-type.md +0 -142
  490. package/docs/architecture/specs/improve-collapse-churn-detector-design.md +0 -634
  491. package/docs/architecture/specs/reviews/task-workflow-unification/README.md +0 -72
  492. package/docs/architecture/specs/reviews/task-workflow-unification/findings-consolidated.md +0 -152
  493. package/docs/architecture/specs/reviews/task-workflow-unification/library-eval-alternatives.md +0 -352
  494. package/docs/architecture/specs/reviews/task-workflow-unification/library-eval-bunqueue.md +0 -300
  495. package/docs/architecture/specs/reviews/task-workflow-unification/library-eval-openworkflow.md +0 -402
  496. package/docs/architecture/specs/reviews/task-workflow-unification/opus-review-1.md +0 -758
  497. package/docs/architecture/specs/reviews/task-workflow-unification/opus-review-2.md +0 -645
  498. package/docs/architecture/specs/reviews/task-workflow-unification/opus-review-3.md +0 -602
  499. package/docs/architecture/specs/reviews/task-workflow-unification/panel-r1-adversarial.md +0 -27
  500. package/docs/architecture/specs/reviews/task-workflow-unification/panel-r1-architecture.md +0 -27
  501. package/docs/architecture/specs/reviews/task-workflow-unification/panel-r1-coverage.md +0 -74
  502. package/docs/architecture/specs/reviews/task-workflow-unification/panel-r1-security.md +0 -15
  503. package/docs/architecture/specs/reviews/task-workflow-unification/panel-r2-adversarial.md +0 -132
  504. package/docs/architecture/specs/reviews/task-workflow-unification/panel-r2-verification.md +0 -147
  505. package/docs/architecture/specs/stash-conventions-code-spec.md +0 -275
  506. package/docs/architecture/specs/stash-organization-conventions.md +0 -377
  507. package/docs/architecture/specs/task-workflow-format-unification.md +0 -721
  508. package/docs/architecture/specs/workflow-engine-buy-vs-build.md +0 -231
  509. package/docs/architecture/specs/workflow-format-unification.md +0 -432
  510. package/docs/architecture/testing/manual-testing-checklist.md +0 -3411
  511. package/docs/architecture/testing/okf-v0.2-conformance-runbook.md +0 -924
  512. package/docs/architecture/testing/task-workflow-manual-tests.md +0 -1720
  513. package/docs/guides/claude-code-vs-akm-workflows.md +0 -29
  514. package/docs/guides/knowledge-management.md +0 -18
  515. package/docs/maintainers/curate-workmap.md +0 -335
  516. package/docs/migration/v0.5-to-v0.6.md +0 -759
  517. package/docs/migration/v0.7-to-v0.8.md +0 -1378
  518. package/docs/plans/0.9.2-agent-command-workflow-plan.md +0 -423
@@ -0,0 +1,114 @@
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
+ * Where the engines of improve strategies, index passes and workflow gates went: the
6
+ * `connection` / `harness` they name now, or the process they moved to. See `convert-engines.ts`.
7
+ */
8
+ import { isDeepStrictEqual } from "node:util";
9
+ import { isRecord } from "../common.js";
10
+ import { objectAt, str } from "./convert-engines-shared.js";
11
+ /** What a strategy's process, quality gate or judgment once said about where it runs and how. */
12
+ const EXECUTION_KEYS = ["connection", "harness", "model", "llm", "timeoutMs"];
13
+ /** Rewrite the `engine` of `holder` as the `connection` or `harness` it names now, unless the holder already says. */
14
+ export function retargeter(conversion, target) {
15
+ return (holder, where, harnessOk = true) => {
16
+ if (!isRecord(holder) || !("engine" in holder))
17
+ return;
18
+ conversion.changed = true;
19
+ const engine = str(holder.engine);
20
+ delete holder.engine;
21
+ const found = engine === undefined ? undefined : target(engine);
22
+ if (found === undefined)
23
+ conversion.notes.push(`${where}: engine ${JSON.stringify(engine)} is not carried over.`);
24
+ else if ("harness" in found && !harnessOk)
25
+ conversion.notes.push(`${where}: index passes run on connections only; engine "${engine}" is not carried over.`);
26
+ else
27
+ for (const [key, value] of Object.entries(found))
28
+ holder[key] ??= value;
29
+ };
30
+ }
31
+ /**
32
+ * A strategy's `engine`, `model`, `llm` and `timeoutMs` are dropped (it says which processes run, not where), and
33
+ * where its processes, quality gates and triage judgment said a process runs moves to `improve.processes.<name>` /
34
+ * `improve.qualityGate`; the first strategy to say it wins.
35
+ */
36
+ export function moveStrategyExecution(improve, conversion, retarget) {
37
+ if (!isRecord(improve.strategies))
38
+ return;
39
+ const hoist = (holder, from, place, destination) => {
40
+ if (!isRecord(holder))
41
+ return;
42
+ retarget(holder, `${from}.engine`);
43
+ const found = EXECUTION_KEYS.filter((key) => key in holder);
44
+ if (found.length === 0)
45
+ return;
46
+ conversion.changed = true;
47
+ const into = destination();
48
+ for (const key of found) {
49
+ const value = holder[key];
50
+ delete holder[key];
51
+ const names = key === "connection" || key === "harness";
52
+ const taken = names ? "connection" in into || "harness" in into : key in into;
53
+ if (!taken)
54
+ into[key] = value;
55
+ else if (!isDeepStrictEqual(into[key], value))
56
+ conversion.notes.push(`${from}.${key}: ${place} already says where this runs; the first choice is kept.`);
57
+ }
58
+ };
59
+ const processEntry = (name) => () => objectAt(objectAt(improve, "processes"), name);
60
+ for (const [strategyName, strategy] of Object.entries(improve.strategies)) {
61
+ if (!isRecord(strategy))
62
+ continue;
63
+ for (const key of ["engine", "model", "llm", "timeoutMs"]) {
64
+ if (key in strategy) {
65
+ delete strategy[key];
66
+ conversion.changed = true;
67
+ conversion.notes.push(`improve.strategies.${strategyName}.${key}: a strategy says which processes run, not where; it is dropped.`);
68
+ }
69
+ }
70
+ for (const [processName, process] of Object.entries(isRecord(strategy.processes) ? strategy.processes : {})) {
71
+ const where = `improve.strategies.${strategyName}.processes.${processName}`;
72
+ if (!isRecord(process))
73
+ continue;
74
+ // Triage's judgment is the model call; in 0.9 its setting was the nearer one, so it is hoisted first and wins.
75
+ hoist(process.judgment, `${where}.judgment`, "improve.processes.triage", processEntry("triage"));
76
+ hoist(process, where, `improve.processes.${processName}`, processEntry(processName));
77
+ hoist(process.qualityGate, `${where}.qualityGate`, "improve.qualityGate", () => objectAt(improve, "qualityGate"));
78
+ }
79
+ }
80
+ }
81
+ /** `defaults.improveStrategy`: `improve.strategy`. */
82
+ export function improveStrategyDefault(out, defaults, improve) {
83
+ if (defaults.improveStrategy === undefined)
84
+ return;
85
+ out.improve = { ...(isRecord(improve) ? improve : {}) };
86
+ out.improve.strategy ??= defaults.improveStrategy;
87
+ }
88
+ /** `workflow.judgeEngine`: a gate's judge is the default connection or harness now. */
89
+ export function dropJudgeEngine(out, conversion) {
90
+ const workflow = out.workflow;
91
+ if (!isRecord(workflow) || !("judgeEngine" in workflow))
92
+ return;
93
+ delete workflow.judgeEngine;
94
+ conversion.changed = true;
95
+ conversion.notes.push("workflow.judgeEngine: a gate's judge is the default connection or harness now; it is dropped.");
96
+ }
97
+ /** `index.defaults.*` and `index.<pass>.engine`: `index.*` and `connection`; a harness cannot run an index pass. */
98
+ export function convertIndexEngines(out, conversion, retarget) {
99
+ const index = out.index;
100
+ if (!isRecord(index))
101
+ return;
102
+ const indexDefaults = index.defaults;
103
+ delete index.defaults;
104
+ if (isRecord(indexDefaults)) {
105
+ conversion.changed = true;
106
+ retarget(indexDefaults, "index.defaults.engine", false);
107
+ for (const key of ["connection", "model", "timeoutMs", "llm"])
108
+ if (indexDefaults[key] !== undefined)
109
+ index[key] ??= indexDefaults[key];
110
+ }
111
+ for (const [pass, value] of Object.entries(index))
112
+ if (pass !== "connection")
113
+ retarget(value, `index.${pass}.engine`, false);
114
+ }
@@ -0,0 +1,40 @@
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
+ * What the pieces of the engines conversion share: the shapes they pass around and the
6
+ * few helpers more than one of them needs. See `convert-engines.ts`.
7
+ */
8
+ import { isRecord } from "../common.js";
9
+ import { normalizeExtraParamKey } from "../extra-params.js";
10
+ import { inferenceWireFields } from "../llm-inference.js";
11
+ export const str = (value) => (typeof value === "string" && value ? value : undefined);
12
+ export const asDict = (value) => (isRecord(value) ? value : {});
13
+ /**
14
+ * The request fields an old engine's (or a `models.json` entry's) inference
15
+ * becomes. The first-class settings win over `extraParams`: an `extraParams` key
16
+ * that names the same field as one of them (`temperature`, `maxTokens`/`max_tokens`,
17
+ * `enableThinking`, `reasoningEffort`, `chat_template_kwargs`) is dropped, with a
18
+ * note that names the key and not its value.
19
+ */
20
+ export function wireFieldsOf(inference, where, notes) {
21
+ const { extraParams, ...settings } = inference;
22
+ const firstClass = inferenceWireFields(settings);
23
+ const taken = new Set(Object.keys(firstClass).map(normalizeExtraParamKey));
24
+ const extras = {};
25
+ for (const [key, value] of Object.entries(isRecord(extraParams) ? extraParams : {})) {
26
+ if (taken.has(normalizeExtraParamKey(key))) {
27
+ notes.push(`${where}: extraParams.${key} is dropped, because the setting it shadows takes precedence.`);
28
+ }
29
+ else {
30
+ extras[key] = value;
31
+ }
32
+ }
33
+ return { ...extras, ...firstClass };
34
+ }
35
+ /** `holder[key]` as an object, made on `holder` when it is not one yet. */
36
+ export function objectAt(holder, key) {
37
+ if (!isRecord(holder[key]))
38
+ holder[key] = {};
39
+ return holder[key];
40
+ }
@@ -0,0 +1,300 @@
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
+ * The pre-0.10 `engines` / `defaults` config read as `connections` / `harnesses`.
6
+ *
7
+ * One pure function, two call sites: the loader runs it in memory on every read
8
+ * (`runConfigFilePipeline`) and `akm migrate apply` writes its result back.
9
+ * Whatever it cannot carry over is named in `notes` and dropped. One step per row of
10
+ * the migration table in `docs/reference/configuration.md`; `models.json` and the
11
+ * references in strategies, index passes and gates are folded in by their own modules.
12
+ */
13
+ import { isRecord } from "../common.js";
14
+ import { convertIndexEngines, dropJudgeEngine, improveStrategyDefault, moveStrategyExecution, retargeter, } from "./convert-engine-references.js";
15
+ import { asDict, str, wireFieldsOf, } from "./convert-engines-shared.js";
16
+ import { foldEngineModels, foldModelsOverlay } from "./convert-models-overlay.js";
17
+ import { deepMergeConfig } from "./deep-merge.js";
18
+ import { isEnvReference } from "./schema/primitives.js";
19
+ const LLM_ENGINE_KEYS = new Set([
20
+ "kind",
21
+ "provider",
22
+ "endpoint",
23
+ "model",
24
+ "apiKey",
25
+ "apiKeyFile",
26
+ "temperature",
27
+ "maxTokens",
28
+ "timeoutMs",
29
+ "concurrency",
30
+ "supportsJsonSchema",
31
+ "extraParams",
32
+ "contextLength",
33
+ "enableThinking",
34
+ "reasoningEffort",
35
+ ]);
36
+ const AGENT_ENGINE_KEYS = new Set([
37
+ "kind",
38
+ "platform",
39
+ "bin",
40
+ "args",
41
+ "workspace",
42
+ "model",
43
+ "agent",
44
+ "timeoutMs",
45
+ "llmEngine",
46
+ ]);
47
+ const CARRIED = ["endpoint", "contextLength", "timeoutMs", "concurrency"];
48
+ /**
49
+ * The environment variables an engine's key used to be read from without being
50
+ * named in config: `AKM_ENGINE_<NAME>_API_KEY` for any engine, and
51
+ * `AKM_LLM_API_KEY` for the engine `defaults.llmEngine` named.
52
+ */
53
+ function implicitKeyVariables(name, defaults) {
54
+ const own = `AKM_ENGINE_${name.toUpperCase().replaceAll("-", "_")}_API_KEY`;
55
+ return name === str(defaults.llmEngine) ? [own, "AKM_LLM_API_KEY"] : [own];
56
+ }
57
+ // ── engines → connections / harnesses ────────────────────────────────────────
58
+ /** `engines.<name>` with `kind: "agent"` and `platform: "opencode-sdk"`: akm's own runtime has no entry of its own. */
59
+ function runtimeEngine(name, engine, converted, conversion) {
60
+ converted.runtimes.set(name, str(engine.llmEngine));
61
+ conversion.notes.push(`engines.${name}: opencode-sdk is akm's own runtime now, with no entry of its own; its model, timeout and workspace are dropped.`);
62
+ }
63
+ /** `engines.<name>` with `kind: "agent"`, any other platform: `harnesses.<name>`. */
64
+ function agentEngineToHarness(name, engine, converted) {
65
+ const harness = { platform: engine.platform };
66
+ for (const key of ["bin", "args", "workspace", "agent", "timeoutMs"])
67
+ if (engine[key] !== undefined)
68
+ harness[key] = engine[key];
69
+ const model = str(engine.model);
70
+ if (model !== undefined)
71
+ converted.ownModelOf.push({ kind: "harnesses", engine: name, model });
72
+ converted.harnesses[name] = harness;
73
+ }
74
+ /**
75
+ * The key of an engine, on its connection: a `$VAR` is kept; a file, a literal or a secret reference cannot be
76
+ * (the key belongs in `credentials.json`); and with none written, the variable it used to be read from implicitly,
77
+ * when that one is set. When none is, the connection has no key, and a note says which variables 0.9 read.
78
+ */
79
+ function carryEngineKey(name, engine, connection, defaults, env, converted, conversion) {
80
+ const apiKey = str(engine.apiKey);
81
+ if (apiKey !== undefined && isEnvReference(apiKey))
82
+ connection.apiKey = apiKey;
83
+ else if (apiKey !== undefined || engine.apiKeyFile !== undefined) {
84
+ converted.keyHolders.push({ engine: name, field: engine.apiKeyFile !== undefined ? "apiKeyFile" : "apiKey" });
85
+ }
86
+ else {
87
+ const variables = implicitKeyVariables(name, defaults);
88
+ const variable = variables.find((candidate) => env?.[candidate]?.trim());
89
+ if (variable !== undefined)
90
+ connection.apiKey = `$${variable}`;
91
+ else {
92
+ conversion.notes.push(`engines.${name}: it names no key, and ${variables.join(" or ")}, which it used to read when set, is not set here, so the connection has no key. If the endpoint needs one, set the variable and run \`akm setup --api-key-env <VARIABLE>\`, or store the key with \`akm setup\`.`);
93
+ }
94
+ }
95
+ }
96
+ /** `engines.<name>` with `kind: "llm"`: `connections.<name>`. */
97
+ function llmEngineToConnection(name, engine, defaults, env, converted, conversion) {
98
+ const connection = {};
99
+ for (const key of CARRIED)
100
+ if (engine[key] !== undefined)
101
+ connection[key] = engine[key];
102
+ carryEngineKey(name, engine, connection, defaults, env, converted, conversion);
103
+ const model = str(engine.model);
104
+ if (model !== undefined)
105
+ converted.ownModelOf.push({ kind: "connections", engine: name, model });
106
+ if (engine.provider !== undefined) {
107
+ conversion.notes.push(`engines.${name}: provider is not a setting any more (akm does not branch on it); it is dropped.`);
108
+ }
109
+ if (engine.supportsJsonSchema === false) {
110
+ conversion.notes.push(`engines.${name}: supportsJsonSchema is not a setting any more; akm retries without a schema when the endpoint rejects one.`);
111
+ }
112
+ Object.assign(connection, wireFieldsOf({
113
+ temperature: engine.temperature,
114
+ maxTokens: engine.maxTokens,
115
+ extraParams: engine.extraParams,
116
+ enableThinking: engine.enableThinking,
117
+ reasoningEffort: engine.reasoningEffort,
118
+ }, `engines.${name}`, conversion.notes));
119
+ converted.connections[name] = connection;
120
+ }
121
+ function convertEngines(engines, defaults, env, conversion) {
122
+ const converted = {
123
+ connections: {},
124
+ harnesses: {},
125
+ runtimes: new Map(),
126
+ keyHolders: [],
127
+ ownModelOf: [],
128
+ };
129
+ for (const [name, engine] of Object.entries(engines)) {
130
+ if (!isRecord(engine))
131
+ continue;
132
+ const unknown = Object.keys(engine).filter((k) => !(engine.kind === "agent" ? AGENT_ENGINE_KEYS : LLM_ENGINE_KEYS).has(k));
133
+ if (unknown.length > 0)
134
+ conversion.notes.push(`engines.${name}: dropped ${unknown.join(", ")}, which akm does not read.`);
135
+ if (engine.kind !== "agent")
136
+ llmEngineToConnection(name, engine, defaults, env, converted, conversion);
137
+ else if (engine.platform === "opencode-sdk")
138
+ runtimeEngine(name, engine, converted, conversion);
139
+ else
140
+ agentEngineToHarness(name, engine, converted);
141
+ }
142
+ return converted;
143
+ }
144
+ // ── the defaults are the entries named `default` ─────────────────────────────
145
+ /**
146
+ * The name each of `names` has once `from` is called `default`. An existing `default` moves aside to
147
+ * `legacy-default`, or the first `legacy-default-<n>` that nothing else (an engine, or an entry the file writes
148
+ * itself under `taken`) already has, so no two entries ever share a name and none is lost.
149
+ */
150
+ function renameMap(names, taken, from) {
151
+ const moved = new Map();
152
+ if (from !== undefined && from !== "default") {
153
+ moved.set(from, "default");
154
+ if (names.includes("default")) {
155
+ const used = new Set([...names, ...taken]);
156
+ let aside = "legacy-default";
157
+ for (let n = 2; used.has(aside); n += 1)
158
+ aside = `legacy-default-${n}`;
159
+ moved.set("default", aside);
160
+ }
161
+ }
162
+ return (name) => moved.get(name) ?? name;
163
+ }
164
+ /** `defaults.llmEngine`, else `defaults.engine`: that connection is `default`; `defaults.engine` naming one of several harnesses: that harness is. */
165
+ function nameDefaults(defaults, converted, conversion, written) {
166
+ const { connections, harnesses, runtimes, keyHolders } = converted;
167
+ const defaultEngine = str(defaults.engine);
168
+ const runtimeLlm = defaultEngine === undefined ? undefined : runtimes.get(defaultEngine);
169
+ const defaultConnection = [str(defaults.llmEngine), defaultEngine, runtimeLlm].find((n) => n !== undefined && n in connections);
170
+ const defaultHarness = defaultEngine !== undefined && defaultEngine in harnesses && Object.keys(harnesses).length > 1
171
+ ? defaultEngine
172
+ : undefined;
173
+ const connectionName = renameMap(Object.keys(connections), Object.keys(written.connections), defaultConnection);
174
+ const harnessName = renameMap(Object.keys(harnesses), Object.keys(written.harnesses), defaultHarness);
175
+ const renamed = (entries, name) => Object.fromEntries(Object.entries(entries).map(([engine, entry]) => [name(engine), entry]));
176
+ const named = {
177
+ connections: renamed(connections, connectionName),
178
+ harnesses: renamed(harnesses, harnessName),
179
+ };
180
+ const defaultHarnessName = "default" in named.harnesses
181
+ ? "default"
182
+ : Object.keys(named.harnesses).length === 1
183
+ ? Object.keys(named.harnesses)[0]
184
+ : undefined;
185
+ if (defaultHarnessName !== undefined && (defaultEngine === undefined || runtimes.has(defaultEngine))) {
186
+ conversion.notes.push(`Agent work ran on akm's own runtime${defaultEngine === undefined ? "" : ` (engines.${defaultEngine})`}; with the harness "${defaultHarnessName}" configured it now runs there. Remove that harness to keep agent work on akm's runtime.`);
187
+ }
188
+ for (const [kind, rename] of [
189
+ ["connections", connectionName],
190
+ ["harnesses", harnessName],
191
+ ]) {
192
+ const aside = rename("default");
193
+ if (aside === "default")
194
+ continue;
195
+ conversion.notes.push(`engines.default is now ${kind}.${aside}, and "default" names another engine: an engine: default key is rewritten by \`akm migrate apply\` where it can be, but a script or scheduled command that passes --engine default now reaches the new "default"; change it to the name ${aside}.`);
196
+ }
197
+ const target = (engine) => {
198
+ if (runtimes.has(engine)) {
199
+ const runtime = runtimes.get(engine);
200
+ return runtime !== undefined && runtime in connections ? { connection: connectionName(runtime) } : undefined;
201
+ }
202
+ if (engine in harnesses)
203
+ return { harness: harnessName(engine) };
204
+ if (engine in connections)
205
+ return { connection: connectionName(engine) };
206
+ return { connection: engine };
207
+ };
208
+ const keys = keyHolders.map(({ engine, field }) => ({
209
+ engine,
210
+ connection: connectionName(engine),
211
+ field,
212
+ }));
213
+ return { defaultConnection, defaultHarness, connectionName, harnessName, ...named, keys, target };
214
+ }
215
+ /** What the file writes under `connections` / `harnesses` itself, read with the converted entries: the written entry wins field by field. */
216
+ function mergeWritten(out, naming) {
217
+ for (const [name, harness] of Object.entries(naming.harnesses)) {
218
+ if (harness.platform === name)
219
+ delete harness.platform;
220
+ }
221
+ return {
222
+ connections: deepMergeConfig(naming.connections, asDict(out.connections)),
223
+ harnesses: deepMergeConfig(naming.harnesses, asDict(out.harnesses)),
224
+ };
225
+ }
226
+ function ownModelsOf(converted, naming) {
227
+ const ownModels = { connections: new Map(), harnesses: new Map() };
228
+ for (const { kind, engine, model } of converted.ownModelOf) {
229
+ ownModels[kind].set(kind === "connections" ? naming.connectionName(engine) : naming.harnessName(engine), model);
230
+ }
231
+ return ownModels;
232
+ }
233
+ // ── the whole conversion ─────────────────────────────────────────────────────
234
+ export function convertEngineConfig(raw, options = {}) {
235
+ const out = structuredClone(raw);
236
+ const engines = asDict(out.engines);
237
+ const defaults = asDict(out.defaults);
238
+ const conversion = {
239
+ notes: [],
240
+ changed: out.engines !== undefined || out.defaults !== undefined,
241
+ };
242
+ const converted = convertEngines(engines, defaults, options.env, conversion);
243
+ const naming = nameDefaults(defaults, converted, conversion, {
244
+ connections: asDict(out.connections),
245
+ harnesses: asDict(out.harnesses),
246
+ });
247
+ const merged = mergeWritten(out, naming);
248
+ const ownModels = ownModelsOf(converted, naming);
249
+ foldModelsOverlay(options.modelsOverlay, {
250
+ conversion,
251
+ merged,
252
+ ownModels,
253
+ written: { connections: asDict(out.connections), harnesses: asDict(out.harnesses) },
254
+ inherited: { connections: options.inherited?.connections ?? {}, harnesses: options.inherited?.harnesses ?? {} },
255
+ renamed: {
256
+ runtime: [...converted.runtimes.values()]
257
+ .filter((name) => name !== undefined && name in converted.connections)
258
+ .map((name) => naming.connectionName(name)),
259
+ connection: (engine) => (engine in converted.connections ? naming.connectionName(engine) : undefined),
260
+ },
261
+ });
262
+ foldEngineModels(merged, ownModels);
263
+ const retarget = retargeter(conversion, naming.target);
264
+ const improve = out.improve;
265
+ if (isRecord(improve))
266
+ moveStrategyExecution(improve, conversion, retarget);
267
+ improveStrategyDefault(out, defaults, improve);
268
+ dropJudgeEngine(out, conversion);
269
+ convertIndexEngines(out, conversion, retarget);
270
+ // Assemble, keeping the file's key order.
271
+ const config = {};
272
+ let placed = false;
273
+ for (const [key, value] of Object.entries(out)) {
274
+ if (key === "defaults")
275
+ continue;
276
+ if (key !== "engines" && key !== "connections" && key !== "harnesses") {
277
+ config[key] = value;
278
+ }
279
+ else if (!placed) {
280
+ placed = true;
281
+ if (Object.keys(merged.connections).length > 0)
282
+ config.connections = merged.connections;
283
+ if (Object.keys(merged.harnesses).length > 0)
284
+ config.harnesses = merged.harnesses;
285
+ }
286
+ }
287
+ const targets = {};
288
+ for (const name of Object.keys(engines).filter((engine) => isRecord(engines[engine]))) {
289
+ const became = naming.target(name);
290
+ if (became !== undefined)
291
+ targets[name] = became;
292
+ }
293
+ return {
294
+ config: conversion.changed ? config : raw,
295
+ notes: conversion.notes,
296
+ changed: conversion.changed,
297
+ keys: naming.keys,
298
+ targets,
299
+ };
300
+ }
@@ -0,0 +1,137 @@
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
+ * `models.json`, and an engine's own `model`, folded into the `models` of the connections
6
+ * and harnesses the engines became. See `convert-engines.ts`.
7
+ */
8
+ import { getHarness } from "../../integrations/harnesses/index.js";
9
+ import { isRecord } from "../common.js";
10
+ import { str, wireFieldsOf } from "./convert-engines-shared.js";
11
+ import { modelForEveryAlias } from "./model-aliases.js";
12
+ const allAliases = (model) => model === undefined ? undefined : modelForEveryAlias(model);
13
+ /** An overlay entry as a model entry: the bare name, or `{ model, ...fields }` when it sets more. */
14
+ function modelEntry(model, fields) {
15
+ return Object.keys(fields).length > 0 ? { model, ...fields } : model;
16
+ }
17
+ // ── models.json folds into the models of what it named ───────────────────────
18
+ /** The models of `entry`, made on it when it has none yet. */
19
+ function modelsOf(entry) {
20
+ entry.models ??= {};
21
+ return entry.models;
22
+ }
23
+ const hasModel = (entry, alias) => isRecord(entry) && isRecord(entry.models) && alias in entry.models;
24
+ /**
25
+ * The overlay's rows: one per alias and column, the runtime's column first (it is the weakest, naming OpenCode's own
26
+ * models), then a connection's own, then `*`, which fills what is left. The flat shorthand is the `*` column.
27
+ */
28
+ function overlayRows(modelsOverlay) {
29
+ const overlay = isRecord(modelsOverlay) && isRecord(modelsOverlay.aliases) ? modelsOverlay.aliases : {};
30
+ const rows = Object.entries(overlay).flatMap(([alias, columns]) => {
31
+ if (!isRecord(columns))
32
+ return [];
33
+ const flat = Object.fromEntries(Object.entries(columns).filter(([k]) => k === "model" || k === "inference" || k === "engine"));
34
+ const perColumn = Object.entries(columns).filter(([k]) => !(k in flat));
35
+ return [...perColumn, ...(Object.keys(flat).length > 0 ? [["*", flat]] : [])].map(([column, profile]) => ({
36
+ alias,
37
+ column,
38
+ profile,
39
+ }));
40
+ });
41
+ const rank = (column) => (column === "opencode-sdk" ? 0 : column === "*" ? 2 : 1);
42
+ return rows.sort((a, b) => rank(a.column) - rank(b.column));
43
+ }
44
+ /**
45
+ * `models.json`: an alias is set by, nearest first, the config's own `models`, models.json's column for that
46
+ * connection or harness, models.json's `*` column (and the flat shorthand, which is that), the engine's own model.
47
+ */
48
+ export function foldModelsOverlay(modelsOverlay, fold) {
49
+ const { conversion, merged, written, inherited, ownModels, renamed } = fold;
50
+ const { notes } = conversion;
51
+ const mergedConnections = merged.connections;
52
+ const mergedHarnesses = merged.harnesses;
53
+ const inheritedConnections = inherited.connections;
54
+ const inheritedHarnesses = inherited.harnesses;
55
+ const writtenConnections = written.connections;
56
+ const writtenHarnesses = written.harnesses;
57
+ /** Whether the config itself, the file or its base, already names a model for the alias. */
58
+ const configNames = (own, base, name, alias) => hasModel(own[name], alias) || hasModel(base[name], alias);
59
+ const platformOf = (name) => String((mergedHarnesses[name] ?? inheritedHarnesses[name])?.platform ?? name);
60
+ let folded = false;
61
+ for (const { alias, column, profile } of overlayRows(modelsOverlay)) {
62
+ const p = typeof profile === "string" ? { model: profile } : isRecord(profile) ? profile : {};
63
+ const { effort, ...portable } = (isRecord(p.inference) ? p.inference : {});
64
+ const where = `models.json ${alias}.${column === "*" ? "(all)" : column}`;
65
+ const wire = wireFieldsOf({ ...portable, reasoningEffort: portable.reasoningEffort ?? effort }, where, notes);
66
+ if (p.engine !== undefined) {
67
+ notes.push(`${where}: an engine indirection is not carried over.`);
68
+ continue;
69
+ }
70
+ const candidates = column === "*"
71
+ ? [...new Set([...Object.keys(mergedConnections), ...Object.keys(inheritedConnections)])]
72
+ : column === "opencode-sdk"
73
+ ? [...renamed.runtime]
74
+ : renamed.connection(column) !== undefined
75
+ ? [renamed.connection(column)]
76
+ : column in writtenConnections || column in inheritedConnections
77
+ ? [column]
78
+ : [];
79
+ const harnessNamed = [...new Set([...Object.keys(mergedHarnesses), ...Object.keys(inheritedHarnesses)])].filter((name) => platformOf(name) === column);
80
+ if (candidates.length === 0 && harnessNamed.length === 0) {
81
+ notes.push(`${where}: names no configured connection or harness, so it is not carried over.`);
82
+ continue;
83
+ }
84
+ // The config's own choice stands, and `*` leaves what an explicit column already set.
85
+ const connectionNames = candidates.filter((name) => !configNames(writtenConnections, inheritedConnections, name, alias) &&
86
+ !(column === "*" && hasModel(mergedConnections[name], alias)));
87
+ const harnessNames = harnessNamed.filter((name) => !configNames(writtenHarnesses, inheritedHarnesses, name, alias));
88
+ if (connectionNames.length === 0 && harnessNames.length === 0) {
89
+ // Only the config's own choice is worth a note; an explicit column that came first is the overlay's own.
90
+ const keptByConfig = candidates.some((name) => configNames(writtenConnections, inheritedConnections, name, alias)) ||
91
+ harnessNamed.some((name) => configNames(writtenHarnesses, inheritedHarnesses, name, alias));
92
+ if (keptByConfig)
93
+ notes.push(`${where}: the config already names a model for it, so it is not carried over.`);
94
+ continue;
95
+ }
96
+ for (const name of connectionNames) {
97
+ const current = mergedConnections[name]?.models;
98
+ const existing = current?.[alias];
99
+ const model = str(p.model) ?? str(isRecord(existing) ? existing.model : existing) ?? ownModels.connections.get(name);
100
+ if (model === undefined)
101
+ continue;
102
+ // A connection only the base defines gets a partial entry here; the base completes it.
103
+ mergedConnections[name] ??= {};
104
+ modelsOf(mergedConnections[name])[alias] = modelEntry(model, wire);
105
+ folded = true;
106
+ }
107
+ for (const name of harnessNames) {
108
+ const model = str(p.model) ?? str(getHarness(platformOf(name))?.models?.[alias]);
109
+ if (model === undefined)
110
+ continue;
111
+ mergedHarnesses[name] ??= {};
112
+ modelsOf(mergedHarnesses[name])[alias] = model;
113
+ folded = true;
114
+ if (Object.keys(wire).length > 0)
115
+ notes.push(`${where}: a harness takes the model only; the inference settings are not carried over.`);
116
+ }
117
+ }
118
+ if (folded)
119
+ conversion.changed = true;
120
+ }
121
+ /** An engine's `model`: every alias nothing else named is that model, on the entry the engine became. */
122
+ export function foldEngineModels(merged, ownModels) {
123
+ for (const [kind, entries] of [
124
+ ["connections", merged.connections],
125
+ ["harnesses", merged.harnesses],
126
+ ]) {
127
+ for (const [name, model] of ownModels[kind]) {
128
+ const entry = entries[name];
129
+ if (!isRecord(entry))
130
+ continue;
131
+ for (const [alias, value] of Object.entries(allAliases(model) ?? {})) {
132
+ if (!hasModel(entry, alias))
133
+ modelsOf(entry)[alias] = value;
134
+ }
135
+ }
136
+ }
137
+ }