import { c as normalizeOptionalString, d as normalizeStringifiedOptionalString } from "./string-coerce-Bje8XVt9.js";
import { t as CONFIG_PATH } from "./paths-B2cMK-wd.js";
import { t as formatDocsLink } from "./links-BszRQhGa.js";
import { r as theme } from "./theme-B128avno.js";
import { t as formatCliCommand } from "./command-format-BORwwHyH.js";
import { g as shortenHomePath } from "./utils-DvkbxKCZ.js";
import { a as coerceSecretRef, c as isValidEnvSecretRefId, p as resolveSecretInputRef } from "./types.secrets-BHp0Y_k0.js";
import { a as formatExecSecretRefIdValidationMessage, c as isValidSecretProviderAlias, d as validateExecSecretRefId, o as isValidExecSecretRefId, s as isValidFileSecretRefId, u as secretRefKey } from "./ref-contract-DtvCiPbj.js";
import { w as SecretProviderSchema } from "./zod-schema.core-urFIFYTN.js";
import { t as isBlockedObjectKey } from "./prototype-keys-B9rjoUHr.js";
import { n as discoverConfigSecretTargets, s as resolveConfigSecretTargetByPath } from "./target-registry-i1t6-neo.js";
import { n as defaultRuntime, r as writeRuntimeJson } from "./runtime-CIJX7ulQ.js";
import { n as info, o as success, t as danger } from "./globals-DJisCUAe.js";
import { a as resolveSecretRefValue } from "./resolve-VYkQwLbm.js";
import { C as validateConfigObjectRaw, u as readConfigFileSnapshot, x as collectUnsupportedSecretRefPolicyIssues } from "./io-CaVVH-CQ.js";
import { r as replaceConfigFile } from "./mutate-C86tBthp.js";
import "./config-B9rKdgUB.js";
import { a as normalizeConfigIssues, n as formatConfigIssueLines } from "./issue-format-DPCYJ_FB.js";
import { n as redactConfigObject } from "./redact-snapshot-CS26egqY.js";
import { n as readBestEffortRuntimeConfigSchema } from "./runtime-schema-4BT5hf-I.js";
import { n as setCommandJsonMode } from "./json-mode-CRyTy3ku.js";
import fs from "node:fs";
import JSON5 from "json5";
//#region src/cli/config-set-input.ts
function hasBatchMode(opts) {
	return Boolean(normalizeOptionalString(opts.batchJson) || normalizeOptionalString(opts.batchFile));
}
function hasRefBuilderOptions(opts) {
	return Boolean(opts.refProvider || opts.refSource || opts.refId);
}
function hasProviderBuilderOptions(opts) {
	return Boolean(opts.providerSource || opts.providerAllowlist?.length || opts.providerPath || opts.providerMode || opts.providerTimeoutMs || opts.providerMaxBytes || opts.providerCommand || opts.providerArg?.length || opts.providerNoOutputTimeoutMs || opts.providerMaxOutputBytes || opts.providerJsonOnly || opts.providerEnv?.length || opts.providerPassEnv?.length || opts.providerTrustedDir?.length || opts.providerAllowInsecurePath || opts.providerAllowSymlinkCommand);
}
function parseJson5Raw(raw, label) {
	try {
		return JSON5.parse(raw);
	} catch (err) {
		throw new Error(`Failed to parse ${label}: ${String(err)}`, { cause: err });
	}
}
function parseBatchEntries(raw, sourceLabel) {
	const parsed = parseJson5Raw(raw, sourceLabel);
	if (!Array.isArray(parsed)) throw new Error(`${sourceLabel} must be a JSON array.`);
	const out = [];
	for (const [index, entry] of parsed.entries()) {
		if (!entry || typeof entry !== "object" || Array.isArray(entry)) throw new Error(`${sourceLabel}[${index}] must be an object.`);
		const typed = entry;
		const path = normalizeOptionalString(typed.path) ?? "";
		if (!path) throw new Error(`${sourceLabel}[${index}].path is required.`);
		const hasValue = Object.prototype.hasOwnProperty.call(typed, "value");
		const hasRef = Object.prototype.hasOwnProperty.call(typed, "ref");
		const hasProvider = Object.prototype.hasOwnProperty.call(typed, "provider");
		if (Number(hasValue) + Number(hasRef) + Number(hasProvider) !== 1) throw new Error(`${sourceLabel}[${index}] must include exactly one of: value, ref, provider.`);
		out.push({
			path,
			...hasValue ? { value: typed.value } : {},
			...hasRef ? { ref: typed.ref } : {},
			...hasProvider ? { provider: typed.provider } : {}
		});
	}
	return out;
}
function parseBatchSource(opts) {
	const batchJson = normalizeOptionalString(opts.batchJson);
	const batchFile = normalizeOptionalString(opts.batchFile);
	const hasInline = Boolean(batchJson);
	const hasFile = Boolean(batchFile);
	if (!hasInline && !hasFile) return null;
	if (hasInline && hasFile) throw new Error("Use either --batch-json or --batch-file, not both.");
	if (hasInline) return parseBatchEntries(batchJson, "--batch-json");
	const pathname = normalizeStringifiedOptionalString(opts.batchFile) ?? "";
	if (!pathname) throw new Error("--batch-file must not be empty.");
	return parseBatchEntries(fs.readFileSync(pathname, "utf8"), "--batch-file");
}
//#endregion
//#region src/cli/config-set-parser.ts
function resolveConfigSetMode(params) {
	if (params.hasBatchMode) {
		if (params.hasRefBuilderOptions || params.hasProviderBuilderOptions) return {
			ok: false,
			error: "batch mode (--batch-json/--batch-file) cannot be combined with ref builder (--ref-*) or provider builder (--provider-*) flags."
		};
		return {
			ok: true,
			mode: "batch"
		};
	}
	if (params.hasRefBuilderOptions && params.hasProviderBuilderOptions) return {
		ok: false,
		error: "choose exactly one mode: ref builder (--ref-provider/--ref-source/--ref-id) or provider builder (--provider-*), not both."
	};
	if (params.hasRefBuilderOptions) return {
		ok: true,
		mode: "ref_builder"
	};
	if (params.hasProviderBuilderOptions) return {
		ok: true,
		mode: "provider_builder"
	};
	return {
		ok: true,
		mode: params.strictJson ? "json" : "value"
	};
}
//#endregion
//#region src/cli/config-cli.ts
const GATEWAY_AUTH_MODE_PATH = [
	"gateway",
	"auth",
	"mode"
];
const SECRET_PROVIDER_PATH_PREFIX = ["secrets", "providers"];
const PLUGIN_INSTALL_RECORD_PATH_PREFIX = ["plugins", "installs"];
const CONFIG_SET_DESCRIPTION = [
	"Set config values by path (value mode, ref/provider builder mode, or batch JSON mode).",
	"Examples:",
	formatCliCommand("openclaw config set gateway.port 19001 --strict-json"),
	formatCliCommand("openclaw config set channels.discord.token --ref-provider default --ref-source env --ref-id DISCORD_BOT_TOKEN"),
	formatCliCommand("openclaw config set secrets.providers.vault --provider-source file --provider-path /etc/openclaw/secrets.json --provider-mode json"),
	formatCliCommand("openclaw config set --batch-file ./config-set.batch.json --dry-run")
].join("\n");
const CONFIG_SET_POLICY_ERROR_MAX_ISSUES = 5;
var ConfigSetDryRunValidationError = class extends Error {
	constructor(result) {
		super("config set dry-run validation failed");
		this.result = result;
		this.name = "ConfigSetDryRunValidationError";
	}
};
function isIndexSegment(raw) {
	return /^[0-9]+$/.test(raw);
}
function parseBracketPathSegment(raw, fullPath) {
	const trimmed = raw.trim();
	if (!trimmed) throw new Error(`Invalid path (empty "[]"): ${fullPath}`);
	if (trimmed.startsWith("\"") || trimmed.startsWith("'")) {
		try {
			const parsed = JSON5.parse(trimmed);
			if (typeof parsed === "string" && parsed.trim()) return parsed;
		} catch (err) {
			throw new Error(`Invalid path bracket string (${trimmed}): ${fullPath}`, { cause: err });
		}
		throw new Error(`Invalid path bracket string (${trimmed}): ${fullPath}`);
	}
	return trimmed;
}
function parsePath(raw) {
	const trimmed = raw.trim();
	if (!trimmed) return [];
	const parts = [];
	let current = "";
	let i = 0;
	while (i < trimmed.length) {
		const ch = trimmed[i];
		if (ch === "\\") {
			const next = trimmed[i + 1];
			if (next) current += next;
			i += 2;
			continue;
		}
		if (ch === ".") {
			if (current) parts.push(current);
			current = "";
			i += 1;
			continue;
		}
		if (ch === "[") {
			if (current) parts.push(current);
			current = "";
			const close = trimmed.indexOf("]", i);
			if (close === -1) throw new Error(`Invalid path (missing "]"): ${raw}`);
			const inside = trimmed.slice(i + 1, close).trim();
			if (!inside) throw new Error(`Invalid path (empty "[]"): ${raw}`);
			parts.push(parseBracketPathSegment(inside, raw));
			i = close + 1;
			continue;
		}
		current += ch;
		i += 1;
	}
	if (current) parts.push(current);
	return parts.map((part) => part.trim()).filter(Boolean);
}
function parseValue(raw, opts) {
	const trimmed = raw.trim();
	if (opts.strictJson) try {
		return JSON.parse(trimmed);
	} catch (err) {
		throw new Error(`Failed to parse JSON value: ${String(err)}`, { cause: err });
	}
	try {
		return JSON5.parse(trimmed);
	} catch {
		return raw;
	}
}
function hasOwnPathKey(value, key) {
	return Object.prototype.hasOwnProperty.call(value, key);
}
function isPlainRecord(value) {
	return Boolean(value && typeof value === "object" && !Array.isArray(value));
}
function formatDoctorHint(message) {
	return `Run \`${formatCliCommand("openclaw doctor")}\` ${message}`;
}
function formatUnsupportedSecretRefPolicyFailureMessage(issues) {
	const lines = ["Config policy validation failed: unsupported SecretRef usage was detected.", ...issues.slice(0, CONFIG_SET_POLICY_ERROR_MAX_ISSUES).map((issue) => `- ${issue}`)];
	if (issues.length > CONFIG_SET_POLICY_ERROR_MAX_ISSUES) lines.push(`- ... ${issues.length - CONFIG_SET_POLICY_ERROR_MAX_ISSUES} more`);
	return lines.join("\n");
}
function validatePathSegments(path) {
	for (const segment of path) if (!isIndexSegment(segment) && isBlockedObjectKey(segment)) throw new Error(`Invalid path segment: ${segment}`);
}
function getAtPath(root, path) {
	let current = root;
	for (const segment of path) {
		if (!current || typeof current !== "object") return { found: false };
		if (Array.isArray(current)) {
			if (!isIndexSegment(segment)) return { found: false };
			const index = Number.parseInt(segment, 10);
			if (!Number.isFinite(index) || index < 0 || index >= current.length) return { found: false };
			current = current[index];
			continue;
		}
		const record = current;
		if (!hasOwnPathKey(record, segment)) return { found: false };
		current = record[segment];
	}
	return {
		found: true,
		value: current
	};
}
function setAtPath(root, path, value) {
	let current = root;
	for (let i = 0; i < path.length - 1; i += 1) {
		const segment = path[i];
		const next = path[i + 1];
		const nextIsIndex = Boolean(next && isIndexSegment(next));
		if (Array.isArray(current)) {
			if (!isIndexSegment(segment)) throw new Error(`Expected numeric index for array segment "${segment}"`);
			const index = Number.parseInt(segment, 10);
			const existing = current[index];
			if (!existing || typeof existing !== "object") current[index] = nextIsIndex ? [] : {};
			current = current[index];
			continue;
		}
		if (!current || typeof current !== "object") throw new Error(`Cannot traverse into "${segment}" (not an object)`);
		const record = current;
		const existing = hasOwnPathKey(record, segment) ? record[segment] : void 0;
		if (!existing || typeof existing !== "object") record[segment] = nextIsIndex ? [] : {};
		current = record[segment];
	}
	const last = path[path.length - 1];
	if (Array.isArray(current)) {
		if (!isIndexSegment(last)) throw new Error(`Expected numeric index for array segment "${last}"`);
		const index = Number.parseInt(last, 10);
		current[index] = value;
		return;
	}
	if (!current || typeof current !== "object") throw new Error(`Cannot set "${last}" (parent is not an object)`);
	current[last] = value;
}
function modelArrayIds(value) {
	if (!Array.isArray(value)) return null;
	const ids = /* @__PURE__ */ new Set();
	for (const entry of value) {
		if (!isPlainRecord(entry) || typeof entry.id !== "string" || !entry.id.trim()) return null;
		ids.add(entry.id.trim());
	}
	return ids;
}
function mergeModelArrays(existing, patch) {
	const merged = [...existing];
	const indexById = /* @__PURE__ */ new Map();
	for (const [index, entry] of merged.entries()) if (isPlainRecord(entry) && typeof entry.id === "string" && entry.id.trim()) indexById.set(entry.id.trim(), index);
	for (const entry of patch) {
		if (!isPlainRecord(entry) || typeof entry.id !== "string" || !entry.id.trim()) {
			merged.push(entry);
			continue;
		}
		const id = entry.id.trim();
		const existingIndex = indexById.get(id);
		if (existingIndex === void 0) {
			indexById.set(id, merged.length);
			merged.push(entry);
			continue;
		}
		const existingEntry = merged[existingIndex];
		merged[existingIndex] = isPlainRecord(existingEntry) ? {
			...existingEntry,
			...entry
		} : entry;
	}
	return merged;
}
function mergeConfigValue(existing, patch, path) {
	if (isProviderModelListPath(path) && Array.isArray(existing) && Array.isArray(patch)) return mergeModelArrays(existing, patch);
	if (isPlainRecord(existing) && isPlainRecord(patch)) {
		const next = { ...existing };
		for (const [key, value] of Object.entries(patch)) next[key] = hasOwnPathKey(next, key) && isPlainRecord(next[key]) && isPlainRecord(value) ? mergeConfigValue(next[key], value, [...path, key]) : value;
		return next;
	}
	throw new Error(`Cannot merge ${toDotPath(path)}; use --replace to replace intentionally.`);
}
function mergeAtPath(root, path, value) {
	const existing = getAtPath(root, path);
	if (!existing.found) {
		setAtPath(root, path, value);
		return;
	}
	setAtPath(root, path, mergeConfigValue(existing.value, value, path));
}
function isProviderModelListPath(path) {
	return path.length === 4 && path[0] === "models" && path[1] === "providers" && path[3] === "models";
}
function isProtectedMapReplacementPath(path) {
	if (path.join(".") === "agents.defaults.models") return true;
	if (path.join(".") === "models.providers") return true;
	if (path.length === 3 && path[0] === "models" && path[1] === "providers") return true;
	if (path.join(".") === "plugins.entries") return true;
	if (path.join(".") === "auth.profiles") return true;
	return false;
}
function isProtectedArrayReplacementPath(path) {
	return isProviderModelListPath(path) || path.join(".") === "agents.list";
}
function formatRemovedEntries(entries) {
	const visible = entries.slice(0, 6);
	const suffix = entries.length > visible.length ? `, ... ${entries.length - visible.length} more` : "";
	return `${visible.join(", ")}${suffix}`;
}
function assertNonDestructiveReplacement(params) {
	if (params.allowReplace) return;
	const existing = getAtPath(params.root, params.path);
	if (!existing.found) return;
	const pathLabel = toDotPath(params.path);
	if (isProtectedMapReplacementPath(params.path) && isPlainRecord(existing.value)) {
		if (!isPlainRecord(params.value)) return;
		const nextKeys = new Set(Object.keys(params.value));
		const removed = Object.keys(existing.value).filter((key) => !nextKeys.has(key));
		if (removed.length > 0) throw new Error(`Refusing to replace ${pathLabel}; it would remove existing entries: ${formatRemovedEntries(removed)}. Use --merge to merge object values or --replace to replace intentionally.`);
	}
	if (isProtectedArrayReplacementPath(params.path)) {
		const existingIds = modelArrayIds(existing.value);
		const nextIds = modelArrayIds(params.value);
		if (!existingIds || !nextIds) return;
		const removed = [...existingIds].filter((id) => !nextIds.has(id));
		if (removed.length > 0) throw new Error(`Refusing to replace ${pathLabel}; it would remove existing entries: ${formatRemovedEntries(removed)}. Use --merge to merge by id or --replace to replace intentionally.`);
	}
}
function unsetAtPath(root, path) {
	let current = root;
	for (let i = 0; i < path.length - 1; i += 1) {
		const segment = path[i];
		if (!current || typeof current !== "object") return false;
		if (Array.isArray(current)) {
			if (!isIndexSegment(segment)) return false;
			const index = Number.parseInt(segment, 10);
			if (!Number.isFinite(index) || index < 0 || index >= current.length) return false;
			current = current[index];
			continue;
		}
		const record = current;
		if (!hasOwnPathKey(record, segment)) return false;
		current = record[segment];
	}
	const last = path[path.length - 1];
	if (Array.isArray(current)) {
		if (!isIndexSegment(last)) return false;
		const index = Number.parseInt(last, 10);
		if (!Number.isFinite(index) || index < 0 || index >= current.length) return false;
		current.splice(index, 1);
		return true;
	}
	if (!current || typeof current !== "object") return false;
	const record = current;
	if (!hasOwnPathKey(record, last)) return false;
	delete record[last];
	return true;
}
async function loadValidConfig(runtime = defaultRuntime) {
	const snapshot = await readConfigFileSnapshot();
	if (snapshot.valid) return snapshot;
	runtime.error(`Config invalid at ${shortenHomePath(snapshot.path)}.`);
	for (const line of formatConfigIssueLines(snapshot.issues, "-", { normalizeRoot: true })) runtime.error(line);
	runtime.error(formatDoctorHint("to repair, then retry."));
	runtime.exit(1);
	return snapshot;
}
function parseRequiredPath(path) {
	const parsedPath = parsePath(path);
	if (parsedPath.length === 0) throw new Error("Path is empty.");
	validatePathSegments(parsedPath);
	return parsedPath;
}
function pathEquals(path, expected) {
	return path.length === expected.length && path.every((segment, index) => segment === expected[index]);
}
function pruneInactiveGatewayAuthCredentials(params) {
	if (!params.operations.some((operation) => pathEquals(operation.requestedPath, GATEWAY_AUTH_MODE_PATH))) return [];
	const gatewayRaw = params.root.gateway;
	if (!gatewayRaw || typeof gatewayRaw !== "object" || Array.isArray(gatewayRaw)) return [];
	const authRaw = gatewayRaw.auth;
	if (!authRaw || typeof authRaw !== "object" || Array.isArray(authRaw)) return [];
	const auth = authRaw;
	const mode = normalizeOptionalString(auth.mode) ?? "";
	const removedPaths = [];
	const remove = (key) => {
		if (Object.hasOwn(auth, key)) {
			delete auth[key];
			removedPaths.push(`gateway.auth.${key}`);
		}
	};
	if (mode === "token") remove("password");
	else if (mode === "password") remove("token");
	else if (mode === "trusted-proxy") {
		remove("token");
		remove("password");
	}
	return removedPaths;
}
function toDotPath(path) {
	return path.join(".");
}
function parseSecretRefSource(raw, label) {
	const source = raw.trim();
	if (source === "env" || source === "file" || source === "exec") return source;
	throw new Error(`${label} must be one of: env, file, exec.`);
}
function parseSecretRefBuilder(params) {
	const provider = params.provider.trim();
	if (!provider) throw new Error(`${params.fieldPrefix}.provider is required.`);
	if (!isValidSecretProviderAlias(provider)) throw new Error(`${params.fieldPrefix}.provider must match /^[a-z][a-z0-9_-]{0,63}$/ (example: "default").`);
	const source = parseSecretRefSource(params.source, `${params.fieldPrefix}.source`);
	const id = params.id.trim();
	if (!id) throw new Error(`${params.fieldPrefix}.id is required.`);
	if (source === "env" && !isValidEnvSecretRefId(id)) throw new Error(`${params.fieldPrefix}.id must match /^[A-Z][A-Z0-9_]{0,127}$/ for env refs.`);
	if (source === "file" && !isValidFileSecretRefId(id)) throw new Error(`${params.fieldPrefix}.id must be an absolute JSON pointer (or "value" for singleValue mode).`);
	if (source === "exec") {
		if (!validateExecSecretRefId(id).ok) throw new Error(formatExecSecretRefIdValidationMessage());
	}
	return {
		source,
		provider,
		id
	};
}
function parseOptionalPositiveInteger(raw, flag) {
	if (raw === void 0) return;
	const trimmed = raw.trim();
	if (!trimmed) throw new Error(`${flag} must not be empty.`);
	const parsed = Number(trimmed);
	if (!Number.isInteger(parsed) || parsed <= 0) throw new Error(`${flag} must be a positive integer.`);
	return parsed;
}
function parseProviderEnvEntries(entries) {
	if (!entries || entries.length === 0) return;
	const env = {};
	for (const entry of entries) {
		const separator = entry.indexOf("=");
		if (separator <= 0) throw new Error(`--provider-env expects KEY=VALUE entries (received: "${entry}").`);
		const key = entry.slice(0, separator).trim();
		if (!key) throw new Error(`--provider-env key must not be empty (received: "${entry}").`);
		env[key] = entry.slice(separator + 1);
	}
	return Object.keys(env).length > 0 ? env : void 0;
}
function parseProviderAliasPath(path) {
	if (!(path.length === 3 && path[0] === SECRET_PROVIDER_PATH_PREFIX[0] && path[1] === SECRET_PROVIDER_PATH_PREFIX[1])) throw new Error("Provider builder mode requires path \"secrets.providers.<alias>\" (example: secrets.providers.vault).");
	const alias = path[2] ?? "";
	if (!isValidSecretProviderAlias(alias)) throw new Error(`Provider alias "${alias}" must match /^[a-z][a-z0-9_-]{0,63}$/ (example: "default").`);
	return alias;
}
function buildProviderFromBuilder(opts) {
	const sourceRaw = opts.providerSource?.trim();
	if (!sourceRaw) throw new Error("--provider-source is required in provider builder mode.");
	const source = parseSecretRefSource(sourceRaw, "--provider-source");
	const timeoutMs = parseOptionalPositiveInteger(opts.providerTimeoutMs, "--provider-timeout-ms");
	const maxBytes = parseOptionalPositiveInteger(opts.providerMaxBytes, "--provider-max-bytes");
	const noOutputTimeoutMs = parseOptionalPositiveInteger(opts.providerNoOutputTimeoutMs, "--provider-no-output-timeout-ms");
	const maxOutputBytes = parseOptionalPositiveInteger(opts.providerMaxOutputBytes, "--provider-max-output-bytes");
	const providerEnv = parseProviderEnvEntries(opts.providerEnv);
	let provider;
	if (source === "env") {
		const allowlist = (opts.providerAllowlist ?? []).map((entry) => entry.trim()).filter(Boolean);
		for (const envName of allowlist) if (!isValidEnvSecretRefId(envName)) throw new Error(`--provider-allowlist entry "${envName}" must match /^[A-Z][A-Z0-9_]{0,127}$/.`);
		provider = {
			source: "env",
			...allowlist.length > 0 ? { allowlist } : {}
		};
	} else if (source === "file") {
		const filePath = opts.providerPath?.trim();
		if (!filePath) throw new Error("--provider-path is required when --provider-source file is used.");
		const modeRaw = opts.providerMode?.trim();
		if (modeRaw && modeRaw !== "singleValue" && modeRaw !== "json") throw new Error("--provider-mode must be one of: singleValue, json.");
		const mode = modeRaw === "singleValue" || modeRaw === "json" ? modeRaw : void 0;
		provider = {
			source: "file",
			path: filePath,
			...mode ? { mode } : {},
			...timeoutMs !== void 0 ? { timeoutMs } : {},
			...maxBytes !== void 0 ? { maxBytes } : {},
			...opts.providerAllowInsecurePath ? { allowInsecurePath: true } : {}
		};
	} else {
		const command = opts.providerCommand?.trim();
		if (!command) throw new Error("--provider-command is required when --provider-source exec is used.");
		provider = {
			source: "exec",
			command,
			...opts.providerArg && opts.providerArg.length > 0 ? { args: opts.providerArg.map((entry) => entry.trim()) } : {},
			...timeoutMs !== void 0 ? { timeoutMs } : {},
			...noOutputTimeoutMs !== void 0 ? { noOutputTimeoutMs } : {},
			...maxOutputBytes !== void 0 ? { maxOutputBytes } : {},
			...opts.providerJsonOnly ? { jsonOnly: true } : {},
			...providerEnv ? { env: providerEnv } : {},
			...opts.providerPassEnv && opts.providerPassEnv.length > 0 ? { passEnv: opts.providerPassEnv.map((entry) => entry.trim()).filter(Boolean) } : {},
			...opts.providerTrustedDir && opts.providerTrustedDir.length > 0 ? { trustedDirs: opts.providerTrustedDir.map((entry) => entry.trim()).filter(Boolean) } : {},
			...opts.providerAllowInsecurePath ? { allowInsecurePath: true } : {},
			...opts.providerAllowSymlinkCommand ? { allowSymlinkCommand: true } : {}
		};
	}
	const validated = SecretProviderSchema.safeParse(provider);
	if (!validated.success) {
		const issue = validated.error.issues[0];
		const issuePath = issue?.path?.join(".") ?? "<provider>";
		const issueMessage = issue?.message ?? "Invalid provider config.";
		throw new Error(`Provider builder config invalid at ${issuePath}: ${issueMessage}`);
	}
	return validated.data;
}
function parseSecretRefFromUnknown(value, label) {
	if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error(`${label} must be an object with source/provider/id.`);
	const candidate = value;
	if (typeof candidate.provider !== "string" || typeof candidate.source !== "string" || typeof candidate.id !== "string") throw new Error(`${label} must include string fields: source, provider, id.`);
	return parseSecretRefBuilder({
		provider: candidate.provider,
		source: candidate.source,
		id: candidate.id,
		fieldPrefix: label
	});
}
function buildRefAssignmentOperation(params) {
	const resolved = resolveConfigSecretTargetByPath(params.requestedPath);
	if (resolved?.entry.secretShape === "sibling_ref" && resolved.refPathSegments) return {
		inputMode: params.inputMode,
		requestedPath: params.requestedPath,
		setPath: resolved.refPathSegments,
		value: params.ref,
		schemaValidated: true,
		touchedSecretTargetPath: toDotPath(resolved.pathSegments),
		assignedRef: params.ref,
		...resolved.providerId ? { touchedProviderAlias: resolved.providerId } : {}
	};
	return {
		inputMode: params.inputMode,
		requestedPath: params.requestedPath,
		setPath: params.requestedPath,
		value: params.ref,
		schemaValidated: true,
		touchedSecretTargetPath: resolved ? toDotPath(resolved.pathSegments) : toDotPath(params.requestedPath),
		assignedRef: params.ref,
		...resolved?.providerId ? { touchedProviderAlias: resolved.providerId } : {}
	};
}
function parseProviderAliasFromTargetPath(path) {
	if (path.length >= 3 && path[0] === SECRET_PROVIDER_PATH_PREFIX[0] && path[1] === SECRET_PROVIDER_PATH_PREFIX[1]) return path[2] ?? null;
	return null;
}
function buildValueAssignmentOperation(params) {
	const resolved = resolveConfigSecretTargetByPath(params.requestedPath);
	const providerAlias = parseProviderAliasFromTargetPath(params.requestedPath);
	const coercedRef = coerceSecretRef(params.value);
	return {
		inputMode: params.inputMode,
		requestedPath: params.requestedPath,
		setPath: params.requestedPath,
		value: params.value,
		...resolved ? { touchedSecretTargetPath: toDotPath(resolved.pathSegments) } : {},
		...providerAlias ? { touchedProviderAlias: providerAlias } : {},
		...coercedRef ? { assignedRef: coercedRef } : {}
	};
}
function parseBatchOperations(entries) {
	const operations = [];
	for (const [index, entry] of entries.entries()) {
		const path = parseRequiredPath(entry.path);
		if (entry.ref !== void 0) {
			const ref = parseSecretRefFromUnknown(entry.ref, `batch[${index}].ref`);
			operations.push(buildRefAssignmentOperation({
				requestedPath: path,
				ref,
				inputMode: "json"
			}));
			continue;
		}
		if (entry.provider !== void 0) {
			const alias = parseProviderAliasPath(path);
			const validated = SecretProviderSchema.safeParse(entry.provider);
			if (!validated.success) {
				const issue = validated.error.issues[0];
				const issuePath = issue?.path?.join(".") ?? "<provider>";
				throw new Error(`batch[${index}].provider invalid at ${issuePath}: ${issue?.message ?? ""}`);
			}
			operations.push({
				inputMode: "json",
				requestedPath: path,
				setPath: path,
				value: validated.data,
				schemaValidated: true,
				touchedProviderAlias: alias
			});
			continue;
		}
		operations.push(buildValueAssignmentOperation({
			requestedPath: path,
			value: entry.value,
			inputMode: "json"
		}));
	}
	return operations;
}
function modeError(message) {
	return /* @__PURE__ */ new Error(`config set mode error: ${message}`);
}
function buildSingleSetOperations(params) {
	const pathProvided = typeof params.path === "string" && params.path.trim().length > 0;
	const parsedPath = pathProvided ? parseRequiredPath(params.path) : null;
	const strictJson = Boolean(params.opts.strictJson || params.opts.json);
	const modeResolution = resolveConfigSetMode({
		hasBatchMode: false,
		hasRefBuilderOptions: hasRefBuilderOptions(params.opts),
		hasProviderBuilderOptions: hasProviderBuilderOptions(params.opts),
		strictJson
	});
	if (!modeResolution.ok) throw modeError(modeResolution.error);
	if (modeResolution.mode === "ref_builder") {
		if (!pathProvided || !parsedPath) throw modeError("ref builder mode requires <path>.");
		if (params.value !== void 0) throw modeError("ref builder mode does not accept <value>.");
		if (!params.opts.refProvider || !params.opts.refSource || !params.opts.refId) throw modeError("ref builder mode requires --ref-provider <alias>, --ref-source <env|file|exec>, and --ref-id <id>.");
		return [buildRefAssignmentOperation({
			requestedPath: parsedPath,
			ref: parseSecretRefBuilder({
				provider: params.opts.refProvider,
				source: params.opts.refSource,
				id: params.opts.refId,
				fieldPrefix: "ref"
			}),
			inputMode: "builder"
		})];
	}
	if (modeResolution.mode === "provider_builder") {
		if (!pathProvided || !parsedPath) throw modeError("provider builder mode requires <path>.");
		if (params.value !== void 0) throw modeError("provider builder mode does not accept <value>.");
		const alias = parseProviderAliasPath(parsedPath);
		return [{
			inputMode: "builder",
			requestedPath: parsedPath,
			setPath: parsedPath,
			value: buildProviderFromBuilder(params.opts),
			schemaValidated: true,
			touchedProviderAlias: alias
		}];
	}
	if (!pathProvided || !parsedPath) throw modeError("value/json mode requires <path> when batch mode is not used.");
	if (params.value === void 0) throw modeError("value/json mode requires <value>.");
	return [buildValueAssignmentOperation({
		requestedPath: parsedPath,
		value: parseValue(params.value, { strictJson }),
		inputMode: modeResolution.mode === "json" ? "json" : "value"
	})];
}
function collectDryRunRefs(params) {
	const refsByKey = /* @__PURE__ */ new Map();
	const targetPaths = /* @__PURE__ */ new Set();
	const providerAliases = /* @__PURE__ */ new Set();
	for (const operation of params.operations) {
		if (operation.assignedRef) refsByKey.set(secretRefKey(operation.assignedRef), operation.assignedRef);
		if (operation.touchedSecretTargetPath) targetPaths.add(operation.touchedSecretTargetPath);
		if (operation.touchedProviderAlias) providerAliases.add(operation.touchedProviderAlias);
	}
	if (targetPaths.size === 0 && providerAliases.size === 0) return [...refsByKey.values()];
	const defaults = params.config.secrets?.defaults;
	for (const target of discoverConfigSecretTargets(params.config)) {
		const { ref } = resolveSecretInputRef({
			value: target.value,
			refValue: target.refValue,
			defaults
		});
		if (!ref) continue;
		if (targetPaths.has(target.path) || providerAliases.has(ref.provider)) refsByKey.set(secretRefKey(ref), ref);
	}
	return [...refsByKey.values()];
}
async function collectDryRunResolvabilityErrors(params) {
	const failures = [];
	for (const ref of params.refs) try {
		await resolveSecretRefValue(ref, {
			config: params.config,
			env: process.env
		});
	} catch (err) {
		failures.push({
			kind: "resolvability",
			message: String(err),
			ref: `${ref.source}:${ref.provider}:${ref.id}`
		});
	}
	return failures;
}
function collectDryRunStaticErrorsForSkippedExecRefs(params) {
	const failures = [];
	for (const ref of params.refs) {
		const id = ref.id.trim();
		const refLabel = `${ref.source}:${ref.provider}:${id}`;
		if (!id) {
			failures.push({
				kind: "resolvability",
				message: "Error: Secret reference id is empty.",
				ref: refLabel
			});
			continue;
		}
		if (!isValidExecSecretRefId(id)) {
			failures.push({
				kind: "resolvability",
				message: `Error: ${formatExecSecretRefIdValidationMessage()} (ref: ${refLabel}).`,
				ref: refLabel
			});
			continue;
		}
		const providerConfig = params.config.secrets?.providers?.[ref.provider];
		if (!providerConfig) {
			failures.push({
				kind: "resolvability",
				message: `Error: Secret provider "${ref.provider}" is not configured (ref: ${refLabel}).`,
				ref: refLabel
			});
			continue;
		}
		if (providerConfig.source !== ref.source) failures.push({
			kind: "resolvability",
			message: `Error: Secret provider "${ref.provider}" has source "${providerConfig.source}" but ref requests "${ref.source}".`,
			ref: refLabel
		});
	}
	return failures;
}
function selectDryRunRefsForResolution(params) {
	const refsToResolve = [];
	const skippedExecRefs = [];
	for (const ref of params.refs) {
		if (ref.source === "exec" && !params.allowExecInDryRun) {
			skippedExecRefs.push(ref);
			continue;
		}
		refsToResolve.push(ref);
	}
	return {
		refsToResolve,
		skippedExecRefs
	};
}
function pathStartsWith(path, prefix) {
	return prefix.every((segment, index) => path[index] === segment);
}
function formatPluginInstallConfigSetError() {
	return [
		"plugins.installs is managed by the plugin index and cannot be edited with config set.",
		"",
		"Use plugin commands instead:",
		`  ${formatCliCommand("openclaw plugins install <spec>")}`,
		`  ${formatCliCommand("openclaw plugins update <plugin-id>")}`,
		`  ${formatCliCommand("openclaw plugins uninstall <plugin-id>")}`
	].join("\n");
}
function collectDryRunSchemaErrors(params) {
	const validated = validateConfigObjectRaw(params.config, { touchedPaths: params.operations.map((operation) => operation.setPath) });
	if (validated.ok) return [];
	return formatConfigIssueLines(validated.issues, "-", { normalizeRoot: true }).map((message) => ({
		kind: "schema",
		message
	}));
}
function dedupeDryRunErrors(errors) {
	const deduped = [];
	const seen = /* @__PURE__ */ new Set();
	for (const error of errors) {
		const key = error.kind === "resolvability" ? `${error.kind}\u0000${error.ref ?? ""}\u0000${error.message}` : `${error.kind}\u0000${error.message}`;
		if (seen.has(key)) continue;
		seen.add(key);
		deduped.push(error);
	}
	return deduped;
}
function formatDryRunFailureMessage(params) {
	const { errors, skippedExecRefs } = params;
	const schemaErrors = errors.filter((error) => error.kind === "schema");
	const resolveErrors = errors.filter((error) => error.kind === "resolvability");
	const lines = [];
	if (schemaErrors.length > 0) {
		lines.push("Dry run failed: config schema validation failed.");
		lines.push(...schemaErrors.map((error) => `- ${error.message}`));
	}
	if (resolveErrors.length > 0) {
		lines.push(`Dry run failed: ${resolveErrors.length} SecretRef assignment(s) could not be resolved.`);
		lines.push(...resolveErrors.slice(0, 5).map((error) => `- ${error.ref ?? "<unknown-ref>"} -> ${error.message}`));
		if (resolveErrors.length > 5) lines.push(`- ... ${resolveErrors.length - 5} more`);
	}
	if (skippedExecRefs > 0) lines.push(`Dry run note: skipped ${skippedExecRefs} exec SecretRef resolvability check(s). Re-run with --allow-exec to execute exec providers during dry-run.`);
	return lines.join("\n");
}
async function runConfigSet(opts) {
	const runtime = opts.runtime ?? defaultRuntime;
	try {
		const modeResolution = resolveConfigSetMode({
			hasBatchMode: hasBatchMode(opts.cliOptions),
			hasRefBuilderOptions: hasRefBuilderOptions(opts.cliOptions),
			hasProviderBuilderOptions: hasProviderBuilderOptions(opts.cliOptions),
			strictJson: Boolean(opts.cliOptions.strictJson || opts.cliOptions.json)
		});
		if (!modeResolution.ok) throw modeError(modeResolution.error);
		if (opts.cliOptions.allowExec && !opts.cliOptions.dryRun) throw modeError("--allow-exec requires --dry-run.");
		if (opts.cliOptions.merge && opts.cliOptions.replace) throw modeError("choose either --merge or --replace, not both.");
		const batchEntries = parseBatchSource(opts.cliOptions);
		if (batchEntries) {
			if (opts.path !== void 0 || opts.value !== void 0) throw modeError("batch mode does not accept <path> or <value> arguments.");
		}
		const operations = batchEntries ? parseBatchOperations(batchEntries) : buildSingleSetOperations({
			path: opts.path,
			value: opts.value,
			opts: opts.cliOptions
		});
		if (operations.some((operation) => pathStartsWith(operation.requestedPath, PLUGIN_INSTALL_RECORD_PATH_PREFIX))) throw new Error(formatPluginInstallConfigSetError());
		const snapshot = await loadValidConfig(runtime);
		const next = structuredClone(snapshot.resolved);
		for (const operation of operations) if (opts.cliOptions.merge) mergeAtPath(next, operation.setPath, operation.value);
		else {
			assertNonDestructiveReplacement({
				root: next,
				path: operation.setPath,
				value: operation.value,
				allowReplace: opts.cliOptions.replace
			});
			setAtPath(next, operation.setPath, operation.value);
		}
		const removedGatewayAuthPaths = pruneInactiveGatewayAuthCredentials({
			root: next,
			operations
		});
		const nextConfig = next;
		const policyIssueLines = formatConfigIssueLines(collectUnsupportedSecretRefPolicyIssues(nextConfig), "", { normalizeRoot: true }).map((line) => line.trim());
		if (opts.cliOptions.dryRun) {
			const hasJsonMode = operations.some((operation) => operation.inputMode === "json");
			const hasBuilderMode = operations.some((operation) => operation.inputMode === "builder");
			const requiresFullSchemaValidation = operations.some((operation) => operation.inputMode === "json" && operation.schemaValidated !== true);
			const selectedDryRunRefs = selectDryRunRefsForResolution({
				refs: hasJsonMode || hasBuilderMode ? collectDryRunRefs({
					config: nextConfig,
					operations
				}) : [],
				allowExecInDryRun: Boolean(opts.cliOptions.allowExec)
			});
			const errors = [];
			if ((!hasJsonMode || !requiresFullSchemaValidation) && policyIssueLines.length > 0) errors.push(...policyIssueLines.map((message) => ({
				kind: "schema",
				message
			})));
			if (requiresFullSchemaValidation) errors.push(...collectDryRunSchemaErrors({
				config: nextConfig,
				operations
			}));
			if (hasJsonMode || hasBuilderMode) {
				errors.push(...collectDryRunStaticErrorsForSkippedExecRefs({
					refs: selectedDryRunRefs.skippedExecRefs,
					config: nextConfig
				}));
				errors.push(...await collectDryRunResolvabilityErrors({
					refs: selectedDryRunRefs.refsToResolve,
					config: nextConfig
				}));
			}
			const dedupedErrors = dedupeDryRunErrors(errors);
			const dryRunResult = {
				ok: dedupedErrors.length === 0,
				operations: operations.length,
				configPath: shortenHomePath(snapshot.path),
				inputModes: [...new Set(operations.map((operation) => operation.inputMode))],
				checks: {
					schema: requiresFullSchemaValidation || policyIssueLines.length > 0,
					resolvability: hasJsonMode || hasBuilderMode,
					resolvabilityComplete: (hasJsonMode || hasBuilderMode) && selectedDryRunRefs.skippedExecRefs.length === 0
				},
				refsChecked: selectedDryRunRefs.refsToResolve.length,
				skippedExecRefs: selectedDryRunRefs.skippedExecRefs.length,
				...dedupedErrors.length > 0 ? { errors: dedupedErrors } : {}
			};
			if (dedupedErrors.length > 0) {
				if (opts.cliOptions.json) throw new ConfigSetDryRunValidationError(dryRunResult);
				throw new Error(formatDryRunFailureMessage({
					errors: dedupedErrors,
					skippedExecRefs: selectedDryRunRefs.skippedExecRefs.length
				}));
			}
			if (opts.cliOptions.json) writeRuntimeJson(runtime, dryRunResult);
			else {
				if (!dryRunResult.checks.schema && !dryRunResult.checks.resolvability) runtime.log(info("Dry run note: value mode does not run schema/resolvability checks. Use --strict-json, builder flags, or batch mode to enable validation checks."));
				if (dryRunResult.skippedExecRefs > 0) runtime.log(info(`Dry run note: skipped ${dryRunResult.skippedExecRefs} exec SecretRef resolvability check(s). Re-run with --allow-exec to execute exec providers during dry-run.`));
				runtime.log(info(`Dry run successful: ${operations.length} update(s) validated against ${shortenHomePath(snapshot.path)}.`));
			}
			return;
		}
		if (policyIssueLines.length > 0) throw new Error(formatUnsupportedSecretRefPolicyFailureMessage(policyIssueLines));
		await replaceConfigFile({
			nextConfig: next,
			...snapshot.hash !== void 0 ? { baseHash: snapshot.hash } : {}
		});
		if (removedGatewayAuthPaths.length > 0) runtime.log(info(`Removed inactive ${removedGatewayAuthPaths.join(", ")} for gateway.auth.mode=${nextConfig.gateway?.auth?.mode ?? "<unset>"}.`));
		if (operations.length === 1) {
			runtime.log(info(`Updated ${toDotPath(operations[0]?.requestedPath ?? [])}. Restart the gateway to apply.`));
			return;
		}
		runtime.log(info(`Updated ${operations.length} config paths. Restart the gateway to apply.`));
	} catch (err) {
		if (opts.cliOptions.dryRun && opts.cliOptions.json && err instanceof ConfigSetDryRunValidationError) {
			writeRuntimeJson(runtime, err.result);
			runtime.exit(1);
			return;
		}
		runtime.error(danger(String(err)));
		runtime.exit(1);
	}
}
async function runConfigGet(opts) {
	const runtime = opts.runtime ?? defaultRuntime;
	try {
		const parsedPath = parseRequiredPath(opts.path);
		const res = getAtPath(redactConfigObject((await loadValidConfig(runtime)).config), parsedPath);
		if (!res.found) {
			runtime.error(danger(`Config path not found: ${opts.path}`));
			runtime.exit(1);
			return;
		}
		if (opts.json) {
			writeRuntimeJson(runtime, res.value ?? null);
			return;
		}
		if (typeof res.value === "string" || typeof res.value === "number" || typeof res.value === "boolean") {
			runtime.log(String(res.value));
			return;
		}
		writeRuntimeJson(runtime, res.value ?? null);
	} catch (err) {
		runtime.error(danger(String(err)));
		runtime.exit(1);
	}
}
async function runConfigUnset(opts) {
	const runtime = opts.runtime ?? defaultRuntime;
	try {
		const parsedPath = parseRequiredPath(opts.path);
		const snapshot = await loadValidConfig(runtime);
		const next = structuredClone(snapshot.resolved);
		if (!unsetAtPath(next, parsedPath)) {
			runtime.error(danger(`Config path not found: ${opts.path}`));
			runtime.exit(1);
			return;
		}
		await replaceConfigFile({
			nextConfig: next,
			...snapshot.hash !== void 0 ? { baseHash: snapshot.hash } : {},
			writeOptions: { unsetPaths: [parsedPath] }
		});
		runtime.log(info(`Removed ${opts.path}. Restart the gateway to apply.`));
	} catch (err) {
		runtime.error(danger(String(err)));
		runtime.exit(1);
	}
}
async function runConfigFile(opts) {
	const runtime = opts.runtime ?? defaultRuntime;
	try {
		const snapshot = await readConfigFileSnapshot();
		runtime.log(shortenHomePath(snapshot.path));
	} catch (err) {
		runtime.error(danger(String(err)));
		runtime.exit(1);
	}
}
async function buildCliConfigSchema() {
	const schema = structuredClone((await readBestEffortRuntimeConfigSchema()).schema);
	schema.properties = {
		$schema: { type: "string" },
		...schema.properties
	};
	return schema;
}
async function runConfigSchema(opts = {}) {
	const runtime = opts.runtime ?? defaultRuntime;
	try {
		writeRuntimeJson(runtime, await buildCliConfigSchema());
	} catch (err) {
		runtime.error(danger(`Config schema error: ${String(err)}`));
		runtime.exit(1);
	}
}
async function runConfigValidate(opts = {}) {
	const runtime = opts.runtime ?? defaultRuntime;
	let outputPath = CONFIG_PATH ?? "openclaw.json";
	try {
		const snapshot = await readConfigFileSnapshot();
		outputPath = snapshot.path;
		const shortPath = shortenHomePath(outputPath);
		if (!snapshot.exists) {
			if (opts.json) writeRuntimeJson(runtime, {
				valid: false,
				path: outputPath,
				error: "file not found"
			}, 0);
			else runtime.error(danger(`Config file not found: ${shortPath}`));
			runtime.exit(1);
			return;
		}
		if (!snapshot.valid) {
			const issues = normalizeConfigIssues(snapshot.issues);
			if (opts.json) writeRuntimeJson(runtime, {
				valid: false,
				path: outputPath,
				issues
			});
			else {
				runtime.error(danger(`Config invalid at ${shortPath}:`));
				for (const line of formatConfigIssueLines(issues, danger("×"), { normalizeRoot: true })) runtime.error(`  ${line}`);
				runtime.error("");
				runtime.error(formatDoctorHint("to repair, or fix the keys above manually."));
			}
			runtime.exit(1);
			return;
		}
		if (opts.json) writeRuntimeJson(runtime, {
			valid: true,
			path: outputPath
		}, 0);
		else runtime.log(success(`Config valid: ${shortPath}`));
	} catch (err) {
		if (opts.json) writeRuntimeJson(runtime, {
			valid: false,
			path: outputPath,
			error: String(err)
		}, 0);
		else runtime.error(danger(`Config validation error: ${String(err)}`));
		runtime.exit(1);
	}
}
function registerConfigCli(program) {
	const cmd = program.command("config").description("Non-interactive config helpers (get/set/unset/file/schema/validate). Run without subcommand for guided setup.").addHelpText("after", () => `\n${theme.muted("Docs:")} ${formatDocsLink("/cli/config", "docs.openclaw.ai/cli/config")}\n`).option("--section <section>", "Configuration sections for guided setup (repeatable). Use with no subcommand.", (value, previous) => [...previous, value], []).action(async (opts) => {
		const { configureCommandFromSectionsArg } = await import("./configure-BTJmKlPg.js");
		await configureCommandFromSectionsArg(opts.section, defaultRuntime);
	});
	cmd.command("get").description("Get a config value by dot path").argument("<path>", "Config path (dot or bracket notation)").option("--json", "Output JSON", false).action(async (path, opts) => {
		await runConfigGet({
			path,
			json: Boolean(opts.json)
		});
	});
	setCommandJsonMode(cmd.command("set"), "parse-only").description(CONFIG_SET_DESCRIPTION).argument("[path]", "Config path (dot or bracket notation)").argument("[value]", "Value (JSON/JSON5 or raw string)").option("--strict-json", "Strict JSON parsing (error instead of raw string fallback)", false).option("--json", "Legacy alias for --strict-json", false).option("--dry-run", "Validate changes without writing openclaw.json (checks run in builder/json/batch modes; exec SecretRefs are skipped unless --allow-exec is set)", false).option("--allow-exec", "Dry-run only: allow exec SecretRef resolvability checks (may execute provider commands)", false).option("--merge", "Merge object/map values instead of replacing the target path", false).option("--replace", "Allow full replacement of protected map/list paths such as agents.defaults.models", false).option("--ref-provider <alias>", "SecretRef builder: provider alias").option("--ref-source <source>", "SecretRef builder: source (env|file|exec)").option("--ref-id <id>", "SecretRef builder: ref id").option("--provider-source <source>", "Provider builder: source (env|file|exec)").option("--provider-allowlist <envVar>", "Provider builder (env): allowlist entry (repeatable)", (value, previous) => [...previous, value], []).option("--provider-path <path>", "Provider builder (file): path").option("--provider-mode <mode>", "Provider builder (file): mode (singleValue|json)").option("--provider-timeout-ms <ms>", "Provider builder (file|exec): timeout ms").option("--provider-max-bytes <bytes>", "Provider builder (file): max bytes").option("--provider-command <path>", "Provider builder (exec): absolute command path").option("--provider-arg <arg>", "Provider builder (exec): command arg (repeatable)", (value, previous) => [...previous, value], []).option("--provider-no-output-timeout-ms <ms>", "Provider builder (exec): no-output timeout ms").option("--provider-max-output-bytes <bytes>", "Provider builder (exec): max output bytes").option("--provider-json-only", "Provider builder (exec): require JSON output", false).option("--provider-env <key=value>", "Provider builder (exec): env assignment (repeatable)", (value, previous) => [...previous, value], []).option("--provider-pass-env <envVar>", "Provider builder (exec): pass host env var (repeatable)", (value, previous) => [...previous, value], []).option("--provider-trusted-dir <path>", "Provider builder (exec): trusted directory (repeatable)", (value, previous) => [...previous, value], []).option("--provider-allow-insecure-path", "Provider builder (file|exec): bypass strict path permission checks", false).option("--provider-allow-symlink-command", "Provider builder (exec): allow command symlink path", false).option("--batch-json <json>", "Batch mode: JSON array of set operations").option("--batch-file <path>", "Batch mode: read JSON array of set operations from file").action(async (path, value, opts) => {
		await runConfigSet({
			path,
			value,
			cliOptions: opts
		});
	});
	cmd.command("unset").description("Remove a config value by dot path").argument("<path>", "Config path (dot or bracket notation)").action(async (path) => {
		await runConfigUnset({ path });
	});
	cmd.command("file").description("Print the active config file path").action(async () => {
		await runConfigFile({});
	});
	cmd.command("schema").description("Print the JSON schema for openclaw.json").action(async () => {
		await runConfigSchema({});
	});
	cmd.command("validate").description("Validate the current config against the schema without starting the gateway").option("--json", "Output validation result as JSON", false).action(async (opts) => {
		await runConfigValidate({ json: Boolean(opts.json) });
	});
}
//#endregion
export { registerConfigCli, runConfigFile, runConfigGet, runConfigSchema, runConfigSet, runConfigUnset, runConfigValidate };
