import { u as resolveGatewayPort } from "./paths-mmi2xb99.js";
import { s as visibleWidth } from "./subsystem-D4e4nOE7.js";
import { I as VERSION, r as loadConfig } from "./config-C9wUwpYY.js";
import { H as parseAgentSessionKey, N as normalizeAgentId, P as normalizeMainKey, c as resolveDefaultAgentId, k as buildAgentMainSessionKey } from "./agent-scope-BcV171ci.js";
import { Mt as PROTOCOL_VERSION, t as GatewayClient } from "./client-FZxVEb3g.js";
import { m as GATEWAY_CLIENT_NAMES, p as GATEWAY_CLIENT_MODES } from "./message-channel-eeeqF-J8.js";
import { d as normalizeUsageDisplay, i as formatThinkingLevels, o as listThinkingLevelLabels, p as resolveResponseUsageMode } from "./pi-embedded-helpers-Hus0BP0L.js";
import { n as resolveToolDisplay, t as formatToolDetail } from "./tool-display-D8xZqYsu.js";
import { a as extractContentFromMessage, c as formatContextUsageLine, d as resolveFinalAssistantText, i as composeThinkingAndContent, l as formatTokens, n as formatAge, o as extractTextFromMessage, p as formatTokenCount, r as asString, s as extractThinkingFromMessage, u as isCommandMessage, v as listChatCommands, y as listChatCommandsForConfig } from "./channel-summary-xp5M-jlo.js";
import chalk from "chalk";
import { spawn } from "node:child_process";
import { randomUUID } from "node:crypto";
import { Box, CombinedAutocompleteProvider, Container, Editor, Input, Key, Loader, Markdown, ProcessTerminal, SelectList, SettingsList, Spacer, TUI, Text, getKeybindings, isKeyRelease, matchesKey, truncateToWidth } from "@mariozechner/pi-tui";
import { highlight, supportsLanguage } from "cli-highlight";

//#region ../../src/tui/commands.ts
const VERBOSE_LEVELS = ["on", "off"];
const REASONING_LEVELS = ["on", "off"];
const ELEVATED_LEVELS = [
	"on",
	"off",
	"ask",
	"full"
];
const ACTIVATION_LEVELS = ["mention", "always"];
const USAGE_FOOTER_LEVELS = [
	"off",
	"tokens",
	"full"
];
const COMMAND_ALIASES = { elev: "elevated" };
function parseCommand(input) {
	const trimmed = input.replace(/^\//, "").trim();
	if (!trimmed) return {
		name: "",
		args: ""
	};
	const [name, ...rest] = trimmed.split(/\s+/);
	const normalized = name.toLowerCase();
	return {
		name: COMMAND_ALIASES[normalized] ?? normalized,
		args: rest.join(" ").trim()
	};
}
function getSlashCommands(options = {}) {
	const thinkLevels = listThinkingLevelLabels(options.provider, options.model);
	const commands = [
		{
			name: "help",
			description: "Show slash command help"
		},
		{
			name: "status",
			description: "Show gateway status summary"
		},
		{
			name: "agent",
			description: "Switch agent (or open picker)"
		},
		{
			name: "agents",
			description: "Open agent picker"
		},
		{
			name: "session",
			description: "Switch session (or open picker)"
		},
		{
			name: "sessions",
			description: "Open session picker"
		},
		{
			name: "model",
			description: "Set model (or open picker)"
		},
		{
			name: "models",
			description: "Open model picker"
		},
		{
			name: "think",
			description: "Set thinking level",
			getArgumentCompletions: (prefix) => thinkLevels.filter((v) => v.startsWith(prefix.toLowerCase())).map((value) => ({
				value,
				label: value
			}))
		},
		{
			name: "verbose",
			description: "Set verbose on/off",
			getArgumentCompletions: (prefix) => VERBOSE_LEVELS.filter((v) => v.startsWith(prefix.toLowerCase())).map((value) => ({
				value,
				label: value
			}))
		},
		{
			name: "reasoning",
			description: "Set reasoning on/off",
			getArgumentCompletions: (prefix) => REASONING_LEVELS.filter((v) => v.startsWith(prefix.toLowerCase())).map((value) => ({
				value,
				label: value
			}))
		},
		{
			name: "usage",
			description: "Toggle per-response usage line",
			getArgumentCompletions: (prefix) => USAGE_FOOTER_LEVELS.filter((v) => v.startsWith(prefix.toLowerCase())).map((value) => ({
				value,
				label: value
			}))
		},
		{
			name: "elevated",
			description: "Set elevated on/off/ask/full",
			getArgumentCompletions: (prefix) => ELEVATED_LEVELS.filter((v) => v.startsWith(prefix.toLowerCase())).map((value) => ({
				value,
				label: value
			}))
		},
		{
			name: "elev",
			description: "Alias for /elevated",
			getArgumentCompletions: (prefix) => ELEVATED_LEVELS.filter((v) => v.startsWith(prefix.toLowerCase())).map((value) => ({
				value,
				label: value
			}))
		},
		{
			name: "activation",
			description: "Set group activation",
			getArgumentCompletions: (prefix) => ACTIVATION_LEVELS.filter((v) => v.startsWith(prefix.toLowerCase())).map((value) => ({
				value,
				label: value
			}))
		},
		{
			name: "abort",
			description: "Abort active run"
		},
		{
			name: "new",
			description: "Reset the session"
		},
		{
			name: "reset",
			description: "Reset the session"
		},
		{
			name: "settings",
			description: "Open settings"
		},
		{
			name: "exit",
			description: "Exit the TUI"
		},
		{
			name: "quit",
			description: "Exit the TUI"
		}
	];
	const seen = new Set(commands.map((command) => command.name));
	const gatewayCommands = options.cfg ? listChatCommandsForConfig(options.cfg) : listChatCommands();
	for (const command of gatewayCommands) {
		const aliases = command.textAliases.length > 0 ? command.textAliases : [`/${command.key}`];
		for (const alias of aliases) {
			const name = alias.replace(/^\//, "").trim();
			if (!name || seen.has(name)) continue;
			seen.add(name);
			commands.push({
				name,
				description: command.description
			});
		}
	}
	return commands;
}
function helpText(options = {}) {
	return [
		"Slash commands:",
		"/help",
		"/commands",
		"/status",
		"/agent <id> (or /agents)",
		"/session <key> (or /sessions)",
		"/model <provider/model> (or /models)",
		`/think <${formatThinkingLevels(options.provider, options.model, "|")}>`,
		"/verbose <on|off>",
		"/reasoning <on|off>",
		"/usage <off|tokens|full>",
		"/elevated <on|off|ask|full>",
		"/elev <on|off|ask|full>",
		"/activation <mention|always>",
		"/new or /reset",
		"/abort",
		"/settings",
		"/exit"
	].join("\n");
}

//#endregion
//#region ../../src/tui/theme/syntax-theme.ts
/**
* Syntax highlighting theme for code blocks.
* Uses chalk functions to style different token types.
*/
function createSyntaxTheme(fallback) {
	return {
		keyword: chalk.hex("#C586C0"),
		built_in: chalk.hex("#4EC9B0"),
		type: chalk.hex("#4EC9B0"),
		literal: chalk.hex("#569CD6"),
		number: chalk.hex("#B5CEA8"),
		string: chalk.hex("#CE9178"),
		regexp: chalk.hex("#D16969"),
		symbol: chalk.hex("#B5CEA8"),
		class: chalk.hex("#4EC9B0"),
		function: chalk.hex("#DCDCAA"),
		title: chalk.hex("#DCDCAA"),
		params: chalk.hex("#9CDCFE"),
		comment: chalk.hex("#6A9955"),
		doctag: chalk.hex("#608B4E"),
		meta: chalk.hex("#9CDCFE"),
		"meta-keyword": chalk.hex("#C586C0"),
		"meta-string": chalk.hex("#CE9178"),
		section: chalk.hex("#DCDCAA"),
		tag: chalk.hex("#569CD6"),
		name: chalk.hex("#9CDCFE"),
		attr: chalk.hex("#9CDCFE"),
		attribute: chalk.hex("#9CDCFE"),
		variable: chalk.hex("#9CDCFE"),
		bullet: chalk.hex("#D7BA7D"),
		code: chalk.hex("#CE9178"),
		emphasis: chalk.italic,
		strong: chalk.bold,
		formula: chalk.hex("#C586C0"),
		link: chalk.hex("#4EC9B0"),
		quote: chalk.hex("#6A9955"),
		addition: chalk.hex("#B5CEA8"),
		deletion: chalk.hex("#F44747"),
		"selector-tag": chalk.hex("#D7BA7D"),
		"selector-id": chalk.hex("#D7BA7D"),
		"selector-class": chalk.hex("#D7BA7D"),
		"selector-attr": chalk.hex("#D7BA7D"),
		"selector-pseudo": chalk.hex("#D7BA7D"),
		"template-tag": chalk.hex("#C586C0"),
		"template-variable": chalk.hex("#9CDCFE"),
		default: fallback
	};
}

//#endregion
//#region ../../src/tui/theme/theme.ts
const palette = {
	text: "#E8E3D5",
	dim: "#7B7F87",
	accent: "#F6C453",
	accentSoft: "#F2A65A",
	border: "#3C414B",
	userBg: "#2B2F36",
	userText: "#F3EEE0",
	systemText: "#9BA3B2",
	toolPendingBg: "#1F2A2F",
	toolSuccessBg: "#1E2D23",
	toolErrorBg: "#2F1F1F",
	toolTitle: "#F6C453",
	toolOutput: "#E1DACB",
	quote: "#8CC8FF",
	quoteBorder: "#3B4D6B",
	code: "#F0C987",
	codeBlock: "#1E232A",
	codeBorder: "#343A45",
	link: "#7DD3A5",
	error: "#F97066",
	success: "#7DD3A5"
};
const fg = (hex) => (text) => chalk.hex(hex)(text);
const bg = (hex) => (text) => chalk.bgHex(hex)(text);
const syntaxTheme = createSyntaxTheme(fg(palette.code));
/**
* Highlight code with syntax coloring.
* Returns an array of lines with ANSI escape codes.
*/
function highlightCode(code, lang) {
	try {
		return highlight(code, {
			language: lang && supportsLanguage(lang) ? lang : void 0,
			theme: syntaxTheme,
			ignoreIllegals: true
		}).split("\n");
	} catch {
		return code.split("\n").map((line) => fg(palette.code)(line));
	}
}
const theme = {
	fg: fg(palette.text),
	dim: fg(palette.dim),
	accent: fg(palette.accent),
	accentSoft: fg(palette.accentSoft),
	success: fg(palette.success),
	error: fg(palette.error),
	header: (text) => chalk.bold(fg(palette.accent)(text)),
	system: fg(palette.systemText),
	userBg: bg(palette.userBg),
	userText: fg(palette.userText),
	toolTitle: fg(palette.toolTitle),
	toolOutput: fg(palette.toolOutput),
	toolPendingBg: bg(palette.toolPendingBg),
	toolSuccessBg: bg(palette.toolSuccessBg),
	toolErrorBg: bg(palette.toolErrorBg),
	border: fg(palette.border),
	bold: (text) => chalk.bold(text),
	italic: (text) => chalk.italic(text)
};
const markdownTheme = {
	heading: (text) => chalk.bold(fg(palette.accent)(text)),
	link: (text) => fg(palette.link)(text),
	linkUrl: (text) => chalk.dim(text),
	code: (text) => fg(palette.code)(text),
	codeBlock: (text) => fg(palette.code)(text),
	codeBlockBorder: (text) => fg(palette.codeBorder)(text),
	quote: (text) => fg(palette.quote)(text),
	quoteBorder: (text) => fg(palette.quoteBorder)(text),
	hr: (text) => fg(palette.border)(text),
	listBullet: (text) => fg(palette.accentSoft)(text),
	bold: (text) => chalk.bold(text),
	italic: (text) => chalk.italic(text),
	strikethrough: (text) => chalk.strikethrough(text),
	underline: (text) => chalk.underline(text),
	highlightCode
};
const selectListTheme = {
	selectedPrefix: (text) => fg(palette.accent)(text),
	selectedText: (text) => chalk.bold(fg(palette.accent)(text)),
	description: (text) => fg(palette.dim)(text),
	scrollInfo: (text) => fg(palette.dim)(text),
	noMatch: (text) => fg(palette.dim)(text)
};
const filterableSelectListTheme = {
	...selectListTheme,
	filterLabel: (text) => fg(palette.dim)(text)
};
const settingsListTheme = {
	label: (text, selected) => selected ? chalk.bold(fg(palette.accent)(text)) : fg(palette.text)(text),
	value: (text, selected) => selected ? fg(palette.accentSoft)(text) : fg(palette.dim)(text),
	description: (text) => fg(palette.systemText)(text),
	cursor: fg(palette.accent)("→ "),
	hint: (text) => fg(palette.dim)(text)
};
const editorTheme = {
	borderColor: (text) => fg(palette.border)(text),
	selectList: selectListTheme
};
const searchableSelectListTheme = {
	selectedPrefix: (text) => fg(palette.accent)(text),
	selectedText: (text) => chalk.bold(fg(palette.accent)(text)),
	description: (text) => fg(palette.dim)(text),
	scrollInfo: (text) => fg(palette.dim)(text),
	noMatch: (text) => fg(palette.dim)(text),
	searchPrompt: (text) => fg(palette.accentSoft)(text),
	searchInput: (text) => fg(palette.text)(text),
	matchHighlight: (text) => chalk.bold(fg(palette.accent)(text))
};

//#endregion
//#region ../../src/tui/components/assistant-message.ts
var AssistantMessageComponent = class extends Container {
	constructor(text) {
		super();
		this.body = new Markdown(text, 1, 0, markdownTheme, { color: (line) => theme.fg(line) });
		this.addChild(new Spacer(1));
		this.addChild(this.body);
	}
	setText(text) {
		this.body.setText(text);
	}
};

//#endregion
//#region ../../src/tui/components/tool-execution.ts
const PREVIEW_LINES = 12;
function formatArgs(toolName, args) {
	const detail = formatToolDetail(resolveToolDisplay({
		name: toolName,
		args
	}));
	if (detail) return detail;
	if (!args || typeof args !== "object") return "";
	try {
		return JSON.stringify(args);
	} catch {
		return "";
	}
}
function extractText(result) {
	if (!result?.content) return "";
	const lines = [];
	for (const entry of result.content) if (entry.type === "text" && entry.text) lines.push(entry.text);
	else if (entry.type === "image") {
		const mime = entry.mimeType ?? "image";
		const size = entry.bytes ? ` ${Math.round(entry.bytes / 1024)}kb` : "";
		const omitted = entry.omitted ? " (omitted)" : "";
		lines.push(`[${mime}${size}${omitted}]`);
	}
	return lines.join("\n").trim();
}
var ToolExecutionComponent = class extends Container {
	constructor(toolName, args) {
		super();
		this.expanded = false;
		this.isError = false;
		this.isPartial = true;
		this.toolName = toolName;
		this.args = args;
		this.box = new Box(1, 1, (line) => theme.toolPendingBg(line));
		this.header = new Text("", 0, 0);
		this.argsLine = new Text("", 0, 0);
		this.output = new Markdown("", 0, 0, markdownTheme, { color: (line) => theme.toolOutput(line) });
		this.addChild(new Spacer(1));
		this.addChild(this.box);
		this.box.addChild(this.header);
		this.box.addChild(this.argsLine);
		this.box.addChild(this.output);
		this.refresh();
	}
	setArgs(args) {
		this.args = args;
		this.refresh();
	}
	setExpanded(expanded) {
		this.expanded = expanded;
		this.refresh();
	}
	setResult(result, opts) {
		this.result = result;
		this.isPartial = false;
		this.isError = Boolean(opts?.isError);
		this.refresh();
	}
	setPartialResult(result) {
		this.result = result;
		this.isPartial = true;
		this.refresh();
	}
	refresh() {
		const bg = this.isPartial ? theme.toolPendingBg : this.isError ? theme.toolErrorBg : theme.toolSuccessBg;
		this.box.setBgFn((line) => bg(line));
		const display = resolveToolDisplay({
			name: this.toolName,
			args: this.args
		});
		const title = `${display.emoji} ${display.label}${this.isPartial ? " (running)" : ""}`;
		this.header.setText(theme.toolTitle(theme.bold(title)));
		const argLine = formatArgs(this.toolName, this.args);
		this.argsLine.setText(argLine ? theme.dim(argLine) : theme.dim(" "));
		const text = extractText(this.result) || (this.isPartial ? "…" : "");
		if (!this.expanded && text) {
			const lines = text.split("\n");
			const preview = lines.length > PREVIEW_LINES ? `${lines.slice(0, PREVIEW_LINES).join("\n")}\n…` : text;
			this.output.setText(preview);
		} else this.output.setText(text);
	}
};

//#endregion
//#region ../../src/tui/components/user-message.ts
var UserMessageComponent = class extends Container {
	constructor(text) {
		super();
		this.body = new Markdown(text, 1, 1, markdownTheme, {
			bgColor: (line) => theme.userBg(line),
			color: (line) => theme.userText(line)
		});
		this.addChild(new Spacer(1));
		this.addChild(this.body);
	}
	setText(text) {
		this.body.setText(text);
	}
};

//#endregion
//#region ../../src/tui/components/chat-log.ts
var ChatLog = class extends Container {
	constructor(..._args) {
		super(..._args);
		this.toolById = /* @__PURE__ */ new Map();
		this.streamingRuns = /* @__PURE__ */ new Map();
		this.toolsExpanded = false;
	}
	clearAll() {
		this.clear();
		this.toolById.clear();
		this.streamingRuns.clear();
	}
	addSystem(text) {
		this.addChild(new Spacer(1));
		this.addChild(new Text(theme.system(text), 1, 0));
	}
	addUser(text) {
		this.addChild(new UserMessageComponent(text));
	}
	resolveRunId(runId) {
		return runId ?? "default";
	}
	startAssistant(text, runId) {
		const component = new AssistantMessageComponent(text);
		this.streamingRuns.set(this.resolveRunId(runId), component);
		this.addChild(component);
		return component;
	}
	updateAssistant(text, runId) {
		const effectiveRunId = this.resolveRunId(runId);
		const existing = this.streamingRuns.get(effectiveRunId);
		if (!existing) {
			this.startAssistant(text, runId);
			return;
		}
		existing.setText(text);
	}
	finalizeAssistant(text, runId) {
		const effectiveRunId = this.resolveRunId(runId);
		const existing = this.streamingRuns.get(effectiveRunId);
		if (existing) {
			existing.setText(text);
			this.streamingRuns.delete(effectiveRunId);
			return;
		}
		this.addChild(new AssistantMessageComponent(text));
	}
	startTool(toolCallId, toolName, args) {
		const existing = this.toolById.get(toolCallId);
		if (existing) {
			existing.setArgs(args);
			return existing;
		}
		const component = new ToolExecutionComponent(toolName, args);
		component.setExpanded(this.toolsExpanded);
		this.toolById.set(toolCallId, component);
		this.addChild(component);
		return component;
	}
	updateToolArgs(toolCallId, args) {
		const existing = this.toolById.get(toolCallId);
		if (!existing) return;
		existing.setArgs(args);
	}
	updateToolResult(toolCallId, result, opts) {
		const existing = this.toolById.get(toolCallId);
		if (!existing) return;
		if (opts?.partial) {
			existing.setPartialResult(result);
			return;
		}
		existing.setResult(result, { isError: opts?.isError });
	}
	setToolsExpanded(expanded) {
		this.toolsExpanded = expanded;
		for (const tool of this.toolById.values()) tool.setExpanded(expanded);
	}
};

//#endregion
//#region ../../src/tui/components/custom-editor.ts
var CustomEditor = class extends Editor {
	handleInput(data) {
		if (matchesKey(data, Key.alt("enter")) && this.onAltEnter) {
			this.onAltEnter();
			return;
		}
		if (matchesKey(data, Key.ctrl("l")) && this.onCtrlL) {
			this.onCtrlL();
			return;
		}
		if (matchesKey(data, Key.ctrl("o")) && this.onCtrlO) {
			this.onCtrlO();
			return;
		}
		if (matchesKey(data, Key.ctrl("p")) && this.onCtrlP) {
			this.onCtrlP();
			return;
		}
		if (matchesKey(data, Key.ctrl("g")) && this.onCtrlG) {
			this.onCtrlG();
			return;
		}
		if (matchesKey(data, Key.ctrl("t")) && this.onCtrlT) {
			this.onCtrlT();
			return;
		}
		if (matchesKey(data, Key.shift("tab")) && this.onShiftTab) {
			this.onShiftTab();
			return;
		}
		if (matchesKey(data, Key.escape) && this.onEscape && !this.isShowingAutocomplete()) {
			this.onEscape();
			return;
		}
		if (matchesKey(data, Key.ctrl("c")) && this.onCtrlC) {
			this.onCtrlC();
			return;
		}
		if (matchesKey(data, Key.ctrl("d"))) {
			if (this.getText().length === 0 && this.onCtrlD) this.onCtrlD();
			return;
		}
		super.handleInput(data);
	}
};

//#endregion
//#region ../../src/tui/gateway-chat.ts
var GatewayChatClient = class {
	constructor(opts) {
		const resolved = resolveGatewayConnection(opts);
		this.connection = resolved;
		this.readyPromise = new Promise((resolve) => {
			this.resolveReady = resolve;
		});
		this.client = new GatewayClient({
			url: resolved.url,
			token: resolved.token,
			password: resolved.password,
			clientName: GATEWAY_CLIENT_NAMES.GATEWAY_CLIENT,
			clientDisplayName: "edwinpai-tui",
			clientVersion: VERSION,
			platform: process.platform,
			mode: GATEWAY_CLIENT_MODES.UI,
			instanceId: randomUUID(),
			minProtocol: PROTOCOL_VERSION,
			maxProtocol: PROTOCOL_VERSION,
			onHelloOk: (hello) => {
				this.hello = hello;
				this.resolveReady?.();
				this.onConnected?.();
			},
			onEvent: (evt) => {
				this.onEvent?.({
					event: evt.event,
					payload: evt.payload,
					seq: evt.seq
				});
			},
			onClose: (_code, reason) => {
				this.onDisconnected?.(reason);
			},
			onGap: (info) => {
				this.onGap?.(info);
			}
		});
	}
	start() {
		this.client.start();
	}
	stop() {
		this.client.stop();
	}
	async waitForReady() {
		await this.readyPromise;
	}
	async sendChat(opts) {
		const runId = randomUUID();
		await this.client.request("chat.send", {
			sessionKey: opts.sessionKey,
			message: opts.message,
			thinking: opts.thinking,
			deliver: opts.deliver,
			timeoutMs: opts.timeoutMs,
			idempotencyKey: runId
		});
		return { runId };
	}
	async abortChat(opts) {
		return await this.client.request("chat.abort", {
			sessionKey: opts.sessionKey,
			runId: opts.runId
		});
	}
	async loadHistory(opts) {
		return await this.client.request("chat.history", {
			sessionKey: opts.sessionKey,
			limit: opts.limit
		});
	}
	async listSessions(opts) {
		return await this.client.request("sessions.list", {
			limit: opts?.limit,
			activeMinutes: opts?.activeMinutes,
			includeGlobal: opts?.includeGlobal,
			includeUnknown: opts?.includeUnknown,
			includeDerivedTitles: opts?.includeDerivedTitles,
			includeLastMessage: opts?.includeLastMessage,
			agentId: opts?.agentId
		});
	}
	async listAgents() {
		return await this.client.request("agents.list", {});
	}
	async patchSession(opts) {
		return await this.client.request("sessions.patch", opts);
	}
	async resetSession(key) {
		return await this.client.request("sessions.reset", { key });
	}
	async getStatus() {
		return await this.client.request("status");
	}
	async listModels() {
		const res = await this.client.request("models.list");
		return Array.isArray(res?.models) ? res.models : [];
	}
};
function resolveGatewayConnection(opts) {
	const config = loadConfig();
	const isRemoteMode = config.gateway?.mode === "remote";
	const remote = isRemoteMode ? config.gateway?.remote : void 0;
	const authToken = config.gateway?.auth?.token;
	const localPort = resolveGatewayPort(config);
	return {
		url: (typeof opts.url === "string" && opts.url.trim().length > 0 ? opts.url.trim() : void 0) || (typeof remote?.url === "string" && remote.url.trim().length > 0 ? remote.url.trim() : void 0) || `ws://127.0.0.1:${localPort}`,
		token: (typeof opts.token === "string" && opts.token.trim().length > 0 ? opts.token.trim() : void 0) || (isRemoteMode ? typeof remote?.token === "string" && remote.token.trim().length > 0 ? remote.token.trim() : void 0 : process.env.EDWINPAI_GATEWAY_TOKEN?.trim() || (typeof authToken === "string" && authToken.trim().length > 0 ? authToken.trim() : void 0)),
		password: (typeof opts.password === "string" && opts.password.trim().length > 0 ? opts.password.trim() : void 0) || process.env.EDWINPAI_GATEWAY_PASSWORD?.trim() || (typeof remote?.password === "string" && remote.password.trim().length > 0 ? remote.password.trim() : void 0)
	};
}

//#endregion
//#region ../../src/utils/time-format.ts
function formatRelativeTime(timestamp) {
	const diff = Date.now() - timestamp;
	const seconds = Math.floor(diff / 1e3);
	const minutes = Math.floor(seconds / 60);
	const hours = Math.floor(minutes / 60);
	const days = Math.floor(hours / 24);
	if (seconds < 60) return "just now";
	if (minutes < 60) return `${minutes}m ago`;
	if (hours < 24) return `${hours}h ago`;
	if (days === 1) return "Yesterday";
	if (days < 7) return `${days}d ago`;
	return new Date(timestamp).toLocaleDateString(void 0, {
		month: "short",
		day: "numeric"
	});
}

//#endregion
//#region ../../src/tui/components/fuzzy-filter.ts
/**
* Shared fuzzy filtering utilities for select list components.
*/
/**
* Word boundary characters for matching.
*/
const WORD_BOUNDARY_CHARS = /[\s\-_./:#@]/;
/**
* Check if position is at a word boundary.
*/
function isWordBoundary(text, index) {
	return index === 0 || WORD_BOUNDARY_CHARS.test(text[index - 1] ?? "");
}
/**
* Find index where query matches at a word boundary in text.
* Returns null if no match.
*/
function findWordBoundaryIndex(text, query) {
	if (!query) return null;
	const textLower = text.toLowerCase();
	const queryLower = query.toLowerCase();
	const maxIndex = textLower.length - queryLower.length;
	if (maxIndex < 0) return null;
	for (let i = 0; i <= maxIndex; i++) if (textLower.startsWith(queryLower, i) && isWordBoundary(textLower, i)) return i;
	return null;
}
/**
* Fuzzy match with pre-lowercased inputs (avoids toLowerCase on every keystroke).
* Returns score (lower = better) or null if no match.
*/
function fuzzyMatchLower(queryLower, textLower) {
	if (queryLower.length === 0) return 0;
	if (queryLower.length > textLower.length) return null;
	let queryIndex = 0;
	let score = 0;
	let lastMatchIndex = -1;
	let consecutiveMatches = 0;
	for (let i = 0; i < textLower.length && queryIndex < queryLower.length; i++) if (textLower[i] === queryLower[queryIndex]) {
		const isAtWordBoundary = isWordBoundary(textLower, i);
		if (lastMatchIndex === i - 1) {
			consecutiveMatches++;
			score -= consecutiveMatches * 5;
		} else {
			consecutiveMatches = 0;
			if (lastMatchIndex >= 0) score += (i - lastMatchIndex - 1) * 2;
		}
		if (isAtWordBoundary) score -= 10;
		score += i * .1;
		lastMatchIndex = i;
		queryIndex++;
	}
	return queryIndex < queryLower.length ? null : score;
}
/**
* Filter items using pre-lowercased searchTextLower field.
* Supports space-separated tokens (all must match).
*/
function fuzzyFilterLower(items, queryLower) {
	const trimmed = queryLower.trim();
	if (!trimmed) return items;
	const tokens = trimmed.split(/\s+/).filter((t) => t.length > 0);
	if (tokens.length === 0) return items;
	const results = [];
	for (const item of items) {
		const text = item.searchTextLower ?? "";
		let totalScore = 0;
		let allMatch = true;
		for (const token of tokens) {
			const score = fuzzyMatchLower(token, text);
			if (score !== null) totalScore += score;
			else {
				allMatch = false;
				break;
			}
		}
		if (allMatch) results.push({
			item,
			score: totalScore
		});
	}
	results.sort((a, b) => a.score - b.score);
	return results.map((r) => r.item);
}
/**
* Prepare items for fuzzy filtering by pre-computing lowercase search text.
*/
function prepareSearchItems(items) {
	return items.map((item) => {
		const parts = [];
		if (item.label) parts.push(item.label);
		if (item.description) parts.push(item.description);
		if (item.searchText) parts.push(item.searchText);
		return {
			...item,
			searchTextLower: parts.join(" ").toLowerCase()
		};
	});
}

//#endregion
//#region ../../src/tui/components/filterable-select-list.ts
/**
* Combines text input filtering with a select list.
* User types to filter, arrows/j/k to navigate, Enter to select, Escape to clear/cancel.
*/
var FilterableSelectList = class {
	constructor(items, maxVisible, theme) {
		this.filterText = "";
		this.allItems = prepareSearchItems(items);
		this.maxVisible = maxVisible;
		this.theme = theme;
		this.input = new Input();
		this.selectList = new SelectList(this.allItems, maxVisible, theme);
	}
	applyFilter() {
		const queryLower = this.filterText.toLowerCase();
		if (!queryLower.trim()) {
			this.selectList = new SelectList(this.allItems, this.maxVisible, this.theme);
			return;
		}
		this.selectList = new SelectList(fuzzyFilterLower(this.allItems, queryLower), this.maxVisible, this.theme);
	}
	invalidate() {
		this.input.invalidate();
		this.selectList.invalidate();
	}
	render(width) {
		const lines = [];
		const filterLabel = this.theme.filterLabel("Filter: ");
		const inputText = this.input.render(width - 8)[0] ?? "";
		lines.push(filterLabel + inputText);
		lines.push(chalk.dim("─".repeat(Math.max(0, width))));
		const listLines = this.selectList.render(width);
		lines.push(...listLines);
		return lines;
	}
	handleInput(keyData) {
		const allowVimNav = !this.filterText.trim();
		if (matchesKey(keyData, "up") || matchesKey(keyData, "ctrl+p") || allowVimNav && keyData === "k") {
			this.selectList.handleInput("\x1B[A");
			return;
		}
		if (matchesKey(keyData, "down") || matchesKey(keyData, "ctrl+n") || allowVimNav && keyData === "j") {
			this.selectList.handleInput("\x1B[B");
			return;
		}
		if (matchesKey(keyData, "enter")) {
			const selected = this.selectList.getSelectedItem();
			if (selected) this.onSelect?.(selected);
			return;
		}
		if (getKeybindings().matches(keyData, "tui.select.cancel")) {
			if (this.filterText) {
				this.filterText = "";
				this.input.setValue("");
				this.applyFilter();
			} else this.onCancel?.();
			return;
		}
		const prevValue = this.input.getValue();
		this.input.handleInput(keyData);
		const newValue = this.input.getValue();
		if (newValue !== prevValue) {
			this.filterText = newValue;
			this.applyFilter();
		}
	}
	getSelectedItem() {
		return this.selectList.getSelectedItem();
	}
	getFilterText() {
		return this.filterText;
	}
};

//#endregion
//#region ../../src/tui/components/searchable-select-list.ts
/**
* A select list with a search input at the top for fuzzy filtering.
*/
var SearchableSelectList = class {
	constructor(items, maxVisible, theme) {
		this.selectedIndex = 0;
		this.regexCache = /* @__PURE__ */ new Map();
		this.compareByScore = (a, b) => {
			if (a.tier !== b.tier) return a.tier - b.tier;
			if (a.score !== b.score) return a.score - b.score;
			return this.getItemLabel(a.item).localeCompare(this.getItemLabel(b.item));
		};
		this.items = items;
		this.filteredItems = items;
		this.maxVisible = maxVisible;
		this.theme = theme;
		this.searchInput = new Input();
	}
	getCachedRegex(pattern) {
		let regex = this.regexCache.get(pattern);
		if (!regex) {
			regex = new RegExp(this.escapeRegex(pattern), "gi");
			this.regexCache.set(pattern, regex);
		}
		return regex;
	}
	updateFilter() {
		const query = this.searchInput.getValue().trim();
		if (!query) this.filteredItems = this.items;
		else this.filteredItems = this.smartFilter(query);
		this.selectedIndex = 0;
		this.notifySelectionChange();
	}
	/**
	* Smart filtering that prioritizes:
	* 1. Exact substring match in label (highest priority)
	* 2. Word-boundary prefix match in label
	* 3. Exact substring in description
	* 4. Fuzzy match (lowest priority)
	*/
	smartFilter(query) {
		const q = query.toLowerCase();
		const scoredItems = [];
		const fuzzyCandidates = [];
		for (const item of this.items) {
			const label = item.label.toLowerCase();
			const desc = (item.description ?? "").toLowerCase();
			const labelIndex = label.indexOf(q);
			if (labelIndex !== -1) {
				scoredItems.push({
					item,
					tier: 0,
					score: labelIndex
				});
				continue;
			}
			const wordBoundaryIndex = findWordBoundaryIndex(label, q);
			if (wordBoundaryIndex !== null) {
				scoredItems.push({
					item,
					tier: 1,
					score: wordBoundaryIndex
				});
				continue;
			}
			const descIndex = desc.indexOf(q);
			if (descIndex !== -1) {
				scoredItems.push({
					item,
					tier: 2,
					score: descIndex
				});
				continue;
			}
			fuzzyCandidates.push(item);
		}
		scoredItems.sort(this.compareByScore);
		const fuzzyMatches = fuzzyFilterLower(prepareSearchItems(fuzzyCandidates), q);
		return [...scoredItems.map((s) => s.item), ...fuzzyMatches];
	}
	escapeRegex(str) {
		return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
	}
	getItemLabel(item) {
		return item.label || item.value;
	}
	highlightMatch(text, query) {
		const tokens = query.trim().split(/\s+/).map((token) => token.toLowerCase()).filter((token) => token.length > 0);
		if (tokens.length === 0) return text;
		const uniqueTokens = Array.from(new Set(tokens)).toSorted((a, b) => b.length - a.length);
		let result = text;
		for (const token of uniqueTokens) {
			const regex = this.getCachedRegex(token);
			result = result.replace(regex, (match) => this.theme.matchHighlight(match));
		}
		return result;
	}
	setSelectedIndex(index) {
		this.selectedIndex = Math.max(0, Math.min(index, this.filteredItems.length - 1));
	}
	invalidate() {
		this.searchInput.invalidate();
	}
	render(width) {
		const lines = [];
		const prompt = this.theme.searchPrompt("search: ");
		const inputWidth = Math.max(1, width - visibleWidth(prompt));
		const inputText = this.searchInput.render(inputWidth)[0] ?? "";
		lines.push(`${prompt}${this.theme.searchInput(inputText)}`);
		lines.push("");
		const query = this.searchInput.getValue().trim();
		if (this.filteredItems.length === 0) {
			lines.push(this.theme.noMatch("  No matches"));
			return lines;
		}
		const startIndex = Math.max(0, Math.min(this.selectedIndex - Math.floor(this.maxVisible / 2), this.filteredItems.length - this.maxVisible));
		const endIndex = Math.min(startIndex + this.maxVisible, this.filteredItems.length);
		for (let i = startIndex; i < endIndex; i++) {
			const item = this.filteredItems[i];
			if (!item) continue;
			const isSelected = i === this.selectedIndex;
			lines.push(this.renderItemLine(item, isSelected, width, query));
		}
		if (this.filteredItems.length > this.maxVisible) {
			const scrollInfo = `${this.selectedIndex + 1}/${this.filteredItems.length}`;
			lines.push(this.theme.scrollInfo(`  ${scrollInfo}`));
		}
		return lines;
	}
	renderItemLine(item, isSelected, width, query) {
		const prefix = isSelected ? "→ " : "  ";
		const prefixWidth = prefix.length;
		const displayValue = this.getItemLabel(item);
		if (item.description && width > 40) {
			const truncatedValue = truncateToWidth(displayValue, Math.min(30, width - prefixWidth - 4), "");
			const valueText = this.highlightMatch(truncatedValue, query);
			const spacingWidth = Math.max(1, 32 - visibleWidth(valueText));
			const spacing = " ".repeat(spacingWidth);
			const remainingWidth = width - (prefixWidth + visibleWidth(valueText) + spacing.length) - 2;
			if (remainingWidth > 10) {
				const truncatedDesc = truncateToWidth(item.description, remainingWidth, "");
				const highlightedDesc = this.highlightMatch(truncatedDesc, query);
				const line = `${prefix}${valueText}${spacing}${isSelected ? highlightedDesc : this.theme.description(highlightedDesc)}`;
				return isSelected ? this.theme.selectedText(line) : line;
			}
		}
		const truncatedValue = truncateToWidth(displayValue, width - prefixWidth - 2, "");
		const line = `${prefix}${this.highlightMatch(truncatedValue, query)}`;
		return isSelected ? this.theme.selectedText(line) : line;
	}
	handleInput(keyData) {
		if (isKeyRelease(keyData)) return;
		const allowVimNav = !this.searchInput.getValue().trim();
		if (matchesKey(keyData, "up") || matchesKey(keyData, "ctrl+p") || allowVimNav && keyData === "k") {
			this.selectedIndex = Math.max(0, this.selectedIndex - 1);
			this.notifySelectionChange();
			return;
		}
		if (matchesKey(keyData, "down") || matchesKey(keyData, "ctrl+n") || allowVimNav && keyData === "j") {
			this.selectedIndex = Math.min(this.filteredItems.length - 1, this.selectedIndex + 1);
			this.notifySelectionChange();
			return;
		}
		if (matchesKey(keyData, "enter")) {
			const item = this.filteredItems[this.selectedIndex];
			if (item && this.onSelect) this.onSelect(item);
			return;
		}
		if (getKeybindings().matches(keyData, "tui.select.cancel")) {
			if (this.onCancel) this.onCancel();
			return;
		}
		const prevValue = this.searchInput.getValue();
		this.searchInput.handleInput(keyData);
		if (prevValue !== this.searchInput.getValue()) this.updateFilter();
	}
	notifySelectionChange() {
		const item = this.filteredItems[this.selectedIndex];
		if (item && this.onSelectionChange) this.onSelectionChange(item);
	}
	getSelectedItem() {
		return this.filteredItems[this.selectedIndex] ?? null;
	}
};

//#endregion
//#region ../../src/tui/components/selectors.ts
function createSearchableSelectList(items, maxVisible = 7) {
	return new SearchableSelectList(items, maxVisible, searchableSelectListTheme);
}
function createFilterableSelectList(items, maxVisible = 7) {
	return new FilterableSelectList(items, maxVisible, filterableSelectListTheme);
}
function createSettingsList(items, onChange, onCancel, maxVisible = 7) {
	return new SettingsList(items, maxVisible, settingsListTheme, onChange, onCancel);
}

//#endregion
//#region ../../src/tui/tui-status-summary.ts
function formatStatusSummary(summary) {
	const lines = [];
	lines.push("Gateway status");
	if (!summary.linkChannel) lines.push("Link channel: unknown");
	else {
		const linkLabel = summary.linkChannel.label ?? "Link channel";
		const linked = summary.linkChannel.linked === true;
		const authAge = linked && typeof summary.linkChannel.authAgeMs === "number" ? ` (last refreshed ${formatAge(summary.linkChannel.authAgeMs)})` : "";
		lines.push(`${linkLabel}: ${linked ? "linked" : "not linked"}${authAge}`);
	}
	const providerSummary = Array.isArray(summary.providerSummary) ? summary.providerSummary : [];
	if (providerSummary.length > 0) {
		lines.push("");
		lines.push("System:");
		for (const line of providerSummary) lines.push(`  ${line}`);
	}
	const heartbeatAgents = summary.heartbeat?.agents ?? [];
	if (heartbeatAgents.length > 0) {
		const heartbeatParts = heartbeatAgents.map((agent) => {
			const agentId = agent.agentId ?? "unknown";
			if (!agent.enabled || !agent.everyMs) return `disabled (${agentId})`;
			return `${agent.every ?? "unknown"} (${agentId})`;
		});
		lines.push("");
		lines.push(`Heartbeat: ${heartbeatParts.join(", ")}`);
	}
	const sessionPaths = summary.sessions?.paths ?? [];
	if (sessionPaths.length === 1) lines.push(`Session store: ${sessionPaths[0]}`);
	else if (sessionPaths.length > 1) lines.push(`Session stores: ${sessionPaths.length}`);
	const defaults = summary.sessions?.defaults;
	const defaultModel = defaults?.model ?? "unknown";
	const defaultCtx = typeof defaults?.contextTokens === "number" ? ` (${formatTokenCount(defaults.contextTokens)} ctx)` : "";
	lines.push(`Default model: ${defaultModel}${defaultCtx}`);
	const sessionCount = summary.sessions?.count ?? 0;
	lines.push(`Active sessions: ${sessionCount}`);
	const recent = Array.isArray(summary.sessions?.recent) ? summary.sessions?.recent : [];
	if (recent.length > 0) {
		lines.push("Recent sessions:");
		for (const entry of recent) {
			const ageLabel = typeof entry.age === "number" ? formatAge(entry.age) : "no activity";
			const model = entry.model ?? "unknown";
			const usage = formatContextUsageLine({
				total: entry.totalTokens ?? null,
				context: entry.contextTokens ?? null,
				remaining: entry.remainingTokens ?? null,
				percent: entry.percentUsed ?? null
			});
			const flags = entry.flags?.length ? ` | flags: ${entry.flags.join(", ")}` : "";
			lines.push(`- ${entry.key}${entry.kind ? ` [${entry.kind}]` : ""} | ${ageLabel} | model ${model} | ${usage}${flags}`);
		}
	}
	const queued = Array.isArray(summary.queuedSystemEvents) ? summary.queuedSystemEvents : [];
	if (queued.length > 0) {
		const preview = queued.slice(0, 3).join(" | ");
		lines.push(`Queued system events (${queued.length}): ${preview}`);
	}
	return lines;
}

//#endregion
//#region ../../src/tui/tui-command-handlers.ts
function createCommandHandlers(context) {
	const { client, chatLog, tui, opts, state, deliverDefault, openOverlay, closeOverlay, refreshSessionInfo, loadHistory, setSession, refreshAgents, abortActive, setActivityStatus, formatSessionKey } = context;
	const setAgent = async (id) => {
		state.currentAgentId = normalizeAgentId(id);
		await setSession("");
	};
	const openModelSelector = async () => {
		try {
			const models = await client.listModels();
			if (models.length === 0) {
				chatLog.addSystem("no models available");
				tui.requestRender();
				return;
			}
			const selector = createSearchableSelectList(models.map((model) => ({
				value: `${model.provider}/${model.id}`,
				label: `${model.provider}/${model.id}`,
				description: model.name && model.name !== model.id ? model.name : ""
			})), 9);
			selector.onSelect = (item) => {
				(async () => {
					try {
						await client.patchSession({
							key: state.currentSessionKey,
							model: item.value
						});
						chatLog.addSystem(`model set to ${item.value}`);
						await refreshSessionInfo();
					} catch (err) {
						chatLog.addSystem(`model set failed: ${String(err)}`);
					}
					closeOverlay();
					tui.requestRender();
				})();
			};
			selector.onCancel = () => {
				closeOverlay();
				tui.requestRender();
			};
			openOverlay(selector);
			tui.requestRender();
		} catch (err) {
			chatLog.addSystem(`model list failed: ${String(err)}`);
			tui.requestRender();
		}
	};
	const openAgentSelector = async () => {
		await refreshAgents();
		if (state.agents.length === 0) {
			chatLog.addSystem("no agents found");
			tui.requestRender();
			return;
		}
		const selector = createSearchableSelectList(state.agents.map((agent) => ({
			value: agent.id,
			label: agent.name ? `${agent.id} (${agent.name})` : agent.id,
			description: agent.id === state.agentDefaultId ? "default" : ""
		})), 9);
		selector.onSelect = (item) => {
			(async () => {
				closeOverlay();
				await setAgent(item.value);
				tui.requestRender();
			})();
		};
		selector.onCancel = () => {
			closeOverlay();
			tui.requestRender();
		};
		openOverlay(selector);
		tui.requestRender();
	};
	const openSessionSelector = async () => {
		try {
			const selector = createFilterableSelectList((await client.listSessions({
				includeGlobal: false,
				includeUnknown: false,
				includeDerivedTitles: true,
				includeLastMessage: true,
				agentId: state.currentAgentId
			})).sessions.map((session) => {
				const title = session.derivedTitle ?? session.displayName;
				const formattedKey = formatSessionKey(session.key);
				const label = title && title !== formattedKey ? `${title} (${formattedKey})` : formattedKey;
				const timePart = session.updatedAt ? formatRelativeTime(session.updatedAt) : "";
				const preview = session.lastMessagePreview?.replace(/\s+/g, " ").trim();
				const description = timePart && preview ? `${timePart} · ${preview}` : preview ?? timePart;
				return {
					value: session.key,
					label,
					description,
					searchText: [
						session.displayName,
						session.label,
						session.subject,
						session.sessionId,
						session.key,
						session.lastMessagePreview
					].filter(Boolean).join(" ")
				};
			}), 9);
			selector.onSelect = (item) => {
				(async () => {
					closeOverlay();
					await setSession(item.value);
					tui.requestRender();
				})();
			};
			selector.onCancel = () => {
				closeOverlay();
				tui.requestRender();
			};
			openOverlay(selector);
			tui.requestRender();
		} catch (err) {
			chatLog.addSystem(`sessions list failed: ${String(err)}`);
			tui.requestRender();
		}
	};
	const openSettings = () => {
		openOverlay(createSettingsList([{
			id: "tools",
			label: "Tool output",
			currentValue: state.toolsExpanded ? "expanded" : "collapsed",
			values: ["collapsed", "expanded"]
		}, {
			id: "thinking",
			label: "Show thinking",
			currentValue: state.showThinking ? "on" : "off",
			values: ["off", "on"]
		}], (id, value) => {
			if (id === "tools") {
				state.toolsExpanded = value === "expanded";
				chatLog.setToolsExpanded(state.toolsExpanded);
			}
			if (id === "thinking") {
				state.showThinking = value === "on";
				loadHistory();
			}
			tui.requestRender();
		}, () => {
			closeOverlay();
			tui.requestRender();
		}));
		tui.requestRender();
	};
	const handleCommand = async (raw) => {
		const { name, args } = parseCommand(raw);
		if (!name) return;
		switch (name) {
			case "help":
				chatLog.addSystem(helpText({
					provider: state.sessionInfo.modelProvider,
					model: state.sessionInfo.model
				}));
				break;
			case "status":
				try {
					const status = await client.getStatus();
					if (typeof status === "string") {
						chatLog.addSystem(status);
						break;
					}
					if (status && typeof status === "object") {
						const lines = formatStatusSummary(status);
						for (const line of lines) chatLog.addSystem(line);
						break;
					}
					chatLog.addSystem("status: unknown response");
				} catch (err) {
					chatLog.addSystem(`status failed: ${String(err)}`);
				}
				break;
			case "agent":
				if (!args) await openAgentSelector();
				else await setAgent(args);
				break;
			case "agents":
				await openAgentSelector();
				break;
			case "session":
				if (!args) await openSessionSelector();
				else await setSession(args);
				break;
			case "sessions":
				await openSessionSelector();
				break;
			case "model":
				if (!args) await openModelSelector();
				else try {
					await client.patchSession({
						key: state.currentSessionKey,
						model: args
					});
					chatLog.addSystem(`model set to ${args}`);
					await refreshSessionInfo();
				} catch (err) {
					chatLog.addSystem(`model set failed: ${String(err)}`);
				}
				break;
			case "models":
				await openModelSelector();
				break;
			case "think":
				if (!args) {
					const levels = formatThinkingLevels(state.sessionInfo.modelProvider, state.sessionInfo.model, "|");
					chatLog.addSystem(`usage: /think <${levels}>`);
					break;
				}
				try {
					await client.patchSession({
						key: state.currentSessionKey,
						thinkingLevel: args
					});
					chatLog.addSystem(`thinking set to ${args}`);
					await refreshSessionInfo();
				} catch (err) {
					chatLog.addSystem(`think failed: ${String(err)}`);
				}
				break;
			case "verbose":
				if (!args) {
					chatLog.addSystem("usage: /verbose <on|off>");
					break;
				}
				try {
					await client.patchSession({
						key: state.currentSessionKey,
						verboseLevel: args
					});
					chatLog.addSystem(`verbose set to ${args}`);
					await refreshSessionInfo();
				} catch (err) {
					chatLog.addSystem(`verbose failed: ${String(err)}`);
				}
				break;
			case "reasoning":
				if (!args) {
					chatLog.addSystem("usage: /reasoning <on|off>");
					break;
				}
				try {
					await client.patchSession({
						key: state.currentSessionKey,
						reasoningLevel: args
					});
					chatLog.addSystem(`reasoning set to ${args}`);
					await refreshSessionInfo();
				} catch (err) {
					chatLog.addSystem(`reasoning failed: ${String(err)}`);
				}
				break;
			case "usage": {
				const normalized = args ? normalizeUsageDisplay(args) : void 0;
				if (args && !normalized) {
					chatLog.addSystem("usage: /usage <off|tokens|full>");
					break;
				}
				const currentRaw = state.sessionInfo.responseUsage;
				const current = resolveResponseUsageMode(currentRaw);
				const next = normalized ?? (current === "off" ? "tokens" : current === "tokens" ? "full" : "off");
				try {
					await client.patchSession({
						key: state.currentSessionKey,
						responseUsage: next === "off" ? null : next
					});
					chatLog.addSystem(`usage footer: ${next}`);
					await refreshSessionInfo();
				} catch (err) {
					chatLog.addSystem(`usage failed: ${String(err)}`);
				}
				break;
			}
			case "elevated":
				if (!args) {
					chatLog.addSystem("usage: /elevated <on|off|ask|full>");
					break;
				}
				if (![
					"on",
					"off",
					"ask",
					"full"
				].includes(args)) {
					chatLog.addSystem("usage: /elevated <on|off|ask|full>");
					break;
				}
				try {
					await client.patchSession({
						key: state.currentSessionKey,
						elevatedLevel: args
					});
					chatLog.addSystem(`elevated set to ${args}`);
					await refreshSessionInfo();
				} catch (err) {
					chatLog.addSystem(`elevated failed: ${String(err)}`);
				}
				break;
			case "activation":
				if (!args) {
					chatLog.addSystem("usage: /activation <mention|always>");
					break;
				}
				try {
					await client.patchSession({
						key: state.currentSessionKey,
						groupActivation: args === "always" ? "always" : "mention"
					});
					chatLog.addSystem(`activation set to ${args}`);
					await refreshSessionInfo();
				} catch (err) {
					chatLog.addSystem(`activation failed: ${String(err)}`);
				}
				break;
			case "new":
			case "reset":
				try {
					state.sessionInfo.inputTokens = null;
					state.sessionInfo.outputTokens = null;
					state.sessionInfo.totalTokens = null;
					tui.requestRender();
					await client.resetSession(state.currentSessionKey);
					chatLog.addSystem(`session ${state.currentSessionKey} reset`);
					await loadHistory();
				} catch (err) {
					chatLog.addSystem(`reset failed: ${String(err)}`);
				}
				break;
			case "abort":
				await abortActive();
				break;
			case "settings":
				openSettings();
				break;
			case "exit":
			case "quit":
				client.stop();
				tui.stop();
				process.exit(0);
				break;
			default:
				await sendMessage(raw);
				break;
		}
		tui.requestRender();
	};
	const sendMessage = async (text) => {
		try {
			chatLog.addUser(text);
			tui.requestRender();
			setActivityStatus("sending");
			const { runId } = await client.sendChat({
				sessionKey: state.currentSessionKey,
				message: text,
				thinking: opts.thinking,
				deliver: deliverDefault,
				timeoutMs: opts.timeoutMs
			});
			state.activeChatRunId = runId;
			setActivityStatus("waiting");
		} catch (err) {
			chatLog.addSystem(`send failed: ${String(err)}`);
			setActivityStatus("error");
		}
		tui.requestRender();
	};
	return {
		handleCommand,
		sendMessage,
		openModelSelector,
		openAgentSelector,
		openSessionSelector,
		openSettings,
		setAgent
	};
}

//#endregion
//#region ../../src/tui/tui-stream-assembler.ts
var TuiStreamAssembler = class {
	constructor() {
		this.runs = /* @__PURE__ */ new Map();
	}
	getOrCreateRun(runId) {
		let state = this.runs.get(runId);
		if (!state) {
			state = {
				thinkingText: "",
				contentText: "",
				displayText: ""
			};
			this.runs.set(runId, state);
		}
		return state;
	}
	updateRunState(state, message, showThinking) {
		const thinkingText = extractThinkingFromMessage(message);
		const contentText = extractContentFromMessage(message);
		if (thinkingText) state.thinkingText = thinkingText;
		if (contentText) state.contentText = contentText;
		state.displayText = composeThinkingAndContent({
			thinkingText: state.thinkingText,
			contentText: state.contentText,
			showThinking
		});
	}
	ingestDelta(runId, message, showThinking) {
		const state = this.getOrCreateRun(runId);
		const previousDisplayText = state.displayText;
		this.updateRunState(state, message, showThinking);
		if (!state.displayText || state.displayText === previousDisplayText) return null;
		return state.displayText;
	}
	finalize(runId, message, showThinking) {
		const state = this.getOrCreateRun(runId);
		this.updateRunState(state, message, showThinking);
		const finalComposed = state.displayText;
		const finalText = resolveFinalAssistantText({
			finalText: finalComposed,
			streamedText: state.displayText
		});
		this.runs.delete(runId);
		return finalText;
	}
	drop(runId) {
		this.runs.delete(runId);
	}
};

//#endregion
//#region ../../src/tui/tui-event-handlers.ts
function createEventHandlers(context) {
	const { chatLog, tui, state, setActivityStatus, refreshSessionInfo } = context;
	const finalizedRuns = /* @__PURE__ */ new Map();
	const sessionRuns = /* @__PURE__ */ new Map();
	let streamAssembler = new TuiStreamAssembler();
	let lastSessionKey = state.currentSessionKey;
	const pruneRunMap = (runs) => {
		if (runs.size <= 200) return;
		const keepUntil = Date.now() - 600 * 1e3;
		for (const [key, ts] of runs) {
			if (runs.size <= 150) break;
			if (ts < keepUntil) runs.delete(key);
		}
		if (runs.size > 200) for (const key of runs.keys()) {
			runs.delete(key);
			if (runs.size <= 150) break;
		}
	};
	const syncSessionKey = () => {
		if (state.currentSessionKey === lastSessionKey) return;
		lastSessionKey = state.currentSessionKey;
		finalizedRuns.clear();
		sessionRuns.clear();
		streamAssembler = new TuiStreamAssembler();
	};
	const noteSessionRun = (runId) => {
		sessionRuns.set(runId, Date.now());
		pruneRunMap(sessionRuns);
	};
	const noteFinalizedRun = (runId) => {
		finalizedRuns.set(runId, Date.now());
		sessionRuns.delete(runId);
		streamAssembler.drop(runId);
		pruneRunMap(finalizedRuns);
	};
	const handleChatEvent = (payload) => {
		if (!payload || typeof payload !== "object") return;
		const evt = payload;
		syncSessionKey();
		if (evt.sessionKey !== state.currentSessionKey) return;
		if (finalizedRuns.has(evt.runId)) {
			if (evt.state === "delta") return;
			if (evt.state === "final") return;
		}
		noteSessionRun(evt.runId);
		if (!state.activeChatRunId) state.activeChatRunId = evt.runId;
		if (evt.state === "delta") {
			const displayText = streamAssembler.ingestDelta(evt.runId, evt.message, state.showThinking);
			if (!displayText) return;
			chatLog.updateAssistant(displayText, evt.runId);
			setActivityStatus("streaming");
		}
		if (evt.state === "final") {
			if (isCommandMessage(evt.message)) {
				const text = extractTextFromMessage(evt.message);
				if (text) chatLog.addSystem(text);
				streamAssembler.drop(evt.runId);
				noteFinalizedRun(evt.runId);
				state.activeChatRunId = null;
				setActivityStatus("idle");
				refreshSessionInfo?.();
				tui.requestRender();
				return;
			}
			const stopReason = evt.message && typeof evt.message === "object" && !Array.isArray(evt.message) ? typeof evt.message.stopReason === "string" ? evt.message.stopReason : "" : "";
			const finalText = streamAssembler.finalize(evt.runId, evt.message, state.showThinking);
			chatLog.finalizeAssistant(finalText, evt.runId);
			noteFinalizedRun(evt.runId);
			state.activeChatRunId = null;
			setActivityStatus(stopReason === "error" ? "error" : "idle");
			refreshSessionInfo?.();
		}
		if (evt.state === "aborted") {
			chatLog.addSystem("run aborted");
			streamAssembler.drop(evt.runId);
			sessionRuns.delete(evt.runId);
			state.activeChatRunId = null;
			setActivityStatus("aborted");
			refreshSessionInfo?.();
		}
		if (evt.state === "error") {
			chatLog.addSystem(`run error: ${evt.errorMessage ?? "unknown"}`);
			streamAssembler.drop(evt.runId);
			sessionRuns.delete(evt.runId);
			state.activeChatRunId = null;
			setActivityStatus("error");
			refreshSessionInfo?.();
		}
		tui.requestRender();
	};
	const handleAgentEvent = (payload) => {
		if (!payload || typeof payload !== "object") return;
		const evt = payload;
		syncSessionKey();
		const isActiveRun = evt.runId === state.activeChatRunId;
		if (!isActiveRun && !sessionRuns.has(evt.runId)) return;
		if (evt.stream === "tool") {
			const data = evt.data ?? {};
			const phase = asString(data.phase, "");
			const toolCallId = asString(data.toolCallId, "");
			const toolName = asString(data.name, "tool");
			if (!toolCallId) return;
			if (phase === "start") chatLog.startTool(toolCallId, toolName, data.args);
			else if (phase === "update") chatLog.updateToolResult(toolCallId, data.partialResult, { partial: true });
			else if (phase === "result") chatLog.updateToolResult(toolCallId, data.result, { isError: Boolean(data.isError) });
			tui.requestRender();
			return;
		}
		if (evt.stream === "lifecycle") {
			if (!isActiveRun) return;
			const phase = typeof evt.data?.phase === "string" ? evt.data.phase : "";
			if (phase === "start") setActivityStatus("running");
			if (phase === "end") setActivityStatus("idle");
			if (phase === "error") setActivityStatus("error");
			tui.requestRender();
		}
	};
	return {
		handleChatEvent,
		handleAgentEvent
	};
}

//#endregion
//#region ../../src/tui/tui-local-shell.ts
function createLocalShellRunner(deps) {
	let localExecAsked = false;
	let localExecAllowed = false;
	const createSelector = deps.createSelector ?? createSearchableSelectList;
	const spawnCommand = deps.spawnCommand ?? spawn;
	const getCwd = deps.getCwd ?? (() => process.cwd());
	const env = deps.env ?? process.env;
	const maxChars = deps.maxOutputChars ?? 4e4;
	const ensureLocalExecAllowed = async () => {
		if (localExecAllowed) return true;
		if (localExecAsked) return false;
		localExecAsked = true;
		return await new Promise((resolve) => {
			deps.chatLog.addSystem("Allow local shell commands for this session?");
			deps.chatLog.addSystem("This runs commands on YOUR machine (not the gateway) and may delete files or reveal secrets.");
			deps.chatLog.addSystem("Select Yes/No (arrows + Enter), Esc to cancel.");
			const selector = createSelector([{
				value: "no",
				label: "No"
			}, {
				value: "yes",
				label: "Yes"
			}], 2);
			selector.onSelect = (item) => {
				deps.closeOverlay();
				if (item.value === "yes") {
					localExecAllowed = true;
					deps.chatLog.addSystem("local shell: enabled for this session");
					resolve(true);
				} else {
					deps.chatLog.addSystem("local shell: not enabled");
					resolve(false);
				}
				deps.tui.requestRender();
			};
			selector.onCancel = () => {
				deps.closeOverlay();
				deps.chatLog.addSystem("local shell: cancelled");
				deps.tui.requestRender();
				resolve(false);
			};
			deps.openOverlay(selector);
			deps.tui.requestRender();
		});
	};
	const runLocalShellLine = async (line) => {
		const cmd = line.slice(1);
		if (cmd === "") return;
		if (localExecAsked && !localExecAllowed) {
			deps.chatLog.addSystem("local shell: not enabled for this session");
			deps.tui.requestRender();
			return;
		}
		if (!await ensureLocalExecAllowed()) return;
		deps.chatLog.addSystem(`[local] $ ${cmd}`);
		deps.tui.requestRender();
		await new Promise((resolve) => {
			const child = spawnCommand(cmd, {
				shell: true,
				cwd: getCwd(),
				env
			});
			let stdout = "";
			let stderr = "";
			child.stdout.on("data", (buf) => {
				stdout += buf.toString("utf8");
			});
			child.stderr.on("data", (buf) => {
				stderr += buf.toString("utf8");
			});
			child.on("close", (code, signal) => {
				const combined = (stdout + (stderr ? (stdout ? "\n" : "") + stderr : "")).slice(0, maxChars).trimEnd();
				if (combined) for (const line of combined.split("\n")) deps.chatLog.addSystem(`[local] ${line}`);
				deps.chatLog.addSystem(`[local] exit ${code ?? "?"}${signal ? ` (signal ${String(signal)})` : ""}`);
				deps.tui.requestRender();
				resolve();
			});
			child.on("error", (err) => {
				deps.chatLog.addSystem(`[local] error: ${String(err)}`);
				deps.tui.requestRender();
				resolve();
			});
		});
	};
	return { runLocalShellLine };
}

//#endregion
//#region ../../src/tui/tui-overlays.ts
function createOverlayHandlers(host, fallbackFocus) {
	const openOverlay = (component) => {
		host.showOverlay(component);
	};
	const closeOverlay = () => {
		if (host.hasOverlay()) {
			host.hideOverlay();
			return;
		}
		host.setFocus(fallbackFocus);
	};
	return {
		openOverlay,
		closeOverlay
	};
}

//#endregion
//#region ../../src/tui/tui-session-actions.ts
function createSessionActions(context) {
	const { client, chatLog, tui, opts, state, agentNames, initialSessionInput, initialSessionAgentId, resolveSessionKey, updateHeader, updateFooter, updateAutocompleteProvider, setActivityStatus } = context;
	let refreshSessionInfoPromise = null;
	const applyAgentsResult = (result) => {
		state.agentDefaultId = normalizeAgentId(result.defaultId);
		state.sessionMainKey = normalizeMainKey(result.mainKey);
		state.sessionScope = result.scope ?? state.sessionScope;
		state.agents = result.agents.map((agent) => ({
			id: normalizeAgentId(agent.id),
			name: agent.name?.trim() || void 0
		}));
		agentNames.clear();
		for (const agent of state.agents) if (agent.name) agentNames.set(agent.id, agent.name);
		if (!state.initialSessionApplied) {
			if (initialSessionAgentId) {
				if (state.agents.some((agent) => agent.id === initialSessionAgentId)) state.currentAgentId = initialSessionAgentId;
			} else if (!state.agents.some((agent) => agent.id === state.currentAgentId)) state.currentAgentId = state.agents[0]?.id ?? normalizeAgentId(result.defaultId ?? state.currentAgentId);
			const nextSessionKey = resolveSessionKey(initialSessionInput);
			if (nextSessionKey !== state.currentSessionKey) state.currentSessionKey = nextSessionKey;
			state.initialSessionApplied = true;
		} else if (!state.agents.some((agent) => agent.id === state.currentAgentId)) state.currentAgentId = state.agents[0]?.id ?? normalizeAgentId(result.defaultId ?? state.currentAgentId);
		updateHeader();
		updateFooter();
	};
	const refreshAgents = async () => {
		try {
			applyAgentsResult(await client.listAgents());
		} catch (err) {
			chatLog.addSystem(`agents list failed: ${String(err)}`);
		}
	};
	const updateAgentFromSessionKey = (key) => {
		const parsed = parseAgentSessionKey(key);
		if (!parsed) return;
		const next = normalizeAgentId(parsed.agentId);
		if (next !== state.currentAgentId) state.currentAgentId = next;
	};
	const refreshSessionInfo = async () => {
		if (refreshSessionInfoPromise) return refreshSessionInfoPromise;
		refreshSessionInfoPromise = (async () => {
			try {
				const listAgentId = state.currentSessionKey === "global" || state.currentSessionKey === "unknown" ? void 0 : state.currentAgentId;
				const result = await client.listSessions({
					includeGlobal: false,
					includeUnknown: false,
					agentId: listAgentId
				});
				const entry = result.sessions.find((row) => {
					if (row.key === state.currentSessionKey) return true;
					return parseAgentSessionKey(row.key)?.rest === state.currentSessionKey;
				});
				state.sessionInfo = {
					thinkingLevel: entry?.thinkingLevel,
					verboseLevel: entry?.verboseLevel,
					reasoningLevel: entry?.reasoningLevel,
					model: entry?.model ?? result.defaults?.model ?? void 0,
					modelProvider: entry?.modelProvider ?? result.defaults?.modelProvider ?? void 0,
					contextTokens: entry?.contextTokens ?? result.defaults?.contextTokens,
					inputTokens: entry?.inputTokens ?? null,
					outputTokens: entry?.outputTokens ?? null,
					totalTokens: entry?.totalTokens ?? null,
					responseUsage: entry?.responseUsage,
					updatedAt: entry?.updatedAt ?? null,
					displayName: entry?.displayName
				};
			} catch (err) {
				chatLog.addSystem(`sessions list failed: ${String(err)}`);
			}
			updateAutocompleteProvider();
			updateFooter();
			tui.requestRender();
		})();
		try {
			await refreshSessionInfoPromise;
		} finally {
			refreshSessionInfoPromise = null;
		}
	};
	const loadHistory = async () => {
		try {
			const record = await client.loadHistory({
				sessionKey: state.currentSessionKey,
				limit: opts.historyLimit ?? 200
			});
			state.currentSessionId = typeof record.sessionId === "string" ? record.sessionId : null;
			state.sessionInfo.thinkingLevel = record.thinkingLevel ?? state.sessionInfo.thinkingLevel;
			chatLog.clearAll();
			chatLog.addSystem(`session ${state.currentSessionKey}`);
			for (const entry of record.messages ?? []) {
				if (!entry || typeof entry !== "object") continue;
				const message = entry;
				if (isCommandMessage(message)) {
					const text = extractTextFromMessage(message);
					if (text) chatLog.addSystem(text);
					continue;
				}
				if (message.role === "user") {
					const text = extractTextFromMessage(message);
					if (text) chatLog.addUser(text);
					continue;
				}
				if (message.role === "assistant") {
					const text = extractTextFromMessage(message, { includeThinking: state.showThinking });
					if (text) chatLog.finalizeAssistant(text);
					continue;
				}
				if (message.role === "toolResult") {
					const toolCallId = asString(message.toolCallId, "");
					const toolName = asString(message.toolName, "tool");
					chatLog.startTool(toolCallId, toolName, {}).setResult({
						content: Array.isArray(message.content) ? message.content : [],
						details: typeof message.details === "object" && message.details ? message.details : void 0
					}, { isError: Boolean(message.isError) });
				}
			}
			state.historyLoaded = true;
		} catch (err) {
			chatLog.addSystem(`history failed: ${String(err)}`);
		}
		await refreshSessionInfo();
		tui.requestRender();
	};
	const setSession = async (rawKey) => {
		const nextKey = resolveSessionKey(rawKey);
		updateAgentFromSessionKey(nextKey);
		state.currentSessionKey = nextKey;
		state.activeChatRunId = null;
		state.currentSessionId = null;
		state.historyLoaded = false;
		updateHeader();
		updateFooter();
		await loadHistory();
	};
	const abortActive = async () => {
		if (!state.activeChatRunId) {
			chatLog.addSystem("no active run");
			tui.requestRender();
			return;
		}
		try {
			await client.abortChat({
				sessionKey: state.currentSessionKey,
				runId: state.activeChatRunId
			});
			setActivityStatus("aborted");
		} catch (err) {
			chatLog.addSystem(`abort failed: ${String(err)}`);
			setActivityStatus("abort failed");
		}
		tui.requestRender();
	};
	return {
		applyAgentsResult,
		refreshAgents,
		refreshSessionInfo,
		loadHistory,
		setSession,
		abortActive
	};
}

//#endregion
//#region ../../src/tui/tui-waiting.ts
const defaultWaitingPhrases = [
	"flibbertigibbeting",
	"kerfuffling",
	"dillydallying",
	"twiddling thumbs",
	"noodling",
	"bamboozling",
	"moseying",
	"hobnobbing",
	"pondering",
	"conjuring"
];
function pickWaitingPhrase(tick, phrases = defaultWaitingPhrases) {
	return phrases[Math.floor(tick / 10) % phrases.length] ?? phrases[0] ?? "waiting";
}
function shimmerText(theme, text, tick) {
	const width = 6;
	const hi = (ch) => theme.bold(theme.accentSoft(ch));
	const pos = tick % (text.length + width);
	const start = Math.max(0, pos - width);
	const end = Math.min(text.length - 1, pos);
	let out = "";
	for (let i = 0; i < text.length; i++) {
		const ch = text[i];
		out += i >= start && i <= end ? hi(ch) : theme.dim(ch);
	}
	return out;
}
function buildWaitingStatusMessage(params) {
	const phrase = pickWaitingPhrase(params.tick, params.phrases);
	return `${shimmerText(params.theme, `${phrase}…`, params.tick)} • ${params.elapsed} | ${params.connectionStatus}`;
}

//#endregion
//#region ../../src/tui/tui.ts
function createEditorSubmitHandler(params) {
	return (text) => {
		const raw = text;
		const value = raw.trim();
		params.editor.setText("");
		if (!value) return;
		if (raw.startsWith("!") && raw !== "!") {
			params.editor.addToHistory(raw);
			params.handleBangLine(raw);
			return;
		}
		params.editor.addToHistory(value);
		if (value.startsWith("/")) {
			params.handleCommand(value);
			return;
		}
		params.sendMessage(value);
	};
}
async function runTui(opts) {
	const config = loadConfig();
	const initialSessionInput = (opts.session ?? "").trim();
	let sessionScope = config.session?.scope ?? "per-sender";
	let sessionMainKey = normalizeMainKey(config.session?.mainKey);
	let agentDefaultId = resolveDefaultAgentId(config);
	let currentAgentId = agentDefaultId;
	let agents = [];
	const agentNames = /* @__PURE__ */ new Map();
	let currentSessionKey = "";
	let initialSessionApplied = false;
	let currentSessionId = null;
	let activeChatRunId = null;
	let historyLoaded = false;
	let isConnected = false;
	let wasDisconnected = false;
	let toolsExpanded = false;
	let showThinking = false;
	const deliverDefault = opts.deliver ?? false;
	const autoMessage = opts.message?.trim();
	let autoMessageSent = false;
	let sessionInfo = {};
	let lastCtrlCAt = 0;
	let activityStatus = "idle";
	let connectionStatus = "connecting";
	let statusTimeout = null;
	let statusTimer = null;
	let statusStartedAt = null;
	let lastActivityStatus = activityStatus;
	const state = {
		get agentDefaultId() {
			return agentDefaultId;
		},
		set agentDefaultId(value) {
			agentDefaultId = value;
		},
		get sessionMainKey() {
			return sessionMainKey;
		},
		set sessionMainKey(value) {
			sessionMainKey = value;
		},
		get sessionScope() {
			return sessionScope;
		},
		set sessionScope(value) {
			sessionScope = value;
		},
		get agents() {
			return agents;
		},
		set agents(value) {
			agents = value;
		},
		get currentAgentId() {
			return currentAgentId;
		},
		set currentAgentId(value) {
			currentAgentId = value;
		},
		get currentSessionKey() {
			return currentSessionKey;
		},
		set currentSessionKey(value) {
			currentSessionKey = value;
		},
		get currentSessionId() {
			return currentSessionId;
		},
		set currentSessionId(value) {
			currentSessionId = value;
		},
		get activeChatRunId() {
			return activeChatRunId;
		},
		set activeChatRunId(value) {
			activeChatRunId = value;
		},
		get historyLoaded() {
			return historyLoaded;
		},
		set historyLoaded(value) {
			historyLoaded = value;
		},
		get sessionInfo() {
			return sessionInfo;
		},
		set sessionInfo(value) {
			sessionInfo = value;
		},
		get initialSessionApplied() {
			return initialSessionApplied;
		},
		set initialSessionApplied(value) {
			initialSessionApplied = value;
		},
		get isConnected() {
			return isConnected;
		},
		set isConnected(value) {
			isConnected = value;
		},
		get autoMessageSent() {
			return autoMessageSent;
		},
		set autoMessageSent(value) {
			autoMessageSent = value;
		},
		get toolsExpanded() {
			return toolsExpanded;
		},
		set toolsExpanded(value) {
			toolsExpanded = value;
		},
		get showThinking() {
			return showThinking;
		},
		set showThinking(value) {
			showThinking = value;
		},
		get connectionStatus() {
			return connectionStatus;
		},
		set connectionStatus(value) {
			connectionStatus = value;
		},
		get activityStatus() {
			return activityStatus;
		},
		set activityStatus(value) {
			activityStatus = value;
		},
		get statusTimeout() {
			return statusTimeout;
		},
		set statusTimeout(value) {
			statusTimeout = value;
		},
		get lastCtrlCAt() {
			return lastCtrlCAt;
		},
		set lastCtrlCAt(value) {
			lastCtrlCAt = value;
		}
	};
	const client = new GatewayChatClient({
		url: opts.url,
		token: opts.token,
		password: opts.password
	});
	const tui = new TUI(new ProcessTerminal());
	const header = new Text("", 1, 0);
	const statusContainer = new Container();
	const footer = new Text("", 1, 0);
	const chatLog = new ChatLog();
	const editor = new CustomEditor(tui, editorTheme);
	const root = new Container();
	root.addChild(header);
	root.addChild(chatLog);
	root.addChild(statusContainer);
	root.addChild(footer);
	root.addChild(editor);
	const updateAutocompleteProvider = () => {
		editor.setAutocompleteProvider(new CombinedAutocompleteProvider(getSlashCommands({
			cfg: config,
			provider: sessionInfo.modelProvider,
			model: sessionInfo.model
		}), process.cwd()));
	};
	tui.addChild(root);
	tui.setFocus(editor);
	const formatSessionKey = (key) => {
		if (key === "global" || key === "unknown") return key;
		return parseAgentSessionKey(key)?.rest ?? key;
	};
	const formatAgentLabel = (id) => {
		const name = agentNames.get(id);
		return name ? `${id} (${name})` : id;
	};
	const resolveSessionKey = (raw) => {
		const trimmed = (raw ?? "").trim();
		if (sessionScope === "global") return "global";
		if (!trimmed) return buildAgentMainSessionKey({
			agentId: currentAgentId,
			mainKey: sessionMainKey
		});
		if (trimmed === "global" || trimmed === "unknown") return trimmed;
		if (trimmed.startsWith("agent:")) return trimmed;
		return `agent:${currentAgentId}:${trimmed}`;
	};
	currentSessionKey = resolveSessionKey(initialSessionInput);
	const updateHeader = () => {
		const sessionLabel = formatSessionKey(currentSessionKey);
		const agentLabel = formatAgentLabel(currentAgentId);
		header.setText(theme.header(`edwinpai tui - ${client.connection.url} - agent ${agentLabel} - session ${sessionLabel}`));
	};
	const busyStates = new Set([
		"sending",
		"waiting",
		"streaming",
		"running"
	]);
	let statusText = null;
	let statusLoader = null;
	const formatElapsed = (startMs) => {
		const totalSeconds = Math.max(0, Math.floor((Date.now() - startMs) / 1e3));
		if (totalSeconds < 60) return `${totalSeconds}s`;
		return `${Math.floor(totalSeconds / 60)}m ${totalSeconds % 60}s`;
	};
	const ensureStatusText = () => {
		if (statusText) return;
		statusContainer.clear();
		statusLoader?.stop();
		statusLoader = null;
		statusText = new Text("", 1, 0);
		statusContainer.addChild(statusText);
	};
	const ensureStatusLoader = () => {
		if (statusLoader) return;
		statusContainer.clear();
		statusText = null;
		statusLoader = new Loader(tui, (spinner) => theme.accent(spinner), (text) => theme.bold(theme.accentSoft(text)), "");
		statusContainer.addChild(statusLoader);
	};
	let waitingTick = 0;
	let waitingTimer = null;
	let waitingPhrase = null;
	const updateBusyStatusMessage = () => {
		if (!statusLoader || !statusStartedAt) return;
		const elapsed = formatElapsed(statusStartedAt);
		if (activityStatus === "waiting") {
			waitingTick++;
			statusLoader.setMessage(buildWaitingStatusMessage({
				theme,
				tick: waitingTick,
				elapsed,
				connectionStatus,
				phrases: waitingPhrase ? [waitingPhrase] : void 0
			}));
			return;
		}
		statusLoader.setMessage(`${activityStatus} • ${elapsed} | ${connectionStatus}`);
	};
	const startStatusTimer = () => {
		if (statusTimer) return;
		statusTimer = setInterval(() => {
			if (!busyStates.has(activityStatus)) return;
			updateBusyStatusMessage();
		}, 1e3);
	};
	const stopStatusTimer = () => {
		if (!statusTimer) return;
		clearInterval(statusTimer);
		statusTimer = null;
	};
	const startWaitingTimer = () => {
		if (waitingTimer) return;
		if (!waitingPhrase) waitingPhrase = defaultWaitingPhrases[Math.floor(Math.random() * defaultWaitingPhrases.length)] ?? defaultWaitingPhrases[0] ?? "waiting";
		waitingTick = 0;
		waitingTimer = setInterval(() => {
			if (activityStatus !== "waiting") return;
			updateBusyStatusMessage();
		}, 120);
	};
	const stopWaitingTimer = () => {
		if (!waitingTimer) return;
		clearInterval(waitingTimer);
		waitingTimer = null;
		waitingPhrase = null;
	};
	const renderStatus = () => {
		if (busyStates.has(activityStatus)) {
			if (!statusStartedAt || lastActivityStatus !== activityStatus) statusStartedAt = Date.now();
			ensureStatusLoader();
			if (activityStatus === "waiting") {
				stopStatusTimer();
				startWaitingTimer();
			} else {
				stopWaitingTimer();
				startStatusTimer();
			}
			updateBusyStatusMessage();
		} else {
			statusStartedAt = null;
			stopStatusTimer();
			stopWaitingTimer();
			statusLoader?.stop();
			statusLoader = null;
			ensureStatusText();
			const text = activityStatus ? `${connectionStatus} | ${activityStatus}` : connectionStatus;
			statusText?.setText(theme.dim(text));
		}
		lastActivityStatus = activityStatus;
	};
	const setConnectionStatus = (text, ttlMs) => {
		connectionStatus = text;
		renderStatus();
		if (statusTimeout) clearTimeout(statusTimeout);
		if (ttlMs && ttlMs > 0) statusTimeout = setTimeout(() => {
			connectionStatus = isConnected ? "connected" : "disconnected";
			renderStatus();
		}, ttlMs);
	};
	const setActivityStatus = (text) => {
		activityStatus = text;
		renderStatus();
	};
	const resolveConfiguredModelLabel = () => {
		try {
			const primary = config.agents?.defaults?.model?.primary;
			if (!primary) return void 0;
			const models = config.agents?.defaults?.models;
			if (models) {
				for (const [key, val] of Object.entries(models)) if (key === primary || key.endsWith(`/${val?.alias}`)) {
					const alias = val?.alias;
					if (alias) return alias;
				}
			}
			return primary;
		} catch {
			return;
		}
	};
	const updateFooter = () => {
		const sessionKeyLabel = formatSessionKey(currentSessionKey);
		const sessionLabel = sessionInfo.displayName ? `${sessionKeyLabel} (${sessionInfo.displayName})` : sessionKeyLabel;
		const agentLabel = formatAgentLabel(currentAgentId);
		const modelLabel = resolveConfiguredModelLabel() ?? (sessionInfo.model ? sessionInfo.modelProvider ? `${sessionInfo.modelProvider}/${sessionInfo.model}` : sessionInfo.model : "unknown");
		const tokens = formatTokens(sessionInfo.totalTokens ?? null, sessionInfo.contextTokens ?? null);
		const think = sessionInfo.thinkingLevel ?? "off";
		const verbose = sessionInfo.verboseLevel ?? "off";
		const reasoning = sessionInfo.reasoningLevel ?? "off";
		const reasoningLabel = reasoning === "on" ? "reasoning" : reasoning === "stream" ? "reasoning:stream" : null;
		const footerParts = [
			`agent ${agentLabel}`,
			`session ${sessionLabel}`,
			modelLabel,
			think !== "off" ? `think ${think}` : null,
			verbose !== "off" ? `verbose ${verbose}` : null,
			reasoningLabel,
			tokens
		].filter(Boolean);
		footer.setText(theme.dim(footerParts.join(" | ")));
	};
	const { openOverlay, closeOverlay } = createOverlayHandlers(tui, editor);
	const { refreshAgents, refreshSessionInfo, loadHistory, setSession, abortActive } = createSessionActions({
		client,
		chatLog,
		tui,
		opts,
		state,
		agentNames,
		initialSessionInput,
		initialSessionAgentId: (() => {
			if (!initialSessionInput) return null;
			const parsed = parseAgentSessionKey(initialSessionInput);
			return parsed ? normalizeAgentId(parsed.agentId) : null;
		})(),
		resolveSessionKey,
		updateHeader,
		updateFooter,
		updateAutocompleteProvider,
		setActivityStatus
	});
	const { handleChatEvent, handleAgentEvent } = createEventHandlers({
		chatLog,
		tui,
		state,
		setActivityStatus,
		refreshSessionInfo
	});
	const { handleCommand, sendMessage, openModelSelector, openAgentSelector, openSessionSelector } = createCommandHandlers({
		client,
		chatLog,
		tui,
		opts,
		state,
		deliverDefault,
		openOverlay,
		closeOverlay,
		refreshSessionInfo,
		loadHistory,
		setSession,
		refreshAgents,
		abortActive,
		setActivityStatus,
		formatSessionKey
	});
	const { runLocalShellLine } = createLocalShellRunner({
		chatLog,
		tui,
		openOverlay,
		closeOverlay
	});
	updateAutocompleteProvider();
	editor.onSubmit = createEditorSubmitHandler({
		editor,
		handleCommand,
		sendMessage,
		handleBangLine: runLocalShellLine
	});
	editor.onEscape = () => {
		abortActive();
	};
	editor.onCtrlC = () => {
		const now = Date.now();
		if (editor.getText().trim().length > 0) {
			editor.setText("");
			setActivityStatus("cleared input");
			tui.requestRender();
			return;
		}
		if (now - lastCtrlCAt < 1e3) {
			client.stop();
			tui.stop();
			process.exit(0);
		}
		lastCtrlCAt = now;
		setActivityStatus("press ctrl+c again to exit");
		tui.requestRender();
	};
	editor.onCtrlD = () => {
		client.stop();
		tui.stop();
		process.exit(0);
	};
	editor.onCtrlO = () => {
		toolsExpanded = !toolsExpanded;
		chatLog.setToolsExpanded(toolsExpanded);
		setActivityStatus(toolsExpanded ? "tools expanded" : "tools collapsed");
		tui.requestRender();
	};
	editor.onCtrlL = () => {
		openModelSelector();
	};
	editor.onCtrlG = () => {
		openAgentSelector();
	};
	editor.onCtrlP = () => {
		openSessionSelector();
	};
	editor.onCtrlT = () => {
		showThinking = !showThinking;
		loadHistory();
	};
	client.onEvent = (evt) => {
		if (evt.event === "chat") handleChatEvent(evt.payload);
		if (evt.event === "agent") handleAgentEvent(evt.payload);
	};
	client.onConnected = () => {
		isConnected = true;
		const reconnected = wasDisconnected;
		wasDisconnected = false;
		setConnectionStatus("connected");
		(async () => {
			await refreshAgents();
			updateHeader();
			await loadHistory();
			setConnectionStatus(reconnected ? "gateway reconnected" : "gateway connected", 4e3);
			tui.requestRender();
			if (!autoMessageSent && autoMessage) {
				autoMessageSent = true;
				await sendMessage(autoMessage);
			}
			updateFooter();
			tui.requestRender();
		})();
	};
	client.onDisconnected = (reason) => {
		isConnected = false;
		wasDisconnected = true;
		historyLoaded = false;
		setConnectionStatus(`gateway disconnected: ${reason?.trim() ? reason.trim() : "closed"}`, 5e3);
		setActivityStatus("idle");
		updateFooter();
		tui.requestRender();
	};
	client.onGap = (info) => {
		setConnectionStatus(`event gap: expected ${info.expected}, got ${info.received}`, 5e3);
		tui.requestRender();
	};
	updateHeader();
	setConnectionStatus("connecting");
	updateFooter();
	tui.start();
	client.start();
	await new Promise((resolve) => {
		const finish = () => resolve();
		process.once("exit", finish);
		process.once("SIGINT", finish);
		process.once("SIGTERM", finish);
	});
}

//#endregion
export { runTui as t };