import { _ as resolveStateDir, h as resolveOAuthDir, i as isNixMode, o as resolveConfigPath, u as resolveGatewayPort } from "./paths-C9FmTW1x.js";
import { U as theme, b as resolveHomeDir } from "./agent-paths-BySKyq9I.js";
import { Dn as loadConfig, Jn as parseDurationMs, dd as formatCliCommand, eu as runExec, kn as readConfigFileSnapshot } from "./agent-scope-CLn_Ws3B.js";
import "./commands-registry-DfzoWf4b.js";
import { $o as getTailnetHostname, Bt as detectBrowserOpenSupport, Ht as formatControlUiSshHint, Jt as openUrl, Qt as resolveControlUiLinks, _o as normalizePublicHost, an as removePath, bo as resolveControlUiBootCheck, go as createLoginGrant, in as listAgentSessionDirs, mo as CONTROL_UI_LOGIN_DEFAULT_GRANT_TTL_MS, on as removeStateAndLinkedPaths, rn as buildCleanupPlan, sn as removeWorkspaceDirs, xo as normalizeControlUiBasePath } from "./reply-DQfPM5ia.js";
import { d as defaultRuntime } from "./errors-Dx3S3Nrp.js";
import "./send-DI5jsj-s.js";
import "./send-Dg2_aoK-.js";
import "./github-copilot-token-BA45-q56.js";
import "./chat-envelope-D_wSv26N.js";
import "./pi-model-discovery-BftA1L--.js";
import "./dangerous-tools-C88-uuUI.js";
import "./chrome-BFIqTpDi.js";
import "./pairing-token-BFGorDQo.js";
import "./ip-D_T5zbZS.js";
import "./ws-cvQhrVP3.js";
import "./onboarding.wallet-B12p7GUZ.js";
import "./wallet-runtime-config-BlRWvEER.js";
import "./wallet-provider-registry-ax0NJo0F.js";
import "./wallet-BPiknFdt.js";
import "./wallet-approval-auth-DT-vofLs.js";
import "./reply-prefix-BRvLVE6I.js";
import "./media-ZuS0crH3.js";
import "./path-alias-guards-DivKBvV8.js";
import "./fs-safe-Cp0MI7Oo.js";
import "./runtime-bsvPuEXH.js";
import "./device-identity-DzUZ06fL.js";
import "./solana-bond-signing-CgswTuFe.js";
import "./diagnostic-Cl18V9Cy.js";
import "./federation-BrNm7xtG.js";
import { n as callGateway } from "./call-s6DNIELo.js";
import "./chunk-tBRG1JLR.js";
import "./markdown-tables-DvKl7MfL.js";
import "./send-aHqtlYYi.js";
import "./fetch-guard-hWUtz61M.js";
import "./ssrf-Blf4NrHS.js";
import "./outbound-attachment-BHTb_aF7.js";
import "./fetch-BJWQWfdf.js";
import "./delivery-queue-9lp1uujZ.js";
import "./deps-CBapZnsi.js";
import "./memory-e9aOXNx1.js";
import "./memory-search-B8y2GTeB.js";
import "./manager-DI2w66Ae.js";
import "./query-expansion-BdzehFyx.js";
import "./memory-cli-mMVfDz8Z.js";
import "./target-errors-_IirSOQ1.js";
import "./render-C2MRWrC0.js";
import "./diagnostic-session-state-89enG0Yp.js";
import "./send-B3O8oJLA.js";
import "./model-CfutahU0.js";
import "./exec-approvals-allowlist-C5bxRc7H.js";
import "./dangerous-name-matching-B2YH8EDF.js";
import "./skills-D1Qdj69-.js";
import "./node-match-BNTZ8TY5.js";
import "./system-run-command-BvFkDQae.js";
import "./channel-selection-EDP8q9uz.js";
import "./task-planner-BW6kdamv.js";
import "./trash-BiHtb5y8.js";
import "./paths-BA7z-HF9.js";
import "./send-CKgt65ud.js";
import "./resolve-route-CbII9dNc.js";
import "./pairing-store-CUPrh2Qy.js";
import "./session-cost-usage-DQSpjhkP.js";
import "./skills-clawhub-kuGAFKgL.js";
import "./config-eval-CuVkTCse.js";
import "./channel-activity-BkfQ8RFW.js";
import "./tables-apsvCDwc.js";
import "./proxy-DU7W9XSc.js";
import "./config-BKhx4paQ.js";
import { t as formatDocsLink } from "./links-BeUKckiL.js";
import { n as runCommandWithRuntime } from "./cli-utils-DJ7Nfw8J.js";
import "./help-format-H4GNCFCs.js";
import "./progress-CDqdg8f8.js";
import "./replies-Xddrs-mt.js";
import "./skills-remote-DkdYN-8J.js";
import "./skill-commands-CxJHp3z6.js";
import { a as stylePromptTitle, i as stylePromptMessage, r as stylePromptHint } from "./prompt-style-Db5iJoaI.js";
import "./pairing-labels-sAC1Ty3_.js";
import "./program-context-Di7qiwOM.js";
import "./skills-status-Bgumcv_3.js";
import { t as copyToClipboard } from "./clipboard-nPo22dPI.js";
import "./completion-cli-Bd9iPo4A.js";
import "./managed-up-BykEd-7K.js";
import "./daemon-install-helpers-CG_Lmgua.js";
import "./systemd-ZvgpcrfV.js";
import { t as resolveGatewayService } from "./service-DbZp-Ejz.js";
import "./service-audit-B5uApPZ5.js";
import "./diagnostics-xs78uPKj.js";
import { a as probeHostedDashboardBrowserPath } from "./health-DTTfLYjl.js";
import "./heartbeat-runner-DXh84Wuy.js";
import "./update-check-O2MzLp2j.js";
import "./logging-C8GVa7dS.js";
import "./installs-BS-BIvab.js";
import "./channels-status-issues-BKJ6osOg.js";
import "./update-runner-C0SU1jGT.js";
import "./note-BVXI9hXT.js";
import "./doctor-config-flow-BN2bIR8A.js";
import "./systemd-linger-S605QEIC.js";
import "./health-format-BDteAZU6.js";
import { n as doctorCommand, t as selectStyled } from "./prompt-select-styled-8KBIPNro.js";
import fs from "node:fs";
import path from "node:path";
import { cancel, confirm, isCancel, multiselect } from "@clack/prompts";

//#region src/commands/dashboard-link.ts
const AGENT_DOMAIN_SUFFIX = ".agents.fased.app";
function readStateGatewayToken(env = process.env) {
	try {
		const filePath = path.join(resolveStateDir(env), "gateway-secret");
		if (!fs.existsSync(filePath)) return "";
		return fs.readFileSync(filePath, "utf8").trim();
	} catch {
		return "";
	}
}
function collectGatewayTokenCandidates(snapshot, options) {
	const out = [];
	const optionToken = options.token?.trim() || "";
	if (optionToken) out.push({
		source: "option",
		token: optionToken
	});
	const envToken = process.env.FASED_GATEWAY_TOKEN?.trim() || "";
	if (envToken) out.push({
		source: "env",
		token: envToken
	});
	const stateToken = readStateGatewayToken(process.env);
	if (stateToken) out.push({
		source: "state-file",
		token: stateToken
	});
	if (snapshot.valid) {
		const configuredToken = snapshot.config?.gateway?.auth?.token?.trim();
		if (configuredToken) out.push({
			source: "config",
			token: configuredToken
		});
	}
	return out;
}
function resolveGatewayToken(snapshot, options) {
	const optionToken = options.token?.trim() || "";
	if (optionToken) return {
		token: optionToken,
		source: "option"
	};
	const candidates = collectGatewayTokenCandidates(snapshot, options);
	const distinct = /* @__PURE__ */ new Map();
	for (const candidate of candidates) {
		const list = distinct.get(candidate.token) ?? [];
		list.push(candidate.source);
		distinct.set(candidate.token, list);
	}
	if (distinct.size > 1) {
		const parts = candidates.map((candidate) => `${candidate.source}=set`).join(", ");
		throw new Error(`gateway token mismatch across sources (${parts}); align --token / FASED_GATEWAY_TOKEN / ~/.fased/gateway-secret / gateway.auth.token`);
	}
	if (candidates.length === 0) return {
		token: "",
		source: "config"
	};
	return {
		token: candidates[0].token,
		source: candidates[0].source
	};
}
async function dashboardLinkCommand(runtime = defaultRuntime, options) {
	const rawPublicUrl = options.publicUrl?.trim() || "";
	if (!rawPublicUrl) throw new Error("missing required --public-url");
	let parsed;
	try {
		parsed = new URL(rawPublicUrl);
	} catch {
		throw new Error("invalid --public-url");
	}
	if (parsed.protocol !== "https:") throw new Error("public URL must use https://");
	const host = normalizePublicHost(parsed.host);
	if (!host) throw new Error("public URL host is invalid");
	if (!options.allowCustomHost && !host.endsWith(AGENT_DOMAIN_SUFFIX)) throw new Error("public URL host must be under *.agents.fased.app (use --allow-custom-host to override)");
	const resolvedToken = resolveGatewayToken(await readConfigFileSnapshot(), options);
	const gatewayToken = resolvedToken.token;
	if (!gatewayToken) throw new Error("gateway token not configured (set --token, FASED_GATEWAY_TOKEN, ~/.fased/gateway-secret, or gateway.auth.token)");
	const ttlMs = options.ttl ? parseDurationMs(options.ttl, { defaultUnit: "m" }) : CONTROL_UI_LOGIN_DEFAULT_GRANT_TTL_MS;
	if (ttlMs <= 0) throw new Error("ttl must be greater than 0");
	const grant = createLoginGrant({
		gatewayToken,
		host,
		ttlMs
	});
	const finalUrl = new URL(parsed.toString());
	const hashParams = new URLSearchParams();
	hashParams.set("login", grant);
	if (options.onboarding) hashParams.set("onboarding", "1");
	finalUrl.hash = hashParams.toString();
	runtime.log(`Dashboard login URL: ${finalUrl.toString()}`);
	runtime.log(`Grant TTL: ${Math.ceil(ttlMs / 1e3)}s`);
	runtime.log(`Gateway token source: ${resolvedToken.source}`);
	runtime.log("This link is one-time use. If leaked, revoke by rotating gateway token.");
}

//#endregion
//#region src/commands/dashboard.ts
const LOCAL_DASHBOARD_GATEWAY_TIMEOUT_MS = 3e4;
const HOSTED_DASHBOARD_GATEWAY_TIMEOUT_MS = 12e4;
const HOSTED_DASHBOARD_BROWSER_TIMEOUT_MS = 12e4;
function buildDashboardUrl(params) {
	const url = new URL(params.httpUrl);
	const hashParams = new URLSearchParams();
	const token = params.token?.trim();
	if (token) hashParams.set("token", token);
	const hash = hashParams.toString();
	url.hash = hash ? `#${hash}` : "";
	return url.toString();
}
async function resolveHostedDashboardHttpUrl(params) {
	if (!params.tailscaleMode || params.tailscaleMode === "off") return null;
	const dns = await getTailnetHostname((cmd, args) => runExec(cmd, args, {
		timeoutMs: 1200,
		maxBuffer: 2e5
	})).catch(() => null);
	if (!dns) return null;
	const basePath = normalizeControlUiBasePath(params.basePath);
	return `https://${dns}${basePath ? `${basePath}/` : "/"}`;
}
async function probeDashboardGateway(cfg, timeoutMs = 5e3) {
	try {
		const summary = await callGateway({
			method: "health",
			timeoutMs,
			config: cfg
		});
		return {
			ok: true,
			durationMs: typeof summary.durationMs === "number" ? summary.durationMs : null
		};
	} catch (err) {
		const message = err instanceof Error ? err.message : String(err);
		return {
			ok: false,
			message: message.split("\n")[0] ?? message
		};
	}
}
function isHostedDashboardUrl(httpUrl, localHttpUrl) {
	try {
		const hosted = new URL(httpUrl);
		const local = new URL(localHttpUrl);
		return hosted.origin !== local.origin && hosted.protocol === "https:";
	} catch {
		return false;
	}
}
function isGatewayWarmupTimeout(message) {
	return /gateway timeout|operation was aborted|aborted due to timeout/i.test(message);
}
function buildDashboardWsUrl(httpUrl) {
	try {
		const url = new URL(httpUrl);
		url.protocol = url.protocol === "https:" ? "wss:" : "ws:";
		url.search = "";
		url.hash = "";
		return url.toString();
	} catch {
		return null;
	}
}
function formatBootAssetLine(label, asset) {
	if (!asset) return `Dashboard ${label}: not referenced`;
	const status = typeof asset.status === "number" ? String(asset.status) : "fetch failed";
	const contentType = asset.contentType?.trim() || "missing content-type";
	const suffix = asset.ok ? "" : ` (${asset.message ?? "failed"})`;
	return `Dashboard ${label}: ${asset.url} [${status}, ${contentType}]${suffix}`;
}
function logHostedDashboardBootCheck(runtime, bootCheck) {
	const indexStatus = typeof bootCheck.indexResponse.status === "number" ? String(bootCheck.indexResponse.status) : "fetch failed";
	const indexType = bootCheck.indexResponse.contentType?.trim() || "missing content-type";
	const indexSuffix = bootCheck.indexResponse.ok ? "" : ` (${bootCheck.indexResponse.message ?? "failed"})`;
	runtime.log(`Dashboard boot check: ${bootCheck.index} via ${bootCheck.serve}`);
	runtime.log(`Dashboard index: ${bootCheck.indexResponse.url} [${indexStatus}, ${indexType}]${indexSuffix}`);
	runtime.log(formatBootAssetLine("entry JS", bootCheck.entryJs));
	runtime.log(formatBootAssetLine("app JS", bootCheck.appJs));
}
function resolveLocalDashboardBootCheck(params) {
	const origin = (() => {
		try {
			return new URL(params.httpUrl).origin;
		} catch {
			return "http://localhost";
		}
	})();
	return resolveControlUiBootCheck({
		basePath: params.basePath,
		origin,
		serve: "direct"
	});
}
function logLocalDashboardBootCheck(runtime, bootCheck) {
	const indexStatus = typeof bootCheck.indexResponse.status === "number" ? String(bootCheck.indexResponse.status) : "fetch failed";
	const indexType = bootCheck.indexResponse.contentType?.trim() || "missing content-type";
	const indexSuffix = bootCheck.indexResponse.ok ? "" : ` (${bootCheck.indexResponse.message ?? "failed"})`;
	runtime.log(`Dashboard boot check: ${bootCheck.index} via ${bootCheck.serve}`);
	runtime.log(`Dashboard index: ${bootCheck.indexResponse.url} [${indexStatus}, ${indexType}]${indexSuffix}`);
	runtime.log(formatBootAssetLine("entry JS", bootCheck.entryJs));
	runtime.log(formatBootAssetLine("app JS", bootCheck.appJs));
}
async function dashboardCommand(runtime = defaultRuntime, options = {}) {
	const snapshot = await readConfigFileSnapshot();
	const cfg = snapshot.valid ? snapshot.config : {};
	const port = resolveGatewayPort(cfg);
	const bind = cfg.gateway?.bind ?? "loopback";
	const basePath = cfg.gateway?.controlUi?.basePath;
	const customBindHost = cfg.gateway?.customBindHost;
	const token = cfg.gateway?.auth?.token ?? process.env.FASED_GATEWAY_TOKEN ?? "";
	const links = resolveControlUiLinks({
		port,
		bind: bind === "lan" ? "loopback" : bind,
		customBindHost,
		basePath
	});
	const hostedHttpUrl = await resolveHostedDashboardHttpUrl({
		tailscaleMode: cfg.gateway?.tailscale?.mode ?? "off",
		basePath
	}) ?? links.httpUrl;
	const hostedDashboard = isHostedDashboardUrl(hostedHttpUrl, links.httpUrl);
	const dashboardUrl = buildDashboardUrl({
		httpUrl: hostedHttpUrl,
		token
	});
	const gatewayProbe = await probeDashboardGateway(cfg, hostedDashboard ? HOSTED_DASHBOARD_GATEWAY_TIMEOUT_MS : LOCAL_DASHBOARD_GATEWAY_TIMEOUT_MS);
	if (gatewayProbe.ok) {
		const suffix = gatewayProbe.durationMs != null ? ` (${Math.max(0, Math.round(gatewayProbe.durationMs))}ms)` : "";
		runtime.log(`Gateway: online${suffix}`);
	} else {
		const warming = hostedDashboard && isGatewayWarmupTimeout(gatewayProbe.message);
		runtime.log(`Gateway: ${warming ? "warming" : "offline"} (${gatewayProbe.message})`);
		runtime.log(warming ? "Hosted Gateway is still warming after restart; retry dashboard after it settles." : "The dashboard page may load, but it will stay offline until the Gateway is healthy.");
		runtime.log("Run: fased health");
	}
	if (hostedDashboard) if (!gatewayProbe.ok) {
		const warming = isGatewayWarmupTimeout(gatewayProbe.message);
		runtime.log(`Dashboard browser path: not checked via Tailscale (gateway ${warming ? "warming" : "offline"})`);
		const wsUrl = buildDashboardWsUrl(hostedHttpUrl);
		if (wsUrl) runtime.log(`Dashboard websocket: ${wsUrl}`);
	} else if (token.trim()) {
		const hostedProbe = await probeHostedDashboardBrowserPath({
			httpUrl: hostedHttpUrl,
			token,
			timeoutMs: HOSTED_DASHBOARD_BROWSER_TIMEOUT_MS
		});
		if (hostedProbe.ok) {
			runtime.log(`Dashboard browser path: online via Tailscale (${Math.max(0, Math.round(hostedProbe.durationMs))}ms)`);
			if (options.noOpen) logHostedDashboardBootCheck(runtime, hostedProbe.bootCheck);
		} else {
			runtime.log(`Dashboard browser path: offline via Tailscale (${hostedProbe.stage}: ${hostedProbe.message})`);
			if (hostedProbe.bootCheck) logHostedDashboardBootCheck(runtime, hostedProbe.bootCheck);
			if (hostedProbe.wsUrl) runtime.log(`Dashboard websocket: ${hostedProbe.wsUrl}`);
		}
	} else runtime.log("Dashboard browser path: not checked (missing gateway token)");
	else if (options.noOpen) {
		logLocalDashboardBootCheck(runtime, resolveLocalDashboardBootCheck({
			httpUrl: links.httpUrl,
			basePath
		}));
		runtime.log(`Dashboard websocket: ${links.wsUrl}`);
	}
	runtime.log(`Dashboard URL: ${dashboardUrl}`);
	if (!options.noOpen) {
		const copied = await copyToClipboard(dashboardUrl).catch(() => false);
		runtime.log(copied ? "Copied to clipboard." : "Copy to clipboard unavailable.");
	}
	let opened = false;
	let hint;
	if (!options.noOpen) {
		if ((await detectBrowserOpenSupport()).ok) opened = await openUrl(dashboardUrl);
		if (!opened) hint = formatControlUiSshHint({
			port,
			basePath,
			token: token || void 0
		});
	} else hint = "Browser launch disabled (--no-open). Use the URL above.";
	if (opened) runtime.log("Opened in your browser. Keep that tab to control Fased Agent.");
	else if (hint) runtime.log(hint);
}

//#endregion
//#region src/commands/cleanup-plan.ts
function resolveCleanupPlanFromDisk() {
	const cfg = loadConfig();
	const stateDir = resolveStateDir();
	const configPath = resolveConfigPath();
	const oauthDir = resolveOAuthDir();
	return {
		cfg,
		stateDir,
		configPath,
		oauthDir,
		...buildCleanupPlan({
			cfg,
			stateDir,
			configPath,
			oauthDir
		})
	};
}

//#endregion
//#region src/commands/reset.ts
async function stopGatewayIfRunning(runtime) {
	if (isNixMode) return;
	const service = resolveGatewayService();
	let loaded = false;
	try {
		loaded = await service.isLoaded({ env: process.env });
	} catch (err) {
		runtime.error(`Gateway service check failed: ${String(err)}`);
		return;
	}
	if (!loaded) return;
	try {
		await service.stop({
			env: process.env,
			stdout: process.stdout
		});
	} catch (err) {
		runtime.error(`Gateway stop failed: ${String(err)}`);
	}
}
async function resetCommand(runtime, opts) {
	const interactive = !opts.nonInteractive;
	if (!interactive && !opts.yes) {
		runtime.error("Non-interactive mode requires --yes.");
		runtime.exit(1);
		return;
	}
	let scope = opts.scope;
	if (!scope) {
		if (!interactive) {
			runtime.error("Non-interactive mode requires --scope.");
			runtime.exit(1);
			return;
		}
		const selection = await selectStyled({
			message: "Reset scope",
			options: [
				{
					value: "config",
					label: "Config only",
					hint: "fased.json; preserves wallets and Tailscale access"
				},
				{
					value: "config+creds+sessions",
					label: "Config + credentials + sessions",
					hint: "preserves wallets, workspace, and Tailscale access"
				},
				{
					value: "full",
					label: "Full reset",
					hint: "state dir + workspace, but preserves wallet material"
				}
			],
			initialValue: "config+creds+sessions"
		});
		if (isCancel(selection)) {
			cancel(stylePromptTitle("Reset cancelled.") ?? "Reset cancelled.");
			runtime.exit(0);
			return;
		}
		scope = selection;
	}
	if (![
		"config",
		"config+creds+sessions",
		"full"
	].includes(scope)) {
		runtime.error("Invalid --scope. Expected \"config\", \"config+creds+sessions\", or \"full\".");
		runtime.exit(1);
		return;
	}
	if (interactive && !opts.yes) {
		const ok = await confirm({ message: stylePromptMessage(`Proceed with ${scope} reset? Wallet material and Tailscale device access are preserved.`) });
		if (isCancel(ok) || !ok) {
			cancel(stylePromptTitle("Reset cancelled.") ?? "Reset cancelled.");
			runtime.exit(0);
			return;
		}
	}
	const dryRun = Boolean(opts.dryRun);
	const { stateDir, configPath, oauthDir, configInsideState, oauthInsideState, workspaceDirs } = resolveCleanupPlanFromDisk();
	if (scope !== "config") if (dryRun) runtime.log("[dry-run] stop gateway service");
	else await stopGatewayIfRunning(runtime);
	if (scope === "config") {
		await removePath(configPath, runtime, {
			dryRun,
			label: configPath
		});
		return;
	}
	if (scope === "config+creds+sessions") {
		await removePath(configPath, runtime, {
			dryRun,
			label: configPath
		});
		await removePath(oauthDir, runtime, {
			dryRun,
			label: oauthDir
		});
		const sessionDirs = await listAgentSessionDirs(stateDir);
		for (const dir of sessionDirs) await removePath(dir, runtime, {
			dryRun,
			label: dir
		});
		runtime.log(`Next: ${formatCliCommand("fased onboard --install-daemon")}`);
		return;
	}
	if (scope === "full") {
		await removeStateAndLinkedPaths({
			stateDir,
			configPath,
			oauthDir,
			configInsideState,
			oauthInsideState
		}, runtime, {
			dryRun,
			preserveWalletDir: true
		});
		await removeWorkspaceDirs(workspaceDirs, runtime, { dryRun });
		runtime.log(`Next: ${formatCliCommand("fased onboard --install-daemon")}`);
		return;
	}
}

//#endregion
//#region src/commands/uninstall.ts
const multiselectStyled = (params) => multiselect({
	...params,
	message: stylePromptMessage(params.message),
	options: params.options.map((opt) => opt.hint === void 0 ? opt : {
		...opt,
		hint: stylePromptHint(opt.hint)
	})
});
function buildScopeSelection(opts) {
	const hadExplicit = Boolean(opts.all || opts.service || opts.state || opts.workspace || opts.app);
	const scopes = /* @__PURE__ */ new Set();
	if (opts.all || opts.service) scopes.add("service");
	if (opts.all || opts.state) scopes.add("state");
	if (opts.all || opts.workspace) scopes.add("workspace");
	if (opts.all || opts.app) scopes.add("app");
	return {
		scopes,
		hadExplicit
	};
}
async function stopAndUninstallService(runtime) {
	if (isNixMode) {
		runtime.error("Nix mode detected; service uninstall is disabled.");
		return false;
	}
	const service = resolveGatewayService();
	let loaded = false;
	try {
		loaded = await service.isLoaded({ env: process.env });
	} catch (err) {
		runtime.error(`Gateway service check failed: ${String(err)}`);
		return false;
	}
	if (!loaded) {
		runtime.log(`Gateway service ${service.notLoadedText}.`);
		return true;
	}
	try {
		await service.stop({
			env: process.env,
			stdout: process.stdout
		});
	} catch (err) {
		runtime.error(`Gateway stop failed: ${String(err)}`);
	}
	try {
		await service.uninstall({
			env: process.env,
			stdout: process.stdout
		});
		return true;
	} catch (err) {
		runtime.error(`Gateway uninstall failed: ${String(err)}`);
		return false;
	}
}
async function removeMacApp(runtime, dryRun) {
	if (process.platform !== "darwin") return;
	await removePath("/Applications/FasedAgent.app", runtime, {
		dryRun,
		label: "/Applications/FasedAgent.app"
	});
}
async function uninstallCommand(runtime, opts) {
	const { scopes, hadExplicit } = buildScopeSelection(opts);
	const interactive = !opts.nonInteractive;
	if (!interactive && !opts.yes) {
		runtime.error("Non-interactive mode requires --yes.");
		runtime.exit(1);
		return;
	}
	if (!hadExplicit) {
		if (!interactive) {
			runtime.error("Non-interactive mode requires explicit scopes (use --all).");
			runtime.exit(1);
			return;
		}
		const selection = await multiselectStyled({
			message: "Uninstall which components?",
			options: [
				{
					value: "service",
					label: "Gateway service",
					hint: "launchd / systemd / schtasks"
				},
				{
					value: "state",
					label: "State + config",
					hint: "~/.fased"
				},
				{
					value: "workspace",
					label: "Workspace",
					hint: "agent files"
				},
				{
					value: "app",
					label: "macOS app",
					hint: "/Applications/FasedAgent.app"
				}
			],
			initialValues: [
				"service",
				"state",
				"workspace"
			]
		});
		if (isCancel(selection)) {
			cancel(stylePromptTitle("Uninstall cancelled.") ?? "Uninstall cancelled.");
			runtime.exit(0);
			return;
		}
		for (const value of selection) scopes.add(value);
	}
	if (scopes.size === 0) {
		runtime.log("Nothing selected.");
		return;
	}
	if (interactive && !opts.yes) {
		const ok = await confirm({ message: stylePromptMessage("Proceed with uninstall?") });
		if (isCancel(ok) || !ok) {
			cancel(stylePromptTitle("Uninstall cancelled.") ?? "Uninstall cancelled.");
			runtime.exit(0);
			return;
		}
	}
	const dryRun = Boolean(opts.dryRun);
	const { stateDir, configPath, oauthDir, configInsideState, oauthInsideState, workspaceDirs } = resolveCleanupPlanFromDisk();
	if (scopes.has("service")) if (dryRun) runtime.log("[dry-run] remove gateway service");
	else await stopAndUninstallService(runtime);
	if (scopes.has("state")) await removeStateAndLinkedPaths({
		stateDir,
		configPath,
		oauthDir,
		configInsideState,
		oauthInsideState
	}, runtime, { dryRun });
	if (scopes.has("workspace")) await removeWorkspaceDirs(workspaceDirs, runtime, { dryRun });
	if (scopes.has("app")) await removeMacApp(runtime, dryRun);
	runtime.log("CLI still installed. Remove via npm/pnpm if desired.");
	if (scopes.has("state") && !scopes.has("workspace")) {
		const home = resolveHomeDir();
		if (home && workspaceDirs.some((dir) => dir.startsWith(path.resolve(home)))) runtime.log("Tip: workspaces were preserved. Re-run with --workspace to remove them.");
	}
}

//#endregion
//#region src/cli/program/register.maintenance.ts
function registerMaintenanceCommands(program) {
	program.command("doctor").description("Health checks + quick fixes for the gateway and channels").addHelpText("after", () => `\n${theme.muted("Docs:")} ${formatDocsLink("/cli/doctor", "docs.fased.ai/cli/doctor")}\n`).option("--no-workspace-suggestions", "Disable workspace memory system suggestions", false).option("--yes", "Accept defaults without prompting", false).option("--repair", "Apply recommended repairs without prompting", false).option("--fix", "Apply recommended repairs (alias for --repair)", false).option("--force", "Apply aggressive repairs (overwrites custom service config)", false).option("--non-interactive", "Run without prompts (safe migrations only)", false).option("--generate-gateway-token", "Generate and configure a gateway token", false).option("--deep", "Scan system services for extra gateway installs", false).action(async (opts) => {
		await runCommandWithRuntime(defaultRuntime, async () => {
			await doctorCommand(defaultRuntime, {
				workspaceSuggestions: opts.workspaceSuggestions,
				yes: Boolean(opts.yes),
				repair: Boolean(opts.repair) || Boolean(opts.fix),
				force: Boolean(opts.force),
				nonInteractive: Boolean(opts.nonInteractive),
				generateGatewayToken: Boolean(opts.generateGatewayToken),
				deep: Boolean(opts.deep)
			});
			defaultRuntime.exit(0);
		});
	});
	program.command("dashboard-link").description("Generate a one-time public Control UI login link").addHelpText("after", () => `\n${theme.muted("Docs:")} ${formatDocsLink("/web/public-ui-login", "docs.fased.ai/web/public-ui-login")}\n`).requiredOption("--public-url <url>", "Public Control UI URL (https://<slug>.agents.fased.app)").option("--token <token>", "Gateway token override for grant signing").option("--ttl <duration>", "Grant TTL (e.g. 10m, 1h)", "10m").option("--onboarding", "Append onboarding=1 in link hash", false).option("--allow-custom-host", "Allow non-*.agents.fased.app host", false).action(async (opts) => {
		await runCommandWithRuntime(defaultRuntime, async () => {
			await dashboardLinkCommand(defaultRuntime, {
				publicUrl: String(opts.publicUrl ?? ""),
				token: String(opts.token ?? ""),
				ttl: String(opts.ttl ?? ""),
				onboarding: Boolean(opts.onboarding),
				allowCustomHost: Boolean(opts.allowCustomHost)
			});
		});
	});
	program.command("dashboard").description("Open the Control UI with your current token").addHelpText("after", () => `\n${theme.muted("Docs:")} ${formatDocsLink("/cli/dashboard", "docs.fased.ai/cli/dashboard")}\n`).option("--no-open", "Print URL but do not launch a browser").action(async (opts) => {
		await runCommandWithRuntime(defaultRuntime, async () => {
			await dashboardCommand(defaultRuntime, { noOpen: opts.open === false });
		});
	});
	program.command("reset").description("Reset local config/state (keeps the CLI installed)").addHelpText("after", () => `\n${theme.muted("Docs:")} ${formatDocsLink("/cli/reset", "docs.fased.ai/cli/reset")}\n`).option("--scope <scope>", "config|config+creds+sessions|full (default: interactive prompt)").option("--yes", "Skip confirmation prompts", false).option("--non-interactive", "Disable prompts (requires --scope + --yes)", false).option("--dry-run", "Print actions without removing files", false).action(async (opts) => {
		await runCommandWithRuntime(defaultRuntime, async () => {
			await resetCommand(defaultRuntime, {
				scope: opts.scope,
				yes: Boolean(opts.yes),
				nonInteractive: Boolean(opts.nonInteractive),
				dryRun: Boolean(opts.dryRun)
			});
		});
	});
	program.command("uninstall").description("Uninstall the gateway service + local data (CLI remains)").addHelpText("after", () => `\n${theme.muted("Docs:")} ${formatDocsLink("/cli/uninstall", "docs.fased.ai/cli/uninstall")}\n`).option("--service", "Remove the gateway service", false).option("--state", "Remove state + config", false).option("--workspace", "Remove workspace dirs", false).option("--app", "Remove the macOS app", false).option("--all", "Remove service + state + workspace + app", false).option("--yes", "Skip confirmation prompts", false).option("--non-interactive", "Disable prompts (requires --yes)", false).option("--dry-run", "Print actions without removing files", false).action(async (opts) => {
		await runCommandWithRuntime(defaultRuntime, async () => {
			await uninstallCommand(defaultRuntime, {
				service: Boolean(opts.service),
				state: Boolean(opts.state),
				workspace: Boolean(opts.workspace),
				app: Boolean(opts.app),
				all: Boolean(opts.all),
				yes: Boolean(opts.yes),
				nonInteractive: Boolean(opts.nonInteractive),
				dryRun: Boolean(opts.dryRun)
			});
		});
	});
}

//#endregion
export { registerMaintenanceCommands };