okengine 0.10.2 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +76 -10
- package/site/content/docs/ai/mcp.mdx +0 -1
- package/site/content/docs/deployment/docker-swarm.mdx +48 -111
- package/site/content/docs/deployment/docker.mdx +43 -36
- package/site/content/docs/deployment/index.mdx +9 -9
- package/site/content/docs/deployment/kubernetes.mdx +4 -4
- package/site/content/docs/elements/ai.mdx +7 -13
- package/site/content/docs/elements/channel.mdx +9 -13
- package/site/content/docs/elements/clock.mdx +8 -14
- package/site/content/docs/elements/flow.mdx +46 -54
- package/site/content/docs/elements/gate.mdx +6 -11
- package/site/content/docs/elements/signal.mdx +2 -8
- package/site/content/docs/elements/store.mdx +79 -93
- package/site/content/docs/elements/vault.mdx +89 -76
- package/site/content/docs/get-started/basic-usage.mdx +8 -14
- package/site/content/docs/get-started/installation.mdx +36 -36
- package/site/content/docs/get-started/introduction.mdx +11 -0
- package/site/content/docs/get-started/why.mdx +3 -4
- package/site/content/docs/index.mdx +0 -1
- package/site/content/docs/meta.json +0 -1
- package/site/content/docs/plugins/anonymous.mdx +1 -1
- package/site/content/docs/plugins/magic-link.mdx +11 -11
- package/site/content/docs/plugins/otp.mdx +2 -2
- package/site/content/docs/plugins/passkey.mdx +1 -1
- package/site/content/docs/plugins/two-factor.mdx +1 -1
- package/site/content/docs/plugins/username.mdx +1 -1
- package/site/content/docs/recipes/caddy.mdx +1 -1
- package/site/content/docs/recipes/cockroachdb.mdx +2 -2
- package/site/content/docs/recipes/dragonfly.mdx +1 -1
- package/site/content/docs/recipes/index.mdx +1 -2
- package/site/content/docs/recipes/llama-cpp.mdx +21 -23
- package/site/content/docs/recipes/mailpit.mdx +11 -11
- package/site/content/docs/recipes/meilisearch.mdx +10 -10
- package/site/content/docs/recipes/meta.json +0 -1
- package/site/content/docs/recipes/ollama.mdx +1 -1
- package/site/content/docs/recipes/pgdog.mdx +12 -9
- package/site/content/docs/recipes/postgres.mdx +3 -3
- package/site/content/docs/recipes/redis.mdx +2 -2
- package/site/content/docs/recipes/rustfs.mdx +10 -7
- package/site/content/docs/recipes/sglang.mdx +1 -1
- package/site/content/docs/recipes/supabase-docker.mdx +1 -1
- package/site/content/docs/recipes/timescale.mdx +2 -2
- package/site/content/docs/recipes/valkey.mdx +1 -1
- package/site/content/docs/recipes/vllm.mdx +1 -1
- package/site/content/docs/recipes/yugabytedb.mdx +2 -2
- package/site/content/docs/reference/cli.md +61 -38
- package/site/content/docs/reference/configuration.mdx +145 -70
- package/site/content/docs/reference/environment-variables.mdx +36 -28
- package/site/content/docs/reference/errors.mdx +28 -29
- package/site/content/docs/reference/fx.mdx +14 -7
- package/site/content/docs/reference/i18n.mdx +17 -6
- package/site/content/docs/reference/index.mdx +5 -0
- package/site/content/docs/reference/meta.json +1 -0
- package/site/content/docs/reference/migrating-environments.mdx +158 -0
- package/site/content/docs/reference/plugins.mdx +2 -2
- package/src/auth/gate-auth.test.ts +12 -10
- package/src/cli/ai-setup/ai-setup.test.ts +30 -16
- package/src/cli/ai-setup/apply.ts +111 -15
- package/src/cli/ai-setup/catalog.ts +3 -3
- package/src/cli/ai-setup/index.ts +1 -1
- package/src/cli/ai-setup/prompts.ts +1 -1
- package/src/cli/ai-setup/recommend.test.ts +1 -1
- package/src/cli/ask-seed.test.ts +3 -3
- package/src/cli/build.ts +8 -9
- package/src/cli/db-auto-push.test.ts +6 -3
- package/src/cli/db-auto-push.ts +7 -5
- package/src/cli/db-seed.ts +7 -8
- package/src/cli/db.test.ts +70 -71
- package/src/cli/db.ts +86 -12
- package/src/cli/dev-controller.test.ts +35 -0
- package/src/cli/dev-controller.ts +298 -0
- package/src/cli/dev-controls.ts +11 -65
- package/src/cli/dev-db-push.test.ts +47 -15
- package/src/cli/dev-schema-sync.test.ts +11 -11
- package/src/cli/dev-schema-sync.ts +10 -10
- package/src/cli/dev-session-lock.test.ts +106 -0
- package/src/cli/dev-session-lock.ts +209 -0
- package/src/cli/dev.test.ts +246 -114
- package/src/cli/dev.ts +153 -205
- package/src/cli/doc-staleness.test.ts +3 -6
- package/src/cli/docker-clean.test.ts +33 -1
- package/src/cli/docker-clean.ts +28 -33
- package/src/cli/docker-cli.test.ts +12 -11
- package/src/cli/docker.ts +95 -20
- package/src/cli/doctor.test.ts +40 -0
- package/src/cli/doctor.ts +142 -9
- package/src/cli/drizzle-env.test.ts +11 -13
- package/src/cli/drizzle-env.ts +18 -11
- package/src/cli/ensure-drizzle-config.ts +11 -14
- package/src/cli/hero-meta.test.ts +15 -15
- package/src/cli/hero-meta.ts +10 -9
- package/src/cli/index.ts +36 -6
- package/src/cli/load-config.images.test.ts +44 -10
- package/src/cli/load-config.source.test.ts +50 -0
- package/src/cli/load-config.ts +35 -29
- package/src/cli/meilisearch-local.ts +1 -2
- package/src/cli/mode.ts +7 -58
- package/src/cli/registry.ts +175 -19
- package/src/cli/resolve-dev-sql-env.test.ts +8 -16
- package/src/cli/resolve-dev-sql-env.ts +13 -15
- package/src/cli/safe-defaults.test.ts +29 -11
- package/src/cli/schema.ts +65 -16
- package/src/cli/test.ts +58 -0
- package/src/cli/tui/App.tsx +252 -0
- package/src/cli/tui/DevLive.tsx +116 -0
- package/src/cli/tui/components/ConfirmDialog.tsx +48 -0
- package/src/cli/tui/components/HeaderBar.tsx +67 -0
- package/src/cli/tui/components/LogStream.tsx +47 -0
- package/src/cli/tui/components/PanelCard.tsx +39 -0
- package/src/cli/tui/components/SelectRow.tsx +37 -0
- package/src/cli/tui/components/SlashPalette.tsx +172 -0
- package/src/cli/tui/components/Spinner.tsx +32 -0
- package/src/cli/tui/components/StatusBar.tsx +51 -0
- package/src/cli/tui/components/StatusDot.tsx +37 -0
- package/src/cli/tui/components/TabBar.tsx +49 -0
- package/src/cli/tui/components/Wordmark.tsx +43 -0
- package/src/cli/tui/format.ts +38 -0
- package/src/cli/tui/keys.test.ts +18 -0
- package/src/cli/tui/keys.ts +26 -0
- package/src/cli/tui/launch.test.ts +18 -0
- package/src/cli/tui/launch.ts +57 -0
- package/src/cli/tui/panels/Dashboard.tsx +201 -0
- package/src/cli/tui/panels/Database.tsx +198 -0
- package/src/cli/tui/panels/Dev.tsx +257 -0
- package/src/cli/tui/panels/Docker.tsx +357 -0
- package/src/cli/tui/panels/Navigator.test.ts +22 -0
- package/src/cli/tui/panels/Navigator.tsx +213 -0
- package/src/cli/tui/slash-catalog.test.ts +31 -0
- package/src/cli/tui/slash-catalog.ts +184 -0
- package/src/cli/tui/slash-run.ts +54 -0
- package/src/cli/tui/state/ports.ts +95 -0
- package/src/cli/tui/theme.ts +24 -0
- package/src/cli/vault-cmd.test.ts +402 -0
- package/src/cli/vault-cmd.ts +727 -69
- package/src/cli/vault-secure-input.test.ts +56 -0
- package/src/cli/vault-secure-input.ts +124 -0
- package/src/compiler/effects-infer.ts +7 -0
- package/src/compiler/extract.ts +12 -0
- package/src/compiler/fixtures/skyport/oke.config.ts +7 -5
- package/src/compiler/fixtures/skyport/src/flows/payments/index.ts +1 -1
- package/src/compiler/fixtures/skyport.expected.json +1 -1
- package/src/compiler/generate-adopt.ts +27 -1
- package/src/compiler-entry.ts +7 -0
- package/src/config/define-config.test.ts +111 -47
- package/src/config/driver-defaults.test.ts +115 -0
- package/src/config/driver-defaults.ts +156 -0
- package/src/config/index.ts +246 -131
- package/src/config/resolve-driver.test.ts +14 -19
- package/src/console/server/app.ts +4 -2
- package/src/console/server/console.test.ts +58 -1
- package/src/console/server/flows.ts +22 -2
- package/src/console/server/index.ts +3 -0
- package/src/console/server/operator-db.test.ts +55 -13
- package/src/console/server/operator-db.ts +305 -263
- package/src/console/server/serve.ts +16 -7
- package/src/console/server/state.ts +31 -9
- package/src/console/server/vault.test.ts +120 -5
- package/src/console/server/vault.ts +208 -12
- package/src/console/ui/dist/assets/{index-D-9KFce5.js → index--Y0Uaz-m.js} +2 -2
- package/src/console/ui/dist/assets/panel-vault-BkZdJPX8.js +1 -0
- package/src/console/ui/dist/assets/style-C3L349iZ.css +3 -0
- package/src/console/ui/dist/index.html +2 -2
- package/src/console/ui/shell/client.ts +16 -0
- package/src/console/ui/shell/panels/vault/VaultPanel.tsx +54 -1
- package/src/console/ui/vault/VaultA11yView.tsx +33 -1
- package/src/console/ui/vault/backend.test.ts +75 -0
- package/src/console/ui/vault/backend.ts +117 -0
- package/src/console/ui/vault/fixture.ts +21 -2
- package/src/console/ui/vault/index.ts +11 -1
- package/src/console/ui/vault/types.ts +26 -0
- package/src/docker/compose.ts +164 -61
- package/src/docker/derive.ts +106 -12
- package/src/docker/docker.test.ts +156 -110
- package/src/docker/helpers.ts +98 -0
- package/src/docker/images-config.test.ts +163 -0
- package/src/docker/index.ts +30 -5
- package/src/docker/recipes/index.ts +0 -3
- package/src/docker/recipes/llama-cpp.ts +4 -4
- package/src/docker/recipes/pgdog.ts +9 -2
- package/src/docker/resources.test.ts +71 -0
- package/src/docker/resources.ts +176 -0
- package/src/docker/stack-id.test.ts +11 -4
- package/src/docker/stack-id.ts +42 -32
- package/src/docker/stack.integration.test.ts +4 -15
- package/src/docker/types.ts +35 -3
- package/src/drivers/ai-ollama.integration.test.ts +2 -2
- package/src/drivers/conformance.test.ts +11 -12
- package/src/drivers/drizzle-dialect.test.ts +0 -4
- package/src/drivers/drizzle-dialect.ts +7 -13
- package/src/drivers/index.ts +24 -7
- package/src/drivers/journal-postgres.test.ts +3 -1
- package/src/drivers/journal-postgres.ts +4 -2
- package/src/drivers/meilisearch.ts +1 -1
- package/src/drivers/pglite.ts +28 -5
- package/src/drivers/types.ts +9 -11
- package/src/drivers/vault-aws-secrets-manager.test.ts +159 -0
- package/src/drivers/vault-aws-secrets-manager.ts +333 -0
- package/src/drivers/vault-builtin.test.ts +110 -0
- package/src/drivers/vault-builtin.ts +184 -0
- package/src/drivers/vault-driver-removal.test.ts +13 -0
- package/src/drivers/vault-managed.test.ts +95 -0
- package/src/drivers/vault-managed.ts +101 -25
- package/src/drivers/vault-types.ts +25 -5
- package/src/elements/ai/runtime.ts +1 -1
- package/src/elements/clock/chaos.test.ts +4 -1
- package/src/elements/clock/durable.ts +57 -4
- package/src/elements/clock.test.ts +13 -14
- package/src/elements/gate/constants.ts +18 -0
- package/src/elements/gate.test.ts +1 -1
- package/src/elements/gate.ts +2 -2
- package/src/elements/store/domain-ddl.test.ts +5 -12
- package/src/elements/store/emit-drizzle.ts +44 -19
- package/src/elements/store/index-boot.test.ts +15 -116
- package/src/elements/store/load-plugin-tables.ts +1 -1
- package/src/elements/store/resource-list-docs.fixture.ts +12 -6
- package/src/elements/store/resource-list-docs.test.ts +64 -44
- package/src/elements/store/resource.test.ts +17 -10
- package/src/elements/store/runtime.ts +9 -12
- package/src/elements/store/schema-decl.test.ts +16 -32
- package/src/elements/store/seed.test.ts +1 -2
- package/src/elements/store/seed.ts +7 -8
- package/src/elements/store/sql-condition.test.ts +2 -2
- package/src/elements/store/sql-session.test.ts +8 -10
- package/src/elements/store/sql-session.ts +10 -2
- package/src/elements/store.test.ts +13 -13
- package/src/elements/vault/audit.ts +233 -0
- package/src/elements/vault/boot-chain.test.ts +78 -0
- package/src/elements/vault/boot-chain.ts +43 -39
- package/src/elements/vault/builtin-adapter.test.ts +479 -0
- package/src/elements/vault/builtin-adapter.ts +1184 -0
- package/src/elements/vault/crypto.test.ts +237 -0
- package/src/elements/vault/crypto.ts +431 -0
- package/src/elements/vault/declare.ts +164 -3
- package/src/elements/vault/errors.ts +56 -0
- package/src/elements/vault/kms-unseal.test.ts +76 -0
- package/src/elements/vault/kms-unseal.ts +181 -0
- package/src/elements/vault/path.ts +90 -0
- package/src/elements/vault/resilience.test.ts +102 -0
- package/src/elements/vault/resilience.ts +107 -0
- package/src/elements/vault/runtime.ts +36 -4
- package/src/elements/vault/security-checklist.test.ts +130 -0
- package/src/elements/vault/storage.ts +448 -0
- package/src/elements/vault/types.ts +288 -0
- package/src/elements/vault/unseal.ts +150 -0
- package/src/elements/vault.test.ts +72 -4
- package/src/elements/vault.ts +91 -2
- package/src/full.ts +248 -0
- package/src/http.ts +41 -0
- package/src/i18n/interpolate-simple.ts +37 -0
- package/src/i18n/messages.ts +51 -4
- package/src/i18n-entry.ts +7 -0
- package/src/index.ts +35 -145
- package/src/journal-entry.ts +20 -0
- package/src/kernel/adopt-barrel-fresh.test.ts +25 -10
- package/src/kernel/app.ts +40 -42
- package/src/kernel/auto-registry.test.ts +2 -2
- package/src/kernel/boot-bind/ai.test.ts +5 -5
- package/src/kernel/boot-bind/ai.ts +2 -1
- package/src/kernel/boot-bind/channel.test.ts +6 -6
- package/src/kernel/boot-bind/channel.ts +5 -4
- package/src/kernel/boot-bind/clock.ts +5 -5
- package/src/kernel/boot-bind/gate.ts +6 -7
- package/src/kernel/boot-bind/honor-config.test.ts +42 -42
- package/src/kernel/boot-bind/journal.ts +5 -5
- package/src/kernel/boot-bind/signal.ts +3 -1
- package/src/kernel/boot-bind/store.test.ts +55 -37
- package/src/kernel/boot-bind/store.ts +24 -34
- package/src/kernel/boot-bind/vault.ts +19 -4
- package/src/kernel/boot.test.ts +12 -4
- package/src/kernel/boot.ts +31 -19
- package/src/kernel/budget-entry.ts +1 -1
- package/src/kernel/compensate.test.ts +288 -1
- package/src/kernel/compensate.ts +126 -0
- package/src/kernel/concurrency.test.ts +10 -9
- package/src/kernel/effects-stamping.test.ts +27 -2
- package/src/kernel/element-registries.ts +5 -3
- package/src/kernel/flow.ts +4 -2
- package/src/kernel/fx.test.ts +119 -3
- package/src/kernel/fx.ts +215 -40
- package/src/kernel/index.ts +14 -0
- package/src/kernel/journal.ts +130 -7
- package/src/kernel/pipeline.test.ts +20 -6
- package/src/kernel/redacted.test.ts +35 -0
- package/src/kernel/redacted.ts +24 -2
- package/src/kernel/router/create-default.ts +16 -0
- package/src/kernel/router/create-edge.ts +18 -0
- package/src/kernel/router/create.ts +23 -0
- package/src/kernel/router/index.ts +23 -0
- package/src/kernel/router/linear.ts +88 -0
- package/src/kernel/router/regexp.ts +188 -0
- package/src/kernel/router/smart.ts +120 -0
- package/src/kernel/router/trie.ts +108 -0
- package/src/kernel/router/types.ts +56 -0
- package/src/kernel/router.ts +18 -532
- package/src/kernel-entry.ts +43 -0
- package/src/manifest/fixtures/skyport.excerpt.json +1 -1
- package/src/manifest/fixtures/skyport.manifest.json +1 -1
- package/src/plugins/config-source.test.ts +7 -7
- package/src/release/build-lib.ts +58 -0
- package/src/release/exports.test.ts +4 -2
- package/src/release/exports.ts +30 -4
- package/src/release/measure.ts +101 -22
- package/src/runs/duckdb.ts +7 -2
- package/src/shared/optional-peer.ts +41 -0
- package/src/term.test.ts +3 -44
- package/src/test/create-test-app.ts +12 -0
- package/src/test/provisions.integration.test.ts +1 -1
- package/src/test/reset-element-registries.ts +2 -0
- package/src/upgrade/codemods.test.ts +7 -20
- package/src/upgrade/codemods.ts +93 -60
- package/site/content/docs/console/access.mdx +0 -29
- package/site/content/docs/console/ai.mdx +0 -35
- package/site/content/docs/console/architecture.mdx +0 -35
- package/site/content/docs/console/channels.mdx +0 -37
- package/site/content/docs/console/clock.mdx +0 -51
- package/site/content/docs/console/flows.mdx +0 -31
- package/site/content/docs/console/gates.mdx +0 -73
- package/site/content/docs/console/index.mdx +0 -54
- package/site/content/docs/console/manifest-diff.mdx +0 -34
- package/site/content/docs/console/meta.json +0 -24
- package/site/content/docs/console/overview.mdx +0 -40
- package/site/content/docs/console/plugins.mdx +0 -41
- package/site/content/docs/console/privacy.mdx +0 -32
- package/site/content/docs/console/runs.mdx +0 -50
- package/site/content/docs/console/signals.mdx +0 -40
- package/site/content/docs/console/store.mdx +0 -32
- package/site/content/docs/console/tenancy.mdx +0 -32
- package/site/content/docs/console/traces.mdx +0 -38
- package/site/content/docs/console/vault.mdx +0 -41
- package/site/content/docs/recipes/openbao.mdx +0 -141
- package/src/cli/ask-dev-mode.ts +0 -40
- package/src/cli/dev-mode.test.ts +0 -45
- package/src/cli/dev-mode.ts +0 -78
- package/src/cli/openbao-bootstrap.test.ts +0 -150
- package/src/cli/openbao-bootstrap.ts +0 -321
- package/src/cli/openbao-restart.integration.test.ts +0 -145
- package/src/console/ui/dist/assets/panel-vault-Za1GyJfM.js +0 -1
- package/src/console/ui/dist/assets/style-C8MxEWPd.css +0 -3
- package/src/docker/recipes/openbao.ts +0 -47
- package/src/drivers/libsql.ts +0 -179
- package/src/drivers/sqlite.ts +0 -44
- package/src/drivers/vault-openbao.test.ts +0 -97
- package/src/drivers/vault-openbao.ts +0 -143
package/src/cli/dev.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* `oke dev` — watch · hot reload · Console :6533 · MCP :6535 · client types on save.
|
|
3
|
-
*
|
|
3
|
+
* Always starts Docker Compose infra and runs the app on host Bun.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { watch } from "node:fs";
|
|
@@ -19,7 +19,6 @@ import {
|
|
|
19
19
|
stackAppSlug,
|
|
20
20
|
stackInstanceId,
|
|
21
21
|
writeDerivedFiles,
|
|
22
|
-
formatStackEnv,
|
|
23
22
|
type DeriveOptions,
|
|
24
23
|
} from "../docker/index.ts";
|
|
25
24
|
import type { Manifest } from "../manifest/types.ts";
|
|
@@ -45,19 +44,13 @@ import {
|
|
|
45
44
|
} from "../term.ts";
|
|
46
45
|
import { clientAdd } from "./client-add.ts";
|
|
47
46
|
import { resolveDriverId } from "../config/index.ts";
|
|
48
|
-
import {
|
|
49
|
-
import {
|
|
50
|
-
formatDevControlsHint,
|
|
51
|
-
startDevControls,
|
|
52
|
-
type DevComposeControlAction,
|
|
53
|
-
} from "./dev-controls.ts";
|
|
47
|
+
import type { DevComposeControlAction } from "./dev-controls.ts";
|
|
54
48
|
import {
|
|
55
49
|
createDebouncedRunner,
|
|
56
50
|
isDomainSchemaWatchPath,
|
|
57
51
|
resolveDevAutoPush,
|
|
58
52
|
} from "./db-auto-push.ts";
|
|
59
53
|
import { resolveDrizzleConfigPath, runPush } from "./db.ts";
|
|
60
|
-
import { readDevMode, shouldAskDevMode, writeDevMode, type DevMode } from "./dev-mode.ts";
|
|
61
54
|
import {
|
|
62
55
|
buildDevHeroSnapshot,
|
|
63
56
|
encodeHeroSnapshot,
|
|
@@ -68,6 +61,7 @@ import {
|
|
|
68
61
|
import { loadManifest, loadOkeConfig, resolveImages } from "./load-config.ts";
|
|
69
62
|
import { mcpContextFromConsole } from "./mcp-from-console.ts";
|
|
70
63
|
import { resolveDevPorts } from "./ports.ts";
|
|
64
|
+
import { clearDevSessionLock, writeDevSessionLock } from "./dev-session-lock.ts";
|
|
71
65
|
|
|
72
66
|
/** Max wait for the `bun --hot` app child to bind a port. */
|
|
73
67
|
const APP_READY_TIMEOUT_MS = 30_000;
|
|
@@ -153,12 +147,10 @@ export interface DevOptions {
|
|
|
153
147
|
readonly cwd?: string;
|
|
154
148
|
readonly entry?: string;
|
|
155
149
|
/**
|
|
156
|
-
*
|
|
157
|
-
*
|
|
150
|
+
* Optional compose role filter. `true` / unset → all roles from images;
|
|
151
|
+
* a string list → only those roles.
|
|
158
152
|
*/
|
|
159
153
|
readonly docker?: boolean | readonly string[];
|
|
160
|
-
/** Force local for this session only (never writes `.oke/mode`). */
|
|
161
|
-
readonly local?: boolean;
|
|
162
154
|
/**
|
|
163
155
|
* Opt out of auto `oke db push` on schema change for this session.
|
|
164
156
|
* Also set via `--no-db-push`.
|
|
@@ -178,11 +170,13 @@ export interface DevOptions {
|
|
|
178
170
|
readonly onDbAutoPush?: (filename: string) => void;
|
|
179
171
|
/**
|
|
180
172
|
* Injectable `.adopt()` barrel regeneration (tests). Default: real
|
|
181
|
-
* `generateAdoptBarrel` + write to `<cwd>/src/flows/generated.ts
|
|
182
|
-
* once per `oke dev` session, before
|
|
183
|
-
* a real file on disk, so `oke dev`'s
|
|
184
|
-
* `Bun.build()` resolve it
|
|
185
|
-
* plugin, which does not — see
|
|
173
|
+
* `generateAdoptBarrel` + atomic write to `<cwd>/src/flows/generated.ts`
|
|
174
|
+
* (`generated.ts.tmp` → rename). Runs once per `oke dev` session, before
|
|
175
|
+
* the entry is resolved/imported — a real file on disk, so `oke dev`'s
|
|
176
|
+
* runtime `import()` and `oke build`'s `Bun.build()` resolve it
|
|
177
|
+
* identically (unlike a virtual-module Bun plugin, which does not — see
|
|
178
|
+
* `compiler/generate-adopt.ts`). Atomic so a concurrent import during
|
|
179
|
+
* `bun --hot` never sees a torn mid-write file.
|
|
186
180
|
*
|
|
187
181
|
* @param cwd - Project root
|
|
188
182
|
*/
|
|
@@ -284,14 +278,16 @@ export interface DevOptions {
|
|
|
284
278
|
* app code while preserving the listen socket.
|
|
285
279
|
*/
|
|
286
280
|
readonly startApp?: (entry: string, env: Record<string, string>) => Promise<DevAppHandle>;
|
|
287
|
-
/**
|
|
288
|
-
* Injectable mode prompt (tests). Default: {@link askDevMode}.
|
|
289
|
-
*/
|
|
290
|
-
readonly ask?: AskDevModeFn;
|
|
291
281
|
/**
|
|
292
282
|
* Override stdin TTY detection (tests). Default: `process.stdin.isTTY`.
|
|
293
283
|
*/
|
|
294
284
|
readonly stdinIsTTY?: boolean;
|
|
285
|
+
/**
|
|
286
|
+
* Probe Docker daemon availability (injectable). Default: `docker info`.
|
|
287
|
+
* Skipped on {@link dryRun}; when {@link composeUp} is injected and this is
|
|
288
|
+
* omitted, the probe is a no-op (unit tests never shell out).
|
|
289
|
+
*/
|
|
290
|
+
readonly assertDocker?: () => Promise<void>;
|
|
295
291
|
}
|
|
296
292
|
|
|
297
293
|
/** Result of a dry-run / prepared / live-but-detached dev session. */
|
|
@@ -346,18 +342,18 @@ export async function runDev(options: DevOptions = {}): Promise<DevResult> {
|
|
|
346
342
|
const cwd = options.cwd ?? process.cwd();
|
|
347
343
|
|
|
348
344
|
// One-shot `.adopt()` barrel regen for the session — real file on disk
|
|
349
|
-
// (`src/flows/generated.ts`), written
|
|
350
|
-
// below so a freshly-added flows unit is
|
|
351
|
-
// Best-effort like `syncDevSchema` below:
|
|
352
|
-
// yet (or a synthetic test tree) never
|
|
345
|
+
// (`src/flows/generated.ts`), written atomically (tmp → rename) before the
|
|
346
|
+
// entry is resolved/imported below so a freshly-added flows unit is
|
|
347
|
+
// adoptable without a hand edit. Best-effort like `syncDevSchema` below:
|
|
348
|
+
// a project with no `src/flows` yet (or a synthetic test tree) never
|
|
349
|
+
// blocks the dev session.
|
|
353
350
|
const syncAdoptBarrel =
|
|
354
351
|
options.syncAdoptBarrel ??
|
|
355
352
|
(async (root: string) => {
|
|
356
|
-
const { generateAdoptBarrel } =
|
|
357
|
-
|
|
353
|
+
const { generateAdoptBarrel, writeAdoptBarrel } =
|
|
354
|
+
await import("../compiler/generate-adopt.ts");
|
|
358
355
|
const { source, units } = await generateAdoptBarrel({ rootDir: root });
|
|
359
|
-
await
|
|
360
|
-
await writeFile(resolve(root, "src/flows/generated.ts"), source);
|
|
356
|
+
await writeAdoptBarrel(root, source);
|
|
361
357
|
return units;
|
|
362
358
|
});
|
|
363
359
|
try {
|
|
@@ -409,42 +405,16 @@ export async function runDev(options: DevOptions = {}): Promise<DevResult> {
|
|
|
409
405
|
return { code: 1 };
|
|
410
406
|
}
|
|
411
407
|
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
const savedMode = await readDevMode(cwd);
|
|
421
|
-
const explicit = explicitLocal || explicitDocker;
|
|
422
|
-
let mode: DevMode;
|
|
423
|
-
if (explicitLocal) {
|
|
424
|
-
mode = "local";
|
|
425
|
-
} else if (explicitDocker) {
|
|
426
|
-
mode = "docker";
|
|
427
|
-
} else if (savedMode !== null) {
|
|
428
|
-
mode = savedMode;
|
|
429
|
-
} else if (
|
|
430
|
-
shouldAskDevMode({
|
|
431
|
-
saved: savedMode,
|
|
432
|
-
explicit,
|
|
433
|
-
stdinIsTTY: options.stdinIsTTY ?? process.stdin.isTTY,
|
|
434
|
-
})
|
|
435
|
-
) {
|
|
436
|
-
const ask = options.ask ?? askDevMode;
|
|
437
|
-
const chosen = await ask();
|
|
438
|
-
if (chosen === null) {
|
|
439
|
-
console.error("oke dev: cancelled");
|
|
408
|
+
// Fail fast when the Docker daemon is down (skip on dryRun / injected compose).
|
|
409
|
+
if (!options.dryRun) {
|
|
410
|
+
const probe = options.assertDocker ?? (options.composeUp ? async () => {} : assertDockerDaemon);
|
|
411
|
+
try {
|
|
412
|
+
await probe();
|
|
413
|
+
} catch (err) {
|
|
414
|
+
console.error(err instanceof Error ? err.message : String(err));
|
|
440
415
|
restoreWarn();
|
|
441
416
|
return { code: 1 };
|
|
442
417
|
}
|
|
443
|
-
mode = chosen;
|
|
444
|
-
await writeDevMode(cwd, mode);
|
|
445
|
-
} else {
|
|
446
|
-
// Non-TTY + unset: deterministic local — zero ask, zero docker, no save.
|
|
447
|
-
mode = "local";
|
|
448
418
|
}
|
|
449
419
|
|
|
450
420
|
// Paint chrome immediately so docker/vault work is never a blank 6s wait.
|
|
@@ -457,7 +427,7 @@ export async function runDev(options: DevOptions = {}): Promise<DevResult> {
|
|
|
457
427
|
} catch {
|
|
458
428
|
// shipped binary may not sit next to package.json
|
|
459
429
|
}
|
|
460
|
-
const earlyProfile = resolveDevProfile({ docker:
|
|
430
|
+
const earlyProfile = resolveDevProfile({ docker: true, nodeEnv: "development" });
|
|
461
431
|
write(
|
|
462
432
|
formatDevBanner({
|
|
463
433
|
profile: earlyProfile,
|
|
@@ -507,26 +477,7 @@ export async function runDev(options: DevOptions = {}): Promise<DevResult> {
|
|
|
507
477
|
loadedConfig = null;
|
|
508
478
|
}
|
|
509
479
|
|
|
510
|
-
|
|
511
|
-
// as a fourth local process (binary on PATH — a documented prerequisite,
|
|
512
|
-
// like Docker for --docker). Docker mode instead relies on the recipe.
|
|
513
|
-
let meili: import("./meilisearch-local.ts").LocalMeilisearchHandle | null = null;
|
|
514
|
-
if (mode === "local") {
|
|
515
|
-
const indexId = resolveDriverId(loadedConfig?.drivers?.store?.index, "local") ?? "memory";
|
|
516
|
-
if (indexId === "meilisearch") {
|
|
517
|
-
try {
|
|
518
|
-
const { startLocalMeilisearch } = await import("./meilisearch-local.ts");
|
|
519
|
-
meili = await startLocalMeilisearch({ cwd });
|
|
520
|
-
write(formatStatusLine(`meilisearch local server on ${meili.url}`));
|
|
521
|
-
} catch (err) {
|
|
522
|
-
console.error(err instanceof Error ? err.message : String(err));
|
|
523
|
-
restoreWarn();
|
|
524
|
-
return { code: 1 };
|
|
525
|
-
}
|
|
526
|
-
}
|
|
527
|
-
}
|
|
528
|
-
|
|
529
|
-
if (mode === "docker") {
|
|
480
|
+
{
|
|
530
481
|
let images = options.images;
|
|
531
482
|
if (!images) {
|
|
532
483
|
if (!loadedConfig) {
|
|
@@ -571,6 +522,7 @@ export async function runDev(options: DevOptions = {}): Promise<DevResult> {
|
|
|
571
522
|
images,
|
|
572
523
|
app: appSlug,
|
|
573
524
|
prod: false,
|
|
525
|
+
layout: "single",
|
|
574
526
|
includeApp: false,
|
|
575
527
|
composeDir,
|
|
576
528
|
instanceId,
|
|
@@ -578,11 +530,15 @@ export async function runDev(options: DevOptions = {}): Promise<DevResult> {
|
|
|
578
530
|
...(controls ? { controls } : {}),
|
|
579
531
|
host: "127.0.0.1",
|
|
580
532
|
});
|
|
581
|
-
//
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
(f
|
|
585
|
-
|
|
533
|
+
// User-owned overrides — include only if the file already exists.
|
|
534
|
+
composeFiles = [];
|
|
535
|
+
for (const f of derived.composeFiles) {
|
|
536
|
+
if (f === "compose.override.yml" || f === "docker-compose.override.yml") {
|
|
537
|
+
if (await Bun.file(resolve(dockerOut, f)).exists()) composeFiles.push(f);
|
|
538
|
+
continue;
|
|
539
|
+
}
|
|
540
|
+
composeFiles.push(f);
|
|
541
|
+
}
|
|
586
542
|
stackEnv = { ...derived.stackEnv };
|
|
587
543
|
|
|
588
544
|
const roleLabel = (role: string): string => {
|
|
@@ -646,7 +602,7 @@ export async function runDev(options: DevOptions = {}): Promise<DevResult> {
|
|
|
646
602
|
if (code !== 0) {
|
|
647
603
|
const detail = [stdout.trim(), stderr.trim()].filter(Boolean).join("\n");
|
|
648
604
|
throw new Error(
|
|
649
|
-
`oke dev
|
|
605
|
+
`oke dev: docker compose exited ${code}` + (detail ? `\n${detail}` : ""),
|
|
650
606
|
);
|
|
651
607
|
}
|
|
652
608
|
});
|
|
@@ -661,27 +617,6 @@ export async function runDev(options: DevOptions = {}): Promise<DevResult> {
|
|
|
661
617
|
env: { ...stackEnv! },
|
|
662
618
|
};
|
|
663
619
|
|
|
664
|
-
// Real OpenBao vault: init once / unseal every start, then expose the
|
|
665
|
-
// least-privilege app token to the app + Console (never root).
|
|
666
|
-
const vaultSpec = derived.specs.find((s) => s.role === "vault");
|
|
667
|
-
if (vaultSpec) {
|
|
668
|
-
bootProgress.set("vault", formatStatusLine("vault unseal…", undefined, "pending"));
|
|
669
|
-
const { ensureOpenBao, openbaoStackEnv } = await import("./openbao-bootstrap.ts");
|
|
670
|
-
const vaultNames = await tryLoadVaultSecretNames(cwd);
|
|
671
|
-
const boot = await ensureOpenBao({
|
|
672
|
-
cwd,
|
|
673
|
-
url: `http://127.0.0.1:${vaultSpec.hostPort}`,
|
|
674
|
-
names: vaultNames,
|
|
675
|
-
});
|
|
676
|
-
Object.assign(stackEnv!, openbaoStackEnv(boot));
|
|
677
|
-
Object.assign(dockerStarted.env, openbaoStackEnv(boot));
|
|
678
|
-
// Rewrite .env.docker with the full stack env (including token) so a
|
|
679
|
-
// later ensureDockerStack / writeDerivedFiles does not drop it.
|
|
680
|
-
const envPath = resolve(dockerOut, ".env.docker");
|
|
681
|
-
await Bun.write(envPath, formatStackEnv(stackEnv!));
|
|
682
|
-
bootProgress.set("vault", formatStatusLine("vault ready", undefined, "ready"));
|
|
683
|
-
}
|
|
684
|
-
|
|
685
620
|
// Stream compose health until infra is up (AI may stay pending — model load).
|
|
686
621
|
const aiServiceName = derived.specs.find((s) => s.role === "ai")?.serviceName;
|
|
687
622
|
const labelForService = (serviceName: string): string => {
|
|
@@ -745,7 +680,7 @@ export async function runDev(options: DevOptions = {}): Promise<DevResult> {
|
|
|
745
680
|
const model =
|
|
746
681
|
stackEnv!.OKE_AI_MODEL?.trim() ||
|
|
747
682
|
process.env.OKE_AI_MODEL?.trim() ||
|
|
748
|
-
(recipeId === "ollama" ? "qwen3.5:9b" : "
|
|
683
|
+
(recipeId === "ollama" ? "qwen3.5:9b" : "granite3.3:2b");
|
|
749
684
|
const url = `http://127.0.0.1:${aiSpec.hostPort}`;
|
|
750
685
|
const paintAi = (status: DevStatus, detail?: string) => {
|
|
751
686
|
heroAiStatus = status;
|
|
@@ -805,7 +740,7 @@ export async function runDev(options: DevOptions = {}): Promise<DevResult> {
|
|
|
805
740
|
} catch (err) {
|
|
806
741
|
const msg = err instanceof Error ? err.message : String(err);
|
|
807
742
|
console.error(msg);
|
|
808
|
-
console.error("oke dev:
|
|
743
|
+
console.error("oke dev: Docker Compose failed — fix compose and retry");
|
|
809
744
|
restoreWarn();
|
|
810
745
|
return { code: 1 };
|
|
811
746
|
}
|
|
@@ -831,9 +766,9 @@ export async function runDev(options: DevOptions = {}): Promise<DevResult> {
|
|
|
831
766
|
}
|
|
832
767
|
const heroSnapshot = buildDevHeroSnapshot({
|
|
833
768
|
config: loadedConfig,
|
|
834
|
-
docker:
|
|
835
|
-
sqlDriver:
|
|
836
|
-
kvDriver:
|
|
769
|
+
docker: true,
|
|
770
|
+
sqlDriver: stackSqlDriver,
|
|
771
|
+
kvDriver: stackKvDriver,
|
|
837
772
|
aiModel: heroAiModel,
|
|
838
773
|
aiStatus: heroAiStatus,
|
|
839
774
|
version: okeVersion,
|
|
@@ -948,7 +883,7 @@ export async function runDev(options: DevOptions = {}): Promise<DevResult> {
|
|
|
948
883
|
bootProgress.clear();
|
|
949
884
|
const bootBoard = createAnchoredBoard(write);
|
|
950
885
|
bootBoard.paint(paintBootBoard(heroAiStatus));
|
|
951
|
-
// Track
|
|
886
|
+
// Track lines printed below the board so live ● repaints stay anchored.
|
|
952
887
|
write = bootBoard.wrapWrite(write);
|
|
953
888
|
|
|
954
889
|
if (options.dryRun) {
|
|
@@ -1043,27 +978,26 @@ export async function runDev(options: DevOptions = {}): Promise<DevResult> {
|
|
|
1043
978
|
setProcessEnv("OKE_KV_DRIVER", stackKvDriver);
|
|
1044
979
|
}
|
|
1045
980
|
|
|
1046
|
-
// One-shot schema sync for the
|
|
1047
|
-
//
|
|
1048
|
-
// drizzle-kit. Data planes stay isolated — session flags never rewrite
|
|
1049
|
-
// `.oke/mode`. Watch auto-push below remains local-only.
|
|
981
|
+
// One-shot schema sync for the compose (`dev`) profile: emits
|
|
982
|
+
// schema.drizzle.ts for the active dialect, then pushes via drizzle-kit.
|
|
1050
983
|
if (!options.noDbPush) {
|
|
1051
984
|
const { syncDevSchema } = await import("./dev-schema-sync.ts");
|
|
985
|
+
const configEnv = "dev" as const;
|
|
1052
986
|
try {
|
|
1053
|
-
const result = await syncDevSchema(cwd,
|
|
987
|
+
const result = await syncDevSchema(cwd, configEnv, {
|
|
1054
988
|
write: chromeWrite,
|
|
1055
|
-
quietComposeReady:
|
|
989
|
+
quietComposeReady: true,
|
|
1056
990
|
});
|
|
1057
991
|
write(
|
|
1058
992
|
formatStatusLine(
|
|
1059
|
-
`oke db push (
|
|
993
|
+
`oke db push (dev · ${result.dialect}) ${result.code === 0 ? "ok" : "failed"}`,
|
|
1060
994
|
),
|
|
1061
995
|
);
|
|
1062
996
|
if (result.code === 0) {
|
|
1063
997
|
const { maybeAskSeed } = await import("./ask-seed.ts");
|
|
1064
998
|
await maybeAskSeed({
|
|
1065
999
|
cwd,
|
|
1066
|
-
env:
|
|
1000
|
+
env: configEnv,
|
|
1067
1001
|
write,
|
|
1068
1002
|
stdinIsTTY: options.stdinIsTTY ?? process.stdin.isTTY,
|
|
1069
1003
|
});
|
|
@@ -1071,7 +1005,7 @@ export async function runDev(options: DevOptions = {}): Promise<DevResult> {
|
|
|
1071
1005
|
} catch (err) {
|
|
1072
1006
|
write(
|
|
1073
1007
|
formatStatusLine(
|
|
1074
|
-
`oke db push (
|
|
1008
|
+
`oke db push (dev) skipped — ${err instanceof Error ? err.message : String(err)}`,
|
|
1075
1009
|
),
|
|
1076
1010
|
);
|
|
1077
1011
|
}
|
|
@@ -1102,7 +1036,6 @@ export async function runDev(options: DevOptions = {}): Promise<DevResult> {
|
|
|
1102
1036
|
OKE_KV_DRIVER: stackKvDriver,
|
|
1103
1037
|
}
|
|
1104
1038
|
: {}),
|
|
1105
|
-
...(meili?.overlay ?? {}),
|
|
1106
1039
|
/** Backend child — parent Console owns process-local boot notices. */
|
|
1107
1040
|
OKE_SUPPRESS_BOOT_WARN: "1",
|
|
1108
1041
|
};
|
|
@@ -1250,7 +1183,10 @@ export async function runDev(options: DevOptions = {}): Promise<DevResult> {
|
|
|
1250
1183
|
options.dbPush ??
|
|
1251
1184
|
(async (projectCwd: string) => {
|
|
1252
1185
|
const configPath = await resolveDrizzleConfigPath(projectCwd);
|
|
1253
|
-
return runPush(configPath, (t) => write(t), {
|
|
1186
|
+
return runPush(configPath, (t) => write(t), {
|
|
1187
|
+
cwd: projectCwd,
|
|
1188
|
+
env: "dev",
|
|
1189
|
+
});
|
|
1254
1190
|
});
|
|
1255
1191
|
|
|
1256
1192
|
let lastSchemaFilename = "";
|
|
@@ -1272,9 +1208,6 @@ export async function runDev(options: DevOptions = {}): Promise<DevResult> {
|
|
|
1272
1208
|
}
|
|
1273
1209
|
|
|
1274
1210
|
write(formatDevLogSeparator());
|
|
1275
|
-
if (dockerStarted && (options.stdinIsTTY ?? process.stdin.isTTY)) {
|
|
1276
|
-
write(formatDevControlsHint());
|
|
1277
|
-
}
|
|
1278
1211
|
|
|
1279
1212
|
const watchFs: DevWatchFn =
|
|
1280
1213
|
options.watchFs ?? ((path, watchOptions, listener) => watch(path, watchOptions, listener));
|
|
@@ -1306,11 +1239,11 @@ export async function runDev(options: DevOptions = {}): Promise<DevResult> {
|
|
|
1306
1239
|
bootBoard.stop();
|
|
1307
1240
|
autoPushRunner.cancel();
|
|
1308
1241
|
watcher.close();
|
|
1309
|
-
meili?.stop();
|
|
1310
1242
|
app.stop();
|
|
1311
1243
|
consoleServer.stop();
|
|
1312
1244
|
mcpServer?.stop();
|
|
1313
1245
|
docsMcpServer?.stop();
|
|
1246
|
+
void clearDevSessionLock(cwd);
|
|
1314
1247
|
if (dockerStarted) {
|
|
1315
1248
|
const started = dockerStarted;
|
|
1316
1249
|
dockerStarted = null;
|
|
@@ -1371,9 +1304,22 @@ export async function runDev(options: DevOptions = {}): Promise<DevResult> {
|
|
|
1371
1304
|
consoleState,
|
|
1372
1305
|
};
|
|
1373
1306
|
|
|
1307
|
+
// Record ownership so a later `oke` TUI can attach without spawning a second stack.
|
|
1308
|
+
await writeDevSessionLock(cwd, {
|
|
1309
|
+
pid: process.pid,
|
|
1310
|
+
ports: {
|
|
1311
|
+
app: boundAppPort,
|
|
1312
|
+
console: boundConsolePort,
|
|
1313
|
+
mcp: boundMcpPort,
|
|
1314
|
+
docsMcp: boundDocsMcpPort,
|
|
1315
|
+
},
|
|
1316
|
+
startedAt: new Date().toISOString(),
|
|
1317
|
+
cwd,
|
|
1318
|
+
});
|
|
1319
|
+
|
|
1374
1320
|
if (options.onReady) await options.onReady(session);
|
|
1375
1321
|
|
|
1376
|
-
// Keyboard controls (docker + TTY):
|
|
1322
|
+
// Keyboard controls (docker + TTY): Ink replaces raw-mode stdin.
|
|
1377
1323
|
if (keepAlive && dockerStarted && (options.stdinIsTTY ?? process.stdin.isTTY)) {
|
|
1378
1324
|
const started = dockerStarted;
|
|
1379
1325
|
const syncComposeBoard = async (): Promise<void> => {
|
|
@@ -1389,7 +1335,6 @@ export async function runDev(options: DevOptions = {}): Promise<DevResult> {
|
|
|
1389
1335
|
};
|
|
1390
1336
|
const refreshChrome = async (): Promise<void> => {
|
|
1391
1337
|
await syncComposeBoard();
|
|
1392
|
-
// Clear log noise; reprint head + latest ● board + surfaces + empty Logs.
|
|
1393
1338
|
write(clearTerminalScreen());
|
|
1394
1339
|
bootBoard.reset();
|
|
1395
1340
|
write(
|
|
@@ -1410,48 +1355,49 @@ export async function runDev(options: DevOptions = {}): Promise<DevResult> {
|
|
|
1410
1355
|
write(formatServiceLine("Docs MCP", `http://127.0.0.1:${boundDocsMcpPort}`));
|
|
1411
1356
|
}
|
|
1412
1357
|
write(formatDevLogSeparator());
|
|
1413
|
-
write(formatDevControlsHint());
|
|
1414
1358
|
};
|
|
1415
|
-
const
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1359
|
+
const composeAction = async (action: DevComposeControlAction): Promise<void> => {
|
|
1360
|
+
const files = started.files;
|
|
1361
|
+
const finalArgs =
|
|
1362
|
+
action === "up"
|
|
1363
|
+
? ["compose", ...files.flatMap((f) => ["-f", f]), "up", "-d"]
|
|
1364
|
+
: ["compose", ...files.flatMap((f) => ["-f", f]), action];
|
|
1365
|
+
const proc = Bun.spawn(["docker", ...finalArgs], {
|
|
1366
|
+
cwd: started.cwd,
|
|
1367
|
+
stdout: "pipe",
|
|
1368
|
+
stderr: "pipe",
|
|
1369
|
+
env: { ...process.env, ...started.env },
|
|
1370
|
+
});
|
|
1371
|
+
const [stdout, stderr, code] = await Promise.all([
|
|
1372
|
+
new Response(proc.stdout).text(),
|
|
1373
|
+
new Response(proc.stderr).text(),
|
|
1374
|
+
proc.exited,
|
|
1375
|
+
]);
|
|
1376
|
+
if (code !== 0) {
|
|
1377
|
+
const detail = [stdout.trim(), stderr.trim()].filter(Boolean).join("\n");
|
|
1378
|
+
throw new Error(`docker compose ${action} exited ${code}` + (detail ? `\n${detail}` : ""));
|
|
1379
|
+
}
|
|
1380
|
+
await syncComposeBoard();
|
|
1381
|
+
};
|
|
1382
|
+
|
|
1383
|
+
try {
|
|
1384
|
+
const { launchDevLiveControls } = await import("./tui/DevLive.tsx");
|
|
1385
|
+
await launchDevLiveControls({
|
|
1386
|
+
onRefresh: () => refreshChrome(),
|
|
1387
|
+
onComposeUp: () => composeAction("up"),
|
|
1388
|
+
onComposeStop: () => composeAction("stop"),
|
|
1389
|
+
onQuit: () => {
|
|
1390
|
+
stop();
|
|
1391
|
+
process.exit(0);
|
|
1392
|
+
},
|
|
1393
|
+
});
|
|
1394
|
+
// Esc / unmount without q — still tear down.
|
|
1395
|
+
stop();
|
|
1396
|
+
} catch {
|
|
1397
|
+
// Ink optional — fall back to keep-alive without keyboard chrome.
|
|
1398
|
+
await new Promise(() => {});
|
|
1399
|
+
}
|
|
1400
|
+
return { code: 0, plan: session.plan, session };
|
|
1455
1401
|
}
|
|
1456
1402
|
|
|
1457
1403
|
if (!keepAlive) {
|
|
@@ -1463,21 +1409,6 @@ export async function runDev(options: DevOptions = {}): Promise<DevResult> {
|
|
|
1463
1409
|
return { code: 0, plan: session.plan, session };
|
|
1464
1410
|
}
|
|
1465
1411
|
|
|
1466
|
-
/**
|
|
1467
|
-
* Declared vault secret names from the project Manifest (policy scope).
|
|
1468
|
-
*
|
|
1469
|
-
* @param cwd - Project root
|
|
1470
|
-
*/
|
|
1471
|
-
async function tryLoadVaultSecretNames(cwd: string): Promise<readonly string[]> {
|
|
1472
|
-
try {
|
|
1473
|
-
const { extractManifest } = await import("../compiler/extract.ts");
|
|
1474
|
-
const manifest = await extractManifest({ rootDir: cwd });
|
|
1475
|
-
return Object.keys(manifest.vault ?? {});
|
|
1476
|
-
} catch {
|
|
1477
|
-
return [];
|
|
1478
|
-
}
|
|
1479
|
-
}
|
|
1480
|
-
|
|
1481
1412
|
/**
|
|
1482
1413
|
* True when a Manifest has no declared flows (scaffold / empty extract).
|
|
1483
1414
|
*
|
|
@@ -1609,20 +1540,34 @@ async function waitForAppReady(
|
|
|
1609
1540
|
}
|
|
1610
1541
|
|
|
1611
1542
|
/**
|
|
1612
|
-
*
|
|
1543
|
+
* Probe `docker info` — throws a clear error when the daemon is unavailable.
|
|
1544
|
+
*/
|
|
1545
|
+
async function assertDockerDaemon(): Promise<void> {
|
|
1546
|
+
const proc = Bun.spawn(["docker", "info"], {
|
|
1547
|
+
stdout: "pipe",
|
|
1548
|
+
stderr: "pipe",
|
|
1549
|
+
});
|
|
1550
|
+
const [stderr, code] = await Promise.all([new Response(proc.stderr).text(), proc.exited]);
|
|
1551
|
+
if (code === 0) return;
|
|
1552
|
+
const detail = stderr.trim();
|
|
1553
|
+
throw new Error(
|
|
1554
|
+
"oke dev: Docker daemon unavailable — start Docker Desktop (or the Docker daemon) and retry" +
|
|
1555
|
+
(detail ? `\n${detail}` : ""),
|
|
1556
|
+
);
|
|
1557
|
+
}
|
|
1558
|
+
|
|
1559
|
+
/**
|
|
1560
|
+
* CLI entry for `oke dev [-d [roles]]`.
|
|
1613
1561
|
*
|
|
1614
1562
|
* @param args - Args after `dev`
|
|
1615
1563
|
*/
|
|
1616
1564
|
export async function devCli(args: readonly string[]): Promise<number> {
|
|
1617
1565
|
let docker: boolean | string[] | undefined;
|
|
1618
|
-
let local = false;
|
|
1619
1566
|
let noDbPush = false;
|
|
1620
1567
|
let entry: string | undefined;
|
|
1621
1568
|
for (let i = 0; i < args.length; i++) {
|
|
1622
1569
|
const a = args[i]!;
|
|
1623
|
-
if (a === "--
|
|
1624
|
-
local = true;
|
|
1625
|
-
} else if (a === "--docker" || a === "-d") {
|
|
1570
|
+
if (a === "--docker" || a === "-d") {
|
|
1626
1571
|
const next = args[i + 1];
|
|
1627
1572
|
if (next && !next.startsWith("-") && /^[\w.,]+$/.test(next)) {
|
|
1628
1573
|
docker = next
|
|
@@ -1637,23 +1582,26 @@ export async function devCli(args: readonly string[]): Promise<number> {
|
|
|
1637
1582
|
noDbPush = true;
|
|
1638
1583
|
} else if (a === "--entry" || a === "-e") entry = args[++i];
|
|
1639
1584
|
else if (a === "--help" || a === "-h") {
|
|
1640
|
-
console.log(`oke dev [
|
|
1585
|
+
console.log(`oke dev [-d [roles]] [--no-db-push] [--entry|-e src/app.ts]
|
|
1641
1586
|
|
|
1642
1587
|
Watch · hot reload · Console :6533 · app :6530 · MCP :6535
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1588
|
+
Always starts Docker Compose under docker/ and runs the app on host Bun
|
|
1589
|
+
with compose store drivers (Postgres/Redis). Regenerates client types on
|
|
1590
|
+
every save. Auto-runs \`oke db push\` when schema.ts changes (opt out:
|
|
1591
|
+
--no-db-push).
|
|
1592
|
+
|
|
1593
|
+
Optional \`-d\` / \`--docker\` filters which compose roles to start
|
|
1594
|
+
(e.g. \`-d store.sql,store.kv\`). Requires a running Docker daemon.
|
|
1595
|
+
Use \`oke test\` for PGLite / in-memory test posture (no Compose).
|
|
1651
1596
|
`);
|
|
1652
1597
|
return 0;
|
|
1598
|
+
} else if (a === "--local" || a === "-l") {
|
|
1599
|
+
console.error("oke dev: --local was removed — `oke dev` always uses Docker Compose");
|
|
1600
|
+
console.error("Use `oke test` for PGLite test posture.");
|
|
1601
|
+
return 1;
|
|
1653
1602
|
}
|
|
1654
1603
|
}
|
|
1655
1604
|
const { code } = await runDev({
|
|
1656
|
-
...(local ? { local: true } : {}),
|
|
1657
1605
|
...(docker === undefined ? {} : { docker }),
|
|
1658
1606
|
...(noDbPush ? { noDbPush: true } : {}),
|
|
1659
1607
|
entry,
|
|
@@ -11,9 +11,7 @@ import { join } from "node:path";
|
|
|
11
11
|
|
|
12
12
|
const ROOT = join(import.meta.dir, "../..");
|
|
13
13
|
|
|
14
|
-
/** Forbidden
|
|
15
|
-
const FORBIDDEN_STACK_FLAG = ["--", "stack"].join("");
|
|
16
|
-
/** Forbidden compose env filename. */
|
|
14
|
+
/** Forbidden compose env filename (legacy soft-compat). */
|
|
17
15
|
const FORBIDDEN_ENV_STACK = [".env.", "stack"].join("");
|
|
18
16
|
/** Forbidden env var — name avoids the contiguous token so this file is clean. */
|
|
19
17
|
const FORBIDDEN_LEGACY_ENV = ["OKE_", "STACK"].join("");
|
|
@@ -47,9 +45,8 @@ function assertZeroGitGrep(pattern: string, ignorePrefixes: readonly string[] =
|
|
|
47
45
|
}
|
|
48
46
|
|
|
49
47
|
describe("legacy stack-mode removal gate", () => {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
});
|
|
48
|
+
// `--stack` is first-class again (Swarm `docker-stack.yml` layout). Legacy
|
|
49
|
+
// soft-compat was the env filename + vault helper surface — those stay forbidden.
|
|
53
50
|
|
|
54
51
|
test("tracked tree has zero legacy compose env filename outside changelog", () => {
|
|
55
52
|
assertZeroGitGrep(FORBIDDEN_ENV_STACK, ["changelog.md:"]);
|