okengine 0.18.4 → 0.19.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.
- package/AGENTS.md +18 -10
- package/README.md +2 -2
- package/package.json +51 -50
- package/site/content/docs/ai/index.mdx +25 -6
- package/site/content/docs/ai/llms-txt.mdx +1 -1
- package/site/content/docs/ai/meta.json +1 -1
- package/site/content/docs/ai/skills.mdx +4 -1
- package/site/content/docs/ai/try-it.mdx +58 -0
- package/site/content/docs/client/auth.mdx +208 -0
- package/site/content/docs/client/calling.mdx +451 -0
- package/site/content/docs/client/index.mdx +209 -0
- package/site/content/docs/client/live.mdx +234 -0
- package/site/content/docs/client/meta.json +5 -0
- package/site/content/docs/client/react.mdx +249 -0
- package/site/content/docs/elements/ai/agents.mdx +232 -0
- package/site/content/docs/elements/ai/index.mdx +341 -0
- package/site/content/docs/elements/ai/mcp.mdx +275 -0
- package/site/content/docs/elements/ai/meta.json +5 -0
- package/site/content/docs/elements/ai/models.mdx +283 -0
- package/site/content/docs/elements/ai/prompts.mdx +256 -0
- package/site/content/docs/elements/channel/email.mdx +266 -0
- package/site/content/docs/elements/channel/index.mdx +344 -0
- package/site/content/docs/elements/channel/meta.json +5 -0
- package/site/content/docs/elements/channel/push.mdx +218 -0
- package/site/content/docs/elements/channel/receipts.mdx +206 -0
- package/site/content/docs/elements/channel/sms.mdx +264 -0
- package/site/content/docs/elements/channel/whatsapp.mdx +220 -0
- package/site/content/docs/elements/clock/index.mdx +300 -0
- package/site/content/docs/elements/clock/meta.json +5 -0
- package/site/content/docs/elements/clock/schedules.mdx +508 -0
- package/site/content/docs/elements/clock/sleep.mdx +445 -0
- package/site/content/docs/elements/flow/consumers.mdx +707 -0
- package/site/content/docs/elements/flow/http.mdx +1080 -0
- package/site/content/docs/elements/flow/index.mdx +618 -0
- package/site/content/docs/elements/flow/meta.json +5 -0
- package/site/content/docs/elements/flow/routing.mdx +559 -0
- package/site/content/docs/elements/flow/workflows.mdx +640 -0
- package/site/content/docs/elements/gate/auth.mdx +371 -0
- package/site/content/docs/elements/gate/authorization.mdx +298 -0
- package/site/content/docs/elements/gate/index.mdx +418 -0
- package/site/content/docs/elements/gate/meta.json +5 -0
- package/site/content/docs/elements/gate/rate-limits.mdx +365 -0
- package/site/content/docs/elements/gate/rls.mdx +303 -0
- package/site/content/docs/elements/gate/tenancy.mdx +372 -0
- package/site/content/docs/elements/index.mdx +52 -11
- package/site/content/docs/elements/signal/broadcast.mdx +517 -0
- package/site/content/docs/elements/signal/index.mdx +352 -0
- package/site/content/docs/elements/signal/live.mdx +590 -0
- package/site/content/docs/elements/signal/meta.json +5 -0
- package/site/content/docs/elements/signal/once.mdx +596 -0
- package/site/content/docs/elements/store/files.mdx +659 -0
- package/site/content/docs/elements/store/index.mdx +310 -0
- package/site/content/docs/elements/store/kv.mdx +629 -0
- package/site/content/docs/elements/store/meta.json +5 -0
- package/site/content/docs/elements/store/search.mdx +946 -0
- package/site/content/docs/elements/store/sql.mdx +937 -0
- package/site/content/docs/elements/vault/config.mdx +256 -0
- package/site/content/docs/elements/vault/index.mdx +356 -0
- package/site/content/docs/elements/vault/meta.json +5 -0
- package/site/content/docs/elements/vault/rotation.mdx +273 -0
- package/site/content/docs/elements/vault/secrets.mdx +285 -0
- package/site/content/docs/index.mdx +78 -30
- package/site/content/docs/meta.json +11 -8
- package/site/content/docs/plugins/cors.mdx +2 -1
- package/site/content/docs/plugins/csrf.mdx +4 -1
- package/site/content/docs/plugins/headers.mdx +2 -1
- package/site/content/docs/plugins/ip-allowlist.mdx +2 -1
- package/site/content/docs/plugins/magic-link.mdx +6 -0
- package/site/content/docs/plugins/maintenance-mode.mdx +2 -1
- package/site/content/docs/plugins/oauth.mdx +1 -1
- package/site/content/docs/plugins/otp.mdx +12 -1
- package/site/content/docs/plugins/passkey.mdx +39 -15
- package/site/content/docs/plugins/two-factor.mdx +91 -34
- package/site/content/docs/plugins/username.mdx +1 -1
- package/site/content/docs/recipes/caddy.mdx +3 -3
- package/site/content/docs/recipes/index.mdx +18 -28
- package/site/content/docs/recipes/mailpit.mdx +1 -1
- package/site/content/docs/recipes/meilisearch.mdx +3 -3
- package/site/content/docs/recipes/meta.json +1 -4
- package/site/content/docs/recipes/nginx.mdx +2 -2
- package/site/content/docs/recipes/openrouter.mdx +283 -0
- package/site/content/docs/recipes/pgdog.mdx +3 -3
- package/site/content/docs/recipes/postgres.mdx +1 -2
- package/site/content/docs/recipes/rustfs.mdx +2 -2
- package/site/content/docs/recipes/traefik.mdx +3 -3
- package/site/content/docs/reference/cli.mdx +231 -0
- package/site/content/docs/reference/configuration.mdx +30 -10
- package/site/content/docs/reference/environment-variables.mdx +93 -20
- package/site/content/docs/reference/errors.mdx +132 -29
- package/site/content/docs/reference/fx.mdx +137 -73
- package/site/content/docs/reference/index.mdx +13 -21
- package/site/content/docs/reference/meta.json +4 -5
- package/site/content/docs/reference/okid.mdx +42 -17
- package/site/content/docs/reference/plugins.mdx +4 -3
- package/site/content/docs/reference/security.mdx +197 -0
- package/site/content/docs/understand/meta.json +5 -0
- package/site/content/docs/understand/the-anatomy.mdx +132 -0
- package/site/content/docs/understand/the-model.mdx +32 -0
- package/site/content/docs/understand/the-problem.mdx +74 -0
- package/site/content/docs/understand/the-vocabulary.mdx +26 -0
- package/src/auth/api-keys.ts +2 -1
- package/src/auth/bindings.ts +64 -16
- package/src/auth/gate-auth.test.ts +6 -1
- package/src/auth/identity.ts +152 -5
- package/src/auth/index.ts +29 -0
- package/src/auth/invites.ts +2 -1
- package/src/auth/method-context.ts +41 -0
- package/src/auth/oauth-as/crypto.ts +2 -1
- package/src/auth/oauth-as/stores.ts +2 -1
- package/src/auth/operator.ts +2 -1
- package/src/auth/sessions-jwt.test.ts +77 -0
- package/src/auth/sessions.ts +20 -4
- package/src/auth/tenants.ts +3 -2
- package/src/auth/two-factor-challenge.test.ts +61 -0
- package/src/auth/two-factor-challenge.ts +284 -0
- package/src/auth/verification.ts +5 -0
- package/src/bench/REPORT.md +49 -0
- package/src/bench/g03-signal-once.bench.ts +1 -1
- package/src/bench/g10-observability-contention.bench.ts +1 -1
- package/src/bench/g17-hybrid-search.bench.ts +572 -0
- package/src/bench/load-app.ts +2 -10
- package/src/cli/ai-setup/ai-setup.test.ts +331 -42
- package/src/cli/ai-setup/apply.ts +294 -52
- package/src/cli/ai-setup/catalog.ts +238 -1342
- package/src/cli/ai-setup/index.ts +14 -99
- package/src/cli/ai-setup/prompts.ts +60 -443
- package/src/cli/ask-seed.test.ts +96 -0
- package/src/cli/ask-seed.ts +82 -0
- package/src/cli/ask-vault-gaps.test.ts +84 -0
- package/src/cli/ask-vault-gaps.ts +146 -0
- package/src/cli/build.ts +2 -2
- package/src/cli/client-add.test.ts +26 -1
- package/src/cli/client-add.ts +106 -27
- package/src/cli/competitor-mention-removal.test.ts +1 -1
- package/src/cli/db-seed.ts +2 -0
- package/src/cli/db.ts +150 -11
- package/src/cli/dev.ts +119 -211
- package/src/cli/docker-clean.ts +2 -2
- package/src/cli/docker-cli.test.ts +1 -1
- package/src/cli/doctor-diff.ts +4 -2
- package/src/cli/doctor-pii.test.ts +1 -1
- package/src/cli/doctor.ts +14 -1
- package/src/cli/hero-meta.test.ts +4 -2
- package/src/cli/load-config.images.test.ts +8 -10
- package/src/cli/load-config.ts +1 -1
- package/src/cli/registry.ts +22 -10
- package/src/cli/replay.ts +3 -1
- package/src/cli/start.ts +1 -1
- package/src/cli/tui/keys.ts +2 -3
- package/src/client/auth/cookies.ts +74 -0
- package/src/client/auth/create-auth-client.ts +636 -0
- package/src/client/auth/denials.ts +99 -0
- package/src/client/auth/session.ts +283 -0
- package/src/client/auth.test.ts +251 -0
- package/src/client/auth.ts +39 -114
- package/src/client/create-with-session.ts +245 -0
- package/src/client/create.ts +51 -5
- package/src/client/index.ts +11 -1
- package/src/client/live.ts +11 -79
- package/src/client/notes-contract.test.ts +5 -10
- package/src/client/sse.ts +137 -0
- package/src/client/stream.ts +147 -0
- package/src/client/transport.test.ts +32 -0
- package/src/client/transport.ts +123 -26
- package/src/client/types.ts +118 -14
- package/src/client-react/index.ts +185 -24
- package/src/client-react/use-live-query.ts +13 -3
- package/src/compiler/aot.test.ts +7 -4
- package/src/compiler/effects-embed.test.ts +56 -0
- package/src/compiler/effects-fetch.test.ts +43 -0
- package/src/compiler/effects-infer.ts +58 -2
- package/src/compiler/extract.test.ts +258 -44
- package/src/compiler/extract.ts +566 -48
- package/src/compiler/fixtures/skyport/src/flows/bookings/index.ts +7 -4
- package/src/compiler/fixtures/skyport/src/flows/bookings/signals.ts +2 -8
- package/src/compiler/fixtures/skyport.expected.json +4 -4
- package/src/compiler/fixtures/triggers/five-triggers.ts +14 -10
- package/src/compiler/response.ts +2 -2
- package/src/compiler/search-writer-isolation.test.ts +40 -0
- package/src/config/index.ts +11 -0
- package/src/console/server/app.ts +17 -23
- package/src/console/server/bind.ts +4 -0
- package/src/console/server/console.test.ts +2 -2
- package/src/console/server/flows-invoke.test.ts +50 -34
- package/src/console/server/flows.ts +436 -255
- package/src/console/server/runs-ingest.test.ts +6 -3
- package/src/console/server/serve.ts +1 -1
- package/src/console/server/signals.test.ts +1 -5
- package/src/console/server/signals.ts +8 -6
- package/src/console/server/state.ts +6 -1
- package/src/console/server/store.ts +1 -1
- package/src/console/ui-next/dist/assets/FileExportIcon-Ck-5od4R.js +1 -0
- package/src/console/ui-next/dist/assets/MoreHorizontalCircle01Icon-gMNGsE37.js +1 -0
- package/src/console/ui-next/dist/assets/PlusSignIcon-CwG3nxfu.js +1 -0
- package/src/console/ui-next/dist/assets/UnavailableIcon-D9cvHVPr.js +1 -0
- package/src/console/ui-next/dist/assets/UserIcon-DaE2PB5_.js +1 -0
- package/src/console/ui-next/dist/assets/access-page-DFeymU07.js +4 -0
- package/src/console/ui-next/dist/assets/agent-disclosure-U1rdfblp.js +1 -0
- package/src/console/ui-next/dist/assets/cache-glyph-BeFJeqBG.js +1 -0
- package/src/console/ui-next/dist/assets/call-pii-button-CVAONPii.js +1 -0
- package/src/console/ui-next/dist/assets/collapsible-D2A6NJ-3.js +1 -0
- package/src/console/ui-next/dist/assets/copy-inline-button-CAYD18cr.js +1 -0
- package/src/console/ui-next/dist/assets/dagre.esm-B1_XeuLP.js +1 -0
- package/src/console/ui-next/dist/assets/detail-header-DVWNjWjg.js +1 -0
- package/src/console/ui-next/dist/assets/dropdown-menu-4h2LOVXM.js +1 -0
- package/src/console/ui-next/dist/assets/duration-tone-Cgk_h5ja.js +9 -0
- package/src/console/ui-next/dist/assets/element-icons-BI8cJgdh.js +1 -0
- package/src/console/ui-next/dist/assets/explorer-empty-CJs5A-wm.js +1 -0
- package/src/console/ui-next/dist/assets/flows-page-Dss7941e.js +1 -0
- package/src/console/ui-next/dist/assets/highlighted-json-MYZQtRnw.js +154 -0
- package/src/console/ui-next/dist/assets/http-method-Jrh39p7A.js +1 -0
- package/src/console/ui-next/dist/assets/index-D0zS5rKO.css +2 -0
- package/src/console/ui-next/dist/assets/index-DXP2dBIF.js +63 -0
- package/src/console/ui-next/dist/assets/observability-page-HvolXxTI.js +4 -0
- package/src/console/ui-next/dist/assets/react-dom-Ddte4I-Q.js +9 -0
- package/src/console/ui-next/dist/assets/replica-lag-CSh2dzrb.js +18 -0
- package/src/console/ui-next/dist/assets/request-meta-BatF8KrK.js +1 -0
- package/src/console/ui-next/dist/assets/shortcut-keys-3ILd8oGn.js +1 -0
- package/src/console/ui-next/dist/assets/{sql-BskegiFM.js → sql-BsFa4tDR.js} +1 -1
- package/src/console/ui-next/dist/assets/store-page-eiKiHnNe.js +41 -0
- package/src/console/ui-next/dist/assets/trace-detail-sheet-CZkMeKS-.js +2 -0
- package/src/console/ui-next/dist/assets/tree-expand-toggle-CW8y5A2h.js +55 -0
- package/src/console/ui-next/dist/assets/units-page-B_RWJrEO.js +1 -0
- package/src/console/ui-next/dist/assets/{use-vault-list-uk4WVboC.js → use-vault-list-CT4-gajj.js} +1 -1
- package/src/console/ui-next/dist/assets/vault-page-CWrg-A68.js +2 -0
- package/src/console/ui-next/dist/assets/xyflow-CSyC6ryz.css +1 -0
- package/src/console/ui-next/dist/assets/xyflow-yApv7D4e.js +7 -0
- package/src/console/ui-next/dist/index.html +6 -13
- package/src/console/ui-next/seed-invoke-host.ts +21 -18
- package/src/console/ui-next/src/client.ts +7 -2
- package/src/console/ui-next/src/features/flows/graph/element-map.ts +2 -0
- package/src/console/ui-next/src/features/flows/traces/effect-kind.ts +12 -2
- package/src/console/ui-next/src/features/flows/traces/effect-summary.ts +4 -0
- package/src/console/ui-next/src/features/flows/traces/trace-detail-sheet.tsx +8 -0
- package/src/console/ui-next/src/features/flows/traces/waterfall-bars.ts +4 -0
- package/src/console/ui-next/src/features/flows/traces/waterfall-tooltip.ts +9 -3
- package/src/console/ui-next/src/features/store/detail/reveal-cell.tsx +7 -11
- package/src/console/ui-next/src/features/store/detail/store-row-detail-sheet.tsx +2 -2
- package/src/console/ui-next/src/features/store/lib/fields-from-table.ts +2 -0
- package/src/console/ui-next/src/features/store/lib/grid-model.test.ts +25 -1
- package/src/console/ui-next/src/features/store/lib/grid-model.ts +36 -1
- package/src/console/ui-next/src/features/store/query/query-results.tsx +3 -3
- package/src/console/ui-next/src/features/units/detail/effects-summary.tsx +2 -0
- package/src/console/ui-next/src/features/units/lib/call-read-safe.ts +3 -1
- package/src/console/ui-next/src/features/units/lib/fields-from-schema.ts +6 -0
- package/src/docker/ai-model-status.test.ts +1 -12
- package/src/docker/ai-model-status.ts +10 -38
- package/src/docker/compose-up.test.ts +100 -0
- package/src/docker/compose-up.ts +292 -0
- package/src/docker/compose.ts +4 -14
- package/src/docker/derive.ts +9 -34
- package/src/docker/docker.test.ts +16 -261
- package/src/docker/images-config.test.ts +13 -25
- package/src/docker/index.ts +1 -24
- package/src/docker/recipes/index.ts +0 -23
- package/src/docker/recipes/pgdog.ts +6 -4
- package/src/docker/stack-id.test.ts +2 -2
- package/src/docker/stack-id.ts +0 -1
- package/src/docker/types.ts +2 -2
- package/src/drivers/ai-anthropic.ts +10 -0
- package/src/drivers/ai-openai-compatible.ts +34 -7
- package/src/drivers/ai-providers.test.ts +0 -107
- package/src/drivers/ai-stream.test.ts +0 -34
- package/src/drivers/ai-types.ts +17 -8
- package/src/drivers/channel-fcm.ts +6 -1
- package/src/drivers/channel-msegat.ts +6 -1
- package/src/drivers/channel-resend.ts +5 -1
- package/src/drivers/channel-smtp.ts +5 -1
- package/src/drivers/channel-sndr.ts +10 -1
- package/src/drivers/channel-taqnyat-mail.ts +5 -1
- package/src/drivers/channel-taqnyat-whatsapp.ts +6 -1
- package/src/drivers/channel-taqnyat.ts +6 -1
- package/src/drivers/channel-types.ts +10 -0
- package/src/drivers/channel-unifonic.ts +6 -1
- package/src/drivers/channel-wa-cloud.ts +6 -1
- package/src/drivers/channel-webpush.ts +6 -1
- package/src/drivers/external.ts +33 -0
- package/src/drivers/index.ts +0 -10
- package/src/drivers/meilisearch.ts +6 -0
- package/src/drivers/oauth-types.ts +4 -0
- package/src/drivers/postgres.test.ts +74 -3
- package/src/drivers/postgres.ts +175 -6
- package/src/drivers/signal-types.ts +5 -5
- package/src/drivers/types.ts +7 -0
- package/src/drivers/vault-types.ts +5 -0
- package/src/elements/ai/declare.ts +17 -4
- package/src/elements/ai/eval.ts +1 -1
- package/src/elements/ai/mcp-http.ts +1 -1
- package/src/elements/ai/pii.ts +1 -1
- package/src/elements/ai/providers.test.ts +289 -0
- package/src/elements/ai/providers.ts +169 -0
- package/src/elements/ai/runtime.ts +68 -5
- package/src/elements/ai/schema.ts +2 -2
- package/src/elements/ai.test.ts +7 -7
- package/src/elements/ai.ts +17 -1
- package/src/elements/channel/runtime.ts +105 -12
- package/src/elements/clock/cron-fields.test.ts +144 -0
- package/src/elements/clock/cron-fields.ts +185 -0
- package/src/elements/clock/declare.ts +247 -3
- package/src/elements/clock.ts +21 -1
- package/src/elements/index.ts +15 -0
- package/src/elements/signal/chaos-child.ts +1 -2
- package/src/elements/signal/declare.ts +65 -37
- package/src/elements/signal/delivery-modes.test.ts +11 -31
- package/src/elements/signal/dry-run-replay.test.ts +1 -7
- package/src/elements/signal/dry-run-write-isolation.test.ts +1 -7
- package/src/elements/signal/key-ordering.test.ts +6 -26
- package/src/elements/signal/lease-reclaim.test.ts +2 -6
- package/src/elements/signal/optional-emit.test.ts +6 -9
- package/src/elements/signal/order-lifecycle.test.ts +4 -17
- package/src/elements/signal/orphan-messages.test.ts +4 -15
- package/src/elements/signal/reconcile.test.ts +2 -2
- package/src/elements/signal/runtime.ts +1 -1
- package/src/elements/signal/schema-emit.test.ts +4 -8
- package/src/elements/signal.test.ts +24 -49
- package/src/elements/signal.ts +9 -2
- package/src/elements/store/domain-ddl.test.ts +1 -1
- package/src/elements/store/live-http.test.ts +9 -4
- package/src/elements/store/prepare-row.test.ts +123 -0
- package/src/elements/store/resource.ts +43 -12
- package/src/elements/store/schema-decl.ts +117 -0
- package/src/elements/store/search-backfill.ts +205 -0
- package/src/elements/store/search-bind.ts +66 -0
- package/src/elements/store/search-bm25.ts +78 -0
- package/src/elements/store/search-ddl.ts +156 -0
- package/src/elements/store/search-embed-flow.ts +141 -0
- package/src/elements/store/search-errors.ts +34 -0
- package/src/elements/store/search-fusion.ts +112 -0
- package/src/elements/store/search-lsh.ts +179 -0
- package/src/elements/store/search-runtime.ts +300 -0
- package/src/elements/store/search.test.ts +144 -0
- package/src/elements/store/sql-session.test.ts +1 -0
- package/src/elements/store/sql-session.ts +83 -3
- package/src/elements/store/table.ts +23 -2
- package/src/elements/store/upsert-app.test.ts +1 -3
- package/src/elements/store.ts +50 -0
- package/src/full.ts +4 -2
- package/src/http.ts +4 -1
- package/src/i18n/catalogs/ar.ts +14 -6
- package/src/i18n/catalogs/en.ts +14 -6
- package/src/index.ts +6 -1
- package/src/kernel/adopt-barrel-fresh.test.ts +7 -7
- package/src/kernel/adopt-routes.ts +9 -1
- package/src/kernel/app-auth.ts +5 -0
- package/src/kernel/app.ts +102 -9
- package/src/kernel/auto-cache.test.ts +6 -12
- package/src/kernel/auto-registry.test.ts +3 -3
- package/src/kernel/boot-bind/ai.test.ts +22 -19
- package/src/kernel/boot-bind/ai.ts +5 -43
- package/src/kernel/boot-bind/clock.ts +23 -5
- package/src/kernel/boot-bind/honor-config.test.ts +4 -4
- package/src/kernel/boot.test.ts +11 -6
- package/src/kernel/boot.ts +66 -16
- package/src/kernel/boundary-contract.ts +93 -0
- package/src/kernel/budget.test.ts +1 -1
- package/src/kernel/call.ts +89 -0
- package/src/kernel/capability.ts +6 -0
- package/src/kernel/client-descriptor.ts +123 -0
- package/src/kernel/clock-timezone.test.ts +80 -0
- package/src/kernel/correlation.test.ts +1 -1
- package/src/kernel/dry-run.ts +11 -8
- package/src/kernel/effects-stamping.test.ts +42 -9
- package/src/kernel/effects.test.ts +4 -2
- package/src/kernel/effects.ts +51 -9
- package/src/kernel/errors-channel.ts +17 -0
- package/src/kernel/errors-live-resume.ts +3 -2
- package/src/kernel/errors-tenant.ts +7 -4
- package/src/kernel/errors.registry-helpers.ts +96 -0
- package/src/kernel/errors.registry.test.ts +139 -25
- package/src/kernel/errors.ts +102 -23
- package/src/kernel/external-effects.test.ts +196 -0
- package/src/kernel/flow.test.ts +13 -4
- package/src/kernel/flow.ts +69 -71
- package/src/kernel/fx-ask-telemetry.test.ts +2 -2
- package/src/kernel/fx-dead-letters.test.ts +3 -3
- package/src/kernel/fx-fetch.ts +55 -0
- package/src/kernel/fx-live-stream.ts +2 -2
- package/src/kernel/fx-live.test.ts +8 -8
- package/src/kernel/fx.test.ts +17 -11
- package/src/kernel/fx.ts +180 -57
- package/src/kernel/horizontal-child.ts +1 -1
- package/src/kernel/http-query.test.ts +3 -6
- package/src/kernel/index.ts +13 -3
- package/src/kernel/instance-id.ts +1 -1
- package/src/kernel/instances.test.ts +40 -0
- package/src/kernel/instances.ts +47 -9
- package/src/kernel/live-http.test.ts +6 -7
- package/src/kernel/live-http.ts +6 -2
- package/src/kernel/live-resume.test.ts +1 -1
- package/src/kernel/mcp-tool.test.ts +3 -3
- package/src/kernel/on.ts +98 -4
- package/src/kernel/pipeline.test.ts +12 -15
- package/src/kernel/plugin-elements.test.ts +1 -1
- package/src/kernel/stamp-http.test.ts +3 -3
- package/src/kernel/triggers.ts +210 -95
- package/src/kernel-entry.ts +0 -1
- package/src/manifest/diff.ts +11 -1
- package/src/manifest/fixtures/skyport.excerpt.json +1 -1
- package/src/manifest/types.ts +46 -2
- package/src/mcp/docs-index.ts +3 -3
- package/src/mcp/docs-mcp.test.ts +2 -2
- package/src/mcp/docs-tools.ts +1 -1
- package/src/okid.test.ts +56 -0
- package/src/okid.ts +55 -11
- package/src/plugins/anonymous.ts +8 -4
- package/src/plugins/auth/shared.ts +27 -3
- package/src/plugins/auth-delivery.mailpit.integration.test.ts +1 -1
- package/src/plugins/auth-methods.security.test.ts +561 -23
- package/src/plugins/config-source.ts +1 -1
- package/src/plugins/csrf.test.ts +65 -0
- package/src/plugins/index.ts +2 -0
- package/src/plugins/magic-link.ts +36 -16
- package/src/plugins/oauth/shared.ts +3 -1
- package/src/plugins/oauth.ts +22 -14
- package/src/plugins/otp.ts +37 -21
- package/src/plugins/passkey-webauthn.ts +9 -6
- package/src/plugins/passkey.ts +98 -26
- package/src/plugins/pre-account-hijack.test.ts +223 -0
- package/src/plugins/two-factor.ts +466 -37
- package/src/plugins/username.ts +19 -7
- package/src/release/build-lib.ts +1 -0
- package/src/release/limits.ts +2 -2
- package/src/release/measure.ts +1 -1
- package/src/runs/collect.test.ts +0 -2
- package/src/runtime/json-code-block.test.ts +250 -20
- package/src/runtime/json-code-block.ts +1261 -41
- package/src/term.test.ts +1 -1
- package/src/test/create-test-app.test.ts +12 -12
- package/src/test/live-signals.test.ts +6 -6
- package/src/test/provisions.integration.test.ts +10 -14
- package/src/test/reset-element-registries.ts +1 -1
- package/src/test/tenant-isolation.test.ts +12 -6
- package/site/content/docs/deployment/docker-swarm.mdx +0 -164
- package/site/content/docs/deployment/docker.mdx +0 -227
- package/site/content/docs/deployment/index.mdx +0 -83
- package/site/content/docs/deployment/kubernetes.mdx +0 -176
- package/site/content/docs/deployment/meta.json +0 -5
- package/site/content/docs/deployment/reverse-proxy.mdx +0 -234
- package/site/content/docs/elements/ai.mdx +0 -385
- package/site/content/docs/elements/channel.mdx +0 -346
- package/site/content/docs/elements/clock.mdx +0 -244
- package/site/content/docs/elements/flow.mdx +0 -420
- package/site/content/docs/elements/gate.mdx +0 -436
- package/site/content/docs/elements/signal.mdx +0 -380
- package/site/content/docs/elements/store.mdx +0 -1099
- package/site/content/docs/elements/vault.mdx +0 -405
- package/site/content/docs/get-started/basic-usage.mdx +0 -173
- package/site/content/docs/get-started/index.mdx +0 -43
- package/site/content/docs/get-started/installation.mdx +0 -220
- package/site/content/docs/get-started/introduction.mdx +0 -132
- package/site/content/docs/get-started/meta.json +0 -13
- package/site/content/docs/get-started/project-structure.mdx +0 -925
- package/site/content/docs/get-started/testing.mdx +0 -328
- package/site/content/docs/get-started/why.mdx +0 -162
- package/site/content/docs/recipes/llama-cpp.mdx +0 -151
- package/site/content/docs/recipes/ollama.mdx +0 -142
- package/site/content/docs/recipes/sglang.mdx +0 -105
- package/site/content/docs/recipes/vllm.mdx +0 -106
- package/site/content/docs/reference/cli.md +0 -232
- package/site/content/docs/reference/client.mdx +0 -469
- package/site/content/docs/reference/security.md +0 -74
- package/src/cli/ai-setup/detect-ollama.ts +0 -213
- package/src/cli/ai-setup/recommend.test.ts +0 -225
- package/src/cli/ai-setup/recommend.ts +0 -225
- package/src/cli/dev-controls.test.ts +0 -122
- package/src/cli/dev-controls.ts +0 -164
- package/src/cli/tui/DevLive.tsx +0 -126
- package/src/console/ui-next/dist/assets/access-page-De7Lc2JC.js +0 -4
- package/src/console/ui-next/dist/assets/agent-disclosure-BP0Y0Sux.js +0 -1
- package/src/console/ui-next/dist/assets/cache-glyph-B5X-NM0-.js +0 -1
- package/src/console/ui-next/dist/assets/call-pii-button-ChAUiLo9.js +0 -1
- package/src/console/ui-next/dist/assets/collapsible-DGnOM2ph.js +0 -1
- package/src/console/ui-next/dist/assets/copy-inline-button-DBHhgHKP.js +0 -1
- package/src/console/ui-next/dist/assets/dagre.esm-ZwcdTuZZ.js +0 -1
- package/src/console/ui-next/dist/assets/detail-header-DhHM1iaZ.js +0 -1
- package/src/console/ui-next/dist/assets/dropdown-menu-_NjTEo5_.js +0 -1
- package/src/console/ui-next/dist/assets/duration-tone-sC3lGABz.js +0 -9
- package/src/console/ui-next/dist/assets/element-icons-BVXtRyd3.js +0 -1
- package/src/console/ui-next/dist/assets/explorer-empty-2uIhBu0_.js +0 -1
- package/src/console/ui-next/dist/assets/flows-page-RGy7VEA_.js +0 -1
- package/src/console/ui-next/dist/assets/highlighted-json-Awq7gYdu.js +0 -154
- package/src/console/ui-next/dist/assets/http-method-_UHM2ODJ.js +0 -1
- package/src/console/ui-next/dist/assets/index-Ck88Jmv8.css +0 -2
- package/src/console/ui-next/dist/assets/index-_rgpdVzo.js +0 -66
- package/src/console/ui-next/dist/assets/link-BX6Vqztd.js +0 -1
- package/src/console/ui-next/dist/assets/observability-page-Ds6pcnh-.js +0 -4
- package/src/console/ui-next/dist/assets/preload-helper-oH4irX4C.js +0 -1
- package/src/console/ui-next/dist/assets/react-D8E3mtu1.js +0 -1
- package/src/console/ui-next/dist/assets/react-dom-Bph1y7z7.js +0 -9
- package/src/console/ui-next/dist/assets/replica-lag-DKRrbvdo.js +0 -18
- package/src/console/ui-next/dist/assets/request-meta-DV0ywz7t.js +0 -1
- package/src/console/ui-next/dist/assets/shortcut-JQIZlWfm.js +0 -1
- package/src/console/ui-next/dist/assets/shortcut-keys-DKxNTe_m.js +0 -1
- package/src/console/ui-next/dist/assets/skeleton-D-czQJT6.js +0 -1
- package/src/console/ui-next/dist/assets/store-page-02xOiqIK.js +0 -41
- package/src/console/ui-next/dist/assets/trace-detail-sheet-B09O8rA6.js +0 -2
- package/src/console/ui-next/dist/assets/tree-expand-toggle-BtyhmWb4.js +0 -55
- package/src/console/ui-next/dist/assets/units-page-4rHOePuE.js +0 -1
- package/src/console/ui-next/dist/assets/useMutation-B8EO02Ej.js +0 -1
- package/src/console/ui-next/dist/assets/useRender-BE2A9BWC.js +0 -1
- package/src/console/ui-next/dist/assets/vault-page-DISPgxLM.js +0 -2
- package/src/console/ui-next/dist/assets/xyflow-D7n4g6go.js +0 -7
- package/src/console/ui-next/dist/assets/xyflow-DZ0Ws1xk.css +0 -1
- package/src/docker/ollama-pull.ts +0 -232
- package/src/docker/recipes/llama-cpp.ts +0 -298
- package/src/docker/recipes/ollama.ts +0 -44
- package/src/docker/recipes/sglang.ts +0 -55
- package/src/docker/recipes/vllm.ts +0 -44
- package/src/drivers/ai-ollama-tools.integration.test.ts +0 -109
- package/src/drivers/ai-ollama.integration.test.ts +0 -184
- package/src/drivers/ai-ollama.ts +0 -389
- package/src/drivers/ollama.ts +0 -14
package/src/cli/dev.ts
CHANGED
|
@@ -48,7 +48,6 @@ import {
|
|
|
48
48
|
} from "../term.ts";
|
|
49
49
|
import { clientAdd } from "./client-add.ts";
|
|
50
50
|
import { resolveDriverId } from "../config/index.ts";
|
|
51
|
-
import type { DevComposeControlAction } from "./dev-controls.ts";
|
|
52
51
|
import {
|
|
53
52
|
createDebouncedRunner,
|
|
54
53
|
isDomainSchemaWatchPath,
|
|
@@ -498,10 +497,12 @@ export async function runDev(options: DevOptions = {}): Promise<DevResult> {
|
|
|
498
497
|
let pendingAiModelWatch: {
|
|
499
498
|
readonly url: string;
|
|
500
499
|
readonly model: string;
|
|
501
|
-
readonly kind: "openai-compatible"
|
|
500
|
+
readonly kind: "openai-compatible";
|
|
502
501
|
} | null = null;
|
|
503
502
|
/** Hero AI status dot (yellow while model loads). */
|
|
504
503
|
let heroAiStatus: DevStatus | undefined;
|
|
504
|
+
/** Compose AI service name when `images.ai` is pinned — undefined for cloud AI. */
|
|
505
|
+
let stackAiServiceName: string | undefined;
|
|
505
506
|
let loadedConfig: Awaited<ReturnType<typeof loadOkeConfig>>["config"] | null = null;
|
|
506
507
|
try {
|
|
507
508
|
loadedConfig = (await loadOkeConfig(cwd)).config;
|
|
@@ -628,24 +629,42 @@ export async function runDev(options: DevOptions = {}): Promise<DevResult> {
|
|
|
628
629
|
const up =
|
|
629
630
|
options.composeUp ??
|
|
630
631
|
(async (files, dir) => {
|
|
631
|
-
const
|
|
632
|
-
|
|
632
|
+
const {
|
|
633
|
+
runComposeUp,
|
|
634
|
+
formatComposeUpEventMessage,
|
|
635
|
+
composeUpPhaseStatus,
|
|
636
|
+
shortenComposeTarget,
|
|
637
|
+
} = await import("../docker/compose-up.ts");
|
|
638
|
+
await runComposeUp({
|
|
639
|
+
files,
|
|
633
640
|
cwd: dir,
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
641
|
+
env: stackEnv!,
|
|
642
|
+
onEvent: (event) => {
|
|
643
|
+
const message = formatComposeUpEventMessage(event);
|
|
644
|
+
if (!message) return;
|
|
645
|
+
const status = event.phase
|
|
646
|
+
? composeUpPhaseStatus(event.phase)
|
|
647
|
+
: ("pending" as const);
|
|
648
|
+
const perService =
|
|
649
|
+
event.target &&
|
|
650
|
+
event.phase &&
|
|
651
|
+
event.phase !== "other" &&
|
|
652
|
+
(event.kind === undefined ||
|
|
653
|
+
event.kind === "container" ||
|
|
654
|
+
event.kind === "image" ||
|
|
655
|
+
event.kind === "service");
|
|
656
|
+
if (perService && event.target) {
|
|
657
|
+
const key = `compose:${shortenComposeTarget(event.target)}`;
|
|
658
|
+
bootProgress.set(key, formatStatusLine(message, undefined, status));
|
|
659
|
+
return;
|
|
660
|
+
}
|
|
661
|
+
// Download / network / misc — one activity row so pulls never look frozen.
|
|
662
|
+
bootProgress.set(
|
|
663
|
+
"compose:activity",
|
|
664
|
+
formatStatusLine(message, undefined, status === "error" ? "error" : "pending"),
|
|
665
|
+
);
|
|
666
|
+
},
|
|
637
667
|
});
|
|
638
|
-
const [stdout, stderr, code] = await Promise.all([
|
|
639
|
-
new Response(proc.stdout).text(),
|
|
640
|
-
new Response(proc.stderr).text(),
|
|
641
|
-
proc.exited,
|
|
642
|
-
]);
|
|
643
|
-
if (code !== 0) {
|
|
644
|
-
const detail = [stdout.trim(), stderr.trim()].filter(Boolean).join("\n");
|
|
645
|
-
throw new Error(
|
|
646
|
-
`oke dev: docker compose exited ${code}` + (detail ? `\n${detail}` : ""),
|
|
647
|
-
);
|
|
648
|
-
}
|
|
649
668
|
});
|
|
650
669
|
bootProgress.set("compose", formatStatusLine("docker compose up…", undefined, "pending"));
|
|
651
670
|
// Compose files live under docker/; cwd for compose is that directory.
|
|
@@ -661,6 +680,7 @@ export async function runDev(options: DevOptions = {}): Promise<DevResult> {
|
|
|
661
680
|
|
|
662
681
|
// Stream compose health until infra is up (AI may stay pending — model load).
|
|
663
682
|
const aiServiceName = derived.specs.find((s) => s.role === "ai")?.serviceName;
|
|
683
|
+
stackAiServiceName = aiServiceName;
|
|
664
684
|
const labelForService = (serviceName: string): string => {
|
|
665
685
|
const spec = derived.specs.find((s) => s.serviceName === serviceName);
|
|
666
686
|
return spec ? roleLabel(spec.role) : serviceName;
|
|
@@ -689,9 +709,10 @@ export async function runDev(options: DevOptions = {}): Promise<DevResult> {
|
|
|
689
709
|
cwd: dockerOut,
|
|
690
710
|
env: dockerStarted.env,
|
|
691
711
|
run: composeHealthRun,
|
|
692
|
-
|
|
712
|
+
// Postgres init + PgDog health can exceed 20s on a cold volume.
|
|
713
|
+
timeoutMs: 90_000,
|
|
693
714
|
isDone: (map) => {
|
|
694
|
-
// Empty ps (compose just-created / injectable gap): do not spin
|
|
715
|
+
// Empty ps (compose just-created / injectable gap): do not spin forever.
|
|
695
716
|
if (map.size === 0) return true;
|
|
696
717
|
return [...map.entries()].every(
|
|
697
718
|
([name, s]) => name === aiServiceName || s === "ready" || s === "error",
|
|
@@ -712,73 +733,8 @@ export async function runDev(options: DevOptions = {}): Promise<DevResult> {
|
|
|
712
733
|
};
|
|
713
734
|
}
|
|
714
735
|
|
|
715
|
-
//
|
|
716
|
-
//
|
|
717
|
-
// the background. Never treat compose "healthy" as model-ready.
|
|
718
|
-
const aiSpec = derived.specs.find((s) => s.role === "ai");
|
|
719
|
-
if (aiSpec) {
|
|
720
|
-
const { recipeFor } = await import("../docker/recipes/index.ts");
|
|
721
|
-
const recipeId = recipeFor(aiSpec.image).id;
|
|
722
|
-
const model =
|
|
723
|
-
stackEnv!.OKE_AI_MODEL?.trim() ||
|
|
724
|
-
process.env.OKE_AI_MODEL?.trim() ||
|
|
725
|
-
(recipeId === "ollama" ? "qwen3.5:9b" : "granite3.3:2b");
|
|
726
|
-
const url = `http://127.0.0.1:${aiSpec.hostPort}`;
|
|
727
|
-
const paintAi = (status: DevStatus, detail?: string) => {
|
|
728
|
-
heroAiStatus = status;
|
|
729
|
-
if (!pendingStackSummary) return;
|
|
730
|
-
pendingStackSummary = {
|
|
731
|
-
...pendingStackSummary,
|
|
732
|
-
services: pendingStackSummary.services.map((svc) =>
|
|
733
|
-
svc.serviceName === aiSpec.serviceName
|
|
734
|
-
? {
|
|
735
|
-
...svc,
|
|
736
|
-
status,
|
|
737
|
-
detail: detail ?? svc.detail,
|
|
738
|
-
}
|
|
739
|
-
: svc,
|
|
740
|
-
),
|
|
741
|
-
};
|
|
742
|
-
};
|
|
743
|
-
if (recipeId === "ollama") {
|
|
744
|
-
bootProgress.set(
|
|
745
|
-
"ai-model",
|
|
746
|
-
formatStatusLine(`AI ${model} — ensuring…`, undefined, "pending"),
|
|
747
|
-
);
|
|
748
|
-
const { ensureOllamaModel } = await import("../docker/ollama-pull.ts");
|
|
749
|
-
await ensureOllamaModel({
|
|
750
|
-
url,
|
|
751
|
-
model,
|
|
752
|
-
onStatus: (line) =>
|
|
753
|
-
bootProgress.set("ai-model", formatStatusLine(line, undefined, "pending")),
|
|
754
|
-
});
|
|
755
|
-
pendingAiModelWatch = { url, model, kind: "ollama" };
|
|
756
|
-
paintAi("ready", model);
|
|
757
|
-
} else if (recipeId === "llama-cpp" || recipeId === "vllm" || recipeId === "sglang") {
|
|
758
|
-
pendingAiModelWatch = {
|
|
759
|
-
url: `${url}/v1`,
|
|
760
|
-
model,
|
|
761
|
-
kind: "openai-compatible",
|
|
762
|
-
};
|
|
763
|
-
bootProgress.set(
|
|
764
|
-
"ai-model",
|
|
765
|
-
formatStatusLine(`AI ${model} — probing…`, undefined, "pending"),
|
|
766
|
-
);
|
|
767
|
-
const { probeAiModelStatus, formatAiModelStatusMessage } =
|
|
768
|
-
await import("../docker/ai-model-status.ts");
|
|
769
|
-
const snap = await probeAiModelStatus({
|
|
770
|
-
url: `${url}/v1`,
|
|
771
|
-
model,
|
|
772
|
-
kind: "openai-compatible",
|
|
773
|
-
});
|
|
774
|
-
const status = devStatusFromAiPhase(snap.phase);
|
|
775
|
-
paintAi(status, snap.phase === "ready" ? model : `${model} · ${snap.phase}`);
|
|
776
|
-
bootProgress.set(
|
|
777
|
-
"ai-model",
|
|
778
|
-
formatStatusLine(formatAiModelStatusMessage(snap), undefined, status),
|
|
779
|
-
);
|
|
780
|
-
}
|
|
781
|
-
}
|
|
736
|
+
// Compose no longer ships local AI recipes — BYO `OKE_AI_URL` watch
|
|
737
|
+
// is armed below after stackEnv / process.env are known.
|
|
782
738
|
} catch (err) {
|
|
783
739
|
const msg = err instanceof Error ? err.message : String(err);
|
|
784
740
|
console.error(msg);
|
|
@@ -802,6 +758,19 @@ export async function runDev(options: DevOptions = {}): Promise<DevResult> {
|
|
|
802
758
|
|
|
803
759
|
const heroAiModel =
|
|
804
760
|
stackEnv?.OKE_AI_MODEL?.trim() || process.env.OKE_AI_MODEL?.trim() || undefined;
|
|
761
|
+
// BYO OpenAI-compatible server (LM Studio, llama.cpp, …) — poll readiness
|
|
762
|
+
// without blocking boot. Registry cloud (OpenRouter) has no OKE_AI_URL.
|
|
763
|
+
if (!pendingAiModelWatch) {
|
|
764
|
+
const byoUrl = stackEnv?.OKE_AI_URL?.trim() || process.env.OKE_AI_URL?.trim() || undefined;
|
|
765
|
+
const byoModel = heroAiModel;
|
|
766
|
+
if (byoUrl && byoModel) {
|
|
767
|
+
pendingAiModelWatch = {
|
|
768
|
+
url: byoUrl,
|
|
769
|
+
model: byoModel,
|
|
770
|
+
kind: "openai-compatible",
|
|
771
|
+
};
|
|
772
|
+
}
|
|
773
|
+
}
|
|
805
774
|
// OpenAI-compatible model load can outlive compose health — default AI ● to pending.
|
|
806
775
|
if (pendingAiModelWatch && heroAiStatus === undefined) {
|
|
807
776
|
heroAiStatus = "pending";
|
|
@@ -840,7 +809,10 @@ export async function runDev(options: DevOptions = {}): Promise<DevResult> {
|
|
|
840
809
|
const one = (name: string) => h.get(name);
|
|
841
810
|
switch (element) {
|
|
842
811
|
case "ai": {
|
|
843
|
-
|
|
812
|
+
// Cloud / host AI has no compose service — ignore orphaned exited
|
|
813
|
+
// containers left over after `images.ai` was removed.
|
|
814
|
+
if (!stackAiServiceName) return aiStatus;
|
|
815
|
+
const container = one(stackAiServiceName);
|
|
844
816
|
if (container === "error") return "error";
|
|
845
817
|
return aiStatus ?? container;
|
|
846
818
|
}
|
|
@@ -883,7 +855,7 @@ export async function runDev(options: DevOptions = {}): Promise<DevResult> {
|
|
|
883
855
|
st === "ready" || st === "idle"
|
|
884
856
|
? null
|
|
885
857
|
: st === "error"
|
|
886
|
-
? liveComposeHealth.get(
|
|
858
|
+
? stackAiServiceName && liveComposeHealth.get(stackAiServiceName) === "error"
|
|
887
859
|
? "stopped"
|
|
888
860
|
: "error"
|
|
889
861
|
: "loading";
|
|
@@ -901,7 +873,7 @@ export async function runDev(options: DevOptions = {}): Promise<DevResult> {
|
|
|
901
873
|
const fromHealth = svc.serviceName ? liveComposeHealth.get(svc.serviceName) : undefined;
|
|
902
874
|
let status = fromHealth ?? svc.status ?? "pending";
|
|
903
875
|
let detail = svc.detail;
|
|
904
|
-
if (svc.serviceName ===
|
|
876
|
+
if (stackAiServiceName && svc.serviceName === stackAiServiceName) {
|
|
905
877
|
if (fromHealth === "error") {
|
|
906
878
|
status = "error";
|
|
907
879
|
detail = heroAiModel ? `${heroAiModel} · stopped` : "stopped";
|
|
@@ -941,9 +913,7 @@ export async function runDev(options: DevOptions = {}): Promise<DevResult> {
|
|
|
941
913
|
return { code: 0, plan };
|
|
942
914
|
}
|
|
943
915
|
|
|
944
|
-
let boardPaused = false;
|
|
945
916
|
const repaintBoard = (aiStatus?: DevStatus): void => {
|
|
946
|
-
if (boardPaused) return;
|
|
947
917
|
bootBoard.paint(paintBootBoard(aiStatus ?? heroAiStatus));
|
|
948
918
|
};
|
|
949
919
|
|
|
@@ -963,7 +933,7 @@ export async function runDev(options: DevOptions = {}): Promise<DevResult> {
|
|
|
963
933
|
onStatus: (_line, status) => {
|
|
964
934
|
const st = devStatusFromAiPhase(status.phase);
|
|
965
935
|
// Container stopped wins over model-phase "loading".
|
|
966
|
-
if (liveComposeHealth.get(
|
|
936
|
+
if (stackAiServiceName && liveComposeHealth.get(stackAiServiceName) === "error") {
|
|
967
937
|
heroAiStatus = "error";
|
|
968
938
|
repaintBoard("error");
|
|
969
939
|
if (!sawAiPaint) {
|
|
@@ -1012,6 +982,7 @@ export async function runDev(options: DevOptions = {}): Promise<DevResult> {
|
|
|
1012
982
|
|
|
1013
983
|
// One-shot schema sync for the compose (`dev`) profile: emits
|
|
1014
984
|
// schema.drizzle.ts for the active dialect, then pushes via drizzle-kit.
|
|
985
|
+
let schemaPushOk = options.noDbPush === true;
|
|
1015
986
|
if (!options.noDbPush) {
|
|
1016
987
|
const { syncDevSchema } = await import("./dev-schema-sync.ts");
|
|
1017
988
|
const configEnv = "dev" as const;
|
|
@@ -1027,11 +998,40 @@ export async function runDev(options: DevOptions = {}): Promise<DevResult> {
|
|
|
1027
998
|
`oke db push (dev · ${result.dialect}) ${result.code === 0 ? "ok" : "failed"}`,
|
|
1028
999
|
),
|
|
1029
1000
|
);
|
|
1001
|
+
schemaPushOk = result.code === 0;
|
|
1030
1002
|
} catch (err) {
|
|
1031
1003
|
write(await formatDevSchemaSyncFailure(cwd, err, "boot"));
|
|
1032
1004
|
}
|
|
1033
1005
|
}
|
|
1034
1006
|
|
|
1007
|
+
// Vault gaps before seed / app — missing contracts (e.g. OPENROUTER_API_KEY).
|
|
1008
|
+
{
|
|
1009
|
+
const { maybeAskVaultGaps } = await import("./ask-vault-gaps.ts");
|
|
1010
|
+
const vaultCode = await maybeAskVaultGaps({
|
|
1011
|
+
cwd,
|
|
1012
|
+
entry,
|
|
1013
|
+
write,
|
|
1014
|
+
stdinIsTTY: options.stdinIsTTY ?? process.stdin.isTTY,
|
|
1015
|
+
});
|
|
1016
|
+
if (vaultCode !== 0) {
|
|
1017
|
+
bootBoard.stop();
|
|
1018
|
+
restoreProcessEnv();
|
|
1019
|
+
restoreWarn();
|
|
1020
|
+
return { code: vaultCode };
|
|
1021
|
+
}
|
|
1022
|
+
}
|
|
1023
|
+
|
|
1024
|
+
// First-time seed ask only after a successful push (needs live schema).
|
|
1025
|
+
if (schemaPushOk && !options.noDbPush) {
|
|
1026
|
+
const { maybeAskSeed } = await import("./ask-seed.ts");
|
|
1027
|
+
await maybeAskSeed({
|
|
1028
|
+
cwd,
|
|
1029
|
+
env: "dev",
|
|
1030
|
+
write,
|
|
1031
|
+
stdinIsTTY: options.stdinIsTTY ?? process.stdin.isTTY,
|
|
1032
|
+
});
|
|
1033
|
+
}
|
|
1034
|
+
|
|
1035
1035
|
const autoPushEnabled = resolveDevAutoPush({
|
|
1036
1036
|
noDbPush: options.noDbPush,
|
|
1037
1037
|
docker: Boolean(stackEnv),
|
|
@@ -1208,23 +1208,20 @@ export async function runDev(options: DevOptions = {}): Promise<DevResult> {
|
|
|
1208
1208
|
env[RUNS_INGEST_SECRET_ENV] = ingestSecret;
|
|
1209
1209
|
}
|
|
1210
1210
|
|
|
1211
|
-
|
|
1212
|
-
|
|
1211
|
+
let app: DevAppHandle | null = await startApp(plan.entry, env);
|
|
1212
|
+
let boundAppPort = app.port ?? appPort;
|
|
1213
|
+
env.PORT = String(boundAppPort);
|
|
1213
1214
|
|
|
1214
1215
|
let mcpServer: DevMcpHandle | null = null;
|
|
1215
1216
|
let secret: string | null = null;
|
|
1216
1217
|
let sessions: SessionStore | null = null;
|
|
1217
1218
|
let attachedHost: { readonly stop: () => Promise<void> } | null = null;
|
|
1218
1219
|
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
consoleState = state;
|
|
1222
|
-
try {
|
|
1223
|
-
const { attachHostToConsole } = await import("./attach-host-console.ts");
|
|
1224
|
-
attachedHost = await attachHostToConsole({
|
|
1220
|
+
const attachHostOpts = consoleServer.console
|
|
1221
|
+
? {
|
|
1225
1222
|
entry: plan.entry,
|
|
1226
1223
|
cwd,
|
|
1227
|
-
state,
|
|
1224
|
+
state: consoleServer.console.state,
|
|
1228
1225
|
...(ingestSecret
|
|
1229
1226
|
? {
|
|
1230
1227
|
runsBridge: {
|
|
@@ -1233,7 +1230,15 @@ export async function runDev(options: DevOptions = {}): Promise<DevResult> {
|
|
|
1233
1230
|
},
|
|
1234
1231
|
}
|
|
1235
1232
|
: {}),
|
|
1236
|
-
}
|
|
1233
|
+
}
|
|
1234
|
+
: null;
|
|
1235
|
+
|
|
1236
|
+
if (consoleServer.console && attachHostOpts) {
|
|
1237
|
+
const state = consoleServer.console.state;
|
|
1238
|
+
consoleState = state;
|
|
1239
|
+
try {
|
|
1240
|
+
const { attachHostToConsole } = await import("./attach-host-console.ts");
|
|
1241
|
+
attachedHost = await attachHostToConsole(attachHostOpts);
|
|
1237
1242
|
} catch (err) {
|
|
1238
1243
|
write(
|
|
1239
1244
|
formatStatusLine(
|
|
@@ -1269,7 +1274,7 @@ export async function runDev(options: DevOptions = {}): Promise<DevResult> {
|
|
|
1269
1274
|
const boundDocsMcpPort = docsMcpServer?.port ?? docsMcpPort;
|
|
1270
1275
|
const docsMcpUrl = docsMcpServer?.url ?? null;
|
|
1271
1276
|
|
|
1272
|
-
const appUrl = app
|
|
1277
|
+
const appUrl = app?.url?.origin ?? `http://127.0.0.1:${boundAppPort}`;
|
|
1273
1278
|
await regen(appUrl);
|
|
1274
1279
|
|
|
1275
1280
|
const dbPush =
|
|
@@ -1365,15 +1370,11 @@ export async function runDev(options: DevOptions = {}): Promise<DevResult> {
|
|
|
1365
1370
|
}
|
|
1366
1371
|
});
|
|
1367
1372
|
|
|
1368
|
-
let stopDevControls: (() => void) | null = null;
|
|
1369
|
-
|
|
1370
1373
|
let stopped = false;
|
|
1371
1374
|
const stop = () => {
|
|
1372
1375
|
if (stopped) return;
|
|
1373
1376
|
stopped = true;
|
|
1374
1377
|
restoreWarn();
|
|
1375
|
-
stopDevControls?.();
|
|
1376
|
-
stopDevControls = null;
|
|
1377
1378
|
stopAiModelWatch?.();
|
|
1378
1379
|
stopAiModelWatch = null;
|
|
1379
1380
|
stopComposeHealthWatch?.();
|
|
@@ -1384,7 +1385,15 @@ export async function runDev(options: DevOptions = {}): Promise<DevResult> {
|
|
|
1384
1385
|
const host = attachedHost;
|
|
1385
1386
|
attachedHost = null;
|
|
1386
1387
|
void host?.stop();
|
|
1387
|
-
|
|
1388
|
+
const appHandle = app;
|
|
1389
|
+
app = null;
|
|
1390
|
+
void Promise.resolve(appHandle?.stop());
|
|
1391
|
+
void import("../drivers/postgres.ts")
|
|
1392
|
+
.then(async ({ pauseSharedPostgresClients, resumeSharedPostgresClients }) => {
|
|
1393
|
+
await pauseSharedPostgresClients();
|
|
1394
|
+
resumeSharedPostgresClients();
|
|
1395
|
+
})
|
|
1396
|
+
.catch(() => {});
|
|
1388
1397
|
consoleServer.stop();
|
|
1389
1398
|
mcpServer?.stop();
|
|
1390
1399
|
docsMcpServer?.stop();
|
|
@@ -1467,112 +1476,11 @@ export async function runDev(options: DevOptions = {}): Promise<DevResult> {
|
|
|
1467
1476
|
|
|
1468
1477
|
if (options.onReady) await options.onReady(session);
|
|
1469
1478
|
|
|
1470
|
-
// Keyboard controls (docker + TTY): Ink replaces raw-mode stdin.
|
|
1471
|
-
if (keepAlive && dockerStarted && (options.stdinIsTTY ?? process.stdin.isTTY)) {
|
|
1472
|
-
const started = dockerStarted;
|
|
1473
|
-
const syncComposeBoard = async (): Promise<void> => {
|
|
1474
|
-
const { readComposeHealth } = await import("../docker/compose-health.ts");
|
|
1475
|
-
liveComposeHealth = await readComposeHealth({
|
|
1476
|
-
files: started.files,
|
|
1477
|
-
cwd: started.cwd,
|
|
1478
|
-
env: started.env,
|
|
1479
|
-
run: composeHealthRun,
|
|
1480
|
-
});
|
|
1481
|
-
if (liveComposeHealth.get("ai") === "error") heroAiStatus = "error";
|
|
1482
|
-
repaintBoard();
|
|
1483
|
-
};
|
|
1484
|
-
const refreshChrome = async (): Promise<void> => {
|
|
1485
|
-
await syncComposeBoard();
|
|
1486
|
-
paintReadyChrome();
|
|
1487
|
-
};
|
|
1488
|
-
const waitComposeReady = async (): Promise<void> => {
|
|
1489
|
-
const { watchComposeHealth } = await import("../docker/compose-health.ts");
|
|
1490
|
-
const aiServiceName = started.aiServiceName;
|
|
1491
|
-
liveComposeHealth = await watchComposeHealth({
|
|
1492
|
-
files: started.files,
|
|
1493
|
-
cwd: started.cwd,
|
|
1494
|
-
env: started.env,
|
|
1495
|
-
run: composeHealthRun,
|
|
1496
|
-
timeoutMs: 20_000,
|
|
1497
|
-
isDone: (map) => {
|
|
1498
|
-
if (map.size === 0) return true;
|
|
1499
|
-
return [...map.entries()].every(
|
|
1500
|
-
([name, s]) => name === aiServiceName || s === "ready" || s === "error",
|
|
1501
|
-
);
|
|
1502
|
-
},
|
|
1503
|
-
});
|
|
1504
|
-
if (liveComposeHealth.get("ai") === "error") heroAiStatus = "error";
|
|
1505
|
-
};
|
|
1506
|
-
|
|
1507
|
-
const composeAction = async (action: DevComposeControlAction): Promise<void> => {
|
|
1508
|
-
const files = started.files;
|
|
1509
|
-
const finalArgs =
|
|
1510
|
-
action === "up"
|
|
1511
|
-
? ["compose", ...files.flatMap((f) => ["-f", f]), "up", "-d"]
|
|
1512
|
-
: ["compose", ...files.flatMap((f) => ["-f", f]), action];
|
|
1513
|
-
const proc = Bun.spawn(["docker", ...finalArgs], {
|
|
1514
|
-
cwd: started.cwd,
|
|
1515
|
-
stdout: "pipe",
|
|
1516
|
-
stderr: "pipe",
|
|
1517
|
-
env: { ...process.env, ...started.env },
|
|
1518
|
-
});
|
|
1519
|
-
const [stdout, stderr, code] = await Promise.all([
|
|
1520
|
-
new Response(proc.stdout).text(),
|
|
1521
|
-
new Response(proc.stderr).text(),
|
|
1522
|
-
proc.exited,
|
|
1523
|
-
]);
|
|
1524
|
-
if (code !== 0) {
|
|
1525
|
-
const detail = [stdout.trim(), stderr.trim()].filter(Boolean).join("\n");
|
|
1526
|
-
throw new Error(`docker compose ${action} exited ${code}` + (detail ? `\n${detail}` : ""));
|
|
1527
|
-
}
|
|
1528
|
-
if (action === "up") await waitComposeReady();
|
|
1529
|
-
await syncComposeBoard();
|
|
1530
|
-
};
|
|
1531
|
-
|
|
1532
|
-
try {
|
|
1533
|
-
const { launchDevLiveControls } = await import("./tui/DevLive.tsx");
|
|
1534
|
-
await launchDevLiveControls({
|
|
1535
|
-
onRefresh: () => refreshChrome(),
|
|
1536
|
-
onSeed: async () => {
|
|
1537
|
-
const { runSlashCli } = await import("./tui/slash-run.ts");
|
|
1538
|
-
boardPaused = true;
|
|
1539
|
-
const lines: string[] = [];
|
|
1540
|
-
try {
|
|
1541
|
-
const code = await runSlashCli(cwd, ["db", "seed", "--force"], (line) => {
|
|
1542
|
-
lines.push(line);
|
|
1543
|
-
write(line);
|
|
1544
|
-
});
|
|
1545
|
-
if (code === 0) return;
|
|
1546
|
-
const last = [...lines]
|
|
1547
|
-
.reverse()
|
|
1548
|
-
.map((line) => line.trim())
|
|
1549
|
-
.find((line) => line.length > 0 && !line.startsWith("✗") && !line.startsWith("$"));
|
|
1550
|
-
throw new Error(last || "oke db seed failed");
|
|
1551
|
-
} finally {
|
|
1552
|
-
boardPaused = false;
|
|
1553
|
-
}
|
|
1554
|
-
},
|
|
1555
|
-
onComposeUp: () => composeAction("up"),
|
|
1556
|
-
onComposeStop: () => composeAction("stop"),
|
|
1557
|
-
onQuit: () => {
|
|
1558
|
-
stop();
|
|
1559
|
-
process.exit(0);
|
|
1560
|
-
},
|
|
1561
|
-
});
|
|
1562
|
-
// Esc / unmount without q — still tear down.
|
|
1563
|
-
stop();
|
|
1564
|
-
} catch {
|
|
1565
|
-
// Inconsequential: Ink/TUI is optional chrome — fall back to keep-alive without keyboard.
|
|
1566
|
-
await new Promise(() => {});
|
|
1567
|
-
}
|
|
1568
|
-
return { code: 0, plan: session.plan, session };
|
|
1569
|
-
}
|
|
1570
|
-
|
|
1571
1479
|
if (!keepAlive) {
|
|
1572
1480
|
return { code: 0, plan: session.plan, session };
|
|
1573
1481
|
}
|
|
1574
1482
|
|
|
1575
|
-
// Keep the process alive.
|
|
1483
|
+
// Keep the process alive (Ctrl+C / SIGTERM → session.stop).
|
|
1576
1484
|
await new Promise(() => {});
|
|
1577
1485
|
return { code: 0, plan: session.plan, session };
|
|
1578
1486
|
}
|
package/src/cli/docker-clean.ts
CHANGED
|
@@ -326,7 +326,7 @@ async function askIncludeOthersPrompt(): Promise<boolean | null> {
|
|
|
326
326
|
initialValue: false,
|
|
327
327
|
});
|
|
328
328
|
if (isCancel(value)) return null;
|
|
329
|
-
return value;
|
|
329
|
+
return Boolean(value);
|
|
330
330
|
}
|
|
331
331
|
|
|
332
332
|
/**
|
|
@@ -356,7 +356,7 @@ async function pickProjectKeys(options: {
|
|
|
356
356
|
required: false,
|
|
357
357
|
});
|
|
358
358
|
if (isCancel(value)) return null;
|
|
359
|
-
return value;
|
|
359
|
+
return Array.isArray(value) ? value : null;
|
|
360
360
|
}
|
|
361
361
|
|
|
362
362
|
/**
|
package/src/cli/doctor-diff.ts
CHANGED
|
@@ -81,7 +81,9 @@ export async function runDoctorDiff(options: DoctorDiffOptions = {}): Promise<Do
|
|
|
81
81
|
for (const c of undeclared) {
|
|
82
82
|
write(` [contract-breaking] ${c.path}: ${c.summary}\n`);
|
|
83
83
|
}
|
|
84
|
-
write(
|
|
84
|
+
write(
|
|
85
|
+
"Acknowledge intentional breaks with `breaking: true` on the HTTP / call / MCP / resource contract bag.\n",
|
|
86
|
+
);
|
|
85
87
|
return { code: EXIT_RUNTIME, undeclared, allChanges: all };
|
|
86
88
|
}
|
|
87
89
|
|
|
@@ -223,7 +225,7 @@ export async function doctorDiffCli(args: readonly string[]): Promise<number> {
|
|
|
223
225
|
|
|
224
226
|
CI gate: fail on undeclared contract-breaking Manifest changes.
|
|
225
227
|
Default: git merge-base (main/master) vs working-tree manifest.
|
|
226
|
-
Acknowledge intentional breaks with breaking: true on the
|
|
228
|
+
Acknowledge intentional breaks with breaking: true on the HTTP / call / MCP / resource contract bag.
|
|
227
229
|
`);
|
|
228
230
|
return EXIT_OK;
|
|
229
231
|
}
|
|
@@ -87,7 +87,7 @@ describe("doctor-pii", () => {
|
|
|
87
87
|
db: { facet: "sql", classifications: { email: { pii: true } } },
|
|
88
88
|
},
|
|
89
89
|
ai: {
|
|
90
|
-
models: { m: { provider: "
|
|
90
|
+
models: { m: { provider: "anthropic" } },
|
|
91
91
|
prompts: { summarize: { model: "m" } },
|
|
92
92
|
},
|
|
93
93
|
});
|
package/src/cli/doctor.ts
CHANGED
|
@@ -102,7 +102,8 @@ export interface DoctorFinding {
|
|
|
102
102
|
| "cdc_outbox_backlog"
|
|
103
103
|
| "cdc_outbox_retention"
|
|
104
104
|
| "live_subscriber_pressure"
|
|
105
|
-
| "live_fanout_queue_saturated"
|
|
105
|
+
| "live_fanout_queue_saturated"
|
|
106
|
+
| "search_backfill_required";
|
|
106
107
|
readonly severity: "error" | "warn";
|
|
107
108
|
readonly message: string;
|
|
108
109
|
}
|
|
@@ -414,6 +415,18 @@ export async function runDoctor(options: DoctorOptions = {}): Promise<{
|
|
|
414
415
|
}
|
|
415
416
|
|
|
416
417
|
if (manifest) {
|
|
418
|
+
for (const store of Object.values(manifest.stores ?? {})) {
|
|
419
|
+
if (store.facet !== "sql" || !store.tables) continue;
|
|
420
|
+
for (const [tableName, table] of Object.entries(store.tables)) {
|
|
421
|
+
if (table.search?.backfillRequired === true) {
|
|
422
|
+
findings.push({
|
|
423
|
+
code: "search_backfill_required",
|
|
424
|
+
severity: "warn",
|
|
425
|
+
message: `table "${tableName}" has searchable/embed columns on existing data — run \`oke db search-backfill ${tableName}\` (never auto on push)`,
|
|
426
|
+
});
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
}
|
|
417
430
|
findings.push(...checkManifestPiiAsks(manifest));
|
|
418
431
|
}
|
|
419
432
|
|
|
@@ -114,9 +114,11 @@ describe("hero-meta", () => {
|
|
|
114
114
|
ai: { dev: "openai-compatible", test: "mock", prod: "openai-compatible" },
|
|
115
115
|
},
|
|
116
116
|
},
|
|
117
|
-
{ docker: true, sqlDriver: "postgres", kvDriver: "redis", aiModel: "
|
|
117
|
+
{ docker: true, sqlDriver: "postgres", kvDriver: "redis", aiModel: "openrouter/free" },
|
|
118
|
+
);
|
|
119
|
+
expect(rows.find((r) => r.element === "ai")?.detail).toBe(
|
|
120
|
+
"openai-compatible · openrouter/free",
|
|
118
121
|
);
|
|
119
|
-
expect(rows.find((r) => r.element === "ai")?.detail).toBe("openai-compatible · granite3.3:2b");
|
|
120
122
|
expect(rows.find((r) => r.element === "ai")?.status).not.toBe("idle");
|
|
121
123
|
});
|
|
122
124
|
|
|
@@ -20,9 +20,8 @@ describe("flattenImagesConfig", () => {
|
|
|
20
20
|
files: "rustfs/rustfs:1.0.0",
|
|
21
21
|
index: "getmeili/meilisearch:v1.53",
|
|
22
22
|
},
|
|
23
|
-
channel: { email: "axllent/mailpit:v1.
|
|
24
|
-
|
|
25
|
-
pgdog: "ghcr.io/pgdogdev/pgdog:v0.1.53",
|
|
23
|
+
channel: { email: "axllent/mailpit:v1.31.1" },
|
|
24
|
+
pgdog: "ghcr.io/pgdogdev/pgdog:v0.1.57",
|
|
26
25
|
proxy: "caddy:2-alpine",
|
|
27
26
|
}),
|
|
28
27
|
).toEqual({
|
|
@@ -30,9 +29,8 @@ describe("flattenImagesConfig", () => {
|
|
|
30
29
|
"store.kv": "redis:8-alpine",
|
|
31
30
|
"store.files": "rustfs/rustfs:1.0.0",
|
|
32
31
|
"store.index": "getmeili/meilisearch:v1.53",
|
|
33
|
-
"channel.email": "axllent/mailpit:v1.
|
|
34
|
-
|
|
35
|
-
pgdog: "ghcr.io/pgdogdev/pgdog:v0.1.53",
|
|
32
|
+
"channel.email": "axllent/mailpit:v1.31.1",
|
|
33
|
+
pgdog: "ghcr.io/pgdogdev/pgdog:v0.1.57",
|
|
36
34
|
proxy: "caddy:2-alpine",
|
|
37
35
|
});
|
|
38
36
|
});
|
|
@@ -55,7 +53,7 @@ describe("defaultImagesFromConfig", () => {
|
|
|
55
53
|
});
|
|
56
54
|
expect(images).toEqual({
|
|
57
55
|
"store.sql": "postgres:18-alpine",
|
|
58
|
-
pgdog: "ghcr.io/pgdogdev/pgdog:v0.1.
|
|
56
|
+
pgdog: "ghcr.io/pgdogdev/pgdog:v0.1.57",
|
|
59
57
|
"store.kv": "redis:8-alpine",
|
|
60
58
|
});
|
|
61
59
|
});
|
|
@@ -70,7 +68,7 @@ describe("defaultImagesFromConfig", () => {
|
|
|
70
68
|
},
|
|
71
69
|
});
|
|
72
70
|
expect(images["store.sql"]).toBe("pgvector/pgvector:pg17");
|
|
73
|
-
expect(images.pgdog).toBe("ghcr.io/pgdogdev/pgdog:v0.1.
|
|
71
|
+
expect(images.pgdog).toBe("ghcr.io/pgdogdev/pgdog:v0.1.57");
|
|
74
72
|
});
|
|
75
73
|
|
|
76
74
|
test("clock postgres alone pulls store.sql image", () => {
|
|
@@ -81,7 +79,7 @@ describe("defaultImagesFromConfig", () => {
|
|
|
81
79
|
});
|
|
82
80
|
expect(images).toEqual({
|
|
83
81
|
"store.sql": "postgres:18-alpine",
|
|
84
|
-
pgdog: "ghcr.io/pgdogdev/pgdog:v0.1.
|
|
82
|
+
pgdog: "ghcr.io/pgdogdev/pgdog:v0.1.57",
|
|
85
83
|
});
|
|
86
84
|
});
|
|
87
85
|
|
|
@@ -93,7 +91,7 @@ describe("defaultImagesFromConfig", () => {
|
|
|
93
91
|
});
|
|
94
92
|
expect(images).toEqual({
|
|
95
93
|
"store.sql": "postgres:18-alpine",
|
|
96
|
-
pgdog: "ghcr.io/pgdogdev/pgdog:v0.1.
|
|
94
|
+
pgdog: "ghcr.io/pgdogdev/pgdog:v0.1.57",
|
|
97
95
|
});
|
|
98
96
|
});
|
|
99
97
|
|
package/src/cli/load-config.ts
CHANGED
|
@@ -15,7 +15,7 @@ import type { Manifest } from "../manifest/types.ts";
|
|
|
15
15
|
/** Default image pins when `images` is omitted but prod drivers need containers. */
|
|
16
16
|
const DEFAULT_SQL_IMAGE = "postgres:18-alpine";
|
|
17
17
|
const DEFAULT_PGVECTOR_IMAGE = "pgvector/pgvector:pg17";
|
|
18
|
-
const DEFAULT_PGDOG_IMAGE = "ghcr.io/pgdogdev/pgdog:v0.1.
|
|
18
|
+
const DEFAULT_PGDOG_IMAGE = "ghcr.io/pgdogdev/pgdog:v0.1.57";
|
|
19
19
|
const DEFAULT_KV_IMAGE = "redis:8-alpine";
|
|
20
20
|
|
|
21
21
|
/**
|