|
| 1 | +import { |
| 2 | +cloneEnvWithPlatformSemantics, |
| 3 | +createConfigRuntimeEnv, |
| 4 | +} from "../../config/config-env-vars.js"; |
| 5 | +import { |
| 6 | +ALLOW_OLDER_BINARY_DESTRUCTIVE_ACTIONS_ENV, |
| 7 | +formatFutureConfigActionBlock, |
| 8 | +resolveFutureConfigActionBlock, |
| 9 | +} from "../../config/future-version-guard.js"; |
| 10 | +// Gateway-specific future-config actions shared by pre-bootstrap and runtime startup. |
| 11 | +import type { ConfigFileSnapshot, OpenClawConfig } from "../../config/types.js"; |
| 12 | +import type { RuntimeEnv } from "../../runtime.js"; |
| 13 | +import type { GatewayRunOpts } from "./run-options.js"; |
| 14 | + |
| 15 | +export type GatewayRunPreBootstrapOptions = Pick<GatewayRunOpts, "force" | "reset">; |
| 16 | + |
| 17 | +type GatewayRunFutureConfigGuardParams = { |
| 18 | +opts: GatewayRunPreBootstrapOptions; |
| 19 | +snapshot?: ConfigFileSnapshot | null; |
| 20 | +config?: Pick<OpenClawConfig, "env" | "meta"> | null; |
| 21 | +}; |
| 22 | + |
| 23 | +function resolveGatewayRunFutureConfigBlock(params: GatewayRunFutureConfigGuardParams) { |
| 24 | +const processServiceMode = Boolean(process.env.OPENCLAW_SERVICE_MARKER?.trim()); |
| 25 | +const candidateConfig = |
| 26 | +params.config ?? |
| 27 | +(params.snapshot?.valid ? (params.snapshot.sourceConfig ?? params.snapshot.config) : undefined); |
| 28 | +const candidateServiceMode = |
| 29 | +!params.opts.reset && |
| 30 | +Boolean( |
| 31 | +candidateConfig |
| 32 | + ? createConfigRuntimeEnv(candidateConfig, process.env).OPENCLAW_SERVICE_MARKER?.trim() |
| 33 | + : undefined, |
| 34 | +); |
| 35 | +const serviceMode = processServiceMode || candidateServiceMode; |
| 36 | +// Reset runs before service/force startup, while ordinary startup now runs state migrations. |
| 37 | +const futureAction = params.opts.reset |
| 38 | + ? { action: "reset the dev gateway state", exitCode: 1 } |
| 39 | + : serviceMode |
| 40 | + ? { action: "start the gateway service", exitCode: 78 } |
| 41 | + : params.opts.force |
| 42 | + ? { action: "force-kill gateway port listeners", exitCode: 1 } |
| 43 | + : { action: "run automatic gateway startup migrations", exitCode: 1 }; |
| 44 | +const guardEnv = serviceMode ? cloneEnvWithPlatformSemantics(process.env) : process.env; |
| 45 | +if (serviceMode) { |
| 46 | +delete guardEnv[ALLOW_OLDER_BINARY_DESTRUCTIVE_ACTIONS_ENV]; |
| 47 | +} |
| 48 | +const block = resolveFutureConfigActionBlock({ |
| 49 | +action: futureAction.action, |
| 50 | +snapshot: params.snapshot, |
| 51 | +config: params.config, |
| 52 | +env: guardEnv, |
| 53 | +}); |
| 54 | +return block ? { block, exitCode: futureAction.exitCode, serviceMode } : null; |
| 55 | +} |
| 56 | + |
| 57 | +export function isGatewayRunFutureConfigAllowed( |
| 58 | +params: GatewayRunFutureConfigGuardParams, |
| 59 | +): boolean { |
| 60 | +return resolveGatewayRunFutureConfigBlock(params) === null; |
| 61 | +} |
| 62 | + |
| 63 | +export function enforceGatewayRunFutureConfigGuard( |
| 64 | +params: GatewayRunFutureConfigGuardParams & { runtime: RuntimeEnv }, |
| 65 | +): boolean { |
| 66 | +const resolved = resolveGatewayRunFutureConfigBlock(params); |
| 67 | +if (!resolved) { |
| 68 | +return true; |
| 69 | +} |
| 70 | +if (resolved.serviceMode) { |
| 71 | +delete process.env[ALLOW_OLDER_BINARY_DESTRUCTIVE_ACTIONS_ENV]; |
| 72 | +} |
| 73 | +params.runtime.error(formatFutureConfigActionBlock(resolved.block)); |
| 74 | +params.runtime.exit(resolved.exitCode); |
| 75 | +return false; |
| 76 | +} |