import { n as DEFAULT_KOI_ID } from "./session-key-B2OXLVi_.js";
import { a as resolveExecApprovalsPath, n as expandHome, o as resolveExecApprovalsSocketPath, r as normalizeExecApprovals, s as saveExecApprovals, t as ensureExecApprovals } from "./exec-approvals-io-CeAmdjpP.js";
import fs from "node:fs";
import path from "node:path";
import crypto from "node:crypto";
import net from "node:net";

//#region src/infra/exec-approvals-resolve.ts
/**
* @module infra/exec-approvals-resolve
*
* Resolution logic: merging defaults/wildcard/koi overrides, PATH-based
* executable resolution, and allowlist pattern matching.
*/
const DEFAULT_SECURITY = "deny";
const DEFAULT_ASK = "on-miss";
const DEFAULT_ASK_FALLBACK = "deny";
const DEFAULT_AUTO_ALLOW_SKILLS = false;
function normalizeSecurity(value, fallback) {
	if (value === "allowlist" || value === "full" || value === "deny") return value;
	return fallback;
}
function normalizeAsk(value, fallback) {
	if (value === "always" || value === "off" || value === "on-miss") return value;
	return fallback;
}
/**
* Resolves the fully merged exec-approval settings for a given koi,
* combining file defaults, wildcard koi, and koi-specific overrides.
*/
function resolveExecApprovals(koiId, overrides) {
	const file = ensureExecApprovals();
	return resolveExecApprovalsFromFile({
		file,
		koiId,
		overrides,
		path: resolveExecApprovalsPath(),
		socketPath: expandHome(file.socket?.path ?? resolveExecApprovalsSocketPath()),
		token: file.socket?.token ?? ""
	});
}
/** Pure version of {@link resolveExecApprovals} that takes an already-loaded file. */
function resolveExecApprovalsFromFile(params) {
	const file = normalizeExecApprovals(params.file);
	const defaults = file.defaults ?? {};
	const koiKey = params.koiId ?? DEFAULT_KOI_ID;
	const koi = file.kois?.[koiKey] ?? {};
	const wildcard = file.kois?.["*"] ?? {};
	const fallbackSecurity = params.overrides?.security ?? DEFAULT_SECURITY;
	const fallbackAsk = params.overrides?.ask ?? DEFAULT_ASK;
	const fallbackAskFallback = params.overrides?.askFallback ?? DEFAULT_ASK_FALLBACK;
	const fallbackAutoAllowSkills = params.overrides?.autoAllowSkills ?? DEFAULT_AUTO_ALLOW_SKILLS;
	const resolvedDefaults = {
		security: normalizeSecurity(defaults.security, fallbackSecurity),
		ask: normalizeAsk(defaults.ask, fallbackAsk),
		askFallback: normalizeSecurity(defaults.askFallback ?? fallbackAskFallback, fallbackAskFallback),
		autoAllowSkills: Boolean(defaults.autoAllowSkills ?? fallbackAutoAllowSkills)
	};
	const resolvedKoi = {
		security: normalizeSecurity(koi.security ?? wildcard.security ?? resolvedDefaults.security, resolvedDefaults.security),
		ask: normalizeAsk(koi.ask ?? wildcard.ask ?? resolvedDefaults.ask, resolvedDefaults.ask),
		askFallback: normalizeSecurity(koi.askFallback ?? wildcard.askFallback ?? resolvedDefaults.askFallback, resolvedDefaults.askFallback),
		autoAllowSkills: Boolean(koi.autoAllowSkills ?? wildcard.autoAllowSkills ?? resolvedDefaults.autoAllowSkills)
	};
	const allowlist = [...Array.isArray(wildcard.allowlist) ? wildcard.allowlist : [], ...Array.isArray(koi.allowlist) ? koi.allowlist : []];
	return {
		path: params.path ?? resolveExecApprovalsPath(),
		socketPath: expandHome(params.socketPath ?? file.socket?.path ?? resolveExecApprovalsSocketPath()),
		token: params.token ?? file.socket?.token ?? "",
		defaults: resolvedDefaults,
		koi: resolvedKoi,
		allowlist,
		file
	};
}
function isExecutableFile(filePath) {
	try {
		if (!fs.statSync(filePath).isFile()) return false;
		if (process.platform !== "win32") fs.accessSync(filePath, fs.constants.X_OK);
		return true;
	} catch {
		return false;
	}
}
function resolveExecutablePath(rawExecutable, cwd, env) {
	const expanded = rawExecutable.startsWith("~") ? expandHome(rawExecutable) : rawExecutable;
	if (expanded.includes("/") || expanded.includes("\\")) {
		if (path.isAbsolute(expanded)) return isExecutableFile(expanded) ? expanded : void 0;
		const base = cwd && cwd.trim() ? cwd.trim() : process.cwd();
		const candidate = path.resolve(base, expanded);
		return isExecutableFile(candidate) ? candidate : void 0;
	}
	const entries = (env?.PATH ?? env?.Path ?? process.env.PATH ?? process.env.Path ?? "").split(path.delimiter).filter(Boolean);
	const hasExtension = process.platform === "win32" && path.extname(expanded).length > 0;
	const extensions = process.platform === "win32" ? hasExtension ? [""] : (env?.PATHEXT ?? env?.Pathext ?? process.env.PATHEXT ?? process.env.Pathext ?? ".EXE;.CMD;.BAT;.COM").split(";").map((ext) => ext.toLowerCase()) : [""];
	for (const entry of entries) for (const ext of extensions) {
		const candidate = path.join(entry, expanded + ext);
		if (isExecutableFile(candidate)) return candidate;
	}
}
function resolveCommandResolutionFromArgv(argv, cwd, env) {
	const rawExecutable = argv[0]?.trim();
	if (!rawExecutable) return null;
	const resolvedPath = resolveExecutablePath(rawExecutable, cwd, env);
	return {
		rawExecutable,
		resolvedPath,
		executableName: resolvedPath ? path.basename(resolvedPath) : rawExecutable
	};
}
function normalizeMatchTarget(value) {
	if (process.platform === "win32") return value.replace(/^\\\\[?.]\\/, "").replace(/\\/g, "/").toLowerCase();
	return value.replace(/\\\\/g, "/").toLowerCase();
}
function tryRealpath(value) {
	try {
		return fs.realpathSync(value);
	} catch {
		return null;
	}
}
function globToRegExp(pattern) {
	let regex = "^";
	let i = 0;
	while (i < pattern.length) {
		const ch = pattern[i];
		if (ch === "*") {
			if (pattern[i + 1] === "*") {
				regex += ".*";
				i += 2;
				continue;
			}
			regex += "[^/]*";
			i += 1;
			continue;
		}
		if (ch === "?") {
			regex += ".";
			i += 1;
			continue;
		}
		regex += ch.replace(/[.*+?^${}()|[\\]\\\\]/g, "\\$&");
		i += 1;
	}
	regex += "$";
	return new RegExp(regex, "i");
}
function matchesPattern(pattern, target) {
	const trimmed = pattern.trim();
	if (!trimmed) return false;
	const expanded = trimmed.startsWith("~") ? expandHome(trimmed) : trimmed;
	const hasWildcard = /[*?]/.test(expanded);
	let normalizedPattern = expanded;
	let normalizedTarget = target;
	if (process.platform === "win32" && !hasWildcard) {
		normalizedPattern = tryRealpath(expanded) ?? expanded;
		normalizedTarget = tryRealpath(target) ?? target;
	}
	normalizedPattern = normalizeMatchTarget(normalizedPattern);
	normalizedTarget = normalizeMatchTarget(normalizedTarget);
	return globToRegExp(normalizedPattern).test(normalizedTarget);
}
function resolveAllowlistCandidatePath(resolution, cwd) {
	if (!resolution) return;
	if (resolution.resolvedPath) return resolution.resolvedPath;
	const raw = resolution.rawExecutable?.trim();
	if (!raw) return;
	const expanded = raw.startsWith("~") ? expandHome(raw) : raw;
	if (!expanded.includes("/") && !expanded.includes("\\")) return;
	if (path.isAbsolute(expanded)) return expanded;
	const base = cwd && cwd.trim() ? cwd.trim() : process.cwd();
	return path.resolve(base, expanded);
}
/**
* Checks whether a resolved command matches any allowlist entry by path pattern.
* @returns The matching entry, or null if no match found.
*/
function matchAllowlist(entries, resolution) {
	if (!entries.length || !resolution?.resolvedPath) return null;
	const resolvedPath = resolution.resolvedPath;
	for (const entry of entries) {
		const pattern = entry.pattern?.trim();
		if (!pattern) continue;
		if (!(pattern.includes("/") || pattern.includes("\\") || pattern.includes("~"))) continue;
		if (matchesPattern(pattern, resolvedPath)) return entry;
	}
	return null;
}

//#endregion
//#region src/infra/exec-approvals-analysis.ts
/**
* @module infra/exec-approvals-analysis
*
* Shell command analysis: parsing pipelines, chains, quoting, argv tokenization,
* safe-bin detection, and cross-platform (Unix + Windows) command handling.
*/
const DEFAULT_SAFE_BINS = [
	"jq",
	"grep",
	"cut",
	"sort",
	"uniq",
	"head",
	"tail",
	"tr",
	"wc"
];
const DISALLOWED_PIPELINE_TOKENS = new Set([
	">",
	"<",
	"`",
	"\n",
	"\r",
	"(",
	")"
]);
const DOUBLE_QUOTE_ESCAPES = new Set([
	"\\",
	"\"",
	"$",
	"`",
	"\n",
	"\r"
]);
const WINDOWS_UNSUPPORTED_TOKENS = new Set([
	"&",
	"|",
	"<",
	">",
	"^",
	"(",
	")",
	"%",
	"!",
	"\n",
	"\r"
]);
function isDoubleQuoteEscape(next) {
	return Boolean(next && DOUBLE_QUOTE_ESCAPES.has(next));
}
/**
* Iterates through a command string while respecting shell quoting rules.
* The callback receives each character and the next character, and returns an action:
* - "split": push current buffer as a segment and start a new one
* - "skip": skip this character (and optionally the next via skip count)
* - "include": add this character to the buffer
* - { reject: reason }: abort with an error
*/
function iterateQuoteAware(command, onChar) {
	const parts = [];
	let buf = "";
	let inSingle = false;
	let inDouble = false;
	let escaped = false;
	let hasSplit = false;
	const pushPart = () => {
		const trimmed = buf.trim();
		if (trimmed) parts.push(trimmed);
		buf = "";
	};
	for (let i = 0; i < command.length; i += 1) {
		const ch = command[i];
		const next = command[i + 1];
		if (escaped) {
			buf += ch;
			escaped = false;
			continue;
		}
		if (!inSingle && !inDouble && ch === "\\") {
			escaped = true;
			buf += ch;
			continue;
		}
		if (inSingle) {
			if (ch === "'") inSingle = false;
			buf += ch;
			continue;
		}
		if (inDouble) {
			if (ch === "\\" && isDoubleQuoteEscape(next)) {
				buf += ch;
				buf += next;
				i += 1;
				continue;
			}
			if (ch === "$" && next === "(") return {
				ok: false,
				reason: "unsupported shell token: $()"
			};
			if (ch === "`") return {
				ok: false,
				reason: "unsupported shell token: `"
			};
			if (ch === "\n" || ch === "\r") return {
				ok: false,
				reason: "unsupported shell token: newline"
			};
			if (ch === "\"") inDouble = false;
			buf += ch;
			continue;
		}
		if (ch === "'") {
			inSingle = true;
			buf += ch;
			continue;
		}
		if (ch === "\"") {
			inDouble = true;
			buf += ch;
			continue;
		}
		const action = onChar(ch, next, i);
		if (typeof action === "object" && "reject" in action) return {
			ok: false,
			reason: action.reject
		};
		if (action === "split") {
			pushPart();
			hasSplit = true;
			continue;
		}
		if (action === "skip") continue;
		buf += ch;
	}
	if (escaped || inSingle || inDouble) return {
		ok: false,
		reason: "unterminated shell quote/escape"
	};
	pushPart();
	return {
		ok: true,
		parts,
		hasSplit
	};
}
function splitShellPipeline(command) {
	let emptySegment = false;
	const result = iterateQuoteAware(command, (ch, next) => {
		if (ch === "|" && next === "|") return { reject: "unsupported shell token: ||" };
		if (ch === "|" && next === "&") return { reject: "unsupported shell token: |&" };
		if (ch === "|") {
			emptySegment = true;
			return "split";
		}
		if (ch === "&" || ch === ";") return { reject: `unsupported shell token: ${ch}` };
		if (DISALLOWED_PIPELINE_TOKENS.has(ch)) return { reject: `unsupported shell token: ${ch}` };
		if (ch === "$" && next === "(") return { reject: "unsupported shell token: $()" };
		emptySegment = false;
		return "include";
	});
	if (!result.ok) return {
		ok: false,
		reason: result.reason,
		segments: []
	};
	if (emptySegment || result.parts.length === 0) return {
		ok: false,
		reason: result.parts.length === 0 ? "empty command" : "empty pipeline segment",
		segments: []
	};
	return {
		ok: true,
		segments: result.parts
	};
}
function findWindowsUnsupportedToken(command) {
	for (const ch of command) if (WINDOWS_UNSUPPORTED_TOKENS.has(ch)) {
		if (ch === "\n" || ch === "\r") return "newline";
		return ch;
	}
	return null;
}
function tokenizeWindowsSegment(segment) {
	const tokens = [];
	let buf = "";
	let inDouble = false;
	const pushToken = () => {
		if (buf.length > 0) {
			tokens.push(buf);
			buf = "";
		}
	};
	for (let i = 0; i < segment.length; i += 1) {
		const ch = segment[i];
		if (ch === "\"") {
			inDouble = !inDouble;
			continue;
		}
		if (!inDouble && /\s/.test(ch)) {
			pushToken();
			continue;
		}
		buf += ch;
	}
	if (inDouble) return null;
	pushToken();
	return tokens.length > 0 ? tokens : null;
}
function analyzeWindowsShellCommand(params) {
	const unsupported = findWindowsUnsupportedToken(params.command);
	if (unsupported) return {
		ok: false,
		reason: `unsupported windows shell token: ${unsupported}`,
		segments: []
	};
	const argv = tokenizeWindowsSegment(params.command);
	if (!argv || argv.length === 0) return {
		ok: false,
		reason: "unable to parse windows command",
		segments: []
	};
	return {
		ok: true,
		segments: [{
			raw: params.command,
			argv,
			resolution: resolveCommandResolutionFromArgv(argv, params.cwd, params.env)
		}]
	};
}
function isWindowsPlatform(platform) {
	return String(platform ?? "").trim().toLowerCase().startsWith("win");
}
function tokenizeShellSegment(segment) {
	const tokens = [];
	let buf = "";
	let inSingle = false;
	let inDouble = false;
	let escaped = false;
	const pushToken = () => {
		if (buf.length > 0) {
			tokens.push(buf);
			buf = "";
		}
	};
	for (let i = 0; i < segment.length; i += 1) {
		const ch = segment[i];
		if (escaped) {
			buf += ch;
			escaped = false;
			continue;
		}
		if (!inSingle && !inDouble && ch === "\\") {
			escaped = true;
			continue;
		}
		if (inSingle) {
			if (ch === "'") inSingle = false;
			else buf += ch;
			continue;
		}
		if (inDouble) {
			const next = segment[i + 1];
			if (ch === "\\" && isDoubleQuoteEscape(next)) {
				buf += next;
				i += 1;
				continue;
			}
			if (ch === "\"") inDouble = false;
			else buf += ch;
			continue;
		}
		if (ch === "'") {
			inSingle = true;
			continue;
		}
		if (ch === "\"") {
			inDouble = true;
			continue;
		}
		if (/\s/.test(ch)) {
			pushToken();
			continue;
		}
		buf += ch;
	}
	if (escaped || inSingle || inDouble) return null;
	pushToken();
	return tokens;
}
function parseSegmentsFromParts(parts, cwd, env) {
	const segments = [];
	for (const raw of parts) {
		const argv = tokenizeShellSegment(raw);
		if (!argv || argv.length === 0) return null;
		segments.push({
			raw,
			argv,
			resolution: resolveCommandResolutionFromArgv(argv, cwd, env)
		});
	}
	return segments;
}
/**
* Splits a command string by chain operators (&&, ||, ;) while respecting quotes.
* Returns null when no chain is present or when the chain is malformed.
*/
function splitCommandChain(command) {
	const parts = [];
	let buf = "";
	let inSingle = false;
	let inDouble = false;
	let escaped = false;
	let foundChain = false;
	let invalidChain = false;
	const pushPart = () => {
		const trimmed = buf.trim();
		if (trimmed) {
			parts.push(trimmed);
			buf = "";
			return true;
		}
		buf = "";
		return false;
	};
	for (let i = 0; i < command.length; i += 1) {
		const ch = command[i];
		const next = command[i + 1];
		if (escaped) {
			buf += ch;
			escaped = false;
			continue;
		}
		if (!inSingle && !inDouble && ch === "\\") {
			escaped = true;
			buf += ch;
			continue;
		}
		if (inSingle) {
			if (ch === "'") inSingle = false;
			buf += ch;
			continue;
		}
		if (inDouble) {
			if (ch === "\\" && isDoubleQuoteEscape(next)) {
				buf += ch;
				buf += next;
				i += 1;
				continue;
			}
			if (ch === "\"") inDouble = false;
			buf += ch;
			continue;
		}
		if (ch === "'") {
			inSingle = true;
			buf += ch;
			continue;
		}
		if (ch === "\"") {
			inDouble = true;
			buf += ch;
			continue;
		}
		if (ch === "&" && command[i + 1] === "&") {
			if (!pushPart()) invalidChain = true;
			i += 1;
			foundChain = true;
			continue;
		}
		if (ch === "|" && command[i + 1] === "|") {
			if (!pushPart()) invalidChain = true;
			i += 1;
			foundChain = true;
			continue;
		}
		if (ch === ";") {
			if (!pushPart()) invalidChain = true;
			foundChain = true;
			continue;
		}
		buf += ch;
	}
	const pushedFinal = pushPart();
	if (!foundChain) return null;
	if (invalidChain || !pushedFinal) return null;
	return parts.length > 0 ? parts : null;
}
/**
* Parses a shell command string into segments (handling pipes, chains, quoting)
* and resolves each segment's executable. Cross-platform (Unix + Windows).
*/
function analyzeShellCommand(params) {
	if (isWindowsPlatform(params.platform)) return analyzeWindowsShellCommand(params);
	const chainParts = splitCommandChain(params.command);
	if (chainParts) {
		const chains = [];
		const allSegments = [];
		for (const part of chainParts) {
			const pipelineSplit = splitShellPipeline(part);
			if (!pipelineSplit.ok) return {
				ok: false,
				reason: pipelineSplit.reason,
				segments: []
			};
			const segments = parseSegmentsFromParts(pipelineSplit.segments, params.cwd, params.env);
			if (!segments) return {
				ok: false,
				reason: "unable to parse shell segment",
				segments: []
			};
			chains.push(segments);
			allSegments.push(...segments);
		}
		return {
			ok: true,
			segments: allSegments,
			chains
		};
	}
	const split = splitShellPipeline(params.command);
	if (!split.ok) return {
		ok: false,
		reason: split.reason,
		segments: []
	};
	const segments = parseSegmentsFromParts(split.segments, params.cwd, params.env);
	if (!segments) return {
		ok: false,
		reason: "unable to parse shell segment",
		segments: []
	};
	return {
		ok: true,
		segments
	};
}
/** Analyzes a pre-split argv array (no shell parsing needed). */
function analyzeArgvCommand(params) {
	const argv = params.argv.filter((entry) => entry.trim().length > 0);
	if (argv.length === 0) return {
		ok: false,
		reason: "empty argv",
		segments: []
	};
	return {
		ok: true,
		segments: [{
			raw: argv.join(" "),
			argv,
			resolution: resolveCommandResolutionFromArgv(argv, params.cwd, params.env)
		}]
	};
}
function isPathLikeToken(value) {
	const trimmed = value.trim();
	if (!trimmed) return false;
	if (trimmed === "-") return false;
	if (trimmed.startsWith("./") || trimmed.startsWith("../") || trimmed.startsWith("~")) return true;
	if (trimmed.startsWith("/")) return true;
	return /^[A-Za-z]:[\\/]/.test(trimmed);
}
function defaultFileExists(filePath) {
	try {
		return fs.existsSync(filePath);
	} catch {
		return false;
	}
}
/** Normalizes a list of safe binary names to a lowercase Set. */
function normalizeSafeBins(entries) {
	if (!Array.isArray(entries)) return /* @__PURE__ */ new Set();
	const normalized = entries.map((entry) => entry.trim().toLowerCase()).filter((entry) => entry.length > 0);
	return new Set(normalized);
}
/** Resolves safe bins from config, falling back to DEFAULT_SAFE_BINS when undefined. */
function resolveSafeBins(entries) {
	if (entries === void 0) return normalizeSafeBins(DEFAULT_SAFE_BINS);
	return normalizeSafeBins(entries ?? []);
}
/**
* Checks whether a command invokes a "safe" binary (e.g. grep, jq) without
* file path arguments that could leak data. Safe bins are auto-allowed.
*/
function isSafeBinUsage(params) {
	if (params.safeBins.size === 0) return false;
	const resolution = params.resolution;
	const execName = resolution?.executableName?.toLowerCase();
	if (!execName) return false;
	if (!(params.safeBins.has(execName) || process.platform === "win32" && params.safeBins.has(path.parse(execName).name))) return false;
	if (!resolution?.resolvedPath) return false;
	const cwd = params.cwd ?? process.cwd();
	const exists = params.fileExists ?? defaultFileExists;
	const argv = params.argv.slice(1);
	for (let i = 0; i < argv.length; i += 1) {
		const token = argv[i];
		if (!token) continue;
		if (token === "-") continue;
		if (token.startsWith("-")) {
			const eqIndex = token.indexOf("=");
			if (eqIndex > 0) {
				const value = token.slice(eqIndex + 1);
				if (value && (isPathLikeToken(value) || exists(path.resolve(cwd, value)))) return false;
			}
			continue;
		}
		if (isPathLikeToken(token)) return false;
		if (exists(path.resolve(cwd, token))) return false;
	}
	return true;
}

//#endregion
//#region src/infra/exec-approvals-evaluate.ts
/**
* @module infra/exec-approvals-evaluate
*
* Evaluation logic: determining whether commands pass the allowlist,
* recording usage, adding entries, and socket-based approval requests.
*/
function evaluateSegments(segments, params) {
	const matches = [];
	const allowSkills = params.autoAllowSkills === true && (params.skillBins?.size ?? 0) > 0;
	return {
		satisfied: segments.every((segment) => {
			const candidatePath = resolveAllowlistCandidatePath(segment.resolution, params.cwd);
			const candidateResolution = candidatePath && segment.resolution ? {
				...segment.resolution,
				resolvedPath: candidatePath
			} : segment.resolution;
			const match = matchAllowlist(params.allowlist, candidateResolution);
			if (match) matches.push(match);
			const safe = isSafeBinUsage({
				argv: segment.argv,
				resolution: segment.resolution,
				safeBins: params.safeBins,
				cwd: params.cwd
			});
			const skillAllow = allowSkills && segment.resolution?.executableName ? params.skillBins?.has(segment.resolution.executableName) : false;
			return Boolean(match || safe || skillAllow);
		}),
		matches
	};
}
/**
* Evaluates whether all segments of a parsed command are covered by the
* allowlist, safe bins, or skill bins. Returns match details.
*/
function evaluateExecAllowlist(params) {
	const allowlistMatches = [];
	if (!params.analysis.ok || params.analysis.segments.length === 0) return {
		allowlistSatisfied: false,
		allowlistMatches
	};
	if (params.analysis.chains) {
		for (const chainSegments of params.analysis.chains) {
			const result = evaluateSegments(chainSegments, {
				allowlist: params.allowlist,
				safeBins: params.safeBins,
				cwd: params.cwd,
				skillBins: params.skillBins,
				autoAllowSkills: params.autoAllowSkills
			});
			if (!result.satisfied) return {
				allowlistSatisfied: false,
				allowlistMatches: []
			};
			allowlistMatches.push(...result.matches);
		}
		return {
			allowlistSatisfied: true,
			allowlistMatches
		};
	}
	const result = evaluateSegments(params.analysis.segments, {
		allowlist: params.allowlist,
		safeBins: params.safeBins,
		cwd: params.cwd,
		skillBins: params.skillBins,
		autoAllowSkills: params.autoAllowSkills
	});
	return {
		allowlistSatisfied: result.satisfied,
		allowlistMatches: result.matches
	};
}
/**
* Evaluates allowlist for shell commands (including &&, ||, ;) and returns analysis metadata.
*/
function evaluateShellAllowlist(params) {
	const chainParts = isWindowsPlatform(params.platform) ? null : splitCommandChain(params.command);
	if (!chainParts) {
		const analysis = analyzeShellCommand({
			command: params.command,
			cwd: params.cwd,
			env: params.env,
			platform: params.platform
		});
		if (!analysis.ok) return {
			analysisOk: false,
			allowlistSatisfied: false,
			allowlistMatches: [],
			segments: []
		};
		const evaluation = evaluateExecAllowlist({
			analysis,
			allowlist: params.allowlist,
			safeBins: params.safeBins,
			cwd: params.cwd,
			skillBins: params.skillBins,
			autoAllowSkills: params.autoAllowSkills
		});
		return {
			analysisOk: true,
			allowlistSatisfied: evaluation.allowlistSatisfied,
			allowlistMatches: evaluation.allowlistMatches,
			segments: analysis.segments
		};
	}
	const allowlistMatches = [];
	const segments = [];
	for (const part of chainParts) {
		const analysis = analyzeShellCommand({
			command: part,
			cwd: params.cwd,
			env: params.env,
			platform: params.platform
		});
		if (!analysis.ok) return {
			analysisOk: false,
			allowlistSatisfied: false,
			allowlistMatches: [],
			segments: []
		};
		segments.push(...analysis.segments);
		const evaluation = evaluateExecAllowlist({
			analysis,
			allowlist: params.allowlist,
			safeBins: params.safeBins,
			cwd: params.cwd,
			skillBins: params.skillBins,
			autoAllowSkills: params.autoAllowSkills
		});
		allowlistMatches.push(...evaluation.allowlistMatches);
		if (!evaluation.allowlistSatisfied) return {
			analysisOk: true,
			allowlistSatisfied: false,
			allowlistMatches,
			segments
		};
	}
	return {
		analysisOk: true,
		allowlistSatisfied: true,
		allowlistMatches,
		segments
	};
}
/**
* Determines whether a command requires interactive approval based on
* the ask mode, security level, and allowlist analysis result.
*/
function requiresExecApproval(params) {
	return params.ask === "always" || params.ask === "on-miss" && params.security === "allowlist" && (!params.analysisOk || !params.allowlistSatisfied);
}
/** Updates the last-used timestamp and command for an allowlist entry after execution. */
function recordAllowlistUse(approvals, koiId, entry, command, resolvedPath) {
	const target = koiId ?? DEFAULT_KOI_ID;
	const kois = approvals.kois ?? {};
	const existing = kois[target] ?? {};
	const nextAllowlist = (Array.isArray(existing.allowlist) ? existing.allowlist : []).map((item) => item.pattern === entry.pattern ? {
		...item,
		id: item.id ?? crypto.randomUUID(),
		lastUsedAt: Date.now(),
		lastUsedCommand: command,
		lastResolvedPath: resolvedPath
	} : item);
	kois[target] = {
		...existing,
		allowlist: nextAllowlist
	};
	approvals.kois = kois;
	saveExecApprovals(approvals);
}
/** Adds a new pattern to a koi's allowlist if not already present. */
function addAllowlistEntry(approvals, koiId, pattern) {
	const target = koiId ?? DEFAULT_KOI_ID;
	const kois = approvals.kois ?? {};
	const existing = kois[target] ?? {};
	const allowlist = Array.isArray(existing.allowlist) ? existing.allowlist : [];
	const trimmed = pattern.trim();
	if (!trimmed) return;
	if (allowlist.some((entry) => entry.pattern === trimmed)) return;
	allowlist.push({
		id: crypto.randomUUID(),
		pattern: trimmed,
		lastUsedAt: Date.now()
	});
	kois[target] = {
		...existing,
		allowlist
	};
	approvals.kois = kois;
	saveExecApprovals(approvals);
}
/** Returns the more restrictive of two security levels (deny < allowlist < full). */
function minSecurity(a, b) {
	const order = {
		deny: 0,
		allowlist: 1,
		full: 2
	};
	return order[a] <= order[b] ? a : b;
}
/** Returns the more aggressive of two ask modes (off < on-miss < always). */
function maxAsk(a, b) {
	const order = {
		off: 0,
		"on-miss": 1,
		always: 2
	};
	return order[a] >= order[b] ? a : b;
}

//#endregion
export { minSecurity as a, analyzeArgvCommand as c, resolveExecApprovalsFromFile as d, maxAsk as i, resolveSafeBins as l, evaluateExecAllowlist as n, recordAllowlistUse as o, evaluateShellAllowlist as r, requiresExecApproval as s, addAllowlistEntry as t, resolveExecApprovals as u };