import { n as sliceUtf16Safe, r as truncateUtf16Safe } from "./utf16-slice-D_ngcYKd.js";
import { l as normalizeOptionalString } from "./string-coerce-CIXf7egm.js";
import "./utils-B2aozS-T.js";
import { c as resolveAgentConfig } from "./agent-scope-config-adSj-fCz.js";
import "./agent-scope-CB42Y_8g.js";
import { t as sanitizeGoogleAssistantFirstOrdering } from "./google-turn-ordering-CAKKJfPd.js";
//#region src/agents/embedded-agent-helpers/bootstrap.ts
/**
* Builds and sanitizes bootstrap context inserted into embedded-agent sessions.
*/
function isBase64Signature(value) {
	const trimmed = value.trim();
	if (!trimmed) return false;
	const compact = trimmed.replace(/\s+/g, "");
	if (!/^[A-Za-z0-9+/=_-]+$/.test(compact)) return false;
	const isUrl = compact.includes("-") || compact.includes("_");
	try {
		const buf = Buffer.from(compact, isUrl ? "base64url" : "base64");
		if (buf.length === 0) return false;
		const encoded = buf.toString(isUrl ? "base64url" : "base64");
		const normalize = (input) => input.replace(/=+$/g, "");
		return normalize(encoded) === normalize(compact);
	} catch {
		return false;
	}
}
/**
* Strips Claude-style thought_signature fields from content blocks.
*
* Gemini expects thought signatures as base64-encoded bytes, but Claude stores message ids
* like "msg_abc123...". We only strip "msg_*" to preserve any provider-valid signatures.
*/
function stripThoughtSignatures(content, options) {
	if (!Array.isArray(content)) return content;
	const allowBase64Only = options?.allowBase64Only ?? false;
	const includeCamelCase = options?.includeCamelCase ?? false;
	const shouldStripSignature = (value) => {
		if (!allowBase64Only) return typeof value === "string" && value.startsWith("msg_");
		return typeof value !== "string" || !isBase64Signature(value);
	};
	return content.map((block) => {
		if (!block || typeof block !== "object") return block;
		const rec = block;
		const stripSnake = shouldStripSignature(rec.thought_signature);
		const stripCamel = includeCamelCase ? shouldStripSignature(rec.thoughtSignature) : false;
		if (!stripSnake && !stripCamel) return block;
		const next = { ...rec };
		if (stripSnake) delete next.thought_signature;
		if (stripCamel) delete next.thoughtSignature;
		return next;
	});
}
const DEFAULT_BOOTSTRAP_MAX_CHARS = 2e4;
const DEFAULT_BOOTSTRAP_TOTAL_MAX_CHARS = 6e4;
const USER_BOOTSTRAP_MAX_CHARS = 4e3;
const MIN_BOOTSTRAP_FILE_BUDGET_CHARS = 64;
const BOOTSTRAP_HEAD_RATIO = .75;
const BOOTSTRAP_TAIL_RATIO = .25;
const MIN_BOOTSTRAP_TRIMMED_CONTENT_CHARS = 16;
const AGENTS_BOOTSTRAP_FILENAME = "AGENTS.md";
const USER_BOOTSTRAP_FILENAME = "USER.md";
const AGENTS_POLICY_DIGEST_RATIO = .35;
const AGENTS_POLICY_HEAD_RATIO = .45;
const AGENTS_POLICY_TAIL_RATIO = .15;
const AGENTS_POLICY_DIGEST_MAX_LINE_CHARS = 240;
function resolveBootstrapMaxChars(cfg, agentId) {
	const raw = cfg && agentId ? resolveAgentConfig(cfg, agentId)?.bootstrapMaxChars ?? cfg.agents?.defaults?.bootstrapMaxChars : cfg?.agents?.defaults?.bootstrapMaxChars;
	if (typeof raw === "number" && Number.isFinite(raw) && raw > 0) return Math.floor(raw);
	return DEFAULT_BOOTSTRAP_MAX_CHARS;
}
function resolveBootstrapTotalMaxChars(cfg, agentId) {
	const raw = cfg && agentId ? resolveAgentConfig(cfg, agentId)?.bootstrapTotalMaxChars ?? cfg.agents?.defaults?.bootstrapTotalMaxChars : cfg?.agents?.defaults?.bootstrapTotalMaxChars;
	if (typeof raw === "number" && Number.isFinite(raw) && raw > 0) return Math.floor(raw);
	return DEFAULT_BOOTSTRAP_TOTAL_MAX_CHARS;
}
function isAgentsBootstrapFile(fileName) {
	return fileName?.toLowerCase() === AGENTS_BOOTSTRAP_FILENAME.toLowerCase();
}
function isUserBootstrapFile(fileName) {
	return fileName?.toLowerCase() === USER_BOOTSTRAP_FILENAME.toLowerCase();
}
function isPolicyDigestCandidate(line) {
	if (/^(?:#{1,6}|\s*[-*+]|\s*\d+[.)])\s+\S/u.test(line)) return true;
	return /\b(?:AGENTS\.md|scoped|required|must|never|do not|before subtree|read scoped|owner|security|secret|credential|test|validation|command|commit|push|github|pr)\b/iu.test(line);
}
function normalizePolicyDigestLine(line) {
	const normalized = line.trim().replace(/\s+/gu, " ");
	if (normalized.length <= AGENTS_POLICY_DIGEST_MAX_LINE_CHARS) return normalized;
	return `${truncateUtf16Safe(normalized, AGENTS_POLICY_DIGEST_MAX_LINE_CHARS - 1)}…`;
}
function buildAgentsPolicyDigest(content, budget) {
	if (budget <= 0) return {
		text: "",
		omittedLines: 0
	};
	const candidates = content.split(/\r?\n/u).map((line, index) => ({
		index,
		line: normalizePolicyDigestLine(line)
	})).filter(({ line }) => line.length > 0 && isPolicyDigestCandidate(line));
	const highPriorityPattern = /\b(?:AGENTS\.md|scoped|required|must|never|do not|before subtree|read scoped|security|secret|credential)\b/iu;
	const selected = /* @__PURE__ */ new Set();
	let used = 0;
	const trySelect = (candidate) => {
		const separatorChars = selected.size > 0 ? 1 : 0;
		if (used + separatorChars + candidate.line.length > budget) return;
		selected.add(candidate.index);
		used += separatorChars + candidate.line.length;
	};
	for (const candidate of candidates) if (highPriorityPattern.test(candidate.line)) trySelect(candidate);
	for (const candidate of candidates) if (!selected.has(candidate.index)) trySelect(candidate);
	const lines = candidates.filter((candidate) => selected.has(candidate.index)).toSorted((a, b) => a.index - b.index).map((candidate) => candidate.line);
	return {
		text: lines.join("\n"),
		omittedLines: Math.max(0, candidates.length - lines.length)
	};
}
function trimAgentsBootstrapContent(content, maxChars) {
	const trimmed = content.trimEnd();
	if (trimmed.length <= maxChars) return {
		content: trimmed,
		truncated: false,
		maxChars,
		originalLength: trimmed.length
	};
	let headChars = Math.floor(maxChars * AGENTS_POLICY_HEAD_RATIO);
	let tailChars = Math.floor(maxChars * AGENTS_POLICY_TAIL_RATIO);
	let digestBudget = Math.floor(maxChars * AGENTS_POLICY_DIGEST_RATIO);
	let digest = buildAgentsPolicyDigest(trimmed, digestBudget);
	const render = () => [
		sliceUtf16Safe(trimmed, 0, headChars),
		`[...truncated, read ${AGENTS_BOOTSTRAP_FILENAME} for full content...]`,
		digest.text ? "[Policy digest from AGENTS.md]" : "",
		digest.text,
		digest.omittedLines > 0 ? `[...${digest.omittedLines} more policy lines omitted...]` : "",
		`…(truncated ${AGENTS_BOOTSTRAP_FILENAME}: kept ${headChars}+policy ${digest.text.length}+${tailChars} chars of ${trimmed.length})…`,
		tailChars > 0 ? sliceUtf16Safe(trimmed, -tailChars) : ""
	].filter((part) => part.length > 0).join("\n");
	let rendered = render();
	while (rendered.length > maxChars && (tailChars > 0 || headChars > 1 || digestBudget > 0)) {
		const overflow = rendered.length - maxChars;
		if (tailChars > 0) tailChars = Math.max(0, tailChars - overflow);
		else if (headChars > 1) headChars = Math.max(1, headChars - overflow);
		else {
			digestBudget = Math.max(0, digestBudget - overflow);
			digest = buildAgentsPolicyDigest(trimmed, digestBudget);
		}
		rendered = render();
	}
	return {
		content: rendered.length > maxChars ? truncateUtf16Safe(rendered, maxChars) : rendered,
		truncated: true,
		maxChars,
		originalLength: trimmed.length
	};
}
function trimBootstrapContent(content, fileName, maxChars) {
	const trimmed = content.trimEnd();
	if (trimmed.length <= maxChars) return {
		content: trimmed,
		truncated: false,
		maxChars,
		originalLength: trimmed.length
	};
	if (isAgentsBootstrapFile(fileName)) return trimAgentsBootstrapContent(content, maxChars);
	const markerTemplate = (headChars, tailChars) => [
		"",
		`[...truncated, read ${fileName} for full content...]`,
		`…(truncated ${fileName}: kept ${headChars}+${tailChars} chars of ${trimmed.length})…`,
		""
	].join("\n");
	const compactMarkerTemplate = (headChars, tailChars) => `[…truncated ${headChars}+${tailChars}/${trimmed.length}]`;
	const separatorCharsFor = (headCount, tailCount, markerContent) => markerContent.includes("\n") ? Number(headCount > 0) + Number(tailCount > 0) : 0;
	const renderTruncatedContent = (head, markerContent, tail) => [
		head,
		markerContent,
		tail
	].filter((part) => part.length > 0).join(markerContent.includes("\n") ? "\n" : "");
	const resolveMarkerTemplate = () => {
		const fullMarker = markerTemplate(0, 0);
		return maxChars - fullMarker.length - separatorCharsFor(1, 1, fullMarker) >= MIN_BOOTSTRAP_TRIMMED_CONTENT_CHARS ? markerTemplate : compactMarkerTemplate;
	};
	const resolvedMarkerTemplate = resolveMarkerTemplate();
	let headChars = 0;
	let tailChars = 0;
	let marker = resolvedMarkerTemplate(headChars, tailChars);
	for (let attempt = 0; attempt < 3; attempt += 1) {
		const contentBudget = Math.max(0, maxChars - marker.length - separatorCharsFor(headChars, tailChars, marker));
		const nextHeadChars = Math.floor(contentBudget * BOOTSTRAP_HEAD_RATIO);
		const nextTailChars = Math.floor(contentBudget * BOOTSTRAP_TAIL_RATIO);
		const nextMarker = resolvedMarkerTemplate(nextHeadChars, nextTailChars);
		if (nextHeadChars === headChars && nextTailChars === tailChars && nextMarker.length === marker.length) break;
		headChars = nextHeadChars;
		tailChars = nextTailChars;
		marker = nextMarker;
	}
	let renderedLength = headChars + tailChars + marker.length + separatorCharsFor(headChars, tailChars, marker);
	while (renderedLength > maxChars && (tailChars > 0 || headChars > 0)) {
		const overflow = renderedLength - maxChars;
		if (tailChars > 0) tailChars = Math.max(0, tailChars - overflow);
		else headChars = Math.max(0, headChars - overflow);
		marker = resolvedMarkerTemplate(headChars, tailChars);
		renderedLength = headChars + tailChars + marker.length + separatorCharsFor(headChars, tailChars, marker);
	}
	if (headChars === 0 && tailChars === 0 && trimmed.length > 0) {
		const singleHeadMarker = resolvedMarkerTemplate(1, 0);
		if (1 + singleHeadMarker.length + separatorCharsFor(1, 0, singleHeadMarker) <= maxChars) {
			headChars = 1;
			marker = singleHeadMarker;
		}
	}
	const head = sliceUtf16Safe(trimmed, 0, headChars);
	const tail = tailChars > 0 ? sliceUtf16Safe(trimmed, -tailChars) : "";
	const contentWithMarker = renderTruncatedContent(head, marker, tail);
	return {
		content: contentWithMarker.length > maxChars ? truncateUtf16Safe(contentWithMarker, maxChars) : contentWithMarker,
		truncated: true,
		maxChars,
		originalLength: trimmed.length
	};
}
function clampToBudget(content, budget) {
	if (budget <= 0) return "";
	if (content.length <= budget) return content;
	if (budget <= 3) return truncateUtf16Safe(content, budget);
	return `${truncateUtf16Safe(content, budget - 1)}…`;
}
function buildBootstrapContextFiles(files, opts) {
	const maxChars = opts?.maxChars ?? DEFAULT_BOOTSTRAP_MAX_CHARS;
	let remainingTotalChars = Math.max(1, Math.floor(opts?.totalMaxChars ?? Math.max(maxChars, DEFAULT_BOOTSTRAP_TOTAL_MAX_CHARS)));
	const result = [];
	for (const file of files) {
		if (remainingTotalChars <= 0) break;
		const pathValue = normalizeOptionalString(file.path) ?? "";
		if (!pathValue) {
			opts?.warn?.(`skipping bootstrap file "${file.name}" — missing or invalid "path" field (hook may have used "filePath" instead)`);
			continue;
		}
		if (file.missing) {
			const cappedMissingText = clampToBudget(`[MISSING] Expected at: ${pathValue}`, remainingTotalChars);
			if (!cappedMissingText) break;
			remainingTotalChars = Math.max(0, remainingTotalChars - cappedMissingText.length);
			result.push({
				path: pathValue,
				content: cappedMissingText
			});
			continue;
		}
		if (remainingTotalChars < MIN_BOOTSTRAP_FILE_BUDGET_CHARS) {
			opts?.warn?.(`remaining bootstrap budget is ${remainingTotalChars} chars (<${MIN_BOOTSTRAP_FILE_BUDGET_CHARS}); skipping additional bootstrap files`);
			break;
		}
		const fileBudget = isUserBootstrapFile(file.name) ? Math.min(maxChars, USER_BOOTSTRAP_MAX_CHARS) : maxChars;
		const fileMaxChars = Math.max(1, Math.min(fileBudget, remainingTotalChars));
		const trimmed = trimBootstrapContent(file.content ?? "", file.name, fileMaxChars);
		const contentWithinBudget = clampToBudget(trimmed.content, remainingTotalChars);
		if (!contentWithinBudget) continue;
		if (trimmed.truncated || contentWithinBudget.length < trimmed.content.length) opts?.warn?.(`workspace bootstrap file ${file.name} is ${trimmed.originalLength} chars (limit ${trimmed.maxChars}); truncating in injected context`);
		remainingTotalChars = Math.max(0, remainingTotalChars - contentWithinBudget.length);
		result.push({
			path: pathValue,
			content: contentWithinBudget
		});
	}
	return result;
}
function sanitizeGoogleTurnOrdering(messages) {
	return sanitizeGoogleAssistantFirstOrdering(messages);
}
//#endregion
export { sanitizeGoogleTurnOrdering as a, resolveBootstrapTotalMaxChars as i, buildBootstrapContextFiles as n, stripThoughtSignatures as o, resolveBootstrapMaxChars as r, USER_BOOTSTRAP_MAX_CHARS as t };
