import { t as __exportAll } from "./rolldown-runtime-Cbj13DAv.js";
import { A as isRich, E as setVerbose, j as theme, k as colorize } from "./registry-Sbac4a4z.js";
import { _ as resolveStateDir } from "./paths-By0XjHBk.js";
import { _ as shortenHomeInString, v as shortenHomePath } from "./utils-CTPsqyE_.js";
import { f as defaultRuntime } from "./subsystem-CHbO_DkH.js";
import { l as resolveDefaultAgentId } from "./agent-scope-DOrZjOnW.js";
import { i as loadConfig, l as writeConfigFile, o as readConfigFileSnapshot } from "./config-B4jkreCN.js";
import { n as formatErrorMessage } from "./errors-bI7Tdx75.js";
import { s as resolveSessionTranscriptsDirForAgent } from "./paths-BtvQ7JvU.js";
import { i as resolveApiKeyForProvider } from "./model-auth-1EAQvYRv.js";
import { t as getMemorySearchManager } from "./memory-BZ24UkLW.js";
import { i as resolveOllamaBaseUrl, r as probeOllamaEmbeddingModels } from "./manager-Cw7IJGbB.js";
import { c as normalizeExtraMemoryPaths, s as listMemoryFiles } from "./internal-DVCddhhN.js";
import { t as formatDocsLink } from "./links-Bqr0FxXx.js";
import { r as withManager } from "./cli-utils-CuyGL3rq.js";
import { t as formatHelpExamples } from "./help-format-7hFcsqss.js";
import { n as withProgress, r as withProgressTotals } from "./progress-swt2y17x.js";
import path from "node:path";
import fs from "node:fs";
import os from "node:os";
import fs$1 from "node:fs/promises";

//#region src/cli/memory-cli.ts
var memory_cli_exports = /* @__PURE__ */ __exportAll({
	registerMemoryCli: () => registerMemoryCli,
	runMemoryStatus: () => runMemoryStatus
});
function formatSourceLabel(source, workspaceDir, agentId) {
	if (source === "memory") return shortenHomeInString(`memory (MEMORY.md + ${path.join(workspaceDir, "memory")}${path.sep}*.md)`);
	if (source === "sessions") {
		const stateDir = resolveStateDir(process.env, os.homedir);
		return shortenHomeInString(`sessions (${path.join(stateDir, "agents", agentId, "sessions")}${path.sep}*.jsonl)`);
	}
	return source;
}
function resolveAgent(cfg, agent) {
	const trimmed = agent?.trim();
	if (trimmed) return trimmed;
	return resolveDefaultAgentId(cfg);
}
function resolveAgentIds(cfg, agent) {
	const trimmed = agent?.trim();
	if (trimmed) return [trimmed];
	const list = cfg.agents?.list ?? [];
	if (list.length > 0) return list.map((entry) => entry.id).filter(Boolean);
	return [resolveDefaultAgentId(cfg)];
}
function formatExtraPaths(workspaceDir, extraPaths) {
	return normalizeExtraMemoryPaths(workspaceDir, extraPaths).map((entry) => shortenHomePath(entry));
}
async function withMemoryManagerForAgent(params) {
	const managerParams = {
		cfg: params.cfg,
		agentId: params.agentId
	};
	if (params.purpose) managerParams.purpose = params.purpose;
	await withManager({
		getManager: () => getMemorySearchManager(managerParams),
		onMissing: (error) => defaultRuntime.log(error ?? "Memory search disabled."),
		onCloseError: (err) => defaultRuntime.error(`Memory manager close failed: ${formatErrorMessage(err)}`),
		close: async (manager) => {
			await manager.close?.();
		},
		run: params.run
	});
}
async function checkReadableFile(pathname) {
	try {
		await fs$1.access(pathname, fs.constants.R_OK);
		return { exists: true };
	} catch (err) {
		const code = err.code;
		if (code === "ENOENT") return { exists: false };
		return {
			exists: true,
			issue: `${shortenHomePath(pathname)} not readable (${code ?? "error"})`
		};
	}
}
async function scanSessionFiles(agentId) {
	const issues = [];
	const sessionsDir = resolveSessionTranscriptsDirForAgent(agentId);
	try {
		return {
			source: "sessions",
			totalFiles: (await fs$1.readdir(sessionsDir, { withFileTypes: true })).filter((entry) => entry.isFile() && entry.name.endsWith(".jsonl")).length,
			issues
		};
	} catch (err) {
		const code = err.code;
		if (code === "ENOENT") {
			issues.push(`sessions directory missing (${shortenHomePath(sessionsDir)})`);
			return {
				source: "sessions",
				totalFiles: 0,
				issues
			};
		}
		issues.push(`sessions directory not accessible (${shortenHomePath(sessionsDir)}): ${code ?? "error"}`);
		return {
			source: "sessions",
			totalFiles: null,
			issues
		};
	}
}
async function scanMemoryFiles(workspaceDir, extraPaths = []) {
	const issues = [];
	const memoryFile = path.join(workspaceDir, "MEMORY.md");
	const altMemoryFile = path.join(workspaceDir, "memory.md");
	const memoryDir = path.join(workspaceDir, "memory");
	const primary = await checkReadableFile(memoryFile);
	const alt = await checkReadableFile(altMemoryFile);
	if (primary.issue) issues.push(primary.issue);
	if (alt.issue) issues.push(alt.issue);
	const resolvedExtraPaths = normalizeExtraMemoryPaths(workspaceDir, extraPaths);
	for (const extraPath of resolvedExtraPaths) try {
		if ((await fs$1.lstat(extraPath)).isSymbolicLink()) continue;
		const extraCheck = await checkReadableFile(extraPath);
		if (extraCheck.issue) issues.push(extraCheck.issue);
	} catch (err) {
		const code = err.code;
		if (code === "ENOENT") issues.push(`additional memory path missing (${shortenHomePath(extraPath)})`);
		else issues.push(`additional memory path not accessible (${shortenHomePath(extraPath)}): ${code ?? "error"}`);
	}
	let dirReadable = null;
	try {
		await fs$1.access(memoryDir, fs.constants.R_OK);
		dirReadable = true;
	} catch (err) {
		const code = err.code;
		if (code === "ENOENT") {
			issues.push(`memory directory missing (${shortenHomePath(memoryDir)})`);
			dirReadable = false;
		} else {
			issues.push(`memory directory not accessible (${shortenHomePath(memoryDir)}): ${code ?? "error"}`);
			dirReadable = null;
		}
	}
	let listed = [];
	let listedOk = false;
	try {
		listed = await listMemoryFiles(workspaceDir, resolvedExtraPaths);
		listedOk = true;
	} catch (err) {
		const code = err.code;
		if (dirReadable !== null) {
			issues.push(`memory directory scan failed (${shortenHomePath(memoryDir)}): ${code ?? "error"}`);
			dirReadable = null;
		}
	}
	let totalFiles = 0;
	if (dirReadable === null) totalFiles = null;
	else {
		const files = new Set(listedOk ? listed : []);
		if (!listedOk) {
			if (primary.exists) files.add(memoryFile);
			if (alt.exists) files.add(altMemoryFile);
		}
		totalFiles = files.size;
	}
	if ((totalFiles ?? 0) === 0 && issues.length === 0) issues.push(`no memory files found in ${shortenHomePath(workspaceDir)}`);
	return {
		source: "memory",
		totalFiles,
		issues
	};
}
async function summarizeQmdIndexArtifact(manager) {
	const status = manager.status?.();
	if (!status || status.backend !== "qmd") return null;
	const dbPath = status.dbPath?.trim();
	if (!dbPath) return null;
	let stat;
	try {
		stat = await fs$1.stat(dbPath);
	} catch (err) {
		const code = err.code;
		if (code === "ENOENT") throw new Error(`QMD index file not found: ${shortenHomePath(dbPath)}`, { cause: err });
		throw new Error(`QMD index file check failed: ${shortenHomePath(dbPath)} (${code ?? "error"})`, { cause: err });
	}
	if (!stat.isFile() || stat.size <= 0) throw new Error(`QMD index file is empty: ${shortenHomePath(dbPath)}`);
	return `QMD index: ${shortenHomePath(dbPath)} (${stat.size} bytes)`;
}
async function scanMemorySources(params) {
	const scans = [];
	const extraPaths = params.extraPaths ?? [];
	for (const source of params.sources) {
		if (source === "memory") scans.push(await scanMemoryFiles(params.workspaceDir, extraPaths));
		if (source === "sessions") scans.push(await scanSessionFiles(params.agentId));
	}
	const issues = scans.flatMap((scan) => scan.issues);
	const totals = scans.map((scan) => scan.totalFiles);
	const numericTotals = totals.filter((total) => total !== null);
	return {
		sources: scans,
		totalFiles: totals.some((total) => total === null) ? null : numericTotals.reduce((sum, total) => sum + total, 0),
		issues
	};
}
async function runMemoryStatus(opts) {
	setVerbose(Boolean(opts.verbose));
	const cfg = loadConfig();
	const agentIds = resolveAgentIds(cfg, opts.agent);
	const allResults = [];
	for (const agentId of agentIds) await withMemoryManagerForAgent({
		cfg,
		agentId,
		purpose: opts.index ? "default" : "status",
		run: async (manager) => {
			const deep = Boolean(opts.deep || opts.index);
			let embeddingProbe;
			let indexError;
			const syncFn = manager.sync ? manager.sync.bind(manager) : void 0;
			if (deep) {
				await withProgress({
					label: "Checking memory…",
					total: 2
				}, async (progress) => {
					progress.setLabel("Probing vector…");
					await manager.probeVectorAvailability();
					progress.tick();
					progress.setLabel("Probing embeddings…");
					embeddingProbe = await manager.probeEmbeddingAvailability();
					progress.tick();
				});
				if (opts.index && syncFn) await withProgressTotals({
					label: "Indexing memory…",
					total: 0,
					fallback: opts.verbose ? "line" : void 0
				}, async (update, progress) => {
					try {
						await syncFn({
							reason: "cli",
							force: Boolean(opts.force),
							progress: (syncUpdate) => {
								update({
									completed: syncUpdate.completed,
									total: syncUpdate.total,
									label: syncUpdate.label
								});
								if (syncUpdate.label) progress.setLabel(syncUpdate.label);
							}
						});
					} catch (err) {
						indexError = formatErrorMessage(err);
						defaultRuntime.error(`Memory index failed: ${indexError}`);
						process.exitCode = 1;
					}
				});
				else if (opts.index && !syncFn) defaultRuntime.log("Memory backend does not support manual reindex.");
			} else await manager.probeVectorAvailability();
			const status = manager.status();
			const sources = status.sources?.length ? status.sources : ["memory"];
			const workspaceDir = status.workspaceDir;
			const scan = workspaceDir ? await scanMemorySources({
				workspaceDir,
				agentId,
				sources,
				extraPaths: status.extraPaths
			}) : void 0;
			allResults.push({
				agentId,
				status,
				embeddingProbe,
				indexError,
				scan
			});
		}
	});
	if (opts.json) {
		defaultRuntime.log(JSON.stringify(allResults, null, 2));
		return;
	}
	const rich = isRich();
	const heading = (text) => colorize(rich, theme.heading, text);
	const muted = (text) => colorize(rich, theme.muted, text);
	const info = (text) => colorize(rich, theme.info, text);
	const success = (text) => colorize(rich, theme.success, text);
	const warn = (text) => colorize(rich, theme.warn, text);
	const accent = (text) => colorize(rich, theme.accent, text);
	const label = (text) => muted(`${text}:`);
	for (const result of allResults) {
		const { agentId, status, embeddingProbe, indexError, scan } = result;
		const filesIndexed = status.files ?? 0;
		const chunksIndexed = status.chunks ?? 0;
		const totalFiles = scan?.totalFiles ?? null;
		const indexedLabel = totalFiles === null ? `${filesIndexed}/? files · ${chunksIndexed} chunks` : `${filesIndexed}/${totalFiles} files · ${chunksIndexed} chunks`;
		if (opts.index) {
			const line = indexError ? `Memory index failed: ${indexError}` : "Memory index complete.";
			defaultRuntime.log(line);
		}
		const requestedProvider = status.requestedProvider ?? status.provider;
		const modelLabel = status.model ?? status.provider;
		const storePath = status.dbPath ? shortenHomePath(status.dbPath) : "<unknown>";
		const workspacePath = status.workspaceDir ? shortenHomePath(status.workspaceDir) : "<unknown>";
		const sourceList = status.sources?.length ? status.sources.join(", ") : null;
		const extraPaths = status.workspaceDir ? formatExtraPaths(status.workspaceDir, status.extraPaths ?? []) : [];
		const lines = [
			`${heading("Memory Search")} ${muted(`(${agentId})`)}`,
			`${label("Provider")} ${info(status.provider)} ${muted(`(requested: ${requestedProvider})`)}`,
			`${label("Model")} ${info(modelLabel)}`,
			sourceList ? `${label("Sources")} ${info(sourceList)}` : null,
			extraPaths.length ? `${label("Extra paths")} ${info(extraPaths.join(", "))}` : null,
			`${label("Indexed")} ${success(indexedLabel)}`,
			`${label("Dirty")} ${status.dirty ? warn("yes") : muted("no")}`,
			`${label("Store")} ${info(storePath)}`,
			`${label("Workspace")} ${info(workspacePath)}`
		].filter(Boolean);
		if (embeddingProbe) {
			const state = embeddingProbe.ok ? "ready" : "unavailable";
			const stateColor = embeddingProbe.ok ? theme.success : theme.warn;
			lines.push(`${label("Embeddings")} ${colorize(rich, stateColor, state)}`);
			if (embeddingProbe.error) lines.push(`${label("Embeddings error")} ${warn(embeddingProbe.error)}`);
		}
		if (status.sourceCounts?.length) {
			lines.push(label("By source"));
			for (const entry of status.sourceCounts) {
				const total = scan?.sources?.find((scanEntry) => scanEntry.source === entry.source)?.totalFiles;
				const counts = total === null ? `${entry.files}/? files · ${entry.chunks} chunks` : `${entry.files}/${total} files · ${entry.chunks} chunks`;
				lines.push(`  ${accent(entry.source)} ${muted("·")} ${muted(counts)}`);
			}
		}
		if (status.fallback) lines.push(`${label("Fallback")} ${warn(status.fallback.from)}`);
		if (status.vector) {
			const vectorState = status.vector.enabled ? status.vector.available === void 0 ? "unknown" : status.vector.available ? "ready" : "unavailable" : "disabled";
			const vectorColor = vectorState === "ready" ? theme.success : vectorState === "unavailable" ? theme.warn : theme.muted;
			lines.push(`${label("Vector")} ${colorize(rich, vectorColor, vectorState)}`);
			if (status.vector.dims) lines.push(`${label("Vector dims")} ${info(String(status.vector.dims))}`);
			if (status.vector.extensionPath) lines.push(`${label("Vector path")} ${info(shortenHomePath(status.vector.extensionPath))}`);
			if (status.vector.loadError) lines.push(`${label("Vector error")} ${warn(status.vector.loadError)}`);
		}
		if (status.fts) {
			const ftsState = status.fts.enabled ? status.fts.available ? "ready" : "unavailable" : "disabled";
			const ftsColor = ftsState === "ready" ? theme.success : ftsState === "unavailable" ? theme.warn : theme.muted;
			lines.push(`${label("FTS")} ${colorize(rich, ftsColor, ftsState)}`);
			if (status.fts.error) lines.push(`${label("FTS error")} ${warn(status.fts.error)}`);
		}
		if (status.cache) {
			const cacheState = status.cache.enabled ? "enabled" : "disabled";
			const cacheColor = status.cache.enabled ? theme.success : theme.muted;
			const suffix = status.cache.enabled && typeof status.cache.entries === "number" ? ` (${status.cache.entries} entries)` : "";
			lines.push(`${label("Embedding cache")} ${colorize(rich, cacheColor, cacheState)}${suffix}`);
			if (status.cache.enabled && typeof status.cache.maxEntries === "number") lines.push(`${label("Cache cap")} ${info(String(status.cache.maxEntries))}`);
		}
		if (status.batch) {
			const batchState = status.batch.enabled ? "enabled" : "disabled";
			const batchColor = status.batch.enabled ? theme.success : theme.warn;
			const batchSuffix = ` (failures ${status.batch.failures}/${status.batch.limit})`;
			lines.push(`${label("Batch")} ${colorize(rich, batchColor, batchState)}${muted(batchSuffix)}`);
			if (status.batch.lastError) lines.push(`${label("Batch error")} ${warn(status.batch.lastError)}`);
		}
		if (status.fallback?.reason) lines.push(muted(status.fallback.reason));
		if (indexError) lines.push(`${label("Index error")} ${warn(indexError)}`);
		if (scan?.issues.length) {
			lines.push(label("Issues"));
			for (const issue of scan.issues) lines.push(`  ${warn(issue)}`);
		}
		defaultRuntime.log(lines.join("\n"));
		defaultRuntime.log("");
	}
}
function registerMemoryCli(program) {
	const memory = program.command("memory").description("Search, inspect, and reindex memory files").addHelpText("after", () => `\n${theme.heading("Examples:")}\n${formatHelpExamples([
		["symi memory status", "Show index and provider status."],
		["symi memory index --force", "Force a full reindex."],
		["symi memory search --query \"deployment notes\"", "Search indexed memory entries."],
		["symi memory status --json", "Output machine-readable JSON."]
	])}\n\n${theme.muted("Docs:")} ${formatDocsLink("/cli/memory", "docs.symi.ai/cli/memory")}\n`);
	memory.command("status").description("Show memory search index status").option("--agent <id>", "Agent id (default: default agent)").option("--json", "Print JSON").option("--deep", "Probe embedding provider availability").option("--index", "Reindex if dirty (implies --deep)").option("--verbose", "Verbose logging", false).action(async (opts) => {
		await runMemoryStatus(opts);
	});
	memory.command("index").description("Reindex memory files").option("--agent <id>", "Agent id (default: default agent)").option("--force", "Force full reindex", false).option("--verbose", "Verbose logging", false).action(async (opts) => {
		setVerbose(Boolean(opts.verbose));
		const cfg = loadConfig();
		const agentIds = resolveAgentIds(cfg, opts.agent);
		for (const agentId of agentIds) await withMemoryManagerForAgent({
			cfg,
			agentId,
			run: async (manager) => {
				try {
					const syncFn = manager.sync ? manager.sync.bind(manager) : void 0;
					if (opts.verbose) {
						const status = manager.status();
						const rich = isRich();
						const heading = (text) => colorize(rich, theme.heading, text);
						const muted = (text) => colorize(rich, theme.muted, text);
						const info = (text) => colorize(rich, theme.info, text);
						const warn = (text) => colorize(rich, theme.warn, text);
						const label = (text) => muted(`${text}:`);
						const sourceLabels = (status.sources ?? []).map((source) => formatSourceLabel(source, status.workspaceDir ?? "", agentId));
						const extraPaths = status.workspaceDir ? formatExtraPaths(status.workspaceDir, status.extraPaths ?? []) : [];
						const requestedProvider = status.requestedProvider ?? status.provider;
						const modelLabel = status.model ?? status.provider;
						const lines = [
							`${heading("Memory Index")} ${muted(`(${agentId})`)}`,
							`${label("Provider")} ${info(status.provider)} ${muted(`(requested: ${requestedProvider})`)}`,
							`${label("Model")} ${info(modelLabel)}`,
							sourceLabels.length ? `${label("Sources")} ${info(sourceLabels.join(", "))}` : null,
							extraPaths.length ? `${label("Extra paths")} ${info(extraPaths.join(", "))}` : null
						].filter(Boolean);
						if (status.fallback) lines.push(`${label("Fallback")} ${warn(status.fallback.from)}`);
						defaultRuntime.log(lines.join("\n"));
						defaultRuntime.log("");
					}
					const startedAt = Date.now();
					let lastLabel = "Indexing memory…";
					let lastCompleted = 0;
					let lastTotal = 0;
					const formatElapsed = () => {
						const elapsedMs = Math.max(0, Date.now() - startedAt);
						const seconds = Math.floor(elapsedMs / 1e3);
						const minutes = Math.floor(seconds / 60);
						const remainingSeconds = seconds % 60;
						return `${minutes}:${String(remainingSeconds).padStart(2, "0")}`;
					};
					const formatEta = () => {
						if (lastTotal <= 0 || lastCompleted <= 0) return null;
						const elapsedMs = Math.max(1, Date.now() - startedAt);
						const rate = lastCompleted / elapsedMs;
						if (!Number.isFinite(rate) || rate <= 0) return null;
						const remainingMs = Math.max(0, (lastTotal - lastCompleted) / rate);
						const seconds = Math.floor(remainingMs / 1e3);
						const minutes = Math.floor(seconds / 60);
						const remainingSeconds = seconds % 60;
						return `${minutes}:${String(remainingSeconds).padStart(2, "0")}`;
					};
					const buildLabel = () => {
						const elapsed = formatElapsed();
						const eta = formatEta();
						return eta ? `${lastLabel} · elapsed ${elapsed} · eta ${eta}` : `${lastLabel} · elapsed ${elapsed}`;
					};
					if (!syncFn) {
						defaultRuntime.log("Memory backend does not support manual reindex.");
						return;
					}
					await withProgressTotals({
						label: "Indexing memory…",
						total: 0,
						fallback: opts.verbose ? "line" : void 0
					}, async (update, progress) => {
						const interval = setInterval(() => {
							progress.setLabel(buildLabel());
						}, 1e3);
						try {
							await syncFn({
								reason: "cli",
								force: Boolean(opts.force),
								progress: (syncUpdate) => {
									if (syncUpdate.label) lastLabel = syncUpdate.label;
									lastCompleted = syncUpdate.completed;
									lastTotal = syncUpdate.total;
									update({
										completed: syncUpdate.completed,
										total: syncUpdate.total,
										label: buildLabel()
									});
									progress.setLabel(buildLabel());
								}
							});
						} finally {
							clearInterval(interval);
						}
					});
					const qmdIndexSummary = await summarizeQmdIndexArtifact(manager);
					if (qmdIndexSummary) defaultRuntime.log(qmdIndexSummary);
					defaultRuntime.log(`Memory index updated (${agentId}).`);
				} catch (err) {
					const message = formatErrorMessage(err);
					defaultRuntime.error(`Memory index failed (${agentId}): ${message}`);
					process.exitCode = 1;
				}
			}
		});
	});
	memory.command("search").description("Search memory files").argument("<query>", "Search query").option("--agent <id>", "Agent id (default: default agent)").option("--max-results <n>", "Max results", (value) => Number(value)).option("--min-score <n>", "Minimum score", (value) => Number(value)).option("--json", "Print JSON").action(async (query, opts) => {
		const cfg = loadConfig();
		await withMemoryManagerForAgent({
			cfg,
			agentId: resolveAgent(cfg, opts.agent),
			run: async (manager) => {
				let results;
				try {
					results = await manager.search(query, {
						maxResults: opts.maxResults,
						minScore: opts.minScore
					});
				} catch (err) {
					const message = formatErrorMessage(err);
					defaultRuntime.error(`Memory search failed: ${message}`);
					process.exitCode = 1;
					return;
				}
				if (opts.json) {
					defaultRuntime.log(JSON.stringify({ results }, null, 2));
					return;
				}
				if (results.length === 0) {
					defaultRuntime.log("No matches.");
					return;
				}
				const rich = isRich();
				const lines = [];
				for (const result of results) {
					lines.push(`${colorize(rich, theme.success, result.score.toFixed(3))} ${colorize(rich, theme.accent, `${shortenHomePath(result.path)}:${result.startLine}-${result.endLine}`)}`);
					lines.push(colorize(rich, theme.muted, result.snippet));
					lines.push("");
				}
				defaultRuntime.log(lines.join("\n").trim());
			}
		});
	});
	memory.command("consolidate").description("Run the L3 long-term-memory cycle (decay, reinforce, cluster, promote, prune)").option("--agent <id>", "Agent id (default: default agent)").option("--force", "Bypass the min-interval guard", false).option("--json", "Print JSON").action(async (opts) => {
		const cfg = loadConfig();
		await withMemoryManagerForAgent({
			cfg,
			agentId: resolveAgent(cfg, opts.agent),
			run: async (manager) => {
				if (!manager.runL3CycleIfDue) {
					defaultRuntime.log("L3 consolidation not supported by current memory backend.");
					return;
				}
				try {
					const result = await manager.runL3CycleIfDue({ force: Boolean(opts.force) });
					if (opts.json) {
						defaultRuntime.log(JSON.stringify(result, null, 2));
						return;
					}
					if (result.skipped) {
						defaultRuntime.log(`Skipped: ${result.skipped.reason}`);
						return;
					}
					defaultRuntime.log([
						`L3 cycle complete (${result.durationMs}ms):`,
						`  decayed:     ${result.decayed}`,
						`  reinforced:  ${result.reinforced}`,
						`  propagated:  ${result.propagated}`,
						`  clusters:    ${result.clustersSynthesized}`,
						`  beliefs:     ${result.beliefsCreated}`,
						`  promoted:    ${result.promoted}`,
						`  pruned:      ${result.pruned}`,
						result.paths.symiCore ? `  → ${result.paths.symiCore}` : "",
						result.paths.symiBeliefs ? `  → ${result.paths.symiBeliefs}` : ""
					].filter(Boolean).join("\n"));
				} catch (err) {
					const message = formatErrorMessage(err);
					defaultRuntime.error(`Consolidate failed: ${message}`);
					process.exitCode = 1;
				}
			}
		});
	});
	memory.command("pin").description("Pin the top-matching chunk so L3 never decays or prunes it").argument("<query>", "Natural-language query").option("--agent <id>", "Agent id (default: default agent)").option("--min-score <n>", "Minimum score", (value) => Number(value)).option("--json", "Print JSON").action(async (query, opts) => {
		await runPinCommand({
			query,
			opts,
			action: "pin"
		});
	});
	memory.command("unpin").description("Remove a pin so a chunk can age and be pruned normally").argument("<query>", "Natural-language query").option("--agent <id>", "Agent id (default: default agent)").option("--min-score <n>", "Minimum score", (value) => Number(value)).option("--json", "Print JSON").action(async (query, opts) => {
		await runPinCommand({
			query,
			opts,
			action: "unpin"
		});
	});
	memory.command("setup").description("Auto-detect and configure the best embedding provider").option("--agent <id>", "Agent id (default: default agent)").option("--dry-run", "Show what would be configured without writing", false).option("--verbose", "Verbose logging", false).action(async (opts) => {
		setVerbose(Boolean(opts.verbose));
		await runMemorySetup(opts);
	});
}
async function runPinCommand(params) {
	const cfg = loadConfig();
	await withMemoryManagerForAgent({
		cfg,
		agentId: resolveAgent(cfg, params.opts.agent),
		run: async (manager) => {
			if (!(params.action === "pin" ? !!manager.pin : !!manager.unpin)) {
				defaultRuntime.log(`memory ${params.action} not supported by current backend.`);
				return;
			}
			try {
				const pinArgs = {
					query: params.query,
					minScore: params.opts.minScore
				};
				const result = params.action === "pin" ? await manager.pin(pinArgs) : await manager.unpin(pinArgs);
				if (params.opts.json) {
					defaultRuntime.log(JSON.stringify(result, null, 2));
					return;
				}
				if (!result.found) {
					defaultRuntime.log(`No match: ${result.reason}`);
					return;
				}
				const verb = params.action === "pin" ? "Pinned" : "Unpinned";
				defaultRuntime.log(`${verb} ${result.path}:${result.startLine}-${result.endLine} (${result.chunkId})`);
			} catch (err) {
				defaultRuntime.error(`memory ${params.action} failed: ${formatErrorMessage(err)}`);
				process.exitCode = 1;
			}
		}
	});
}
async function detectEmbeddingProviders(cfg) {
	const detected = [];
	const ollamaProbe = await probeOllamaEmbeddingModels(resolveOllamaBaseUrl(cfg));
	if (ollamaProbe && ollamaProbe.models.length > 0) detected.push({
		id: "ollama",
		model: ollamaProbe.models[0],
		baseUrl: ollamaProbe.baseUrl,
		reason: `Ollama at ${ollamaProbe.baseUrl} — ${ollamaProbe.models[0]}`
	});
	for (const remote of [
		{
			id: "openai",
			envKey: "OPENAI_API_KEY",
			defaultModel: "text-embedding-3-small"
		},
		{
			id: "gemini",
			envKey: "GEMINI_API_KEY",
			defaultModel: "gemini-embedding-001"
		},
		{
			id: "voyage",
			envKey: "VOYAGE_API_KEY",
			defaultModel: "voyage-4-large"
		}
	]) {
		const envValue = process.env[remote.envKey]?.trim();
		let hasKey = Boolean(envValue);
		if (!hasKey) try {
			const resolved = await resolveApiKeyForProvider({
				provider: remote.id,
				cfg
			});
			hasKey = Boolean(resolved?.apiKey);
		} catch {}
		if (hasKey) detected.push({
			id: remote.id,
			model: remote.defaultModel,
			reason: `${remote.id} — API key found`
		});
	}
	return detected;
}
function setNestedValue(obj, path, value) {
	let current = obj;
	for (let i = 0; i < path.length - 1; i++) {
		const key = path[i];
		if (current[key] === void 0 || typeof current[key] !== "object" || current[key] === null) current[key] = {};
		current = current[key];
	}
	current[path[path.length - 1]] = value;
}
async function runMemorySetup(opts) {
	const rich = isRich();
	const heading = (text) => colorize(rich, theme.heading, text);
	const success = (text) => colorize(rich, theme.success, text);
	const warn = (text) => colorize(rich, theme.warn, text);
	const info = (text) => colorize(rich, theme.info, text);
	const muted = (text) => colorize(rich, theme.muted, text);
	const cfg = loadConfig();
	const agentId = resolveAgent(cfg, opts.agent);
	defaultRuntime.log(heading("Detecting embedding providers..."));
	defaultRuntime.log("");
	const detected = await detectEmbeddingProviders(cfg);
	const ollamaBase = resolveOllamaBaseUrl(cfg);
	const ollamaFound = detected.some((d) => d.id === "ollama");
	const openaiFound = detected.some((d) => d.id === "openai");
	const geminiFound = detected.some((d) => d.id === "gemini");
	const voyageFound = detected.some((d) => d.id === "voyage");
	if (ollamaFound) defaultRuntime.log(`  ${success("✓")} ${detected.find((d) => d.id === "ollama").reason}`);
	else defaultRuntime.log(`  ${warn("✗")} Ollama — not reachable at ${ollamaBase} or no embedding models`);
	if (openaiFound) defaultRuntime.log(`  ${success("✓")} ${detected.find((d) => d.id === "openai").reason}`);
	else defaultRuntime.log(`  ${warn("✗")} OpenAI — no API key`);
	if (geminiFound) defaultRuntime.log(`  ${success("✓")} ${detected.find((d) => d.id === "gemini").reason}`);
	else defaultRuntime.log(`  ${warn("✗")} Gemini — no API key`);
	if (voyageFound) defaultRuntime.log(`  ${success("✓")} ${detected.find((d) => d.id === "voyage").reason}`);
	else defaultRuntime.log(`  ${warn("✗")} Voyage — no API key`);
	defaultRuntime.log("");
	if (detected.length === 0) {
		defaultRuntime.error("No embedding providers detected.");
		defaultRuntime.error("");
		defaultRuntime.error("To fix, do one of:");
		defaultRuntime.error("  - Install Ollama and pull an embedding model: ollama pull nomic-embed-text");
		defaultRuntime.error("  - Set OPENAI_API_KEY environment variable");
		defaultRuntime.error("  - Set GEMINI_API_KEY or VOYAGE_API_KEY environment variable");
		process.exitCode = 1;
		return;
	}
	const best = detected[0];
	defaultRuntime.log(`${heading("Configuring:")} ${info(best.id)} (${best.model})`);
	if (opts.dryRun) {
		defaultRuntime.log(muted("  (dry run — no changes written)"));
		const configProvider = best.id === "ollama" ? "openai" : best.id;
		defaultRuntime.log(`  provider = ${info(configProvider)}${best.id === "ollama" ? muted(" (via Ollama)") : ""}`);
		defaultRuntime.log(`  model = ${info(best.model)}`);
		if (best.baseUrl) {
			const configUrl = best.id === "ollama" ? `${best.baseUrl}/v1` : best.baseUrl;
			defaultRuntime.log(`  remote.baseUrl = ${info(configUrl)}`);
		}
		return;
	}
	const snapshot = await readConfigFileSnapshot();
	const next = structuredClone(snapshot.resolved);
	const memPath = [
		"agents",
		"defaults",
		"memorySearch"
	];
	setNestedValue(next, [...memPath, "enabled"], true);
	setNestedValue(next, [...memPath, "sources"], ["memory", "sessions"]);
	if (best.id === "ollama" && best.baseUrl) {
		setNestedValue(next, [...memPath, "provider"], "openai");
		setNestedValue(next, [...memPath, "model"], best.model);
		setNestedValue(next, [
			...memPath,
			"remote",
			"baseUrl"
		], `${best.baseUrl}/v1`);
		setNestedValue(next, [
			...memPath,
			"remote",
			"apiKey"
		], "ollama-local");
	} else {
		setNestedValue(next, [...memPath, "provider"], best.id);
		setNestedValue(next, [...memPath, "model"], best.model);
		if (best.baseUrl) setNestedValue(next, [
			...memPath,
			"remote",
			"baseUrl"
		], best.baseUrl);
	}
	await writeConfigFile(next);
	defaultRuntime.log(`  ${success("✓")} Updated symi.json`);
	defaultRuntime.log("");
	defaultRuntime.log(heading("Indexing memory files..."));
	const freshCfg = loadConfig();
	let indexOk = false;
	await withMemoryManagerForAgent({
		cfg: freshCfg,
		agentId,
		run: async (manager) => {
			const syncFn = manager.sync ? manager.sync.bind(manager) : void 0;
			if (!syncFn) {
				defaultRuntime.log(warn("  Memory backend does not support indexing."));
				return;
			}
			try {
				await withProgressTotals({
					label: "Indexing memory…",
					total: 0
				}, async (update, progress) => {
					await syncFn({
						reason: "cli",
						force: true,
						progress: (syncUpdate) => {
							update({
								completed: syncUpdate.completed,
								total: syncUpdate.total,
								label: syncUpdate.label
							});
							if (syncUpdate.label) progress.setLabel(syncUpdate.label);
						}
					});
				});
				const status = manager.status();
				defaultRuntime.log(`  ${success("✓")} ${status.files ?? 0} files → ${status.chunks ?? 0} chunks` + (status.vector?.dims ? ` (${status.vector.dims}-dim vectors)` : ""));
				indexOk = true;
			} catch (err) {
				defaultRuntime.error(`  ${warn("✗")} Index failed: ${formatErrorMessage(err)}`);
			}
		}
	});
	if (!indexOk) {
		process.exitCode = 1;
		return;
	}
	defaultRuntime.log("");
	defaultRuntime.log(heading("Verifying search..."));
	await withMemoryManagerForAgent({
		cfg: freshCfg,
		agentId,
		run: async (manager) => {
			try {
				const results = await manager.search("test memory verification", { maxResults: 3 });
				defaultRuntime.log(`  ${success("✓")} Test query returned ${results.length} results` + (results.length > 0 ? ` (score ${results[results.length - 1].score.toFixed(2)}–${results[0].score.toFixed(2)})` : ""));
			} catch (err) {
				defaultRuntime.log(`  ${warn("✗")} Search verification failed: ${formatErrorMessage(err)}`);
				process.exitCode = 1;
				return;
			}
		}
	});
	defaultRuntime.log("");
	defaultRuntime.log(success("Memory system is fully operational."));
	defaultRuntime.log(muted("Restart the gateway to apply: systemctl --user restart symi-gateway"));
}

//#endregion
export { registerMemoryCli as n, memory_cli_exports as t };