okengine 0.10.2 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (343) hide show
  1. package/package.json +76 -10
  2. package/site/content/docs/ai/mcp.mdx +0 -1
  3. package/site/content/docs/deployment/docker-swarm.mdx +48 -111
  4. package/site/content/docs/deployment/docker.mdx +43 -36
  5. package/site/content/docs/deployment/index.mdx +9 -9
  6. package/site/content/docs/deployment/kubernetes.mdx +4 -4
  7. package/site/content/docs/elements/ai.mdx +7 -13
  8. package/site/content/docs/elements/channel.mdx +9 -13
  9. package/site/content/docs/elements/clock.mdx +8 -14
  10. package/site/content/docs/elements/flow.mdx +46 -54
  11. package/site/content/docs/elements/gate.mdx +6 -11
  12. package/site/content/docs/elements/signal.mdx +2 -8
  13. package/site/content/docs/elements/store.mdx +79 -93
  14. package/site/content/docs/elements/vault.mdx +89 -76
  15. package/site/content/docs/get-started/basic-usage.mdx +8 -14
  16. package/site/content/docs/get-started/installation.mdx +36 -36
  17. package/site/content/docs/get-started/introduction.mdx +11 -0
  18. package/site/content/docs/get-started/why.mdx +3 -4
  19. package/site/content/docs/index.mdx +0 -1
  20. package/site/content/docs/meta.json +0 -1
  21. package/site/content/docs/plugins/anonymous.mdx +1 -1
  22. package/site/content/docs/plugins/magic-link.mdx +11 -11
  23. package/site/content/docs/plugins/otp.mdx +2 -2
  24. package/site/content/docs/plugins/passkey.mdx +1 -1
  25. package/site/content/docs/plugins/two-factor.mdx +1 -1
  26. package/site/content/docs/plugins/username.mdx +1 -1
  27. package/site/content/docs/recipes/caddy.mdx +1 -1
  28. package/site/content/docs/recipes/cockroachdb.mdx +2 -2
  29. package/site/content/docs/recipes/dragonfly.mdx +1 -1
  30. package/site/content/docs/recipes/index.mdx +1 -2
  31. package/site/content/docs/recipes/llama-cpp.mdx +21 -23
  32. package/site/content/docs/recipes/mailpit.mdx +11 -11
  33. package/site/content/docs/recipes/meilisearch.mdx +10 -10
  34. package/site/content/docs/recipes/meta.json +0 -1
  35. package/site/content/docs/recipes/ollama.mdx +1 -1
  36. package/site/content/docs/recipes/pgdog.mdx +12 -9
  37. package/site/content/docs/recipes/postgres.mdx +3 -3
  38. package/site/content/docs/recipes/redis.mdx +2 -2
  39. package/site/content/docs/recipes/rustfs.mdx +10 -7
  40. package/site/content/docs/recipes/sglang.mdx +1 -1
  41. package/site/content/docs/recipes/supabase-docker.mdx +1 -1
  42. package/site/content/docs/recipes/timescale.mdx +2 -2
  43. package/site/content/docs/recipes/valkey.mdx +1 -1
  44. package/site/content/docs/recipes/vllm.mdx +1 -1
  45. package/site/content/docs/recipes/yugabytedb.mdx +2 -2
  46. package/site/content/docs/reference/cli.md +61 -38
  47. package/site/content/docs/reference/configuration.mdx +145 -70
  48. package/site/content/docs/reference/environment-variables.mdx +36 -28
  49. package/site/content/docs/reference/errors.mdx +28 -29
  50. package/site/content/docs/reference/fx.mdx +14 -7
  51. package/site/content/docs/reference/i18n.mdx +17 -6
  52. package/site/content/docs/reference/index.mdx +5 -0
  53. package/site/content/docs/reference/meta.json +1 -0
  54. package/site/content/docs/reference/migrating-environments.mdx +158 -0
  55. package/site/content/docs/reference/plugins.mdx +2 -2
  56. package/src/auth/gate-auth.test.ts +12 -10
  57. package/src/cli/ai-setup/ai-setup.test.ts +30 -16
  58. package/src/cli/ai-setup/apply.ts +111 -15
  59. package/src/cli/ai-setup/catalog.ts +3 -3
  60. package/src/cli/ai-setup/index.ts +1 -1
  61. package/src/cli/ai-setup/prompts.ts +1 -1
  62. package/src/cli/ai-setup/recommend.test.ts +1 -1
  63. package/src/cli/ask-seed.test.ts +3 -3
  64. package/src/cli/build.ts +8 -9
  65. package/src/cli/db-auto-push.test.ts +6 -3
  66. package/src/cli/db-auto-push.ts +7 -5
  67. package/src/cli/db-seed.ts +7 -8
  68. package/src/cli/db.test.ts +70 -71
  69. package/src/cli/db.ts +86 -12
  70. package/src/cli/dev-controller.test.ts +35 -0
  71. package/src/cli/dev-controller.ts +298 -0
  72. package/src/cli/dev-controls.ts +11 -65
  73. package/src/cli/dev-db-push.test.ts +47 -15
  74. package/src/cli/dev-schema-sync.test.ts +11 -11
  75. package/src/cli/dev-schema-sync.ts +10 -10
  76. package/src/cli/dev-session-lock.test.ts +106 -0
  77. package/src/cli/dev-session-lock.ts +209 -0
  78. package/src/cli/dev.test.ts +246 -114
  79. package/src/cli/dev.ts +153 -205
  80. package/src/cli/doc-staleness.test.ts +3 -6
  81. package/src/cli/docker-clean.test.ts +33 -1
  82. package/src/cli/docker-clean.ts +28 -33
  83. package/src/cli/docker-cli.test.ts +12 -11
  84. package/src/cli/docker.ts +95 -20
  85. package/src/cli/doctor.test.ts +40 -0
  86. package/src/cli/doctor.ts +142 -9
  87. package/src/cli/drizzle-env.test.ts +11 -13
  88. package/src/cli/drizzle-env.ts +18 -11
  89. package/src/cli/ensure-drizzle-config.ts +11 -14
  90. package/src/cli/hero-meta.test.ts +15 -15
  91. package/src/cli/hero-meta.ts +10 -9
  92. package/src/cli/index.ts +36 -6
  93. package/src/cli/load-config.images.test.ts +44 -10
  94. package/src/cli/load-config.source.test.ts +50 -0
  95. package/src/cli/load-config.ts +35 -29
  96. package/src/cli/meilisearch-local.ts +1 -2
  97. package/src/cli/mode.ts +7 -58
  98. package/src/cli/registry.ts +175 -19
  99. package/src/cli/resolve-dev-sql-env.test.ts +8 -16
  100. package/src/cli/resolve-dev-sql-env.ts +13 -15
  101. package/src/cli/safe-defaults.test.ts +29 -11
  102. package/src/cli/schema.ts +65 -16
  103. package/src/cli/test.ts +58 -0
  104. package/src/cli/tui/App.tsx +252 -0
  105. package/src/cli/tui/DevLive.tsx +116 -0
  106. package/src/cli/tui/components/ConfirmDialog.tsx +48 -0
  107. package/src/cli/tui/components/HeaderBar.tsx +67 -0
  108. package/src/cli/tui/components/LogStream.tsx +47 -0
  109. package/src/cli/tui/components/PanelCard.tsx +39 -0
  110. package/src/cli/tui/components/SelectRow.tsx +37 -0
  111. package/src/cli/tui/components/SlashPalette.tsx +172 -0
  112. package/src/cli/tui/components/Spinner.tsx +32 -0
  113. package/src/cli/tui/components/StatusBar.tsx +51 -0
  114. package/src/cli/tui/components/StatusDot.tsx +37 -0
  115. package/src/cli/tui/components/TabBar.tsx +49 -0
  116. package/src/cli/tui/components/Wordmark.tsx +43 -0
  117. package/src/cli/tui/format.ts +38 -0
  118. package/src/cli/tui/keys.test.ts +18 -0
  119. package/src/cli/tui/keys.ts +26 -0
  120. package/src/cli/tui/launch.test.ts +18 -0
  121. package/src/cli/tui/launch.ts +57 -0
  122. package/src/cli/tui/panels/Dashboard.tsx +201 -0
  123. package/src/cli/tui/panels/Database.tsx +198 -0
  124. package/src/cli/tui/panels/Dev.tsx +257 -0
  125. package/src/cli/tui/panels/Docker.tsx +357 -0
  126. package/src/cli/tui/panels/Navigator.test.ts +22 -0
  127. package/src/cli/tui/panels/Navigator.tsx +213 -0
  128. package/src/cli/tui/slash-catalog.test.ts +31 -0
  129. package/src/cli/tui/slash-catalog.ts +184 -0
  130. package/src/cli/tui/slash-run.ts +54 -0
  131. package/src/cli/tui/state/ports.ts +95 -0
  132. package/src/cli/tui/theme.ts +24 -0
  133. package/src/cli/vault-cmd.test.ts +402 -0
  134. package/src/cli/vault-cmd.ts +727 -69
  135. package/src/cli/vault-secure-input.test.ts +56 -0
  136. package/src/cli/vault-secure-input.ts +124 -0
  137. package/src/compiler/effects-infer.ts +7 -0
  138. package/src/compiler/extract.ts +12 -0
  139. package/src/compiler/fixtures/skyport/oke.config.ts +7 -5
  140. package/src/compiler/fixtures/skyport/src/flows/payments/index.ts +1 -1
  141. package/src/compiler/fixtures/skyport.expected.json +1 -1
  142. package/src/compiler/generate-adopt.ts +27 -1
  143. package/src/compiler-entry.ts +7 -0
  144. package/src/config/define-config.test.ts +111 -47
  145. package/src/config/driver-defaults.test.ts +115 -0
  146. package/src/config/driver-defaults.ts +156 -0
  147. package/src/config/index.ts +246 -131
  148. package/src/config/resolve-driver.test.ts +14 -19
  149. package/src/console/server/app.ts +4 -2
  150. package/src/console/server/console.test.ts +58 -1
  151. package/src/console/server/flows.ts +22 -2
  152. package/src/console/server/index.ts +3 -0
  153. package/src/console/server/operator-db.test.ts +55 -13
  154. package/src/console/server/operator-db.ts +305 -263
  155. package/src/console/server/serve.ts +16 -7
  156. package/src/console/server/state.ts +31 -9
  157. package/src/console/server/vault.test.ts +120 -5
  158. package/src/console/server/vault.ts +208 -12
  159. package/src/console/ui/dist/assets/{index-D-9KFce5.js → index--Y0Uaz-m.js} +2 -2
  160. package/src/console/ui/dist/assets/panel-vault-BkZdJPX8.js +1 -0
  161. package/src/console/ui/dist/assets/style-C3L349iZ.css +3 -0
  162. package/src/console/ui/dist/index.html +2 -2
  163. package/src/console/ui/shell/client.ts +16 -0
  164. package/src/console/ui/shell/panels/vault/VaultPanel.tsx +54 -1
  165. package/src/console/ui/vault/VaultA11yView.tsx +33 -1
  166. package/src/console/ui/vault/backend.test.ts +75 -0
  167. package/src/console/ui/vault/backend.ts +117 -0
  168. package/src/console/ui/vault/fixture.ts +21 -2
  169. package/src/console/ui/vault/index.ts +11 -1
  170. package/src/console/ui/vault/types.ts +26 -0
  171. package/src/docker/compose.ts +164 -61
  172. package/src/docker/derive.ts +106 -12
  173. package/src/docker/docker.test.ts +156 -110
  174. package/src/docker/helpers.ts +98 -0
  175. package/src/docker/images-config.test.ts +163 -0
  176. package/src/docker/index.ts +30 -5
  177. package/src/docker/recipes/index.ts +0 -3
  178. package/src/docker/recipes/llama-cpp.ts +4 -4
  179. package/src/docker/recipes/pgdog.ts +9 -2
  180. package/src/docker/resources.test.ts +71 -0
  181. package/src/docker/resources.ts +176 -0
  182. package/src/docker/stack-id.test.ts +11 -4
  183. package/src/docker/stack-id.ts +42 -32
  184. package/src/docker/stack.integration.test.ts +4 -15
  185. package/src/docker/types.ts +35 -3
  186. package/src/drivers/ai-ollama.integration.test.ts +2 -2
  187. package/src/drivers/conformance.test.ts +11 -12
  188. package/src/drivers/drizzle-dialect.test.ts +0 -4
  189. package/src/drivers/drizzle-dialect.ts +7 -13
  190. package/src/drivers/index.ts +24 -7
  191. package/src/drivers/journal-postgres.test.ts +3 -1
  192. package/src/drivers/journal-postgres.ts +4 -2
  193. package/src/drivers/meilisearch.ts +1 -1
  194. package/src/drivers/pglite.ts +28 -5
  195. package/src/drivers/types.ts +9 -11
  196. package/src/drivers/vault-aws-secrets-manager.test.ts +159 -0
  197. package/src/drivers/vault-aws-secrets-manager.ts +333 -0
  198. package/src/drivers/vault-builtin.test.ts +110 -0
  199. package/src/drivers/vault-builtin.ts +184 -0
  200. package/src/drivers/vault-driver-removal.test.ts +13 -0
  201. package/src/drivers/vault-managed.test.ts +95 -0
  202. package/src/drivers/vault-managed.ts +101 -25
  203. package/src/drivers/vault-types.ts +25 -5
  204. package/src/elements/ai/runtime.ts +1 -1
  205. package/src/elements/clock/chaos.test.ts +4 -1
  206. package/src/elements/clock/durable.ts +57 -4
  207. package/src/elements/clock.test.ts +13 -14
  208. package/src/elements/gate/constants.ts +18 -0
  209. package/src/elements/gate.test.ts +1 -1
  210. package/src/elements/gate.ts +2 -2
  211. package/src/elements/store/domain-ddl.test.ts +5 -12
  212. package/src/elements/store/emit-drizzle.ts +44 -19
  213. package/src/elements/store/index-boot.test.ts +15 -116
  214. package/src/elements/store/load-plugin-tables.ts +1 -1
  215. package/src/elements/store/resource-list-docs.fixture.ts +12 -6
  216. package/src/elements/store/resource-list-docs.test.ts +64 -44
  217. package/src/elements/store/resource.test.ts +17 -10
  218. package/src/elements/store/runtime.ts +9 -12
  219. package/src/elements/store/schema-decl.test.ts +16 -32
  220. package/src/elements/store/seed.test.ts +1 -2
  221. package/src/elements/store/seed.ts +7 -8
  222. package/src/elements/store/sql-condition.test.ts +2 -2
  223. package/src/elements/store/sql-session.test.ts +8 -10
  224. package/src/elements/store/sql-session.ts +10 -2
  225. package/src/elements/store.test.ts +13 -13
  226. package/src/elements/vault/audit.ts +233 -0
  227. package/src/elements/vault/boot-chain.test.ts +78 -0
  228. package/src/elements/vault/boot-chain.ts +43 -39
  229. package/src/elements/vault/builtin-adapter.test.ts +479 -0
  230. package/src/elements/vault/builtin-adapter.ts +1184 -0
  231. package/src/elements/vault/crypto.test.ts +237 -0
  232. package/src/elements/vault/crypto.ts +431 -0
  233. package/src/elements/vault/declare.ts +164 -3
  234. package/src/elements/vault/errors.ts +56 -0
  235. package/src/elements/vault/kms-unseal.test.ts +76 -0
  236. package/src/elements/vault/kms-unseal.ts +181 -0
  237. package/src/elements/vault/path.ts +90 -0
  238. package/src/elements/vault/resilience.test.ts +102 -0
  239. package/src/elements/vault/resilience.ts +107 -0
  240. package/src/elements/vault/runtime.ts +36 -4
  241. package/src/elements/vault/security-checklist.test.ts +130 -0
  242. package/src/elements/vault/storage.ts +448 -0
  243. package/src/elements/vault/types.ts +288 -0
  244. package/src/elements/vault/unseal.ts +150 -0
  245. package/src/elements/vault.test.ts +72 -4
  246. package/src/elements/vault.ts +91 -2
  247. package/src/full.ts +248 -0
  248. package/src/http.ts +41 -0
  249. package/src/i18n/interpolate-simple.ts +37 -0
  250. package/src/i18n/messages.ts +51 -4
  251. package/src/i18n-entry.ts +7 -0
  252. package/src/index.ts +35 -145
  253. package/src/journal-entry.ts +20 -0
  254. package/src/kernel/adopt-barrel-fresh.test.ts +25 -10
  255. package/src/kernel/app.ts +40 -42
  256. package/src/kernel/auto-registry.test.ts +2 -2
  257. package/src/kernel/boot-bind/ai.test.ts +5 -5
  258. package/src/kernel/boot-bind/ai.ts +2 -1
  259. package/src/kernel/boot-bind/channel.test.ts +6 -6
  260. package/src/kernel/boot-bind/channel.ts +5 -4
  261. package/src/kernel/boot-bind/clock.ts +5 -5
  262. package/src/kernel/boot-bind/gate.ts +6 -7
  263. package/src/kernel/boot-bind/honor-config.test.ts +42 -42
  264. package/src/kernel/boot-bind/journal.ts +5 -5
  265. package/src/kernel/boot-bind/signal.ts +3 -1
  266. package/src/kernel/boot-bind/store.test.ts +55 -37
  267. package/src/kernel/boot-bind/store.ts +24 -34
  268. package/src/kernel/boot-bind/vault.ts +19 -4
  269. package/src/kernel/boot.test.ts +12 -4
  270. package/src/kernel/boot.ts +31 -19
  271. package/src/kernel/budget-entry.ts +1 -1
  272. package/src/kernel/compensate.test.ts +288 -1
  273. package/src/kernel/compensate.ts +126 -0
  274. package/src/kernel/concurrency.test.ts +10 -9
  275. package/src/kernel/effects-stamping.test.ts +27 -2
  276. package/src/kernel/element-registries.ts +5 -3
  277. package/src/kernel/flow.ts +4 -2
  278. package/src/kernel/fx.test.ts +119 -3
  279. package/src/kernel/fx.ts +215 -40
  280. package/src/kernel/index.ts +14 -0
  281. package/src/kernel/journal.ts +130 -7
  282. package/src/kernel/pipeline.test.ts +20 -6
  283. package/src/kernel/redacted.test.ts +35 -0
  284. package/src/kernel/redacted.ts +24 -2
  285. package/src/kernel/router/create-default.ts +16 -0
  286. package/src/kernel/router/create-edge.ts +18 -0
  287. package/src/kernel/router/create.ts +23 -0
  288. package/src/kernel/router/index.ts +23 -0
  289. package/src/kernel/router/linear.ts +88 -0
  290. package/src/kernel/router/regexp.ts +188 -0
  291. package/src/kernel/router/smart.ts +120 -0
  292. package/src/kernel/router/trie.ts +108 -0
  293. package/src/kernel/router/types.ts +56 -0
  294. package/src/kernel/router.ts +18 -532
  295. package/src/kernel-entry.ts +43 -0
  296. package/src/manifest/fixtures/skyport.excerpt.json +1 -1
  297. package/src/manifest/fixtures/skyport.manifest.json +1 -1
  298. package/src/plugins/config-source.test.ts +7 -7
  299. package/src/release/build-lib.ts +58 -0
  300. package/src/release/exports.test.ts +4 -2
  301. package/src/release/exports.ts +30 -4
  302. package/src/release/measure.ts +101 -22
  303. package/src/runs/duckdb.ts +7 -2
  304. package/src/shared/optional-peer.ts +41 -0
  305. package/src/term.test.ts +3 -44
  306. package/src/test/create-test-app.ts +12 -0
  307. package/src/test/provisions.integration.test.ts +1 -1
  308. package/src/test/reset-element-registries.ts +2 -0
  309. package/src/upgrade/codemods.test.ts +7 -20
  310. package/src/upgrade/codemods.ts +93 -60
  311. package/site/content/docs/console/access.mdx +0 -29
  312. package/site/content/docs/console/ai.mdx +0 -35
  313. package/site/content/docs/console/architecture.mdx +0 -35
  314. package/site/content/docs/console/channels.mdx +0 -37
  315. package/site/content/docs/console/clock.mdx +0 -51
  316. package/site/content/docs/console/flows.mdx +0 -31
  317. package/site/content/docs/console/gates.mdx +0 -73
  318. package/site/content/docs/console/index.mdx +0 -54
  319. package/site/content/docs/console/manifest-diff.mdx +0 -34
  320. package/site/content/docs/console/meta.json +0 -24
  321. package/site/content/docs/console/overview.mdx +0 -40
  322. package/site/content/docs/console/plugins.mdx +0 -41
  323. package/site/content/docs/console/privacy.mdx +0 -32
  324. package/site/content/docs/console/runs.mdx +0 -50
  325. package/site/content/docs/console/signals.mdx +0 -40
  326. package/site/content/docs/console/store.mdx +0 -32
  327. package/site/content/docs/console/tenancy.mdx +0 -32
  328. package/site/content/docs/console/traces.mdx +0 -38
  329. package/site/content/docs/console/vault.mdx +0 -41
  330. package/site/content/docs/recipes/openbao.mdx +0 -141
  331. package/src/cli/ask-dev-mode.ts +0 -40
  332. package/src/cli/dev-mode.test.ts +0 -45
  333. package/src/cli/dev-mode.ts +0 -78
  334. package/src/cli/openbao-bootstrap.test.ts +0 -150
  335. package/src/cli/openbao-bootstrap.ts +0 -321
  336. package/src/cli/openbao-restart.integration.test.ts +0 -145
  337. package/src/console/ui/dist/assets/panel-vault-Za1GyJfM.js +0 -1
  338. package/src/console/ui/dist/assets/style-C8MxEWPd.css +0 -3
  339. package/src/docker/recipes/openbao.ts +0 -47
  340. package/src/drivers/libsql.ts +0 -179
  341. package/src/drivers/sqlite.ts +0 -44
  342. package/src/drivers/vault-openbao.test.ts +0 -97
  343. package/src/drivers/vault-openbao.ts +0 -143
@@ -40,8 +40,8 @@ export interface ServeConsoleOptions extends CreateConsoleAppOptions {
40
40
  /** Boot environment — use `"dev"` / `"prod"` so Bearer auth is production-like. */
41
41
  readonly env?: "dev" | "prod" | "test";
42
42
  /**
43
- * Persist operators + secret under `.oke/` (default true).
44
- * Set false for ephemeral test servers.
43
+ * Persist operators in Postgres `oke_console` (+ `.oke/console.secret`).
44
+ * Default true. Set false for ephemeral test servers.
45
45
  */
46
46
  readonly persist?: boolean;
47
47
  }
@@ -83,9 +83,18 @@ export async function serveConsole(
83
83
  : {}),
84
84
  });
85
85
 
86
- // Console serve `"dev"` is the auth/session flavor ConfigEnv uses `local`.
87
- const env = options.env ?? "dev";
88
- await handle.app.boot({ env: env === "dev" ? "local" : env });
86
+ // Console serve defaults to `test` drivers when compose isn't up; pass
87
+ // `env: "dev"` only with compose URLs (or memory overrides) available.
88
+ // Never inherit `OKE_DOCKER=1` from `oke dev` into capability minting
89
+ // Console operator flows don't stamp Manifest effects, and docker+dev
90
+ // would otherwise hard-fail with OKE1008 on the first undeclared flow
91
+ // (`console.setup.status`). Compose URLs for Manifest panels bind via
92
+ // `bindManifest*` below, not this boot's driver map.
93
+ const env = options.env ?? "test";
94
+ await handle.app.boot({
95
+ env: env === "dev" || env === "test" || env === "prod" ? env : "test",
96
+ docker: false,
97
+ });
89
98
  handle.state.listRuns = async () => {
90
99
  const runs = handle.app.bootResult?.runs;
91
100
  if (!runs) return [];
@@ -182,7 +191,7 @@ export async function serveConsole(
182
191
  stop(closeActive = false) {
183
192
  server.stop(closeActive);
184
193
  void handle.app.stop();
185
- persistence?.close();
194
+ void persistence?.close();
186
195
  },
187
196
  };
188
197
  }
@@ -195,7 +204,7 @@ export async function serveConsole(
195
204
  export async function startConsoleApp(
196
205
  options: CreateConsoleAppOptions & {
197
206
  readonly env?: "dev" | "prod" | "test";
198
- /** Opt-in durable operators under `.oke/` (default false for unit tests). */
207
+ /** Opt-in durable operators in `oke_console` (default false for unit tests). */
199
208
  readonly persist?: boolean;
200
209
  } = {},
201
210
  ): Promise<ConsoleAppHandle> {
@@ -58,7 +58,7 @@ import {
58
58
  type SimulateGatesInput,
59
59
  type SimulateGatesResult,
60
60
  } from "./gates.ts";
61
- import type { ConsoleVaultRow, VaultWriteInput } from "./vault.ts";
61
+ import type { ConsoleVaultBackend, ConsoleVaultRow, VaultWriteInput } from "./vault.ts";
62
62
  import type { ChannelInbox } from "../../drivers/channel-types.ts";
63
63
  import type { ChannelRuntime, TemplateCatalog } from "../../elements/channel.ts";
64
64
  import type { ConsoleChannelPreview, ConsoleChannelsList, EmailAuthResult } from "./channels.ts";
@@ -68,6 +68,9 @@ import type { ConsolePluginsList } from "./plugins.ts";
68
68
  import type { ConsoleDiffProjection } from "./diff.ts";
69
69
  import { loadConsolePanel, type ConsolePanelId } from "./panel-load.ts";
70
70
 
71
+ /** How long a built-in Vault backend probe is reused across list polls. */
72
+ const VAULT_BACKEND_TTL_MS = 15_000;
73
+
71
74
  /** User-plane identity row for the Flows invoke-as picker. */
72
75
  export interface ConsoleIdentity {
73
76
  readonly id: string;
@@ -251,6 +254,7 @@ export interface ConsoleState {
251
254
  listVault: () => Promise<{
252
255
  readonly secrets: readonly ConsoleVaultRow[];
253
256
  readonly env: string;
257
+ readonly backend: ConsoleVaultBackend | null;
254
258
  }>;
255
259
  /** Set a vault value (write-only). */
256
260
  setVault: (
@@ -328,15 +332,15 @@ export interface ConsoleState {
328
332
  /** Whether first operator exists (wizard permanently closed). */
329
333
  get setupClosed(): boolean;
330
334
  /**
331
- * Persist an operator after claim/create (SQLite under `.oke/`).
335
+ * Persist an operator after claim/create (`oke_console` schema).
332
336
  * No-op when persistence is disabled (tests / memory-only).
333
337
  */
334
- persistOperator: (operatorId: string) => void;
338
+ persistOperator: (operatorId: string) => void | Promise<void>;
335
339
  /**
336
- * Persist sessions after issue / revoke (SQLite under `.oke/`).
340
+ * Persist sessions after issue / revoke (`oke_console` schema).
337
341
  * No-op when persistence is disabled (tests / memory-only).
338
342
  */
339
- persistSessions: () => void;
343
+ persistSessions: () => void | Promise<void>;
340
344
  /**
341
345
  * Per-email login attempt timestamps for credential-check rate limiting
342
346
  * (console §10.4 — same 5/60s strategy as setup-claim).
@@ -390,14 +394,14 @@ export interface CreateConsoleStateOptions {
390
394
  readonly okeConfig?: OkeConfig | null;
391
395
  /** Host plugin registry for scopes / capabilities. */
392
396
  readonly pluginRegistry?: PluginRegistry | null;
393
- /** Pre-hydrated operator store (from `.oke/console.sqlite`). */
397
+ /** Pre-hydrated operator store (from `oke_console` / PGlite fallback). */
394
398
  readonly operators?: OperatorStore;
395
- /** Pre-hydrated session store (from `.oke/console.sqlite`). */
399
+ /** Pre-hydrated session store (from `oke_console` / PGlite fallback). */
396
400
  readonly sessions?: SessionStore;
397
401
  /** Persist hook after claim/create. */
398
- readonly persistOperator?: (operatorId: string) => void;
402
+ readonly persistOperator?: (operatorId: string) => void | Promise<void>;
399
403
  /** Persist hook after session issue / revoke. */
400
- readonly persistSessions?: () => void;
404
+ readonly persistSessions?: () => void | Promise<void>;
401
405
  }
402
406
 
403
407
  /**
@@ -427,6 +431,23 @@ export function createConsoleState(options: CreateConsoleStateOptions = {}): Con
427
431
  return loadConsolePanel<T>(id);
428
432
  };
429
433
 
434
+ // The Vault panel polls; probing the built-in backend opens a SQL
435
+ // connection, so hold the answer for a beat rather than per refresh.
436
+ let backendMemo: { readonly at: number; readonly value: ConsoleVaultBackend | null } | null =
437
+ null;
438
+ const vaultBackend = async (
439
+ vault: typeof import("./vault.ts"),
440
+ ): Promise<ConsoleVaultBackend | null> => {
441
+ const at = state.now();
442
+ if (backendMemo && at - backendMemo.at < VAULT_BACKEND_TTL_MS) return backendMemo.value;
443
+ const value = await vault.probeVaultBackend({
444
+ config: state.okeConfig,
445
+ env: state.production ? "prod" : "dev",
446
+ });
447
+ backendMemo = { at, value };
448
+ return value;
449
+ };
450
+
430
451
  const state: ConsoleState = {
431
452
  operators,
432
453
  sessions,
@@ -733,6 +754,7 @@ export function createConsoleState(options: CreateConsoleStateOptions = {}): Con
733
754
  journal: state.journalStore,
734
755
  env: state.vaultEnv,
735
756
  now: state.now,
757
+ backend: await vaultBackend(vault),
736
758
  });
737
759
  },
738
760
  setVault: async (input) => {
@@ -10,11 +10,15 @@ import type { Manifest } from "../../manifest/types.ts";
10
10
  import {
11
11
  assertNoSecretLeak,
12
12
  blastRadiusOf,
13
+ probeVaultBackend,
13
14
  projectVaultList,
14
15
  readersOf,
16
+ resolveVaultDriverId,
15
17
  rotateVaultValue,
16
18
  setVaultValue,
19
+ toConsoleVaultStatus,
17
20
  } from "./vault.ts";
21
+ import type { VaultStatus } from "../../elements/vault/types.ts";
18
22
 
19
23
  const SECRET = "sk_live_console_vault_test_do_not_leak";
20
24
 
@@ -75,13 +79,13 @@ describe("projectVaultList", () => {
75
79
  const { secrets, env } = await projectVaultList({
76
80
  manifest: manifest(),
77
81
  runtime: rt,
78
- env: "local",
82
+ env: "test",
79
83
  peerFingerprints: {
80
84
  STRIPE_KEY: { staging: fingerprintSecretSync(SECRET) },
81
85
  },
82
86
  });
83
87
 
84
- expect(env).toBe("local");
88
+ expect(env).toBe("test");
85
89
  const stripe = secrets.find((s) => s.name === "STRIPE_KEY");
86
90
  const pub = secrets.find((s) => s.name === "PUBLIC_APP_URL");
87
91
  expect(stripe?.sensitive).toBe(true);
@@ -124,7 +128,7 @@ describe("projectVaultList", () => {
124
128
  const { secrets } = await projectVaultList({
125
129
  manifest: null,
126
130
  runtime: rt,
127
- env: "local",
131
+ env: "test",
128
132
  });
129
133
  const row = secrets.find((s) => s.name === "KEY");
130
134
  expect(row?.winner).toBe(".env.local");
@@ -141,7 +145,7 @@ describe("projectVaultList", () => {
141
145
  const { secrets } = await projectVaultList({
142
146
  manifest: manifest(),
143
147
  runtime: rt,
144
- env: "local",
148
+ env: "test",
145
149
  });
146
150
  expect(secrets.find((s) => s.name === "STRIPE_KEY")?.lastReadAt).toBe(1_700_000_000_000);
147
151
  });
@@ -202,13 +206,124 @@ describe("projectVaultList", () => {
202
206
  manifest: manifest(),
203
207
  runtime: rt,
204
208
  journal,
205
- env: "local",
209
+ env: "test",
206
210
  now: () => now,
207
211
  });
208
212
  expect(secrets.find((s) => s.name === "STRIPE_KEY")?.blastRadius.count).toBe(2);
209
213
  });
210
214
  });
211
215
 
216
+ describe("backend badge", () => {
217
+ const builtinStatus: VaultStatus = {
218
+ sealed: true,
219
+ initialized: true,
220
+ masterKeyPresent: true,
221
+ kekVersion: 2,
222
+ secretCount: 3,
223
+ sealCount: 1,
224
+ lastSealedAt: new Date(1_700_000_100_000),
225
+ lastUnsealedAt: new Date(1_700_000_000_000),
226
+ rewrapTargetKekVersion: 3,
227
+ };
228
+
229
+ test("driver id comes from config, falling back to framework defaults", () => {
230
+ expect(resolveVaultDriverId(null, "dev")).toBe("env");
231
+ expect(resolveVaultDriverId(null, "test")).toBe("memory");
232
+ expect(resolveVaultDriverId(null, "prod")).toBe("vault");
233
+ expect(resolveVaultDriverId({ drivers: { vault: { dev: "managed" } } }, "dev")).toBe("managed");
234
+ expect(resolveVaultDriverId({ drivers: { vault: { dev: "builtin" } } }, "dev")).toBe("vault");
235
+ // An unknown id is a boot concern — the Console still renders.
236
+ expect(resolveVaultDriverId({ drivers: { vault: { dev: "nope" } } }, "dev")).toBe("env");
237
+ expect(
238
+ resolveVaultDriverId({ drivers: { vault: { dev: ["open", "bao"].join("") } } }, "dev"),
239
+ ).toBe("env");
240
+ });
241
+
242
+ test("non-builtin driver reports its id and no status", async () => {
243
+ const backend = await probeVaultBackend({
244
+ config: { drivers: { vault: { dev: "managed" } } },
245
+ env: "dev",
246
+ processEnv: {},
247
+ });
248
+ expect(backend).toEqual({
249
+ driverId: "managed",
250
+ builtin: false,
251
+ status: null,
252
+ unavailable: null,
253
+ });
254
+ });
255
+
256
+ test("builtin status is JSON-safe and sealed follows the master key", async () => {
257
+ const sealed = await probeVaultBackend({
258
+ config: { drivers: { vault: { dev: "vault" } } },
259
+ env: "dev",
260
+ processEnv: {},
261
+ loadStatus: async () => builtinStatus,
262
+ });
263
+ expect(sealed.builtin).toBe(true);
264
+ expect(sealed.status).toEqual({
265
+ ...toConsoleVaultStatus(builtinStatus),
266
+ sealed: true,
267
+ });
268
+ expect(sealed.status?.lastUnsealedAt).toBe(1_700_000_000_000);
269
+ expect(sealed.status?.rewrapTargetKekVersion).toBe(3);
270
+
271
+ const unsealed = await probeVaultBackend({
272
+ config: { drivers: { vault: { dev: "vault" } } },
273
+ env: "dev",
274
+ processEnv: { OKE_VAULT_MASTER_KEY: "a-base64-key" },
275
+ loadStatus: async () => builtinStatus,
276
+ });
277
+ expect(unsealed.status?.sealed).toBe(false);
278
+ });
279
+
280
+ test("an unreachable builtin backend degrades to a reason, never a throw", async () => {
281
+ const backend = await probeVaultBackend({
282
+ config: { drivers: { vault: { dev: "vault" } } },
283
+ env: "dev",
284
+ processEnv: {},
285
+ loadStatus: async () => {
286
+ throw new Error("relation oke_vault_status does not exist");
287
+ },
288
+ });
289
+ expect(backend.status).toBeNull();
290
+ expect(backend.unavailable).toContain("oke_vault_status");
291
+ });
292
+
293
+ test("builtin backend with no SQL configured says so instead of spinning PGlite", async () => {
294
+ const backend = await probeVaultBackend({
295
+ config: { drivers: { vault: { dev: "vault" } } },
296
+ env: "dev",
297
+ processEnv: {},
298
+ });
299
+ expect(backend.status).toBeNull();
300
+ expect(backend.unavailable).toContain("DATABASE_URL");
301
+ });
302
+
303
+ test("the projection passes the backend through untouched", async () => {
304
+ const rt = await runtime();
305
+ const backend = await probeVaultBackend({
306
+ config: { drivers: { vault: { dev: "memory" } } },
307
+ env: "dev",
308
+ processEnv: {},
309
+ });
310
+ const listed = await projectVaultList({
311
+ manifest: manifest(),
312
+ runtime: rt,
313
+ env: "test",
314
+ backend,
315
+ });
316
+ expect(listed.backend).toEqual(backend);
317
+
318
+ const unprobed = await projectVaultList({
319
+ manifest: manifest(),
320
+ runtime: rt,
321
+ env: "test",
322
+ });
323
+ expect(unprobed.backend).toBeNull();
324
+ });
325
+ });
326
+
212
327
  describe("set / rotate", () => {
213
328
  test("set updates fingerprint and never returns value", async () => {
214
329
  const rt = await runtime();
@@ -6,8 +6,10 @@
6
6
  * rotation blast radius are derived — never reimplemented in the UI.
7
7
  */
8
8
 
9
- import type { ConfigEnv } from "../../config/index.ts";
10
- import { buildVaultBootChain } from "../../elements/vault/boot-chain.ts";
9
+ import { resolveDriverId, type ConfigEnv, type OkeConfig } from "../../config/index.ts";
10
+ import { VAULT_DEFAULTS } from "../../config/driver-defaults.ts";
11
+ import type { VaultDriverId } from "../../drivers/vault-types.ts";
12
+ import { buildVaultBootChain, normalizeVaultDriverId } from "../../elements/vault/boot-chain.ts";
11
13
  import {
12
14
  createVaultRuntime,
13
15
  vault as declareVault,
@@ -16,6 +18,7 @@ import {
16
18
  type VaultRuntime,
17
19
  type VaultSecretDecl,
18
20
  } from "../../elements/vault.ts";
21
+ import type { VaultStatus } from "../../elements/vault/types.ts";
19
22
  import type { JournalRun, JournalStore } from "../../kernel/journal.ts";
20
23
  import type { Manifest } from "../../manifest/types.ts";
21
24
 
@@ -58,11 +61,11 @@ export interface ConsoleVaultRow {
58
61
  readonly winner: VaultResolutionSource | null;
59
62
  /** Full resolution chain for the current environment. */
60
63
  readonly resolution: readonly VaultResolutionStep[];
61
- /** Flow ids that declare `fx.vault(name)` in Manifest effects. */
64
+ /** Flow ids that declare `fx.vault.get(name)` in Manifest effects. */
62
65
  readonly readers: readonly string[];
63
66
  /** In-flight durable runs that will wake holding a new key after rotate. */
64
67
  readonly blastRadius: ConsoleVaultBlastRadius;
65
- /** Epoch-ms of last `fx.vault` / runtime read; `null` if never read. */
68
+ /** Epoch-ms of last `fx.vault.get` / runtime read; `null` if never read. */
66
69
  readonly lastReadAt: number | null;
67
70
  /**
68
71
  * When the current fingerprint equals another environment's — warning,
@@ -71,12 +74,63 @@ export interface ConsoleVaultRow {
71
74
  readonly sharedFingerprintEnvs: readonly VaultEnvLabel[];
72
75
  }
73
76
 
77
+ /**
78
+ * Built-in Vault backend state, JSON-safe (dates become epoch-ms).
79
+ *
80
+ * Mirrors {@link VaultStatus} minus the resume cursor, which is an internal
81
+ * rewrap detail with no operator meaning.
82
+ */
83
+ export interface ConsoleVaultBuiltinStatus {
84
+ /** Whether `oke vault init` has run against this backend. */
85
+ readonly initialized: boolean;
86
+ /**
87
+ * Whether the Console process can open secrets. The built-in store keeps
88
+ * the master key in memory per process, so this is `true` whenever
89
+ * `OKE_VAULT_MASTER_KEY` is absent — even if another process is unsealed.
90
+ */
91
+ readonly sealed: boolean;
92
+ /** Whether a master-key record exists in the backend. */
93
+ readonly masterKeyPresent: boolean;
94
+ /** KEK generation new writes are wrapped under. */
95
+ readonly kekVersion: number;
96
+ /** Live (non-deleted) secret paths. */
97
+ readonly secretCount: number;
98
+ /** Seals since initialization. */
99
+ readonly sealCount: number;
100
+ /** Epoch-ms of the last seal, or `null`. */
101
+ readonly lastSealedAt: number | null;
102
+ /** Epoch-ms of the last unseal, or `null`. */
103
+ readonly lastUnsealedAt: number | null;
104
+ /** KEK generation an in-flight master rotation is migrating toward. */
105
+ readonly rewrapTargetKekVersion: number | null;
106
+ }
107
+
108
+ /**
109
+ * Which backend terminates the resolution chain, and its state.
110
+ *
111
+ * Only the built-in `vault` driver has a seal lifecycle to report; every
112
+ * other driver surfaces its id alone so the operator still knows where the
113
+ * last layer reads from.
114
+ */
115
+ export interface ConsoleVaultBackend {
116
+ /** `drivers.vault` id resolved for the current environment. */
117
+ readonly driverId: VaultDriverId;
118
+ /** Whether {@link driverId} is okengine's own encrypted-at-rest store. */
119
+ readonly builtin: boolean;
120
+ /** Backend status — `null` for non-builtin drivers or when unreachable. */
121
+ readonly status: ConsoleVaultBuiltinStatus | null;
122
+ /** Why {@link status} is missing for a builtin backend; `null` otherwise. */
123
+ readonly unavailable: string | null;
124
+ }
125
+
74
126
  /** Options when projecting the vault list. */
75
127
  export interface ProjectVaultOptions {
76
128
  readonly manifest: Manifest | null;
77
129
  readonly runtime: VaultRuntime | null;
78
130
  /** Current process environment label. */
79
131
  readonly env?: VaultEnvLabel;
132
+ /** Backend badge from {@link probeVaultBackend}; `null` when unprobed. */
133
+ readonly backend?: ConsoleVaultBackend | null;
80
134
  /**
81
135
  * Optional peer-environment fingerprints (e.g. staging from a remote
82
136
  * probe). Never values — fingerprints only.
@@ -95,8 +149,9 @@ export interface ProjectVaultOptions {
95
149
  export async function projectVaultList(options: ProjectVaultOptions): Promise<{
96
150
  readonly secrets: readonly ConsoleVaultRow[];
97
151
  readonly env: VaultEnvLabel;
152
+ readonly backend: ConsoleVaultBackend | null;
98
153
  }> {
99
- const env = options.env ?? "local";
154
+ const env = options.env ?? "dev";
100
155
  const now = options.now ?? (() => Date.now());
101
156
  const names = collectNames(options.manifest, options.runtime);
102
157
  const journalRuns = options.journal
@@ -150,7 +205,144 @@ export async function projectVaultList(options: ProjectVaultOptions): Promise<{
150
205
  });
151
206
  }
152
207
 
153
- return { secrets, env };
208
+ return { secrets, env, backend: options.backend ?? null };
209
+ }
210
+
211
+ /**
212
+ * Environment variable holding the base64 master key. Mirrors the driver's
213
+ * own constant so the probe stays free of a static `drivers/` import.
214
+ */
215
+ const VAULT_MASTER_KEY_ENV = "OKE_VAULT_MASTER_KEY";
216
+
217
+ /**
218
+ * Resolve `drivers.vault` for an environment, falling back to the framework
219
+ * defaults (`env` in dev, `memory` in test, the built-in store in prod).
220
+ *
221
+ * @param config - Loaded `oke.config`, when available
222
+ * @param env - Active config environment
223
+ */
224
+ export function resolveVaultDriverId(
225
+ config: OkeConfig | null | undefined,
226
+ env: ConfigEnv,
227
+ ): VaultDriverId {
228
+ const raw = resolveDriverId(config?.drivers?.vault, env, VAULT_DEFAULTS);
229
+ if (raw === undefined) return "env";
230
+ try {
231
+ return normalizeVaultDriverId(raw);
232
+ } catch {
233
+ // An unknown id is a boot concern; the Console still renders the list.
234
+ return "env";
235
+ }
236
+ }
237
+
238
+ /** Options for {@link probeVaultBackend}. */
239
+ export interface ProbeVaultBackendOptions {
240
+ /** Loaded `oke.config` — supplies `drivers.vault`. */
241
+ readonly config?: OkeConfig | null;
242
+ /** Active config environment (default `dev`). */
243
+ readonly env?: ConfigEnv;
244
+ /** Process environment for SQL URL / master-key capability (default `process.env`). */
245
+ readonly processEnv?: Readonly<Record<string, string | undefined>>;
246
+ /**
247
+ * Status source. Injected by tests; by default the built-in adapter is
248
+ * opened *sealed* over the configured SQL URL, so the probe never unseals
249
+ * and never writes an unseal audit row.
250
+ */
251
+ readonly loadStatus?: () => Promise<VaultStatus>;
252
+ }
253
+
254
+ /**
255
+ * Report which backend serves the terminal chain layer, plus its state when
256
+ * that backend is the built-in store.
257
+ *
258
+ * The Console never holds the master key on the operator's behalf: the probe
259
+ * reads backend facts only, and reports `sealed` from whether this process
260
+ * has `OKE_VAULT_MASTER_KEY` at all.
261
+ *
262
+ * @param options - Config / env / status source
263
+ */
264
+ export async function probeVaultBackend(
265
+ options: ProbeVaultBackendOptions = {},
266
+ ): Promise<ConsoleVaultBackend> {
267
+ const env = options.env ?? "dev";
268
+ const driverId = resolveVaultDriverId(options.config, env);
269
+ if (driverId !== "vault") {
270
+ return { driverId, builtin: false, status: null, unavailable: null };
271
+ }
272
+
273
+ const processEnv = options.processEnv ?? process.env;
274
+ const keyHeld = (processEnv[VAULT_MASTER_KEY_ENV] ?? "").trim().length > 0;
275
+
276
+ const load = options.loadStatus ?? defaultBuiltinStatusLoader(processEnv);
277
+ if (!load) {
278
+ return {
279
+ driverId,
280
+ builtin: true,
281
+ status: null,
282
+ unavailable: "No SQL URL configured — set DATABASE_URL or OKE_STORE_SQL_URL",
283
+ };
284
+ }
285
+
286
+ try {
287
+ const status = await load();
288
+ return {
289
+ driverId,
290
+ builtin: true,
291
+ status: { ...toConsoleVaultStatus(status), sealed: !keyHeld },
292
+ unavailable: null,
293
+ };
294
+ } catch (error) {
295
+ // Uninitialized / unreachable is an ordinary operator state, not a crash.
296
+ return {
297
+ driverId,
298
+ builtin: true,
299
+ status: null,
300
+ unavailable: error instanceof Error ? error.message : String(error),
301
+ };
302
+ }
303
+ }
304
+
305
+ /**
306
+ * Convert an adapter {@link VaultStatus} into the JSON-safe Console shape.
307
+ *
308
+ * @param status - Adapter status
309
+ */
310
+ export function toConsoleVaultStatus(status: VaultStatus): ConsoleVaultBuiltinStatus {
311
+ return {
312
+ initialized: status.initialized,
313
+ sealed: status.sealed,
314
+ masterKeyPresent: status.masterKeyPresent,
315
+ kekVersion: status.kekVersion,
316
+ secretCount: status.secretCount,
317
+ sealCount: status.sealCount,
318
+ lastSealedAt: status.lastSealedAt?.getTime() ?? null,
319
+ lastUnsealedAt: status.lastUnsealedAt?.getTime() ?? null,
320
+ rewrapTargetKekVersion: status.rewrapTargetKekVersion ?? null,
321
+ };
322
+ }
323
+
324
+ /**
325
+ * Build the default status loader: open the built-in adapter sealed over the
326
+ * configured SQL URL. Returns `null` when no SQL is configured — spinning up
327
+ * a throwaway PGlite instance would report an empty vault that does not exist.
328
+ *
329
+ * @param processEnv - Environment supplying the SQL URL
330
+ */
331
+ function defaultBuiltinStatusLoader(
332
+ processEnv: Readonly<Record<string, string | undefined>>,
333
+ ): (() => Promise<VaultStatus>) | null {
334
+ const url = processEnv.DATABASE_URL ?? processEnv.OKE_STORE_SQL_URL;
335
+ if (url === undefined || url.trim().length === 0) return null;
336
+ return async () => {
337
+ const { openBuiltinVaultAdapter } = await import("../../drivers/vault-builtin.ts");
338
+ // `masterKey: ""` keeps the adapter sealed — status needs no unseal.
339
+ const opened = await openBuiltinVaultAdapter({ url, env: processEnv, masterKey: "" });
340
+ try {
341
+ return await opened.adapter.status();
342
+ } finally {
343
+ await opened.close();
344
+ }
345
+ };
154
346
  }
155
347
 
156
348
  /** Input for set / rotate. */
@@ -206,6 +398,11 @@ export async function createManifestVaultRuntime(
206
398
  readonly allowDevFallbacks?: boolean;
207
399
  readonly seed?: Readonly<Record<string, string>>;
208
400
  readonly now?: () => number;
401
+ /**
402
+ * Backend driver for the terminal layer. Defaults to the built-in
403
+ * `vault` store when `drivers.vault` is not consulted.
404
+ */
405
+ readonly driverId?: VaultDriverId;
209
406
  } = {},
210
407
  ): Promise<VaultRuntime | null> {
211
408
  const entries = Object.entries(manifest.vault ?? {});
@@ -231,19 +428,18 @@ export async function createManifestVaultRuntime(
231
428
  });
232
429
 
233
430
  const seed = options.seed ?? {};
234
- const env = options.env ?? "local";
235
- // Auto-detect: prefer OpenBao when credentials exist; soft-fallback to memory
236
- // (historical Console behaviour never fail the Console for missing vault).
431
+ const env = options.env ?? "dev";
432
+ // Soft-fallback to memory when the backend is unreachable — the Console
433
+ // must never fail to list contracts because a vault is missing.
237
434
  const runtime = createVaultRuntime({
238
435
  secrets,
239
436
  allowDevFallbacks: options.allowDevFallbacks ?? env !== "prod",
240
437
  now: options.now,
241
438
  chain: buildVaultBootChain({
242
439
  cwd,
243
- driverId: "openbao",
244
- env,
440
+ driverId: options.driverId ?? "vault",
441
+ env: env === "dev" || env === "test" || env === "prod" ? env : "dev",
245
442
  seed,
246
- missingOpenbao: "memory",
247
443
  }),
248
444
  });
249
445
  await runtime.boot();