okengine 0.21.1 → 0.23.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 (342) hide show
  1. package/AGENTS.md +11 -4
  2. package/LICENSE +202 -0
  3. package/NOTICE +2 -0
  4. package/README.md +15 -9
  5. package/manifest.v1.schema.json +54 -0
  6. package/package.json +53 -38
  7. package/site/content/docs/ai/mcp.mdx +13 -9
  8. package/site/content/docs/ai/skills.mdx +2 -2
  9. package/site/content/docs/client/calling.mdx +27 -19
  10. package/site/content/docs/client/index.mdx +1 -1
  11. package/site/content/docs/elements/ai/agents.mdx +61 -13
  12. package/site/content/docs/elements/ai/decide.mdx +536 -0
  13. package/site/content/docs/elements/ai/events.mdx +373 -0
  14. package/site/content/docs/elements/ai/index.mdx +9 -3
  15. package/site/content/docs/elements/ai/meta.json +1 -1
  16. package/site/content/docs/elements/ai/prompts.mdx +4 -2
  17. package/site/content/docs/elements/channel/email.mdx +1 -1
  18. package/site/content/docs/elements/channel/index.mdx +1 -1
  19. package/site/content/docs/elements/flow/http.mdx +4 -4
  20. package/site/content/docs/elements/flow/index.mdx +3 -3
  21. package/site/content/docs/elements/flow/meta.json +1 -1
  22. package/site/content/docs/elements/gate/auth.mdx +4 -1
  23. package/site/content/docs/elements/gate/tenancy.mdx +1 -1
  24. package/site/content/docs/elements/store/index.mdx +1 -1
  25. package/site/content/docs/elements/store/kv.mdx +5 -5
  26. package/site/content/docs/elements/vault/rotation.mdx +15 -0
  27. package/site/content/docs/plugins/otp.mdx +31 -31
  28. package/site/content/docs/recipes/dragonfly.mdx +5 -5
  29. package/site/content/docs/recipes/index.mdx +6 -6
  30. package/site/content/docs/recipes/mailpit.mdx +1 -1
  31. package/site/content/docs/recipes/meilisearch.mdx +1 -1
  32. package/site/content/docs/recipes/pgdog.mdx +1 -1
  33. package/site/content/docs/recipes/postgres.mdx +12 -8
  34. package/site/content/docs/recipes/redis.mdx +4 -4
  35. package/site/content/docs/reference/cli.mdx +2 -1
  36. package/site/content/docs/reference/configuration.mdx +11 -9
  37. package/site/content/docs/reference/errors.mdx +12 -2
  38. package/site/content/docs/reference/fx.mdx +35 -21
  39. package/site/content/docs/reference/idempotency.mdx +192 -0
  40. package/site/content/docs/reference/index.mdx +6 -1
  41. package/site/content/docs/reference/meta.json +2 -1
  42. package/site/content/docs/understand/meta.json +1 -1
  43. package/site/content/docs/{elements/flow → understand}/routing.mdx +11 -10
  44. package/site/content/docs/understand/the-architecture.mdx +14 -12
  45. package/site/content/docs/understand/try-it.mdx +3 -3
  46. package/src/auth/api-key-sql.test.ts +44 -0
  47. package/src/auth/api-key-sql.ts +1 -0
  48. package/src/auth/api-keys.ts +30 -12
  49. package/src/auth/config.ts +6 -2
  50. package/src/auth/gate-auth.test.ts +20 -0
  51. package/src/cli/agents-md.test.ts +25 -0
  52. package/src/cli/ask-vault-gaps.test.ts +38 -1
  53. package/src/cli/ask-vault-gaps.ts +35 -2
  54. package/src/cli/competitor-mention-removal.test.ts +3 -3
  55. package/src/cli/decide.ts +174 -0
  56. package/src/cli/decision-lock-watch.test.ts +45 -0
  57. package/src/cli/decision-lock-watch.ts +51 -0
  58. package/src/cli/dev-app-runner.ts +34 -8
  59. package/src/cli/dev-auth-secret.test.ts +49 -0
  60. package/src/cli/dev-auth-secret.ts +49 -0
  61. package/src/cli/dev-hot.test.ts +41 -0
  62. package/src/cli/dev-hot.ts +48 -0
  63. package/src/cli/dev.test.ts +1 -1
  64. package/src/cli/dev.ts +24 -6
  65. package/src/cli/docker-cli.test.ts +1 -1
  66. package/src/cli/eval.ts +142 -1
  67. package/src/cli/index.ts +14 -1
  68. package/src/cli/load-config.images.test.ts +12 -12
  69. package/src/cli/load-config.ts +2 -2
  70. package/src/cli/mcp-from-console.ts +48 -0
  71. package/src/cli/registry.ts +35 -1
  72. package/src/cli/vault-cmd.test.ts +23 -0
  73. package/src/cli/vault-cmd.ts +7 -0
  74. package/src/client/agent.ts +307 -0
  75. package/src/client/create.ts +18 -1
  76. package/src/client/transport.test.ts +245 -0
  77. package/src/client/transport.ts +133 -19
  78. package/src/client/types.ts +29 -3
  79. package/src/client-react/index.ts +7 -1
  80. package/src/client-react/use-agent-run.test.ts +271 -0
  81. package/src/client-react/use-agent-run.ts +193 -0
  82. package/src/compiler/ai-approval.test.ts +36 -0
  83. package/src/compiler/ai-repair.test.ts +22 -0
  84. package/src/compiler/decisions.extract.test.ts +164 -0
  85. package/src/compiler/effects-infer.ts +753 -17
  86. package/src/compiler/extract.test.ts +37 -0
  87. package/src/compiler/extract.ts +381 -24
  88. package/src/compiler/fixtures/skyport.expected.json +24 -0
  89. package/src/compiler/fx-follow.test.ts +164 -0
  90. package/src/compiler/fx-index.ts +399 -0
  91. package/src/compiler/response.ts +35 -2
  92. package/src/config/index.ts +21 -3
  93. package/src/console/server/ai-runs-flows.ts +269 -0
  94. package/src/console/server/ai-runs.test.ts +323 -0
  95. package/src/console/server/ai-runs.ts +562 -0
  96. package/src/console/server/ai.ts +12 -1
  97. package/src/console/server/app.ts +10 -1
  98. package/src/console/server/decisions-flows.ts +157 -0
  99. package/src/console/server/decisions.test.ts +66 -0
  100. package/src/console/server/decisions.ts +229 -0
  101. package/src/console/server/flows-invoke.test.ts +2 -2
  102. package/src/console/server/flows.ts +50 -2
  103. package/src/console/server/invoke-user-flow.ts +9 -0
  104. package/src/console/server/runs-ingest.ts +16 -0
  105. package/src/console/server/serve.ts +5 -0
  106. package/src/console/server/state.ts +25 -1
  107. package/src/console/server/store-stats.test.ts +47 -0
  108. package/src/console/server/store-stats.ts +92 -18
  109. package/src/console/ui-next/dist/assets/access-page-DDKkhT9v.js +4 -0
  110. package/src/console/ui-next/dist/assets/agent-disclosure-62Xts8Xi.js +1 -0
  111. package/src/console/ui-next/dist/assets/{cache-glyph-92uM5MO7.js → cache-glyph-DyeoKHKA.js} +1 -1
  112. package/src/console/ui-next/dist/assets/{call-pii-button-DtGVPtcs.js → call-pii-button-DvfpLXsU.js} +1 -1
  113. package/src/console/ui-next/dist/assets/{collapsible-DN7l6zmC.js → collapsible-BY03SeCg.js} +1 -1
  114. package/src/console/ui-next/dist/assets/confirm-sheet-DZfuJXP4.js +1 -0
  115. package/src/console/ui-next/dist/assets/copy-inline-button-BTjPVjRT.js +1 -0
  116. package/src/console/ui-next/dist/assets/decisions-page-CgkKlA56.js +1 -0
  117. package/src/console/ui-next/dist/assets/detail-header-Dk5LipF6.js +1 -0
  118. package/src/console/ui-next/dist/assets/dropdown-menu-CRGrj5JU.js +1 -0
  119. package/src/console/ui-next/dist/assets/duration-tone-Y6HLjyJ5.js +9 -0
  120. package/src/console/ui-next/dist/assets/element-icons-C6t8Vlml.js +1 -0
  121. package/src/console/ui-next/dist/assets/explorer-chrome-Dslh2yE8.js +1 -0
  122. package/src/console/ui-next/dist/assets/explorer-empty-CIVg7Jgb.js +1 -0
  123. package/src/console/ui-next/dist/assets/flows-page-DLPfNy-_.js +1 -0
  124. package/src/console/ui-next/dist/assets/{highlighted-json-BlAEVgNW.js → highlighted-json-D7nNzpgB.js} +1 -1
  125. package/src/console/ui-next/dist/assets/{http-method-BDf7OAHv.js → http-method-DdL19zzh.js} +1 -1
  126. package/src/console/ui-next/dist/assets/index-BlrN49Hs.css +2 -0
  127. package/src/console/ui-next/dist/assets/index-C0lc_s9d.js +58 -0
  128. package/src/console/ui-next/dist/assets/observability-page-CRlcyLCC.js +8 -0
  129. package/src/console/ui-next/dist/assets/{replica-lag-B3GLNVfF.js → replica-lag-Bb3FWUu9.js} +7 -7
  130. package/src/console/ui-next/dist/assets/request-meta-DYBMWhX8.js +1 -0
  131. package/src/console/ui-next/dist/assets/shortcut-keys-DTE1sjTC.js +1 -0
  132. package/src/console/ui-next/dist/assets/store-page-CcE-SXC8.js +41 -0
  133. package/src/console/ui-next/dist/assets/trace-detail-sheet-CKMSEQ4s.js +2 -0
  134. package/src/console/ui-next/dist/assets/tree-expand-toggle-QOfk0M0H.js +55 -0
  135. package/src/console/ui-next/dist/assets/units-page-DKC1CDDd.js +1 -0
  136. package/src/console/ui-next/dist/assets/use-vault-list-BAyQG8Re.js +1 -0
  137. package/src/console/ui-next/dist/assets/vault-page-B54v4Yit.js +2 -0
  138. package/src/console/ui-next/dist/index.html +4 -3
  139. package/src/console/ui-next/seed-parked-approval.ts +126 -0
  140. package/src/console/ui-next/src/client.ts +224 -1
  141. package/src/console/ui-next/src/components/explorer/detail-header.tsx +9 -0
  142. package/src/console/ui-next/src/components/explorer/explorer-start-toggle.tsx +5 -1
  143. package/src/console/ui-next/src/components/ui/sheet-form.tsx +21 -12
  144. package/src/console/ui-next/src/features/flows/decisions/decisions-page.tsx +216 -0
  145. package/src/console/ui-next/src/features/flows/decisions/resolve.test.ts +48 -0
  146. package/src/console/ui-next/src/features/flows/decisions/resolve.ts +111 -0
  147. package/src/console/ui-next/src/features/flows/flows-page.tsx +10 -0
  148. package/src/console/ui-next/src/features/flows/graph/element-map.ts +1 -0
  149. package/src/console/ui-next/src/features/flows/traces/effect-kind.ts +6 -0
  150. package/src/console/ui-next/src/features/flows/traces/effect-summary.test.ts +24 -0
  151. package/src/console/ui-next/src/features/flows/traces/effect-summary.ts +24 -0
  152. package/src/console/ui-next/src/features/flows/traces/http-status.ts +58 -0
  153. package/src/console/ui-next/src/features/flows/traces/request-client-card.tsx +355 -0
  154. package/src/console/ui-next/src/features/flows/traces/request-client.test.ts +114 -0
  155. package/src/console/ui-next/src/features/flows/traces/request-client.ts +423 -0
  156. package/src/console/ui-next/src/features/flows/traces/request-input-view.test.ts +52 -6
  157. package/src/console/ui-next/src/features/flows/traces/request-input-view.ts +85 -19
  158. package/src/console/ui-next/src/features/flows/traces/trace-detail-sheet.tsx +505 -80
  159. package/src/console/ui-next/src/features/flows/traces/trace-lanes.test.ts +61 -0
  160. package/src/console/ui-next/src/features/flows/traces/trace-lanes.ts +78 -0
  161. package/src/console/ui-next/src/features/flows/traces/trace-nav.test.ts +48 -0
  162. package/src/console/ui-next/src/features/flows/traces/trace-nav.ts +57 -0
  163. package/src/console/ui-next/src/features/flows/traces/trace-request-section.tsx +275 -96
  164. package/src/console/ui-next/src/features/flows/traces/traces-pane.tsx +16 -2
  165. package/src/console/ui-next/src/features/observability/detail/ai-runs.tsx +369 -0
  166. package/src/console/ui-next/src/features/observability/observability-page.tsx +31 -1
  167. package/src/console/ui-next/src/features/observability/state/observability-selection.ts +18 -3
  168. package/src/console/ui-next/src/features/store/performance/kv-performance-panel.tsx +12 -1
  169. package/src/console/ui-next/src/features/store/performance/performance-panel.tsx +14 -1
  170. package/src/console/ui-next/src/features/units/call/call-api-panel.tsx +1 -1
  171. package/src/console/ui-next/src/features/units/detail/flow-contract-panel.tsx +15 -2
  172. package/src/console/ui-next/src/features/units/explorer/units-tree.tsx +73 -18
  173. package/src/console/ui-next/src/features/units/lib/unit-tree.test.ts +21 -0
  174. package/src/console/ui-next/src/features/units/lib/unit-tree.ts +82 -0
  175. package/src/console/ui-next/src/features/units/units-page.tsx +25 -7
  176. package/src/console/ui-next/src/router.tsx +17 -0
  177. package/src/console/ui-next/ui-next-seed-runs.ts +23 -0
  178. package/src/console/ui-next/vite-console-kernel-plugin.ts +43 -3
  179. package/src/console/ui-next/vite.config.ts +9 -0
  180. package/src/docker/docker.test.ts +13 -13
  181. package/src/docker/images-config.test.ts +12 -12
  182. package/src/docker/recipes/dragonfly.ts +3 -2
  183. package/src/docker/recipes/redis.ts +1 -1
  184. package/src/docker/stack-id.test.ts +1 -1
  185. package/src/drivers/ai-anthropic.ts +212 -21
  186. package/src/drivers/ai-mock.ts +34 -1
  187. package/src/drivers/ai-openai-compatible.ts +67 -26
  188. package/src/drivers/ai-preconnect.ts +18 -0
  189. package/src/drivers/ai-stream.test.ts +62 -0
  190. package/src/drivers/ai-types.ts +20 -0
  191. package/src/drivers/journal-postgres.ts +455 -3
  192. package/src/drivers/meilisearch.ts +2 -0
  193. package/src/drivers/memory-ddl.test.ts +18 -0
  194. package/src/drivers/memory.ts +21 -1
  195. package/src/drivers/pg-rls.test.ts +31 -0
  196. package/src/drivers/pg-rls.ts +15 -0
  197. package/src/drivers/postgres.test.ts +9 -0
  198. package/src/drivers/postgres.ts +49 -11
  199. package/src/drivers/vault-builtin.test.ts +10 -0
  200. package/src/drivers/vault-builtin.ts +13 -1
  201. package/src/drivers/vault-remote-bag.ts +5 -1
  202. package/src/drivers/vault-types.ts +6 -1
  203. package/src/elements/ai/agent-event-slot.ts +27 -0
  204. package/src/elements/ai/approval-http.ts +207 -0
  205. package/src/elements/ai/approval.test.ts +741 -0
  206. package/src/elements/ai/approval.ts +228 -0
  207. package/src/elements/ai/decisions/bind.ts +163 -0
  208. package/src/elements/ai/decisions/certificate.test.ts +291 -0
  209. package/src/elements/ai/decisions/certificate.ts +377 -0
  210. package/src/elements/ai/decisions/certify.ts +314 -0
  211. package/src/elements/ai/decisions/decide.test.ts +953 -0
  212. package/src/elements/ai/decisions/e2e.test.ts +399 -0
  213. package/src/elements/ai/decisions/export.test.ts +120 -0
  214. package/src/elements/ai/decisions/export.ts +146 -0
  215. package/src/elements/ai/decisions/fixtures/openrouter-request.json +24 -0
  216. package/src/elements/ai/decisions/fixtures/openrouter-response.json +22 -0
  217. package/src/elements/ai/decisions/fixtures/typesafe-request.json +19 -0
  218. package/src/elements/ai/decisions/fixtures/typesafe-response.json +13 -0
  219. package/src/elements/ai/decisions/http.test.ts +154 -0
  220. package/src/elements/ai/decisions/http.ts +240 -0
  221. package/src/elements/ai/decisions/labels.test.ts +282 -0
  222. package/src/elements/ai/decisions/labels.ts +257 -0
  223. package/src/elements/ai/decisions/openrouter.live.test.ts +136 -0
  224. package/src/elements/ai/decisions/openrouter.ts +36 -0
  225. package/src/elements/ai/decisions/provider.ts +102 -0
  226. package/src/elements/ai/decisions/typesafe.ts +36 -0
  227. package/src/elements/ai/declare.ts +252 -1
  228. package/src/elements/ai/events.test.ts +379 -0
  229. package/src/elements/ai/events.ts +138 -0
  230. package/src/elements/ai/run-events.test.ts +461 -0
  231. package/src/elements/ai/run-events.ts +522 -0
  232. package/src/elements/ai/runtime.ts +1186 -105
  233. package/src/elements/ai/stream-turn.ts +214 -0
  234. package/src/elements/ai/stream.live.test.ts +76 -0
  235. package/src/elements/ai/subagent.test.ts +136 -0
  236. package/src/elements/ai.test.ts +497 -3
  237. package/src/elements/ai.ts +16 -1
  238. package/src/elements/clock/durable.ts +27 -1
  239. package/src/elements/store/emit-drizzle.ts +2 -2
  240. package/src/elements/store/live-default.test.ts +2 -0
  241. package/src/elements/store/live-http.test.ts +1 -0
  242. package/src/elements/store/resource-list-docs.test.ts +2 -2
  243. package/src/elements/store/resource.test.ts +3 -3
  244. package/src/elements/store/schema-decl.test.ts +1 -0
  245. package/src/elements/store/sql-condition.ts +24 -7
  246. package/src/elements/store/sql-session.test.ts +51 -0
  247. package/src/elements/store/sql-session.ts +111 -1
  248. package/src/elements/store/upsert-app.test.ts +1 -1
  249. package/src/elements/vault/audit.test.ts +137 -0
  250. package/src/elements/vault/audit.ts +106 -13
  251. package/src/elements/vault/boot-chain.ts +9 -1
  252. package/src/elements/vault/builtin-adapter.ts +33 -3
  253. package/src/i18n/catalogs/ar.ts +9 -0
  254. package/src/i18n/catalogs/en.ts +9 -0
  255. package/src/index.ts +2 -0
  256. package/src/kernel/abort-scope.ts +33 -2
  257. package/src/kernel/agent-event-store.ts +448 -0
  258. package/src/kernel/app.ts +294 -19
  259. package/src/kernel/auto-cache.test.ts +6 -6
  260. package/src/kernel/boot-bind/ai.ts +3 -0
  261. package/src/kernel/boot-bind/store.test.ts +26 -0
  262. package/src/kernel/boot-bind/store.ts +82 -6
  263. package/src/kernel/boot-bind/vault.ts +1 -0
  264. package/src/kernel/boot.ts +34 -5
  265. package/src/kernel/builtin-errors.ts +10 -0
  266. package/src/kernel/capability.ts +3 -0
  267. package/src/kernel/client-descriptor.ts +1 -0
  268. package/src/kernel/concurrency.test.ts +33 -0
  269. package/src/kernel/decision-label-store.ts +441 -0
  270. package/src/kernel/effects-stamping.test.ts +2 -2
  271. package/src/kernel/effects.test.ts +2 -1
  272. package/src/kernel/effects.ts +13 -1
  273. package/src/kernel/element-registries.ts +3 -0
  274. package/src/kernel/errors-compiler.ts +20 -0
  275. package/src/kernel/errors-text.ts +4 -0
  276. package/src/kernel/errors.ts +2 -0
  277. package/src/kernel/external-effects.test.ts +36 -0
  278. package/src/kernel/flow.test.ts +2 -3
  279. package/src/kernel/flow.ts +24 -0
  280. package/src/kernel/fx-decide.ts +761 -0
  281. package/src/kernel/fx-fetch.ts +5 -1
  282. package/src/kernel/fx.test.ts +12 -5
  283. package/src/kernel/fx.ts +316 -29
  284. package/src/kernel/http-frame.test.ts +94 -0
  285. package/src/kernel/http-frame.ts +203 -0
  286. package/src/kernel/idempotency-store.ts +578 -0
  287. package/src/kernel/idempotency.test.ts +556 -0
  288. package/src/kernel/idempotency.ts +304 -0
  289. package/src/kernel/index.ts +1 -0
  290. package/src/kernel/journal.ts +160 -0
  291. package/src/kernel/json-result.ts +10 -0
  292. package/src/kernel/pipeline.test.ts +45 -0
  293. package/src/kernel/sse-id.ts +32 -0
  294. package/src/manifest/diff.ts +1 -0
  295. package/src/manifest/types.ts +37 -2
  296. package/src/mcp/ai-tools.test.ts +202 -0
  297. package/src/mcp/authorization.ts +66 -0
  298. package/src/mcp/session.ts +3 -0
  299. package/src/mcp/tools.ts +168 -0
  300. package/src/plugins/auth-delivery.mailpit.integration.test.ts +1 -1
  301. package/src/plugins/otp.test.ts +65 -1
  302. package/src/plugins/otp.ts +59 -7
  303. package/src/release/absolute-regression.test.ts +63 -0
  304. package/src/release/http-graph.test.ts +27 -0
  305. package/src/release/http-graph.ts +95 -0
  306. package/src/release/index.ts +3 -0
  307. package/src/release/limits.ts +17 -2
  308. package/src/release/measure.ts +144 -28
  309. package/src/runs/collect.ts +4 -1
  310. package/src/runs/parquet.test.ts +27 -1
  311. package/src/runs/parquet.ts +19 -0
  312. package/src/runs/types.ts +31 -0
  313. package/src/runtime/json-code-block.test.ts +106 -47
  314. package/src/runtime/json-code-block.ts +1209 -46
  315. package/src/term.test.ts +13 -0
  316. package/src/term.ts +81 -49
  317. package/src/test/create-test-app.test.ts +3 -1
  318. package/src/test/create-test-app.ts +40 -0
  319. package/src/test/live-signals.test.ts +1 -0
  320. package/src/test/provisions.integration.test.ts +1 -0
  321. package/src/test/tenant-isolation.test.ts +1 -0
  322. package/src/console/ui-next/dist/assets/PlusSignIcon-CwG3nxfu.js +0 -1
  323. package/src/console/ui-next/dist/assets/access-page-Bgt9bq2r.js +0 -4
  324. package/src/console/ui-next/dist/assets/agent-disclosure-B43CXZZR.js +0 -1
  325. package/src/console/ui-next/dist/assets/copy-inline-button-CAYD18cr.js +0 -1
  326. package/src/console/ui-next/dist/assets/detail-header-DVWNjWjg.js +0 -1
  327. package/src/console/ui-next/dist/assets/dropdown-menu-4h2LOVXM.js +0 -1
  328. package/src/console/ui-next/dist/assets/duration-tone-BmIR9FV8.js +0 -9
  329. package/src/console/ui-next/dist/assets/element-icons-BI8cJgdh.js +0 -1
  330. package/src/console/ui-next/dist/assets/explorer-empty-CJs5A-wm.js +0 -1
  331. package/src/console/ui-next/dist/assets/flows-page-BMHs-IzK.js +0 -1
  332. package/src/console/ui-next/dist/assets/index-BKpaes3n.js +0 -63
  333. package/src/console/ui-next/dist/assets/index-VxoEz295.css +0 -2
  334. package/src/console/ui-next/dist/assets/observability-page-WnVLI-0j.js +0 -4
  335. package/src/console/ui-next/dist/assets/request-meta-DMbnAe3f.js +0 -1
  336. package/src/console/ui-next/dist/assets/shortcut-keys-3ILd8oGn.js +0 -1
  337. package/src/console/ui-next/dist/assets/store-page-KvFDingJ.js +0 -41
  338. package/src/console/ui-next/dist/assets/trace-detail-sheet-Htk8Cm9t.js +0 -2
  339. package/src/console/ui-next/dist/assets/tree-expand-toggle-CFMPWX4f.js +0 -55
  340. package/src/console/ui-next/dist/assets/units-page-C4NdNuxP.js +0 -1
  341. package/src/console/ui-next/dist/assets/use-vault-list-CT4-gajj.js +0 -1
  342. package/src/console/ui-next/dist/assets/vault-page-CBYl0LW_.js +0 -2
@@ -8,6 +8,7 @@ import {
8
8
  FilterHorizontalIcon,
9
9
  Folder01Icon,
10
10
  InternetAntenna03Icon,
11
+ PinIcon,
11
12
  SecurityCheckIcon,
12
13
  Timer01Icon,
13
14
  UserIcon,
@@ -54,6 +55,10 @@ import {
54
55
  countActiveFacets,
55
56
  filterUnitTree,
56
57
  filterUnitsAdvanced,
58
+ loadPinnedUnits,
59
+ orderPinnedGroups,
60
+ savePinnedUnits,
61
+ togglePinnedUnit,
57
62
  unitTreeAncestorKeys,
58
63
  unitTreeBandKey,
59
64
  unitTreeGroupKey,
@@ -90,6 +95,7 @@ export function UnitsTree({ groups, selectedFlowId, onSelect }: UnitsTreeProps):
90
95
  const [advancedOpen, setAdvancedOpen] = useState(false);
91
96
  const [facets, setFacets] = useState<UnitTreeFacets>({});
92
97
  const [openByKey, setOpenByKey] = useState<Readonly<Record<string, boolean>>>({});
98
+ const [pinned, setPinned] = useState<readonly string[]>(() => loadPinnedUnits());
93
99
 
94
100
  const availableKinds = useMemo(() => {
95
101
  const present = new Set<FlowTriggerKind>();
@@ -171,6 +177,14 @@ export function UnitsTree({ groups, selectedFlowId, onSelect }: UnitsTreeProps):
171
177
  deliveries: toggleItem(prev.deliveries ?? [], delivery),
172
178
  }));
173
179
 
180
+ const togglePin = (unit: string): void => {
181
+ setPinned((prev) => {
182
+ const next = togglePinnedUnit(prev, unit);
183
+ savePinnedUnits(next);
184
+ return next;
185
+ });
186
+ };
187
+
174
188
  return (
175
189
  <div className="flex h-full min-h-0 flex-col overflow-hidden" data-slot="units-tree">
176
190
  <div className="shrink-0 border-b border-border/60">
@@ -341,6 +355,8 @@ export function UnitsTree({ groups, selectedFlowId, onSelect }: UnitsTreeProps):
341
355
  }
342
356
  selectedFlowId={selectedFlowId}
343
357
  onSelect={onSelect}
358
+ pinned={pinned}
359
+ onTogglePin={togglePin}
344
360
  />
345
361
  );
346
362
  })}
@@ -438,6 +454,8 @@ function TriggerBand({
438
454
  onGroupOpenChange,
439
455
  selectedFlowId,
440
456
  onSelect,
457
+ pinned,
458
+ onTogglePin,
441
459
  }: {
442
460
  readonly band: UnitTreeBand;
443
461
  readonly open: boolean;
@@ -446,10 +464,13 @@ function TriggerBand({
446
464
  readonly onGroupOpenChange: (unit: string, open: boolean) => void;
447
465
  readonly selectedFlowId: string | null;
448
466
  readonly onSelect: (flowId: string) => void;
467
+ readonly pinned: readonly string[];
468
+ readonly onTogglePin: (unit: string) => void;
449
469
  }): JSX.Element {
450
470
  const kindSpec = FLOW_TRIGGER_KIND_SPECS[band.id];
451
- const flowCount = band.groups.reduce((n, g) => n + g.flows.length, 0);
452
- const units = band.groups.map((g) => g.unit);
471
+ const groups = orderPinnedGroups(band.groups, pinned);
472
+ const flowCount = groups.reduce((n, g) => n + g.flows.length, 0);
473
+ const units = groups.map((g) => g.unit);
453
474
  const unitsOpen = units.length > 0 && units.every((unit) => groupOpen(unit));
454
475
 
455
476
  const toggleUnits = (): void => {
@@ -501,7 +522,7 @@ function TriggerBand({
501
522
  />
502
523
  <CollapsibleContent>
503
524
  <ul className="flex flex-col">
504
- {band.groups.map((g) => (
525
+ {groups.map((g) => (
505
526
  <UnitGroupItem
506
527
  key={`${band.id}:${g.unit}`}
507
528
  group={g}
@@ -509,6 +530,8 @@ function TriggerBand({
509
530
  onOpenChange={(next) => onGroupOpenChange(g.unit, next)}
510
531
  selectedFlowId={selectedFlowId}
511
532
  onSelect={onSelect}
533
+ pinned={pinned.includes(g.unit)}
534
+ onTogglePin={() => onTogglePin(g.unit)}
512
535
  />
513
536
  ))}
514
537
  </ul>
@@ -529,30 +552,62 @@ function UnitGroupItem({
529
552
  onOpenChange,
530
553
  selectedFlowId,
531
554
  onSelect,
555
+ pinned,
556
+ onTogglePin,
532
557
  }: {
533
558
  readonly group: UnitGroup;
534
559
  readonly open: boolean;
535
560
  readonly onOpenChange: (open: boolean) => void;
536
561
  readonly selectedFlowId: string | null;
537
562
  readonly onSelect: (flowId: string) => void;
563
+ readonly pinned: boolean;
564
+ readonly onTogglePin: () => void;
538
565
  }): JSX.Element {
566
+ const pinLabel = pinned ? `Unpin ${group.unit}` : `Pin ${group.unit}`;
539
567
  return (
540
- <li data-slot="unit-group" data-unit={group.unit}>
568
+ <li data-slot="unit-group" data-unit={group.unit} data-pinned={pinned ? "true" : undefined}>
541
569
  <Collapsible open={open} onOpenChange={onOpenChange}>
542
- <CollapsibleTrigger className={cn(EXPLORER_GROUP_ROW_CLASS, "pl-4")}>
543
- <HugeiconsIcon
544
- icon={ArrowDown01Icon}
545
- className={cn(EXPLORER_CHEVRON_CLASS, !open && "-rotate-90")}
546
- aria-hidden
547
- />
548
- <HugeiconsIcon
549
- icon={Folder01Icon}
550
- className={cn(EXPLORER_ICON_CLASS, "text-muted-foreground")}
551
- aria-hidden
552
- />
553
- <span className="min-w-0 flex-1 truncate font-medium text-foreground">{group.unit}</span>
554
- <span className={EXPLORER_COUNT_CLASS}>{group.flows.length}</span>
555
- </CollapsibleTrigger>
570
+ <CollapsibleTrigger
571
+ nativeButton={false}
572
+ className={cn(EXPLORER_GROUP_ROW_CLASS, "pl-4")}
573
+ data-slot="unit-group-toggle"
574
+ render={(props) => (
575
+ <div {...props}>
576
+ <HugeiconsIcon
577
+ icon={ArrowDown01Icon}
578
+ className={cn(EXPLORER_CHEVRON_CLASS, !open && "-rotate-90")}
579
+ aria-hidden
580
+ />
581
+ <HugeiconsIcon
582
+ icon={Folder01Icon}
583
+ className={cn(EXPLORER_ICON_CLASS, "text-muted-foreground")}
584
+ aria-hidden
585
+ />
586
+ <span className="flex min-w-0 flex-1 items-center">
587
+ <span className="min-w-0 truncate font-medium text-foreground">{group.unit}</span>
588
+ <button
589
+ type="button"
590
+ aria-label={pinLabel}
591
+ aria-pressed={pinned}
592
+ data-slot="unit-pin"
593
+ onClick={(event) => {
594
+ event.stopPropagation();
595
+ onTogglePin();
596
+ }}
597
+ className={cn(
598
+ "inline-flex shrink-0 items-center justify-center overflow-hidden text-muted-foreground transition-[width,opacity,margin] hover:text-foreground focus-visible:ring-2 focus-visible:ring-ring/40 focus-visible:outline-none",
599
+ pinned
600
+ ? "ml-1.5 size-3.5 text-foreground"
601
+ : "pointer-events-none ml-0 size-0 opacity-0 group-hover/folder:pointer-events-auto group-hover/folder:ml-1.5 group-hover/folder:size-3.5 group-hover/folder:opacity-100 group-focus-within/folder:pointer-events-auto group-focus-within/folder:ml-1.5 group-focus-within/folder:size-3.5 group-focus-within/folder:opacity-100",
602
+ )}
603
+ >
604
+ <HugeiconsIcon icon={PinIcon} className="size-3 shrink-0" aria-hidden />
605
+ </button>
606
+ </span>
607
+ <span className={EXPLORER_COUNT_CLASS}>{group.flows.length}</span>
608
+ </div>
609
+ )}
610
+ />
556
611
  <CollapsibleContent>
557
612
  <ul className="flex flex-col">
558
613
  {group.flows.map((f) => (
@@ -10,6 +10,9 @@ import {
10
10
  countActiveFacets,
11
11
  filterUnitTree,
12
12
  filterUnitsAdvanced,
13
+ orderPinnedGroups,
14
+ parsePinnedUnits,
15
+ togglePinnedUnit,
13
16
  unitTreeAncestorKeys,
14
17
  unitTreeBandKey,
15
18
  unitTreeGroupKey,
@@ -289,6 +292,24 @@ describe("bandUnitTree", () => {
289
292
  expect(unitTreeAncestorKeys(bands, "missing")).toEqual([]);
290
293
  });
291
294
 
295
+ test("pinned folders rise to the front and toggle in newest-first order", () => {
296
+ const http = bandUnitTree(TREE)[0]!;
297
+ expect(parsePinnedUnits(["orders", "", "orders", 1, "billing"])).toEqual(["orders", "billing"]);
298
+ expect(parsePinnedUnits("orders")).toEqual([]);
299
+ expect(orderPinnedGroups(http.groups, ["orders"]).map((g) => g.unit)).toEqual([
300
+ "orders",
301
+ "billing",
302
+ ]);
303
+ expect(orderPinnedGroups(http.groups, []).map((g) => g.unit)).toEqual(["billing", "orders"]);
304
+ const pinned = togglePinnedUnit(togglePinnedUnit([], "billing"), "orders");
305
+ expect(pinned).toEqual(["orders", "billing"]);
306
+ expect(orderPinnedGroups(http.groups, pinned).map((g) => g.unit)).toEqual([
307
+ "orders",
308
+ "billing",
309
+ ]);
310
+ expect(togglePinnedUnit(pinned, "orders")).toEqual(["billing"]);
311
+ });
312
+
292
313
  test("bands and unit folders default closed unless searching", () => {
293
314
  expect(unitTreeIsOpen("band:http", {})).toBe(false);
294
315
  expect(unitTreeIsOpen("unit:http:billing", {})).toBe(false);
@@ -87,6 +87,88 @@ export function bandUnitTree(groups: readonly UnitGroup[]): readonly UnitTreeBan
87
87
  });
88
88
  }
89
89
 
90
+ /** localStorage key for pinned Units explorer folders. */
91
+ export const PINNED_UNITS_KEY = "oke_units_pinned";
92
+
93
+ /**
94
+ * Parse a stored pin list. Empty and duplicate names are dropped; order is kept.
95
+ *
96
+ * @param value - JSON from localStorage
97
+ */
98
+ export function parsePinnedUnits(value: unknown): readonly string[] {
99
+ if (!Array.isArray(value)) return [];
100
+ const seen = new Set<string>();
101
+ const out: string[] = [];
102
+ for (const item of value) {
103
+ if (typeof item !== "string" || item.length === 0 || seen.has(item)) continue;
104
+ seen.add(item);
105
+ out.push(item);
106
+ }
107
+ return out;
108
+ }
109
+
110
+ /**
111
+ * Load pinned unit folders from localStorage.
112
+ */
113
+ export function loadPinnedUnits(): readonly string[] {
114
+ try {
115
+ if (typeof localStorage === "undefined") return [];
116
+ const raw = localStorage.getItem(PINNED_UNITS_KEY);
117
+ if (!raw) return [];
118
+ return parsePinnedUnits(JSON.parse(raw) as unknown);
119
+ } catch {
120
+ return [];
121
+ }
122
+ }
123
+
124
+ /**
125
+ * Persist pinned unit folders. Newest pin is first.
126
+ *
127
+ * @param pinned - Unit names, newest first
128
+ */
129
+ export function savePinnedUnits(pinned: readonly string[]): void {
130
+ try {
131
+ if (typeof localStorage === "undefined") return;
132
+ localStorage.setItem(PINNED_UNITS_KEY, JSON.stringify(pinned));
133
+ } catch {
134
+ // quota / private mode
135
+ }
136
+ }
137
+
138
+ /**
139
+ * Pin or unpin a unit folder. A new pin is placed first.
140
+ *
141
+ * @param pinned - Current pins, newest first
142
+ * @param unit - Unit name to toggle
143
+ */
144
+ export function togglePinnedUnit(pinned: readonly string[], unit: string): readonly string[] {
145
+ return pinned.includes(unit) ? pinned.filter((item) => item !== unit) : [unit, ...pinned];
146
+ }
147
+
148
+ /**
149
+ * Lift pinned folders to the front of a band. Pin order is newest first;
150
+ * unpinned folders keep their current order.
151
+ *
152
+ * @param groups - Unit folders in one band
153
+ * @param pinned - Pinned unit names, newest first
154
+ */
155
+ export function orderPinnedGroups(
156
+ groups: readonly UnitGroup[],
157
+ pinned: readonly string[],
158
+ ): readonly UnitGroup[] {
159
+ if (pinned.length === 0 || groups.length < 2) return groups;
160
+ const rank = new Map(pinned.map((unit, index) => [unit, index]));
161
+ return groups
162
+ .map((group, index) => ({ group, index, pin: rank.get(group.unit) }))
163
+ .sort((a, b) => {
164
+ if (a.pin !== undefined && b.pin !== undefined) return a.pin - b.pin;
165
+ if (a.pin !== undefined) return -1;
166
+ if (b.pin !== undefined) return 1;
167
+ return a.index - b.index;
168
+ })
169
+ .map((row) => row.group);
170
+ }
171
+
90
172
  /**
91
173
  * Open-state key for a trigger-kind band in the Units tree.
92
174
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Flows page — Manifest service catalog + docked Call API.
2
+ * Flows page — Manifest service catalog, contract, and a Call API rail.
3
3
  */
4
4
 
5
5
  import { useMemo, type JSX } from "react";
@@ -27,6 +27,7 @@ export function UnitsPage(): JSX.Element {
27
27
  useConsoleLive(true);
28
28
  const { selectedFlowId: urlFlowId, setSelectedFlow } = useUnitsSelection();
29
29
  const start = useExplorerStartPanel();
30
+ const callRail = useExplorerStartPanel();
30
31
  const groups = useMemo(() => buildUnitTree(manifestQuery.data ?? null), [manifestQuery.data]);
31
32
  const startToggle = (
32
33
  <ExplorerStartToggle
@@ -37,6 +38,16 @@ export function UnitsPage(): JSX.Element {
37
38
  dataSlot="flows-tree-toggle"
38
39
  />
39
40
  );
41
+ const callToggle = (
42
+ <ExplorerStartToggle
43
+ open={callRail.open}
44
+ onToggle={callRail.toggle}
45
+ noun="Call API"
46
+ controlsId="call-api-rail"
47
+ dataSlot="call-api-toggle"
48
+ side="end"
49
+ />
50
+ );
40
51
 
41
52
  const selectedFlowId = urlFlowId ?? groups[0]?.flows[0]?.id ?? null;
42
53
  const selectedRow = useMemo(() => {
@@ -79,25 +90,32 @@ export function UnitsPage(): JSX.Element {
79
90
  <div className="h-full min-h-0 overflow-hidden">
80
91
  {selectedRow ? (
81
92
  <ResizablePanelGroup
82
- orientation="vertical"
93
+ orientation="horizontal"
83
94
  className="min-h-0 flex-1"
84
95
  data-slot="units-inspector"
85
96
  >
86
- <ResizablePanel defaultSize="56%" minSize="28%" className="min-h-0 overflow-hidden">
97
+ <ResizablePanel defaultSize="62%" minSize="36%" className="min-h-0 overflow-hidden">
87
98
  <FlowContractPanel
88
99
  row={selectedRow}
89
100
  manifest={manifestQuery.data ?? null}
90
101
  runs={runs.data}
91
102
  leading={startToggle}
103
+ trailing={callToggle}
92
104
  />
93
105
  </ResizablePanel>
94
- <ResizableHandle withHandle />
106
+ {callRail.open ? <ResizableHandle withHandle /> : null}
95
107
  <ResizablePanel
96
- defaultSize="44%"
97
- minSize="220px"
108
+ panelRef={callRail.panelRef}
109
+ collapsible
110
+ collapsedSize={0}
111
+ defaultSize="38%"
112
+ minSize="352px"
113
+ onResize={callRail.onResize}
98
114
  className="min-h-0 overflow-hidden"
99
115
  >
100
- <CallApiPanel row={selectedRow} manifest={manifestQuery.data ?? null} />
116
+ <div id="call-api-rail" className="h-full min-h-0 overflow-hidden">
117
+ <CallApiPanel row={selectedRow} manifest={manifestQuery.data ?? null} />
118
+ </div>
101
119
  </ResizablePanel>
102
120
  </ResizablePanelGroup>
103
121
  ) : (
@@ -107,6 +107,22 @@ const flowsRoute = createRoute({
107
107
  component: lazyRouteComponent(() => import("./features/units/units-page.tsx"), "UnitsPage"),
108
108
  });
109
109
 
110
+ const decisionsRoute = createRoute({
111
+ getParentRoute: () => authenticatedRoute,
112
+ path: "/flows/decisions",
113
+ validateSearch: (search: Record<string, unknown>) => {
114
+ const decision =
115
+ typeof search.decision === "string" && search.decision.length > 0
116
+ ? search.decision
117
+ : undefined;
118
+ return { ...(decision !== undefined ? { decision } : {}) };
119
+ },
120
+ component: lazyRouteComponent(
121
+ () => import("./features/flows/decisions/decisions-page.tsx"),
122
+ "DecisionsPage",
123
+ ),
124
+ });
125
+
110
126
  const storeRoute = createRoute({
111
127
  getParentRoute: () => authenticatedRoute,
112
128
  path: "/store",
@@ -152,6 +168,7 @@ const routeTree = rootRoute.addChildren([
152
168
  authenticatedRoute.addChildren([
153
169
  overviewRoute,
154
170
  flowsRoute,
171
+ decisionsRoute,
155
172
  storeRoute,
156
173
  vaultRoute,
157
174
  accessRoute,
@@ -363,6 +363,29 @@ export function createUiNextSeedRuns(now: number = Date.now()): readonly WideEve
363
363
  replica: "replica",
364
364
  replicaLagMs: 12,
365
365
  buildVersion: BUILD,
366
+ http: {
367
+ request: {
368
+ method: "GET",
369
+ path: "/tasks",
370
+ query: { limit: "20" },
371
+ headers: {
372
+ accept: "application/json",
373
+ authorization: "[redacted]",
374
+ host: "localhost:6530",
375
+ "user-agent":
376
+ "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36",
377
+ "sec-ch-ua-platform": '"macOS"',
378
+ "sec-ch-ua-mobile": "?0",
379
+ "cf-connecting-ip": "203.0.113.10",
380
+ },
381
+ },
382
+ response: {
383
+ status: 200,
384
+ headers: {
385
+ "content-type": "application/json",
386
+ },
387
+ },
388
+ },
366
389
  output: {
367
390
  count: 3,
368
391
  tasks: [
@@ -15,7 +15,7 @@
15
15
  import type { Plugin, ViteDevServer } from "vite";
16
16
  import { isPortInUse } from "../../cli/ports.ts";
17
17
  import { CONSOLE_PORT } from "../../runtime/types.ts";
18
- import { serveConsole, type ConsoleServerHandle } from "../server/serve.ts";
18
+ import type { ConsoleServerHandle } from "../server/serve.ts";
19
19
  import {
20
20
  isConsoleFresh,
21
21
  isConsoleKernelSkipped,
@@ -30,6 +30,21 @@ import {
30
30
  uiNextSeededSummary,
31
31
  } from "./ui-next-seed.ts";
32
32
 
33
+ /**
34
+ * Load a Console module from its source file.
35
+ *
36
+ * Vite bundles this plugin into a config chunk. A literal `import()` is
37
+ * inlined there, and Bun `import.meta.dir` then points at that chunk, so
38
+ * `lazyRequire` looks for `aot.js` beside the chunk. A variable specifier
39
+ * stays out of the bundle and keeps the real source directory.
40
+ *
41
+ * @param relativePath - Path relative to this plugin file
42
+ */
43
+ async function importSource<T>(relativePath: string): Promise<T> {
44
+ const href = new URL(relativePath, import.meta.url).href;
45
+ return (await import(href)) as T;
46
+ }
47
+
33
48
  /** Vite SPA URL for ui-next (proxies `/console` → kernel :6533). */
34
49
  const UI_NEXT_DEV_URL = "http://127.0.0.1:6537";
35
50
 
@@ -78,6 +93,7 @@ function printConsoleNextBanner(
78
93
  export function okeConsoleKernelPlugin(): Plugin {
79
94
  let handle: ConsoleServerHandle | null = null;
80
95
  let stopping = false;
96
+ let parkedStop: (() => Promise<void>) | null = null;
81
97
 
82
98
  const stop = (): void => {
83
99
  if (stopping || !handle) return;
@@ -87,6 +103,8 @@ export function okeConsoleKernelPlugin(): Plugin {
87
103
  } catch {
88
104
  // ignore
89
105
  }
106
+ void parkedStop?.();
107
+ parkedStop = null;
90
108
  handle = null;
91
109
  };
92
110
 
@@ -133,6 +151,15 @@ export function okeConsoleKernelPlugin(): Plugin {
133
151
 
134
152
  const operators = fresh ? undefined : (await seedUiNextDevOperator()).store;
135
153
 
154
+ const parked = seeded
155
+ ? await importSource<typeof import("./seed-parked-approval.ts")>(
156
+ "./seed-parked-approval.ts",
157
+ ).then((mod) => mod.bootParkedApproval())
158
+ : null;
159
+ if (parked) parkedStop = () => parked.stop();
160
+
161
+ const { serveConsole } =
162
+ await importSource<typeof import("../server/serve.ts")>("../server/serve.ts");
136
163
  handle = await serveConsole({
137
164
  port,
138
165
  hostname,
@@ -142,10 +169,21 @@ export function okeConsoleKernelPlugin(): Plugin {
142
169
  env: "test",
143
170
  secret: process.env.OKE_CONSOLE_SECRET ?? "oke-console-next-dev-secret",
144
171
  ...(operators ? { operators } : {}),
172
+ ...(parked ? { journalStore: parked.store } : {}),
145
173
  ...(seeded
146
174
  ? { manifest: UI_NEXT_SEEDED_MANIFEST, vaultLayerSeed: UI_NEXT_SEED_VAULT_LAYERS }
147
175
  : {}),
148
176
  });
177
+ if (parked) {
178
+ handle.console.state.forwardAgent = (request) => parked.fetch(request);
179
+ handle.console.state.afterAgentApproval = () => parked.resume();
180
+ if (parked.log) {
181
+ const { setAgentEventLog } = await importSource<
182
+ typeof import("../../elements/ai/run-events.ts")
183
+ >("../../elements/ai/run-events.ts");
184
+ setAgentEventLog(parked.log);
185
+ }
186
+ }
149
187
 
150
188
  if (seeded) {
151
189
  const runs = handle.console.app.bootResult?.runs;
@@ -154,7 +192,8 @@ export function okeConsoleKernelPlugin(): Plugin {
154
192
  }
155
193
  await appendUiNextSeedRun(runs);
156
194
  if (handle.console.state.storeRuntime) {
157
- const { seedUiNextStoreData } = await import("./ui-next-seed.ts");
195
+ const { seedUiNextStoreData } =
196
+ await importSource<typeof import("./ui-next-seed.ts")>("./ui-next-seed.ts");
158
197
  await seedUiNextStoreData(handle.console.state.storeRuntime);
159
198
  }
160
199
  // Same thin host substitute as the Playwright fixture — Replay hits
@@ -162,7 +201,8 @@ export function okeConsoleKernelPlugin(): Plugin {
162
201
  handle.console.state.replayTrace = async ({ event, dryRun }) => ({
163
202
  output: { replayed: event.id, dryRun, input: event.input ?? null },
164
203
  });
165
- const { bootUiNextSeedInvoke } = await import("./seed-invoke-host.ts");
204
+ const { bootUiNextSeedInvoke } =
205
+ await importSource<typeof import("./seed-invoke-host.ts")>("./seed-invoke-host.ts");
166
206
  const seedInvoke = await bootUiNextSeedInvoke({
167
207
  ...(handle.console.state.storeRuntime
168
208
  ? { storeRuntime: handle.console.state.storeRuntime }
@@ -82,6 +82,15 @@ export default defineConfig(({ command }) => {
82
82
  changeOrigin: true,
83
83
  ws: true,
84
84
  },
85
+ "/agent": {
86
+ // `oke dev` serves follow on the app (:6530). An explicit
87
+ // `OKE_CONSOLE_PROXY` is the Console kernel, which forwards `/agent`.
88
+ target:
89
+ attachToOkeDev && process.env["OKE_CONSOLE_PROXY"] === undefined
90
+ ? "http://127.0.0.1:6530"
91
+ : consoleProxy,
92
+ changeOrigin: true,
93
+ },
85
94
  },
86
95
  },
87
96
  };
@@ -358,12 +358,12 @@ describe("image recipes", () => {
358
358
  });
359
359
 
360
360
  test("pgdog matches the official image and waits on store-sql", () => {
361
- expect(recipeFor("ghcr.io/pgdogdev/pgdog:v0.1.57").id).toBe("pgdog");
361
+ expect(recipeFor("ghcr.io/pgdogdev/pgdog:v0.1.59").id).toBe("pgdog");
362
362
  expect(pgdog.match("ghcr.io/pgdogdev/pgdog:main")).toBe(true);
363
363
  const applied = pgdog.apply({
364
364
  role: "pgdog",
365
365
  serviceName: "pgdog",
366
- image: "ghcr.io/pgdogdev/pgdog:v0.1.57",
366
+ image: "ghcr.io/pgdogdev/pgdog:v0.1.59",
367
367
  port: 6432,
368
368
  hostPort: 6432,
369
369
  credentials: fixedCreds["store.sql"],
@@ -402,11 +402,11 @@ describe("image recipes", () => {
402
402
  });
403
403
 
404
404
  test("meilisearch matches the official image and emits a http URL", () => {
405
- expect(recipeFor("getmeili/meilisearch:v1.53").id).toBe("meilisearch");
405
+ expect(recipeFor("getmeili/meilisearch:v1.54").id).toBe("meilisearch");
406
406
  const spec: ServiceSpec = {
407
407
  role: "store.index",
408
408
  serviceName: "store-index",
409
- image: "getmeili/meilisearch:v1.53",
409
+ image: "getmeili/meilisearch:v1.54",
410
410
  port: 7700,
411
411
  hostPort: 7700,
412
412
  credentials: { user: "oke", password: "meili-master-key", database: "oke" },
@@ -604,8 +604,8 @@ describe("deriveInfrastructure", () => {
604
604
  test("compose YAML spaces services and adds role comments", () => {
605
605
  const result = deriveInfrastructure({
606
606
  images: {
607
- "channel.email": "axllent/mailpit:v1.31.1",
608
- pgdog: "ghcr.io/pgdogdev/pgdog:v0.1.57",
607
+ "channel.email": "axllent/mailpit:v1.31.2",
608
+ pgdog: "ghcr.io/pgdogdev/pgdog:v0.1.59",
609
609
  "store.sql": "postgres:16",
610
610
  },
611
611
  credentials: { "store.sql": fixedCreds["store.sql"] },
@@ -726,7 +726,7 @@ describe("deriveInfrastructure", () => {
726
726
  const result = deriveInfrastructure({
727
727
  images: {
728
728
  "store.sql": "postgres:18-alpine",
729
- pgdog: "ghcr.io/pgdogdev/pgdog:v0.1.57",
729
+ pgdog: "ghcr.io/pgdogdev/pgdog:v0.1.59",
730
730
  },
731
731
  credentials: { "store.sql": fixedCreds["store.sql"] },
732
732
  prod: true,
@@ -741,7 +741,7 @@ describe("deriveInfrastructure", () => {
741
741
  expect(result.stackEnv.OKE_STORE_SQL_URL).toContain(":5432/");
742
742
 
743
743
  const pgdogYml = result.files.find((f) => f.path === DOCKER_COMPOSE)!.content;
744
- expect(pgdogYml).toContain("ghcr.io/pgdogdev/pgdog:v0.1.57");
744
+ expect(pgdogYml).toContain("ghcr.io/pgdogdev/pgdog:v0.1.59");
745
745
  expect(pgdogYml).toContain("store-sql");
746
746
  expect(pgdogYml).toContain("service_healthy");
747
747
  expect(pgdogYml).not.toContain(fixedCreds["store.sql"].password);
@@ -809,14 +809,14 @@ describe("deriveInfrastructure", () => {
809
809
 
810
810
  test("store.index meilisearch emits its own URL + master key env", () => {
811
811
  const result = deriveInfrastructure({
812
- images: { "store.index": "getmeili/meilisearch:v1.53" },
812
+ images: { "store.index": "getmeili/meilisearch:v1.54" },
813
813
  credentials: {
814
814
  "store.index": { user: "oke", password: "meili-master-key", database: "oke" },
815
815
  },
816
816
  app: "skyport",
817
817
  });
818
818
  const yml = result.files.find((f) => f.path === DOCKER_COMPOSE)!.content;
819
- expect(yml).toContain("getmeili/meilisearch:v1.53");
819
+ expect(yml).toContain("getmeili/meilisearch:v1.54");
820
820
  expect(yml).toContain("${OKE_STORE_INDEX_KEY}");
821
821
  expect(yml).toContain("meili_data");
822
822
  expect(yml).not.toContain("meili-master-key");
@@ -831,7 +831,7 @@ describe("deriveInfrastructure", () => {
831
831
  "store.sql": "postgres:18-alpine",
832
832
  "store.kv": "redis:8-alpine",
833
833
  "store.files": "rustfs/rustfs:1.0.0",
834
- "channel.email": "axllent/mailpit:v1.31.1",
834
+ "channel.email": "axllent/mailpit:v1.31.2",
835
835
  },
836
836
  credentials: {
837
837
  ...fixedCreds,
@@ -874,7 +874,7 @@ describe("deriveInfrastructure", () => {
874
874
  const n = Number.parseInt(id.slice(0, 4), 16) % 1000;
875
875
  const result = deriveInfrastructure({
876
876
  images: {
877
- "channel.email": "axllent/mailpit:v1.31.1",
877
+ "channel.email": "axllent/mailpit:v1.31.2",
878
878
  "store.files": "rustfs/rustfs:1.0.0",
879
879
  },
880
880
  instanceId: id,
@@ -913,7 +913,7 @@ describe("deriveInfrastructure", () => {
913
913
  const n = Number.parseInt(id.slice(0, 4), 16) % 1000;
914
914
  const rows = resolveStack({
915
915
  images: {
916
- "channel.email": "axllent/mailpit:v1.31.1",
916
+ "channel.email": "axllent/mailpit:v1.31.2",
917
917
  "store.files": "rustfs/rustfs:1.0.0",
918
918
  },
919
919
  instanceId: id,