import { P as theme, _ as defaultRuntime, ot as resolveStateDir } from "./entry.js";
import { G as writeConfigFile, z as loadConfig } from "./auth-profiles-CgnoZiYS.js";
import "./agent-scope-Cezno7_M.js";
import { b as shortenHomeInString, h as resolveConfigDir, v as resolveUserPath, x as shortenHomePath } from "./utils-CD6tCvSG.js";
import "./core-root-CmA71BTT.js";
import "./logger-BcqRk323.js";
import "./exec-CaapFZaD.js";
import { A as defaultSlotIdForKey, k as applyExclusiveSlotSelection } from "./registry-CBFkaKwt.js";
import "./github-copilot-token-DHTToceK.js";
import { c as resolveBundledPluginsDir, t as clearPluginManifestRegistryCache } from "./manifest-registry-DdFBL-mx.js";
import "./version-sf9dgjHP.js";
import "./dock-MGfYkqVd.js";
import "./tokens-RCFQ-amj.js";
import "./compact-DGr2hadh.js";
import "./accounts-DQj4GURA.js";
import "./plugins-D7VGnP8X.js";
import "./logging-JZEg5nDp.js";
import "./send-CVUi_VO-.js";
import "./send-B_LE3LuQ.js";
import "./with-timeout-B6VGlljS.js";
import "./deliver-DmWt0aVn.js";
import "./diagnostic-D0TTrgNC.js";
import "./accounts-F1jmiu3k.js";
import "./image-ops-DxLQocoR.js";
import "./send-DZcZ8m6m.js";
import "./pi-model-discovery-BMNFsJrD.js";
import "./message-channel-DelDwlJy.js";
import "./pi-embedded-helpers-Jygiu_rm.js";
import "./sandbox-DapwL3Y3.js";
import "./tool-catalog-DwAGTRaX.js";
import "./chrome-CNj5RXTP.js";
import { l as promptYesNo } from "./tailscale-5K9XNlhO.js";
import "./tailnet-mjXbAxqf.js";
import "./ws-GlDBWD0H.js";
import "./auth-V2FS08vr.js";
import "./server-context-BF4RP1eP.js";
import "./frontmatter-B5GM2mXS.js";
import "./skills-CE-unP39.js";
import "./path-alias-guards-CNxRjVah.js";
import "./paths-BDDFj5Fw.js";
import "./redact-CC_d52A1.js";
import "./errors-DAcI6n_m.js";
import "./fs-safe-qdP8sV7U.js";
import "./proxy-env-B6UxsfXo.js";
import "./store-B5eeaWQa.js";
import "./ports-D8nInYfq.js";
import "./trash-CrF5N5Zh.js";
import "./server-middleware-BniDse6Q.js";
import "./sessions-CSzvEM0w.js";
import "./accounts-BMuunqOS.js";
import "./paths-COzEpwhO.js";
import "./chat-envelope-BUdriZB0.js";
import "./tool-images-Dtu-s5JK.js";
import "./thinking-BYXvmTqG.js";
import "./models-config-BVwpS5BT.js";
import "./exec-approvals-allowlist-DLolanQl.js";
import "./exec-safe-bin-runtime-policy-yz_-h-RQ.js";
import "./model-catalog-BqfN8gX9.js";
import "./fetch-syFYVRt3.js";
import "./audio-transcription-runner-BVW6o6TV.js";
import "./fetch-guard-CcDaj5My.js";
import "./image-D4aFv0X1.js";
import "./tool-display-B_FNOYTS.js";
import "./api-key-rotation-DLAEpbFc.js";
import "./proxy-fetch-TWpl-yhl.js";
import "./ir-BCFPWtL_.js";
import "./render-C9LkRUhd.js";
import "./target-errors-Ci3M951J.js";
import "./commands-CmZqo7n4.js";
import "./commands-registry-CaALqeCJ.js";
import "./session-cost-usage-WqkA7nWJ.js";
import "./sqlite-BkaDx2XJ.js";
import "./client-B8ehJjd1.js";
import "./call-BAwuZELF.js";
import "./pairing-token-01jjmach.js";
import "./fetch-1d1K1Sbw.js";
import "./pairing-store-Da6gxB-g.js";
import "./exec-approvals-B2nfDOCa.js";
import "./nodes-screen-D9eByp18.js";
import "./system-run-command-C9eoW3Ze.js";
import "./session-utils-CfyCGZX2.js";
import "./skill-commands-B4itYgGX.js";
import "./pi-tools.policy-vXZNXpv0.js";
import "./workspace-dirs-CEAXZCb7.js";
import "./channel-activity-CtGt6xvS.js";
import "./tables-gNfYyl-h.js";
import "./server-lifecycle-BH1bn6N4.js";
import "./stagger-C4U8O7GM.js";
import "./channel-selection-CccMG0Tp.js";
import "./plugin-auto-enable-BG8smK-4.js";
import "./send-CipSFPME.js";
import "./outbound-attachment-Bx3xWzM0.js";
import "./delivery-queue-BU5OeQMD.js";
import "./send-Dp0h-d5B.js";
import "./proxy-Dgwoliym.js";
import "./timeouts-3s3tygPw.js";
import "./runtime-config-collectors-C7Cs7evp.js";
import "./command-secret-targets-AV-RDTsr.js";
import "./onboard-helpers-DePmX0qT.js";
import "./prompt-style-Bi8LEJM5.js";
import "./pairing-labels-DL4tko6o.js";
import "./memory-cli-BEJgeUeO.js";
import "./manager-C7W4Rpg2.js";
import { t as formatDocsLink } from "./links-C87Xouo6.js";
import "./cli-utils-DWSfnwCw.js";
import "./help-format-Cwn7EEhh.js";
import "./progress-DiO7soys.js";
import { n as setPluginEnabledInConfig, t as enablePluginInConfig } from "./enable-CtGKeVAp.js";
import { u as resolveArchiveKind } from "./install-safe-path-BgP-Lt6B.js";
import "./npm-pack-install-DhQLXOOC.js";
import "./skill-scanner-Bb6LWuTZ.js";
import { a as installPluginFromPath, i as installPluginFromNpmSpec, n as recordPluginInstall, o as resolvePluginInstallDir, r as PLUGIN_INSTALL_ERROR_CODE } from "./installs-_DVKes3h.js";
import { t as renderTable } from "./table-1Y5hIMzl.js";
import { i as buildPluginStatusReport, n as resolvePinnedNpmInstallRecordForCli, r as looksLikeLocalInstallSpec } from "./npm-resolution-cMWOxvbf.js";
import { n as updateNpmInstalledPlugins, r as findBundledPluginSource } from "./update-BiZNaMTb.js";
import os from "node:os";
import path from "node:path";
import fs from "node:fs";
import fs$1 from "node:fs/promises";

//#region src/plugins/source-display.ts
function tryRelative(root, filePath) {
	const rel = path.relative(root, filePath);
	if (!rel || rel === ".") return null;
	if (rel === "..") return null;
	if (rel.startsWith(`..${path.sep}`) || rel.startsWith("../") || rel.startsWith("..\\")) return null;
	if (path.isAbsolute(rel)) return null;
	return rel.replaceAll("\\", "/");
}
function resolvePluginSourceRoots(params) {
	return {
		stock: resolveBundledPluginsDir(),
		global: path.join(resolveConfigDir(), "extensions"),
		workspace: params.workspaceDir ? path.join(params.workspaceDir, ".gensparx", "extensions") : void 0
	};
}
function formatPluginSourceForTable(plugin, roots) {
	const raw = plugin.source;
	if (plugin.origin === "bundled" && roots.stock) {
		const rel = tryRelative(roots.stock, raw);
		if (rel) return {
			value: `stock:${rel}`,
			rootKey: "stock"
		};
	}
	if (plugin.origin === "workspace" && roots.workspace) {
		const rel = tryRelative(roots.workspace, raw);
		if (rel) return {
			value: `workspace:${rel}`,
			rootKey: "workspace"
		};
	}
	if (plugin.origin === "global" && roots.global) {
		const rel = tryRelative(roots.global, raw);
		if (rel) return {
			value: `global:${rel}`,
			rootKey: "global"
		};
	}
	return { value: shortenHomeInString(raw) };
}

//#endregion
//#region src/plugins/uninstall.ts
function resolveUninstallDirectoryTarget(params) {
	if (!params.hasInstall) return null;
	if (params.installRecord?.source === "path") return null;
	let defaultPath;
	try {
		defaultPath = resolvePluginInstallDir(params.pluginId, params.extensionsDir);
	} catch {
		return null;
	}
	const configuredPath = params.installRecord?.installPath;
	if (!configuredPath) return defaultPath;
	if (path.resolve(configuredPath) === path.resolve(defaultPath)) return configuredPath;
	return defaultPath;
}
/**
* Remove plugin references from config (pure config mutation).
* Returns a new config with the plugin removed from entries, installs, allow, load.paths, and slots.
*/
function removePluginFromConfig(cfg, pluginId) {
	const actions = {
		entry: false,
		install: false,
		allowlist: false,
		loadPath: false,
		memorySlot: false
	};
	const pluginsConfig = cfg.plugins ?? {};
	let entries = pluginsConfig.entries;
	if (entries && pluginId in entries) {
		const { [pluginId]: _, ...rest } = entries;
		entries = Object.keys(rest).length > 0 ? rest : void 0;
		actions.entry = true;
	}
	let installs = pluginsConfig.installs;
	const installRecord = installs?.[pluginId];
	if (installs && pluginId in installs) {
		const { [pluginId]: _, ...rest } = installs;
		installs = Object.keys(rest).length > 0 ? rest : void 0;
		actions.install = true;
	}
	let allow = pluginsConfig.allow;
	if (Array.isArray(allow) && allow.includes(pluginId)) {
		allow = allow.filter((id) => id !== pluginId);
		if (allow.length === 0) allow = void 0;
		actions.allowlist = true;
	}
	let load = pluginsConfig.load;
	if (installRecord?.source === "path" && installRecord.sourcePath) {
		const sourcePath = installRecord.sourcePath;
		const loadPaths = load?.paths;
		if (Array.isArray(loadPaths) && loadPaths.includes(sourcePath)) {
			const nextLoadPaths = loadPaths.filter((p) => p !== sourcePath);
			load = nextLoadPaths.length > 0 ? {
				...load,
				paths: nextLoadPaths
			} : void 0;
			actions.loadPath = true;
		}
	}
	let slots = pluginsConfig.slots;
	if (slots?.memory === pluginId) {
		slots = {
			...slots,
			memory: defaultSlotIdForKey("memory")
		};
		actions.memorySlot = true;
	}
	if (slots && Object.keys(slots).length === 0) slots = void 0;
	const cleanedPlugins = {
		...pluginsConfig,
		entries,
		installs,
		allow,
		load,
		slots
	};
	if (cleanedPlugins.entries === void 0) delete cleanedPlugins.entries;
	if (cleanedPlugins.installs === void 0) delete cleanedPlugins.installs;
	if (cleanedPlugins.allow === void 0) delete cleanedPlugins.allow;
	if (cleanedPlugins.load === void 0) delete cleanedPlugins.load;
	if (cleanedPlugins.slots === void 0) delete cleanedPlugins.slots;
	return {
		config: {
			...cfg,
			plugins: Object.keys(cleanedPlugins).length > 0 ? cleanedPlugins : void 0
		},
		actions
	};
}
/**
* Uninstall a plugin by removing it from config and optionally deleting installed files.
* Linked plugins (source === "path") never have their source directory deleted.
*/
async function uninstallPlugin(params) {
	const { config, pluginId, deleteFiles = true, extensionsDir } = params;
	const hasEntry = pluginId in (config.plugins?.entries ?? {});
	const hasInstall = pluginId in (config.plugins?.installs ?? {});
	if (!hasEntry && !hasInstall) return {
		ok: false,
		error: `Plugin not found: ${pluginId}`
	};
	const installRecord = config.plugins?.installs?.[pluginId];
	const isLinked = installRecord?.source === "path";
	const { config: newConfig, actions: configActions } = removePluginFromConfig(config, pluginId);
	const actions = {
		...configActions,
		directory: false
	};
	const warnings = [];
	const deleteTarget = deleteFiles && !isLinked ? resolveUninstallDirectoryTarget({
		pluginId,
		hasInstall,
		installRecord,
		extensionsDir
	}) : null;
	if (deleteTarget) {
		const existed = await fs$1.access(deleteTarget).then(() => true).catch(() => false) ?? false;
		try {
			await fs$1.rm(deleteTarget, {
				recursive: true,
				force: true
			});
			actions.directory = existed;
		} catch (error) {
			warnings.push(`Failed to remove plugin directory ${deleteTarget}: ${error instanceof Error ? error.message : String(error)}`);
		}
	}
	return {
		ok: true,
		config: newConfig,
		pluginId,
		actions,
		warnings
	};
}

//#endregion
//#region src/cli/plugin-install-plan.ts
function isBareNpmPackageName(spec) {
	const trimmed = spec.trim();
	return /^[a-z0-9][a-z0-9-._~]*$/.test(trimmed);
}
function resolveBundledInstallPlanBeforeNpm(params) {
	if (!isBareNpmPackageName(params.rawSpec)) return null;
	const bundledSource = params.findBundledSource({
		kind: "pluginId",
		value: params.rawSpec
	});
	if (!bundledSource) return null;
	return {
		bundledSource,
		warning: `Using bundled plugin "${bundledSource.pluginId}" from ${shortenHomePath(bundledSource.localPath)} for bare install spec "${params.rawSpec}". To install an npm package with the same name, use a scoped package name (for example @scope/${params.rawSpec}).`
	};
}
function resolveBundledInstallPlanForNpmFailure(params) {
	if (params.code !== PLUGIN_INSTALL_ERROR_CODE.NPM_PACKAGE_NOT_FOUND) return null;
	const bundledSource = params.findBundledSource({
		kind: "npmSpec",
		value: params.rawSpec
	});
	if (!bundledSource) return null;
	return {
		bundledSource,
		warning: `npm package unavailable for ${params.rawSpec}; using bundled plugin at ${shortenHomePath(bundledSource.localPath)}.`
	};
}

//#endregion
//#region src/cli/plugins-cli.ts
function resolveFileNpmSpecToLocalPath(raw) {
	const trimmed = raw.trim();
	if (!trimmed.toLowerCase().startsWith("file:")) return null;
	const rest = trimmed.slice(5);
	if (!rest) return {
		ok: false,
		error: "unsupported file: spec: missing path"
	};
	if (rest.startsWith("///")) return {
		ok: true,
		path: rest.slice(2)
	};
	if (rest.startsWith("//localhost/")) return {
		ok: true,
		path: rest.slice(11)
	};
	if (rest.startsWith("//")) return {
		ok: false,
		error: "unsupported file: URL host (expected \"file:<path>\" or \"file:///abs/path\")"
	};
	return {
		ok: true,
		path: rest
	};
}
function formatPluginLine(plugin, verbose = false) {
	const status = plugin.status === "loaded" ? theme.success("loaded") : plugin.status === "disabled" ? theme.warn("disabled") : theme.error("error");
	const name = theme.command(plugin.name || plugin.id);
	const idSuffix = plugin.name && plugin.name !== plugin.id ? theme.muted(` (${plugin.id})`) : "";
	const desc = plugin.description ? theme.muted(plugin.description.length > 60 ? `${plugin.description.slice(0, 57)}...` : plugin.description) : theme.muted("(no description)");
	if (!verbose) return `${name}${idSuffix} ${status} - ${desc}`;
	const parts = [
		`${name}${idSuffix} ${status}`,
		`  source: ${theme.muted(shortenHomeInString(plugin.source))}`,
		`  origin: ${plugin.origin}`
	];
	if (plugin.version) parts.push(`  version: ${plugin.version}`);
	if (plugin.providerIds.length > 0) parts.push(`  providers: ${plugin.providerIds.join(", ")}`);
	if (plugin.error) parts.push(theme.error(`  error: ${plugin.error}`));
	return parts.join("\n");
}
function applySlotSelectionForPlugin(config, pluginId) {
	const report = buildPluginStatusReport({ config });
	const plugin = report.plugins.find((entry) => entry.id === pluginId);
	if (!plugin) return {
		config,
		warnings: []
	};
	const result = applyExclusiveSlotSelection({
		config,
		selectedId: plugin.id,
		selectedKind: plugin.kind,
		registry: report
	});
	return {
		config: result.config,
		warnings: result.warnings
	};
}
function createPluginInstallLogger() {
	return {
		info: (msg) => defaultRuntime.log(msg),
		warn: (msg) => defaultRuntime.log(theme.warn(msg))
	};
}
function logSlotWarnings(warnings) {
	if (warnings.length === 0) return;
	for (const warning of warnings) defaultRuntime.log(theme.warn(warning));
}
async function installBundledPluginSource(params) {
	const existing = params.config.plugins?.load?.paths ?? [];
	const mergedPaths = Array.from(new Set([...existing, params.bundledSource.localPath]));
	let next = {
		...params.config,
		plugins: {
			...params.config.plugins,
			load: {
				...params.config.plugins?.load,
				paths: mergedPaths
			},
			entries: {
				...params.config.plugins?.entries,
				[params.bundledSource.pluginId]: {
					...params.config.plugins?.entries?.[params.bundledSource.pluginId],
					enabled: true
				}
			}
		}
	};
	next = recordPluginInstall(next, {
		pluginId: params.bundledSource.pluginId,
		source: "path",
		spec: params.rawSpec,
		sourcePath: params.bundledSource.localPath,
		installPath: params.bundledSource.localPath
	});
	const slotResult = applySlotSelectionForPlugin(next, params.bundledSource.pluginId);
	next = slotResult.config;
	await writeConfigFile(next);
	logSlotWarnings(slotResult.warnings);
	defaultRuntime.log(theme.warn(params.warning));
	defaultRuntime.log(`Installed plugin: ${params.bundledSource.pluginId}`);
	defaultRuntime.log(`Restart the gateway to load plugins.`);
}
async function runPluginInstallCommand(params) {
	const { raw, opts } = params;
	const fileSpec = resolveFileNpmSpecToLocalPath(raw);
	if (fileSpec && !fileSpec.ok) {
		defaultRuntime.error(fileSpec.error);
		process.exit(1);
	}
	const resolved = resolveUserPath(fileSpec && fileSpec.ok ? fileSpec.path : raw);
	const cfg = loadConfig();
	if (fs.existsSync(resolved)) {
		if (opts.link) {
			const existing = cfg.plugins?.load?.paths ?? [];
			const merged = Array.from(new Set([...existing, resolved]));
			const probe = await installPluginFromPath({
				path: resolved,
				dryRun: true
			});
			if (!probe.ok) {
				defaultRuntime.error(probe.error);
				process.exit(1);
			}
			let next = enablePluginInConfig({
				...cfg,
				plugins: {
					...cfg.plugins,
					load: {
						...cfg.plugins?.load,
						paths: merged
					}
				}
			}, probe.pluginId).config;
			next = recordPluginInstall(next, {
				pluginId: probe.pluginId,
				source: "path",
				sourcePath: resolved,
				installPath: resolved,
				version: probe.version
			});
			const slotResult = applySlotSelectionForPlugin(next, probe.pluginId);
			next = slotResult.config;
			await writeConfigFile(next);
			logSlotWarnings(slotResult.warnings);
			defaultRuntime.log(`Linked plugin path: ${shortenHomePath(resolved)}`);
			defaultRuntime.log(`Restart the gateway to load plugins.`);
			return;
		}
		const result = await installPluginFromPath({
			path: resolved,
			logger: createPluginInstallLogger()
		});
		if (!result.ok) {
			defaultRuntime.error(result.error);
			process.exit(1);
		}
		clearPluginManifestRegistryCache();
		let next = enablePluginInConfig(cfg, result.pluginId).config;
		const source = resolveArchiveKind(resolved) ? "archive" : "path";
		next = recordPluginInstall(next, {
			pluginId: result.pluginId,
			source,
			sourcePath: resolved,
			installPath: result.targetDir,
			version: result.version
		});
		const slotResult = applySlotSelectionForPlugin(next, result.pluginId);
		next = slotResult.config;
		await writeConfigFile(next);
		logSlotWarnings(slotResult.warnings);
		defaultRuntime.log(`Installed plugin: ${result.pluginId}`);
		defaultRuntime.log(`Restart the gateway to load plugins.`);
		return;
	}
	if (opts.link) {
		defaultRuntime.error("`--link` requires a local path.");
		process.exit(1);
	}
	if (looksLikeLocalInstallSpec(raw, [
		".ts",
		".js",
		".mjs",
		".cjs",
		".tgz",
		".tar.gz",
		".tar",
		".zip"
	])) {
		defaultRuntime.error(`Path not found: ${resolved}`);
		process.exit(1);
	}
	const bundledPreNpmPlan = resolveBundledInstallPlanBeforeNpm({
		rawSpec: raw,
		findBundledSource: (lookup) => findBundledPluginSource({ lookup })
	});
	if (bundledPreNpmPlan) {
		await installBundledPluginSource({
			config: cfg,
			rawSpec: raw,
			bundledSource: bundledPreNpmPlan.bundledSource,
			warning: bundledPreNpmPlan.warning
		});
		return;
	}
	const result = await installPluginFromNpmSpec({
		spec: raw,
		logger: createPluginInstallLogger()
	});
	if (!result.ok) {
		const bundledFallbackPlan = resolveBundledInstallPlanForNpmFailure({
			rawSpec: raw,
			code: result.code,
			findBundledSource: (lookup) => findBundledPluginSource({ lookup })
		});
		if (!bundledFallbackPlan) {
			defaultRuntime.error(result.error);
			process.exit(1);
		}
		await installBundledPluginSource({
			config: cfg,
			rawSpec: raw,
			bundledSource: bundledFallbackPlan.bundledSource,
			warning: bundledFallbackPlan.warning
		});
		return;
	}
	clearPluginManifestRegistryCache();
	let next = enablePluginInConfig(cfg, result.pluginId).config;
	const installRecord = resolvePinnedNpmInstallRecordForCli(raw, Boolean(opts.pin), result.targetDir, result.version, result.npmResolution, defaultRuntime.log, theme.warn);
	next = recordPluginInstall(next, {
		pluginId: result.pluginId,
		...installRecord
	});
	const slotResult = applySlotSelectionForPlugin(next, result.pluginId);
	next = slotResult.config;
	await writeConfigFile(next);
	logSlotWarnings(slotResult.warnings);
	defaultRuntime.log(`Installed plugin: ${result.pluginId}`);
	defaultRuntime.log(`Restart the gateway to load plugins.`);
}
function registerPluginsCli(program) {
	const plugins = program.command("plugins").description("Manage gensparx plugins and extensions").addHelpText("after", () => `\n${theme.muted("Docs:")} ${formatDocsLink("/cli/plugins", "docs.gensparx.com/cli/plugins")}\n`);
	plugins.command("list").description("List discovered plugins").option("--json", "Print JSON").option("--enabled", "Only show enabled plugins", false).option("--verbose", "Show detailed entries", false).action((opts) => {
		const report = buildPluginStatusReport();
		const list = opts.enabled ? report.plugins.filter((p) => p.status === "loaded") : report.plugins;
		if (opts.json) {
			const payload = {
				workspaceDir: report.workspaceDir,
				plugins: list,
				diagnostics: report.diagnostics
			};
			defaultRuntime.log(JSON.stringify(payload, null, 2));
			return;
		}
		if (list.length === 0) {
			defaultRuntime.log(theme.muted("No plugins found."));
			return;
		}
		const loaded = list.filter((p) => p.status === "loaded").length;
		defaultRuntime.log(`${theme.heading("Plugins")} ${theme.muted(`(${loaded}/${list.length} loaded)`)}`);
		if (!opts.verbose) {
			const tableWidth = Math.max(60, (process.stdout.columns ?? 120) - 1);
			const sourceRoots = resolvePluginSourceRoots({ workspaceDir: report.workspaceDir });
			const usedRoots = /* @__PURE__ */ new Set();
			const rows = list.map((plugin) => {
				const desc = plugin.description ? theme.muted(plugin.description) : "";
				const formattedSource = formatPluginSourceForTable(plugin, sourceRoots);
				if (formattedSource.rootKey) usedRoots.add(formattedSource.rootKey);
				const sourceLine = desc ? `${formattedSource.value}\n${desc}` : formattedSource.value;
				return {
					Name: plugin.name || plugin.id,
					ID: plugin.name && plugin.name !== plugin.id ? plugin.id : "",
					Status: plugin.status === "loaded" ? theme.success("loaded") : plugin.status === "disabled" ? theme.warn("disabled") : theme.error("error"),
					Source: sourceLine,
					Version: plugin.version ?? ""
				};
			});
			if (usedRoots.size > 0) {
				defaultRuntime.log(theme.muted("Source roots:"));
				for (const key of [
					"stock",
					"workspace",
					"global"
				]) {
					if (!usedRoots.has(key)) continue;
					const dir = sourceRoots[key];
					if (!dir) continue;
					defaultRuntime.log(`  ${theme.command(`${key}:`)} ${theme.muted(dir)}`);
				}
				defaultRuntime.log("");
			}
			defaultRuntime.log(renderTable({
				width: tableWidth,
				columns: [
					{
						key: "Name",
						header: "Name",
						minWidth: 14,
						flex: true
					},
					{
						key: "ID",
						header: "ID",
						minWidth: 10,
						flex: true
					},
					{
						key: "Status",
						header: "Status",
						minWidth: 10
					},
					{
						key: "Source",
						header: "Source",
						minWidth: 26,
						flex: true
					},
					{
						key: "Version",
						header: "Version",
						minWidth: 8
					}
				],
				rows
			}).trimEnd());
			return;
		}
		const lines = [];
		for (const plugin of list) {
			lines.push(formatPluginLine(plugin, true));
			lines.push("");
		}
		defaultRuntime.log(lines.join("\n").trim());
	});
	plugins.command("info").description("Show plugin details").argument("<id>", "Plugin id").option("--json", "Print JSON").action((id, opts) => {
		const plugin = buildPluginStatusReport().plugins.find((p) => p.id === id || p.name === id);
		if (!plugin) {
			defaultRuntime.error(`Plugin not found: ${id}`);
			process.exit(1);
		}
		const install = loadConfig().plugins?.installs?.[plugin.id];
		if (opts.json) {
			defaultRuntime.log(JSON.stringify(plugin, null, 2));
			return;
		}
		const lines = [];
		lines.push(theme.heading(plugin.name || plugin.id));
		if (plugin.name && plugin.name !== plugin.id) lines.push(theme.muted(`id: ${plugin.id}`));
		if (plugin.description) lines.push(plugin.description);
		lines.push("");
		lines.push(`${theme.muted("Status:")} ${plugin.status}`);
		lines.push(`${theme.muted("Source:")} ${shortenHomeInString(plugin.source)}`);
		lines.push(`${theme.muted("Origin:")} ${plugin.origin}`);
		if (plugin.version) lines.push(`${theme.muted("Version:")} ${plugin.version}`);
		if (plugin.toolNames.length > 0) lines.push(`${theme.muted("Tools:")} ${plugin.toolNames.join(", ")}`);
		if (plugin.hookNames.length > 0) lines.push(`${theme.muted("Hooks:")} ${plugin.hookNames.join(", ")}`);
		if (plugin.gatewayMethods.length > 0) lines.push(`${theme.muted("Gateway methods:")} ${plugin.gatewayMethods.join(", ")}`);
		if (plugin.providerIds.length > 0) lines.push(`${theme.muted("Providers:")} ${plugin.providerIds.join(", ")}`);
		if (plugin.cliCommands.length > 0) lines.push(`${theme.muted("CLI commands:")} ${plugin.cliCommands.join(", ")}`);
		if (plugin.services.length > 0) lines.push(`${theme.muted("Services:")} ${plugin.services.join(", ")}`);
		if (plugin.error) lines.push(`${theme.error("Error:")} ${plugin.error}`);
		if (install) {
			lines.push("");
			lines.push(`${theme.muted("Install:")} ${install.source}`);
			if (install.spec) lines.push(`${theme.muted("Spec:")} ${install.spec}`);
			if (install.sourcePath) lines.push(`${theme.muted("Source path:")} ${shortenHomePath(install.sourcePath)}`);
			if (install.installPath) lines.push(`${theme.muted("Install path:")} ${shortenHomePath(install.installPath)}`);
			if (install.version) lines.push(`${theme.muted("Recorded version:")} ${install.version}`);
			if (install.installedAt) lines.push(`${theme.muted("Installed at:")} ${install.installedAt}`);
		}
		defaultRuntime.log(lines.join("\n"));
	});
	plugins.command("enable").description("Enable a plugin in config").argument("<id>", "Plugin id").action(async (id) => {
		const enableResult = enablePluginInConfig(loadConfig(), id);
		let next = enableResult.config;
		const slotResult = applySlotSelectionForPlugin(next, id);
		next = slotResult.config;
		await writeConfigFile(next);
		logSlotWarnings(slotResult.warnings);
		if (enableResult.enabled) {
			defaultRuntime.log(`Enabled plugin "${id}". Restart the gateway to apply.`);
			return;
		}
		defaultRuntime.log(theme.warn(`Plugin "${id}" could not be enabled (${enableResult.reason ?? "unknown reason"}).`));
	});
	plugins.command("disable").description("Disable a plugin in config").argument("<id>", "Plugin id").action(async (id) => {
		await writeConfigFile(setPluginEnabledInConfig(loadConfig(), id, false));
		defaultRuntime.log(`Disabled plugin "${id}". Restart the gateway to apply.`);
	});
	plugins.command("uninstall").description("Uninstall a plugin").argument("<id>", "Plugin id").option("--keep-files", "Keep installed files on disk", false).option("--keep-config", "Deprecated alias for --keep-files", false).option("--force", "Skip confirmation prompt", false).option("--dry-run", "Show what would be removed without making changes", false).action(async (id, opts) => {
		const cfg = loadConfig();
		const report = buildPluginStatusReport({ config: cfg });
		const extensionsDir = path.join(resolveStateDir(process.env, os.homedir), "extensions");
		const keepFiles = Boolean(opts.keepFiles || opts.keepConfig);
		if (opts.keepConfig) defaultRuntime.log(theme.warn("`--keep-config` is deprecated, use `--keep-files`."));
		const plugin = report.plugins.find((p) => p.id === id || p.name === id);
		const pluginId = plugin?.id ?? id;
		const hasEntry = pluginId in (cfg.plugins?.entries ?? {});
		const hasInstall = pluginId in (cfg.plugins?.installs ?? {});
		if (!hasEntry && !hasInstall) {
			if (plugin) defaultRuntime.error(`Plugin "${pluginId}" is not managed by plugins config/install records and cannot be uninstalled.`);
			else defaultRuntime.error(`Plugin not found: ${id}`);
			process.exit(1);
		}
		const install = cfg.plugins?.installs?.[pluginId];
		const isLinked = install?.source === "path";
		const preview = [];
		if (hasEntry) preview.push("config entry");
		if (hasInstall) preview.push("install record");
		if (cfg.plugins?.allow?.includes(pluginId)) preview.push("allowlist entry");
		if (isLinked && install?.sourcePath && cfg.plugins?.load?.paths?.includes(install.sourcePath)) preview.push("load path");
		if (cfg.plugins?.slots?.memory === pluginId) preview.push(`memory slot (will reset to "memory-core")`);
		const deleteTarget = !keepFiles ? resolveUninstallDirectoryTarget({
			pluginId,
			hasInstall,
			installRecord: install,
			extensionsDir
		}) : null;
		if (deleteTarget) preview.push(`directory: ${shortenHomePath(deleteTarget)}`);
		const pluginName = plugin?.name || pluginId;
		defaultRuntime.log(`Plugin: ${theme.command(pluginName)}${pluginName !== pluginId ? theme.muted(` (${pluginId})`) : ""}`);
		defaultRuntime.log(`Will remove: ${preview.length > 0 ? preview.join(", ") : "(nothing)"}`);
		if (opts.dryRun) {
			defaultRuntime.log(theme.muted("Dry run, no changes made."));
			return;
		}
		if (!opts.force) {
			if (!await promptYesNo(`Uninstall plugin "${pluginId}"?`)) {
				defaultRuntime.log("Cancelled.");
				return;
			}
		}
		const result = await uninstallPlugin({
			config: cfg,
			pluginId,
			deleteFiles: !keepFiles,
			extensionsDir
		});
		if (!result.ok) {
			defaultRuntime.error(result.error);
			process.exit(1);
		}
		for (const warning of result.warnings) defaultRuntime.log(theme.warn(warning));
		await writeConfigFile(result.config);
		const removed = [];
		if (result.actions.entry) removed.push("config entry");
		if (result.actions.install) removed.push("install record");
		if (result.actions.allowlist) removed.push("allowlist");
		if (result.actions.loadPath) removed.push("load path");
		if (result.actions.memorySlot) removed.push("memory slot");
		if (result.actions.directory) removed.push("directory");
		defaultRuntime.log(`Uninstalled plugin "${pluginId}". Removed: ${removed.length > 0 ? removed.join(", ") : "nothing"}.`);
		defaultRuntime.log("Restart the gateway to apply changes.");
	});
	plugins.command("install").description("Install a plugin (path, archive, or npm spec)").argument("<path-or-spec>", "Path (.ts/.js/.zip/.tgz/.tar.gz) or an npm package spec").option("-l, --link", "Link a local path instead of copying", false).option("--pin", "Record npm installs as exact resolved <name>@<version>", false).action(async (raw, opts) => {
		await runPluginInstallCommand({
			raw,
			opts
		});
	});
	plugins.command("update").description("Update installed plugins (npm installs only)").argument("[id]", "Plugin id (omit with --all)").option("--all", "Update all tracked plugins", false).option("--dry-run", "Show what would change without writing", false).action(async (id, opts) => {
		const cfg = loadConfig();
		const installs = cfg.plugins?.installs ?? {};
		const targets = opts.all ? Object.keys(installs) : id ? [id] : [];
		if (targets.length === 0) {
			if (opts.all) {
				defaultRuntime.log("No npm-installed plugins to update.");
				return;
			}
			defaultRuntime.error("Provide a plugin id or use --all.");
			process.exit(1);
		}
		const result = await updateNpmInstalledPlugins({
			config: cfg,
			pluginIds: targets,
			dryRun: opts.dryRun,
			logger: {
				info: (msg) => defaultRuntime.log(msg),
				warn: (msg) => defaultRuntime.log(theme.warn(msg))
			},
			onIntegrityDrift: async (drift) => {
				const specLabel = drift.resolvedSpec ?? drift.spec;
				defaultRuntime.log(theme.warn(`Integrity drift detected for "${drift.pluginId}" (${specLabel})\nExpected: ${drift.expectedIntegrity}\nActual:   ${drift.actualIntegrity}`));
				if (drift.dryRun) return true;
				return await promptYesNo(`Continue updating "${drift.pluginId}" with this artifact?`);
			}
		});
		for (const outcome of result.outcomes) {
			if (outcome.status === "error") {
				defaultRuntime.log(theme.error(outcome.message));
				continue;
			}
			if (outcome.status === "skipped") {
				defaultRuntime.log(theme.warn(outcome.message));
				continue;
			}
			defaultRuntime.log(outcome.message);
		}
		if (!opts.dryRun && result.changed) {
			await writeConfigFile(result.config);
			defaultRuntime.log("Restart the gateway to load plugins.");
		}
	});
	plugins.command("doctor").description("Report plugin load issues").action(() => {
		const report = buildPluginStatusReport();
		const errors = report.plugins.filter((p) => p.status === "error");
		const diags = report.diagnostics.filter((d) => d.level === "error");
		if (errors.length === 0 && diags.length === 0) {
			defaultRuntime.log("No plugin issues detected.");
			return;
		}
		const lines = [];
		if (errors.length > 0) {
			lines.push(theme.error("Plugin errors:"));
			for (const entry of errors) lines.push(`- ${entry.id}: ${entry.error ?? "failed to load"} (${entry.source})`);
		}
		if (diags.length > 0) {
			if (lines.length > 0) lines.push("");
			lines.push(theme.warn("Diagnostics:"));
			for (const diag of diags) {
				const target = diag.pluginId ? `${diag.pluginId}: ` : "";
				lines.push(`- ${target}${diag.message}`);
			}
		}
		const docs = formatDocsLink("/plugin", "docs.gensparx.com/plugin");
		lines.push("");
		lines.push(`${theme.muted("Docs:")} ${docs}`);
		defaultRuntime.log(lines.join("\n"));
	});
}

//#endregion
export { registerPluginsCli };