UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

2,129 lines • 71.1 kB
import path from "node:path";
import os from "node:os";
import { AsyncLocalStorage, AsyncResource } from "node:async_hooks";
import fs from "node:fs";
import { readRegularFileSync } from "@openclaw/fs-safe/advanced";
import { parse } from "dotenv";
import { compareBuild, parse as parse$1 } from "semver";
import "@openclaw/fs-safe/path";
//#region packages/normalization-core/src/string-coerce.ts
/** Trims string input and returns null for non-strings or empty strings. */
function normalizeNullableString(value) {
	if (typeof value !== "string") return null;
	const trimmed = value.trim();
	return trimmed ? trimmed : null;
}
/** Trims string input and returns undefined for non-strings or empty strings. */
function normalizeOptionalString(value) {
	return normalizeNullableString(value) ?? void 0;
}
/** Lowercases a normalized optional string. */
function normalizeOptionalLowercaseString(value) {
	return normalizeOptionalString(value)?.toLowerCase();
}
/** Lowercases a normalized string or returns an empty string when absent. */
function normalizeLowercaseStringOrEmpty(value) {
	return normalizeOptionalLowercaseString(value) ?? "";
}
//#endregion
//#region src/daemon/constants.ts
/** Cross-platform daemon service names, labels, and profile-aware descriptions. */
const GATEWAY_LAUNCH_AGENT_LABEL = "ai.openclaw.gateway";
const GATEWAY_SYSTEMD_SERVICE_NAME = "openclaw-gateway";
const GATEWAY_WINDOWS_TASK_NAME = "OpenClaw Gateway";
const GATEWAY_SERVICE_SELECTOR_ENV_KEYS = [
	"OPENCLAW_STATE_DIR",
	"OPENCLAW_CONFIG_PATH",
	"OPENCLAW_PROFILE",
	"OPENCLAW_GATEWAY_PORT",
	"OPENCLAW_LAUNCHD_LABEL",
	"OPENCLAW_SYSTEMD_UNIT",
	"OPENCLAW_WINDOWS_TASK_NAME"
];
function isGatewayServiceEnv(env) {
	if (env.OPENCLAW_SERVICE_MARKER?.trim() !== "openclaw") return false;
	const serviceKind = env.OPENCLAW_SERVICE_KIND?.trim();
	return !serviceKind || serviceKind === "gateway";
}
function normalizeGatewayProfile(profile) {
	const trimmed = profile?.trim();
	if (!trimmed || normalizeLowercaseStringOrEmpty(trimmed) === "default") return null;
	return trimmed;
}
function resolveGatewayProfileSuffix(profile) {
	const normalized = normalizeGatewayProfile(profile);
	return normalized ? `-${normalized}` : "";
}
function resolveGatewayLaunchAgentLabel(profile) {
	const normalized = normalizeGatewayProfile(profile);
	if (!normalized) return GATEWAY_LAUNCH_AGENT_LABEL;
	return `ai.openclaw.${normalized}`;
}
function resolveGatewaySystemdServiceName(profile) {
	return `${GATEWAY_SYSTEMD_SERVICE_NAME}${resolveGatewayProfileSuffix(profile)}`;
}
function resolveGatewayWindowsTaskName(profile) {
	const normalized = normalizeGatewayProfile(profile);
	if (!normalized) return GATEWAY_WINDOWS_TASK_NAME;
	return `OpenClaw Gateway (${normalized})`;
}
//#endregion
//#region packages/normalization-core/src/home-dir.ts
function normalizeHomeDirValue(value) {
	const trimmed = value?.trim();
	return trimmed && trimmed !== "undefined" && trimmed !== "null" ? trimmed : void 0;
}
function normalizeSafe(homedir) {
	try {
		return normalizeHomeDirValue(homedir());
	} catch {
		return;
	}
}
function resolveTermuxHome(env) {
	const prefix = normalizeHomeDirValue(env.PREFIX);
	if (!prefix || !normalizeHomeDirValue(env.ANDROID_DATA)) return;
	if (!/(?:^|\/)com\.termux\/files\/usr\/?$/u.test(prefix.replace(/\\/gu, "/"))) return;
	return path.resolve(prefix, "..", "home");
}
function resolveRawOsHomeDir(env, homedir) {
	return normalizeHomeDirValue(env.HOME) ?? normalizeHomeDirValue(env.USERPROFILE) ?? resolveTermuxHome(env) ?? normalizeSafe(homedir);
}
function resolveOsHomeDir(env = process.env, homedir = os.homedir) {
	const raw = resolveRawOsHomeDir(env, homedir);
	return raw ? path.resolve(raw) : void 0;
}
function resolveEffectiveHomeDir(env = process.env, homedir = os.homedir, options) {
	const explicitHome = normalizeHomeDirValue(env.OPENCLAW_HOME);
	if (!explicitHome) return resolveOsHomeDir(env, homedir);
	if (explicitHome === "~" || explicitHome.startsWith("~/") || explicitHome.startsWith("~\\")) {
		const osHome = resolveRawOsHomeDir(env, homedir);
		if (!osHome) return options?.preserveUnresolvedTilde ? path.resolve(explicitHome) : void 0;
		return path.resolve(explicitHome.replace(/^~(?=$|[\\/])/, () => osHome));
	}
	return path.resolve(explicitHome);
}
//#endregion
//#region src/shared/global-singleton.ts
/**
* Process-local singleton helpers for registries, caches, and SDK-visible shared state.
* Keys must be symbols so unrelated modules cannot collide on `globalThis` property names.
*/
const GLOBAL_SINGLETON_RESETS_KEY = Symbol.for("openclaw.globalSingletonLifecycleResets");
function resolveGlobalSingletonResetRegistry() {
	const globalStore = globalThis;
	const existing = globalStore[GLOBAL_SINGLETON_RESETS_KEY];
	if (existing instanceof Map) return existing;
	const created = /* @__PURE__ */ new Map();
	globalStore[GLOBAL_SINGLETON_RESETS_KEY] = created;
	return created;
}
/** Resolves a process-local singleton for caches and registries that tolerate helper lookup. */
function resolveGlobalSingleton(key, create, reset, lifecycle = "close-and-restart") {
	const globalStore = globalThis;
	let value;
	if (Object.hasOwn(globalStore, key)) value = globalStore[key];
	else {
		value = create();
		globalStore[key] = value;
	}
	if (reset) resolveGlobalSingletonResetRegistry().set(key, {
		lifecycle,
		reset: () => reset(value)
	});
	return value;
}
//#endregion
//#region src/infra/safe-cwd.ts
function tryProcessCwd() {
	try {
		return process.cwd();
	} catch {
		return;
	}
}
//#endregion
//#region src/infra/home-dir.ts
const userPathBaseDirectory = resolveGlobalSingleton(Symbol.for("openclaw.userPathBaseDirectory"), () => new AsyncLocalStorage());
/** Resolves the effective home or falls back to cwd when no home source exists. */
function resolveRequiredHomeDir(env = process.env, homedir = os.homedir) {
	const resolved = resolveEffectiveHomeDir(env, homedir) ?? tryProcessCwd();
	if (resolved) return path.resolve(resolved);
	throw new Error("Unable to resolve an OpenClaw home: set OPENCLAW_HOME, HOME, or USERPROFILE, or run from an existing directory.");
}
/** Expands leading `~`, `~/`, or `~\` with the effective home when one is known. */
function expandHomePrefix(input, opts) {
	if (!input.startsWith("~")) return input;
	const home = normalizeHomeDirValue(opts?.home) ?? resolveEffectiveHomeDir(opts?.env ?? process.env, opts?.homedir ?? os.homedir);
	if (!home) return input;
	return input.replace(/^~(?=$|[\\/])/, () => home);
}
function resolvePathWithHome(input, opts, resolveHome) {
	const trimmed = input.trim();
	if (!trimmed) return trimmed;
	const expanded = trimmed.startsWith("~") ? expandHomePrefix(trimmed, {
		home: resolveHome(opts?.env ?? process.env, opts?.homedir ?? os.homedir),
		env: opts?.env,
		homedir: opts?.homedir
	}) : trimmed;
	const base = userPathBaseDirectory.getStore();
	return base ? path.resolve(base, expanded) : path.resolve(expanded);
}
/** Resolves a user-supplied path after trimming and expanding against the effective home. */
function resolveHomeRelativePath(input, opts) {
	return resolvePathWithHome(input, opts, resolveRequiredHomeDir);
}
/** Resolves a user path against the effective home, preserving an empty input. */
function resolveUserPath(input, env = process.env, homedir = os.homedir) {
	if (!input) return "";
	return resolveHomeRelativePath(input, {
		env,
		homedir
	});
}
//#endregion
//#region src/claws/experimental.ts
const EXPERIMENTAL_CLAWS_ENV = "OPENCLAW_EXPERIMENTAL_CLAWS";
function isExperimentalClawsEnabled(env = process.env) {
	const value = env[EXPERIMENTAL_CLAWS_ENV]?.trim().toLowerCase();
	return value === "1" || value === "true";
}
[.../* @__PURE__ */ new Set([
	"-r",
	"--preload",
	"--require",
	"--import",
	"--loader",
	"--experimental-loader",
	"--test-reporter",
	"--test-global-setup"
])];
const ROOT_BOOLEAN_FLAGS = /* @__PURE__ */ new Set(["--dev", "--no-color"]);
const ROOT_VALUE_FLAGS = /* @__PURE__ */ new Set([
	"--profile",
	"--log-level",
	"--container"
]);
/** Returns whether a token can be consumed as a root option value. */
function isValueToken(arg) {
	if (!arg || arg === "--") return false;
	if (!arg.startsWith("-")) return true;
	return /^-\d+(?:\.\d+)?$/.test(arg);
}
/** Count root-option tokens conservatively for route matching. */
function consumeRootOptionToken(args, index) {
	const arg = args[index];
	if (!arg) return 0;
	if (ROOT_BOOLEAN_FLAGS.has(arg)) return 1;
	if (arg.startsWith("--profile=") || arg.startsWith("--log-level=") || arg.startsWith("--container=")) return 1;
	if (ROOT_VALUE_FLAGS.has(arg)) return isValueToken(args[index + 1]) ? 2 : 1;
	return 0;
}
/** Consume required root values by their Commander role before startup policy is selected. */
function consumeRootCommandOptionToken(args, index) {
	return consumeKnownOptionToken(args, index, ROOT_BOOLEAN_FLAGS, ROOT_VALUE_FLAGS, "command-path");
}
/** Read positional command tokens while accepting root options at any pre-terminator position. */
function getRootOptionAwareCommandPath(argv, depth) {
	const args = argv.slice(2);
	const path = [];
	let literal = false;
	for (let index = 0; index < args.length; index += 1) {
		const arg = args[index];
		if (!arg) break;
		if (!literal && arg === "--") {
			if (path.length > 0) break;
			literal = true;
			continue;
		}
		const consumed = literal ? 0 : consumeRootCommandOptionToken(args, index);
		if (consumed > 0) {
			index += consumed - 1;
			continue;
		}
		if (!literal && arg.startsWith("-")) continue;
		path.push(arg);
		if (path.length >= depth) break;
	}
	return path;
}
function consumeKnownOptionToken(args, index, booleanFlags, valueFlags, mode) {
	const arg = args[index];
	if (!arg || arg === "--" || !arg.startsWith("-")) return 0;
	const equalsIndex = arg.indexOf("=");
	const flag = equalsIndex === -1 ? arg : arg.slice(0, equalsIndex);
	if (booleanFlags.has(flag)) return equalsIndex === -1 ? 1 : 0;
	if (!valueFlags.has(flag)) return 0;
	if (equalsIndex !== -1) return mode === "command-path" || arg.slice(equalsIndex + 1).trim() ? 1 : 0;
	if (mode === "command-path") return args[index + 1] !== void 0 ? 2 : 0;
	return isValueToken(args[index + 1]) ? 2 : 0;
}
/** Parse command positionals while consuming known root and command options. */
function getCommandPositionalsWithRootOptions(argv, options) {
	return parseCommandArgsWithRootOptions(argv, options, false);
}
function parseCommandArgsWithRootOptions(argv, options, returnTail, returnOptions = false) {
	const args = argv.slice(2);
	const booleanFlags = new Set(options.booleanFlags ?? []);
	const valueFlags = new Set(options.valueFlags ?? []);
	const positionals = [];
	const rootOptions = [];
	const commandOptions = [];
	let commandIndex = 0;
	let literal = false;
	for (let index = 0; index < args.length; index += 1) {
		const arg = args[index];
		if (arg === void 0) break;
		if (!literal && arg === "--") {
			if (options.mode !== "command-path") break;
			literal = true;
			continue;
		}
		const rootConsumed = literal ? 0 : options.mode === "command-path" ? consumeRootCommandOptionToken(args, index) : consumeRootOptionToken(args, index);
		if (rootConsumed > 0) {
			(commandIndex > 0 && booleanFlags.has(arg) ? commandOptions : rootOptions).push(...args.slice(index, index + rootConsumed));
			index += rootConsumed - 1;
			continue;
		}
		if (!literal && arg.startsWith("-")) {
			const optionConsumed = consumeKnownOptionToken(args, index, booleanFlags, valueFlags, options.mode);
			if (optionConsumed === 0 || commandIndex === 0) return null;
			commandOptions.push(arg);
			index += optionConsumed - 1;
			continue;
		}
		if (commandIndex < options.commandPath.length) {
			if (arg !== options.commandPath[commandIndex]) return null;
			commandIndex += 1;
			if (returnTail && commandIndex === options.commandPath.length) {
				const tail = args.slice(index + 1);
				return literal ? ["--", ...tail] : tail;
			}
			continue;
		}
		positionals.push(arg);
		if (!returnOptions && positionals.length === options.maxPositionals) return positionals;
	}
	return commandIndex < options.commandPath.length ? null : returnOptions ? {
		rootOptions,
		commandOptions
	} : positionals;
}
//#endregion
//#region src/cli/update-option-specs.ts
const UPDATE_OPTION_SPECS = [
	[
		"--json",
		"Output result as JSON",
		false
	],
	["--no-restart", "Skip restarting the gateway service after a successful update"],
	[
		"--dry-run",
		"Preview update actions without making changes",
		false
	],
	["--admission <auto|installed>", "Select candidate or installed admission checks (default: auto)"],
	["--channel <stable|extended-stable|beta|dev>", "Persist update channel (git + npm)"],
	["--tag <dist-tag|version|spec>", "Override the package target for this update (dist-tag, version, or package spec)"],
	["--timeout <seconds>", "Set a per-step deadline in seconds"],
	["--drain-timeout <seconds>", "Set the immutable activation drain budget before interruption"],
	["--sha <commit>", "Prepare an exact official commit for an adopted immutable installation"],
	[
		"--yes",
		"Skip confirmation prompts (non-interactive)",
		false
	],
	[
		"--reapply-local-overrides",
		"Replay trusted packaged dist edits when the target baseline is unchanged",
		false
	],
	[
		"--accept-capabilities",
		"Accept widened plugin capabilities",
		false
	]
];
//#endregion
//#region src/cli/parent-command-path.ts
const AGENT_PARENT_BOOLEAN_FLAGS = [
	"--local",
	"--deliver",
	"--json"
];
const AGENT_PARENT_VALUE_FLAGS = [
	"-m",
	"--message",
	"--message-file",
	"-t",
	"--to",
	"--session-key",
	"--session-id",
	"--agent",
	"--model",
	"--thinking",
	"--verbose",
	"--channel",
	"--reply-to",
	"--reply-channel",
	"--reply-account",
	"--timeout"
];
const MODELS_PARENT_BOOLEAN_FLAGS = [
	"--json",
	"--status-json",
	"--status-plain"
];
const MODELS_PARENT_VALUE_FLAGS = ["--agent"];
const UPDATE_PARENT_BOOLEAN_FLAGS = UPDATE_OPTION_SPECS.filter(([flags]) => !flags.includes("<")).map(([flags]) => flags);
const UPDATE_PARENT_VALUE_FLAGS = UPDATE_OPTION_SPECS.filter(([flags]) => flags.includes("<")).map(([flags]) => flags.slice(0, flags.indexOf(" ")));
const PARENT_COMMAND_FLAGS = /* @__PURE__ */ new Map([
	["agent", [AGENT_PARENT_BOOLEAN_FLAGS, AGENT_PARENT_VALUE_FLAGS]],
	["models", [MODELS_PARENT_BOOLEAN_FLAGS, MODELS_PARENT_VALUE_FLAGS]],
	["config", [[], ["--section"]]],
	["skills", [["--json"], ["--agent"]]],
	["channels", [[], ["--agent"]]],
	["update", [UPDATE_PARENT_BOOLEAN_FLAGS, UPDATE_PARENT_VALUE_FLAGS]]
]);
/** Resolve the parent commands whose options may precede a child command. */
function resolveCliParentCommandPath(argv, expectedParent) {
	const [command] = getRootOptionAwareCommandPath(argv, 1);
	if (!command || expectedParent && command !== expectedParent) return null;
	const flags = PARENT_COMMAND_FLAGS.get(command);
	if (!flags) return null;
	const [booleanFlags, valueFlags] = flags;
	const child = getCommandPositionalsWithRootOptions(argv, {
		commandPath: [command],
		booleanFlags,
		valueFlags,
		maxPositionals: 1,
		mode: "command-path"
	})?.[0];
	return child ? [command, child] : [command];
}
//#endregion
//#region src/cli/config-output-mode.ts
/** Config values, paths, and schemas reserve stdout for machine-consumed output. */
function isConfigMachineOutput(argv) {
	const subcommand = resolveCliParentCommandPath(argv, "config")?.[1];
	return subcommand === "get" || subcommand === "file" || subcommand === "schema";
}
//#endregion
//#region src/cli/program/command-tree.ts
function getCommandHierarchy(command) {
	const hierarchy = [];
	for (let current = command; current; current = current.parent ?? null) hierarchy.unshift(current);
	return hierarchy;
}
//#endregion
//#region src/cli/program/commander-parse-facts.ts
function requiresFollowingValue(token, options) {
	if (token.includes("=")) return false;
	const exact = options.find((option) => option.short === token || option.long === token);
	if (exact) return exact.required;
	if (!token.startsWith("-") || token.startsWith("--")) return false;
	const shortGroup = token.slice(1);
	for (let index = 0; index < shortGroup.length; index += 1) {
		const option = options.find((candidate) => candidate.short === `-${shortGroup[index]}`);
		if (!option) return false;
		if (option.required || option.optional) return option.required && index === shortGroup.length - 1;
	}
	return false;
}
/** Match an argv token in its actual Commander role rather than its spelling alone. */
function hasCommanderOptionToken(command, argv, tokens, kind) {
	const hierarchy = getCommandHierarchy(command);
	const args = argv.slice(2);
	let commandIndex = 0;
	for (let index = 0; index < args.length; index += 1) {
		const arg = args[index];
		if (arg === void 0 || arg === "--") break;
		const nextCommand = hierarchy[commandIndex + 1];
		if (nextCommand && (arg === nextCommand.name() || nextCommand.aliases().includes(arg))) {
			commandIndex += 1;
			continue;
		}
		if (requiresFollowingValue(arg, hierarchy[commandIndex]?.options ?? [])) {
			const value = args[index + 1];
			if (kind === "value" && value && tokens.has(value)) return true;
			index += 1;
			continue;
		}
		if (kind === "flag" && tokens.has(arg.split("=")[0] ?? arg)) return true;
	}
	return false;
}
//#endregion
//#region src/cli/machine-output-argv.ts
/** Prefer registered option roles; early discovery falls back to literal option spellings. */
function hasMachineOutputOption(argv, flag, command) {
	if (command) return hasCommanderOptionToken(command, argv, /* @__PURE__ */ new Set([flag]), "flag");
	for (const arg of argv.slice(2)) {
		if (arg === "--") return false;
		if (arg === flag || arg.startsWith(`${flag}=`)) return true;
	}
	return false;
}
//#endregion
//#region src/cli/doctor-output-mode.ts
/** Bare doctor JSON and non-TTY lint runs own machine-readable stdout. */
function isDoctorMachineOutput(params) {
	if (hasMachineOutputOption(params.argv, "--lint")) return hasMachineOutputOption(params.argv, "--json") || !params.stdoutIsTTY;
	const existingMachineMode = hasMachineOutputOption(params.argv, "--post-upgrade") || hasMachineOutputOption(params.argv, "--state-sqlite") || hasMachineOutputOption(params.argv, "--session-sqlite");
	return hasMachineOutputOption(params.argv, "--json") && !existingMachineMode;
}
//#endregion
//#region src/cli/program/core-command-descriptors.ts
const CORE_CLI_COMMAND_DESCRIPTORS = [
	{
		name: "setup",
		description: "Chat with OpenClaw; onboard when setup is incomplete",
		hasSubcommands: false
	},
	{
		name: "crestodian",
		description: "Deprecated: use openclaw setup",
		hasSubcommands: false,
		hidden: true
	},
	{
		name: "onboard",
		description: "Guided setup for auth, models, Gateway, workspace, channels, and skills",
		hasSubcommands: true
	},
	{
		name: "configure",
		description: "Interactive configuration for credentials, channels, gateway, and agent defaults",
		hasSubcommands: false
	},
	{
		name: "config",
		description: "Non-interactive config helpers (get/set/patch/unset/file/schema/validate). Run without subcommand for guided setup.",
		hasSubcommands: true,
		machineOutput: ({ argv }) => isConfigMachineOutput(argv)
	},
	{
		name: "claws",
		description: "Inspect and add experimental OpenClaw Claws",
		hasSubcommands: true,
		parentDefaultHelp: true
	},
	{
		name: "backup",
		description: "Create, verify, and restore backup archives and SQLite snapshots",
		hasSubcommands: true
	},
	{
		name: "database",
		description: "Inspect database schema compatibility and shared-state write ownership",
		hasSubcommands: true,
		parentDefaultHelp: true
	},
	{
		name: "migrate",
		description: "Import state from another agent system",
		hasSubcommands: true
	},
	{
		name: "storage",
		description: "List, initialize, and test configured storage locations",
		hasSubcommands: true,
		parentDefaultHelp: true,
		machineOutput: ({ argv }) => hasMachineOutputOption(argv, "--json")
	},
	{
		name: "doctor",
		description: "Health checks + quick fixes for the gateway and channels",
		hasSubcommands: false,
		machineOutput: isDoctorMachineOutput
	},
	{
		name: "triage",
		description: "Collect sanitized diagnostics and open a local coding agent for repair",
		hasSubcommands: false,
		machineOutput: ({ argv }) => hasMachineOutputOption(argv, "--json")
	},
	{
		name: "dashboard",
		description: "Open the Control UI with your current token",
		hasSubcommands: false
	},
	{
		name: "reset",
		description: "Reset local config/state (keeps the CLI installed)",
		hasSubcommands: false
	},
	{
		name: "uninstall",
		description: "Uninstall the gateway service + local data",
		hasSubcommands: false
	},
	{
		name: "message",
		description: "Send, read, and manage messages and channel actions",
		hasSubcommands: true
	},
	{
		name: "mcp",
		description: "Manage OpenClaw mcp.servers config and channel bridge",
		hasSubcommands: true,
		parentDefaultHelp: true
	},
	{
		name: "transcripts",
		description: "Inspect stored transcripts",
		hasSubcommands: true
	},
	{
		name: "agent",
		description: "Run an agent turn via the Gateway (use --local for embedded)",
		hasSubcommands: true
	},
	{
		name: "agents",
		description: "Manage isolated agents (workspaces + auth + routing)",
		hasSubcommands: true
	},
	{
		name: "status",
		description: "Show channel health and recent session recipients",
		hasSubcommands: false
	},
	{
		name: "health",
		description: "Fetch health from the running gateway",
		hasSubcommands: false
	},
	{
		name: "audit",
		description: "Inspect activity records and exact-run identity context",
		hasSubcommands: false
	},
	{
		name: "sessions",
		description: "List stored conversation sessions",
		hasSubcommands: true
	}
];
const CRON_GATEWAY_VALUE_FLAGS = [
	"url",
	"port",
	"token",
	"password",
	"timeout",
	"expectFinal"
].filter((name) => name !== "expectFinal").map((name) => `--${name}`);
const MACHINE_OUTPUT_COMMANDS$1 = new Set(Object.entries({
	status: [],
	add: ["create"],
	rm: ["remove", "delete"],
	enable: [],
	disable: [],
	get: [],
	runs: [],
	run: [],
	edit: [],
	scratch: []
}).flatMap(([name, aliases]) => [name].concat(aliases)));
function isCronMachineOutput(argv) {
	const [root] = getRootOptionAwareCommandPath(argv, 1);
	if (!root) return false;
	const [command] = getCommandPositionalsWithRootOptions(argv, {
		commandPath: [root],
		booleanFlags: ["--expect-final"],
		valueFlags: CRON_GATEWAY_VALUE_FLAGS,
		maxPositionals: 1
	}) ?? [];
	return command !== void 0 && MACHINE_OUTPUT_COMMANDS$1.has(command);
}
//#endregion
//#region src/cli/devices-output-mode.ts
function isDevicesMachineOutput(argv) {
	const [, command] = getRootOptionAwareCommandPath(argv, 2);
	return command === "rotate" || command === "revoke";
}
//#endregion
//#region gateway-run-argv.mjs
const GATEWAY_RUN_VALUE_FLAGS = /* @__PURE__ */ new Set([
	"--port",
	"--bind",
	"--token",
	"--token-file",
	"--auth",
	"--password",
	"--password-file",
	"--tailscale",
	"--ws-log",
	"--raw-stream-path"
]);
const GATEWAY_RUN_BOOLEAN_FLAGS = /* @__PURE__ */ new Set([
	"--tailscale-reset-on-exit",
	"--allow-unconfigured",
	"--dev",
	"--ambient-channels",
	"--dev-ambient-channels",
	"--reset",
	"--update-canary",
	"--force",
	"--verbose",
	"--cli-backend-logs",
	"--claude-cli-logs",
	"--compact",
	"--raw-stream"
]);
//#endregion
//#region src/daemon/windows-task-supervisor-contract.ts
/** Internal argument used by generated Windows Gateway service launchers. */
const WINDOWS_TASK_SUPERVISOR_FLAG = "--task-supervisor";
/** Internal argument marking the Gateway child owned by the task supervisor. */
const WINDOWS_TASK_SUPERVISOR_CHILD_FLAG = "--task-supervisor-child";
//#endregion
//#region src/cli/gateway-run-argv.ts
/** Resolve the gateway command path from raw argv without full Commander registration. */
function resolveGatewayCommandPath(argv, depth = 2) {
	const positionals = getCommandPositionalsWithRootOptions(argv, {
		commandPath: ["gateway"],
		booleanFlags: [...GATEWAY_RUN_BOOLEAN_FLAGS, WINDOWS_TASK_SUPERVISOR_FLAG],
		valueFlags: [...GATEWAY_RUN_VALUE_FLAGS, WINDOWS_TASK_SUPERVISOR_CHILD_FLAG],
		maxPositionals: depth - 1,
		mode: "command-path"
	});
	return positionals ? ["gateway", ...positionals] : null;
}
/** Resolve the gateway command path used by catalog and startup-policy lookups. */
function resolveGatewayCatalogCommandPath(argv) {
	return resolveGatewayCommandPath(argv, 2);
}
//#endregion
//#region src/cli/gateway-cli/output-mode.ts
function isGatewayMachineOutput(argv) {
	const [, command, action] = resolveGatewayCommandPath([...argv], 3) ?? [];
	return command === "restart-handoff" && (action === "capabilities" || action === "consume");
}
//#endregion
//#region src/cli/models-output-mode.ts
/** Resolve the parent-command alias for `models status --json`. */
function isModelsStatusJsonOutput(argv, command) {
	return hasMachineOutputOption(argv, "--json", command) || resolveCliParentCommandPath(argv, "models")?.length === 1 && hasMachineOutputOption(argv, "--status-json", command);
}
function isModelsPlainMachineOutput(argv, command) {
	const commandPath = resolveCliParentCommandPath(argv, "models");
	return commandPath !== null && (hasMachineOutputOption(argv, "--plain", command) || commandPath.length === 1 && hasMachineOutputOption(argv, "--status-plain", command));
}
//#endregion
//#region src/cli/nodes-cli/output-mode.ts
function isNodesMachineOutput(argv) {
	const [, command] = getRootOptionAwareCommandPath(argv, 2);
	return command === "invoke" || command === "approve" || command === "reject";
}
//#endregion
//#region src/cli/proxy-output-mode.ts
const MACHINE_OUTPUT_COMMANDS = /* @__PURE__ */ new Set([
	"blob",
	"coverage",
	"purge",
	"query",
	"sessions"
]);
/** Proxy inspection commands reserve stdout for JSON or raw captured content. */
function isProxyMachineOutput(argv) {
	const [, command] = getRootOptionAwareCommandPath(argv, 2);
	return MACHINE_OUTPUT_COMMANDS.has(command ?? "");
}
//#endregion
//#region src/cli/skills-output-mode.ts
/** Skill verification emits JSON unless the caller explicitly requests the Markdown card. */
function isSkillsMachineOutput(argv, command) {
	return resolveCliParentCommandPath(argv, "skills")?.[1] === "verify" && !hasMachineOutputOption(argv, "--card", command);
}
//#endregion
//#region src/cli/system-output-mode.ts
const DEFAULT_JSON_PATHS = /* @__PURE__ */ new Set([
	"heartbeat disable",
	"heartbeat enable",
	"heartbeat last",
	"presence"
]);
/** System query/control commands emit JSON even when `--json` is omitted. */
function isSystemMachineOutput(argv) {
	return DEFAULT_JSON_PATHS.has(getRootOptionAwareCommandPath(argv, 3).slice(1).join(" "));
}
resolveGlobalSingleton(Symbol.for("openclaw.asyncWorkScope"), () => new AsyncLocalStorage());
resolveGlobalSingleton(Symbol.for("openclaw.asyncWorkScopeAncestry"), () => new AsyncLocalStorage());
resolveGlobalSingleton(Symbol.for("openclaw.detachedAsyncContext"), () => new AsyncResource("openclaw.detached-async-context"));
resolveGlobalSingleton(Symbol.for("openclaw.pluginSourceRecoveryUnavailableError"), () => class SourceRecoveryUnavailableError extends Error {
	constructor(cause) {
		super("Captured plugin source is missing; its previous code cannot be recovered.", { cause });
		this.name = "PluginSourceRecoveryUnavailableError";
	}
});
resolveGlobalSingleton(Symbol.for("openclaw.pluginInstanceDrainTimeoutError"), () => class DrainTimeoutError extends Error {
	constructor(message, settled, options, forcedRetirement) {
		super(message, options);
		this.settled = settled;
		this.forcedRetirement = forcedRetirement;
		this.name = "PluginInstanceDrainTimeoutError";
	}
});
//#endregion
//#region src/plugins/plugin-instance-invocation.ts
var InvocationFrame = class InvocationFrame {
	constructor(scopes, invocation = scopes.invocation) {
		this.invocation = invocation;
		this.metadataScope = scopes.metadataScope;
		this.cacheScope = scopes.cacheScope;
		this.sourceCaptureStorage = scopes.sourceCaptureStorage;
	}
	withScopes(scopes) {
		return new InvocationFrame(scopes);
	}
};
/** Copy core scopes through the current owner so runtime-only fields survive. */
function createPluginExecutionFrame(scopes, current) {
	return current ? current.withScopes(scopes) : new InvocationFrame(scopes);
}
const pluginExecutionContext = resolveGlobalSingleton(Symbol.for("openclaw.pluginInstanceInvocation"), () => {
	const frames = new AsyncLocalStorage();
	return {
		invocation: {
			getStore() {
				return frames.getStore()?.invocation;
			},
			run(invocation, run) {
				const current = frames.getStore();
				return frames.run(current?.invocation === invocation ? current : createPluginExecutionFrame({
					...current,
					invocation
				}, current), run);
			},
			exit(run) {
				const current = frames.getStore();
				return current?.invocation ? frames.run(current.withScopes({
					...current,
					invocation: void 0
				}), run) : run();
			}
		},
		getFrame() {
			return frames.getStore();
		},
		runFrame(frame, run) {
			return frames.run(frame, run);
		}
	};
});
pluginExecutionContext.invocation;
pluginExecutionContext.getFrame;
pluginExecutionContext.runFrame;
resolveGlobalSingleton(Symbol.for("openclaw.pluginCache"), () => ({
	snapshotOwners: /* @__PURE__ */ new WeakMap(),
	retirements: []
}));
resolveGlobalSingleton(Symbol.for("openclaw.pluginCacheRetainers"), () => /* @__PURE__ */ new WeakMap());
resolveGlobalSingleton(Symbol.for("openclaw.pluginInstanceCacheOwners"), () => /* @__PURE__ */ new WeakMap());
path.join("dist", "plugin-sdk", "qa-lab.js");
/** Return true when private QA CLI routes should be exposed. */
function isPrivateQaCliEnabled(env = process.env) {
	return env.OPENCLAW_ENABLE_PRIVATE_QA_CLI === "1";
}
//#endregion
//#region src/cli/program/subcli-descriptors.ts
const subCliCommandDescriptors = [
	{
		name: "acp",
		description: "Run an ACP bridge backed by the Gateway",
		hasSubcommands: true
	},
	{
		name: "gateway",
		description: "Run, inspect, and query the WebSocket Gateway",
		hasSubcommands: true,
		machineOutput: ({ argv }) => isGatewayMachineOutput(argv)
	},
	{
		name: "daemon",
		description: "Manage the Gateway service (launchd/systemd/schtasks)",
		hasSubcommands: true
	},
	{
		name: "logs",
		description: "Tail gateway file logs via RPC",
		hasSubcommands: false
	},
	{
		name: "system",
		description: "System tools (events, heartbeat, presence)",
		hasSubcommands: true,
		machineOutput: ({ argv }) => isSystemMachineOutput(argv)
	},
	{
		name: "models",
		description: "Model discovery, scanning, and configuration",
		hasSubcommands: true,
		machineOutput: ({ argv }) => isModelsStatusJsonOutput(argv) || isModelsPlainMachineOutput(argv)
	},
	{
		name: "promos",
		description: "Discover and claim promotional model offers from ClawHub",
		hasSubcommands: true
	},
	{
		name: "telemetry",
		description: "Inspect and manage anonymous usage telemetry",
		hasSubcommands: true,
		parentDefaultHelp: true
	},
	{
		name: "infer",
		description: "Run provider-backed inference commands through a stable CLI surface",
		hasSubcommands: true
	},
	{
		name: "capability",
		description: "Run provider capability commands (fallback alias: infer)",
		hasSubcommands: true
	},
	{
		name: "approvals",
		description: "Manage approval policy and pending requests",
		hasSubcommands: true,
		parentDefaultHelp: true
	},
	{
		name: "exec-approvals",
		description: "Manage exec approvals (alias for approvals)",
		hasSubcommands: true
	},
	{
		name: "exec-policy",
		description: "Show or synchronize requested exec policy with host approvals",
		hasSubcommands: true
	},
	{
		name: "nodes",
		description: "Manage gateway-owned nodes (pairing, status, invoke, and media)",
		hasSubcommands: true,
		machineOutput: ({ argv }) => isNodesMachineOutput(argv)
	},
	{
		name: "devices",
		description: "Device pairing and auth tokens (for mobile app setup codes, use `openclaw qr` instead)",
		hasSubcommands: true,
		machineOutput: ({ argv }) => isDevicesMachineOutput(argv),
		parentDefaultHelp: true
	},
	{
		name: "users",
		description: "Manage durable user profiles and email aliases",
		hasSubcommands: true,
		parentDefaultHelp: true
	},
	{
		name: "node",
		description: "Run and manage the headless node host service",
		hasSubcommands: true
	},
	{
		name: "connect",
		description: "Connect this machine to an OpenClaw Gateway as a node",
		hasSubcommands: false
	},
	{
		name: "worker",
		description: "Run the restricted cloud worker runtime",
		hasSubcommands: false
	},
	{
		name: "sandbox",
		description: "Manage sandbox containers (Docker-based agent isolation)",
		hasSubcommands: true
	},
	{
		name: "fleet",
		description: "Provision and manage isolated tenant cells (experimental)",
		hasSubcommands: true
	},
	{
		name: "worktrees",
		description: "Create, inspect, restore, and clean up managed worktrees",
		hasSubcommands: true,
		parentDefaultHelp: true
	},
	{
		name: "attach",
		description: "Attach Claude Code to a gateway session with scoped MCP tools",
		hasSubcommands: false
	},
	{
		name: "tui",
		description: "Open a terminal UI connected to the Gateway",
		hasSubcommands: false
	},
	{
		name: "resume",
		description: "Resume a recent Gateway session in the TUI",
		hasSubcommands: false
	},
	{
		name: "terminal",
		description: "Open a local terminal UI (alias for tui --local)",
		hasSubcommands: false
	},
	{
		name: "chat",
		description: "Open a local terminal UI (alias for tui --local)",
		hasSubcommands: false
	},
	{
		name: "cron",
		description: "Manage automations (via Gateway)",
		hasSubcommands: true,
		machineOutput: ({ argv }) => isCronMachineOutput(argv),
		parentDefaultHelp: true
	},
	{
		name: "automations",
		description: "Manage automations (alias for cron)",
		hasSubcommands: true,
		machineOutput: ({ argv }) => isCronMachineOutput(argv),
		parentDefaultHelp: true
	},
	{
		name: "dns",
		description: "DNS helpers for wide-area discovery (Tailscale + CoreDNS)",
		hasSubcommands: true
	},
	{
		name: "docs",
		description: "Search the live OpenClaw docs",
		hasSubcommands: false
	},
	{
		name: "qa",
		description: "Run QA scenarios and launch the private QA debugger UI",
		hasSubcommands: true
	},
	{
		name: "proxy",
		description: "Run the OpenClaw debug proxy and inspect captured traffic",
		hasSubcommands: true,
		machineOutput: ({ argv }) => isProxyMachineOutput(argv)
	},
	{
		name: "hooks",
		description: "Manage internal agent hooks",
		hasSubcommands: true
	},
	{
		name: "webhooks",
		description: "Webhook helpers and integrations",
		hasSubcommands: true
	},
	{
		name: "qr",
		description: "Generate a mobile pairing QR code and setup code",
		hasSubcommands: false
	},
	{
		name: "clawbot",
		description: "Legacy clawbot command aliases",
		hasSubcommands: true
	},
	{
		name: "pairing",
		description: "Secure DM pairing (approve inbound requests)",
		hasSubcommands: true
	},
	{
		name: "plugins",
		description: "Manage OpenClaw plugins and extensions",
		hasSubcommands: true,
		parentDefaultHelp: true
	},
	{
		name: "channels",
		description: "Manage connected chat channels and accounts",
		hasSubcommands: true,
		parentDefaultHelp: true
	},
	{
		name: "directory",
		description: "Lookup contact and group IDs (self, peers, groups) for supported chat channels",
		hasSubcommands: true
	},
	{
		name: "security",
		description: "Audit local config and state for common security foot-guns",
		hasSubcommands: true
	},
	{
		name: "secrets",
		description: "Secrets runtime controls",
		hasSubcommands: true
	},
	{
		name: "skills",
		description: "List and inspect available skills",
		hasSubcommands: true,
		machineOutput: ({ argv }) => isSkillsMachineOutput(argv)
	},
	{
		name: "update",
		description: "Update OpenClaw and inspect update channel status",
		hasSubcommands: true
	},
	{
		name: "completion",
		description: "Generate shell completion script",
		hasSubcommands: false
	}
];
const SUB_CLI_DESCRIPTORS = getSubCliEntriesCore();
function getSubCliEntriesCore() {
	return isPrivateQaCliEnabled() ? subCliCommandDescriptors : subCliCommandDescriptors.filter((descriptor) => descriptor.name !== "qa");
}
//#endregion
//#region src/cli/argv.ts
const HELP_FLAGS = /* @__PURE__ */ new Set(["-h", "--help"]);
const VERSION_FLAGS = /* @__PURE__ */ new Set([
	"-V",
	"--version",
	.../* @__PURE__ */ new Set(["-v"])
]);
const ROOT_COMMAND_DESCRIPTORS = [...CORE_CLI_COMMAND_DESCRIPTORS.filter((descriptor) => descriptor.name !== "claws" || isExperimentalClawsEnabled()), ...SUB_CLI_DESCRIPTORS];
const KNOWN_ROOT_COMMANDS = new Set(ROOT_COMMAND_DESCRIPTORS.map((descriptor) => descriptor.name));
const ROOT_COMMANDS_WITH_SUBCOMMANDS = new Set(ROOT_COMMAND_DESCRIPTORS.filter((descriptor) => descriptor.hasSubcommands).map((descriptor) => descriptor.name));
function isHelpOrVersionInvocation(argv) {
	if (isRootVersionInvocation(argv)) return true;
	const args = argv.slice(2);
	let sawCommandOption = false;
	let literal = false;
	const positionals = [];
	for (let i = 0; i < args.length; i += 1) {
		const arg = args[i];
		if (!arg) break;
		if (!literal && arg === "--") {
			literal = true;
			continue;
		}
		const rootConsumed = literal ? 0 : consumeRootOptionToken(args, i);
		if (rootConsumed > 0) {
			i += rootConsumed - 1;
			continue;
		}
		if (!literal && HELP_FLAGS.has(arg)) return true;
		if (!literal && arg.startsWith("-")) {
			sawCommandOption = true;
			continue;
		}
		positionals.push(arg);
		if (arg !== "help") continue;
		if (sawCommandOption) return false;
		if (positionals.length === 1) return true;
		const [primary] = positionals;
		if (!primary || !KNOWN_ROOT_COMMANDS.has(primary)) return true;
		if (positionals.length === 2 && ROOT_COMMANDS_WITH_SUBCOMMANDS.has(primary)) return true;
		return false;
	}
	return false;
}
function isRootVersionInvocation(argv) {
	return isRootInvocationForFlags(argv, VERSION_FLAGS);
}
function isRootInvocationForFlags(argv, targetFlags) {
	const args = argv.slice(2);
	let hasTarget = false;
	for (let i = 0; i < args.length; i += 1) {
		const arg = args[i];
		if (!arg) continue;
		if (arg === "--") break;
		if (targetFlags.has(arg)) {
			hasTarget = true;
			continue;
		}
		const consumed = consumeRootOptionToken(args, i);
		if (consumed > 0) {
			i += consumed - 1;
			continue;
		}
		return false;
	}
	return hasTarget;
}
function isRootHelpInvocation(argv) {
	return isRootInvocationForFlags(argv, HELP_FLAGS);
}
function getCommandPathWithRootOptions(argv, depth = 2) {
	return getRootOptionAwareCommandPath(argv, depth);
}
function getPrimaryCommand(argv) {
	const [primary] = getCommandPathWithRootOptions(argv, 1);
	return primary ?? null;
}
//#endregion
//#region src/cli/argv-invocation.ts
/** Resolves command path and help/version mode from a raw process argv array. */
function resolveCliArgvInvocation(argv) {
	return {
		argv,
		commandPath: resolveGatewayCatalogCommandPath(argv) ?? resolveCliParentCommandPath(argv) ?? getCommandPathWithRootOptions(argv, 2),
		primary: getPrimaryCommand(argv),
		hasHelpOrVersion: isHelpOrVersionInvocation(argv),
		isRootHelpInvocation: isRootHelpInvocation(argv)
	};
}
//#endregion
//#region src/cli/profile-utils.ts
const PROFILE_NAME_RE = /^[a-z0-9][a-z0-9_-]{0,63}$/i;
function isValidProfileName(value) {
	return PROFILE_NAME_RE.test(value);
}
/** Resolve the canonical home-scoped state root for a validated CLI profile. */
function resolveProfileStateDir(profile, env, homedir) {
	const trimmed = profile.trim();
	if (!isValidProfileName(trimmed)) throw new Error(`Invalid profile name: ${JSON.stringify(profile)}`);
	const suffix = normalizeLowercaseStringOrEmpty(trimmed) === "default" ? "" : `-${trimmed}`;
	return path.join(resolveRequiredHomeDir(env, homedir), `.openclaw${suffix}`);
}
//#endregion
//#region src/cli/root-option-scan.ts
/** Walk argv once, letting callers consume custom flags before forwarding root options. */
function scanCliRootOptions(argv, visit) {
	if (argv.length < 2) return {
		ok: true,
		argv
	};
	const out = argv.slice(0, 2);
	const args = argv.slice(2);
	for (let i = 0; i < args.length; i += 1) {
		const arg = args[i];
		if (arg === void 0) continue;
		if (arg === "--") {
			out.push(arg, ...args.slice(i + 1));
			break;
		}
		const visited = visit({
			arg,
			args,
			index: i,
			out
		});
		if (visited.kind === "error") return {
			ok: false,
			error: visited.error
		};
		if (visited.kind === "handled") {
			if (visited.consumedNext) i += 1;
			continue;
		}
		const consumedRootOption = consumeRootOptionToken(args, i);
		if (consumedRootOption > 0) {
			for (let offset = 0; offset < consumedRootOption; offset += 1) {
				const token = args[i + offset];
				if (token !== void 0) out.push(token);
			}
			i += consumedRootOption - 1;
			continue;
		}
		out.push(arg);
	}
	return {
		ok: true,
		argv: out
	};
}
//#endregion
//#region src/infra/inline-option-token.ts
/** Splits one CLI-style option token into its flag name and optional inline value. */
function parseInlineOptionToken(token) {
	const separatorIndex = token.indexOf("=");
	if (separatorIndex < 0) return {
		name: token,
		hasInlineValue: false
	};
	return {
		name: token.slice(0, separatorIndex),
		hasInlineValue: true,
		inlineValue: token.slice(separatorIndex + 1)
	};
}
//#endregion
//#region src/cli/root-option-value.ts
/** Return the normalized option value and whether the next argv token was consumed. */
function takeCliRootOptionValue(raw, next) {
	const parsed = parseInlineOptionToken(raw);
	if (parsed.hasInlineValue) return {
		value: (parsed.inlineValue ?? "").trim() || null,
		consumedNext: false
	};
	const consumedNext = isValueToken(next);
	return {
		value: (consumedNext ? next.trim() : "") || null,
		consumedNext
	};
}
//#endregion
//#region src/cli/profile.ts
function parseCliProfileArgs(argv) {
	let profile = null;
	let sawDev = false;
	const scanned = scanCliRootOptions(argv, ({ arg, args, index, out }) => {
		if (arg === "--dev") {
			if (resolveCliArgvInvocation(out).primary === "gateway") {
				out.push(arg);
				return { kind: "handled" };
			}
			if (profile && profile !== "dev") return {
				kind: "error",
				error: "Cannot combine --dev with --profile"
			};
			sawDev = true;
			profile = "dev";
			return { kind: "handled" };
		}
		if (arg === "--profile" || arg.startsWith("--profile=")) {
			const next = args[index + 1];
			const { value, consumedNext } = takeCliRootOptionValue(arg, next);
			const [primary, secondary] = resolveCliArgvInvocation(out).commandPath;
			if (primary === "qa" && secondary === "matrix") {
				out.push(arg);
				if (consumedNext && next !== void 0) out.push(next);
				return {
					kind: "handled",
					consumedNext
				};
			}
			if (sawDev) return {
				kind: "error",
				error: "Cannot combine --dev with --profile"
			};
			if (!value) return {
				kind: "error",
				error: "--profile requires a value"
			};
			if (!isValidProfileName(value)) return {
				kind: "error",
				error: "Invalid --profile (use letters, numbers, \"_\", \"-\" only)"
			};
			profile = value;
			return {
				kind: "handled",
				consumedNext
			};
		}
		return { kind: "pass" };
	});
	if (!scanned.ok) return scanned;
	return {
		ok: true,
		profile,
		argv: scanned.argv
	};
}
function applyCliProfileEnv(params) {
	const env = params.env ?? process.env;
	const homedir = params.homedir ?? os.homedir;
	const profile = params.profile.trim();
	if (!profile) return;
	const inheritedProfile = normalizeOptionalString(env.OPENCLAW_PROFILE) ?? "default";
	const existingStateDir = normalizeOptionalString(env.OPENCLAW_STATE_DIR);
	const existingConfigPath = normalizeOptionalString(env.OPENCLAW_CONFIG_PATH);
	const inheritedProfileStateDir = resolveProfileStateDir(inheritedProfile, env, homedir);
	const selectedProfileStateDir = resolveProfileStateDir(profile, env, homedir);
	const switchesInheritedProfile = inheritedProfileStateDir !== selectedProfileStateDir;
	const inheritedSystemdServiceName = resolveGatewaySystemdServiceName(inheritedProfile);
	const inheritedServiceSelectors = {
		OPENCLAW_LAUNCHD_LABEL: [resolveGatewayLaunchAgentLabel(inheritedProfile)],
		OPENCLAW_SYSTEMD_UNIT: [inheritedSystemdServiceName, `${inheritedSystemdServiceName}.service`],
		OPENCLAW_WINDOWS_TASK_NAME: [resolveGatewayWindowsTaskName(inheritedProfile)]
	};
	const switchesInheritedProfileState = Boolean(existingStateDir && switchesInheritedProfile && resolveHomeRelativePath(existingStateDir, {
		env,
		homedir
	}) === inheritedProfileStateDir);
	const replacesInheritedProfileConfig = Boolean(switchesInheritedProfile && (!existingStateDir || switchesInheritedProfileState) && existingConfigPath && resolveHomeRelativePath(existingConfigPath, {
		env,
		homedir
	}) === path.join(inheritedProfileStateDir, "openclaw.json"));
	const inheritedManagedServiceSelectors = switchesInheritedProfile && isGatewayServiceEnv(env) && switchesInheritedProfileState && replacesInheritedProfileConfig;
	if (inheritedManagedServiceSelectors) for (const key of GATEWAY_SERVICE_SELECTOR_ENV_KEYS) delete env[key];
	env.OPENCLAW_PROFILE = profile;
	const retainedStateDir = inheritedManagedServiceSelectors ? void 0 : existingStateDir;
	const stateDir = retainedStateDir && !switchesInheritedProfileState ? retainedStateDir : selectedProfileStateDir;
	if (!retainedStateDir || switchesInheritedProfileState) env.OPENCLAW_STATE_DIR = stateDir;
	if (!inheritedManagedServiceSelectors && (!existingConfigPath || replacesInheritedProfileConfig)) env.OPENCLAW_CONFIG_PATH = path.join(stateDir, "openclaw.json");
	if (switchesInheritedProfile && !inheritedManagedServiceSelectors) for (const [key, inheritedValues] of Object.entries(inheritedServiceSelectors)) {
		const activeValue = normalizeOptionalString(env[key]);
		if (activeValue && inheritedValues.includes(activeValue)) delete env[key];
	}
	if (profile === "dev" && !env.OPENCLAW_GATEWAY_PORT?.trim()) env.OPENCLAW_GATEWAY_PORT = "19001";
}
//#endregion
//#region src/infra/test-runtime-env.ts
/** Detects Vitest/test execution from the env shape used by local and worker processes. */
function isVitestRuntimeEnv(env = process.env) {
	const vitest = env.VITEST;
	return vitest === "true" || vitest === "1" || env.VITEST_POOL_ID !== void 0 || env.VITEST_WORKER_ID !== void 0 || env.NODE_ENV === "test";
}
/** Enables the shared fast-test shortcuts only inside a detected test runtime. */
function isFastTestRuntimeEnv(env = process.env) {
	return env.OPENCLAW_TEST_FAST === "1" && (isVitestRuntimeEnv(env) || env !== process.env && isVitestRuntimeEnv(process.env));
}
//#endregion
//#region src/config/state-dir.ts
function resolveLegacyStateDirs(homedir = resolveRequiredHomeDir) {
	return [path.join(homedir(), ".clawdbot")];
}
function resolveNewStateDir(homedir = resolveRequiredHomeDir) {
	return path.join(homedir(), ".openclaw");
}
/**
* State directory for mutable data (sessions, logs, caches).
* Can be overridden via OPENCLAW_STATE_DIR.
* Default: ~/.openclaw
*/
function resolveStateDir(env = process.env, homedir = () => resolveRequiredHomeDir(env, os.homedir)) {
	const effectiveHomedir = () => resolveRequiredHomeDir(env, homedir);
	const override = env.OPENCLAW_STATE_DIR?.trim();
	if (override) return resolveHomeRelativePath(override, {
		env,
		homedir: effectiveHomedir
	});
	return resolveStateDirFromHome(env, effectiveHomedir);
}
/** Select a default state directory from the caller's already resolved home. */
function resolveStateDirFromHome(env, effectiveHomedir) {
	const newDir = resolveNewStateDir(effectiveHomedir);
	if (isFastTestRuntimeEnv(env) || fs.existsSync(newDir)) return newDir;
	return resolveLegacyStateDirs(effectiveHomedir).find((dir) => fs.existsSync(dir)) ?? newDir;
}
//#endregion
//#region src/infra/config-dir.ts
/** Resolves the OpenClaw config directory from state/config env overrides or home. */
function resolveConfigDir(env = process.env, homedir = os.homedir) {
	const override = env.OPENCLAW_STATE_DIR?.trim();
	if (override) return resolveUserPath(override, env, homedir);
	const configPath = env.OPENCLAW_CONFIG_PATH?.trim();
	if (configPath) return path.dirname(resolveUserPath(configPath, env, homedir));
	return path.join(resolveRequiredHomeDir(env, homedir), ".openclaw");
}
//#endregion
//#region src/infra/fs-safe-env.ts
const nativeModeKey = "OPENCLAW_FS_SAFE_NATIVE_MODE";
const legacyModeKeys = ["FS_SAFE_PYTHON_MODE", "OPENCLAW_FS_SAFE_PYTHON_MODE"];
const legacyKeys = [
	...legacyModeKeys,
	"FS_SAFE_PYTHON",
	"OPENCLAW_FS_SAFE_PYTHON",
	"OPENCLAW_PINNED_PYTHON",
	"OPENCLAW_PINNED_WRITE_PYTHON"
];
const fallbacks = /* @__PURE__ */ new WeakMap();
let warned = false;
function nativeModeIsValid(value) {
	const normalized = value?.trim().toLowerCase() ?? "";
	return /^(?:0|false|off|never|1|true|on|auto|required|require)$/u.test(normalized);
}
function currentFallback(env) {
	const fallback = fallbacks.get(env);
	return fallback && env[fallback.key] === fallback.value ? fallback : void 0;
}
/** Retire our unchanged projection before an environment owner writes real inputs. */
function clearFsSafeEnvFallback(env) {
	const fallback = currentFallback(env);
	fallbacks.delete(env);
	if (!fallback) return;
	if (!fallback.existed) delete env[fallback.key];
	else env[fallback.key] = fallback.previous;
}
/** Preserve OpenClaw's retired Python mode env contract below both native names. */
function normalizeFsSafeNativeEnv(env = process.env) {
	clearFsSafeEnvFallback(env);
	const configured = legacyKeys.filter((key) => env[key] !== void 0);
	if (configured.length && env === process.env && !warned) {
		warned = true;
		process.emitWarning(`${configured.join(", ")} is deprecated. OpenClaw maps legacy mode values to native mode only when neither FS_SAFE_NATIVE_MODE nor OPENCLAW_FS_SAFE_NATIVE_MODE selects a mode. Replace Python mode variables with native mode variables; interpreter path settings are ignored.`, {
			code: "FS_SAFE_PYTHON_DEPRECATED",
			type: "DeprecationWarning"
		});
	}
	if (nativeModeIsValid(env.FS_SAFE_NATIVE_MODE) || nativeModeIsValid(env[nativeModeKey])) return;
	const value = legacyModeKeys.map((key) => env[key]).find((entry) => entry !== void 0);
	if (value === void 0) return;
	const keys = Object.keys(env);
	const key = !keys.includes(nativeModeKey) && Object.hasOwn(env, nativeModeKey) ? keys.find((candidate) => candidate.toUpperCase() === nativeModeKey) ?? nativeModeKey : nativeModeKey;
	const existed = Object.hasOwn(env, key);
	const previous = env[key];
	env[key] = value;
	fallbacks.set(env, {
		key,
		value,
		previous,
		existed
	});
}
//#endregion
//#region src/infra/host-env-security-policy.json
var host_env_security_policy_default = {
	blockedEverywhereKeys: [
		"NODE_OPTIONS",
		"NODE_PATH",
		"NODE_REDIRECT_WARNINGS",
		"NODE_REPL_EXTERNAL_MODULE",
		"NODE_REPL_HISTORY",
		"NODE_V8_COVERAGE",
		"PYTHONHOME",
		"PYTHONPATH",
		"PERL5LIB",
		"PERL5OPT",
		"RUBYLIB",
		"RUBYOPT",
		"BASHOPTS",
		"BASH_ENV",
		"ENV",
		"KSH_ENV",
		"BROWSER",
		"GIT_ALLOW_PROTOCOL",
		"GIT_EDITOR",
		"GIT_EXTERNAL_DIFF",
		"GIT_DIR",
		"GIT_WORK_TREE",
		"GIT_COMMON_DIR",
		"GIT_EXEC_PATH",
		"GIT_INDEX_FILE",
		"GIT_OBJECT_DIRECTORY",
		"GIT_ALTERNATE_OBJECT_DIRECTORIES",
		"GIT_NAMESPACE",
		"GIT_PROTOCOL_FROM_USER",
		"GIT_SEQUENCE_EDITOR",
		"GIT_TEMPLATE_DIR",
		"GIT_SSL_NO_VERIFY",
		"GIT_SSL_CAINFO",
		"GIT_SSL_CAPATH",
		"CC",
		"CPP",
		"CXX",
		"CXXCPP",
		"CARGO_BUILD_RUSTC",
		"CARGO_BUILD_RUSTC_WRAPPER",
		"CARGO_BUILD_RUSTC_WORKSPACE_WRAPPER",
		"CARGO_BUILD_RUSTDOC",
		"RUSTC",
		"RUSTC_WRAPPER",
		"RUSTC_WORKSPACE_WRAPPER",
		"RUSTDOC",
		"CMAKE_C_COMPILER",
		"CMAKE_CXX_COMPILER",
		"SHELL",
		"SHELLOPTS",
		"PS4",
		"GCONV_PATH",
		"IFS",
		"SSLKEYLOGFILE",
		"JAVA_OPTS",
		"JAVA_TOOL_OPTIONS",
		"_JAVA_OPTIONS",
		"JDK_JAVA_OPTIONS",
		"PYTHONBREAKPOINT",
		"DOTNET_STARTUP_HOOKS",
		"DOTNET_ADDITIONAL_DEPS",
		"FPATH",
		"GLIBC_TUNABLES",
		"MAVEN_OPTS",
		"MAKE",
		"MAKEFLAGS",
		"MFLAGS",
		"SBT_OPTS",
		"GRADLE_OPTS",
		"ANT_OPTS",
		"HGRCPATH",
		"HGEDITOR",
		"HGMERGE",
		"EXINIT",
		"VIMINIT",
		"MYVIMRC",
		"GVIMINIT",
		"LUA_INIT",
		"LUA_INIT_5_1",
		"LUA_INIT_5_2",
		"LUA_INIT_5_3",
		"LUA_INIT_5_4",
		"EMACSLOADPATH",
		"RUBYSHELL",
		"GIT_HOOK_PATH",
		"SVN_EDITOR",
		"SVN_SSH",
		"BZR_EDITOR",
		"BZR_SSH",
		"BZR_PLUGIN_PATH",
		"SUDO_ASKPASS",
		"JULIA_EDITOR",
		"CONFIG_SITE",
		"CONFIG_SHELL",
		"CMAKE_TOOLCHAIN_FILE",
		"CATALINA_OPTS",
		"CORECLR_PROFILER",
		"HELM_PLUGINS",
		"PACKER_PLUGIN_PATH",
		"VAGRANT_VAGRANTFILE",
		"ERL_AFLAGS",
		"ERL_FLAGS",
		"ERL_ZFLAGS",
		"ELIXIR_ERL_OPTIONS",
		"R_ENVIRON",
		"R_PROFILE",
		"R_ENVIRON_USER",
		"R_PROFILE_USER",
		"TCLLIBPATH",
		"HOSTALIASES"
	],
	blockedOverrideOnlyKeys: [
		"HOME",
		"GRADLE_USER_HOME",
		"ZDOTDIR",
		"GIT_DIR",
		"GIT_WORK_TREE",
		"GIT_COMMON_DIR",
		"GIT_INDEX_FILE",
		"GIT_OBJECT_DIRECTORY",
		"GIT_ALTERNATE_OBJECT_DIRECTORIES",
		"GIT_NAMESPACE",
		"GIT_SSH_COMMAND",
		"GIT_SSH",
		"GIT_PROXY_COMMAND",
		"GIT_ASKPASS",
		"GIT_SSL_NO_VERIFY",
		"GIT_SSL_CAINFO",
		"GIT_SSL_CAPATH",
		"SSH_ASKPASS",
		"LESSOPEN",
		"LESSCLOSE",
		"PAGER",
		"MANPAGER",
		"GIT_PAGER",
		"EDITOR",
		"VISUAL",
		"FCEDIT",
		"SUDO_EDITOR",
		"PROMPT_COMMAND",
		"HISTFILE",
		"PERL5DB",
		"PERL5DBCMD",
		"OPENSSL_CONF",
		"OPENSSL_ENGINES",
		"PYTHONSTARTUP",
		"WGETRC",
		"CURL_HOME",
		"CLASSPATH",
		"CFLAGS",
		"CGO_CFLAGS",
		"CGO_LDFLAGS",
		"GOFLAGS",
		"MAKEFLAGS",
		"MFLAGS",
		"CORECLR_PROFILER_PATH",
		"PHPRC",
		"PHP_INI_SCAN_DIR",
		"DENO_DIR",
		"BUN_CONFIG_REGISTRY",
		"YARN_RC_FILENAME",
		"HTTP_PROXY",
		"HTTPS_PROXY",
		"ALL_PROXY",
		"NO_PROXY",
		"NODE_TLS_REJECT_UNAUTHORIZED",
		"NODE_EXTRA_CA_CERTS",
		"SSL_CERT_FILE",
		"SSL_CERT_DIR",
		"REQUESTS_CA_BUNDLE",
		"CURL_CA_BUNDLE",
		"DOCKER_HOST",
		"DOCKER_TLS_VERIFY",
		"DOCKER_CERT_PATH",
		"PIP_INDEX_URL",
		"PIP_PYPI_URL",
		"PIP_EXTRA_INDEX_URL",
		"PIP_CONFIG_FILE",
		"PIP_FIND_LINKS",
		"PIP_TRUSTED_HOST",
		"UV_INDEX",
		"UV_INDEX_URL",
		"UV_PYTHON",
		"UV_EXTRA_INDEX_URL",
		"UV_DEFAULT_INDEX",
		"DOCKER_CONTEXT",
		"LIBRARY_PATH",
		"LDFLAGS",
		"CPATH",
		"C_INCLUDE_PATH",
		"CPLUS_INCLUDE_PATH",
		"OBJC_INCLUDE_PATH",
		"GOPROXY",
		"GONOSUMCHECK",
		"GONOSUMDB",
		"GONOPROXY",
		"GOPRIVATE",
		"GOENV",
		"GOPATH",
		"HGRCPATH",
		"PYTHONUSERBASE",
		"RUSTC_WRAPPER",
		"RUSTFLAGS",
		"RUSTUP_DIST_ROOT",
		"RUSTUP_DIST_SERVER",
		"RUSTUP_HOME",
		"RUSTUP_TOOLCHAIN",
		"RUSTUP_UPDATE_ROOT",
		"CARGO_HOME",
		"VIRTUAL_ENV",
		"LUA_PATH",
		"LUA_CPATH",
		"GEM_HOME",
		"GEM_PATH",
		"BUNDLE_GEMFILE",
		"COMPOSER_HOME",
		"CONDA_DEFAULT_ENV",
		"CONDA_PREFIX",
		"CARGO_BUILD_RUSTC_WRAPPER",
		"XDG_CACHE_HOME",
		"XDG_CONFIG_DIRS",
		"XDG_CONFIG_HOME",
		"XDG_DATA_DIRS",
		"XDG_DATA_HOME",
		"XDG_RUNTIME_DIR",
		"XDG_STATE_HOME",
		"AWS_CONFIG_FILE",
		"KUBECONFIG",
		"GOOGLE_APPLICATION_CREDENTIALS",
		"AWS_SHARED_CREDENTIALS_FILE",
		"AWS_WEB_IDENTITY_TOKEN_FILE",
		"AZURE_AUTH_LOCATION",
		"HELM_HOME",
		"ANSIBLE_CONFIG",
		"ANSIBLE_LIBRARY",
		"ANSIBLE_CALLBACK_PLUGINS",
		"ANSIBLE_COLLECTIONS_PATH",
		"ANSIBLE_CONNECTION_PLUGINS",
		"ANSIBLE_FILTER_PLUGINS",
		"ANSIBLE_INVENTORY_PLUGINS",
		"ANSIBLE_LOOKUP_PLUGINS",
		"ANSIBLE_MODULE_UTILS",
		"ANSIBLE_REMOTE_TEMP",
		"ANSIBLE_ROLES_PATH",
		"ANSIBLE_STRATEGY_PLUGINS",
		"R_LIBS_USER",
		"TF_CLI_CONFIG_FILE",
		"TF_PLUGIN_CACHE_DIR",
		"AMQP_URL",
		"AWS_ACCESS_KEY_ID",
		"AWS_CONTAINER_CREDENTIALS_FULL_URI",
		"AWS_CONTAINER_CREDENTIALS_RELATIVE_URI",
		"AWS_SECRET_ACCESS_KEY",
		"AWS_SECURITY_TOKEN",
		"AWS_SESSION_TOKEN",
		"AZURE_CLIENT_ID",
		"AZURE_CLIENT_SECRET",
		"DATABASE_URL",
		"GH_TOKEN",
		"GITHUB_TOKEN",
		"GITLAB_TOKEN",
		"MONGODB_URI",
		"NODE_AUTH_TOKEN",
		"NPM_TOKEN",
		"REDIS_URL",
		"SSH_AUTH_SOCK",
		"SYSTEMROOT",
		"WINDIR"
	],
	allowedInheritedOverrideOnlyKeys: [
		"ALL_PROXY",
		"AWS_CONFIG_FILE",
		"AWS_SHARED_CREDENTIALS_FILE",
		"AWS_WEB_IDENTITY_TOKEN_FILE",
		"AZURE_AUTH_LOCATION",
		"CURL_CA_BUNDLE",
		"DOCKER_CERT_PATH",
		"DOCKER_CONTEXT",
		"DOCKER_HOST",
		"DOCKER_TLS_VERIFY",
		"GIT_PAGER",
		"GOOGLE_APPLICATION_CREDENTIALS",
		"GRADLE_USER_HOME",
		"HISTFILE",
		"HOME",
		"HTTPS_PROXY",
		"HTTP_PROXY",
		"KUBECONFIG",
		"MANPAGER",
		"NODE_EXTRA_CA_CERTS",
		"NODE_TLS_REJECT_UNAUTHORIZED",
		"NO_PROXY",
		"PAGER",
		"REQUESTS_CA_BUNDLE",
		"RUSTUP_DIST_ROOT",
		"RUSTUP_DIST_SERVER",
		"RUSTUP_HOME",
		"RUSTUP_TOOLCHAIN",
		"RUSTUP_UPDATE_ROOT",
		"SSH_AUTH_SOCK",
		"SSL_CERT_DIR",
		"SSL_CERT_FILE",
		"SYSTEMROOT",
		"WINDIR",
		"XDG_CACHE_HOME",
		"XDG_CONFIG_DIRS",
		"XDG_CONFIG_HOME",
		"XDG_DATA_DIRS",
		"XDG_DATA_HOME",
		"XDG_RUNTIME_DIR",
		"XDG_STATE_HOME",
		"ZDOTDIR"
	],
	blockedOverridePrefixes: [
		"GIT_CONFIG_",
		"NPM_CONFIG_",
		"CARGO_REGISTRIES_",
		"TF_VAR_"
	],
	blockedPrefixes: [
		"DYLD_",
		"LD_",
		"BASH_FUNC_"
	]
};
//#endregion
//#region src/infra/host-env-security-policy.js
function sortUniqueUppercase(values) {
	return Object.freeze(Array.from(new Set(values.map((value) => value.toUpperCase()))).toSorted((left, right) => left < right ? -1 : left > right ? 1 : 0));
}
function derivePolicyArrays(policy) {
	const blockedEverywhereKeys = policy.blockedEverywhereKeys ?? [];
	const blockedOverrideOnlyKeys = policy.blockedOverrideOnlyKeys ?? [];
	const allowedInheritedOverrideOnlyKeys = policy.allowedInheritedOverrideOnlyKeys ?? [];
	const allowedInheritedOverrideOnlyUpper = new Set(allowedInheritedOverrideOnlyKeys.map((value) => value.toUpperCase()));
	const blockedPrefixes = policy.blockedPrefixes ?? [];
	const blockedOverridePrefixes = policy.blockedOverridePrefixes ?? [];
	const blockedInheritedPrefixes = policy.blockedInheritedPrefixes ?? blockedPrefixes;
	return {
		blockedInheritedKeys: sortUniqueUppercase([...blockedEverywhereKeys, ...blockedOverrideOnlyKeys.filter((value) => !allowedInheritedOverrideOnlyUpper.has(value.toUpperCase()))]),
		blockedInheritedPrefixes: sortUniqueUppercase(blockedInheritedPrefixes),
		blockedKeys: sortUniqueUppercase(blockedEverywhereKeys),
		blockedOverrideKeys: sortUniqueUppercase(blockedOverrideOnlyKeys),
		blockedPrefixes: sortUniqueUppercase(blockedPrefixes),
		blockedOverridePrefixes: sortUniqueUppercase(blockedOverridePrefixes)
	};
}
/**
* Normalizes raw host environment policy JSON into immutable lookup arrays.
*/
function loadHostEnvSecurityPolicy(rawPolicy = host_env_security_policy_default) {
	const derived = derivePolicyArrays(rawPolicy);
	return Object.freeze({
		blockedEverywhereKeys: Object.freeze(rawPolicy.blockedEverywhereKeys ?? []),
		blockedOverrideOnlyKeys: Object.freeze(rawPolicy.blockedOverrideOnlyKeys ?? []),
		allowedInheritedOverrideOnlyKeys: Object.freeze(rawPolicy.allowedInheritedOverrideOnlyKeys ?? []),
		blockedInheritedKeys: derived.blockedInheritedKeys,
		blockedInheritedPrefixes: derived.blockedInheritedPrefixes,
		blockedPrefixes: derived.blockedPrefixes,
		blockedOverridePrefixes: derived.blockedOverridePrefixes,
		blockedKeys: derived.blockedKeys,
		blockedOverrideKeys: derived.blockedOverrideKeys
	});
}
/**
* Process-wide host environment security policy derived from generated JSON.
*/
const HOST_ENV_SECURITY_POLICY = loadHostEnvSecurityPolicy();
//#endregion
//#region src/infra/host-env-security.ts
const PORTABLE_ENV_VAR_KEY = /^[A-Za-z_][A-Za-z0-9_]*$/;
new Set(HOST_ENV_SECURITY_POLICY.blockedKeys);
new Set(HOST_ENV_SECURITY_POLICY.blockedInheritedKeys);
new Set(HOST_ENV_SECURITY_POLICY.blockedOverrideKeys);
new AsyncLocalStorage();
function normalizeEnvVarKey(rawKey, options) {
	const key = rawKey.trim();
	if (!key) return null;
	if (options?.portable && !PORTABLE_ENV_VAR_KEY.test(key)) return null;
	return key;
}
//#endregion
//#region src/infra/dotenv-global-core.ts
/** Maximum bytes to read from any dotenv file. */
const MAX_DOTENV_FILE_BYTES = 1048576;
function reportDotEnvReadError(params, error) {
	if (params.quiet) return;
	if ((error && typeof error === "object" && "code" in error ? String(error.code) : void 0) !== "ENOENT") params.onWarning?.(`Failed to read ${params.filePath}: ${String(error)}`, { error });
	if (error instanceof Error && error.message?.startsWith("File exceeds")) params.onWarning?.(`skipping oversized .env file (max ${MAX_DOTENV_FILE_BYTES} bytes): ${params.filePath}`);
}
function parseDotEnvFile(params, content) {
	const entries = [];
	for (const [rawKey, value] of Object.entries(parse(content))) {
		const key = normalizeEnvVarKey(rawKey, { portable: true });
		if (key && (params.entryFilter?.(key, value) ?? true)) entries.push({
			key,
			value
		});
	}
	return {
		filePath: params.filePath,
		entries
	};
}
function readDotEnvFileCore(params) {
	let content;
	try {
		const resolved = fs.realpathSync(params.filePath);
		const { buffer } = readRegularFileSync({
			filePath: resolved,
			maxBytes: MAX_DOTENV_FILE_BYTES
		});
		content = buffer;
	} catch (error) {
		reportDotEnvReadError(params, error);
		return null;
	}
	return parseDotEnvFile(params, content);
}
function loadParsedDotEnvFiles(files, env, overrideKeys, onWarning) {
	clearFsSafeEnvFallback(env);
	const preExistingKeys = new Set(Object.keys(env));
	const canonicalizeKey = (key) => normalizeEnvVarKey(key, { portable: true })?.toUpperCase() ?? null;
	const normalizedOverrideKeys = new Set([...overrideKeys ?? []].flatMap((key) => {
		const normalized = canonicalizeKey(key);
		return normalized ? [normalized] : [];
	}));
	const conflicts = /* @__PURE__ */ new Map();
	const firstSeen = /* @__PURE__ */ new Map();
	const appliedKeysByFile = /* @__PURE__ */ new Map();
	for (const file of files) for (const { key, value } of file.entries) {
		const canonicalKey = canonicalizeKey(key);
		const mayOverride = canonicalKey !== null && normalizedOverrideKeys.has(canonicalKey);
		const precedenceKey = mayOverride && canonicalKey ? canonicalKey : key;
		if (preExistingKeys.has(key) && !mayOverride) continue;
		const previous = firstSeen.get(precedenceKey);
		if (previous) {
			if (previous.value !== value) {
				const conflictKey = `${previous.filePath}\u0000${file.filePath}`;
				const existing = conflicts.get(conflictKey);
				if (existing) existing.keys.add(key);
				else conflicts.set(conflictKey, {
					keptPath: previous.filePath,
					ignoredPath: file.filePath,
					keys: /* @__PURE__ */ new Set([key])
				});
			}
			continue;
		}
		firstSeen.set(precedenceKey, {
			value,
			filePath: file.filePath
		});
		if (env[key] === void 0 || mayOverride) {
			if (mayOverride) {
				for (const inheritedKey of preExistingKeys) if (canonicalizeKey(inheritedKey) === canonicalKey) env[inheritedKey] = value;
			}
			env[key] = value;
			const appliedKeys = appliedKeysByFile.get(file.filePath);
			if (appliedKeys) appliedKeys.push(key);
			else appliedKeysByFile.set(file.filePath, [key]);
		}
	}
	normalizeFsSafeNativeEnv(env);
	for (const conflict of conflicts.values()) {
		const keys = [...conflict.keys].toSorted();
		onWarning?.(`Conflicting values in ${conflict.keptPath} and ${conflict.ignoredPath} for ${keys.join(", ")}; keeping ${conflict.keptPath}.`, {
			keptPath: conflict.keptPath,
			ignoredPath: conflict.ignoredPath,
			keys
		});
	}
	return appliedKeysByFile;
}
function resolveGlobalDotEnvPaths(opts, env) {
	const stateEnvPath = opts.stateEnvPath ?? path.join(resolveConfigDir(env), ".env");
	const globalEnvPaths = [.../* @__PURE__ */ new Set([stateEnvPath, ...opts.additionalEnvPaths ?? []])];
	const home = resolveRequiredHomeDir(env, os.homedir);
	const defaultStateEnvPath = path.join(home, ".openclaw", ".env");
	return {
		globalEnvPaths,
		gatewayEnvPath: env.OPENCLAW_STATE_DIR?.trim() !== void 0 && path.resolve(stateEnvPath) !== path.resolve(defaultStateEnvPath) ? void 0 : path.join(home, ".config", "openclaw", "gateway.env")
	};
}
function applyGlobalDotEnvFiles(globalEnvs, gatewayEnv, env, overrideKeys, onWarning) {
	const parsed = [...globalEnvs, gatewayEnv].filter((file) => file !== null);
	const appliedKeysByFile = loadParsedDotEnvFiles(parsed, env, overrideKeys, onWarning);
	return {
		dotenvPresentKeys: [...new Set(parsed.flatMap((file) => file.entries.map(({ key }) => key)))],
		stateEnvAppliedKeys: globalEnvs.flatMap((file) => file ? appliedKeysByFile.get(file.filePath) ?? [] : []),
		gatewayEnvAppliedKeys: gatewayEnv ? appliedKeysByFile.get(gatewayEnv.filePath) ?? [] : []
	};
}
/** Load global runtime dotenv files with first-wins precedence, defaulting to `process.env`. */
function loadGlobalRuntimeDotEnvFilesCore(opts = {}) {
	const env = opts.env ?? process.env;
	const { globalEnvPaths, gatewayEnvPath } = resolveGlobalDotEnvPaths(opts, env);
	const readOptions = {
		entryFilter: opts.entryFilter,
		quiet: opts.quiet ?? true,
		onWarning: opts.onWarning
	};
	return applyGlobalDotEnvFiles(globalEnvPaths.map((filePath) => readDotEnvFileCore({
		...readOptions,
		filePath
	})), gatewayEnvPath ? readDotEnvFileCore({
		...readOptions,
		filePath: gatewayEnvPath
	}) : null, env, opts.overrideKeys, opts.onWarning);
}
//#endregion
//#region src/infra/semver.ts
function isOpenClawCorrectionSemver(version) {
	return version.prerelease.length === 1 && typeof version.prerelease[0] === "number";
}
function toOpenClawComparableVersion(version) {
	if (isOpenClawCorrectionSemver(version)) return `${version.major}.${version.minor}.${version.patch}+${version.prerelease[0]}`;
	return version.version;
}
/** Compares prereleases, stable releases, then OpenClaw numeric corrections. */
function compareOpenClawSemver(left, right) {
	return compareBuild(toOpenClawComparableVersion(left), toOpenClawComparableVersion(right));
}
//#endregion
//#region src/infra/npm-registry-spec.ts
const OPENCLAW_RELEASE_PREFIX_RE = /^\d{4}\./;
/** Parses OpenClaw's monthly patch stable/alpha/beta/correction version format. */
function parseOpenClawReleaseVersion(value) {
	const trimmed = value.trim();
	const parsed = OPENCLAW_RELEASE_PREFIX_RE.test(trimmed) ? parse$1(trimmed) : null;
	if (!parsed || parsed.build.length > 0) return null;
	if (parsed.minor < 1 || parsed.minor > 12 || parsed.patch < 1) return null;
	const [label, sequence] = parsed.prerelease;
	const isStable = parsed.prerelease.length === 0;
	const isCorrection = isOpenClawCorrectionSemver(parsed) && typeof label === "number" && label > 0;
	const isPrerelease = parsed.prerelease.length === 2 && (label === "alpha" || label === "beta") && typeof sequence === "number" && sequence > 0;
	if (!isStable && !isCorrection && !isPrerelease) return null;
	return parsed;
}
/** Compares OpenClaw monthly patch release versions across alpha, beta, stable, and corrections. */
function compareOpenClawReleaseVersions(left, right) {
	const parsedLeft = parseOpenClawReleaseVersion(left);
	const parsedRight = parseOpenClawReleaseVersion(right);
	return parsedLeft && parsedRight ? compareOpenClawSemver(parsedLeft, parsedRight) : null;
}
//#endregion
//#region src/config/paths.ts
/**
* Nix mode detection: When OPENCLAW_NIX_MODE=1, the gateway is running under Nix.
* In this mode:
* - No auto-install flows should be attempted
* - Missing dependencies should produce actionable Nix-specific error messages
* - Config is managed externally (read-only from Nix perspective)
*/
function resolveIsNixMode(env = process.env) {
	return env.OPENCLAW_NIX_MODE === "1";
}
resolveIsNixMode();
const CONFIG_FILENAME = "openclaw.json";
const LEGACY_CONFIG_FILENAMES = ["clawdbot.json"];
function configPathsInStateDir(stateDir) {
	return [CONFIG_FILENAME, ...LEGACY_CONFIG_FILENAMES].map((name) => path.join(stateDir, name));
}
function findExistingConfigPath(candidates) {
	return candidates.find((candidate) => fs.existsSync(candidate));
}
/** Build a homedir thunk that respects OPENCLAW_HOME for the given env. */
function envHomedir(env) {
	return () => resolveRequiredHomeDir(env, os.homedir);
}
resolveStateDir();
/**
* Config file path (JSON or JSON5).
* Can be overridden via OPENCLAW_CONFIG_PATH.
* Default: ~/.openclaw/openclaw.json (or $OPENCLAW_STATE_DIR/openclaw.json)
*/
function resolveCanonicalConfigPath(env = process.env, stateDir) {
	const override = env.OPENCLAW_CONFIG_PATH?.trim();
	if (override) return resolveUserPath(override, env, envHomedir(env));
	return path.join(stateDir ?? resolveStateDir(env, envHomedir(env)), CONFIG_FILENAME);
}
/**
* Resolve the active config path by preferring existing config candidates
* before falling back to the canonical path.
*/
function resolveConfigPathCandidate(env = process.env, homedir = envHomedir(env)) {
	const override = env.OPENCLAW_CONFIG_PATH?.trim();
	if (override) return resolveUserPath(override, env, homedir);
	if (isFastTestRuntimeEnv(env)) return resolveCanonicalConfigPath(env, resolveStateDir(env, homedir));
	return findExistingConfigPath(resolveDefaultConfigCandidates(env, homedir)) ?? resolveCanonicalConfigPath(env, resolveStateDir(env, homedir));
}
resolveConfigPathCandidate();
/**
* Resolve default config path candidates across default locations.
* Order: explicit config path → state-dir-derived paths → new default.
*/
function resolveDefaultConfigCandidates(env = process.env, homedir = envHomedir(env)) {
	const effectiveHomedir = () => resolveRequiredHomeDir(env, homedir);
	const explicit = env.OPENCLAW_CONFIG_PATH?.trim();
	if (explicit) return [resolveUserPath(explicit, env, effectiveHomedir)];
	const openclawStateDir = env.OPENCLAW_STATE_DIR?.trim();
	return [
		...openclawStateDir ? [resolveUserPath(openclawStateDir, env, effectiveHomedir)] : [],
		resolveNewStateDir(effectiveHomedir),
		...resolveLegacyStateDirs(effectiveHomedir)
	].flatMap(configPathsInStateDir);
}
AsyncLocalStorage.snapshot();
//#endregion
//#region src/state/openclaw-state-db.paths.ts
/** Resolve the shared state SQLite file path. */
function resolveOpenClawStateSqlitePath(env = process.env) {
	return path.join(resolveStateDir(env), "state", "openclaw.sqlite");
}
//#endregion
//#region src/node-host/launcher-client.ts
/** A companion retains stdin's write end; EOF also retires the node after an app crash. */
function watchNodeHostParentStdin(onClose) {
	const input = process.stdin;
	let closed = false;
	const close = () => {
		if (!closed) {
			closed = true;
			onClose();
		}
	};
	input.once("end", close);
	input.once("error", close);
	input.once("close", close);
	input.resume();
	if (input.readableEnded || input.destroyed) queueMicrotask(close);
	return () => {
		closed = true;
		input.off("end", close);
		input.off("error", close);
		input.off("close", close);
		input.pause();
	};
}
//#endregion
//#region src/node-host/launcher-bootstrap.ts
function resolveNodeHostLauncherStateDir(argv, inheritedEnv) {
	const parsed = parseCliProfileArgs(argv);
	if (!parsed.ok) return null;
	const env = { ...inheritedEnv };
	if (parsed.profile) applyCliProfileEnv({
		profile: parsed.profile,
		env
	});
	loadGlobalRuntimeDotEnvFilesCore({
		env,
		stateEnvPath: path.join(resolveStateDir(env), ".env"),
		quiet: true,
		onWarning: (message) => process.stderr.write(`openclaw: ${message}\n`)
	});
	return resolveStateDir(env);
}
//#endregion
export { compareOpenClawReleaseVersions, resolveNodeHostLauncherStateDir, resolveOpenClawStateSqlitePath, watchNodeHostParentStdin };