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
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Active SQL env resolution
|
|
2
|
+
* Active SQL env resolution — Docker-first (`dev` default).
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import { afterEach, describe, expect, test } from "bun:test";
|
|
6
6
|
import { mkdtemp, rm } from "node:fs/promises";
|
|
7
7
|
import { tmpdir } from "node:os";
|
|
8
8
|
import { join } from "node:path";
|
|
9
|
-
import { writeDevMode } from "./dev-mode.ts";
|
|
10
9
|
import { resolveDevSqlEnv } from "./resolve-dev-sql-env.ts";
|
|
11
10
|
|
|
12
11
|
const dirs: string[] = [];
|
|
@@ -22,27 +21,20 @@ async function tempDir(): Promise<string> {
|
|
|
22
21
|
}
|
|
23
22
|
|
|
24
23
|
describe("resolveDevSqlEnv", () => {
|
|
25
|
-
test("defaults to
|
|
24
|
+
test("defaults to dev (Docker-first)", async () => {
|
|
26
25
|
const dir = await tempDir();
|
|
27
|
-
expect(await resolveDevSqlEnv(dir)).toBe("
|
|
26
|
+
expect(await resolveDevSqlEnv(dir)).toBe("dev");
|
|
28
27
|
});
|
|
29
28
|
|
|
30
29
|
test("explicit env override wins", async () => {
|
|
31
30
|
const dir = await tempDir();
|
|
32
|
-
await
|
|
33
|
-
expect(await resolveDevSqlEnv(dir, { env: "
|
|
31
|
+
expect(await resolveDevSqlEnv(dir, { env: "test" })).toBe("test");
|
|
32
|
+
expect(await resolveDevSqlEnv(dir, { env: "dev" })).toBe("dev");
|
|
34
33
|
});
|
|
35
34
|
|
|
36
|
-
test("
|
|
35
|
+
test("docker flag is ignored (always dev unless env set)", async () => {
|
|
37
36
|
const dir = await tempDir();
|
|
38
|
-
await
|
|
39
|
-
expect(await resolveDevSqlEnv(dir, { docker:
|
|
40
|
-
expect(await resolveDevSqlEnv(dir, { docker: false })).toBe("local");
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
test("reads saved .oke/mode", async () => {
|
|
44
|
-
const dir = await tempDir();
|
|
45
|
-
await writeDevMode(dir, "docker");
|
|
46
|
-
expect(await resolveDevSqlEnv(dir)).toBe("docker");
|
|
37
|
+
expect(await resolveDevSqlEnv(dir, { docker: true })).toBe("dev");
|
|
38
|
+
expect(await resolveDevSqlEnv(dir, { docker: false })).toBe("dev");
|
|
47
39
|
});
|
|
48
40
|
});
|
|
@@ -1,42 +1,40 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Resolve the active SQL env for schema tooling (`oke db`, `oke
|
|
3
|
-
*
|
|
2
|
+
* Resolve the active SQL env for schema tooling (`oke db`, `oke dev`
|
|
3
|
+
* one-shot sync). Docker-first: `oke dev` always uses `dev`.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import type { ConfigEnv } from "../config/index.ts";
|
|
7
|
-
import { readDevMode } from "./dev-mode.ts";
|
|
8
7
|
|
|
9
8
|
/** Options for {@link resolveDevSqlEnv}. */
|
|
10
9
|
export interface ResolveDevSqlEnvOptions {
|
|
11
10
|
/**
|
|
12
|
-
* Session override — `true` means
|
|
13
|
-
* `
|
|
11
|
+
* Session override — `true` means compose infra is up. Ignored for env
|
|
12
|
+
* selection (always `dev` unless `options.env` is set); kept for call-site
|
|
13
|
+
* compatibility.
|
|
14
14
|
*/
|
|
15
15
|
readonly docker?: boolean;
|
|
16
16
|
/**
|
|
17
|
-
* Explicit env override (e.g. `oke db --env
|
|
17
|
+
* Explicit env override (e.g. `oke db --env test`). Wins over the default.
|
|
18
18
|
*/
|
|
19
19
|
readonly env?: ConfigEnv;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
/**
|
|
23
|
-
* Resolve the SQL
|
|
23
|
+
* Resolve the SQL {@link ConfigEnv} for tooling without prompting.
|
|
24
24
|
*
|
|
25
25
|
* Order:
|
|
26
26
|
* 1. Explicit `options.env` (CLI flag)
|
|
27
|
-
* 2.
|
|
28
|
-
* 3. `.oke/mode` persisted preference
|
|
29
|
-
* 4. Default `local`
|
|
27
|
+
* 2. Default `dev` (Docker-first local development)
|
|
30
28
|
*
|
|
31
|
-
* @param
|
|
29
|
+
* @param _cwd - Project root (unused; kept for call-site compatibility)
|
|
32
30
|
* @param options - Session / CLI overrides
|
|
33
31
|
*/
|
|
34
32
|
export async function resolveDevSqlEnv(
|
|
35
|
-
|
|
33
|
+
_cwd: string,
|
|
36
34
|
options: ResolveDevSqlEnvOptions = {},
|
|
37
35
|
): Promise<ConfigEnv> {
|
|
36
|
+
void _cwd;
|
|
37
|
+
void options.docker;
|
|
38
38
|
if (options.env !== undefined) return options.env;
|
|
39
|
-
|
|
40
|
-
const saved = await readDevMode(cwd);
|
|
41
|
-
return saved ?? "local";
|
|
39
|
+
return "dev";
|
|
42
40
|
}
|
|
@@ -12,36 +12,54 @@ import { runImagesPin } from "./images.ts";
|
|
|
12
12
|
import { upgradeCli } from "./upgrade.ts";
|
|
13
13
|
|
|
14
14
|
describe("oke safe-default overrides", () => {
|
|
15
|
-
test("docker
|
|
15
|
+
test("docker prod overlays are on by default; --no-prod opts out", async () => {
|
|
16
16
|
const dir = await mkdtemp(join(tmpdir(), "oke-safe-docker-"));
|
|
17
17
|
await Bun.write(
|
|
18
18
|
join(dir, "oke.config.ts"),
|
|
19
|
-
`export default { images: {
|
|
19
|
+
`export default { images: { store: { sql: "postgres:18-alpine" } } }\n`,
|
|
20
20
|
);
|
|
21
|
-
// Without --prod, derive still runs but prod overlays are not requested.
|
|
22
|
-
// We assert the parser default by calling runDockerDerive via dockerCli
|
|
23
|
-
// with a dry path: inspect that -p flips prod on.
|
|
24
21
|
const { runDockerDerive } = await import("./docker.ts");
|
|
25
|
-
|
|
22
|
+
|
|
23
|
+
// Default layout is single: prod readiness/deploy folds into docker-compose.yml
|
|
24
|
+
// (no separate compose.prod.yml). Assert production-grade content is present.
|
|
25
|
+
const defaults = await runDockerDerive({
|
|
26
|
+
cwd: dir,
|
|
27
|
+
outDir: dir,
|
|
28
|
+
images: { "store.sql": "postgres:18-alpine" },
|
|
29
|
+
dryRun: true,
|
|
30
|
+
write: () => {},
|
|
31
|
+
});
|
|
32
|
+
expect(defaults.code).toBe(0);
|
|
33
|
+
const defaultCompose = defaults.result?.files.find((f) => f.path === "docker-compose.yml");
|
|
34
|
+
expect(defaultCompose).toBeDefined();
|
|
35
|
+
expect(defaultCompose!.content).toContain("/_/ready");
|
|
36
|
+
expect(defaults.result?.files.some((f) => f.path.includes("prod"))).toBe(false);
|
|
37
|
+
|
|
38
|
+
const noProd = await runDockerDerive({
|
|
26
39
|
cwd: dir,
|
|
27
40
|
outDir: dir,
|
|
28
41
|
images: { "store.sql": "postgres:18-alpine" },
|
|
42
|
+
prod: false,
|
|
29
43
|
dryRun: true,
|
|
30
44
|
write: () => {},
|
|
31
45
|
});
|
|
32
|
-
expect(
|
|
33
|
-
|
|
46
|
+
expect(noProd.code).toBe(0);
|
|
47
|
+
const noProdCompose = noProd.result?.files.find((f) => f.path === "docker-compose.yml");
|
|
48
|
+
expect(noProdCompose).toBeDefined();
|
|
49
|
+
expect(noProdCompose!.content).not.toContain("/_/ready");
|
|
34
50
|
|
|
35
|
-
|
|
51
|
+
// Split layout still emits a separate compose.prod.yml when prod is on.
|
|
52
|
+
const splitProd = await runDockerDerive({
|
|
36
53
|
cwd: dir,
|
|
37
54
|
outDir: dir,
|
|
38
55
|
images: { "store.sql": "postgres:18-alpine" },
|
|
39
56
|
prod: true,
|
|
57
|
+
layout: "split",
|
|
40
58
|
dryRun: true,
|
|
41
59
|
write: () => {},
|
|
42
60
|
});
|
|
43
|
-
expect(
|
|
44
|
-
expect(
|
|
61
|
+
expect(splitProd.code).toBe(0);
|
|
62
|
+
expect(splitProd.result?.files.some((f) => f.path === "compose.prod.yml")).toBe(true);
|
|
45
63
|
|
|
46
64
|
expect(await dockerCli(["--help"])).toBe(0);
|
|
47
65
|
});
|
package/src/cli/schema.ts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* `oke schema generate` — core + auth + plugin tables →
|
|
2
|
+
* `oke schema generate` — core + auth + plugin tables → `.oke/schema/oke.ts`.
|
|
3
|
+
*
|
|
4
|
+
* Domain Drizzle lives under `src/db/` (`oke db …`). This file is the
|
|
5
|
+
* generated system/stub catalogue — kept under `.oke/` so it never lands
|
|
6
|
+
* at the project root next to app source.
|
|
3
7
|
*/
|
|
4
8
|
|
|
5
9
|
import { createHash } from "node:crypto";
|
|
@@ -15,10 +19,16 @@ import type { Manifest } from "../manifest/types.ts";
|
|
|
15
19
|
import { loadManifest } from "./load-config.ts";
|
|
16
20
|
|
|
17
21
|
/** Fingerprint file written beside generated schema. */
|
|
18
|
-
export const SCHEMA_FINGERPRINT_FILE = "schema/.oke-schema.sha256";
|
|
22
|
+
export const SCHEMA_FINGERPRINT_FILE = ".oke/schema/.oke-schema.sha256";
|
|
23
|
+
|
|
24
|
+
/** Default generated system schema path (under `.oke/`, not project root). */
|
|
25
|
+
export const SCHEMA_OUT = ".oke/schema/oke.ts";
|
|
19
26
|
|
|
20
|
-
/**
|
|
21
|
-
export const
|
|
27
|
+
/** Pre-0.10.4 path — still read for doctor / --check soft-compat. */
|
|
28
|
+
export const LEGACY_SCHEMA_OUT = "schema/oke.ts";
|
|
29
|
+
|
|
30
|
+
/** Pre-0.10.4 fingerprint path. */
|
|
31
|
+
export const LEGACY_SCHEMA_FINGERPRINT_FILE = "schema/.oke-schema.sha256";
|
|
22
32
|
|
|
23
33
|
/** Options for {@link runSchemaGenerate}. */
|
|
24
34
|
export interface SchemaGenerateOptions {
|
|
@@ -36,7 +46,7 @@ export interface SchemaGenerateOptions {
|
|
|
36
46
|
}
|
|
37
47
|
|
|
38
48
|
/**
|
|
39
|
-
* Generate
|
|
49
|
+
* Generate `.oke/schema/oke.ts` from Manifest store tables + core auth columns.
|
|
40
50
|
*
|
|
41
51
|
* @param options - Manifest / check flag
|
|
42
52
|
*/
|
|
@@ -60,6 +70,11 @@ export async function runSchemaGenerate(options: SchemaGenerateOptions = {}): Pr
|
|
|
60
70
|
"oke_crons",
|
|
61
71
|
"oke_signal_config",
|
|
62
72
|
"oke_console_prefs",
|
|
73
|
+
"oke_vault_secrets",
|
|
74
|
+
"oke_vault_keys",
|
|
75
|
+
"oke_vault_audit",
|
|
76
|
+
"oke_vault_master",
|
|
77
|
+
"oke_vault_status",
|
|
63
78
|
...(options.extraTables ?? []),
|
|
64
79
|
]);
|
|
65
80
|
if (authSchema) {
|
|
@@ -85,13 +100,31 @@ export async function runSchemaGenerate(options: SchemaGenerateOptions = {}): Pr
|
|
|
85
100
|
}
|
|
86
101
|
|
|
87
102
|
const source = emitSchemaSource([...tables].sort(), authSchema);
|
|
88
|
-
const
|
|
103
|
+
const outRel = options.out ?? SCHEMA_OUT;
|
|
104
|
+
const out = resolve(cwd, outRel);
|
|
89
105
|
const fp = hashSource(source);
|
|
106
|
+
const fpRel = options.out
|
|
107
|
+
? `${dirname(outRel)}/.oke-schema.sha256`.replace(/^\.\//, "")
|
|
108
|
+
: SCHEMA_FINGERPRINT_FILE;
|
|
90
109
|
|
|
91
110
|
if (options.check) {
|
|
92
111
|
const existing = Bun.file(out);
|
|
93
112
|
if (!(await existing.exists())) {
|
|
94
|
-
|
|
113
|
+
// Soft-compat: accept a correct legacy root `schema/oke.ts` during migrate.
|
|
114
|
+
if (!options.out) {
|
|
115
|
+
const legacy = Bun.file(resolve(cwd, LEGACY_SCHEMA_OUT));
|
|
116
|
+
if (await legacy.exists()) {
|
|
117
|
+
if (hashSource(await legacy.text()) === fp) {
|
|
118
|
+
write(
|
|
119
|
+
"oke schema generate --check: ok (legacy schema/oke.ts — re-run without --check to move under .oke/schema/)\n",
|
|
120
|
+
);
|
|
121
|
+
return 0;
|
|
122
|
+
}
|
|
123
|
+
write("oke schema generate --check: schema drift\n");
|
|
124
|
+
return 1;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
write(`oke schema generate --check: ${outRel} missing\n`);
|
|
95
128
|
return 1;
|
|
96
129
|
}
|
|
97
130
|
const current = await existing.text();
|
|
@@ -105,7 +138,7 @@ export async function runSchemaGenerate(options: SchemaGenerateOptions = {}): Pr
|
|
|
105
138
|
|
|
106
139
|
await mkdir(dirname(out), { recursive: true });
|
|
107
140
|
await Bun.write(out, source);
|
|
108
|
-
await Bun.write(resolve(cwd,
|
|
141
|
+
await Bun.write(resolve(cwd, fpRel), `${fp}\n`);
|
|
109
142
|
write(`oke schema generate: wrote ${out} (${tables.size} table(s))\n`);
|
|
110
143
|
return 0;
|
|
111
144
|
}
|
|
@@ -128,6 +161,11 @@ export async function schemaFingerprint(cwd: string, manifest?: Manifest): Promi
|
|
|
128
161
|
"oke_crons",
|
|
129
162
|
"oke_signal_config",
|
|
130
163
|
"oke_console_prefs",
|
|
164
|
+
"oke_vault_secrets",
|
|
165
|
+
"oke_vault_keys",
|
|
166
|
+
"oke_vault_audit",
|
|
167
|
+
"oke_vault_master",
|
|
168
|
+
"oke_vault_status",
|
|
131
169
|
...authSchema.tableNames,
|
|
132
170
|
]);
|
|
133
171
|
if (m?.stores) {
|
|
@@ -141,16 +179,24 @@ export async function schemaFingerprint(cwd: string, manifest?: Manifest): Promi
|
|
|
141
179
|
/**
|
|
142
180
|
* Read the on-disk schema fingerprint, if any.
|
|
143
181
|
*
|
|
182
|
+
* Prefers `.oke/schema/`, then legacy root `schema/`.
|
|
183
|
+
*
|
|
144
184
|
* @param cwd - Project root
|
|
145
185
|
*/
|
|
146
186
|
export async function readSchemaFingerprint(cwd: string): Promise<string | null> {
|
|
147
|
-
const
|
|
148
|
-
|
|
149
|
-
|
|
187
|
+
for (const rel of [SCHEMA_FINGERPRINT_FILE, LEGACY_SCHEMA_FINGERPRINT_FILE] as const) {
|
|
188
|
+
const fpFile = Bun.file(resolve(cwd, rel));
|
|
189
|
+
if (await fpFile.exists()) {
|
|
190
|
+
return (await fpFile.text()).trim();
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
for (const rel of [SCHEMA_OUT, LEGACY_SCHEMA_OUT] as const) {
|
|
194
|
+
const schema = Bun.file(resolve(cwd, rel));
|
|
195
|
+
if (await schema.exists()) {
|
|
196
|
+
return hashSource(await schema.text());
|
|
197
|
+
}
|
|
150
198
|
}
|
|
151
|
-
|
|
152
|
-
if (!(await schema.exists())) return null;
|
|
153
|
-
return hashSource(await schema.text());
|
|
199
|
+
return null;
|
|
154
200
|
}
|
|
155
201
|
|
|
156
202
|
/**
|
|
@@ -173,9 +219,11 @@ export async function schemaCli(args: readonly string[]): Promise<number> {
|
|
|
173
219
|
else if (a === "--manifest" || a === "-m") manifestPath = rest[++i];
|
|
174
220
|
else if (a === "--out" || a === "-o") out = rest[++i];
|
|
175
221
|
else if (a === "--help" || a === "-h") {
|
|
176
|
-
console.log(`oke schema generate [--check|-c] [--out|-o schema/oke.ts]
|
|
222
|
+
console.log(`oke schema generate [--check|-c] [--out|-o .oke/schema/oke.ts]
|
|
177
223
|
|
|
178
|
-
Emit core auth columns + Manifest store tables
|
|
224
|
+
Emit core auth columns + Manifest store tables into \`.oke/schema/oke.ts\`
|
|
225
|
+
(system stubs — not domain Drizzle under src/db/). Use --check in CI to fail on drift.
|
|
226
|
+
Re-run after adding plugins / auth tables so the stub catalogue stays current.
|
|
179
227
|
`);
|
|
180
228
|
return 0;
|
|
181
229
|
}
|
|
@@ -211,6 +259,7 @@ export function emitSchemaSource(
|
|
|
211
259
|
return `/**
|
|
212
260
|
* Generated by \`oke schema generate\` — do not edit.
|
|
213
261
|
* Core Gate auth tables + Manifest store tables.
|
|
262
|
+
* Path: \`.oke/schema/oke.ts\` (system stubs; domain schema lives under \`src/db/\`).
|
|
214
263
|
*/
|
|
215
264
|
|
|
216
265
|
${decls}
|
package/src/cli/test.ts
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `oke test` — run `bun test` with PGLite test posture (no Docker Compose).
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* CLI entry for `oke test`.
|
|
7
|
+
*
|
|
8
|
+
* Sets `NODE_ENV=test` and a default in-memory PGLite URL, verifies
|
|
9
|
+
* `@electric-sql/pglite` resolves, then forwards remaining argv to `bun test`.
|
|
10
|
+
*
|
|
11
|
+
* @param args - Args after `test` (forwarded to `bun test`)
|
|
12
|
+
*/
|
|
13
|
+
export async function testCli(args: readonly string[]): Promise<number> {
|
|
14
|
+
for (const a of args) {
|
|
15
|
+
if (a === "--help" || a === "-h") {
|
|
16
|
+
console.log(`oke test [...bun test args]
|
|
17
|
+
|
|
18
|
+
Run bun test with PGLite test posture (NODE_ENV=test).
|
|
19
|
+
Does not start Docker Compose.
|
|
20
|
+
|
|
21
|
+
Environment (set if unset):
|
|
22
|
+
NODE_ENV=test
|
|
23
|
+
OKE_PGLITE_URL=memory://
|
|
24
|
+
`);
|
|
25
|
+
return 0;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (process.env.NODE_ENV === undefined || process.env.NODE_ENV === "") {
|
|
30
|
+
process.env.NODE_ENV = "test";
|
|
31
|
+
}
|
|
32
|
+
if (process.env.OKE_PGLITE_URL === undefined || process.env.OKE_PGLITE_URL === "") {
|
|
33
|
+
process.env.OKE_PGLITE_URL = "memory://";
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
try {
|
|
37
|
+
await import("@electric-sql/pglite");
|
|
38
|
+
} catch {
|
|
39
|
+
try {
|
|
40
|
+
Bun.resolveSync("@electric-sql/pglite", process.cwd());
|
|
41
|
+
} catch {
|
|
42
|
+
console.error(
|
|
43
|
+
"oke test: `@electric-sql/pglite` is not installed — add it as a dependency (okengine peers it for the pglite SQL driver)",
|
|
44
|
+
);
|
|
45
|
+
return 1;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const proc = Bun.spawn(["bun", "test", ...args], {
|
|
50
|
+
cwd: process.cwd(),
|
|
51
|
+
env: process.env as Record<string, string>,
|
|
52
|
+
stdin: "inherit",
|
|
53
|
+
stdout: "inherit",
|
|
54
|
+
stderr: "inherit",
|
|
55
|
+
});
|
|
56
|
+
const code = await proc.exited;
|
|
57
|
+
return code ?? 1;
|
|
58
|
+
}
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interactive `oke` shell — brand chrome, focus layers, `/` palette.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { Box, useApp, useInput } from "ink";
|
|
6
|
+
import { useCallback, useEffect, useMemo, useRef, useState, type ReactElement } from "react";
|
|
7
|
+
import { DevController } from "../dev-controller.ts";
|
|
8
|
+
import type { DevOwnership } from "../dev-session-lock.ts";
|
|
9
|
+
import { ConfirmDialog } from "./components/ConfirmDialog.tsx";
|
|
10
|
+
import { HeaderBar } from "./components/HeaderBar.tsx";
|
|
11
|
+
import { SlashPalette } from "./components/SlashPalette.tsx";
|
|
12
|
+
import { StatusBar, type FooterStatus } from "./components/StatusBar.tsx";
|
|
13
|
+
import { TabBar } from "./components/TabBar.tsx";
|
|
14
|
+
import { DashboardPanel } from "./panels/Dashboard.tsx";
|
|
15
|
+
import { DatabasePanel } from "./panels/Database.tsx";
|
|
16
|
+
import { DevPanel } from "./panels/Dev.tsx";
|
|
17
|
+
import { DockerPanel } from "./panels/Docker.tsx";
|
|
18
|
+
import { NavigatorPanel } from "./panels/Navigator.tsx";
|
|
19
|
+
import { runSlashCli } from "./slash-run.ts";
|
|
20
|
+
import { pollPortSnapshot } from "./state/ports.ts";
|
|
21
|
+
import { TUI_MUTED } from "./theme.ts";
|
|
22
|
+
|
|
23
|
+
const PANELS = ["dashboard", "dev", "database", "docker", "navigator"] as const;
|
|
24
|
+
type PanelId = (typeof PANELS)[number];
|
|
25
|
+
|
|
26
|
+
const TABS = [
|
|
27
|
+
{ id: "dashboard", label: "Dashboard" },
|
|
28
|
+
{ id: "dev", label: "Dev" },
|
|
29
|
+
{ id: "database", label: "Database" },
|
|
30
|
+
{ id: "docker", label: "Docker" },
|
|
31
|
+
{ id: "navigator", label: "Navigator" },
|
|
32
|
+
] as const;
|
|
33
|
+
|
|
34
|
+
/** Props for {@link OkeTuiApp}. */
|
|
35
|
+
export type OkeTuiAppProps = {
|
|
36
|
+
readonly cwd: string;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Root Ink application.
|
|
41
|
+
*
|
|
42
|
+
* @param props - cwd
|
|
43
|
+
*/
|
|
44
|
+
export function OkeTuiApp(props: OkeTuiAppProps): ReactElement {
|
|
45
|
+
const { exit } = useApp();
|
|
46
|
+
const [panelIndex, setPanelIndex] = useState(0);
|
|
47
|
+
const [focusLayer, setFocusLayer] = useState<"tabs" | "panel">("tabs");
|
|
48
|
+
const [logs, setLogs] = useState<string[]>([]);
|
|
49
|
+
const [slashOpen, setSlashOpen] = useState(false);
|
|
50
|
+
const [slashBusy, setSlashBusy] = useState(false);
|
|
51
|
+
const [quitConfirm, setQuitConfirm] = useState(false);
|
|
52
|
+
const [ownership, setOwnership] = useState<DevOwnership>("stopped");
|
|
53
|
+
const [footerStatus, setFooterStatus] = useState<FooterStatus>({ kind: "idle" });
|
|
54
|
+
const doneTimer = useRef<ReturnType<typeof setTimeout> | null>(null);
|
|
55
|
+
const controller = useMemo(() => new DevController(), []);
|
|
56
|
+
|
|
57
|
+
const onLog = useCallback((line: string) => {
|
|
58
|
+
setLogs((prev) => {
|
|
59
|
+
const next = [...prev, ...line.split("\n").filter((l) => l.length > 0)];
|
|
60
|
+
return next.slice(-200);
|
|
61
|
+
});
|
|
62
|
+
}, []);
|
|
63
|
+
|
|
64
|
+
const onStatus = useCallback((status: FooterStatus) => {
|
|
65
|
+
if (doneTimer.current) {
|
|
66
|
+
clearTimeout(doneTimer.current);
|
|
67
|
+
doneTimer.current = null;
|
|
68
|
+
}
|
|
69
|
+
setFooterStatus(status);
|
|
70
|
+
if (status.kind === "done") {
|
|
71
|
+
doneTimer.current = setTimeout(() => {
|
|
72
|
+
setFooterStatus({ kind: "idle" });
|
|
73
|
+
doneTimer.current = null;
|
|
74
|
+
}, 2000);
|
|
75
|
+
}
|
|
76
|
+
}, []);
|
|
77
|
+
|
|
78
|
+
useEffect(() => {
|
|
79
|
+
const tick = (): void => {
|
|
80
|
+
void pollPortSnapshot(props.cwd).then((s) => setOwnership(s.ownership));
|
|
81
|
+
};
|
|
82
|
+
tick();
|
|
83
|
+
const id = setInterval(tick, 2000);
|
|
84
|
+
const off = controller.on((e) => {
|
|
85
|
+
if (e.type === "ownership" || e.type === "ready") {
|
|
86
|
+
setOwnership(e.ownership);
|
|
87
|
+
}
|
|
88
|
+
if (e.type === "exit") setOwnership("stopped");
|
|
89
|
+
});
|
|
90
|
+
return () => {
|
|
91
|
+
clearInterval(id);
|
|
92
|
+
off();
|
|
93
|
+
if (doneTimer.current) clearTimeout(doneTimer.current);
|
|
94
|
+
};
|
|
95
|
+
}, [controller, props.cwd]);
|
|
96
|
+
|
|
97
|
+
const panel = (PANELS[panelIndex] ?? "dashboard") as PanelId;
|
|
98
|
+
const panelActive = !slashOpen && !quitConfirm && focusLayer === "panel";
|
|
99
|
+
|
|
100
|
+
const jumpPanel = useCallback((panelId: string) => {
|
|
101
|
+
const idx = PANELS.indexOf(panelId as PanelId);
|
|
102
|
+
if (idx >= 0) {
|
|
103
|
+
setPanelIndex(idx);
|
|
104
|
+
setFocusLayer("panel");
|
|
105
|
+
}
|
|
106
|
+
}, []);
|
|
107
|
+
|
|
108
|
+
const runCli = useCallback(
|
|
109
|
+
async (argv: readonly string[]) => {
|
|
110
|
+
setSlashBusy(true);
|
|
111
|
+
onStatus({ kind: "running", label: `Running oke ${argv.join(" ")}…` });
|
|
112
|
+
try {
|
|
113
|
+
await runSlashCli(props.cwd, argv, onLog);
|
|
114
|
+
onStatus({ kind: "done", label: "Done" });
|
|
115
|
+
} catch {
|
|
116
|
+
onStatus({ kind: "done", label: "Failed" });
|
|
117
|
+
} finally {
|
|
118
|
+
setSlashBusy(false);
|
|
119
|
+
}
|
|
120
|
+
},
|
|
121
|
+
[props.cwd, onLog, onStatus],
|
|
122
|
+
);
|
|
123
|
+
|
|
124
|
+
const requestQuit = useCallback(() => {
|
|
125
|
+
if (ownership === "managed") {
|
|
126
|
+
setQuitConfirm(true);
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
exit();
|
|
130
|
+
}, [ownership, exit]);
|
|
131
|
+
|
|
132
|
+
useInput((input, key) => {
|
|
133
|
+
if (slashOpen || quitConfirm) return;
|
|
134
|
+
|
|
135
|
+
if (key.escape) {
|
|
136
|
+
if (focusLayer === "panel") {
|
|
137
|
+
setFocusLayer("tabs");
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
requestQuit();
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
if (input === "/") {
|
|
144
|
+
setSlashOpen(true);
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
const n = Number(input);
|
|
148
|
+
if (n >= 1 && n <= PANELS.length) {
|
|
149
|
+
setPanelIndex(n - 1);
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
// Global panel switch: Tab always; ←→ when focus is on the tab strip.
|
|
153
|
+
if (key.tab) {
|
|
154
|
+
setPanelIndex((i) => (i + 1) % PANELS.length);
|
|
155
|
+
setFocusLayer("tabs");
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
if (focusLayer === "tabs") {
|
|
159
|
+
if (key.leftArrow) {
|
|
160
|
+
setPanelIndex((i) => (i - 1 + PANELS.length) % PANELS.length);
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
if (key.rightArrow) {
|
|
164
|
+
setPanelIndex((i) => (i + 1) % PANELS.length);
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
if (key.downArrow || key.return) {
|
|
168
|
+
setFocusLayer("panel");
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
if (quitConfirm) {
|
|
174
|
+
return (
|
|
175
|
+
<Box
|
|
176
|
+
flexDirection="column"
|
|
177
|
+
borderStyle="round"
|
|
178
|
+
borderColor={TUI_MUTED}
|
|
179
|
+
width="100%"
|
|
180
|
+
padding={1}
|
|
181
|
+
>
|
|
182
|
+
<ConfirmDialog
|
|
183
|
+
message="Stop managed oke dev and quit TUI?"
|
|
184
|
+
onConfirm={() => {
|
|
185
|
+
void controller.stop().then(() => exit());
|
|
186
|
+
}}
|
|
187
|
+
onCancel={() => setQuitConfirm(false)}
|
|
188
|
+
/>
|
|
189
|
+
</Box>
|
|
190
|
+
);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
return (
|
|
194
|
+
<Box
|
|
195
|
+
flexDirection="column"
|
|
196
|
+
borderStyle="round"
|
|
197
|
+
borderColor={TUI_MUTED}
|
|
198
|
+
width="100%"
|
|
199
|
+
paddingX={1}
|
|
200
|
+
paddingY={0}
|
|
201
|
+
>
|
|
202
|
+
<Box paddingY={1}>
|
|
203
|
+
<HeaderBar cwd={props.cwd} />
|
|
204
|
+
</Box>
|
|
205
|
+
<TabBar tabs={TABS} activeIndex={panelIndex} focused={focusLayer === "tabs"} />
|
|
206
|
+
|
|
207
|
+
{slashOpen ? (
|
|
208
|
+
<Box marginTop={1} flexGrow={1} minHeight={10}>
|
|
209
|
+
<SlashPalette
|
|
210
|
+
cwd={props.cwd}
|
|
211
|
+
busy={slashBusy}
|
|
212
|
+
onClose={() => setSlashOpen(false)}
|
|
213
|
+
onJumpPanel={jumpPanel}
|
|
214
|
+
onRunCli={runCli}
|
|
215
|
+
/>
|
|
216
|
+
</Box>
|
|
217
|
+
) : (
|
|
218
|
+
<Box flexDirection="column" flexGrow={1} marginTop={1} minHeight={10} gap={1}>
|
|
219
|
+
{panel === "dashboard" ? (
|
|
220
|
+
<DashboardPanel
|
|
221
|
+
cwd={props.cwd}
|
|
222
|
+
active={panelActive}
|
|
223
|
+
onJumpPanel={jumpPanel}
|
|
224
|
+
onStatus={onStatus}
|
|
225
|
+
/>
|
|
226
|
+
) : null}
|
|
227
|
+
{panel === "dev" ? (
|
|
228
|
+
<DevPanel
|
|
229
|
+
cwd={props.cwd}
|
|
230
|
+
controller={controller}
|
|
231
|
+
onLog={onLog}
|
|
232
|
+
logs={logs}
|
|
233
|
+
active={panelActive}
|
|
234
|
+
onStatus={onStatus}
|
|
235
|
+
/>
|
|
236
|
+
) : null}
|
|
237
|
+
{panel === "database" ? (
|
|
238
|
+
<DatabasePanel cwd={props.cwd} active={panelActive} onLog={onLog} onStatus={onStatus} />
|
|
239
|
+
) : null}
|
|
240
|
+
{panel === "docker" ? (
|
|
241
|
+
<DockerPanel cwd={props.cwd} active={panelActive} onLog={onLog} onStatus={onStatus} />
|
|
242
|
+
) : null}
|
|
243
|
+
{panel === "navigator" ? <NavigatorPanel cwd={props.cwd} active={panelActive} /> : null}
|
|
244
|
+
</Box>
|
|
245
|
+
)}
|
|
246
|
+
|
|
247
|
+
<Box marginTop={0}>
|
|
248
|
+
<StatusBar status={footerStatus} />
|
|
249
|
+
</Box>
|
|
250
|
+
</Box>
|
|
251
|
+
);
|
|
252
|
+
}
|