import { P as normalizeAnyChannelId, s as defaultRuntime } from "./subsystem-hATE68va.js";
import "./paths-VdmjGGyc.js";
import { n as isRich, r as theme, t as colorize } from "./theme-C5EwWDWE.js";
import "./ansi-By7x1TI7.js";
import { a as buildKoiMainSessionKey, d as resolveKoiIdFromSessionKey, l as normalizeKoiId, u as normalizeMainKey, v as parseKoiSessionKey } from "./session-key-B2OXLVi_.js";
import "./utils-D019Z2NU.js";
import "./exec-xrC0ejqg.js";
import { i as resolveKoiConfig } from "./koi-scope-D8R_V4oO.js";
import "./model-selection-Bue40sP3.js";
import "./dist-CUiRTtgg.js";
import "./dist-cjs-DKbiqPag.js";
import { t as formatCliCommand } from "./command-format-CAp_zt7z.js";
import "./boolean-CBeSt-pi.js";
import "./env-Dliiu-O6.js";
import "./github-copilot-token-CNBLk7kR.js";
import { o as loadConfig } from "./config-CJCyYQfd.js";
import "./manifest-registry-oBOOUSYE.js";
import "./plugins-4Dg2aV3Z.js";
import { A as resolveKoiMainSessionKey, i as loadSessionStore, j as resolveMainSessionKey } from "./sessions-p608GJQF.js";
import "./dist-qohLth5U.js";
import "./lib-DySFL26z.js";
import "./src-CuBVmkDD.js";
import "./core-CYIM8X9C.js";
import { d as resolveSandboxToolPolicyForKoi, i as removeSandboxContainer, l as resolveSandboxConfigForKoi, n as listSandboxContainers, r as removeSandboxBrowserContainer, t as listSandboxBrowsers } from "./sandbox-CH6Z4NF9.js";
import "./chrome-qnrH3SE9.js";
import "./skills-belB1fF2.js";
import "./routes-B_ID_OU2.js";
import "./server-context-BfQWGTuX.js";
import "./image-ops-D4trOw4b.js";
import { t as INTERNAL_MESSAGE_CHANNEL } from "./message-channel-DFpLxeOe.js";
import "./logging-DbUpYaKc.js";
import "./accounts-Grk0tpBF.js";
import { o as resolveStorePath } from "./paths-DeB-Vw2o.js";
import { t as formatDocsLink } from "./links-RRRDj3kH.js";
import { t as formatHelpExamples } from "./help-format-lN5-Ns06.js";
import { confirm } from "@clack/prompts";

//#region src/commands/sandbox-explain.ts
const SANDBOX_DOCS_URL = "https://docs.skykoi.com/sandbox";
function normalizeExplainSessionKey(params) {
	const raw = (params.session ?? "").trim();
	if (!raw) return resolveKoiMainSessionKey({
		cfg: params.cfg,
		koiId: params.koiId
	});
	if (raw.includes(":")) return raw;
	if (raw === "global") return "global";
	return buildKoiMainSessionKey({
		koiId: params.koiId,
		mainKey: normalizeMainKey(raw)
	});
}
function inferProviderFromSessionKey(params) {
	const parsed = parseKoiSessionKey(params.sessionKey);
	if (!parsed) return;
	const rest = parsed.rest.trim();
	if (!rest) return;
	const parts = rest.split(":").filter(Boolean);
	if (parts.length === 0) return;
	const configuredMainKey = normalizeMainKey(params.cfg.session?.mainKey);
	if (parts[0] === configuredMainKey) return;
	const candidate = parts[0]?.trim().toLowerCase();
	if (!candidate) return;
	if (candidate === INTERNAL_MESSAGE_CHANNEL) return INTERNAL_MESSAGE_CHANNEL;
	return normalizeAnyChannelId(candidate) ?? void 0;
}
function resolveActiveChannel(params) {
	const entry = loadSessionStore(resolveStorePath(params.cfg.session?.store, { koiId: params.koiId }))[params.sessionKey];
	const candidate = (entry?.lastChannel ?? entry?.channel ?? entry?.lastProvider ?? entry?.provider ?? "").trim().toLowerCase();
	if (candidate === INTERNAL_MESSAGE_CHANNEL) return INTERNAL_MESSAGE_CHANNEL;
	const normalized = normalizeAnyChannelId(candidate);
	if (normalized) return normalized;
	return inferProviderFromSessionKey({
		cfg: params.cfg,
		sessionKey: params.sessionKey
	});
}
async function sandboxExplainCommand(opts, runtime) {
	const cfg = loadConfig();
	const defaultKoiId = resolveKoiIdFromSessionKey(resolveMainSessionKey(cfg));
	const resolvedKoiId = normalizeKoiId(opts.koi?.trim() ? opts.koi : opts.session?.trim() ? resolveKoiIdFromSessionKey(opts.session) : defaultKoiId);
	const sessionKey = normalizeExplainSessionKey({
		cfg,
		koiId: resolvedKoiId,
		session: opts.session
	});
	const sandboxCfg = resolveSandboxConfigForKoi(cfg, resolvedKoiId);
	const toolPolicy = resolveSandboxToolPolicyForKoi(cfg, resolvedKoiId);
	const mainSessionKey = resolveKoiMainSessionKey({
		cfg,
		koiId: resolvedKoiId
	});
	const sessionIsSandboxed = sandboxCfg.mode === "all" ? true : sandboxCfg.mode === "off" ? false : sessionKey.trim() !== mainSessionKey.trim();
	const channel = resolveActiveChannel({
		cfg,
		koiId: resolvedKoiId,
		sessionKey
	});
	const koiConfig = resolveKoiConfig(cfg, resolvedKoiId);
	const elevatedGlobal = cfg.tools?.elevated;
	const elevatedKoi = koiConfig?.tools?.elevated;
	const elevatedGlobalEnabled = elevatedGlobal?.enabled !== false;
	const elevatedKoiEnabled = elevatedKoi?.enabled !== false;
	const elevatedEnabled = elevatedGlobalEnabled && elevatedKoiEnabled;
	const globalAllow = channel ? elevatedGlobal?.allowFrom?.[channel] : void 0;
	const koiAllow = channel ? elevatedKoi?.allowFrom?.[channel] : void 0;
	const allowTokens = (values) => (values ?? []).map((v) => String(v).trim()).filter(Boolean);
	const globalAllowTokens = allowTokens(globalAllow);
	const koiAllowTokens = allowTokens(koiAllow);
	const elevatedAllowedByConfig = elevatedEnabled && Boolean(channel) && globalAllowTokens.length > 0 && (elevatedKoi?.allowFrom ? koiAllowTokens.length > 0 : true);
	const elevatedAlwaysAllowedByConfig = elevatedAllowedByConfig && globalAllowTokens.includes("*") && (elevatedKoi?.allowFrom ? koiAllowTokens.includes("*") : true);
	const elevatedFailures = [];
	if (!elevatedGlobalEnabled) elevatedFailures.push({
		gate: "enabled",
		key: "tools.elevated.enabled"
	});
	if (!elevatedKoiEnabled) elevatedFailures.push({
		gate: "enabled",
		key: "kois.list[].tools.elevated.enabled"
	});
	if (channel && globalAllowTokens.length === 0) elevatedFailures.push({
		gate: "allowFrom",
		key: `tools.elevated.allowFrom.${channel}`
	});
	if (channel && elevatedKoi?.allowFrom && koiAllowTokens.length === 0) elevatedFailures.push({
		gate: "allowFrom",
		key: `kois.list[].tools.elevated.allowFrom.${channel}`
	});
	const fixIt = [];
	if (sandboxCfg.mode !== "off") {
		fixIt.push("kois.defaults.sandbox.mode=off");
		fixIt.push("kois.list[].sandbox.mode=off");
	}
	fixIt.push("tools.sandbox.tools.allow");
	fixIt.push("tools.sandbox.tools.deny");
	fixIt.push("kois.list[].tools.sandbox.tools.allow");
	fixIt.push("kois.list[].tools.sandbox.tools.deny");
	fixIt.push("tools.elevated.enabled");
	if (channel) fixIt.push(`tools.elevated.allowFrom.${channel}`);
	const payload = {
		docsUrl: SANDBOX_DOCS_URL,
		koiId: resolvedKoiId,
		sessionKey,
		mainSessionKey,
		sandbox: {
			mode: sandboxCfg.mode,
			scope: sandboxCfg.scope,
			perSession: sandboxCfg.scope === "session",
			workspaceAccess: sandboxCfg.workspaceAccess,
			workspaceRoot: sandboxCfg.workspaceRoot,
			sessionIsSandboxed,
			tools: {
				allow: toolPolicy.allow,
				deny: toolPolicy.deny,
				sources: toolPolicy.sources
			}
		},
		elevated: {
			enabled: elevatedEnabled,
			channel,
			allowedByConfig: elevatedAllowedByConfig,
			alwaysAllowedByConfig: elevatedAlwaysAllowedByConfig,
			allowFrom: {
				global: channel ? globalAllowTokens : void 0,
				koi: elevatedKoi?.allowFrom && channel ? koiAllowTokens : void 0
			},
			failures: elevatedFailures
		},
		fixIt
	};
	if (opts.json) {
		runtime.log(`${JSON.stringify(payload, null, 2)}\n`);
		return;
	}
	const rich = isRich();
	const heading = (value) => colorize(rich, theme.heading, value);
	const key = (value) => colorize(rich, theme.muted, value);
	const value = (val) => colorize(rich, theme.info, val);
	const ok = (val) => colorize(rich, theme.success, val);
	const warn = (val) => colorize(rich, theme.warn, val);
	const err = (val) => colorize(rich, theme.error, val);
	const bool = (flag) => flag ? ok("true") : err("false");
	const lines = [];
	lines.push(heading("Effective sandbox:"));
	lines.push(`  ${key("koiId:")} ${value(payload.koiId)}`);
	lines.push(`  ${key("sessionKey:")} ${value(payload.sessionKey)}`);
	lines.push(`  ${key("mainSessionKey:")} ${value(payload.mainSessionKey)}`);
	lines.push(`  ${key("runtime:")} ${payload.sandbox.sessionIsSandboxed ? warn("sandboxed") : ok("direct")}`);
	lines.push(`  ${key("mode:")} ${value(payload.sandbox.mode)} ${key("scope:")} ${value(payload.sandbox.scope)} ${key("perSession:")} ${bool(payload.sandbox.perSession)}`);
	lines.push(`  ${key("workspaceAccess:")} ${value(payload.sandbox.workspaceAccess)} ${key("workspaceRoot:")} ${value(payload.sandbox.workspaceRoot)}`);
	lines.push("");
	lines.push(heading("Sandbox tool policy:"));
	lines.push(`  ${key(`allow (${payload.sandbox.tools.sources.allow.source}):`)} ${value(payload.sandbox.tools.allow.join(", ") || "(empty)")}`);
	lines.push(`  ${key(`deny  (${payload.sandbox.tools.sources.deny.source}):`)} ${value(payload.sandbox.tools.deny.join(", ") || "(empty)")}`);
	lines.push("");
	lines.push(heading("Elevated:"));
	lines.push(`  ${key("enabled:")} ${bool(payload.elevated.enabled)}`);
	lines.push(`  ${key("channel:")} ${value(payload.elevated.channel ?? "(unknown)")}`);
	lines.push(`  ${key("allowedByConfig:")} ${bool(payload.elevated.allowedByConfig)}`);
	if (payload.elevated.failures.length > 0) lines.push(`  ${key("failing gates:")} ${warn(payload.elevated.failures.map((f) => `${f.gate} (${f.key})`).join(", "))}`);
	if (payload.sandbox.mode === "non-main" && payload.sandbox.sessionIsSandboxed) {
		lines.push("");
		lines.push(`${warn("Hint:")} sandbox mode is non-main; use main session key to run direct: ${value(payload.mainSessionKey)}`);
	}
	lines.push("");
	lines.push(heading("Fix-it:"));
	for (const key of payload.fixIt) lines.push(`  - ${key}`);
	lines.push("");
	lines.push(`${key("Docs:")} ${formatDocsLink("/sandbox", "docs.skykoi.com/sandbox")}`);
	runtime.log(`${lines.join("\n")}\n`);
}

//#endregion
//#region src/commands/sandbox-formatters.ts
/**
* Formatting utilities for sandbox CLI output
*/
function formatStatus(running) {
	return running ? "🟢 running" : "⚫ stopped";
}
function formatSimpleStatus(running) {
	return running ? "running" : "stopped";
}
function formatImageMatch(matches) {
	return matches ? "✓" : "⚠️  mismatch";
}
function formatAge(ms) {
	const seconds = Math.floor(ms / 1e3);
	const minutes = Math.floor(seconds / 60);
	const hours = Math.floor(minutes / 60);
	const days = Math.floor(hours / 24);
	if (days > 0) return `${days}d ${hours % 24}h`;
	if (hours > 0) return `${hours}h ${minutes % 60}m`;
	if (minutes > 0) return `${minutes}m`;
	return `${seconds}s`;
}

//#endregion
//#region src/commands/sandbox-display.ts
function displayItems(items, config, runtime) {
	if (items.length === 0) {
		runtime.log(config.emptyMessage);
		return;
	}
	runtime.log(`\n${config.title}\n`);
	for (const item of items) config.renderItem(item, runtime);
}
function displayContainers(containers, runtime) {
	displayItems(containers, {
		emptyMessage: "No sandbox containers found.",
		title: "📦 Sandbox Containers:",
		renderItem: (container, rt) => {
			rt.log(`  ${container.containerName}`);
			rt.log(`    Status:  ${formatStatus(container.running)}`);
			rt.log(`    Image:   ${container.image} ${formatImageMatch(container.imageMatch)}`);
			rt.log(`    Age:     ${formatAge(Date.now() - container.createdAtMs)}`);
			rt.log(`    Idle:    ${formatAge(Date.now() - container.lastUsedAtMs)}`);
			rt.log(`    Session: ${container.sessionKey}`);
			rt.log("");
		}
	}, runtime);
}
function displayBrowsers(browsers, runtime) {
	displayItems(browsers, {
		emptyMessage: "No sandbox browser containers found.",
		title: "🌐 Sandbox Browser Containers:",
		renderItem: (browser, rt) => {
			rt.log(`  ${browser.containerName}`);
			rt.log(`    Status:  ${formatStatus(browser.running)}`);
			rt.log(`    Image:   ${browser.image} ${formatImageMatch(browser.imageMatch)}`);
			rt.log(`    CDP:     ${browser.cdpPort}`);
			if (browser.noVncPort) rt.log(`    noVNC:   ${browser.noVncPort}`);
			rt.log(`    Age:     ${formatAge(Date.now() - browser.createdAtMs)}`);
			rt.log(`    Idle:    ${formatAge(Date.now() - browser.lastUsedAtMs)}`);
			rt.log(`    Session: ${browser.sessionKey}`);
			rt.log("");
		}
	}, runtime);
}
function displaySummary(containers, browsers, runtime) {
	const totalCount = containers.length + browsers.length;
	const runningCount = containers.filter((c) => c.running).length + browsers.filter((b) => b.running).length;
	const mismatchCount = containers.filter((c) => !c.imageMatch).length + browsers.filter((b) => !b.imageMatch).length;
	runtime.log(`Total: ${totalCount} (${runningCount} running)`);
	if (mismatchCount > 0) {
		runtime.log(`\n⚠️  ${mismatchCount} container(s) with image mismatch detected.`);
		runtime.log(`   Run '${formatCliCommand("skykoi sandbox recreate --all")}' to update all containers.`);
	}
}
function displayRecreatePreview(containers, browsers, runtime) {
	runtime.log("\nContainers to be recreated:\n");
	if (containers.length > 0) {
		runtime.log("📦 Sandbox Containers:");
		for (const container of containers) runtime.log(`  - ${container.containerName} (${formatSimpleStatus(container.running)})`);
	}
	if (browsers.length > 0) {
		runtime.log("\n🌐 Browser Containers:");
		for (const browser of browsers) runtime.log(`  - ${browser.containerName} (${formatSimpleStatus(browser.running)})`);
	}
	const total = containers.length + browsers.length;
	runtime.log(`\nTotal: ${total} container(s)`);
}
function displayRecreateResult(result, runtime) {
	runtime.log(`\nDone: ${result.successCount} removed, ${result.failCount} failed`);
	if (result.successCount > 0) runtime.log("\nContainers will be automatically recreated when the koi is next used.");
}

//#endregion
//#region src/commands/sandbox.ts
async function sandboxListCommand(opts, runtime) {
	const containers = opts.browser ? [] : await listSandboxContainers().catch(() => []);
	const browsers = opts.browser ? await listSandboxBrowsers().catch(() => []) : [];
	if (opts.json) {
		runtime.log(JSON.stringify({
			containers,
			browsers
		}, null, 2));
		return;
	}
	if (opts.browser) displayBrowsers(browsers, runtime);
	else displayContainers(containers, runtime);
	displaySummary(containers, browsers, runtime);
}
async function sandboxRecreateCommand(opts, runtime) {
	if (!validateRecreateOptions(opts, runtime)) return;
	const filtered = await fetchAndFilterContainers(opts);
	if (filtered.containers.length + filtered.browsers.length === 0) {
		runtime.log("No containers found matching the criteria.");
		return;
	}
	displayRecreatePreview(filtered.containers, filtered.browsers, runtime);
	if (!opts.force && !await confirmRecreate()) {
		runtime.log("Cancelled.");
		return;
	}
	const result = await removeContainers(filtered, runtime);
	displayRecreateResult(result, runtime);
	if (result.failCount > 0) runtime.exit(1);
}
function validateRecreateOptions(opts, runtime) {
	if (!opts.all && !opts.session && !opts.koi) {
		runtime.error("Please specify --all, --session <key>, or --koi <id>");
		runtime.exit(1);
		return false;
	}
	if ([
		opts.all,
		opts.session,
		opts.koi
	].filter(Boolean).length > 1) {
		runtime.error("Please specify only one of: --all, --session, --koi");
		runtime.exit(1);
		return false;
	}
	return true;
}
async function fetchAndFilterContainers(opts) {
	const allContainers = await listSandboxContainers().catch(() => []);
	const allBrowsers = await listSandboxBrowsers().catch(() => []);
	let containers = opts.browser ? [] : allContainers;
	let browsers = opts.browser ? allBrowsers : [];
	if (opts.session) {
		containers = containers.filter((c) => c.sessionKey === opts.session);
		browsers = browsers.filter((b) => b.sessionKey === opts.session);
	} else if (opts.koi) {
		const matchesKoi = createKoiMatcher(opts.koi);
		containers = containers.filter(matchesKoi);
		browsers = browsers.filter(matchesKoi);
	}
	return {
		containers,
		browsers
	};
}
function createKoiMatcher(koiId) {
	const koiPrefix = `koi:${koiId}`;
	return (item) => item.sessionKey === koiPrefix || item.sessionKey.startsWith(`${koiPrefix}:`);
}
async function confirmRecreate() {
	const result = await confirm({
		message: "This will stop and remove these containers. Continue?",
		initialValue: false
	});
	return result !== false && result !== Symbol.for("clack:cancel");
}
async function removeContainers(filtered, runtime) {
	runtime.log("\nRemoving containers...\n");
	let successCount = 0;
	let failCount = 0;
	for (const container of filtered.containers) if ((await removeContainer(container.containerName, removeSandboxContainer, runtime)).success) successCount++;
	else failCount++;
	for (const browser of filtered.browsers) if ((await removeContainer(browser.containerName, removeSandboxBrowserContainer, runtime)).success) successCount++;
	else failCount++;
	return {
		successCount,
		failCount
	};
}
async function removeContainer(containerName, removeFn, runtime) {
	try {
		await removeFn(containerName);
		runtime.log(`✓ Removed ${containerName}`);
		return { success: true };
	} catch (err) {
		runtime.error(`✗ Failed to remove ${containerName}: ${String(err)}`);
		return { success: false };
	}
}

//#endregion
//#region src/cli/sandbox-cli.ts
const SANDBOX_EXAMPLES = {
	main: [
		["SKYKOI sandbox list", "List all sandbox containers."],
		["SKYKOI sandbox list --browser", "List only browser containers."],
		["SKYKOI sandbox recreate --all", "Recreate all containers."],
		["SKYKOI sandbox recreate --session main", "Recreate a specific session."],
		["SKYKOI sandbox recreate --koi mybot", "Recreate koi containers."],
		["SKYKOI sandbox explain", "Explain effective sandbox config."]
	],
	list: [
		["SKYKOI sandbox list", "List all sandbox containers."],
		["SKYKOI sandbox list --browser", "List only browser containers."],
		["SKYKOI sandbox list --json", "JSON output."]
	],
	recreate: [
		["SKYKOI sandbox recreate --all", "Recreate all containers."],
		["SKYKOI sandbox recreate --session main", "Recreate a specific session."],
		["SKYKOI sandbox recreate --koi mybot", "Recreate a specific koi (includes sub-koi)."],
		["SKYKOI sandbox recreate --browser --all", "Recreate only browser containers."],
		["SKYKOI sandbox recreate --all --force", "Skip confirmation."]
	],
	explain: [
		["SKYKOI sandbox explain", "Show effective sandbox config."],
		["SKYKOI sandbox explain --session koi:main:main", "Explain a specific session."],
		["SKYKOI sandbox explain --koi work", "Explain an koi sandbox."],
		["SKYKOI sandbox explain --json", "JSON output."]
	]
};
function createRunner(commandFn) {
	return async (opts) => {
		try {
			await commandFn(opts, defaultRuntime);
		} catch (err) {
			defaultRuntime.error(String(err));
			defaultRuntime.exit(1);
		}
	};
}
function registerSandboxCli(program) {
	const sandbox = program.command("sandbox").description("Manage sandbox containers (Docker-based koi isolation)").addHelpText("after", () => `\n${theme.heading("Examples:")}\n${formatHelpExamples(SANDBOX_EXAMPLES.main)}\n`).addHelpText("after", () => `\n${theme.muted("Docs:")} ${formatDocsLink("/cli/sandbox", "docs.skykoi.com/cli/sandbox")}\n`).action(() => {
		sandbox.help({ error: true });
	});
	sandbox.command("list").description("List sandbox containers and their status").option("--json", "Output result as JSON", false).option("--browser", "List browser containers only", false).addHelpText("after", () => `\n${theme.heading("Examples:")}\n${formatHelpExamples(SANDBOX_EXAMPLES.list)}\n\n${theme.heading("Output includes:")}\n${theme.muted("- Container name and status (running/stopped)")}\n${theme.muted("- Docker image and whether it matches current config")}\n${theme.muted("- Age (time since creation)")}\n${theme.muted("- Idle time (time since last use)")}\n${theme.muted("- Associated session/koi ID")}`).action(createRunner((opts) => sandboxListCommand({
		browser: Boolean(opts.browser),
		json: Boolean(opts.json)
	}, defaultRuntime)));
	sandbox.command("recreate").description("Remove containers to force recreation with updated config").option("--all", "Recreate all sandbox containers", false).option("--session <key>", "Recreate container for specific session").option("--koi <id>", "Recreate containers for specific koi").option("--browser", "Only recreate browser containers", false).option("--force", "Skip confirmation prompt", false).addHelpText("after", () => `\n${theme.heading("Examples:")}\n${formatHelpExamples(SANDBOX_EXAMPLES.recreate)}\n\n${theme.heading("Why use this?")}\n${theme.muted("After updating Docker images or sandbox configuration, existing containers continue running with old settings.")}\n${theme.muted("This command removes them so they'll be recreated automatically with current config when next needed.")}\n\n${theme.heading("Filter options:")}\n${theme.muted("  --all          Remove all sandbox containers")}\n${theme.muted("  --session      Remove container for specific session key")}\n${theme.muted("  --koi        Remove containers for koi (includes koi:id:* variants)")}\n\n${theme.heading("Modifiers:")}\n${theme.muted("  --browser      Only affect browser containers (not regular sandbox)")}\n${theme.muted("  --force        Skip confirmation prompt")}`).action(createRunner((opts) => sandboxRecreateCommand({
		all: Boolean(opts.all),
		session: opts.session,
		koi: opts.koi,
		browser: Boolean(opts.browser),
		force: Boolean(opts.force)
	}, defaultRuntime)));
	sandbox.command("explain").description("Explain effective sandbox/tool policy for a session/koi").option("--session <key>", "Session key to inspect (defaults to koi main)").option("--koi <id>", "Koi id to inspect (defaults to derived koi)").option("--json", "Output result as JSON", false).addHelpText("after", () => `\n${theme.heading("Examples:")}\n${formatHelpExamples(SANDBOX_EXAMPLES.explain)}\n`).action(createRunner((opts) => sandboxExplainCommand({
		session: opts.session,
		koi: opts.koi,
		json: Boolean(opts.json)
	}, defaultRuntime)));
}

//#endregion
export { registerSandboxCli };