okengine 0.2.6 → 0.2.8

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 (584) hide show
  1. package/AGENTS.md +24 -23
  2. package/README.md +52 -346
  3. package/docs/spec/console.md +165 -142
  4. package/docs/spec/example.md +490 -312
  5. package/docs/spec/four-applications.md +495 -314
  6. package/docs/spec/unified-theory.md +184 -175
  7. package/package.json +45 -37
  8. package/spec/manifest.v1.schema.json +40 -9
  9. package/src/auth/api-keys.ts +2 -5
  10. package/src/auth/attenuation.ts +2 -6
  11. package/src/auth/auth.test.ts +53 -31
  12. package/src/auth/invoke-as.ts +1 -3
  13. package/src/auth/operator.ts +8 -26
  14. package/src/auth/planes.ts +2 -7
  15. package/src/auth/plugin.ts +4 -7
  16. package/src/auth/roles.ts +1 -5
  17. package/src/auth/sessions.ts +10 -39
  18. package/src/cli/args.ts +1 -5
  19. package/src/cli/ask-dev-mode.ts +40 -0
  20. package/src/cli/build.ts +1 -2
  21. package/src/cli/client-add.test.ts +8 -15
  22. package/src/cli/client-add.ts +5 -14
  23. package/src/cli/completion.test.ts +1 -5
  24. package/src/cli/completion.ts +4 -17
  25. package/src/cli/db-auto-push.test.ts +64 -0
  26. package/src/cli/db-auto-push.ts +72 -0
  27. package/src/cli/db.test.ts +189 -0
  28. package/src/cli/db.ts +386 -0
  29. package/src/cli/dev-app-runner.ts +2 -8
  30. package/src/cli/dev-db-push.test.ts +163 -0
  31. package/src/cli/dev-mode.test.ts +45 -0
  32. package/src/cli/dev-mode.ts +78 -0
  33. package/src/cli/dev.test.ts +148 -21
  34. package/src/cli/dev.ts +208 -134
  35. package/src/cli/doc-drift.test.ts +3 -2
  36. package/src/cli/doc-drift.ts +21 -50
  37. package/src/cli/doc-staleness.test.ts +69 -0
  38. package/src/cli/docker-cli.test.ts +7 -8
  39. package/src/cli/docker.ts +1 -3
  40. package/src/cli/doctor-diff-examples.ts +1 -3
  41. package/src/cli/doctor-diff.test.ts +1 -5
  42. package/src/cli/doctor-diff.ts +17 -46
  43. package/src/cli/doctor-pii.ts +2 -7
  44. package/src/cli/doctor.test.ts +26 -4
  45. package/src/cli/doctor.ts +35 -11
  46. package/src/cli/eval.ts +4 -14
  47. package/src/cli/gates-list.ts +1 -4
  48. package/src/cli/hero-meta.test.ts +17 -19
  49. package/src/cli/hero-meta.ts +20 -30
  50. package/src/cli/images.ts +3 -8
  51. package/src/cli/index.ts +11 -2
  52. package/src/cli/load-config.images.test.ts +14 -14
  53. package/src/cli/load-config.ts +41 -47
  54. package/src/cli/mcp-from-console.ts +1 -4
  55. package/src/cli/mode.ts +45 -0
  56. package/src/cli/ports.test.ts +4 -13
  57. package/src/cli/ports.ts +1 -3
  58. package/src/cli/privacy-erase.ts +1 -3
  59. package/src/cli/registry.ts +75 -25
  60. package/src/cli/schema.ts +3 -10
  61. package/src/cli/stack.ts +2 -7
  62. package/src/cli/start.ts +4 -15
  63. package/src/cli/upgrade.ts +1 -4
  64. package/src/client/budget-entry.ts +1 -6
  65. package/src/client/create.test.ts +6 -12
  66. package/src/client/create.ts +2 -8
  67. package/src/client/errors.ts +1 -4
  68. package/src/client/index.ts +1 -6
  69. package/src/client/notes-contract.test.ts +4 -13
  70. package/src/client/transport.ts +9 -30
  71. package/src/client/types.ts +8 -29
  72. package/src/compiler/aot.test.ts +2 -9
  73. package/src/compiler/aot.ts +1 -4
  74. package/src/compiler/differential.test.ts +3 -11
  75. package/src/compiler/dynamic.ts +1 -4
  76. package/src/compiler/effects-infer.ts +8 -34
  77. package/src/compiler/emit.ts +1 -3
  78. package/src/compiler/extract.test.ts +96 -30
  79. package/src/compiler/extract.ts +362 -156
  80. package/src/compiler/fixtures/skyport/oke.config.ts +1 -1
  81. package/src/compiler/fixtures/skyport/src/flows/bookings/index.ts +7 -3
  82. package/src/compiler/fixtures/skyport/src/flows/payments/index.ts +1 -3
  83. package/src/compiler/fixtures/skyport/src/flows/support/index.ts +4 -1
  84. package/src/compiler/fixtures/skyport.expected.json +24 -83
  85. package/src/compiler/fixtures/triggers/five-triggers.ts +1 -2
  86. package/src/compiler/http-parse.ts +2 -9
  87. package/src/compiler/index.ts +1 -5
  88. package/src/compiler/response.ts +4 -7
  89. package/src/compiler/sucrose.ts +11 -31
  90. package/src/config/define-config.test.ts +57 -34
  91. package/src/config/index.ts +181 -37
  92. package/src/config/resolve-driver.test.ts +28 -17
  93. package/src/console/budget.test.ts +1 -4
  94. package/src/console/index.ts +1 -4
  95. package/src/console/server/access.test.ts +15 -43
  96. package/src/console/server/access.ts +19 -49
  97. package/src/console/server/ai.test.ts +3 -11
  98. package/src/console/server/ai.ts +23 -46
  99. package/src/console/server/app.ts +14 -45
  100. package/src/console/server/auth-rate.test.ts +4 -12
  101. package/src/console/server/bind.ts +1 -5
  102. package/src/console/server/channels.test.ts +2 -6
  103. package/src/console/server/channels.ts +10 -35
  104. package/src/console/server/claim.ts +2 -8
  105. package/src/console/server/clock.test.ts +2 -6
  106. package/src/console/server/clock.ts +8 -26
  107. package/src/console/server/console.test.ts +1 -3
  108. package/src/console/server/diff.test.ts +5 -17
  109. package/src/console/server/diff.ts +10 -31
  110. package/src/console/server/dry-run.audit.test.ts +2 -8
  111. package/src/console/server/flows.ts +64 -233
  112. package/src/console/server/gates.test.ts +14 -50
  113. package/src/console/server/gates.ts +13 -48
  114. package/src/console/server/index.ts +2 -9
  115. package/src/console/server/live.ts +3 -12
  116. package/src/console/server/operator-db.test.ts +4 -15
  117. package/src/console/server/operator-db.ts +13 -32
  118. package/src/console/server/plugin.ts +50 -53
  119. package/src/console/server/plugins.test.ts +2 -6
  120. package/src/console/server/plugins.ts +17 -56
  121. package/src/console/server/runs-pii.ts +2 -7
  122. package/src/console/server/security.gate.test.ts +18 -40
  123. package/src/console/server/serve.ts +10 -25
  124. package/src/console/server/signals.test.ts +1 -3
  125. package/src/console/server/signals.ts +17 -40
  126. package/src/console/server/state.ts +21 -59
  127. package/src/console/server/store.test.ts +20 -22
  128. package/src/console/server/store.ts +31 -76
  129. package/src/console/server/vault.test.ts +12 -29
  130. package/src/console/server/vault.ts +23 -60
  131. package/src/console/ui/access/AccessA11yView.tsx +6 -21
  132. package/src/console/ui/access/a11y.test.tsx +3 -12
  133. package/src/console/ui/access/acknowledgement.test.ts +1 -4
  134. package/src/console/ui/access/acknowledgement.ts +1 -3
  135. package/src/console/ui/access/blast-radius.ts +1 -3
  136. package/src/console/ui/access/confirmation.test.ts +1 -5
  137. package/src/console/ui/access/confirmation.ts +1 -4
  138. package/src/console/ui/access/fixture.ts +1 -5
  139. package/src/console/ui/access/grantable.test.ts +1 -3
  140. package/src/console/ui/access/grantable.ts +2 -7
  141. package/src/console/ui/access/index.ts +2 -9
  142. package/src/console/ui/access/provenance.test.ts +1 -3
  143. package/src/console/ui/access/provenance.ts +2 -6
  144. package/src/console/ui/access/search.test.ts +1 -5
  145. package/src/console/ui/access/search.ts +2 -6
  146. package/src/console/ui/ai/AiA11yView.tsx +6 -17
  147. package/src/console/ui/ai/a11y.test.tsx +2 -5
  148. package/src/console/ui/ai/fixture.ts +2 -7
  149. package/src/console/ui/ai/format.ts +1 -3
  150. package/src/console/ui/ai/group.test.ts +1 -3
  151. package/src/console/ui/ai/group.ts +4 -12
  152. package/src/console/ui/ai/index.ts +2 -9
  153. package/src/console/ui/ai/promotion.test.ts +2 -7
  154. package/src/console/ui/ai/promotion.ts +4 -13
  155. package/src/console/ui/ai/search.test.ts +2 -11
  156. package/src/console/ui/ai/search.ts +3 -13
  157. package/src/console/ui/ai/types.ts +1 -8
  158. package/src/console/ui/architecture/ArchitectureA11yView.tsx +8 -29
  159. package/src/console/ui/architecture/a11y.test.tsx +1 -2
  160. package/src/console/ui/architecture/declared.ts +1 -5
  161. package/src/console/ui/architecture/index.ts +7 -35
  162. package/src/console/ui/architecture/layout.ts +1 -3
  163. package/src/console/ui/architecture/pathologies.ts +10 -19
  164. package/src/console/ui/architecture/search.ts +6 -15
  165. package/src/console/ui/architecture/traffic.ts +4 -14
  166. package/src/console/ui/architecture/types.ts +2 -10
  167. package/src/console/ui/architecture/view.test.ts +7 -19
  168. package/src/console/ui/architecture/view.ts +9 -36
  169. package/src/console/ui/channels/ChannelsA11yView.tsx +4 -13
  170. package/src/console/ui/channels/a11y.test.tsx +1 -2
  171. package/src/console/ui/channels/confirmation.test.ts +1 -4
  172. package/src/console/ui/channels/confirmation.ts +1 -4
  173. package/src/console/ui/channels/findings.ts +1 -5
  174. package/src/console/ui/channels/index.ts +2 -8
  175. package/src/console/ui/channels/locale.test.ts +1 -3
  176. package/src/console/ui/channels/locale.ts +2 -8
  177. package/src/console/ui/channels/search.ts +4 -13
  178. package/src/console/ui/channels/taxonomy.ts +1 -3
  179. package/src/console/ui/clock/ClockA11yView.tsx +9 -26
  180. package/src/console/ui/clock/a11y.test.tsx +2 -5
  181. package/src/console/ui/clock/confirmation.test.ts +1 -3
  182. package/src/console/ui/clock/confirmation.ts +1 -4
  183. package/src/console/ui/clock/findings.ts +1 -4
  184. package/src/console/ui/clock/health.ts +2 -7
  185. package/src/console/ui/clock/index.ts +2 -10
  186. package/src/console/ui/clock/search.test.ts +1 -3
  187. package/src/console/ui/clock/search.ts +2 -6
  188. package/src/console/ui/clock/timeline.test.ts +1 -3
  189. package/src/console/ui/clock/waiting-on.test.ts +1 -5
  190. package/src/console/ui/clock/waiting-on.ts +2 -7
  191. package/src/console/ui/diff/DiffA11yView.tsx +8 -17
  192. package/src/console/ui/diff/a11y.test.tsx +2 -5
  193. package/src/console/ui/diff/group.test.ts +3 -13
  194. package/src/console/ui/diff/group.ts +2 -8
  195. package/src/console/ui/diff/index.ts +2 -8
  196. package/src/console/ui/diff/search.test.ts +1 -5
  197. package/src/console/ui/diff/search.ts +4 -16
  198. package/src/console/ui/diff/summary.ts +1 -2
  199. package/src/console/ui/dist/assets/{index-Dy4jht9P.js → index-BWo8R7NR.js} +2 -2
  200. package/src/console/ui/dist/assets/{panel-access-Dd37LU2c.js → panel-access-C0J2D-a2.js} +1 -1
  201. package/src/console/ui/dist/assets/{panel-ai-CC7LR6-J.js → panel-ai-D_m6WQI8.js} +1 -1
  202. package/src/console/ui/dist/assets/{panel-architecture-B5b3iKCz.js → panel-architecture-CKnXFyUx.js} +1 -1
  203. package/src/console/ui/dist/assets/{panel-channels-CeNjTKXp.js → panel-channels-BOmQ-onL.js} +1 -1
  204. package/src/console/ui/dist/assets/{panel-clock-DgFTLoHV.js → panel-clock-giAq0Ccv.js} +1 -1
  205. package/src/console/ui/dist/assets/{panel-diff-DxehccqB.js → panel-diff-cdonmH8c.js} +1 -1
  206. package/src/console/ui/dist/assets/{panel-flows-BtrVn-Eg.js → panel-flows-DlCU5zjA.js} +2 -2
  207. package/src/console/ui/dist/assets/{panel-gates-Z9MKRGdH.js → panel-gates-XclZxWD5.js} +1 -1
  208. package/src/console/ui/dist/assets/{panel-overview-Dt_AeXgd.js → panel-overview-BznEOTnb.js} +1 -1
  209. package/src/console/ui/dist/assets/{panel-plugins-DWd0TowH.js → panel-plugins-CcGM1g64.js} +1 -1
  210. package/src/console/ui/dist/assets/{panel-runs-DGstFHeq.js → panel-runs-CGWNHLR4.js} +1 -1
  211. package/src/console/ui/dist/assets/{panel-signals-DzEa2Fnt.js → panel-signals-CNywkdak.js} +1 -1
  212. package/src/console/ui/dist/assets/{panel-store-BJkbNgxx.js → panel-store-KmTbFHMH.js} +1 -1
  213. package/src/console/ui/dist/assets/{panel-traces-BaRVO3gM.js → panel-traces-DBLx2ilD.js} +1 -1
  214. package/src/console/ui/dist/assets/panel-vault-CEnFc0dk.js +1 -0
  215. package/src/console/ui/dist/index.html +1 -1
  216. package/src/console/ui/flows/FlowsA11yView.tsx +7 -22
  217. package/src/console/ui/flows/a11y.test.tsx +2 -8
  218. package/src/console/ui/flows/buffer.test.ts +3 -11
  219. package/src/console/ui/flows/buffer.ts +4 -11
  220. package/src/console/ui/flows/confirmation.ts +1 -3
  221. package/src/console/ui/flows/contract.test.ts +3 -7
  222. package/src/console/ui/flows/contract.ts +12 -36
  223. package/src/console/ui/flows/graph.test.ts +3 -11
  224. package/src/console/ui/flows/graph.ts +5 -15
  225. package/src/console/ui/flows/index.ts +1 -6
  226. package/src/console/ui/flows/save-as-test.ts +1 -3
  227. package/src/console/ui/flows/search.ts +8 -25
  228. package/src/console/ui/flows/tiers.ts +2 -9
  229. package/src/console/ui/gates/GatesA11yView.tsx +4 -13
  230. package/src/console/ui/gates/a11y.test.tsx +2 -5
  231. package/src/console/ui/gates/audit.ts +1 -3
  232. package/src/console/ui/gates/denial.test.ts +1 -3
  233. package/src/console/ui/gates/denial.ts +4 -12
  234. package/src/console/ui/gates/findings.ts +1 -3
  235. package/src/console/ui/gates/group.test.ts +3 -3
  236. package/src/console/ui/gates/group.ts +3 -11
  237. package/src/console/ui/gates/index.ts +2 -10
  238. package/src/console/ui/gates/search.ts +3 -10
  239. package/src/console/ui/overview/OverviewA11yView.tsx +9 -27
  240. package/src/console/ui/overview/a11y.test.tsx +1 -2
  241. package/src/console/ui/overview/busiest.ts +1 -3
  242. package/src/console/ui/overview/compose.ts +1 -13
  243. package/src/console/ui/overview/cost.ts +34 -38
  244. package/src/console/ui/overview/fixture.ts +21 -26
  245. package/src/console/ui/overview/golden.ts +4 -14
  246. package/src/console/ui/overview/index.ts +2 -9
  247. package/src/console/ui/overview/rank.test.ts +3 -10
  248. package/src/console/ui/overview/rank.ts +2 -7
  249. package/src/console/ui/overview/slo.test.ts +5 -9
  250. package/src/console/ui/overview/slo.ts +6 -23
  251. package/src/console/ui/overview/verdict.ts +3 -10
  252. package/src/console/ui/plugins/PluginsA11yView.tsx +8 -18
  253. package/src/console/ui/plugins/a11y.test.tsx +1 -2
  254. package/src/console/ui/plugins/fixture.ts +2 -4
  255. package/src/console/ui/plugins/group.test.ts +1 -3
  256. package/src/console/ui/plugins/group.ts +1 -6
  257. package/src/console/ui/plugins/index.ts +3 -13
  258. package/src/console/ui/plugins/search.ts +7 -19
  259. package/src/console/ui/runs/RunsA11yView.tsx +5 -20
  260. package/src/console/ui/runs/a11y.test.tsx +2 -5
  261. package/src/console/ui/runs/explain.ts +2 -6
  262. package/src/console/ui/runs/group.ts +3 -12
  263. package/src/console/ui/runs/histogram.test.ts +2 -11
  264. package/src/console/ui/runs/histogram.ts +1 -4
  265. package/src/console/ui/runs/index.ts +4 -18
  266. package/src/console/ui/runs/project.ts +2 -6
  267. package/src/console/ui/runs/query.test.ts +1 -3
  268. package/src/console/ui/runs/query.ts +12 -35
  269. package/src/console/ui/runs/search.ts +5 -19
  270. package/src/console/ui/runs/trace-link.test.ts +2 -6
  271. package/src/console/ui/runs/trace-link.ts +4 -16
  272. package/src/console/ui/runs/types.ts +1 -3
  273. package/src/console/ui/shell/App.tsx +2 -10
  274. package/src/console/ui/shell/client.ts +22 -115
  275. package/src/console/ui/shell/components/ui.tsx +1 -4
  276. package/src/console/ui/shell/layout/Shell.tsx +2 -4
  277. package/src/console/ui/shell/main.tsx +31 -96
  278. package/src/console/ui/shell/panels/access/AccessPanel.tsx +34 -98
  279. package/src/console/ui/shell/panels/ai/AiPanel.tsx +35 -106
  280. package/src/console/ui/shell/panels/architecture/ArchitecturePanel.tsx +18 -66
  281. package/src/console/ui/shell/panels/channels/ChannelsPanel.tsx +20 -57
  282. package/src/console/ui/shell/panels/clock/ClockPanel.tsx +22 -54
  283. package/src/console/ui/shell/panels/diff/DiffPanel.tsx +20 -61
  284. package/src/console/ui/shell/panels/flows/ContractEditor.tsx +6 -23
  285. package/src/console/ui/shell/panels/flows/FlowDrawer.tsx +13 -28
  286. package/src/console/ui/shell/panels/flows/FlowsPanel.tsx +9 -29
  287. package/src/console/ui/shell/panels/gates/GatesPanel.tsx +24 -80
  288. package/src/console/ui/shell/panels/overview/OverviewPanel.tsx +20 -58
  289. package/src/console/ui/shell/panels/plugins/PluginsPanel.tsx +16 -41
  290. package/src/console/ui/shell/panels/runs/RunsPanel.tsx +31 -99
  291. package/src/console/ui/shell/panels/signals/SignalsPanel.tsx +38 -101
  292. package/src/console/ui/shell/panels/store/StorePanel.tsx +27 -66
  293. package/src/console/ui/shell/panels/traces/TracesPanel.tsx +28 -89
  294. package/src/console/ui/shell/panels/vault/VaultPanel.tsx +22 -53
  295. package/src/console/ui/shell/setup/Wizard.tsx +3 -5
  296. package/src/console/ui/shell/styles.css +1 -2
  297. package/src/console/ui/signals/SignalsA11yView.tsx +9 -33
  298. package/src/console/ui/signals/a11y.test.tsx +2 -5
  299. package/src/console/ui/signals/confirmation.test.ts +1 -5
  300. package/src/console/ui/signals/confirmation.ts +2 -6
  301. package/src/console/ui/signals/dry-run.ts +1 -3
  302. package/src/console/ui/signals/durable.ts +1 -3
  303. package/src/console/ui/signals/findings.ts +1 -3
  304. package/src/console/ui/signals/group.test.ts +2 -8
  305. package/src/console/ui/signals/group.ts +2 -10
  306. package/src/console/ui/signals/index.ts +1 -4
  307. package/src/console/ui/signals/monitor.ts +2 -7
  308. package/src/console/ui/signals/schema-form.test.ts +3 -14
  309. package/src/console/ui/signals/schema-form.ts +1 -4
  310. package/src/console/ui/signals/search.ts +4 -13
  311. package/src/console/ui/store/StoreA11yView.tsx +3 -9
  312. package/src/console/ui/store/a11y.test.tsx +2 -5
  313. package/src/console/ui/store/confirmation.test.ts +1 -3
  314. package/src/console/ui/store/confirmation.ts +1 -4
  315. package/src/console/ui/store/dry-run.ts +2 -5
  316. package/src/console/ui/store/fixture.ts +1 -2
  317. package/src/console/ui/store/group.test.ts +1 -6
  318. package/src/console/ui/store/group.ts +1 -4
  319. package/src/console/ui/store/index.ts +1 -5
  320. package/src/console/ui/store/search.ts +2 -6
  321. package/src/console/ui/store/will-not-fire.ts +1 -2
  322. package/src/console/ui/traces/TracesA11yView.tsx +10 -29
  323. package/src/console/ui/traces/a11y.test.tsx +1 -2
  324. package/src/console/ui/traces/chain.test.ts +5 -19
  325. package/src/console/ui/traces/chain.ts +1 -3
  326. package/src/console/ui/traces/critical-path.test.ts +1 -3
  327. package/src/console/ui/traces/critical-path.ts +2 -6
  328. package/src/console/ui/traces/filter.test.ts +2 -6
  329. package/src/console/ui/traces/filter.ts +5 -13
  330. package/src/console/ui/traces/fold.test.ts +4 -12
  331. package/src/console/ui/traces/fold.ts +1 -3
  332. package/src/console/ui/traces/mini.ts +1 -3
  333. package/src/console/ui/traces/replay.test.ts +1 -3
  334. package/src/console/ui/traces/replay.ts +1 -3
  335. package/src/console/ui/traces/sampling.ts +1 -4
  336. package/src/console/ui/traces/search.ts +4 -17
  337. package/src/console/ui/traces/tier.ts +1 -3
  338. package/src/console/ui/vault/VaultA11yView.tsx +5 -17
  339. package/src/console/ui/vault/a11y.test.tsx +1 -2
  340. package/src/console/ui/vault/blast-radius.ts +1 -3
  341. package/src/console/ui/vault/confirmation.test.ts +1 -5
  342. package/src/console/ui/vault/confirmation.ts +1 -4
  343. package/src/console/ui/vault/dormant.test.ts +1 -4
  344. package/src/console/ui/vault/export-safe.test.ts +1 -5
  345. package/src/console/ui/vault/export-safe.ts +1 -4
  346. package/src/console/ui/vault/fixture.ts +3 -3
  347. package/src/console/ui/vault/group.ts +1 -2
  348. package/src/console/ui/vault/index.ts +2 -10
  349. package/src/console/ui/vault/search.ts +2 -6
  350. package/src/console/ui/vault/types.ts +1 -1
  351. package/src/console/xss.gate.test.ts +1 -3
  352. package/src/docker/compose.ts +112 -20
  353. package/src/docker/derive.ts +5 -19
  354. package/src/docker/docker.test.ts +15 -15
  355. package/src/docker/dockerfile.integration.test.ts +12 -21
  356. package/src/docker/helpers.ts +5 -4
  357. package/src/docker/index.ts +4 -11
  358. package/src/docker/pin.ts +1 -9
  359. package/src/docker/recipes/index.ts +5 -6
  360. package/src/docker/recipes/mailpit.ts +22 -0
  361. package/src/docker/recipes/postgres.ts +17 -6
  362. package/src/docker/recipes/redis.ts +6 -1
  363. package/src/docker/recipes/rustfs.ts +33 -0
  364. package/src/docker/stack-id.test.ts +33 -0
  365. package/src/docker/stack-id.ts +25 -13
  366. package/src/docker/stack.integration.test.ts +6 -21
  367. package/src/docker/types.ts +13 -4
  368. package/src/drivers/ai-anthropic.ts +5 -14
  369. package/src/drivers/ai-mock.ts +2 -5
  370. package/src/drivers/ai-openai-compatible.ts +4 -10
  371. package/src/drivers/ai-providers.test.ts +6 -13
  372. package/src/drivers/bun-native-completeness.test.ts +6 -15
  373. package/src/drivers/channel-console.ts +6 -7
  374. package/src/drivers/channel-fcm.ts +20 -30
  375. package/src/drivers/channel-resend.ts +1 -3
  376. package/src/drivers/channel-smtp.ts +2 -6
  377. package/src/drivers/channel-types.ts +2 -12
  378. package/src/drivers/channel-unifonic.ts +2 -6
  379. package/src/drivers/channel-wa-cloud.ts +2 -6
  380. package/src/drivers/channel-webpush.ts +21 -60
  381. package/src/drivers/conformance.test.ts +2 -10
  382. package/src/drivers/conformance.ts +8 -21
  383. package/src/drivers/fs.ts +2 -8
  384. package/src/drivers/index.ts +12 -56
  385. package/src/drivers/memory.ts +14 -41
  386. package/src/drivers/pgvector.ts +7 -11
  387. package/src/drivers/postgres.ts +7 -13
  388. package/src/drivers/redis.ts +13 -37
  389. package/src/drivers/s3.ts +5 -17
  390. package/src/drivers/signal-engine.ts +12 -49
  391. package/src/drivers/signal-memory.ts +2 -8
  392. package/src/drivers/signal-nats.ts +4 -9
  393. package/src/drivers/signal-postgres.ts +62 -129
  394. package/src/drivers/signal-redis.ts +7 -21
  395. package/src/drivers/signal-types.ts +1 -4
  396. package/src/drivers/sqlite.ts +3 -12
  397. package/src/drivers/types.ts +4 -23
  398. package/src/drivers/vault-env.ts +2 -6
  399. package/src/drivers/vault-infisical.ts +1 -5
  400. package/src/drivers/vault-managed.ts +1 -5
  401. package/src/drivers/vault-memory.ts +1 -5
  402. package/src/drivers/vault-openbao.ts +1 -5
  403. package/src/drivers/vault-sops.ts +10 -35
  404. package/src/drivers/vault-types.ts +1 -7
  405. package/src/elements/ai/declare.ts +4 -14
  406. package/src/elements/ai/eval.ts +2 -6
  407. package/src/elements/ai/pii.ts +1 -3
  408. package/src/elements/ai/runtime.ts +12 -50
  409. package/src/elements/ai/schema.ts +4 -15
  410. package/src/elements/ai.test.ts +13 -24
  411. package/src/elements/ai.ts +1 -5
  412. package/src/elements/channel/consent.ts +3 -12
  413. package/src/elements/channel/costs.ts +4 -15
  414. package/src/elements/channel/declare.ts +1 -4
  415. package/src/elements/channel/email-auth.ts +1 -4
  416. package/src/elements/channel/locale.ts +2 -10
  417. package/src/elements/channel/mask.ts +1 -3
  418. package/src/elements/channel/mime.ts +2 -12
  419. package/src/elements/channel/outcomes.test.ts +1 -5
  420. package/src/elements/channel/outcomes.ts +5 -15
  421. package/src/elements/channel/receipts.ts +2 -7
  422. package/src/elements/channel/runtime.ts +28 -74
  423. package/src/elements/channel/suppression.ts +8 -14
  424. package/src/elements/channel.test.ts +8 -31
  425. package/src/elements/channel.ts +3 -14
  426. package/src/elements/clock/actions.ts +6 -18
  427. package/src/elements/clock/declare.ts +1 -3
  428. package/src/elements/clock/dst.ts +1 -5
  429. package/src/elements/clock/durable.ts +4 -16
  430. package/src/elements/clock/health.ts +2 -7
  431. package/src/elements/clock/leader.ts +2 -9
  432. package/src/elements/clock/reconcile.ts +4 -15
  433. package/src/elements/clock/runtime.ts +2 -5
  434. package/src/elements/clock/schedule.ts +4 -20
  435. package/src/elements/clock.test.ts +2 -7
  436. package/src/elements/clock.ts +5 -23
  437. package/src/elements/gate/permissions.ts +1 -4
  438. package/src/elements/gate/runtime.ts +7 -28
  439. package/src/elements/gate.ts +1 -5
  440. package/src/elements/index.ts +9 -7
  441. package/src/elements/signal/declare.ts +2 -7
  442. package/src/elements/signal/reconcile.test.ts +1 -4
  443. package/src/elements/signal/runtime.ts +1 -3
  444. package/src/elements/signal.test.ts +3 -15
  445. package/src/elements/signal.ts +2 -8
  446. package/src/elements/store/cache.test.ts +46 -0
  447. package/src/elements/store/cache.ts +3 -11
  448. package/src/elements/store/classify.ts +5 -22
  449. package/src/elements/store/declare.ts +8 -17
  450. package/src/elements/store/domain-ddl.test.ts +86 -0
  451. package/src/elements/store/emit-drizzle.ts +363 -0
  452. package/src/elements/store/files-policy.test.ts +1 -5
  453. package/src/elements/store/files-policy.ts +4 -12
  454. package/src/elements/store/load-plugin-tables.ts +103 -0
  455. package/src/elements/store/missing-relation.test.ts +83 -0
  456. package/src/elements/store/missing-relation.ts +38 -0
  457. package/src/elements/store/replica.ts +1 -4
  458. package/src/elements/store/runtime.ts +25 -28
  459. package/src/elements/store/schema-decl.test.ts +227 -0
  460. package/src/elements/store/schema-decl.ts +516 -0
  461. package/src/elements/store/sql-condition.ts +11 -21
  462. package/src/elements/store/sql-session.test.ts +50 -0
  463. package/src/elements/store/sql-session.ts +60 -63
  464. package/src/elements/store/table.ts +35 -19
  465. package/src/elements/store.test.ts +17 -39
  466. package/src/elements/store.ts +37 -31
  467. package/src/elements/vault/chain.ts +34 -0
  468. package/src/elements/vault/declare.ts +22 -32
  469. package/src/elements/vault/fingerprint.ts +2 -7
  470. package/src/elements/vault/redact.ts +2 -6
  471. package/src/elements/vault/runtime.ts +18 -32
  472. package/src/elements/vault.test.ts +12 -28
  473. package/src/elements/vault.ts +8 -12
  474. package/src/index.ts +5 -2
  475. package/src/kernel/adopt-routes.ts +15 -29
  476. package/src/kernel/app.ts +34 -94
  477. package/src/kernel/auth-resolve.ts +2 -9
  478. package/src/kernel/boot-bind/ai.ts +1 -4
  479. package/src/kernel/boot-bind/channel.ts +2 -8
  480. package/src/kernel/boot-bind/clock.ts +2 -6
  481. package/src/kernel/boot-bind/gate.ts +2 -8
  482. package/src/kernel/boot-bind/runs.ts +1 -3
  483. package/src/kernel/boot-bind/signal.ts +3 -10
  484. package/src/kernel/boot-bind/store.test.ts +17 -17
  485. package/src/kernel/boot-bind/store.ts +44 -50
  486. package/src/kernel/boot-bind/vault.ts +2 -8
  487. package/src/kernel/boot.test.ts +4 -9
  488. package/src/kernel/boot.ts +29 -76
  489. package/src/kernel/budget.test.ts +1 -3
  490. package/src/kernel/capability.ts +3 -10
  491. package/src/kernel/dry-run.test.ts +1 -4
  492. package/src/kernel/dry-run.ts +3 -11
  493. package/src/kernel/effects.test.ts +1 -5
  494. package/src/kernel/effects.ts +4 -11
  495. package/src/kernel/errors.registry.test.ts +2 -8
  496. package/src/kernel/errors.ts +23 -32
  497. package/src/kernel/flow.test.ts +12 -25
  498. package/src/kernel/flow.ts +5 -25
  499. package/src/kernel/fx.test.ts +15 -44
  500. package/src/kernel/fx.ts +27 -79
  501. package/src/kernel/hook-timing.test.ts +3 -6
  502. package/src/kernel/hook-timing.ts +5 -14
  503. package/src/kernel/hooks.test.ts +10 -10
  504. package/src/kernel/hooks.ts +3 -12
  505. package/src/kernel/index.ts +4 -17
  506. package/src/kernel/journal.ts +7 -31
  507. package/src/kernel/on.ts +1 -6
  508. package/src/kernel/pipeline.test.ts +10 -19
  509. package/src/kernel/pipeline.ts +5 -17
  510. package/src/kernel/plug.ts +4 -11
  511. package/src/kernel/plugin/conflicts.test.ts +13 -25
  512. package/src/kernel/plugin/decorate.test.ts +8 -13
  513. package/src/kernel/plugin/scoping.test.ts +4 -11
  514. package/src/kernel/plugin.ts +48 -24
  515. package/src/kernel/registry.ts +80 -29
  516. package/src/kernel/router.test.ts +15 -13
  517. package/src/kernel/router.ts +9 -29
  518. package/src/kernel/routing-budget.test.ts +1 -3
  519. package/src/kernel/run-telemetry.ts +1 -3
  520. package/src/kernel/triggers.ts +4 -21
  521. package/src/manifest/diff.test.ts +26 -91
  522. package/src/manifest/diff.ts +95 -225
  523. package/src/manifest/index.ts +2 -9
  524. package/src/manifest/types.ts +29 -5
  525. package/src/manifest/undeclared.test.ts +4 -12
  526. package/src/manifest/undeclared.ts +1 -2
  527. package/src/manifest/validate.test.ts +2 -6
  528. package/src/manifest/validate.ts +4 -14
  529. package/src/mcp/authorization.ts +8 -27
  530. package/src/mcp/confirmation.ts +3 -10
  531. package/src/mcp/data.ts +2 -6
  532. package/src/mcp/docs-index.ts +4 -7
  533. package/src/mcp/docs-mcp.test.ts +3 -12
  534. package/src/mcp/docs-server.ts +7 -27
  535. package/src/mcp/docs-tools.ts +2 -6
  536. package/src/mcp/index.ts +1 -6
  537. package/src/mcp/injection.gate.test.ts +4 -18
  538. package/src/mcp/mcp.test.ts +18 -49
  539. package/src/mcp/protocol.ts +3 -10
  540. package/src/mcp/server.ts +11 -52
  541. package/src/mcp/session.ts +4 -14
  542. package/src/mcp/tools.ts +14 -50
  543. package/src/plugins/catalogue.test.ts +3 -7
  544. package/src/plugins/catalogue.ts +1 -3
  545. package/src/plugins/node-import-scan.ts +2 -5
  546. package/src/plugins/supply-chain.ts +5 -17
  547. package/src/release/exports.ts +3 -8
  548. package/src/release/measure.exports.test.ts +1 -3
  549. package/src/release/measure.ts +15 -43
  550. package/src/runs/bench.test.ts +1 -3
  551. package/src/runs/collect.ts +8 -25
  552. package/src/runs/drivers/clickhouse.ts +2 -9
  553. package/src/runs/drivers/files.ts +9 -31
  554. package/src/runs/drivers/memory.ts +5 -22
  555. package/src/runs/drivers/postgres.ts +8 -20
  556. package/src/runs/duckdb.ts +2 -8
  557. package/src/runs/index.ts +3 -14
  558. package/src/runs/outlier.ts +3 -10
  559. package/src/runs/parquet.ts +8 -26
  560. package/src/runs/privacy.ts +2 -8
  561. package/src/runs/runs.test.ts +3 -9
  562. package/src/runs/runtime.ts +7 -32
  563. package/src/runs/shred.ts +10 -29
  564. package/src/runs/types.ts +1 -4
  565. package/src/runtime/bun.ts +4 -15
  566. package/src/runtime/cold-start.bench.ts +1 -3
  567. package/src/runtime/dev-request-log.test.ts +1 -4
  568. package/src/runtime/dev-request-log.ts +1 -4
  569. package/src/runtime/index.ts +1 -6
  570. package/src/runtime/primitives.ts +5 -4
  571. package/src/runtime/security.ts +3 -13
  572. package/src/runtime/serve.test.ts +4 -7
  573. package/src/runtime/types.ts +1 -4
  574. package/src/runtime/web-standard.ts +3 -15
  575. package/src/term.test.ts +4 -6
  576. package/src/term.ts +49 -98
  577. package/src/test/create-test-app.test.ts +4 -14
  578. package/src/test/create-test-app.ts +13 -31
  579. package/src/test/provisions.integration.test.ts +3 -11
  580. package/src/upgrade/codemods.test.ts +25 -6
  581. package/src/upgrade/codemods.ts +116 -3
  582. package/src/validation/standard-schema.test.ts +2 -5
  583. package/src/validation/standard-schema.ts +13 -33
  584. package/src/console/ui/dist/assets/panel-vault-BbfWdox0.js +0 -1
package/src/cli/dev.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * `oke dev` — watch · hot reload · Console :6533 · MCP :6535 · client types on save.
3
- * `oke dev --stack` boots infra compose and binds prod store drivers (Postgres/Redis).
3
+ * Mode: `local` (in-memory) or `docker` (compose infra + host Bun).
4
4
  */
5
5
 
6
6
  import { watch } from "node:fs";
@@ -13,7 +13,6 @@ import type { ConsoleState } from "../console/server/state.ts";
13
13
  import {
14
14
  DEFAULT_DOCKER_DIR,
15
15
  deriveInfrastructure,
16
- formatStackEnv,
17
16
  loadExistingStackCredentials,
18
17
  stackAppSlug,
19
18
  stackInstanceId,
@@ -22,11 +21,7 @@ import {
22
21
  } from "../docker/index.ts";
23
22
  import type { Manifest } from "../manifest/types.ts";
24
23
  import type { McpContext } from "../mcp/tools.ts";
25
- import {
26
- APP_PORT,
27
- CONSOLE_PORT,
28
- MCP_PORT,
29
- } from "../runtime/types.ts";
24
+ import { APP_PORT, CONSOLE_PORT, MCP_PORT } from "../runtime/types.ts";
30
25
  import {
31
26
  formatDevBanner,
32
27
  formatDevLogSeparator,
@@ -36,15 +31,16 @@ import {
36
31
  } from "../term.ts";
37
32
  import { clientAdd } from "./client-add.ts";
38
33
  import { resolveDriverId } from "../config/index.ts";
34
+ import { askDevMode, type AskDevModeFn } from "./ask-dev-mode.ts";
39
35
  import {
40
- buildDevHeroSnapshot,
41
- encodeHeroSnapshot,
42
- } from "./hero-meta.ts";
43
- import {
44
- loadManifest,
45
- loadOkeConfig,
46
- resolveImages,
47
- } from "./load-config.ts";
36
+ createDebouncedRunner,
37
+ isDomainSchemaWatchPath,
38
+ resolveDevAutoPush,
39
+ } from "./db-auto-push.ts";
40
+ import { resolveDrizzleConfigPath, runPush } from "./db.ts";
41
+ import { readDevMode, shouldAskDevMode, writeDevMode, type DevMode } from "./dev-mode.ts";
42
+ import { buildDevHeroSnapshot, encodeHeroSnapshot } from "./hero-meta.ts";
43
+ import { loadManifest, loadOkeConfig, resolveImages } from "./load-config.ts";
48
44
  import { mcpContextFromConsole } from "./mcp-from-console.ts";
49
45
  import { resolveDevPorts } from "./ports.ts";
50
46
 
@@ -114,7 +110,30 @@ export interface DevSession {
114
110
  export interface DevOptions {
115
111
  readonly cwd?: string;
116
112
  readonly entry?: string;
117
- readonly stack?: boolean | readonly string[];
113
+ /**
114
+ * Session-only mode override. `true` / role list → docker; `false` → local.
115
+ * When unset, resolve from `.oke/mode` / TTY ask / non-TTY default `local`.
116
+ */
117
+ readonly docker?: boolean | readonly string[];
118
+ /** Force local for this session only (never writes `.oke/mode`). */
119
+ readonly local?: boolean;
120
+ /**
121
+ * Opt out of auto `oke db push` on schema change for this session.
122
+ * Also set via `--no-db-push`.
123
+ */
124
+ readonly noDbPush?: boolean;
125
+ /**
126
+ * Injectable domain-schema push (tests). Default: {@link runPush}.
127
+ *
128
+ * @param cwd - Project root
129
+ */
130
+ readonly dbPush?: (cwd: string) => Promise<number>;
131
+ /**
132
+ * Called when a schema watch path triggers auto-push (tests).
133
+ *
134
+ * @param filename - Relative path from the watcher
135
+ */
136
+ readonly onDbAutoPush?: (filename: string) => void;
118
137
  readonly images?: Readonly<Record<string, string>>;
119
138
  readonly credentials?: DeriveOptions["credentials"];
120
139
  readonly write?: (text: string) => void;
@@ -138,15 +157,12 @@ export interface DevOptions {
138
157
  readonly consolePort?: number;
139
158
  readonly mcpPort?: number;
140
159
  /**
141
- * Boot compose stack (injectable).
160
+ * Boot compose (injectable).
142
161
  *
143
162
  * @param composeFiles - `-f` list excluding override if missing
144
- * @param cwd - Project root
163
+ * @param cwd - Compose directory (`docker/`)
145
164
  */
146
- readonly composeUp?: (
147
- composeFiles: readonly string[],
148
- cwd: string,
149
- ) => Promise<void>;
165
+ readonly composeUp?: (composeFiles: readonly string[], cwd: string) => Promise<void>;
150
166
  /**
151
167
  * Regenerate client types (injectable).
152
168
  *
@@ -166,10 +182,15 @@ export interface DevOptions {
166
182
  * (import → `app.boot()` → `createBunRuntime().serve`) so Bun soft-reloads
167
183
  * app code while preserving the listen socket.
168
184
  */
169
- readonly startApp?: (
170
- entry: string,
171
- env: Record<string, string>,
172
- ) => Promise<DevAppHandle>;
185
+ readonly startApp?: (entry: string, env: Record<string, string>) => Promise<DevAppHandle>;
186
+ /**
187
+ * Injectable mode prompt (tests). Default: {@link askDevMode}.
188
+ */
189
+ readonly ask?: AskDevModeFn;
190
+ /**
191
+ * Override stdin TTY detection (tests). Default: `process.stdin.isTTY`.
192
+ */
193
+ readonly stdinIsTTY?: boolean;
173
194
  }
174
195
 
175
196
  /** Result of a dry-run / prepared / live-but-detached dev session. */
@@ -236,20 +257,55 @@ export async function runDev(options: DevOptions = {}): Promise<DevResult> {
236
257
  return { code: 1 };
237
258
  }
238
259
 
260
+ const explicitLocal = options.local === true;
261
+ const explicitDocker = options.docker === true || Array.isArray(options.docker);
262
+ if (explicitLocal && explicitDocker) {
263
+ console.error("oke dev: use either --local or --docker, not both");
264
+ return { code: 1 };
265
+ }
266
+
267
+ const savedMode = await readDevMode(cwd);
268
+ const explicit = explicitLocal || explicitDocker;
269
+ let mode: DevMode;
270
+ if (explicitLocal) {
271
+ mode = "local";
272
+ } else if (explicitDocker) {
273
+ mode = "docker";
274
+ } else if (savedMode !== null) {
275
+ mode = savedMode;
276
+ } else if (
277
+ shouldAskDevMode({
278
+ saved: savedMode,
279
+ explicit,
280
+ stdinIsTTY: options.stdinIsTTY ?? process.stdin.isTTY,
281
+ })
282
+ ) {
283
+ const ask = options.ask ?? askDevMode;
284
+ const chosen = await ask();
285
+ if (chosen === null) {
286
+ console.error("oke dev: cancelled");
287
+ return { code: 1 };
288
+ }
289
+ mode = chosen;
290
+ await writeDevMode(cwd, mode);
291
+ } else {
292
+ // Non-TTY + unset: deterministic local — zero ask, zero docker, no save.
293
+ mode = "local";
294
+ }
295
+
239
296
  let stackRoles: string[] | null = null;
240
297
  let composeFiles: string[] | null = null;
241
298
  let stackEnv: Record<string, string> | null = null;
242
299
  let stackSqlDriver = "postgres";
243
300
  let stackKvDriver = "redis";
244
- let loadedConfig: Awaited<ReturnType<typeof loadOkeConfig>>["config"] | null =
245
- null;
301
+ let loadedConfig: Awaited<ReturnType<typeof loadOkeConfig>>["config"] | null = null;
246
302
  try {
247
303
  loadedConfig = (await loadOkeConfig(cwd)).config;
248
304
  } catch {
249
305
  loadedConfig = null;
250
306
  }
251
307
 
252
- if (options.stack) {
308
+ if (mode === "docker") {
253
309
  let images = options.images;
254
310
  if (!images) {
255
311
  if (!loadedConfig) {
@@ -271,28 +327,23 @@ export async function runDev(options: DevOptions = {}): Promise<DevResult> {
271
327
  loadedConfig = null;
272
328
  }
273
329
  }
274
- if (Array.isArray(options.stack)) {
275
- const allow = new Set(options.stack);
276
- images = Object.fromEntries(
277
- Object.entries(images).filter(([role]) => allow.has(role)),
278
- );
330
+ if (Array.isArray(options.docker)) {
331
+ const allow = new Set(options.docker);
332
+ images = Object.fromEntries(Object.entries(images).filter(([role]) => allow.has(role)));
279
333
  stackRoles = [...allow];
280
334
  } else {
281
335
  stackRoles = Object.keys(images);
282
336
  }
283
337
 
284
- stackSqlDriver =
285
- resolveDriverId(loadedConfig?.drivers?.store?.sql, "prod") ?? "postgres";
286
- stackKvDriver =
287
- resolveDriverId(loadedConfig?.drivers?.store?.kv, "prod") ?? "redis";
338
+ stackSqlDriver = resolveDriverId(loadedConfig?.drivers?.store?.sql, "prod") ?? "postgres";
339
+ stackKvDriver = resolveDriverId(loadedConfig?.drivers?.store?.kv, "prod") ?? "redis";
288
340
 
289
341
  const composeDir = DEFAULT_DOCKER_DIR;
290
342
  const dockerOut = resolve(cwd, composeDir);
291
343
  const instanceId = stackInstanceId(cwd);
292
344
  const appSlug = stackAppSlug(cwd);
293
345
  const reusedCreds =
294
- options.credentials ??
295
- (await loadExistingStackCredentials(cwd, stackRoles));
346
+ options.credentials ?? (await loadExistingStackCredentials(cwd, stackRoles));
296
347
  const derived = deriveInfrastructure({
297
348
  images,
298
349
  app: appSlug,
@@ -304,38 +355,40 @@ export async function runDev(options: DevOptions = {}): Promise<DevResult> {
304
355
  host: "127.0.0.1",
305
356
  });
306
357
  // Layer 4 is user-owned — include only if the file already exists.
307
- const existingOverride = await Bun.file(
308
- resolve(dockerOut, "compose.override.yml"),
309
- ).exists();
358
+ const existingOverride = await Bun.file(resolve(dockerOut, "compose.override.yml")).exists();
310
359
  composeFiles = derived.composeFiles.filter(
311
360
  (f) => f !== "compose.override.yml" || existingOverride,
312
361
  );
313
362
  stackEnv = { ...derived.stackEnv };
314
363
 
315
364
  if (!options.dryRun) {
316
- await writeDerivedFiles(derived, dockerOut, {
317
- writeStackEnv: true,
318
- stackEnvDir: cwd,
319
- });
320
- // Ensure .env.stack is at project root for the host Bun app / vault.
321
- await Bun.write(resolve(cwd, ".env.stack"), formatStackEnv(stackEnv));
322
- const up =
323
- options.composeUp ??
324
- (async (files, dir) => {
325
- const args = ["compose", ...files.flatMap((f) => ["-f", f]), "up", "-d"];
326
- const proc = Bun.spawn(["docker", ...args], {
327
- cwd: dir,
328
- stdout: "inherit",
329
- stderr: "inherit",
330
- env: { ...process.env, ...stackEnv! },
331
- });
332
- const code = await proc.exited;
333
- if (code !== 0) {
334
- throw new Error(`oke dev --stack: docker compose exited ${code}`);
335
- }
365
+ try {
366
+ await writeDerivedFiles(derived, dockerOut, {
367
+ writeStackEnv: true,
336
368
  });
337
- // Compose files live under docker/; cwd for compose is that directory.
338
- await up(composeFiles, dockerOut);
369
+ const up =
370
+ options.composeUp ??
371
+ (async (files, dir) => {
372
+ const args = ["compose", ...files.flatMap((f) => ["-f", f]), "up", "-d"];
373
+ const proc = Bun.spawn(["docker", ...args], {
374
+ cwd: dir,
375
+ stdout: "inherit",
376
+ stderr: "inherit",
377
+ env: { ...process.env, ...stackEnv! },
378
+ });
379
+ const code = await proc.exited;
380
+ if (code !== 0) {
381
+ throw new Error(`oke dev --docker: docker compose exited ${code}`);
382
+ }
383
+ });
384
+ // Compose files live under docker/; cwd for compose is that directory.
385
+ await up(composeFiles, dockerOut);
386
+ } catch (err) {
387
+ const msg = err instanceof Error ? err.message : String(err);
388
+ console.error(msg);
389
+ console.error("oke dev: docker mode failed — fix compose, or run `oke mode local`");
390
+ return { code: 1 };
391
+ }
339
392
  const roleLabel = (role: string): string => {
340
393
  if (role === "store.sql") return "postgres";
341
394
  if (role === "store.kv") return "redis";
@@ -370,9 +423,9 @@ export async function runDev(options: DevOptions = {}): Promise<DevResult> {
370
423
 
371
424
  let okeVersion = "0.0.0";
372
425
  try {
373
- const pkg = (await Bun.file(
374
- resolve(import.meta.dir, "../../package.json"),
375
- ).json()) as { version?: string };
426
+ const pkg = (await Bun.file(resolve(import.meta.dir, "../../package.json")).json()) as {
427
+ version?: string;
428
+ };
376
429
  if (typeof pkg.version === "string") okeVersion = pkg.version;
377
430
  } catch {
378
431
  // shipped binary may not sit next to package.json
@@ -380,9 +433,9 @@ export async function runDev(options: DevOptions = {}): Promise<DevResult> {
380
433
 
381
434
  const heroSnapshot = buildDevHeroSnapshot({
382
435
  config: loadedConfig,
383
- stack: Boolean(options.stack),
384
- sqlDriver: options.stack ? stackSqlDriver : undefined,
385
- kvDriver: options.stack ? stackKvDriver : undefined,
436
+ docker: mode === "docker",
437
+ sqlDriver: mode === "docker" ? stackSqlDriver : undefined,
438
+ kvDriver: mode === "docker" ? stackKvDriver : undefined,
386
439
  version: okeVersion,
387
440
  nodeEnv: "development",
388
441
  });
@@ -399,6 +452,12 @@ export async function runDev(options: DevOptions = {}): Promise<DevResult> {
399
452
 
400
453
  if (options.dryRun) return { code: 0, plan };
401
454
 
455
+ const autoPushEnabled = resolveDevAutoPush({
456
+ noDbPush: options.noDbPush,
457
+ docker: Boolean(stackEnv),
458
+ configAutoPush: loadedConfig?.db?.autoPush,
459
+ });
460
+
402
461
  const env: Record<string, string> = {
403
462
  ...(process.env as Record<string, string>),
404
463
  NODE_ENV: "development",
@@ -408,10 +467,12 @@ export async function runDev(options: DevOptions = {}): Promise<DevResult> {
408
467
  OKE_DEV_HERO_CONSOLE: `http://127.0.0.1:${consolePort}`,
409
468
  OKE_DEV_HERO_MCP: `http://127.0.0.1:${mcpPort}`,
410
469
  OKE_DEV_HERO_META: encodeHeroSnapshot(heroSnapshot),
470
+ // Propagate opt-out so the app disables ensureFromMeta when auto-push owns DDL.
471
+ ...(autoPushEnabled ? { OKE_DB_AUTO_PUSH: "1" } : { OKE_DB_AUTO_PUSH: "0" }),
411
472
  ...(stackEnv ?? {}),
412
473
  ...(stackEnv
413
474
  ? {
414
- OKE_STACK: "1",
475
+ OKE_DOCKER: "1",
415
476
  OKE_SQL_DRIVER: stackSqlDriver,
416
477
  OKE_KV_DRIVER: stackKvDriver,
417
478
  }
@@ -419,18 +480,12 @@ export async function runDev(options: DevOptions = {}): Promise<DevResult> {
419
480
  };
420
481
  process.env.OKE_DEV_REQUEST_LOG = "1";
421
482
 
422
- const startApp =
423
- options.startApp ??
424
- ((entryPath, appEnv) => startAppHot(cwd, entryPath, appEnv));
483
+ const startApp = options.startApp ?? ((entryPath, appEnv) => startAppHot(cwd, entryPath, appEnv));
425
484
 
426
485
  const seedManifest =
427
- options.manifest !== undefined
428
- ? options.manifest
429
- : await tryLoadProjectManifest(cwd);
486
+ options.manifest !== undefined ? options.manifest : await tryLoadProjectManifest(cwd);
430
487
 
431
- async function refreshManifestInto(
432
- state: ConsoleState | null,
433
- ): Promise<void> {
488
+ async function refreshManifestInto(state: ConsoleState | null): Promise<void> {
434
489
  if (!state) return;
435
490
  try {
436
491
  const { extractManifest } = await import("../compiler/extract.ts");
@@ -445,9 +500,7 @@ export async function runDev(options: DevOptions = {}): Promise<DevResult> {
445
500
  const serveConsole =
446
501
  options.serveConsole ??
447
502
  (async (port) => {
448
- const { serveConsole: serveConsoleKernel } = await import(
449
- "../console/server/serve.ts"
450
- );
503
+ const { serveConsole: serveConsoleKernel } = await import("../console/server/serve.ts");
451
504
  const server = await serveConsoleKernel({
452
505
  port,
453
506
  hostname: "127.0.0.1",
@@ -455,16 +508,9 @@ export async function runDev(options: DevOptions = {}): Promise<DevResult> {
455
508
  env: "dev",
456
509
  silentClaim: options.silentClaim ?? false,
457
510
  ...(options.secret !== undefined ? { secret: options.secret } : {}),
458
- ...(seedManifest !== undefined && seedManifest !== null
459
- ? { manifest: seedManifest }
460
- : {}),
511
+ ...(seedManifest !== undefined && seedManifest !== null ? { manifest: seedManifest } : {}),
461
512
  });
462
- write(
463
- formatServiceLine(
464
- "Console",
465
- `http://127.0.0.1:${server.port}`,
466
- ),
467
- );
513
+ write(formatServiceLine("Console", `http://127.0.0.1:${server.port}`));
468
514
  return {
469
515
  console: server.console,
470
516
  port: server.port,
@@ -538,27 +584,53 @@ export async function runDev(options: DevOptions = {}): Promise<DevResult> {
538
584
  const boundMcpPort = mcpServer?.port ?? mcpPort;
539
585
  const mcpUrl = mcpServer?.url ?? null;
540
586
 
541
- const appUrl =
542
- app.url?.origin ?? `http://127.0.0.1:${boundAppPort}`;
587
+ const appUrl = app.url?.origin ?? `http://127.0.0.1:${boundAppPort}`;
543
588
  await regen(appUrl);
589
+
590
+ const dbPush =
591
+ options.dbPush ??
592
+ (async (projectCwd: string) => {
593
+ const configPath = await resolveDrizzleConfigPath(projectCwd);
594
+ return runPush(configPath, (t) => write(t));
595
+ });
596
+
597
+ let lastSchemaFilename = "";
598
+ const autoPushRunner = createDebouncedRunner(async () => {
599
+ if (!autoPushEnabled) return;
600
+ options.onDbAutoPush?.(lastSchemaFilename);
601
+ write(formatStatusLine("oke db push (schema change)"));
602
+ try {
603
+ await dbPush(cwd);
604
+ } catch {
605
+ // Mid-edit / kit unavailable — next save retries.
606
+ }
607
+ });
608
+
609
+ // Initial sync so local DB matches schema.ts without a prior manual push.
610
+ if (autoPushEnabled) {
611
+ lastSchemaFilename = "src/schema.ts";
612
+ autoPushRunner.trigger();
613
+ }
614
+
544
615
  write(formatDevLogSeparator());
545
616
 
546
- const watcher = watch(
547
- resolve(cwd, "src"),
548
- { recursive: true },
549
- () => {
550
- void regen(appUrl);
551
- // Only live-extract when the host did not pin a Manifest (tests).
552
- if (options.manifest === undefined) {
553
- void refreshManifestInto(consoleState);
554
- }
555
- },
556
- );
617
+ const watcher = watch(resolve(cwd, "src"), { recursive: true }, (_event, filename) => {
618
+ void regen(appUrl);
619
+ // Only live-extract when the host did not pin a Manifest (tests).
620
+ if (options.manifest === undefined) {
621
+ void refreshManifestInto(consoleState);
622
+ }
623
+ if (autoPushEnabled && isDomainSchemaWatchPath(filename?.toString())) {
624
+ lastSchemaFilename = filename?.toString() ?? "schema.ts";
625
+ autoPushRunner.trigger();
626
+ }
627
+ });
557
628
 
558
629
  let stopped = false;
559
630
  const stop = () => {
560
631
  if (stopped) return;
561
632
  stopped = true;
633
+ autoPushRunner.cancel();
562
634
  watcher.close();
563
635
  app.stop();
564
636
  consoleServer.stop();
@@ -619,9 +691,7 @@ function isSparseManifest(manifest: Manifest): boolean {
619
691
  *
620
692
  * @param cwd - Project root
621
693
  */
622
- async function tryLoadProjectManifest(
623
- cwd: string,
624
- ): Promise<Manifest | null | undefined> {
694
+ async function tryLoadProjectManifest(cwd: string): Promise<Manifest | null | undefined> {
625
695
  let extracted: Manifest | undefined;
626
696
  try {
627
697
  const { extractManifest } = await import("../compiler/extract.ts");
@@ -658,10 +728,7 @@ async function startAppHot(
658
728
  ): Promise<DevAppHandle> {
659
729
  const absoluteEntry = resolve(cwd, entryPath);
660
730
  const runner = resolve(import.meta.dir, "dev-app-runner.ts");
661
- const readyPath = join(
662
- tmpdir(),
663
- `oke-dev-ready-${crypto.randomUUID()}.txt`,
664
- );
731
+ const readyPath = join(tmpdir(), `oke-dev-ready-${crypto.randomUUID()}.txt`);
665
732
  const hostname = "127.0.0.1";
666
733
  const env: Record<string, string> = {
667
734
  ...appEnv,
@@ -696,11 +763,7 @@ async function startAppHot(
696
763
  };
697
764
 
698
765
  try {
699
- const boundPort = await waitForAppReady(
700
- readyPath,
701
- proc,
702
- APP_READY_TIMEOUT_MS,
703
- );
766
+ const boundPort = await waitForAppReady(readyPath, proc, APP_READY_TIMEOUT_MS);
704
767
  // Child prints the App ready line (again on each soft reload).
705
768
  const url = new URL(`http://${hostname}:${boundPort}/`);
706
769
  return { stop, port: boundPort, url };
@@ -726,9 +789,7 @@ async function waitForAppReady(
726
789
  while (Date.now() - started < timeoutMs) {
727
790
  const exitCode = proc.exitCode;
728
791
  if (exitCode !== null) {
729
- throw new Error(
730
- `oke dev: app process exited before ready (code ${exitCode})`,
731
- );
792
+ throw new Error(`oke dev: app process exited before ready (code ${exitCode})`);
732
793
  }
733
794
  if (await Bun.file(readyPath).exists()) {
734
795
  const text = (await Bun.file(readyPath).text()).trim();
@@ -740,44 +801,57 @@ async function waitForAppReady(
740
801
  }
741
802
  await Bun.sleep(25);
742
803
  }
743
- throw new Error(
744
- `oke dev: app did not become ready within ${timeoutMs}ms`,
745
- );
804
+ throw new Error(`oke dev: app did not become ready within ${timeoutMs}ms`);
746
805
  }
747
806
 
748
807
  /**
749
- * CLI entry for `oke dev [--stack|-s [roles]]`.
808
+ * CLI entry for `oke dev [--local|-l] [--docker|-d [roles]]`.
750
809
  *
751
810
  * @param args - Args after `dev`
752
811
  */
753
812
  export async function devCli(args: readonly string[]): Promise<number> {
754
- let stack: boolean | string[] | undefined;
813
+ let docker: boolean | string[] | undefined;
814
+ let local = false;
815
+ let noDbPush = false;
755
816
  let entry: string | undefined;
756
817
  for (let i = 0; i < args.length; i++) {
757
818
  const a = args[i]!;
758
- if (a === "--stack" || a === "-s") {
819
+ if (a === "--local" || a === "-l") {
820
+ local = true;
821
+ } else if (a === "--docker" || a === "-d") {
759
822
  const next = args[i + 1];
760
823
  if (next && !next.startsWith("-") && /^[\w.,]+$/.test(next)) {
761
- stack = next.split(",").map((s) => s.trim()).filter(Boolean);
824
+ docker = next
825
+ .split(",")
826
+ .map((s) => s.trim())
827
+ .filter(Boolean);
762
828
  i++;
763
829
  } else {
764
- stack = true;
830
+ docker = true;
765
831
  }
832
+ } else if (a === "--no-db-push") {
833
+ noDbPush = true;
766
834
  } else if (a === "--entry" || a === "-e") entry = args[++i];
767
835
  else if (a === "--help" || a === "-h") {
768
- console.log(`oke dev [--stack|-s [roles]] [--entry|-e src/app.ts]
836
+ console.log(`oke dev [--local|-l] [--docker|-d [roles]] [--no-db-push] [--entry|-e src/app.ts]
769
837
 
770
838
  Watch · hot reload · Console :6533 · app :6530 · MCP :6535
771
839
  Regenerates client types on every save.
772
- --stack boots infra under docker/ and runs the app on host Bun with prod
773
- store drivers (Postgres/Redis) so local mimics the server.
774
- Partial roles: -s store.sql,store.kv.
840
+ Local mode auto-runs \`oke db push\` when schema.ts changes (opt out: --no-db-push).
841
+
842
+ Bare \`oke dev\` uses .oke/mode (one-time prompt on a TTY; non-TTY → local).
843
+ --local / --docker override for this session only (never write .oke/mode).
844
+ --docker boots infra under docker/ and runs the app on host Bun with prod
845
+ store drivers (Postgres/Redis). Partial roles: -d store.sql,store.kv.
846
+ Change the saved default with \`oke mode local|docker\`.
775
847
  `);
776
848
  return 0;
777
849
  }
778
850
  }
779
851
  const { code } = await runDev({
780
- stack: stack === undefined ? undefined : stack,
852
+ ...(local ? { local: true } : {}),
853
+ ...(docker === undefined ? {} : { docker }),
854
+ ...(noDbPush ? { noDbPush: true } : {}),
781
855
  entry,
782
856
  });
783
857
  return code;
@@ -12,8 +12,9 @@ import {
12
12
  } from "./doc-drift.ts";
13
13
 
14
14
  describe("doc-drift", () => {
15
- test("normalizeTs trims trailing whitespace", () => {
16
- expect(normalizeTs("a \n b\t\n")).toBe("a\n b");
15
+ test("normalizeTs collapses whitespace (indent-insensitive)", () => {
16
+ expect(normalizeTs("a \n b\t\n")).toBe("a b");
17
+ expect(normalizeTs(" const t = 1;\n const u = 2;")).toBe("const t = 1; const u = 2;");
17
18
  });
18
19
 
19
20
  test("parseClaimedFences picks headed typescript only", () => {