import { d as resolveIsNixMode, u as resolveGatewayPort } from "./paths-mmi2xb99.js";
import { c as defaultRuntime } from "./subsystem-_lp1q2Mi.js";
import { r as loadConfig } from "./config-VoJVjSgT.js";
import { t as formatCliCommand } from "./command-format-D8drL8c2.js";
import { t as isWSL } from "./wsl-BFoXHNBM.js";
import { t as resolveGatewayService } from "./service-BssQxmRt.js";
import { r as isSystemdUserServiceAvailable } from "./systemd-pzbs8ZOA.js";
import { n as auditGatewayServiceConfig, t as SERVICE_AUDIT_CODES } from "./service-audit-Dvc0hKtz.js";
import { i as buildGatewayInstallPlan, r as isGatewayDaemonRuntime, t as DEFAULT_GATEWAY_DAEMON_RUNTIME } from "./daemon-runtime-CEk_30Dc.js";
import { n as renderSystemdUnavailableHints } from "./systemd-hints-CzgT_W5U.js";
import { n as createNullWriter, r as emitDaemonActionJson, t as buildDaemonServiceSnapshot } from "./response-EhRrUCse.js";
import { i as parsePort, s as renderGatewayServiceStartHints } from "./shared-CdxZFobZ.js";
import { execFileSync } from "node:child_process";
import { setTimeout as setTimeout$1 } from "node:timers/promises";

//#region ../../src/cli/daemon-cli/install.ts
async function runDaemonInstall(opts) {
	const json = Boolean(opts.json);
	const warnings = [];
	const stdout = json ? createNullWriter() : process.stdout;
	const emit = (payload) => {
		if (!json) return;
		emitDaemonActionJson({
			action: "install",
			...payload
		});
	};
	const fail = (message) => {
		if (json) emit({
			ok: false,
			error: message,
			warnings: warnings.length ? warnings : void 0
		});
		else defaultRuntime.error(message);
		defaultRuntime.exit(1);
	};
	if (resolveIsNixMode(process.env)) {
		fail("Nix mode detected; service install is disabled.");
		return;
	}
	const cfg = loadConfig();
	const portOverride = parsePort(opts.port);
	if (opts.port !== void 0 && portOverride === null) {
		fail("Invalid port");
		return;
	}
	const port = portOverride ?? resolveGatewayPort(cfg);
	if (!Number.isFinite(port) || port <= 0) {
		fail("Invalid port");
		return;
	}
	const runtimeRaw = opts.runtime ? String(opts.runtime) : DEFAULT_GATEWAY_DAEMON_RUNTIME;
	if (!isGatewayDaemonRuntime(runtimeRaw)) {
		fail("Invalid --runtime (use \"node\" or \"bun\")");
		return;
	}
	const service = resolveGatewayService();
	let loaded = false;
	try {
		loaded = await service.isLoaded({ env: process.env });
	} catch (err) {
		fail(`Gateway service check failed: ${String(err)}`);
		return;
	}
	if (loaded) {
		if (!opts.force) {
			emit({
				ok: true,
				result: "already-installed",
				message: `Gateway service already ${service.loadedText}.`,
				service: buildDaemonServiceSnapshot(service, loaded),
				warnings: warnings.length ? warnings : void 0
			});
			if (!json) {
				defaultRuntime.log(`Gateway service already ${service.loadedText}.`);
				defaultRuntime.log(`Reinstall with: ${formatCliCommand("edwinpai gateway install --force")}`);
			}
			return;
		}
	}
	const { programArguments, workingDirectory, environment } = await buildGatewayInstallPlan({
		env: process.env,
		port,
		token: opts.token || cfg.gateway?.auth?.token || process.env.EDWINPAI_GATEWAY_TOKEN,
		runtime: runtimeRaw,
		warn: (message) => {
			if (json) warnings.push(message);
			else defaultRuntime.log(message);
		},
		config: cfg
	});
	try {
		await service.install({
			env: process.env,
			stdout,
			programArguments,
			workingDirectory,
			environment
		});
	} catch (err) {
		fail(`Gateway install failed: ${String(err)}`);
		return;
	}
	let installed = true;
	try {
		installed = await service.isLoaded({ env: process.env });
	} catch {
		installed = true;
	}
	emit({
		ok: true,
		result: "installed",
		service: buildDaemonServiceSnapshot(service, installed),
		warnings: warnings.length ? warnings : void 0
	});
}

//#endregion
//#region ../../src/cli/daemon-cli/conflicts.ts
function normalizeWindowsCommand(command, fallbackName) {
	const trimmed = command.trim();
	if (trimmed) return trimmed;
	return fallbackName.trim();
}
function parsePsOutput(output) {
	return output.split(/\r?\n/).map((line) => line.trim()).filter(Boolean).map((line) => {
		const match = line.match(/^(\d+)\s+(\d+)\s+(.*)$/);
		if (!match) return null;
		const pid = Number.parseInt(match[1] ?? "", 10);
		const ppid = Number.parseInt(match[2] ?? "", 10);
		const command = (match[3] ?? "").trim();
		if (!Number.isFinite(pid) || !Number.isFinite(ppid) || !command) return null;
		return {
			pid,
			ppid,
			command
		};
	}).filter((entry) => Boolean(entry));
}
function parseWindowsProcessListJson(output) {
	const parsed = JSON.parse(output);
	return (Array.isArray(parsed) ? parsed : parsed ? [parsed] : []).map((row) => {
		const pid = Number(row.ProcessId ?? NaN);
		const ppid = Number(row.ParentProcessId ?? 0);
		if (!Number.isFinite(pid) || !Number.isFinite(ppid)) return null;
		return {
			pid,
			ppid,
			command: normalizeWindowsCommand(String(row.CommandLine ?? ""), String(row.Name ?? ""))
		};
	}).filter((entry) => Boolean(entry));
}
function collectDescendantPids(processes, rootPid) {
	const byParent = /* @__PURE__ */ new Map();
	for (const proc of processes) {
		const list = byParent.get(proc.ppid) ?? [];
		list.push(proc.pid);
		byParent.set(proc.ppid, list);
	}
	const seen = /* @__PURE__ */ new Set();
	const out = [];
	const queue = [rootPid];
	while (queue.length > 0) {
		const current = queue.shift();
		if (current == null || seen.has(current)) continue;
		seen.add(current);
		out.push(current);
		for (const child of byParent.get(current) ?? []) queue.push(child);
	}
	return out;
}
function isStatusCommand(command) {
	return /edwinpai(?:\.cmd|\.exe)?\s+gateway\s+status/i.test(command);
}
function isGatewayCommand(command) {
	const normalized = command.trim().toLowerCase();
	return normalized === "edwinpai-gateway" || normalized.endsWith("edwinpai-gateway.exe");
}
function selectConflictingGatewayProcesses(processes, options = {}) {
	const activeGatewayPid = options.activeGatewayPid ?? null;
	const byPid = new Map(processes.map((proc) => [proc.pid, proc]));
	const selected = /* @__PURE__ */ new Set();
	for (const proc of processes) if (isStatusCommand(proc.command)) for (const pid of collectDescendantPids(processes, proc.pid)) selected.add(pid);
	for (const proc of processes) if (isGatewayCommand(proc.command) && proc.pid !== activeGatewayPid) selected.add(proc.pid);
	if (activeGatewayPid != null) selected.delete(activeGatewayPid);
	return [...selected].map((pid) => byPid.get(pid)).filter((entry) => Boolean(entry)).sort((a, b) => a.pid - b.pid);
}
function listUnixProcesses() {
	return parsePsOutput(execFileSync("ps", ["-Ao", "pid=,ppid=,command="], { encoding: "utf-8" }));
}
function listWindowsProcesses() {
	return parseWindowsProcessListJson(execFileSync("powershell.exe", [
		"-NoProfile",
		"-Command",
		[
			"$ErrorActionPreference = 'Stop'",
			"$procs = Get-CimInstance Win32_Process | Select-Object ProcessId, ParentProcessId, CommandLine, Name",
			"$procs | ConvertTo-Json -Compress"
		].join("; ")
	], { encoding: "utf-8" }));
}
function listProcesses() {
	if (process.platform === "win32") return listWindowsProcesses();
	return listUnixProcesses();
}
function terminatePid(proc, force) {
	if (process.platform === "win32") {
		const args = [
			"/PID",
			String(proc.pid),
			"/T"
		];
		if (force) args.push("/F");
		try {
			execFileSync("taskkill.exe", args, { stdio: "ignore" });
		} catch {}
		return;
	}
	try {
		process.kill(proc.pid, force ? "SIGKILL" : "SIGTERM");
	} catch {}
}
async function killConflictingGatewayProcesses(options = {}) {
	const timeoutMs = Math.max(options.timeoutMs ?? 1200, 0);
	const intervalMs = Math.max(options.intervalMs ?? 100, 1);
	const initial = selectConflictingGatewayProcesses(listProcesses(), { activeGatewayPid: options.activeGatewayPid });
	if (initial.length === 0) return {
		killed: [],
		escalated: []
	};
	for (const proc of initial) terminatePid(proc, false);
	let waitedMs = 0;
	while (waitedMs < timeoutMs) {
		if (selectConflictingGatewayProcesses(listProcesses(), { activeGatewayPid: options.activeGatewayPid }).length === 0) return {
			killed: initial,
			escalated: []
		};
		await new Promise((resolve) => setTimeout(resolve, intervalMs));
		waitedMs += intervalMs;
	}
	const escalated = selectConflictingGatewayProcesses(listProcesses(), { activeGatewayPid: options.activeGatewayPid });
	for (const proc of escalated) terminatePid(proc, true);
	return {
		killed: initial,
		escalated
	};
}

//#endregion
//#region ../../src/cli/daemon-cli/lifecycle.ts
function isRestartBlockingServiceIssue(issue) {
	return issue.level === "aggressive" || issue.code === SERVICE_AUDIT_CODES.gatewayCommandMissing;
}
function renderServiceRepairHints() {
	return [
		formatCliCommand("edwinpai gateway install --force"),
		formatCliCommand("edwinpai gateway restart"),
		formatCliCommand("edwinpai gateway status")
	];
}
function parseRestartVerifyTimeoutMs(env) {
	const raw = env.EDWINPAI_GATEWAY_RESTART_VERIFY_TIMEOUT_MS;
	if (raw !== void 0 && raw.trim() !== "") {
		const parsed = Number(raw);
		if (Number.isFinite(parsed)) return Math.max(0, Math.floor(parsed));
	}
	return 5e3;
}
async function waitForRestartedGatewayPid(params) {
	const timeoutMs = parseRestartVerifyTimeoutMs(params.env);
	const deadline = Date.now() + timeoutMs;
	let lastLoaded = true;
	let lastPid = null;
	while (true) {
		try {
			lastLoaded = await params.service.isLoaded({ env: params.env });
			lastPid = (await params.service.readRuntime(params.env)).pid ?? null;
			if (!lastLoaded) return {
				loaded: false,
				pid: lastPid
			};
			if (params.previousPid === null || lastPid !== null && lastPid !== params.previousPid) return {
				loaded: lastLoaded,
				pid: lastPid
			};
		} catch {}
		if (Date.now() >= deadline) return {
			loaded: lastLoaded,
			pid: lastPid
		};
		await setTimeout$1(Math.min(100, Math.max(0, deadline - Date.now())));
	}
}
async function runDaemonUninstall(opts = {}) {
	const json = Boolean(opts.json);
	const stdout = json ? createNullWriter() : process.stdout;
	const emit = (payload) => {
		if (!json) return;
		emitDaemonActionJson({
			action: "uninstall",
			...payload
		});
	};
	const fail = (message) => {
		if (json) emit({
			ok: false,
			error: message
		});
		else defaultRuntime.error(message);
		defaultRuntime.exit(1);
	};
	if (resolveIsNixMode(process.env)) {
		fail("Nix mode detected; service uninstall is disabled.");
		return;
	}
	const service = resolveGatewayService();
	let loaded = false;
	try {
		loaded = await service.isLoaded({ env: process.env });
	} catch {
		loaded = false;
	}
	if (loaded) try {
		await service.stop({
			env: process.env,
			stdout
		});
	} catch {}
	try {
		await service.uninstall({
			env: process.env,
			stdout
		});
	} catch (err) {
		fail(`Gateway uninstall failed: ${String(err)}`);
		return;
	}
	loaded = false;
	try {
		loaded = await service.isLoaded({ env: process.env });
	} catch {
		loaded = false;
	}
	if (loaded) {
		fail("Gateway service still loaded after uninstall.");
		return;
	}
	emit({
		ok: true,
		result: "uninstalled",
		service: buildDaemonServiceSnapshot(service, loaded)
	});
}
async function runDaemonStart(opts = {}) {
	const json = Boolean(opts.json);
	const stdout = json ? createNullWriter() : process.stdout;
	const emit = (payload) => {
		if (!json) return;
		emitDaemonActionJson({
			action: "start",
			...payload
		});
	};
	const fail = (message, hints) => {
		if (json) emit({
			ok: false,
			error: message,
			hints
		});
		else defaultRuntime.error(message);
		defaultRuntime.exit(1);
	};
	const service = resolveGatewayService();
	let loaded = false;
	try {
		loaded = await service.isLoaded({ env: process.env });
	} catch (err) {
		fail(`Gateway service check failed: ${String(err)}`);
		return;
	}
	if (!loaded) {
		let hints = renderGatewayServiceStartHints();
		if (process.platform === "linux") {
			if (!await isSystemdUserServiceAvailable().catch(() => false)) hints = [...hints, ...renderSystemdUnavailableHints({ wsl: await isWSL() })];
		}
		emit({
			ok: true,
			result: "not-loaded",
			message: `Gateway service ${service.notLoadedText}.`,
			hints,
			service: buildDaemonServiceSnapshot(service, loaded)
		});
		if (!json) {
			defaultRuntime.log(`Gateway service ${service.notLoadedText}.`);
			for (const hint of hints) defaultRuntime.log(`Start with: ${hint}`);
		}
		return;
	}
	try {
		await service.restart({
			env: process.env,
			stdout
		});
	} catch (err) {
		const hints = renderGatewayServiceStartHints();
		fail(`Gateway start failed: ${String(err)}`, hints);
		return;
	}
	let started = true;
	try {
		started = await service.isLoaded({ env: process.env });
	} catch {
		started = true;
	}
	emit({
		ok: true,
		result: "started",
		service: buildDaemonServiceSnapshot(service, started)
	});
}
async function runDaemonStop(opts = {}) {
	const json = Boolean(opts.json);
	const stdout = json ? createNullWriter() : process.stdout;
	const emit = (payload) => {
		if (!json) return;
		emitDaemonActionJson({
			action: "stop",
			...payload
		});
	};
	const fail = (message) => {
		if (json) emit({
			ok: false,
			error: message
		});
		else defaultRuntime.error(message);
		defaultRuntime.exit(1);
	};
	const service = resolveGatewayService();
	let loaded = false;
	try {
		loaded = await service.isLoaded({ env: process.env });
	} catch (err) {
		fail(`Gateway service check failed: ${String(err)}`);
		return;
	}
	if (!loaded) {
		emit({
			ok: true,
			result: "not-loaded",
			message: `Gateway service ${service.notLoadedText}.`,
			service: buildDaemonServiceSnapshot(service, loaded)
		});
		if (!json) defaultRuntime.log(`Gateway service ${service.notLoadedText}.`);
		return;
	}
	try {
		await service.stop({
			env: process.env,
			stdout
		});
	} catch (err) {
		fail(`Gateway stop failed: ${String(err)}`);
		return;
	}
	let stopped = false;
	try {
		stopped = await service.isLoaded({ env: process.env });
	} catch {
		stopped = false;
	}
	emit({
		ok: true,
		result: "stopped",
		service: buildDaemonServiceSnapshot(service, stopped)
	});
}
/**
* Restart the gateway service service.
* @returns `true` if restart succeeded, `false` if the service was not loaded.
* Throws/exits on check or restart failures.
*/
async function runDaemonRestart(opts = {}) {
	const json = Boolean(opts.json);
	const stdout = json ? createNullWriter() : process.stdout;
	const emit = (payload) => {
		if (!json) return;
		emitDaemonActionJson({
			action: "restart",
			...payload
		});
	};
	const fail = (message, hints) => {
		if (json) emit({
			ok: false,
			error: message,
			hints
		});
		else defaultRuntime.error(message);
		defaultRuntime.exit(1);
	};
	const service = resolveGatewayService();
	let loaded = false;
	try {
		loaded = await service.isLoaded({ env: process.env });
	} catch (err) {
		fail(`Gateway service check failed: ${String(err)}`);
		return false;
	}
	if (!loaded) {
		let hints = renderGatewayServiceStartHints();
		if (process.platform === "linux") {
			if (!await isSystemdUserServiceAvailable().catch(() => false)) hints = [...hints, ...renderSystemdUnavailableHints({ wsl: await isWSL() })];
		}
		emit({
			ok: true,
			result: "not-loaded",
			message: `Gateway service ${service.notLoadedText}.`,
			hints,
			service: buildDaemonServiceSnapshot(service, loaded)
		});
		if (!json) {
			defaultRuntime.log(`Gateway service ${service.notLoadedText}.`);
			for (const hint of hints) defaultRuntime.log(`Start with: ${hint}`);
		}
		return false;
	}
	const command = await service.readCommand(process.env).catch(() => null);
	const blockingIssues = (await auditGatewayServiceConfig({
		env: process.env,
		command,
		config: loadConfig()
	}).catch(() => null))?.issues.filter(isRestartBlockingServiceIssue) ?? [];
	if (blockingIssues.length > 0) {
		const hints = renderServiceRepairHints();
		const detail = blockingIssues.map((issue) => issue.detail ? `${issue.message} (${issue.detail})` : issue.message).join("; ");
		emit({
			ok: false,
			result: "repair-required",
			error: `Gateway service wiring looks stale or non-standard: ${detail}`,
			hints,
			service: buildDaemonServiceSnapshot(service, loaded)
		});
		if (!json) {
			defaultRuntime.error(`Gateway service wiring looks stale or non-standard: ${detail}`);
			defaultRuntime.error("Restart skipped because the service may still launch an older EdwinPAI install.");
			for (const hint of hints) defaultRuntime.error(`Repair with: ${hint}`);
		}
		defaultRuntime.exit(1);
		return false;
	}
	try {
		let activeGatewayPid = null;
		try {
			activeGatewayPid = (await service.readRuntime(process.env)).pid ?? null;
		} catch {
			activeGatewayPid = null;
		}
		const cleanedBefore = await killConflictingGatewayProcesses({ activeGatewayPid });
		if (!json) {
			for (const proc of cleanedBefore.killed) defaultRuntime.log(`Restart cleanup: terminated pid ${proc.pid} (${proc.command})`);
			for (const proc of cleanedBefore.escalated) defaultRuntime.log(`Restart cleanup: escalated to SIGKILL for pid ${proc.pid} (${proc.command})`);
		}
		await service.restart({
			env: process.env,
			stdout
		});
		const restartVerification = await waitForRestartedGatewayPid({
			service,
			env: process.env,
			previousPid: activeGatewayPid
		});
		const restarted = restartVerification.loaded;
		const restartedGatewayPid = restartVerification.pid;
		if (activeGatewayPid !== null && restartedGatewayPid === activeGatewayPid) throw new Error(`service restart did not replace the running gateway process (pid ${activeGatewayPid})`);
		const cleanedAfter = await killConflictingGatewayProcesses({ activeGatewayPid: restartedGatewayPid });
		if (!json) {
			for (const proc of cleanedAfter.killed) defaultRuntime.log(`Restart cleanup: terminated post-restart pid ${proc.pid} (${proc.command})`);
			for (const proc of cleanedAfter.escalated) defaultRuntime.log(`Restart cleanup: escalated post-restart to SIGKILL for pid ${proc.pid} (${proc.command})`);
		}
		emit({
			ok: true,
			result: "restarted",
			service: buildDaemonServiceSnapshot(service, restarted)
		});
		return true;
	} catch (err) {
		const hints = renderGatewayServiceStartHints();
		fail(`Gateway restart failed: ${String(err)}`, hints);
		return false;
	}
}

//#endregion
export { runDaemonInstall as a, runDaemonUninstall as i, runDaemonStart as n, runDaemonStop as r, runDaemonRestart as t };