akm-cli 0.8.1 → 0.9.0-beta.0

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 (318) hide show
  1. package/CHANGELOG.md +258 -0
  2. package/dist/assets/help/help-proposals.md +1 -2
  3. package/dist/assets/hints/cli-hints-full.md +34 -19
  4. package/dist/assets/hints/cli-hints-short.md +1 -1
  5. package/dist/assets/profiles/catchup.json +13 -0
  6. package/dist/assets/profiles/consolidate.json +13 -0
  7. package/dist/assets/profiles/frequent.json +13 -0
  8. package/dist/assets/stash-skeleton/README.md +76 -0
  9. package/dist/assets/tasks/core/backup.yml +4 -0
  10. package/dist/assets/tasks/core/extract.yml +4 -0
  11. package/dist/assets/tasks/core/improve.yml +4 -0
  12. package/dist/assets/tasks/core/index-refresh.yml +4 -0
  13. package/dist/assets/tasks/core/sync.yml +4 -0
  14. package/dist/assets/tasks/core/update-stashes.yml +4 -0
  15. package/dist/assets/tasks/core/version-check.yml +4 -0
  16. package/dist/cli/config-migrate.js +6 -6
  17. package/dist/cli/config-validate.js +4 -4
  18. package/dist/cli/confirm.js +3 -3
  19. package/dist/cli/parse-args.js +1 -1
  20. package/dist/cli/shared.js +51 -14
  21. package/dist/cli-node.mjs +26 -0
  22. package/dist/cli.js +171 -3857
  23. package/dist/commands/{agent-dispatch.js → agent/agent-dispatch.js} +6 -6
  24. package/dist/commands/{agent-support.js → agent/agent-support.js} +2 -2
  25. package/dist/commands/agent/contribute-cli.js +200 -0
  26. package/dist/commands/completions.js +1 -1
  27. package/dist/commands/config-cli.js +240 -3
  28. package/dist/commands/config-edit.js +344 -0
  29. package/dist/commands/db-cli.js +2 -2
  30. package/dist/commands/env/env-cli.js +529 -0
  31. package/dist/commands/env/env.js +410 -0
  32. package/dist/commands/env/secret-cli.js +259 -0
  33. package/dist/commands/{secret.js → env/secret.js} +6 -47
  34. package/dist/commands/events.js +4 -4
  35. package/dist/commands/feedback-cli.js +18 -34
  36. package/dist/commands/graph/graph-cli.js +132 -0
  37. package/dist/commands/{graph.js → graph/graph.js} +22 -16
  38. package/dist/commands/health/checks.js +279 -0
  39. package/dist/commands/health.js +101 -249
  40. package/dist/commands/{consolidate.js → improve/consolidate.js} +52 -40
  41. package/dist/commands/{distill-promotion-policy.js → improve/distill-promotion-policy.js} +3 -3
  42. package/dist/commands/{distill.js → improve/distill.js} +39 -18
  43. package/dist/commands/{eval-cases.js → improve/eval-cases.js} +1 -1
  44. package/dist/commands/{extract-cli.js → improve/extract-cli.js} +4 -4
  45. package/dist/commands/{extract-prompt.js → improve/extract-prompt.js} +2 -2
  46. package/dist/commands/{extract.js → improve/extract.js} +185 -26
  47. package/dist/commands/{improve-auto-accept.js → improve/improve-auto-accept.js} +4 -4
  48. package/dist/commands/{improve-cli.js → improve/improve-cli.js} +45 -23
  49. package/dist/commands/{improve-profiles.js → improve/improve-profiles.js} +13 -7
  50. package/dist/commands/{improve-result-file.js → improve/improve-result-file.js} +10 -5
  51. package/dist/commands/{improve.js → improve/improve.js} +536 -248
  52. package/dist/{core → commands/improve/memory}/memory-belief.js +2 -2
  53. package/dist/{core → commands/improve/memory}/memory-contradiction-detect.js +5 -5
  54. package/dist/{core → commands/improve/memory}/memory-improve.js +4 -4
  55. package/dist/commands/{reflect.js → improve/reflect.js} +33 -28
  56. package/dist/commands/improve/session-asset.js +248 -0
  57. package/dist/commands/lint/agent-linter.js +1 -1
  58. package/dist/commands/lint/base-linter.js +55 -37
  59. package/dist/commands/lint/command-linter.js +1 -1
  60. package/dist/commands/lint/default-linter.js +1 -1
  61. package/dist/commands/lint/env-key-rules.js +1 -1
  62. package/dist/commands/lint/index.js +19 -25
  63. package/dist/commands/lint/knowledge-linter.js +1 -1
  64. package/dist/commands/lint/memory-linter.js +1 -1
  65. package/dist/commands/lint/registry.js +8 -8
  66. package/dist/commands/lint/skill-linter.js +1 -1
  67. package/dist/commands/lint/task-linter.js +1 -1
  68. package/dist/commands/lint/workflow-linter.js +1 -1
  69. package/dist/commands/lint.js +1 -1
  70. package/dist/commands/observability-cli.js +244 -0
  71. package/dist/commands/{proposal-drain-policies.js → proposal/drain-policies.js} +3 -3
  72. package/dist/commands/{proposal-drain.js → proposal/drain.js} +15 -10
  73. package/dist/commands/proposal/proposal-cli.js +478 -0
  74. package/dist/commands/{proposal.js → proposal/proposal.js} +5 -5
  75. package/dist/commands/{propose.js → proposal/propose.js} +11 -11
  76. package/dist/{core → commands/proposal/validators}/proposal-quality-validators.js +8 -3
  77. package/dist/{core → commands/proposal/validators}/proposal-validators.js +5 -5
  78. package/dist/{core → commands/proposal/validators}/proposals.js +13 -7
  79. package/dist/commands/{curate.js → read/curate.js} +7 -7
  80. package/dist/commands/{knowledge.js → read/knowledge.js} +22 -9
  81. package/dist/commands/{registry-search.js → read/registry-search.js} +5 -5
  82. package/dist/commands/{remember-cli.js → read/remember-cli.js} +15 -7
  83. package/dist/commands/read/search-cli.js +207 -0
  84. package/dist/commands/{search.js → read/search.js} +22 -27
  85. package/dist/commands/{show.js → read/show.js} +77 -44
  86. package/dist/commands/registry-cli.js +8 -8
  87. package/dist/commands/remember.js +8 -8
  88. package/dist/commands/sources/add-cli.js +293 -0
  89. package/dist/commands/{history.js → sources/history.js} +27 -25
  90. package/dist/commands/{info.js → sources/info.js} +6 -6
  91. package/dist/commands/{init.js → sources/init.js} +10 -5
  92. package/dist/commands/{installed-stashes.js → sources/installed-stashes.js} +12 -12
  93. package/dist/commands/{migration-help.js → sources/migration-help.js} +3 -2
  94. package/dist/commands/{schema-repair.js → sources/schema-repair.js} +8 -8
  95. package/dist/commands/{self-update.js → sources/self-update.js} +10 -9
  96. package/dist/commands/{source-add.js → sources/source-add.js} +10 -10
  97. package/dist/commands/{source-clone.js → sources/source-clone.js} +7 -7
  98. package/dist/commands/{source-manage.js → sources/source-manage.js} +4 -4
  99. package/dist/commands/sources/sources-cli.js +305 -0
  100. package/dist/commands/sources/stash-cli.js +219 -0
  101. package/dist/commands/sources/stash-skeleton.js +79 -0
  102. package/dist/commands/tasks/default-tasks.js +173 -0
  103. package/dist/commands/tasks/tasks-cli.js +210 -0
  104. package/dist/commands/{tasks.js → tasks/tasks.js} +14 -14
  105. package/dist/commands/wiki-cli.js +307 -0
  106. package/dist/commands/workflow-cli.js +329 -0
  107. package/dist/core/action-contributors.js +1 -1
  108. package/dist/core/assert.js +40 -0
  109. package/dist/core/asset/asset-create.js +54 -0
  110. package/dist/core/{asset-ref.js → asset/asset-ref.js} +21 -4
  111. package/dist/core/{asset-registry.js → asset/asset-registry.js} +3 -3
  112. package/dist/core/{asset-spec.js → asset/asset-spec.js} +17 -31
  113. package/dist/core/{markdown.js → asset/markdown.js} +1 -1
  114. package/dist/core/asset/stash-meta.js +110 -0
  115. package/dist/core/best-effort.js +64 -0
  116. package/dist/core/common.js +32 -18
  117. package/dist/core/{config-io.js → config/config-io.js} +29 -19
  118. package/dist/core/{config-migration.js → config/config-migration.js} +11 -9
  119. package/dist/core/{config-schema.js → config/config-schema.js} +45 -1
  120. package/dist/core/config/config-types.js +16 -0
  121. package/dist/core/{config-walker.js → config/config-walker.js} +2 -2
  122. package/dist/core/{config.js → config/config.js} +10 -8
  123. package/dist/core/env-secret-ref.js +90 -0
  124. package/dist/core/errors.js +13 -3
  125. package/dist/core/events.js +27 -4
  126. package/dist/core/file-lock.js +1 -1
  127. package/dist/core/improve-types.js +48 -0
  128. package/dist/core/lesson-lint.js +2 -2
  129. package/dist/core/paths.js +2 -2
  130. package/dist/{setup/ripgrep-install.js → core/ripgrep/install.js} +2 -2
  131. package/dist/{setup/ripgrep-resolve.js → core/ripgrep/resolve.js} +2 -2
  132. package/dist/core/state-db.js +88 -46
  133. package/dist/core/text-truncation.js +148 -0
  134. package/dist/core/time.js +1 -1
  135. package/dist/core/write-source.js +98 -85
  136. package/dist/indexer/{db-backup.js → db/db-backup.js} +9 -24
  137. package/dist/indexer/{db.js → db/db.js} +126 -116
  138. package/dist/indexer/{graph-db.js → db/graph-db.js} +9 -4
  139. package/dist/indexer/{llm-cache.js → db/llm-cache.js} +15 -12
  140. package/dist/indexer/ensure-index.js +4 -4
  141. package/dist/indexer/{graph-boost.js → graph/graph-boost.js} +1 -1
  142. package/dist/indexer/{graph-extraction.js → graph/graph-extraction.js} +55 -13
  143. package/dist/indexer/indexer.js +37 -30
  144. package/dist/indexer/init.js +54 -0
  145. package/dist/indexer/manifest.js +10 -10
  146. package/dist/indexer/{memory-inference.js → passes/memory-inference.js} +92 -23
  147. package/dist/indexer/{metadata-contributors.js → passes/metadata-contributors.js} +10 -8
  148. package/dist/indexer/{metadata.js → passes/metadata.js} +15 -19
  149. package/dist/indexer/{staleness-detect.js → passes/staleness-detect.js} +53 -12
  150. package/dist/indexer/{db-search.js → search/db-search.js} +28 -16
  151. package/dist/indexer/{ranking-contributors.js → search/ranking-contributors.js} +1 -1
  152. package/dist/indexer/{ranking.js → search/ranking.js} +2 -2
  153. package/dist/indexer/{search-hit-enrichers.js → search/search-hit-enrichers.js} +3 -3
  154. package/dist/indexer/{search-source.js → search/search-source.js} +8 -8
  155. package/dist/indexer/{semantic-status.js → search/semantic-status.js} +3 -3
  156. package/dist/indexer/usage/unmigrated-vaults-guard.js +94 -0
  157. package/dist/indexer/{usage-events.js → usage/usage-events.js} +32 -0
  158. package/dist/indexer/{file-context.js → walk/file-context.js} +10 -15
  159. package/dist/indexer/{matchers.js → walk/matchers.js} +13 -9
  160. package/dist/indexer/{path-resolver.js → walk/path-resolver.js} +6 -6
  161. package/dist/indexer/{project-context.js → walk/project-context.js} +1 -1
  162. package/dist/indexer/{walker.js → walk/walker.js} +4 -3
  163. package/dist/integrations/agent/builder-shared.js +39 -0
  164. package/dist/integrations/agent/builders.js +14 -81
  165. package/dist/integrations/agent/config.js +6 -4
  166. package/dist/integrations/agent/detect.js +1 -1
  167. package/dist/integrations/agent/index.js +23 -8
  168. package/dist/integrations/agent/prompts.js +2 -3
  169. package/dist/integrations/agent/runner.js +22 -3
  170. package/dist/integrations/agent/spawn.js +9 -10
  171. package/dist/integrations/harnesses/claude/agent-builder.js +48 -0
  172. package/dist/integrations/harnesses/claude/config-import.js +70 -0
  173. package/dist/integrations/harnesses/claude/index.js +64 -0
  174. package/dist/integrations/{session-logs/providers/claude-code.js → harnesses/claude/session-log.js} +16 -1
  175. package/dist/integrations/harnesses/index.js +144 -0
  176. package/dist/integrations/harnesses/opencode/agent-builder.js +43 -0
  177. package/dist/integrations/harnesses/opencode/config-import.js +82 -0
  178. package/dist/integrations/harnesses/opencode/index.js +59 -0
  179. package/dist/integrations/{session-logs/providers/opencode.js → harnesses/opencode/session-log.js} +1 -1
  180. package/dist/integrations/harnesses/opencode-sdk/index.js +49 -0
  181. package/dist/integrations/harnesses/opencode-sdk/sdk-runner.js +234 -0
  182. package/dist/integrations/harnesses/types.js +43 -0
  183. package/dist/integrations/lockfile.js +7 -16
  184. package/dist/integrations/session-logs/index.js +82 -9
  185. package/dist/llm/call-ai.js +4 -4
  186. package/dist/llm/client.js +131 -6
  187. package/dist/llm/embedder.js +6 -6
  188. package/dist/llm/embedders/local.js +9 -22
  189. package/dist/llm/embedders/remote.js +2 -2
  190. package/dist/llm/embedders/types.js +1 -1
  191. package/dist/llm/graph-extract.js +31 -12
  192. package/dist/llm/index-passes.js +1 -1
  193. package/dist/llm/memory-infer.js +12 -5
  194. package/dist/llm/metadata-enhance.js +2 -2
  195. package/dist/output/context.js +6 -44
  196. package/dist/output/renderers.js +88 -58
  197. package/dist/output/shapes/curate.js +7 -3
  198. package/dist/output/shapes/distill.js +7 -3
  199. package/dist/output/shapes/env-list.js +18 -16
  200. package/dist/output/shapes/events.js +5 -4
  201. package/dist/output/shapes/helpers.js +2 -4
  202. package/dist/output/shapes/history.js +7 -3
  203. package/dist/output/shapes/passthrough.js +8 -11
  204. package/dist/output/shapes/{proposal-accept.js → proposal/accept.js} +7 -3
  205. package/dist/output/shapes/{proposal-diff.js → proposal/diff.js} +7 -3
  206. package/dist/output/shapes/{proposal-list.js → proposal/list.js} +7 -3
  207. package/dist/output/shapes/{proposal-producer.js → proposal/producer.js} +5 -4
  208. package/dist/output/shapes/{proposal-reject.js → proposal/reject.js} +7 -3
  209. package/dist/output/shapes/{proposal-show.js → proposal/show.js} +7 -3
  210. package/dist/output/shapes/registry-search.js +7 -3
  211. package/dist/output/shapes/registry.js +12 -0
  212. package/dist/output/shapes/search.js +7 -3
  213. package/dist/output/shapes/secret-list.js +18 -16
  214. package/dist/output/shapes/show.js +7 -3
  215. package/dist/output/shapes.js +55 -30
  216. package/dist/output/text/add.js +2 -3
  217. package/dist/output/text/clone.js +2 -3
  218. package/dist/output/text/config.js +2 -3
  219. package/dist/output/text/curate.js +4 -3
  220. package/dist/output/text/distill.js +2 -3
  221. package/dist/output/text/enable-disable.js +5 -4
  222. package/dist/output/text/env.js +13 -0
  223. package/dist/output/text/events.js +5 -4
  224. package/dist/output/text/feedback.js +4 -3
  225. package/dist/output/text/helpers.js +54 -39
  226. package/dist/output/text/history.js +2 -3
  227. package/dist/output/text/import.js +2 -3
  228. package/dist/output/text/index.js +2 -3
  229. package/dist/output/text/info.js +2 -3
  230. package/dist/output/text/init.js +2 -3
  231. package/dist/output/text/list.js +2 -3
  232. package/dist/output/text/proposal/producer.js +9 -0
  233. package/dist/output/text/proposal/proposal.js +13 -0
  234. package/dist/output/text/registry-commands.js +8 -7
  235. package/dist/output/text/registry.js +12 -0
  236. package/dist/output/text/remember.js +4 -3
  237. package/dist/output/text/remove.js +2 -3
  238. package/dist/output/text/save.js +2 -3
  239. package/dist/output/text/search.js +4 -3
  240. package/dist/output/text/show.js +4 -3
  241. package/dist/output/text/update.js +2 -3
  242. package/dist/output/text/upgrade.js +2 -3
  243. package/dist/output/text/wiki.js +12 -11
  244. package/dist/output/text/workflow.js +12 -10
  245. package/dist/output/text.js +66 -32
  246. package/dist/registry/build-index.js +11 -10
  247. package/dist/registry/factory.js +1 -1
  248. package/dist/registry/origin-resolve.js +1 -1
  249. package/dist/registry/providers/index.js +2 -2
  250. package/dist/registry/providers/skills-sh.js +91 -72
  251. package/dist/registry/providers/static-index.js +75 -52
  252. package/dist/registry/resolve.js +3 -3
  253. package/dist/runtime.js +242 -0
  254. package/dist/scripts/migrate-storage.js +1594 -673
  255. package/dist/scripts/migrations/import-fs-improve-runs-to-db.js +240 -166
  256. package/dist/setup/detect.js +338 -9
  257. package/dist/setup/harness-config-import.js +56 -0
  258. package/dist/setup/registry-stash-loader.js +99 -0
  259. package/dist/setup/setup.js +664 -96
  260. package/dist/sources/include.js +1 -1
  261. package/dist/sources/provider-factory.js +2 -2
  262. package/dist/sources/providers/filesystem.js +3 -3
  263. package/dist/sources/providers/git.js +9 -9
  264. package/dist/sources/providers/index.js +4 -4
  265. package/dist/sources/providers/npm.js +6 -6
  266. package/dist/sources/providers/provider-utils.js +13 -20
  267. package/dist/sources/providers/sync-from-ref.js +5 -5
  268. package/dist/sources/providers/tar-utils.js +2 -2
  269. package/dist/sources/providers/website.js +2 -2
  270. package/dist/sources/resolve.js +5 -5
  271. package/dist/sources/website-ingest.js +5 -5
  272. package/dist/storage/database.js +102 -0
  273. package/dist/storage/engines/sqlite-migrations.js +42 -0
  274. package/dist/storage/locations.js +25 -0
  275. package/dist/storage/repositories/index-db.js +43 -0
  276. package/dist/storage/repositories/workflow-runs-repository.js +141 -0
  277. package/dist/tasks/backends/cron.js +4 -4
  278. package/dist/tasks/backends/exec-utils.js +32 -0
  279. package/dist/tasks/backends/index.js +3 -3
  280. package/dist/tasks/backends/launchd.js +7 -14
  281. package/dist/tasks/backends/schtasks.js +7 -16
  282. package/dist/tasks/embedded.js +71 -0
  283. package/dist/tasks/parser.js +2 -2
  284. package/dist/tasks/resolveAkmBin.js +1 -1
  285. package/dist/tasks/runner.js +28 -15
  286. package/dist/tasks/schedule.js +1 -1
  287. package/dist/tasks/validator.js +7 -7
  288. package/dist/text-import-hook.mjs +51 -0
  289. package/dist/version.js +2 -1
  290. package/dist/wiki/wiki.js +7 -7
  291. package/dist/workflows/{authoring.js → authoring/authoring.js} +6 -6
  292. package/dist/workflows/{scope-key.js → authoring/scope-key.js} +1 -1
  293. package/dist/workflows/cli.js +1 -1
  294. package/dist/workflows/db.js +50 -32
  295. package/dist/workflows/parser.js +4 -4
  296. package/dist/workflows/renderer.js +5 -5
  297. package/dist/workflows/runtime/agent-identity.js +56 -0
  298. package/dist/workflows/runtime/checkin.js +57 -0
  299. package/dist/workflows/{runs.js → runtime/runs.js} +197 -101
  300. package/dist/workflows/validate-summary.js +82 -0
  301. package/docs/README.md +1 -1
  302. package/docs/data-and-telemetry.md +6 -6
  303. package/package.json +16 -8
  304. package/dist/commands/add-cli.js +0 -279
  305. package/dist/commands/env.js +0 -213
  306. package/dist/integrations/agent/sdk-runner.js +0 -126
  307. package/dist/output/shapes/vault-list.js +0 -19
  308. package/dist/output/text/proposal-producer.js +0 -8
  309. package/dist/output/text/proposal.js +0 -12
  310. package/dist/output/text/vault.js +0 -16
  311. /package/dist/core/{asset-serialize.js → asset/asset-serialize.js} +0 -0
  312. /package/dist/core/{frontmatter.js → asset/frontmatter.js} +0 -0
  313. /package/dist/core/{config-sources.js → config/config-sources.js} +0 -0
  314. /package/dist/indexer/{graph-dedup.js → graph/graph-dedup.js} +0 -0
  315. /package/dist/{core/config-types.js → indexer/passes/pass-context.js} +0 -0
  316. /package/dist/indexer/{search-fields.js → search/search-fields.js} +0 -0
  317. /package/dist/indexer/{index-context.js → walk/index-context.js} +0 -0
  318. /package/dist/workflows/{document-cache.js → runtime/document-cache.js} +0 -0
@@ -1,11 +1,26 @@
1
1
  // This Source Code Form is subject to the terms of the Mozilla Public
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
- export { getCommandBuilder } from "./builders";
5
- export { DEFAULT_AGENT_TIMEOUT_MS, listAgentProfileNames, listResolvedAgentProfiles, parseAgentConfig, requireAgentProfile, resolveAgentProfile, resolveDefaultProfileName, resolveProfileFromConfig, } from "./config";
6
- export { defaultWhich, detectAgentCliProfiles, pickDefaultAgentProfile } from "./detect";
7
- export { listBuiltinModelAliases, resolveModel } from "./model-aliases";
8
- export { BUILTIN_AGENT_PROFILE_NAMES, getBuiltinAgentProfile, listBuiltinAgentProfiles, } from "./profiles";
9
- export { buildProposePrompt, buildReflectPrompt, buildSchemaRepairPrompt, extractDraftConfidence, parseAgentProposalPayload, stripJsonFences, } from "./prompts";
10
- export { runAgentSdk } from "./sdk-runner";
11
- export { runAgent } from "./spawn";
4
+ /**
5
+ * Internal entry point for the `agent` integration. CLI-only project no
6
+ * public exports map. Other akm modules import from this barrel for the
7
+ * sake of grouping imports.
8
+ *
9
+ * Surface:
10
+ * • Types: AgentProfile, AgentConfig, AgentRunResult, AgentFailureReason.
11
+ * • Profiles: getBuiltinAgentProfile, listBuiltinAgentProfiles, BUILTIN_AGENT_PROFILE_NAMES.
12
+ * • Config: parseAgentConfig, resolveProfileFromConfig, requireAgentProfile, listResolvedAgentProfiles, listAgentProfileNames.
13
+ * • Spawn: runAgent. Builders: getCommandBuilder, AgentCommandBuilder, AgentDispatchRequest — platform-specific argv construction.
14
+ * • Detection: detectAgentCliProfiles, pickDefaultAgentProfile, defaultWhich.
15
+ */
16
+ // The OpenCode SDK runner moved to its harness directory in #564
17
+ // (`harnesses/opencode-sdk/`). Re-exported here so existing `agent/index`
18
+ // import sites keep working.
19
+ export { runAgentSdk } from "../harnesses/opencode-sdk/index.js";
20
+ export { getCommandBuilder } from "./builders.js";
21
+ export { DEFAULT_AGENT_TIMEOUT_MS, listAgentProfileNames, listResolvedAgentProfiles, parseAgentConfig, requireAgentProfile, resolveAgentProfile, resolveDefaultProfileName, resolveProfileFromConfig, } from "./config.js";
22
+ export { defaultWhich, detectAgentCliProfiles, pickDefaultAgentProfile } from "./detect.js";
23
+ export { listBuiltinModelAliases, resolveModel } from "./model-aliases.js";
24
+ export { BUILTIN_AGENT_PROFILE_NAMES, getBuiltinAgentProfile, listBuiltinAgentProfiles, } from "./profiles.js";
25
+ export { buildProposePrompt, buildReflectPrompt, buildSchemaRepairPrompt, extractDraftConfidence, parseAgentProposalPayload, stripJsonFences, } from "./prompts.js";
26
+ export { runAgent } from "./spawn.js";
@@ -25,8 +25,8 @@
25
25
  * `frontmatter` is optional — the proposal queue parses it from `content`
26
26
  * during validation. We carry it through if the agent supplies it.
27
27
  */
28
- import { TYPE_DIRS } from "../../core/asset-spec";
29
- import { parseEmbeddedJsonResponse, stripCodeFences, stripThinkBlocks } from "../../core/parse";
28
+ import { TYPE_DIRS } from "../../core/asset/asset-spec.js";
29
+ import { parseEmbeddedJsonResponse, stripCodeFences, stripThinkBlocks } from "../../core/parse.js";
30
30
  /**
31
31
  * Per-asset-type frontmatter / authoring hints surfaced in the prompt so
32
32
  * the agent can produce content that passes proposal validation. Kept tiny:
@@ -42,7 +42,6 @@ const TYPE_HINTS = {
42
42
  workflow: "workflow assets are markdown describing a multi-step process. Include `# <Title>` and ordered `## Step N` sections.",
43
43
  script: "script assets are executable text files. Include a shebang and minimal usage comment.",
44
44
  env: "env assets are `.env` files holding a group of related CONFIGURATION for an app/service (KEY=VALUE pairs, `#` comments) — URLs, flags, and any credentials it needs. Values may or may not be sensitive; all are protected (key names discoverable, values stay on disk). Inject with `akm env run env:<name> -- <cmd>` (the safe path — values never reach stdout/your context); do NOT run `akm env export` and read its output, as that prints values. For a single sensitive value used on its own for authentication (token, key, cert) use a `secret` instead. Never echo values back to the user.",
45
- vault: "vault assets are DEPRECATED (use env). They store environment variables (KEY=VALUE pairs); comments use `#`. Never echo secret values back to the user.",
46
45
  wiki: "wiki assets are markdown reference pages with `# Title` and structured headings.",
47
46
  };
48
47
  function hintForType(type) {
@@ -1,8 +1,27 @@
1
1
  // This Source Code Form is subject to the terms of the Mozilla Public
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
- import { ConfigError } from "../../core/errors";
5
- import { warn } from "../../core/warn";
4
+ import { ConfigError } from "../../core/errors.js";
5
+ import { warn } from "../../core/warn.js";
6
+ // ── RunnerSpec capability predicates (H1) ───────────────────────────────────
7
+ // The `RunnerSpec` union is dispatched ad-hoc across the improve slice. These
8
+ // predicates co-locate the capability questions with the union definition so
9
+ // callers stop hand-inlining `kind !== "llm"` (which couples the call site to
10
+ // the exact shape of the union). They are typed as TypeScript type guards so
11
+ // narrowing flows through to the `connection` / `profile` accessors.
12
+ /** The in-tree LLM HTTP runner (`chatCompletion`); has no filesystem access. */
13
+ export function runnerIsLlm(runner) {
14
+ return runner.kind === "llm";
15
+ }
16
+ /**
17
+ * Whether this runner can honour the file-write contract. Agent CLI + OpenCode
18
+ * SDK runners both have filesystem access; the direct LLM HTTP runner does NOT
19
+ * (see `src/llm/call-ai.ts`). Equivalent to `!runnerIsLlm(runner)` but names
20
+ * the capability the callers actually care about.
21
+ */
22
+ export function runnerSupportsFileWrite(runner) {
23
+ return runner.kind !== "llm";
24
+ }
6
25
  function resolveEffectiveMode(entry, profileName, config) {
7
26
  if (entry.mode)
8
27
  return entry.mode;
@@ -205,4 +224,4 @@ export function getStalenessDetectionThresholdDays(config) {
205
224
  }
206
225
  // Re-export `isProcessEnabled` from feature-gate.ts so callers that previously
207
226
  // imported it from runner.ts continue to work.
208
- export { isProcessEnabled } from "../../llm/feature-gate";
227
+ export { isProcessEnabled } from "../../llm/feature-gate.js";
@@ -17,8 +17,9 @@
17
17
  import fs from "node:fs";
18
18
  import os from "node:os";
19
19
  import path from "node:path";
20
- import { getCommandBuilder } from "./builders";
21
- import { DEFAULT_AGENT_TIMEOUT_MS } from "./config";
20
+ import { spawn as runtimeSpawn } from "../../runtime.js";
21
+ import { getCommandBuilder } from "./builders.js";
22
+ import { DEFAULT_AGENT_TIMEOUT_MS } from "./config.js";
22
23
  /**
23
24
  * Kill the process group of `proc` with `signal`, falling back to
24
25
  * `proc.kill(signal)` when `proc.pid` is unavailable (e.g. test fakes).
@@ -103,12 +104,10 @@ function pathCandidatesForCurrentPlatform(home) {
103
104
  function resolveSpawnFn(options) {
104
105
  if (options.spawn)
105
106
  return options.spawn;
106
- // Pull from globalThis so tests that swap it out at module level are honoured.
107
- const bun = globalThis.Bun;
108
- if (!bun?.spawn) {
109
- throw new Error("Bun.spawn is unavailable; pass options.spawn for non-Bun environments.");
110
- }
111
- return bun.spawn.bind(bun);
107
+ // Default to the runtime-boundary spawn, which delegates to the native
108
+ // subprocess API on each runtime. Tests inject `options.spawn` to avoid
109
+ // poking real binaries.
110
+ return runtimeSpawn;
112
111
  }
113
112
  /**
114
113
  * Build the child env. Starts empty and copies through:
@@ -169,7 +168,7 @@ async function readStream(stream, opts) {
169
168
  *
170
169
  * Failure modes (see {@link AgentFailureReason}):
171
170
  *
172
- * • `spawn_failed` — `Bun.spawn` threw synchronously.
171
+ * • `spawn_failed` — the spawn call threw synchronously.
173
172
  * • `timeout` — exceeded the resolved timeout.
174
173
  * • `non_zero_exit` — child exited with a non-zero code.
175
174
  * • `parse_error` — `parseOutput === "json"` and stdout was not JSON.
@@ -233,7 +232,7 @@ export async function runAgent(profile, prompt, options = {}) {
233
232
  };
234
233
  }
235
234
  // Hard timeout. We prefer SIGTERM, then SIGKILL if SIGTERM is ignored,
236
- // but Bun.spawn only exposes a single .kill() — one signal is enough
235
+ // but the subprocess only exposes a single .kill() — one signal is enough
237
236
  // for the structured-failure contract.
238
237
  //
239
238
  // BUG-M3: only flag `timedOut` when the child has not already exited. A
@@ -0,0 +1,48 @@
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
+ * Claude Code agent command builder (migrated from `agent/builders.ts`, #563).
6
+ *
7
+ * Translates a platform-agnostic {@link AgentDispatchRequest} into the exact
8
+ * argv the `claude` CLI expects. This is the Claude-specific slice of the
9
+ * builder strategy; the shared infrastructure (`AgentCommandBuilder`,
10
+ * `getCommandBuilder`, the OpenCode/default builders, flag/tool helpers) stays
11
+ * in `agent/builders.ts`, which imports this builder back into
12
+ * `BUILTIN_BUILDERS`.
13
+ *
14
+ * Behaviour-preserving relocation: the produced argv is byte-identical to the
15
+ * pre-migration `claudeBuilder`. The builder's `platform` stays `'claude'` (the
16
+ * canonical harness id).
17
+ */
18
+ import { assertNotFlag, normalizeTools } from "../../agent/builder-shared.js";
19
+ import { resolveModel } from "../../agent/model-aliases.js";
20
+ /**
21
+ * Claude Code builder.
22
+ * Command shape: claude [--system-prompt "..."] [--model <m>] [--allowedTools <t>] --print "<prompt>"
23
+ *
24
+ * --print switches Claude Code to non-interactive captured output mode.
25
+ */
26
+ export const claudeBuilder = {
27
+ platform: "claude",
28
+ build(profile, req) {
29
+ assertNotFlag(req.systemPrompt, "systemPrompt");
30
+ assertNotFlag(req.model, "model");
31
+ const args = [...profile.args];
32
+ if (req.systemPrompt) {
33
+ args.push("--system-prompt", req.systemPrompt);
34
+ }
35
+ if (req.model) {
36
+ const resolved = resolveModel(req.model, "claude", profile.modelAliases);
37
+ args.push("--model", resolved);
38
+ }
39
+ if (req.tools) {
40
+ args.push("--allowedTools", normalizeTools(req.tools));
41
+ }
42
+ // --print = non-interactive, outputs to stdout — required for captured mode
43
+ args.push("--print");
44
+ args.push("--");
45
+ args.push(req.prompt);
46
+ return { argv: [profile.bin, ...args] };
47
+ },
48
+ };
@@ -0,0 +1,70 @@
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
+ * Claude Code LLM-config importer (migrated from `setup/harness-config-import.ts`,
6
+ * #563).
7
+ *
8
+ * Detects a Claude Code installation (filesystem only, no network) and reads
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.
13
+ *
14
+ * Behaviour-preserving relocation.
15
+ */
16
+ import fs from "node:fs";
17
+ import path from "node:path";
18
+ function homeDir() {
19
+ return process.env.HOME ?? process.env.USERPROFILE ?? "";
20
+ }
21
+ /**
22
+ * Imports LLM config from a Claude Code installation.
23
+ *
24
+ * Claude Code stores settings in `~/.claude/settings.json` or `~/.claude.json`.
25
+ * The model field may appear at the root or under `env.ANTHROPIC_MODEL`.
26
+ * The API key is always `ANTHROPIC_API_KEY`.
27
+ */
28
+ export const claudeCodeImporter = {
29
+ harnessName: "Claude Code",
30
+ detect() {
31
+ const home = homeDir();
32
+ // Claude Code is installed if the ~/.claude/ directory exists
33
+ return fs.existsSync(path.join(home, ".claude"));
34
+ },
35
+ importConfig() {
36
+ const home = homeDir();
37
+ // Try ~/.claude/settings.json, then ~/.claude.json
38
+ const candidates = [path.join(home, ".claude", "settings.json"), path.join(home, ".claude.json")];
39
+ for (const filePath of candidates) {
40
+ try {
41
+ if (!fs.existsSync(filePath))
42
+ continue;
43
+ const raw = JSON.parse(fs.readFileSync(filePath, "utf8"));
44
+ // Claude Code settings: model may be at root or nested under env
45
+ const envBlock = raw.env;
46
+ const model = typeof raw.model === "string"
47
+ ? raw.model
48
+ : typeof envBlock?.ANTHROPIC_MODEL === "string"
49
+ ? String(envBlock.ANTHROPIC_MODEL)
50
+ : undefined;
51
+ return {
52
+ harnessName: "Claude Code",
53
+ provider: "anthropic",
54
+ model: model ?? "claude-sonnet-4-5",
55
+ apiKeyEnvVar: "ANTHROPIC_API_KEY",
56
+ };
57
+ }
58
+ catch {
59
+ // try next candidate
60
+ }
61
+ }
62
+ // ~/.claude exists but no readable settings — still return basic Anthropic config
63
+ return {
64
+ harnessName: "Claude Code",
65
+ provider: "anthropic",
66
+ model: "claude-sonnet-4-5",
67
+ apiKeyEnvVar: "ANTHROPIC_API_KEY",
68
+ };
69
+ },
70
+ };
@@ -0,0 +1,64 @@
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
+ * Claude Code harness (#563).
6
+ *
7
+ * This is the per-harness barrel that gathers the Claude Code integration
8
+ * surfaces that were previously scattered across the codebase:
9
+ * - session-log reader → ./session-log.ts (ClaudeCodeProvider)
10
+ * - agent command builder → ./agent-builder.ts (claudeBuilder)
11
+ * - config importer → ./config-import.ts (claudeCodeImporter)
12
+ *
13
+ * It also defines {@link ClaudeHarness}, the {@link AkmHarness} descriptor that
14
+ * `HARNESS_REGISTRY` registers.
15
+ *
16
+ * ## id normalization bridge ('claude' vs 'claude-code')
17
+ *
18
+ * The canonical, persisted id is `'claude'` (used by the agent runner, agent
19
+ * profiles, the Zod config schema and `--type` resolution after normalization).
20
+ * `'claude-code'` is the historical RUNTIME identity — the string stamped on
21
+ * session-log events/refs, the extracted-session dedup key, and the value
22
+ * `resolveAgentIdentity` reports. It is registered as an `alias` and exposed as
23
+ * `runtimeId` so BOTH directions round-trip via `normalizeHarnessId()` /
24
+ * `denormalizeRuntimeIdentity()`. Existing persisted configs and session logs
25
+ * that say `'claude-code'` keep working unchanged.
26
+ */
27
+ import { BaseHarness } from "../types.js";
28
+ export { claudeBuilder } from "./agent-builder.js";
29
+ export { claudeCodeImporter } from "./config-import.js";
30
+ export { ClaudeCodeProvider } from "./session-log.js";
31
+ function caps(c) {
32
+ return {
33
+ sessionLogs: false,
34
+ agentDispatch: false,
35
+ detection: false,
36
+ configImport: false,
37
+ runtimeIdentity: false,
38
+ v1Migration: false,
39
+ ...c,
40
+ };
41
+ }
42
+ /**
43
+ * Claude Code.
44
+ *
45
+ * Canonical id is `'claude'`; `'claude-code'` is the runtime/session-log
46
+ * identity and is registered as an alias so both directions round-trip.
47
+ */
48
+ export class ClaudeHarness extends BaseHarness {
49
+ id = "claude";
50
+ displayName = "Claude Code";
51
+ aliases = ["claude-code"];
52
+ runtimeId = "claude-code";
53
+ // Home-relative config dir scanned by `akm setup` (#567). Claude Code has a
54
+ // session-log provider, so offering it as a stash source is functional.
55
+ setupDetectionDir = ".claude";
56
+ capabilities = caps({
57
+ sessionLogs: true,
58
+ agentDispatch: true,
59
+ detection: true,
60
+ configImport: true,
61
+ runtimeIdentity: true,
62
+ v1Migration: true,
63
+ });
64
+ }
@@ -4,7 +4,7 @@
4
4
  import fs from "node:fs";
5
5
  import os from "node:os";
6
6
  import path from "node:path";
7
- import { extractInlineRefMentions } from "../inline-refs";
7
+ import { extractInlineRefMentions } from "../../session-logs/inline-refs.js";
8
8
  const CLAUDE_PROJECTS_DIR = path.join(os.homedir(), ".claude", "projects");
9
9
  /**
10
10
  * Parse a single Claude Code JSONL event into a normalized {@link SessionEvent}.
@@ -75,7 +75,22 @@ function parseClaudeEvent(entry, sessionId, filePath, fallbackTsMs) {
75
75
  filePath,
76
76
  };
77
77
  }
78
+ /**
79
+ * Claude Code native session-log reader.
80
+ *
81
+ * id-normalization note (#563): the canonical harness id is `'claude'`, but
82
+ * the provider's `name` — which is STAMPED onto every {@link SessionEvent} /
83
+ * {@link SessionRef} (`harness: this.name`), used as the extracted-session
84
+ * dedup key, and embedded in `session:<harness>:<id>` proposal refs — stays
85
+ * `'claude-code'` (the harness runtimeId). Changing it would silently break
86
+ * round-tripping of already-persisted session-tracking rows and refs. Registry
87
+ * lookups normalize `'claude-code'` → `'claude'` via the #562 bridge
88
+ * (`getHarness`), and the `--type` flag accepts both, so the canonical id and
89
+ * the persisted runtime string coexist without drift.
90
+ */
78
91
  export class ClaudeCodeProvider {
92
+ // Runtime identity (NOT the canonical id) — see class doc. Equals
93
+ // HARNESS_BY_ID.get("claude").runtimeId.
79
94
  name = "claude-code";
80
95
  isAvailable() {
81
96
  return fs.existsSync(CLAUDE_PROJECTS_DIR);
@@ -0,0 +1,144 @@
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
+ * Single registration point for every akm agent harness (#562).
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.
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).
15
+ *
16
+ * Implementations (session-log readers, agent profiles) are migrated under each
17
+ * harness in #563/#564; this step only owns ids + capability membership and
18
+ * wires the existing call sites to consult it (behaviour-preserving).
19
+ */
20
+ import { ClaudeHarness } from "./claude/index.js";
21
+ import { OpencodeHarness } from "./opencode/index.js";
22
+ import { OpencodeSdkHarness } from "./opencode-sdk/index.js";
23
+ // Each harness descriptor (ClaudeHarness, OpencodeHarness, OpencodeSdkHarness)
24
+ // lives in its own per-harness directory alongside that harness's session-log
25
+ // reader, agent builder, config importer, and/or SDK runner (#563/#564). They
26
+ // are imported above and registered in HARNESS_REGISTRY below.
27
+ /**
28
+ * The single registration point. Add a harness here (and nothing else) to make
29
+ * every derived registry pick it up.
30
+ *
31
+ * Typed `as const` (not `AkmHarness[]`) so each entry keeps its literal `id`,
32
+ * which lets `VALID_HARNESS_IDS` stay a literal tuple — `HarnessId`,
33
+ * `z.enum(...)`, and the `platform` union all need the literal types.
34
+ */
35
+ // Order is significant: VALID_HARNESS_IDS derives from this array and feeds the
36
+ // committed JSON-schema enum order. Kept as [opencode, claude, opencode-sdk] to
37
+ // match the pre-unification VALID_HARNESS_IDS so the generated schema does not
38
+ // drift (behaviour-preserving, #562).
39
+ export const HARNESS_REGISTRY = Object.freeze([
40
+ new OpencodeHarness(),
41
+ new ClaudeHarness(),
42
+ new OpencodeSdkHarness(),
43
+ ]);
44
+ /** Lookup by canonical id. */
45
+ export const HARNESS_BY_ID = new Map(HARNESS_REGISTRY.map((h) => [h.id, h]));
46
+ /**
47
+ * Lookup by canonical id OR any alias OR runtime id — the normalization bridge
48
+ * resolver. Both 'claude' and 'claude-code' map to the Claude harness.
49
+ */
50
+ const HARNESS_BY_ANY_ID = (() => {
51
+ const m = new Map();
52
+ for (const h of HARNESS_REGISTRY) {
53
+ m.set(h.id, h);
54
+ if (h.runtimeId)
55
+ m.set(h.runtimeId, h);
56
+ for (const a of h.aliases)
57
+ m.set(a, h);
58
+ }
59
+ return m;
60
+ })();
61
+ /**
62
+ * Canonical, ordered list of valid harness / platform ids. The Zod
63
+ * `AgentPlatformSchema` enum, the `AgentProfileConfigV2` platform union,
64
+ * `parseAgentProfilesMapV2`'s membership check, and setup's `DetectedHarness`
65
+ * union all derive from this so they cannot drift.
66
+ */
67
+ export const VALID_HARNESS_IDS = Object.freeze(HARNESS_REGISTRY.map((h) => h.id));
68
+ /** Harnesses that expose readable native session logs. */
69
+ export const SESSION_LOG_HARNESSES = HARNESS_REGISTRY.filter((h) => h.capabilities.sessionLogs);
70
+ /** Harnesses that can be dispatched as an agent CLI / SDK. */
71
+ export const AGENT_DISPATCH_HARNESSES = HARNESS_REGISTRY.filter((h) => h.capabilities.agentDispatch);
72
+ /** Harnesses that can import an existing harness config into akm. */
73
+ export const CONFIG_IMPORTER_HARNESSES = HARNESS_REGISTRY.filter((h) => h.capabilities.configImport);
74
+ /** Harnesses that participate in `akm setup` detection. */
75
+ export const DETECTION_HARNESSES = HARNESS_REGISTRY.filter((h) => h.capabilities.detection);
76
+ /**
77
+ * Resolve any id form (canonical id, alias, or runtime id) to the harness
78
+ * descriptor, or `undefined` if unknown.
79
+ */
80
+ export function getHarness(id) {
81
+ return HARNESS_BY_ANY_ID.get(id);
82
+ }
83
+ /**
84
+ * id normalization bridge — alias → canonical.
85
+ *
86
+ * Maps any known alias/runtime id to its canonical persisted id (e.g.
87
+ * 'claude-code' → 'claude'). Unknown ids pass through unchanged so callers can
88
+ * still validate them. This is what keeps existing persisted configs that say
89
+ * 'claude-code' working against the canonical 'claude' registry.
90
+ */
91
+ export function normalizeHarnessId(id) {
92
+ return HARNESS_BY_ANY_ID.get(id)?.id ?? id;
93
+ }
94
+ /**
95
+ * Resolve a legacy v1 agent-profile name to its v2 platform id (#566).
96
+ *
97
+ * v1 agent profiles never carried an explicit `platform`; it had to be inferred
98
+ * from the profile name. This is the SINGLE registry-backed resolver that
99
+ * replaces both the old standalone `guessAgentPlatform()` in config-migration
100
+ * and the `name.includes("claude") ? "claude" : "opencode"` heuristic in setup.
101
+ * Each harness owns its own `matchesV1ProfileName()`; an unknown name matches no
102
+ * harness and returns `undefined`, so the caller drops it instead of silently
103
+ * defaulting to `'opencode'`.
104
+ *
105
+ * Harnesses are consulted most-specific-id-first (longest id wins) so a
106
+ * decorated name like `"opencode-sdk-fast"` resolves to `'opencode-sdk'` rather
107
+ * than being over-matched by OpenCode's `"opencode"` prefix.
108
+ */
109
+ const V1_RESOLUTION_ORDER = [...HARNESS_REGISTRY].sort((a, b) => b.id.length - a.id.length);
110
+ export function v1ProfilePlatform(name) {
111
+ for (const h of V1_RESOLUTION_ORDER) {
112
+ if (h.matchesV1ProfileName(name))
113
+ return h.id;
114
+ }
115
+ return undefined;
116
+ }
117
+ /**
118
+ * Default agent-profile name for a detected harness id (#566).
119
+ *
120
+ * Used by `akm setup`'s headless/recommended-config path so a newly added
121
+ * dispatch-capable harness gets a usable default profile name (its canonical
122
+ * id) instead of falling through a hardcoded if-chain with no default. Returns
123
+ * `undefined` for `"none"` or any id that is unknown / not agent-dispatch
124
+ * capable.
125
+ */
126
+ export function defaultProfileName(detected) {
127
+ const h = HARNESS_BY_ANY_ID.get(detected);
128
+ if (!h?.capabilities.agentDispatch)
129
+ return undefined;
130
+ return h.id;
131
+ }
132
+ /**
133
+ * id normalization bridge — canonical → runtime identity.
134
+ *
135
+ * Maps a canonical id to the string a harness reports at runtime / in its
136
+ * session logs (e.g. 'claude' → 'claude-code'). Used by workflow run
137
+ * attribution and the session-logs provider name so the persisted runtime
138
+ * identity stays stable. Falls back to the canonical id when the harness has no
139
+ * distinct runtime identity.
140
+ */
141
+ export function denormalizeRuntimeIdentity(id) {
142
+ const h = HARNESS_BY_ANY_ID.get(id);
143
+ return h?.runtimeId ?? h?.id ?? id;
144
+ }
@@ -0,0 +1,43 @@
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
+ * OpenCode agent command builder (migrated from `agent/builders.ts`, #564).
6
+ *
7
+ * Translates a platform-agnostic {@link AgentDispatchRequest} into the exact
8
+ * argv the `opencode` CLI expects. This is the OpenCode-specific slice of the
9
+ * builder strategy; the shared infrastructure (`AgentCommandBuilder`,
10
+ * `getCommandBuilder`, the default builder, flag/tool helpers) stays in
11
+ * `agent/builders.ts`, which imports this builder back into `BUILTIN_BUILDERS`.
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).
16
+ */
17
+ import { assertNotFlag } from "../../agent/builder-shared.js";
18
+ import { resolveModel } from "../../agent/model-aliases.js";
19
+ /**
20
+ * OpenCode builder.
21
+ * Command shape: opencode run [--system-prompt "..."] [--model <m>] "<prompt>"
22
+ *
23
+ * Tool policy is omitted — opencode manages tool access through its own agent
24
+ * config files, not via CLI flags.
25
+ */
26
+ export const opencodeBuilder = {
27
+ platform: "opencode",
28
+ build(profile, req) {
29
+ assertNotFlag(req.systemPrompt, "systemPrompt");
30
+ assertNotFlag(req.model, "model");
31
+ const args = [...profile.args]; // starts with ["run"]
32
+ if (req.systemPrompt) {
33
+ args.push("--system-prompt", req.systemPrompt);
34
+ }
35
+ if (req.model) {
36
+ const resolved = resolveModel(req.model, "opencode", profile.modelAliases);
37
+ args.push("--model", resolved);
38
+ }
39
+ args.push("--");
40
+ args.push(req.prompt);
41
+ return { argv: [profile.bin, ...args] };
42
+ },
43
+ };
@@ -0,0 +1,82 @@
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
+ * OpenCode LLM-config importer (migrated from `setup/harness-config-import.ts`,
6
+ * #564).
7
+ *
8
+ * Detects an OpenCode installation (filesystem only, no network) and reads its
9
+ * config to extract LLM connection details. API key VALUES are never stored —
10
+ * only the env var name that holds them. The pluggable registry
11
+ * (`HARNESS_CONFIG_IMPORTERS`) and the Claude importer stay in their respective
12
+ * modules; `setup/harness-config-import.ts` imports this importer back.
13
+ *
14
+ * Behaviour-preserving relocation.
15
+ */
16
+ import fs from "node:fs";
17
+ import path from "node:path";
18
+ function homeDir() {
19
+ return process.env.HOME ?? process.env.USERPROFILE ?? "";
20
+ }
21
+ /**
22
+ * Imports LLM config from an OpenCode installation.
23
+ *
24
+ * OpenCode stores config in `~/.config/opencode/config.json` or
25
+ * `~/.opencode/config.json`. Its schema has a `providers` array and a
26
+ * `model` field. API keys in providers appear as `$ENV_VAR_NAME` references.
27
+ */
28
+ export const openCodeImporter = {
29
+ harnessName: "OpenCode",
30
+ detect() {
31
+ const home = homeDir();
32
+ return fs.existsSync(path.join(home, ".config", "opencode")) || fs.existsSync(path.join(home, ".opencode"));
33
+ },
34
+ importConfig() {
35
+ const home = homeDir();
36
+ const candidates = [
37
+ path.join(home, ".config", "opencode", "config.json"),
38
+ path.join(home, ".opencode", "config.json"),
39
+ path.join(process.cwd(), ".opencode", "config.json"),
40
+ ];
41
+ for (const filePath of candidates) {
42
+ try {
43
+ if (!fs.existsSync(filePath))
44
+ continue;
45
+ const raw = JSON.parse(fs.readFileSync(filePath, "utf8"));
46
+ // OpenCode config shape: { model?: string, providers?: Array<{id, apiKey, baseUrl, ...}> }
47
+ const model = typeof raw.model === "string" ? raw.model : undefined;
48
+ // Extract provider info from the first entry in the providers array
49
+ let provider;
50
+ let baseUrl;
51
+ let apiKeyEnvVar;
52
+ const providers = Array.isArray(raw.providers) ? raw.providers : [];
53
+ if (providers.length > 0) {
54
+ const first = providers[0];
55
+ provider = typeof first?.id === "string" ? first.id : undefined;
56
+ baseUrl =
57
+ typeof first?.baseUrl === "string"
58
+ ? first.baseUrl
59
+ : typeof first?.base_url === "string"
60
+ ? first.base_url
61
+ : undefined;
62
+ // apiKey is an env var reference like "$OPENAI_API_KEY" — extract the var name
63
+ const apiKeyVal = typeof first?.apiKey === "string" ? first.apiKey : "";
64
+ if (apiKeyVal.startsWith("$")) {
65
+ apiKeyEnvVar = apiKeyVal.slice(1);
66
+ }
67
+ }
68
+ return {
69
+ harnessName: "OpenCode",
70
+ provider,
71
+ model,
72
+ baseUrl,
73
+ apiKeyEnvVar,
74
+ };
75
+ }
76
+ catch {
77
+ // try next candidate
78
+ }
79
+ }
80
+ return null;
81
+ },
82
+ };