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/docker/compose.ts
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Compose artefact emission — three production-grade layouts:
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* 4. `compose.override.yml` — user-owned; oke never writes it
|
|
4
|
+
* - `single` (default) → `docker-compose.yml`
|
|
5
|
+
* - `split` → `compose.yml` + `compose.<role>.yml` (+ `compose.prod.yml` when prod)
|
|
6
|
+
* - `stack` → `docker-stack.yml` (Swarm `docker stack deploy -c`)
|
|
8
7
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* `-f` merge order; never includes layer 4.
|
|
8
|
+
* User-owned overrides (`docker-compose.override.yml` / `compose.override.yml`)
|
|
9
|
+
* are listed in {@link emitComposeLayers}'s `composeFiles` but never written.
|
|
12
10
|
*/
|
|
13
11
|
|
|
14
|
-
import { defaultHostPort, envPrefix, serviceNameFor
|
|
12
|
+
import { composeToYaml, defaultHostPort, envPrefix, serviceNameFor } from "./helpers.ts";
|
|
15
13
|
import { recipeFor } from "./recipes/index.ts";
|
|
14
|
+
import { allocateServiceResources, mergeDeployResources, type ServerBudget } from "./resources.ts";
|
|
16
15
|
import type {
|
|
16
|
+
ComposeLayout,
|
|
17
17
|
DeriveOptions,
|
|
18
18
|
GeneratedFile,
|
|
19
19
|
ImageRecipe,
|
|
@@ -25,14 +25,26 @@ import { generateCredentials } from "./credentials.ts";
|
|
|
25
25
|
import { extraHostPortForInstance, hostPortForInstance, STACK_CONTROL_KEYS } from "./stack-id.ts";
|
|
26
26
|
import { APP_PORT } from "../runtime/types.ts";
|
|
27
27
|
|
|
28
|
-
/**
|
|
28
|
+
/** Default single-file compose artefact. */
|
|
29
|
+
export const DOCKER_COMPOSE = "docker-compose.yml";
|
|
30
|
+
|
|
31
|
+
/** User-owned override beside {@link DOCKER_COMPOSE} — never written by oke. */
|
|
32
|
+
export const DOCKER_COMPOSE_OVERRIDE = "docker-compose.override.yml";
|
|
33
|
+
|
|
34
|
+
/** Swarm stack artefact (`docker stack deploy -c`). */
|
|
35
|
+
export const DOCKER_STACK = "docker-stack.yml";
|
|
36
|
+
|
|
37
|
+
/** Split-layout base layer. */
|
|
38
|
+
export const COMPOSE_BASE = "compose.yml";
|
|
39
|
+
|
|
40
|
+
/** Split-layout user override — never written by derivation. */
|
|
29
41
|
export const COMPOSE_OVERRIDE = "compose.override.yml";
|
|
30
42
|
|
|
31
43
|
/**
|
|
32
|
-
*
|
|
33
|
-
*
|
|
44
|
+
* @deprecated Prefer {@link DOCKER_COMPOSE} or {@link DOCKER_STACK}. Kept as an
|
|
45
|
+
* alias of {@link DOCKER_COMPOSE} for soft-compat with older tests / docs.
|
|
34
46
|
*/
|
|
35
|
-
export const COMPOSE_ALL =
|
|
47
|
+
export const COMPOSE_ALL = DOCKER_COMPOSE;
|
|
36
48
|
|
|
37
49
|
/**
|
|
38
50
|
* Relative path refs for compose files living under {@link DeriveOptions.composeDir}.
|
|
@@ -80,7 +92,7 @@ export function buildSpecs(options: DeriveOptions): ServiceSpec[] {
|
|
|
80
92
|
}
|
|
81
93
|
|
|
82
94
|
/**
|
|
83
|
-
* Emit compose
|
|
95
|
+
* Emit compose artefacts for the chosen {@link ComposeLayout}.
|
|
84
96
|
*
|
|
85
97
|
* @param specs - Normalised services
|
|
86
98
|
* @param options - Derive options
|
|
@@ -93,15 +105,18 @@ export function emitComposeLayers(
|
|
|
93
105
|
const appPort = options.appPort ?? APP_PORT;
|
|
94
106
|
const app = options.app ?? "app";
|
|
95
107
|
const includeApp = options.includeApp !== false;
|
|
108
|
+
const layout: ComposeLayout = options.layout ?? "single";
|
|
96
109
|
const paths = composePathRefs(options.composeDir ?? DEFAULT_DOCKER_DIR);
|
|
97
110
|
const files: GeneratedFile[] = [];
|
|
98
|
-
/** Layers
|
|
111
|
+
/** Layers as objects — same merge Compose would apply via `-f` order. */
|
|
99
112
|
const mergeLayers: Record<string, unknown>[] = [];
|
|
100
113
|
|
|
101
114
|
// Layer 1 — project name + network (+ optional app for deploy / oke docker)
|
|
102
115
|
const base: Record<string, unknown> = {
|
|
103
116
|
name: `oke-${app}`,
|
|
104
|
-
networks: {
|
|
117
|
+
networks: {
|
|
118
|
+
oke: { driver: layout === "stack" ? "overlay" : "bridge" },
|
|
119
|
+
},
|
|
105
120
|
};
|
|
106
121
|
if (includeApp) {
|
|
107
122
|
// `image` + `build`: local compose builds and tags; Swarm stack deploy
|
|
@@ -113,10 +128,14 @@ export function emitComposeLayers(
|
|
|
113
128
|
base.services = {
|
|
114
129
|
app: {
|
|
115
130
|
image: `oke-${app}:latest`,
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
131
|
+
...(layout === "stack"
|
|
132
|
+
? {}
|
|
133
|
+
: {
|
|
134
|
+
build: {
|
|
135
|
+
context: paths.buildContext,
|
|
136
|
+
dockerfile: paths.dockerfile,
|
|
137
|
+
},
|
|
138
|
+
}),
|
|
120
139
|
...(hasProxy ? {} : { ports: [`${appPort}:${appPort}`] }),
|
|
121
140
|
env_file: [paths.envFile],
|
|
122
141
|
depends_on: Object.fromEntries(
|
|
@@ -127,9 +146,9 @@ export function emitComposeLayers(
|
|
|
127
146
|
};
|
|
128
147
|
}
|
|
129
148
|
mergeLayers.push(base);
|
|
130
|
-
files.push({ path: "compose.yml", content: `${toYaml(base)}\n` });
|
|
131
149
|
|
|
132
150
|
// Layer 2 — per-role
|
|
151
|
+
const roleDocs: { readonly role: string; readonly doc: Record<string, unknown> }[] = [];
|
|
133
152
|
for (const spec of specs) {
|
|
134
153
|
const recipe = recipeFor(spec.image, recipes);
|
|
135
154
|
const applied = recipe.apply(spec);
|
|
@@ -177,11 +196,11 @@ export function emitComposeLayers(
|
|
|
177
196
|
doc.volumes = namedVolumes;
|
|
178
197
|
}
|
|
179
198
|
mergeLayers.push(doc);
|
|
180
|
-
|
|
181
|
-
files.push({ path, content: `${toYaml(doc)}\n` });
|
|
199
|
+
roleDocs.push({ role: spec.role, doc });
|
|
182
200
|
}
|
|
183
201
|
|
|
184
|
-
// Layer 3 — prod overlay (
|
|
202
|
+
// Layer 3 — prod overlay (readiness + deploy policy; resources budgeted below)
|
|
203
|
+
let prodDoc: Record<string, unknown> | undefined;
|
|
185
204
|
if (options.prod) {
|
|
186
205
|
const prodServices: Record<string, unknown> = {};
|
|
187
206
|
if (includeApp) {
|
|
@@ -218,9 +237,6 @@ export function emitComposeLayers(
|
|
|
218
237
|
max_attempts: 3,
|
|
219
238
|
window: "120s",
|
|
220
239
|
},
|
|
221
|
-
resources: {
|
|
222
|
-
limits: { cpus: "1.0", memory: "512M" },
|
|
223
|
-
},
|
|
224
240
|
},
|
|
225
241
|
secrets: specs.flatMap((s) => secretNames(s)),
|
|
226
242
|
};
|
|
@@ -228,37 +244,117 @@ export function emitComposeLayers(
|
|
|
228
244
|
for (const spec of specs) {
|
|
229
245
|
prodServices[spec.serviceName] = {
|
|
230
246
|
deploy: {
|
|
231
|
-
|
|
232
|
-
|
|
247
|
+
restart_policy: {
|
|
248
|
+
condition: "on-failure",
|
|
249
|
+
delay: "5s",
|
|
250
|
+
max_attempts: 3,
|
|
251
|
+
window: "120s",
|
|
233
252
|
},
|
|
234
253
|
},
|
|
235
254
|
secrets: secretNames(spec),
|
|
236
255
|
};
|
|
237
256
|
}
|
|
238
|
-
|
|
257
|
+
prodDoc = { services: prodServices };
|
|
239
258
|
mergeLayers.push(prodDoc);
|
|
240
|
-
files.push({
|
|
241
|
-
path: "compose.prod.yml",
|
|
242
|
-
content: `${toYaml(prodDoc)}\n`,
|
|
243
|
-
});
|
|
244
259
|
}
|
|
245
260
|
|
|
246
|
-
// Additive single-file merge of layers 1–3 (not in `-f` order; no layer 4).
|
|
247
261
|
const merged = mergeLayers.reduce<Record<string, unknown>>(
|
|
248
262
|
(acc, layer) => deepMergeCompose(acc, layer),
|
|
249
263
|
{},
|
|
250
264
|
);
|
|
251
|
-
files.push({ path: COMPOSE_ALL, content: `${toYaml(merged)}\n` });
|
|
252
|
-
|
|
253
|
-
// Layer 4 — never written. Document merge order only.
|
|
254
|
-
const composeFiles = [
|
|
255
|
-
"compose.yml",
|
|
256
|
-
...specs.map((s) => `compose.${s.role}.yml`),
|
|
257
|
-
...(options.prod ? ["compose.prod.yml"] : []),
|
|
258
|
-
COMPOSE_OVERRIDE,
|
|
259
|
-
];
|
|
260
265
|
|
|
261
|
-
|
|
266
|
+
if (options.prod) {
|
|
267
|
+
applyResourceBudget(merged, {
|
|
268
|
+
cpus: options.serverCpus,
|
|
269
|
+
memoryGb: options.serverMemoryGb,
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
if (layout === "single") {
|
|
274
|
+
files.push({ path: DOCKER_COMPOSE, content: formatComposeYaml(merged) });
|
|
275
|
+
return {
|
|
276
|
+
files,
|
|
277
|
+
composeFiles: [DOCKER_COMPOSE, DOCKER_COMPOSE_OVERRIDE],
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
if (layout === "stack") {
|
|
282
|
+
files.push({ path: DOCKER_STACK, content: formatComposeYaml(merged) });
|
|
283
|
+
return {
|
|
284
|
+
files,
|
|
285
|
+
composeFiles: [DOCKER_STACK],
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// split — layered files + optional prod overlay; override never written
|
|
290
|
+
files.push({ path: COMPOSE_BASE, content: formatComposeYaml(base) });
|
|
291
|
+
for (const { role, doc } of roleDocs) {
|
|
292
|
+
files.push({ path: `compose.${role}.yml`, content: formatComposeYaml(doc) });
|
|
293
|
+
}
|
|
294
|
+
if (prodDoc) {
|
|
295
|
+
// Re-emit prod overlay with budgeted resources so `-f` merge matches single.
|
|
296
|
+
const budgetedProd = budgetProdOverlay(prodDoc, merged);
|
|
297
|
+
files.push({
|
|
298
|
+
path: "compose.prod.yml",
|
|
299
|
+
content: formatComposeYaml(budgetedProd),
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
return {
|
|
303
|
+
files,
|
|
304
|
+
composeFiles: [
|
|
305
|
+
COMPOSE_BASE,
|
|
306
|
+
...specs.map((s) => `compose.${s.role}.yml`),
|
|
307
|
+
...(prodDoc ? ["compose.prod.yml"] : []),
|
|
308
|
+
COMPOSE_OVERRIDE,
|
|
309
|
+
],
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
/**
|
|
314
|
+
* Write budgeted `deploy.resources` onto every service in a merged compose doc.
|
|
315
|
+
*
|
|
316
|
+
* @param doc - Merged compose document (mutated)
|
|
317
|
+
* @param budget - Host capacity
|
|
318
|
+
*/
|
|
319
|
+
function applyResourceBudget(doc: Record<string, unknown>, budget: Partial<ServerBudget>): void {
|
|
320
|
+
const services = doc.services;
|
|
321
|
+
if (!isPlainObject(services)) return;
|
|
322
|
+
const names = Object.keys(services);
|
|
323
|
+
const limits = allocateServiceResources(names, budget);
|
|
324
|
+
for (const name of names) {
|
|
325
|
+
const limit = limits.get(name);
|
|
326
|
+
if (!limit) continue;
|
|
327
|
+
const svc = services[name];
|
|
328
|
+
if (!isPlainObject(svc)) continue;
|
|
329
|
+
const existingDeploy = isPlainObject(svc.deploy) ? svc.deploy : undefined;
|
|
330
|
+
svc.deploy = mergeDeployResources(limit, existingDeploy);
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
/**
|
|
335
|
+
* Copy budgeted `deploy.resources` from the merged doc onto the prod overlay
|
|
336
|
+
* so split `-f` merges stay aligned with the single-file output.
|
|
337
|
+
*
|
|
338
|
+
* @param prodDoc - Prod overlay before budgeting
|
|
339
|
+
* @param merged - Fully merged (already budgeted) document
|
|
340
|
+
*/
|
|
341
|
+
function budgetProdOverlay(
|
|
342
|
+
prodDoc: Record<string, unknown>,
|
|
343
|
+
merged: Record<string, unknown>,
|
|
344
|
+
): Record<string, unknown> {
|
|
345
|
+
const out = deepMergeCompose({}, prodDoc);
|
|
346
|
+
const outServices = out.services;
|
|
347
|
+
const mergedServices = merged.services;
|
|
348
|
+
if (!isPlainObject(outServices) || !isPlainObject(mergedServices)) return out;
|
|
349
|
+
for (const [name, svc] of Object.entries(outServices)) {
|
|
350
|
+
if (!isPlainObject(svc)) continue;
|
|
351
|
+
const mergedSvc = mergedServices[name];
|
|
352
|
+
if (!isPlainObject(mergedSvc) || !isPlainObject(mergedSvc.deploy)) continue;
|
|
353
|
+
const mergedDeploy = mergedSvc.deploy;
|
|
354
|
+
const prevDeploy = isPlainObject(svc.deploy) ? svc.deploy : {};
|
|
355
|
+
svc.deploy = deepMergeCompose({ ...prevDeploy }, { ...mergedDeploy });
|
|
356
|
+
}
|
|
357
|
+
return out;
|
|
262
358
|
}
|
|
263
359
|
|
|
264
360
|
/**
|
|
@@ -359,15 +455,6 @@ export function buildStackEnv(
|
|
|
359
455
|
env.SMTP_HOST = host;
|
|
360
456
|
env.SMTP_PORT = String(spec.hostPort);
|
|
361
457
|
if (uiHost !== undefined) env.MAILPIT_UI_URL = `http://${host}:${uiHost}`;
|
|
362
|
-
} else if (spec.role === "vault") {
|
|
363
|
-
// Token is minted by OpenBao bootstrap and preserved via stack controls —
|
|
364
|
-
// never a generated password here.
|
|
365
|
-
env[`${prefix}_URL`] = url;
|
|
366
|
-
env.OKE_VAULT_URL = url;
|
|
367
|
-
if (controls.OKE_VAULT_TOKEN) {
|
|
368
|
-
env.OKE_VAULT_TOKEN = controls.OKE_VAULT_TOKEN;
|
|
369
|
-
env.OKE_VAULT_MOUNT = controls.OKE_VAULT_MOUNT ?? "secret";
|
|
370
|
-
}
|
|
371
458
|
} else if (spec.role === "store.index") {
|
|
372
459
|
// Meilisearch: standalone HTTP URL + the generated master key.
|
|
373
460
|
env[`${prefix}_URL`] = url;
|
|
@@ -419,11 +506,31 @@ const ROLE_SECTION_TITLE: Readonly<Record<string, string>> = {
|
|
|
419
506
|
"store.index": "store.index — search index",
|
|
420
507
|
"channel.email": "channel.email — Mailpit (SMTP + UI)",
|
|
421
508
|
signal: "signal — message bus",
|
|
422
|
-
vault: "vault — OpenBao",
|
|
423
509
|
ai: "ai — local inference (llama.cpp / Ollama / vLLM / SGLang)",
|
|
424
510
|
proxy: "proxy — TLS terminator (Caddy / Traefik)",
|
|
425
511
|
};
|
|
426
512
|
|
|
513
|
+
/**
|
|
514
|
+
* Serialise a compose mapping with section gaps and per-service comments.
|
|
515
|
+
*
|
|
516
|
+
* @param doc - Merged or layered compose document
|
|
517
|
+
*/
|
|
518
|
+
function formatComposeYaml(doc: Record<string, unknown>): string {
|
|
519
|
+
return composeToYaml(doc, { serviceComment: commentForComposeService });
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
/**
|
|
523
|
+
* Human-readable comment for a compose service key.
|
|
524
|
+
*
|
|
525
|
+
* @param serviceName - Compose service name (`store-sql`, `app`, …)
|
|
526
|
+
*/
|
|
527
|
+
function commentForComposeService(serviceName: string): string {
|
|
528
|
+
if (serviceName === "app") return "App — okengine runtime";
|
|
529
|
+
if (serviceName === "socket-proxy") return "Docker socket proxy (Traefik companion)";
|
|
530
|
+
const role = serviceName.replaceAll("-", ".");
|
|
531
|
+
return ROLE_SECTION_TITLE[role] ?? role;
|
|
532
|
+
}
|
|
533
|
+
|
|
427
534
|
/** Friendly aliases emitted beside their role block. */
|
|
428
535
|
const ROLE_ALIASES: Readonly<Record<string, readonly string[]>> = {
|
|
429
536
|
"store.sql": ["DATABASE_URL", "PGDATA", "POSTGRES_INITDB_ARGS"],
|
|
@@ -454,7 +561,6 @@ const ROLE_ALIASES: Readonly<Record<string, readonly string[]>> = {
|
|
|
454
561
|
// OKE_AI_URL is already emitted as `${prefix}_URL` — do not alias it again.
|
|
455
562
|
ai: ["OKE_AI_MODEL", "OKE_AI_CTX_SIZE"],
|
|
456
563
|
proxy: ["OKE_PROXY_HOST", "OKE_PROXY_ACME_EMAIL"],
|
|
457
|
-
vault: ["OKE_VAULT_TOKEN", "OKE_VAULT_MOUNT"],
|
|
458
564
|
"store.index": ["OKE_STORE_INDEX_KEY"],
|
|
459
565
|
};
|
|
460
566
|
|
|
@@ -474,7 +580,7 @@ const ROLE_CONTROL_EXAMPLES: Readonly<Record<string, readonly string[]>> = {
|
|
|
474
580
|
// OKE_AI_CTX_SIZE bounds the KV cache llama-server allocates at load —
|
|
475
581
|
// left at the model's full native context (often 32K-256K+), a small
|
|
476
582
|
// model's KV cache alone can OOM the container regardless of host RAM.
|
|
477
|
-
ai: ["OKE_AI_MODEL=
|
|
583
|
+
ai: ["OKE_AI_MODEL=granite3.3:2b", "OKE_AI_CTX_SIZE=4096"],
|
|
478
584
|
proxy: ["OKE_PROXY_HOST=localhost", "OKE_PROXY_ACME_EMAIL=admin@example.com"],
|
|
479
585
|
};
|
|
480
586
|
|
|
@@ -503,9 +609,6 @@ function roleFromEnvKey(key: string): string | undefined {
|
|
|
503
609
|
if (key === "OKE_PROXY_URL" || key === "OKE_PROXY_HOST" || key === "OKE_PROXY_ACME_EMAIL") {
|
|
504
610
|
return "proxy";
|
|
505
611
|
}
|
|
506
|
-
if (key === "OKE_VAULT_TOKEN" || key === "OKE_VAULT_MOUNT" || key === "OKE_VAULT_URL") {
|
|
507
|
-
return "vault";
|
|
508
|
-
}
|
|
509
612
|
if (key === "OKE_STORE_INDEX_KEY" || key === "OKE_STORE_INDEX_URL") return "store.index";
|
|
510
613
|
return undefined;
|
|
511
614
|
}
|
|
@@ -530,7 +633,7 @@ export function formatStackEnv(env: Readonly<Record<string, string>>): string {
|
|
|
530
633
|
"# Vault resolution: process.env → .env.local → docker/.env.docker → driver",
|
|
531
634
|
"#",
|
|
532
635
|
"# Re-run `oke dev --docker` to regenerate. Put compose tweaks in",
|
|
533
|
-
"# compose.override.yml — never put secrets in YAML.",
|
|
636
|
+
"# docker-compose.override.yml (or compose.override.yml for --split) — never put secrets in YAML.",
|
|
534
637
|
"",
|
|
535
638
|
];
|
|
536
639
|
|
package/src/docker/derive.ts
CHANGED
|
@@ -2,11 +2,14 @@
|
|
|
2
2
|
* Derive Dockerfile + compose files from config image pins.
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import { mkdirSync } from "node:fs";
|
|
5
|
+
import { mkdirSync, readdirSync, rmSync, statSync, unlinkSync } from "node:fs";
|
|
6
|
+
import { dirname, join } from "node:path";
|
|
6
7
|
import {
|
|
7
8
|
assertNoCredentialsInYaml,
|
|
8
9
|
buildSpecs,
|
|
9
10
|
buildStackEnv,
|
|
11
|
+
COMPOSE_OVERRIDE,
|
|
12
|
+
DOCKER_COMPOSE_OVERRIDE,
|
|
10
13
|
emitComposeLayers,
|
|
11
14
|
formatStackEnv,
|
|
12
15
|
} from "./compose.ts";
|
|
@@ -17,7 +20,7 @@ import {
|
|
|
17
20
|
LLAMA_CPP_ENTRYPOINT_FILE,
|
|
18
21
|
llamaCpp,
|
|
19
22
|
} from "./recipes/llama-cpp.ts";
|
|
20
|
-
import { buildPgDogToml, buildPgDogUsersToml } from "./recipes/pgdog.ts";
|
|
23
|
+
import { buildPgDogToml, buildPgDogUsersToml, PGDOG_CONFIG_DIR } from "./recipes/pgdog.ts";
|
|
21
24
|
import type { DeriveOptions, DeriveResult, GeneratedFile } from "./types.ts";
|
|
22
25
|
import { DEFAULT_DOCKER_DIR } from "./types.ts";
|
|
23
26
|
import { APP_PORT } from "../runtime/types.ts";
|
|
@@ -26,10 +29,10 @@ import { APP_PORT } from "../runtime/types.ts";
|
|
|
26
29
|
* Derive infrastructure files from normalised image pins.
|
|
27
30
|
*
|
|
28
31
|
* Credentials land only in the returned `stackEnv` (for `.env.docker`) and
|
|
29
|
-
* in `users.toml` when PgDog is present — never in generated YAML.
|
|
30
|
-
*
|
|
32
|
+
* in `pgdog/users.toml` when PgDog is present — never in generated YAML.
|
|
33
|
+
* User-owned overrides are listed in `composeFiles` but never written.
|
|
31
34
|
*
|
|
32
|
-
* @param options - Images / app / prod
|
|
35
|
+
* @param options - Images / app / prod / layout flags
|
|
33
36
|
*/
|
|
34
37
|
export function deriveInfrastructure(options: DeriveOptions): DeriveResult {
|
|
35
38
|
if (!options.images || Object.keys(options.images).length === 0) {
|
|
@@ -42,6 +45,7 @@ export function deriveInfrastructure(options: DeriveOptions): DeriveResult {
|
|
|
42
45
|
...options,
|
|
43
46
|
composeDir: options.composeDir ?? DEFAULT_DOCKER_DIR,
|
|
44
47
|
includeApp: options.includeApp !== false,
|
|
48
|
+
layout: options.layout ?? "single",
|
|
45
49
|
};
|
|
46
50
|
|
|
47
51
|
const specs = buildSpecs(normalised);
|
|
@@ -99,8 +103,8 @@ function llamaCppEntrypointFiles(specs: DeriveResult["specs"]): GeneratedFile[]
|
|
|
99
103
|
/**
|
|
100
104
|
* Emit PgDog TOML configs when both `pgdog` and `store.sql` are in the stack.
|
|
101
105
|
*
|
|
102
|
-
* `pgdog.toml` has no secrets; `users.toml` mirrors store.sql
|
|
103
|
-
* (same trust boundary as `.env.docker` — do not commit).
|
|
106
|
+
* `pgdog/pgdog.toml` has no secrets; `pgdog/users.toml` mirrors store.sql
|
|
107
|
+
* credentials (same trust boundary as `.env.docker` — do not commit).
|
|
104
108
|
*
|
|
105
109
|
* @param specs - Normalised services
|
|
106
110
|
*/
|
|
@@ -110,14 +114,14 @@ function pgdogConfigFiles(specs: DeriveResult["specs"]): GeneratedFile[] {
|
|
|
110
114
|
if (!sql || !pooler) return [];
|
|
111
115
|
return [
|
|
112
116
|
{
|
|
113
|
-
path:
|
|
117
|
+
path: `${PGDOG_CONFIG_DIR}/pgdog.toml`,
|
|
114
118
|
content: buildPgDogToml({
|
|
115
119
|
database: sql.credentials.database,
|
|
116
120
|
postgresPort: sql.port,
|
|
117
121
|
}),
|
|
118
122
|
},
|
|
119
123
|
{
|
|
120
|
-
path:
|
|
124
|
+
path: `${PGDOG_CONFIG_DIR}/users.toml`,
|
|
121
125
|
content: buildPgDogUsersToml({
|
|
122
126
|
user: sql.credentials.user,
|
|
123
127
|
password: sql.credentials.password,
|
|
@@ -149,8 +153,9 @@ function proxyConfigFiles(
|
|
|
149
153
|
}
|
|
150
154
|
|
|
151
155
|
/**
|
|
152
|
-
* Write derived files to disk. Never writes
|
|
153
|
-
*
|
|
156
|
+
* Write derived files to disk. Never writes user overrides or credential
|
|
157
|
+
* values into YAML. Prunes stale generated compose / PgDog artefacts from a
|
|
158
|
+
* previous layout. Optionally writes `docker/.env.docker`.
|
|
154
159
|
*
|
|
155
160
|
* @param result - Derive result
|
|
156
161
|
* @param outDir - Destination for Dockerfile / compose (usually `docker/`)
|
|
@@ -166,8 +171,11 @@ export async function writeDerivedFiles(
|
|
|
166
171
|
const written: string[] = [];
|
|
167
172
|
const root = outDir.replace(/\/$/, "");
|
|
168
173
|
mkdirSync(root, { recursive: true });
|
|
174
|
+
const keep = new Set(result.files.map((f) => f.path));
|
|
175
|
+
pruneStaleGenerated(root, keep);
|
|
169
176
|
for (const file of result.files) {
|
|
170
|
-
const path =
|
|
177
|
+
const path = join(root, file.path);
|
|
178
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
171
179
|
await Bun.write(path, file.content);
|
|
172
180
|
written.push(path);
|
|
173
181
|
}
|
|
@@ -178,3 +186,89 @@ export async function writeDerivedFiles(
|
|
|
178
186
|
}
|
|
179
187
|
return written;
|
|
180
188
|
}
|
|
189
|
+
|
|
190
|
+
/** Generated compose / companion paths safe to delete when absent from a derive. */
|
|
191
|
+
const PRUNE_ROOT_FILES = new Set([
|
|
192
|
+
"Dockerfile",
|
|
193
|
+
"docker-compose.yml",
|
|
194
|
+
"docker-stack.yml",
|
|
195
|
+
"compose.yml",
|
|
196
|
+
"compose.all.yml",
|
|
197
|
+
"compose.prod.yml",
|
|
198
|
+
"Caddyfile",
|
|
199
|
+
LLAMA_CPP_ENTRYPOINT_FILE,
|
|
200
|
+
"pgdog.toml",
|
|
201
|
+
"users.toml",
|
|
202
|
+
]);
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Remove previously generated artefacts that the current layout no longer emits.
|
|
206
|
+
* Never touches user overrides or `.env.docker`.
|
|
207
|
+
*
|
|
208
|
+
* @param root - Compose directory
|
|
209
|
+
* @param keep - Relative paths that will be rewritten
|
|
210
|
+
*/
|
|
211
|
+
function pruneStaleGenerated(root: string, keep: ReadonlySet<string>): void {
|
|
212
|
+
let entries: string[];
|
|
213
|
+
try {
|
|
214
|
+
entries = readdirSync(root);
|
|
215
|
+
} catch {
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
for (const name of entries) {
|
|
219
|
+
if (name === COMPOSE_OVERRIDE || name === DOCKER_COMPOSE_OVERRIDE) continue;
|
|
220
|
+
if (name === ".env.docker") continue;
|
|
221
|
+
const abs = join(root, name);
|
|
222
|
+
let st: ReturnType<typeof statSync>;
|
|
223
|
+
try {
|
|
224
|
+
st = statSync(abs);
|
|
225
|
+
} catch {
|
|
226
|
+
continue;
|
|
227
|
+
}
|
|
228
|
+
if (st.isDirectory()) {
|
|
229
|
+
if (name === PGDOG_CONFIG_DIR) {
|
|
230
|
+
prunePgDogDir(abs, keep);
|
|
231
|
+
}
|
|
232
|
+
continue;
|
|
233
|
+
}
|
|
234
|
+
if (!st.isFile()) continue;
|
|
235
|
+
const rel = name;
|
|
236
|
+
if (keep.has(rel)) continue;
|
|
237
|
+
if (PRUNE_ROOT_FILES.has(name) || /^compose\..+\.yml$/.test(name)) {
|
|
238
|
+
try {
|
|
239
|
+
unlinkSync(abs);
|
|
240
|
+
} catch {
|
|
241
|
+
// best-effort
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Drop legacy / unused files under `pgdog/`.
|
|
249
|
+
*
|
|
250
|
+
* @param dir - Absolute `pgdog/` path
|
|
251
|
+
* @param keep - Relative keep set (`pgdog/…`)
|
|
252
|
+
*/
|
|
253
|
+
function prunePgDogDir(dir: string, keep: ReadonlySet<string>): void {
|
|
254
|
+
let entries: string[];
|
|
255
|
+
try {
|
|
256
|
+
entries = readdirSync(dir);
|
|
257
|
+
} catch {
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
260
|
+
for (const name of entries) {
|
|
261
|
+
const rel = `${PGDOG_CONFIG_DIR}/${name}`;
|
|
262
|
+
if (keep.has(rel)) continue;
|
|
263
|
+
try {
|
|
264
|
+
unlinkSync(join(dir, name));
|
|
265
|
+
} catch {
|
|
266
|
+
// best-effort
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
try {
|
|
270
|
+
if (readdirSync(dir).length === 0) rmSync(dir, { recursive: true, force: true });
|
|
271
|
+
} catch {
|
|
272
|
+
// best-effort
|
|
273
|
+
}
|
|
274
|
+
}
|