import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent"; import { SettingsManager, getAgentDir } from "@earendil-works/pi-coding-agent"; import { effectiveIntegration, type ReinjectDeliveryMode, type SkillReinjectSettings, } from "./settings"; import type { AutoCompactIntegration, RuntimeFlags } from "./state"; /** Detect @capyup/pi-auto-compact via public getCommands API (SPEC §16.4). */ export function detectPiAutoCompact(pi: ExtensionAPI): boolean { return pi.getCommands().some((command) => command.name === "auto-compact"); } /** Detect pi-auto-compact and cache result in runtime flags (SPEC §16.4). */ export function detectAndCachePiAutoCompact(pi: ExtensionAPI, runtime: RuntimeFlags): boolean { runtime.autoCompactDetected = detectPiAutoCompact(pi); return runtime.autoCompactDetected; } /** Resolve re-inject delivery mode from settings, detect cache, and session override (SPEC §6.5.3). */ export function resolveDeliveryMode( settings: SkillReinjectSettings, runtime: RuntimeFlags, sessionIntegrationOverride?: AutoCompactIntegration | null, ): ReinjectDeliveryMode { return effectiveIntegration(settings, runtime.autoCompactDetected, sessionIntegrationOverride); } /** pi-auto-compact follow-up message prefixes (SPEC §16.9); documentation/tests only, not runtime v1. */ export const PI_AUTO_COMPACT_FOLLOW_UP_PREFIXES = [ "Auto-compact ran before this turn.", "Auto-compact ran mid-turn.", "Emergency auto-compact ran.", "Auto-compact ran on session resume.", ] as const; const PI_DEFAULT_COMPACTION_ENABLED = true; function readCompactionEnabled(settings: object): boolean | undefined { const compaction = (settings as Record).compaction; if (!compaction || typeof compaction !== "object" || Array.isArray(compaction)) { return undefined; } const enabled = (compaction as Record).enabled; return typeof enabled === "boolean" ? enabled : undefined; } /** Merged Pi compaction.enabled with project-over-global semantics (SPEC §16.7). */ export function resolvePiDefaultCompactionEnabled( globalSettings: object, projectSettings: object, ): boolean { return ( readCompactionEnabled(projectSettings) ?? readCompactionEnabled(globalSettings) ?? PI_DEFAULT_COMPACTION_ENABLED ); } export function isPiDefaultCompactionEnabled(ctx: ExtensionContext): boolean { const manager = SettingsManager.create(ctx.cwd, getAgentDir(), { projectTrusted: ctx.isProjectTrusted(), }); return resolvePiDefaultCompactionEnabled( manager.getGlobalSettings(), manager.getProjectSettings(), ); } /** One-time ui.notify when Pi default compaction and pi-auto-compact are both active (SPEC §16.7). */ export function maybeNotifyCompactionCoexistenceHint( ctx: ExtensionContext, runtime: RuntimeFlags, piDefaultCompactionEnabled = isPiDefaultCompactionEnabled(ctx), ): void { if (runtime.compactionCoexistenceHintShown || !runtime.autoCompactDetected) { return; } if (!piDefaultCompactionEnabled) { return; } if (ctx.hasUI) { ctx.ui.notify( "Pi built-in auto-compaction and pi-auto-compact are both enabled. Consider setting compaction.enabled to false in settings.json.", "info", ); } runtime.compactionCoexistenceHintShown = true; }