akm-cli 0.10.261013-beta → 0.10.261014-beta

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (477) hide show
  1. package/CHANGELOG.md +494 -3
  2. package/README.md +15 -0
  3. package/SECURITY.md +9 -8
  4. package/STABILITY.md +45 -49
  5. package/dist/assets/hints/cli-hints-full.md +15 -12
  6. package/dist/assets/opencode/akm-plugin.js +177 -0
  7. package/dist/assets/stash-skeleton/README.md +1 -1
  8. package/dist/assets/tasks/core/improve.yml +1 -1
  9. package/dist/assets/tasks/improve/akm-improve-consolidate.yml +1 -1
  10. package/dist/assets/ui/config.js +27 -10
  11. package/dist/assets/workflows/workflow-template.md +2 -2
  12. package/dist/cli/clack.js +3 -1
  13. package/dist/cli/selection.js +33 -0
  14. package/dist/cli/shared.js +14 -1
  15. package/dist/cli/unknown-flags.js +6 -37
  16. package/dist/cli.js +69 -48
  17. package/dist/commands/agent/agent-dispatch.js +17 -25
  18. package/dist/commands/agent/contribute-cli.js +9 -8
  19. package/dist/commands/command/command-cli.js +4 -8
  20. package/dist/commands/command/command-execution.js +25 -39
  21. package/dist/commands/completions.js +1 -1
  22. package/dist/commands/config-cli.js +14 -5
  23. package/dist/commands/env/child-env.js +12 -14
  24. package/dist/commands/env/env-cli.js +2 -2
  25. package/dist/commands/env/secret-cli.js +2 -2
  26. package/dist/commands/health/checks.js +10 -849
  27. package/dist/commands/health/connections-and-harnesses-check.js +109 -0
  28. package/dist/commands/health/egress.js +3 -3
  29. package/dist/commands/health/html-report.js +9 -10
  30. package/dist/commands/health/plugin-staleness.js +18 -11
  31. package/dist/commands/health/report-view-model.js +16 -12
  32. package/dist/commands/health/semantic-search-check.js +85 -0
  33. package/dist/commands/health/type-directory-check.js +0 -3
  34. package/dist/commands/health.js +30 -42
  35. package/dist/commands/improve/consolidate/pair-pass.js +10 -25
  36. package/dist/commands/improve/consolidate.js +10 -15
  37. package/dist/commands/improve/distill.js +5 -15
  38. package/dist/commands/improve/eligibility.js +1 -1
  39. package/dist/commands/improve/execution.js +37 -40
  40. package/dist/commands/improve/extract-cli.js +6 -11
  41. package/dist/commands/improve/extract-prompt.js +2 -2
  42. package/dist/commands/improve/extract.js +67 -97
  43. package/dist/commands/improve/improve-cli.js +22 -128
  44. package/dist/commands/improve/improve-report.js +1 -1
  45. package/dist/commands/improve/improve-strategies.js +25 -108
  46. package/dist/commands/improve/improve.js +10 -14
  47. package/dist/commands/improve/loop-stages.js +3 -0
  48. package/dist/commands/improve/memory/memory-improve.js +1 -1
  49. package/dist/commands/improve/preparation.js +8 -13
  50. package/dist/commands/improve/reflect.js +203 -332
  51. package/dist/commands/improve/retrieval-scope.js +1 -1
  52. package/dist/commands/improve/session-asset.js +3 -2
  53. package/dist/commands/improve/stage.js +87 -115
  54. package/dist/commands/lint/base-linter.js +3 -3
  55. package/dist/commands/lint/index.js +2 -2
  56. package/dist/commands/models-cli.js +103 -63
  57. package/dist/commands/proposal/drain.js +26 -39
  58. package/dist/commands/proposal/proposal-cli.js +14 -18
  59. package/dist/commands/proposal/propose-cli.js +4 -2
  60. package/dist/commands/proposal/propose.js +37 -64
  61. package/dist/commands/proposal/repository.js +17 -17
  62. package/dist/commands/proposal/validators/proposal-validators.js +2 -2
  63. package/dist/commands/read/curate.js +10 -6
  64. package/dist/commands/read/registry-search.js +2 -48
  65. package/dist/commands/read/search-cli.js +1 -8
  66. package/dist/commands/read/search.js +5 -6
  67. package/dist/commands/read/show.js +2 -4
  68. package/dist/commands/remember.js +25 -40
  69. package/dist/commands/sources/bundle-config-ops.js +2 -2
  70. package/dist/commands/sources/info.js +12 -1
  71. package/dist/commands/sources/init.js +1 -1
  72. package/dist/commands/sources/installed-stashes.js +2 -2
  73. package/dist/commands/sources/migration-help.js +1 -1
  74. package/dist/commands/sources/plugin-upgrade.js +8 -15
  75. package/dist/commands/sources/schema-repair.js +4 -8
  76. package/dist/commands/sources/source-add.js +2 -2
  77. package/dist/commands/sources/source-manage.js +4 -4
  78. package/dist/commands/targets.js +175 -0
  79. package/dist/commands/tasks/explain.js +103 -68
  80. package/dist/commands/tasks/tasks-cli.js +9 -11
  81. package/dist/commands/tasks/tasks.js +37 -41
  82. package/dist/commands/ui/api.js +11 -3
  83. package/dist/commands/ui/redact.js +1 -27
  84. package/dist/commands/ui/workspace-actions.js +1 -1
  85. package/dist/commands/workflow/plan.js +1 -1
  86. package/dist/commands/workflow-cli.js +3 -4
  87. package/dist/core/adapter/adapters/agent-skills-adapter.js +10 -11
  88. package/dist/core/adapter/adapters/akm-adapter.js +33 -38
  89. package/dist/core/adapter/adapters/akm-lint.js +7 -8
  90. package/dist/core/adapter/adapters/akm-task-adapter.js +3 -3
  91. package/dist/core/adapter/adapters/akm-workflow-adapter.js +5 -5
  92. package/dist/core/adapter/adapters/claude-adapter.js +1 -1
  93. package/dist/core/adapter/adapters/dotenv-adapter.js +3 -3
  94. package/dist/core/adapter/adapters/generic-files-adapter.js +5 -5
  95. package/dist/core/adapter/adapters/index.js +3 -4
  96. package/dist/core/adapter/adapters/llm-wiki-adapter.js +12 -14
  97. package/dist/core/adapter/adapters/okf-adapter.js +8 -10
  98. package/dist/core/adapter/adapters/opencode-adapter.js +1 -1
  99. package/dist/core/adapter/adapters/shared.js +3 -3
  100. package/dist/core/adapter/adapters/tool-dir-shared.js +7 -25
  101. package/dist/core/adapter/adapters/website-snapshot-adapter.js +3 -3
  102. package/dist/core/adapter/detect-adapter.js +1 -1
  103. package/dist/core/adapter/execution-source.js +13 -35
  104. package/dist/core/adapter/registry.js +1 -1
  105. package/dist/core/adapter/validate-context.js +2 -4
  106. package/dist/core/asset/asset-placement.js +1 -1
  107. package/dist/core/asset/asset-ref.js +3 -3
  108. package/dist/core/closest-match.js +37 -0
  109. package/dist/core/common.js +33 -5
  110. package/dist/core/config/config-io.js +26 -18
  111. package/dist/core/config/config-schema.js +19 -106
  112. package/dist/core/config/config-sources.js +3 -3
  113. package/dist/core/config/config-types.js +4 -4
  114. package/dist/core/config/config-walker.js +50 -77
  115. package/dist/core/config/config.js +385 -93
  116. package/dist/core/config/convert-engine-references.js +114 -0
  117. package/dist/core/config/convert-engines-shared.js +40 -0
  118. package/dist/core/config/convert-engines.js +300 -0
  119. package/dist/core/config/convert-models-overlay.js +137 -0
  120. package/dist/core/config/credentials.js +304 -0
  121. package/dist/core/config/engine-semantics.js +3 -3
  122. package/dist/core/config/migrate-keys.js +222 -0
  123. package/dist/core/config/model-aliases.js +37 -0
  124. package/dist/core/config/models-file.js +34 -0
  125. package/dist/core/config/retired-engines.js +53 -0
  126. package/dist/core/config/schema/connections.js +41 -0
  127. package/dist/core/config/schema/embedding.js +2 -2
  128. package/dist/core/config/schema/harnesses.js +41 -0
  129. package/dist/core/config/schema/improve-processes.js +9 -28
  130. package/dist/core/config/schema/improve.js +36 -1
  131. package/dist/core/config/schema/index-config.js +18 -20
  132. package/dist/core/config/schema/primitives.js +41 -22
  133. package/dist/core/config/schema/search.js +6 -11
  134. package/dist/core/config/schema/sources-bundles.js +7 -7
  135. package/dist/core/config/schema/workflow.js +2 -6
  136. package/dist/core/config/unusable-entries.js +66 -0
  137. package/dist/core/content-safety.js +3 -6
  138. package/dist/core/endpoint-url.js +47 -0
  139. package/dist/core/errors.js +9 -15
  140. package/dist/core/extra-params.js +3 -3
  141. package/dist/core/improve-result.js +8 -9
  142. package/dist/core/json-schema.js +1 -1
  143. package/dist/core/lesson-lint.js +1 -1
  144. package/dist/core/llm-inference.js +80 -0
  145. package/dist/core/parse.js +2 -2
  146. package/dist/core/paths.js +32 -4
  147. package/dist/core/recognition-util.js +8 -10
  148. package/dist/core/redaction.js +78 -52
  149. package/dist/core/state/migrations.js +17 -22
  150. package/dist/core/structured.js +2 -68
  151. package/dist/core/subprocess.js +63 -22
  152. package/dist/core/type-presentation.js +10 -14
  153. package/dist/execution/input-contract.js +3 -6
  154. package/dist/execution/notices.js +49 -0
  155. package/dist/execution/resolved-request.js +24 -40
  156. package/dist/execution/source.js +21 -45
  157. package/dist/execution/target-ref.js +2 -2
  158. package/dist/indexer/bundle-identity-guard.js +6 -5
  159. package/dist/indexer/ensure-index.js +1 -1
  160. package/dist/indexer/index-writer-lock.js +1 -1
  161. package/dist/indexer/indexer.js +19 -6
  162. package/dist/indexer/installations.js +11 -14
  163. package/dist/indexer/materialize-embeddings.js +20 -16
  164. package/dist/indexer/passes/memory-inference.js +21 -50
  165. package/dist/indexer/passes/metadata.js +5 -5
  166. package/dist/indexer/scan/doc-to-entry.js +1 -1
  167. package/dist/indexer/scan/drain-dir.js +6 -8
  168. package/dist/indexer/search/db-search.js +9 -7
  169. package/dist/indexer/search/search-source.js +40 -22
  170. package/dist/indexer/usage/usage-events.js +2 -3
  171. package/dist/indexer/walk/index-context.js +2 -1
  172. package/dist/indexer/walk/matchers.js +3 -11
  173. package/dist/indexer/walk/walker.js +14 -4
  174. package/dist/integrations/agent/akm-read-tools.js +81 -0
  175. package/dist/integrations/agent/config.js +1 -1
  176. package/dist/integrations/agent/detect.js +32 -36
  177. package/dist/integrations/agent/execution.js +130 -428
  178. package/dist/integrations/agent/index.js +1 -1
  179. package/dist/integrations/agent/profiles.js +24 -28
  180. package/dist/integrations/agent/prompts.js +17 -30
  181. package/dist/integrations/agent/request-lowering.js +67 -101
  182. package/dist/integrations/agent/resolution.js +332 -0
  183. package/dist/integrations/agent/runner-dispatch.js +154 -178
  184. package/dist/integrations/agent/runner.js +20 -72
  185. package/dist/integrations/agent/runtime-port.js +4 -0
  186. package/dist/integrations/agent/runtime.js +10 -0
  187. package/dist/integrations/agent/spawn.js +65 -190
  188. package/dist/integrations/harnesses/aider/index.js +19 -39
  189. package/dist/integrations/harnesses/amazonq/index.js +17 -32
  190. package/dist/integrations/harnesses/claude/index.js +59 -28
  191. package/dist/integrations/harnesses/claude/session-log.js +7 -5
  192. package/dist/integrations/harnesses/codex/index.js +19 -31
  193. package/dist/integrations/harnesses/copilot/index.js +17 -35
  194. package/dist/integrations/harnesses/gemini/index.js +18 -34
  195. package/dist/integrations/harnesses/harness.js +36 -0
  196. package/dist/integrations/harnesses/index.js +20 -51
  197. package/dist/integrations/harnesses/opencode/agent-builder.js +132 -100
  198. package/dist/integrations/harnesses/opencode/index.js +11 -33
  199. package/dist/integrations/harnesses/opencode/roots.js +50 -0
  200. package/dist/integrations/harnesses/opencode/runtime/binary.js +206 -0
  201. package/dist/integrations/harnesses/opencode/runtime/command.js +152 -0
  202. package/dist/integrations/harnesses/opencode/runtime/index.js +177 -0
  203. package/dist/integrations/harnesses/opencode/runtime/tar.js +107 -0
  204. package/dist/integrations/harnesses/opencode/session-log-v1.js +15 -7
  205. package/dist/integrations/harnesses/opencode/session-log-v2.js +72 -48
  206. package/dist/integrations/harnesses/opencode/session-log.js +58 -137
  207. package/dist/integrations/harnesses/opencode/version.js +34 -53
  208. package/dist/integrations/harnesses/openhands/index.js +13 -37
  209. package/dist/integrations/harnesses/pi/index.js +21 -32
  210. package/dist/integrations/lockfile.js +1 -1
  211. package/dist/integrations/session-logs/index.js +11 -31
  212. package/dist/llm/client.js +93 -111
  213. package/dist/llm/embedder.js +19 -34
  214. package/dist/llm/embedders/connection.js +31 -0
  215. package/dist/llm/embedders/local-model-files.js +56 -0
  216. package/dist/llm/embedders/local.js +146 -115
  217. package/dist/llm/embedders/remote.js +26 -24
  218. package/dist/llm/embedders/types.js +1 -1
  219. package/dist/llm/index-passes.js +33 -39
  220. package/dist/llm/memory-infer.js +67 -77
  221. package/dist/llm/model-list.js +35 -0
  222. package/dist/llm/rerank-client.js +8 -14
  223. package/dist/llm/structured-call.js +45 -99
  224. package/dist/llm/structured.js +60 -0
  225. package/dist/output/renderers.js +2 -7
  226. package/dist/output/shapes/helpers.js +18 -42
  227. package/dist/output/shapes/passthrough.js +1 -0
  228. package/dist/output/shapes.js +1 -7
  229. package/dist/output/text/command-format.js +29 -37
  230. package/dist/output/text/health-format.js +8 -2
  231. package/dist/output/text/helpers.js +1 -1
  232. package/dist/output/text/migrate.js +12 -0
  233. package/dist/output/text/models.js +3 -2
  234. package/dist/output/text/registry-commands.js +1 -2
  235. package/dist/output/text/show-format.js +0 -2
  236. package/dist/output/text/targets-table.js +70 -0
  237. package/dist/output/text/workflow-format.js +7 -8
  238. package/dist/output/text.js +1 -1
  239. package/dist/registry/providers/skills-sh.js +1 -28
  240. package/dist/registry/providers/static-index.js +1 -71
  241. package/dist/runtime.js +6 -2
  242. package/dist/scripts/akm-migrate-node.js +5280 -4263
  243. package/dist/scripts/akm-migrate.js +5280 -4263
  244. package/dist/setup/detect.js +28 -273
  245. package/dist/setup/endpoint.js +36 -0
  246. package/dist/setup/semantic-assets.js +13 -19
  247. package/dist/setup/setup-flags.js +77 -0
  248. package/dist/setup/setup-plan.js +144 -0
  249. package/dist/setup/setup.js +134 -358
  250. package/dist/setup/steps/connection-shared.js +49 -101
  251. package/dist/setup/steps/connection.js +121 -524
  252. package/dist/setup/steps/embeddings.js +151 -0
  253. package/dist/setup/steps/harnesses.js +118 -0
  254. package/dist/setup/steps/platforms.js +2 -81
  255. package/dist/setup/steps.js +10 -0
  256. package/dist/setup/summary.js +67 -0
  257. package/dist/sources/freshness.js +16 -21
  258. package/dist/sources/providers/git-provider.js +2 -9
  259. package/dist/sources/providers/provider-utils.js +1 -5
  260. package/dist/sources/snapshot-fetchers/robots.js +11 -12
  261. package/dist/sources/snapshot-fetchers/website-ingest.js +8 -15
  262. package/dist/standalone/onnxruntime-library.js +52 -0
  263. package/dist/storage/repositories/improve-ledger-repository.js +1 -1
  264. package/dist/storage/repositories/improve-runs-repository.js +0 -13
  265. package/dist/storage/repositories/index-entries-repository.js +2 -2
  266. package/dist/storage/repositories/workflow-runs-repository.js +8 -15
  267. package/dist/storage/sqlite-read-snapshot.js +33 -29
  268. package/dist/tasks/log-redaction.js +7 -119
  269. package/dist/tasks/prepare/prepare-support.js +5 -5
  270. package/dist/tasks/prepare/prepare.js +5 -5
  271. package/dist/tasks/prepare/script-capture.js +3 -5
  272. package/dist/tasks/run/attempt-lifecycle.js +17 -35
  273. package/dist/tasks/run/load-task.js +8 -13
  274. package/dist/tasks/run/run-command-task.js +15 -10
  275. package/dist/tasks/run/run-native-task.js +8 -13
  276. package/dist/tasks/run/run-task.js +5 -8
  277. package/dist/tasks/run/run-workflow-task.js +12 -19
  278. package/dist/tasks/run/task-history.js +9 -17
  279. package/dist/tasks/run/task-log.js +1 -5
  280. package/dist/tasks/scheduler-invocation.js +13 -18
  281. package/dist/tasks/source/bounded-document.js +31 -76
  282. package/dist/tasks/source/project-v4.js +5 -3
  283. package/dist/tasks/source/task-input-diagnostics.js +3 -4
  284. package/dist/tasks/source/task-source-v4.js +47 -68
  285. package/dist/tasks/source-v3.js +2 -5
  286. package/dist/tasks/task-run-reserved-flags.js +1 -2
  287. package/dist/workflows/authoring/authoring.js +2 -7
  288. package/dist/workflows/concurrency-policy.js +4 -4
  289. package/dist/workflows/exec/child-workflow.js +0 -2
  290. package/dist/workflows/exec/dispatch-redaction.js +14 -83
  291. package/dist/workflows/exec/environment.js +2 -3
  292. package/dist/workflows/exec/exec-unit.js +10 -59
  293. package/dist/workflows/exec/frozen-judge.js +10 -26
  294. package/dist/workflows/exec/native-executor.js +56 -45
  295. package/dist/workflows/exec/run-workflow.js +7 -24
  296. package/dist/workflows/exec/step-work.js +9 -14
  297. package/dist/workflows/exec/unit-dispatch.js +6 -13
  298. package/dist/workflows/freeze/freeze.js +14 -32
  299. package/dist/workflows/freeze/step-values.js +5 -11
  300. package/dist/workflows/freeze/targets/command.js +3 -6
  301. package/dist/workflows/freeze/task-bindings.js +0 -1
  302. package/dist/workflows/parser.js +44 -34
  303. package/dist/workflows/plan.js +3 -1
  304. package/dist/workflows/renderer.js +6 -5
  305. package/dist/workflows/resource-limits.js +2 -2
  306. package/dist/workflows/runtime/run-plan.js +2 -1
  307. package/dist/workflows/runtime/runs.js +14 -9
  308. package/docs/README.md +10 -16
  309. package/docs/architecture/README.md +2 -37
  310. package/docs/architecture/adapters.md +2 -2
  311. package/docs/architecture/akm-core-principles.md +256 -118
  312. package/docs/architecture/architecture.md +282 -98
  313. package/docs/architecture/improvement.md +8 -2
  314. package/docs/architecture/internals/classification.md +1 -3
  315. package/docs/architecture/internals/fresh-host-rebuild-runbook.md +7 -6
  316. package/docs/architecture/internals/health-advisories.md +35 -74
  317. package/docs/architecture/internals/improve-workflow.md +27 -26
  318. package/docs/architecture/internals/indexing.md +3 -3
  319. package/docs/architecture/internals/storage-locations.md +45 -12
  320. package/docs/architecture/persisted-data-compat.md +9 -6
  321. package/docs/architecture/specs/okf-support.md +9 -11
  322. package/docs/architecture/specs/ref.md +7 -9
  323. package/docs/architecture/testing/testing-workflow.md +164 -42
  324. package/docs/architecture/workflow-engine.md +17 -14
  325. package/docs/guides/README.md +0 -1
  326. package/docs/guides/author-bundles.md +1 -3
  327. package/docs/guides/author-workflows.md +61 -73
  328. package/docs/guides/bundles.md +4 -5
  329. package/docs/guides/discover-and-load.md +1 -1
  330. package/docs/guides/getting-started.md +49 -3
  331. package/docs/guides/improve-the-library.md +10 -4
  332. package/docs/guides/recipes/headless-install.md +11 -16
  333. package/docs/guides/run-workflows.md +6 -9
  334. package/docs/guides/scheduling.md +2 -2
  335. package/docs/guides/use-with-any-agent.md +20 -22
  336. package/docs/integration/bundling-akm.md +19 -9
  337. package/docs/maintainers/README.md +0 -3
  338. package/docs/migration/README.md +10 -3
  339. package/docs/migration/release-notes/0.10.0.md +81 -16
  340. package/docs/migration/release-notes/0.6.0.md +1 -1
  341. package/docs/migration/release-notes/0.7.0.md +1 -1
  342. package/docs/migration/release-notes/0.9.0.md +1 -1
  343. package/docs/migration/release-notes/README.md +1 -1
  344. package/docs/migration/v0.9-to-v0.10.md +295 -59
  345. package/docs/migration/v0.9.1-to-v0.9.2.md +6 -5
  346. package/docs/posts/config-v2-lessons-16.md +1 -1
  347. package/docs/posts/llm-mode-reflect-13.md +1 -1
  348. package/docs/posts/release-0.6.0.md +11 -11
  349. package/docs/posts/release-0.8.0.md +4 -4
  350. package/docs/posts/workflows-vaults-09.md +1 -1
  351. package/docs/reference/README.md +1 -1
  352. package/docs/reference/asset-types.md +2 -2
  353. package/docs/reference/cli.md +356 -279
  354. package/docs/reference/configuration.md +569 -557
  355. package/docs/reference/data-and-telemetry.md +8 -5
  356. package/docs/reference/env-and-secrets.md +11 -5
  357. package/docs/reference/refs.md +3 -20
  358. package/docs/reference/registry.md +6 -27
  359. package/docs/reference/supported-formats.md +1 -1
  360. package/docs/reference/tasks.md +11 -8
  361. package/docs/reference/ui-api.md +11 -6
  362. package/docs/reference/workflow-schema.md +106 -134
  363. package/docs/reference/workflows.md +4 -6
  364. package/package.json +9 -11
  365. package/schemas/akm-config.json +1696 -2922
  366. package/schemas/akm-task.json +2 -0
  367. package/schemas/akm-workflow.json +36 -9
  368. package/ROADMAP.md +0 -112
  369. package/dist/assets/models.json +0 -35
  370. package/dist/commands/health/engine-usage.js +0 -45
  371. package/dist/core/config/schema/engines.js +0 -160
  372. package/dist/core/config/schema/execution.js +0 -23
  373. package/dist/core/spawn-env.js +0 -268
  374. package/dist/integrations/agent/builder-shared.js +0 -33
  375. package/dist/integrations/agent/builders.js +0 -43
  376. package/dist/integrations/agent/engine-fallback.js +0 -59
  377. package/dist/integrations/agent/engine-resolution.js +0 -335
  378. package/dist/integrations/agent/model-map.js +0 -475
  379. package/dist/integrations/harnesses/aider/agent-builder.js +0 -107
  380. package/dist/integrations/harnesses/aider/result-extractor.js +0 -53
  381. package/dist/integrations/harnesses/amazonq/agent-builder.js +0 -138
  382. package/dist/integrations/harnesses/amazonq/result-extractor.js +0 -48
  383. package/dist/integrations/harnesses/claude/agent-builder.js +0 -106
  384. package/dist/integrations/harnesses/claude/config-import.js +0 -67
  385. package/dist/integrations/harnesses/claude/result-extractor.js +0 -67
  386. package/dist/integrations/harnesses/codex/agent-builder.js +0 -150
  387. package/dist/integrations/harnesses/codex/result-extractor.js +0 -110
  388. package/dist/integrations/harnesses/copilot/agent-builder.js +0 -117
  389. package/dist/integrations/harnesses/copilot/result-extractor.js +0 -178
  390. package/dist/integrations/harnesses/gemini/agent-builder.js +0 -114
  391. package/dist/integrations/harnesses/gemini/result-extractor.js +0 -149
  392. package/dist/integrations/harnesses/opencode/config-import.js +0 -149
  393. package/dist/integrations/harnesses/opencode/model-config.js +0 -33
  394. package/dist/integrations/harnesses/opencode/model-work-agent.js +0 -115
  395. package/dist/integrations/harnesses/opencode/session-log-types.js +0 -12
  396. package/dist/integrations/harnesses/opencode-sdk/index.js +0 -44
  397. package/dist/integrations/harnesses/opencode-sdk/sdk-runner.js +0 -1052
  398. package/dist/integrations/harnesses/opencode-sdk/v1-adapter.js +0 -199
  399. package/dist/integrations/harnesses/opencode-sdk/v2-adapter.js +0 -254
  400. package/dist/integrations/harnesses/opencode-sdk/wire.js +0 -66
  401. package/dist/integrations/harnesses/openhands/agent-builder.js +0 -120
  402. package/dist/integrations/harnesses/openhands/result-extractor.js +0 -135
  403. package/dist/integrations/harnesses/pi/agent-builder.js +0 -89
  404. package/dist/integrations/harnesses/pi/result-extractor.js +0 -168
  405. package/dist/integrations/harnesses/shared.js +0 -18
  406. package/dist/integrations/harnesses/types.js +0 -55
  407. package/dist/llm/feature-gate.js +0 -115
  408. package/dist/output/shapes/models-list.js +0 -16
  409. package/dist/output/shapes/registry-search.js +0 -10
  410. package/dist/setup/detected-engines.js +0 -136
  411. package/dist/setup/engine-config.js +0 -97
  412. package/dist/setup/harness-config-import.js +0 -47
  413. package/dist/setup/providers.js +0 -14
  414. package/dist/setup/steps/semantic.js +0 -39
  415. package/dist/workflows/exec/lowering-notices.js +0 -23
  416. package/docs/architecture/0.10-process-rules.md +0 -832
  417. package/docs/architecture/akm-architecture-decision-history.md +0 -2055
  418. package/docs/architecture/comparisons/claude-code-vs-akm-workflows-full.md +0 -544
  419. package/docs/architecture/decisions/0001-no-interpolation-attached-structured-context.md +0 -72
  420. package/docs/architecture/decisions/0002-unit-reuse-and-input-hash-scope.md +0 -142
  421. package/docs/architecture/decisions/0003-child-env-allowlist-and-provenance.md +0 -187
  422. package/docs/architecture/decisions/0004-task-input-contract-and-flag-coercion.md +0 -97
  423. package/docs/architecture/decisions/0005-task-result-vocabulary-and-legacy-read-mapping.md +0 -108
  424. package/docs/architecture/decisions/0006-task-source-version-routing.md +0 -124
  425. package/docs/architecture/decisions/0007-workflow-composition-bounds.md +0 -83
  426. package/docs/architecture/decisions/0008-task-binding-normalization.md +0 -88
  427. package/docs/architecture/decisions/0009-child-run-publication-column-parity.md +0 -80
  428. package/docs/architecture/decisions/0010-driver-protocol-cut.md +0 -36
  429. package/docs/architecture/decisions/0011-engine-run-loop-invariants.md +0 -125
  430. package/docs/architecture/decisions/README.md +0 -62
  431. package/docs/architecture/internals/functional-contract-patterns.md +0 -340
  432. package/docs/architecture/internals/registry-network-boundary.md +0 -57
  433. package/docs/architecture/internals/search.md +0 -248
  434. package/docs/architecture/reviews/env-secret-access.md +0 -319
  435. package/docs/architecture/runtime-boundary-design.md +0 -153
  436. package/docs/architecture/specs/0.9.0-close-out-plan.md +0 -361
  437. package/docs/architecture/specs/0.9.0-decisions.md +0 -532
  438. package/docs/architecture/specs/0.9.0-docs-code-drift-register.md +0 -745
  439. package/docs/architecture/specs/0.9.0-open-items-register.md +0 -135
  440. package/docs/architecture/specs/0.9.0-public-api-issue-backlog.md +0 -740
  441. package/docs/architecture/specs/0.9.0-release-surface-review.md +0 -636
  442. package/docs/architecture/specs/agent-command-engine-model-design.md +0 -513
  443. package/docs/architecture/specs/akm-0.9.0-bundle-adapter-spec.md +0 -501
  444. package/docs/architecture/specs/akm-0.9.0-ref-grammar-decision.md +0 -291
  445. package/docs/architecture/specs/akm-format-neutral-bundle-workspace-spec.md +0 -2059
  446. package/docs/architecture/specs/di-seams-plan.md +0 -539
  447. package/docs/architecture/specs/driver-protocol-keep-or-cut.md +0 -275
  448. package/docs/architecture/specs/fact-asset-type.md +0 -142
  449. package/docs/architecture/specs/improve-collapse-churn-detector-design.md +0 -634
  450. package/docs/architecture/specs/reviews/task-workflow-unification/README.md +0 -72
  451. package/docs/architecture/specs/reviews/task-workflow-unification/findings-consolidated.md +0 -152
  452. package/docs/architecture/specs/reviews/task-workflow-unification/library-eval-alternatives.md +0 -352
  453. package/docs/architecture/specs/reviews/task-workflow-unification/library-eval-bunqueue.md +0 -300
  454. package/docs/architecture/specs/reviews/task-workflow-unification/library-eval-openworkflow.md +0 -402
  455. package/docs/architecture/specs/reviews/task-workflow-unification/opus-review-1.md +0 -758
  456. package/docs/architecture/specs/reviews/task-workflow-unification/opus-review-2.md +0 -645
  457. package/docs/architecture/specs/reviews/task-workflow-unification/opus-review-3.md +0 -602
  458. package/docs/architecture/specs/reviews/task-workflow-unification/panel-r1-adversarial.md +0 -27
  459. package/docs/architecture/specs/reviews/task-workflow-unification/panel-r1-architecture.md +0 -27
  460. package/docs/architecture/specs/reviews/task-workflow-unification/panel-r1-coverage.md +0 -74
  461. package/docs/architecture/specs/reviews/task-workflow-unification/panel-r1-security.md +0 -15
  462. package/docs/architecture/specs/reviews/task-workflow-unification/panel-r2-adversarial.md +0 -132
  463. package/docs/architecture/specs/reviews/task-workflow-unification/panel-r2-verification.md +0 -147
  464. package/docs/architecture/specs/stash-conventions-code-spec.md +0 -275
  465. package/docs/architecture/specs/stash-organization-conventions.md +0 -377
  466. package/docs/architecture/specs/task-workflow-format-unification.md +0 -721
  467. package/docs/architecture/specs/workflow-engine-buy-vs-build.md +0 -231
  468. package/docs/architecture/specs/workflow-format-unification.md +0 -432
  469. package/docs/architecture/testing/manual-testing-checklist.md +0 -3379
  470. package/docs/architecture/testing/okf-v0.2-conformance-runbook.md +0 -924
  471. package/docs/architecture/testing/task-workflow-manual-tests.md +0 -1702
  472. package/docs/guides/claude-code-vs-akm-workflows.md +0 -29
  473. package/docs/guides/knowledge-management.md +0 -18
  474. package/docs/maintainers/curate-workmap.md +0 -335
  475. package/docs/migration/v0.5-to-v0.6.md +0 -759
  476. package/docs/migration/v0.7-to-v0.8.md +0 -1378
  477. package/docs/plans/0.9.2-agent-command-workflow-plan.md +0 -423
@@ -0,0 +1,107 @@
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
+ * One member of a gzip-compressed tar archive, streamed to a file. This is all
6
+ * akm needs of tar: the OpenCode binary is a single regular file of about 240 MB
7
+ * inside its package tarball, so it is never held in memory and no tar library
8
+ * is a dependency.
9
+ */
10
+ import fs from "node:fs";
11
+ import { pipeline } from "node:stream";
12
+ import zlib from "node:zlib";
13
+ const BLOCK_BYTES = 512;
14
+ /** Exact reads from a stream of chunks. */
15
+ class ByteReader {
16
+ #chunks;
17
+ #pending = Buffer.alloc(0);
18
+ constructor(source) {
19
+ this.#chunks = source[Symbol.asyncIterator]();
20
+ }
21
+ /** Up to `max` bytes, at least one unless the stream has ended (`undefined`). */
22
+ async read(max) {
23
+ if (this.#pending.length === 0) {
24
+ const next = await this.#chunks.next();
25
+ if (next.done)
26
+ return undefined;
27
+ this.#pending = next.value;
28
+ }
29
+ const taken = this.#pending.subarray(0, max);
30
+ this.#pending = this.#pending.subarray(taken.length);
31
+ return taken;
32
+ }
33
+ async exact(count) {
34
+ const parts = [];
35
+ for (let left = count; left > 0;) {
36
+ const part = await this.read(left);
37
+ if (!part)
38
+ throw new Error("the archive ends inside an entry");
39
+ parts.push(part);
40
+ left -= part.length;
41
+ }
42
+ return Buffer.concat(parts);
43
+ }
44
+ async skip(count) {
45
+ for (let left = count; left > 0;) {
46
+ const part = await this.read(left);
47
+ if (!part)
48
+ throw new Error("the archive ends inside an entry");
49
+ left -= part.length;
50
+ }
51
+ }
52
+ }
53
+ /** A header field of NUL-terminated text. */
54
+ const field = (header, start, end) => {
55
+ const bytes = header.subarray(start, end);
56
+ const stop = bytes.indexOf(0);
57
+ return bytes.subarray(0, stop < 0 ? bytes.length : stop).toString("utf8");
58
+ };
59
+ /**
60
+ * Write the regular file `member` of the `.tgz` at `archive` to `destination` (mode 0755) and return its size. Entries
61
+ * are matched by the header's name field alone, which holds up to 100 bytes; a longer name, which tar keeps in the
62
+ * ustar prefix field or a PAX `path` record, is not read, so such a member is never found. The one member akm reads,
63
+ * `package/bin/opencode`, is short. Extended headers are skipped like any other entry that is not the member.
64
+ */
65
+ export async function extractTarGzMember(archive, member, destination) {
66
+ const gunzip = zlib.createGunzip();
67
+ pipeline(fs.createReadStream(archive), gunzip, () => { });
68
+ const reader = new ByteReader(gunzip);
69
+ try {
70
+ return await extractFrom(reader, archive, member, destination);
71
+ }
72
+ finally {
73
+ // The rest of the archive is not read: close it now rather than when the stream is collected.
74
+ gunzip.destroy();
75
+ }
76
+ }
77
+ async function extractFrom(reader, archive, member, destination) {
78
+ for (;;) {
79
+ const header = await reader.exact(BLOCK_BYTES);
80
+ if (header.every((byte) => byte === 0))
81
+ throw new Error(`${archive} has no ${member}`);
82
+ const name = field(header, 0, 100).replace(/^\.\//, "");
83
+ const typeflag = String.fromCharCode(header[156] ?? 0);
84
+ const size = Number.parseInt(field(header, 124, 136).trim() || "0", 8);
85
+ if (!Number.isSafeInteger(size))
86
+ throw new Error(`${archive} is not a tar archive this reader understands`);
87
+ const padding = (BLOCK_BYTES - (size % BLOCK_BYTES)) % BLOCK_BYTES;
88
+ if (name !== member || (typeflag !== "0" && typeflag !== "\0")) {
89
+ await reader.skip(size + padding);
90
+ continue;
91
+ }
92
+ const out = await fs.promises.open(destination, "w", 0o755);
93
+ try {
94
+ for (let left = size; left > 0;) {
95
+ const part = await reader.read(left);
96
+ if (!part)
97
+ throw new Error(`${archive} ends inside ${member}`);
98
+ await out.writeFile(part);
99
+ left -= part.length;
100
+ }
101
+ }
102
+ finally {
103
+ await out.close();
104
+ }
105
+ return size;
106
+ }
107
+ }
@@ -2,7 +2,16 @@
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
  import { extractInlineRefMentions } from "../../session-logs/inline-refs.js";
5
- import { toMeta } from "./session-log-types.js";
5
+ /** The metadata of a row, with a column that is absent or empty left out. */
6
+ export function toMeta(r, sessionId) {
7
+ return {
8
+ sessionId,
9
+ startedAt: typeof r.time_created === "number" ? r.time_created : undefined,
10
+ endedAt: typeof r.time_updated === "number" ? r.time_updated : undefined,
11
+ projectHint: typeof r.directory === "string" && r.directory.length > 0 ? r.directory : undefined,
12
+ title: typeof r.title === "string" && r.title.length > 0 ? r.title : undefined,
13
+ };
14
+ }
6
15
  /** Listing needs only `session`; reading a session needs `message` and `part`, and fails loudly without them. */
7
16
  export const V1_TABLES = ["session"];
8
17
  /** Every V1 session updated at or after `sinceMs`, newest first. Throws on an incompatible schema. */
@@ -12,18 +21,17 @@ export function listV1Sessions(db, sinceMs) {
12
21
  .all(sinceMs);
13
22
  return rows.map((r) => toMeta(r, r.id));
14
23
  }
15
- /** Whether a V1 `session` row exists for `sessionId`. */
16
- export function hasV1Session(db, sessionId) {
17
- return db.prepare("SELECT id FROM session WHERE id = ?").get(sessionId) !== undefined;
18
- }
19
24
  /**
20
25
  * One event per message, text-parts concatenated in time order. Throws on an
21
- * incompatible schema; individual unparsable rows are skipped.
26
+ * incompatible schema or a session that is not in the file; individual unparsable
27
+ * rows are skipped.
22
28
  */
23
29
  export function readV1Session(db, harness, sessionId, filePath) {
24
30
  const meta = db
25
31
  .prepare("SELECT title, directory, time_created, time_updated FROM session WHERE id = ?")
26
32
  .get(sessionId);
33
+ if (!meta)
34
+ throw new Error(`session ${sessionId} is not in the file`);
27
35
  const messages = db
28
36
  .prepare("SELECT id, data, time_created FROM message WHERE session_id = ? ORDER BY time_created ASC, id ASC")
29
37
  .all(sessionId);
@@ -68,5 +76,5 @@ export function readV1Session(db, harness, sessionId, filePath) {
68
76
  inlineRefs.push(...extractInlineRefMentions(text, ts));
69
77
  }
70
78
  events.sort((a, b) => (a.ts ?? 0) - (b.ts ?? 0));
71
- return { meta: meta ? toMeta(meta, sessionId) : { sessionId }, events, inlineRefs };
79
+ return { meta: toMeta(meta, sessionId), events, inlineRefs };
72
80
  }
@@ -2,37 +2,25 @@
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
- * OpenCode 2 session-store adapter. V2 keeps one `session_v2` row per session
6
- * and the ordered conversation as `session_message` rows (`type` + JSON `data`
7
- * minus `id`/`type`, shapes from `@opencode/client` `SessionMessageInfo`).
8
- * Read-only: the database is never migrated; V1 rows a native upgrade copied
9
- * here arrive as the same shapes under the same session id.
5
+ * OpenCode 2 session store: the `session_v2` and `session_message` tables, read
6
+ * with SQLite only. Nothing here starts OpenCode (which would migrate the file
7
+ * and resume its suspended sessions); it reads the rows as they are.
10
8
  *
11
- * Mapping into the session-log contract follows the Codex reader: user and
12
- * assistant text become events of that role, a tool call becomes
13
- * `[tool:<name>] <input>` and its outcome a `tool` event
14
- * `[tool_result] <output>`, so the inline-ref scanner sees shell commands.
15
- * Reasoning, compaction, synthetic/system and bookkeeping messages are skipped.
9
+ * A message row is `(id, type, data)`; OpenCode decodes it as `{ ...data, id, type }`,
10
+ * which is rebuilt here. Only top-level sessions are read, and akm's own
11
+ * model-work sessions are left out: OpenCode 2 stores the agent a session ran as,
12
+ * and akm runs model work as one agent (`./agent-builder.ts`).
13
+ *
14
+ * Mapping to events follows the Codex reader: user and assistant text become events of
15
+ * that role, a tool call becomes `[tool:<name>] <input>` and its outcome a
16
+ * `tool` event `[tool_result] <output>`, so the inline-ref scanner sees shell
17
+ * commands. Reasoning, compaction, synthetic/system and bookkeeping messages
18
+ * are skipped.
16
19
  */
17
20
  import { asRecord, tryParseJson } from "../../../core/common.js";
18
- import { warnOnce } from "../../../core/warn.js";
19
21
  import { extractInlineRefMentions } from "../../session-logs/inline-refs.js";
20
- import { toMeta } from "./session-log-types.js";
21
- export const V2_TABLES = ["session_v2", "session_message"];
22
- /** Every V2 session updated at or after `sinceMs`, newest first. Throws on an incompatible schema. */
23
- export function listV2Sessions(db, sinceMs) {
24
- const rows = db
25
- .prepare("SELECT id, title, directory, time_created, time_updated FROM session_v2 WHERE time_updated >= ? ORDER BY time_updated DESC")
26
- .all(sinceMs);
27
- return rows.map((r) => toMeta(r, r.id));
28
- }
29
- /** Whether `sessionId` has a `session_v2` row, and how many `session_message` rows it owns. */
30
- export function v2SessionState(db, sessionId) {
31
- const row = db
32
- .prepare("SELECT (SELECT COUNT(*) FROM session_message WHERE session_id = s.id) AS n FROM session_v2 s WHERE s.id = ?")
33
- .get(sessionId);
34
- return row ? { exists: true, messages: row.n } : { exists: false, messages: 0 };
35
- }
22
+ import { MODEL_WORK_AGENT } from "./agent-builder.js";
23
+ import { toMeta } from "./session-log-v1.js";
36
24
  const asObject = asRecord;
37
25
  function asNumber(v) {
38
26
  return typeof v === "number" ? v : undefined;
@@ -69,17 +57,8 @@ function structuredErrorText(err) {
69
57
  return e.message;
70
58
  return typeof e?.type === "string" ? e.type : "error";
71
59
  }
72
- /**
73
- * Rebuild one session's events in `seq` order. Throws on an incompatible
74
- * schema; a message whose JSON cannot be read is skipped with one warning.
75
- */
76
- export function readV2Session(db, harness, sessionId, filePath) {
77
- const meta = db
78
- .prepare("SELECT title, directory, time_created, time_updated FROM session_v2 WHERE id = ?")
79
- .get(sessionId);
80
- const rows = db
81
- .prepare("SELECT id, type, data, time_created FROM session_message WHERE session_id = ? ORDER BY seq ASC, time_created ASC, id ASC")
82
- .all(sessionId);
60
+ /** One session's events and inline refs, from its messages oldest first. A message that is not an object is skipped. */
61
+ export function opencodeMessageEvents(messages, harness, sessionId, filePath) {
83
62
  const events = [];
84
63
  const inlineRefs = [];
85
64
  const push = (role, text, ts) => {
@@ -89,18 +68,16 @@ export function readV2Session(db, harness, sessionId, filePath) {
89
68
  events.push({ harness, text: trimmed, ts, sessionId, role, filePath });
90
69
  inlineRefs.push(...extractInlineRefMentions(trimmed, ts));
91
70
  };
92
- for (const row of rows) {
93
- const data = asObject(tryParseJson(row.data));
94
- if (!data) {
95
- warnOnce(`opencode-v2-message:${filePath}:${row.id}`, `OpenCode 2 history: skipped unreadable message ${row.id} in session ${sessionId} (${filePath}).`);
71
+ for (const message of messages) {
72
+ const data = asObject(message);
73
+ if (!data)
96
74
  continue;
97
- }
98
- const ts = asNumber(asObject(data.time)?.created) ?? asNumber(row.time_created);
99
- if (row.type === "user") {
75
+ const ts = asNumber(asObject(data.time)?.created);
76
+ if (data.type === "user") {
100
77
  if (typeof data.text === "string")
101
78
  push("user", data.text, ts);
102
79
  }
103
- else if (row.type === "assistant") {
80
+ else if (data.type === "assistant") {
104
81
  const content = Array.isArray(data.content) ? data.content : [];
105
82
  const text = content
106
83
  .map((c) => asObject(c))
@@ -128,7 +105,7 @@ export function readV2Session(db, harness, sessionId, filePath) {
128
105
  }
129
106
  }
130
107
  }
131
- else if (row.type === "shell") {
108
+ else if (data.type === "shell") {
132
109
  if (typeof data.command === "string")
133
110
  push("assistant", `[tool:shell] ${data.command}`, ts);
134
111
  const out = asObject(data.output)?.output;
@@ -136,5 +113,52 @@ export function readV2Session(db, harness, sessionId, filePath) {
136
113
  push("tool", `[tool_result] ${out}`, ts);
137
114
  }
138
115
  }
139
- return { meta: meta ? toMeta(meta, sessionId) : { sessionId }, events, inlineRefs };
116
+ return { events, inlineRefs };
117
+ }
118
+ /** The columns of each table akm reads; a file lacking one is a schema akm does not support. */
119
+ const V2_COLUMNS = {
120
+ session_v2: ["id", "parent_id", "title", "directory", "agent", "time_created", "time_updated"],
121
+ session_message: ["id", "session_id", "type", "seq", "data"],
122
+ };
123
+ /** Whether `db` has the OpenCode 2 session tables with the columns akm reads. */
124
+ export function hasV2Tables(db) {
125
+ return Object.entries(V2_COLUMNS).every(([table, columns]) => {
126
+ const present = new Set(db
127
+ .prepare(`PRAGMA table_info(${table})`)
128
+ .all()
129
+ .map((c) => c.name));
130
+ return columns.every((column) => present.has(column));
131
+ });
132
+ }
133
+ /** Top-level sessions that are not akm's model work. */
134
+ const AKM_USER_SESSIONS = `parent_id IS NULL AND (agent IS NULL OR agent != '${MODEL_WORK_AGENT}')`;
135
+ /** Every top-level OpenCode 2 session updated at or after `sinceMs`, newest first. Throws on an incompatible schema. */
136
+ export function listV2Sessions(db, sinceMs) {
137
+ return db
138
+ .prepare(`SELECT id, title, directory, time_created, time_updated FROM session_v2 WHERE ${AKM_USER_SESSIONS} AND time_updated >= ? ORDER BY time_updated DESC`)
139
+ .all(sinceMs)
140
+ .map((row) => toMeta(row, row.id));
141
+ }
142
+ /**
143
+ * The tokens one session's turns used: OpenCode records them on each assistant message and keeps their sums on the
144
+ * session row (equal, measured on 2.1.4). Undefined when the session is not in the file.
145
+ */
146
+ export function v2SessionTokens(db, sessionId) {
147
+ const row = db
148
+ .prepare("SELECT tokens_input, tokens_output, tokens_reasoning FROM session_v2 WHERE id = ?")
149
+ .get(sessionId);
150
+ return row ? { input: row.tokens_input, output: row.tokens_output, reasoning: row.tokens_reasoning } : undefined;
151
+ }
152
+ /** One session's events, from its messages in order. Throws when the session is not in the file. */
153
+ export function readV2Session(db, harness, sessionId, filePath) {
154
+ const row = db
155
+ .prepare("SELECT title, directory, time_created, time_updated FROM session_v2 WHERE id = ?")
156
+ .get(sessionId);
157
+ if (!row)
158
+ throw new Error(`session ${sessionId} is not in the file`);
159
+ const messages = db
160
+ .prepare("SELECT id, type, data FROM session_message WHERE session_id = ? ORDER BY seq ASC")
161
+ .all(sessionId)
162
+ .map((message) => ({ ...asRecord(tryParseJson(message.data)), id: message.id, type: message.type }));
163
+ return { meta: toMeta(row, sessionId), ...opencodeMessageEvents(messages, harness, sessionId, filePath) };
140
164
  }
@@ -2,167 +2,88 @@
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
  import fs from "node:fs";
5
- import os from "node:os";
6
- import path from "node:path";
7
5
  import { toErrorMessage } from "../../../core/common.js";
8
6
  import { warnOnce } from "../../../core/warn.js";
9
7
  import { openDatabase } from "../../../storage/database.js";
10
8
  import { openSqliteReadSnapshot } from "../../../storage/sqlite-read-snapshot.js";
11
9
  import { AbstractSessionLogProvider } from "../../session-logs/provider-base.js";
12
- import { hasV1Session, listV1Sessions, readV1Session, V1_TABLES } from "./session-log-v1.js";
13
- import { listV2Sessions, readV2Session, V2_TABLES, v2SessionState } from "./session-log-v2.js";
14
- function getOpenCodeBaseDir() {
15
- if (process.platform === "darwin") {
16
- return path.join(os.homedir(), "Library", "Application Support", "opencode");
17
- }
18
- return path.join(os.homedir(), ".local", "share", "opencode");
19
- }
20
- /**
21
- * OpenCode session storage: one SQLite file, `<base>/opencode.db`, whose
22
- * layout decides the reader, never the installed binary or its version:
23
- *
24
- * - V1: `session` table, with `message` / `part` for content (`session-log-v1.ts`).
25
- * - V2: `session_v2` / `session_message` tables (`session-log-v2.ts`).
26
- * - Both: a natively upgraded V1 file keeps its V1 tables and gains the V2
27
- * ones. Sessions are merged by id, V2 winning, V1-only ones kept.
28
- * - Neither: an unsupported layout, reported, never presented as empty.
29
- *
30
- * The file is opened read-only and never migrated or written.
31
- */
32
- /** Filename of opencode's SQLite session store, relative to its base dir. */
33
- const OPENCODE_DB_FILENAME = "opencode.db";
34
- function tableNames(db) {
10
+ import { akmOpencodeDatabasePath, databaseIn, opencodeDatabasePath } from "./roots.js";
11
+ import { listV1Sessions, readV1Session, V1_TABLES } from "./session-log-v1.js";
12
+ import { hasV2Tables, listV2Sessions, readV2Session } from "./session-log-v2.js";
13
+ function layoutOf(db) {
35
14
  const rows = db.prepare("SELECT name FROM sqlite_master WHERE type = 'table'").all();
36
- return new Set(rows.map((r) => r.name));
37
- }
38
- function classify(tables) {
39
- const v1 = V1_TABLES.every((t) => tables.has(t));
40
- const v2 = V2_TABLES.every((t) => tables.has(t));
41
- return v1 || v2 ? { kind: "ok", v1, v2 } : { kind: "unsupported", tables: [...tables].sort() };
15
+ const tables = new Set(rows.map((r) => r.name));
16
+ if (tables.has("session_v2") && hasV2Tables(db))
17
+ return "v2";
18
+ return V1_TABLES.every((t) => tables.has(t)) && !tables.has("session_v2") ? "v1" : "unsupported";
42
19
  }
43
20
  export class OpenCodeProvider extends AbstractSessionLogProvider {
44
21
  name = "opencode";
45
- #baseDir = getOpenCodeBaseDir();
22
+ #userDatabase = opencodeDatabasePath();
46
23
  availabilityRoot() {
47
- return this.#dbPath(this.#baseDir);
24
+ return this.#userDatabase;
48
25
  }
49
- /** Absolute path to opencode's SQLite store under `base`. */
50
- #dbPath(base) {
51
- return path.join(base, OPENCODE_DB_FILENAME);
26
+ /** The user's OpenCode history, or akm's own. */
27
+ isAvailable() {
28
+ return super.isAvailable() || fs.existsSync(akmOpencodeDatabasePath());
52
29
  }
53
- /** Classify the store under `location` (default: opencode's data dir) without listing anything. */
54
- inspectStore(location) {
55
- const dbPath = this.#dbPath(location ?? this.#baseDir);
56
- if (!fs.existsSync(dbPath))
57
- return { kind: "missing" };
58
- let db;
59
- try {
60
- db = openDatabase(dbPath, { readonly: true, create: false });
61
- }
62
- catch (error) {
63
- return { kind: "unreadable", reason: toErrorMessage(error) };
64
- }
65
- try {
66
- return classify(tableNames(db));
67
- }
68
- catch (error) {
69
- return { kind: "unreadable", reason: toErrorMessage(error) };
70
- }
71
- finally {
72
- db.close();
73
- }
30
+ /** The stores to read: the one under `location`, else the user's and akm's. */
31
+ #stores(location) {
32
+ if (location)
33
+ return [databaseIn(location)];
34
+ return [this.#userDatabase, akmOpencodeDatabasePath()];
74
35
  }
75
- listSessions(input = {}) {
76
- const dbPath = this.#dbPath(input.location ?? this.#baseDir);
77
- if (!fs.existsSync(dbPath))
78
- return [];
79
- let db;
80
- try {
81
- db = input.isolatedSnapshot
82
- ? openSqliteReadSnapshot(dbPath)
83
- : openDatabase(dbPath, { readonly: true, create: false });
84
- }
85
- catch (error) {
86
- this.#warnUnavailable(dbPath, `cannot open it (${toErrorMessage(error)})`);
87
- return [];
88
- }
89
- if (!db)
90
- return [];
91
- try {
92
- const status = classify(tableNames(db));
93
- if (status.kind !== "ok") {
94
- this.#warnUnavailable(dbPath, `it has neither the OpenCode 1 (${V1_TABLES.join("/")}) nor the OpenCode 2 (${V2_TABLES.join("/")}) tables`);
95
- return [];
36
+ async listSessions(input = {}) {
37
+ const sinceMs = input.sinceMs ?? 0;
38
+ const listed = [];
39
+ for (const dbPath of this.#stores(input.location)) {
40
+ if (!fs.existsSync(dbPath))
41
+ continue;
42
+ try {
43
+ listed.push(...this.#listStore(dbPath, sinceMs, input.isolatedSnapshot === true));
44
+ }
45
+ catch (error) {
46
+ this.#warnUnavailable(dbPath, `cannot list it (${toErrorMessage(error)})`);
96
47
  }
97
- return this.#listFromDb(db, dbPath, input.sinceMs ?? 0, status.v1, status.v2);
98
- }
99
- catch (error) {
100
- this.#warnUnavailable(dbPath, `cannot query it (${toErrorMessage(error)})`);
101
- return [];
102
- }
103
- finally {
104
- db.close();
105
48
  }
49
+ return listed.sort((a, b) => (b.endedAt ?? 0) - (a.endedAt ?? 0));
106
50
  }
107
- readSession(ref) {
108
- const emptyRef = this.sessionRef({ sessionId: ref.sessionId, filePath: ref.filePath });
109
- const empty = { ref: emptyRef, events: [], inlineRefs: [] };
110
- let db;
111
- try {
112
- db = openDatabase(ref.filePath, { readonly: true, create: false });
51
+ /** One session's events. A file or session that cannot be read throws, so the caller records the failure. */
52
+ async readSession(ref) {
53
+ const layout = this.#withDb(ref.filePath, false, layoutOf);
54
+ if (layout === "unsupported") {
55
+ throw new Error(`${ref.filePath} has no supported OpenCode 1 or OpenCode 2 session tables`);
113
56
  }
114
- catch (error) {
115
- this.#warnUnavailable(ref.filePath, `cannot open it (${toErrorMessage(error)})`);
116
- return empty;
57
+ const read = this.#withDb(ref.filePath, false, (db) => layout === "v2"
58
+ ? readV2Session(db, this.name, ref.sessionId, ref.filePath)
59
+ : readV1Session(db, this.name, ref.sessionId, ref.filePath));
60
+ return {
61
+ ref: this.sessionRef({ ...read.meta, filePath: ref.filePath }),
62
+ events: read.events,
63
+ inlineRefs: read.inlineRefs,
64
+ };
65
+ }
66
+ #listStore(dbPath, sinceMs, isolated) {
67
+ const layout = this.#withDb(dbPath, isolated, layoutOf);
68
+ if (layout === "unsupported") {
69
+ this.#warnUnavailable(dbPath, `it has neither the OpenCode 1 (${V1_TABLES.join("/")}) nor the OpenCode 2 tables`);
70
+ return [];
117
71
  }
72
+ const metas = this.#withDb(dbPath, isolated, (db) => layout === "v2" ? listV2Sessions(db, sinceMs) : listV1Sessions(db, sinceMs));
73
+ return metas.map((meta) => this.sessionRef({ ...meta, filePath: dbPath }));
74
+ }
75
+ /** Run `use` on the SQLite file at `dbPath`, read-only (a private copy when `isolated`). */
76
+ #withDb(dbPath, isolated, use) {
77
+ const db = isolated ? openSqliteReadSnapshot(dbPath) : openDatabase(dbPath, { readonly: true, create: false });
78
+ if (!db)
79
+ throw new Error("the file disappeared");
118
80
  try {
119
- const status = classify(tableNames(db));
120
- if (status.kind !== "ok") {
121
- this.#warnUnavailable(ref.filePath, "it has no supported OpenCode 1 or OpenCode 2 session tables");
122
- return empty;
123
- }
124
- // V2 owns a session that has messages there; otherwise a retained V1 copy (a
125
- // session the upgrade has not copied, or copied without messages) is the history.
126
- const v2 = status.v2 ? v2SessionState(db, ref.sessionId) : { exists: false, messages: 0 };
127
- const useV2 = v2.exists && (v2.messages > 0 || !status.v1 || !hasV1Session(db, ref.sessionId));
128
- const read = useV2
129
- ? readV2Session(db, this.name, ref.sessionId, ref.filePath)
130
- : readV1Session(db, this.name, ref.sessionId, ref.filePath);
131
- return {
132
- ref: this.sessionRef({ ...read.meta, filePath: ref.filePath }),
133
- events: read.events,
134
- inlineRefs: read.inlineRefs,
135
- };
136
- }
137
- catch (error) {
138
- this.#warnUnavailable(ref.filePath, `cannot read session ${ref.sessionId} (${toErrorMessage(error)})`);
139
- return empty;
81
+ return use(db);
140
82
  }
141
83
  finally {
142
84
  db.close();
143
85
  }
144
86
  }
145
- /** List each present layout; one failing layout is reported and the other still listed. */
146
- #listFromDb(db, dbPath, sinceMs, v1, v2) {
147
- const merged = new Map();
148
- const attempt = (label, list) => {
149
- try {
150
- for (const meta of list())
151
- if (!merged.has(meta.sessionId))
152
- merged.set(meta.sessionId, meta);
153
- }
154
- catch (error) {
155
- this.#warnUnavailable(dbPath, `its ${label} session tables cannot be queried (${toErrorMessage(error)})`);
156
- }
157
- };
158
- if (v2)
159
- attempt("OpenCode 2", () => listV2Sessions(db, sinceMs));
160
- if (v1)
161
- attempt("OpenCode 1", () => listV1Sessions(db, sinceMs));
162
- return [...merged.values()]
163
- .sort((a, b) => (b.endedAt ?? 0) - (a.endedAt ?? 0))
164
- .map((meta) => this.sessionRef({ ...meta, filePath: dbPath }));
165
- }
166
87
  #warnUnavailable(dbPath, why) {
167
88
  warnOnce(`opencode-history:${dbPath}:${why}`, `OpenCode session history at ${dbPath} was not read: ${why}. This is an unsupported or damaged store, not an empty history.`);
168
89
  }