akm-cli 0.9.1 → 0.9.2-alpha.2

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 (350) hide show
  1. package/CHANGELOG.md +103 -28
  2. package/README.md +3 -1
  3. package/SECURITY.md +1 -1
  4. package/STABILITY.md +1 -1
  5. package/dist/akm +2 -2
  6. package/dist/akm-migrate +2 -2
  7. package/dist/assets/hints/cli-hints-full.md +14 -9
  8. package/dist/assets/improve-strategies/proactive-maintenance.json +1 -1
  9. package/dist/assets/improve-strategies/reflect-distill.json +1 -1
  10. package/dist/assets/models.json +35 -0
  11. package/dist/assets/stash-skeleton/facts/conventions/backlinks.md +3 -4
  12. package/dist/assets/stash-skeleton/facts/conventions/organization.md +1 -3
  13. package/dist/assets/tasks/core/extract.yml +6 -5
  14. package/dist/assets/tasks/core/improve.yml +6 -5
  15. package/dist/assets/tasks/core/index-refresh.yml +6 -5
  16. package/dist/assets/tasks/core/sync.yml +6 -5
  17. package/dist/assets/tasks/core/version-check.yml +6 -5
  18. package/dist/assets/tasks/improve/akm-graph-refresh-weekly.yml +6 -5
  19. package/dist/assets/tasks/improve/akm-improve-catchup.yml +6 -5
  20. package/dist/assets/tasks/improve/akm-improve-consolidate.yml +6 -5
  21. package/dist/assets/tasks/improve/akm-improve-frequent.yml +6 -5
  22. package/dist/assets/tasks/improve/akm-improve-nightly.yml +6 -5
  23. package/dist/cli/confirm.js +2 -2
  24. package/dist/cli/parse-args.js +3 -24
  25. package/dist/cli/retired-commands.js +1 -1
  26. package/dist/cli/shared.js +2 -2
  27. package/dist/cli.js +11 -9
  28. package/dist/commands/agent/agent-dispatch.js +55 -89
  29. package/dist/commands/agent/contribute-cli.js +12 -45
  30. package/dist/commands/command/builtin-action.js +32 -0
  31. package/dist/commands/command/command-cli.js +99 -0
  32. package/dist/commands/command/command-execution.js +308 -0
  33. package/dist/commands/command/execution-source-loader.js +176 -0
  34. package/dist/commands/command/portable-template.js +60 -0
  35. package/dist/commands/config-cli.js +10 -4
  36. package/dist/commands/env/env.js +4 -2
  37. package/dist/commands/feedback-cli.js +1 -1
  38. package/dist/commands/health/checks.js +241 -29
  39. package/dist/commands/health/html-report.js +0 -14
  40. package/dist/commands/health/report-view-model.js +0 -1
  41. package/dist/commands/health/surfaces.js +6 -7
  42. package/dist/commands/health/types.js +0 -2
  43. package/dist/commands/health.js +63 -18
  44. package/dist/commands/improve/collapse-detector.js +5 -6
  45. package/dist/commands/improve/consolidate.js +251 -214
  46. package/dist/commands/improve/distill/promote-memory.js +71 -34
  47. package/dist/commands/improve/distill/quality-gate.js +17 -5
  48. package/dist/commands/improve/distill.js +232 -155
  49. package/dist/commands/improve/eligibility.js +112 -79
  50. package/dist/commands/improve/execution.js +57 -0
  51. package/dist/commands/improve/extract-cli.js +5 -5
  52. package/dist/commands/improve/extract-prompt.js +64 -22
  53. package/dist/commands/improve/extract.js +608 -360
  54. package/dist/commands/improve/improve-strategies.js +43 -14
  55. package/dist/commands/improve/improve.js +249 -29
  56. package/dist/commands/improve/loop-stages.js +11 -17
  57. package/dist/commands/improve/memory/memory-contradiction-detect.js +90 -66
  58. package/dist/commands/improve/outcome-loop.js +22 -38
  59. package/dist/commands/improve/planner.js +134 -0
  60. package/dist/commands/improve/preparation.js +730 -409
  61. package/dist/commands/improve/reflect.js +386 -223
  62. package/dist/commands/improve/run-context.js +3 -4
  63. package/dist/commands/improve/salience.js +6 -58
  64. package/dist/commands/improve/session-asset.js +12 -12
  65. package/dist/commands/lint/index.js +101 -29
  66. package/dist/commands/migrate-cli.js +11 -69
  67. package/dist/commands/migration-tool.js +6 -9
  68. package/dist/commands/models-cli.js +27 -0
  69. package/dist/commands/proposal/drain.js +258 -186
  70. package/dist/commands/proposal/proposal-cli.js +32 -10
  71. package/dist/commands/proposal/proposal.js +2 -5
  72. package/dist/commands/proposal/propose.js +192 -172
  73. package/dist/commands/proposal/repository.js +54 -91
  74. package/dist/commands/proposal/validators/proposal-validators.js +9 -7
  75. package/dist/commands/read/curate.js +53 -22
  76. package/dist/commands/read/registry-search.js +25 -9
  77. package/dist/commands/read/remember-cli.js +14 -2
  78. package/dist/commands/read/search.js +10 -4
  79. package/dist/commands/read/show.js +139 -153
  80. package/dist/commands/registry-cli.js +16 -7
  81. package/dist/commands/remember.js +33 -18
  82. package/dist/commands/sources/add-cli.js +19 -178
  83. package/dist/commands/sources/bundle-cli.js +15 -3
  84. package/dist/commands/sources/dangerous-env-audit.js +135 -0
  85. package/dist/commands/sources/info.js +2 -1
  86. package/dist/commands/sources/installed-stashes.js +901 -177
  87. package/dist/commands/sources/schema-repair.js +174 -95
  88. package/dist/commands/sources/self-update.js +30 -74
  89. package/dist/commands/sources/source-add.js +3 -5
  90. package/dist/commands/sources/sources-cli.js +2 -15
  91. package/dist/commands/sources/update-transaction.js +220 -0
  92. package/dist/commands/tasks/tasks-cli.js +3 -3
  93. package/dist/commands/tasks/tasks.js +736 -317
  94. package/dist/commands/workflow-cli.js +2 -2
  95. package/dist/core/adapter/adapters/agent-skills-adapter.js +3 -0
  96. package/dist/core/adapter/adapters/akm-adapter.js +85 -35
  97. package/dist/core/adapter/adapters/akm-lint.js +54 -39
  98. package/dist/core/adapter/adapters/akm-metadata.js +45 -45
  99. package/dist/core/adapter/adapters/akm-task-adapter.js +32 -49
  100. package/dist/core/adapter/adapters/akm-workflow-adapter.js +38 -23
  101. package/dist/core/adapter/adapters/dotenv-adapter.js +30 -1
  102. package/dist/core/adapter/adapters/generic-files-adapter.js +11 -0
  103. package/dist/core/adapter/adapters/index.js +0 -9
  104. package/dist/core/adapter/adapters/llm-wiki-adapter.js +4 -0
  105. package/dist/core/adapter/adapters/okf-adapter.js +4 -0
  106. package/dist/core/adapter/adapters/opencode-adapter.js +5 -8
  107. package/dist/core/adapter/adapters/tool-dir-shared.js +63 -6
  108. package/dist/core/adapter/adapters/website-snapshot-adapter.js +4 -0
  109. package/dist/core/adapter/execution-source.js +308 -0
  110. package/dist/core/adapter/recognize-match.js +36 -13
  111. package/dist/core/adapter/registry.js +0 -9
  112. package/dist/core/asset/stash-meta.js +94 -4
  113. package/dist/core/common.js +6 -11
  114. package/dist/core/config/config-io.js +3 -3
  115. package/dist/core/config/config-schema.js +18 -40
  116. package/dist/core/config/config-sources.js +11 -21
  117. package/dist/core/config/config-walker.js +31 -13
  118. package/dist/core/config/config.js +23 -26
  119. package/dist/core/config/schema/engines.js +8 -7
  120. package/dist/core/config/schema/improve-processes.js +29 -5
  121. package/dist/core/config/schema/index-config.js +0 -27
  122. package/dist/core/config/schema/primitives.js +1 -23
  123. package/dist/core/config/schema/sources-bundles.js +13 -16
  124. package/dist/core/errors.js +2 -0
  125. package/dist/core/events.js +68 -32
  126. package/dist/core/extra-params.js +1 -0
  127. package/dist/core/improve-result.js +315 -0
  128. package/dist/core/lesson-lint.js +0 -6
  129. package/dist/core/maintenance-barrier.js +4 -4
  130. package/dist/core/network-policy.js +152 -0
  131. package/dist/core/paths.js +1 -1
  132. package/dist/core/recognition-util.js +4 -4
  133. package/dist/core/registry-url.js +456 -0
  134. package/dist/core/state/migrations.js +161 -47
  135. package/dist/core/state-db.js +453 -80
  136. package/dist/core/system-error.js +32 -0
  137. package/dist/core/time.js +2 -12
  138. package/dist/core/write-source.js +0 -18
  139. package/dist/execution/directory-identity.js +52 -0
  140. package/dist/execution/executable-identity.js +107 -0
  141. package/dist/execution/guarded-source.js +398 -0
  142. package/dist/execution/json.js +95 -0
  143. package/dist/{commands/health/types-session-log.js → execution/limits.js} +2 -1
  144. package/dist/execution/record.js +55 -0
  145. package/dist/execution/resolved-request.js +730 -0
  146. package/dist/execution/source.js +320 -0
  147. package/dist/indexer/bundle-identity-guard.js +5 -4
  148. package/dist/indexer/db/graph-db.js +33 -0
  149. package/dist/indexer/graph/graph-boost.js +3 -4
  150. package/dist/indexer/graph/graph-extraction.js +562 -373
  151. package/dist/indexer/index-written-assets.js +78 -39
  152. package/dist/indexer/indexer.js +471 -432
  153. package/dist/indexer/installations.js +6 -0
  154. package/dist/indexer/lookup/adapter-concept-owner.js +283 -0
  155. package/dist/indexer/materialize-embeddings.js +155 -0
  156. package/dist/indexer/passes/memory-inference.js +227 -174
  157. package/dist/indexer/passes/metadata.js +263 -118
  158. package/dist/indexer/scan/doc-to-entry.js +7 -10
  159. package/dist/indexer/scan/drain-dir.js +51 -23
  160. package/dist/indexer/search/db-search.js +156 -50
  161. package/dist/indexer/search/fts-query.js +40 -40
  162. package/dist/indexer/search/ranking.js +36 -1
  163. package/dist/indexer/search/search-attribution.js +3 -1
  164. package/dist/indexer/search/search-fields.js +23 -14
  165. package/dist/indexer/search/search-hit-enrichers.js +1 -1
  166. package/dist/indexer/search/search-source.js +7 -16
  167. package/dist/indexer/search/semantic-status.js +10 -1
  168. package/dist/indexer/usage/show-usage.js +105 -0
  169. package/dist/indexer/usage/usage-events.js +7 -2
  170. package/dist/indexer/walk/matchers.js +40 -10
  171. package/dist/indexer/walk/path-resolver.js +5 -2
  172. package/dist/indexer/walk/walker.js +20 -2
  173. package/dist/integrations/agent/builder-shared.js +3 -6
  174. package/dist/integrations/agent/conversation-fallback.js +16 -0
  175. package/dist/integrations/agent/engine-resolution.js +87 -87
  176. package/dist/integrations/agent/execution-cascade.js +566 -0
  177. package/dist/integrations/agent/execution-definitions.js +211 -0
  178. package/dist/integrations/agent/execution-lowering.js +811 -0
  179. package/dist/integrations/agent/execution-preparation.js +67 -0
  180. package/dist/integrations/agent/index.js +0 -2
  181. package/dist/integrations/agent/inline-execution.js +74 -0
  182. package/dist/integrations/agent/model-map.js +515 -0
  183. package/dist/integrations/agent/persona-fallback.js +30 -0
  184. package/dist/integrations/agent/request-lowering.js +186 -0
  185. package/dist/integrations/agent/runner-dispatch.js +230 -37
  186. package/dist/integrations/agent/runner.js +12 -83
  187. package/dist/integrations/harnesses/aider/agent-builder.js +8 -0
  188. package/dist/integrations/harnesses/aider/index.js +0 -1
  189. package/dist/integrations/harnesses/amazonq/agent-builder.js +8 -0
  190. package/dist/integrations/harnesses/amazonq/index.js +0 -1
  191. package/dist/integrations/harnesses/claude/agent-builder.js +14 -1
  192. package/dist/integrations/harnesses/claude/index.js +1 -5
  193. package/dist/integrations/harnesses/claude/session-log.js +3 -33
  194. package/dist/integrations/harnesses/codex/agent-builder.js +8 -0
  195. package/dist/integrations/harnesses/codex/index.js +0 -1
  196. package/dist/integrations/harnesses/copilot/agent-builder.js +8 -0
  197. package/dist/integrations/harnesses/copilot/index.js +0 -1
  198. package/dist/integrations/harnesses/gemini/agent-builder.js +8 -0
  199. package/dist/integrations/harnesses/gemini/index.js +0 -1
  200. package/dist/integrations/harnesses/index.js +4 -44
  201. package/dist/integrations/harnesses/opencode/agent-builder.js +16 -9
  202. package/dist/integrations/harnesses/opencode/index.js +0 -2
  203. package/dist/integrations/harnesses/opencode/session-log.js +14 -204
  204. package/dist/integrations/harnesses/opencode-sdk/harness.js +12 -1
  205. package/dist/integrations/harnesses/opencode-sdk/sdk-runner.js +40 -42
  206. package/dist/integrations/harnesses/openhands/agent-builder.js +8 -0
  207. package/dist/integrations/harnesses/openhands/index.js +0 -1
  208. package/dist/integrations/harnesses/pi/agent-builder.js +8 -0
  209. package/dist/integrations/harnesses/pi/index.js +0 -1
  210. package/dist/integrations/harnesses/shared.js +0 -1
  211. package/dist/integrations/harnesses/types.js +1 -3
  212. package/dist/integrations/lockfile.js +82 -79
  213. package/dist/integrations/session-logs/index.js +6 -17
  214. package/dist/integrations/session-logs/provider-base.js +1 -29
  215. package/dist/llm/client.js +10 -5
  216. package/dist/llm/embedder.js +6 -7
  217. package/dist/llm/embedders/local.js +37 -88
  218. package/dist/llm/embedders/types.js +1 -1
  219. package/dist/llm/graph-extract.js +75 -50
  220. package/dist/llm/index-passes.js +43 -5
  221. package/dist/llm/memory-infer.js +8 -6
  222. package/dist/llm/metadata-enhance.js +5 -3
  223. package/dist/llm/structured-call.js +122 -25
  224. package/dist/output/format-exempt.js +1 -1
  225. package/dist/output/render-registry.js +0 -16
  226. package/dist/output/renderers.js +12 -7
  227. package/dist/output/shapes/curate.js +1 -0
  228. package/dist/output/shapes/helpers.js +10 -2
  229. package/dist/output/shapes/passthrough.js +2 -0
  230. package/dist/output/text/command-format.js +31 -33
  231. package/dist/output/text/health-format.js +1 -29
  232. package/dist/output/text/migrate.js +6 -56
  233. package/dist/output/text/proposal-format.js +16 -1
  234. package/dist/output/text/workflow-format.js +16 -0
  235. package/dist/registry/network.js +279 -0
  236. package/dist/registry/pinned-request-helper.js +247 -0
  237. package/dist/registry/pinned-transport.js +717 -0
  238. package/dist/registry/providers/skills-sh.js +18 -6
  239. package/dist/registry/providers/static-index.js +20 -7
  240. package/dist/registry/resolve.js +53 -28
  241. package/dist/scripts/akm-migrate-node.js +19334 -52269
  242. package/dist/scripts/akm-migrate.js +19270 -51612
  243. package/dist/setup/registry-stash-loader.js +64 -20
  244. package/dist/setup/semantic-assets.js +9 -34
  245. package/dist/setup/setup.js +12 -30
  246. package/dist/setup/source-identity.js +17 -0
  247. package/dist/setup/steps/sources.js +36 -15
  248. package/dist/setup/steps/tasks.js +39 -11
  249. package/dist/sources/providers/git-provider.js +3 -3
  250. package/dist/sources/providers/npm.js +2 -2
  251. package/dist/sources/providers/provider-utils.js +4 -3
  252. package/dist/sources/providers/website.js +11 -7
  253. package/dist/sources/snapshot-fetchers/host-guard.js +9 -136
  254. package/dist/sources/snapshot-fetchers/website-ingest.js +25 -109
  255. package/dist/sources/website-url.js +73 -0
  256. package/dist/storage/engines/sqlite-migrations.js +81 -26
  257. package/dist/storage/managed-db.js +27 -24
  258. package/dist/storage/repositories/events-repository.js +3 -0
  259. package/dist/storage/repositories/index-connection.js +42 -10
  260. package/dist/storage/repositories/index-entries-repository.js +203 -229
  261. package/dist/storage/repositories/index-entry-mapper.js +8 -12
  262. package/dist/storage/repositories/index-entry-schema.js +255 -0
  263. package/dist/storage/repositories/index-fts-repository.js +64 -71
  264. package/dist/storage/repositories/index-llm-cache-repository.js +8 -13
  265. package/dist/storage/repositories/index-meta-repository.js +0 -11
  266. package/dist/storage/repositories/index-schema.js +74 -350
  267. package/dist/storage/repositories/index-utility-repository.js +12 -17
  268. package/dist/storage/repositories/index-vec-repository.js +56 -7
  269. package/dist/storage/repositories/proposals-repository.js +4 -127
  270. package/dist/storage/repositories/registry-cache.js +2 -1
  271. package/dist/storage/repositories/task-history-repository.js +20 -40
  272. package/dist/storage/repositories/workflow-runs-repository.js +228 -129
  273. package/dist/storage/sqlite-read-snapshot.js +148 -0
  274. package/dist/tasks/backends/cron.js +170 -42
  275. package/dist/tasks/backends/index.js +1 -1
  276. package/dist/tasks/backends/launchd.js +787 -202
  277. package/dist/tasks/backends/schtasks.js +282 -83
  278. package/dist/tasks/embedded.js +7 -7
  279. package/dist/tasks/frozen-script.js +50 -0
  280. package/dist/tasks/resolve-akm-bin.js +5 -1
  281. package/dist/tasks/runner.js +239 -251
  282. package/dist/tasks/runtime-v3.js +281 -0
  283. package/dist/tasks/scheduler-binding.js +272 -0
  284. package/dist/tasks/scheduler-invocation.js +57 -43
  285. package/dist/tasks/scheduler-sync.js +654 -0
  286. package/dist/tasks/source-v3.js +752 -0
  287. package/dist/tasks/standalone-script-entry.js +5 -0
  288. package/dist/tasks/task-id.js +29 -0
  289. package/dist/workflows/authoring/authoring.js +15 -32
  290. package/dist/workflows/exec/dispatch-redaction.js +14 -8
  291. package/dist/workflows/exec/exec-unit.js +7 -28
  292. package/dist/workflows/exec/frozen-judge.js +57 -89
  293. package/dist/workflows/exec/lowering-notices.js +23 -0
  294. package/dist/workflows/exec/native-executor.js +301 -458
  295. package/dist/workflows/exec/param-secrets.js +4 -3
  296. package/dist/workflows/exec/run-workflow.js +26 -32
  297. package/dist/workflows/exec/step-work.js +105 -109
  298. package/dist/workflows/exec/unit-dispatch.js +103 -27
  299. package/dist/workflows/exec/unit-writer.js +3 -3
  300. package/dist/workflows/exec/worktree.js +2 -2
  301. package/dist/workflows/ir/compile.js +86 -72
  302. package/dist/workflows/ir/environment-v4.js +328 -0
  303. package/dist/workflows/ir/freeze-v4.js +122 -0
  304. package/dist/workflows/ir/plan-hash.js +13 -7
  305. package/dist/workflows/ir/schema-v4.js +525 -0
  306. package/dist/workflows/ir/schema.js +25 -284
  307. package/dist/workflows/ir/source-freeze-v4.js +506 -0
  308. package/dist/workflows/parser.js +27 -24
  309. package/dist/workflows/program/schema.js +1 -2
  310. package/dist/workflows/renderer.js +42 -29
  311. package/dist/workflows/resource-limits.js +4 -5
  312. package/dist/workflows/runtime/agent-identity.js +11 -13
  313. package/dist/workflows/runtime/plan-classifier.js +8 -8
  314. package/dist/workflows/runtime/runs.js +27 -43
  315. package/dist/workflows/runtime/workflow-asset-loader.js +45 -205
  316. package/dist/workflows/source-files.js +373 -0
  317. package/dist/workflows/source-ir/compile.js +196 -0
  318. package/dist/workflows/source-ir/github-yaml.js +577 -0
  319. package/dist/workflows/source-ir/ordering.js +38 -0
  320. package/dist/workflows/source-ir/program.js +50 -0
  321. package/dist/workflows/source-ir/result.js +26 -0
  322. package/dist/workflows/source-ir/schema.js +772 -0
  323. package/dist/workflows/source-ir/semantics.js +242 -0
  324. package/dist/workflows/source-ir/uses.js +14 -0
  325. package/docs/README.md +2 -0
  326. package/docs/migration/README.md +3 -1
  327. package/docs/migration/release-notes/0.9.2.md +55 -0
  328. package/docs/migration/release-notes/README.md +5 -0
  329. package/docs/migration/v0.8-to-v0.9.md +76 -1077
  330. package/docs/migration/v0.9.0-troubleshooting.md +104 -516
  331. package/docs/migration/v0.9.1-to-v0.9.2.md +150 -0
  332. package/docs/reference/README.md +1 -0
  333. package/docs/reference/cli.md +230 -98
  334. package/docs/reference/configuration.md +159 -36
  335. package/docs/reference/data-and-telemetry.md +19 -1
  336. package/docs/reference/supported-formats.md +23 -3
  337. package/docs/reference/tasks.md +182 -0
  338. package/docs/reference/workflow-schema.md +91 -40
  339. package/docs/reference/workflows.md +33 -6
  340. package/package.json +10 -6
  341. package/schemas/akm-config.json +372 -224
  342. package/schemas/akm-task.json +324 -80
  343. package/schemas/akm-workflow.json +6 -9
  344. package/dist/core/migration-operation.js +0 -75
  345. package/dist/integrations/agent/model-aliases.js +0 -74
  346. package/dist/tasks/parser.js +0 -380
  347. package/dist/tasks/schema.js +0 -123
  348. package/dist/tasks/validator.js +0 -80
  349. package/dist/workflows/ir/freeze.js +0 -320
  350. package/dist/workflows/runtime/document-cache.js +0 -13
@@ -5,6 +5,7 @@ import fs from "node:fs";
5
5
  import os from "node:os";
6
6
  import path from "node:path";
7
7
  import { openDatabase } from "../../../storage/database.js";
8
+ import { openSqliteReadSnapshot } from "../../../storage/sqlite-read-snapshot.js";
8
9
  import { extractInlineRefMentions } from "../../session-logs/inline-refs.js";
9
10
  import { AbstractSessionLogProvider } from "../../session-logs/provider-base.js";
10
11
  function getOpenCodeBaseDir() {
@@ -14,21 +15,12 @@ function getOpenCodeBaseDir() {
14
15
  return path.join(os.homedir(), ".local", "share", "opencode");
15
16
  }
16
17
  /**
17
- * Opencode storage layouts:
18
+ * Opencode session storage:
18
19
  *
19
20
  * SQLite (current, observed 2026-06): `<base>/opencode.db` — a Drizzle-managed
20
21
  * database with `session` / `message` / `part` tables. Message text lives in
21
22
  * `part` rows (`data` JSON, `type: "text"`); `message.data` holds role/timing.
22
- * This is the layout current opencode builds write; it is preferred whenever
23
- * `opencode.db` exists.
24
- *
25
- * JSON files (legacy, observed 2026-05): `<base>/storage/session/<projectId>/
26
- * <sessionId>.json` (metadata) + `<base>/storage/message/<sessionId>/
27
- * <messageId>.json` (one per message). Read only when `opencode.db` is absent.
28
- *
29
- * Older builds wrote logs directly into `<base>/log/` and `<base>/*.log`;
30
- * those are still scanned by {@link OpenCodeProvider.readEvents} for
31
- * backward compatibility with the existing failure-pattern aggregator.
23
+ * This is the sole supported layout.
32
24
  */
33
25
  /** Filename of opencode's SQLite session store, relative to its base dir. */
34
26
  const OPENCODE_DB_FILENAME = "opencode.db";
@@ -36,153 +28,22 @@ export class OpenCodeProvider extends AbstractSessionLogProvider {
36
28
  name = "opencode";
37
29
  #baseDir = getOpenCodeBaseDir();
38
30
  availabilityRoot() {
39
- return this.#baseDir;
31
+ return this.#dbPath(this.#baseDir);
40
32
  }
41
33
  /** Absolute path to opencode's SQLite store under `base`. */
42
34
  #dbPath(base) {
43
35
  return path.join(base, OPENCODE_DB_FILENAME);
44
36
  }
45
- *readEvents(input) {
46
- // Legacy behavior: stream raw log lines from the top-level dir and `log/`
47
- // subdirectory. Kept to keep `getExecutionLogCandidates` working without
48
- // a coordinated change to its caller. New code should use
49
- // {@link listSessions} + {@link readSession} instead.
50
- const candidates = [this.#baseDir, path.join(this.#baseDir, "log")];
51
- for (const dir of candidates) {
52
- if (!fs.existsSync(dir))
53
- continue;
54
- try {
55
- for (const file of fs.readdirSync(dir)) {
56
- const full = path.join(dir, file);
57
- const stat = this.statSafe(full);
58
- if (!stat?.isFile())
59
- continue;
60
- if (stat.mtimeMs < input.sinceMs)
61
- continue;
62
- if (!file.endsWith(".json") && !file.endsWith(".jsonl") && !file.endsWith(".log"))
63
- continue;
64
- const content = fs.readFileSync(full, "utf8");
65
- const lines = content.includes("\n") ? content.split("\n") : [content];
66
- yield* this.logLineEvents({
67
- lines,
68
- filePath: full,
69
- fallbackTsMs: stat.mtimeMs,
70
- selectText: (entry) => entry?.content ?? entry?.message ?? entry?.text ?? "",
71
- selectSessionId: (entry) => entry?.sessionId,
72
- });
73
- }
74
- }
75
- catch {
76
- // unreadable dir — skip
77
- }
78
- }
79
- }
80
37
  listSessions(input = {}) {
81
38
  const base = input.location ?? this.#baseDir;
82
39
  const sinceMs = input.sinceMs ?? 0;
83
40
  const dbPath = this.#dbPath(base);
84
- if (fs.existsSync(dbPath))
85
- return this.#listSessionsFromDb(dbPath, sinceMs);
86
- const sessionRoot = path.join(base, "storage", "session");
87
- if (!fs.existsSync(sessionRoot))
41
+ if (!fs.existsSync(dbPath))
88
42
  return [];
89
- return this.listSessionsFromFiles({
90
- sinceMs,
91
- enumerate: () => this.#legacySessionFiles(sessionRoot),
92
- summarize: (filePath, stat) => this.#legacySessionSummary(filePath, stat),
93
- });
94
- }
95
- /** Legacy JSON layout: `<sessionRoot>/<projectId>/<sessionId>.json`. */
96
- *#legacySessionFiles(sessionRoot) {
97
- for (const projectId of fs.readdirSync(sessionRoot)) {
98
- const projectDir = path.join(sessionRoot, projectId);
99
- if (!this.statSafe(projectDir)?.isDirectory())
100
- continue;
101
- for (const file of fs.readdirSync(projectDir)) {
102
- if (!file.endsWith(".json"))
103
- continue;
104
- yield path.join(projectDir, file);
105
- }
106
- }
107
- }
108
- /** Summarize one legacy session metadata file; `undefined` when unreadable. */
109
- #legacySessionSummary(filePath, stat) {
110
- let meta;
111
- try {
112
- meta = JSON.parse(fs.readFileSync(filePath, "utf8"));
113
- }
114
- catch {
115
- return undefined;
116
- }
117
- const time = meta?.time ?? undefined;
118
- return this.sessionRef({
119
- sessionId: typeof meta?.id === "string" ? meta.id : path.basename(filePath, ".json"),
120
- filePath,
121
- startedAt: typeof time?.created === "number" ? time.created : stat.ctimeMs,
122
- endedAt: typeof time?.updated === "number" ? time.updated : stat.mtimeMs,
123
- // Fallback is the project directory name (the legacy layout's projectId).
124
- projectHint: typeof meta?.directory === "string" ? meta.directory : path.basename(path.dirname(filePath)),
125
- title: typeof meta?.title === "string" ? meta.title : undefined,
126
- });
43
+ return this.#listSessionsFromDb(dbPath, sinceMs, input.isolatedSnapshot ?? false);
127
44
  }
128
45
  readSession(ref) {
129
- if (path.basename(ref.filePath) === OPENCODE_DB_FILENAME)
130
- return this.#readSessionFromDb(ref);
131
- let meta = {};
132
- try {
133
- meta = JSON.parse(fs.readFileSync(ref.filePath, "utf8"));
134
- }
135
- catch {
136
- // metadata missing — proceed with empty defaults
137
- }
138
- const time = meta.time ?? undefined;
139
- const startedAt = typeof time?.created === "number" ? time.created : undefined;
140
- const endedAt = typeof time?.updated === "number" ? time.updated : undefined;
141
- const title = typeof meta.title === "string" ? meta.title : undefined;
142
- const projectHint = typeof meta.directory === "string" ? meta.directory : undefined;
143
- const events = [];
144
- const inlineRefs = [];
145
- // Resolve message directory: <baseDir>/storage/message/<sessionId>/
146
- const inferredBase = this.#inferBaseFromSessionPath(ref.filePath) ?? this.#baseDir;
147
- const msgDir = path.join(inferredBase, "storage", "message", ref.sessionId);
148
- if (fs.existsSync(msgDir)) {
149
- try {
150
- const files = fs.readdirSync(msgDir).filter((f) => f.endsWith(".json"));
151
- for (const file of files) {
152
- const full = path.join(msgDir, file);
153
- let msg;
154
- try {
155
- msg = JSON.parse(fs.readFileSync(full, "utf8"));
156
- }
157
- catch {
158
- continue;
159
- }
160
- if (!msg)
161
- continue;
162
- const evt = this.#messageToEvent(msg, ref.sessionId, full);
163
- if (evt) {
164
- events.push(evt);
165
- inlineRefs.push(...extractInlineRefMentions(evt.text, evt.ts));
166
- }
167
- }
168
- }
169
- catch {
170
- // unreadable msg dir — skip
171
- }
172
- }
173
- events.sort((a, b) => (a.ts ?? 0) - (b.ts ?? 0));
174
- return {
175
- ref: this.sessionRef({
176
- sessionId: ref.sessionId,
177
- filePath: ref.filePath,
178
- startedAt,
179
- endedAt,
180
- projectHint,
181
- title,
182
- }),
183
- events,
184
- inlineRefs,
185
- };
46
+ return this.#readSessionFromDb(ref);
186
47
  }
187
48
  /**
188
49
  * List sessions from the SQLite store. `filePath` on each summary is the
@@ -190,10 +51,15 @@ export class OpenCodeProvider extends AbstractSessionLogProvider {
190
51
  * Returns `[]` (never throws) when the DB is unreadable or lacks the expected
191
52
  * schema — callers treat a missing harness as "no sessions".
192
53
  */
193
- #listSessionsFromDb(dbPath, sinceMs) {
54
+ #listSessionsFromDb(dbPath, sinceMs, isolatedSnapshot) {
194
55
  let db;
195
56
  try {
196
- db = openDatabase(dbPath, { readonly: true, create: false });
57
+ const opened = isolatedSnapshot
58
+ ? openSqliteReadSnapshot(dbPath)
59
+ : openDatabase(dbPath, { readonly: true, create: false });
60
+ if (!opened)
61
+ return [];
62
+ db = opened;
197
63
  }
198
64
  catch {
199
65
  return [];
@@ -311,60 +177,4 @@ export class OpenCodeProvider extends AbstractSessionLogProvider {
311
177
  db.close();
312
178
  }
313
179
  }
314
- /**
315
- * Derive opencode base dir from a session metadata file path so a caller
316
- * passing a custom `--location` can still find the message dir.
317
- * Layout: `<base>/storage/session/<projectId>/<id>.json` → base.
318
- */
319
- #inferBaseFromSessionPath(filePath) {
320
- // Walk up: <id>.json → <projectId> → session → storage → <base>
321
- const dir = path.dirname(filePath);
322
- const parts = dir.split(path.sep);
323
- if (parts.length < 3)
324
- return undefined;
325
- const last = parts[parts.length - 1];
326
- const sndLast = parts[parts.length - 2];
327
- const thirdLast = parts[parts.length - 3];
328
- if (sndLast !== "session" || thirdLast !== "storage" || !last)
329
- return undefined;
330
- return parts.slice(0, parts.length - 3).join(path.sep);
331
- }
332
- #messageToEvent(msg, sessionId, filePath) {
333
- const time = msg.time ?? undefined;
334
- const ts = typeof time?.created === "number" ? time.created : typeof msg.timestamp === "number" ? msg.timestamp : 0;
335
- const role = typeof msg.role === "string" ? msg.role : "unknown";
336
- // Opencode message bodies live in summary.title / summary.diffs[].before/after /
337
- // parts (referenced from storage/part/<msg-id>/). For listing+extraction
338
- // purposes the summary block is sufficient — it's what the platform itself
339
- // surfaces as the message preview.
340
- const summary = msg.summary;
341
- const parts = [];
342
- if (typeof summary?.title === "string")
343
- parts.push(summary.title);
344
- if (Array.isArray(summary?.parts)) {
345
- for (const p of summary.parts) {
346
- if (typeof p === "string")
347
- parts.push(p);
348
- else if (p && typeof p === "object") {
349
- const text = p.text;
350
- if (typeof text === "string")
351
- parts.push(text);
352
- }
353
- }
354
- }
355
- // content field for some opencode versions
356
- if (typeof msg.content === "string")
357
- parts.push(msg.content);
358
- const text = parts.join("\n").trim();
359
- if (text.length < 1)
360
- return undefined;
361
- return {
362
- harness: this.name,
363
- text,
364
- ts: ts || undefined,
365
- sessionId,
366
- role,
367
- filePath,
368
- };
369
- }
370
180
  }
@@ -21,6 +21,7 @@
21
21
  * Importing the descriptor from this leaf keeps the registry a config-leaf and
22
22
  * breaks the cycle.
23
23
  */
24
+ import { createAgentRequestLowerer } from "../../agent/request-lowering.js";
24
25
  import { caps } from "../shared.js";
25
26
  import { BaseHarness } from "../types.js";
26
27
  /**
@@ -31,7 +32,6 @@ import { BaseHarness } from "../types.js";
31
32
  export class OpencodeSdkHarness extends BaseHarness {
32
33
  id = "opencode-sdk";
33
34
  displayName = "OpenCode SDK";
34
- aliases = [];
35
35
  // ── Workflow-engine descriptor (plan §"Capability matrix", P2) ────────────
36
36
  // Embedded-SDK dispatch on this machine ⇒ local-runner (the matrix's
37
37
  // "local (sdk/cli)" row, SDK half).
@@ -39,6 +39,17 @@ export class OpencodeSdkHarness extends BaseHarness {
39
39
  // `session.prompt` returns structured SDK events/messages; akm extracts the
40
40
  // final message then validates against the node schema ⇒ native-json tier.
41
41
  structuredOutput = "native-json";
42
+ executionLowerer = {
43
+ platform: "opencode-sdk",
44
+ personaChannel: "native",
45
+ lower: createAgentRequestLowerer({
46
+ adapter: "opencode-sdk",
47
+ personaChannel: "native",
48
+ nativeAgentSelector: true,
49
+ tools: "sdk",
50
+ outputSchema: false,
51
+ }),
52
+ };
42
53
  // No flag-shaped resume: session reuse is programmatic — the SDK session id is
43
54
  // stored opportunistically on the unit row and passed back to
44
55
  // `session.prompt`, not replayed via a CLI flag.
@@ -93,7 +93,6 @@
93
93
  import { spawn } from "node:child_process";
94
94
  import { createHash } from "node:crypto";
95
95
  import { DEFAULT_AGENT_TIMEOUT_MS } from "../../agent/config.js";
96
- import { resolveModel } from "../../agent/model-aliases.js";
97
96
  // Server registry — one server per complete server-material signature. Caller
98
97
  // deadlines race the shared promise independently; they never become startup
99
98
  // configuration inherited by later callers.
@@ -234,22 +233,13 @@ function toolsToSdkAllowlist(tools) {
234
233
  }
235
234
  /**
236
235
  * Assemble the OpenCode SDK server config from the profile + LLM fallback.
237
- * Pure and exported for tests. `profile.model` is resolved through the model
238
- * alias tables (platform key `"opencode-sdk"`) so config aliases like
239
- * `"model": "fast"` work on the SDK path the same way they do for CLI
240
- * builders. Note there is no built-in alias column for `opencode-sdk` —
241
- * built-in opus/sonnet/haiku strings are CLI-provider-qualified and would
242
- * collide with the `akm-custom/` provider prefixing below, so only profile
243
- * and config-root alias tables apply here.
236
+ * Pure and exported for tests. `profile.model` is already exact because model
237
+ * aliases resolve once before harness lowering.
244
238
  */
245
239
  export function buildSdkConfig(profile, llmConfig) {
246
240
  const endpoint = llmConfig?.endpoint;
247
241
  const apiKey = llmConfig?.apiKey;
248
- const profileModel = profile.model
249
- ? profile.modelIsExact
250
- ? profile.model
251
- : resolveModel(profile.model, "opencode-sdk", profile.modelAliases, profile.globalModelAliases)
252
- : undefined;
242
+ const profileModel = profile.model;
253
243
  const model = profileModel ?? llmConfig?.model;
254
244
  const sdkConfig = {};
255
245
  if (model)
@@ -279,25 +269,28 @@ function serverRegistryKey(profile, env) {
279
269
  .update(JSON.stringify(canonicalize(material)))
280
270
  .digest("hex");
281
271
  }
272
+ const OPENCODE_SDK_SERVER_ENV_NAMES = [
273
+ "HOME",
274
+ "PATH",
275
+ "USER",
276
+ "LANG",
277
+ "LC_ALL",
278
+ "TERM",
279
+ "TMPDIR",
280
+ "SYSTEMROOT",
281
+ "COMSPEC",
282
+ "PATHEXT",
283
+ "WINDIR",
284
+ "TEMP",
285
+ "TMP",
286
+ ];
287
+ /** @internal Exact environment allowlist used to start the OpenCode SDK server. */
288
+ export function opencodeSdkServerEnvironmentNames(profile) {
289
+ return [...new Set([...OPENCODE_SDK_SERVER_ENV_NAMES, ...(profile.envPassthrough ?? [])])];
290
+ }
282
291
  function buildServerEnv(profile, config, bindings, envSource) {
283
292
  const env = {};
284
- const inheritedNames = new Set([
285
- "HOME",
286
- "PATH",
287
- "USER",
288
- "LANG",
289
- "LC_ALL",
290
- "TERM",
291
- "TMPDIR",
292
- "SYSTEMROOT",
293
- "COMSPEC",
294
- "PATHEXT",
295
- "WINDIR",
296
- "TEMP",
297
- "TMP",
298
- ...(profile.envPassthrough ?? []),
299
- ]);
300
- for (const key of inheritedNames) {
293
+ for (const key of opencodeSdkServerEnvironmentNames(profile)) {
301
294
  const value = envSource[key];
302
295
  if (value !== undefined)
303
296
  env[key] = value;
@@ -688,6 +681,17 @@ async function deleteSessionBestEffort(client, sessionId, query, setTimeoutFn, c
688
681
  return `OpenCode session cleanup failed: ${errorText(err)}`;
689
682
  }
690
683
  }
684
+ function abortedBeforeSdkStart(profile) {
685
+ return {
686
+ ok: false,
687
+ stdout: "",
688
+ stderr: "",
689
+ durationMs: 0,
690
+ exitCode: null,
691
+ reason: "aborted",
692
+ error: `opencode-sdk agent "${profile.name}" not started: caller signal already aborted`,
693
+ };
694
+ }
691
695
  export async function runOpencodeSdk(profile, prompt, opts = {}, llmConfig) {
692
696
  const start = Date.now();
693
697
  const timeoutMs = opts.timeoutMs !== undefined ? opts.timeoutMs : DEFAULT_AGENT_TIMEOUT_MS;
@@ -695,17 +699,8 @@ export async function runOpencodeSdk(profile, prompt, opts = {}, llmConfig) {
695
699
  const remainingTimeoutMs = () => (deadline === null ? null : Math.max(0, deadline - Date.now()));
696
700
  const setTimeoutImpl = opts.setTimeoutFn ?? setTimeout;
697
701
  const clearTimeoutImpl = opts.clearTimeoutFn ?? clearTimeout;
698
- if (opts.signal?.aborted) {
699
- return {
700
- ok: false,
701
- stdout: "",
702
- stderr: "",
703
- durationMs: 0,
704
- exitCode: null,
705
- reason: "aborted",
706
- error: `opencode-sdk agent "${profile.name}" not started: caller signal already aborted`,
707
- };
708
- }
702
+ if (opts.signal?.aborted)
703
+ return abortedBeforeSdkStart(profile);
709
704
  let client;
710
705
  if (_testServer) {
711
706
  client = _testServer.client;
@@ -831,14 +826,17 @@ export async function runOpencodeSdk(profile, prompt, opts = {}, llmConfig) {
831
826
  error: "Failed to create OpenCode session",
832
827
  };
833
828
  }
834
- // #564 bug fixes (1) + (2): forward systemPrompt and tools from the abstract
829
+ // Forward the exact native agent selector, systemPrompt, and tools from the abstract
835
830
  // dispatch request. Both were previously accepted on AgentDispatchRequest but
836
831
  // silently dropped on the SDK path, so SDK-mode dispatch ignored agent-asset
837
832
  // system prompts and tool policies entirely (the CLI path honours both).
838
833
  const dispatch = opts.dispatch;
834
+ const agent = dispatch?.agent;
839
835
  const system = dispatch?.systemPrompt;
840
836
  const tools = toolsToSdkAllowlist(dispatch?.tools);
841
837
  const body = { parts: [{ type: "text", text: prompt }] };
838
+ if (agent)
839
+ body.agent = agent;
842
840
  if (system)
843
841
  body.system = system;
844
842
  if (tools)
@@ -72,6 +72,7 @@
72
72
  * (`./index.ts`).
73
73
  */
74
74
  import { assertNotFlag, resolveDispatchModel, } from "../../agent/builder-shared.js";
75
+ import { createAgentRequestLowerer } from "../../agent/request-lowering.js";
75
76
  /** Canonical harness/platform id used for model-alias resolution. */
76
77
  export const OPENHANDS_PLATFORM = "openhands";
77
78
  /**
@@ -106,6 +107,13 @@ function buildTaskPayload(req) {
106
107
  */
107
108
  export const openhandsBuilder = {
108
109
  platform: OPENHANDS_PLATFORM,
110
+ personaChannel: "prompt",
111
+ lower: createAgentRequestLowerer({
112
+ adapter: OPENHANDS_PLATFORM,
113
+ personaChannel: "prompt",
114
+ tools: "none",
115
+ outputSchema: true,
116
+ }),
109
117
  build(profile, req) {
110
118
  assertNotFlag(req.systemPrompt, "systemPrompt");
111
119
  assertNotFlag(req.model, "model");
@@ -26,7 +26,6 @@ export { openhandsResultExtractor } from "./result-extractor.js";
26
26
  export class OpenhandsHarness extends BaseHarness {
27
27
  id = "openhands";
28
28
  displayName = "OpenHands";
29
- aliases = [];
30
29
  agentBuilder = openhandsBuilder;
31
30
  resultExtractor = openhandsResultExtractor;
32
31
  // ── Workflow-engine descriptor (plan §"Capability matrix", P2) ────────────
@@ -51,6 +51,7 @@
51
51
  * (`./index.ts`).
52
52
  */
53
53
  import { assertNotFlag, resolveDispatchModel, } from "../../agent/builder-shared.js";
54
+ import { createAgentRequestLowerer } from "../../agent/request-lowering.js";
54
55
  /** Canonical harness/platform id used for model-alias resolution. */
55
56
  export const PI_PLATFORM = "pi";
56
57
  /**
@@ -72,6 +73,13 @@ function buildPromptPayload(req) {
72
73
  */
73
74
  export const piBuilder = {
74
75
  platform: PI_PLATFORM,
76
+ personaChannel: "native",
77
+ lower: createAgentRequestLowerer({
78
+ adapter: PI_PLATFORM,
79
+ personaChannel: "native",
80
+ tools: "none",
81
+ outputSchema: true,
82
+ }),
75
83
  build(profile, req) {
76
84
  assertNotFlag(req.systemPrompt, "systemPrompt");
77
85
  assertNotFlag(req.model, "model");
@@ -26,7 +26,6 @@ export { piResultExtractor } from "./result-extractor.js";
26
26
  export class PiHarness extends BaseHarness {
27
27
  id = "pi";
28
28
  displayName = "Pi";
29
- aliases = [];
30
29
  agentBuilder = piBuilder;
31
30
  resultExtractor = piResultExtractor;
32
31
  // ── Workflow-engine descriptor (plan §"Capability matrix", P2) ────────────
@@ -7,7 +7,6 @@ export function caps(c) {
7
7
  agentDispatch: false,
8
8
  detection: false,
9
9
  configImport: false,
10
- runtimeIdentity: false,
11
10
  ...c,
12
11
  };
13
12
  }
@@ -44,11 +44,9 @@ export function isSessionLogHarness(h) {
44
44
  * (Claude, OpenCode) declare their own required `sessionLogProvider`.
45
45
  */
46
46
  export class BaseHarness {
47
- runtimeId;
48
47
  setupDetectionDir;
49
48
  agentBuilder;
50
- pattern;
51
- structuredOutput;
49
+ executionLowerer;
52
50
  identityEnv;
53
51
  presenceEnv;
54
52
  resultExtractor;