okengine 0.10.3 → 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/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 -7
- package/site/content/docs/elements/channel.mdx +9 -7
- package/site/content/docs/elements/clock.mdx +8 -8
- package/site/content/docs/elements/flow.mdx +46 -47
- package/site/content/docs/elements/gate.mdx +6 -5
- package/site/content/docs/elements/signal.mdx +2 -2
- package/site/content/docs/elements/store.mdx +71 -78
- package/site/content/docs/elements/vault.mdx +89 -70
- package/site/content/docs/get-started/basic-usage.mdx +8 -8
- 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 +2 -2
- 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 +11 -4
- 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 +27 -15
- 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 +1 -1
- 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 +166 -121
- package/src/cli/dev.ts +138 -192
- 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 +55 -15
- 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 +16 -12
- package/src/cli/load-config.source.test.ts +50 -0
- package/src/cli/load-config.ts +34 -28
- 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 +28 -10
- 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/fixtures/skyport/oke.config.ts +3 -3
- package/src/compiler/fixtures/skyport/src/flows/payments/index.ts +1 -1
- package/src/compiler/fixtures/skyport.expected.json +1 -1
- package/src/compiler-entry.ts +7 -0
- package/src/config/define-config.test.ts +111 -47
- package/src/config/driver-defaults.test.ts +16 -23
- package/src/config/driver-defaults.ts +33 -63
- package/src/config/index.ts +169 -144
- 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 +3 -8
- 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 +3 -10
- package/src/kernel/boot-bind/clock.ts +2 -2
- package/src/kernel/boot-bind/gate.ts +5 -9
- package/src/kernel/boot-bind/honor-config.test.ts +42 -42
- package/src/kernel/boot-bind/journal.ts +2 -2
- package/src/kernel/boot-bind/store.test.ts +43 -44
- package/src/kernel/boot-bind/store.ts +16 -41
- package/src/kernel/boot-bind/vault.ts +16 -1
- 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/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`.
|
|
@@ -286,14 +278,16 @@ export interface DevOptions {
|
|
|
286
278
|
* app code while preserving the listen socket.
|
|
287
279
|
*/
|
|
288
280
|
readonly startApp?: (entry: string, env: Record<string, string>) => Promise<DevAppHandle>;
|
|
289
|
-
/**
|
|
290
|
-
* Injectable mode prompt (tests). Default: {@link askDevMode}.
|
|
291
|
-
*/
|
|
292
|
-
readonly ask?: AskDevModeFn;
|
|
293
281
|
/**
|
|
294
282
|
* Override stdin TTY detection (tests). Default: `process.stdin.isTTY`.
|
|
295
283
|
*/
|
|
296
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>;
|
|
297
291
|
}
|
|
298
292
|
|
|
299
293
|
/** Result of a dry-run / prepared / live-but-detached dev session. */
|
|
@@ -411,42 +405,16 @@ export async function runDev(options: DevOptions = {}): Promise<DevResult> {
|
|
|
411
405
|
return { code: 1 };
|
|
412
406
|
}
|
|
413
407
|
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
const savedMode = await readDevMode(cwd);
|
|
423
|
-
const explicit = explicitLocal || explicitDocker;
|
|
424
|
-
let mode: DevMode;
|
|
425
|
-
if (explicitLocal) {
|
|
426
|
-
mode = "local";
|
|
427
|
-
} else if (explicitDocker) {
|
|
428
|
-
mode = "docker";
|
|
429
|
-
} else if (savedMode !== null) {
|
|
430
|
-
mode = savedMode;
|
|
431
|
-
} else if (
|
|
432
|
-
shouldAskDevMode({
|
|
433
|
-
saved: savedMode,
|
|
434
|
-
explicit,
|
|
435
|
-
stdinIsTTY: options.stdinIsTTY ?? process.stdin.isTTY,
|
|
436
|
-
})
|
|
437
|
-
) {
|
|
438
|
-
const ask = options.ask ?? askDevMode;
|
|
439
|
-
const chosen = await ask();
|
|
440
|
-
if (chosen === null) {
|
|
441
|
-
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));
|
|
442
415
|
restoreWarn();
|
|
443
416
|
return { code: 1 };
|
|
444
417
|
}
|
|
445
|
-
mode = chosen;
|
|
446
|
-
await writeDevMode(cwd, mode);
|
|
447
|
-
} else {
|
|
448
|
-
// Non-TTY + unset: deterministic local — zero ask, zero docker, no save.
|
|
449
|
-
mode = "local";
|
|
450
418
|
}
|
|
451
419
|
|
|
452
420
|
// Paint chrome immediately so docker/vault work is never a blank 6s wait.
|
|
@@ -459,7 +427,7 @@ export async function runDev(options: DevOptions = {}): Promise<DevResult> {
|
|
|
459
427
|
} catch {
|
|
460
428
|
// shipped binary may not sit next to package.json
|
|
461
429
|
}
|
|
462
|
-
const earlyProfile = resolveDevProfile({ docker:
|
|
430
|
+
const earlyProfile = resolveDevProfile({ docker: true, nodeEnv: "development" });
|
|
463
431
|
write(
|
|
464
432
|
formatDevBanner({
|
|
465
433
|
profile: earlyProfile,
|
|
@@ -509,26 +477,7 @@ export async function runDev(options: DevOptions = {}): Promise<DevResult> {
|
|
|
509
477
|
loadedConfig = null;
|
|
510
478
|
}
|
|
511
479
|
|
|
512
|
-
|
|
513
|
-
// as a fourth local process (binary on PATH — a documented prerequisite,
|
|
514
|
-
// like Docker for --docker). Docker mode instead relies on the recipe.
|
|
515
|
-
let meili: import("./meilisearch-local.ts").LocalMeilisearchHandle | null = null;
|
|
516
|
-
if (mode === "local") {
|
|
517
|
-
const indexId = resolveDriverId(loadedConfig?.drivers?.store?.index, "local") ?? "memory";
|
|
518
|
-
if (indexId === "meilisearch") {
|
|
519
|
-
try {
|
|
520
|
-
const { startLocalMeilisearch } = await import("./meilisearch-local.ts");
|
|
521
|
-
meili = await startLocalMeilisearch({ cwd });
|
|
522
|
-
write(formatStatusLine(`meilisearch local server on ${meili.url}`));
|
|
523
|
-
} catch (err) {
|
|
524
|
-
console.error(err instanceof Error ? err.message : String(err));
|
|
525
|
-
restoreWarn();
|
|
526
|
-
return { code: 1 };
|
|
527
|
-
}
|
|
528
|
-
}
|
|
529
|
-
}
|
|
530
|
-
|
|
531
|
-
if (mode === "docker") {
|
|
480
|
+
{
|
|
532
481
|
let images = options.images;
|
|
533
482
|
if (!images) {
|
|
534
483
|
if (!loadedConfig) {
|
|
@@ -573,6 +522,7 @@ export async function runDev(options: DevOptions = {}): Promise<DevResult> {
|
|
|
573
522
|
images,
|
|
574
523
|
app: appSlug,
|
|
575
524
|
prod: false,
|
|
525
|
+
layout: "single",
|
|
576
526
|
includeApp: false,
|
|
577
527
|
composeDir,
|
|
578
528
|
instanceId,
|
|
@@ -580,11 +530,15 @@ export async function runDev(options: DevOptions = {}): Promise<DevResult> {
|
|
|
580
530
|
...(controls ? { controls } : {}),
|
|
581
531
|
host: "127.0.0.1",
|
|
582
532
|
});
|
|
583
|
-
//
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
(f
|
|
587
|
-
|
|
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
|
+
}
|
|
588
542
|
stackEnv = { ...derived.stackEnv };
|
|
589
543
|
|
|
590
544
|
const roleLabel = (role: string): string => {
|
|
@@ -648,7 +602,7 @@ export async function runDev(options: DevOptions = {}): Promise<DevResult> {
|
|
|
648
602
|
if (code !== 0) {
|
|
649
603
|
const detail = [stdout.trim(), stderr.trim()].filter(Boolean).join("\n");
|
|
650
604
|
throw new Error(
|
|
651
|
-
`oke dev
|
|
605
|
+
`oke dev: docker compose exited ${code}` + (detail ? `\n${detail}` : ""),
|
|
652
606
|
);
|
|
653
607
|
}
|
|
654
608
|
});
|
|
@@ -663,27 +617,6 @@ export async function runDev(options: DevOptions = {}): Promise<DevResult> {
|
|
|
663
617
|
env: { ...stackEnv! },
|
|
664
618
|
};
|
|
665
619
|
|
|
666
|
-
// Real OpenBao vault: init once / unseal every start, then expose the
|
|
667
|
-
// least-privilege app token to the app + Console (never root).
|
|
668
|
-
const vaultSpec = derived.specs.find((s) => s.role === "vault");
|
|
669
|
-
if (vaultSpec) {
|
|
670
|
-
bootProgress.set("vault", formatStatusLine("vault unseal…", undefined, "pending"));
|
|
671
|
-
const { ensureOpenBao, openbaoStackEnv } = await import("./openbao-bootstrap.ts");
|
|
672
|
-
const vaultNames = await tryLoadVaultSecretNames(cwd);
|
|
673
|
-
const boot = await ensureOpenBao({
|
|
674
|
-
cwd,
|
|
675
|
-
url: `http://127.0.0.1:${vaultSpec.hostPort}`,
|
|
676
|
-
names: vaultNames,
|
|
677
|
-
});
|
|
678
|
-
Object.assign(stackEnv!, openbaoStackEnv(boot));
|
|
679
|
-
Object.assign(dockerStarted.env, openbaoStackEnv(boot));
|
|
680
|
-
// Rewrite .env.docker with the full stack env (including token) so a
|
|
681
|
-
// later ensureDockerStack / writeDerivedFiles does not drop it.
|
|
682
|
-
const envPath = resolve(dockerOut, ".env.docker");
|
|
683
|
-
await Bun.write(envPath, formatStackEnv(stackEnv!));
|
|
684
|
-
bootProgress.set("vault", formatStatusLine("vault ready", undefined, "ready"));
|
|
685
|
-
}
|
|
686
|
-
|
|
687
620
|
// Stream compose health until infra is up (AI may stay pending — model load).
|
|
688
621
|
const aiServiceName = derived.specs.find((s) => s.role === "ai")?.serviceName;
|
|
689
622
|
const labelForService = (serviceName: string): string => {
|
|
@@ -747,7 +680,7 @@ export async function runDev(options: DevOptions = {}): Promise<DevResult> {
|
|
|
747
680
|
const model =
|
|
748
681
|
stackEnv!.OKE_AI_MODEL?.trim() ||
|
|
749
682
|
process.env.OKE_AI_MODEL?.trim() ||
|
|
750
|
-
(recipeId === "ollama" ? "qwen3.5:9b" : "
|
|
683
|
+
(recipeId === "ollama" ? "qwen3.5:9b" : "granite3.3:2b");
|
|
751
684
|
const url = `http://127.0.0.1:${aiSpec.hostPort}`;
|
|
752
685
|
const paintAi = (status: DevStatus, detail?: string) => {
|
|
753
686
|
heroAiStatus = status;
|
|
@@ -807,7 +740,7 @@ export async function runDev(options: DevOptions = {}): Promise<DevResult> {
|
|
|
807
740
|
} catch (err) {
|
|
808
741
|
const msg = err instanceof Error ? err.message : String(err);
|
|
809
742
|
console.error(msg);
|
|
810
|
-
console.error("oke dev:
|
|
743
|
+
console.error("oke dev: Docker Compose failed — fix compose and retry");
|
|
811
744
|
restoreWarn();
|
|
812
745
|
return { code: 1 };
|
|
813
746
|
}
|
|
@@ -833,9 +766,9 @@ export async function runDev(options: DevOptions = {}): Promise<DevResult> {
|
|
|
833
766
|
}
|
|
834
767
|
const heroSnapshot = buildDevHeroSnapshot({
|
|
835
768
|
config: loadedConfig,
|
|
836
|
-
docker:
|
|
837
|
-
sqlDriver:
|
|
838
|
-
kvDriver:
|
|
769
|
+
docker: true,
|
|
770
|
+
sqlDriver: stackSqlDriver,
|
|
771
|
+
kvDriver: stackKvDriver,
|
|
839
772
|
aiModel: heroAiModel,
|
|
840
773
|
aiStatus: heroAiStatus,
|
|
841
774
|
version: okeVersion,
|
|
@@ -950,7 +883,7 @@ export async function runDev(options: DevOptions = {}): Promise<DevResult> {
|
|
|
950
883
|
bootProgress.clear();
|
|
951
884
|
const bootBoard = createAnchoredBoard(write);
|
|
952
885
|
bootBoard.paint(paintBootBoard(heroAiStatus));
|
|
953
|
-
// Track
|
|
886
|
+
// Track lines printed below the board so live ● repaints stay anchored.
|
|
954
887
|
write = bootBoard.wrapWrite(write);
|
|
955
888
|
|
|
956
889
|
if (options.dryRun) {
|
|
@@ -1045,27 +978,26 @@ export async function runDev(options: DevOptions = {}): Promise<DevResult> {
|
|
|
1045
978
|
setProcessEnv("OKE_KV_DRIVER", stackKvDriver);
|
|
1046
979
|
}
|
|
1047
980
|
|
|
1048
|
-
// One-shot schema sync for the
|
|
1049
|
-
//
|
|
1050
|
-
// drizzle-kit. Data planes stay isolated — session flags never rewrite
|
|
1051
|
-
// `.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.
|
|
1052
983
|
if (!options.noDbPush) {
|
|
1053
984
|
const { syncDevSchema } = await import("./dev-schema-sync.ts");
|
|
985
|
+
const configEnv = "dev" as const;
|
|
1054
986
|
try {
|
|
1055
|
-
const result = await syncDevSchema(cwd,
|
|
987
|
+
const result = await syncDevSchema(cwd, configEnv, {
|
|
1056
988
|
write: chromeWrite,
|
|
1057
|
-
quietComposeReady:
|
|
989
|
+
quietComposeReady: true,
|
|
1058
990
|
});
|
|
1059
991
|
write(
|
|
1060
992
|
formatStatusLine(
|
|
1061
|
-
`oke db push (
|
|
993
|
+
`oke db push (dev · ${result.dialect}) ${result.code === 0 ? "ok" : "failed"}`,
|
|
1062
994
|
),
|
|
1063
995
|
);
|
|
1064
996
|
if (result.code === 0) {
|
|
1065
997
|
const { maybeAskSeed } = await import("./ask-seed.ts");
|
|
1066
998
|
await maybeAskSeed({
|
|
1067
999
|
cwd,
|
|
1068
|
-
env:
|
|
1000
|
+
env: configEnv,
|
|
1069
1001
|
write,
|
|
1070
1002
|
stdinIsTTY: options.stdinIsTTY ?? process.stdin.isTTY,
|
|
1071
1003
|
});
|
|
@@ -1073,7 +1005,7 @@ export async function runDev(options: DevOptions = {}): Promise<DevResult> {
|
|
|
1073
1005
|
} catch (err) {
|
|
1074
1006
|
write(
|
|
1075
1007
|
formatStatusLine(
|
|
1076
|
-
`oke db push (
|
|
1008
|
+
`oke db push (dev) skipped — ${err instanceof Error ? err.message : String(err)}`,
|
|
1077
1009
|
),
|
|
1078
1010
|
);
|
|
1079
1011
|
}
|
|
@@ -1104,7 +1036,6 @@ export async function runDev(options: DevOptions = {}): Promise<DevResult> {
|
|
|
1104
1036
|
OKE_KV_DRIVER: stackKvDriver,
|
|
1105
1037
|
}
|
|
1106
1038
|
: {}),
|
|
1107
|
-
...(meili?.overlay ?? {}),
|
|
1108
1039
|
/** Backend child — parent Console owns process-local boot notices. */
|
|
1109
1040
|
OKE_SUPPRESS_BOOT_WARN: "1",
|
|
1110
1041
|
};
|
|
@@ -1252,7 +1183,10 @@ export async function runDev(options: DevOptions = {}): Promise<DevResult> {
|
|
|
1252
1183
|
options.dbPush ??
|
|
1253
1184
|
(async (projectCwd: string) => {
|
|
1254
1185
|
const configPath = await resolveDrizzleConfigPath(projectCwd);
|
|
1255
|
-
return runPush(configPath, (t) => write(t), {
|
|
1186
|
+
return runPush(configPath, (t) => write(t), {
|
|
1187
|
+
cwd: projectCwd,
|
|
1188
|
+
env: "dev",
|
|
1189
|
+
});
|
|
1256
1190
|
});
|
|
1257
1191
|
|
|
1258
1192
|
let lastSchemaFilename = "";
|
|
@@ -1274,9 +1208,6 @@ export async function runDev(options: DevOptions = {}): Promise<DevResult> {
|
|
|
1274
1208
|
}
|
|
1275
1209
|
|
|
1276
1210
|
write(formatDevLogSeparator());
|
|
1277
|
-
if (dockerStarted && (options.stdinIsTTY ?? process.stdin.isTTY)) {
|
|
1278
|
-
write(formatDevControlsHint());
|
|
1279
|
-
}
|
|
1280
1211
|
|
|
1281
1212
|
const watchFs: DevWatchFn =
|
|
1282
1213
|
options.watchFs ?? ((path, watchOptions, listener) => watch(path, watchOptions, listener));
|
|
@@ -1308,11 +1239,11 @@ export async function runDev(options: DevOptions = {}): Promise<DevResult> {
|
|
|
1308
1239
|
bootBoard.stop();
|
|
1309
1240
|
autoPushRunner.cancel();
|
|
1310
1241
|
watcher.close();
|
|
1311
|
-
meili?.stop();
|
|
1312
1242
|
app.stop();
|
|
1313
1243
|
consoleServer.stop();
|
|
1314
1244
|
mcpServer?.stop();
|
|
1315
1245
|
docsMcpServer?.stop();
|
|
1246
|
+
void clearDevSessionLock(cwd);
|
|
1316
1247
|
if (dockerStarted) {
|
|
1317
1248
|
const started = dockerStarted;
|
|
1318
1249
|
dockerStarted = null;
|
|
@@ -1373,9 +1304,22 @@ export async function runDev(options: DevOptions = {}): Promise<DevResult> {
|
|
|
1373
1304
|
consoleState,
|
|
1374
1305
|
};
|
|
1375
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
|
+
|
|
1376
1320
|
if (options.onReady) await options.onReady(session);
|
|
1377
1321
|
|
|
1378
|
-
// Keyboard controls (docker + TTY):
|
|
1322
|
+
// Keyboard controls (docker + TTY): Ink replaces raw-mode stdin.
|
|
1379
1323
|
if (keepAlive && dockerStarted && (options.stdinIsTTY ?? process.stdin.isTTY)) {
|
|
1380
1324
|
const started = dockerStarted;
|
|
1381
1325
|
const syncComposeBoard = async (): Promise<void> => {
|
|
@@ -1391,7 +1335,6 @@ export async function runDev(options: DevOptions = {}): Promise<DevResult> {
|
|
|
1391
1335
|
};
|
|
1392
1336
|
const refreshChrome = async (): Promise<void> => {
|
|
1393
1337
|
await syncComposeBoard();
|
|
1394
|
-
// Clear log noise; reprint head + latest ● board + surfaces + empty Logs.
|
|
1395
1338
|
write(clearTerminalScreen());
|
|
1396
1339
|
bootBoard.reset();
|
|
1397
1340
|
write(
|
|
@@ -1412,48 +1355,49 @@ export async function runDev(options: DevOptions = {}): Promise<DevResult> {
|
|
|
1412
1355
|
write(formatServiceLine("Docs MCP", `http://127.0.0.1:${boundDocsMcpPort}`));
|
|
1413
1356
|
}
|
|
1414
1357
|
write(formatDevLogSeparator());
|
|
1415
|
-
write(formatDevControlsHint());
|
|
1416
1358
|
};
|
|
1417
|
-
const
|
|
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
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
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 };
|
|
1457
1401
|
}
|
|
1458
1402
|
|
|
1459
1403
|
if (!keepAlive) {
|
|
@@ -1465,21 +1409,6 @@ export async function runDev(options: DevOptions = {}): Promise<DevResult> {
|
|
|
1465
1409
|
return { code: 0, plan: session.plan, session };
|
|
1466
1410
|
}
|
|
1467
1411
|
|
|
1468
|
-
/**
|
|
1469
|
-
* Declared vault secret names from the project Manifest (policy scope).
|
|
1470
|
-
*
|
|
1471
|
-
* @param cwd - Project root
|
|
1472
|
-
*/
|
|
1473
|
-
async function tryLoadVaultSecretNames(cwd: string): Promise<readonly string[]> {
|
|
1474
|
-
try {
|
|
1475
|
-
const { extractManifest } = await import("../compiler/extract.ts");
|
|
1476
|
-
const manifest = await extractManifest({ rootDir: cwd });
|
|
1477
|
-
return Object.keys(manifest.vault ?? {});
|
|
1478
|
-
} catch {
|
|
1479
|
-
return [];
|
|
1480
|
-
}
|
|
1481
|
-
}
|
|
1482
|
-
|
|
1483
1412
|
/**
|
|
1484
1413
|
* True when a Manifest has no declared flows (scaffold / empty extract).
|
|
1485
1414
|
*
|
|
@@ -1611,20 +1540,34 @@ async function waitForAppReady(
|
|
|
1611
1540
|
}
|
|
1612
1541
|
|
|
1613
1542
|
/**
|
|
1614
|
-
*
|
|
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]]`.
|
|
1615
1561
|
*
|
|
1616
1562
|
* @param args - Args after `dev`
|
|
1617
1563
|
*/
|
|
1618
1564
|
export async function devCli(args: readonly string[]): Promise<number> {
|
|
1619
1565
|
let docker: boolean | string[] | undefined;
|
|
1620
|
-
let local = false;
|
|
1621
1566
|
let noDbPush = false;
|
|
1622
1567
|
let entry: string | undefined;
|
|
1623
1568
|
for (let i = 0; i < args.length; i++) {
|
|
1624
1569
|
const a = args[i]!;
|
|
1625
|
-
if (a === "--
|
|
1626
|
-
local = true;
|
|
1627
|
-
} else if (a === "--docker" || a === "-d") {
|
|
1570
|
+
if (a === "--docker" || a === "-d") {
|
|
1628
1571
|
const next = args[i + 1];
|
|
1629
1572
|
if (next && !next.startsWith("-") && /^[\w.,]+$/.test(next)) {
|
|
1630
1573
|
docker = next
|
|
@@ -1639,23 +1582,26 @@ export async function devCli(args: readonly string[]): Promise<number> {
|
|
|
1639
1582
|
noDbPush = true;
|
|
1640
1583
|
} else if (a === "--entry" || a === "-e") entry = args[++i];
|
|
1641
1584
|
else if (a === "--help" || a === "-h") {
|
|
1642
|
-
console.log(`oke dev [
|
|
1585
|
+
console.log(`oke dev [-d [roles]] [--no-db-push] [--entry|-e src/app.ts]
|
|
1643
1586
|
|
|
1644
1587
|
Watch · hot reload · Console :6533 · app :6530 · MCP :6535
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
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).
|
|
1653
1596
|
`);
|
|
1654
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;
|
|
1655
1602
|
}
|
|
1656
1603
|
}
|
|
1657
1604
|
const { code } = await runDev({
|
|
1658
|
-
...(local ? { local: true } : {}),
|
|
1659
1605
|
...(docker === undefined ? {} : { docker }),
|
|
1660
1606
|
...(noDbPush ? { noDbPush: true } : {}),
|
|
1661
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:"]);
|
|
@@ -8,7 +8,12 @@ import { tmpdir } from "node:os";
|
|
|
8
8
|
import { join } from "node:path";
|
|
9
9
|
import { composeProjectName, type DockerRunner } from "../docker/cleanup.ts";
|
|
10
10
|
import { dockerCli } from "./docker.ts";
|
|
11
|
-
import {
|
|
11
|
+
import {
|
|
12
|
+
dockerCleanHelp,
|
|
13
|
+
parseDockerCleanArgs,
|
|
14
|
+
runDockerClean,
|
|
15
|
+
selectionEntries,
|
|
16
|
+
} from "./docker-clean.ts";
|
|
12
17
|
import { EXIT_OK, EXIT_USAGE } from "./exit.ts";
|
|
13
18
|
import { formatOkeHelp, flagTokensFor, OKE_COMMANDS } from "./registry.ts";
|
|
14
19
|
|
|
@@ -176,4 +181,31 @@ describe("oke docker clean", () => {
|
|
|
176
181
|
expect(flagTokensFor(docker, "clean")).toContain("--all");
|
|
177
182
|
expect(formatOkeHelp()).toContain("clean");
|
|
178
183
|
});
|
|
184
|
+
|
|
185
|
+
test("selectionEntries is one row per project (not per container)", () => {
|
|
186
|
+
const entries = selectionEntries([
|
|
187
|
+
{
|
|
188
|
+
project: "oke-dev-aaaaaa",
|
|
189
|
+
containers: [
|
|
190
|
+
{
|
|
191
|
+
id: "1",
|
|
192
|
+
name: "oke-dev-aaaaaa-redis-1",
|
|
193
|
+
service: "redis",
|
|
194
|
+
state: "running",
|
|
195
|
+
project: "oke-dev-aaaaaa",
|
|
196
|
+
},
|
|
197
|
+
{
|
|
198
|
+
id: "2",
|
|
199
|
+
name: "oke-dev-aaaaaa-postgres-1",
|
|
200
|
+
service: "postgres",
|
|
201
|
+
state: "running",
|
|
202
|
+
project: "oke-dev-aaaaaa",
|
|
203
|
+
},
|
|
204
|
+
],
|
|
205
|
+
},
|
|
206
|
+
]);
|
|
207
|
+
expect(entries).toHaveLength(1);
|
|
208
|
+
expect(entries[0]?.label).toBe("oke-dev-aaaaaa");
|
|
209
|
+
expect(entries[0]?.hint).toContain("2 container");
|
|
210
|
+
});
|
|
179
211
|
});
|