akm-cli 0.9.31 → 0.10.261002-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 (270) hide show
  1. package/CHANGELOG.md +420 -0
  2. package/STABILITY.md +99 -57
  3. package/dist/api-node.mjs +20 -0
  4. package/dist/api.d.ts +23 -0
  5. package/dist/api.js +45 -0
  6. package/dist/assets/hints/cli-hints-full.md +15 -29
  7. package/dist/assets/hints/cli-hints-short.md +2 -2
  8. package/dist/assets/improve-strategies/default.json +3 -3
  9. package/dist/assets/prompts/consolidate-pair.md +9 -7
  10. package/dist/assets/stash-skeleton/README.md +1 -1
  11. package/dist/assets/tasks/improve/akm-improve-consolidate.yml +1 -1
  12. package/dist/cli/shared.js +31 -48
  13. package/dist/cli/unknown-flags.js +6 -43
  14. package/dist/cli.js +8 -34
  15. package/dist/commands/agent/contribute-cli.js +1 -1
  16. package/dist/commands/completions.js +1 -2
  17. package/dist/commands/config-cli.js +5 -28
  18. package/dist/commands/env/env-cli.js +5 -5
  19. package/dist/commands/env/secret-cli.js +2 -2
  20. package/dist/commands/feedback-cli.js +75 -49
  21. package/dist/commands/health/checks.js +41 -16
  22. package/dist/commands/health/plugin-staleness.js +52 -22
  23. package/dist/commands/improve/autonomy-gate.js +5 -3
  24. package/dist/commands/improve/consolidate/chunking.js +3 -10
  25. package/dist/commands/improve/consolidate/continuity-check.js +4 -4
  26. package/dist/commands/improve/consolidate/pair-pass.js +29 -10
  27. package/dist/commands/improve/consolidate.js +10 -65
  28. package/dist/commands/improve/distill/lesson-update.js +91 -0
  29. package/dist/commands/improve/distill-guards.js +1 -43
  30. package/dist/commands/improve/distill.js +148 -21
  31. package/dist/commands/improve/eligibility.js +14 -1
  32. package/dist/commands/improve/extract-cli.js +1 -1
  33. package/dist/commands/improve/extract-prompt.js +17 -7
  34. package/dist/commands/improve/extract.js +5 -7
  35. package/dist/commands/improve/improve-cli.js +92 -106
  36. package/dist/commands/improve/improve-strategies.js +8 -12
  37. package/dist/commands/improve/improve.js +134 -52
  38. package/dist/commands/improve/loop-stages.js +18 -5
  39. package/dist/commands/improve/planner.js +0 -1
  40. package/dist/commands/improve/preparation.js +40 -99
  41. package/dist/commands/improve/proactive-maintenance.js +2 -2
  42. package/dist/commands/improve/reflect-noise.js +3 -55
  43. package/dist/commands/improve/reflect.js +29 -34
  44. package/dist/commands/improve/retrieval-queries.js +37 -0
  45. package/dist/commands/improve/retrieval-scope.js +2 -2
  46. package/dist/commands/improve/salience.js +2 -9
  47. package/dist/commands/improve/session-asset.js +4 -1
  48. package/dist/commands/improve/stage.js +23 -12
  49. package/dist/commands/lint/index.js +5 -20
  50. package/dist/commands/observability-cli.js +3 -9
  51. package/dist/commands/proposal/drain.js +43 -6
  52. package/dist/commands/proposal/proposal-cli.js +11 -31
  53. package/dist/commands/proposal/repository.js +20 -14
  54. package/dist/commands/proposal/validators/proposal-quality-validators.js +0 -3
  55. package/dist/commands/read/knowledge.js +3 -3
  56. package/dist/commands/read/remember-cli.js +0 -13
  57. package/dist/commands/read/search-cli.js +29 -97
  58. package/dist/commands/read/search.js +0 -11
  59. package/dist/commands/read/show.js +0 -19
  60. package/dist/commands/sources/plugin-upgrade.js +164 -101
  61. package/dist/commands/sources/sources-cli.js +1 -15
  62. package/dist/commands/sources/stash-cli.js +6 -14
  63. package/dist/commands/tasks/tasks-cli.js +4 -115
  64. package/dist/commands/workflow/plan.js +11 -33
  65. package/dist/commands/workflow-cli.js +2 -7
  66. package/dist/core/adapter/adapter-ids.js +1 -2
  67. package/dist/core/adapter/adapters/agent-skills-adapter.js +0 -4
  68. package/dist/core/adapter/adapters/akm-adapter.js +9 -48
  69. package/dist/core/adapter/adapters/akm-lint.js +10 -26
  70. package/dist/core/adapter/adapters/akm-metadata.js +2 -72
  71. package/dist/core/adapter/adapters/akm-task-adapter.js +0 -5
  72. package/dist/core/adapter/adapters/akm-workflow-adapter.js +9 -28
  73. package/dist/core/adapter/adapters/dotenv-adapter.js +1 -20
  74. package/dist/core/adapter/adapters/generic-files-adapter.js +0 -10
  75. package/dist/core/adapter/adapters/llm-wiki-adapter.js +0 -4
  76. package/dist/core/adapter/adapters/tool-dir-shared.js +0 -24
  77. package/dist/core/adapter/adapters/website-snapshot-adapter.js +4 -4
  78. package/dist/core/adapter/recognize-match.js +3 -4
  79. package/dist/core/common.js +18 -2
  80. package/dist/core/config/config-schema.js +12 -15
  81. package/dist/core/config/config-types.js +6 -15
  82. package/dist/core/config/config-walker.js +6 -23
  83. package/dist/core/config/config.js +17 -80
  84. package/dist/core/config/engine-semantics.js +7 -3
  85. package/dist/core/config/schema/engines.js +7 -7
  86. package/dist/core/config/schema/improve-processes.js +10 -63
  87. package/dist/core/config/schema/improve.js +2 -21
  88. package/dist/core/config/schema/index-config.js +6 -39
  89. package/dist/core/env-secret-ref.js +2 -45
  90. package/dist/core/errors.js +1 -2
  91. package/dist/core/extra-params.js +2 -86
  92. package/dist/core/file-lock.js +2 -6
  93. package/dist/core/improve-result.js +13 -1
  94. package/dist/core/mutation-target.js +2 -2
  95. package/dist/core/paths.js +4 -0
  96. package/dist/core/recognition-util.js +4 -5
  97. package/dist/core/run-lock.js +1 -1
  98. package/dist/core/subprocess.js +49 -0
  99. package/dist/core/warn.js +21 -4
  100. package/dist/core/write-source.js +3 -3
  101. package/dist/execution/target-ref.js +1 -2
  102. package/dist/indexer/indexer.js +15 -6
  103. package/dist/indexer/passes/memory-inference.js +15 -6
  104. package/dist/indexer/search/db-search.js +49 -36
  105. package/dist/indexer/search/fts-query.js +0 -19
  106. package/dist/indexer/search/ranking.js +29 -1
  107. package/dist/indexer/usage/usage-events.js +21 -16
  108. package/dist/integrations/agent/engine-resolution.js +5 -2
  109. package/dist/integrations/agent/index.js +1 -1
  110. package/dist/integrations/agent/profiles.js +41 -98
  111. package/dist/integrations/agent/request-lowering.js +3 -3
  112. package/dist/integrations/harnesses/aider/index.js +5 -0
  113. package/dist/integrations/harnesses/amazonq/index.js +1 -0
  114. package/dist/integrations/harnesses/claude/config-import.js +2 -3
  115. package/dist/integrations/harnesses/claude/index.js +5 -0
  116. package/dist/integrations/harnesses/codex/index.js +1 -0
  117. package/dist/integrations/harnesses/copilot/index.js +1 -0
  118. package/dist/integrations/harnesses/gemini/index.js +1 -0
  119. package/dist/integrations/harnesses/index.js +18 -39
  120. package/dist/integrations/harnesses/opencode/agent-builder.js +60 -35
  121. package/dist/integrations/harnesses/opencode/config-import.js +121 -52
  122. package/dist/integrations/harnesses/opencode/index.js +22 -0
  123. package/dist/integrations/harnesses/opencode/plugin-layout.js +68 -0
  124. package/dist/integrations/harnesses/opencode/session-log-types.js +12 -0
  125. package/dist/integrations/harnesses/opencode/session-log-v1.js +72 -0
  126. package/dist/integrations/harnesses/opencode/session-log-v2.js +140 -0
  127. package/dist/integrations/harnesses/opencode/session-log.js +104 -115
  128. package/dist/integrations/harnesses/opencode/version.js +98 -0
  129. package/dist/integrations/harnesses/opencode-sdk/{harness.js → index.js} +5 -17
  130. package/dist/integrations/harnesses/opencode-sdk/sdk-runner.js +105 -206
  131. package/dist/integrations/harnesses/opencode-sdk/v1-adapter.js +199 -0
  132. package/dist/integrations/harnesses/opencode-sdk/v2-adapter.js +254 -0
  133. package/dist/integrations/harnesses/opencode-sdk/wire.js +66 -0
  134. package/dist/integrations/harnesses/openhands/index.js +1 -0
  135. package/dist/integrations/harnesses/pi/index.js +1 -0
  136. package/dist/integrations/harnesses/shared.js +2 -0
  137. package/dist/integrations/harnesses/types.js +2 -0
  138. package/dist/llm/client.js +41 -11
  139. package/dist/output/cli-hints.js +1 -1
  140. package/dist/output/context.js +10 -19
  141. package/dist/output/format-exempt.js +5 -8
  142. package/dist/output/shapes/helpers.js +1 -22
  143. package/dist/output/shapes/passthrough.js +0 -1
  144. package/dist/output/shapes.js +3 -31
  145. package/dist/output/stdout.js +5 -1
  146. package/dist/output/text/command-format.js +6 -1
  147. package/dist/output/text/workflow-format.js +4 -22
  148. package/dist/scripts/akm-migrate-node.js +15745 -16711
  149. package/dist/scripts/akm-migrate.js +16318 -17280
  150. package/dist/setup/detect.js +10 -4
  151. package/dist/setup/harness-config-import.js +5 -14
  152. package/dist/setup/setup.js +1 -1
  153. package/dist/setup/steps/tasks.js +12 -13
  154. package/dist/sources/providers/git-stash.js +113 -16
  155. package/dist/storage/repositories/index-utility-repository.js +2 -32
  156. package/dist/storage/repositories/index-vec-repository.js +4 -0
  157. package/dist/storage/repositories/task-history-repository.js +0 -5
  158. package/dist/storage/repositories/workflow-runs-repository.js +5 -15
  159. package/dist/tasks/embedded.js +2 -1
  160. package/dist/tasks/run/run-command-task.js +9 -1
  161. package/dist/tasks/run/run-workflow-task.js +4 -3
  162. package/dist/tasks/run/task-history.js +0 -2
  163. package/dist/tasks/run/task-log.js +38 -1
  164. package/dist/tasks/schedule-gates.js +39 -0
  165. package/dist/tasks/scheduler-binding.js +0 -16
  166. package/dist/tasks/scheduler-sync.js +3 -97
  167. package/dist/tasks/source/bounded-document.js +1 -1
  168. package/dist/tasks/source/task-source-v4.js +2 -12
  169. package/dist/tasks/task-run-reserved-flags.js +2 -31
  170. package/dist/workflows/authoring/authoring.js +6 -6
  171. package/dist/workflows/compile.js +8 -65
  172. package/dist/workflows/exec/child-workflow.js +22 -3
  173. package/dist/workflows/exec/native-executor.js +12 -147
  174. package/dist/workflows/exec/run-workflow.js +31 -103
  175. package/dist/workflows/exec/step-work.js +9 -178
  176. package/dist/workflows/exec/unit-dispatch.js +0 -10
  177. package/dist/workflows/freeze/environment.js +3 -44
  178. package/dist/workflows/freeze/freeze.js +8 -41
  179. package/dist/workflows/freeze/targets/child-workflow.js +27 -63
  180. package/dist/workflows/freeze/targets/command.js +2 -16
  181. package/dist/workflows/freeze/targets/shell.js +0 -2
  182. package/dist/workflows/freeze/task-bindings.js +2 -28
  183. package/dist/workflows/ir/params.js +12 -2
  184. package/dist/workflows/parser.js +82 -232
  185. package/dist/workflows/plan.js +1 -1
  186. package/dist/workflows/renderer.js +10 -19
  187. package/dist/workflows/runtime/run-plan.js +11 -53
  188. package/dist/workflows/runtime/runs.js +4 -27
  189. package/dist/workflows/source-files.js +12 -16
  190. package/dist/workflows/source-semantics.js +1 -93
  191. package/docs/README.md +1 -1
  192. package/docs/agents/README.md +3 -3
  193. package/docs/agents/agent-install.md +1 -1
  194. package/docs/architecture/0.10-process-rules.md +827 -0
  195. package/docs/architecture/adapters.md +17 -31
  196. package/docs/architecture/architecture.md +4 -5
  197. package/docs/architecture/improvement.md +115 -76
  198. package/docs/architecture/internals/improve-workflow.md +22 -16
  199. package/docs/architecture/internals/indexing.md +1 -1
  200. package/docs/architecture/internals/search.md +1 -2
  201. package/docs/architecture/internals/storage-locations.md +6 -6
  202. package/docs/architecture/persisted-data-compat.md +13 -4
  203. package/docs/architecture/specs/0.9.0-decisions.md +6 -2
  204. package/docs/architecture/specs/improve-collapse-churn-detector-design.md +2 -2
  205. package/docs/architecture/specs/workflow-format-unification.md +1 -6
  206. package/docs/architecture/testing/manual-testing-checklist.md +21 -30
  207. package/docs/architecture/testing/task-workflow-manual-tests.md +106 -203
  208. package/docs/architecture/testing/testing-workflow.md +1 -1
  209. package/docs/architecture/workflow-engine.md +5 -56
  210. package/docs/guides/author-workflows.md +39 -69
  211. package/docs/guides/bundles.md +3 -1
  212. package/docs/guides/capture-knowledge.md +1 -1
  213. package/docs/guides/claude-code-vs-akm-workflows.md +1 -2
  214. package/docs/guides/discover-and-load.md +4 -4
  215. package/docs/guides/getting-started.md +1 -1
  216. package/docs/guides/improve-the-library.md +10 -9
  217. package/docs/guides/recipes/headless-install.md +2 -2
  218. package/docs/guides/run-workflows.md +1 -1
  219. package/docs/guides/scheduling.md +9 -1
  220. package/docs/guides/use-with-any-agent.md +49 -4
  221. package/docs/integration/bundling-akm.md +7 -6
  222. package/docs/maintainers/curate-workmap.md +1 -2
  223. package/docs/maintainers/release-checklist.md +33 -1
  224. package/docs/migration/README.md +2 -0
  225. package/docs/migration/release-notes/0.10.0.md +201 -0
  226. package/docs/migration/release-notes/README.md +1 -0
  227. package/docs/migration/v0.9-to-v0.10.md +507 -0
  228. package/docs/posts/akm-command-tour.md +3 -3
  229. package/docs/product-surface.md +1 -1
  230. package/docs/reference/README.md +1 -0
  231. package/docs/reference/api.md +65 -0
  232. package/docs/reference/asset-types.md +3 -5
  233. package/docs/reference/bundle-types.md +2 -4
  234. package/docs/reference/cli.md +160 -188
  235. package/docs/reference/configuration.md +101 -20
  236. package/docs/reference/data-and-telemetry.md +2 -2
  237. package/docs/reference/env-and-secrets.md +2 -2
  238. package/docs/reference/supported-formats.md +3 -4
  239. package/docs/reference/tasks.md +12 -19
  240. package/docs/reference/website-sources.md +1 -1
  241. package/docs/reference/workflow-schema.md +89 -317
  242. package/docs/reference/workflows.md +20 -48
  243. package/package.json +12 -2
  244. package/schemas/akm-config.json +2 -243
  245. package/schemas/akm-task.json +2 -3
  246. package/schemas/akm-workflow.json +47 -84
  247. package/dist/assets/improve-strategies/catchup.json +0 -41
  248. package/dist/assets/improve-strategies/proactive-maintenance.json +0 -24
  249. package/dist/assets/improve-strategies/quick.json +0 -17
  250. package/dist/assets/improve-strategies/reflect-distill.json +0 -29
  251. package/dist/assets/improve-strategies/thorough.json +0 -49
  252. package/dist/assets/prompts/retrieval-relevance-judge.md +0 -6
  253. package/dist/assets/tasks/improve/akm-improve-catchup.yml +0 -6
  254. package/dist/assets/tasks/improve/akm-improve-frequent.yml +0 -4
  255. package/dist/assets/tasks/improve/akm-improve-nightly.yml +0 -4
  256. package/dist/cli/retired-commands.js +0 -118
  257. package/dist/commands/improve/retrieval-gate.js +0 -132
  258. package/dist/commands/tasks/validate.js +0 -176
  259. package/dist/core/config/legacy-source-shape-shim.js +0 -117
  260. package/dist/indexer/feedback/utility-policy.js +0 -75
  261. package/dist/integrations/harnesses/ids.js +0 -28
  262. package/dist/tasks/source/task-source-v3-frozen.js +0 -424
  263. package/dist/tasks/source/task-to-v4.js +0 -863
  264. package/dist/workflows/exec/worktree.js +0 -372
  265. package/dist/workflows/freeze/child-output-references.js +0 -83
  266. package/dist/workflows/freeze/identity.js +0 -22
  267. package/dist/workflows/freeze/targets/script.js +0 -50
  268. package/dist/workflows/freeze/targets/task.js +0 -124
  269. package/dist/workflows/github-yaml.js +0 -506
  270. package/dist/workflows/runtime/run-outputs.js +0 -80
@@ -8,116 +8,59 @@
8
8
  * coding-agent CLI. Named engines lower canonical harness metadata into this
9
9
  * intentionally small internal shape. The wrapper is in `./spawn.ts`.
10
10
  */
11
- import { COMMON_SPAWN_ENV_PASSTHROUGH, OPENCODE_ENV_PASSTHROUGH } from "../../core/spawn-env.js";
12
- // AKM_EVENT_SOURCE carries usage-event provenance (improve/task) so that akm
13
- // invocations a spawned agent makes are recorded as machine traffic, not user
14
- // demand (DRIFT-6). Without it in the passthrough whitelist, buildChildEnv drops
15
- // the stamp at the agent boundary — e.g. `akm wiki ingest` spawns an agent whose
16
- // `akm curate/show/search` tool-calls then log source='user', silently inflating
17
- // every lane's read-back (GRR). It is a provenance tag, never a secret.
18
- const COMMON_PASSTHROUGH = COMMON_SPAWN_ENV_PASSTHROUGH;
11
+ import { COMMON_SPAWN_ENV_PASSTHROUGH } from "../../core/spawn-env.js";
12
+ import { HARNESS_REGISTRY } from "../harnesses/index.js";
19
13
  /**
20
- * Built-in profiles for the agent CLIs akm knows out of the box: the five the
21
- * v1 spec calls out explicitly, plus the P2 harness adapters (copilot, pi,
22
- * amazonq, openhands — plan §"Capability matrix"). The fields here are
23
- * conservative defaults — every value is overridable from user config.
14
+ * Built-in profiles for the agent CLIs akm knows out of the box, DERIVED from
15
+ * the harness registry: each harness that declares `profile` defaults gets one,
16
+ * named by its id. The fields are conservative defaults, overridable from user
17
+ * config. Engine lowering selects captured stdio for unattended dispatch.
24
18
  *
25
- * Engine lowering selects captured stdio for unattended dispatch.
19
+ * Built lazily: the registry transitively imports this module, so it cannot be
20
+ * read at module load.
26
21
  */
27
- const BUILTINS = {
28
- opencode: {
29
- name: "opencode",
30
- bin: "opencode",
31
- args: ["run"],
32
- stdio: "interactive",
33
- envPassthrough: [...COMMON_PASSTHROUGH, ...OPENCODE_ENV_PASSTHROUGH],
34
- parseOutput: "text",
35
- },
36
- claude: {
37
- name: "claude",
38
- bin: "claude",
39
- args: [],
40
- stdio: "interactive",
41
- envPassthrough: [...COMMON_PASSTHROUGH, "ANTHROPIC_API_KEY", "CLAUDE_CONFIG"],
42
- parseOutput: "text",
43
- },
44
- codex: {
45
- name: "codex",
46
- bin: "codex",
47
- args: [],
48
- stdio: "interactive",
49
- envPassthrough: [...COMMON_PASSTHROUGH, "OPENAI_API_KEY", "CODEX_CONFIG"],
50
- parseOutput: "text",
51
- },
52
- gemini: {
53
- name: "gemini",
54
- bin: "gemini",
55
- args: [],
56
- stdio: "interactive",
57
- envPassthrough: [...COMMON_PASSTHROUGH, "GEMINI_API_KEY", "GOOGLE_API_KEY"],
58
- parseOutput: "text",
59
- },
60
- aider: {
61
- name: "aider",
62
- bin: "aider",
63
- args: ["--no-auto-commits"],
64
- stdio: "interactive",
65
- envPassthrough: [...COMMON_PASSTHROUGH, "OPENAI_API_KEY", "ANTHROPIC_API_KEY"],
66
- parseOutput: "text",
67
- },
68
- // ── P2 harness-adapter profiles (plan §"Capability matrix") ────────────────
69
- copilot: {
70
- name: "copilot",
71
- bin: "copilot",
72
- args: [],
73
- stdio: "interactive",
74
- envPassthrough: [...COMMON_PASSTHROUGH, "GH_TOKEN", "GITHUB_TOKEN"],
75
- parseOutput: "text",
76
- },
77
- pi: {
78
- name: "pi",
79
- bin: "pi",
80
- args: [],
81
- stdio: "interactive",
82
- envPassthrough: [...COMMON_PASSTHROUGH, "PI_API_KEY", "ANTHROPIC_API_KEY", "OPENAI_API_KEY"],
83
- parseOutput: "text",
84
- },
85
- amazonq: {
86
- name: "amazonq",
87
- bin: "q",
88
- args: [],
89
- stdio: "interactive",
90
- envPassthrough: [...COMMON_PASSTHROUGH, "AWS_PROFILE", "AWS_REGION"],
91
- parseOutput: "text",
92
- },
93
- openhands: {
94
- name: "openhands",
95
- bin: "openhands",
96
- args: [],
97
- stdio: "interactive",
98
- envPassthrough: [...COMMON_PASSTHROUGH, "LLM_MODEL", "LLM_API_KEY", "LLM_BASE_URL"],
99
- parseOutput: "text",
100
- },
101
- };
22
+ let builtins;
23
+ function builtinProfiles() {
24
+ if (builtins)
25
+ return builtins;
26
+ builtins = {};
27
+ for (const harness of HARNESS_REGISTRY) {
28
+ if (!harness.profile)
29
+ continue;
30
+ builtins[harness.id] = {
31
+ name: harness.id,
32
+ bin: harness.profile.bin,
33
+ args: harness.profile.args,
34
+ stdio: "interactive",
35
+ // AKM_EVENT_SOURCE (in the common set) carries usage-event provenance so akm
36
+ // invocations a spawned agent makes are recorded as machine traffic; it is a
37
+ // provenance tag, never a secret.
38
+ envPassthrough: [...COMMON_SPAWN_ENV_PASSTHROUGH, ...harness.profile.envPassthrough],
39
+ parseOutput: "text",
40
+ };
41
+ }
42
+ return builtins;
43
+ }
102
44
  /**
103
45
  * Binary the `opencode-sdk` harness needs on PATH.
104
46
  *
105
- * The embedded SDK is not self-contained, and that is the SDK's own design
106
- * rather than a consequence of how akm drives it: `@opencode-ai/sdk` ships
107
- * with `"dependencies": {}` and its `createOpencodeServer` is itself a
108
- * `spawn("opencode", ["serve", ...])`. akm's runner spawns the same binary
109
- * directly and talks HTTP to it (see `harnesses/opencode-sdk/sdk-runner.ts`),
47
+ * The embedded client is not self-contained, and that is the SDK's own design
48
+ * rather than a consequence of how akm drives it: `@opencode-ai/sdk` (OpenCode 1)
49
+ * ships with `"dependencies": {}` and its `createOpencodeServer` is itself a
50
+ * `spawn("opencode", ["serve", ...])`; `@opencode/client` (OpenCode 2, the
51
+ * default) is an HTTP client only and starts nothing. akm's runner spawns a
52
+ * private `opencode serve` of the engine's detected major (
53
+ * never the v2 background service) and talks HTTP to it through that major's
54
+ * adapter (see `harnesses/opencode-sdk/sdk-runner.ts`, `v1-adapter.ts`, `v2-adapter.ts`),
110
55
  * so the `opencode` binary gates the SDK path exactly as it gates the CLI
111
56
  * path — a host with the npm package but no binary can dispatch neither.
112
- * `opencode-sdk` deliberately has no {@link BUILTINS} entry — it dispatches
57
+ * `opencode-sdk` deliberately declares no `profile` — it dispatches
113
58
  * without argv construction — so this is the one place that pairing lives.
114
59
  */
115
60
  export const OPENCODE_SDK_SERVER_BIN = "opencode";
116
- /** Names of the canonical built-in harness descriptors. Stable, sorted. */
117
- export const BUILTIN_AGENT_PROFILE_NAMES = Object.freeze(Object.keys(BUILTINS).sort());
118
61
  /** Returns the built-in descriptor for a canonical harness id. */
119
62
  export function getBuiltinAgentProfile(name) {
120
- return BUILTINS[name];
63
+ return builtinProfiles()[name];
121
64
  }
122
65
  /**
123
66
  * Return a copy of every canonical built-in descriptor keyed by harness id.
@@ -125,7 +68,7 @@ export function getBuiltinAgentProfile(name) {
125
68
  */
126
69
  export function listBuiltinAgentProfiles() {
127
70
  const out = {};
128
- for (const [name, profile] of Object.entries(BUILTINS)) {
71
+ for (const [name, profile] of Object.entries(builtinProfiles())) {
129
72
  out[name] = { ...profile };
130
73
  }
131
74
  return out;
@@ -4,7 +4,7 @@
4
4
  import { ConfigError } from "../../core/errors.js";
5
5
  import { withSchemaInstruction } from "../../core/structured.js";
6
6
  import { MODEL_WORK_POLICY_ID } from "../../execution/source.js";
7
- import { HARNESS_MODEL_WORK_IDS, HARNESS_NATIVE_AGENT_IDS } from "../harnesses/ids.js";
7
+ import { getHarness } from "../harnesses/index.js";
8
8
  import { composeConversationFallbackPrompt } from "./conversation-fallback.js";
9
9
  import { composePersonaFallbackPrompt } from "./persona-fallback.js";
10
10
  /** A tool selection that actually names tools (not omitted, null, or empty). */
@@ -77,7 +77,7 @@ export function createAgentRequestLowerer(options) {
77
77
  }
78
78
  }
79
79
  else if (typeof request.agent === "string") {
80
- if (!HARNESS_NATIVE_AGENT_IDS.has(options.adapter)) {
80
+ if (!getHarness(options.adapter)?.capabilities.nativeAgent) {
81
81
  throw new ConfigError(`The ${options.adapter} transport cannot consume native agent selector ${JSON.stringify(request.agent)}.`, "INVALID_CONFIG_FILE");
82
82
  }
83
83
  dispatch.agent = request.agent;
@@ -99,7 +99,7 @@ export function createAgentRequestLowerer(options) {
99
99
  }
100
100
  }
101
101
  if (modelWork) {
102
- if (!HARNESS_MODEL_WORK_IDS.has(options.adapter)) {
102
+ if (!getHarness(options.adapter)?.capabilities.modelWork) {
103
103
  throw new ConfigError(`The ${options.adapter} transport cannot enforce the model-work tool policy.`, "INVALID_CONFIG_FILE");
104
104
  }
105
105
  // The builder selects its own confined agent or flags; another agent would replace them.
@@ -27,6 +27,11 @@ export class AiderHarness extends BaseHarness {
27
27
  id = "aider";
28
28
  displayName = "Aider";
29
29
  agentBuilder = aiderBuilder;
30
+ profile = {
31
+ bin: "aider",
32
+ args: ["--no-auto-commits"],
33
+ envPassthrough: ["OPENAI_API_KEY", "ANTHROPIC_API_KEY"],
34
+ };
30
35
  resultExtractor = aiderResultExtractor;
31
36
  // ── Workflow-engine descriptor (plan §"Capability matrix", P2) ────────────
32
37
  // No flag-shaped resume: Aider persists context in chat-history files
@@ -28,6 +28,7 @@ export class AmazonqHarness extends BaseHarness {
28
28
  id = "amazonq";
29
29
  displayName = "Amazon Q Developer CLI";
30
30
  agentBuilder = amazonqBuilder;
31
+ profile = { bin: "q", args: [], envPassthrough: ["AWS_PROFILE", "AWS_REGION"] };
31
32
  resultExtractor = amazonqResultExtractor;
32
33
  // ── Workflow-engine descriptor (plan §"Capability matrix", P2) ────────────
33
34
  // No `identityEnv`: the matrix lists Q's identity markers as uncertain, and
@@ -7,9 +7,8 @@
7
7
  *
8
8
  * Detects a Claude Code installation (filesystem only, no network) and reads
9
9
  * its config to extract LLM connection details. API key VALUES are never
10
- * stored — only the env var name that holds them. The pluggable registry
11
- * (`HARNESS_CONFIG_IMPORTERS`) and the OpenCode importer stay in
12
- * `setup/harness-config-import.ts`, which imports this importer back.
10
+ * stored — only the env var name that holds them. `ClaudeHarness` declares it
11
+ * as its `configImporter`.
13
12
  *
14
13
  * Behaviour-preserving relocation.
15
14
  */
@@ -4,6 +4,7 @@
4
4
  import { caps } from "../shared.js";
5
5
  import { BaseHarness } from "../types.js";
6
6
  import { claudeBuilder } from "./agent-builder.js";
7
+ import { claudeCodeImporter } from "./config-import.js";
7
8
  import { claudeResultExtractor } from "./result-extractor.js";
8
9
  import { ClaudeCodeProvider } from "./session-log.js";
9
10
  export { claudeBuilder } from "./agent-builder.js";
@@ -22,7 +23,9 @@ export class ClaudeHarness extends BaseHarness {
22
23
  // session-log provider, so offering it as a stash source is functional.
23
24
  setupDetectionDir = ".claude";
24
25
  agentBuilder = claudeBuilder;
26
+ profile = { bin: "claude", args: [], envPassthrough: ["ANTHROPIC_API_KEY", "CLAUDE_CONFIG"] };
25
27
  resultExtractor = claudeResultExtractor;
28
+ configImporter = claudeCodeImporter;
26
29
  // ── Workflow-engine descriptor (plan §"Capability matrix", P2) ────────────
27
30
  // Session-id env marker: presence of a concrete session id (not the bare
28
31
  // "running under Claude Code" flag) attributes a run to this harness.
@@ -32,6 +35,8 @@ export class ClaudeHarness extends BaseHarness {
32
35
  sessionLogs: true,
33
36
  agentDispatch: true,
34
37
  detection: true,
38
+ modelWork: true,
39
+ nativeAgent: true,
35
40
  configImport: true,
36
41
  });
37
42
  }
@@ -20,6 +20,7 @@ export class CodexHarness extends BaseHarness {
20
20
  // No `setupDetectionDir`: `~/.codex` holds credentials and session rollouts,
21
21
  // not assets, so `akm setup` must not offer it as a stash source.
22
22
  agentBuilder = codexBuilder;
23
+ profile = { bin: "codex", args: [], envPassthrough: ["OPENAI_API_KEY", "CODEX_CONFIG"] };
23
24
  resultExtractor = codexResultExtractor;
24
25
  // ── Workflow-engine descriptor (plan §"Capability matrix", P2) ────────────
25
26
  // No flag-shaped resume: codex resume is the `exec resume <id>` SUBCOMMAND
@@ -28,6 +28,7 @@ export class CopilotHarness extends BaseHarness {
28
28
  id = "copilot";
29
29
  displayName = "GitHub Copilot CLI";
30
30
  agentBuilder = copilotBuilder;
31
+ profile = { bin: "copilot", args: [], envPassthrough: ["GH_TOKEN", "GITHUB_TOKEN"] };
31
32
  resultExtractor = copilotResultExtractor;
32
33
  // ── Workflow-engine descriptor (plan §"Capability matrix", P2) ────────────
33
34
  // Session-id env marker only. The matrix's other candidates (GH_TOKEN,
@@ -27,6 +27,7 @@ export class GeminiHarness extends BaseHarness {
27
27
  id = "gemini";
28
28
  displayName = "Gemini CLI";
29
29
  agentBuilder = geminiBuilder;
30
+ profile = { bin: "gemini", args: [], envPassthrough: ["GEMINI_API_KEY", "GOOGLE_API_KEY"] };
30
31
  resultExtractor = geminiResultExtractor;
31
32
  // ── Workflow-engine descriptor (plan §"Capability matrix", P2) ────────────
32
33
  // The matrix's identity marker: Gemini CLI stamps GEMINI_CLI=1 only on
@@ -2,16 +2,17 @@
2
2
  // License, v. 2.0. If a copy of the MPL was not distributed with this
3
3
  // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
4
  /**
5
- * Single registration point for every akm agent harness (#562).
5
+ * Single registration point for every akm agent harness (#562, #1095).
6
6
  *
7
- * `HARNESS_REGISTRY` is the ONE source of truth that replaces the three
8
- * previously-disconnected registries (session-logs index, agent profiles,
9
- * config/setup platform strings). All derived exports below are computed from
10
- * it, so adding a harness is a single entry here instead of ~16 scattered edits.
7
+ * `HARNESS_REGISTRY` is the ONE source of truth. Each harness is a
8
+ * self-contained folder (`./<id>/index.ts`) exporting its descriptor; the
9
+ * config schema's platform enum, the built-in agent profiles, command
10
+ * builders, setup choices and the docs table all derive from the array below.
11
11
  *
12
- * This module is a dependency-graph LEAF: it imports nothing from
13
- * `core/config`. `core/config/config-types.ts` derives `VALID_HARNESS_IDS`
14
- * from here, which keeps the import direction acyclic (config ← harnesses).
12
+ * Adding a harness: create `./<id>/index.ts`, add its class here. Removing:
13
+ * delete both. This module must stay free of runtime `core/config` imports
14
+ * (config derives `VALID_HARNESS_IDS` from here), so a harness's heavy runner
15
+ * (e.g. `opencode-sdk/sdk-runner.ts`) is imported by its caller, not here.
15
16
  */
16
17
  import { AiderHarness } from "./aider/index.js";
17
18
  import { AmazonqHarness } from "./amazonq/index.js";
@@ -19,26 +20,14 @@ import { ClaudeHarness } from "./claude/index.js";
19
20
  import { CodexHarness } from "./codex/index.js";
20
21
  import { CopilotHarness } from "./copilot/index.js";
21
22
  import { GeminiHarness } from "./gemini/index.js";
22
- import { HARNESS_ID_TABLE } from "./ids.js";
23
23
  import { OpencodeHarness } from "./opencode/index.js";
24
- // Import the descriptor from its LEAF module, not the per-harness barrel: the
25
- // barrel re-exports `./sdk-runner` (which imports `core/config`, and
26
- // `core/config/config-types` derives `VALID_HARNESS_IDS` back from this file).
27
- // Importing the class through the barrel would form an initialization cycle
28
- // that throws a TDZ error when the barrel is the first module loaded in a fresh
29
- // graph (see ./opencode-sdk/harness.ts). This keeps the registry a config-leaf.
30
- import { OpencodeSdkHarness } from "./opencode-sdk/harness.js";
24
+ import { OpencodeSdkHarness } from "./opencode-sdk/index.js";
31
25
  import { OpenhandsHarness } from "./openhands/index.js";
32
26
  import { PiHarness } from "./pi/index.js";
33
27
  import { isSessionLogHarness } from "./types.js";
34
28
  export { isSessionLogHarness } from "./types.js";
35
- // Each harness descriptor (ClaudeHarness, OpencodeHarness, OpencodeSdkHarness)
36
- // lives in its own per-harness directory alongside that harness's session-log
37
- // reader, agent builder, config importer, and/or SDK runner (#563/#564). They
38
- // are imported above and registered in HARNESS_REGISTRY below.
39
29
  /**
40
- * The single registration point. Add a harness here (and nothing else) to make
41
- * every derived registry pick it up.
30
+ * The single registration point.
42
31
  *
43
32
  * Typed `as const` (not `AkmHarness[]`) so each entry keeps its literal `id`,
44
33
  * which lets `VALID_HARNESS_IDS` stay a literal tuple — `HarnessId`,
@@ -62,23 +51,6 @@ export const HARNESS_REGISTRY = Object.freeze([
62
51
  new AmazonqHarness(),
63
52
  new OpenhandsHarness(),
64
53
  ]);
65
- // Construction-time drift guard (WI-9.8 KILL 3, D.3 edge B): ./ids.ts's
66
- // HARNESS_ID_TABLE is config's dependency-free mirror of (id, agentDispatch)
67
- // for every registered harness, kept out of core/config's import graph so
68
- // config doesn't have to import this (heavier) barrel. Assert they match so
69
- // the mirror can never silently drift — a new/reordered/recapability'd
70
- // harness that forgets to update ./ids.ts fails loudly here instead of
71
- // quietly breaking config's platform validation.
72
- if (HARNESS_REGISTRY.length !== HARNESS_ID_TABLE.length) {
73
- throw new Error(`harnesses/ids.ts HARNESS_ID_TABLE has ${HARNESS_ID_TABLE.length} entries but HARNESS_REGISTRY has ${HARNESS_REGISTRY.length} — update ids.ts to match.`);
74
- }
75
- HARNESS_REGISTRY.forEach((h, i) => {
76
- const expected = HARNESS_ID_TABLE[i];
77
- if (!expected || expected.id !== h.id || expected.agentDispatch !== h.capabilities.agentDispatch) {
78
- throw new Error(`harnesses/ids.ts HARNESS_ID_TABLE[${i}] (${expected?.id ?? "<missing>"}, agentDispatch=${expected?.agentDispatch}) ` +
79
- `does not match HARNESS_REGISTRY[${i}] (${h.id}, agentDispatch=${h.capabilities.agentDispatch}) — update ids.ts to match.`);
80
- }
81
- });
82
54
  /** Lookup by the one supported harness id. */
83
55
  export const HARNESS_BY_ID = new Map(HARNESS_REGISTRY.map((h) => [h.id, h]));
84
56
  /**
@@ -96,6 +68,13 @@ export const VALID_HARNESS_IDS = Object.freeze(HARNESS_REGISTRY.map((h) => h.id)
96
68
  export const SESSION_LOG_HARNESSES = HARNESS_REGISTRY.filter(isSessionLogHarness);
97
69
  /** Harnesses that can be dispatched as an agent CLI / SDK. */
98
70
  export const AGENT_DISPATCH_HARNESSES = HARNESS_REGISTRY.filter((h) => h.capabilities.agentDispatch);
71
+ const idsWith = (flag) => new Set(HARNESS_REGISTRY.filter(flag).map((h) => h.id));
72
+ /** Harness ids whose `capabilities.agentDispatch` is `true`. */
73
+ export const HARNESS_AGENT_DISPATCH_IDS = idsWith((h) => h.capabilities.agentDispatch);
74
+ /** Harness ids that confine the model-work tool policy, so unattended model work may run on them. */
75
+ export const HARNESS_MODEL_WORK_IDS = idsWith((h) => h.capabilities.modelWork);
76
+ /** Harness ids that can run a named native agent, so an engine may name a default `agent`. */
77
+ export const HARNESS_NATIVE_AGENT_IDS = idsWith((h) => h.capabilities.nativeAgent);
99
78
  /**
100
79
  * Resolve an exact harness id to its descriptor, or `undefined` if unknown.
101
80
  */
@@ -10,30 +10,75 @@
10
10
  * `getCommandBuilder`, the default builder, flag/tool helpers) stays in
11
11
  * `agent/builders.ts`, which imports this builder back into `BUILTIN_BUILDERS`.
12
12
  *
13
- * Behaviour-preserving relocation: the produced argv is byte-identical to the
14
- * pre-migration `opencodeBuilder`. The builder's `platform` stays `'opencode'`
15
- * (the canonical harness id).
13
+ * The builder's `platform` stays `'opencode'` (the canonical harness id). The
14
+ * one thing that depends on the OpenCode major (`./version.ts`, one cached
15
+ * `--version` run per binary) is `--standalone`, added on OpenCode 2 only; the
16
+ * OpenCode 1 argv is byte-identical to the pre-OpenCode-2 builder's.
16
17
  */
17
- import { modelFromArgs, resolveDispatchModel } from "../../agent/builder-shared.js";
18
+ import { modelFromArgs, resolveDispatchModel, } from "../../agent/builder-shared.js";
18
19
  import { createAgentRequestLowerer } from "../../agent/request-lowering.js";
19
20
  import { MODEL_WORK_AGENT_INFERENCE, opencodeInferenceConfig } from "./model-config.js";
20
21
  import { MODEL_WORK_OPENCODE_AGENT, modelWorkOpencodeConfig, modelWorkPluginEnv } from "./model-work-agent.js";
22
+ import { detectOpencodeMajor } from "./version.js";
21
23
  /**
22
- * OpenCode builder.
23
- * Command shape: opencode run [--agent <name>] [--model <m>] -- "<prompt>"
24
+ * OpenCode 2's `run` attaches to a shared background service by default,
25
+ * starting it when absent and leaving it running after the run; `--standalone`
26
+ * runs a private server that exits with the run (and reads the
27
+ * `OPENCODE_CONFIG_CONTENT` model work travels in, which the service ignores).
28
+ * OpenCode 1 has no such flag. An engine whose own `args` name `--server`
29
+ * chose that server, so it gets no `--standalone`. `--auto` is never passed:
30
+ * a non-interactive run rejects a permission request, on both majors.
31
+ */
32
+ const STANDALONE_FLAG = "--standalone";
33
+ function standalone(major, flags) {
34
+ if (major !== 2)
35
+ return [];
36
+ const chosen = flags.some((arg) => arg === STANDALONE_FLAG || arg === "--server" || arg.startsWith("--server="));
37
+ return chosen ? [] : [STANDALONE_FLAG];
38
+ }
39
+ /**
40
+ * The flags before the `--` separator of an ordinary dispatch: the engine's
41
+ * `args` (without any `--model` when the request names one), then `--agent`
42
+ * and `--model`. Both majors spell these the same way.
43
+ */
44
+ function ordinaryFlags(profile, req) {
45
+ const args = req.model ? [] : [...profile.args];
46
+ if (req.model) {
47
+ for (let index = 0; index < profile.args.length; index += 1) {
48
+ const arg = profile.args[index];
49
+ if (arg === undefined)
50
+ continue;
51
+ if (arg === "--model") {
52
+ index += 1;
53
+ }
54
+ else if (!arg.startsWith("--model=")) {
55
+ args.push(arg);
56
+ }
57
+ }
58
+ }
59
+ if (req.agent) {
60
+ args.push("--agent", req.agent);
61
+ }
62
+ if (req.model) {
63
+ args.push("--model", resolveDispatchModel(req, profile, "opencode"));
64
+ }
65
+ return args;
66
+ }
67
+ /**
68
+ * OpenCode builder: `opencode run [--standalone] [--agent <name>] [--model <m>] -- "<prompt>"`
69
+ * (`--standalone` on OpenCode 2 only).
24
70
  *
25
71
  * `opencode run` has no system-prompt option (1.18.25 prints its usage and
26
72
  * exits 1 on `--system-prompt`), so the shared lowerer composes a persona
27
73
  * into the prompt.
28
74
  *
29
- * Tool policy is omitted — opencode manages tool access through its own agent
75
+ * Tool policy is omitted: opencode manages tool access through its own agent
30
76
  * config files, not via CLI flags. The one exception is the model-work tool
31
77
  * policy: the builder injects its confined agent through
32
78
  * `OPENCODE_CONFIG_CONTENT` and selects it with `--agent`. That command is
33
- * akm's own (`opencode run --agent akm-model-work`): the engine's `args` are
34
- * left out, because one such as `--attach` or `--dir` would move the run out
35
- * of the injected config or the scratch working directory. Only the model they
36
- * name is kept.
79
+ * akm's own: the engine's `args` are left out, because one such as `--attach`
80
+ * or `--dir` would move the run out of the injected config or the scratch
81
+ * working directory. Only the model they name is kept.
37
82
  *
38
83
  * Model work's agent carries the request's inference options
39
84
  * (`./model-config.ts`). Any other dispatch injects nothing and carries none, so
@@ -49,6 +94,7 @@ export const opencodeBuilder = {
49
94
  inference: MODEL_WORK_AGENT_INFERENCE,
50
95
  }),
51
96
  build(profile, req) {
97
+ const major = detectOpencodeMajor(profile.bin).major;
52
98
  if (req.modelWork) {
53
99
  const model = req.model ?? modelFromArgs(profile.args);
54
100
  const { agentOptions } = opencodeInferenceConfig(req.inference, true);
@@ -56,6 +102,7 @@ export const opencodeBuilder = {
56
102
  argv: [
57
103
  profile.bin,
58
104
  "run",
105
+ ...standalone(major, []),
59
106
  "--agent",
60
107
  MODEL_WORK_OPENCODE_AGENT,
61
108
  ...(model ? ["--model", model] : []),
@@ -68,29 +115,7 @@ export const opencodeBuilder = {
68
115
  },
69
116
  };
70
117
  }
71
- const args = req.model ? [] : [...profile.args];
72
- if (req.model) {
73
- for (let index = 0; index < profile.args.length; index += 1) {
74
- const arg = profile.args[index];
75
- if (arg === undefined)
76
- continue;
77
- if (arg === "--model") {
78
- index += 1;
79
- }
80
- else if (!arg.startsWith("--model=")) {
81
- args.push(arg);
82
- }
83
- }
84
- }
85
- if (req.agent) {
86
- args.push("--agent", req.agent);
87
- }
88
- if (req.model) {
89
- const resolved = resolveDispatchModel(req, profile, "opencode");
90
- args.push("--model", resolved);
91
- }
92
- args.push("--");
93
- args.push(req.prompt);
94
- return { argv: [profile.bin, ...args] };
118
+ const flags = ordinaryFlags(profile, req);
119
+ return { argv: [profile.bin, ...flags, ...standalone(major, flags), "--", req.prompt] };
95
120
  },
96
121
  };