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>
This commit is contained in:
+56
-1
@@ -1,4 +1,5 @@
|
|||||||
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
|
||||||
|
import { SettingsManager, getAgentDir } from "@earendil-works/pi-coding-agent";
|
||||||
import {
|
import {
|
||||||
effectiveIntegration,
|
effectiveIntegration,
|
||||||
type ReinjectDeliveryMode,
|
type ReinjectDeliveryMode,
|
||||||
@@ -33,3 +34,57 @@ export const PI_AUTO_COMPACT_FOLLOW_UP_PREFIXES = [
|
|||||||
"Emergency auto-compact ran.",
|
"Emergency auto-compact ran.",
|
||||||
"Auto-compact ran on session resume.",
|
"Auto-compact ran on session resume.",
|
||||||
] as const;
|
] 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;
|
||||||
|
}
|
||||||
|
|||||||
@@ -31,6 +31,8 @@ export interface ExtensionState {
|
|||||||
export interface RuntimeFlags {
|
export interface RuntimeFlags {
|
||||||
autoCompactDetected: boolean;
|
autoCompactDetected: boolean;
|
||||||
autoCompactIntegration: AutoCompactIntegration;
|
autoCompactIntegration: AutoCompactIntegration;
|
||||||
|
/** One-time hint when Pi default compaction coexists with pi-auto-compact (SPEC §16.7). */
|
||||||
|
compactionCoexistenceHintShown: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const STATE_ENTRY_TYPE = "skill-reinject:state";
|
export const STATE_ENTRY_TYPE = "skill-reinject:state";
|
||||||
@@ -84,6 +86,7 @@ export function createRuntimeFlags(): RuntimeFlags {
|
|||||||
return {
|
return {
|
||||||
autoCompactDetected: false,
|
autoCompactDetected: false,
|
||||||
autoCompactIntegration: "auto",
|
autoCompactIntegration: "auto",
|
||||||
|
compactionCoexistenceHintShown: false,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,8 +2,10 @@ import { describe, expect, it } from "vitest";
|
|||||||
import {
|
import {
|
||||||
detectAndCachePiAutoCompact,
|
detectAndCachePiAutoCompact,
|
||||||
detectPiAutoCompact,
|
detectPiAutoCompact,
|
||||||
|
maybeNotifyCompactionCoexistenceHint,
|
||||||
PI_AUTO_COMPACT_FOLLOW_UP_PREFIXES,
|
PI_AUTO_COMPACT_FOLLOW_UP_PREFIXES,
|
||||||
resolveDeliveryMode,
|
resolveDeliveryMode,
|
||||||
|
resolvePiDefaultCompactionEnabled,
|
||||||
} from "../src/auto-compact";
|
} from "../src/auto-compact";
|
||||||
import { createDefaultSettings } from "../src/settings";
|
import { createDefaultSettings } from "../src/settings";
|
||||||
import { createRuntimeFlags } from "../src/state";
|
import { createRuntimeFlags } from "../src/state";
|
||||||
@@ -53,3 +55,54 @@ describe("PI_AUTO_COMPACT_FOLLOW_UP_PREFIXES", () => {
|
|||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("resolvePiDefaultCompactionEnabled", () => {
|
||||||
|
it("defaults to enabled when compaction settings are absent", () => {
|
||||||
|
expect(resolvePiDefaultCompactionEnabled({}, {})).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("lets project override global compaction.enabled", () => {
|
||||||
|
expect(
|
||||||
|
resolvePiDefaultCompactionEnabled(
|
||||||
|
{ compaction: { enabled: true } },
|
||||||
|
{ compaction: { enabled: false } },
|
||||||
|
),
|
||||||
|
).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("maybeNotifyCompactionCoexistenceHint", () => {
|
||||||
|
it("notifies once when pi-auto-compact and Pi compaction are both active", () => {
|
||||||
|
const runtime = createRuntimeFlags();
|
||||||
|
runtime.autoCompactDetected = true;
|
||||||
|
const notifications: string[] = [];
|
||||||
|
const ctx = {
|
||||||
|
hasUI: true,
|
||||||
|
ui: {
|
||||||
|
notify: (message: string) => {
|
||||||
|
notifications.push(message);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
maybeNotifyCompactionCoexistenceHint(ctx as never, runtime, true);
|
||||||
|
maybeNotifyCompactionCoexistenceHint(ctx as never, runtime, true);
|
||||||
|
|
||||||
|
expect(notifications).toHaveLength(1);
|
||||||
|
expect(runtime.compactionCoexistenceHintShown).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("skips notify when pi-auto-compact is not detected", () => {
|
||||||
|
const runtime = createRuntimeFlags();
|
||||||
|
const notifications: string[] = [];
|
||||||
|
const ctx = {
|
||||||
|
hasUI: true,
|
||||||
|
ui: { notify: (message: string) => notifications.push(message) },
|
||||||
|
};
|
||||||
|
|
||||||
|
maybeNotifyCompactionCoexistenceHint(ctx as never, runtime, true);
|
||||||
|
|
||||||
|
expect(notifications).toHaveLength(0);
|
||||||
|
expect(runtime.compactionCoexistenceHintShown).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user