import { j as resolveTimerTimeoutMs } from "./number-coercion-CJQ8TR--.js";
import { c as resolveConfigPath, f as resolveGatewayPort } from "./paths-BprY_fto.js";
import { i as resolveAgentModelPrimaryValue } from "./model-input-B2zxl6MM.js";
import { o as resolveAgentEffectiveModelPrimary } from "./agent-scope-CMwhTQTF.js";
import { u as normalizeAgentId } from "./session-key-B_NoIfpX.js";
import { c as resolveDefaultAgentId, t as listAgentEntries } from "./agent-scope-config-Di1rn1p5.js";
import { u as readConfigFileSnapshot } from "./io-CVFQolkW.js";
import "./config-BzUsatE2.js";
import { i as resolveOpenClawReferencePaths, n as OPENCLAW_SOURCE_URL, t as OPENCLAW_DOCS_URL } from "./docs-path-BV57VemT.js";
import { spawn } from "node:child_process";
//#region src/crestodian/probes.ts
const LOCAL_COMMAND_PROBE_OUTPUT_MAX_CHARS = 16 * 1024;
const LOCAL_COMMAND_PROBE_KILL_GRACE_MS = 500;
function appendBounded(previous, chunk, limit) {
	const next = previous + chunk;
	return next.length > limit ? next.slice(-limit) : next;
}
/** Probe a command by running a small version command with bounded output and timeout. */
async function probeLocalCommand(command, args = ["--version"], opts = {}) {
	const timeoutMs = resolveTimerTimeoutMs(opts.timeoutMs, 1500);
	const outputLimit = opts.outputLimit ?? LOCAL_COMMAND_PROBE_OUTPUT_MAX_CHARS;
	const timeoutKillGraceMs = resolveTimerTimeoutMs(opts.timeoutKillGraceMs, LOCAL_COMMAND_PROBE_KILL_GRACE_MS, 0);
	return await new Promise((resolve) => {
		let stdout = "";
		let stderr = "";
		let settled = false;
		let timedOut = false;
		let killTimer;
		const child = spawn(command, args, { stdio: [
			"ignore",
			"pipe",
			"pipe"
		] });
		const timeoutResult = () => ({
			command,
			found: true,
			error: `timed out after ${timeoutMs}ms`
		});
		const finish = (result) => {
			if (settled) return;
			settled = true;
			clearTimeout(timer);
			if (killTimer) clearTimeout(killTimer);
			resolve(result);
		};
		const timer = setTimeout(() => {
			timedOut = true;
			child.kill("SIGTERM");
			killTimer = setTimeout(() => {
				child.kill("SIGKILL");
				child.stdout.destroy();
				child.stderr.destroy();
				finish(timeoutResult());
			}, timeoutKillGraceMs);
			killTimer.unref?.();
		}, timeoutMs);
		child.stdout.setEncoding("utf8");
		child.stderr.setEncoding("utf8");
		child.stdout.on("data", (chunk) => {
			stdout = appendBounded(stdout, String(chunk), outputLimit);
		});
		child.stderr.on("data", (chunk) => {
			stderr = appendBounded(stderr, String(chunk), outputLimit);
		});
		child.on("error", (err) => {
			finish({
				command,
				found: err.code !== "ENOENT",
				error: err.code === "ENOENT" ? "not found" : err.message
			});
		});
		child.on("close", (code) => {
			if (timedOut) {
				finish(timeoutResult());
				return;
			}
			const text = `${stdout}\n${stderr}`.trim().split(/\r?\n/)[0]?.trim();
			finish({
				command,
				found: code === 0 || Boolean(text),
				version: text || void 0,
				error: code === 0 ? void 0 : `exited ${String(code)}`
			});
		});
	});
}
/** Probe a Gateway URL by translating it to its HTTP /healthz endpoint. */
async function probeGatewayUrl(url, opts = {}) {
	const httpUrl = url.replace(/^ws:/, "http:").replace(/^wss:/, "https:");
	const healthUrl = new URL("/healthz", httpUrl).toString();
	const timeoutMs = resolveTimerTimeoutMs(opts.timeoutMs, 900);
	const controller = new AbortController();
	const timeout = setTimeout(() => controller.abort(), timeoutMs);
	try {
		const response = await fetch(healthUrl, {
			method: "GET",
			signal: controller.signal
		});
		return {
			reachable: response.ok,
			url,
			error: response.ok ? void 0 : response.statusText
		};
	} catch (err) {
		return {
			reachable: false,
			url,
			error: err instanceof Error ? err.message : String(err)
		};
	} finally {
		clearTimeout(timeout);
	}
}
//#endregion
//#region src/crestodian/overview.ts
function issueMessages(snapshot) {
	return snapshot.issues.map((issue) => {
		return `${issue.path ? `${issue.path}: ` : ""}${issue.message}`;
	});
}
function buildAgentSummaries(cfg) {
	const defaultAgentId = resolveDefaultAgentId(cfg);
	const entries = listAgentEntries(cfg);
	if (entries.length === 0) return [{
		id: defaultAgentId,
		isDefault: true,
		model: resolveAgentEffectiveModelPrimary(cfg, defaultAgentId)
	}];
	const seen = /* @__PURE__ */ new Set();
	const summaries = [];
	for (const entry of entries) {
		const id = normalizeAgentId(entry.id);
		if (seen.has(id)) continue;
		seen.add(id);
		const summary = {
			id,
			isDefault: id === defaultAgentId
		};
		if (typeof entry.name === "string") summary.name = entry.name;
		const model = resolveAgentEffectiveModelPrimary(cfg, id);
		if (model) summary.model = model;
		if (typeof entry.workspace === "string") summary.workspace = entry.workspace;
		summaries.push(summary);
	}
	return summaries;
}
function resolveFastTestReferences(env) {
	if (env.OPENCLAW_TEST_FAST !== "1") return;
	const sourcePath = process.cwd();
	return {
		sourcePath,
		docsPath: `${sourcePath}/docs`
	};
}
async function loadCrestodianOverview(opts = {}) {
	const env = opts.env ?? process.env;
	const deps = opts.deps ?? {};
	const snapshot = await (deps.readConfigFileSnapshot ?? readConfigFileSnapshot)();
	const cfg = snapshot.runtimeConfig ?? snapshot.sourceConfig ?? {};
	const defaultAgentId = resolveDefaultAgentId(cfg);
	const defaultModel = resolveAgentEffectiveModelPrimary(cfg, defaultAgentId) ?? resolveAgentModelPrimaryValue(cfg.agents?.defaults?.model);
	const configPath = snapshot.path || (deps.resolveConfigPath ?? resolveConfigPath)(env);
	let gatewayUrl = `ws://127.0.0.1:${(deps.resolveGatewayPort ?? resolveGatewayPort)(cfg, env)}`;
	let gatewaySource = "local loopback";
	let gatewayError;
	try {
		const details = (deps.buildGatewayConnectionDetails ?? (await import("./call-Uv2x4Wrs.js")).buildGatewayConnectionDetails)({
			config: cfg,
			configPath
		});
		gatewayUrl = details.url;
		gatewaySource = details.urlSource;
		gatewayError = details.remoteFallbackNote;
	} catch (err) {
		gatewayError = err instanceof Error ? err.message : String(err);
	}
	const resolveReferences = deps.resolveOpenClawReferencePaths ?? resolveOpenClawReferencePaths;
	const commandProbe = deps.probeLocalCommand ?? probeLocalCommand;
	const [codex, claude, gateway, references] = await Promise.all([
		commandProbe("codex"),
		commandProbe("claude"),
		(deps.probeGatewayUrl ?? probeGatewayUrl)(gatewayUrl),
		resolveFastTestReferences(env) ?? resolveReferences({
			argv1: process.argv[1],
			cwd: process.cwd(),
			moduleUrl: import.meta.url
		})
	]);
	return {
		config: {
			path: configPath,
			exists: snapshot.exists,
			valid: snapshot.valid,
			issues: issueMessages(snapshot),
			hash: snapshot.hash ?? null
		},
		agents: buildAgentSummaries(cfg),
		defaultAgentId,
		defaultModel,
		tools: {
			codex,
			claude,
			apiKeys: {
				openai: Boolean(env.OPENAI_API_KEY?.trim()),
				anthropic: Boolean(env.ANTHROPIC_API_KEY?.trim())
			}
		},
		gateway: {
			url: gateway.url,
			source: gatewaySource,
			reachable: gateway.reachable,
			error: gateway.error ?? gatewayError
		},
		references: {
			docsPath: references.docsPath ?? void 0,
			docsUrl: OPENCLAW_DOCS_URL,
			sourcePath: references.sourcePath ?? void 0,
			sourceUrl: OPENCLAW_SOURCE_URL
		}
	};
}
function formatCommandProbe(probe) {
	if (!probe.found) return "not found";
	if (probe.version) return probe.version;
	return probe.error ? `found (${probe.error})` : "found";
}
function formatCrestodianOverview(overview) {
	const agentLines = overview.agents.map((agent) => {
		return `  - ${[
			agent.id,
			agent.isDefault ? "default" : void 0,
			agent.name ? `name=${agent.name}` : void 0,
			agent.model ? `model=${agent.model}` : void 0,
			agent.workspace ? `workspace=${agent.workspace}` : void 0
		].filter(Boolean).join(" | ")}`;
	});
	const configStatus = overview.config.valid ? overview.config.exists ? "valid" : "missing (configless rescue mode)" : "invalid";
	const issueLines = overview.config.issues.length > 0 ? ["Config issues:", ...overview.config.issues.map((issue) => `  - ${issue}`)] : [];
	return [
		"Crestodian online. Little claws, typed tools.",
		"",
		`Config: ${configStatus}`,
		`Path: ${overview.config.path}`,
		`Default agent: ${overview.defaultAgentId}`,
		`Default model: ${overview.defaultModel ?? "not configured"}`,
		"Agents:",
		...agentLines,
		`Codex: ${formatCommandProbe(overview.tools.codex)}`,
		`Claude Code: ${formatCommandProbe(overview.tools.claude)}`,
		`API keys: OpenAI ${overview.tools.apiKeys.openai ? "found" : "not found"}, Anthropic ${overview.tools.apiKeys.anthropic ? "found" : "not found"}`,
		`Planner: ${overview.defaultModel ? `model-assisted via ${overview.defaultModel} for fuzzy local commands` : "deterministic only until a model is configured"}`,
		`Docs: ${overview.references.docsPath ?? overview.references.docsUrl}`,
		overview.references.sourcePath ? `Source: ${overview.references.sourcePath}` : `Source: ${overview.references.sourceUrl}`,
		`Gateway: ${overview.gateway.reachable ? "reachable" : "not reachable"} (${overview.gateway.url}, ${overview.gateway.source})`,
		overview.gateway.error ? `Gateway note: ${overview.gateway.error}` : void 0,
		`Next: ${recommendCrestodianNextStep(overview)}`,
		...issueLines
	].filter((line) => line !== void 0).join("\n");
}
function recommendCrestodianNextStep(overview) {
	if (!overview.config.exists) return "run \"setup\" to create a starter config";
	if (!overview.config.valid) return "run \"validate config\" or \"doctor\" to inspect the config";
	if (!overview.defaultModel) return "run \"setup\" or \"set default model <provider/model>\"";
	if (!overview.gateway.reachable) return "run \"gateway status\" or \"restart gateway\"";
	return "run \"talk to agent\" to enter your default agent";
}
function formatStartupConfigStatus(overview) {
	if (!overview.config.exists) return "missing";
	return overview.config.valid ? "valid" : "invalid";
}
function formatStartupUse(overview) {
	if (overview.defaultModel) return `Using: ${overview.defaultModel} for fuzzy local planning.`;
	return "Using: deterministic typed commands until we configure a model.";
}
function formatStartupGatewayStatus(overview) {
	if (overview.gateway.reachable) return `Gateway: reachable at ${overview.gateway.url}.`;
	return `Gateway: not reachable at ${overview.gateway.url}; I already did the first probe.`;
}
function formatStartupAction(overview) {
	if (!overview.config.exists) return "I can start by creating a starter config with `setup`.";
	if (!overview.config.valid) return "I can start debugging with `validate config` or `doctor`.";
	if (!overview.defaultModel) return "I can start by choosing a model with `setup`.";
	if (!overview.gateway.reachable) return "I can start debugging with `gateway status`, or queue `restart gateway` for approval.";
	return "Everything basic is reachable. Use `talk to agent` when you want the normal agent.";
}
function formatCrestodianStartupMessage(overview) {
	const agent = overview.agents.find((entry) => entry.id === overview.defaultAgentId);
	const agentLabel = agent?.name ? `${overview.defaultAgentId} (${agent.name})` : overview.defaultAgentId;
	return [
		"## Hi, I'm Crestodian.",
		"",
		"- Start me when setup, config, Gateway, model choice, or agent routing feels off.",
		`- ${formatStartupUse(overview)}`,
		`- Config: ${formatStartupConfigStatus(overview)}. Default agent: ${agentLabel}.`,
		`- ${formatStartupGatewayStatus(overview)}`,
		"",
		formatStartupAction(overview)
	].join("\n");
}
//#endregion
export { formatCrestodianStartupMessage as n, loadCrestodianOverview as r, formatCrestodianOverview as t };
