akm-cli 0.10.261012-beta → 0.10.261014-beta

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (518) hide show
  1. package/CHANGELOG.md +710 -3
  2. package/README.md +15 -0
  3. package/SECURITY.md +11 -10
  4. package/STABILITY.md +47 -51
  5. package/dist/assets/hints/cli-hints-full.md +21 -19
  6. package/dist/assets/hints/cli-hints-short.md +3 -4
  7. package/dist/assets/opencode/akm-plugin.js +177 -0
  8. package/dist/assets/stash-skeleton/README.md +1 -1
  9. package/dist/assets/tasks/core/improve.yml +1 -1
  10. package/dist/assets/tasks/improve/akm-improve-consolidate.yml +1 -1
  11. package/dist/assets/ui/config.js +27 -10
  12. package/dist/assets/workflows/workflow-template.md +2 -2
  13. package/dist/cli/clack.js +3 -1
  14. package/dist/cli/selection.js +33 -0
  15. package/dist/cli/shared.js +14 -1
  16. package/dist/cli/unknown-flags.js +6 -37
  17. package/dist/cli.js +69 -48
  18. package/dist/commands/agent/agent-dispatch.js +17 -25
  19. package/dist/commands/agent/contribute-cli.js +9 -8
  20. package/dist/commands/command/command-cli.js +4 -8
  21. package/dist/commands/command/command-execution.js +25 -39
  22. package/dist/commands/command/execution-source-loader.js +10 -14
  23. package/dist/commands/completions.js +1 -1
  24. package/dist/commands/config-cli.js +14 -5
  25. package/dist/commands/env/child-env.js +12 -14
  26. package/dist/commands/env/env-binding.js +47 -58
  27. package/dist/commands/env/env-cli.js +22 -24
  28. package/dist/commands/env/env.js +10 -58
  29. package/dist/commands/env/secret-cli.js +11 -29
  30. package/dist/commands/env/secret.js +3 -10
  31. package/dist/commands/health/checks.js +10 -849
  32. package/dist/commands/health/connections-and-harnesses-check.js +109 -0
  33. package/dist/commands/health/egress.js +3 -3
  34. package/dist/commands/health/html-report.js +9 -10
  35. package/dist/commands/health/plugin-staleness.js +18 -11
  36. package/dist/commands/health/report-view-model.js +16 -12
  37. package/dist/commands/health/scheduler-binary.js +1 -1
  38. package/dist/commands/health/semantic-search-check.js +85 -0
  39. package/dist/commands/health/type-directory-check.js +0 -3
  40. package/dist/commands/health.js +30 -42
  41. package/dist/commands/improve/consolidate/pair-pass.js +10 -25
  42. package/dist/commands/improve/consolidate.js +10 -15
  43. package/dist/commands/improve/distill.js +5 -17
  44. package/dist/commands/improve/eligibility.js +1 -3
  45. package/dist/commands/improve/execution.js +37 -40
  46. package/dist/commands/improve/extract-cli.js +6 -11
  47. package/dist/commands/improve/extract-prompt.js +2 -2
  48. package/dist/commands/improve/extract.js +67 -97
  49. package/dist/commands/improve/improve-cli.js +22 -128
  50. package/dist/commands/improve/improve-report.js +1 -1
  51. package/dist/commands/improve/improve-strategies.js +25 -108
  52. package/dist/commands/improve/improve.js +10 -14
  53. package/dist/commands/improve/loop-stages.js +3 -0
  54. package/dist/commands/improve/memory/memory-improve.js +1 -1
  55. package/dist/commands/improve/preparation.js +8 -13
  56. package/dist/commands/improve/reflect.js +203 -332
  57. package/dist/commands/improve/retrieval-scope.js +1 -1
  58. package/dist/commands/improve/session-asset.js +3 -2
  59. package/dist/commands/improve/stage.js +87 -115
  60. package/dist/commands/lint/base-linter.js +3 -3
  61. package/dist/commands/lint/env-key-rules.js +7 -6
  62. package/dist/commands/lint/index.js +3 -3
  63. package/dist/commands/models-cli.js +103 -63
  64. package/dist/commands/proposal/drain.js +26 -39
  65. package/dist/commands/proposal/proposal-cli.js +14 -18
  66. package/dist/commands/proposal/propose-cli.js +4 -2
  67. package/dist/commands/proposal/propose.js +37 -64
  68. package/dist/commands/proposal/repository.js +17 -17
  69. package/dist/commands/proposal/validators/proposal-validators.js +3 -6
  70. package/dist/commands/read/curate.js +10 -6
  71. package/dist/commands/read/registry-search.js +2 -48
  72. package/dist/commands/read/search-cli.js +1 -8
  73. package/dist/commands/read/search.js +5 -6
  74. package/dist/commands/read/show.js +6 -29
  75. package/dist/commands/remember.js +25 -40
  76. package/dist/commands/sources/add-cli.js +8 -63
  77. package/dist/commands/sources/bundle-cli.js +8 -9
  78. package/dist/commands/sources/bundle-config-ops.js +2 -2
  79. package/dist/commands/sources/info.js +12 -1
  80. package/dist/commands/sources/init.js +1 -1
  81. package/dist/commands/sources/installed-stashes.js +119 -63
  82. package/dist/commands/sources/migration-help.js +1 -1
  83. package/dist/commands/sources/plugin-upgrade.js +8 -15
  84. package/dist/commands/sources/schema-repair.js +4 -10
  85. package/dist/commands/sources/source-add.js +2 -2
  86. package/dist/commands/sources/source-clone.js +31 -7
  87. package/dist/commands/sources/source-manage.js +4 -4
  88. package/dist/commands/targets.js +175 -0
  89. package/dist/commands/tasks/explain.js +104 -69
  90. package/dist/commands/tasks/tasks-cli.js +9 -11
  91. package/dist/commands/tasks/tasks.js +75 -97
  92. package/dist/commands/ui/api.js +11 -3
  93. package/dist/commands/ui/redact.js +5 -31
  94. package/dist/commands/ui/workspace-actions.js +1 -1
  95. package/dist/commands/workflow/plan.js +48 -9
  96. package/dist/commands/workflow-cli.js +40 -45
  97. package/dist/core/adapter/adapters/agent-skills-adapter.js +10 -11
  98. package/dist/core/adapter/adapters/akm-adapter.js +36 -41
  99. package/dist/core/adapter/adapters/akm-lint.js +10 -12
  100. package/dist/core/adapter/adapters/akm-metadata.js +2 -2
  101. package/dist/core/adapter/adapters/akm-task-adapter.js +8 -9
  102. package/dist/core/adapter/adapters/akm-workflow-adapter.js +5 -5
  103. package/dist/core/adapter/adapters/claude-adapter.js +1 -1
  104. package/dist/core/adapter/adapters/dotenv-adapter.js +7 -6
  105. package/dist/core/adapter/adapters/generic-files-adapter.js +5 -5
  106. package/dist/core/adapter/adapters/index.js +3 -4
  107. package/dist/core/adapter/adapters/llm-wiki-adapter.js +12 -14
  108. package/dist/core/adapter/adapters/okf-adapter.js +8 -10
  109. package/dist/core/adapter/adapters/opencode-adapter.js +1 -1
  110. package/dist/core/adapter/adapters/shared.js +3 -3
  111. package/dist/core/adapter/adapters/tool-dir-shared.js +7 -25
  112. package/dist/core/adapter/adapters/website-snapshot-adapter.js +3 -3
  113. package/dist/core/adapter/detect-adapter.js +1 -1
  114. package/dist/core/adapter/execution-source.js +13 -35
  115. package/dist/core/adapter/registry.js +1 -1
  116. package/dist/core/adapter/validate-context.js +2 -4
  117. package/dist/core/asset/asset-placement.js +1 -1
  118. package/dist/core/asset/asset-ref.js +3 -3
  119. package/dist/core/asset/resolve-ref.js +5 -0
  120. package/dist/core/bundle-rename.js +12 -4
  121. package/dist/core/closest-match.js +37 -0
  122. package/dist/core/common.js +37 -57
  123. package/dist/core/config/config-io.js +26 -18
  124. package/dist/core/config/config-schema.js +19 -106
  125. package/dist/core/config/config-sources.js +3 -3
  126. package/dist/core/config/config-types.js +4 -4
  127. package/dist/core/config/config-walker.js +50 -77
  128. package/dist/core/config/config.js +438 -109
  129. package/dist/core/config/convert-engine-references.js +114 -0
  130. package/dist/core/config/convert-engines-shared.js +40 -0
  131. package/dist/core/config/convert-engines.js +300 -0
  132. package/dist/core/config/convert-models-overlay.js +137 -0
  133. package/dist/core/config/credentials.js +304 -0
  134. package/dist/core/config/engine-semantics.js +3 -3
  135. package/dist/core/config/migrate-keys.js +222 -0
  136. package/dist/core/config/model-aliases.js +37 -0
  137. package/dist/core/config/models-file.js +34 -0
  138. package/dist/core/config/retired-engines.js +53 -0
  139. package/dist/core/config/schema/connections.js +41 -0
  140. package/dist/core/config/schema/embedding.js +2 -2
  141. package/dist/core/config/schema/harnesses.js +41 -0
  142. package/dist/core/config/schema/improve-processes.js +9 -28
  143. package/dist/core/config/schema/improve.js +36 -1
  144. package/dist/core/config/schema/index-config.js +18 -20
  145. package/dist/core/config/schema/primitives.js +42 -17
  146. package/dist/core/config/schema/search.js +6 -11
  147. package/dist/core/config/schema/sources-bundles.js +9 -9
  148. package/dist/core/config/schema/workflow.js +2 -6
  149. package/dist/core/config/unusable-entries.js +66 -0
  150. package/dist/core/content-safety.js +3 -6
  151. package/dist/core/endpoint-url.js +47 -0
  152. package/dist/core/env-secret-ref.js +84 -73
  153. package/dist/core/errors.js +10 -16
  154. package/dist/core/extra-params.js +3 -3
  155. package/dist/core/improve-result.js +8 -9
  156. package/dist/core/json-schema.js +1 -1
  157. package/dist/core/lesson-lint.js +1 -1
  158. package/dist/core/llm-inference.js +80 -0
  159. package/dist/core/parse.js +2 -2
  160. package/dist/core/paths.js +33 -10
  161. package/dist/core/recognition-util.js +8 -10
  162. package/dist/core/redaction.js +94 -55
  163. package/dist/core/ref-token.js +82 -0
  164. package/dist/core/secret-value.js +14 -0
  165. package/dist/core/state/migrations.js +17 -22
  166. package/dist/core/structured.js +2 -68
  167. package/dist/core/subprocess.js +63 -22
  168. package/dist/core/type-presentation.js +10 -14
  169. package/dist/core/write-source.js +20 -4
  170. package/dist/execution/input-contract.js +3 -6
  171. package/dist/execution/notices.js +49 -0
  172. package/dist/execution/resolved-request.js +24 -40
  173. package/dist/execution/source.js +21 -45
  174. package/dist/execution/target-ref.js +2 -2
  175. package/dist/indexer/bundle-identity-guard.js +6 -5
  176. package/dist/indexer/ensure-index.js +1 -1
  177. package/dist/indexer/index-writer-lock.js +1 -1
  178. package/dist/indexer/indexer.js +46 -42
  179. package/dist/indexer/installations.js +12 -22
  180. package/dist/indexer/lookup/adapter-concept-owner.js +40 -14
  181. package/dist/indexer/materialize-embeddings.js +20 -16
  182. package/dist/indexer/passes/memory-inference.js +21 -50
  183. package/dist/indexer/passes/metadata.js +5 -5
  184. package/dist/indexer/scan/doc-to-entry.js +1 -1
  185. package/dist/indexer/scan/drain-dir.js +9 -11
  186. package/dist/indexer/search/db-search.js +9 -7
  187. package/dist/indexer/search/search-source.js +42 -22
  188. package/dist/indexer/usage/usage-events.js +2 -3
  189. package/dist/indexer/walk/index-context.js +2 -1
  190. package/dist/indexer/walk/matchers.js +3 -11
  191. package/dist/indexer/walk/path-resolver.js +13 -68
  192. package/dist/indexer/walk/walker.js +32 -26
  193. package/dist/integrations/agent/akm-read-tools.js +81 -0
  194. package/dist/integrations/agent/config.js +1 -1
  195. package/dist/integrations/agent/detect.js +32 -36
  196. package/dist/integrations/agent/execution.js +130 -428
  197. package/dist/integrations/agent/index.js +1 -1
  198. package/dist/integrations/agent/profiles.js +24 -28
  199. package/dist/integrations/agent/prompts.js +17 -30
  200. package/dist/integrations/agent/request-lowering.js +67 -101
  201. package/dist/integrations/agent/resolution.js +332 -0
  202. package/dist/integrations/agent/runner-dispatch.js +156 -181
  203. package/dist/integrations/agent/runner.js +20 -70
  204. package/dist/integrations/agent/runtime-port.js +4 -0
  205. package/dist/integrations/agent/runtime.js +10 -0
  206. package/dist/integrations/agent/spawn.js +65 -190
  207. package/dist/integrations/harnesses/aider/index.js +19 -39
  208. package/dist/integrations/harnesses/amazonq/index.js +17 -32
  209. package/dist/integrations/harnesses/claude/index.js +59 -28
  210. package/dist/integrations/harnesses/claude/session-log.js +7 -5
  211. package/dist/integrations/harnesses/codex/index.js +19 -31
  212. package/dist/integrations/harnesses/copilot/index.js +17 -35
  213. package/dist/integrations/harnesses/gemini/index.js +18 -34
  214. package/dist/integrations/harnesses/harness.js +36 -0
  215. package/dist/integrations/harnesses/index.js +20 -51
  216. package/dist/integrations/harnesses/opencode/agent-builder.js +132 -100
  217. package/dist/integrations/harnesses/opencode/index.js +11 -33
  218. package/dist/integrations/harnesses/opencode/roots.js +50 -0
  219. package/dist/integrations/harnesses/opencode/runtime/binary.js +206 -0
  220. package/dist/integrations/harnesses/opencode/runtime/command.js +152 -0
  221. package/dist/integrations/harnesses/opencode/runtime/index.js +177 -0
  222. package/dist/integrations/harnesses/opencode/runtime/tar.js +107 -0
  223. package/dist/integrations/harnesses/opencode/session-log-v1.js +15 -7
  224. package/dist/integrations/harnesses/opencode/session-log-v2.js +72 -48
  225. package/dist/integrations/harnesses/opencode/session-log.js +58 -137
  226. package/dist/integrations/harnesses/opencode/version.js +34 -53
  227. package/dist/integrations/harnesses/openhands/index.js +13 -37
  228. package/dist/integrations/harnesses/pi/index.js +21 -32
  229. package/dist/integrations/lockfile.js +1 -1
  230. package/dist/integrations/session-logs/index.js +11 -31
  231. package/dist/llm/client.js +93 -111
  232. package/dist/llm/embedder.js +19 -34
  233. package/dist/llm/embedders/connection.js +31 -0
  234. package/dist/llm/embedders/local-model-files.js +56 -0
  235. package/dist/llm/embedders/local.js +146 -115
  236. package/dist/llm/embedders/remote.js +26 -23
  237. package/dist/llm/embedders/types.js +1 -1
  238. package/dist/llm/index-passes.js +33 -39
  239. package/dist/llm/memory-infer.js +67 -77
  240. package/dist/llm/model-list.js +35 -0
  241. package/dist/llm/rerank-client.js +8 -14
  242. package/dist/llm/structured-call.js +45 -99
  243. package/dist/llm/structured.js +60 -0
  244. package/dist/output/renderers.js +2 -8
  245. package/dist/output/shapes/helpers.js +18 -44
  246. package/dist/output/shapes/passthrough.js +1 -0
  247. package/dist/output/shapes.js +1 -7
  248. package/dist/output/text/command-format.js +41 -39
  249. package/dist/output/text/health-format.js +8 -2
  250. package/dist/output/text/helpers.js +1 -1
  251. package/dist/output/text/migrate.js +12 -0
  252. package/dist/output/text/models.js +3 -2
  253. package/dist/output/text/registry-commands.js +1 -2
  254. package/dist/output/text/show-directives.js +16 -28
  255. package/dist/output/text/show-format.js +0 -2
  256. package/dist/output/text/targets-table.js +70 -0
  257. package/dist/output/text/workflow-format.js +44 -15
  258. package/dist/output/text.js +1 -1
  259. package/dist/registry/providers/skills-sh.js +1 -28
  260. package/dist/registry/providers/static-index.js +1 -71
  261. package/dist/runtime.js +6 -2
  262. package/dist/scripts/akm-migrate-node.js +47095 -44905
  263. package/dist/scripts/akm-migrate.js +46946 -44755
  264. package/dist/setup/detect.js +28 -273
  265. package/dist/setup/endpoint.js +36 -0
  266. package/dist/setup/semantic-assets.js +13 -19
  267. package/dist/setup/setup-flags.js +77 -0
  268. package/dist/setup/setup-plan.js +144 -0
  269. package/dist/setup/setup.js +134 -358
  270. package/dist/setup/steps/connection-shared.js +49 -101
  271. package/dist/setup/steps/connection.js +121 -524
  272. package/dist/setup/steps/embeddings.js +151 -0
  273. package/dist/setup/steps/harnesses.js +118 -0
  274. package/dist/setup/steps/platforms.js +2 -81
  275. package/dist/setup/steps/tasks.js +1 -2
  276. package/dist/setup/steps.js +10 -0
  277. package/dist/setup/summary.js +67 -0
  278. package/dist/sources/freshness.js +16 -21
  279. package/dist/sources/providers/git-provider.js +2 -9
  280. package/dist/sources/providers/provider-utils.js +13 -5
  281. package/dist/sources/resolve.js +12 -16
  282. package/dist/sources/snapshot-fetchers/robots.js +11 -12
  283. package/dist/sources/snapshot-fetchers/secret-seam.js +2 -4
  284. package/dist/sources/snapshot-fetchers/website-ingest.js +8 -15
  285. package/dist/sources/snapshot-fetchers/x.js +1 -1
  286. package/dist/standalone/onnxruntime-library.js +52 -0
  287. package/dist/storage/repositories/improve-ledger-repository.js +1 -1
  288. package/dist/storage/repositories/improve-runs-repository.js +0 -13
  289. package/dist/storage/repositories/index-entries-repository.js +2 -2
  290. package/dist/storage/repositories/proposals-repository.js +2 -2
  291. package/dist/storage/repositories/task-history-repository.js +2 -2
  292. package/dist/storage/repositories/workflow-runs-repository.js +44 -129
  293. package/dist/storage/sqlite-read-snapshot.js +33 -29
  294. package/dist/tasks/embedded.js +1 -1
  295. package/dist/tasks/log-redaction.js +7 -119
  296. package/dist/tasks/prepare/prepare-support.js +8 -7
  297. package/dist/tasks/prepare/prepare.js +8 -9
  298. package/dist/tasks/prepare/script-capture.js +9 -25
  299. package/dist/tasks/run/attempt-lifecycle.js +17 -35
  300. package/dist/tasks/run/load-task.js +54 -27
  301. package/dist/tasks/run/run-command-task.js +15 -10
  302. package/dist/tasks/run/run-native-task.js +8 -21
  303. package/dist/tasks/run/run-task.js +5 -8
  304. package/dist/tasks/run/run-workflow-task.js +14 -21
  305. package/dist/tasks/run/task-history.js +9 -17
  306. package/dist/tasks/run/task-log.js +1 -5
  307. package/dist/tasks/scheduler-invocation.js +13 -18
  308. package/dist/tasks/scheduler-sync.js +0 -1
  309. package/dist/tasks/source/bounded-document.js +31 -117
  310. package/dist/tasks/source/parse-task-source.js +0 -1
  311. package/dist/tasks/source/project-v4.js +5 -3
  312. package/dist/tasks/source/task-input-diagnostics.js +3 -4
  313. package/dist/tasks/source/task-source-v4.js +48 -72
  314. package/dist/tasks/source-v3.js +2 -5
  315. package/dist/tasks/task-run-reserved-flags.js +1 -2
  316. package/dist/workflows/authoring/authoring.js +2 -7
  317. package/dist/workflows/compile.js +1 -15
  318. package/dist/workflows/concurrency-policy.js +4 -4
  319. package/dist/workflows/exec/child-workflow.js +1 -4
  320. package/dist/workflows/exec/dispatch-redaction.js +35 -86
  321. package/dist/workflows/exec/environment.js +13 -77
  322. package/dist/workflows/exec/exec-unit.js +14 -55
  323. package/dist/workflows/exec/frozen-judge.js +26 -28
  324. package/dist/workflows/exec/native-executor.js +126 -71
  325. package/dist/workflows/exec/run-workflow.js +38 -42
  326. package/dist/workflows/exec/step-work.js +13 -17
  327. package/dist/workflows/exec/unit-dispatch.js +7 -21
  328. package/dist/workflows/freeze/environment.js +14 -119
  329. package/dist/workflows/freeze/freeze.js +14 -33
  330. package/dist/workflows/freeze/step-values.js +6 -13
  331. package/dist/workflows/freeze/targets/child-workflow.js +3 -5
  332. package/dist/workflows/freeze/targets/command.js +9 -15
  333. package/dist/workflows/freeze/targets/shell.js +0 -3
  334. package/dist/workflows/freeze/task-bindings.js +0 -1
  335. package/dist/workflows/parser.js +50 -59
  336. package/dist/workflows/plan.js +8 -2
  337. package/dist/workflows/renderer.js +83 -9
  338. package/dist/workflows/resource-limits.js +2 -2
  339. package/dist/workflows/runtime/run-plan.js +38 -23
  340. package/dist/workflows/runtime/runs.js +55 -93
  341. package/dist/workflows/runtime/workflow-asset-loader.js +55 -86
  342. package/dist/workflows/source-files.js +7 -19
  343. package/docs/README.md +10 -16
  344. package/docs/architecture/README.md +2 -37
  345. package/docs/architecture/adapters.md +2 -2
  346. package/docs/architecture/akm-core-principles.md +256 -118
  347. package/docs/architecture/architecture.md +283 -99
  348. package/docs/architecture/improvement.md +8 -2
  349. package/docs/architecture/internals/classification.md +1 -3
  350. package/docs/architecture/internals/fresh-host-rebuild-runbook.md +7 -6
  351. package/docs/architecture/internals/health-advisories.md +35 -74
  352. package/docs/architecture/internals/improve-workflow.md +27 -26
  353. package/docs/architecture/internals/indexing.md +3 -3
  354. package/docs/architecture/internals/storage-locations.md +48 -15
  355. package/docs/architecture/persisted-data-compat.md +10 -6
  356. package/docs/architecture/specs/okf-support.md +9 -11
  357. package/docs/architecture/specs/ref.md +7 -9
  358. package/docs/architecture/testing/testing-workflow.md +172 -52
  359. package/docs/architecture/workflow-engine.md +51 -34
  360. package/docs/guides/README.md +0 -1
  361. package/docs/guides/author-bundles.md +15 -20
  362. package/docs/guides/author-workflows.md +93 -71
  363. package/docs/guides/bundles.md +20 -16
  364. package/docs/guides/discover-and-load.md +1 -1
  365. package/docs/guides/getting-started.md +49 -3
  366. package/docs/guides/improve-the-library.md +10 -4
  367. package/docs/guides/recipes/headless-install.md +11 -16
  368. package/docs/guides/run-workflows.md +29 -20
  369. package/docs/guides/scheduling.md +2 -2
  370. package/docs/guides/use-with-any-agent.md +20 -22
  371. package/docs/integration/bundling-akm.md +19 -9
  372. package/docs/maintainers/README.md +2 -6
  373. package/docs/maintainers/release-checklist.md +73 -126
  374. package/docs/migration/README.md +10 -3
  375. package/docs/migration/release-notes/0.10.0.md +81 -16
  376. package/docs/migration/release-notes/0.6.0.md +1 -1
  377. package/docs/migration/release-notes/0.7.0.md +1 -1
  378. package/docs/migration/release-notes/0.9.0.md +1 -1
  379. package/docs/migration/release-notes/README.md +1 -1
  380. package/docs/migration/v0.9-to-v0.10.md +300 -60
  381. package/docs/migration/v0.9.1-to-v0.9.2.md +6 -5
  382. package/docs/posts/config-v2-lessons-16.md +1 -1
  383. package/docs/posts/llm-mode-reflect-13.md +1 -1
  384. package/docs/posts/release-0.6.0.md +11 -11
  385. package/docs/posts/release-0.8.0.md +4 -4
  386. package/docs/posts/workflows-vaults-09.md +1 -1
  387. package/docs/reference/README.md +1 -1
  388. package/docs/reference/asset-types.md +2 -2
  389. package/docs/reference/cli.md +477 -388
  390. package/docs/reference/configuration.md +569 -550
  391. package/docs/reference/data-and-telemetry.md +9 -6
  392. package/docs/reference/env-and-secrets.md +72 -15
  393. package/docs/reference/refs.md +3 -20
  394. package/docs/reference/registry.md +12 -38
  395. package/docs/reference/supported-formats.md +1 -1
  396. package/docs/reference/tasks.md +22 -11
  397. package/docs/reference/ui-api.md +14 -9
  398. package/docs/reference/workflow-schema.md +199 -154
  399. package/docs/reference/workflows.md +4 -6
  400. package/package.json +9 -11
  401. package/schemas/akm-config.json +1696 -2922
  402. package/schemas/akm-task.json +4 -4
  403. package/schemas/akm-workflow.json +36 -9
  404. package/ROADMAP.md +0 -112
  405. package/dist/assets/models.json +0 -35
  406. package/dist/commands/health/engine-usage.js +0 -45
  407. package/dist/commands/sources/dangerous-env-audit.js +0 -134
  408. package/dist/core/activation-policy.js +0 -67
  409. package/dist/core/config/schema/engines.js +0 -160
  410. package/dist/core/config/schema/execution.js +0 -23
  411. package/dist/core/spawn-env.js +0 -268
  412. package/dist/execution/directory-identity.js +0 -78
  413. package/dist/integrations/agent/builder-shared.js +0 -33
  414. package/dist/integrations/agent/builders.js +0 -43
  415. package/dist/integrations/agent/engine-fallback.js +0 -59
  416. package/dist/integrations/agent/engine-resolution.js +0 -333
  417. package/dist/integrations/agent/model-map.js +0 -475
  418. package/dist/integrations/harnesses/aider/agent-builder.js +0 -107
  419. package/dist/integrations/harnesses/aider/result-extractor.js +0 -53
  420. package/dist/integrations/harnesses/amazonq/agent-builder.js +0 -138
  421. package/dist/integrations/harnesses/amazonq/result-extractor.js +0 -48
  422. package/dist/integrations/harnesses/claude/agent-builder.js +0 -106
  423. package/dist/integrations/harnesses/claude/config-import.js +0 -67
  424. package/dist/integrations/harnesses/claude/result-extractor.js +0 -67
  425. package/dist/integrations/harnesses/codex/agent-builder.js +0 -150
  426. package/dist/integrations/harnesses/codex/result-extractor.js +0 -110
  427. package/dist/integrations/harnesses/copilot/agent-builder.js +0 -117
  428. package/dist/integrations/harnesses/copilot/result-extractor.js +0 -178
  429. package/dist/integrations/harnesses/gemini/agent-builder.js +0 -114
  430. package/dist/integrations/harnesses/gemini/result-extractor.js +0 -149
  431. package/dist/integrations/harnesses/opencode/config-import.js +0 -149
  432. package/dist/integrations/harnesses/opencode/model-config.js +0 -33
  433. package/dist/integrations/harnesses/opencode/model-work-agent.js +0 -115
  434. package/dist/integrations/harnesses/opencode/session-log-types.js +0 -12
  435. package/dist/integrations/harnesses/opencode-sdk/index.js +0 -44
  436. package/dist/integrations/harnesses/opencode-sdk/sdk-runner.js +0 -1052
  437. package/dist/integrations/harnesses/opencode-sdk/v1-adapter.js +0 -199
  438. package/dist/integrations/harnesses/opencode-sdk/v2-adapter.js +0 -254
  439. package/dist/integrations/harnesses/opencode-sdk/wire.js +0 -66
  440. package/dist/integrations/harnesses/openhands/agent-builder.js +0 -120
  441. package/dist/integrations/harnesses/openhands/result-extractor.js +0 -135
  442. package/dist/integrations/harnesses/pi/agent-builder.js +0 -89
  443. package/dist/integrations/harnesses/pi/result-extractor.js +0 -168
  444. package/dist/integrations/harnesses/shared.js +0 -18
  445. package/dist/integrations/harnesses/types.js +0 -55
  446. package/dist/llm/feature-gate.js +0 -115
  447. package/dist/output/shapes/models-list.js +0 -16
  448. package/dist/output/shapes/registry-search.js +0 -10
  449. package/dist/setup/detected-engines.js +0 -136
  450. package/dist/setup/engine-config.js +0 -97
  451. package/dist/setup/harness-config-import.js +0 -47
  452. package/dist/setup/providers.js +0 -14
  453. package/dist/setup/steps/semantic.js +0 -39
  454. package/dist/workflows/authoring/scope-key.js +0 -79
  455. package/dist/workflows/exec/lowering-notices.js +0 -23
  456. package/dist/workflows/source-semantics.js +0 -110
  457. package/docs/architecture/0.10-process-rules.md +0 -832
  458. package/docs/architecture/akm-architecture-decision-history.md +0 -2055
  459. package/docs/architecture/comparisons/claude-code-vs-akm-workflows-full.md +0 -550
  460. package/docs/architecture/decisions/0001-no-interpolation-attached-structured-context.md +0 -72
  461. package/docs/architecture/decisions/0002-unit-reuse-and-input-hash-scope.md +0 -142
  462. package/docs/architecture/decisions/0003-child-env-allowlist-and-provenance.md +0 -189
  463. package/docs/architecture/decisions/0004-task-input-contract-and-flag-coercion.md +0 -97
  464. package/docs/architecture/decisions/0005-task-result-vocabulary-and-legacy-read-mapping.md +0 -108
  465. package/docs/architecture/decisions/0006-task-source-version-routing.md +0 -124
  466. package/docs/architecture/decisions/0007-workflow-composition-bounds.md +0 -83
  467. package/docs/architecture/decisions/0008-task-binding-normalization.md +0 -88
  468. package/docs/architecture/decisions/0009-child-run-publication-column-parity.md +0 -80
  469. package/docs/architecture/decisions/0010-driver-protocol-cut.md +0 -36
  470. package/docs/architecture/decisions/0011-engine-run-loop-invariants.md +0 -125
  471. package/docs/architecture/decisions/README.md +0 -62
  472. package/docs/architecture/internals/functional-contract-patterns.md +0 -340
  473. package/docs/architecture/internals/registry-network-boundary.md +0 -57
  474. package/docs/architecture/internals/search.md +0 -248
  475. package/docs/architecture/reviews/env-secret-access.md +0 -319
  476. package/docs/architecture/runtime-boundary-design.md +0 -153
  477. package/docs/architecture/specs/0.9.0-close-out-plan.md +0 -361
  478. package/docs/architecture/specs/0.9.0-decisions.md +0 -532
  479. package/docs/architecture/specs/0.9.0-docs-code-drift-register.md +0 -745
  480. package/docs/architecture/specs/0.9.0-open-items-register.md +0 -135
  481. package/docs/architecture/specs/0.9.0-public-api-issue-backlog.md +0 -740
  482. package/docs/architecture/specs/0.9.0-release-surface-review.md +0 -636
  483. package/docs/architecture/specs/agent-command-engine-model-design.md +0 -513
  484. package/docs/architecture/specs/akm-0.9.0-bundle-adapter-spec.md +0 -501
  485. package/docs/architecture/specs/akm-0.9.0-ref-grammar-decision.md +0 -291
  486. package/docs/architecture/specs/akm-format-neutral-bundle-workspace-spec.md +0 -2059
  487. package/docs/architecture/specs/di-seams-plan.md +0 -539
  488. package/docs/architecture/specs/driver-protocol-keep-or-cut.md +0 -275
  489. package/docs/architecture/specs/fact-asset-type.md +0 -142
  490. package/docs/architecture/specs/improve-collapse-churn-detector-design.md +0 -634
  491. package/docs/architecture/specs/reviews/task-workflow-unification/README.md +0 -72
  492. package/docs/architecture/specs/reviews/task-workflow-unification/findings-consolidated.md +0 -152
  493. package/docs/architecture/specs/reviews/task-workflow-unification/library-eval-alternatives.md +0 -352
  494. package/docs/architecture/specs/reviews/task-workflow-unification/library-eval-bunqueue.md +0 -300
  495. package/docs/architecture/specs/reviews/task-workflow-unification/library-eval-openworkflow.md +0 -402
  496. package/docs/architecture/specs/reviews/task-workflow-unification/opus-review-1.md +0 -758
  497. package/docs/architecture/specs/reviews/task-workflow-unification/opus-review-2.md +0 -645
  498. package/docs/architecture/specs/reviews/task-workflow-unification/opus-review-3.md +0 -602
  499. package/docs/architecture/specs/reviews/task-workflow-unification/panel-r1-adversarial.md +0 -27
  500. package/docs/architecture/specs/reviews/task-workflow-unification/panel-r1-architecture.md +0 -27
  501. package/docs/architecture/specs/reviews/task-workflow-unification/panel-r1-coverage.md +0 -74
  502. package/docs/architecture/specs/reviews/task-workflow-unification/panel-r1-security.md +0 -15
  503. package/docs/architecture/specs/reviews/task-workflow-unification/panel-r2-adversarial.md +0 -132
  504. package/docs/architecture/specs/reviews/task-workflow-unification/panel-r2-verification.md +0 -147
  505. package/docs/architecture/specs/stash-conventions-code-spec.md +0 -275
  506. package/docs/architecture/specs/stash-organization-conventions.md +0 -377
  507. package/docs/architecture/specs/task-workflow-format-unification.md +0 -721
  508. package/docs/architecture/specs/workflow-engine-buy-vs-build.md +0 -231
  509. package/docs/architecture/specs/workflow-format-unification.md +0 -432
  510. package/docs/architecture/testing/manual-testing-checklist.md +0 -3411
  511. package/docs/architecture/testing/okf-v0.2-conformance-runbook.md +0 -924
  512. package/docs/architecture/testing/task-workflow-manual-tests.md +0 -1720
  513. package/docs/guides/claude-code-vs-akm-workflows.md +0 -29
  514. package/docs/guides/knowledge-management.md +0 -18
  515. package/docs/maintainers/curate-workmap.md +0 -335
  516. package/docs/migration/v0.5-to-v0.6.md +0 -759
  517. package/docs/migration/v0.7-to-v0.8.md +0 -1378
  518. package/docs/plans/0.9.2-agent-command-workflow-plan.md +0 -423
@@ -1,319 +0,0 @@
1
- # Architecture Review: Runtime secret resolution for in-process source fetchers
2
-
3
- **Repo:** `/home/user/akm` (read-only review)
4
- **Subject:** How the X snapshot fetcher (`src/sources/snapshot-fetchers/x.ts`) — and, more generally, the provider `sync()` / bundle-update path — should read a bearer token from akm's secret store at runtime, given a ref like `secrets/x-bearer-token`, without (a) leaking the value into agent/LLM/log context or (b) forming a static or dynamic import cycle.
5
- **Date:** 2026-08-02
6
-
7
- ---
8
-
9
- ## 1. Executive summary
10
-
11
- The root cause is a **Dependency Inversion violation**: the secret-store reader (`src/core/env-secret-ref.ts`) transitively imports the entire source-provider → fetcher-registry → fetcher subgraph (via `indexer/search/search-source.ts`), so any module inside that subgraph that reaches back to the store closes an import cycle the repo's ratchet forbids. The already-shipped fix is the right shape — a `resolveSecret?: (ref) => string | null` capability injected onto `FetcherContext` from callers positioned *above* the cycle (`src/sources/snapshot-fetchers/types.ts:43`) — but it is only wired in from the two command-layer entry points, leaving the provider-registry `sync()` / bundle-update path (`src/sources/providers/website.ts:26-32`) environment-variable-only. The recommended solution is to **formalize that existing seam as a first-class `SecretResolver` capability and thread it through the `sync()` path the same way it is already threaded through the `fetch()` path** — construct it once in `secret-seam.ts` (the sole sanctioned `env-secret-ref` importer, already outside the cycle) and pass it as data through `ensureSourceCaches → provider.sync → ensureWebsiteMirror`. This extends the shipped idiom rather than inventing a parallel one, adds no `env-secret-ref` import inside the cycle, and preserves the `secret run` value-containment discipline (same-frame header set, never returned upward, swallow-to-null).
12
-
13
- ---
14
-
15
- ## 2. Current architecture
16
-
17
- ### 2.1 How a ref resolves to a value
18
-
19
- A "ref" (`secrets/x-bearer-token`, `env/FOO`) is resolved to an **absolute path** — never to bytes — inside `src/core/env-secret-ref.ts`:
20
-
21
- 1. `parseSecretRef` / `parseEnvRef` parse the ref into an `AssetRef` (`{type, name, origin}`); bare names auto-qualify to `env/` or `secrets/`, and legacy `vault:` / colon spellings are rejected loudly, not translated. (`src/core/env-secret-ref.ts:75-153`)
22
- 2. `findEnvSource` locates which configured bundle source holds the ref by `fs.existsSync` probing candidate source paths, using `resolveSourceEntries(undefined, loadConfig())` + `resolveSourcesForOrigin`. (`src/core/env-secret-ref.ts:85-106`)
23
- 3. `resolveSecretPath` / `resolveEnvPath` compute the absolute path via `assetPathForName` + an `isWithin` traversal guard and return `{name, absPath, source}` only — they never open the file. (`src/core/env-secret-ref.ts:121-145,168-195`)
24
-
25
- The **only** place raw secret bytes are read is `readValue` (`src/commands/env/secret.ts:102-108`), an `fs.readFileSync` wrapper with a documented no-log / no-stdout contract; `loadEnv` (`src/commands/env/env.ts:89-100`) is the analogous whole-file reader for `.env`.
26
-
27
- For fetchers specifically, the read path is `resolveSecretFromStore(ref)` in `src/sources/snapshot-fetchers/secret-seam.ts:23-31`: it calls `resolveSecretPath`, `fs.existsSync`, `fs.readFileSync(...).trim()`, and returns `null` for *any* failure — the underlying error (which can embed filesystem paths) is deliberately swallowed.
28
-
29
- ### 2.2 How values are kept out of context
30
-
31
- akm keeps secret/env values out of agent/LLM/log surfaces with two layers:
32
-
33
- - **Structural boundary.** The only sanctioned "use the value" path is `secret run`, which reads the file and injects it as `$VAR` into a `spawnSync` child's env — the read string never appears in a return value, in `output()`, or in the audit event (`src/commands/env/secret-cli.ts:213-231`; the `secret_access` event records ref + var name only, "never the value", `:221-226`). `env run` does the identical thing for whole `.env` files (`src/commands/env/env-cli.ts:280-301`). `env export` is the one path that writes a raw value, to a mode-`0600` file, never stdout (`src/commands/env/env-cli.ts:211-237`). `format-exempt.ts:53-67` formally classifies these as non-envelope commands so `--format` can't leak a value.
34
- - **Defense-in-depth scrubber.** `src/core/redaction.ts` provides `collectSensitiveValues` / `redactSensitiveText` / `redactSensitiveValue` (`:193-398`) plus a pattern-based `redactCredentialPatterns` (`:307-341`, catches `Bearer` tokens, `sk-`/`key-` keys) invoked at every real output boundary — LLM error bodies (`src/llm/client.ts`), workflow reports (`src/workflows/exec/report.ts`), agent dispatch (`src/integrations/agent/runner-dispatch.ts`), proposal/improve output.
35
-
36
- Today `x.ts` obeys the structural rule: `resolveXBearerToken` (`src/sources/snapshot-fetchers/x.ts:79-87`) returns the token to `fetch()`, which passes it straight into an `Authorization: Bearer` header inside `xApiJson`'s call frame (`x.ts:111-118`) and never onto a `FetcherContext` field, a `WikiSnapshotResult`, or an event.
37
-
38
- ### 2.3 The import cycle
39
-
40
- ```
41
- src/core/env-secret-ref.ts
42
- │ import { resolveSourceEntries } (env-secret-ref.ts:18)
43
- ▼
44
- src/indexer/search/search-source.ts
45
- │ import { resolveSourceProviderFactory } (search-source.ts:13)
46
- │ import "../../sources/providers/index" (search-source.ts:16, side-effect)
47
- ▼
48
- src/sources/providers/index.ts
49
- │ imports ./website (and ./filesystem, ./git-provider, ./npm)
50
- ▼
51
- src/sources/providers/website.ts
52
- │ import { ensureWebsiteMirror } from ../snapshot-fetchers/website-ingest
53
- ▼
54
- src/sources/snapshot-fetchers/website-ingest.ts
55
- │ import { loadWikiSnapshotFetchers } from ./registry
56
- ▼
57
- src/sources/snapshot-fetchers/registry.ts ──▶ x.ts, rss.ts, … (the fetchers)
58
-
59
- ╭──────────────────── THE FORBIDDEN BACK-EDGE ────────────────────╮
60
- │ If x.ts (or website.ts) imports core/env-secret-ref — directly, │
61
- │ or via secret-seam.ts, or via a dynamic import() — the arrow │
62
- │ closes back to the top and the cycle-ratchet rejects it. │
63
- ╰──────────────────────────────────────────────────────────────────╯
64
- ```
65
-
66
- `origin-resolve.ts` (`src/registry/origin-resolve.ts:5-9`) and `mutation-target.ts` (`src/core/mutation-target.ts:5-11`), both imported by `env-secret-ref.ts`, also reach `search-source.ts` — they reinforce the same vector rather than adding a second one. The pure helpers `env-secret-ref` imports (`config/config.ts`, `asset/*`) carry no provider/fetcher edges and are not part of the cycle.
67
-
68
- ---
69
-
70
- ## 3. Why it's hard
71
-
72
- ### 3.1 The precise SOLID violation
73
-
74
- `core/env-secret-ref.ts` is a low-level detail (how akm reads a secret file) that has been made to **depend on** a high-level policy module graph (the whole source-resolution / provider / fetcher subsystem) through the single edge at `env-secret-ref.ts:18`. A fetcher (`x.ts`) is a high-level consumer whose policy is "authorize this outbound request." Because the concrete store sits *upstream* of the fetcher in the import graph, the fetcher cannot depend on the concrete store without a cycle. This is a textbook **DIP** situation: the fix must make both the consumer and the store depend on an **abstraction** (a leaf type), with the concrete store **injected** from a composition root above the cycle.
75
-
76
- ### 3.2 Why each naive fix fails
77
-
78
- | Attempt | Why it fails |
79
- |---|---|
80
- | **Static import** of `env-secret-ref` from `x.ts` | Closes the back-edge directly. Ratchet rejects. |
81
- | **Lazy `import()`** of `env-secret-ref` (or `secret-seam`) from inside the cycle | Same cycle; the ratchet treats dynamic `import()` as **"cycle-laundering"** and rejects it too. (`x.ts:73-74` documents this.) |
82
- | **Relocated reader module** | Moving the reader still leaves a module *inside* the subgraph importing something that transitively reaches `env-secret-ref` — the *importer edge* is what closes the cycle, so relocation-without-severing keeps the back-edge. |
83
- | **Shipped `FetcherContext.resolveSecret` seam** (`types.ts:43`) | Architecturally correct — injected, not imported. But populated **only** by the two command-layer callers (`src/commands/read/knowledge.ts:145`, `src/commands/sources/source-add.ts:173`) via `resolveSecretFromStore`. |
84
-
85
- ### 3.3 The `sync()` gap
86
-
87
- The provider-registry refresh path never populates the seam. `website.ts`'s registered factory closure calls `ensureWebsiteMirror(config, { requireStashDir, force, ...allowPrivateHosts })` with **no `resolveSecret` key** (`src/sources/providers/website.ts:26-32`), and structurally *cannot* import one: `website.ts` is itself inside the cycle. The full downstream plumbing already exists — `ensureWebsiteMirror` → `scrapeWebsiteToStash` → `fetchSnapshotViaRegistry` → `FetcherContext.resolveSecret` all thread an optional `resolveSecret` (`website-ingest.ts:194-233,273-290,374-385`) — the *only* missing piece is that nothing inside the providers/registry subgraph can construct or receive a real resolver to hand in as that option's value. `ensureSourceCaches` calls `provider.sync({ force })` with no secret parameter (`search-source.ts:383`), and its sole materializing caller `indexer.ts:688-689` passes only `{ force, materialize }`. So the bundle-update path is `X_BEARER_TOKEN`-env-only.
88
-
89
- ---
90
-
91
- ## 4. Options considered
92
-
93
- Four proposals were developed and adversarially critiqued. All four break the cycle correctly against the real edge list; they differ on idiom-fit, blast radius, and risk. Critic ranking: **P4 > P2 > P3 > P1**.
94
-
95
- ### 4.1 Proposal 1 — Secret-resolver runtime-registration port (service locator)
96
-
97
- A zero-import leaf `src/core/secret-resolver-port.ts` holds a single registrable `SecretResolver` slot; a registration module (importing `secret-seam`) self-registers it, side-effect-imported from `cli.ts`; in-cycle consumers call `resolveRegisteredSecret(ref)`.
98
-
99
- - **SOLID:** DIP inversion is real; SRP clean. But it introduces a **global mutable singleton / service locator** — an ambient dependency invisible in signatures — which is *not* a house idiom (akm uses context-object injection, not service location). Creates **two parallel seams** for one capability, which the subsystem map explicitly warned against.
100
- - **Critic verdict: VIABLE, score 5 (lowest).** The "mirrors `registerSourceProvider`" framing is misleading: `registerSourceProvider` is safe because `search-source.ts` *eagerly* side-effect-imports `providers/index`, guaranteeing registration before any `sync()`. P1's registration module imports `env-secret-ref`, so `search-source` **cannot** import it — registration hangs off `cli.ts` alone with **no load-order guarantee**. Any entry that reaches `ensureSourceCaches` without going through `cli.ts` (tests, library embedding, a second binary, a workflow executor importing `search-source` directly) silently degrades to env-var-only. Requires a test-reset hook to avoid cross-test leakage.
101
-
102
- ### 4.2 Proposal 2 — `CredentialProvider` capability (opaque, replaces the field)
103
-
104
- A pure-type leaf `src/sources/credential-provider.ts` defines `CredentialProvider { has(ref): boolean; authorizeBearer(ref, headers): void }` and `SourceProviderContext { credentials? }`. `FetcherContext.resolveSecret` is **replaced** by `credentials?`; `SourceProviderFactory` gains a 2nd `context?` arg; the value is injected from above.
105
-
106
- - **SOLID:** Strongest value-containment of the four — `authorizeBearer` returns `void`, `has` returns `boolean`, so **there is no value to return upward**; the token never enters consumer scope as a standalone variable. Clean ISP (two focused methods) and DIP. **But** it deliberately violates the map's "extend not replace / reuse the field name" guidance: it renames the shipped field and changes factory arity, forcing lockstep migration of `x.ts`, `website-ingest` plumbing, two command sites, and all test doubles.
107
- - **Critic verdict: VIABLE, score 7.** Compiles; cycle-break is real (leaf type is a graph sink). Principled long-term target *if* a breaking contract change is ever acceptable — today the replace-the-field churn is unjustified when P4 reaches the same consumers additively.
108
-
109
- ### 4.3 Proposal 3 — Leaf secret-read module with a provider-free enumerator
110
-
111
- Split `env-secret-ref.ts` into a WRITE module and a new **leaf** `src/core/env-secret-read.ts` whose source enumeration (`secretSourceRoots`) is rebuilt from `bundlesToSourceEntries` + `lockContentRootFor` + `resolveStashDir` instead of `resolveSourceEntries` — **deleting** the `env-secret-ref → search-source` edge entirely.
112
-
113
- - **SOLID:** Best SRP (separates read-resolution from write/mutation) and the only proposal that *removes* the load-bearing edge rather than routing a value around it. Verified the leaf's dependency set (`config/config`, `integrations/lockfile`, `core/common`, `asset-placement`, `resolve-ref`) has zero path to `search-source` or the providers subgraph. This is genuinely *not* the failed relocated-reader attempt, because it deletes the `resolveSourceEntries` call rather than moving it.
114
- - **Critic verdict: VIABLE, score 6.** The decisive risk is an **OCP smell / second source-of-truth**: `secretSourceRoots` reimplements a slice of `resolveSourceEntries`, drops `deriveInstallations` origin matching (registryId-equality only), drops the `provider.path()` fallback for legacy/unlocked git-npm bundles, and skips website caches — so it can silently resolve a **different file** than the CLI would. That is exactly the resolver-mismatch class that got `secret path` / `secret remove` amputated (R-027 / D-49). Only safe if `secretSourceRoots` delegates to a shared lock-first helper also used by `resolveEntryContentDir`. Keep as a **future** structural cleanup, not the primary fix.
115
-
116
- ### 4.4 Proposal 4 — Threaded `SecretResolver` capability (recommended)
117
-
118
- Promote the ad-hoc `resolveSecret?:(ref)=>string|null` into a first-class `SecretResolver` object, constructed once in `secret-seam.ts` (the sole sanctioned `env-secret-ref` importer, already outside the cycle) and threaded as an explicit **call-time parameter** through the `sync()` path (`ensureSourceCaches → provider.sync options → website.ts`) exactly as it is already threaded through the `fetch()` path. Closes the gap with **no registry, no dynamic import, no reader relocation, no new global**, and **extends** the shipped seam rather than replacing it.
119
-
120
- - **SOLID:** SRP — the capability has one responsibility (`ref → value | null`); `secret-seam.ts` stays the single place that knows about `env-secret-ref`. OCP — a future provider kind (private git remote, authed npm registry) reads `options.secrets` in its own `sync()` with zero contract change. LSP — every `SecretResolver` substitute (store-backed, env-only stub, fixed-token fake) is interchangeable; `secrets?` stays optional (absent = documented env-var-only). ISP — single-method interface. DIP — this is the crux and the mechanism: in-cycle modules (`search-source`, `website.ts`, `x.ts`) depend on the `SecretResolver` **abstraction** (a leaf type in `provider.ts`), and the concrete binding is injected from composition roots above the cycle.
121
- - **Critic verdict: RECOMMEND, score 8 (highest).** Compiles, cycle-break is real: `SecretResolver` goes in `src/sources/provider.ts`, a verified graph **sink** (it imports only type-only `config/config` and `sources/types`), so `search-source`/`website` importing a type creates no runtime back-edge; the concrete `storeSecretResolver` lives in `secret-seam.ts` (imported by nothing in the subgraph) and reaches `website.ts` as **plain data** on the sync options object handed down from `indexer.ts` (confirmed above the cycle). Value containment matches the `secret-cli.ts` bar.
122
- - **One real weakness:** the `secrets` option is optional and *not* compiler-enforced, so a future call site that forgets to forward it silently degrades to env-var-only — the same failure class that produced today's gap, closed here but not eliminated for future callers. (Mitigated by the hybrid grafts below.)
123
-
124
- ---
125
-
126
- ## 5. Recommendation
127
-
128
- **Adopt Proposal 4 (Threaded `SecretResolver` capability), with two cheap hardening grafts.** It is the minimal, additive, idiom-faithful fix: it extends the already-shipped `FetcherContext.resolveSecret` capability-injection seam down the `sync()` path instead of inventing a parallel mechanism, reaches both fetchers **and** provider `sync()`, and keeps the ratchet green because no `env-secret-ref` import lands inside the providers/registry/fetchers subgraph.
129
-
130
- ### 5.1 The abstraction (leaf type, a graph sink)
131
-
132
- In `src/sources/provider.ts` (alongside `SourceProvider`; this module imports only type-only `config/config` and `sources/types`, so it stays a sink):
133
-
134
- ```ts
135
- export interface SecretResolver {
136
- /** Resolve a store ref → value or null. Never logs, never throws upward. */
137
- resolveSecret(ref: string): string | null;
138
- }
139
-
140
- export interface SyncOptions {
141
- force?: boolean;
142
- secrets?: SecretResolver;
143
- }
144
-
145
- export interface SourceProvider {
146
- readonly name: string;
147
- readonly kind: SourceKind;
148
- path(): string;
149
- sync?(options?: SyncOptions): Promise<void>; // was: sync?(options?: { force?: boolean })
150
- }
151
- ```
152
-
153
- `SourceProviderFactory` is unchanged (`(config: SourceConfigEntry) => SourceProvider`) — no factory arity change, unlike P2.
154
-
155
- ### 5.2 The single composition root (already outside the cycle)
156
-
157
- In `src/sources/snapshot-fetchers/secret-seam.ts` (already the ONLY module importing `core/env-secret-ref`, and imported by nothing in the providers/registry/fetchers subgraph — verified: only `commands/read/knowledge.ts` and `commands/sources/source-add.ts` import it today):
158
-
159
- ```ts
160
- export const storeSecretResolver: SecretResolver = { resolveSecret: resolveSecretFromStore };
161
- ```
162
-
163
- **Graft (a) — belt-and-suspenders containment (from P2/`llm/client.ts`):** have this resolver register any resolved token into `redactSensitiveText` / `redactSensitiveValue`'s `sensitiveValues` set (`src/core/redaction.ts:193-398`), so that if a request-header ever reaches a serialized error/log surface the token is scrubbed. The structural never-returned-upward guarantee holds independently; this covers the residual transient `headers.Authorization` exposure that all four proposals share.
164
-
165
- ### 5.3 Threading through the `sync()` path (data, not imports)
166
-
167
- `src/indexer/search/search-source.ts` — import the **type only**:
168
-
169
- ```ts
170
- export async function ensureSourceCaches(
171
- config?: AkmConfig,
172
- options?: { force?: boolean; materialize?: boolean; secrets?: SecretResolver },
173
- ): Promise<void> {
174
- // …
175
- await provider.sync({ force, secrets: options?.secrets }); // was: provider.sync({ force }) (search-source.ts:383)
176
- }
177
- ```
178
-
179
- `src/sources/providers/website.ts` sync() — the one missing line (imports the `SecretResolver` **type** only; the resolver arrives as data):
180
-
181
- ```ts
182
- async sync(options?: SyncOptions) {
183
- await ensureWebsiteMirror(config, {
184
- requireStashDir: true,
185
- force: options?.force,
186
- resolveSecret: options?.secrets?.resolveSecret, // ← closes the gap; feeds the EXISTING plumbing
187
- ...(allowPrivateHosts ? { allowPrivateHosts: true } : {}),
188
- });
189
- }
190
- ```
191
-
192
- `FetcherContext.resolveSecret` (`types.ts:43`) and the entire `website-ingest.ts` `resolveSecret` plumbing (`:194-233,273-290,374-385`) are **unchanged** — the capability's `.resolveSecret` method feeds the existing field.
193
-
194
- ### 5.4 Wiring at the entry surfaces (all verified above the cycle)
195
-
196
- - `src/indexer/indexer.ts:688-689` (full-index / hydrate — the env-var-only path today): pass `secrets: storeSecretResolver` into the existing `ensureSourceCaches(config, { force: full, materialize: …, secrets: storeSecretResolver })`. This is the step that actually closes the `sync()` gap. (`indexer.ts` reaches `search-source` via dynamic `import(...)`, confirming it is above the cycle.)
197
- - `src/commands/sources/source-add.ts:173` and `src/commands/read/knowledge.ts:145`: optionally normalize the inline `resolveSecret: resolveSecretFromStore` to `resolveSecret: storeSecretResolver.resolveSecret` — behavior-identical; leaving them untouched still compiles.
198
-
199
- ### 5.5 How it serves fetchers AND provider `sync()`
200
-
201
- - **Fetchers:** `x.ts` continues to read `context.resolveSecret` via `resolveXBearerToken` (`x.ts:79-87`) — no change to the fetcher. The value now arrives on the `sync()` path too, so `secrets/x-bearer-token` resolves during bundle update, not just from command-layer URL ingest.
202
- - **Provider `sync()`:** any provider kind that later needs credentials reads `options.secrets` in its own `sync()` — the seam is on the shared `SourceProvider`/`SyncOptions` contract, so it generalizes beyond `website.ts`'s previously-ad-hoc plumbing.
203
-
204
- **Graft (b) — anti-regression lint:** add a boundary lint (precedent: `scripts/lint-runtime-boundary.ts`, `scripts/lint-write-source-chokepoint.ts`) asserting that `materialize=true` callers of `ensureSourceCaches` supply a `SecretResolver`, neutralizing P4's one weakness (the optional, non-compiler-enforced threading).
205
-
206
- ---
207
-
208
- ## 6. Migration plan (each step keeps the ratchet green; each is independently provable)
209
-
210
- 1. **Add the leaf abstraction.** Add `SecretResolver` + `SyncOptions` to `src/sources/provider.ts` and widen `sync?()` to `SyncOptions`. Type-only, no behavior change — all four provider kinds' `sync` bodies still typecheck.
211
- *Proves:* `tsc`/build green; import-cycle ratchet green (no new runtime edge; `provider.ts` remains a sink).
212
- 2. **Add the composition root.** Add `export const storeSecretResolver` to `secret-seam.ts`. Include graft (a): register resolved tokens into `redactSensitiveText`'s `sensitiveValues`.
213
- *Proves:* unit test that `storeSecretResolver.resolveSecret("secrets/x-bearer-token")` returns the file value for a fixture store and `null` on missing/unreadable; a redaction test asserting the token is scrubbed from a synthesized header-bearing error string.
214
- 3. **Thread the option through `ensureSourceCaches`.** Add `secrets?: SecretResolver` to its options and forward it into `provider.sync(...)` (`search-source.ts:383`). Type-only import of `SecretResolver`.
215
- *Proves:* ratchet green (no `env-secret-ref` import added to the subgraph); existing `ensureSourceCaches` tests unchanged (option is optional).
216
- 4. **Populate `website.ts` sync().** Add `resolveSecret: options?.secrets?.resolveSecret` to the `ensureWebsiteMirror` call. Type-only import.
217
- *Proves:* ratchet green; a website-provider `sync()` test with a stub `SecretResolver` asserts the stub is invoked with `secrets/x-bearer-token` (previously never called).
218
- 5. **Wire the entry surface.** Pass `secrets: storeSecretResolver` at `indexer.ts:688-689`.
219
- *Proves:* integration test — run bundle update / full index on a website source whose X fetcher needs `secrets/x-bearer-token` with `X_BEARER_TOKEN` **unset**; assert the store value is used (previously env-only), AND assert the token never appears in `output()`, in `appendEvent`/`logs.db`, or in any structured surface.
220
- 6. **Normalize command call sites (optional, cosmetic).** Swap `source-add.ts:173` / `knowledge.ts:145` to `storeSecretResolver.resolveSecret`.
221
- *Proves:* existing command-layer fetcher tests remain green (behavior-identical).
222
- 7. **Add the anti-regression lint (graft b).** Assert `materialize=true` callers of `ensureSourceCaches` pass a `SecretResolver`.
223
- *Proves:* the lint fails on a deliberately-omitted call site and passes on the wired one.
224
-
225
- Each step is additive and green in isolation, so the cycle ratchet never goes red and the change can land incrementally.
226
-
227
- ---
228
-
229
- ## 7. Risks and non-goals
230
-
231
- **Risks**
232
-
233
- - **Optional-threading regression (accepted, mitigated).** `secrets?` is optional and not compiler-enforced; a future `ensureSourceCaches`/`provider.sync` call site that forgets it silently reverts to env-var-only — the exact failure class being fixed, relocated to "did every caller pass it?". Graft (b)'s lint is the guard.
234
- - **New value-materialization location.** The bundle-update / `sync()` path now reads a secret into memory where it previously did not. It stays confined to the `fetch()` call frame (`x.ts:111-118`), but it is a new location to audit against the never-in-context bar; graft (a) covers the residual serialized-header case.
235
- - **Shared-contract widening.** `SourceProvider.sync`'s option type widens for a concern only `website` needs today. This is intentional future-proofing (OCP), and all existing `sync` bodies still typecheck, but it does touch a semi-public interface.
236
- - **Underlying coupling remains.** P4 does **not** delete the `env-secret-ref → search-source` edge; it only guarantees the store stays on the outer side of it. The architectural smell (the store resolver transitively importing the whole source-resolution machinery) persists — see non-goals.
237
-
238
- **Non-goals**
239
-
240
- - **No new command surface / return path.** Do not add an `x-bearer-token path`-style command; the precedent (`secret path` / `secret remove` removal, R-027 / D-49) is that akm removes a surface rather than risk a resolver mismatch or accidental exposure.
241
- - **Do not rely on `--format` / `output()` exemption as the safety mechanism.** The new path must be structurally value-free on its own (same-frame header set, never returned upward), not depend on CLI-level formatting exemptions.
242
- - **Do not ship Proposal 3's independent enumerator now.** Deleting the `env-secret-ref → search-source` edge (P3) is the correct *eventual* structural cleanup, but only if `secretSourceRoots` **delegates to a shared lock-first helper** also used by `resolveEntryContentDir`; the as-written second-source-of-truth reintroduces the resolver-mismatch class that already cost `secret path` / `secret remove`. Track it as a separate, later refactor. **Update (issue #744): that condition was tested and cannot be met today — see §8 for the measurements and the single blocking edge.**
243
- - **Do not adopt Proposal 2's breaking field rename now.** The opaque `CredentialProvider` (void/boolean methods, strongest containment) is the principled long-term target if a breaking contract change ever becomes acceptable; today its lockstep churn is unjustified when P4 reaches the same consumers additively.
244
-
245
- ---
246
-
247
- ## 8. P3 feasibility re-assessment (issue #744, 2026-08-12) — BLOCKED on one edge
248
-
249
- §7 defers P3 with a condition: it may land "only if `secretSourceRoots` **delegates to a shared lock-first helper** also used by `resolveEntryContentDir`." That condition was tested directly. **It cannot be met today.** The blocker is a single import edge, named at the end of this section; P3 should stay deferred until that edge is severed.
250
-
251
- ### 8.1 What was built and measured
252
-
253
- The strongest possible reading of the §7 condition was implemented as a probe: rather than write a *new* `secretSourceRoots` that "delegates to" a shared helper, `SearchSource`, `resolveSourceEntries` and `resolveEntryContentDir` were moved **verbatim** out of `indexer/search/search-source.ts` into a candidate leaf module, so the reader and the indexer would call the *same function object* — one resolver by construction, not two that agree by convention. That is strictly better than the proposal's sketch and removes any second-source-of-truth argument.
254
-
255
- It still fails, for a reason the original critique did not reach.
256
-
257
- ### 8.2 Finding 1 — the "lock-first helper" is lock-first but **provider-second**, and the second half is load-bearing
258
-
259
- `lockContentRootFor` (`src/integrations/lockfile.ts:169-177`) answers **only** for `git`/`npm` bundles that carry a lock `localRoot`; its first line returns `undefined` for every other kind by construction:
260
-
261
- ```ts
262
- if (!bundleId || (type !== "git" && type !== "npm")) return undefined;
263
- ```
264
-
265
- So for a **filesystem** bundle (the primary bundle — where `secrets/` actually live), a **website** cache, and a **legacy/unlocked git** bundle, the content root comes exclusively from the second half of `resolveEntryContentDir`: `resolveSourceProviderFactory(entry.type)` → `factory(entry)` → `provider.path()`. Exactly the three cases the issue's acceptance criteria demand be pinned.
266
-
267
- And that second half is not an implementation detail to route around — it is the repo's *declared* single source of truth (`search-source.ts:161-166`): "each provider owns its own path… This replaces the old per-kind switch ladder (filesystem path / git cache / website cache) that lived here in 0.6.0." Any leaf resolver that derives those paths itself reintroduces the ladder 0.6.0 deleted.
268
-
269
- ### 8.3 Finding 2 — a leaf cannot populate the provider registry, and a half-populated registry mis-resolves **silently**
270
-
271
- The registry is populated by one eager side-effect import, `search-source.ts:16` (`import "../../sources/providers/index"`). A leaf reader structurally cannot perform it: `providers/index → website.ts → website-ingest.ts → snapshot-fetchers/registry.ts → x.ts` is the fetcher subgraph, and pulling it in is the very coupling P3 exists to delete.
272
-
273
- Measured against a fixture config holding all five shapes (filesystem primary, lock-managed git, **legacy/unlocked git**, **website cache**, lock-managed npm), same config, two processes:
274
-
275
- | bundle | via `search-source` (registered) | via the leaf (not registered) |
276
- |---|---|---|
277
- | `primary` (filesystem) | `…/fixture/primary-stash` | `…/.akm/unresolved-sources/primary` ❌ |
278
- | `locked-git` | `…/installs/locked-git/content` | same ✅ (lock-first) |
279
- | `legacy-git` | `…/cache/registry-index/git-07aa…/repo` | same ✅ *(by accident — see below)* |
280
- | `site-cache` (website) | `…/cache/registry-index/website-de10…` | `…/.akm/unresolved-sources/site-cache` ❌ |
281
- | `locked-npm` | `…/installs/locked-npm` | same ✅ (lock-first) |
282
-
283
- End to end, with the secret genuinely present in the primary bundle:
284
-
285
- - `resolveSecretPath("secrets/x-bearer-token")` today → `…/fixture/primary-stash/secrets/x-bearer-token`
286
- - the same logic on the leaf enumerator → `…/.akm/unresolved-sources/primary/secrets/x-bearer-token`
287
-
288
- **A different file, no error, no warning** — `findEnvSource` falls back to `candidates[0]` when its `existsSync` probe finds nothing, and `resolveSecretFromStore` swallows every failure to `null`. This is precisely the resolver-mismatch class that cost `secret path` / `secret remove` (R-027 / D-49).
289
-
290
- Worse than a clean failure: registration is **partial and accidental**. In the leaf's import closure `git` *is* registered — not deliberately, but because `core/write-source.ts` happens to import `sources/providers/git.ts`. So the leaf resolves git correctly and filesystem/website incorrectly, and which kinds work depends on which unrelated modules got pulled in. A resolver whose correctness varies by transitive import order is the worst available property.
291
-
292
- ### 8.4 Finding 3 — all three escapes are closed
293
-
294
- | Escape | Result |
295
- |---|---|
296
- | (a) Derive filesystem/website/git roots in the leaf | Reinstates the per-kind switch ladder deleted in 0.6.0 — the second source of truth §7 forbids. |
297
- | (b) Side-effect-import `providers/index` from the leaf | Measured: **7 cycle participants** (`env-secret-read`, `source-entries`, `providers/index`, `website`, `website-ingest`, `snapshot-fetchers/registry`, `x`) against an **absolute 0 baseline**. This is the subgraph coming back through another door. |
298
- | (c) Rely on ambient registration order | §4.1's rejected P1 flaw, with a worse failure mode: P1 degraded to env-var-only, this resolves a *different file*. Making it loud needs either a hardcoded four-kind list (new duplicated truth) or turning `resolveEntryContentDir`'s deliberately-soft `undefined` degradation — which the indexer relies on to keep running past a bad source — into a throw. |
299
-
300
- ### 8.5 The one blocking edge, and the prerequisite
301
-
302
- The single edge that makes `providers/index` unimportable from a leaf is:
303
-
304
- ```
305
- src/sources/providers/website.ts ──▶ src/sources/snapshot-fetchers/website-ingest.ts
306
- ```
307
-
308
- `website.ts` needs `getWebsiteCachePaths` / `validateWebsiteUrl` / `shouldAllowPrivateWebsiteUrlForTests` for `path()`, and `ensureWebsiteMirror` for `sync()`. The other three providers are already subgraph-free (`filesystem.ts`, `git.ts`, `npm.ts`).
309
-
310
- Re-running the P3 graph with **only that edge removed** yields **0 cycle participants**. So the prerequisite is exact and singular:
311
-
312
- 1. Extract the pure path derivations (`getWebsiteCachePaths` + `normalizeSiteUrl`, `validateWebsiteUrl`, `shouldAllowPrivateWebsiteUrlForTests`) from `website-ingest.ts` into a leaf module both it and `website.ts` import. Necessary, **not sufficient** — `sync()` still reaches `ensureWebsiteMirror`.
313
- 2. Stop `website.ts`'s `sync()` from statically importing `ensureWebsiteMirror` — inject the mirror as a capability on `SyncOptions`, bound from a composition root, exactly the P4 idiom applied to the mirror instead of the secret.
314
-
315
- With both done, `providers/index` becomes a leaf-importable registration point, the moved `resolveSourceEntries` is genuinely one shared resolver, and P3's acceptance criteria are reachable. Until then P3 cannot satisfy §7's condition and must not land.
316
-
317
- ### 8.6 Correction to the issue's framing
318
-
319
- `CYCLE_PARTICIPANT_BASELINE` is **already empty** and the ratchet is absolute; `bun scripts/lint-import-cycles.ts` reports `0 cycle participant(s)`. There is no import cycle in `src/` today — `env-secret-ref → search-source` is a one-way DAG edge, and the cycle is only *latent* (it closes if a fetcher imports the reader). So #744's "the baseline shrinks" criterion is vacuous as written: the measurable win P3 offers is not a smaller baseline but the removal of the latent back-edge, which is what §8.5 gates.
@@ -1,153 +0,0 @@
1
- # Runtime Boundary Design — AKM 0.9.0
2
-
3
- > **Implementation note (added later):** both target files below now exist —
4
- > `src/storage/database.ts` and `src/runtime.ts` — so this design has landed.
5
- > The "3 hard-import files" named in the original checklist (`src/indexer/db.ts`,
6
- > `src/core/state-db.ts`, `src/workflows/db.ts`) no longer describes the current
7
- > tree: `src/indexer/db.ts` was later split into `src/storage/repositories/index-*.ts`
8
- > (its `Database` opener lives in `src/storage/repositories/index-connection.ts`,
9
- > which imports `openDatabase`/`Database` from `src/storage/database.ts` as this
10
- > design specifies). `src/workflows/db.ts` did exist historically but has since
11
- > been removed — workflow run persistence now lives in
12
- > `src/storage/repositories/workflow-runs-repository.ts`.
13
- > `src/core/state-db.ts` still exists and also imports from `src/storage/database.ts`.
14
- > The checklist items below are kept as the historical design record.
15
-
16
- ## Problem
17
-
18
- Runtime-specific dependencies (`bun:sqlite`, `Bun.*` APIs) leak directly into 33+ source files.
19
- This creates unnecessary coupling, makes Node.js compatibility hard, and means every future
20
- runtime change has a large blast radius.
21
-
22
- ## Goal
23
-
24
- Two files own the entire runtime boundary. Everything else is clean application code.
25
-
26
- ---
27
-
28
- ## File 1: `src/storage/database.ts`
29
-
30
- Single source of truth for SQLite. The rest of the app never imports from `bun:sqlite` or
31
- `better-sqlite3` directly — only from here.
32
-
33
- **Responsibilities:**
34
- - Detect runtime (bun vs node) once at module load
35
- - Load the appropriate SQLite driver (`bun:sqlite` on Bun, `better-sqlite3` on Node)
36
- - Export `Database` type — the common structural type both drivers share
37
- - Export `openDatabase(path, opts?)` factory
38
-
39
- **Design constraints:**
40
- - No adapter classes, no interface hierarchies — the driver APIs are already nearly identical
41
- - The exported `Database` type should be the structural intersection of what both drivers expose
42
- - `openDatabase()` should be a simple function, not a factory class
43
- - `db.query()` (Bun-specific) must be normalised — replace with `db.prepare().all()` at this boundary
44
-
45
- **Architect: investigate and fill in:**
46
- - [ ] Read `src/indexer/db.ts`, `src/core/state-db.ts`, `src/workflows/db.ts` — the 3 hard-import files
47
- - [ ] Identify every method AKM actually calls on a `Database` instance (exec, prepare, transaction, close, query, etc.)
48
- - [ ] Check whether `better-sqlite3`'s type definitions can be used as the exported `Database` type directly, or if a small structural type alias is needed
49
- - [ ] Check `sqliteVec.load(db)` — confirm whether it accepts both driver handles or needs a raw handle escape hatch
50
- - [ ] Write the complete file
51
-
52
- ---
53
-
54
- ## File 2: `src/runtime.ts`
55
-
56
- ~60 lines. Named exports for every `Bun.*` API called outside of the SQLite layer.
57
- Each export works on both runtimes.
58
-
59
- **Known Bun.* call sites to cover (architect: verify these are complete):**
60
-
61
- | Export name | Bun API | Node equivalent |
62
- |---|---|---|
63
- | `spawnSync(cmd, opts)` | `Bun.spawnSync` | `child_process.spawnSync` |
64
- | `spawn(cmd, opts)` | `Bun.spawn` | `child_process.spawn` |
65
- | `readStdin(limitBytes)` | `Bun.stdin.stream()` | `for await (chunk of process.stdin)` |
66
- | `writeResponseToFile(path, res)` | `Bun.write(path, response)` | `stream/promises pipeline` |
67
- | `sha256Hex(data)` | `new Bun.CryptoHasher('sha256')` | `node:crypto createHash` |
68
- | `md5Hex(data)` | `new Bun.CryptoHasher('md5')` | `node:crypto createHash` |
69
- | `semverOrder(a, b)` | `Bun.semver.order` | `semver.compare` (add dep) |
70
- | `getDirname(importMetaUrl)` | `import.meta.dir` | `path.dirname(new URL(url).pathname)` |
71
- | `resolveModule(spec, from)` | `Bun.resolveSync` | `require.resolve` (already has fallback) |
72
- | `sleepSync(ms)` | `Bun.sleepSync` | `Atomics.wait` (already has fallback) |
73
- | `mainPath` | `Bun.main` | `process.argv[1]` |
74
-
75
- **Design constraints:**
76
- - Runtime detection: `const isBun = !!process.versions?.bun` at top of file, used inline
77
- - No class, no factory — just named function exports
78
- - Each export branches once on `isBun`, no per-call overhead
79
- - `node:crypto` is available in both Bun and Node — the crypto exports can skip the `isBun`
80
- branch entirely and just use `createHash` always (simpler, same perf for a CLI)
81
-
82
- **Architect: investigate and fill in:**
83
- - [ ] `grep -rn "Bun\." src --include="*.ts"` — confirm the table above is complete
84
- - [ ] `grep -rn "import\.meta\.dir" src --include="*.ts"` — list all sites, note which have fallbacks
85
- - [ ] Confirm `Readable.toWeb()` is the right Node 18 approach for `writeResponseToFile`
86
- - [ ] Write the complete file
87
-
88
- ---
89
-
90
- ## Call Site Changes
91
-
92
- Once both files exist, the remaining work is mechanical:
93
-
94
- **SQLite type-only imports (~30 files):**
95
- ```ts
96
- // Before
97
- import type { Database } from 'bun:sqlite'
98
- // After
99
- import type { Database } from '../storage/database'
100
- ```
101
-
102
- **SQLite hard imports (3 files — `indexer/db.ts`, `core/state-db.ts`, `workflows/db.ts`):**
103
- - Replace `import { Database } from 'bun:sqlite'` with `import { openDatabase, type Database } from '../storage/database'`
104
- - Replace `new Database(path)` with `openDatabase(path)`
105
- - Replace `db.query<T>(sql).all(params)` with `db.prepare(sql).all(params)` (Bun-specific API)
106
- - Remove `SQLQueryBindings` spread casts
107
-
108
- **Bun.* call sites (~10 files):**
109
- ```ts
110
- // Before
111
- Bun.spawnSync(['git', 'ls-files', ...])
112
- // After
113
- import { spawnSync } from '../runtime'
114
- spawnSync(['git', 'ls-files', ...])
115
- ```
116
-
117
- **Architect: investigate and fill in:**
118
- - [ ] List every call site file and the exact import line change needed
119
- - [ ] Flag any call site where the shim return shape differs from the Bun API (e.g. stdout as string vs Buffer)
120
-
121
- ---
122
-
123
- ## `package.json` Changes
124
-
125
- - Add `better-sqlite3` as `optionalDependency` (prebuilt binaries, no compile step on common platforms)
126
- - Add `@types/better-sqlite3` to `devDependencies`
127
- - Add `semver` to `dependencies` (tiny, zero-deps)
128
- - Add `node: ">=22"` to `engines` (raised from 20.12 when Node 20 support was dropped, 2026-07) (`@clack/core` uses `node:util.styleText`,
129
- which was added in Node 20.12)
130
- - Require Node >= 22 in the npm `preinstall` guard
131
-
132
- ---
133
-
134
- ## What This Is NOT
135
-
136
- - Not an adapter pattern with interface hierarchies
137
- - Not a ports-and-adapters architecture
138
- - Not a plugin system
139
- - Not a DI container
140
-
141
- Just two modules that own the runtime details so the rest of the codebase doesn't have to.
142
-
143
- ---
144
-
145
- ## Child Issues to Create (after design is complete)
146
-
147
- 1. `src/storage/database.ts` + migrate 3 hard-import files
148
- 2. Mechanical: update 30 type-only imports (sed pass + tsc verify)
149
- 3. `src/runtime.ts` + update ~10 call sites
150
- 4. `package.json` + relax preinstall guard + CI Node matrix
151
-
152
- Plus: audit open GitHub issues on itlackey/akm and close any that are superseded by this work
153
- or otherwise stale (milestone 0.9.0 items already addressed, etc.).