import { j as theme } from "./registry-Sbac4a4z.js";
import { _ as resolveStateDir } from "./paths-By0XjHBk.js";
import { u as isRecord } from "./utils-CTPsqyE_.js";
import { t as createSubsystemLogger } from "./subsystem-CHbO_DkH.js";
import { b as ensureAuthProfileStore, c as resolveApiKeyForProfile, h as listProfilesForProvider, m as dedupeProfileIds, n as resolveAuthProfileOrder } from "./auth-profiles-Ce7R_25e.js";
import { t as formatCliCommand } from "./command-format-BzjsXBTi.js";
import { o as normalizeAgentId, p as DEFAULT_ACCOUNT_ID, s as normalizeMainKey, v as isCronRunSessionKey, x as parseAgentSessionKey } from "./session-key-DUSb7CCb.js";
import { i as logDebug } from "./exec-DuYbft0z.js";
import { c as resolveAgentWorkspaceDir, l as resolveDefaultAgentId } from "./agent-scope-DOrZjOnW.js";
import { C as DEFAULT_MODEL, S as DEFAULT_CONTEXT_TOKENS, d as parseModelRef, h as resolveDefaultModelForAgent, m as resolveConfiguredModelRef, u as normalizeProviderId, w as DEFAULT_PROVIDER } from "./model-selection-7wdmO-Iw.js";
import { n as normalizeSecretInput } from "./normalize-secret-input-DjGU5EXe.js";
import { t as resolveSymiAgentDir } from "./agent-paths-BbZSGrUA.js";
import { i as loadConfig } from "./config-B4jkreCN.js";
import { B as resolveAgentMainSessionKey, D as resolveSessionTranscriptCandidates, E as readSessionTitleFieldsFromTranscript, H as resolveMainSessionKey, K as buildGroupDisplayName, R as resolveFreshSessionTotalTokens, o as loadSessionStore, y as normalizeSessionDeliveryFields, z as canonicalizeMainSessionAlias } from "./sessions-Dxf5Kjig.js";
import { n as listChannelPlugins } from "./plugins-CF5skkHh.js";
import { c as resolveStorePath } from "./paths-BtvQ7JvU.js";
import { n as getCustomProviderApiKey } from "./model-auth-1EAQvYRv.js";
import { t as ensureSymiModelsJson } from "./models-config-B5Xxy-c-.js";
import { t as bindAbortRelay } from "./fetch-timeout-BhdrdVp5.js";
import { n as formatTimeAgo } from "./format-relative-D4GQsWlP.js";
import crypto from "node:crypto";
import path from "node:path";
import fs from "node:fs";
import os from "node:os";
import fs$1 from "node:fs/promises";

//#region src/logging/redact-identifier.ts
function sha256HexPrefix(value, len = 12) {
	const safeLen = Number.isFinite(len) ? Math.max(1, Math.floor(len)) : 12;
	return crypto.createHash("sha256").update(value).digest("hex").slice(0, safeLen);
}
function redactIdentifier(value, opts) {
	const trimmed = value?.trim();
	if (!trimmed) return "-";
	return `sha256:${sha256HexPrefix(trimmed, opts?.len ?? 12)}`;
}

//#endregion
//#region src/channels/account-summary.ts
function buildChannelAccountSnapshot(params) {
	const described = params.plugin.config.describeAccount?.(params.account, params.cfg);
	return {
		enabled: params.enabled,
		configured: params.configured,
		...described,
		accountId: params.accountId
	};
}
function formatChannelAllowFrom(params) {
	if (params.plugin.config.formatAllowFrom) return params.plugin.config.formatAllowFrom({
		cfg: params.cfg,
		accountId: params.accountId,
		allowFrom: params.allowFrom
	});
	return params.allowFrom.map((entry) => String(entry).trim()).filter(Boolean);
}

//#endregion
//#region src/infra/channel-summary.ts
const DEFAULT_OPTIONS = {
	colorize: false,
	includeAllowFrom: false
};
const formatAccountLabel = (params) => {
	const base = params.accountId || DEFAULT_ACCOUNT_ID;
	if (params.name?.trim()) return `${base} (${params.name.trim()})`;
	return base;
};
const accountLine = (label, details) => `  - ${label}${details.length ? ` (${details.join(", ")})` : ""}`;
const resolveAccountEnabled = (plugin, account, cfg) => {
	if (plugin.config.isEnabled) return plugin.config.isEnabled(account, cfg);
	if (!account || typeof account !== "object") return true;
	return account.enabled !== false;
};
const resolveAccountConfigured = async (plugin, account, cfg) => {
	if (plugin.config.isConfigured) return await plugin.config.isConfigured(account, cfg);
	return true;
};
const buildAccountDetails = (params) => {
	const details = [];
	const snapshot = params.entry.snapshot;
	if (snapshot.enabled === false) details.push("disabled");
	if (snapshot.dmPolicy) details.push(`dm:${snapshot.dmPolicy}`);
	if (snapshot.tokenSource && snapshot.tokenSource !== "none") details.push(`token:${snapshot.tokenSource}`);
	if (snapshot.botTokenSource && snapshot.botTokenSource !== "none") details.push(`bot:${snapshot.botTokenSource}`);
	if (snapshot.appTokenSource && snapshot.appTokenSource !== "none") details.push(`app:${snapshot.appTokenSource}`);
	if (snapshot.baseUrl) details.push(snapshot.baseUrl);
	if (snapshot.port != null) details.push(`port:${snapshot.port}`);
	if (snapshot.cliPath) details.push(`cli:${snapshot.cliPath}`);
	if (snapshot.dbPath) details.push(`db:${snapshot.dbPath}`);
	if (params.includeAllowFrom && snapshot.allowFrom?.length) {
		const formatted = formatChannelAllowFrom({
			plugin: params.plugin,
			cfg: params.cfg,
			accountId: snapshot.accountId,
			allowFrom: snapshot.allowFrom
		}).slice(0, 2);
		if (formatted.length > 0) details.push(`allow:${formatted.join(",")}`);
	}
	return details;
};
async function buildChannelSummary(cfg, options) {
	const effective = cfg ?? loadConfig();
	const lines = [];
	const resolved = {
		...DEFAULT_OPTIONS,
		...options
	};
	const tint = (value, color) => resolved.colorize && color ? color(value) : value;
	for (const plugin of listChannelPlugins()) {
		const accountIds = plugin.config.listAccountIds(effective);
		const defaultAccountId = plugin.config.defaultAccountId?.(effective) ?? accountIds[0] ?? DEFAULT_ACCOUNT_ID;
		const resolvedAccountIds = accountIds.length > 0 ? accountIds : [defaultAccountId];
		const entries = [];
		for (const accountId of resolvedAccountIds) {
			const account = plugin.config.resolveAccount(effective, accountId);
			const enabled = resolveAccountEnabled(plugin, account, effective);
			const configured = await resolveAccountConfigured(plugin, account, effective);
			const snapshot = buildChannelAccountSnapshot({
				plugin,
				account,
				cfg: effective,
				accountId,
				enabled,
				configured
			});
			entries.push({
				accountId,
				account,
				enabled,
				configured,
				snapshot
			});
		}
		const configuredEntries = entries.filter((entry) => entry.configured);
		const anyEnabled = entries.some((entry) => entry.enabled);
		const fallbackEntry = entries.find((entry) => entry.accountId === defaultAccountId) ?? entries[0];
		const summaryRecord = plugin.status?.buildChannelSummary ? await plugin.status.buildChannelSummary({
			account: fallbackEntry?.account ?? {},
			cfg: effective,
			defaultAccountId,
			snapshot: fallbackEntry?.snapshot ?? { accountId: defaultAccountId }
		}) : void 0;
		const linked = summaryRecord && typeof summaryRecord.linked === "boolean" ? summaryRecord.linked : null;
		const configured = summaryRecord && typeof summaryRecord.configured === "boolean" ? summaryRecord.configured : configuredEntries.length > 0;
		const status = !anyEnabled ? "disabled" : linked !== null ? linked ? "linked" : "not linked" : configured ? "configured" : "not configured";
		const statusColor = status === "linked" || status === "configured" ? theme.success : status === "not linked" ? theme.error : theme.muted;
		let line = `${plugin.meta.label ?? plugin.id}: ${status}`;
		const authAgeMs = summaryRecord && typeof summaryRecord.authAgeMs === "number" ? summaryRecord.authAgeMs : null;
		const self = summaryRecord?.self;
		if (self?.e164) line += ` ${self.e164}`;
		if (authAgeMs != null && authAgeMs >= 0) line += ` auth ${formatTimeAgo(authAgeMs)}`;
		lines.push(tint(line, statusColor));
		if (configuredEntries.length > 0) for (const entry of configuredEntries) {
			const details = buildAccountDetails({
				entry,
				plugin,
				cfg: effective,
				includeAllowFrom: resolved.includeAllowFrom
			});
			lines.push(accountLine(formatAccountLabel({
				accountId: entry.accountId,
				name: entry.snapshot.name
			}), details));
		}
	}
	return lines;
}

//#endregion
//#region src/infra/system-events.ts
const MAX_EVENTS = 20;
const queues = /* @__PURE__ */ new Map();
function requireSessionKey(key) {
	const trimmed = typeof key === "string" ? key.trim() : "";
	if (!trimmed) throw new Error("system events require a sessionKey");
	return trimmed;
}
function normalizeContextKey(key) {
	if (!key) return null;
	const trimmed = key.trim();
	if (!trimmed) return null;
	return trimmed.toLowerCase();
}
function isSystemEventContextChanged(sessionKey, contextKey) {
	const key = requireSessionKey(sessionKey);
	const existing = queues.get(key);
	return normalizeContextKey(contextKey) !== (existing?.lastContextKey ?? null);
}
function enqueueSystemEvent(text, options) {
	const key = requireSessionKey(options?.sessionKey);
	const entry = queues.get(key) ?? (() => {
		const created = {
			queue: [],
			lastText: null,
			lastContextKey: null
		};
		queues.set(key, created);
		return created;
	})();
	const cleaned = text.trim();
	if (!cleaned) return;
	const normalizedContextKey = normalizeContextKey(options?.contextKey);
	entry.lastContextKey = normalizedContextKey;
	if (entry.lastText === cleaned) return;
	entry.lastText = cleaned;
	entry.queue.push({
		text: cleaned,
		ts: Date.now(),
		contextKey: normalizedContextKey
	});
	if (entry.queue.length > MAX_EVENTS) entry.queue.shift();
}
function drainSystemEventEntries(sessionKey) {
	const key = requireSessionKey(sessionKey);
	const entry = queues.get(key);
	if (!entry || entry.queue.length === 0) return [];
	const out = entry.queue.slice();
	entry.queue.length = 0;
	entry.lastText = null;
	entry.lastContextKey = null;
	queues.delete(key);
	return out;
}
function peekSystemEventEntries(sessionKey) {
	const key = requireSessionKey(sessionKey);
	return queues.get(key)?.queue.map((event) => ({ ...event })) ?? [];
}
function peekSystemEvents(sessionKey) {
	return peekSystemEventEntries(sessionKey).map((event) => event.text);
}

//#endregion
//#region src/agents/context.ts
function applyDiscoveredContextWindows(params) {
	for (const model of params.models) {
		if (!model?.id) continue;
		const contextWindow = typeof model.contextWindow === "number" ? Math.trunc(model.contextWindow) : void 0;
		if (!contextWindow || contextWindow <= 0) continue;
		const existing = params.cache.get(model.id);
		if (existing === void 0 || contextWindow < existing) params.cache.set(model.id, contextWindow);
	}
}
function applyConfiguredContextWindows(params) {
	const providers = params.modelsConfig?.providers;
	if (!providers || typeof providers !== "object") return;
	for (const provider of Object.values(providers)) {
		if (!Array.isArray(provider?.models)) continue;
		for (const model of provider.models) {
			const modelId = typeof model?.id === "string" ? model.id : void 0;
			const contextWindow = typeof model?.contextWindow === "number" ? model.contextWindow : void 0;
			if (!modelId || !contextWindow || contextWindow <= 0) continue;
			params.cache.set(modelId, contextWindow);
		}
	}
}
const MODEL_CACHE = /* @__PURE__ */ new Map();
(async () => {
	let cfg;
	try {
		cfg = loadConfig();
	} catch {
		return;
	}
	try {
		await ensureSymiModelsJson(cfg);
	} catch {}
	try {
		const { discoverAuthStorage, discoverModels } = await import("./pi-model-discovery-ClQLvlCW.js").then((n) => n.r);
		const agentDir = resolveSymiAgentDir();
		const modelRegistry = discoverModels(discoverAuthStorage(agentDir), agentDir);
		applyDiscoveredContextWindows({
			cache: MODEL_CACHE,
			models: typeof modelRegistry.getAvailable === "function" ? modelRegistry.getAvailable() : modelRegistry.getAll()
		});
	} catch {}
	applyConfiguredContextWindows({
		cache: MODEL_CACHE,
		modelsConfig: cfg.models
	});
})().catch(() => {});
function lookupContextTokens(modelId) {
	if (!modelId) return;
	return MODEL_CACHE.get(modelId);
}

//#endregion
//#region src/infra/provider-usage.shared.ts
const DEFAULT_TIMEOUT_MS = 5e3;
const PROVIDER_LABELS = {
	anthropic: "Claude",
	"github-copilot": "Copilot",
	"google-gemini-cli": "Gemini",
	"google-antigravity": "Antigravity",
	minimax: "MiniMax",
	"openai-codex": "Codex",
	xiaomi: "Xiaomi",
	zai: "z.ai"
};
const usageProviders = [
	"anthropic",
	"github-copilot",
	"google-gemini-cli",
	"google-antigravity",
	"minimax",
	"openai-codex",
	"xiaomi",
	"zai"
];
function resolveUsageProviderId(provider) {
	if (!provider) return;
	const normalized = normalizeProviderId(provider);
	return usageProviders.includes(normalized) ? normalized : void 0;
}
const ignoredErrors = new Set([
	"No credentials",
	"No token",
	"No API key",
	"Not logged in",
	"No auth"
]);
const clampPercent = (value) => Math.max(0, Math.min(100, Number.isFinite(value) ? value : 0));
const withTimeout = async (work, ms, fallback) => {
	let timeout;
	try {
		return await Promise.race([work, new Promise((resolve) => {
			timeout = setTimeout(() => resolve(fallback), ms);
		})]);
	} finally {
		if (timeout) clearTimeout(timeout);
	}
};

//#endregion
//#region src/infra/provider-usage.format.ts
function formatResetRemaining(targetMs, now) {
	if (!targetMs) return null;
	const diffMs = targetMs - (now ?? Date.now());
	if (diffMs <= 0) return "now";
	const diffMins = Math.floor(diffMs / 6e4);
	if (diffMins < 60) return `${diffMins}m`;
	const hours = Math.floor(diffMins / 60);
	const mins = diffMins % 60;
	if (hours < 24) return mins > 0 ? `${hours}h ${mins}m` : `${hours}h`;
	const days = Math.floor(hours / 24);
	if (days < 7) return `${days}d ${hours % 24}h`;
	return new Intl.DateTimeFormat("en-US", {
		month: "short",
		day: "numeric"
	}).format(new Date(targetMs));
}
function formatUsageWindowSummary(snapshot, opts) {
	if (snapshot.error) return null;
	if (snapshot.windows.length === 0) return null;
	const now = opts?.now ?? Date.now();
	const maxWindows = typeof opts?.maxWindows === "number" && opts.maxWindows > 0 ? Math.min(opts.maxWindows, snapshot.windows.length) : snapshot.windows.length;
	const includeResets = opts?.includeResets ?? false;
	return snapshot.windows.slice(0, maxWindows).map((window) => {
		const remaining = clampPercent(100 - window.usedPercent);
		const reset = includeResets ? formatResetRemaining(window.resetAt, now) : null;
		const resetSuffix = reset ? ` ⏱${reset}` : "";
		return `${window.label} ${remaining.toFixed(0)}% left${resetSuffix}`;
	}).join(" · ");
}
function formatUsageReportLines(summary, opts) {
	if (summary.providers.length === 0) return ["Usage: no provider usage available."];
	const lines = ["Usage:"];
	for (const entry of summary.providers) {
		const planSuffix = entry.plan ? ` (${entry.plan})` : "";
		if (entry.error) {
			lines.push(`  ${entry.displayName}${planSuffix}: ${entry.error}`);
			continue;
		}
		if (entry.windows.length === 0) {
			lines.push(`  ${entry.displayName}${planSuffix}: no data`);
			continue;
		}
		lines.push(`  ${entry.displayName}${planSuffix}`);
		for (const window of entry.windows) {
			const remaining = clampPercent(100 - window.usedPercent);
			const reset = formatResetRemaining(window.resetAt, opts?.now);
			const resetSuffix = reset ? ` · resets ${reset}` : "";
			lines.push(`    ${window.label}: ${remaining.toFixed(0)}% left${resetSuffix}`);
		}
	}
	return lines;
}

//#endregion
//#region src/infra/fetch.ts
const wrapFetchWithAbortSignalMarker = Symbol.for("symi.fetch.abort-signal-wrapped");
function withDuplex(init, input) {
	const hasInitBody = init?.body != null;
	const hasRequestBody = !hasInitBody && typeof Request !== "undefined" && input instanceof Request && input.body != null;
	if (!hasInitBody && !hasRequestBody) return init;
	if (init && "duplex" in init) return init;
	return init ? {
		...init,
		duplex: "half"
	} : { duplex: "half" };
}
function wrapFetchWithAbortSignal(fetchImpl) {
	if (fetchImpl[wrapFetchWithAbortSignalMarker]) return fetchImpl;
	const wrapped = ((input, init) => {
		const patchedInit = withDuplex(init, input);
		const signal = patchedInit?.signal;
		if (!signal) return fetchImpl(input, patchedInit);
		if (typeof AbortSignal !== "undefined" && signal instanceof AbortSignal) return fetchImpl(input, patchedInit);
		if (typeof AbortController === "undefined") return fetchImpl(input, patchedInit);
		if (typeof signal.addEventListener !== "function") return fetchImpl(input, patchedInit);
		const controller = new AbortController();
		const onAbort = bindAbortRelay(controller);
		let listenerAttached = false;
		if (signal.aborted) controller.abort();
		else {
			signal.addEventListener("abort", onAbort, { once: true });
			listenerAttached = true;
		}
		const cleanup = () => {
			if (!listenerAttached || typeof signal.removeEventListener !== "function") return;
			listenerAttached = false;
			try {
				signal.removeEventListener("abort", onAbort);
			} catch {}
		};
		try {
			return fetchImpl(input, {
				...patchedInit,
				signal: controller.signal
			}).finally(cleanup);
		} catch (error) {
			cleanup();
			throw error;
		}
	});
	const wrappedFetch = Object.assign(wrapped, fetchImpl);
	const fetchWithPreconnect = fetchImpl;
	wrappedFetch.preconnect = typeof fetchWithPreconnect.preconnect === "function" ? fetchWithPreconnect.preconnect.bind(fetchWithPreconnect) : () => {};
	Object.defineProperty(wrappedFetch, wrapFetchWithAbortSignalMarker, {
		value: true,
		enumerable: false,
		configurable: false,
		writable: false
	});
	return wrappedFetch;
}
function resolveFetch(fetchImpl) {
	const resolved = fetchImpl ?? globalThis.fetch;
	if (!resolved) return;
	return wrapFetchWithAbortSignal(resolved);
}

//#endregion
//#region src/infra/provider-usage.auth.ts
function parseGoogleToken(apiKey) {
	try {
		const parsed = JSON.parse(apiKey);
		if (parsed && typeof parsed.token === "string") return { token: parsed.token };
	} catch {}
	return null;
}
function resolveZaiApiKey() {
	const envDirect = normalizeSecretInput(process.env.ZAI_API_KEY) || normalizeSecretInput(process.env.Z_AI_API_KEY);
	if (envDirect) return envDirect;
	const cfg = loadConfig();
	const key = getCustomProviderApiKey(cfg, "zai") || getCustomProviderApiKey(cfg, "z-ai");
	if (key) return key;
	const store = ensureAuthProfileStore();
	const apiProfile = [...listProfilesForProvider(store, "zai"), ...listProfilesForProvider(store, "z-ai")].find((id) => store.profiles[id]?.type === "api_key");
	if (apiProfile) {
		const cred = store.profiles[apiProfile];
		if (cred?.type === "api_key" && normalizeSecretInput(cred.key)) return normalizeSecretInput(cred.key);
	}
	try {
		const authPath = path.join(os.homedir(), ".pi", "agent", "auth.json");
		if (!fs.existsSync(authPath)) return;
		const data = JSON.parse(fs.readFileSync(authPath, "utf-8"));
		return data["z-ai"]?.access || data.zai?.access;
	} catch {
		return;
	}
}
function resolveMinimaxApiKey() {
	return resolveProviderApiKeyFromConfigAndStore({
		providerId: "minimax",
		envDirect: [process.env.MINIMAX_CODE_PLAN_KEY, process.env.MINIMAX_API_KEY]
	});
}
function resolveXiaomiApiKey() {
	return resolveProviderApiKeyFromConfigAndStore({
		providerId: "xiaomi",
		envDirect: [process.env.XIAOMI_API_KEY]
	});
}
function resolveProviderApiKeyFromConfigAndStore(params) {
	const envDirect = params.envDirect.map(normalizeSecretInput).find(Boolean);
	if (envDirect) return envDirect;
	const key = getCustomProviderApiKey(loadConfig(), params.providerId);
	if (key) return key;
	const store = ensureAuthProfileStore();
	const cred = listProfilesForProvider(store, params.providerId).map((id) => store.profiles[id]).find((profile) => profile?.type === "api_key" || profile?.type === "token");
	if (!cred) return;
	if (cred.type === "api_key") return normalizeSecretInput(cred.key);
	return normalizeSecretInput(cred.token);
}
async function resolveOAuthToken(params) {
	const cfg = loadConfig();
	const store = ensureAuthProfileStore(params.agentDir, { allowKeychainPrompt: false });
	const deduped = dedupeProfileIds(resolveAuthProfileOrder({
		cfg,
		store,
		provider: params.provider
	}));
	for (const profileId of deduped) {
		const cred = store.profiles[profileId];
		if (!cred || cred.type !== "oauth" && cred.type !== "token") continue;
		try {
			const resolved = await resolveApiKeyForProfile({
				cfg: void 0,
				store,
				profileId,
				agentDir: params.agentDir
			});
			if (resolved) {
				let token = resolved.apiKey;
				if (params.provider === "google-gemini-cli" || params.provider === "google-antigravity") token = parseGoogleToken(resolved.apiKey)?.token ?? resolved.apiKey;
				return {
					provider: params.provider,
					token,
					accountId: cred.type === "oauth" && "accountId" in cred ? cred.accountId : void 0
				};
			}
		} catch {}
	}
	return null;
}
function resolveOAuthProviders(agentDir) {
	const store = ensureAuthProfileStore(agentDir, { allowKeychainPrompt: false });
	const cfg = loadConfig();
	const providers = [
		"anthropic",
		"github-copilot",
		"google-gemini-cli",
		"google-antigravity",
		"openai-codex"
	];
	const isOAuthLikeCredential = (id) => {
		const cred = store.profiles[id];
		return cred?.type === "oauth" || cred?.type === "token";
	};
	return providers.filter((provider) => {
		if (listProfilesForProvider(store, provider).filter(isOAuthLikeCredential).length > 0) return true;
		const normalized = normalizeProviderId(provider);
		return Object.entries(cfg.auth?.profiles ?? {}).filter(([, profile]) => normalizeProviderId(profile.provider) === normalized).map(([id]) => id).filter(isOAuthLikeCredential).length > 0;
	});
}
async function resolveProviderAuths(params) {
	if (params.auth) return params.auth;
	const oauthProviders = resolveOAuthProviders(params.agentDir);
	const auths = [];
	for (const provider of params.providers) {
		if (provider === "zai") {
			const apiKey = resolveZaiApiKey();
			if (apiKey) auths.push({
				provider,
				token: apiKey
			});
			continue;
		}
		if (provider === "minimax") {
			const apiKey = resolveMinimaxApiKey();
			if (apiKey) auths.push({
				provider,
				token: apiKey
			});
			continue;
		}
		if (provider === "xiaomi") {
			const apiKey = resolveXiaomiApiKey();
			if (apiKey) auths.push({
				provider,
				token: apiKey
			});
			continue;
		}
		if (!oauthProviders.includes(provider)) continue;
		const auth = await resolveOAuthToken({
			provider,
			agentDir: params.agentDir
		});
		if (auth) auths.push(auth);
	}
	return auths;
}

//#endregion
//#region src/infra/provider-usage.fetch.shared.ts
async function fetchJson(url, init, timeoutMs, fetchFn) {
	const controller = new AbortController();
	const timer = setTimeout(controller.abort.bind(controller), timeoutMs);
	try {
		return await fetchFn(url, {
			...init,
			signal: controller.signal
		});
	} finally {
		clearTimeout(timer);
	}
}
function parseFiniteNumber(value) {
	if (typeof value === "number" && Number.isFinite(value)) return value;
	if (typeof value === "string") {
		const parsed = Number.parseFloat(value);
		if (Number.isFinite(parsed)) return parsed;
	}
}
function buildUsageErrorSnapshot(provider, error) {
	return {
		provider,
		displayName: PROVIDER_LABELS[provider],
		windows: [],
		error
	};
}
function buildUsageHttpErrorSnapshot(options) {
	if ((options.tokenExpiredStatuses ?? []).includes(options.status)) return buildUsageErrorSnapshot(options.provider, "Token expired");
	const suffix = options.message?.trim() ? `: ${options.message.trim()}` : "";
	return buildUsageErrorSnapshot(options.provider, `HTTP ${options.status}${suffix}`);
}

//#endregion
//#region src/infra/provider-usage.fetch.antigravity.ts
const BASE_URL = "https://cloudcode-pa.googleapis.com";
const LOAD_CODE_ASSIST_PATH = "/v1internal:loadCodeAssist";
const FETCH_AVAILABLE_MODELS_PATH = "/v1internal:fetchAvailableModels";
const METADATA = {
	ideType: "ANTIGRAVITY",
	platform: "PLATFORM_UNSPECIFIED",
	pluginType: "GEMINI"
};
function parseNumber(value) {
	return parseFiniteNumber(value);
}
function parseEpochMs(isoString) {
	if (!isoString?.trim()) return;
	try {
		const ms = Date.parse(isoString);
		if (Number.isFinite(ms)) return ms;
	} catch {}
}
async function parseErrorMessage(res) {
	try {
		const message = (await res.json())?.error?.message?.trim();
		if (message) return message;
	} catch {}
	return `HTTP ${res.status}`;
}
function extractCredits(data) {
	const available = parseNumber(data.availablePromptCredits);
	const monthly = parseNumber(data.planInfo?.monthlyPromptCredits);
	if (available === void 0 || monthly === void 0 || monthly <= 0) return;
	return {
		available,
		monthly
	};
}
function extractPlanInfo(data) {
	const tierName = data.currentTier?.name?.trim();
	if (tierName) return tierName;
	const planType = data.planType?.trim();
	if (planType) return planType;
}
function extractProjectId(data) {
	const project = data.cloudaicompanionProject;
	if (!project) return;
	if (typeof project === "string") return project.trim() ? project : void 0;
	return (typeof project.id === "string" ? project.id.trim() : void 0) || void 0;
}
function extractModelQuotas(data) {
	const result = /* @__PURE__ */ new Map();
	if (!data.models || typeof data.models !== "object") return result;
	for (const [modelId, modelInfo] of Object.entries(data.models)) {
		const quotaInfo = modelInfo.quotaInfo;
		if (!quotaInfo) continue;
		const remainingFraction = parseNumber(quotaInfo.remainingFraction);
		if (remainingFraction === void 0) continue;
		const resetTime = parseEpochMs(quotaInfo.resetTime);
		result.set(modelId, {
			remainingFraction,
			resetTime
		});
	}
	return result;
}
function buildUsageWindows(opts) {
	const windows = [];
	if (opts.credits) {
		const { available, monthly } = opts.credits;
		const usedPercent = clampPercent((monthly - available) / monthly * 100);
		windows.push({
			label: "Credits",
			usedPercent
		});
	}
	if (opts.modelQuotas && opts.modelQuotas.size > 0) {
		const modelWindows = [];
		for (const [modelId, quota] of opts.modelQuotas) {
			const lowerModelId = modelId.toLowerCase();
			if (lowerModelId.includes("chat_") || lowerModelId.includes("tab_")) continue;
			const window = {
				label: modelId,
				usedPercent: clampPercent((1 - quota.remainingFraction) * 100)
			};
			if (quota.resetTime) window.resetAt = quota.resetTime;
			modelWindows.push(window);
		}
		modelWindows.sort((a, b) => b.usedPercent - a.usedPercent);
		const topModels = modelWindows.slice(0, 10);
		logDebug(`[antigravity] Built ${topModels.length} model windows from ${opts.modelQuotas.size} total models`);
		for (const w of topModels) logDebug(`[antigravity]   ${w.label}: ${w.usedPercent.toFixed(1)}% used${w.resetAt ? ` (resets at ${new Date(w.resetAt).toISOString()})` : ""}`);
		windows.push(...topModels);
	}
	return windows;
}
async function fetchAntigravityUsage(token, timeoutMs, fetchFn) {
	const headers = {
		Authorization: `Bearer ${token}`,
		"Content-Type": "application/json",
		"User-Agent": "antigravity",
		"X-Goog-Api-Client": "google-cloud-sdk vscode_cloudshelleditor/0.1"
	};
	let credits;
	let modelQuotas;
	let planInfo;
	let lastError;
	let projectId;
	try {
		const res = await fetchJson(`${BASE_URL}${LOAD_CODE_ASSIST_PATH}`, {
			method: "POST",
			headers,
			body: JSON.stringify({ metadata: METADATA })
		}, timeoutMs, fetchFn);
		if (res.ok) {
			const data = await res.json();
			projectId = extractProjectId(data);
			credits = extractCredits(data);
			planInfo = extractPlanInfo(data);
			logDebug(`[antigravity] Credits: ${credits ? `${credits.available}/${credits.monthly}` : "none"}${planInfo ? ` (plan: ${planInfo})` : ""}`);
		} else {
			lastError = await parseErrorMessage(res);
			if (res.status === 401) return {
				provider: "google-antigravity",
				displayName: PROVIDER_LABELS["google-antigravity"],
				windows: [],
				error: "Token expired"
			};
		}
	} catch {
		lastError = "Network error";
	}
	if (!projectId) logDebug("[antigravity] Missing project id; requesting available models without project");
	try {
		const body = JSON.stringify(projectId ? { project: projectId } : {});
		const res = await fetchJson(`${BASE_URL}${FETCH_AVAILABLE_MODELS_PATH}`, {
			method: "POST",
			headers,
			body
		}, timeoutMs, fetchFn);
		if (res.ok) {
			modelQuotas = extractModelQuotas(await res.json());
			logDebug(`[antigravity] Extracted ${modelQuotas.size} model quotas from API`);
			for (const [modelId, quota] of modelQuotas) logDebug(`[antigravity]   ${modelId}: ${(quota.remainingFraction * 100).toFixed(1)}% remaining${quota.resetTime ? ` (resets ${new Date(quota.resetTime).toISOString()})` : ""}`);
		} else {
			const err = await parseErrorMessage(res);
			if (res.status === 401) lastError = "Token expired";
			else if (!lastError) lastError = err;
		}
	} catch {
		if (!lastError) lastError = "Network error";
	}
	const windows = buildUsageWindows({
		credits,
		modelQuotas
	});
	if (windows.length === 0 && lastError) {
		logDebug(`[antigravity] Returning error snapshot: ${lastError}`);
		return {
			provider: "google-antigravity",
			displayName: PROVIDER_LABELS["google-antigravity"],
			windows: [],
			error: lastError
		};
	}
	const snapshot = {
		provider: "google-antigravity",
		displayName: PROVIDER_LABELS["google-antigravity"],
		windows,
		plan: planInfo
	};
	logDebug(`[antigravity] Returning snapshot with ${windows.length} windows${planInfo ? ` (plan: ${planInfo})` : ""}`);
	logDebug(`[antigravity] Snapshot: ${JSON.stringify(snapshot, null, 2)}`);
	return snapshot;
}

//#endregion
//#region src/infra/provider-usage.fetch.claude.ts
function buildClaudeUsageWindows(data) {
	const windows = [];
	if (data.five_hour?.utilization !== void 0) windows.push({
		label: "5h",
		usedPercent: clampPercent(data.five_hour.utilization),
		resetAt: data.five_hour.resets_at ? new Date(data.five_hour.resets_at).getTime() : void 0
	});
	if (data.seven_day?.utilization !== void 0) windows.push({
		label: "Week",
		usedPercent: clampPercent(data.seven_day.utilization),
		resetAt: data.seven_day.resets_at ? new Date(data.seven_day.resets_at).getTime() : void 0
	});
	const modelWindow = data.seven_day_sonnet || data.seven_day_opus;
	if (modelWindow?.utilization !== void 0) windows.push({
		label: data.seven_day_sonnet ? "Sonnet" : "Opus",
		usedPercent: clampPercent(modelWindow.utilization)
	});
	return windows;
}
function resolveClaudeWebSessionKey() {
	const direct = process.env.CLAUDE_AI_SESSION_KEY?.trim() ?? process.env.CLAUDE_WEB_SESSION_KEY?.trim();
	if (direct?.startsWith("sk-ant-")) return direct;
	const cookieHeader = process.env.CLAUDE_WEB_COOKIE?.trim();
	if (!cookieHeader) return;
	const value = cookieHeader.replace(/^cookie:\\s*/i, "").match(/(?:^|;\\s*)sessionKey=([^;\\s]+)/i)?.[1]?.trim();
	return value?.startsWith("sk-ant-") ? value : void 0;
}
async function fetchClaudeWebUsage(sessionKey, timeoutMs, fetchFn) {
	const headers = {
		Cookie: `sessionKey=${sessionKey}`,
		Accept: "application/json"
	};
	const orgRes = await fetchJson("https://claude.ai/api/organizations", { headers }, timeoutMs, fetchFn);
	if (!orgRes.ok) return null;
	const orgId = (await orgRes.json())?.[0]?.uuid?.trim();
	if (!orgId) return null;
	const usageRes = await fetchJson(`https://claude.ai/api/organizations/${orgId}/usage`, { headers }, timeoutMs, fetchFn);
	if (!usageRes.ok) return null;
	const windows = buildClaudeUsageWindows(await usageRes.json());
	if (windows.length === 0) return null;
	return {
		provider: "anthropic",
		displayName: PROVIDER_LABELS.anthropic,
		windows
	};
}
async function fetchClaudeUsage(token, timeoutMs, fetchFn) {
	const res = await fetchJson("https://api.anthropic.com/api/oauth/usage", { headers: {
		Authorization: `Bearer ${token}`,
		"User-Agent": "symi",
		Accept: "application/json",
		"anthropic-version": "2023-06-01",
		"anthropic-beta": "oauth-2025-04-20"
	} }, timeoutMs, fetchFn);
	if (!res.ok) {
		let message;
		try {
			const raw = (await res.json())?.error?.message;
			if (typeof raw === "string" && raw.trim()) message = raw.trim();
		} catch {}
		if (res.status === 403 && message?.includes("scope requirement user:profile")) {
			const sessionKey = resolveClaudeWebSessionKey();
			if (sessionKey) {
				const web = await fetchClaudeWebUsage(sessionKey, timeoutMs, fetchFn);
				if (web) return web;
			}
		}
		return buildUsageHttpErrorSnapshot({
			provider: "anthropic",
			status: res.status,
			message
		});
	}
	const windows = buildClaudeUsageWindows(await res.json());
	return {
		provider: "anthropic",
		displayName: PROVIDER_LABELS.anthropic,
		windows
	};
}

//#endregion
//#region src/infra/provider-usage.fetch.codex.ts
async function fetchCodexUsage(token, accountId, timeoutMs, fetchFn) {
	const headers = {
		Authorization: `Bearer ${token}`,
		"User-Agent": "CodexBar",
		Accept: "application/json"
	};
	if (accountId) headers["ChatGPT-Account-Id"] = accountId;
	const res = await fetchJson("https://chatgpt.com/backend-api/wham/usage", {
		method: "GET",
		headers
	}, timeoutMs, fetchFn);
	if (!res.ok) return buildUsageHttpErrorSnapshot({
		provider: "openai-codex",
		status: res.status,
		tokenExpiredStatuses: [401, 403]
	});
	const data = await res.json();
	const windows = [];
	if (data.rate_limit?.primary_window) {
		const pw = data.rate_limit.primary_window;
		const windowHours = Math.round((pw.limit_window_seconds || 10800) / 3600);
		windows.push({
			label: `${windowHours}h`,
			usedPercent: clampPercent(pw.used_percent || 0),
			resetAt: pw.reset_at ? pw.reset_at * 1e3 : void 0
		});
	}
	if (data.rate_limit?.secondary_window) {
		const sw = data.rate_limit.secondary_window;
		const windowHours = Math.round((sw.limit_window_seconds || 86400) / 3600);
		const label = windowHours >= 24 ? "Day" : `${windowHours}h`;
		windows.push({
			label,
			usedPercent: clampPercent(sw.used_percent || 0),
			resetAt: sw.reset_at ? sw.reset_at * 1e3 : void 0
		});
	}
	let plan = data.plan_type;
	if (data.credits?.balance !== void 0 && data.credits.balance !== null) {
		const balance = typeof data.credits.balance === "number" ? data.credits.balance : parseFloat(data.credits.balance) || 0;
		plan = plan ? `${plan} ($${balance.toFixed(2)})` : `$${balance.toFixed(2)}`;
	}
	return {
		provider: "openai-codex",
		displayName: PROVIDER_LABELS["openai-codex"],
		windows,
		plan
	};
}

//#endregion
//#region src/infra/provider-usage.fetch.copilot.ts
async function fetchCopilotUsage(token, timeoutMs, fetchFn) {
	const res = await fetchJson("https://api.github.com/copilot_internal/user", { headers: {
		Authorization: `token ${token}`,
		"Editor-Version": "vscode/1.96.2",
		"User-Agent": "GitHubCopilotChat/0.26.7",
		"X-Github-Api-Version": "2025-04-01"
	} }, timeoutMs, fetchFn);
	if (!res.ok) return buildUsageHttpErrorSnapshot({
		provider: "github-copilot",
		status: res.status
	});
	const data = await res.json();
	const windows = [];
	if (data.quota_snapshots?.premium_interactions) {
		const remaining = data.quota_snapshots.premium_interactions.percent_remaining;
		windows.push({
			label: "Premium",
			usedPercent: clampPercent(100 - (remaining ?? 0))
		});
	}
	if (data.quota_snapshots?.chat) {
		const remaining = data.quota_snapshots.chat.percent_remaining;
		windows.push({
			label: "Chat",
			usedPercent: clampPercent(100 - (remaining ?? 0))
		});
	}
	return {
		provider: "github-copilot",
		displayName: PROVIDER_LABELS["github-copilot"],
		windows,
		plan: data.copilot_plan
	};
}

//#endregion
//#region src/infra/provider-usage.fetch.gemini.ts
async function fetchGeminiUsage(token, timeoutMs, fetchFn, provider) {
	const res = await fetchJson("https://cloudcode-pa.googleapis.com/v1internal:retrieveUserQuota", {
		method: "POST",
		headers: {
			Authorization: `Bearer ${token}`,
			"Content-Type": "application/json"
		},
		body: "{}"
	}, timeoutMs, fetchFn);
	if (!res.ok) return buildUsageHttpErrorSnapshot({
		provider,
		status: res.status
	});
	const data = await res.json();
	const quotas = {};
	for (const bucket of data.buckets || []) {
		const model = bucket.modelId || "unknown";
		const frac = bucket.remainingFraction ?? 1;
		if (!quotas[model] || frac < quotas[model]) quotas[model] = frac;
	}
	const windows = [];
	let proMin = 1;
	let flashMin = 1;
	let hasPro = false;
	let hasFlash = false;
	for (const [model, frac] of Object.entries(quotas)) {
		const lower = model.toLowerCase();
		if (lower.includes("pro")) {
			hasPro = true;
			if (frac < proMin) proMin = frac;
		}
		if (lower.includes("flash")) {
			hasFlash = true;
			if (frac < flashMin) flashMin = frac;
		}
	}
	if (hasPro) windows.push({
		label: "Pro",
		usedPercent: clampPercent((1 - proMin) * 100)
	});
	if (hasFlash) windows.push({
		label: "Flash",
		usedPercent: clampPercent((1 - flashMin) * 100)
	});
	return {
		provider,
		displayName: PROVIDER_LABELS[provider],
		windows
	};
}

//#endregion
//#region src/infra/provider-usage.fetch.minimax.ts
const RESET_KEYS = [
	"reset_at",
	"resetAt",
	"reset_time",
	"resetTime",
	"next_reset_at",
	"nextResetAt",
	"next_reset_time",
	"nextResetTime",
	"expires_at",
	"expiresAt",
	"expire_at",
	"expireAt",
	"end_time",
	"endTime",
	"window_end",
	"windowEnd"
];
const PERCENT_KEYS = [
	"used_percent",
	"usedPercent",
	"usage_percent",
	"usagePercent",
	"used_rate",
	"usage_rate",
	"used_ratio",
	"usage_ratio",
	"usedRatio",
	"usageRatio"
];
const USED_KEYS = [
	"used",
	"usage",
	"used_amount",
	"usedAmount",
	"used_tokens",
	"usedTokens",
	"used_quota",
	"usedQuota",
	"used_times",
	"usedTimes",
	"prompt_used",
	"promptUsed",
	"used_prompt",
	"usedPrompt",
	"prompts_used",
	"promptsUsed",
	"current_interval_usage_count",
	"currentIntervalUsageCount",
	"consumed"
];
const TOTAL_KEYS = [
	"total",
	"total_amount",
	"totalAmount",
	"total_tokens",
	"totalTokens",
	"total_quota",
	"totalQuota",
	"total_times",
	"totalTimes",
	"prompt_total",
	"promptTotal",
	"total_prompt",
	"totalPrompt",
	"prompt_limit",
	"promptLimit",
	"limit_prompt",
	"limitPrompt",
	"prompts_total",
	"promptsTotal",
	"total_prompts",
	"totalPrompts",
	"current_interval_total_count",
	"currentIntervalTotalCount",
	"limit",
	"quota",
	"quota_limit",
	"quotaLimit",
	"max"
];
const REMAINING_KEYS = [
	"remain",
	"remaining",
	"remain_amount",
	"remainingAmount",
	"remaining_amount",
	"remain_tokens",
	"remainingTokens",
	"remaining_tokens",
	"remain_quota",
	"remainingQuota",
	"remaining_quota",
	"remain_times",
	"remainingTimes",
	"remaining_times",
	"prompt_remain",
	"promptRemain",
	"remain_prompt",
	"remainPrompt",
	"prompt_remaining",
	"promptRemaining",
	"remaining_prompt",
	"remainingPrompt",
	"prompts_remaining",
	"promptsRemaining",
	"prompt_left",
	"promptLeft",
	"prompts_left",
	"promptsLeft",
	"left"
];
const PLAN_KEYS = [
	"plan",
	"plan_name",
	"planName",
	"product",
	"tier"
];
const WINDOW_HOUR_KEYS = [
	"window_hours",
	"windowHours",
	"duration_hours",
	"durationHours",
	"hours"
];
const WINDOW_MINUTE_KEYS = [
	"window_minutes",
	"windowMinutes",
	"duration_minutes",
	"durationMinutes",
	"minutes"
];
function pickNumber(record, keys) {
	for (const key of keys) {
		const parsed = parseFiniteNumber(record[key]);
		if (parsed !== void 0) return parsed;
	}
}
function pickString(record, keys) {
	for (const key of keys) {
		const value = record[key];
		if (typeof value === "string" && value.trim()) return value.trim();
	}
}
function parseEpoch(value) {
	if (typeof value === "number" && Number.isFinite(value)) {
		if (value < 0xe8d4a51000) return Math.floor(value * 1e3);
		return Math.floor(value);
	}
	if (typeof value === "string" && value.trim()) {
		const parsed = Date.parse(value);
		if (Number.isFinite(parsed)) return parsed;
	}
}
function hasAny(record, keys) {
	return keys.some((key) => key in record);
}
function scoreUsageRecord(record) {
	let score = 0;
	if (hasAny(record, PERCENT_KEYS)) score += 4;
	if (hasAny(record, TOTAL_KEYS)) score += 3;
	if (hasAny(record, USED_KEYS) || hasAny(record, REMAINING_KEYS)) score += 2;
	if (hasAny(record, RESET_KEYS)) score += 1;
	if (hasAny(record, PLAN_KEYS)) score += 1;
	return score;
}
function collectUsageCandidates(root) {
	const MAX_SCAN_DEPTH = 4;
	const MAX_SCAN_NODES = 60;
	const queue = [{
		value: root,
		depth: 0
	}];
	const seen = /* @__PURE__ */ new Set();
	const candidates = [];
	let scanned = 0;
	while (queue.length && scanned < MAX_SCAN_NODES) {
		const next = queue.shift();
		scanned += 1;
		const { value, depth } = next;
		if (isRecord(value)) {
			if (seen.has(value)) continue;
			seen.add(value);
			const score = scoreUsageRecord(value);
			if (score > 0) candidates.push({
				record: value,
				score,
				depth
			});
			if (depth < MAX_SCAN_DEPTH) {
				for (const nested of Object.values(value)) if (isRecord(nested) || Array.isArray(nested)) queue.push({
					value: nested,
					depth: depth + 1
				});
			}
			continue;
		}
		if (Array.isArray(value) && depth < MAX_SCAN_DEPTH) {
			for (const nested of value) if (isRecord(nested) || Array.isArray(nested)) queue.push({
				value: nested,
				depth: depth + 1
			});
		}
	}
	candidates.sort((a, b) => b.score - a.score || a.depth - b.depth);
	return candidates.map((candidate) => candidate.record);
}
function deriveWindowLabel(payload) {
	const hours = pickNumber(payload, WINDOW_HOUR_KEYS);
	if (hours && Number.isFinite(hours)) return `${hours}h`;
	const minutes = pickNumber(payload, WINDOW_MINUTE_KEYS);
	if (minutes && Number.isFinite(minutes)) return `${minutes}m`;
	return "5h";
}
function deriveUsedPercent(payload) {
	const total = pickNumber(payload, TOTAL_KEYS);
	let used = pickNumber(payload, USED_KEYS);
	const remaining = pickNumber(payload, REMAINING_KEYS);
	if (used === void 0 && remaining !== void 0 && total !== void 0) used = total - remaining;
	const fromCounts = total && total > 0 && used !== void 0 && Number.isFinite(used) ? clampPercent(used / total * 100) : null;
	const percentRaw = pickNumber(payload, PERCENT_KEYS);
	if (percentRaw !== void 0) {
		const normalized = clampPercent(percentRaw <= 1 ? percentRaw * 100 : percentRaw);
		if (fromCounts !== null) return fromCounts;
		return normalized;
	}
	return fromCounts;
}
async function fetchMinimaxUsage(apiKey, timeoutMs, fetchFn) {
	const res = await fetchJson("https://api.minimaxi.com/v1/api/openplatform/coding_plan/remains", {
		method: "GET",
		headers: {
			Authorization: `Bearer ${apiKey}`,
			"Content-Type": "application/json",
			"MM-API-Source": "Symi"
		}
	}, timeoutMs, fetchFn);
	if (!res.ok) return buildUsageHttpErrorSnapshot({
		provider: "minimax",
		status: res.status
	});
	const data = await res.json().catch(() => null);
	if (!isRecord(data)) return {
		provider: "minimax",
		displayName: PROVIDER_LABELS.minimax,
		windows: [],
		error: "Invalid JSON"
	};
	const baseResp = isRecord(data.base_resp) ? data.base_resp : void 0;
	if (baseResp && typeof baseResp.status_code === "number" && baseResp.status_code !== 0) return {
		provider: "minimax",
		displayName: PROVIDER_LABELS.minimax,
		windows: [],
		error: baseResp.status_msg?.trim() || "API error"
	};
	const payload = isRecord(data.data) ? data.data : data;
	const candidates = collectUsageCandidates(payload);
	let usageRecord = payload;
	let usedPercent = null;
	for (const candidate of candidates) {
		const candidatePercent = deriveUsedPercent(candidate);
		if (candidatePercent !== null) {
			usageRecord = candidate;
			usedPercent = candidatePercent;
			break;
		}
	}
	if (usedPercent === null) usedPercent = deriveUsedPercent(payload);
	if (usedPercent === null) return {
		provider: "minimax",
		displayName: PROVIDER_LABELS.minimax,
		windows: [],
		error: "Unsupported response shape"
	};
	const resetAt = parseEpoch(pickString(usageRecord, RESET_KEYS)) ?? parseEpoch(pickNumber(usageRecord, RESET_KEYS)) ?? parseEpoch(pickString(payload, RESET_KEYS)) ?? parseEpoch(pickNumber(payload, RESET_KEYS));
	const windows = [{
		label: deriveWindowLabel(usageRecord),
		usedPercent,
		resetAt
	}];
	return {
		provider: "minimax",
		displayName: PROVIDER_LABELS.minimax,
		windows,
		plan: pickString(usageRecord, PLAN_KEYS) ?? pickString(payload, PLAN_KEYS)
	};
}

//#endregion
//#region src/infra/provider-usage.fetch.zai.ts
async function fetchZaiUsage(apiKey, timeoutMs, fetchFn) {
	const res = await fetchJson("https://api.z.ai/api/monitor/usage/quota/limit", {
		method: "GET",
		headers: {
			Authorization: `Bearer ${apiKey}`,
			Accept: "application/json"
		}
	}, timeoutMs, fetchFn);
	if (!res.ok) return buildUsageHttpErrorSnapshot({
		provider: "zai",
		status: res.status
	});
	const data = await res.json();
	if (!data.success || data.code !== 200) return {
		provider: "zai",
		displayName: PROVIDER_LABELS.zai,
		windows: [],
		error: data.msg || "API error"
	};
	const windows = [];
	const limits = data.data?.limits || [];
	for (const limit of limits) {
		const percent = clampPercent(limit.percentage || 0);
		const nextReset = limit.nextResetTime ? new Date(limit.nextResetTime).getTime() : void 0;
		let windowLabel = "Limit";
		if (limit.unit === 1) windowLabel = `${limit.number}d`;
		else if (limit.unit === 3) windowLabel = `${limit.number}h`;
		else if (limit.unit === 5) windowLabel = `${limit.number}m`;
		if (limit.type === "TOKENS_LIMIT") windows.push({
			label: `Tokens (${windowLabel})`,
			usedPercent: percent,
			resetAt: nextReset
		});
		else if (limit.type === "TIME_LIMIT") windows.push({
			label: "Monthly",
			usedPercent: percent,
			resetAt: nextReset
		});
	}
	const planName = data.data?.planName || data.data?.plan || void 0;
	return {
		provider: "zai",
		displayName: PROVIDER_LABELS.zai,
		windows,
		plan: planName
	};
}

//#endregion
//#region src/infra/provider-usage.load.ts
async function loadProviderUsageSummary(opts = {}) {
	const now = opts.now ?? Date.now();
	const timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS;
	const fetchFn = resolveFetch(opts.fetch);
	if (!fetchFn) throw new Error("fetch is not available");
	const auths = await resolveProviderAuths({
		providers: opts.providers ?? usageProviders,
		auth: opts.auth,
		agentDir: opts.agentDir
	});
	if (auths.length === 0) return {
		updatedAt: now,
		providers: []
	};
	const tasks = auths.map((auth) => withTimeout((async () => {
		switch (auth.provider) {
			case "anthropic": return await fetchClaudeUsage(auth.token, timeoutMs, fetchFn);
			case "github-copilot": return await fetchCopilotUsage(auth.token, timeoutMs, fetchFn);
			case "google-antigravity": return await fetchAntigravityUsage(auth.token, timeoutMs, fetchFn);
			case "google-gemini-cli": return await fetchGeminiUsage(auth.token, timeoutMs, fetchFn, auth.provider);
			case "openai-codex": return await fetchCodexUsage(auth.token, auth.accountId, timeoutMs, fetchFn);
			case "minimax": return await fetchMinimaxUsage(auth.token, timeoutMs, fetchFn);
			case "xiaomi": return {
				provider: "xiaomi",
				displayName: PROVIDER_LABELS.xiaomi,
				windows: []
			};
			case "zai": return await fetchZaiUsage(auth.token, timeoutMs, fetchFn);
			default: return {
				provider: auth.provider,
				displayName: PROVIDER_LABELS[auth.provider],
				windows: [],
				error: "Unsupported provider"
			};
		}
	})(), timeoutMs + 1e3, {
		provider: auth.provider,
		displayName: PROVIDER_LABELS[auth.provider],
		windows: [],
		error: "Timeout"
	}));
	return {
		updatedAt: now,
		providers: (await Promise.all(tasks)).filter((entry) => {
			if (entry.windows.length > 0) return true;
			if (!entry.error) return true;
			return !ignoredErrors.has(entry.error);
		})
	};
}

//#endregion
//#region src/infra/restart-sentinel.ts
const SENTINEL_FILENAME = "restart-sentinel.json";
function formatDoctorNonInteractiveHint(env = process.env) {
	return `Run: ${formatCliCommand("symi doctor --non-interactive", env)}`;
}
function resolveRestartSentinelPath(env = process.env) {
	return path.join(resolveStateDir(env), SENTINEL_FILENAME);
}
async function writeRestartSentinel(payload, env = process.env) {
	const filePath = resolveRestartSentinelPath(env);
	await fs$1.mkdir(path.dirname(filePath), { recursive: true });
	const data = {
		version: 1,
		payload
	};
	await fs$1.writeFile(filePath, `${JSON.stringify(data, null, 2)}\n`, "utf-8");
	return filePath;
}
async function readRestartSentinel(env = process.env) {
	const filePath = resolveRestartSentinelPath(env);
	try {
		const raw = await fs$1.readFile(filePath, "utf-8");
		let parsed;
		try {
			parsed = JSON.parse(raw);
		} catch {
			await fs$1.unlink(filePath).catch(() => {});
			return null;
		}
		if (!parsed || parsed.version !== 1 || !parsed.payload) {
			await fs$1.unlink(filePath).catch(() => {});
			return null;
		}
		return parsed;
	} catch {
		return null;
	}
}
async function consumeRestartSentinel(env = process.env) {
	const filePath = resolveRestartSentinelPath(env);
	const parsed = await readRestartSentinel(env);
	if (!parsed) return null;
	await fs$1.unlink(filePath).catch(() => {});
	return parsed;
}
function formatRestartSentinelMessage(payload) {
	const message = payload.message?.trim();
	if (message && !payload.stats) return message;
	const lines = [summarizeRestartSentinel(payload)];
	if (message) lines.push(message);
	const reason = payload.stats?.reason?.trim();
	if (reason) lines.push(`Reason: ${reason}`);
	if (payload.doctorHint?.trim()) lines.push(payload.doctorHint.trim());
	return lines.join("\n");
}
function summarizeRestartSentinel(payload) {
	return `Gateway restart ${payload.kind} ${payload.status}${payload.stats?.mode ? ` (${payload.stats.mode})` : ""}`.trim();
}
function trimLogTail(input, maxChars = 8e3) {
	if (!input) return null;
	const text = input.trimEnd();
	if (text.length <= maxChars) return text;
	return `…${text.slice(text.length - maxChars)}`;
}

//#endregion
//#region src/gateway/session-utils.ts
const log = createSubsystemLogger("session-utils");
const DERIVED_TITLE_MAX_LEN = 60;
const AVATAR_MAX_BYTES = 2 * 1024 * 1024;
const AVATAR_DATA_RE = /^data:/i;
const AVATAR_HTTP_RE = /^https?:\/\//i;
const AVATAR_SCHEME_RE = /^[a-z][a-z0-9+.-]*:/i;
const WINDOWS_ABS_RE = /^[a-zA-Z]:[\\/]/;
const AVATAR_MIME_BY_EXT = {
	".png": "image/png",
	".jpg": "image/jpeg",
	".jpeg": "image/jpeg",
	".webp": "image/webp",
	".gif": "image/gif",
	".svg": "image/svg+xml",
	".bmp": "image/bmp",
	".tif": "image/tiff",
	".tiff": "image/tiff"
};
function resolveAvatarMime(filePath) {
	return AVATAR_MIME_BY_EXT[path.extname(filePath).toLowerCase()] ?? "application/octet-stream";
}
function isWorkspaceRelativePath(value) {
	if (!value) return false;
	if (value.startsWith("~")) return false;
	if (AVATAR_SCHEME_RE.test(value) && !WINDOWS_ABS_RE.test(value)) return false;
	return true;
}
function resolveIdentityAvatarUrl(cfg, agentId, avatar) {
	if (!avatar) return;
	const trimmed = avatar.trim();
	if (!trimmed) return;
	if (AVATAR_DATA_RE.test(trimmed) || AVATAR_HTTP_RE.test(trimmed)) return trimmed;
	if (!isWorkspaceRelativePath(trimmed)) return;
	const workspaceDir = resolveAgentWorkspaceDir(cfg, agentId);
	const workspaceRoot = path.resolve(workspaceDir);
	const resolved = path.resolve(workspaceRoot, trimmed);
	const relative = path.relative(workspaceRoot, resolved);
	if (relative.startsWith("..") || path.isAbsolute(relative)) return;
	try {
		const stat = fs.statSync(resolved);
		if (!stat.isFile() || stat.size > AVATAR_MAX_BYTES) return;
		const buffer = fs.readFileSync(resolved);
		return `data:${resolveAvatarMime(resolved)};base64,${buffer.toString("base64")}`;
	} catch {
		return;
	}
}
function formatSessionIdPrefix(sessionId, updatedAt) {
	const prefix = sessionId.slice(0, 8);
	if (updatedAt && updatedAt > 0) return `${prefix} (${new Date(updatedAt).toISOString().slice(0, 10)})`;
	return prefix;
}
function truncateTitle(text, maxLen) {
	if (text.length <= maxLen) return text;
	const cut = text.slice(0, maxLen - 1);
	const lastSpace = cut.lastIndexOf(" ");
	if (lastSpace > maxLen * .6) return cut.slice(0, lastSpace) + "…";
	return cut + "…";
}
function deriveSessionTitle(entry, firstUserMessage) {
	if (!entry) return;
	if (entry.displayName?.trim()) return entry.displayName.trim();
	if (entry.subject?.trim()) return entry.subject.trim();
	if (firstUserMessage?.trim()) return truncateTitle(firstUserMessage.replace(/\s+/g, " ").trim(), DERIVED_TITLE_MAX_LEN);
	if (entry.sessionId) return formatSessionIdPrefix(entry.sessionId, entry.updatedAt);
}
/**
* Repair a session entry whose sessionFile points to a non-existent transcript.
* Scans the sessions directory for valid .jsonl files and returns the most recent
* one with actual content. This handles the case where session reset updates
* sessions.json with a new sessionId but the transcript file wasn't created.
*/
function repairMissingSessionFile(params) {
	const { entry, storePath, agentId } = params;
	if (resolveSessionTranscriptCandidates(entry.sessionId, storePath, entry.sessionFile, agentId).find((p) => fs.existsSync(p))) return {
		repairedFile: null,
		repairedSessionId: null
	};
	const sessionsDir = path.dirname(storePath);
	let files;
	try {
		files = fs.readdirSync(sessionsDir, { withFileTypes: true });
	} catch {
		return {
			repairedFile: null,
			repairedSessionId: null
		};
	}
	const jsonlFiles = [];
	for (const dirent of files) {
		if (!dirent.isFile() || !dirent.name.endsWith(".jsonl")) continue;
		if (dirent.name.includes(".bak.") || dirent.name.includes(".reset.") || dirent.name.includes(".deleted.")) continue;
		const filePath = path.join(sessionsDir, dirent.name);
		try {
			const stat = fs.statSync(filePath);
			if (stat.size > 0) jsonlFiles.push({
				name: dirent.name,
				path: filePath,
				mtimeMs: stat.mtimeMs,
				size: stat.size
			});
		} catch {}
	}
	if (jsonlFiles.length === 0) return {
		repairedFile: null,
		repairedSessionId: null
	};
	jsonlFiles.sort((a, b) => b.mtimeMs - a.mtimeMs);
	const mostRecent = jsonlFiles[0];
	const sessionIdMatch = mostRecent.name.match(/^([a-f0-9-]{36})\.jsonl$/i);
	if (!sessionIdMatch) return {
		repairedFile: null,
		repairedSessionId: null
	};
	const repairedSessionId = sessionIdMatch[1];
	log.info("repaired missing session file", {
		originalSessionId: entry.sessionId,
		repairedSessionId,
		repairedFile: mostRecent.path
	});
	return {
		repairedFile: mostRecent.path,
		repairedSessionId
	};
}
/**
* Persist a session file repair to the sessions.json store.
* Called asynchronously to avoid blocking the current request.
*/
function persistSessionFileRepair(params) {
	const { storePath, sessionKey, sessionFile, sessionId } = params;
	setImmediate(async () => {
		try {
			const store = loadSessionStore(storePath, { skipCache: true });
			const entry = store[sessionKey];
			if (entry) {
				entry.sessionFile = sessionFile;
				entry.sessionId = sessionId;
				entry.updatedAt = Date.now();
				const json = JSON.stringify(store, null, 2);
				await fs.promises.writeFile(storePath, json, "utf-8");
				log.info("persisted session file repair", {
					sessionKey,
					sessionId
				});
			}
		} catch (err) {
			log.warn("failed to persist session file repair", {
				sessionKey,
				error: String(err)
			});
		}
	});
}
function loadSessionEntry(sessionKey) {
	const cfg = loadConfig();
	const sessionCfg = cfg.session;
	const canonicalKey = resolveSessionStoreKey({
		cfg,
		sessionKey
	});
	const agentId = resolveSessionStoreAgentId(cfg, canonicalKey);
	const storePath = resolveStorePath(sessionCfg?.store, { agentId });
	const store = loadSessionStore(storePath);
	const match = findStoreMatch(store, canonicalKey, sessionKey.trim());
	const legacyKey = match?.key !== canonicalKey ? match?.key : void 0;
	let entry = match?.entry;
	if (entry?.sessionId) {
		const repair = repairMissingSessionFile({
			entry,
			storePath,
			agentId
		});
		if (repair.repairedFile && repair.repairedSessionId) {
			entry = {
				...entry,
				sessionFile: repair.repairedFile,
				sessionId: repair.repairedSessionId
			};
			persistSessionFileRepair({
				storePath,
				sessionKey: match?.key ?? canonicalKey,
				sessionFile: repair.repairedFile,
				sessionId: repair.repairedSessionId
			});
		}
	}
	return {
		cfg,
		storePath,
		store,
		entry,
		canonicalKey,
		legacyKey
	};
}
/**
* Find a session entry by exact or case-insensitive key match.
* Returns both the entry and the actual store key it was found under,
* so callers can clean up legacy mixed-case keys when they differ from canonicalKey.
*/
function findStoreMatch(store, ...candidates) {
	for (const candidate of candidates) if (candidate && store[candidate]) return {
		entry: store[candidate],
		key: candidate
	};
	const loweredSet = new Set(candidates.filter(Boolean).map((c) => c.toLowerCase()));
	for (const key of Object.keys(store)) if (loweredSet.has(key.toLowerCase())) return {
		entry: store[key],
		key
	};
}
/**
* Find all on-disk store keys that match the given key case-insensitively.
* Returns every key from the store whose lowercased form equals the target's lowercased form.
*/
function findStoreKeysIgnoreCase(store, targetKey) {
	const lowered = targetKey.toLowerCase();
	const matches = [];
	for (const key of Object.keys(store)) if (key.toLowerCase() === lowered) matches.push(key);
	return matches;
}
/**
* Remove legacy key variants for one canonical session key.
* Candidates can include aliases (for example, "agent:ops:main" when canonical is "agent:ops:work").
*/
function pruneLegacyStoreKeys(params) {
	const keysToDelete = /* @__PURE__ */ new Set();
	for (const candidate of params.candidates) {
		const trimmed = String(candidate ?? "").trim();
		if (!trimmed) continue;
		if (trimmed !== params.canonicalKey) keysToDelete.add(trimmed);
		for (const match of findStoreKeysIgnoreCase(params.store, trimmed)) if (match !== params.canonicalKey) keysToDelete.add(match);
	}
	for (const key of keysToDelete) delete params.store[key];
}
function classifySessionKey(key, entry) {
	if (key === "global") return "global";
	if (key === "unknown") return "unknown";
	if (entry?.chatType === "group" || entry?.chatType === "channel") return "group";
	if (key.includes(":group:") || key.includes(":channel:")) return "group";
	return "direct";
}
function parseGroupKey(key) {
	const parts = (parseAgentSessionKey(key)?.rest ?? key).split(":").filter(Boolean);
	if (parts.length >= 3) {
		const [channel, kind, ...rest] = parts;
		if (kind === "group" || kind === "channel") return {
			channel,
			kind,
			id: rest.join(":")
		};
	}
	return null;
}
function isStorePathTemplate(store) {
	return typeof store === "string" && store.includes("{agentId}");
}
function listExistingAgentIdsFromDisk() {
	const root = resolveStateDir();
	const agentsDir = path.join(root, "agents");
	try {
		return fs.readdirSync(agentsDir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => normalizeAgentId(entry.name)).filter(Boolean);
	} catch {
		return [];
	}
}
function listConfiguredAgentIds(cfg) {
	const agents = cfg.agents?.list ?? [];
	if (agents.length > 0) {
		const ids = /* @__PURE__ */ new Set();
		for (const entry of agents) if (entry?.id) ids.add(normalizeAgentId(entry.id));
		const defaultId = normalizeAgentId(resolveDefaultAgentId(cfg));
		ids.add(defaultId);
		const sorted = Array.from(ids).filter(Boolean);
		sorted.sort((a, b) => a.localeCompare(b));
		return sorted.includes(defaultId) ? [defaultId, ...sorted.filter((id) => id !== defaultId)] : sorted;
	}
	const ids = /* @__PURE__ */ new Set();
	const defaultId = normalizeAgentId(resolveDefaultAgentId(cfg));
	ids.add(defaultId);
	for (const id of listExistingAgentIdsFromDisk()) ids.add(id);
	const sorted = Array.from(ids).filter(Boolean);
	sorted.sort((a, b) => a.localeCompare(b));
	if (sorted.includes(defaultId)) return [defaultId, ...sorted.filter((id) => id !== defaultId)];
	return sorted;
}
function listAgentsForGateway(cfg) {
	const defaultId = normalizeAgentId(resolveDefaultAgentId(cfg));
	const mainKey = normalizeMainKey(cfg.session?.mainKey);
	const scope = cfg.session?.scope ?? "per-sender";
	const configuredById = /* @__PURE__ */ new Map();
	for (const entry of cfg.agents?.list ?? []) {
		if (!entry?.id) continue;
		const identity = entry.identity ? {
			name: entry.identity.name?.trim() || void 0,
			theme: entry.identity.theme?.trim() || void 0,
			emoji: entry.identity.emoji?.trim() || void 0,
			avatar: entry.identity.avatar?.trim() || void 0,
			avatarUrl: resolveIdentityAvatarUrl(cfg, normalizeAgentId(entry.id), entry.identity.avatar?.trim())
		} : void 0;
		configuredById.set(normalizeAgentId(entry.id), {
			name: typeof entry.name === "string" && entry.name.trim() ? entry.name.trim() : void 0,
			identity
		});
	}
	const explicitIds = new Set((cfg.agents?.list ?? []).map((entry) => entry?.id ? normalizeAgentId(entry.id) : "").filter(Boolean));
	const allowedIds = explicitIds.size > 0 ? new Set([...explicitIds, defaultId]) : null;
	let agentIds = listConfiguredAgentIds(cfg).filter((id) => allowedIds ? allowedIds.has(id) : true);
	if (mainKey && !agentIds.includes(mainKey) && (!allowedIds || allowedIds.has(mainKey))) agentIds = [...agentIds, mainKey];
	return {
		defaultId,
		mainKey,
		scope,
		agents: agentIds.map((id) => {
			const meta = configuredById.get(id);
			return {
				id,
				name: meta?.name,
				identity: meta?.identity
			};
		})
	};
}
function canonicalizeSessionKeyForAgent(agentId, key) {
	const lowered = key.toLowerCase();
	if (lowered === "global" || lowered === "unknown") return lowered;
	if (lowered.startsWith("agent:")) return lowered;
	return `agent:${normalizeAgentId(agentId)}:${lowered}`;
}
function resolveDefaultStoreAgentId(cfg) {
	return normalizeAgentId(resolveDefaultAgentId(cfg));
}
function resolveSessionStoreKey(params) {
	const raw = params.sessionKey.trim();
	if (!raw) return raw;
	const rawLower = raw.toLowerCase();
	if (rawLower === "global" || rawLower === "unknown") return rawLower;
	const parsed = parseAgentSessionKey(raw);
	if (parsed) {
		const agentId = normalizeAgentId(parsed.agentId);
		const lowered = raw.toLowerCase();
		const canonical = canonicalizeMainSessionAlias({
			cfg: params.cfg,
			agentId,
			sessionKey: lowered
		});
		if (canonical !== lowered) return canonical;
		return lowered;
	}
	const lowered = raw.toLowerCase();
	const rawMainKey = normalizeMainKey(params.cfg.session?.mainKey);
	if (lowered === "main" || lowered === rawMainKey) return resolveMainSessionKey(params.cfg);
	return canonicalizeSessionKeyForAgent(resolveDefaultStoreAgentId(params.cfg), lowered);
}
function resolveSessionStoreAgentId(cfg, canonicalKey) {
	if (canonicalKey === "global" || canonicalKey === "unknown") return resolveDefaultStoreAgentId(cfg);
	const parsed = parseAgentSessionKey(canonicalKey);
	if (parsed?.agentId) return normalizeAgentId(parsed.agentId);
	return resolveDefaultStoreAgentId(cfg);
}
function canonicalizeSpawnedByForAgent(cfg, agentId, spawnedBy) {
	const raw = spawnedBy?.trim();
	if (!raw) return;
	const lower = raw.toLowerCase();
	if (lower === "global" || lower === "unknown") return lower;
	let result;
	if (raw.toLowerCase().startsWith("agent:")) result = raw.toLowerCase();
	else result = `agent:${normalizeAgentId(agentId)}:${lower}`;
	const parsed = parseAgentSessionKey(result);
	return canonicalizeMainSessionAlias({
		cfg,
		agentId: parsed?.agentId ? normalizeAgentId(parsed.agentId) : agentId,
		sessionKey: result
	});
}
function resolveGatewaySessionStoreTarget(params) {
	const key = params.key.trim();
	const canonicalKey = resolveSessionStoreKey({
		cfg: params.cfg,
		sessionKey: key
	});
	const agentId = resolveSessionStoreAgentId(params.cfg, canonicalKey);
	const storeConfig = params.cfg.session?.store;
	const storePath = resolveStorePath(storeConfig, { agentId });
	if (canonicalKey === "global" || canonicalKey === "unknown") return {
		agentId,
		storePath,
		canonicalKey,
		storeKeys: key && key !== canonicalKey ? [canonicalKey, key] : [key]
	};
	const storeKeys = /* @__PURE__ */ new Set();
	storeKeys.add(canonicalKey);
	if (key && key !== canonicalKey) storeKeys.add(key);
	if (params.scanLegacyKeys !== false) {
		const scanTargets = new Set(storeKeys);
		if (canonicalKey === resolveAgentMainSessionKey({
			cfg: params.cfg,
			agentId
		})) scanTargets.add(`agent:${agentId}:main`);
		const store = params.store ?? loadSessionStore(storePath);
		for (const seed of scanTargets) for (const legacyKey of findStoreKeysIgnoreCase(store, seed)) storeKeys.add(legacyKey);
	}
	return {
		agentId,
		storePath,
		canonicalKey,
		storeKeys: Array.from(storeKeys)
	};
}
function mergeSessionEntryIntoCombined(params) {
	const { cfg, combined, entry, agentId, canonicalKey } = params;
	const existing = combined[canonicalKey];
	if (existing && (existing.updatedAt ?? 0) > (entry.updatedAt ?? 0)) combined[canonicalKey] = {
		...entry,
		...existing,
		spawnedBy: canonicalizeSpawnedByForAgent(cfg, agentId, existing.spawnedBy ?? entry.spawnedBy)
	};
	else combined[canonicalKey] = {
		...existing,
		...entry,
		spawnedBy: canonicalizeSpawnedByForAgent(cfg, agentId, entry.spawnedBy ?? existing?.spawnedBy)
	};
}
function loadCombinedSessionStoreForGateway(cfg) {
	const storeConfig = cfg.session?.store;
	if (storeConfig && !isStorePathTemplate(storeConfig)) {
		const storePath = resolveStorePath(storeConfig);
		const defaultAgentId = normalizeAgentId(resolveDefaultAgentId(cfg));
		const store = loadSessionStore(storePath);
		const combined = {};
		for (const [key, entry] of Object.entries(store)) mergeSessionEntryIntoCombined({
			cfg,
			combined,
			entry,
			agentId: defaultAgentId,
			canonicalKey: canonicalizeSessionKeyForAgent(defaultAgentId, key)
		});
		return {
			storePath,
			store: combined
		};
	}
	const agentIds = listConfiguredAgentIds(cfg);
	const combined = {};
	for (const agentId of agentIds) {
		const store = loadSessionStore(resolveStorePath(storeConfig, { agentId }));
		for (const [key, entry] of Object.entries(store)) mergeSessionEntryIntoCombined({
			cfg,
			combined,
			entry,
			agentId,
			canonicalKey: canonicalizeSessionKeyForAgent(agentId, key)
		});
	}
	return {
		storePath: typeof storeConfig === "string" && storeConfig.trim() ? storeConfig.trim() : "(multiple)",
		store: combined
	};
}
function getSessionDefaults(cfg) {
	const resolved = resolveConfiguredModelRef({
		cfg,
		defaultProvider: DEFAULT_PROVIDER,
		defaultModel: DEFAULT_MODEL
	});
	const contextTokens = cfg.agents?.defaults?.contextTokens ?? lookupContextTokens(resolved.model) ?? DEFAULT_CONTEXT_TOKENS;
	return {
		modelProvider: resolved.provider ?? null,
		model: resolved.model ?? null,
		contextTokens: contextTokens ?? null
	};
}
function resolveSessionModelRef(cfg, entry, agentId) {
	const resolved = agentId ? resolveDefaultModelForAgent({
		cfg,
		agentId
	}) : resolveConfiguredModelRef({
		cfg,
		defaultProvider: DEFAULT_PROVIDER,
		defaultModel: DEFAULT_MODEL
	});
	let provider = resolved.provider;
	let model = resolved.model;
	const runtimeModel = entry?.model?.trim();
	const runtimeProvider = entry?.modelProvider?.trim();
	if (runtimeModel) {
		const parsedRuntime = parseModelRef(runtimeModel, runtimeProvider || provider || DEFAULT_PROVIDER);
		if (parsedRuntime) {
			provider = parsedRuntime.provider;
			model = parsedRuntime.model;
		} else {
			provider = runtimeProvider || provider;
			model = runtimeModel;
		}
		return {
			provider,
			model
		};
	}
	const storedModelOverride = entry?.modelOverride?.trim();
	if (storedModelOverride) {
		const overrideProvider = entry?.providerOverride?.trim() || provider || DEFAULT_PROVIDER;
		const parsedOverride = parseModelRef(storedModelOverride, overrideProvider);
		if (parsedOverride) {
			provider = parsedOverride.provider;
			model = parsedOverride.model;
		} else {
			provider = overrideProvider;
			model = storedModelOverride;
		}
	}
	return {
		provider,
		model
	};
}
function listSessionsFromStore(params) {
	const { cfg, storePath, store, opts } = params;
	const now = Date.now();
	const includeGlobal = opts.includeGlobal === true;
	const includeUnknown = opts.includeUnknown === true;
	const includeDerivedTitles = opts.includeDerivedTitles === true;
	const includeLastMessage = opts.includeLastMessage === true;
	const spawnedBy = typeof opts.spawnedBy === "string" ? opts.spawnedBy : "";
	const label = typeof opts.label === "string" ? opts.label.trim() : "";
	const agentId = typeof opts.agentId === "string" ? normalizeAgentId(opts.agentId) : "";
	const search = typeof opts.search === "string" ? opts.search.trim().toLowerCase() : "";
	const activeMinutes = typeof opts.activeMinutes === "number" && Number.isFinite(opts.activeMinutes) ? Math.max(1, Math.floor(opts.activeMinutes)) : void 0;
	let sessions = Object.entries(store).filter(([key]) => {
		if (isCronRunSessionKey(key)) return false;
		if (!includeGlobal && key === "global") return false;
		if (!includeUnknown && key === "unknown") return false;
		if (agentId) {
			if (key === "global" || key === "unknown") return false;
			const parsed = parseAgentSessionKey(key);
			if (!parsed) return false;
			return normalizeAgentId(parsed.agentId) === agentId;
		}
		return true;
	}).filter(([key, entry]) => {
		if (!spawnedBy) return true;
		if (key === "unknown" || key === "global") return false;
		return entry?.spawnedBy === spawnedBy;
	}).filter(([, entry]) => {
		if (!label) return true;
		return entry?.label === label;
	}).map(([key, entry]) => {
		const updatedAt = entry?.updatedAt ?? null;
		const total = resolveFreshSessionTotalTokens(entry);
		const totalTokensFresh = typeof entry?.totalTokens === "number" ? entry?.totalTokensFresh !== false : false;
		const parsed = parseGroupKey(key);
		const channel = entry?.channel ?? parsed?.channel;
		const subject = entry?.subject;
		const groupChannel = entry?.groupChannel;
		const space = entry?.space;
		const id = parsed?.id;
		const origin = entry?.origin;
		const originLabel = origin?.label;
		const displayName = entry?.displayName ?? (channel ? buildGroupDisplayName({
			provider: channel,
			subject,
			groupChannel,
			space,
			id,
			key
		}) : void 0) ?? entry?.label ?? originLabel;
		const deliveryFields = normalizeSessionDeliveryFields(entry);
		const resolvedModel = resolveSessionModelRef(cfg, entry, normalizeAgentId(parseAgentSessionKey(key)?.agentId ?? resolveDefaultAgentId(cfg)));
		const modelProvider = resolvedModel.provider ?? DEFAULT_PROVIDER;
		const model = resolvedModel.model ?? DEFAULT_MODEL;
		return {
			key,
			entry,
			kind: classifySessionKey(key, entry),
			label: entry?.label,
			displayName,
			channel,
			subject,
			groupChannel,
			space,
			chatType: entry?.chatType,
			origin,
			updatedAt,
			sessionId: entry?.sessionId,
			systemSent: entry?.systemSent,
			abortedLastRun: entry?.abortedLastRun,
			thinkingLevel: entry?.thinkingLevel,
			verboseLevel: entry?.verboseLevel,
			reasoningLevel: entry?.reasoningLevel,
			elevatedLevel: entry?.elevatedLevel,
			sendPolicy: entry?.sendPolicy,
			inputTokens: entry?.inputTokens,
			outputTokens: entry?.outputTokens,
			totalTokens: total,
			totalTokensFresh,
			responseUsage: entry?.responseUsage,
			modelProvider,
			model,
			contextTokens: entry?.contextTokens,
			deliveryContext: deliveryFields.deliveryContext,
			lastChannel: deliveryFields.lastChannel ?? entry?.lastChannel,
			lastTo: deliveryFields.lastTo ?? entry?.lastTo,
			lastAccountId: deliveryFields.lastAccountId ?? entry?.lastAccountId
		};
	}).toSorted((a, b) => (b.updatedAt ?? 0) - (a.updatedAt ?? 0));
	if (search) sessions = sessions.filter((s) => {
		return [
			s.displayName,
			s.label,
			s.subject,
			s.sessionId,
			s.key
		].some((f) => typeof f === "string" && f.toLowerCase().includes(search));
	});
	if (activeMinutes !== void 0) {
		const cutoff = now - activeMinutes * 6e4;
		sessions = sessions.filter((s) => (s.updatedAt ?? 0) >= cutoff);
	}
	if (typeof opts.limit === "number" && Number.isFinite(opts.limit)) {
		const limit = Math.max(1, Math.floor(opts.limit));
		sessions = sessions.slice(0, limit);
	}
	const finalSessions = sessions.map((s) => {
		const { entry, ...rest } = s;
		let derivedTitle;
		let lastMessagePreview;
		if (entry?.sessionId) {
			if (includeDerivedTitles || includeLastMessage) {
				const parsed = parseAgentSessionKey(s.key);
				const agentId = parsed && parsed.agentId ? normalizeAgentId(parsed.agentId) : resolveDefaultAgentId(cfg);
				const fields = readSessionTitleFieldsFromTranscript(entry.sessionId, storePath, entry.sessionFile, agentId);
				if (includeDerivedTitles) derivedTitle = deriveSessionTitle(entry, fields.firstUserMessage);
				if (includeLastMessage && fields.lastMessagePreview) lastMessagePreview = fields.lastMessagePreview;
			}
		}
		return {
			...rest,
			derivedTitle,
			lastMessagePreview
		};
	});
	return {
		ts: now,
		path: storePath,
		count: finalSessions.length,
		defaults: getSessionDefaults(cfg),
		sessions: finalSessions
	};
}

//#endregion
export { sha256HexPrefix as A, enqueueSystemEvent as C, buildChannelAccountSnapshot as D, buildChannelSummary as E, formatChannelAllowFrom as O, drainSystemEventEntries as S, peekSystemEvents as T, loadProviderUsageSummary as _, loadCombinedSessionStoreForGateway as a, resolveUsageProviderId as b, resolveGatewaySessionStoreTarget as c, formatDoctorNonInteractiveHint as d, formatRestartSentinelMessage as f, writeRestartSentinel as g, trimLogTail as h, listSessionsFromStore as i, redactIdentifier as k, resolveSessionModelRef as l, summarizeRestartSentinel as m, classifySessionKey as n, loadSessionEntry as o, readRestartSentinel as p, listAgentsForGateway as r, pruneLegacyStoreKeys as s, canonicalizeSpawnedByForAgent as t, consumeRestartSentinel as u, formatUsageReportLines as v, isSystemEventContextChanged as w, lookupContextTokens as x, formatUsageWindowSummary as y };