import { CHECKLIST_ITEM_PENDING, TERMINAL_CHECKLIST_STATUSES } from "./checklist-types.js";
//#region src/agent/goals/state.ts
/** Persisted under `SessionMetadata.customData.persistentGoal`. */
const PERSISTENT_GOAL_CUSTOM_KEY = "persistentGoal";
function defaultMaxTurns(cfg) {
	const n = cfg?.maxTurns;
	if (typeof n === "number" && Number.isFinite(n)) return Math.max(1, Math.min(500, Math.floor(n)));
	return 20;
}
function coerceStatus(s) {
	if (s === "active" || s === "paused" || s === "done" || s === "cleared") return s;
}
function coerceChecklistItem(raw) {
	if (!raw || typeof raw !== "object" || Array.isArray(raw)) return null;
	const r = raw;
	const text = typeof r.text === "string" ? r.text.trim() : "";
	if (!text) return null;
	const st = typeof r.status === "string" ? r.status.trim().toLowerCase() : "";
	return {
		text,
		status: st === "completed" || st === "impossible" || st === "pending" ? st : CHECKLIST_ITEM_PENDING,
		addedBy: (typeof r.addedBy === "string" ? r.addedBy.trim().toLowerCase() : "") === "user" ? "user" : "judge",
		addedAt: typeof r.addedAt === "number" && Number.isFinite(r.addedAt) ? Math.floor(r.addedAt) : Date.now(),
		completedAt: typeof r.completedAt === "number" && Number.isFinite(r.completedAt) ? Math.floor(r.completedAt) : void 0,
		evidence: typeof r.evidence === "string" ? r.evidence : void 0
	};
}
function readPersistentGoal(customData) {
	if (!customData || typeof customData !== "object") return null;
	const raw = customData[PERSISTENT_GOAL_CUSTOM_KEY];
	if (raw && typeof raw === "object" && !Array.isArray(raw)) {
		const o = raw;
		const goal = typeof o.goal === "string" ? o.goal.trim() : "";
		if (!goal) return null;
		const status = coerceStatus(o.status) ?? "active";
		const maxTurns = typeof o.maxTurns === "number" && Number.isFinite(o.maxTurns) ? Math.max(1, Math.min(500, Math.floor(o.maxTurns))) : 20;
		const turnsUsed = typeof o.turnsUsed === "number" && Number.isFinite(o.turnsUsed) ? Math.max(0, Math.floor(o.turnsUsed)) : 0;
		const createdAt = typeof o.createdAt === "number" && Number.isFinite(o.createdAt) ? o.createdAt : Date.now();
		const lastTurnAt = typeof o.lastTurnAt === "number" && Number.isFinite(o.lastTurnAt) ? o.lastTurnAt : 0;
		const lastVerdict = o.lastVerdict === "done" || o.lastVerdict === "continue" || o.lastVerdict === "skipped" || o.lastVerdict === "decompose" ? o.lastVerdict : void 0;
		const lastReason = typeof o.lastReason === "string" ? o.lastReason : void 0;
		const pausedReason = typeof o.pausedReason === "string" ? o.pausedReason : void 0;
		const judgeModelRef = typeof o.judgeModelRef === "string" ? o.judgeModelRef.trim() : void 0;
		const consecutiveParseFailures = typeof o.consecutiveParseFailures === "number" && Number.isFinite(o.consecutiveParseFailures) ? Math.max(0, Math.floor(o.consecutiveParseFailures)) : 0;
		const decomposed = Boolean(o.decomposed);
		const uiLocale = o.uiLocale === "zh" || o.uiLocale === "en" ? o.uiLocale : void 0;
		const checklistRaw = o.checklist;
		const checklist = [];
		if (Array.isArray(checklistRaw)) for (const row of checklistRaw) {
			const it = coerceChecklistItem(row);
			if (it) checklist.push(it);
		}
		return {
			goal,
			status,
			turnsUsed,
			maxTurns,
			createdAt,
			lastTurnAt,
			lastVerdict,
			lastReason,
			pausedReason,
			judgeModelRef: judgeModelRef || void 0,
			consecutiveParseFailures,
			decomposed: decomposed || void 0,
			checklist: checklist.length ? checklist : void 0,
			uiLocale
		};
	}
	return null;
}
function serializePersistentGoal(s) {
	return {
		goal: s.goal,
		status: s.status,
		turnsUsed: s.turnsUsed,
		maxTurns: s.maxTurns,
		createdAt: s.createdAt,
		lastTurnAt: s.lastTurnAt,
		...s.lastVerdict ? { lastVerdict: s.lastVerdict } : {},
		...s.lastReason ? { lastReason: s.lastReason } : {},
		...s.pausedReason ? { pausedReason: s.pausedReason } : {},
		...s.judgeModelRef ? { judgeModelRef: s.judgeModelRef } : {},
		...s.consecutiveParseFailures ? { consecutiveParseFailures: s.consecutiveParseFailures } : {},
		...s.decomposed ? { decomposed: true } : {},
		...s.uiLocale ? { uiLocale: s.uiLocale } : {},
		...s.checklist?.length ? { checklist: s.checklist.map((it) => ({
			text: it.text,
			status: it.status,
			addedBy: it.addedBy,
			addedAt: it.addedAt,
			...it.completedAt !== void 0 ? { completedAt: it.completedAt } : {},
			...it.evidence ? { evidence: it.evidence } : {}
		})) } : {}
	};
}
/** Render checklist for continuation prompt (Hermes-style, no numbers in body). */
function renderChecklistPlain(items) {
	if (!items.length) return "(empty)";
	const lines = [];
	for (const it of items) {
		let line = `${it.status === "completed" ? "[x]" : it.status === "impossible" ? "[!]" : "[ ]"} ${it.text}`;
		if (it.status === "impossible" && it.evidence) line += ` (impossible: ${it.evidence})`;
		lines.push(line);
	}
	return lines.join("\n");
}
/** Numbered checklist for judge user prompts (1-based indices). */
function renderChecklistNumbered(items) {
	if (!items.length) return "(empty)";
	const lines = [];
	for (let i = 0; i < items.length; i++) {
		const it = items[i];
		let line = `${i + 1}. ${it.status === "completed" ? "[x]" : it.status === "impossible" ? "[!]" : "[ ]"} ${it.text}`;
		if (it.status === "impossible" && it.evidence) line += ` (impossible: ${it.evidence})`;
		lines.push(line);
	}
	return lines.join("\n");
}
/**
* After LLM decomposition, keep existing checklist rows (e.g. user-added acceptance criteria)
* and append judge-generated items, skipping duplicate text (case-insensitive trim).
*/
function mergeDecomposedChecklistItems(existing, decomposedTexts) {
	const now = Date.now();
	const next = existing.map((it) => ({ ...it }));
	const seen = new Set(next.map((it) => it.text.trim().toLowerCase()));
	for (const row of decomposedTexts) {
		const t = row.text.trim();
		if (!t) continue;
		const key = t.toLowerCase();
		if (seen.has(key)) continue;
		seen.add(key);
		next.push({
			text: t,
			status: CHECKLIST_ITEM_PENDING,
			addedBy: "judge",
			addedAt: now
		});
	}
	return next;
}
function applyJudgeChecklistUpdates(items, parsed) {
	const next = items.map((it) => ({ ...it }));
	const now = Date.now();
	for (const upd of parsed.updates) {
		const idx = upd.index;
		if (idx < 0 || idx >= next.length) continue;
		const item = next[idx];
		if (TERMINAL_CHECKLIST_STATUSES.has(item.status)) continue;
		if (!TERMINAL_CHECKLIST_STATUSES.has(upd.status)) continue;
		item.status = upd.status;
		item.completedAt = now;
		if (upd.evidence?.trim()) item.evidence = upd.evidence.trim();
	}
	for (const ni of parsed.newItems) {
		const t = ni.text.trim();
		if (!t) continue;
		next.push({
			text: t,
			status: CHECKLIST_ITEM_PENDING,
			addedBy: "judge",
			addedAt: now
		});
	}
	return next;
}
function mergeCustomDataPatch(existingCustom, patch) {
	return {
		...existingCustom ?? {},
		...patch
	};
}
//#endregion
export { PERSISTENT_GOAL_CUSTOM_KEY, applyJudgeChecklistUpdates, defaultMaxTurns, mergeCustomDataPatch, mergeDecomposedChecklistItems, readPersistentGoal, renderChecklistNumbered, renderChecklistPlain, serializePersistentGoal };

//# sourceMappingURL=state.js.map