Files
pi-auto-reinject/src/auto-compact.ts
T
grayhook bf862656ae Phase 6: add compaction coexistence hint — one-time notify when both compactors run.
Shows ui.notify once when pi-auto-compact is detected while Pi compaction.enabled stays true.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-17 11:47:27 +07:00

91 lines
3.2 KiB
TypeScript

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<string, unknown>).compaction;
if (!compaction || typeof compaction !== "object" || Array.isArray(compaction)) {
return undefined;
}
const enabled = (compaction as Record<string, unknown>).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;
}