import { n as DEFAULT_KOI_ID } from "./session-key-B2OXLVi_.js";
import fs from "node:fs";
import path from "node:path";
import os from "node:os";
import crypto from "node:crypto";

//#region src/infra/exec-approvals-io.ts
/**
* @module infra/exec-approvals-io
*
* File I/O operations for the exec-approvals security layer: reading, writing,
* normalizing, and bootstrapping the approvals JSON file.
*/
const DEFAULT_FILE = "~/.skykoi/exec-approvals.json";
const DEFAULT_SOCKET = "~/.skykoi/exec-approvals.sock";
function hashExecApprovalsRaw(raw) {
	return crypto.createHash("sha256").update(raw ?? "").digest("hex");
}
function expandHome(value) {
	if (!value) return value;
	if (value === "~") return os.homedir();
	if (value.startsWith("~/")) return path.join(os.homedir(), value.slice(2));
	return value;
}
/** Returns the expanded filesystem path to the exec-approvals JSON file. */
function resolveExecApprovalsPath() {
	return expandHome(DEFAULT_FILE);
}
/** Returns the expanded filesystem path to the exec-approvals Unix socket. */
function resolveExecApprovalsSocketPath() {
	return expandHome(DEFAULT_SOCKET);
}
function normalizeAllowlistPattern(value) {
	const trimmed = value?.trim() ?? "";
	return trimmed ? trimmed.toLowerCase() : null;
}
function mergeLegacyKoi(current, legacy) {
	const allowlist = [];
	const seen = /* @__PURE__ */ new Set();
	const pushEntry = (entry) => {
		const key = normalizeAllowlistPattern(entry.pattern);
		if (!key || seen.has(key)) return;
		seen.add(key);
		allowlist.push(entry);
	};
	for (const entry of current.allowlist ?? []) pushEntry(entry);
	for (const entry of legacy.allowlist ?? []) pushEntry(entry);
	return {
		security: current.security ?? legacy.security,
		ask: current.ask ?? legacy.ask,
		askFallback: current.askFallback ?? legacy.askFallback,
		autoAllowSkills: current.autoAllowSkills ?? legacy.autoAllowSkills,
		allowlist: allowlist.length > 0 ? allowlist : void 0
	};
}
function ensureDir(filePath) {
	const dir = path.dirname(filePath);
	fs.mkdirSync(dir, { recursive: true });
}
function coerceAllowlistEntries(allowlist) {
	if (!Array.isArray(allowlist) || allowlist.length === 0) return Array.isArray(allowlist) ? allowlist : void 0;
	let changed = false;
	const result = [];
	for (const item of allowlist) if (typeof item === "string") {
		const trimmed = item.trim();
		if (trimmed) {
			result.push({ pattern: trimmed });
			changed = true;
		} else changed = true;
	} else if (item && typeof item === "object" && !Array.isArray(item)) {
		const pattern = item.pattern;
		if (typeof pattern === "string" && pattern.trim().length > 0) result.push(item);
		else changed = true;
	} else changed = true;
	return changed ? result.length > 0 ? result : void 0 : allowlist;
}
function ensureAllowlistIds(allowlist) {
	if (!Array.isArray(allowlist) || allowlist.length === 0) return allowlist;
	let changed = false;
	const next = allowlist.map((entry) => {
		if (entry.id) return entry;
		changed = true;
		return {
			...entry,
			id: crypto.randomUUID()
		};
	});
	return changed ? next : allowlist;
}
/**
* Normalizes an exec-approvals file: merges legacy "default" koi into the
* main koi, coerces string allowlist entries into objects, and assigns UUIDs.
*/
function normalizeExecApprovals(file) {
	const socketPath = file.socket?.path?.trim();
	const token = file.socket?.token?.trim();
	const kois = { ...file.kois };
	const legacyDefault = kois.default;
	if (legacyDefault) {
		const main = kois[DEFAULT_KOI_ID];
		kois[DEFAULT_KOI_ID] = main ? mergeLegacyKoi(main, legacyDefault) : legacyDefault;
		delete kois.default;
	}
	for (const [key, koi] of Object.entries(kois)) {
		const allowlist = ensureAllowlistIds(coerceAllowlistEntries(koi.allowlist));
		if (allowlist !== koi.allowlist) kois[key] = {
			...koi,
			allowlist
		};
	}
	return {
		version: 1,
		socket: {
			path: socketPath && socketPath.length > 0 ? socketPath : void 0,
			token: token && token.length > 0 ? token : void 0
		},
		defaults: {
			security: file.defaults?.security,
			ask: file.defaults?.ask,
			askFallback: file.defaults?.askFallback,
			autoAllowSkills: file.defaults?.autoAllowSkills
		},
		kois
	};
}
function generateToken() {
	return crypto.randomBytes(24).toString("base64url");
}
/**
* Reads the exec-approvals file from disk and returns a normalized snapshot
* with a content hash for optimistic-concurrency writes.
*/
function readExecApprovalsSnapshot() {
	const filePath = resolveExecApprovalsPath();
	if (!fs.existsSync(filePath)) return {
		path: filePath,
		exists: false,
		raw: null,
		file: normalizeExecApprovals({
			version: 1,
			kois: {}
		}),
		hash: hashExecApprovalsRaw(null)
	};
	const raw = fs.readFileSync(filePath, "utf8");
	let parsed = null;
	try {
		parsed = JSON.parse(raw);
	} catch {
		parsed = null;
	}
	return {
		path: filePath,
		exists: true,
		raw,
		file: parsed?.version === 1 ? normalizeExecApprovals(parsed) : normalizeExecApprovals({
			version: 1,
			kois: {}
		}),
		hash: hashExecApprovalsRaw(raw)
	};
}
/** Loads and normalizes the exec-approvals file, returning defaults on any error. */
function loadExecApprovals() {
	const filePath = resolveExecApprovalsPath();
	try {
		if (!fs.existsSync(filePath)) return normalizeExecApprovals({
			version: 1,
			kois: {}
		});
		const raw = fs.readFileSync(filePath, "utf8");
		const parsed = JSON.parse(raw);
		if (parsed?.version !== 1) return normalizeExecApprovals({
			version: 1,
			kois: {}
		});
		return normalizeExecApprovals(parsed);
	} catch {
		return normalizeExecApprovals({
			version: 1,
			kois: {}
		});
	}
}
/** Writes the exec-approvals file to disk with restrictive permissions (0o600). */
function saveExecApprovals(file) {
	const filePath = resolveExecApprovalsPath();
	ensureDir(filePath);
	const json = `${JSON.stringify(file, null, 2)}\n`;
	if (process.platform !== "win32") {
		const tmp = `${filePath}.${process.pid}.${crypto.randomUUID()}.tmp`;
		try {
			fs.writeFileSync(tmp, json, {
				mode: 384,
				encoding: "utf-8"
			});
			fs.renameSync(tmp, filePath);
		} finally {
			try {
				fs.unlinkSync(tmp);
			} catch {}
		}
	} else fs.writeFileSync(filePath, json, { mode: 384 });
	try {
		fs.chmodSync(filePath, 384);
	} catch {}
}
/**
* Loads the exec-approvals file, ensures socket path and auth token exist,
* writes it back, and returns the complete file. Idempotent bootstrap call.
*/
function ensureExecApprovals() {
	const next = normalizeExecApprovals(loadExecApprovals());
	const socketPath = next.socket?.path?.trim();
	const token = next.socket?.token?.trim();
	const updated = {
		...next,
		socket: {
			path: socketPath && socketPath.length > 0 ? socketPath : resolveExecApprovalsSocketPath(),
			token: token && token.length > 0 ? token : generateToken()
		}
	};
	saveExecApprovals(updated);
	return updated;
}

//#endregion
export { resolveExecApprovalsPath as a, readExecApprovalsSnapshot as i, expandHome as n, resolveExecApprovalsSocketPath as o, normalizeExecApprovals as r, saveExecApprovals as s, ensureExecApprovals as t };