import { s as defaultRuntime } from "./subsystem-hATE68va.js";
import "./paths-VdmjGGyc.js";
import { n as isRich, r as theme } from "./theme-C5EwWDWE.js";
import "./ansi-By7x1TI7.js";
import "./utils-D019Z2NU.js";
import "./logger-BKidfKRU.js";
import "./exec-BBWSxSu-.js";
import "./koi-scope-BeICsBhH.js";
import "./model-selection-DvQd6xjM.js";
import "./dist-Czg7dzzf.js";
import "./dist-cjs-CtVce_lP.js";
import "./boolean-D-3joTkO.js";
import "./env-ChCKTuXK.js";
import "./github-copilot-token-BqhLBQWA.js";
import "./config-BOTdzMIB.js";
import "./manifest-registry-D7MfBQxU.js";
import "./message-channel-B-LM-U45.js";
import "./device-identity-CBC9Fa-4.js";
import "./client-CnWPlz1L.js";
import "./call-By5olg7I.js";
import { t as formatDocsLink } from "./links-DlFnXfJ_.js";
import "./progress-X-YSIEVf.js";
import { i as readExecApprovalsSnapshot, s as saveExecApprovals } from "./exec-approvals-io-CeAmdjpP.js";
import { t as renderTable } from "./table-Bu1gPkD7.js";
import "./service-C6lyBW0F.js";
import "./systemd-C7TaOB0r.js";
import { n as callGatewayFromCli } from "./gateway-rpc-FMQ_vIWH.js";
import { t as describeUnknownError } from "./shared-BqH9HuJn.js";
import { n as nodesCallOpts, r as resolveNodeId } from "./rpc-CgX_0HtA.js";
import JSON5 from "json5";
import fs from "node:fs/promises";

//#region src/cli/exec-approvals-cli.ts
function formatAge(msAgo) {
	const s = Math.max(0, Math.floor(msAgo / 1e3));
	if (s < 60) return `${s}s`;
	const m = Math.floor(s / 60);
	if (m < 60) return `${m}m`;
	const h = Math.floor(m / 60);
	if (h < 24) return `${h}h`;
	return `${Math.floor(h / 24)}d`;
}
async function readStdin() {
	const chunks = [];
	for await (const chunk of process.stdin) chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk)));
	return Buffer.concat(chunks).toString("utf8");
}
async function resolveTargetNodeId(opts) {
	if (opts.gateway) return null;
	const raw = opts.node?.trim() ?? "";
	if (!raw) return null;
	return await resolveNodeId(opts, raw);
}
async function loadSnapshot(opts, nodeId) {
	return await callGatewayFromCli(nodeId ? "exec.approvals.node.get" : "exec.approvals.get", opts, nodeId ? { nodeId } : {});
}
function loadSnapshotLocal() {
	const snapshot = readExecApprovalsSnapshot();
	return {
		path: snapshot.path,
		exists: snapshot.exists,
		hash: snapshot.hash,
		file: snapshot.file
	};
}
function saveSnapshotLocal(file) {
	saveExecApprovals(file);
	return loadSnapshotLocal();
}
async function loadSnapshotTarget(opts) {
	if (!opts.gateway && !opts.node) return {
		snapshot: loadSnapshotLocal(),
		nodeId: null,
		source: "local"
	};
	const nodeId = await resolveTargetNodeId(opts);
	return {
		snapshot: await loadSnapshot(opts, nodeId),
		nodeId,
		source: nodeId ? "node" : "gateway"
	};
}
function formatCliError(err) {
	const msg = describeUnknownError(err);
	return msg.includes("\n") ? msg.split("\n")[0] : msg;
}
function renderApprovalsSnapshot(snapshot, targetLabel) {
	const rich = isRich();
	const heading = (text) => rich ? theme.heading(text) : text;
	const muted = (text) => rich ? theme.muted(text) : text;
	const tableWidth = Math.max(60, (process.stdout.columns ?? 120) - 1);
	const file = snapshot.file ?? { version: 1 };
	const defaults = file.defaults ?? {};
	const defaultsParts = [
		defaults.security ? `security=${defaults.security}` : null,
		defaults.ask ? `ask=${defaults.ask}` : null,
		defaults.askFallback ? `askFallback=${defaults.askFallback}` : null,
		typeof defaults.autoAllowSkills === "boolean" ? `autoAllowSkills=${defaults.autoAllowSkills ? "on" : "off"}` : null
	].filter(Boolean);
	const kois = file.kois ?? {};
	const allowlistRows = [];
	const now = Date.now();
	for (const [koiId, koi] of Object.entries(kois)) {
		const allowlist = Array.isArray(koi.allowlist) ? koi.allowlist : [];
		for (const entry of allowlist) {
			const pattern = entry?.pattern?.trim() ?? "";
			if (!pattern) continue;
			const lastUsedAt = typeof entry.lastUsedAt === "number" ? entry.lastUsedAt : null;
			allowlistRows.push({
				Target: targetLabel,
				Koi: koiId,
				Pattern: pattern,
				LastUsed: lastUsedAt ? `${formatAge(Math.max(0, now - lastUsedAt))} ago` : muted("unknown")
			});
		}
	}
	const summaryRows = [
		{
			Field: "Target",
			Value: targetLabel
		},
		{
			Field: "Path",
			Value: snapshot.path
		},
		{
			Field: "Exists",
			Value: snapshot.exists ? "yes" : "no"
		},
		{
			Field: "Hash",
			Value: snapshot.hash
		},
		{
			Field: "Version",
			Value: String(file.version ?? 1)
		},
		{
			Field: "Socket",
			Value: file.socket?.path ?? "default"
		},
		{
			Field: "Defaults",
			Value: defaultsParts.length > 0 ? defaultsParts.join(", ") : "none"
		},
		{
			Field: "Kois",
			Value: String(Object.keys(kois).length)
		},
		{
			Field: "Allowlist",
			Value: String(allowlistRows.length)
		}
	];
	defaultRuntime.log(heading("Approvals"));
	defaultRuntime.log(renderTable({
		width: tableWidth,
		columns: [{
			key: "Field",
			header: "Field",
			minWidth: 8
		}, {
			key: "Value",
			header: "Value",
			minWidth: 24,
			flex: true
		}],
		rows: summaryRows
	}).trimEnd());
	if (allowlistRows.length === 0) {
		defaultRuntime.log("");
		defaultRuntime.log(muted("No allowlist entries."));
		return;
	}
	defaultRuntime.log("");
	defaultRuntime.log(heading("Allowlist"));
	defaultRuntime.log(renderTable({
		width: tableWidth,
		columns: [
			{
				key: "Target",
				header: "Target",
				minWidth: 10
			},
			{
				key: "Koi",
				header: "Koi",
				minWidth: 8
			},
			{
				key: "Pattern",
				header: "Pattern",
				minWidth: 20,
				flex: true
			},
			{
				key: "LastUsed",
				header: "Last Used",
				minWidth: 10
			}
		],
		rows: allowlistRows
	}).trimEnd());
}
async function saveSnapshot(opts, nodeId, file, baseHash) {
	return await callGatewayFromCli(nodeId ? "exec.approvals.node.set" : "exec.approvals.set", opts, nodeId ? {
		nodeId,
		file,
		baseHash
	} : {
		file,
		baseHash
	});
}
function resolveKoiKey(value) {
	const trimmed = value?.trim() ?? "";
	return trimmed ? trimmed : "*";
}
function normalizeAllowlistEntry(entry) {
	const pattern = entry?.pattern?.trim() ?? "";
	return pattern ? pattern : null;
}
function ensureKoi(file, koiKey) {
	const kois = file.kois ?? {};
	const entry = kois[koiKey] ?? {};
	file.kois = kois;
	return entry;
}
function isEmptyKoi(koi) {
	const allowlist = Array.isArray(koi.allowlist) ? koi.allowlist : [];
	return !koi.security && !koi.ask && !koi.askFallback && koi.autoAllowSkills === void 0 && allowlist.length === 0;
}
function registerExecApprovalsCli(program) {
	const formatExample = (cmd, desc) => `  ${theme.command(cmd)}\n    ${theme.muted(desc)}`;
	const approvals = program.command("approvals").alias("exec-approvals").description("Manage exec approvals (gateway or node host)").addHelpText("after", () => `\n${theme.muted("Docs:")} ${formatDocsLink("/cli/approvals", "docs.skykoi.com/cli/approvals")}\n`);
	nodesCallOpts(approvals.command("get").description("Fetch exec approvals snapshot").option("--node <node>", "Target node id/name/IP").option("--gateway", "Force gateway approvals", false).action(async (opts) => {
		try {
			const { snapshot, nodeId, source } = await loadSnapshotTarget(opts);
			if (opts.json) {
				defaultRuntime.log(JSON.stringify(snapshot));
				return;
			}
			const muted = (text) => isRich() ? theme.muted(text) : text;
			if (source === "local") {
				defaultRuntime.log(muted("Showing local approvals."));
				defaultRuntime.log("");
			}
			renderApprovalsSnapshot(snapshot, source === "local" ? "local" : nodeId ? `node:${nodeId}` : "gateway");
		} catch (err) {
			defaultRuntime.error(formatCliError(err));
			defaultRuntime.exit(1);
		}
	}));
	nodesCallOpts(approvals.command("set").description("Replace exec approvals with a JSON file").option("--node <node>", "Target node id/name/IP").option("--gateway", "Force gateway approvals", false).option("--file <path>", "Path to JSON file to upload").option("--stdin", "Read JSON from stdin", false).action(async (opts) => {
		try {
			if (!opts.file && !opts.stdin) {
				defaultRuntime.error("Provide --file or --stdin.");
				defaultRuntime.exit(1);
				return;
			}
			if (opts.file && opts.stdin) {
				defaultRuntime.error("Use either --file or --stdin (not both).");
				defaultRuntime.exit(1);
				return;
			}
			const { snapshot, nodeId, source } = await loadSnapshotTarget(opts);
			if (source === "local") defaultRuntime.log(theme.muted("Writing local approvals."));
			const targetLabel = source === "local" ? "local" : nodeId ? `node:${nodeId}` : "gateway";
			if (!snapshot.hash) {
				defaultRuntime.error("Exec approvals hash missing; reload and retry.");
				defaultRuntime.exit(1);
				return;
			}
			const raw = opts.stdin ? await readStdin() : await fs.readFile(String(opts.file), "utf8");
			let file;
			try {
				file = JSON5.parse(raw);
			} catch (err) {
				defaultRuntime.error(`Failed to parse approvals JSON: ${String(err)}`);
				defaultRuntime.exit(1);
				return;
			}
			file.version = 1;
			const next = source === "local" ? saveSnapshotLocal(file) : await saveSnapshot(opts, nodeId, file, snapshot.hash);
			if (opts.json) {
				defaultRuntime.log(JSON.stringify(next));
				return;
			}
			defaultRuntime.log(theme.muted(`Target: ${targetLabel}`));
			renderApprovalsSnapshot(next, targetLabel);
		} catch (err) {
			defaultRuntime.error(formatCliError(err));
			defaultRuntime.exit(1);
		}
	}));
	const allowlist = approvals.command("allowlist").description("Edit the per-koi allowlist").addHelpText("after", () => `\n${theme.heading("Examples:")}\n${formatExample("SKYKOI approvals allowlist add \"~/Projects/**/bin/rg\"", "Allowlist a local binary pattern for the main koi.")}\n${formatExample("SKYKOI approvals allowlist add --koi main --node <id|name|ip> \"/usr/bin/uptime\"", "Allowlist on a specific node/koi.")}\n${formatExample("SKYKOI approvals allowlist add --koi \"*\" \"/usr/bin/uname\"", "Allowlist for all kois (wildcard).")}\n${formatExample("SKYKOI approvals allowlist remove \"~/Projects/**/bin/rg\"", "Remove an allowlist pattern.")}\n\n${theme.muted("Docs:")} ${formatDocsLink("/cli/approvals", "docs.skykoi.com/cli/approvals")}\n`);
	nodesCallOpts(allowlist.command("add <pattern>").description("Add a glob pattern to an allowlist").option("--node <node>", "Target node id/name/IP").option("--gateway", "Force gateway approvals", false).option("--koi <id>", "Koi id (defaults to \"*\")").action(async (pattern, opts) => {
		try {
			const trimmed = pattern.trim();
			if (!trimmed) {
				defaultRuntime.error("Pattern required.");
				defaultRuntime.exit(1);
				return;
			}
			const { snapshot, nodeId, source } = await loadSnapshotTarget(opts);
			if (source === "local") defaultRuntime.log(theme.muted("Writing local approvals."));
			const targetLabel = source === "local" ? "local" : nodeId ? `node:${nodeId}` : "gateway";
			if (!snapshot.hash) {
				defaultRuntime.error("Exec approvals hash missing; reload and retry.");
				defaultRuntime.exit(1);
				return;
			}
			const file = snapshot.file ?? { version: 1 };
			file.version = 1;
			const koiKey = resolveKoiKey(opts.koi);
			const koi = ensureKoi(file, koiKey);
			const allowlistEntries = Array.isArray(koi.allowlist) ? koi.allowlist : [];
			if (allowlistEntries.some((entry) => normalizeAllowlistEntry(entry) === trimmed)) {
				defaultRuntime.log("Already allowlisted.");
				return;
			}
			allowlistEntries.push({
				pattern: trimmed,
				lastUsedAt: Date.now()
			});
			koi.allowlist = allowlistEntries;
			file.kois = {
				...file.kois,
				[koiKey]: koi
			};
			const next = source === "local" ? saveSnapshotLocal(file) : await saveSnapshot(opts, nodeId, file, snapshot.hash);
			if (opts.json) {
				defaultRuntime.log(JSON.stringify(next));
				return;
			}
			defaultRuntime.log(theme.muted(`Target: ${targetLabel}`));
			renderApprovalsSnapshot(next, targetLabel);
		} catch (err) {
			defaultRuntime.error(formatCliError(err));
			defaultRuntime.exit(1);
		}
	}));
	nodesCallOpts(allowlist.command("remove <pattern>").description("Remove a glob pattern from an allowlist").option("--node <node>", "Target node id/name/IP").option("--gateway", "Force gateway approvals", false).option("--koi <id>", "Koi id (defaults to \"*\")").action(async (pattern, opts) => {
		try {
			const trimmed = pattern.trim();
			if (!trimmed) {
				defaultRuntime.error("Pattern required.");
				defaultRuntime.exit(1);
				return;
			}
			const { snapshot, nodeId, source } = await loadSnapshotTarget(opts);
			if (source === "local") defaultRuntime.log(theme.muted("Writing local approvals."));
			const targetLabel = source === "local" ? "local" : nodeId ? `node:${nodeId}` : "gateway";
			if (!snapshot.hash) {
				defaultRuntime.error("Exec approvals hash missing; reload and retry.");
				defaultRuntime.exit(1);
				return;
			}
			const file = snapshot.file ?? { version: 1 };
			file.version = 1;
			const koiKey = resolveKoiKey(opts.koi);
			const koi = ensureKoi(file, koiKey);
			const allowlistEntries = Array.isArray(koi.allowlist) ? koi.allowlist : [];
			const nextEntries = allowlistEntries.filter((entry) => normalizeAllowlistEntry(entry) !== trimmed);
			if (nextEntries.length === allowlistEntries.length) {
				defaultRuntime.log("Pattern not found.");
				return;
			}
			if (nextEntries.length === 0) delete koi.allowlist;
			else koi.allowlist = nextEntries;
			if (isEmptyKoi(koi)) {
				const kois = { ...file.kois };
				delete kois[koiKey];
				file.kois = Object.keys(kois).length > 0 ? kois : void 0;
			} else file.kois = {
				...file.kois,
				[koiKey]: koi
			};
			const next = source === "local" ? saveSnapshotLocal(file) : await saveSnapshot(opts, nodeId, file, snapshot.hash);
			if (opts.json) {
				defaultRuntime.log(JSON.stringify(next));
				return;
			}
			defaultRuntime.log(theme.muted(`Target: ${targetLabel}`));
			renderApprovalsSnapshot(next, targetLabel);
		} catch (err) {
			defaultRuntime.error(formatCliError(err));
			defaultRuntime.exit(1);
		}
	}));
}

//#endregion
export { registerExecApprovalsCli };