import { mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs"; import { dirname, join } from "node:path"; export type CondenseDefaultResult = "updated" | "unchanged" | "skipped-invalid"; const CONDENSE_BUNDLE_DEFAULTS = { enabled: true, pruneOn: "agent-message", batchingMode: "turn", autoBudgetThreshold: 0.735, budgetTurnDelta: 0.04, summarizerModel: "default", summarizerThinking: "default", summarizerIdleTimeoutMs: 90_000, summarizerMaxTimeoutMs: 300_000, quietOversizedSkips: false, } as const; function isObject(value: unknown): value is Record { return value !== null && typeof value === "object" && !Array.isArray(value); } /** Fill missing pi-condense settings with bundle defaults while preserving every explicit user choice. */ export function ensureCondenseDefaults(agentDir: string): CondenseDefaultResult { const targetPath = join(agentDir, "settings.json"); let settings: Record = {}; try { const parsed: unknown = JSON.parse(readFileSync(targetPath, "utf8")); if (!isObject(parsed)) return "skipped-invalid"; settings = parsed; } catch (error) { if ((error as NodeJS.ErrnoException).code !== "ENOENT") return "skipped-invalid"; } const existing = settings.contextPrune; if (existing !== undefined && !isObject(existing)) return "skipped-invalid"; const contextPrune = existing ?? {}; const alreadyComplete = Object.keys(CONDENSE_BUNDLE_DEFAULTS).every((key) => Object.hasOwn(contextPrune, key)); if (alreadyComplete) return "unchanged"; settings.contextPrune = { ...CONDENSE_BUNDLE_DEFAULTS, ...contextPrune }; mkdirSync(dirname(targetPath), { recursive: true }); const temporaryPath = `${targetPath}.my-pi.tmp`; writeFileSync(temporaryPath, `${JSON.stringify(settings, null, 2)}\n`, "utf8"); renameSync(temporaryPath, targetPath); return "updated"; }