import { t as __exportAll } from "./rolldown-runtime-CiIaOW0V.js";
import { $ as extractAcpError, B as AgentSpawnError, C as formatErrorMessage, E as normalizeOutputError, G as PermissionDeniedError, H as ClaudeAcpSessionCreateTimeoutError, J as SessionModeReplayError, K as PermissionPromptUnavailableError, L as promptToDisplayText, M as extractRuntimeSessionId, N as normalizeRuntimeSessionId, Q as SessionResumeRequiredError, R as textPrompt, T as isRetryablePromptError, U as CopilotAcpUnsupportedError, V as AuthPolicyError, W as GeminiAcpStartupTimeoutError, X as SessionNotFoundError, Y as SessionModelReplayError, Z as SessionResolutionError, _ as incrementPerfCounter, a as trySubmitToRunningOwner, b as setPerfGauge, c as isProcessAlive, d as terminateProcess, et as isAcpResourceNotFoundError, f as terminateQueueOwnerForSession, g as getPerfMetricsSnapshot, h as formatPerfMetric, i as trySetModelOnRunningOwner, j as SESSION_RECORD_SCHEMA, l as refreshQueueOwnerLease, m as waitMs$1, n as trySetConfigOptionOnRunningOwner, o as SessionQueueOwner, p as tryAcquireQueueOwnerLease, q as QueueConnectionError, r as trySetModeOnRunningOwner, t as tryCancelOnRunningOwner, u as releaseQueueOwnerLease, v as measurePerf, w as isAcpQueryClosedBeforeResponseError, x as startPerfTimer, y as resetPerfMetrics, z as AgentDisconnectedError } from "./queue-ipc-CgWf63GN.js";
import { n as isSessionUpdateNotification, t as isAcpJsonRpcMessage } from "./acp-jsonrpc-C7pPk9Tw.js";
import fs, { realpathSync, statSync } from "node:fs";
import fs$1 from "node:fs/promises";
import path from "node:path";
import os from "node:os";
import { spawn } from "node:child_process";
import { Readable, Writable } from "node:stream";
import { ClientSideConnection, PROTOCOL_VERSION } from "@agentclientprotocol/sdk";
import readline from "node:readline/promises";
import { randomUUID } from "node:crypto";
//#region src/permission-prompt.ts
async function promptForPermission(options) {
	if (!process.stdin.isTTY || !process.stderr.isTTY) return false;
	if (options.header) process.stderr.write(`\n${options.header}\n`);
	if (options.details && options.details.trim().length > 0) process.stderr.write(`${options.details}\n`);
	const rl = readline.createInterface({
		input: process.stdin,
		output: process.stderr
	});
	try {
		const normalized = (await rl.question(options.prompt)).trim().toLowerCase();
		return normalized === "y" || normalized === "yes";
	} finally {
		rl.close();
	}
}
//#endregion
//#region src/filesystem.ts
const WRITE_PREVIEW_MAX_LINES = 16;
const WRITE_PREVIEW_MAX_CHARS = 1200;
function nowIso$1() {
	return (/* @__PURE__ */ new Date()).toISOString();
}
function isWithinRoot(rootDir, targetPath) {
	const relative = path.relative(rootDir, targetPath);
	return relative.length === 0 || !relative.startsWith("..") && !path.isAbsolute(relative);
}
function toWritePreview(content) {
	const lines = content.replace(/\r\n/g, "\n").split("\n");
	const visibleLines = lines.slice(0, WRITE_PREVIEW_MAX_LINES);
	let preview = visibleLines.join("\n");
	if (lines.length > visibleLines.length) preview += `\n... (${lines.length - visibleLines.length} more lines)`;
	if (preview.length > WRITE_PREVIEW_MAX_CHARS) preview = `${preview.slice(0, WRITE_PREVIEW_MAX_CHARS - 3)}...`;
	return preview;
}
async function defaultConfirmWrite(filePath, preview) {
	return await promptForPermission({
		header: `[permission] Allow write to ${filePath}?`,
		details: preview,
		prompt: "Allow write? (y/N) "
	});
}
function canPromptForPermission$2() {
	return Boolean(process.stdin.isTTY && process.stderr.isTTY);
}
var FileSystemHandlers = class {
	rootDir;
	permissionMode;
	nonInteractivePermissions;
	onOperation;
	usesDefaultConfirmWrite;
	confirmWrite;
	constructor(options) {
		this.rootDir = path.resolve(options.cwd);
		this.permissionMode = options.permissionMode;
		this.nonInteractivePermissions = options.nonInteractivePermissions ?? "deny";
		this.onOperation = options.onOperation;
		this.usesDefaultConfirmWrite = options.confirmWrite == null;
		this.confirmWrite = options.confirmWrite ?? defaultConfirmWrite;
	}
	updatePermissionPolicy(permissionMode, nonInteractivePermissions) {
		this.permissionMode = permissionMode;
		this.nonInteractivePermissions = nonInteractivePermissions ?? "deny";
	}
	async readTextFile(params) {
		const filePath = this.resolvePathWithinRoot(params.path);
		const summary = `read_text_file: ${filePath}`;
		this.emitOperation({
			method: "fs/read_text_file",
			status: "running",
			summary,
			details: this.readWindowDetails(params.line, params.limit),
			timestamp: nowIso$1()
		});
		try {
			if (this.permissionMode === "deny-all") throw new PermissionDeniedError("Permission denied for fs/read_text_file (--deny-all)");
			const content = await fs$1.readFile(filePath, "utf8");
			const sliced = this.sliceContent(content, params.line, params.limit);
			this.emitOperation({
				method: "fs/read_text_file",
				status: "completed",
				summary,
				details: this.readWindowDetails(params.line, params.limit),
				timestamp: nowIso$1()
			});
			return { content: sliced };
		} catch (error) {
			const message = error instanceof Error ? error.message : String(error);
			this.emitOperation({
				method: "fs/read_text_file",
				status: "failed",
				summary,
				details: message,
				timestamp: nowIso$1()
			});
			throw error;
		}
	}
	async writeTextFile(params) {
		const filePath = this.resolvePathWithinRoot(params.path);
		const preview = toWritePreview(params.content);
		const summary = `write_text_file: ${filePath}`;
		this.emitOperation({
			method: "fs/write_text_file",
			status: "running",
			summary,
			details: preview,
			timestamp: nowIso$1()
		});
		try {
			if (!await this.isWriteApproved(filePath, preview)) throw new PermissionDeniedError("Permission denied for fs/write_text_file");
			await fs$1.mkdir(path.dirname(filePath), { recursive: true });
			await fs$1.writeFile(filePath, params.content, "utf8");
			this.emitOperation({
				method: "fs/write_text_file",
				status: "completed",
				summary,
				details: preview,
				timestamp: nowIso$1()
			});
			return {};
		} catch (error) {
			const message = error instanceof Error ? error.message : String(error);
			this.emitOperation({
				method: "fs/write_text_file",
				status: "failed",
				summary,
				details: message,
				timestamp: nowIso$1()
			});
			throw error;
		}
	}
	async isWriteApproved(filePath, preview) {
		if (this.permissionMode === "approve-all") return true;
		if (this.permissionMode === "deny-all") return false;
		if (this.usesDefaultConfirmWrite && this.nonInteractivePermissions === "fail" && !canPromptForPermission$2()) throw new PermissionPromptUnavailableError();
		return await this.confirmWrite(filePath, preview);
	}
	resolvePathWithinRoot(rawPath) {
		if (!path.isAbsolute(rawPath)) throw new Error(`Path must be absolute: ${rawPath}`);
		const resolved = path.resolve(rawPath);
		if (!isWithinRoot(this.rootDir, resolved)) throw new Error(`Path is outside allowed cwd subtree: ${resolved}`);
		return resolved;
	}
	sliceContent(content, line, limit) {
		if (line == null && limit == null) return content;
		const lines = content.split("\n");
		const startIndex = Math.max(0, (line == null ? 1 : Math.max(1, Math.trunc(line))) - 1);
		const maxLines = limit == null ? void 0 : Math.max(0, Math.trunc(limit));
		if (maxLines === 0) return "";
		const endIndex = maxLines == null ? lines.length : Math.min(lines.length, startIndex + maxLines);
		return lines.slice(startIndex, endIndex).join("\n");
	}
	readWindowDetails(line, limit) {
		if (line == null && limit == null) return;
		return `line=${line == null ? 1 : Math.max(1, Math.trunc(line))}, limit=${limit == null ? "all" : Math.max(0, Math.trunc(limit))}`;
	}
	emitOperation(operation) {
		this.onOperation?.(operation);
	}
};
//#endregion
//#region src/permissions.ts
const PERMISSION_MODE_RANK = {
	"deny-all": 0,
	"approve-reads": 1,
	"approve-all": 2
};
function selected(optionId) {
	return { outcome: {
		outcome: "selected",
		optionId
	} };
}
function cancelled() {
	return { outcome: { outcome: "cancelled" } };
}
function pickOption(options, kinds) {
	for (const kind of kinds) {
		const match = options.find((option) => option.kind === kind);
		if (match) return match;
	}
}
function inferToolKind(params) {
	if (params.toolCall.kind) return params.toolCall.kind;
	const title = params.toolCall.title?.trim().toLowerCase();
	if (!title) return;
	const head = title.split(":", 1)[0]?.trim();
	if (!head) return;
	if (head.includes("read") || head.includes("cat")) return "read";
	if (head.includes("search") || head.includes("find") || head.includes("grep")) return "search";
	if (head.includes("write") || head.includes("edit") || head.includes("patch")) return "edit";
	if (head.includes("delete") || head.includes("remove")) return "delete";
	if (head.includes("move") || head.includes("rename")) return "move";
	if (head.includes("run") || head.includes("execute") || head.includes("bash")) return "execute";
	if (head.includes("fetch") || head.includes("http") || head.includes("url")) return "fetch";
	if (head.includes("think")) return "think";
	return "other";
}
function isAutoApprovedReadKind(kind) {
	return kind === "read" || kind === "search";
}
async function promptForToolPermission(params) {
	return await promptForPermission({ prompt: `\n[permission] Allow ${params.toolCall.title ?? "tool"} [${inferToolKind(params) ?? "other"}]? (y/N) ` });
}
function canPromptForPermission$1() {
	return Boolean(process.stdin.isTTY && process.stderr.isTTY);
}
function permissionModeSatisfies(actual, required) {
	return PERMISSION_MODE_RANK[actual] >= PERMISSION_MODE_RANK[required];
}
async function resolvePermissionRequest(params, mode, nonInteractivePolicy = "deny") {
	const options = params.options ?? [];
	if (options.length === 0) return cancelled();
	const allowOption = pickOption(options, ["allow_once", "allow_always"]);
	const rejectOption = pickOption(options, ["reject_once", "reject_always"]);
	if (mode === "approve-all") {
		if (allowOption) return selected(allowOption.optionId);
		return selected(options[0].optionId);
	}
	if (mode === "deny-all") {
		if (rejectOption) return selected(rejectOption.optionId);
		return cancelled();
	}
	if (isAutoApprovedReadKind(inferToolKind(params)) && allowOption) return selected(allowOption.optionId);
	if (!canPromptForPermission$1()) {
		if (nonInteractivePolicy === "fail") throw new PermissionPromptUnavailableError();
		if (rejectOption) return selected(rejectOption.optionId);
		return cancelled();
	}
	const approved = await promptForToolPermission(params);
	if (approved && allowOption) return selected(allowOption.optionId);
	if (!approved && rejectOption) return selected(rejectOption.optionId);
	return cancelled();
}
function classifyPermissionDecision(params, response) {
	if (response.outcome.outcome !== "selected") return "cancelled";
	const selectedOptionId = response.outcome.optionId;
	const selectedOption = params.options.find((option) => option.optionId === selectedOptionId);
	if (!selectedOption) return "cancelled";
	if (selectedOption.kind === "allow_once" || selectedOption.kind === "allow_always") return "approved";
	return "denied";
}
//#endregion
//#region src/session-runtime-helpers.ts
var TimeoutError = class extends Error {
	constructor(timeoutMs) {
		super(`Timed out after ${timeoutMs}ms`);
		this.name = "TimeoutError";
	}
};
var InterruptedError = class extends Error {
	constructor() {
		super("Interrupted");
		this.name = "InterruptedError";
	}
};
async function withTimeout(promise, timeoutMs) {
	if (timeoutMs == null || timeoutMs <= 0) return await promise;
	let timer;
	const timeoutPromise = new Promise((_resolve, reject) => {
		timer = setTimeout(() => {
			reject(new TimeoutError(timeoutMs));
		}, timeoutMs);
	});
	try {
		return await Promise.race([promise, timeoutPromise]);
	} finally {
		if (timer) clearTimeout(timer);
	}
}
async function withInterrupt(run, onInterrupt) {
	return await new Promise((resolve, reject) => {
		let settled = false;
		const finish = (cb) => {
			if (settled) return;
			settled = true;
			process.off("SIGINT", onSigint);
			process.off("SIGTERM", onSigterm);
			process.off("SIGHUP", onSighup);
			cb();
		};
		const rejectInterrupted = () => {
			onInterrupt().finally(() => {
				finish(() => reject(new InterruptedError()));
			});
		};
		const onSigint = () => {
			rejectInterrupted();
		};
		const onSigterm = () => {
			rejectInterrupted();
		};
		const onSighup = () => {
			rejectInterrupted();
		};
		process.once("SIGINT", onSigint);
		process.once("SIGTERM", onSigterm);
		process.once("SIGHUP", onSighup);
		run().then((result) => finish(() => resolve(result)), (error) => finish(() => reject(error)));
	});
}
//#endregion
//#region src/spawn-command-options.ts
function readWindowsEnvValue(env, key) {
	const matchedKey = Object.keys(env).find((entry) => entry.toUpperCase() === key);
	return matchedKey ? env[matchedKey] : void 0;
}
function resolveWindowsCommand(command, env = process.env) {
	const extensions = (readWindowsEnvValue(env, "PATHEXT") ?? ".COM;.EXE;.BAT;.CMD").split(";").map((value) => value.trim().toLowerCase()).filter((value) => value.length > 0);
	const candidates = path.extname(command).length > 0 ? [command] : extensions.map((extension) => `${command}${extension}`);
	if (command.includes("/") || command.includes("\\") || path.isAbsolute(command)) return candidates.find((candidate) => fs.existsSync(candidate));
	const pathValue = readWindowsEnvValue(env, "PATH");
	if (!pathValue) return;
	for (const directory of pathValue.split(";")) {
		const trimmedDirectory = directory.trim();
		if (trimmedDirectory.length === 0) continue;
		for (const candidate of candidates) {
			const resolved = path.join(trimmedDirectory, candidate);
			if (fs.existsSync(resolved)) return resolved;
		}
	}
}
function shouldUseWindowsBatchShell(command, platform = process.platform, env = process.env) {
	if (platform !== "win32") return false;
	const resolvedCommand = resolveWindowsCommand(command, env) ?? command;
	const ext = path.extname(resolvedCommand).toLowerCase();
	return ext === ".cmd" || ext === ".bat";
}
function buildSpawnCommandOptions(command, options, platform = process.platform, env = process.env) {
	if (!shouldUseWindowsBatchShell(command, platform, env)) return options;
	return {
		...options,
		shell: true
	};
}
//#endregion
//#region src/terminal.ts
const DEFAULT_TERMINAL_OUTPUT_LIMIT_BYTES = 64 * 1024;
const DEFAULT_KILL_GRACE_MS = 1500;
function nowIso() {
	return (/* @__PURE__ */ new Date()).toISOString();
}
function toCommandLine(command, args) {
	const renderedArgs = (args ?? []).map((arg) => JSON.stringify(arg)).join(" ");
	return renderedArgs.length > 0 ? `${command} ${renderedArgs}` : command;
}
function toEnvObject(env) {
	if (!env || env.length === 0) return;
	const merged = { ...process.env };
	for (const entry of env) merged[entry.name] = entry.value;
	return merged;
}
function buildTerminalSpawnOptions(command, cwd, env, platform = process.platform) {
	const resolvedEnv = toEnvObject(env);
	return buildSpawnCommandOptions(command, {
		cwd,
		env: resolvedEnv,
		stdio: [
			"ignore",
			"pipe",
			"pipe"
		],
		windowsHide: true
	}, platform, resolvedEnv ?? process.env);
}
function trimToUtf8Boundary(buffer, limit) {
	if (limit <= 0) return Buffer.alloc(0);
	if (buffer.length <= limit) return buffer;
	let start = buffer.length - limit;
	while (start < buffer.length && (buffer[start] & 192) === 128) start += 1;
	if (start >= buffer.length) start = buffer.length - limit;
	return buffer.subarray(start);
}
function waitForSpawn$1(process) {
	return new Promise((resolve, reject) => {
		const onSpawn = () => {
			process.off("error", onError);
			resolve();
		};
		const onError = (error) => {
			process.off("spawn", onSpawn);
			reject(error);
		};
		process.once("spawn", onSpawn);
		process.once("error", onError);
	});
}
async function defaultConfirmExecute(commandLine) {
	return await promptForPermission({ prompt: `\n[permission] Allow terminal command "${commandLine}"? (y/N) ` });
}
function canPromptForPermission() {
	return Boolean(process.stdin.isTTY && process.stderr.isTTY);
}
function waitMs(ms) {
	return new Promise((resolve) => {
		setTimeout(resolve, Math.max(0, ms));
	});
}
var TerminalManager = class {
	cwd;
	permissionMode;
	nonInteractivePermissions;
	onOperation;
	usesDefaultConfirmExecute;
	confirmExecute;
	killGraceMs;
	terminals = /* @__PURE__ */ new Map();
	constructor(options) {
		this.cwd = options.cwd;
		this.permissionMode = options.permissionMode;
		this.nonInteractivePermissions = options.nonInteractivePermissions ?? "deny";
		this.onOperation = options.onOperation;
		this.usesDefaultConfirmExecute = options.confirmExecute == null;
		this.confirmExecute = options.confirmExecute ?? defaultConfirmExecute;
		this.killGraceMs = Math.max(0, Math.round(options.killGraceMs ?? DEFAULT_KILL_GRACE_MS));
	}
	updatePermissionPolicy(permissionMode, nonInteractivePermissions) {
		this.permissionMode = permissionMode;
		this.nonInteractivePermissions = nonInteractivePermissions ?? "deny";
	}
	async createTerminal(params) {
		const commandLine = toCommandLine(params.command, params.args);
		const summary = `terminal/create: ${commandLine}`;
		this.emitOperation({
			method: "terminal/create",
			status: "running",
			summary,
			timestamp: nowIso()
		});
		try {
			if (!await this.isExecuteApproved(commandLine)) throw new PermissionDeniedError("Permission denied for terminal/create");
			const outputByteLimit = Math.max(0, Math.round(params.outputByteLimit ?? DEFAULT_TERMINAL_OUTPUT_LIMIT_BYTES));
			const proc = spawn(params.command, params.args ?? [], buildTerminalSpawnOptions(params.command, params.cwd ?? this.cwd, params.env));
			await waitForSpawn$1(proc);
			let resolveExit = () => {};
			const exitPromise = new Promise((resolve) => {
				resolveExit = resolve;
			});
			const terminal = {
				process: proc,
				output: Buffer.alloc(0),
				truncated: false,
				outputByteLimit,
				exitCode: void 0,
				signal: void 0,
				exitPromise,
				resolveExit
			};
			const appendOutput = (chunk) => {
				const bytes = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
				if (bytes.length === 0) return;
				terminal.output = Buffer.concat([terminal.output, bytes]);
				if (terminal.output.length > terminal.outputByteLimit) {
					terminal.output = trimToUtf8Boundary(terminal.output, terminal.outputByteLimit);
					terminal.truncated = true;
				}
			};
			proc.stdout.on("data", appendOutput);
			proc.stderr.on("data", appendOutput);
			proc.once("exit", (exitCode, signal) => {
				terminal.exitCode = exitCode;
				terminal.signal = signal;
				terminal.resolveExit({
					exitCode: exitCode ?? null,
					signal: signal ?? null
				});
			});
			const terminalId = randomUUID();
			this.terminals.set(terminalId, terminal);
			this.emitOperation({
				method: "terminal/create",
				status: "completed",
				summary,
				details: `terminalId=${terminalId}`,
				timestamp: nowIso()
			});
			return { terminalId };
		} catch (error) {
			const message = error instanceof Error ? error.message : String(error);
			this.emitOperation({
				method: "terminal/create",
				status: "failed",
				summary,
				details: message,
				timestamp: nowIso()
			});
			throw error;
		}
	}
	async terminalOutput(params) {
		const terminal = this.getTerminal(params.terminalId);
		if (!terminal) throw new Error(`Unknown terminal: ${params.terminalId}`);
		const hasExitStatus = terminal.exitCode !== void 0 || terminal.signal !== void 0;
		this.emitOperation({
			method: "terminal/output",
			status: "completed",
			summary: `terminal/output: ${params.terminalId}`,
			timestamp: nowIso()
		});
		return {
			output: terminal.output.toString("utf8"),
			truncated: terminal.truncated,
			exitStatus: hasExitStatus ? {
				exitCode: terminal.exitCode ?? null,
				signal: terminal.signal ?? null
			} : void 0
		};
	}
	async waitForTerminalExit(params) {
		const terminal = this.getTerminal(params.terminalId);
		if (!terminal) throw new Error(`Unknown terminal: ${params.terminalId}`);
		const response = await terminal.exitPromise;
		this.emitOperation({
			method: "terminal/wait_for_exit",
			status: "completed",
			summary: `terminal/wait_for_exit: ${params.terminalId}`,
			details: `exitCode=${response.exitCode ?? "null"}, signal=${response.signal ?? "null"}`,
			timestamp: nowIso()
		});
		return response;
	}
	async killTerminal(params) {
		const terminal = this.getTerminal(params.terminalId);
		if (!terminal) throw new Error(`Unknown terminal: ${params.terminalId}`);
		const summary = `terminal/kill: ${params.terminalId}`;
		this.emitOperation({
			method: "terminal/kill",
			status: "running",
			summary,
			timestamp: nowIso()
		});
		try {
			await this.killProcess(terminal);
			this.emitOperation({
				method: "terminal/kill",
				status: "completed",
				summary,
				timestamp: nowIso()
			});
			return {};
		} catch (error) {
			const message = error instanceof Error ? error.message : String(error);
			this.emitOperation({
				method: "terminal/kill",
				status: "failed",
				summary,
				details: message,
				timestamp: nowIso()
			});
			throw error;
		}
	}
	async releaseTerminal(params) {
		const summary = `terminal/release: ${params.terminalId}`;
		this.emitOperation({
			method: "terminal/release",
			status: "running",
			summary,
			timestamp: nowIso()
		});
		const terminal = this.getTerminal(params.terminalId);
		if (!terminal) {
			this.emitOperation({
				method: "terminal/release",
				status: "completed",
				summary,
				details: "already released",
				timestamp: nowIso()
			});
			return {};
		}
		try {
			await this.killProcess(terminal);
			await terminal.exitPromise.catch(() => {});
			terminal.output = Buffer.alloc(0);
			this.terminals.delete(params.terminalId);
			this.emitOperation({
				method: "terminal/release",
				status: "completed",
				summary,
				timestamp: nowIso()
			});
			return {};
		} catch (error) {
			const message = error instanceof Error ? error.message : String(error);
			this.emitOperation({
				method: "terminal/release",
				status: "failed",
				summary,
				details: message,
				timestamp: nowIso()
			});
			throw error;
		}
	}
	async shutdown() {
		for (const terminalId of Array.from(this.terminals.keys())) await this.releaseTerminal({
			terminalId,
			sessionId: "shutdown"
		});
	}
	getTerminal(terminalId) {
		return this.terminals.get(terminalId);
	}
	emitOperation(operation) {
		this.onOperation?.(operation);
	}
	async isExecuteApproved(commandLine) {
		if (this.permissionMode === "approve-all") return true;
		if (this.permissionMode === "deny-all") return false;
		if (this.usesDefaultConfirmExecute && this.nonInteractivePermissions === "fail" && !canPromptForPermission()) throw new PermissionPromptUnavailableError();
		return await this.confirmExecute(commandLine);
	}
	isRunning(terminal) {
		return terminal.exitCode === void 0 && terminal.signal === void 0;
	}
	async killProcess(terminal) {
		if (!this.isRunning(terminal)) return;
		try {
			terminal.process.kill("SIGTERM");
		} catch {
			return;
		}
		if (await Promise.race([terminal.exitPromise.then(() => true), waitMs(this.killGraceMs).then(() => false)]) || !this.isRunning(terminal)) return;
		try {
			terminal.process.kill("SIGKILL");
		} catch {
			return;
		}
		await Promise.race([terminal.exitPromise.then(() => void 0), waitMs(this.killGraceMs)]);
	}
};
//#endregion
//#region src/client.ts
const REPLAY_IDLE_MS = 80;
const REPLAY_DRAIN_TIMEOUT_MS = 5e3;
const DRAIN_POLL_INTERVAL_MS = 20;
const DEFAULT_AGENT_CLOSE_AFTER_STDIN_END_MS = 100;
const QODER_AGENT_CLOSE_AFTER_STDIN_END_MS = 750;
const AGENT_CLOSE_TERM_GRACE_MS = 1500;
const AGENT_CLOSE_KILL_GRACE_MS = 1e3;
const GEMINI_ACP_STARTUP_TIMEOUT_MS = 15e3;
const CLAUDE_ACP_SESSION_CREATE_TIMEOUT_MS = 6e4;
const GEMINI_VERSION_TIMEOUT_MS = 2e3;
const GEMINI_ACP_FLAG_VERSION = [
	0,
	33,
	0
];
const COPILOT_HELP_TIMEOUT_MS = 2e3;
const SESSION_CONTROL_UNSUPPORTED_ACP_CODES = new Set([-32601, -32602]);
const QODER_BENIGN_STDOUT_LINES = new Set(["Received interrupt signal. Cleaning up resources...", "Cleanup completed. Exiting..."]);
function shouldSuppressSdkConsoleError(args) {
	if (args.length === 0) return false;
	return typeof args[0] === "string" && args[0] === "Error handling request";
}
function installSdkConsoleErrorSuppression() {
	const originalConsoleError = console.error;
	console.error = (...args) => {
		if (shouldSuppressSdkConsoleError(args)) return;
		originalConsoleError(...args);
	};
	return () => {
		console.error = originalConsoleError;
	};
}
function isoNow$2() {
	return (/* @__PURE__ */ new Date()).toISOString();
}
function waitForSpawn(child) {
	return new Promise((resolve, reject) => {
		const onSpawn = () => {
			child.off("error", onError);
			resolve();
		};
		const onError = (error) => {
			child.off("spawn", onSpawn);
			reject(error);
		};
		child.once("spawn", onSpawn);
		child.once("error", onError);
	});
}
function isChildProcessRunning(child) {
	return child.exitCode == null && child.signalCode == null;
}
function requireAgentStdio(child) {
	if (!child.stdin || !child.stdout || !child.stderr) throw new Error("ACP agent must be spawned with piped stdin/stdout/stderr");
	return child;
}
function waitForChildExit(child, timeoutMs) {
	if (!isChildProcessRunning(child)) return Promise.resolve(true);
	return new Promise((resolve) => {
		let settled = false;
		const timer = setTimeout(() => {
			finish(false);
		}, Math.max(0, timeoutMs));
		const finish = (value) => {
			if (settled) return;
			settled = true;
			child.off("close", onExitLike);
			child.off("exit", onExitLike);
			clearTimeout(timer);
			resolve(value);
		};
		const onExitLike = () => {
			finish(true);
		};
		child.once("close", onExitLike);
		child.once("exit", onExitLike);
	});
}
function splitCommandLine(value) {
	const parts = [];
	let current = "";
	let quote = null;
	let escaping = false;
	for (const ch of value) {
		if (escaping) {
			current += ch;
			escaping = false;
			continue;
		}
		if (ch === "\\" && quote !== "'") {
			escaping = true;
			continue;
		}
		if (quote) {
			if (ch === quote) quote = null;
			else current += ch;
			continue;
		}
		if (ch === "'" || ch === "\"") {
			quote = ch;
			continue;
		}
		if (/\s/.test(ch)) {
			if (current.length > 0) {
				parts.push(current);
				current = "";
			}
			continue;
		}
		current += ch;
	}
	if (escaping) current += "\\";
	if (quote) throw new Error("Invalid --agent command: unterminated quote");
	if (current.length > 0) parts.push(current);
	if (parts.length === 0) throw new Error("Invalid --agent command: empty command");
	return {
		command: parts[0],
		args: parts.slice(1)
	};
}
function asAbsoluteCwd(cwd) {
	return path.resolve(cwd);
}
function basenameToken(value) {
	return path.basename(value).toLowerCase().replace(/\.(cmd|exe|bat)$/u, "");
}
function resolveAgentCloseAfterStdinEndMs(agentCommand) {
	const { command } = splitCommandLine(agentCommand);
	return basenameToken(command) === "qodercli" ? QODER_AGENT_CLOSE_AFTER_STDIN_END_MS : DEFAULT_AGENT_CLOSE_AFTER_STDIN_END_MS;
}
function shouldIgnoreNonJsonAgentOutputLine(agentCommand, trimmedLine) {
	const { command } = splitCommandLine(agentCommand);
	return basenameToken(command) === "qodercli" && QODER_BENIGN_STDOUT_LINES.has(trimmedLine);
}
function createNdJsonMessageStream(agentCommand, output, input) {
	const textEncoder = new TextEncoder();
	const textDecoder = new TextDecoder();
	return {
		readable: new ReadableStream({ async start(controller) {
			let content = "";
			const reader = input.getReader();
			try {
				while (true) {
					const { value, done } = await reader.read();
					if (done) break;
					if (!value) continue;
					content += textDecoder.decode(value, { stream: true });
					const lines = content.split("\n");
					content = lines.pop() || "";
					for (const line of lines) {
						const trimmedLine = line.trim();
						if (!trimmedLine || shouldIgnoreNonJsonAgentOutputLine(agentCommand, trimmedLine)) continue;
						try {
							const message = JSON.parse(trimmedLine);
							controller.enqueue(message);
						} catch (err) {
							console.error("Failed to parse JSON message:", trimmedLine, err);
						}
					}
				}
			} finally {
				reader.releaseLock();
				controller.close();
			}
		} }),
		writable: new WritableStream({ async write(message) {
			const content = JSON.stringify(message) + "\n";
			const writer = output.getWriter();
			try {
				await writer.write(textEncoder.encode(content));
			} finally {
				writer.releaseLock();
			}
		} })
	};
}
function isGeminiAcpCommand(command, args) {
	return basenameToken(command) === "gemini" && (args.includes("--acp") || args.includes("--experimental-acp"));
}
function isClaudeAcpCommand(command, args) {
	if (basenameToken(command) === "claude-agent-acp") return true;
	return args.some((arg) => arg.includes("claude-agent-acp"));
}
function isCopilotAcpCommand(command, args) {
	return basenameToken(command) === "copilot" && args.includes("--acp");
}
function isQoderAcpCommand(command, args) {
	return basenameToken(command) === "qodercli" && args.includes("--acp");
}
function hasCommandFlag(args, flagName) {
	return args.some((arg) => arg === flagName || arg.startsWith(`${flagName}=`));
}
function normalizeQoderAllowedToolName(tool) {
	switch (tool.trim().toLowerCase()) {
		case "bash":
		case "glob":
		case "grep":
		case "ls":
		case "read":
		case "write": return tool.trim().toUpperCase();
		default: return tool.trim();
	}
}
function buildQoderAcpCommandArgs(initialArgs, options) {
	const args = [...initialArgs];
	const sessionOptions = options.sessionOptions;
	if (typeof sessionOptions?.maxTurns === "number" && !hasCommandFlag(args, "--max-turns")) args.push(`--max-turns=${sessionOptions.maxTurns}`);
	if (Array.isArray(sessionOptions?.allowedTools) && !hasCommandFlag(args, "--allowed-tools") && !hasCommandFlag(args, "--disallowed-tools")) {
		const encodedTools = sessionOptions.allowedTools.map(normalizeQoderAllowedToolName).join(",");
		args.push(`--allowed-tools=${encodedTools}`);
	}
	return args;
}
function resolveGeminiAcpStartupTimeoutMs() {
	const raw = process.env.ACPX_GEMINI_ACP_STARTUP_TIMEOUT_MS;
	if (typeof raw === "string" && raw.trim().length > 0) {
		const parsed = Number(raw);
		if (Number.isFinite(parsed) && parsed > 0) return Math.round(parsed);
	}
	return GEMINI_ACP_STARTUP_TIMEOUT_MS;
}
function resolveClaudeAcpSessionCreateTimeoutMs() {
	const raw = process.env.ACPX_CLAUDE_ACP_SESSION_CREATE_TIMEOUT_MS;
	if (typeof raw === "string" && raw.trim().length > 0) {
		const parsed = Number(raw);
		if (Number.isFinite(parsed) && parsed > 0) return Math.round(parsed);
	}
	return CLAUDE_ACP_SESSION_CREATE_TIMEOUT_MS;
}
function parseGeminiVersion(value) {
	if (typeof value !== "string") return;
	const normalized = value.trim();
	const match = normalized.match(/(\d+)\.(\d+)\.(\d+)/);
	if (!match) return;
	return {
		raw: normalized,
		parts: [
			Number(match[1]),
			Number(match[2]),
			Number(match[3])
		]
	};
}
function compareVersionParts(left, right) {
	for (let index = 0; index < Math.max(left.length, right.length); index += 1) {
		const leftPart = left[index] ?? 0;
		const rightPart = right[index] ?? 0;
		if (leftPart !== rightPart) return leftPart - rightPart;
	}
	return 0;
}
async function detectGeminiVersion(command) {
	return await new Promise((resolve) => {
		const child = spawn(command, ["--version"], buildSpawnCommandOptions(command, {
			stdio: [
				"ignore",
				"pipe",
				"pipe"
			],
			windowsHide: true
		}));
		let stdout = "";
		let stderr = "";
		let settled = false;
		const finish = (value) => {
			if (settled) return;
			settled = true;
			clearTimeout(timer);
			child.removeAllListeners();
			child.stdout?.removeAllListeners();
			child.stderr?.removeAllListeners();
			resolve(value);
		};
		const timer = setTimeout(() => {
			child.kill("SIGKILL");
			finish(void 0);
		}, GEMINI_VERSION_TIMEOUT_MS);
		child.stdout?.setEncoding("utf8");
		child.stderr?.setEncoding("utf8");
		child.stdout?.on("data", (chunk) => {
			stdout += chunk;
		});
		child.stderr?.on("data", (chunk) => {
			stderr += chunk;
		});
		child.once("error", () => {
			finish(void 0);
		});
		child.once("close", () => {
			finish(parseGeminiVersion(`${stdout}\n${stderr}`.split(/\r?\n/).map((line) => line.trim()).find((line) => /\d+\.\d+\.\d+/.test(line))));
		});
	});
}
async function resolveGeminiCommandArgs(command, args) {
	if (basenameToken(command) !== "gemini" || !args.includes("--acp")) return [...args];
	const version = await detectGeminiVersion(command);
	if (version && compareVersionParts(version.parts, GEMINI_ACP_FLAG_VERSION) < 0) return args.map((arg) => arg === "--acp" ? "--experimental-acp" : arg);
	return [...args];
}
async function readCommandOutput(command, args, timeoutMs) {
	return await new Promise((resolve) => {
		const child = spawn(command, [...args], buildSpawnCommandOptions(command, {
			stdio: [
				"ignore",
				"pipe",
				"pipe"
			],
			windowsHide: true
		}));
		let stdout = "";
		let stderr = "";
		let settled = false;
		const finish = (value) => {
			if (settled) return;
			settled = true;
			clearTimeout(timer);
			child.removeAllListeners();
			child.stdout?.removeAllListeners();
			child.stderr?.removeAllListeners();
			resolve(value);
		};
		const timer = setTimeout(() => {
			child.kill("SIGKILL");
			finish(void 0);
		}, timeoutMs);
		child.stdout?.setEncoding("utf8");
		child.stderr?.setEncoding("utf8");
		child.stdout?.on("data", (chunk) => {
			stdout += chunk;
		});
		child.stderr?.on("data", (chunk) => {
			stderr += chunk;
		});
		child.once("error", () => {
			finish(void 0);
		});
		child.once("close", () => {
			finish(`${stdout}\n${stderr}`);
		});
	});
}
async function buildGeminiAcpStartupTimeoutMessage(command) {
	const parts = ["Gemini CLI ACP startup timed out before initialize completed.", "This usually means the local Gemini CLI is waiting on interactive OAuth or has incompatible ACP subprocess behavior."];
	const version = await detectGeminiVersion(command);
	if (version) parts.push(`Detected Gemini CLI version: ${version.raw}.`);
	if (!process.env.GEMINI_API_KEY && !process.env.GOOGLE_API_KEY) parts.push("No GEMINI_API_KEY or GOOGLE_API_KEY was set for non-interactive auth.");
	parts.push("Try upgrading Gemini CLI and using API-key-based auth for non-interactive ACP runs.");
	return parts.join(" ");
}
function buildClaudeAcpSessionCreateTimeoutMessage() {
	return [
		"Claude ACP session creation timed out before session/new completed.",
		"This matches the known persistent-session stall seen with some Claude Code and @agentclientprotocol/claude-agent-acp combinations.",
		"In harnessed or non-interactive runs, prefer --approve-all with nonInteractivePermissions=deny, upgrade Claude Code and the Claude ACP adapter, or use acpx claude exec as a one-shot fallback."
	].join(" ");
}
async function buildCopilotAcpUnsupportedMessage(command) {
	const parts = ["GitHub Copilot CLI ACP stdio mode is not available in the installed copilot binary.", "acpx copilot expects a Copilot CLI release that supports --acp --stdio."];
	const helpOutput = await readCommandOutput(command, ["--help"], COPILOT_HELP_TIMEOUT_MS);
	if (typeof helpOutput === "string" && !helpOutput.includes("--acp")) parts.push("Detected copilot --help output without --acp support.");
	parts.push("Upgrade GitHub Copilot CLI to a release with ACP stdio support, or use --agent with another ACP-compatible adapter in the meantime.");
	return parts.join(" ");
}
async function ensureCopilotAcpSupport(command) {
	const helpOutput = await readCommandOutput(command, ["--help"], COPILOT_HELP_TIMEOUT_MS);
	if (typeof helpOutput === "string" && !helpOutput.includes("--acp")) throw new CopilotAcpUnsupportedError(await buildCopilotAcpUnsupportedMessage(command), { retryable: false });
}
function toEnvToken(value) {
	return value.trim().replace(/[^a-zA-Z0-9]+/g, "_").replace(/^_+|_+$/g, "").toUpperCase();
}
function buildAuthEnvKeys(methodId) {
	const token = toEnvToken(methodId);
	const keys = new Set([methodId]);
	if (token) {
		keys.add(token);
		keys.add(`ACPX_AUTH_${token}`);
	}
	return [...keys];
}
const authEnvKeysCache = /* @__PURE__ */ new Map();
function authEnvKeys(methodId) {
	const cached = authEnvKeysCache.get(methodId);
	if (cached) return cached;
	const keys = buildAuthEnvKeys(methodId);
	authEnvKeysCache.set(methodId, keys);
	return keys;
}
function readEnvCredential(methodId) {
	for (const key of authEnvKeys(methodId)) {
		const value = process.env[key];
		if (typeof value === "string" && value.trim().length > 0) return value;
	}
}
function buildClaudeCodeOptionsMeta(options) {
	if (!options) return;
	const claudeCodeOptions = {};
	if (typeof options.model === "string" && options.model.trim().length > 0) claudeCodeOptions.model = options.model;
	if (Array.isArray(options.allowedTools)) claudeCodeOptions.allowedTools = [...options.allowedTools];
	if (typeof options.maxTurns === "number") claudeCodeOptions.maxTurns = options.maxTurns;
	if (Object.keys(claudeCodeOptions).length === 0) return;
	return { claudeCode: { options: claudeCodeOptions } };
}
function asRecord$3(value) {
	if (!value || typeof value !== "object" || Array.isArray(value)) return;
	return value;
}
function isLikelySessionControlUnsupportedError(acp) {
	if (SESSION_CONTROL_UNSUPPORTED_ACP_CODES.has(acp.code)) return true;
	if (acp.code !== -32603) return false;
	const details = asRecord$3(acp.data)?.details;
	return typeof details === "string" && details.toLowerCase().includes("invalid params");
}
function formatSessionControlAcpSummary(acp) {
	const details = asRecord$3(acp.data)?.details;
	if (typeof details === "string" && details.trim().length > 0) return `${details.trim()} (ACP ${acp.code}, adapter reported "${acp.message}")`;
	return `${acp.message} (ACP ${acp.code})`;
}
function maybeWrapSessionControlError(method, error, context) {
	const acp = extractAcpError(error);
	if (!acp || !isLikelySessionControlUnsupportedError(acp)) return error;
	const acpSummary = formatSessionControlAcpSummary(acp);
	const message = `Agent rejected ${method}${context ? ` ${context}` : ""}: ${acpSummary}. The adapter may not implement ${method}, or the requested value is not supported.`;
	const wrapped = new Error(message, { cause: error instanceof Error ? error : void 0 });
	wrapped.acp = acp;
	return wrapped;
}
function buildAgentEnvironment(authCredentials) {
	const env = { ...process.env };
	if (!authCredentials) return env;
	for (const [methodId, credential] of Object.entries(authCredentials)) {
		if (typeof credential !== "string" || credential.trim().length === 0) continue;
		if (!methodId.includes("=") && !methodId.includes("\0") && env[methodId] == null) env[methodId] = credential;
		const normalized = toEnvToken(methodId);
		if (normalized) {
			const prefixed = `ACPX_AUTH_${normalized}`;
			if (env[prefixed] == null) env[prefixed] = credential;
			if (env[normalized] == null) env[normalized] = credential;
		}
	}
	return env;
}
function buildAgentSpawnOptions(cwd, authCredentials) {
	return {
		cwd,
		env: buildAgentEnvironment(authCredentials),
		stdio: [
			"pipe",
			"pipe",
			"pipe"
		],
		windowsHide: true
	};
}
var AcpClient = class {
	options;
	connection;
	agent;
	initResult;
	loadedSessionId;
	eventHandlers;
	permissionStats = {
		requested: 0,
		approved: 0,
		denied: 0,
		cancelled: 0
	};
	filesystem;
	terminalManager;
	sessionUpdateChain = Promise.resolve();
	observedSessionUpdates = 0;
	processedSessionUpdates = 0;
	suppressSessionUpdates = false;
	suppressReplaySessionUpdateMessages = false;
	activePrompt;
	cancellingSessionIds = /* @__PURE__ */ new Set();
	closing = false;
	agentStartedAt;
	lastAgentExit;
	lastKnownPid;
	promptPermissionFailures = /* @__PURE__ */ new Map();
	pendingConnectionRequests = /* @__PURE__ */ new Set();
	constructor(options) {
		this.options = {
			...options,
			cwd: asAbsoluteCwd(options.cwd),
			authPolicy: options.authPolicy ?? "skip"
		};
		this.eventHandlers = {
			onAcpMessage: this.options.onAcpMessage,
			onAcpOutputMessage: this.options.onAcpOutputMessage,
			onSessionUpdate: this.options.onSessionUpdate,
			onClientOperation: this.options.onClientOperation
		};
		this.filesystem = new FileSystemHandlers({
			cwd: this.options.cwd,
			permissionMode: this.options.permissionMode,
			nonInteractivePermissions: this.options.nonInteractivePermissions,
			onOperation: (operation) => {
				this.eventHandlers.onClientOperation?.(operation);
			}
		});
		this.terminalManager = new TerminalManager({
			cwd: this.options.cwd,
			permissionMode: this.options.permissionMode,
			nonInteractivePermissions: this.options.nonInteractivePermissions,
			onOperation: (operation) => {
				this.eventHandlers.onClientOperation?.(operation);
			}
		});
	}
	get initializeResult() {
		return this.initResult;
	}
	getAgentPid() {
		return this.agent?.pid ?? this.lastKnownPid;
	}
	getPermissionStats() {
		return { ...this.permissionStats };
	}
	getAgentLifecycleSnapshot() {
		const pid = this.agent?.pid ?? this.lastKnownPid;
		const running = Boolean(this.agent) && this.agent?.exitCode == null && this.agent?.signalCode == null && !this.agent?.killed;
		return {
			pid,
			startedAt: this.agentStartedAt,
			running,
			lastExit: this.lastAgentExit ? { ...this.lastAgentExit } : void 0
		};
	}
	supportsLoadSession() {
		return Boolean(this.initResult?.agentCapabilities?.loadSession);
	}
	setEventHandlers(handlers) {
		this.eventHandlers = { ...handlers };
	}
	clearEventHandlers() {
		this.eventHandlers = {};
	}
	updateRuntimeOptions(options) {
		if (options.permissionMode) this.options.permissionMode = options.permissionMode;
		if (options.nonInteractivePermissions !== void 0) this.options.nonInteractivePermissions = options.nonInteractivePermissions;
		if (options.permissionMode || options.nonInteractivePermissions !== void 0) {
			this.filesystem.updatePermissionPolicy(this.options.permissionMode, this.options.nonInteractivePermissions);
			this.terminalManager.updatePermissionPolicy(this.options.permissionMode, this.options.nonInteractivePermissions);
		}
		if (options.suppressSdkConsoleErrors !== void 0) this.options.suppressSdkConsoleErrors = options.suppressSdkConsoleErrors;
		if (options.verbose !== void 0) this.options.verbose = options.verbose;
	}
	hasReusableSession(sessionId) {
		return this.connection != null && this.agent != null && isChildProcessRunning(this.agent) && this.loadedSessionId === sessionId;
	}
	hasActivePrompt(sessionId) {
		if (!this.activePrompt) return false;
		if (sessionId == null) return true;
		return this.activePrompt.sessionId === sessionId;
	}
	async start() {
		if (this.connection && this.agent && isChildProcessRunning(this.agent)) return;
		if (this.connection || this.agent) await this.close();
		const { command, args: initialArgs } = splitCommandLine(this.options.agentCommand);
		let args = await resolveGeminiCommandArgs(command, initialArgs);
		if (isQoderAcpCommand(command, args)) args = buildQoderAcpCommandArgs(args, this.options);
		this.log(`spawning agent: ${command} ${args.join(" ")}`);
		const geminiAcp = isGeminiAcpCommand(command, args);
		if (isCopilotAcpCommand(command, args)) await ensureCopilotAcpSupport(command);
		const spawnedChild = spawn(command, args, buildSpawnCommandOptions(command, buildAgentSpawnOptions(this.options.cwd, this.options.authCredentials)));
		try {
			await waitForSpawn(spawnedChild);
		} catch (error) {
			throw new AgentSpawnError(this.options.agentCommand, error);
		}
		const child = requireAgentStdio(spawnedChild);
		this.closing = false;
		this.agentStartedAt = isoNow$2();
		this.lastAgentExit = void 0;
		this.lastKnownPid = child.pid ?? void 0;
		this.attachAgentLifecycleObservers(child);
		child.stderr.on("data", (chunk) => {
			if (!this.options.verbose) return;
			process.stderr.write(chunk);
		});
		const input = Writable.toWeb(child.stdin);
		const output = Readable.toWeb(child.stdout);
		const connection = new ClientSideConnection(() => ({
			sessionUpdate: async (params) => {
				await this.handleSessionUpdate(params);
			},
			requestPermission: async (params) => {
				return this.handlePermissionRequest(params);
			},
			readTextFile: async (params) => {
				return this.handleReadTextFile(params);
			},
			writeTextFile: async (params) => {
				return this.handleWriteTextFile(params);
			},
			createTerminal: async (params) => {
				return this.handleCreateTerminal(params);
			},
			terminalOutput: async (params) => {
				return this.handleTerminalOutput(params);
			},
			waitForTerminalExit: async (params) => {
				return this.handleWaitForTerminalExit(params);
			},
			killTerminal: async (params) => {
				return this.handleKillTerminal(params);
			},
			releaseTerminal: async (params) => {
				return this.handleReleaseTerminal(params);
			}
		}), this.createTappedStream(createNdJsonMessageStream(this.options.agentCommand, input, output)));
		connection.signal.addEventListener("abort", () => {
			this.recordAgentExit("connection_close", child.exitCode ?? null, child.signalCode ?? null);
		}, { once: true });
		try {
			const initializePromise = connection.initialize({
				protocolVersion: PROTOCOL_VERSION,
				clientCapabilities: {
					fs: {
						readTextFile: true,
						writeTextFile: true
					},
					terminal: true
				},
				clientInfo: {
					name: "acpx",
					version: "0.1.0"
				}
			});
			const initResult = geminiAcp ? await withTimeout(initializePromise, resolveGeminiAcpStartupTimeoutMs()) : await initializePromise;
			await this.authenticateIfRequired(connection, initResult.authMethods ?? []);
			this.connection = connection;
			this.agent = child;
			this.initResult = initResult;
			this.log(`initialized protocol version ${initResult.protocolVersion}`);
		} catch (error) {
			child.kill();
			if (geminiAcp && error instanceof TimeoutError) throw new GeminiAcpStartupTimeoutError(await buildGeminiAcpStartupTimeoutMessage(command), {
				cause: error,
				retryable: true
			});
			throw error;
		}
	}
	createTappedStream(base) {
		const onAcpMessage = () => this.eventHandlers.onAcpMessage;
		const onAcpOutputMessage = () => this.eventHandlers.onAcpOutputMessage;
		const shouldSuppressInboundReplaySessionUpdate = (message) => {
			return this.suppressReplaySessionUpdateMessages && isSessionUpdateNotification(message);
		};
		return {
			readable: new ReadableStream({ async start(controller) {
				const reader = base.readable.getReader();
				try {
					while (true) {
						const { value, done } = await reader.read();
						if (done) break;
						if (!value) continue;
						if (!shouldSuppressInboundReplaySessionUpdate(value)) {
							onAcpOutputMessage()?.("inbound", value);
							onAcpMessage()?.("inbound", value);
						}
						controller.enqueue(value);
					}
				} finally {
					reader.releaseLock();
					controller.close();
				}
			} }),
			writable: new WritableStream({ async write(message) {
				onAcpOutputMessage()?.("outbound", message);
				onAcpMessage()?.("outbound", message);
				const writer = base.writable.getWriter();
				try {
					await writer.write(message);
				} finally {
					writer.releaseLock();
				}
			} })
		};
	}
	async createSession(cwd = this.options.cwd) {
		const connection = this.getConnection();
		const { command, args } = splitCommandLine(this.options.agentCommand);
		const claudeAcp = isClaudeAcpCommand(command, args);
		let result;
		try {
			const createPromise = this.runConnectionRequest(() => connection.newSession({
				cwd: asAbsoluteCwd(cwd),
				mcpServers: this.options.mcpServers ?? [],
				_meta: buildClaudeCodeOptionsMeta(this.options.sessionOptions)
			}));
			result = claudeAcp ? await withTimeout(createPromise, resolveClaudeAcpSessionCreateTimeoutMs()) : await createPromise;
		} catch (error) {
			if (claudeAcp && error instanceof TimeoutError) throw new ClaudeAcpSessionCreateTimeoutError(buildClaudeAcpSessionCreateTimeoutMessage(), {
				cause: error,
				retryable: true
			});
			throw error;
		}
		this.loadedSessionId = result.sessionId;
		return {
			sessionId: result.sessionId,
			agentSessionId: extractRuntimeSessionId(result._meta),
			models: result.models ?? void 0
		};
	}
	async loadSession(sessionId, cwd = this.options.cwd) {
		this.getConnection();
		return await this.loadSessionWithOptions(sessionId, cwd, {});
	}
	async loadSessionWithOptions(sessionId, cwd = this.options.cwd, options = {}) {
		const connection = this.getConnection();
		const previousSuppression = this.suppressSessionUpdates;
		const previousReplaySuppression = this.suppressReplaySessionUpdateMessages;
		this.suppressSessionUpdates = previousSuppression || Boolean(options.suppressReplayUpdates);
		this.suppressReplaySessionUpdateMessages = previousReplaySuppression || Boolean(options.suppressReplayUpdates);
		let response;
		try {
			response = await this.runConnectionRequest(() => connection.loadSession({
				sessionId,
				cwd: asAbsoluteCwd(cwd),
				mcpServers: this.options.mcpServers ?? []
			}));
			await this.waitForSessionUpdateDrain(options.replayIdleMs ?? REPLAY_IDLE_MS, options.replayDrainTimeoutMs ?? REPLAY_DRAIN_TIMEOUT_MS);
		} finally {
			this.suppressSessionUpdates = previousSuppression;
			this.suppressReplaySessionUpdateMessages = previousReplaySuppression;
		}
		this.loadedSessionId = sessionId;
		return {
			agentSessionId: extractRuntimeSessionId(response?._meta),
			models: response?.models ?? void 0
		};
	}
	async prompt(sessionId, prompt) {
		const connection = this.getConnection();
		const restoreConsoleError = this.options.suppressSdkConsoleErrors ? installSdkConsoleErrorSuppression() : void 0;
		let promptPromise;
		try {
			promptPromise = this.runConnectionRequest(() => connection.prompt({
				sessionId,
				prompt: typeof prompt === "string" ? textPrompt(prompt) : prompt
			}));
		} catch (error) {
			restoreConsoleError?.();
			throw error;
		}
		this.activePrompt = {
			sessionId,
			promise: promptPromise
		};
		try {
			const response = await promptPromise;
			const permissionFailure = this.consumePromptPermissionFailure(sessionId);
			if (permissionFailure) throw permissionFailure;
			return response;
		} catch (error) {
			const permissionFailure = this.consumePromptPermissionFailure(sessionId);
			if (permissionFailure) throw permissionFailure;
			throw error;
		} finally {
			restoreConsoleError?.();
			if (this.activePrompt?.promise === promptPromise) this.activePrompt = void 0;
			this.cancellingSessionIds.delete(sessionId);
			this.promptPermissionFailures.delete(sessionId);
		}
	}
	async setSessionMode(sessionId, modeId) {
		const connection = this.getConnection();
		try {
			await this.runConnectionRequest(() => connection.setSessionMode({
				sessionId,
				modeId
			}));
		} catch (error) {
			throw maybeWrapSessionControlError("session/set_mode", error, `for mode "${modeId}"`);
		}
	}
	async setSessionConfigOption(sessionId, configId, value) {
		const connection = this.getConnection();
		try {
			return await this.runConnectionRequest(() => connection.setSessionConfigOption({
				sessionId,
				configId,
				value
			}));
		} catch (error) {
			throw maybeWrapSessionControlError("session/set_config_option", error, `for "${configId}"="${value}"`);
		}
	}
	async setSessionModel(sessionId, modelId) {
		const connection = this.getConnection();
		try {
			await this.runConnectionRequest(() => connection.unstable_setSessionModel({
				sessionId,
				modelId
			}));
		} catch (error) {
			const wrapped = maybeWrapSessionControlError("session/set_model", error, `for model "${modelId}"`);
			if (wrapped !== error) throw wrapped;
			const acp = extractAcpError(error);
			const summary = acp ? formatSessionControlAcpSummary(acp) : error instanceof Error ? error.message : String(error);
			if (error instanceof Error) throw new Error(`Failed session/set_model for model "${modelId}": ${summary}`, { cause: error });
			throw new Error(`Failed session/set_model for model "${modelId}": ${summary}`, { cause: error });
		}
	}
	async cancel(sessionId) {
		const connection = this.getConnection();
		this.cancellingSessionIds.add(sessionId);
		await this.runConnectionRequest(() => connection.cancel({ sessionId }));
	}
	async requestCancelActivePrompt() {
		const active = this.activePrompt;
		if (!active) return false;
		await this.cancel(active.sessionId);
		return true;
	}
	async cancelActivePrompt(waitMs = 2500) {
		const active = this.activePrompt;
		if (!active) return;
		try {
			await this.cancel(active.sessionId);
		} catch (error) {
			const message = error instanceof Error ? error.message : String(error);
			this.log(`failed to send session/cancel: ${message}`);
		}
		if (waitMs <= 0) return;
		let timer;
		const timeoutPromise = new Promise((resolve) => {
			timer = setTimeout(resolve, waitMs);
		});
		try {
			return await Promise.race([active.promise.then((response) => response, () => void 0), timeoutPromise]);
		} finally {
			if (timer) clearTimeout(timer);
		}
	}
	async close() {
		this.closing = true;
		await this.terminalManager.shutdown();
		const agent = this.agent;
		if (agent) await this.terminateAgentProcess(agent);
		if (this.pendingConnectionRequests.size > 0) this.rejectPendingConnectionRequests(this.lastAgentExit ? new AgentDisconnectedError(this.lastAgentExit.reason, this.lastAgentExit.exitCode, this.lastAgentExit.signal, { outputAlreadyEmitted: Boolean(this.activePrompt) }) : new AgentDisconnectedError("connection_close", null, null, { outputAlreadyEmitted: Boolean(this.activePrompt) }));
		this.sessionUpdateChain = Promise.resolve();
		this.observedSessionUpdates = 0;
		this.processedSessionUpdates = 0;
		this.suppressSessionUpdates = false;
		this.suppressReplaySessionUpdateMessages = false;
		this.activePrompt = void 0;
		this.cancellingSessionIds.clear();
		this.promptPermissionFailures.clear();
		this.loadedSessionId = void 0;
		this.initResult = void 0;
		this.connection = void 0;
		this.agent = void 0;
	}
	async terminateAgentProcess(child) {
		const stdinCloseGraceMs = resolveAgentCloseAfterStdinEndMs(this.options.agentCommand);
		if (!child.stdin.destroyed) try {
			child.stdin.end();
		} catch {}
		let exited = await waitForChildExit(child, stdinCloseGraceMs);
		if (!exited && isChildProcessRunning(child)) {
			try {
				child.kill("SIGTERM");
			} catch {}
			exited = await waitForChildExit(child, AGENT_CLOSE_TERM_GRACE_MS);
		}
		if (!exited && isChildProcessRunning(child)) {
			this.log(`agent did not exit after ${AGENT_CLOSE_TERM_GRACE_MS}ms; forcing SIGKILL`);
			try {
				child.kill("SIGKILL");
			} catch {}
			exited = await waitForChildExit(child, AGENT_CLOSE_KILL_GRACE_MS);
		}
		this.detachAgentHandles(child, !exited);
	}
	detachAgentHandles(agent, unref) {
		const stdin = agent.stdin;
		const stdout = agent.stdout;
		const stderr = agent.stderr;
		stdin?.destroy();
		stdout?.destroy();
		stderr?.destroy();
		if (unref) try {
			agent.unref();
		} catch {}
	}
	getConnection() {
		if (!this.connection) throw new Error("ACP client not started");
		return this.connection;
	}
	log(message) {
		if (!this.options.verbose) return;
		process.stderr.write(`[acpx] ${message}\n`);
	}
	selectAuthMethod(methods) {
		const configCredentials = this.options.authCredentials ?? {};
		for (const method of methods) {
			const envCredential = readEnvCredential(method.id);
			if (envCredential) return {
				methodId: method.id,
				credential: envCredential,
				source: "env"
			};
			const configCredential = configCredentials[method.id] ?? configCredentials[toEnvToken(method.id)];
			if (typeof configCredential === "string" && configCredential.trim().length > 0) return {
				methodId: method.id,
				credential: configCredential,
				source: "config"
			};
		}
	}
	async authenticateIfRequired(connection, methods) {
		if (methods.length === 0) return;
		const selected = this.selectAuthMethod(methods);
		if (!selected) {
			if (this.options.authPolicy === "fail") throw new AuthPolicyError(`agent advertised auth methods [${methods.map((m) => m.id).join(", ")}] but no matching credentials found`);
			this.log(`agent advertised auth methods [${methods.map((m) => m.id).join(", ")}] but no matching credentials found — skipping (agent may handle auth internally)`);
			return;
		}
		await connection.authenticate({ methodId: selected.methodId });
		this.log(`authenticated with method ${selected.methodId} (${selected.source})`);
	}
	async handlePermissionRequest(params) {
		if (this.cancellingSessionIds.has(params.sessionId)) return { outcome: { outcome: "cancelled" } };
		let response;
		try {
			response = await resolvePermissionRequest(params, this.options.permissionMode, this.options.nonInteractivePermissions ?? "deny");
		} catch (error) {
			if (error instanceof PermissionPromptUnavailableError) {
				this.notePromptPermissionFailure(params.sessionId, error);
				this.recordPermissionDecision("cancelled");
				return { outcome: { outcome: "cancelled" } };
			}
			throw error;
		}
		const decision = classifyPermissionDecision(params, response);
		this.recordPermissionDecision(decision);
		return response;
	}
	attachAgentLifecycleObservers(child) {
		child.once("exit", (exitCode, signal) => {
			this.recordAgentExit("process_exit", exitCode, signal);
		});
		child.once("close", (exitCode, signal) => {
			this.recordAgentExit("process_close", exitCode, signal);
		});
		child.stdout.once("close", () => {
			this.recordAgentExit("pipe_close", child.exitCode ?? null, child.signalCode ?? null);
		});
	}
	recordAgentExit(reason, exitCode, signal) {
		if (this.lastAgentExit) return;
		this.lastAgentExit = {
			exitCode,
			signal,
			exitedAt: isoNow$2(),
			reason,
			unexpectedDuringPrompt: !this.closing && Boolean(this.activePrompt)
		};
		this.rejectPendingConnectionRequests(new AgentDisconnectedError(reason, exitCode, signal, { outputAlreadyEmitted: Boolean(this.activePrompt) }));
	}
	notePromptPermissionFailure(sessionId, error) {
		if (!this.promptPermissionFailures.has(sessionId)) this.promptPermissionFailures.set(sessionId, error);
	}
	consumePromptPermissionFailure(sessionId) {
		const error = this.promptPermissionFailures.get(sessionId);
		if (error) this.promptPermissionFailures.delete(sessionId);
		return error;
	}
	async runConnectionRequest(run) {
		return await new Promise((resolve, reject) => {
			const pending = {
				settled: false,
				reject
			};
			const finish = (cb) => {
				if (pending.settled) return;
				pending.settled = true;
				this.pendingConnectionRequests.delete(pending);
				cb();
			};
			this.pendingConnectionRequests.add(pending);
			Promise.resolve().then(run).then((value) => finish(() => resolve(value)), (error) => finish(() => reject(error)));
		});
	}
	rejectPendingConnectionRequests(error) {
		for (const pending of this.pendingConnectionRequests) {
			if (pending.settled) {
				this.pendingConnectionRequests.delete(pending);
				continue;
			}
			pending.settled = true;
			this.pendingConnectionRequests.delete(pending);
			pending.reject(error);
		}
	}
	async handleReadTextFile(params) {
		try {
			return await this.filesystem.readTextFile(params);
		} catch (error) {
			this.recordPermissionError(params.sessionId, error);
			throw error;
		}
	}
	async handleWriteTextFile(params) {
		try {
			return await this.filesystem.writeTextFile(params);
		} catch (error) {
			this.recordPermissionError(params.sessionId, error);
			throw error;
		}
	}
	async handleCreateTerminal(params) {
		try {
			return await this.terminalManager.createTerminal(params);
		} catch (error) {
			this.recordPermissionError(params.sessionId, error);
			throw error;
		}
	}
	async handleTerminalOutput(params) {
		return await this.terminalManager.terminalOutput(params);
	}
	async handleWaitForTerminalExit(params) {
		return await this.terminalManager.waitForTerminalExit(params);
	}
	async handleKillTerminal(params) {
		return await this.terminalManager.killTerminal(params);
	}
	async handleReleaseTerminal(params) {
		return await this.terminalManager.releaseTerminal(params);
	}
	recordPermissionDecision(decision) {
		this.permissionStats.requested += 1;
		if (decision === "approved") {
			this.permissionStats.approved += 1;
			return;
		}
		if (decision === "denied") {
			this.permissionStats.denied += 1;
			return;
		}
		this.permissionStats.cancelled += 1;
	}
	recordPermissionError(sessionId, error) {
		if (error instanceof PermissionPromptUnavailableError) {
			this.notePromptPermissionFailure(sessionId, error);
			this.recordPermissionDecision("cancelled");
			return;
		}
		if (error instanceof PermissionDeniedError) this.recordPermissionDecision("denied");
	}
	async handleSessionUpdate(notification) {
		const sequence = ++this.observedSessionUpdates;
		this.sessionUpdateChain = this.sessionUpdateChain.then(async () => {
			try {
				if (!this.suppressSessionUpdates) this.eventHandlers.onSessionUpdate?.(notification);
			} catch (error) {
				const message = error instanceof Error ? error.message : String(error);
				this.log(`session update handler failed: ${message}`);
			} finally {
				this.processedSessionUpdates = sequence;
			}
		});
		await this.sessionUpdateChain;
	}
	async waitForSessionUpdateDrain(idleMs, timeoutMs) {
		const normalizedIdleMs = Math.max(0, idleMs);
		const normalizedTimeoutMs = Math.max(normalizedIdleMs, timeoutMs);
		const deadline = Date.now() + normalizedTimeoutMs;
		let lastObserved = this.observedSessionUpdates;
		let idleSince = Date.now();
		while (Date.now() <= deadline) {
			const observed = this.observedSessionUpdates;
			if (observed !== lastObserved) {
				lastObserved = observed;
				idleSince = Date.now();
			}
			if (this.processedSessionUpdates === this.observedSessionUpdates && Date.now() - idleSince >= normalizedIdleMs) {
				await this.sessionUpdateChain;
				if (this.processedSessionUpdates === this.observedSessionUpdates) return;
			}
			await new Promise((resolve) => {
				setTimeout(resolve, DRAIN_POLL_INTERVAL_MS);
			});
		}
		throw new Error(`Timed out waiting for session replay drain after ${normalizedTimeoutMs}ms`);
	}
};
//#endregion
//#region src/perf-metrics-capture.ts
const PERF_METRICS_FILE_ENV = "ACPX_PERF_METRICS_FILE";
let installed = false;
let flushed = false;
let captureFilePath;
let captureRole = "cli";
let captureArgv = [];
let captureSequence = 0;
function shouldCapture() {
	return typeof captureFilePath === "string" && captureFilePath.trim().length > 0;
}
function buildPayload(reason) {
	return {
		timestamp: (/* @__PURE__ */ new Date()).toISOString(),
		pid: process.pid,
		ppid: process.ppid,
		role: captureRole,
		argv: captureArgv,
		cwd: process.cwd(),
		sequence: captureSequence,
		reason,
		metrics: getPerfMetricsSnapshot()
	};
}
function writePerfMetricsCapture(reason, resetAfterWrite) {
	if (!shouldCapture()) return false;
	const payload = buildPayload(reason);
	const metrics = payload.metrics;
	if (!(Object.keys(metrics.counters ?? {}).length > 0 || Object.keys(metrics.gauges ?? {}).length > 0 || Object.keys(metrics.timings ?? {}).length > 0)) return false;
	try {
		fs.mkdirSync(path.dirname(captureFilePath), { recursive: true });
		fs.appendFileSync(captureFilePath, `${JSON.stringify(payload)}\n`, "utf8");
		captureSequence += 1;
		if (resetAfterWrite) resetPerfMetrics();
		return true;
	} catch {
		return false;
	}
}
function checkpointPerfMetricsCapture() {
	flushed = false;
	writePerfMetricsCapture("checkpoint", true);
}
function flushPerfMetricsCapture(reason = "exit") {
	if (flushed || !shouldCapture()) return;
	flushed = true;
	writePerfMetricsCapture(reason, false);
}
function installPerfMetricsCapture(options = {}) {
	captureFilePath = options.filePath ?? process.env[PERF_METRICS_FILE_ENV];
	if (!shouldCapture()) return;
	resetPerfMetrics();
	captureRole = options.role ?? captureRole;
	captureArgv = options.argv ?? [];
	captureSequence = 0;
	flushed = false;
	if (installed) return;
	installed = true;
	process.once("exit", () => {
		flushPerfMetricsCapture("exit");
	});
	for (const signal of ["SIGINT", "SIGTERM"]) {
		const handler = () => {
			flushPerfMetricsCapture("signal");
			process.removeListener(signal, handler);
			process.kill(process.pid, signal);
		};
		process.once(signal, handler);
	}
}
//#endregion
//#region src/session-conversation-model.ts
const MAX_RUNTIME_MESSAGES = 200;
const MAX_RUNTIME_AGENT_TEXT_CHARS = 8e3;
const MAX_RUNTIME_THINKING_CHARS = 4e3;
const MAX_RUNTIME_TOOL_IO_CHARS = 4e3;
const MAX_RUNTIME_REQUEST_TOKEN_USAGE = 100;
function isoNow$1() {
	return (/* @__PURE__ */ new Date()).toISOString();
}
function deepClone(value) {
	try {
		return structuredClone(value);
	} catch {
		return value;
	}
}
function hasOwn$1(source, key) {
	return Object.prototype.hasOwnProperty.call(source, key);
}
function normalizeAgentName(value) {
	if (typeof value !== "string") return;
	const trimmed = value.trim();
	return trimmed.length > 0 ? trimmed : void 0;
}
function extractText(content) {
	if (content.type === "text") return content.text;
	if (content.type === "resource_link") return content.title ?? content.name ?? content.uri;
	if (content.type === "resource") {
		if ("text" in content.resource && typeof content.resource.text === "string") return content.resource.text;
		return content.resource.uri;
	}
}
function contentToUserContent(content) {
	if (content.type === "text") return { Text: content.text };
	if (content.type === "resource_link") {
		const value = content.title ?? content.name ?? content.uri;
		return { Mention: {
			uri: content.uri,
			content: value
		} };
	}
	if (content.type === "resource") {
		if ("text" in content.resource && typeof content.resource.text === "string") return { Text: content.resource.text };
		return { Mention: {
			uri: content.resource.uri,
			content: content.resource.uri
		} };
	}
	if (content.type === "image") return { Image: {
		source: content.data,
		size: null
	} };
}
function nextUserMessageId() {
	return randomUUID();
}
function isUserMessage$1(message) {
	return typeof message === "object" && message !== null && hasOwn$1(message, "User");
}
function isAgentMessage$1(message) {
	return typeof message === "object" && message !== null && hasOwn$1(message, "Agent");
}
function isAgentTextContent(content) {
	return hasOwn$1(content, "Text");
}
function isAgentThinkingContent(content) {
	return hasOwn$1(content, "Thinking");
}
function isAgentToolUseContent(content) {
	return hasOwn$1(content, "ToolUse");
}
function updateConversationTimestamp(conversation, timestamp) {
	conversation.updated_at = timestamp;
}
function ensureAgentMessage(conversation) {
	const last = conversation.messages.at(-1);
	if (last && isAgentMessage$1(last)) return last.Agent;
	const created = {
		content: [],
		tool_results: {}
	};
	conversation.messages.push({ Agent: created });
	return created;
}
function appendAgentText(agent, text) {
	if (!text.trim()) return;
	const last = agent.content.at(-1);
	if (last && isAgentTextContent(last)) {
		last.Text = trimRuntimeText(`${last.Text}${text}`, MAX_RUNTIME_AGENT_TEXT_CHARS);
		return;
	}
	const next = { Text: text };
	agent.content.push(next);
}
function appendAgentThinking(agent, text) {
	if (!text.trim()) return;
	const last = agent.content.at(-1);
	if (last && isAgentThinkingContent(last)) {
		last.Thinking.text = trimRuntimeText(`${last.Thinking.text}${text}`, MAX_RUNTIME_THINKING_CHARS);
		return;
	}
	const next = { Thinking: {
		text,
		signature: null
	} };
	agent.content.push(next);
}
function trimRuntimeText(value, maxChars) {
	if (value.length <= maxChars) return value;
	return `${value.slice(0, Math.max(0, maxChars - 3))}...`;
}
function statusIndicatesComplete(status) {
	if (typeof status !== "string") return false;
	const normalized = status.toLowerCase();
	return normalized.includes("complete") || normalized.includes("done") || normalized.includes("success") || normalized.includes("failed") || normalized.includes("error") || normalized.includes("cancel");
}
function statusIndicatesError(status) {
	if (typeof status !== "string") return false;
	const normalized = status.toLowerCase();
	return normalized.includes("fail") || normalized.includes("error");
}
function toToolResultContent(value) {
	if (typeof value === "string") return { Text: trimRuntimeText(value, MAX_RUNTIME_TOOL_IO_CHARS) };
	if (value != null) try {
		return { Text: trimRuntimeText(JSON.stringify(value), MAX_RUNTIME_TOOL_IO_CHARS) };
	} catch {
		return { Text: "[Unserializable value]" };
	}
	return { Text: "" };
}
function toRawInput(value) {
	if (typeof value === "string") return trimRuntimeText(value, MAX_RUNTIME_TOOL_IO_CHARS);
	try {
		return trimRuntimeText(JSON.stringify(value ?? {}), MAX_RUNTIME_TOOL_IO_CHARS);
	} catch {
		return value == null ? "" : "[Unserializable input]";
	}
}
function ensureToolUseContent(agent, toolCallId) {
	for (const content of agent.content) if (isAgentToolUseContent(content) && content.ToolUse.id === toolCallId) return content.ToolUse;
	const created = {
		id: toolCallId,
		name: "tool_call",
		raw_input: "{}",
		input: {},
		is_input_complete: false,
		thought_signature: null
	};
	agent.content.push({ ToolUse: created });
	return created;
}
function upsertToolResult(agent, toolCallId, patch) {
	const existing = agent.tool_results[toolCallId];
	const next = {
		tool_use_id: toolCallId,
		tool_name: patch.tool_name ?? existing?.tool_name ?? "tool_call",
		is_error: patch.is_error ?? existing?.is_error ?? false,
		content: patch.content ?? existing?.content ?? { Text: "" },
		output: patch.output ?? existing?.output
	};
	agent.tool_results[toolCallId] = next;
}
function applyToolCallUpdate(agent, update) {
	const tool = ensureToolUseContent(agent, update.toolCallId);
	if (hasOwn$1(update, "title")) tool.name = normalizeAgentName(update.title) ?? tool.name ?? "tool_call";
	if (hasOwn$1(update, "kind")) {
		const kindName = normalizeAgentName(update.kind);
		if (!tool.name || tool.name === "tool_call") tool.name = kindName ?? tool.name;
	}
	if (hasOwn$1(update, "rawInput")) {
		const rawInput = deepClone(update.rawInput);
		tool.input = rawInput ?? {};
		tool.raw_input = toRawInput(rawInput);
	}
	if (hasOwn$1(update, "status")) tool.is_input_complete = statusIndicatesComplete(update.status);
	if (hasOwn$1(update, "rawOutput") || hasOwn$1(update, "status") || hasOwn$1(update, "title") || hasOwn$1(update, "kind")) {
		const status = update.status;
		const output = hasOwn$1(update, "rawOutput") ? deepClone(update.rawOutput) : void 0;
		upsertToolResult(agent, update.toolCallId, {
			tool_name: tool.name,
			is_error: statusIndicatesError(status),
			content: output === void 0 ? void 0 : toToolResultContent(output),
			output
		});
	}
}
function asRecord$2(value) {
	if (!value || typeof value !== "object" || Array.isArray(value)) return;
	return value;
}
function numberField(source, keys) {
	for (const key of keys) {
		const value = source[key];
		if (typeof value === "number" && Number.isFinite(value) && value >= 0) return value;
	}
}
function usageToTokenUsage(update) {
	const updateRecord = asRecord$2(update);
	const usageMeta = asRecord$2(updateRecord?._meta)?.usage;
	const source = asRecord$2(usageMeta) ?? updateRecord;
	if (!source) return;
	const normalized = {
		input_tokens: numberField(source, ["input_tokens", "inputTokens"]),
		output_tokens: numberField(source, ["output_tokens", "outputTokens"]),
		cache_creation_input_tokens: numberField(source, [
			"cache_creation_input_tokens",
			"cacheCreationInputTokens",
			"cachedWriteTokens"
		]),
		cache_read_input_tokens: numberField(source, [
			"cache_read_input_tokens",
			"cacheReadInputTokens",
			"cachedReadTokens"
		])
	};
	if (normalized.input_tokens === void 0 && normalized.output_tokens === void 0 && normalized.cache_creation_input_tokens === void 0 && normalized.cache_read_input_tokens === void 0) return;
	return normalized;
}
function ensureAcpxState$1(state) {
	return state ?? {};
}
function lastUserMessageId(conversation) {
	for (let index = conversation.messages.length - 1; index >= 0; index -= 1) {
		const message = conversation.messages[index];
		if (message && isUserMessage$1(message)) return message.User.id;
	}
}
function createSessionConversation(timestamp = isoNow$1()) {
	return {
		title: null,
		messages: [],
		updated_at: timestamp,
		cumulative_token_usage: {},
		request_token_usage: {}
	};
}
function cloneSessionConversation(conversation) {
	if (!conversation) return createSessionConversation();
	return {
		title: conversation.title,
		messages: deepClone(conversation.messages ?? []),
		updated_at: conversation.updated_at,
		cumulative_token_usage: deepClone(conversation.cumulative_token_usage ?? {}),
		request_token_usage: deepClone(conversation.request_token_usage ?? {})
	};
}
function cloneSessionAcpxState(state) {
	if (!state) return;
	return {
		current_mode_id: state.current_mode_id,
		desired_mode_id: state.desired_mode_id,
		current_model_id: state.current_model_id,
		available_models: state.available_models ? [...state.available_models] : void 0,
		available_commands: state.available_commands ? [...state.available_commands] : void 0,
		config_options: state.config_options ? deepClone(state.config_options) : void 0,
		session_options: state.session_options ? {
			model: state.session_options.model,
			allowed_tools: state.session_options.allowed_tools ? [...state.session_options.allowed_tools] : void 0,
			max_turns: state.session_options.max_turns
		} : void 0
	};
}
function recordPromptSubmission(conversation, prompt, timestamp = isoNow$1()) {
	const userContent = (typeof prompt === "string" ? textPrompt(prompt) : prompt).map((content) => contentToUserContent(content)).filter((content) => content !== void 0);
	if (userContent.length === 0) return;
	conversation.messages.push({ User: {
		id: nextUserMessageId(),
		content: userContent.map((content) => {
			if ("Text" in content) return { Text: trimRuntimeText(content.Text, MAX_RUNTIME_AGENT_TEXT_CHARS) };
			return content;
		})
	} });
	updateConversationTimestamp(conversation, timestamp);
	trimConversationForRuntime(conversation);
}
function recordSessionUpdate(conversation, state, notification, timestamp = isoNow$1()) {
	const acpx = ensureAcpxState$1(state);
	const update = notification.update;
	switch (update.sessionUpdate) {
		case "user_message_chunk": {
			const userContent = contentToUserContent(update.content);
			if (userContent) conversation.messages.push({ User: {
				id: nextUserMessageId(),
				content: [userContent]
			} });
			break;
		}
		case "agent_message_chunk": {
			const text = extractText(update.content);
			if (text) appendAgentText(ensureAgentMessage(conversation), text);
			break;
		}
		case "agent_thought_chunk": {
			const text = extractText(update.content);
			if (text) appendAgentThinking(ensureAgentMessage(conversation), text);
			break;
		}
		case "tool_call":
		case "tool_call_update":
			applyToolCallUpdate(ensureAgentMessage(conversation), update);
			break;
		case "usage_update": {
			const usage = usageToTokenUsage(update);
			if (usage) {
				conversation.cumulative_token_usage = usage;
				const userId = lastUserMessageId(conversation);
				if (userId) conversation.request_token_usage[userId] = usage;
			}
			break;
		}
		case "session_info_update":
			if (hasOwn$1(update, "title")) conversation.title = update.title ?? null;
			if (hasOwn$1(update, "updatedAt")) conversation.updated_at = update.updatedAt ?? conversation.updated_at;
			break;
		case "available_commands_update":
			acpx.available_commands = update.availableCommands.map((entry) => entry.name).filter((entry) => typeof entry === "string" && entry.trim().length > 0);
			break;
		case "current_mode_update":
			acpx.current_mode_id = update.currentModeId;
			break;
		case "config_option_update":
			acpx.config_options = deepClone(update.configOptions);
			break;
		default: break;
	}
	updateConversationTimestamp(conversation, timestamp);
	trimConversationForRuntime(conversation);
	return acpx;
}
function recordClientOperation(conversation, state, operation, timestamp = isoNow$1()) {
	const acpx = ensureAcpxState$1(state);
	updateConversationTimestamp(conversation, timestamp);
	trimConversationForRuntime(conversation);
	return acpx;
}
function trimConversationForRuntime(conversation) {
	if (conversation.messages.length > MAX_RUNTIME_MESSAGES) conversation.messages = conversation.messages.slice(-MAX_RUNTIME_MESSAGES);
	for (const message of conversation.messages) {
		if (!isAgentMessage$1(message)) {
			if (isUserMessage$1(message)) message.User.content = message.User.content.map((content) => {
				if ("Text" in content) return { Text: trimRuntimeText(content.Text, MAX_RUNTIME_AGENT_TEXT_CHARS) };
				return content;
			});
			continue;
		}
		for (const content of message.Agent.content) if ("Text" in content) content.Text = trimRuntimeText(content.Text, MAX_RUNTIME_AGENT_TEXT_CHARS);
		else if ("Thinking" in content) content.Thinking.text = trimRuntimeText(content.Thinking.text, MAX_RUNTIME_THINKING_CHARS);
		else if ("ToolUse" in content) content.ToolUse.raw_input = trimRuntimeText(content.ToolUse.raw_input, MAX_RUNTIME_TOOL_IO_CHARS);
		for (const result of Object.values(message.Agent.tool_results)) {
			if ("Text" in result.content) result.content.Text = trimRuntimeText(result.content.Text, MAX_RUNTIME_TOOL_IO_CHARS);
			if (typeof result.output === "string") result.output = trimRuntimeText(result.output, MAX_RUNTIME_TOOL_IO_CHARS);
		}
	}
	const requestUsageEntries = Object.entries(conversation.request_token_usage);
	if (requestUsageEntries.length > MAX_RUNTIME_REQUEST_TOKEN_USAGE) conversation.request_token_usage = Object.fromEntries(requestUsageEntries.slice(-MAX_RUNTIME_REQUEST_TOKEN_USAGE));
}
//#endregion
//#region src/session-event-log.ts
const DEFAULT_EVENT_SEGMENT_MAX_BYTES = 64 * 1024 * 1024;
function sessionBaseDir$1() {
	return path.join(os.homedir(), ".acpx", "sessions");
}
function safeSessionId(sessionId) {
	return encodeURIComponent(sessionId);
}
function sessionEventActivePath(sessionId) {
	return path.join(sessionBaseDir$1(), `${safeSessionId(sessionId)}.stream.ndjson`);
}
function sessionEventSegmentPath(sessionId, segment) {
	return path.join(sessionBaseDir$1(), `${safeSessionId(sessionId)}.stream.${segment}.ndjson`);
}
function sessionEventLockPath(sessionId) {
	return path.join(sessionBaseDir$1(), `${safeSessionId(sessionId)}.stream.lock`);
}
function defaultSessionEventLog(sessionId) {
	return {
		active_path: sessionEventActivePath(sessionId),
		segment_count: 5,
		max_segment_bytes: DEFAULT_EVENT_SEGMENT_MAX_BYTES,
		max_segments: 5,
		last_write_at: void 0,
		last_write_error: null
	};
}
//#endregion
//#region src/session-persistence/serialize.ts
function serializeSessionRecordForDisk(record) {
	const canonical = {
		...record,
		schema: SESSION_RECORD_SCHEMA
	};
	return {
		schema: canonical.schema,
		acpx_record_id: canonical.acpxRecordId,
		acp_session_id: canonical.acpSessionId,
		agent_session_id: normalizeRuntimeSessionId(canonical.agentSessionId),
		agent_command: canonical.agentCommand,
		cwd: canonical.cwd,
		name: canonical.name,
		created_at: canonical.createdAt,
		last_used_at: canonical.lastUsedAt,
		last_seq: canonical.lastSeq,
		last_request_id: canonical.lastRequestId,
		event_log: canonical.eventLog,
		closed: canonical.closed,
		closed_at: canonical.closedAt,
		pid: canonical.pid,
		agent_started_at: canonical.agentStartedAt,
		last_prompt_at: canonical.lastPromptAt,
		last_agent_exit_code: canonical.lastAgentExitCode,
		last_agent_exit_signal: canonical.lastAgentExitSignal,
		last_agent_exit_at: canonical.lastAgentExitAt,
		last_agent_disconnect_reason: canonical.lastAgentDisconnectReason,
		protocol_version: canonical.protocolVersion,
		agent_capabilities: canonical.agentCapabilities,
		title: canonical.title,
		messages: canonical.messages,
		updated_at: canonical.updated_at,
		cumulative_token_usage: canonical.cumulative_token_usage,
		request_token_usage: canonical.request_token_usage,
		acpx: canonical.acpx
	};
}
//#endregion
//#region src/persisted-key-policy.ts
const SNAKE_CASE_KEY = /^[a-z][a-z0-9_]*$/;
const ZED_TAG_KEYS = new Set([
	"User",
	"Agent",
	"Resume",
	"Text",
	"Mention",
	"Image",
	"Thinking",
	"RedactedThinking",
	"ToolUse"
]);
const MAP_OBJECT_PATHS = new Set(["request_token_usage", "messages.Agent.tool_results"]);
const OPAQUE_VALUE_PATHS = new Set([
	"agent_capabilities",
	"messages.Agent.content.ToolUse.input",
	"acpx.config_options"
]);
function isRecord(value) {
	return !!value && typeof value === "object" && !Array.isArray(value);
}
function joinPath(path) {
	return path.join(".");
}
function isAllowedKey(path, key) {
	if (ZED_TAG_KEYS.has(key)) return true;
	return false;
}
function shouldSkipKeyRule(path) {
	return MAP_OBJECT_PATHS.has(joinPath(path));
}
function shouldSkipDescend(path) {
	return OPAQUE_VALUE_PATHS.has(joinPath(path)) || isToolResultOutputPath(path);
}
function isToolResultOutputPath(path) {
	if (path.length < 5 || path[path.length - 1] !== "output") return false;
	const toolResultsIndex = path.lastIndexOf("tool_results");
	if (toolResultsIndex === -1 || toolResultsIndex + 2 !== path.length - 1) return false;
	return path.slice(0, toolResultsIndex + 1).join(".") === "messages.Agent.tool_results";
}
function collectViolations(value, path, violations) {
	if (Array.isArray(value)) {
		for (const entry of value) collectViolations(entry, path, violations);
		return;
	}
	if (!isRecord(value)) return;
	const skipKeyRule = shouldSkipKeyRule(path);
	for (const [key, child] of Object.entries(value)) {
		if (!skipKeyRule && !SNAKE_CASE_KEY.test(key) && !isAllowedKey(path, key)) violations.push(`${joinPath(path)}.${key}`.replace(/^\./, ""));
		const childPath = [...path, key];
		if (shouldSkipDescend(childPath)) continue;
		collectViolations(child, childPath, violations);
	}
}
function findPersistedKeyPolicyViolations(value) {
	const violations = [];
	collectViolations(value, [], violations);
	return violations;
}
function assertPersistedKeyPolicy(value) {
	const violations = findPersistedKeyPolicyViolations(value);
	if (violations.length === 0) return;
	throw new Error(`Persisted key policy violation (expected snake_case keys): ${violations.join(", ")}`);
}
//#endregion
//#region src/session-persistence/parse.ts
function asRecord$1(value) {
	if (!value || typeof value !== "object" || Array.isArray(value)) return;
	return value;
}
function hasOwn(source, key) {
	return Object.prototype.hasOwnProperty.call(source, key);
}
function isStringArray(value) {
	return Array.isArray(value) && value.every((entry) => typeof entry === "string");
}
function parseTokenUsage(raw) {
	if (raw === void 0 || raw === null) return;
	const record = asRecord$1(raw);
	if (!record) return null;
	const usage = {};
	for (const field of [
		"input_tokens",
		"output_tokens",
		"cache_creation_input_tokens",
		"cache_read_input_tokens"
	]) {
		const value = record[field];
		if (value === void 0) continue;
		if (typeof value !== "number" || !Number.isFinite(value) || value < 0) return null;
		usage[field] = value;
	}
	return usage;
}
function parseRequestTokenUsage(raw) {
	if (raw === void 0 || raw === null) return;
	const record = asRecord$1(raw);
	if (!record) return null;
	const usage = {};
	for (const [key, value] of Object.entries(record)) {
		const parsed = parseTokenUsage(value);
		if (parsed == null) return null;
		usage[key] = parsed;
	}
	return usage;
}
function isSessionMessageImage(raw) {
	const record = asRecord$1(raw);
	if (!record || typeof record.source !== "string") return false;
	if (record.size === void 0 || record.size === null) return true;
	const size = asRecord$1(record.size);
	return !!size && typeof size.width === "number" && Number.isFinite(size.width) && typeof size.height === "number" && Number.isFinite(size.height);
}
function isUserContent(raw) {
	const record = asRecord$1(raw);
	if (!record) return false;
	if (typeof record.Text === "string") return true;
	if (record.Mention !== void 0) {
		const mention = asRecord$1(record.Mention);
		return !!mention && typeof mention.uri === "string" && typeof mention.content === "string";
	}
	if (record.Image !== void 0) return isSessionMessageImage(record.Image);
	return false;
}
function isToolUse(raw) {
	const record = asRecord$1(raw);
	return !!record && typeof record.id === "string" && typeof record.name === "string" && typeof record.raw_input === "string" && hasOwn(record, "input") && typeof record.is_input_complete === "boolean" && (record.thought_signature === void 0 || record.thought_signature === null || typeof record.thought_signature === "string");
}
function isToolResultContent(raw) {
	const record = asRecord$1(raw);
	if (!record) return false;
	if (typeof record.Text === "string") return true;
	if (record.Image !== void 0) return isSessionMessageImage(record.Image);
	return false;
}
function isToolResult(raw) {
	const record = asRecord$1(raw);
	return !!record && typeof record.tool_use_id === "string" && typeof record.tool_name === "string" && typeof record.is_error === "boolean" && isToolResultContent(record.content);
}
function isAgentContent(raw) {
	const record = asRecord$1(raw);
	if (!record) return false;
	if (typeof record.Text === "string") return true;
	if (record.Thinking !== void 0) {
		const thinking = asRecord$1(record.Thinking);
		return !!thinking && typeof thinking.text === "string" && (thinking.signature === void 0 || thinking.signature === null || typeof thinking.signature === "string");
	}
	if (typeof record.RedactedThinking === "string") return true;
	if (record.ToolUse !== void 0) return isToolUse(record.ToolUse);
	return false;
}
function isUserMessage(raw) {
	const record = asRecord$1(raw);
	if (!record || record.User === void 0) return false;
	const user = asRecord$1(record.User);
	return !!user && typeof user.id === "string" && Array.isArray(user.content) && user.content.every((entry) => isUserContent(entry));
}
function isAgentMessage(raw) {
	const record = asRecord$1(raw);
	if (!record || record.Agent === void 0) return false;
	const agent = asRecord$1(record.Agent);
	if (!agent || !Array.isArray(agent.content) || !agent.content.every(isAgentContent)) return false;
	const toolResults = asRecord$1(agent.tool_results);
	if (!toolResults) return false;
	return Object.values(toolResults).every(isToolResult);
}
function isConversationMessage(raw) {
	return raw === "Resume" || isUserMessage(raw) || isAgentMessage(raw);
}
function parseConversationRecord(record) {
	if (!Array.isArray(record.messages) || !record.messages.every(isConversationMessage) || typeof record.updated_at !== "string") return;
	if (record.title !== void 0 && record.title !== null && typeof record.title !== "string") return;
	const cumulativeTokenUsage = parseTokenUsage(record.cumulative_token_usage);
	const requestTokenUsage = parseRequestTokenUsage(record.request_token_usage);
	if (cumulativeTokenUsage === null || requestTokenUsage === null) return;
	return {
		title: record.title === void 0 || record.title === null || typeof record.title === "string" ? record.title : null,
		messages: record.messages,
		updated_at: record.updated_at,
		cumulative_token_usage: cumulativeTokenUsage ?? {},
		request_token_usage: requestTokenUsage ?? {}
	};
}
function parseAcpxState(raw) {
	const record = asRecord$1(raw);
	if (!record) return;
	const state = {};
	if (typeof record.current_mode_id === "string") state.current_mode_id = record.current_mode_id;
	if (typeof record.desired_mode_id === "string") state.desired_mode_id = record.desired_mode_id;
	if (typeof record.current_model_id === "string") state.current_model_id = record.current_model_id;
	if (isStringArray(record.available_models)) state.available_models = [...record.available_models];
	if (isStringArray(record.available_commands)) state.available_commands = [...record.available_commands];
	if (Array.isArray(record.config_options)) state.config_options = record.config_options;
	const sessionOptions = asRecord$1(record.session_options);
	if (sessionOptions) {
		const parsedSessionOptions = {};
		if (typeof sessionOptions.model === "string") parsedSessionOptions.model = sessionOptions.model;
		if (isStringArray(sessionOptions.allowed_tools)) parsedSessionOptions.allowed_tools = [...sessionOptions.allowed_tools];
		if (typeof sessionOptions.max_turns === "number" && Number.isInteger(sessionOptions.max_turns) && sessionOptions.max_turns > 0) parsedSessionOptions.max_turns = sessionOptions.max_turns;
		if (Object.keys(parsedSessionOptions).length > 0) state.session_options = parsedSessionOptions;
	}
	return state;
}
function parseEventLog(raw, sessionId) {
	const record = asRecord$1(raw);
	if (!record) return defaultSessionEventLog(sessionId);
	if (typeof record.active_path !== "string" || typeof record.segment_count !== "number" || !Number.isInteger(record.segment_count) || record.segment_count < 1 || typeof record.max_segment_bytes !== "number" || !Number.isInteger(record.max_segment_bytes) || record.max_segment_bytes < 1 || typeof record.max_segments !== "number" || !Number.isInteger(record.max_segments) || record.max_segments < 1) return defaultSessionEventLog(sessionId);
	return {
		active_path: record.active_path,
		segment_count: record.segment_count,
		max_segment_bytes: record.max_segment_bytes,
		max_segments: record.max_segments,
		last_write_at: typeof record.last_write_at === "string" ? record.last_write_at : void 0,
		last_write_error: record.last_write_error == null || typeof record.last_write_error === "string" ? record.last_write_error : null
	};
}
function normalizeOptionalName(value) {
	if (value == null) return;
	if (typeof value !== "string") return null;
	const trimmed = value.trim();
	return trimmed.length > 0 ? trimmed : void 0;
}
function normalizeOptionalPid(value) {
	if (value == null) return;
	if (!Number.isInteger(value) || value <= 0) return null;
	return value;
}
function normalizeOptionalBoolean(value, fallback = false) {
	if (value == null) return fallback;
	return typeof value === "boolean" ? value : null;
}
function normalizeOptionalString(value) {
	if (value == null) return;
	return typeof value === "string" ? value : null;
}
function normalizeOptionalExitCode(value) {
	if (value === void 0) return;
	if (value === null) return null;
	if (Number.isInteger(value)) return value;
	return Symbol("invalid");
}
function normalizeOptionalSignal(value) {
	if (value === void 0) return;
	if (value === null) return null;
	if (typeof value === "string") return value;
	return Symbol("invalid");
}
function parseSessionRecord(raw) {
	const record = asRecord$1(raw);
	if (!record) return null;
	if (record.schema !== "acpx.session.v1") return null;
	const name = normalizeOptionalName(record.name);
	const pid = normalizeOptionalPid(record.pid);
	const closed = normalizeOptionalBoolean(record.closed, false);
	const closedAt = normalizeOptionalString(record.closed_at);
	const agentStartedAt = normalizeOptionalString(record.agent_started_at);
	const lastPromptAt = normalizeOptionalString(record.last_prompt_at);
	const lastAgentExitCode = normalizeOptionalExitCode(record.last_agent_exit_code);
	const lastAgentExitSignal = normalizeOptionalSignal(record.last_agent_exit_signal);
	const lastAgentExitAt = normalizeOptionalString(record.last_agent_exit_at);
	const lastAgentDisconnectReason = normalizeOptionalString(record.last_agent_disconnect_reason);
	if (typeof record.acpx_record_id !== "string" || typeof record.acp_session_id !== "string" || typeof record.agent_command !== "string" || typeof record.cwd !== "string" || typeof record.created_at !== "string" || typeof record.last_used_at !== "string" || typeof record.last_seq !== "number" || !Number.isInteger(record.last_seq) || record.last_seq < 0 || name === null || pid === null || closed === null || closedAt === null || agentStartedAt === null || lastPromptAt === null || typeof lastAgentExitCode === "symbol" || typeof lastAgentExitSignal === "symbol" || lastAgentExitAt === null || lastAgentDisconnectReason === null) return null;
	const conversation = parseConversationRecord(record);
	if (!conversation) return null;
	const eventLog = parseEventLog(record.event_log, record.acpx_record_id);
	const lastRequestId = normalizeOptionalString(record.last_request_id);
	if (lastRequestId === null) return null;
	return {
		schema: SESSION_RECORD_SCHEMA,
		acpxRecordId: record.acpx_record_id,
		acpSessionId: record.acp_session_id,
		agentSessionId: normalizeRuntimeSessionId(record.agent_session_id),
		agentCommand: record.agent_command,
		cwd: record.cwd,
		name,
		createdAt: record.created_at,
		lastUsedAt: record.last_used_at,
		lastSeq: record.last_seq,
		lastRequestId,
		eventLog,
		closed,
		closedAt,
		pid,
		agentStartedAt,
		lastPromptAt,
		lastAgentExitCode,
		lastAgentExitSignal,
		lastAgentExitAt,
		lastAgentDisconnectReason,
		protocolVersion: typeof record.protocol_version === "number" ? record.protocol_version : void 0,
		agentCapabilities: asRecord$1(record.agent_capabilities),
		title: conversation.title,
		messages: conversation.messages,
		updated_at: conversation.updated_at,
		cumulative_token_usage: conversation.cumulative_token_usage,
		request_token_usage: conversation.request_token_usage,
		acpx: parseAcpxState(record.acpx)
	};
}
//#endregion
//#region src/session-persistence/index.ts
const SESSION_INDEX_SCHEMA = "acpx.session-index.v1";
function asRecord(value) {
	if (!value || typeof value !== "object" || Array.isArray(value)) return;
	return value;
}
function parseIndexEntry(raw) {
	const record = asRecord(raw);
	if (!record) return;
	if (typeof record.file !== "string" || typeof record.acpxRecordId !== "string" || typeof record.acpSessionId !== "string" || typeof record.agentCommand !== "string" || typeof record.cwd !== "string" || typeof record.lastUsedAt !== "string" || typeof record.closed !== "boolean") return;
	if (record.name !== void 0 && typeof record.name !== "string") return;
	return {
		file: record.file,
		acpxRecordId: record.acpxRecordId,
		acpSessionId: record.acpSessionId,
		agentCommand: record.agentCommand,
		cwd: record.cwd,
		name: record.name,
		closed: record.closed,
		lastUsedAt: record.lastUsedAt
	};
}
function sessionIndexPath(sessionDir) {
	return path.join(sessionDir, "index.json");
}
function toSessionIndexEntry(record, fileName) {
	return {
		file: fileName,
		acpxRecordId: record.acpxRecordId,
		acpSessionId: record.acpSessionId,
		agentCommand: record.agentCommand,
		cwd: record.cwd,
		name: record.name,
		closed: record.closed === true,
		lastUsedAt: record.lastUsedAt
	};
}
async function readSessionIndex(sessionDir) {
	const filePath = sessionIndexPath(sessionDir);
	try {
		const payload = await fs$1.readFile(filePath, "utf8");
		const record = asRecord(JSON.parse(payload));
		if (!record || record.schema !== SESSION_INDEX_SCHEMA || !Array.isArray(record.files)) return;
		const files = record.files.filter((entry) => typeof entry === "string");
		if (files.length !== record.files.length || !Array.isArray(record.entries)) return;
		const entries = record.entries.map((entry) => parseIndexEntry(entry)).filter((entry) => Boolean(entry));
		if (entries.length !== record.entries.length) return;
		return {
			schema: SESSION_INDEX_SCHEMA,
			files,
			entries
		};
	} catch {
		return;
	}
}
async function writeSessionIndex(sessionDir, index) {
	const filePath = sessionIndexPath(sessionDir);
	const tempFile = `${filePath}.${process.pid}.${Date.now()}.tmp`;
	const payload = JSON.stringify({
		schema: SESSION_INDEX_SCHEMA,
		files: [...index.files].toSorted(),
		entries: [...index.entries].toSorted((a, b) => b.lastUsedAt.localeCompare(a.lastUsedAt))
	}, null, 2);
	await fs$1.writeFile(tempFile, `${payload}\n`, "utf8");
	await fs$1.rename(tempFile, filePath);
}
async function rebuildSessionIndex(sessionDir) {
	const files = (await fs$1.readdir(sessionDir, { withFileTypes: true })).filter((entry) => entry.isFile() && entry.name.endsWith(".json") && entry.name !== "index.json").map((entry) => entry.name).toSorted();
	const indexEntries = [];
	for (const file of files) try {
		const payload = await fs$1.readFile(path.join(sessionDir, file), "utf8");
		const parsed = parseSessionRecord(JSON.parse(payload));
		if (!parsed) continue;
		indexEntries.push(toSessionIndexEntry(parsed, file));
	} catch {}
	const index = {
		schema: SESSION_INDEX_SCHEMA,
		files,
		entries: indexEntries
	};
	await writeSessionIndex(sessionDir, index);
	return index;
}
async function loadOrRebuildSessionIndex(sessionDir) {
	const files = (await fs$1.readdir(sessionDir, { withFileTypes: true })).filter((entry) => entry.isFile() && entry.name.endsWith(".json") && entry.name !== "index.json").map((entry) => entry.name).toSorted();
	const existing = await readSessionIndex(sessionDir);
	if (existing && existing.files.length === files.length && existing.files.every((file, index) => file === files[index])) return existing;
	return await rebuildSessionIndex(sessionDir);
}
//#endregion
//#region src/session-persistence/repository.ts
const DEFAULT_HISTORY_LIMIT = 20;
function sessionFilePath(acpxRecordId) {
	const safeId = encodeURIComponent(acpxRecordId);
	return path.join(sessionBaseDir(), `${safeId}.json`);
}
function sessionBaseDir() {
	return path.join(os.homedir(), ".acpx", "sessions");
}
async function ensureSessionDir$1() {
	await fs$1.mkdir(sessionBaseDir(), { recursive: true });
}
async function loadRecordFromIndexEntry(entry) {
	try {
		const payload = await fs$1.readFile(path.join(sessionBaseDir(), entry.file), "utf8");
		return parseSessionRecord(JSON.parse(payload)) ?? void 0;
	} catch {
		return;
	}
}
async function loadSessionIndexEntries() {
	await ensureSessionDir$1();
	return (await measurePerf("session.index_load", async () => {
		return await loadOrRebuildSessionIndex(sessionBaseDir());
	})).entries;
}
function matchesSessionEntry(session, normalizedCwd, normalizedName, includeClosed = false) {
	if (session.cwd !== normalizedCwd) return false;
	if (!includeClosed && session.closed) return false;
	if (normalizedName == null) return session.name == null;
	return session.name === normalizedName;
}
async function writeSessionRecord(record) {
	await measurePerf("session.write_record", async () => {
		await ensureSessionDir$1();
		const persisted = serializeSessionRecordForDisk(record);
		assertPersistedKeyPolicy(persisted);
		const file = sessionFilePath(record.acpxRecordId);
		const tempFile = `${file}.${process.pid}.${Date.now()}.tmp`;
		const payload = JSON.stringify(persisted, null, 2);
		await fs$1.writeFile(tempFile, `${payload}\n`, "utf8");
		await fs$1.rename(tempFile, file);
		const sessionDir = sessionBaseDir();
		const index = await loadOrRebuildSessionIndex(sessionDir);
		const fileName = path.basename(file);
		const entries = index.entries.filter((entry) => entry.file !== fileName);
		entries.push(toSessionIndexEntry(record, fileName));
		await writeSessionIndex(sessionDir, {
			files: [...new Set([...index.files.filter((entry) => entry !== fileName), fileName])],
			entries
		});
	});
}
async function resolveSessionRecord(sessionId) {
	await ensureSessionDir$1();
	const directPath = sessionFilePath(sessionId);
	try {
		const directPayload = await measurePerf("session.resolve_direct", async () => {
			return await fs$1.readFile(directPath, "utf8");
		});
		const directRecord = parseSessionRecord(JSON.parse(directPayload));
		if (directRecord) return directRecord;
	} catch {}
	const entries = await loadSessionIndexEntries();
	const exactEntries = entries.filter((entry) => entry.acpxRecordId === sessionId || entry.acpSessionId === sessionId);
	const exactRecords = (await Promise.all(exactEntries.map((entry) => loadRecordFromIndexEntry(entry)))).filter((entry) => Boolean(entry));
	if (exactRecords.length === 1) return exactRecords[0];
	if (exactRecords.length > 1) throw new SessionResolutionError(`Multiple sessions match id: ${sessionId}`);
	const suffixEntries = entries.filter((entry) => entry.acpxRecordId.endsWith(sessionId) || entry.acpSessionId.endsWith(sessionId));
	const suffixRecords = (await Promise.all(suffixEntries.map((entry) => loadRecordFromIndexEntry(entry)))).filter((entry) => Boolean(entry));
	if (suffixRecords.length === 1) return suffixRecords[0];
	if (suffixRecords.length > 1) throw new SessionResolutionError(`Session id is ambiguous: ${sessionId}`);
	incrementPerfCounter("session.resolve_miss");
	throw new SessionNotFoundError(sessionId);
}
function hasGitDirectory(dir) {
	const gitPath = path.join(dir, ".git");
	try {
		return statSync(gitPath).isDirectory();
	} catch {
		return false;
	}
}
function isWithinBoundary(boundary, target) {
	const relative = path.relative(boundary, target);
	return relative.length === 0 || !relative.startsWith("..") && !path.isAbsolute(relative);
}
function absolutePath(value) {
	return path.resolve(value);
}
function findGitRepositoryRoot(startDir) {
	let current = absolutePath(startDir);
	const root = path.parse(current).root;
	for (;;) {
		if (hasGitDirectory(current)) return current;
		if (current === root) return;
		const parent = path.dirname(current);
		if (parent === current) return;
		current = parent;
	}
}
function normalizeName(value) {
	if (value == null) return;
	const trimmed = value.trim();
	return trimmed.length > 0 ? trimmed : void 0;
}
function isoNow() {
	return (/* @__PURE__ */ new Date()).toISOString();
}
async function listSessions() {
	await ensureSessionDir$1();
	const entries = await loadSessionIndexEntries();
	const records = [];
	for (const entry of entries) {
		const parsed = await loadRecordFromIndexEntry(entry);
		if (parsed) records.push(parsed);
	}
	records.sort((a, b) => b.lastUsedAt.localeCompare(a.lastUsedAt));
	return records;
}
async function listSessionsForAgent(agentCommand) {
	const entries = (await loadSessionIndexEntries()).filter((session) => session.agentCommand === agentCommand);
	return (await Promise.all(entries.map((entry) => loadRecordFromIndexEntry(entry)))).filter((entry) => Boolean(entry)).toSorted((a, b) => b.lastUsedAt.localeCompare(a.lastUsedAt));
}
async function findSession(options) {
	const normalizedCwd = absolutePath(options.cwd);
	const normalizedName = normalizeName(options.name);
	const match = (await loadSessionIndexEntries()).find((session) => session.agentCommand === options.agentCommand && matchesSessionEntry(session, normalizedCwd, normalizedName, options.includeClosed));
	if (!match) return;
	return await loadRecordFromIndexEntry(match);
}
async function findSessionByDirectoryWalk(options) {
	const normalizedName = normalizeName(options.name);
	const normalizedStart = absolutePath(options.cwd);
	const normalizedBoundary = absolutePath(options.boundary ?? normalizedStart);
	const walkBoundary = isWithinBoundary(normalizedBoundary, normalizedStart) ? normalizedBoundary : normalizedStart;
	const sessions = (await loadSessionIndexEntries()).filter((session) => session.agentCommand === options.agentCommand);
	let current = normalizedStart;
	const walkRoot = path.parse(current).root;
	for (;;) {
		const match = sessions.find((session) => matchesSessionEntry(session, current, normalizedName));
		if (match) return await loadRecordFromIndexEntry(match);
		if (current === walkBoundary || current === walkRoot) return;
		const parent = path.dirname(current);
		if (parent === current) return;
		current = parent;
		if (!isWithinBoundary(walkBoundary, current)) return;
	}
}
//#endregion
//#region src/session-events.ts
const LOCK_RETRY_MS = 15;
const EVENT_LOCK_STALE_MS = 15e3;
async function ensureSessionDir() {
	await fs$1.mkdir(sessionBaseDir$1(), { recursive: true });
}
async function pathExists(filePath) {
	try {
		await fs$1.access(filePath);
		return true;
	} catch {
		return false;
	}
}
async function statSize(filePath) {
	try {
		return (await fs$1.stat(filePath)).size;
	} catch {
		return 0;
	}
}
async function countExistingSegments(sessionId, maxSegments) {
	let count = 0;
	for (let segment = 1; segment <= maxSegments; segment += 1) if (await pathExists(sessionEventSegmentPath(sessionId, segment))) count += 1;
	if (await pathExists(sessionEventActivePath(sessionId))) count += 1;
	return count;
}
async function rotateSegments(sessionId, maxSegments) {
	const active = sessionEventActivePath(sessionId);
	const overflow = sessionEventSegmentPath(sessionId, maxSegments);
	await fs$1.unlink(overflow).catch((error) => {
		if (error.code !== "ENOENT") throw error;
	});
	for (let segment = maxSegments - 1; segment >= 1; segment -= 1) {
		const from = sessionEventSegmentPath(sessionId, segment);
		const to = sessionEventSegmentPath(sessionId, segment + 1);
		if (!await pathExists(from)) continue;
		await fs$1.rename(from, to);
	}
	if (await pathExists(active)) await fs$1.rename(active, sessionEventSegmentPath(sessionId, 1));
}
function parseEventLockPayload(raw) {
	try {
		const parsed = JSON.parse(raw);
		if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return {};
		const record = parsed;
		return {
			pid: typeof record.pid === "number" ? record.pid : void 0,
			created_at: typeof record.created_at === "string" ? record.created_at : void 0
		};
	} catch {
		return {};
	}
}
async function removeStaleEventLock(lockPath) {
	try {
		const parsed = parseEventLockPayload(await fs$1.readFile(lockPath, "utf8"));
		const createdAtMs = parsed.created_at ? Date.parse(parsed.created_at) : NaN;
		const lockAgeMs = Number.isFinite(createdAtMs) ? Date.now() - createdAtMs : Number.POSITIVE_INFINITY;
		if (isProcessAlive(parsed.pid) && lockAgeMs <= EVENT_LOCK_STALE_MS) return false;
		await fs$1.unlink(lockPath);
		incrementPerfCounter("session.events.stale_lock_recovered");
		return true;
	} catch (error) {
		if (error.code === "ENOENT") return true;
		return false;
	}
}
async function acquireEventsLock(sessionId) {
	await ensureSessionDir();
	const lockPath = sessionEventLockPath(sessionId);
	const payload = JSON.stringify({
		pid: process.pid,
		created_at: (/* @__PURE__ */ new Date()).toISOString()
	}, null, 2);
	for (;;) try {
		await fs$1.writeFile(lockPath, `${payload}\n`, {
			encoding: "utf8",
			flag: "wx"
		});
		return { filePath: lockPath };
	} catch (error) {
		if (error.code !== "EEXIST") throw error;
		if (await removeStaleEventLock(lockPath)) continue;
		await new Promise((resolve) => {
			setTimeout(resolve, LOCK_RETRY_MS);
		});
	}
}
async function releaseEventsLock(lock) {
	await fs$1.unlink(lock.filePath).catch((error) => {
		if (error.code !== "ENOENT") throw error;
	});
}
var SessionEventWriter = class SessionEventWriter {
	record;
	lock;
	maxSegmentBytes;
	maxSegments;
	activePath;
	activeSizeBytes;
	segmentCount;
	closed = false;
	constructor(record, lock, options, state) {
		this.record = record;
		this.lock = lock;
		this.maxSegmentBytes = options.maxSegmentBytes;
		this.maxSegments = options.maxSegments;
		this.activePath = state.activePath;
		this.activeSizeBytes = state.activeSizeBytes;
		this.segmentCount = state.segmentCount;
	}
	static async open(record, options = {}) {
		const lock = await acquireEventsLock(record.acpxRecordId);
		const maxSegmentBytes = options.maxSegmentBytes ?? record.eventLog.max_segment_bytes ?? 67108864;
		const maxSegments = options.maxSegments ?? record.eventLog.max_segments ?? 5;
		const activePath = sessionEventActivePath(record.acpxRecordId);
		const activeSizeBytes = await statSize(activePath);
		const segmentCount = Number.isInteger(record.eventLog.segment_count) && record.eventLog.segment_count > 0 ? record.eventLog.segment_count : await countExistingSegments(record.acpxRecordId, maxSegments) || 1;
		return new SessionEventWriter(record, lock, {
			maxSegmentBytes,
			maxSegments
		}, {
			activePath,
			activeSizeBytes,
			segmentCount
		});
	}
	getRecord() {
		return this.record;
	}
	async appendMessage(message, options = {}) {
		await this.appendMessages([message], options);
	}
	async appendMessages(messages, options = {}) {
		if (this.closed) throw new Error("SessionEventWriter is closed");
		if (messages.length === 0) return;
		await ensureSessionDir();
		await measurePerf("session.events.append_batch", async () => {
			for (const message of messages) {
				if (!isAcpJsonRpcMessage(message)) throw new Error("Attempted to persist invalid ACP JSON-RPC payload");
				const line = `${JSON.stringify(message)}\n`;
				const lineBytes = Buffer.byteLength(line);
				if (this.activeSizeBytes > 0 && this.activeSizeBytes + lineBytes > this.maxSegmentBytes) {
					await rotateSegments(this.record.acpxRecordId, this.maxSegments);
					this.activePath = sessionEventActivePath(this.record.acpxRecordId);
					this.activeSizeBytes = 0;
					this.segmentCount = Math.min(this.segmentCount + 1, this.maxSegments);
					incrementPerfCounter("session.events.rotate");
				}
				await fs$1.appendFile(this.activePath, line, "utf8");
				this.activeSizeBytes += lineBytes;
				this.record.lastSeq += 1;
				if (Object.hasOwn(message, "id")) {
					const id = message.id;
					if (typeof id === "string" || typeof id === "number") this.record.lastRequestId = String(id);
				}
				const writeTs = (/* @__PURE__ */ new Date()).toISOString();
				this.record.lastUsedAt = writeTs;
				this.record.eventLog = {
					active_path: this.activePath,
					segment_count: this.segmentCount,
					max_segment_bytes: this.maxSegmentBytes,
					max_segments: this.maxSegments,
					last_write_at: writeTs,
					last_write_error: null
				};
			}
		});
		if (options.checkpoint === true) await writeSessionRecord(this.record);
	}
	async checkpoint() {
		if (this.closed) throw new Error("SessionEventWriter is closed");
		await writeSessionRecord(this.record);
	}
	async close(options = {}) {
		if (this.closed) return;
		try {
			if (options.checkpoint !== false) await writeSessionRecord(this.record);
		} finally {
			this.closed = true;
			await releaseEventsLock(this.lock);
		}
	}
};
//#endregion
//#region src/queue-owner-turn-controller.ts
var QueueOwnerTurnController = class {
	options;
	state = "idle";
	pendingCancel = false;
	activeController;
	constructor(options) {
		this.options = options;
	}
	get lifecycleState() {
		return this.state;
	}
	get hasPendingCancel() {
		return this.pendingCancel;
	}
	beginTurn() {
		this.state = "starting";
		this.pendingCancel = false;
	}
	markPromptActive() {
		if (this.state === "starting" || this.state === "active") this.state = "active";
	}
	endTurn() {
		this.state = "idle";
		this.pendingCancel = false;
	}
	beginClosing() {
		this.state = "closing";
		this.pendingCancel = false;
		this.activeController = void 0;
	}
	setActiveController(controller) {
		this.activeController = controller;
	}
	clearActiveController() {
		this.activeController = void 0;
	}
	assertCanHandleControlRequest() {
		if (this.state === "closing") throw new QueueConnectionError("Queue owner is closing", {
			detailCode: "QUEUE_OWNER_SHUTTING_DOWN",
			origin: "queue",
			retryable: true
		});
	}
	async requestCancel() {
		const activeController = this.activeController;
		if (activeController?.hasActivePrompt()) {
			const cancelled = await activeController.requestCancelActivePrompt();
			if (cancelled) this.pendingCancel = false;
			return cancelled;
		}
		if (this.state === "starting" || this.state === "active") {
			this.pendingCancel = true;
			return true;
		}
		return false;
	}
	async applyPendingCancel() {
		const activeController = this.activeController;
		if (!this.pendingCancel || !activeController || !activeController.hasActivePrompt()) return false;
		const cancelled = await activeController.requestCancelActivePrompt();
		if (cancelled) this.pendingCancel = false;
		return cancelled;
	}
	async setSessionMode(modeId, timeoutMs) {
		this.assertCanHandleControlRequest();
		const activeController = this.activeController;
		if (activeController) {
			await this.options.withTimeout(async () => await activeController.setSessionMode(modeId), timeoutMs);
			return;
		}
		await this.options.setSessionModeFallback(modeId, timeoutMs);
	}
	async setSessionModel(modelId, timeoutMs) {
		this.assertCanHandleControlRequest();
		const activeController = this.activeController;
		if (activeController) {
			await this.options.withTimeout(async () => await activeController.setSessionModel(modelId), timeoutMs);
			return;
		}
		await this.options.setSessionModelFallback(modelId, timeoutMs);
	}
	async setSessionConfigOption(configId, value, timeoutMs) {
		this.assertCanHandleControlRequest();
		const activeController = this.activeController;
		if (activeController) return await this.options.withTimeout(async () => await activeController.setSessionConfigOption(configId, value), timeoutMs);
		return await this.options.setSessionConfigOptionFallback(configId, value, timeoutMs);
	}
};
//#endregion
//#region src/session-mode-preference.ts
function ensureAcpxState(state) {
	return state ?? {};
}
function normalizeModeId(modeId) {
	if (typeof modeId !== "string") return;
	const trimmed = modeId.trim();
	return trimmed.length > 0 ? trimmed : void 0;
}
function normalizeModelId(modelId) {
	if (typeof modelId !== "string") return;
	const trimmed = modelId.trim();
	return trimmed.length > 0 ? trimmed : void 0;
}
function getDesiredModeId(state) {
	return normalizeModeId(state?.desired_mode_id);
}
function setDesiredModeId(record, modeId) {
	const acpx = ensureAcpxState(record.acpx);
	const normalized = normalizeModeId(modeId);
	if (normalized) acpx.desired_mode_id = normalized;
	else delete acpx.desired_mode_id;
	record.acpx = acpx;
}
function getDesiredModelId(state) {
	return normalizeModelId(state?.session_options?.model);
}
function setDesiredModelId(record, modelId) {
	const acpx = ensureAcpxState(record.acpx);
	const normalized = normalizeModelId(modelId);
	const sessionOptions = { ...acpx.session_options };
	if (normalized) sessionOptions.model = normalized;
	else delete sessionOptions.model;
	if (typeof sessionOptions.model === "string" || Array.isArray(sessionOptions.allowed_tools) || typeof sessionOptions.max_turns === "number") acpx.session_options = sessionOptions;
	else delete acpx.session_options;
	record.acpx = acpx;
}
function setCurrentModelId(record, modelId) {
	const acpx = ensureAcpxState(record.acpx);
	const normalized = normalizeModelId(modelId);
	if (normalized) acpx.current_model_id = normalized;
	else delete acpx.current_model_id;
	record.acpx = acpx;
}
function syncAdvertisedModelState(record, models) {
	if (!models) return;
	const acpx = ensureAcpxState(record.acpx);
	acpx.current_model_id = models.currentModelId;
	acpx.available_models = models.availableModels.map((model) => model.modelId);
	record.acpx = acpx;
}
//#endregion
//#region src/session-runtime/lifecycle.ts
function applyLifecycleSnapshotToRecord(record, snapshot) {
	record.pid = snapshot.pid;
	record.agentStartedAt = snapshot.startedAt;
	if (snapshot.lastExit) {
		record.lastAgentExitCode = snapshot.lastExit.exitCode;
		record.lastAgentExitSignal = snapshot.lastExit.signal;
		record.lastAgentExitAt = snapshot.lastExit.exitedAt;
		record.lastAgentDisconnectReason = snapshot.lastExit.reason;
		return;
	}
	record.lastAgentExitCode = void 0;
	record.lastAgentExitSignal = void 0;
	record.lastAgentExitAt = void 0;
	record.lastAgentDisconnectReason = void 0;
}
function reconcileAgentSessionId(record, agentSessionId) {
	const normalized = normalizeRuntimeSessionId(agentSessionId);
	if (!normalized) return;
	record.agentSessionId = normalized;
}
function sessionHasAgentMessages(record) {
	return record.messages.some((message) => typeof message === "object" && message !== null && "Agent" in message);
}
function applyConversation(record, conversation) {
	record.title = conversation.title;
	record.messages = conversation.messages;
	record.updated_at = conversation.updated_at;
	record.cumulative_token_usage = conversation.cumulative_token_usage;
	record.request_token_usage = conversation.request_token_usage;
}
//#endregion
//#region src/session-runtime/connect-load.ts
const SESSION_LOAD_UNSUPPORTED_CODES = new Set([-32601, -32602]);
function shouldFallbackToNewSession(error, record) {
	if (error instanceof TimeoutError || error instanceof InterruptedError) return false;
	if (isAcpResourceNotFoundError(error)) return true;
	const acp = extractAcpError(error);
	if (acp && SESSION_LOAD_UNSUPPORTED_CODES.has(acp.code)) return true;
	if (!sessionHasAgentMessages(record)) {
		if (isAcpQueryClosedBeforeResponseError(error)) return true;
		if (acp?.code === -32603) return true;
	}
	return false;
}
function requiresSameSession(resumePolicy) {
	return resumePolicy === "same-session-only";
}
function makeSessionResumeRequiredError(params) {
	return new SessionResumeRequiredError(`Persistent ACP session ${params.record.acpSessionId} could not be resumed: ${params.reason}`, { cause: params.cause instanceof Error ? params.cause : void 0 });
}
async function connectAndLoadSession(options) {
	const record = options.record;
	const client = options.client;
	const sameSessionOnly = requiresSameSession(options.resumePolicy);
	const originalSessionId = record.acpSessionId;
	const originalAgentSessionId = record.agentSessionId;
	const desiredModeId = getDesiredModeId(record.acpx);
	const desiredModelId = getDesiredModelId(record.acpx);
	const storedProcessAlive = isProcessAlive(record.pid);
	const shouldReconnect = Boolean(record.pid) && !storedProcessAlive;
	if (options.verbose) {
		if (storedProcessAlive) process.stderr.write(`[acpx] saved session pid ${record.pid} is running; reconnecting with loadSession\n`);
		else if (shouldReconnect) process.stderr.write(`[acpx] saved session pid ${record.pid} is dead; respawning agent and attempting session/load\n`);
	}
	const reusingLoadedSession = client.hasReusableSession(record.acpSessionId);
	if (reusingLoadedSession) incrementPerfCounter("runtime.connect_and_load.reused_session");
	else await withTimeout(client.start(), options.timeoutMs);
	options.onClientAvailable?.(options.activeController);
	applyLifecycleSnapshotToRecord(record, client.getAgentLifecycleSnapshot());
	record.closed = false;
	record.closedAt = void 0;
	options.onConnectedRecord?.(record);
	let resumed = false;
	let loadError;
	let sessionId = record.acpSessionId;
	let createdFreshSession = false;
	let pendingAgentSessionId = record.agentSessionId;
	let sessionModels;
	if (reusingLoadedSession) resumed = true;
	else if (client.supportsLoadSession()) try {
		const loadResult = await withTimeout(client.loadSessionWithOptions(record.acpSessionId, record.cwd, { suppressReplayUpdates: true }), options.timeoutMs);
		reconcileAgentSessionId(record, loadResult.agentSessionId);
		sessionModels = loadResult.models;
		resumed = true;
	} catch (error) {
		loadError = formatErrorMessage(error);
		if (sameSessionOnly) throw makeSessionResumeRequiredError({
			record,
			reason: loadError,
			cause: error
		});
		if (!shouldFallbackToNewSession(error, record)) throw error;
		const createdSession = await withTimeout(client.createSession(record.cwd), options.timeoutMs);
		sessionId = createdSession.sessionId;
		createdFreshSession = true;
		pendingAgentSessionId = createdSession.agentSessionId;
		sessionModels = createdSession.models;
	}
	else {
		if (sameSessionOnly) throw makeSessionResumeRequiredError({
			record,
			reason: "agent does not support session/load"
		});
		const createdSession = await withTimeout(client.createSession(record.cwd), options.timeoutMs);
		sessionId = createdSession.sessionId;
		createdFreshSession = true;
		pendingAgentSessionId = createdSession.agentSessionId;
		sessionModels = createdSession.models;
	}
	if (createdFreshSession && desiredModeId) try {
		await withTimeout(client.setSessionMode(sessionId, desiredModeId), options.timeoutMs);
		if (options.verbose) process.stderr.write(`[acpx] replayed desired mode ${desiredModeId} on fresh ACP session ${sessionId} (previous ${originalSessionId})\n`);
	} catch (error) {
		const message = `Failed to replay saved session mode ${desiredModeId} on fresh ACP session ${sessionId}: ` + formatErrorMessage(error);
		record.acpSessionId = originalSessionId;
		record.agentSessionId = originalAgentSessionId;
		if (options.verbose) process.stderr.write(`[acpx] ${message}\n`);
		throw new SessionModeReplayError(message, {
			cause: error instanceof Error ? error : void 0,
			retryable: true
		});
	}
	if (createdFreshSession && desiredModelId && sessionModels && desiredModelId !== sessionModels.currentModelId) try {
		await withTimeout(client.setSessionModel(sessionId, desiredModelId), options.timeoutMs);
		setCurrentModelId(record, desiredModelId);
		if (options.verbose) process.stderr.write(`[acpx] replayed desired model ${desiredModelId} on fresh ACP session ${sessionId} (previous ${originalSessionId})\n`);
	} catch (error) {
		const message = `Failed to replay saved session model ${desiredModelId} on fresh ACP session ${sessionId}: ` + formatErrorMessage(error);
		record.acpSessionId = originalSessionId;
		record.agentSessionId = originalAgentSessionId;
		if (options.verbose) process.stderr.write(`[acpx] ${message}\n`);
		throw new SessionModelReplayError(message, {
			cause: error instanceof Error ? error : void 0,
			retryable: true
		});
	}
	if (createdFreshSession) {
		record.acpSessionId = sessionId;
		reconcileAgentSessionId(record, pendingAgentSessionId);
	}
	syncAdvertisedModelState(record, sessionModels);
	if (createdFreshSession && desiredModelId && sessionModels) setCurrentModelId(record, desiredModelId);
	options.onSessionIdResolved?.(sessionId);
	return {
		sessionId,
		agentSessionId: record.agentSessionId,
		resumed,
		loadError
	};
}
//#endregion
//#region src/session-runtime/prompt-runner.ts
function sessionOptionsFromRecord$1(record) {
	const stored = record.acpx?.session_options;
	if (!stored) return;
	const sessionOptions = {};
	if (typeof stored.model === "string" && stored.model.trim().length > 0) sessionOptions.model = stored.model;
	if (Array.isArray(stored.allowed_tools)) sessionOptions.allowedTools = [...stored.allowed_tools];
	if (typeof stored.max_turns === "number") sessionOptions.maxTurns = stored.max_turns;
	return Object.keys(sessionOptions).length > 0 ? sessionOptions : void 0;
}
async function withConnectedSession(options) {
	const record = await resolveSessionRecord(options.sessionRecordId);
	const client = new AcpClient({
		agentCommand: record.agentCommand,
		cwd: absolutePath(record.cwd),
		mcpServers: options.mcpServers,
		permissionMode: options.permissionMode ?? "approve-reads",
		nonInteractivePermissions: options.nonInteractivePermissions,
		authCredentials: options.authCredentials,
		authPolicy: options.authPolicy,
		verbose: options.verbose,
		sessionOptions: sessionOptionsFromRecord$1(record)
	});
	let activeSessionIdForControl = record.acpSessionId;
	let notifiedClientAvailable = false;
	const activeController = {
		hasActivePrompt: () => client.hasActivePrompt(),
		requestCancelActivePrompt: async () => await client.requestCancelActivePrompt(),
		setSessionMode: async (modeId) => {
			await client.setSessionMode(activeSessionIdForControl, modeId);
		},
		setSessionModel: async (modelId) => {
			await client.setSessionModel(activeSessionIdForControl, modelId);
		},
		setSessionConfigOption: async (configId, value) => {
			return await client.setSessionConfigOption(activeSessionIdForControl, configId, value);
		}
	};
	try {
		return await withInterrupt(async () => {
			const { sessionId: activeSessionId, resumed, loadError } = await connectAndLoadSession({
				client,
				record,
				timeoutMs: options.timeoutMs,
				verbose: options.verbose,
				activeController,
				onClientAvailable: (controller) => {
					options.onClientAvailable?.(controller);
					notifiedClientAvailable = true;
				},
				onSessionIdResolved: (sessionId) => {
					activeSessionIdForControl = sessionId;
				}
			});
			const value = await options.run(client, activeSessionId, record);
			record.lastUsedAt = isoNow();
			record.closed = false;
			record.closedAt = void 0;
			record.protocolVersion = client.initializeResult?.protocolVersion;
			record.agentCapabilities = client.initializeResult?.agentCapabilities;
			applyLifecycleSnapshotToRecord(record, client.getAgentLifecycleSnapshot());
			await writeSessionRecord(record);
			return {
				value,
				record,
				resumed,
				loadError
			};
		}, async () => {
			await client.cancelActivePrompt(2500);
			applyLifecycleSnapshotToRecord(record, client.getAgentLifecycleSnapshot());
			record.lastUsedAt = isoNow();
			await writeSessionRecord(record).catch(() => {});
			await client.close();
		});
	} finally {
		if (notifiedClientAvailable) options.onClientClosed?.();
		await client.close();
		applyLifecycleSnapshotToRecord(record, client.getAgentLifecycleSnapshot());
		await writeSessionRecord(record).catch(() => {});
	}
}
async function runSessionSetModeDirect(options) {
	const result = await withConnectedSession({
		sessionRecordId: options.sessionRecordId,
		mcpServers: options.mcpServers,
		nonInteractivePermissions: options.nonInteractivePermissions,
		authCredentials: options.authCredentials,
		authPolicy: options.authPolicy,
		timeoutMs: options.timeoutMs,
		verbose: options.verbose,
		onClientAvailable: options.onClientAvailable,
		onClientClosed: options.onClientClosed,
		run: async (client, sessionId, record) => {
			await withTimeout(client.setSessionMode(sessionId, options.modeId), options.timeoutMs);
			setDesiredModeId(record, options.modeId);
		}
	});
	return {
		record: result.record,
		resumed: result.resumed,
		loadError: result.loadError
	};
}
async function runSessionSetModelDirect(options) {
	const result = await withConnectedSession({
		sessionRecordId: options.sessionRecordId,
		mcpServers: options.mcpServers,
		nonInteractivePermissions: options.nonInteractivePermissions,
		authCredentials: options.authCredentials,
		authPolicy: options.authPolicy,
		timeoutMs: options.timeoutMs,
		verbose: options.verbose,
		onClientAvailable: options.onClientAvailable,
		onClientClosed: options.onClientClosed,
		run: async (client, sessionId, record) => {
			await withTimeout(client.setSessionModel(sessionId, options.modelId), options.timeoutMs);
			setDesiredModelId(record, options.modelId);
			setCurrentModelId(record, options.modelId);
		}
	});
	return {
		record: result.record,
		resumed: result.resumed,
		loadError: result.loadError
	};
}
async function runSessionSetConfigOptionDirect(options) {
	const result = await withConnectedSession({
		sessionRecordId: options.sessionRecordId,
		mcpServers: options.mcpServers,
		nonInteractivePermissions: options.nonInteractivePermissions,
		authCredentials: options.authCredentials,
		authPolicy: options.authPolicy,
		timeoutMs: options.timeoutMs,
		verbose: options.verbose,
		onClientAvailable: options.onClientAvailable,
		onClientClosed: options.onClientClosed,
		run: async (client, sessionId, record) => {
			const response = await withTimeout(client.setSessionConfigOption(sessionId, options.configId, options.value), options.timeoutMs);
			if (options.configId === "mode") setDesiredModeId(record, options.value);
			return response;
		}
	});
	return {
		record: result.record,
		response: result.value,
		resumed: result.resumed,
		loadError: result.loadError
	};
}
//#endregion
//#region src/session-runtime/queue-owner-process.ts
function sanitizeQueueOwnerExecArgv(execArgv = process.execArgv) {
	const sanitized = [];
	for (let index = 0; index < execArgv.length; index += 1) {
		const value = execArgv[index];
		if (value === "--experimental-test-coverage" || value === "--test") continue;
		if (value === "--test-name-pattern" || value === "--test-reporter" || value === "--test-reporter-destination") {
			index += 1;
			continue;
		}
		if (value.startsWith("--test-")) continue;
		if (value === "--inspect" || value === "--inspect-brk" || value === "--inspect-port" || value === "--inspect-publish-uid" || value.startsWith("--inspect=") || value.startsWith("--inspect-brk=") || value.startsWith("--inspect-port=") || value.startsWith("--inspect-publish-uid=") || value === "--debug-port" || value.startsWith("--debug-port=")) {
			if (value === "--inspect" || value === "--inspect-brk" || value === "--inspect-port" || value === "--inspect-publish-uid" || value === "--debug-port") index += 1;
			continue;
		}
		sanitized.push(value);
	}
	return sanitized;
}
function buildQueueOwnerArgOverride(entryPath, execArgv = process.execArgv) {
	const sanitized = sanitizeQueueOwnerExecArgv(execArgv);
	if (sanitized.length === 0) return null;
	return JSON.stringify([
		...sanitized,
		entryPath,
		"__queue-owner"
	]);
}
function resolveQueueOwnerSpawnArgs(argv = process.argv) {
	const override = process.env.ACPX_QUEUE_OWNER_ARGS;
	if (override) {
		const parsed = JSON.parse(override);
		if (Array.isArray(parsed) && parsed.length > 0 && parsed.every((value) => typeof value === "string" && value.length > 0)) return [...parsed];
		throw new Error("acpx self-spawn failed: invalid ACPX_QUEUE_OWNER_ARGS");
	}
	const entry = argv[1];
	if (!entry || entry.trim().length === 0) throw new Error("acpx self-spawn failed: missing CLI entry path");
	return [realpathSync(entry), "__queue-owner"];
}
function queueOwnerRuntimeOptionsFromSend(options) {
	return {
		sessionId: options.sessionId,
		mcpServers: options.mcpServers,
		permissionMode: options.permissionMode,
		nonInteractivePermissions: options.nonInteractivePermissions,
		authCredentials: options.authCredentials,
		authPolicy: options.authPolicy,
		suppressSdkConsoleErrors: options.suppressSdkConsoleErrors,
		verbose: options.verbose,
		ttlMs: options.ttlMs,
		maxQueueDepth: options.maxQueueDepth,
		promptRetries: options.promptRetries
	};
}
function buildQueueOwnerSpawnOptions(payload) {
	return {
		detached: true,
		stdio: "ignore",
		env: {
			...process.env,
			ACPX_QUEUE_OWNER_PAYLOAD: payload
		},
		windowsHide: true
	};
}
function spawnQueueOwnerProcess(options) {
	const payload = JSON.stringify(options);
	spawn(process.execPath, resolveQueueOwnerSpawnArgs(), buildQueueOwnerSpawnOptions(payload)).unref();
}
//#endregion
//#region src/session-runtime.ts
const DEFAULT_QUEUE_OWNER_TTL_MS = 3e5;
const INTERRUPT_CANCEL_WAIT_MS = 2500;
const QUEUE_OWNER_STARTUP_MAX_ATTEMPTS = 120;
const QUEUE_OWNER_HEARTBEAT_INTERVAL_MS = 5e3;
function sessionOptionsFromRecord(record) {
	const stored = record.acpx?.session_options;
	if (!stored) return;
	const sessionOptions = {};
	if (typeof stored.model === "string" && stored.model.trim().length > 0) sessionOptions.model = stored.model;
	if (Array.isArray(stored.allowed_tools)) sessionOptions.allowedTools = [...stored.allowed_tools];
	if (typeof stored.max_turns === "number") sessionOptions.maxTurns = stored.max_turns;
	return Object.keys(sessionOptions).length > 0 ? sessionOptions : void 0;
}
function persistSessionOptions(record, options) {
	const next = options && {
		model: typeof options.model === "string" ? options.model : void 0,
		allowed_tools: Array.isArray(options.allowedTools) ? [...options.allowedTools] : void 0,
		max_turns: typeof options.maxTurns === "number" ? options.maxTurns : void 0
	};
	if (Boolean(next && (typeof next.model === "string" && next.model.trim().length > 0 || Array.isArray(next.allowed_tools) && next.allowed_tools.length > 0 || typeof next.max_turns === "number")) && next) {
		record.acpx = {
			...record.acpx,
			session_options: next
		};
		return;
	}
	if (!record.acpx) return;
	delete record.acpx.session_options;
}
function toPromptResult(stopReason, sessionId, client) {
	return {
		stopReason,
		sessionId,
		permissionStats: client.getPermissionStats()
	};
}
async function applyRequestedModelIfAdvertised(params) {
	const requestedModel = typeof params.requestedModel === "string" ? params.requestedModel.trim() : "";
	if (!requestedModel || !params.models) return false;
	if (params.models.currentModelId === requestedModel) return true;
	await withTimeout(params.client.setSessionModel(params.sessionId, requestedModel), params.timeoutMs);
	return true;
}
var QueueTaskOutputFormatter = class {
	requestId;
	send;
	constructor(task) {
		this.requestId = task.requestId;
		this.send = task.send;
	}
	setContext(_context) {}
	onAcpMessage(message) {
		this.send({
			type: "event",
			requestId: this.requestId,
			message
		});
	}
	onError(params) {
		this.send({
			type: "error",
			requestId: this.requestId,
			code: params.code,
			detailCode: params.detailCode,
			origin: params.origin,
			message: params.message,
			retryable: params.retryable,
			acp: params.acp
		});
	}
	flush() {}
};
const DISCARD_OUTPUT_FORMATTER = {
	setContext(_context) {},
	onAcpMessage() {},
	onError() {},
	flush() {}
};
function jsonRpcIdKey(value) {
	if (typeof value === "string") return `s:${value}`;
	if (typeof value === "number" && Number.isFinite(value)) return `n:${value}`;
}
function extractJsonRpcRequestInfo(message) {
	const candidate = message;
	if (typeof candidate.method !== "string") return;
	const idKey = jsonRpcIdKey(candidate.id);
	if (!idKey) return;
	return {
		idKey,
		method: candidate.method
	};
}
function extractJsonRpcResponseInfo(message) {
	const candidate = message;
	const idKey = jsonRpcIdKey(candidate.id);
	if (!idKey) return;
	const hasError = Object.hasOwn(candidate, "error");
	if (!hasError && !Object.hasOwn(candidate, "result")) return;
	return {
		idKey,
		hasError
	};
}
function filterRecoverableLoadFallbackOutput(messages) {
	const requestMethodById = /* @__PURE__ */ new Map();
	const failedLoadRequestIds = /* @__PURE__ */ new Set();
	for (const message of messages) {
		const request = extractJsonRpcRequestInfo(message);
		if (request) {
			requestMethodById.set(request.idKey, request.method);
			continue;
		}
		const response = extractJsonRpcResponseInfo(message);
		if (!response || !response.hasError) continue;
		if (requestMethodById.get(response.idKey) === "session/load") failedLoadRequestIds.add(response.idKey);
	}
	if (failedLoadRequestIds.size === 0) return messages;
	return messages.filter((message) => {
		const request = extractJsonRpcRequestInfo(message);
		if (request && request.method === "session/load" && failedLoadRequestIds.has(request.idKey)) return false;
		const response = extractJsonRpcResponseInfo(message);
		if (response && failedLoadRequestIds.has(response.idKey)) return false;
		return true;
	});
}
function normalizeQueueOwnerTtlMs(ttlMs) {
	if (ttlMs == null) return DEFAULT_QUEUE_OWNER_TTL_MS;
	if (!Number.isFinite(ttlMs) || ttlMs < 0) return DEFAULT_QUEUE_OWNER_TTL_MS;
	return Math.round(ttlMs);
}
function emitPromptRetryNotice(params) {
	if (params.suppressSdkConsoleErrors) return;
	process.stderr.write(`[acpx] prompt failed (${formatErrorMessage(params.error)}), retrying in ${params.delayMs}ms (attempt ${params.attempt}/${params.maxRetries})\n`);
}
async function runQueuedTask(sessionRecordId, task, options) {
	const outputFormatter = task.waitForCompletion ? new QueueTaskOutputFormatter(task) : DISCARD_OUTPUT_FORMATTER;
	try {
		const result = await runSessionPrompt({
			sessionRecordId,
			mcpServers: options.mcpServers,
			prompt: task.prompt ?? textPrompt(task.message),
			permissionMode: task.permissionMode,
			resumePolicy: task.resumePolicy,
			nonInteractivePermissions: task.nonInteractivePermissions ?? options.nonInteractivePermissions,
			authCredentials: options.authCredentials,
			authPolicy: options.authPolicy,
			outputFormatter,
			timeoutMs: task.timeoutMs,
			suppressSdkConsoleErrors: task.suppressSdkConsoleErrors ?? options.suppressSdkConsoleErrors,
			verbose: options.verbose,
			promptRetries: options.promptRetries,
			onClientAvailable: options.onClientAvailable,
			onClientClosed: options.onClientClosed,
			onPromptActive: options.onPromptActive,
			client: options.sharedClient
		});
		if (task.waitForCompletion) task.send({
			type: "result",
			requestId: task.requestId,
			result
		});
	} catch (error) {
		const normalizedError = normalizeOutputError(error, {
			origin: "runtime",
			detailCode: "QUEUE_RUNTIME_PROMPT_FAILED"
		});
		const alreadyEmitted = error.outputAlreadyEmitted === true;
		if (task.waitForCompletion) task.send({
			type: "error",
			requestId: task.requestId,
			code: normalizedError.code,
			detailCode: normalizedError.detailCode,
			origin: normalizedError.origin,
			message: normalizedError.message,
			retryable: normalizedError.retryable,
			acp: normalizedError.acp,
			outputAlreadyEmitted: alreadyEmitted
		});
		if (error instanceof InterruptedError) throw error;
	} finally {
		task.close();
	}
}
async function runSessionPrompt(options) {
	const stopTotalTimer = startPerfTimer("runtime.prompt.total");
	const output = options.outputFormatter;
	const record = await measurePerf("session.resolve_prompt_record", async () => {
		return await resolveSessionRecord(options.sessionRecordId);
	});
	const conversation = cloneSessionConversation(record);
	let acpxState = cloneSessionAcpxState(record.acpx);
	recordPromptSubmission(conversation, options.prompt, isoNow());
	output.setContext({ sessionId: record.acpxRecordId });
	const eventWriter = await measurePerf("session.events.open", async () => {
		return await SessionEventWriter.open(record);
	});
	const pendingMessages = [];
	const pendingConnectOutputMessages = [];
	let bufferingConnectOutput = true;
	let promptTurnActive = false;
	let promptTurnHadSideEffects = false;
	let sawAcpMessage = false;
	let eventWriterClosed = false;
	const closeEventWriter = async (checkpoint) => {
		if (eventWriterClosed) return;
		eventWriterClosed = true;
		await eventWriter.close({ checkpoint });
	};
	const flushPendingMessages = async (checkpoint = false) => {
		if (pendingMessages.length === 0) return;
		const batch = pendingMessages.splice(0, pendingMessages.length);
		await measurePerf("session.events.flush_pending", async () => {
			await eventWriter.appendMessages(batch, { checkpoint });
		});
	};
	const ownClient = options.client == null;
	const client = options.client ?? new AcpClient({
		agentCommand: record.agentCommand,
		cwd: absolutePath(record.cwd),
		mcpServers: options.mcpServers,
		permissionMode: options.permissionMode,
		nonInteractivePermissions: options.nonInteractivePermissions,
		authCredentials: options.authCredentials,
		authPolicy: options.authPolicy,
		suppressSdkConsoleErrors: options.suppressSdkConsoleErrors,
		verbose: options.verbose,
		sessionOptions: sessionOptionsFromRecord(record)
	});
	client.updateRuntimeOptions({
		permissionMode: options.permissionMode,
		nonInteractivePermissions: options.nonInteractivePermissions,
		suppressSdkConsoleErrors: options.suppressSdkConsoleErrors,
		verbose: options.verbose
	});
	client.setEventHandlers({
		onAcpMessage: (direction, message) => {
			sawAcpMessage = true;
			pendingMessages.push(message);
			options.onAcpMessage?.(direction, message);
		},
		onAcpOutputMessage: (_direction, message) => {
			if (bufferingConnectOutput) {
				pendingConnectOutputMessages.push(message);
				return;
			}
			output.onAcpMessage(message);
		},
		onSessionUpdate: (notification) => {
			if (promptTurnActive) promptTurnHadSideEffects = true;
			acpxState = recordSessionUpdate(conversation, acpxState, notification);
			trimConversationForRuntime(conversation);
			options.onSessionUpdate?.(notification);
		},
		onClientOperation: (operation) => {
			if (promptTurnActive) promptTurnHadSideEffects = true;
			acpxState = recordClientOperation(conversation, acpxState, operation);
			trimConversationForRuntime(conversation);
			options.onClientOperation?.(operation);
		}
	});
	let activeSessionIdForControl = record.acpSessionId;
	let notifiedClientAvailable = false;
	const activeController = {
		hasActivePrompt: () => client.hasActivePrompt(),
		requestCancelActivePrompt: async () => await client.requestCancelActivePrompt(),
		setSessionMode: async (modeId) => {
			await client.setSessionMode(activeSessionIdForControl, modeId);
		},
		setSessionModel: async (modelId) => {
			await client.setSessionModel(activeSessionIdForControl, modelId);
		},
		setSessionConfigOption: async (configId, value) => {
			return await client.setSessionConfigOption(activeSessionIdForControl, configId, value);
		}
	};
	try {
		return await withInterrupt(async () => {
			const connectStartedAt = Date.now();
			const { sessionId: activeSessionId, resumed, loadError } = await measurePerf("runtime.connect_and_load", async () => {
				try {
					return await connectAndLoadSession({
						client,
						record,
						resumePolicy: options.resumePolicy,
						timeoutMs: options.timeoutMs,
						verbose: options.verbose,
						activeController,
						onClientAvailable: (controller) => {
							options.onClientAvailable?.(controller);
							notifiedClientAvailable = true;
						},
						onConnectedRecord: (connectedRecord) => {
							connectedRecord.lastPromptAt = isoNow();
						},
						onSessionIdResolved: (sessionId) => {
							activeSessionIdForControl = sessionId;
						}
					});
				} catch (error) {
					bufferingConnectOutput = false;
					for (const message of pendingConnectOutputMessages) output.onAcpMessage(message);
					pendingConnectOutputMessages.length = 0;
					throw error;
				}
			});
			bufferingConnectOutput = false;
			const connectOutputMessages = loadError == null ? pendingConnectOutputMessages : filterRecoverableLoadFallbackOutput(pendingConnectOutputMessages);
			for (const message of connectOutputMessages) output.onAcpMessage(message);
			pendingConnectOutputMessages.length = 0;
			if (options.verbose) process.stderr.write(`[acpx] ${formatPerfMetric("prompt.connect_and_load", Date.now() - connectStartedAt)}\n`);
			output.setContext({ sessionId: record.acpxRecordId });
			await flushPendingMessages(false);
			const maxRetries = options.promptRetries ?? 0;
			let response;
			promptTurnActive = true;
			for (let attempt = 0;; attempt++) try {
				const promptStartedAt = Date.now();
				const promptPromise = client.prompt(activeSessionId, options.prompt);
				if (attempt === 0 && options.onPromptActive) try {
					await options.onPromptActive();
				} catch (error) {
					if (options.verbose) process.stderr.write("[acpx] onPromptActive hook failed: " + formatErrorMessage(error) + "\n");
				}
				response = await measurePerf("runtime.prompt.agent_turn", async () => {
					return await withTimeout(promptPromise, options.timeoutMs);
				});
				if (options.verbose) process.stderr.write(`[acpx] ${formatPerfMetric("prompt.agent_turn", Date.now() - promptStartedAt)}\n`);
				break;
			} catch (error) {
				const snapshot = client.getAgentLifecycleSnapshot();
				const agentCrashed = snapshot.lastExit?.unexpectedDuringPrompt === true;
				if (attempt < maxRetries && !agentCrashed && !promptTurnHadSideEffects && isRetryablePromptError(error)) {
					const delayMs = Math.min(1e3 * 2 ** attempt, 1e4);
					emitPromptRetryNotice({
						error,
						delayMs,
						attempt: attempt + 1,
						maxRetries,
						suppressSdkConsoleErrors: options.suppressSdkConsoleErrors
					});
					await waitMs$1(delayMs);
					if (!promptTurnHadSideEffects) continue;
				}
				promptTurnActive = false;
				applyLifecycleSnapshotToRecord(record, snapshot);
				const lastExit = snapshot.lastExit;
				if (lastExit?.unexpectedDuringPrompt && options.verbose) process.stderr.write("[acpx] agent disconnected during prompt (" + lastExit.reason + ", exit=" + lastExit.exitCode + ", signal=" + (lastExit.signal ?? "none") + ")\n");
				const normalizedError = normalizeOutputError(error, { origin: "runtime" });
				await flushPendingMessages(false).catch(() => {});
				output.flush();
				record.lastUsedAt = isoNow();
				applyConversation(record, conversation);
				record.acpx = acpxState;
				const propagated = error instanceof Error ? error : new Error(formatErrorMessage(error));
				propagated.outputAlreadyEmitted = sawAcpMessage;
				propagated.normalizedOutputError = normalizedError;
				throw propagated;
			}
			promptTurnActive = false;
			await flushPendingMessages(false);
			output.flush();
			record.lastUsedAt = isoNow();
			record.closed = false;
			record.closedAt = void 0;
			record.protocolVersion = client.initializeResult?.protocolVersion;
			record.agentCapabilities = client.initializeResult?.agentCapabilities;
			applyConversation(record, conversation);
			record.acpx = acpxState;
			applyLifecycleSnapshotToRecord(record, client.getAgentLifecycleSnapshot());
			stopTotalTimer();
			return {
				...toPromptResult(response.stopReason, record.acpxRecordId, client),
				record,
				resumed,
				loadError
			};
		}, async () => {
			await client.cancelActivePrompt(INTERRUPT_CANCEL_WAIT_MS);
			applyLifecycleSnapshotToRecord(record, client.getAgentLifecycleSnapshot());
			record.lastUsedAt = isoNow();
			applyConversation(record, conversation);
			record.acpx = acpxState;
			await flushPendingMessages(false).catch(() => {});
			if (ownClient) await client.close();
		});
	} finally {
		if (options.verbose) process.stderr.write(`[acpx] ${formatPerfMetric("prompt.total", stopTotalTimer())}\n`);
		else stopTotalTimer();
		if (notifiedClientAvailable) options.onClientClosed?.();
		client.clearEventHandlers();
		if (ownClient) await client.close();
		applyLifecycleSnapshotToRecord(record, client.getAgentLifecycleSnapshot());
		applyConversation(record, conversation);
		record.acpx = acpxState;
		await flushPendingMessages(false).catch(() => {});
		await closeEventWriter(true).catch(() => {});
	}
}
async function runOnce(options) {
	const output = options.outputFormatter;
	let promptTurnActive = false;
	let promptTurnHadSideEffects = false;
	const client = new AcpClient({
		agentCommand: options.agentCommand,
		cwd: absolutePath(options.cwd),
		mcpServers: options.mcpServers,
		permissionMode: options.permissionMode,
		nonInteractivePermissions: options.nonInteractivePermissions,
		authCredentials: options.authCredentials,
		authPolicy: options.authPolicy,
		suppressSdkConsoleErrors: options.suppressSdkConsoleErrors,
		verbose: options.verbose,
		onAcpMessage: options.onAcpMessage,
		onAcpOutputMessage: (_direction, message) => output.onAcpMessage(message),
		onSessionUpdate: (notification) => {
			if (promptTurnActive) promptTurnHadSideEffects = true;
			options.onSessionUpdate?.(notification);
		},
		onClientOperation: (operation) => {
			if (promptTurnActive) promptTurnHadSideEffects = true;
			options.onClientOperation?.(operation);
		},
		sessionOptions: options.sessionOptions
	});
	try {
		return await withInterrupt(async () => {
			await measurePerf("runtime.exec.start", async () => {
				await withTimeout(client.start(), options.timeoutMs);
			});
			const createdSession = await measurePerf("runtime.exec.create_session", async () => {
				return await withTimeout(client.createSession(absolutePath(options.cwd)), options.timeoutMs);
			});
			const sessionId = createdSession.sessionId;
			await applyRequestedModelIfAdvertised({
				client,
				sessionId,
				requestedModel: options.sessionOptions?.model,
				models: createdSession.models,
				timeoutMs: options.timeoutMs
			});
			output.setContext({ sessionId });
			const maxRetries = options.promptRetries ?? 0;
			let response;
			promptTurnActive = true;
			for (let attempt = 0;; attempt++) try {
				response = await measurePerf("runtime.exec.prompt", async () => {
					return await withTimeout(client.prompt(sessionId, options.prompt), options.timeoutMs);
				});
				break;
			} catch (error) {
				if (attempt < maxRetries && !promptTurnHadSideEffects && isRetryablePromptError(error)) {
					const delayMs = Math.min(1e3 * 2 ** attempt, 1e4);
					emitPromptRetryNotice({
						error,
						delayMs,
						attempt: attempt + 1,
						maxRetries,
						suppressSdkConsoleErrors: options.suppressSdkConsoleErrors
					});
					await waitMs$1(delayMs);
					if (!promptTurnHadSideEffects) continue;
				}
				promptTurnActive = false;
				throw error;
			}
			promptTurnActive = false;
			output.flush();
			return toPromptResult(response.stopReason, sessionId, client);
		}, async () => {
			await client.cancelActivePrompt(INTERRUPT_CANCEL_WAIT_MS);
			await client.close();
		});
	} finally {
		await client.close();
	}
}
async function createSessionRecordWithClient(client, options) {
	const cwd = absolutePath(options.cwd);
	await measurePerf("runtime.session_create.start", async () => {
		await withTimeout(client.start(), options.timeoutMs);
	});
	let sessionId;
	let agentSessionId;
	let sessionModels;
	let requestedModelApplied = false;
	if (options.resumeSessionId) {
		if (!client.supportsLoadSession()) throw new Error(`Agent command "${options.agentCommand}" does not support session/load; cannot resume session ${options.resumeSessionId}`);
		try {
			const loadedSession = await withTimeout(client.loadSession(options.resumeSessionId, cwd), options.timeoutMs);
			sessionId = options.resumeSessionId;
			agentSessionId = normalizeRuntimeSessionId(loadedSession.agentSessionId);
			sessionModels = loadedSession.models;
			requestedModelApplied = await applyRequestedModelIfAdvertised({
				client,
				sessionId,
				requestedModel: options.sessionOptions?.model,
				models: loadedSession.models,
				timeoutMs: options.timeoutMs
			});
		} catch (error) {
			throw new Error(`Failed to resume ACP session ${options.resumeSessionId}: ${formatErrorMessage(error)}`, { cause: error });
		}
	} else {
		const createdSession = await measurePerf("runtime.session_create.create_session", async () => {
			return await withTimeout(client.createSession(cwd), options.timeoutMs);
		});
		sessionId = createdSession.sessionId;
		agentSessionId = normalizeRuntimeSessionId(createdSession.agentSessionId);
		sessionModels = createdSession.models;
		requestedModelApplied = await applyRequestedModelIfAdvertised({
			client,
			sessionId,
			requestedModel: options.sessionOptions?.model,
			models: createdSession.models,
			timeoutMs: options.timeoutMs
		});
	}
	const lifecycle = client.getAgentLifecycleSnapshot();
	const now = isoNow();
	const record = {
		schema: SESSION_RECORD_SCHEMA,
		acpxRecordId: sessionId,
		acpSessionId: sessionId,
		agentSessionId,
		agentCommand: options.agentCommand,
		cwd,
		name: normalizeName(options.name),
		createdAt: now,
		lastUsedAt: now,
		lastSeq: 0,
		lastRequestId: void 0,
		eventLog: defaultSessionEventLog(sessionId),
		closed: false,
		closedAt: void 0,
		pid: lifecycle.pid,
		agentStartedAt: lifecycle.startedAt,
		protocolVersion: client.initializeResult?.protocolVersion,
		agentCapabilities: client.initializeResult?.agentCapabilities,
		...createSessionConversation(now),
		acpx: {}
	};
	persistSessionOptions(record, options.sessionOptions);
	syncAdvertisedModelState(record, sessionModels);
	if (requestedModelApplied) setCurrentModelId(record, options.sessionOptions?.model);
	await writeSessionRecord(record);
	return record;
}
async function createSessionWithClient(options) {
	const client = new AcpClient({
		agentCommand: options.agentCommand,
		cwd: absolutePath(options.cwd),
		mcpServers: options.mcpServers,
		permissionMode: options.permissionMode,
		nonInteractivePermissions: options.nonInteractivePermissions,
		authCredentials: options.authCredentials,
		authPolicy: options.authPolicy,
		verbose: options.verbose,
		sessionOptions: options.sessionOptions
	});
	try {
		return {
			record: await withInterrupt(async () => {
				return await createSessionRecordWithClient(client, options);
			}, async () => {
				await client.close();
			}),
			client
		};
	} catch (error) {
		await client.close();
		throw error;
	}
}
async function createSession(options) {
	const { record, client } = await createSessionWithClient(options);
	try {
		return record;
	} finally {
		await client.close();
	}
}
async function ensureSession(options) {
	const cwd = absolutePath(options.cwd);
	const gitRoot = findGitRepositoryRoot(cwd);
	const walkBoundary = options.walkBoundary ?? gitRoot ?? cwd;
	const existing = await findSessionByDirectoryWalk({
		agentCommand: options.agentCommand,
		cwd,
		name: options.name,
		boundary: walkBoundary
	});
	if (existing) {
		const requestedModel = options.sessionOptions?.model;
		if (requestedModel) return {
			record: (await setSessionModel({
				sessionId: existing.acpxRecordId,
				modelId: requestedModel,
				mcpServers: options.mcpServers,
				nonInteractivePermissions: options.nonInteractivePermissions,
				authCredentials: options.authCredentials,
				authPolicy: options.authPolicy,
				timeoutMs: options.timeoutMs,
				verbose: options.verbose
			})).record,
			created: false
		};
		return {
			record: existing,
			created: false
		};
	}
	return {
		record: await createSession({
			agentCommand: options.agentCommand,
			cwd,
			name: options.name,
			resumeSessionId: options.resumeSessionId,
			mcpServers: options.mcpServers,
			permissionMode: options.permissionMode,
			nonInteractivePermissions: options.nonInteractivePermissions,
			authCredentials: options.authCredentials,
			authPolicy: options.authPolicy,
			timeoutMs: options.timeoutMs,
			verbose: options.verbose,
			sessionOptions: options.sessionOptions
		}),
		created: true
	};
}
async function submitToRunningOwner(options, waitForCompletion) {
	return await trySubmitToRunningOwner({
		sessionId: options.sessionId,
		message: promptToDisplayText(options.prompt),
		prompt: options.prompt,
		permissionMode: options.permissionMode,
		nonInteractivePermissions: options.nonInteractivePermissions,
		outputFormatter: options.outputFormatter,
		errorEmissionPolicy: options.errorEmissionPolicy,
		timeoutMs: options.timeoutMs,
		suppressSdkConsoleErrors: options.suppressSdkConsoleErrors,
		waitForCompletion,
		verbose: options.verbose
	});
}
async function runSessionQueueOwner(options) {
	const lease = await tryAcquireQueueOwnerLease(options.sessionId);
	if (!lease) return;
	const sessionRecord = await resolveSessionRecord(options.sessionId);
	let owner;
	let heartbeatTimer;
	const sharedClient = new AcpClient({
		agentCommand: sessionRecord.agentCommand,
		cwd: absolutePath(sessionRecord.cwd),
		mcpServers: options.mcpServers,
		permissionMode: options.permissionMode,
		nonInteractivePermissions: options.nonInteractivePermissions,
		authCredentials: options.authCredentials,
		authPolicy: options.authPolicy,
		suppressSdkConsoleErrors: options.suppressSdkConsoleErrors,
		verbose: options.verbose,
		sessionOptions: sessionOptionsFromRecord(sessionRecord)
	});
	const ttlMs = normalizeQueueOwnerTtlMs(options.ttlMs);
	const maxQueueDepth = Math.max(1, Math.round(options.maxQueueDepth ?? 16));
	const taskPollTimeoutMs = ttlMs === 0 ? void 0 : ttlMs;
	const initialTaskPollTimeoutMs = taskPollTimeoutMs == null ? void 0 : Math.max(taskPollTimeoutMs, 1e3);
	const turnController = new QueueOwnerTurnController({
		withTimeout: async (run, timeoutMs) => await withTimeout(run(), timeoutMs),
		setSessionModeFallback: async (modeId, timeoutMs) => {
			await runSessionSetModeDirect({
				sessionRecordId: options.sessionId,
				modeId,
				mcpServers: options.mcpServers,
				nonInteractivePermissions: options.nonInteractivePermissions,
				authCredentials: options.authCredentials,
				authPolicy: options.authPolicy,
				timeoutMs,
				verbose: options.verbose
			});
		},
		setSessionModelFallback: async (modelId, timeoutMs) => {
			await runSessionSetModelDirect({
				sessionRecordId: options.sessionId,
				modelId,
				mcpServers: options.mcpServers,
				nonInteractivePermissions: options.nonInteractivePermissions,
				authCredentials: options.authCredentials,
				authPolicy: options.authPolicy,
				timeoutMs,
				verbose: options.verbose
			});
		},
		setSessionConfigOptionFallback: async (configId, value, timeoutMs) => {
			return (await runSessionSetConfigOptionDirect({
				sessionRecordId: options.sessionId,
				configId,
				value,
				mcpServers: options.mcpServers,
				nonInteractivePermissions: options.nonInteractivePermissions,
				authCredentials: options.authCredentials,
				authPolicy: options.authPolicy,
				timeoutMs,
				verbose: options.verbose
			})).response;
		}
	});
	const applyPendingCancel = async () => {
		return await turnController.applyPendingCancel();
	};
	const scheduleApplyPendingCancel = () => {
		applyPendingCancel().catch((error) => {
			if (options.verbose) process.stderr.write(`[acpx] failed to apply deferred cancel: ${formatErrorMessage(error)}\n`);
		});
	};
	const setActiveController = (controller) => {
		turnController.setActiveController(controller);
		scheduleApplyPendingCancel();
	};
	const clearActiveController = () => {
		turnController.clearActiveController();
	};
	const runPromptTurn = async (run) => {
		turnController.beginTurn();
		try {
			return await run();
		} finally {
			turnController.endTurn();
		}
	};
	try {
		owner = await SessionQueueOwner.start(lease, {
			cancelPrompt: async () => {
				if (!await turnController.requestCancel()) return false;
				await applyPendingCancel();
				return true;
			},
			setSessionMode: async (modeId, timeoutMs) => {
				await turnController.setSessionMode(modeId, timeoutMs);
			},
			setSessionModel: async (modelId, timeoutMs) => {
				await turnController.setSessionModel(modelId, timeoutMs);
			},
			setSessionConfigOption: async (configId, value, timeoutMs) => {
				return await turnController.setSessionConfigOption(configId, value, timeoutMs);
			}
		}, {
			maxQueueDepth,
			onQueueDepthChanged: (queueDepth) => {
				setPerfGauge("queue.owner.depth", queueDepth);
				refreshQueueOwnerLease(lease, { queueDepth }).catch(() => {});
			}
		});
		if (options.verbose) process.stderr.write(`[acpx] queue owner ready for session ${options.sessionId} (ttlMs=${ttlMs}, maxQueueDepth=${maxQueueDepth})\n`);
		await refreshQueueOwnerLease(lease, { queueDepth: owner.queueDepth() }).catch(() => {});
		heartbeatTimer = setInterval(() => {
			refreshQueueOwnerLease(lease, { queueDepth: owner?.queueDepth() ?? 0 }).catch(() => {});
		}, QUEUE_OWNER_HEARTBEAT_INTERVAL_MS);
		let isFirstTask = true;
		while (true) {
			const pollTimeoutMs = isFirstTask ? initialTaskPollTimeoutMs : taskPollTimeoutMs;
			const task = await owner.nextTask(pollTimeoutMs);
			if (!task) break;
			isFirstTask = false;
			await runPromptTurn(async () => {
				try {
					await runQueuedTask(options.sessionId, task, {
						sharedClient,
						verbose: options.verbose,
						mcpServers: options.mcpServers,
						nonInteractivePermissions: options.nonInteractivePermissions,
						authCredentials: options.authCredentials,
						authPolicy: options.authPolicy,
						suppressSdkConsoleErrors: options.suppressSdkConsoleErrors,
						promptRetries: options.promptRetries,
						onClientAvailable: setActiveController,
						onClientClosed: clearActiveController,
						onPromptActive: async () => {
							turnController.markPromptActive();
							await applyPendingCancel();
						}
					});
				} finally {
					checkpointPerfMetricsCapture();
				}
			});
		}
	} finally {
		if (heartbeatTimer) clearInterval(heartbeatTimer);
		turnController.beginClosing();
		if (owner) await owner.close();
		await sharedClient.close().catch(() => {});
		try {
			const record = await resolveSessionRecord(options.sessionId);
			applyLifecycleSnapshotToRecord(record, sharedClient.getAgentLifecycleSnapshot());
			await writeSessionRecord(record);
		} catch {}
		await releaseQueueOwnerLease(lease);
		if (options.verbose) process.stderr.write(`[acpx] queue owner stopped for session ${options.sessionId}\n`);
	}
}
async function sendSession(options) {
	const waitForCompletion = options.waitForCompletion !== false;
	const queuedToOwner = await submitToRunningOwner(options, waitForCompletion);
	if (queuedToOwner) return queuedToOwner;
	spawnQueueOwnerProcess(queueOwnerRuntimeOptionsFromSend(options));
	for (let attempt = 0; attempt < QUEUE_OWNER_STARTUP_MAX_ATTEMPTS; attempt += 1) {
		const queued = await submitToRunningOwner(options, waitForCompletion);
		if (queued) return queued;
		await waitMs$1(50);
	}
	throw new Error(`Session queue owner failed to start for session ${options.sessionId}`);
}
async function sendSessionDirect(options) {
	return await runSessionPrompt({
		sessionRecordId: options.sessionId,
		prompt: options.prompt,
		mcpServers: options.mcpServers,
		permissionMode: options.permissionMode,
		resumePolicy: options.resumePolicy,
		nonInteractivePermissions: options.nonInteractivePermissions,
		authCredentials: options.authCredentials,
		authPolicy: options.authPolicy,
		outputFormatter: options.outputFormatter,
		onAcpMessage: options.onAcpMessage,
		onSessionUpdate: options.onSessionUpdate,
		onClientOperation: options.onClientOperation,
		timeoutMs: options.timeoutMs,
		suppressSdkConsoleErrors: options.suppressSdkConsoleErrors,
		verbose: options.verbose,
		client: options.client
	});
}
async function cancelSessionPrompt(options) {
	const cancelled = await tryCancelOnRunningOwner(options);
	return {
		sessionId: options.sessionId,
		cancelled: cancelled === true
	};
}
async function setSessionMode(options) {
	if (await trySetModeOnRunningOwner(options.sessionId, options.modeId, options.timeoutMs, options.verbose)) {
		const record = await resolveSessionRecord(options.sessionId);
		setDesiredModeId(record, options.modeId);
		await writeSessionRecord(record);
		return {
			record,
			resumed: false
		};
	}
	return await runSessionSetModeDirect({
		sessionRecordId: options.sessionId,
		modeId: options.modeId,
		mcpServers: options.mcpServers,
		nonInteractivePermissions: options.nonInteractivePermissions,
		authCredentials: options.authCredentials,
		authPolicy: options.authPolicy,
		timeoutMs: options.timeoutMs,
		verbose: options.verbose
	});
}
async function setSessionModel(options) {
	if (await trySetModelOnRunningOwner(options.sessionId, options.modelId, options.timeoutMs, options.verbose)) {
		const record = await resolveSessionRecord(options.sessionId);
		setDesiredModelId(record, options.modelId);
		setCurrentModelId(record, options.modelId);
		await writeSessionRecord(record);
		return {
			record,
			resumed: false
		};
	}
	return await runSessionSetModelDirect({
		sessionRecordId: options.sessionId,
		modelId: options.modelId,
		mcpServers: options.mcpServers,
		nonInteractivePermissions: options.nonInteractivePermissions,
		authCredentials: options.authCredentials,
		authPolicy: options.authPolicy,
		timeoutMs: options.timeoutMs,
		verbose: options.verbose
	});
}
async function setSessionConfigOption(options) {
	const ownerResponse = await trySetConfigOptionOnRunningOwner(options.sessionId, options.configId, options.value, options.timeoutMs, options.verbose);
	if (ownerResponse) {
		const record = await resolveSessionRecord(options.sessionId);
		if (options.configId === "mode") {
			setDesiredModeId(record, options.value);
			await writeSessionRecord(record);
		}
		return {
			record,
			response: ownerResponse,
			resumed: false
		};
	}
	return await runSessionSetConfigOptionDirect({
		sessionRecordId: options.sessionId,
		configId: options.configId,
		value: options.value,
		mcpServers: options.mcpServers,
		nonInteractivePermissions: options.nonInteractivePermissions,
		authCredentials: options.authCredentials,
		authPolicy: options.authPolicy,
		timeoutMs: options.timeoutMs,
		verbose: options.verbose
	});
}
function firstAgentCommandToken(command) {
	const trimmed = command.trim();
	if (!trimmed) return;
	const token = trimmed.split(/\s+/, 1)[0];
	return token.length > 0 ? token : void 0;
}
async function isLikelyMatchingProcess(pid, agentCommand) {
	const expectedToken = firstAgentCommandToken(agentCommand);
	if (!expectedToken) return false;
	const procCmdline = `/proc/${pid}/cmdline`;
	try {
		const argv = (await fs$1.readFile(procCmdline, "utf8")).split("\0").map((entry) => entry.trim()).filter((entry) => entry.length > 0);
		if (argv.length === 0) return false;
		const executableBase = path.basename(argv[0]);
		const expectedBase = path.basename(expectedToken);
		return executableBase === expectedBase || argv.some((entry) => path.basename(entry) === expectedBase);
	} catch {
		return true;
	}
}
async function closeSession(sessionId) {
	const record = await resolveSessionRecord(sessionId);
	await terminateQueueOwnerForSession(record.acpxRecordId);
	if (record.pid != null && isProcessAlive(record.pid) && await isLikelyMatchingProcess(record.pid, record.agentCommand)) await terminateProcess(record.pid);
	record.pid = void 0;
	record.closed = true;
	record.closedAt = isoNow();
	await writeSessionRecord(record);
	return record;
}
//#endregion
//#region src/session.ts
var session_exports = /* @__PURE__ */ __exportAll({
	DEFAULT_HISTORY_LIMIT: () => 20,
	DEFAULT_QUEUE_OWNER_TTL_MS: () => DEFAULT_QUEUE_OWNER_TTL_MS,
	InterruptedError: () => InterruptedError,
	TimeoutError: () => TimeoutError,
	cancelSessionPrompt: () => cancelSessionPrompt,
	closeSession: () => closeSession,
	createSession: () => createSession,
	createSessionWithClient: () => createSessionWithClient,
	ensureSession: () => ensureSession,
	findGitRepositoryRoot: () => findGitRepositoryRoot,
	findSession: () => findSession,
	findSessionByDirectoryWalk: () => findSessionByDirectoryWalk,
	isProcessAlive: () => isProcessAlive,
	listSessions: () => listSessions,
	listSessionsForAgent: () => listSessionsForAgent,
	normalizeQueueOwnerTtlMs: () => normalizeQueueOwnerTtlMs,
	runOnce: () => runOnce,
	runSessionQueueOwner: () => runSessionQueueOwner,
	sendSession: () => sendSession,
	sendSessionDirect: () => sendSessionDirect,
	setSessionConfigOption: () => setSessionConfigOption,
	setSessionMode: () => setSessionMode,
	setSessionModel: () => setSessionModel
});
//#endregion
export { TimeoutError as C, permissionModeSatisfies as E, InterruptedError as S, withTimeout as T, recordClientOperation as _, runOnce as a, flushPerfMetricsCapture as b, buildQueueOwnerArgOverride as c, findSession as d, findSessionByDirectoryWalk as f, createSessionConversation as g, cloneSessionAcpxState as h, createSessionWithClient as i, DEFAULT_HISTORY_LIMIT as l, defaultSessionEventLog as m, DEFAULT_QUEUE_OWNER_TTL_MS as n, runSessionQueueOwner as o, resolveSessionRecord as p, cancelSessionPrompt as r, sendSessionDirect as s, session_exports as t, findGitRepositoryRoot as u, recordPromptSubmission as v, withInterrupt as w, installPerfMetricsCapture as x, recordSessionUpdate as y };

//# sourceMappingURL=session-BtpTC2pM.js.map