import { g as resolveStateDir, m as resolveOAuthDir, o as resolveConfigPath } from "./paths-mmi2xb99.js";
import { d as isRich, f as theme } from "./globals-D5pM_phR.js";
import { g as shortenHomePath, h as shortenHomeInString } from "./utils-3Lue6wVm.js";
import { c as defaultRuntime } from "./subsystem-_lp1q2Mi.js";
import "./boolean-BhvV-zDA.js";
import "./env-aEqmsXHj.js";
import "./chrome-7Zn7OYzP.js";
import "./logging-D4aavsm_.js";
import { D as MAX_INCLUDE_DEPTH, E as INCLUDE_KEY, S as parseConfigPath, n as createConfigIO, r as loadConfig, s as writeConfigFile, w as unsetConfigValueAtPath } from "./config-VoJVjSgT.js";
import { N as normalizeAgentId, c as resolveDefaultAgentId } from "./agent-scope-u760_XKU.js";
import { n as runExec } from "./exec-NeyMP-Tl.js";
import "./edwinpai-root-fGTEvnPp.js";
import { ct as saveAuthProfileStore, ot as ensureAuthProfileStore } from "./model-selection-CMHF17-l.js";
import "./github-copilot-token-Bu-iLSUh.js";
import { t as formatCliCommand } from "./command-format-D8drL8c2.js";
import "./manifest-registry-Cobl4jxs.js";
import "./client-BdG39O7o.js";
import "./tailnet-D1VxJifZ.js";
import "./call-BuuyfSRn.js";
import "./message-channel-B4I_vLJb.js";
import "./ws-CvzJ5P1j.js";
import "./sandbox-Cnho92pr.js";
import "./plugins-B3jBOs5H.js";
import "./accounts-DmCFbO1K.js";
import "./routes--IwjIOyE.js";
import "./skills-DMXslih8.js";
import "./server-context-CysGziRI.js";
import "./ports-CgQyR_CW.js";
import "./paths-CzSw2xi4.js";
import "./commands-CYbojHvd.js";
import { i as readChannelAllowFromStore } from "./pairing-store-BHWTx_J7.js";
import { t as formatDocsLink } from "./links-BKmnIRTU.js";
import "./progress-DIssriZ5.js";
import "./helpers-C7AMac6B.js";
import "./tailscale-9brshfui.js";
import "./net-BImkhihx.js";
import "./auth-DQvzz4Ac.js";
import { i as formatIcaclsResetCommand, n as buildVaultSecretMigrationPlan, r as createIcaclsResetCommand, t as runSecurityAudit } from "./audit-C9c7n4Gt.js";
import { n as callGatewayFromCli, t as addGatewayClientOptions } from "./gateway-rpc-DDaEENUI.js";
import path from "node:path";
import JSON5 from "json5";
import fs from "node:fs/promises";

//#region ../../src/security/fix.ts
async function safeChmod(params) {
	try {
		const st = await fs.lstat(params.path);
		if (st.isSymbolicLink()) return {
			kind: "chmod",
			path: params.path,
			mode: params.mode,
			ok: false,
			skipped: "symlink"
		};
		if (params.require === "dir" && !st.isDirectory()) return {
			kind: "chmod",
			path: params.path,
			mode: params.mode,
			ok: false,
			skipped: "not-a-directory"
		};
		if (params.require === "file" && !st.isFile()) return {
			kind: "chmod",
			path: params.path,
			mode: params.mode,
			ok: false,
			skipped: "not-a-file"
		};
		if ((st.mode & 511) === params.mode) return {
			kind: "chmod",
			path: params.path,
			mode: params.mode,
			ok: false,
			skipped: "already"
		};
		await fs.chmod(params.path, params.mode);
		return {
			kind: "chmod",
			path: params.path,
			mode: params.mode,
			ok: true
		};
	} catch (err) {
		if (err.code === "ENOENT") return {
			kind: "chmod",
			path: params.path,
			mode: params.mode,
			ok: false,
			skipped: "missing"
		};
		return {
			kind: "chmod",
			path: params.path,
			mode: params.mode,
			ok: false,
			error: String(err)
		};
	}
}
async function safeAclReset(params) {
	const display = formatIcaclsResetCommand(params.path, {
		isDir: params.require === "dir",
		env: params.env
	});
	try {
		const st = await fs.lstat(params.path);
		if (st.isSymbolicLink()) return {
			kind: "icacls",
			path: params.path,
			command: display,
			ok: false,
			skipped: "symlink"
		};
		if (params.require === "dir" && !st.isDirectory()) return {
			kind: "icacls",
			path: params.path,
			command: display,
			ok: false,
			skipped: "not-a-directory"
		};
		if (params.require === "file" && !st.isFile()) return {
			kind: "icacls",
			path: params.path,
			command: display,
			ok: false,
			skipped: "not-a-file"
		};
		const cmd = createIcaclsResetCommand(params.path, {
			isDir: st.isDirectory(),
			env: params.env
		});
		if (!cmd) return {
			kind: "icacls",
			path: params.path,
			command: display,
			ok: false,
			skipped: "missing-user"
		};
		await (params.exec ?? runExec)(cmd.command, cmd.args);
		return {
			kind: "icacls",
			path: params.path,
			command: cmd.display,
			ok: true
		};
	} catch (err) {
		if (err.code === "ENOENT") return {
			kind: "icacls",
			path: params.path,
			command: display,
			ok: false,
			skipped: "missing"
		};
		return {
			kind: "icacls",
			path: params.path,
			command: display,
			ok: false,
			error: String(err)
		};
	}
}
function setGroupPolicyAllowlist(params) {
	if (!params.cfg.channels) return;
	const section = params.cfg.channels[params.channel];
	if (!section || typeof section !== "object") return;
	if (section.groupPolicy === "open") {
		section.groupPolicy = "allowlist";
		params.changes.push(`channels.${params.channel}.groupPolicy=open -> allowlist`);
		params.policyFlips.add(`channels.${params.channel}.`);
	}
	const accounts = section.accounts;
	if (!accounts || typeof accounts !== "object") return;
	for (const [accountId, accountValue] of Object.entries(accounts)) {
		if (!accountId) continue;
		if (!accountValue || typeof accountValue !== "object") continue;
		const account = accountValue;
		if (account.groupPolicy === "open") {
			account.groupPolicy = "allowlist";
			params.changes.push(`channels.${params.channel}.accounts.${accountId}.groupPolicy=open -> allowlist`);
			params.policyFlips.add(`channels.${params.channel}.accounts.${accountId}.`);
		}
	}
}
function setWhatsAppGroupAllowFromFromStore(params) {
	const section = params.cfg.channels?.whatsapp;
	if (!section || typeof section !== "object") return;
	if (params.storeAllowFrom.length === 0) return;
	const maybeApply = (prefix, obj) => {
		if (!params.policyFlips.has(prefix)) return;
		const allowFrom = Array.isArray(obj.allowFrom) ? obj.allowFrom : [];
		const groupAllowFrom = Array.isArray(obj.groupAllowFrom) ? obj.groupAllowFrom : [];
		if (allowFrom.length > 0) return;
		if (groupAllowFrom.length > 0) return;
		obj.groupAllowFrom = params.storeAllowFrom;
		params.changes.push(`${prefix}groupAllowFrom=pairing-store`);
	};
	maybeApply("channels.whatsapp.", section);
	const accounts = section.accounts;
	if (!accounts || typeof accounts !== "object") return;
	for (const [accountId, accountValue] of Object.entries(accounts)) {
		if (!accountValue || typeof accountValue !== "object") continue;
		const account = accountValue;
		maybeApply(`channels.whatsapp.accounts.${accountId}.`, account);
	}
}
function applyConfigFixes(params) {
	const next = structuredClone(params.cfg ?? {});
	const changes = [];
	const policyFlips = /* @__PURE__ */ new Set();
	if (next.logging?.redactSensitive === "off") {
		next.logging = {
			...next.logging,
			redactSensitive: "tools"
		};
		changes.push("logging.redactSensitive=off -> \"tools\"");
	}
	for (const channel of [
		"telegram",
		"whatsapp",
		"discord",
		"signal",
		"imessage",
		"slack",
		"msteams"
	]) setGroupPolicyAllowlist({
		cfg: next,
		channel,
		changes,
		policyFlips
	});
	return {
		cfg: next,
		changes,
		policyFlips
	};
}
function listDirectIncludes(parsed) {
	const out = [];
	const visit = (value) => {
		if (!value) return;
		if (Array.isArray(value)) {
			for (const item of value) visit(item);
			return;
		}
		if (typeof value !== "object") return;
		const rec = value;
		const includeVal = rec[INCLUDE_KEY];
		if (typeof includeVal === "string") out.push(includeVal);
		else if (Array.isArray(includeVal)) {
			for (const item of includeVal) if (typeof item === "string") out.push(item);
		}
		for (const v of Object.values(rec)) visit(v);
	};
	visit(parsed);
	return out;
}
function resolveIncludePath(baseConfigPath, includePath) {
	return path.normalize(path.isAbsolute(includePath) ? includePath : path.resolve(path.dirname(baseConfigPath), includePath));
}
async function collectIncludePathsRecursive(params) {
	const visited = /* @__PURE__ */ new Set();
	const result = [];
	const walk = async (basePath, parsed, depth) => {
		if (depth > MAX_INCLUDE_DEPTH) return;
		for (const raw of listDirectIncludes(parsed)) {
			const resolved = resolveIncludePath(basePath, raw);
			if (visited.has(resolved)) continue;
			visited.add(resolved);
			result.push(resolved);
			const rawText = await fs.readFile(resolved, "utf-8").catch(() => null);
			if (!rawText) continue;
			const nestedParsed = (() => {
				try {
					return JSON5.parse(rawText);
				} catch {
					return null;
				}
			})();
			if (nestedParsed) await walk(resolved, nestedParsed, depth + 1);
		}
	};
	await walk(params.configPath, params.parsed, 0);
	return result;
}
async function chmodCredentialsAndAgentState(params) {
	const credsDir = resolveOAuthDir(params.env, params.stateDir);
	params.actions.push(await safeChmod({
		path: credsDir,
		mode: 448,
		require: "dir"
	}));
	const credsEntries = await fs.readdir(credsDir, { withFileTypes: true }).catch(() => []);
	for (const entry of credsEntries) {
		if (!entry.isFile()) continue;
		if (!entry.name.endsWith(".json")) continue;
		const p = path.join(credsDir, entry.name);
		params.actions.push(await safeChmod({
			path: p,
			mode: 384,
			require: "file"
		}));
	}
	const ids = /* @__PURE__ */ new Set();
	ids.add(resolveDefaultAgentId(params.cfg));
	const list = Array.isArray(params.cfg.agents?.list) ? params.cfg.agents?.list : [];
	for (const agent of list ?? []) {
		if (!agent || typeof agent !== "object") continue;
		const id = typeof agent.id === "string" ? agent.id.trim() : "";
		if (id) ids.add(id);
	}
	for (const agentId of ids) {
		const normalizedAgentId = normalizeAgentId(agentId);
		const agentRoot = path.join(params.stateDir, "agents", normalizedAgentId);
		const agentDir = path.join(agentRoot, "agent");
		const sessionsDir = path.join(agentRoot, "sessions");
		params.actions.push(await safeChmod({
			path: agentRoot,
			mode: 448,
			require: "dir"
		}));
		params.actions.push(await params.applyPerms({
			path: agentDir,
			mode: 448,
			require: "dir"
		}));
		const authPath = path.join(agentDir, "auth-profiles.json");
		params.actions.push(await params.applyPerms({
			path: authPath,
			mode: 384,
			require: "file"
		}));
		params.actions.push(await params.applyPerms({
			path: sessionsDir,
			mode: 448,
			require: "dir"
		}));
		const storePath = path.join(sessionsDir, "sessions.json");
		params.actions.push(await params.applyPerms({
			path: storePath,
			mode: 384,
			require: "file"
		}));
	}
}
async function fixSecurityFootguns(opts) {
	const env = opts?.env ?? process.env;
	const platform = opts?.platform ?? process.platform;
	const exec = opts?.exec ?? runExec;
	const isWindows = platform === "win32";
	const stateDir = opts?.stateDir ?? resolveStateDir(env);
	const configPath = opts?.configPath ?? resolveConfigPath(env, stateDir);
	const actions = [];
	const errors = [];
	const io = createConfigIO({
		env,
		configPath
	});
	const snap = await io.readConfigFileSnapshot();
	if (!snap.valid) errors.push(...snap.issues.map((i) => `${i.path}: ${i.message}`));
	let configWritten = false;
	let changes = [];
	if (snap.valid) {
		const fixed = applyConfigFixes({
			cfg: snap.config,
			env
		});
		changes = fixed.changes;
		const whatsappStoreAllowFrom = await readChannelAllowFromStore("whatsapp", env).catch(() => []);
		if (whatsappStoreAllowFrom.length > 0) setWhatsAppGroupAllowFromFromStore({
			cfg: fixed.cfg,
			storeAllowFrom: whatsappStoreAllowFrom,
			changes,
			policyFlips: fixed.policyFlips
		});
		if (changes.length > 0) try {
			await io.writeConfigFile(fixed.cfg);
			configWritten = true;
		} catch (err) {
			errors.push(`writeConfigFile failed: ${String(err)}`);
		}
	}
	const applyPerms = (params) => isWindows ? safeAclReset({
		path: params.path,
		require: params.require,
		env,
		exec
	}) : safeChmod({
		path: params.path,
		mode: params.mode,
		require: params.require
	});
	actions.push(await applyPerms({
		path: stateDir,
		mode: 448,
		require: "dir"
	}));
	actions.push(await applyPerms({
		path: configPath,
		mode: 384,
		require: "file"
	}));
	if (snap.exists) {
		const includePaths = await collectIncludePathsRecursive({
			configPath: snap.path,
			parsed: snap.parsed
		}).catch(() => []);
		for (const p of includePaths) actions.push(await applyPerms({
			path: p,
			mode: 384,
			require: "file"
		}));
	}
	await chmodCredentialsAndAgentState({
		env,
		stateDir,
		cfg: snap.config ?? {},
		actions,
		applyPerms
	}).catch((err) => {
		errors.push(`chmodCredentialsAndAgentState failed: ${String(err)}`);
	});
	return {
		ok: errors.length === 0,
		stateDir,
		configPath,
		configWritten,
		changes,
		actions,
		errors
	};
}

//#endregion
//#region ../../src/security/vault-secret-cleanup.ts
function redactAuthProfile(profile) {
	let changed = false;
	const record = profile;
	if (typeof record.key === "string" && record.key.trim()) {
		delete record.key;
		changed = true;
	}
	if (typeof record.token === "string" && record.token.trim()) {
		delete record.token;
		changed = true;
	}
	if (typeof record.access === "string" && record.access.trim()) {
		delete record.access;
		changed = true;
	}
	if (typeof record.refresh === "string" && record.refresh.trim()) {
		delete record.refresh;
		changed = true;
	}
	record.vaultCredentialId = record.vaultCredentialId ?? "migrated-to-vault";
	return changed;
}
async function cleanupVaultSecretFinding(finding, deps = {}) {
	if (finding.sourceKind === "env" || finding.sourceKind === "external-cli") {
		const message = finding.sourceKind === "env" ? `Remove ${finding.source} from the shell/service environment after confirming Vault use works.` : `Keep or remove the original ${finding.source} credential manually after confirming Vault use works.`;
		return {
			sourceKind: finding.sourceKind,
			source: finding.source,
			action: "manual",
			message
		};
	}
	if (finding.sourceKind === "config") {
		const parsed = parseConfigPath(finding.source);
		if (!parsed.ok || !parsed.path) return {
			sourceKind: finding.sourceKind,
			source: finding.source,
			action: "failed",
			message: parsed.error ?? "Invalid config path"
		};
		const cfg = (deps.loadConfig ?? loadConfig)();
		if (!unsetConfigValueAtPath(cfg, parsed.path)) return {
			sourceKind: finding.sourceKind,
			source: finding.source,
			action: "skipped",
			message: "Raw config value was already absent."
		};
		await (deps.writeConfigFile ?? writeConfigFile)(cfg);
		return {
			sourceKind: finding.sourceKind,
			source: finding.source,
			action: "redacted",
			message: `Removed raw config value ${finding.source}; Gateway will use Vault credential ${finding.credentialId}.`
		};
	}
	if (finding.sourceKind === "auth-profile") {
		const ensureStore = deps.ensureAuthProfileStore ?? ensureAuthProfileStore;
		const saveStore = deps.saveAuthProfileStore ?? saveAuthProfileStore;
		const store = ensureStore();
		const profile = store.profiles[finding.source];
		if (!profile) return {
			sourceKind: finding.sourceKind,
			source: finding.source,
			action: "skipped",
			message: "Auth profile was already absent."
		};
		if (!redactAuthProfile(profile)) return {
			sourceKind: finding.sourceKind,
			source: finding.source,
			action: "skipped",
			message: "Auth profile no longer contains a raw key/token."
		};
		saveStore(store);
		return {
			sourceKind: finding.sourceKind,
			source: finding.source,
			action: "redacted",
			message: `Removed raw auth-profile secret ${finding.source}; Gateway will use Vault credential ${finding.credentialId}.`
		};
	}
	return {
		sourceKind: finding.sourceKind,
		source: finding.source,
		action: "failed",
		message: "Unsupported source kind."
	};
}

//#endregion
//#region ../../src/cli/security-cli.ts
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
function entryTypeForFinding(finding) {
	switch (finding.kind) {
		case "bot-token":
		case "oauth-token": return "api_key";
		case "api-key": return "api_key";
		default: return "secret";
	}
}
function cleanupActionForFinding(finding) {
	return finding.sourceKind === "env" || finding.sourceKind === "external-cli" ? "manual" : "redact";
}
async function waitForVaultImportResult(requestId, opts, waitMs) {
	const deadline = Date.now() + waitMs;
	while (Date.now() < deadline) {
		const match = (await callGatewayFromCli("vault.import.pending", {
			...opts,
			json: true,
			timeout: opts.timeout ?? "15000"
		}, {}, { progress: false })).requests?.find((request) => request.id === requestId);
		if (match && [
			"imported",
			"denied",
			"failed",
			"expired"
		].includes(match.status)) return match;
		await sleep(1e3);
	}
	return null;
}
async function runVaultSecretsImport(opts) {
	const plan = buildVaultSecretMigrationPlan({
		cfg: loadConfig(),
		authProfiles: ensureAuthProfileStore(),
		includeRawSecrets: true
	});
	const findings = plan.findings.filter((finding) => finding.rawSecret);
	const results = [];
	const waitMs = Number(opts.waitMs ?? 3e5);
	for (const finding of findings) {
		const request = await callGatewayFromCli("vault.import.request", {
			...opts,
			json: true,
			timeout: opts.timeout ?? "15000"
		}, {
			credentialId: finding.credentialId,
			label: finding.label,
			kind: finding.kind,
			entryType: entryTypeForFinding(finding),
			sourceKind: finding.sourceKind,
			source: finding.source,
			valuePreview: finding.valuePreview,
			cleanupAction: cleanupActionForFinding(finding),
			purpose: `Import ${finding.sourceKind}:${finding.source} into Desktop Vault`,
			rawSecret: finding.rawSecret
		}, { progress: false });
		const resolved = await waitForVaultImportResult(request.id, opts, waitMs);
		if (!resolved) results.push({
			finding,
			request,
			status: "timeout",
			note: "Timed out waiting for Desktop approval"
		});
		else if (resolved.status === "imported") {
			const cleanup = await cleanupVaultSecretFinding(finding);
			results.push({
				finding,
				request: resolved,
				status: "imported",
				note: cleanup.message
			});
		} else results.push({
			finding,
			request: resolved,
			status: resolved.status
		});
	}
	const output = {
		imported: results.filter((r) => r.status === "imported").length,
		failed: results.filter((r) => !["imported"].includes(r.status)).length,
		results: results.map(({ finding, request, status, note }) => ({
			credentialId: finding.credentialId,
			label: finding.label,
			sourceKind: finding.sourceKind,
			source: finding.source,
			valuePreview: finding.valuePreview,
			requestId: request?.id,
			status,
			note
		})),
		blocked: plan.blocked.filter((item) => !item.includes("Automated import"))
	};
	if (opts.json) {
		defaultRuntime.log(JSON.stringify(output, null, 2));
		return;
	}
	const lines = ["EdwinPAI Vault secret import"];
	if (findings.length === 0) lines.push("No raw mapped secrets detected in config/env/auth profiles.");
	else {
		lines.push(`Queued ${findings.length} import approval request(s).`);
		for (const result of output.results) {
			lines.push(`- ${result.label} (${result.credentialId}) from ${result.sourceKind}:${result.source} [${result.valuePreview}] → ${result.status}`);
			if (result.note) lines.push(`  ${result.note}`);
		}
	}
	defaultRuntime.log(lines.join("\n"));
}
function formatSummary(summary) {
	const rich = isRich();
	const c = summary.critical;
	const w = summary.warn;
	const i = summary.info;
	const parts = [];
	parts.push(rich ? theme.error(`${c} critical`) : `${c} critical`);
	parts.push(rich ? theme.warn(`${w} warn`) : `${w} warn`);
	parts.push(rich ? theme.muted(`${i} info`) : `${i} info`);
	return parts.join(" · ");
}
function registerSecurityCli(program) {
	const security = program.command("security").description("Security tools (audit)").addHelpText("after", () => `\n${theme.muted("Docs:")} ${formatDocsLink("/cli/security", "docs.edwinpai.com/cli/security")}\n`);
	security.command("vault-secrets").description("Scan raw config/env/auth-profile secrets that should move to Desktop Vault").option("--json", "Print JSON", false).option("--import", "Queue approval-gated imports into Desktop Vault", false).option("--wait-ms <ms>", "How long to wait for Desktop import approvals", "300000").addHelpText("after", "\nImport mode requires Desktop connected to the Gateway Action Approvals stream.\n").hook("preAction", (thisCommand) => {
		addGatewayClientOptions(thisCommand);
	}).action(async (opts) => {
		if (opts.import) {
			await runVaultSecretsImport(opts);
			return;
		}
		const plan = buildVaultSecretMigrationPlan({
			cfg: loadConfig(),
			authProfiles: ensureAuthProfileStore()
		});
		if (opts.json) {
			defaultRuntime.log(JSON.stringify(plan, null, 2));
			return;
		}
		const lines = [];
		lines.push("EdwinPAI Vault secret migration scan");
		if (plan.findings.length === 0) lines.push("No raw mapped secrets detected in config/env/auth profiles.");
		else {
			lines.push(`${plan.findings.length} raw mapped secret(s) detected:`);
			for (const finding of plan.findings) {
				lines.push(`- ${finding.label} (${finding.credentialId}) from ${finding.sourceKind}:${finding.source} [${finding.valuePreview}]`);
				lines.push(`  ${finding.remediation}`);
			}
		}
		if (plan.blocked.length > 0) {
			lines.push("");
			lines.push("Not automated yet:");
			for (const item of plan.blocked) lines.push(`- ${item}`);
		}
		defaultRuntime.log(lines.join("\n"));
	});
	security.command("audit").description("Audit config + local state for common security foot-guns").option("--deep", "Attempt live Gateway probe (best-effort)", false).option("--fix", "Apply safe fixes (tighten defaults + chmod state/config)", false).option("--json", "Print JSON", false).action(async (opts) => {
		const fixResult = opts.fix ? await fixSecurityFootguns().catch((_err) => null) : null;
		const report = await runSecurityAudit({
			config: loadConfig(),
			deep: Boolean(opts.deep),
			includeFilesystem: true,
			includeChannelSecurity: true
		});
		if (opts.json) {
			defaultRuntime.log(JSON.stringify(fixResult ? {
				fix: fixResult,
				report
			} : report, null, 2));
			return;
		}
		const rich = isRich();
		const heading = (text) => rich ? theme.heading(text) : text;
		const muted = (text) => rich ? theme.muted(text) : text;
		const lines = [];
		lines.push(heading("EdwinPAI security audit"));
		lines.push(muted(`Summary: ${formatSummary(report.summary)}`));
		lines.push(muted(`Run deeper: ${formatCliCommand("edwinpai security audit --deep")}`));
		if (opts.fix) {
			lines.push(muted(`Fix: ${formatCliCommand("edwinpai security audit --fix")}`));
			if (!fixResult) lines.push(muted("Fixes: failed to apply (unexpected error)"));
			else if (fixResult.errors.length === 0 && fixResult.changes.length === 0 && fixResult.actions.every((a) => !a.ok)) lines.push(muted("Fixes: no changes applied"));
			else {
				lines.push("");
				lines.push(heading("FIX"));
				for (const change of fixResult.changes) lines.push(muted(`  ${shortenHomeInString(change)}`));
				for (const action of fixResult.actions) {
					if (action.kind === "chmod") {
						const mode = action.mode.toString(8).padStart(3, "0");
						if (action.ok) lines.push(muted(`  chmod ${mode} ${shortenHomePath(action.path)}`));
						else if (action.skipped) lines.push(muted(`  skip chmod ${mode} ${shortenHomePath(action.path)} (${action.skipped})`));
						else if (action.error) lines.push(muted(`  chmod ${mode} ${shortenHomePath(action.path)} failed: ${action.error}`));
						continue;
					}
					const command = shortenHomeInString(action.command);
					if (action.ok) lines.push(muted(`  ${command}`));
					else if (action.skipped) lines.push(muted(`  skip ${command} (${action.skipped})`));
					else if (action.error) lines.push(muted(`  ${command} failed: ${action.error}`));
				}
				if (fixResult.errors.length > 0) for (const err of fixResult.errors) lines.push(muted(`  error: ${shortenHomeInString(err)}`));
			}
		}
		const bySeverity = (sev) => report.findings.filter((f) => f.severity === sev);
		const render = (sev) => {
			const list = bySeverity(sev);
			if (list.length === 0) return;
			const label = sev === "critical" ? rich ? theme.error("CRITICAL") : "CRITICAL" : sev === "warn" ? rich ? theme.warn("WARN") : "WARN" : rich ? theme.muted("INFO") : "INFO";
			lines.push("");
			lines.push(heading(label));
			for (const f of list) {
				lines.push(`${theme.muted(f.checkId)} ${f.title}`);
				lines.push(`  ${f.detail}`);
				if (f.remediation?.trim()) lines.push(`  ${muted(`Fix: ${f.remediation.trim()}`)}`);
			}
		};
		render("critical");
		render("warn");
		render("info");
		defaultRuntime.log(lines.join("\n"));
	});
}

//#endregion
export { registerSecurityCli };