import { r as formatErrorMessage } from "./errors-CGMew-1w.js";
import { i as normalizeLowercaseStringOrEmpty, o as normalizeOptionalLowercaseString, s as normalizeOptionalString } from "./string-coerce-CIT1-v_a.js";
import { l as isRecord$2 } from "./utils-CE5zxr9Z.js";
import { n as resolvePreferredKaijiBotTmpDir } from "./tmp-kaijibot-dir-NjkPBIBe.js";
import { t as createSubsystemLogger } from "./subsystem-qDUB67UD.js";
import { t as isTruthyEnvValue } from "./env-CStj6mGv.js";
import { o as loadAuthProfileStoreForRuntime, v as readClaudeCliCredentialsCached, y as readCodexCliCredentialsCached } from "./store-DLavseDR.js";
import { k as resolveRuntimeCliBackends, p as resolveDefaultModelForAgent } from "./model-selection-DCVjDyLz.js";
import { r as normalizeProviderId } from "./provider-id-Cy-cze0N.js";
import { p as scopedHeartbeatWakeOptions } from "./session-key-NGoeHrFI.js";
import { y as resolveSessionAgentIds } from "./agent-scope-BA9YeMqS.js";
import { a as shouldLogVerbose } from "./globals-D7B2Z7Cq.js";
import { at as resolveOwnerDisplaySetting } from "./io-B_JNqEVl.js";
import { n as resolvePluginSetupCliBackend } from "./setup-registry-O052mzhV.js";
import { o as sanitizeHostExecEnv } from "./host-env-security-1-qBf4wh.js";
import { i as applyMergePatch } from "./schema-validator-B92QvQiK.js";
import { c as loadEnabledBundleMcpConfig, o as extractMcpServerMap } from "./loader-D74RThYg.js";
import { n as buildTtsSystemPromptHint } from "./tts-qnVRObT8.js";
import { i as resolveBootstrapContextForRun, o as resolveHeartbeatPromptForSystemPrompt, r as makeBootstrapWarn } from "./bootstrap-files-7_zENDFm.js";
import { _ as resolveBootstrapPromptTruncationWarningMode, g as resolveBootstrapMaxChars, v as resolveBootstrapTotalMaxChars } from "./pi-embedded-helpers-XZLyX3NH.js";
import { m as isFailoverErrorMessage, n as classifyFailoverReason } from "./errors-BAYY50Ex.js";
import { n as sanitizeImageBlocks } from "./tool-images-mp7a2XiB.js";
import { n as requestHeartbeatNow } from "./heartbeat-wake-CwF_Pnqd.js";
import { i as enqueueSystemEvent } from "./system-events-CAYHEKX1.js";
import { n as detectRuntimeShell, t as getProcessSupervisor } from "./supervisor-DRs1XTkq.js";
import { n as extensionForMime } from "./mime-Cooz5Nk0.js";
import { i as isFailoverError, s as resolveFailoverStatus, t as FailoverError } from "./failover-error-CGdVbNet.js";
import { i as emitAgentEvent } from "./agent-events-Ca1q9xo_.js";
import { t as KeyedAsyncQueue } from "./keyed-async-queue-B_KrP3Pr.js";
import { i as stripSystemPromptCacheBoundary } from "./system-prompt-cache-boundary-D7aVImc6.js";
import { i as resolveSystemPromptOverride, t as buildAgentSystemPrompt } from "./system-prompt-Q8Oihi5d.js";
import { t as buildModelAliasLines } from "./model-alias-lines-D3QuoJ6h.js";
import { a as buildSystemPromptParams, i as buildSystemPromptReport, n as detectImageReferences, o as redactRunIdentifier, r as loadImageFromRef, s as resolveRunWorkspaceDir } from "./images-CkIwHDOg.js";
import { a as prependBootstrapPromptWarning, i as buildBootstrapTruncationReportMeta, n as buildBootstrapInjectionStats, r as buildBootstrapPromptWarning, t as analyzeBootstrapBudget } from "./bootstrap-budget-BWmyIAGS.js";
import { n as CLI_RESUME_WATCHDOG_DEFAULTS, r as CLI_WATCHDOG_MIN_TIMEOUT_MS, t as CLI_FRESH_WATCHDOG_DEFAULTS } from "./cli-watchdog-defaults-BLv4e5vt.js";
import path from "node:path";
import os from "node:os";
import fs from "node:fs/promises";
import crypto from "node:crypto";
//#region src/agents/cli-output.ts
function isClaudeCliProvider$1(providerId) {
	return normalizeLowercaseStringOrEmpty(providerId) === "claude-cli";
}
function extractJsonObjectCandidates(raw) {
	const candidates = [];
	let depth = 0;
	let start = -1;
	let inString = false;
	let escaped = false;
	for (let index = 0; index < raw.length; index += 1) {
		const char = raw[index] ?? "";
		if (escaped) {
			escaped = false;
			continue;
		}
		if (char === "\\") {
			if (inString) escaped = true;
			continue;
		}
		if (char === "\"") {
			inString = !inString;
			continue;
		}
		if (inString) continue;
		if (char === "{") {
			if (depth === 0) start = index;
			depth += 1;
			continue;
		}
		if (char === "}" && depth > 0) {
			depth -= 1;
			if (depth === 0 && start >= 0) {
				candidates.push(raw.slice(start, index + 1));
				start = -1;
			}
		}
	}
	return candidates;
}
function parseJsonRecordCandidates(raw) {
	const parsedRecords = [];
	const trimmed = raw.trim();
	if (!trimmed) return parsedRecords;
	try {
		const parsed = JSON.parse(trimmed);
		if (isRecord$2(parsed)) {
			parsedRecords.push(parsed);
			return parsedRecords;
		}
	} catch {}
	for (const candidate of extractJsonObjectCandidates(trimmed)) try {
		const parsed = JSON.parse(candidate);
		if (isRecord$2(parsed)) parsedRecords.push(parsed);
	} catch {}
	return parsedRecords;
}
function readNestedErrorMessage(parsed) {
	if (isRecord$2(parsed.error)) {
		const errorMessage = readNestedErrorMessage(parsed.error);
		if (errorMessage) return errorMessage;
	}
	if (typeof parsed.message === "string") {
		const trimmed = parsed.message.trim();
		if (trimmed) return trimmed;
	}
	if (typeof parsed.error === "string") {
		const trimmed = parsed.error.trim();
		if (trimmed) return trimmed;
	}
}
function unwrapCliErrorText(raw) {
	const trimmed = raw.trim();
	if (!trimmed) return "";
	for (const parsed of parseJsonRecordCandidates(trimmed)) {
		const nested = readNestedErrorMessage(parsed);
		if (nested) return nested;
	}
	return trimmed;
}
function toCliUsage(raw) {
	const pick = (key) => typeof raw[key] === "number" && raw[key] > 0 ? raw[key] : void 0;
	const totalInput = pick("input_tokens") ?? pick("inputTokens");
	const output = pick("output_tokens") ?? pick("outputTokens");
	const cacheRead = pick("cache_read_input_tokens") ?? pick("cached_input_tokens") ?? pick("cacheRead") ?? pick("cached");
	const input = pick("input") ?? (Object.hasOwn(raw, "cached") && typeof totalInput === "number" ? Math.max(0, totalInput - (cacheRead ?? 0)) : totalInput);
	const cacheWrite = pick("cache_creation_input_tokens") ?? pick("cache_write_input_tokens") ?? pick("cacheWrite");
	const total = pick("total_tokens") ?? pick("total");
	if (!input && !output && !cacheRead && !cacheWrite && !total) return;
	return {
		input,
		output,
		cacheRead,
		cacheWrite,
		total
	};
}
function readCliUsage(parsed) {
	if (isRecord$2(parsed.usage)) {
		const usage = toCliUsage(parsed.usage);
		if (usage) return usage;
	}
	if (isRecord$2(parsed.stats)) return toCliUsage(parsed.stats);
}
function collectCliText(value) {
	if (!value) return "";
	if (typeof value === "string") return value;
	if (Array.isArray(value)) return value.map((entry) => collectCliText(entry)).join("");
	if (!isRecord$2(value)) return "";
	if (typeof value.response === "string") return value.response;
	if (typeof value.text === "string") return value.text;
	if (typeof value.result === "string") return value.result;
	if (typeof value.content === "string") return value.content;
	if (Array.isArray(value.content)) return value.content.map((entry) => collectCliText(entry)).join("");
	if (isRecord$2(value.message)) return collectCliText(value.message);
	return "";
}
function collectExplicitCliErrorText(parsed) {
	const nested = readNestedErrorMessage(parsed);
	if (nested) return unwrapCliErrorText(nested);
	if (parsed.is_error === true && typeof parsed.result === "string") return unwrapCliErrorText(parsed.result);
	if (parsed.type === "assistant") {
		const text = collectCliText(parsed.message);
		if (/^\s*API Error:/i.test(text)) return unwrapCliErrorText(text);
	}
	if (parsed.type === "error") return unwrapCliErrorText(collectCliText(parsed.message) || collectCliText(parsed.content) || collectCliText(parsed.result) || collectCliText(parsed));
	return "";
}
function pickCliSessionId(parsed, backend) {
	const fields = backend.sessionIdFields ?? [
		"session_id",
		"sessionId",
		"conversation_id",
		"conversationId"
	];
	for (const field of fields) {
		const value = parsed[field];
		if (typeof value === "string" && value.trim()) return value.trim();
	}
}
function parseCliJson(raw, backend) {
	const parsedRecords = parseJsonRecordCandidates(raw);
	if (parsedRecords.length === 0) return null;
	let sessionId;
	let usage;
	let text = "";
	let sawStructuredOutput = false;
	for (const parsed of parsedRecords) {
		sessionId = pickCliSessionId(parsed, backend) ?? sessionId;
		usage = readCliUsage(parsed) ?? usage;
		const trimmedText = (collectCliText(parsed.message) || collectCliText(parsed.content) || collectCliText(parsed.result) || collectCliText(parsed.response) || collectCliText(parsed)).trim();
		if (trimmedText) {
			text = trimmedText;
			sawStructuredOutput = true;
			continue;
		}
		if (sessionId || usage) sawStructuredOutput = true;
	}
	if (!text && !sawStructuredOutput) return null;
	return {
		text,
		sessionId,
		usage
	};
}
function parseClaudeCliJsonlResult(params) {
	if (!isClaudeCliProvider$1(params.providerId)) return null;
	if (typeof params.parsed.type === "string" && params.parsed.type === "result" && typeof params.parsed.result === "string") {
		const resultText = params.parsed.result.trim();
		if (resultText) return {
			text: resultText,
			sessionId: params.sessionId,
			usage: params.usage
		};
		return {
			text: "",
			sessionId: params.sessionId,
			usage: params.usage
		};
	}
	return null;
}
function parseClaudeCliStreamingDelta(params) {
	if (!isClaudeCliProvider$1(params.providerId)) return null;
	if (params.parsed.type !== "stream_event" || !isRecord$2(params.parsed.event)) return null;
	const event = params.parsed.event;
	if (event.type !== "content_block_delta" || !isRecord$2(event.delta)) return null;
	const delta = event.delta;
	if (delta.type !== "text_delta" || typeof delta.text !== "string") return null;
	if (!delta.text) return null;
	return {
		text: `${params.textSoFar}${delta.text}`,
		delta: delta.text,
		sessionId: params.sessionId,
		usage: params.usage
	};
}
function createCliJsonlStreamingParser(params) {
	let lineBuffer = "";
	let assistantText = "";
	let sessionId;
	let usage;
	const handleParsedRecord = (parsed) => {
		sessionId = pickCliSessionId(parsed, params.backend) ?? sessionId;
		if (!sessionId && typeof parsed.thread_id === "string") sessionId = parsed.thread_id.trim();
		if (isRecord$2(parsed.usage)) usage = toCliUsage(parsed.usage) ?? usage;
		const delta = parseClaudeCliStreamingDelta({
			providerId: params.providerId,
			parsed,
			textSoFar: assistantText,
			sessionId,
			usage
		});
		if (!delta) return;
		assistantText = delta.text;
		params.onAssistantDelta(delta);
	};
	const flushLines = (flushPartial) => {
		while (true) {
			const newlineIndex = lineBuffer.indexOf("\n");
			if (newlineIndex < 0) break;
			const line = lineBuffer.slice(0, newlineIndex).trim();
			lineBuffer = lineBuffer.slice(newlineIndex + 1);
			if (!line) continue;
			for (const parsed of parseJsonRecordCandidates(line)) handleParsedRecord(parsed);
		}
		if (!flushPartial) return;
		const tail = lineBuffer.trim();
		lineBuffer = "";
		if (!tail) return;
		for (const parsed of parseJsonRecordCandidates(tail)) handleParsedRecord(parsed);
	};
	return {
		push(chunk) {
			if (!chunk) return;
			lineBuffer += chunk;
			flushLines(false);
		},
		finish() {
			flushLines(true);
		}
	};
}
function parseCliJsonl(raw, backend, providerId) {
	const lines = raw.split(/\r?\n/g).map((line) => line.trim()).filter(Boolean);
	if (lines.length === 0) return null;
	let sessionId;
	let usage;
	const texts = [];
	for (const line of lines) for (const parsed of parseJsonRecordCandidates(line)) {
		if (!sessionId) sessionId = pickCliSessionId(parsed, backend);
		if (!sessionId && typeof parsed.thread_id === "string") sessionId = parsed.thread_id.trim();
		usage = readCliUsage(parsed) ?? usage;
		const claudeResult = parseClaudeCliJsonlResult({
			providerId,
			parsed,
			sessionId,
			usage
		});
		if (claudeResult) return claudeResult;
		const item = isRecord$2(parsed.item) ? parsed.item : null;
		if (item && typeof item.text === "string") {
			const type = normalizeLowercaseStringOrEmpty(item.type);
			if (!type || type.includes("message")) texts.push(item.text);
		}
	}
	const text = texts.join("\n").trim();
	if (!text) return null;
	return {
		text,
		sessionId,
		usage
	};
}
function parseCliOutput(params) {
	const outputMode = params.outputMode ?? "text";
	if (outputMode === "text") return {
		text: params.raw.trim(),
		sessionId: params.fallbackSessionId
	};
	if (outputMode === "jsonl") return parseCliJsonl(params.raw, params.backend, params.providerId) ?? {
		text: params.raw.trim(),
		sessionId: params.fallbackSessionId
	};
	return parseCliJson(params.raw, params.backend) ?? {
		text: params.raw.trim(),
		sessionId: params.fallbackSessionId
	};
}
function extractCliErrorMessage(raw) {
	const parsedRecords = parseJsonRecordCandidates(raw);
	if (parsedRecords.length === 0) return null;
	let errorText = "";
	for (const parsed of parsedRecords) {
		const next = collectExplicitCliErrorText(parsed);
		if (next) errorText = next;
	}
	return errorText || null;
}
//#endregion
//#region src/agents/cli-runner/toml-inline.ts
function escapeTomlString(value) {
	return value.replaceAll("\\", "\\\\").replaceAll("\"", "\\\"");
}
function formatTomlKey(key) {
	return /^[A-Za-z0-9_-]+$/.test(key) ? key : `"${escapeTomlString(key)}"`;
}
function isRecord$1(value) {
	return typeof value === "object" && value !== null && !Array.isArray(value);
}
function serializeTomlInlineValue(value) {
	if (typeof value === "string") return `"${escapeTomlString(value)}"`;
	if (typeof value === "number" || typeof value === "bigint") return String(value);
	if (typeof value === "boolean") return value ? "true" : "false";
	if (Array.isArray(value)) return `[${value.map((entry) => serializeTomlInlineValue(entry)).join(", ")}]`;
	if (isRecord$1(value)) return `{ ${Object.entries(value).map(([key, entry]) => `${formatTomlKey(key)} = ${serializeTomlInlineValue(entry)}`).join(", ")} }`;
	throw new Error(`Unsupported TOML inline value: ${String(value)}`);
}
function formatTomlConfigOverride(key, value) {
	return `${key}=${serializeTomlInlineValue(value)}`;
}
//#endregion
//#region src/agents/cli-runner/reliability.ts
function pickWatchdogProfile(backend, useResume) {
	const defaults = useResume ? CLI_RESUME_WATCHDOG_DEFAULTS : CLI_FRESH_WATCHDOG_DEFAULTS;
	const configured = useResume ? backend.reliability?.watchdog?.resume : backend.reliability?.watchdog?.fresh;
	const ratio = (() => {
		const value = configured?.noOutputTimeoutRatio;
		if (typeof value !== "number" || !Number.isFinite(value)) return defaults.noOutputTimeoutRatio;
		return Math.max(.05, Math.min(.95, value));
	})();
	const minMs = (() => {
		const value = configured?.minMs;
		if (typeof value !== "number" || !Number.isFinite(value)) return defaults.minMs;
		return Math.max(CLI_WATCHDOG_MIN_TIMEOUT_MS, Math.floor(value));
	})();
	const maxMs = (() => {
		const value = configured?.maxMs;
		if (typeof value !== "number" || !Number.isFinite(value)) return defaults.maxMs;
		return Math.max(CLI_WATCHDOG_MIN_TIMEOUT_MS, Math.floor(value));
	})();
	return {
		noOutputTimeoutMs: typeof configured?.noOutputTimeoutMs === "number" && Number.isFinite(configured.noOutputTimeoutMs) ? Math.max(CLI_WATCHDOG_MIN_TIMEOUT_MS, Math.floor(configured.noOutputTimeoutMs)) : void 0,
		noOutputTimeoutRatio: ratio,
		minMs: Math.min(minMs, maxMs),
		maxMs: Math.max(minMs, maxMs)
	};
}
function resolveCliNoOutputTimeoutMs(params) {
	const profile = pickWatchdogProfile(params.backend, params.useResume);
	const cap = Math.max(CLI_WATCHDOG_MIN_TIMEOUT_MS, params.timeoutMs - 1e3);
	if (profile.noOutputTimeoutMs !== void 0) return Math.min(profile.noOutputTimeoutMs, cap);
	const computed = Math.floor(params.timeoutMs * profile.noOutputTimeoutRatio);
	const bounded = Math.min(profile.maxMs, Math.max(profile.minMs, computed));
	return Math.min(bounded, cap);
}
function buildCliSupervisorScopeKey(params) {
	const commandToken = normalizeLowercaseStringOrEmpty(path.basename(params.backend.command ?? ""));
	const backendToken = normalizeLowercaseStringOrEmpty(params.backendId);
	const sessionToken = params.cliSessionId?.trim();
	if (!sessionToken) return;
	return `cli:${backendToken}:${commandToken}:${sessionToken}`;
}
//#endregion
//#region src/agents/cli-runner/helpers.ts
const CLI_RUN_QUEUE = new KeyedAsyncQueue();
function isClaudeCliProvider(providerId) {
	return normalizeOptionalLowercaseString(providerId) === "claude-cli";
}
function enqueueCliRun(key, task) {
	return CLI_RUN_QUEUE.enqueue(key, task);
}
function resolveCliRunQueueKey(params) {
	if (params.serialize === false) return `${params.backendId}:${params.runId}`;
	if (isClaudeCliProvider(params.backendId)) {
		const sessionId = params.cliSessionId?.trim();
		if (sessionId) return `${params.backendId}:session:${sessionId}`;
		const workspaceDir = params.workspaceDir.trim();
		if (workspaceDir) return `${params.backendId}:workspace:${workspaceDir}`;
	}
	return params.backendId;
}
function buildSystemPrompt(params) {
	const defaultModelRef = resolveDefaultModelForAgent({
		cfg: params.config ?? {},
		agentId: params.agentId
	});
	const defaultModelLabel = `${defaultModelRef.provider}/${defaultModelRef.model}`;
	const { runtimeInfo, userTimezone, userTime, userTimeFormat } = buildSystemPromptParams({
		config: params.config,
		agentId: params.agentId,
		workspaceDir: params.workspaceDir,
		cwd: process.cwd(),
		runtime: {
			host: "kaijibot",
			os: `${os.type()} ${os.release()}`,
			arch: os.arch(),
			node: process.version,
			model: params.modelDisplay,
			defaultModel: defaultModelLabel,
			shell: detectRuntimeShell()
		}
	});
	const ttsHint = params.config ? buildTtsSystemPromptHint(params.config) : void 0;
	const ownerDisplay = resolveOwnerDisplaySetting(params.config);
	return buildAgentSystemPrompt({
		workspaceDir: params.workspaceDir,
		defaultThinkLevel: params.defaultThinkLevel,
		extraSystemPrompt: params.extraSystemPrompt,
		ownerNumbers: params.ownerNumbers,
		ownerDisplay: ownerDisplay.ownerDisplay,
		ownerDisplaySecret: ownerDisplay.ownerDisplaySecret,
		reasoningTagHint: false,
		heartbeatPrompt: params.heartbeatPrompt,
		docsPath: params.docsPath,
		acpEnabled: params.config?.acp?.enabled !== false,
		runtimeInfo,
		toolNames: params.tools.map((tool) => tool.name),
		modelAliasLines: buildModelAliasLines(params.config),
		userTimezone,
		userTime,
		userTimeFormat,
		contextFiles: params.contextFiles,
		ttsHint,
		memoryCitationsMode: params.config?.memory?.citations
	});
}
function normalizeCliModel(modelId, backend) {
	const trimmed = modelId.trim();
	if (!trimmed) return trimmed;
	const direct = backend.modelAliases?.[trimmed];
	if (direct) return direct;
	const lower = normalizeLowercaseStringOrEmpty(trimmed);
	const mapped = backend.modelAliases?.[lower];
	if (mapped) return mapped;
	return trimmed;
}
function resolveSystemPromptUsage(params) {
	const systemPrompt = params.systemPrompt?.trim();
	if (!systemPrompt) return null;
	const when = params.backend.systemPromptWhen ?? "first";
	if (when === "never") return null;
	if (when === "first" && !params.isNewSession) return null;
	if (!params.backend.systemPromptArg?.trim() && !params.backend.systemPromptFileConfigKey?.trim()) return null;
	return systemPrompt;
}
function resolveSessionIdToSend(params) {
	const mode = params.backend.sessionMode ?? "always";
	const existing = params.cliSessionId?.trim();
	if (mode === "none") return {
		sessionId: void 0,
		isNew: !existing
	};
	if (mode === "existing") return {
		sessionId: existing,
		isNew: !existing
	};
	if (existing) return {
		sessionId: existing,
		isNew: false
	};
	return {
		sessionId: crypto.randomUUID(),
		isNew: true
	};
}
function resolvePromptInput(params) {
	if ((params.backend.input ?? "arg") === "stdin") return { stdin: params.prompt };
	if (params.backend.maxPromptArgChars && params.prompt.length > params.backend.maxPromptArgChars) return { stdin: params.prompt };
	return { argsPrompt: params.prompt };
}
function resolveCliImagePath(image) {
	const ext = extensionForMime(image.mimeType) ?? ".bin";
	const digest = crypto.createHash("sha256").update(image.mimeType).update("\0").update(image.data).digest("hex");
	return path.join(resolvePreferredKaijiBotTmpDir(), "kaijibot-cli-images", `${digest}${ext}`);
}
function resolveCliImageRoot(params) {
	if (params.backend.imagePathScope === "workspace") return path.join(params.workspaceDir, ".kaijibot-cli-images");
	return path.join(resolvePreferredKaijiBotTmpDir(), "kaijibot-cli-images");
}
function appendImagePathsToPrompt(prompt, paths, prefix = "") {
	if (!paths.length) return prompt;
	const trimmed = prompt.trimEnd();
	return `${trimmed}${trimmed ? "\n\n" : ""}${paths.map((entry) => `${prefix}${entry}`).join("\n")}`;
}
async function loadPromptRefImages(params) {
	const refs = detectImageReferences(params.prompt);
	if (refs.length === 0) return [];
	const maxBytes = params.maxBytes ?? 6291456;
	const seen = /* @__PURE__ */ new Set();
	const images = [];
	for (const ref of refs) {
		const key = `${ref.type}:${ref.resolved}`;
		if (seen.has(key)) continue;
		seen.add(key);
		const image = await loadImageFromRef(ref, params.workspaceDir, {
			maxBytes,
			workspaceOnly: params.workspaceOnly,
			sandbox: params.sandbox
		});
		if (image) images.push(image);
	}
	const { images: sanitizedImages } = await sanitizeImageBlocks(images, "prompt:images", { maxBytes });
	return sanitizedImages;
}
async function writeCliImages(params) {
	const imageRoot = resolveCliImageRoot({
		backend: params.backend,
		workspaceDir: params.workspaceDir
	});
	await fs.mkdir(imageRoot, {
		recursive: true,
		mode: 448
	});
	const paths = [];
	for (let i = 0; i < params.images.length; i += 1) {
		const image = params.images[i];
		const fileName = path.basename(resolveCliImagePath(image));
		const filePath = path.join(imageRoot, fileName);
		const buffer = Buffer.from(image.data, "base64");
		await fs.writeFile(filePath, buffer, { mode: 384 });
		paths.push(filePath);
	}
	const cleanup = async () => {};
	return {
		paths,
		cleanup
	};
}
async function writeCliSystemPromptFile(params) {
	if (!params.backend.systemPromptFileConfigKey?.trim()) return { cleanup: async () => {} };
	const tempDir = await fs.mkdtemp(path.join(resolvePreferredKaijiBotTmpDir(), "kaijibot-cli-system-prompt-"));
	const filePath = path.join(tempDir, "system-prompt.md");
	await fs.writeFile(filePath, stripSystemPromptCacheBoundary(params.systemPrompt), {
		encoding: "utf-8",
		mode: 384
	});
	return {
		filePath,
		cleanup: async () => {
			await fs.rm(tempDir, {
				recursive: true,
				force: true
			});
		}
	};
}
async function prepareCliPromptImagePayload(params) {
	let prompt = params.prompt;
	const resolvedImages = params.images && params.images.length > 0 ? params.images : await loadPromptRefImages({
		prompt,
		workspaceDir: params.workspaceDir
	});
	if (resolvedImages.length === 0) return { prompt };
	const imagePayload = await writeCliImages({
		backend: params.backend,
		workspaceDir: params.workspaceDir,
		images: resolvedImages
	});
	const imagePaths = imagePayload.paths;
	if (!params.backend.imageArg || params.backend.input === "stdin" || params.backend.imageArg === "@") prompt = appendImagePathsToPrompt(prompt, imagePaths, params.backend.imageArg === "@" ? "@" : "");
	return {
		prompt,
		imagePaths,
		cleanupImages: imagePayload.cleanup
	};
}
function buildCliArgs(params) {
	const args = [...params.baseArgs];
	if (params.backend.modelArg && params.modelId) args.push(params.backend.modelArg, params.modelId);
	if (!params.useResume && params.systemPrompt && params.systemPromptFilePath && params.backend.systemPromptFileConfigKey) args.push(params.backend.systemPromptFileConfigArg ?? "-c", formatTomlConfigOverride(params.backend.systemPromptFileConfigKey, params.systemPromptFilePath));
	else if (!params.useResume && params.systemPrompt && params.backend.systemPromptArg) args.push(params.backend.systemPromptArg, stripSystemPromptCacheBoundary(params.systemPrompt));
	if (!params.useResume && params.sessionId) {
		if (params.backend.sessionArgs && params.backend.sessionArgs.length > 0) for (const entry of params.backend.sessionArgs) args.push(entry.replaceAll("{sessionId}", params.sessionId));
		else if (params.backend.sessionArg) args.push(params.backend.sessionArg, params.sessionId);
	}
	if (params.imagePaths && params.imagePaths.length > 0) {
		const mode = params.backend.imageMode ?? "repeat";
		const imageArg = params.backend.imageArg;
		if (imageArg && imageArg !== "@") if (mode === "list") args.push(imageArg, params.imagePaths.join(","));
		else for (const imagePath of params.imagePaths) args.push(imageArg, imagePath);
	}
	if (params.promptArg !== void 0) {
		let replacedPromptPlaceholder = false;
		for (let i = 0; i < args.length; i += 1) if (args[i] === "{prompt}") {
			args[i] = params.promptArg;
			replacedPromptPlaceholder = true;
		}
		if (replacedPromptPlaceholder) return args;
		args.push(params.promptArg);
	}
	return args;
}
//#endregion
//#region src/agents/cli-runner/log.ts
const cliBackendLog = createSubsystemLogger("agent/cli-backend");
//#endregion
//#region src/agents/cli-runner/execute.ts
const executeDeps = {
	getProcessSupervisor,
	enqueueSystemEvent,
	requestHeartbeatNow
};
function createCliAbortError() {
	const error = /* @__PURE__ */ new Error("CLI run aborted");
	error.name = "AbortError";
	return error;
}
function buildCliLogArgs(params) {
	const logArgs = [];
	for (let i = 0; i < params.args.length; i += 1) {
		const arg = params.args[i] ?? "";
		if (arg === params.systemPromptArg) {
			const systemPromptValue = params.args[i + 1] ?? "";
			logArgs.push(arg, `<systemPrompt:${systemPromptValue.length} chars>`);
			i += 1;
			continue;
		}
		if (arg === params.sessionArg) {
			logArgs.push(arg, params.args[i + 1] ?? "");
			i += 1;
			continue;
		}
		if (arg === params.modelArg) {
			logArgs.push(arg, params.args[i + 1] ?? "");
			i += 1;
			continue;
		}
		if (arg === params.imageArg) {
			logArgs.push(arg, "<image>");
			i += 1;
			continue;
		}
		logArgs.push(arg);
	}
	if (params.argsPrompt) {
		const promptIndex = logArgs.indexOf(params.argsPrompt);
		if (promptIndex >= 0) logArgs[promptIndex] = `<prompt:${params.argsPrompt.length} chars>`;
	}
	return logArgs;
}
async function executePreparedCliRun(context, cliSessionIdToUse) {
	const params = context.params;
	if (params.abortSignal?.aborted) throw createCliAbortError();
	const backend = context.preparedBackend.backend;
	const { sessionId: resolvedSessionId, isNew } = resolveSessionIdToSend({
		backend,
		cliSessionId: cliSessionIdToUse
	});
	const useResume = Boolean(cliSessionIdToUse && resolvedSessionId && backend.resumeArgs && backend.resumeArgs.length > 0);
	const systemPromptArg = resolveSystemPromptUsage({
		backend,
		isNewSession: isNew,
		systemPrompt: context.systemPrompt
	});
	const systemPromptFile = !useResume && systemPromptArg ? await writeCliSystemPromptFile({
		backend,
		systemPrompt: systemPromptArg
	}) : void 0;
	let prompt = prependBootstrapPromptWarning(params.prompt, context.bootstrapPromptWarningLines, { preserveExactPrompt: context.heartbeatPrompt });
	const { prompt: promptWithImages, imagePaths, cleanupImages } = await prepareCliPromptImagePayload({
		backend,
		prompt,
		workspaceDir: context.workspaceDir,
		images: params.images
	});
	prompt = promptWithImages;
	const { argsPrompt, stdin } = resolvePromptInput({
		backend,
		prompt
	});
	const stdinPayload = stdin ?? "";
	const baseArgs = useResume ? backend.resumeArgs ?? backend.args ?? [] : backend.args ?? [];
	const args = buildCliArgs({
		backend,
		baseArgs: useResume ? baseArgs.map((entry) => entry.replaceAll("{sessionId}", resolvedSessionId ?? "")) : baseArgs,
		modelId: context.normalizedModel,
		sessionId: resolvedSessionId,
		systemPrompt: systemPromptArg,
		systemPromptFilePath: systemPromptFile?.filePath,
		imagePaths,
		promptArg: argsPrompt,
		useResume
	});
	const queueKey = resolveCliRunQueueKey({
		backendId: context.backendResolved.id,
		serialize: backend.serialize,
		runId: params.runId,
		workspaceDir: context.workspaceDir,
		cliSessionId: useResume ? resolvedSessionId : void 0
	});
	try {
		return await enqueueCliRun(queueKey, async () => {
			cliBackendLog.info(`cli exec: provider=${params.provider} model=${context.normalizedModel} promptChars=${params.prompt.length}`);
			const logOutputText = isTruthyEnvValue(process.env["KAIJIBOT_CLI_BACKEND_LOG_OUTPUT"]) || isTruthyEnvValue(process.env["KAIJIBOT_CLAUDE_CLI_LOG_OUTPUT"]);
			if (logOutputText) {
				const logArgs = buildCliLogArgs({
					args,
					systemPromptArg: backend.systemPromptArg,
					sessionArg: backend.sessionArg,
					modelArg: backend.modelArg,
					imageArg: backend.imageArg,
					argsPrompt
				});
				cliBackendLog.info(`cli argv: ${backend.command} ${logArgs.join(" ")}`);
			}
			const env = (() => {
				const next = sanitizeHostExecEnv({
					baseEnv: process.env,
					blockPathOverrides: true
				});
				for (const key of backend.clearEnv ?? []) delete next[key];
				if (backend.env && Object.keys(backend.env).length > 0) Object.assign(next, sanitizeHostExecEnv({
					baseEnv: {},
					overrides: backend.env,
					blockPathOverrides: true
				}));
				Object.assign(next, context.preparedBackend.env);
				return next;
			})();
			const noOutputTimeoutMs = resolveCliNoOutputTimeoutMs({
				backend,
				timeoutMs: params.timeoutMs,
				useResume
			});
			const streamingParser = backend.output === "jsonl" ? createCliJsonlStreamingParser({
				backend,
				providerId: context.backendResolved.id,
				onAssistantDelta: ({ text, delta }) => {
					emitAgentEvent({
						runId: params.runId,
						stream: "assistant",
						data: {
							text,
							delta
						}
					});
				}
			}) : null;
			const supervisor = executeDeps.getProcessSupervisor();
			const scopeKey = buildCliSupervisorScopeKey({
				backend,
				backendId: context.backendResolved.id,
				cliSessionId: useResume ? resolvedSessionId : void 0
			});
			const managedRun = await supervisor.spawn({
				sessionId: params.sessionId,
				backendId: context.backendResolved.id,
				scopeKey,
				replaceExistingScope: Boolean(useResume && scopeKey),
				mode: "child",
				argv: [backend.command, ...args],
				timeoutMs: params.timeoutMs,
				noOutputTimeoutMs,
				cwd: context.workspaceDir,
				env,
				input: stdinPayload,
				onStdout: streamingParser ? (chunk) => streamingParser.push(chunk) : void 0
			});
			const replyBackendHandle = params.replyOperation ? {
				kind: "cli",
				cancel: () => {
					managedRun.cancel("manual-cancel");
				},
				isStreaming: () => false
			} : void 0;
			if (replyBackendHandle) params.replyOperation?.attachBackend(replyBackendHandle);
			const abortManagedRun = () => {
				managedRun.cancel("manual-cancel");
			};
			params.abortSignal?.addEventListener("abort", abortManagedRun, { once: true });
			if (params.abortSignal?.aborted) abortManagedRun();
			let result;
			try {
				result = await managedRun.wait();
			} finally {
				if (replyBackendHandle) params.replyOperation?.detachBackend(replyBackendHandle);
				params.abortSignal?.removeEventListener("abort", abortManagedRun);
			}
			streamingParser?.finish();
			if (params.abortSignal?.aborted && result.reason === "manual-cancel") throw createCliAbortError();
			const stdout = result.stdout.trim();
			const stderr = result.stderr.trim();
			if (logOutputText) {
				if (stdout) cliBackendLog.info(`cli stdout:\n${stdout}`);
				if (stderr) cliBackendLog.info(`cli stderr:\n${stderr}`);
			}
			if (shouldLogVerbose()) {
				if (stdout) cliBackendLog.debug(`cli stdout:\n${stdout}`);
				if (stderr) cliBackendLog.debug(`cli stderr:\n${stderr}`);
			}
			if (result.exitCode !== 0 || result.reason !== "exit") {
				if (result.reason === "no-output-timeout" || result.noOutputTimedOut) {
					const timeoutReason = `CLI produced no output for ${Math.round(noOutputTimeoutMs / 1e3)}s and was terminated.`;
					cliBackendLog.warn(`cli watchdog timeout: provider=${params.provider} model=${context.modelId} session=${resolvedSessionId ?? params.sessionId} noOutputTimeoutMs=${noOutputTimeoutMs} pid=${managedRun.pid ?? "unknown"}`);
					if (params.sessionKey) {
						const stallNotice = [
							`CLI agent (${params.provider}) produced no output for ${Math.round(noOutputTimeoutMs / 1e3)}s and was terminated.`,
							"It may have been waiting for interactive input or an approval prompt.",
							"For Claude Code, prefer --permission-mode bypassPermissions --print."
						].join(" ");
						executeDeps.enqueueSystemEvent(stallNotice, { sessionKey: params.sessionKey });
						executeDeps.requestHeartbeatNow(scopedHeartbeatWakeOptions(params.sessionKey, { reason: "cli:watchdog:stall" }));
					}
					throw new FailoverError(timeoutReason, {
						reason: "timeout",
						provider: params.provider,
						model: context.modelId,
						status: resolveFailoverStatus("timeout")
					});
				}
				if (result.reason === "overall-timeout") throw new FailoverError(`CLI exceeded timeout (${Math.round(params.timeoutMs / 1e3)}s) and was terminated.`, {
					reason: "timeout",
					provider: params.provider,
					model: context.modelId,
					status: resolveFailoverStatus("timeout")
				});
				const primaryErrorText = stderr || stdout;
				const err = (extractCliErrorMessage(primaryErrorText) ?? (stderr ? extractCliErrorMessage(stdout) : null)) || primaryErrorText || "CLI failed.";
				const reason = classifyFailoverReason(err, { provider: params.provider }) ?? "unknown";
				const status = resolveFailoverStatus(reason);
				throw new FailoverError(err, {
					reason,
					provider: params.provider,
					model: context.modelId,
					status
				});
			}
			return parseCliOutput({
				raw: stdout,
				backend,
				providerId: context.backendResolved.id,
				outputMode: useResume ? backend.resumeOutput ?? backend.output : backend.output,
				fallbackSessionId: resolvedSessionId
			});
		});
	} finally {
		if (systemPromptFile) await systemPromptFile.cleanup();
		if (cleanupImages) await cleanupImages();
	}
}
//#endregion
//#region src/gateway/mcp-http.loopback-runtime.ts
let activeRuntime;
function getActiveMcpLoopbackRuntime() {
	return activeRuntime ? { ...activeRuntime } : void 0;
}
function setActiveMcpLoopbackRuntime(runtime) {
	activeRuntime = { ...runtime };
}
function clearActiveMcpLoopbackRuntime(token) {
	if (activeRuntime?.token === token) activeRuntime = void 0;
}
function createMcpLoopbackServerConfig(port) {
	return { mcpServers: { kaijibot: {
		type: "http",
		url: `http://127.0.0.1:${port}/mcp`,
		headers: {
			Authorization: "Bearer ${KAIJIBOT_MCP_TOKEN}",
			"x-session-key": "${KAIJIBOT_MCP_SESSION_KEY}",
			"x-kaijibot-agent-id": "${KAIJIBOT_MCP_AGENT_ID}",
			"x-kaijibot-account-id": "${KAIJIBOT_MCP_ACCOUNT_ID}",
			"x-kaijibot-message-channel": "${KAIJIBOT_MCP_MESSAGE_CHANNEL}"
		}
	} } };
}
const cliAuthEpochDeps = {
	readClaudeCliCredentialsCached,
	readCodexCliCredentialsCached,
	loadAuthProfileStoreForRuntime
};
function hashCliAuthEpochPart(value) {
	return crypto.createHash("sha256").update(value).digest("hex");
}
function encodeUnknown(value) {
	return JSON.stringify(value ?? null);
}
function encodeClaudeCredential(credential) {
	if (credential.type === "oauth") return JSON.stringify([
		"oauth",
		credential.provider,
		credential.access,
		credential.refresh,
		credential.expires
	]);
	return JSON.stringify([
		"token",
		credential.provider,
		credential.token,
		credential.expires
	]);
}
function encodeCodexCredential(credential) {
	return JSON.stringify([
		credential.type,
		credential.provider,
		credential.access,
		credential.refresh,
		credential.expires,
		credential.accountId ?? null
	]);
}
function encodeAuthProfileCredential(credential) {
	switch (credential.type) {
		case "api_key": return JSON.stringify([
			"api_key",
			credential.provider,
			credential.key ?? null,
			encodeUnknown(credential.keyRef),
			credential.email ?? null,
			credential.displayName ?? null,
			encodeUnknown(credential.metadata)
		]);
		case "token": return JSON.stringify([
			"token",
			credential.provider,
			credential.token ?? null,
			encodeUnknown(credential.tokenRef),
			credential.expires ?? null,
			credential.email ?? null,
			credential.displayName ?? null
		]);
		case "oauth": return JSON.stringify([
			"oauth",
			credential.provider,
			credential.access,
			credential.refresh,
			credential.expires,
			credential.clientId ?? null,
			credential.email ?? null,
			credential.displayName ?? null,
			credential.enterpriseUrl ?? null,
			credential.projectId ?? null,
			credential.accountId ?? null,
			credential.managedBy ?? null
		]);
	}
}
function getLocalCliCredentialFingerprint(provider) {
	switch (provider) {
		case "claude-cli": {
			const credential = cliAuthEpochDeps.readClaudeCliCredentialsCached({
				ttlMs: 5e3,
				allowKeychainPrompt: false
			});
			return credential ? hashCliAuthEpochPart(encodeClaudeCredential(credential)) : void 0;
		}
		case "codex-cli": {
			const credential = cliAuthEpochDeps.readCodexCliCredentialsCached({ ttlMs: 5e3 });
			return credential ? hashCliAuthEpochPart(encodeCodexCredential(credential)) : void 0;
		}
		default: return;
	}
}
function getAuthProfileCredential(store, authProfileId) {
	if (!authProfileId) return;
	return store.profiles[authProfileId];
}
async function resolveCliAuthEpoch(params) {
	const provider = params.provider.trim();
	const authProfileId = normalizeOptionalString(params.authProfileId);
	const parts = [];
	const localFingerprint = getLocalCliCredentialFingerprint(provider);
	if (localFingerprint) parts.push(`local:${provider}:${localFingerprint}`);
	if (authProfileId) {
		const credential = getAuthProfileCredential(cliAuthEpochDeps.loadAuthProfileStoreForRuntime(void 0, {
			readOnly: true,
			allowKeychainPrompt: false
		}), authProfileId);
		if (credential) parts.push(`profile:${authProfileId}:${hashCliAuthEpochPart(encodeAuthProfileCredential(credential))}`);
	}
	if (parts.length === 0) return;
	return hashCliAuthEpochPart(parts.join("\n"));
}
//#endregion
//#region src/agents/cli-backends.ts
const FALLBACK_CLI_BACKEND_POLICIES = {};
function normalizeBundleMcpMode(mode, enabled) {
	if (!enabled) return;
	return mode ?? "claude-config-file";
}
function resolveSetupCliBackendPolicy(provider) {
	const entry = resolvePluginSetupCliBackend({ backend: provider });
	if (!entry) return;
	return {
		bundleMcp: entry.backend.bundleMcp === true,
		bundleMcpMode: normalizeBundleMcpMode(entry.backend.bundleMcpMode, entry.backend.bundleMcp === true),
		baseConfig: entry.backend.config,
		normalizeConfig: entry.backend.normalizeConfig
	};
}
function resolveFallbackCliBackendPolicy(provider) {
	return FALLBACK_CLI_BACKEND_POLICIES[provider] ?? resolveSetupCliBackendPolicy(provider);
}
function normalizeBackendKey(key) {
	return normalizeProviderId(key);
}
function pickBackendConfig(config, normalizedId) {
	const directKey = Object.keys(config).find((key) => normalizeOptionalLowercaseString(key) === normalizedId);
	if (directKey) return config[directKey];
	for (const [key, entry] of Object.entries(config)) if (normalizeBackendKey(key) === normalizedId) return entry;
}
function resolveRegisteredBackend(provider) {
	const normalized = normalizeBackendKey(provider);
	return resolveRuntimeCliBackends().find((entry) => normalizeBackendKey(entry.id) === normalized);
}
function mergeBackendConfig(base, override) {
	if (!override) return { ...base };
	const baseFresh = base.reliability?.watchdog?.fresh ?? {};
	const baseResume = base.reliability?.watchdog?.resume ?? {};
	const overrideFresh = override.reliability?.watchdog?.fresh ?? {};
	const overrideResume = override.reliability?.watchdog?.resume ?? {};
	return {
		...base,
		...override,
		args: override.args ?? base.args,
		env: {
			...base.env,
			...override.env
		},
		modelAliases: {
			...base.modelAliases,
			...override.modelAliases
		},
		clearEnv: Array.from(new Set([...base.clearEnv ?? [], ...override.clearEnv ?? []])),
		sessionIdFields: override.sessionIdFields ?? base.sessionIdFields,
		sessionArgs: override.sessionArgs ?? base.sessionArgs,
		resumeArgs: override.resumeArgs ?? base.resumeArgs,
		reliability: {
			...base.reliability,
			...override.reliability,
			watchdog: {
				...base.reliability?.watchdog,
				...override.reliability?.watchdog,
				fresh: {
					...baseFresh,
					...overrideFresh
				},
				resume: {
					...baseResume,
					...overrideResume
				}
			}
		}
	};
}
function resolveCliBackendConfig(provider, cfg) {
	const normalized = normalizeBackendKey(provider);
	const override = pickBackendConfig(cfg?.agents?.defaults?.cliBackends ?? {}, normalized);
	const registered = resolveRegisteredBackend(normalized);
	if (registered) {
		const merged = mergeBackendConfig(registered.config, override);
		const config = registered.normalizeConfig ? registered.normalizeConfig(merged) : merged;
		const command = config.command?.trim();
		if (!command) return null;
		return {
			id: normalized,
			config: {
				...config,
				command
			},
			bundleMcp: registered.bundleMcp === true,
			bundleMcpMode: normalizeBundleMcpMode(registered.bundleMcpMode, registered.bundleMcp === true),
			pluginId: registered.pluginId
		};
	}
	const fallbackPolicy = resolveFallbackCliBackendPolicy(normalized);
	if (!override) {
		if (!fallbackPolicy?.baseConfig) return null;
		const baseConfig = fallbackPolicy.normalizeConfig ? fallbackPolicy.normalizeConfig(fallbackPolicy.baseConfig) : fallbackPolicy.baseConfig;
		const command = baseConfig.command?.trim();
		if (!command) return null;
		return {
			id: normalized,
			config: {
				...baseConfig,
				command
			},
			bundleMcp: fallbackPolicy.bundleMcp,
			bundleMcpMode: fallbackPolicy.bundleMcpMode
		};
	}
	const mergedFallback = fallbackPolicy?.baseConfig ? mergeBackendConfig(fallbackPolicy.baseConfig, override) : override;
	const config = fallbackPolicy?.normalizeConfig ? fallbackPolicy.normalizeConfig(mergedFallback) : mergedFallback;
	const command = config.command?.trim();
	if (!command) return null;
	return {
		id: normalized,
		config: {
			...config,
			command
		},
		bundleMcp: fallbackPolicy?.bundleMcp === true,
		bundleMcpMode: fallbackPolicy?.bundleMcpMode
	};
}
//#endregion
//#region src/agents/cli-session.ts
const CLAUDE_CLI_BACKEND_ID = "claude-cli";
function hashCliSessionText(value) {
	const trimmed = normalizeOptionalString(value);
	if (!trimmed) return;
	return crypto.createHash("sha256").update(trimmed).digest("hex");
}
function getCliSessionBinding(entry, provider) {
	if (!entry) return;
	const normalized = normalizeProviderId(provider);
	const fromBindings = entry.cliSessionBindings?.[normalized];
	const bindingSessionId = normalizeOptionalString(fromBindings?.sessionId);
	if (bindingSessionId) return {
		sessionId: bindingSessionId,
		authProfileId: normalizeOptionalString(fromBindings?.authProfileId),
		authEpoch: normalizeOptionalString(fromBindings?.authEpoch),
		extraSystemPromptHash: normalizeOptionalString(fromBindings?.extraSystemPromptHash),
		mcpConfigHash: normalizeOptionalString(fromBindings?.mcpConfigHash)
	};
	const fromMap = entry.cliSessionIds?.[normalized];
	const normalizedFromMap = normalizeOptionalString(fromMap);
	if (normalizedFromMap) return { sessionId: normalizedFromMap };
	if (normalized === CLAUDE_CLI_BACKEND_ID) {
		const legacy = normalizeOptionalString(entry.claudeCliSessionId);
		if (legacy) return { sessionId: legacy };
	}
}
function getCliSessionId(entry, provider) {
	return getCliSessionBinding(entry, provider)?.sessionId;
}
function setCliSessionId(entry, provider, sessionId) {
	setCliSessionBinding(entry, provider, { sessionId });
}
function setCliSessionBinding(entry, provider, binding) {
	const normalized = normalizeProviderId(provider);
	const trimmed = binding.sessionId.trim();
	if (!trimmed) return;
	entry.cliSessionBindings = {
		...entry.cliSessionBindings,
		[normalized]: {
			sessionId: trimmed,
			...normalizeOptionalString(binding.authProfileId) ? { authProfileId: normalizeOptionalString(binding.authProfileId) } : {},
			...normalizeOptionalString(binding.authEpoch) ? { authEpoch: normalizeOptionalString(binding.authEpoch) } : {},
			...normalizeOptionalString(binding.extraSystemPromptHash) ? { extraSystemPromptHash: normalizeOptionalString(binding.extraSystemPromptHash) } : {},
			...normalizeOptionalString(binding.mcpConfigHash) ? { mcpConfigHash: normalizeOptionalString(binding.mcpConfigHash) } : {}
		}
	};
	entry.cliSessionIds = {
		...entry.cliSessionIds,
		[normalized]: trimmed
	};
	if (normalized === CLAUDE_CLI_BACKEND_ID) entry.claudeCliSessionId = trimmed;
}
function clearCliSession(entry, provider) {
	const normalized = normalizeProviderId(provider);
	if (entry.cliSessionBindings?.[normalized] !== void 0) {
		const next = { ...entry.cliSessionBindings };
		delete next[normalized];
		entry.cliSessionBindings = Object.keys(next).length > 0 ? next : void 0;
	}
	if (entry.cliSessionIds?.[normalized] !== void 0) {
		const next = { ...entry.cliSessionIds };
		delete next[normalized];
		entry.cliSessionIds = Object.keys(next).length > 0 ? next : void 0;
	}
	if (normalized === CLAUDE_CLI_BACKEND_ID) delete entry.claudeCliSessionId;
}
function resolveCliSessionReuse(params) {
	const binding = params.binding;
	const sessionId = normalizeOptionalString(binding?.sessionId);
	if (!sessionId) return {};
	const currentAuthProfileId = normalizeOptionalString(params.authProfileId);
	const currentAuthEpoch = normalizeOptionalString(params.authEpoch);
	const currentExtraSystemPromptHash = normalizeOptionalString(params.extraSystemPromptHash);
	const currentMcpConfigHash = normalizeOptionalString(params.mcpConfigHash);
	if (normalizeOptionalString(binding?.authProfileId) !== currentAuthProfileId) return { invalidatedReason: "auth-profile" };
	if (normalizeOptionalString(binding?.authEpoch) !== currentAuthEpoch) return { invalidatedReason: "auth-epoch" };
	if (normalizeOptionalString(binding?.extraSystemPromptHash) !== currentExtraSystemPromptHash) return { invalidatedReason: "system-prompt" };
	if (normalizeOptionalString(binding?.mcpConfigHash) !== currentMcpConfigHash) return { invalidatedReason: "mcp" };
	return { sessionId };
}
//#endregion
//#region src/agents/cli-runner/bundle-mcp.ts
function resolveBundleMcpMode(mode) {
	return mode ?? "claude-config-file";
}
async function readExternalMcpConfig(configPath) {
	try {
		return { mcpServers: extractMcpServerMap(JSON.parse(await fs.readFile(configPath, "utf-8"))) };
	} catch {
		return { mcpServers: {} };
	}
}
async function readJsonObject(filePath) {
	try {
		const raw = JSON.parse(await fs.readFile(filePath, "utf-8"));
		return raw && typeof raw === "object" && !Array.isArray(raw) ? { ...raw } : {};
	} catch {
		return {};
	}
}
function findMcpConfigPath(args) {
	if (!args?.length) return;
	for (let i = 0; i < args.length; i += 1) {
		const arg = args[i] ?? "";
		if (arg === "--mcp-config") return normalizeOptionalString(args[i + 1]);
		if (arg.startsWith("--mcp-config=")) return normalizeOptionalString(arg.slice(13));
	}
}
function injectClaudeMcpConfigArgs(args, mcpConfigPath) {
	const next = [];
	for (let i = 0; i < (args?.length ?? 0); i += 1) {
		const arg = args?.[i] ?? "";
		if (arg === "--strict-mcp-config") continue;
		if (arg === "--mcp-config") {
			i += 1;
			continue;
		}
		if (arg.startsWith("--mcp-config=")) continue;
		next.push(arg);
	}
	next.push("--strict-mcp-config", "--mcp-config", mcpConfigPath);
	return next;
}
function isRecord(value) {
	return typeof value === "object" && value !== null && !Array.isArray(value);
}
function normalizeStringArray(value) {
	return Array.isArray(value) && value.every((entry) => typeof entry === "string") ? [...value] : void 0;
}
function normalizeStringRecord(value) {
	if (!isRecord(value)) return;
	const entries = Object.entries(value).filter((entry) => {
		return typeof entry[1] === "string";
	});
	return entries.length > 0 ? Object.fromEntries(entries) : void 0;
}
function decodeHeaderEnvPlaceholder(value) {
	const bearerMatch = /^Bearer \${([A-Z0-9_]+)}$/.exec(value);
	if (bearerMatch) return {
		envVar: bearerMatch[1],
		bearer: true
	};
	const envMatch = /^\${([A-Z0-9_]+)}$/.exec(value);
	if (envMatch) return {
		envVar: envMatch[1],
		bearer: false
	};
	return null;
}
function applyCommonServerConfig(next, server) {
	if (typeof server.command === "string") next.command = server.command;
	const args = normalizeStringArray(server.args);
	if (args) next.args = args;
	const env = normalizeStringRecord(server.env);
	if (env) next.env = env;
	if (typeof server.cwd === "string") next.cwd = server.cwd;
	if (typeof server.url === "string") next.url = server.url;
}
function normalizeCodexServerConfig(server) {
	const next = {};
	applyCommonServerConfig(next, server);
	const httpHeaders = normalizeStringRecord(server.headers);
	if (httpHeaders) {
		const staticHeaders = {};
		const envHeaders = {};
		for (const [name, value] of Object.entries(httpHeaders)) {
			const decoded = decodeHeaderEnvPlaceholder(value);
			if (!decoded) {
				staticHeaders[name] = value;
				continue;
			}
			if (decoded.bearer && normalizeOptionalLowercaseString(name) === "authorization") {
				next.bearer_token_env_var = decoded.envVar;
				continue;
			}
			envHeaders[name] = decoded.envVar;
		}
		if (Object.keys(staticHeaders).length > 0) next.http_headers = staticHeaders;
		if (Object.keys(envHeaders).length > 0) next.env_http_headers = envHeaders;
	}
	return next;
}
function resolveEnvPlaceholder(value, inheritedEnv) {
	const decoded = decodeHeaderEnvPlaceholder(value);
	if (!decoded) return value;
	const resolved = inheritedEnv?.[decoded.envVar] ?? process.env[decoded.envVar] ?? "";
	return decoded.bearer ? `Bearer ${resolved}` : resolved;
}
function normalizeGeminiServerConfig(server, inheritedEnv) {
	const next = {};
	applyCommonServerConfig(next, server);
	if (typeof server.type === "string") next.type = server.type;
	const headers = normalizeStringRecord(server.headers);
	if (headers) next.headers = Object.fromEntries(Object.entries(headers).map(([name, value]) => [name, resolveEnvPlaceholder(value, inheritedEnv)]));
	if (typeof server.trust === "boolean") next.trust = server.trust;
	return next;
}
function injectCodexMcpConfigArgs(args, config) {
	const overrides = serializeTomlInlineValue(Object.fromEntries(Object.entries(config.mcpServers).map(([name, server]) => [name, normalizeCodexServerConfig(server)])));
	return [
		...args ?? [],
		"-c",
		`mcp_servers=${overrides}`
	];
}
async function writeGeminiSystemSettings(mergedConfig, inheritedEnv) {
	const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "kaijibot-gemini-mcp-"));
	const settingsPath = path.join(tempDir, "settings.json");
	const existingSettingsPath = inheritedEnv?.GEMINI_CLI_SYSTEM_SETTINGS_PATH ?? process.env.GEMINI_CLI_SYSTEM_SETTINGS_PATH;
	const base = typeof existingSettingsPath === "string" && existingSettingsPath.trim() ? await readJsonObject(existingSettingsPath) : {};
	const normalizedConfig = { mcpServers: Object.fromEntries(Object.entries(mergedConfig.mcpServers).map(([name, server]) => [name, normalizeGeminiServerConfig(server, inheritedEnv)])) };
	const settings = applyMergePatch(base, {
		mcp: { allowed: Object.keys(normalizedConfig.mcpServers) },
		mcpServers: normalizedConfig.mcpServers
	});
	await fs.writeFile(settingsPath, `${JSON.stringify(settings, null, 2)}\n`, "utf-8");
	return {
		env: {
			...inheritedEnv,
			GEMINI_CLI_SYSTEM_SETTINGS_PATH: settingsPath
		},
		cleanup: async () => {
			await fs.rm(tempDir, {
				recursive: true,
				force: true
			});
		}
	};
}
async function prepareModeSpecificBundleMcpConfig(params) {
	const serializedConfig = `${JSON.stringify(params.mergedConfig, null, 2)}\n`;
	const mcpConfigHash = crypto.createHash("sha256").update(serializedConfig).digest("hex");
	if (params.mode === "codex-config-overrides") return {
		backend: {
			...params.backend,
			args: injectCodexMcpConfigArgs(params.backend.args, params.mergedConfig),
			resumeArgs: injectCodexMcpConfigArgs(params.backend.resumeArgs ?? params.backend.args ?? [], params.mergedConfig)
		},
		mcpConfigHash,
		env: params.env
	};
	if (params.mode === "gemini-system-settings") {
		const settings = await writeGeminiSystemSettings(params.mergedConfig, params.env);
		return {
			backend: params.backend,
			mcpConfigHash,
			env: settings.env,
			cleanup: settings.cleanup
		};
	}
	const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "kaijibot-cli-mcp-"));
	const mcpConfigPath = path.join(tempDir, "mcp.json");
	await fs.writeFile(mcpConfigPath, serializedConfig, "utf-8");
	return {
		backend: {
			...params.backend,
			args: injectClaudeMcpConfigArgs(params.backend.args, mcpConfigPath),
			resumeArgs: injectClaudeMcpConfigArgs(params.backend.resumeArgs ?? params.backend.args ?? [], mcpConfigPath)
		},
		mcpConfigHash,
		env: params.env,
		cleanup: async () => {
			await fs.rm(tempDir, {
				recursive: true,
				force: true
			});
		}
	};
}
async function prepareCliBundleMcpConfig(params) {
	if (!params.enabled) return {
		backend: params.backend,
		env: params.env
	};
	const mode = resolveBundleMcpMode(params.mode);
	const existingMcpConfigPath = mode === "claude-config-file" ? findMcpConfigPath(params.backend.resumeArgs) ?? findMcpConfigPath(params.backend.args) : void 0;
	let mergedConfig = { mcpServers: {} };
	if (existingMcpConfigPath) {
		const resolvedExistingPath = path.isAbsolute(existingMcpConfigPath) ? existingMcpConfigPath : path.resolve(params.workspaceDir, existingMcpConfigPath);
		mergedConfig = applyMergePatch(mergedConfig, await readExternalMcpConfig(resolvedExistingPath));
	}
	const bundleConfig = loadEnabledBundleMcpConfig({
		workspaceDir: params.workspaceDir,
		cfg: params.config
	});
	for (const diagnostic of bundleConfig.diagnostics) params.warn?.(`bundle MCP skipped for ${diagnostic.pluginId}: ${diagnostic.message}`);
	mergedConfig = applyMergePatch(mergedConfig, bundleConfig.config);
	if (params.additionalConfig) mergedConfig = applyMergePatch(mergedConfig, params.additionalConfig);
	return await prepareModeSpecificBundleMcpConfig({
		mode,
		backend: params.backend,
		mergedConfig,
		env: params.env
	});
}
//#endregion
//#region src/agents/cli-runner/prepare.ts
const prepareDeps = {
	makeBootstrapWarn,
	resolveBootstrapContextForRun,
	getActiveMcpLoopbackRuntime,
	createMcpLoopbackServerConfig,
	resolveKaijiBotDocsPath: async (params) => (await import("./docs-path--c-g2UAz.js")).resolveKaijiBotDocsPath(params)
};
async function prepareCliRunContext(params) {
	const started = Date.now();
	const workspaceResolution = resolveRunWorkspaceDir({
		workspaceDir: params.workspaceDir,
		sessionKey: params.sessionKey,
		agentId: params.agentId,
		config: params.config
	});
	const resolvedWorkspace = workspaceResolution.workspaceDir;
	const redactedSessionId = redactRunIdentifier(params.sessionId);
	const redactedSessionKey = redactRunIdentifier(params.sessionKey);
	const redactedWorkspace = redactRunIdentifier(resolvedWorkspace);
	if (workspaceResolution.usedFallback) cliBackendLog.warn(`[workspace-fallback] caller=runCliAgent reason=${workspaceResolution.fallbackReason} run=${params.runId} session=${redactedSessionId} sessionKey=${redactedSessionKey} agent=${workspaceResolution.agentId} workspace=${redactedWorkspace}`);
	const workspaceDir = resolvedWorkspace;
	const backendResolved = resolveCliBackendConfig(params.provider, params.config);
	if (!backendResolved) throw new Error(`Unknown CLI backend: ${params.provider}`);
	const authEpoch = await resolveCliAuthEpoch({
		provider: params.provider,
		authProfileId: params.authProfileId
	});
	const extraSystemPrompt = params.extraSystemPrompt?.trim() ?? "";
	const extraSystemPromptHash = hashCliSessionText(extraSystemPrompt);
	const modelId = (params.model ?? "default").trim() || "default";
	const normalizedModel = normalizeCliModel(modelId, backendResolved.config);
	const modelDisplay = `${params.provider}/${modelId}`;
	const sessionLabel = params.sessionKey ?? params.sessionId;
	const { bootstrapFiles, contextFiles } = await prepareDeps.resolveBootstrapContextForRun({
		workspaceDir,
		config: params.config,
		sessionKey: params.sessionKey,
		sessionId: params.sessionId,
		warn: prepareDeps.makeBootstrapWarn({
			sessionLabel,
			warn: (message) => cliBackendLog.warn(message)
		})
	});
	const bootstrapMaxChars = resolveBootstrapMaxChars(params.config);
	const bootstrapTotalMaxChars = resolveBootstrapTotalMaxChars(params.config);
	const bootstrapAnalysis = analyzeBootstrapBudget({
		files: buildBootstrapInjectionStats({
			bootstrapFiles,
			injectedFiles: contextFiles
		}),
		bootstrapMaxChars,
		bootstrapTotalMaxChars
	});
	const bootstrapPromptWarningMode = resolveBootstrapPromptTruncationWarningMode(params.config);
	const bootstrapPromptWarning = buildBootstrapPromptWarning({
		analysis: bootstrapAnalysis,
		mode: bootstrapPromptWarningMode,
		seenSignatures: params.bootstrapPromptWarningSignaturesSeen,
		previousSignature: params.bootstrapPromptWarningSignature
	});
	const { defaultAgentId, sessionAgentId } = resolveSessionAgentIds({
		sessionKey: params.sessionKey,
		config: params.config,
		agentId: params.agentId
	});
	const mcpLoopbackRuntime = backendResolved.bundleMcp ? prepareDeps.getActiveMcpLoopbackRuntime() : void 0;
	const preparedBackend = await prepareCliBundleMcpConfig({
		enabled: backendResolved.bundleMcp,
		mode: backendResolved.bundleMcpMode,
		backend: backendResolved.config,
		workspaceDir,
		config: params.config,
		additionalConfig: mcpLoopbackRuntime ? prepareDeps.createMcpLoopbackServerConfig(mcpLoopbackRuntime.port) : void 0,
		env: mcpLoopbackRuntime ? {
			KAIJIBOT_MCP_TOKEN: mcpLoopbackRuntime.token,
			KAIJIBOT_MCP_AGENT_ID: sessionAgentId ?? "",
			KAIJIBOT_MCP_ACCOUNT_ID: params.agentAccountId ?? "",
			KAIJIBOT_MCP_SESSION_KEY: params.sessionKey ?? "",
			KAIJIBOT_MCP_MESSAGE_CHANNEL: params.messageProvider ?? ""
		} : void 0,
		warn: (message) => cliBackendLog.warn(message)
	});
	const reusableCliSession = params.cliSessionBinding ? resolveCliSessionReuse({
		binding: params.cliSessionBinding,
		authProfileId: params.authProfileId,
		authEpoch,
		extraSystemPromptHash,
		mcpConfigHash: preparedBackend.mcpConfigHash
	}) : params.cliSessionId ? { sessionId: params.cliSessionId } : {};
	if (reusableCliSession.invalidatedReason) cliBackendLog.info(`cli session reset: provider=${params.provider} reason=${reusableCliSession.invalidatedReason}`);
	const heartbeatPrompt = resolveHeartbeatPromptForSystemPrompt({
		config: params.config,
		agentId: sessionAgentId,
		defaultAgentId
	});
	const docsPath = await prepareDeps.resolveKaijiBotDocsPath({
		workspaceDir,
		argv1: process.argv[1],
		cwd: process.cwd(),
		moduleUrl: import.meta.url
	});
	const systemPrompt = resolveSystemPromptOverride({
		config: params.config,
		agentId: sessionAgentId
	}) ?? buildSystemPrompt({
		workspaceDir,
		config: params.config,
		defaultThinkLevel: params.thinkLevel,
		extraSystemPrompt,
		ownerNumbers: params.ownerNumbers,
		heartbeatPrompt,
		docsPath: docsPath ?? void 0,
		tools: [],
		contextFiles,
		modelDisplay,
		agentId: sessionAgentId
	});
	return {
		params,
		started,
		workspaceDir,
		backendResolved,
		preparedBackend,
		reusableCliSession,
		modelId,
		normalizedModel,
		systemPrompt,
		systemPromptReport: buildSystemPromptReport({
			source: "run",
			generatedAt: Date.now(),
			sessionId: params.sessionId,
			sessionKey: params.sessionKey,
			provider: params.provider,
			model: modelId,
			workspaceDir,
			bootstrapMaxChars,
			bootstrapTotalMaxChars,
			bootstrapTruncation: buildBootstrapTruncationReportMeta({
				analysis: bootstrapAnalysis,
				warningMode: bootstrapPromptWarningMode,
				warning: bootstrapPromptWarning
			}),
			sandbox: {
				mode: "off",
				sandboxed: false
			},
			systemPrompt,
			bootstrapFiles,
			injectedFiles: contextFiles,
			skillsPrompt: "",
			tools: []
		}),
		bootstrapPromptWarningLines: bootstrapPromptWarning.lines,
		heartbeatPrompt,
		authEpoch,
		extraSystemPromptHash
	};
}
//#endregion
//#region src/agents/cli-runner.ts
async function runCliAgent(params) {
	return runPreparedCliAgent(await prepareCliRunContext(params));
}
async function runPreparedCliAgent(context) {
	const { params } = context;
	const buildCliRunResult = (resultParams) => {
		const text = resultParams.output.text?.trim();
		return {
			payloads: text ? [{ text }] : void 0,
			meta: {
				durationMs: Date.now() - context.started,
				systemPromptReport: context.systemPromptReport,
				agentMeta: {
					sessionId: resultParams.effectiveCliSessionId ?? params.sessionId ?? "",
					provider: params.provider,
					model: context.modelId,
					usage: resultParams.output.usage,
					...resultParams.effectiveCliSessionId ? { cliSessionBinding: {
						sessionId: resultParams.effectiveCliSessionId,
						...params.authProfileId ? { authProfileId: params.authProfileId } : {},
						...context.authEpoch ? { authEpoch: context.authEpoch } : {},
						...context.extraSystemPromptHash ? { extraSystemPromptHash: context.extraSystemPromptHash } : {},
						...context.preparedBackend.mcpConfigHash ? { mcpConfigHash: context.preparedBackend.mcpConfigHash } : {}
					} } : {}
				}
			}
		};
	};
	try {
		try {
			const output = await executePreparedCliRun(context, context.reusableCliSession.sessionId);
			return buildCliRunResult({
				output,
				effectiveCliSessionId: output.sessionId ?? context.reusableCliSession.sessionId
			});
		} catch (err) {
			if (isFailoverError(err)) {
				const retryableSessionId = context.reusableCliSession.sessionId ?? params.cliSessionId;
				if (err.reason === "session_expired" && retryableSessionId && params.sessionKey) {
					const output = await executePreparedCliRun(context, void 0);
					const effectiveCliSessionId = output.sessionId;
					return buildCliRunResult({
						output,
						effectiveCliSessionId
					});
				}
				throw err;
			}
			const message = formatErrorMessage(err);
			if (isFailoverErrorMessage(message, { provider: params.provider })) {
				const reason = classifyFailoverReason(message, { provider: params.provider }) ?? "unknown";
				const status = resolveFailoverStatus(reason);
				throw new FailoverError(message, {
					reason,
					provider: params.provider,
					model: context.modelId,
					status
				});
			}
			throw err;
		}
	} finally {
		await context.preparedBackend.cleanup?.();
	}
}
//#endregion
export { setCliSessionBinding as a, setActiveMcpLoopbackRuntime as c, getCliSessionId as i, clearCliSession as n, setCliSessionId as o, getCliSessionBinding as r, clearActiveMcpLoopbackRuntime as s, runCliAgent as t };
