Merge PR #6507: fix(plugins): restore pi-sprite legacy compatibility (@roboomp)
This commit is contained in:
@@ -90,6 +90,9 @@
|
||||
### Fixed
|
||||
|
||||
- Fixed `/context` counting hidden, explicit-only skills (`hide: true` / `disable-model-invocation`) in the Skills category and subtracting that inflated estimate from the first system-prompt block, which reported `System prompt: 0 tokens` and inflated Skills usage. Accounting now counts only the skills actually rendered into the system prompt — mirroring `buildSystemPrompt`'s filter, so hidden skills and all skills when the `read` tool is unavailable contribute zero ([#6498](https://github.com/can1357/oh-my-pi/issues/6498)).
|
||||
### Fixed
|
||||
|
||||
- Fixed `pi-sprite` failing plugin validation because the legacy Pi compatibility shims omitted `createExtensionRuntime` and terminal capability/image-deletion helpers used by the extension ([#6506](https://github.com/can1357/oh-my-pi/issues/6506)).
|
||||
|
||||
## [17.1.1] - 2026-07-24
|
||||
|
||||
|
||||
@@ -861,6 +861,11 @@ export interface ResourceLoader {
|
||||
readonly __ompLegacyPiLoader?: true;
|
||||
}
|
||||
|
||||
/** Create a pre-initialization runtime for legacy extension resource loaders. */
|
||||
export function createExtensionRuntime(): ExtensionRuntime {
|
||||
return new ExtensionRuntime();
|
||||
}
|
||||
|
||||
/**
|
||||
* Loader-owned inputs that {@link createAgentSession} needs regardless of
|
||||
* whether the caller provided extra options. `cwd`/`agentDir` fall back to
|
||||
@@ -894,7 +899,7 @@ export class DefaultResourceLoader implements ResourceLoader {
|
||||
readonly __ompLegacyPiLoader = true as const;
|
||||
#state: ResolvedLoaderState;
|
||||
#options: DefaultResourceLoaderOptions;
|
||||
#extensionsResult: LoadExtensionsResult = { extensions: [], errors: [], runtime: new ExtensionRuntime() };
|
||||
#extensionsResult: LoadExtensionsResult = { extensions: [], errors: [], runtime: createExtensionRuntime() };
|
||||
#skills: Skill[] = [];
|
||||
#skillDiagnostics: ResourceDiagnostic[] = [];
|
||||
#prompts: PromptTemplate[] = [];
|
||||
@@ -1043,7 +1048,7 @@ export class DefaultResourceLoader implements ResourceLoader {
|
||||
const { cwd, noExtensions, additionalExtensionPaths, extensionFactories, eventBus } = this.#state;
|
||||
|
||||
if (noExtensions && additionalExtensionPaths.length === 0 && extensionFactories.length === 0) {
|
||||
return { extensions: [], errors: [], runtime: new ExtensionRuntime() };
|
||||
return { extensions: [], errors: [], runtime: createExtensionRuntime() };
|
||||
}
|
||||
|
||||
const paths = await discoverSessionExtensionPaths(
|
||||
|
||||
@@ -6,5 +6,31 @@
|
||||
* exposes the equivalent, broader `decodePrintableKey` helper. Keep the legacy
|
||||
* name available without reintroducing it into the canonical package surface.
|
||||
*/
|
||||
import { ImageProtocol, isInsideTmux, TERMINAL, wrapTmuxPassthrough } from "@oh-my-pi/pi-tui";
|
||||
|
||||
export * from "@oh-my-pi/pi-tui";
|
||||
export { decodePrintableKey as decodeKittyPrintable } from "@oh-my-pi/pi-tui";
|
||||
export {
|
||||
decodePrintableKey as decodeKittyPrintable,
|
||||
encodeKittyDeleteImage as deleteKittyImage,
|
||||
} from "@oh-my-pi/pi-tui";
|
||||
|
||||
/** Report canonical terminal capabilities through the legacy Pi TUI shape. */
|
||||
export function getCapabilities(): {
|
||||
images: "kitty" | "iterm2" | null;
|
||||
trueColor: boolean;
|
||||
hyperlinks: boolean;
|
||||
} {
|
||||
const images =
|
||||
TERMINAL.imageProtocol === ImageProtocol.Kitty
|
||||
? "kitty"
|
||||
: TERMINAL.imageProtocol === ImageProtocol.Iterm2
|
||||
? "iterm2"
|
||||
: null;
|
||||
return { images, trueColor: TERMINAL.trueColor, hyperlinks: TERMINAL.hyperlinks };
|
||||
}
|
||||
|
||||
/** Delete every Kitty graphics image using the legacy Pi TUI control sequence. */
|
||||
export function deleteAllKittyImages(): string {
|
||||
const sequence = "\x1b_Ga=d,d=A,q=2\x1b\\";
|
||||
return isInsideTmux() ? wrapTmuxPassthrough(sequence) : sequence;
|
||||
}
|
||||
|
||||
@@ -265,6 +265,28 @@ describe("legacy pi package root remaps (issue #1474)", () => {
|
||||
expect(loaded.printable).toBe("a");
|
||||
});
|
||||
|
||||
it("loads pi-sprite's legacy terminal helpers", async () => {
|
||||
const entry = await writeFixtureExtension(
|
||||
[
|
||||
'import { deleteAllKittyImages, deleteKittyImage, getCapabilities } from "@earendil-works/pi-tui";',
|
||||
"export const deleteOne = deleteKittyImage(42);",
|
||||
"export const deleteAll = deleteAllKittyImages();",
|
||||
"export const capabilities = getCapabilities();",
|
||||
].join("\n"),
|
||||
);
|
||||
|
||||
const loaded = (await loadLegacyPiModule(entry)) as {
|
||||
deleteOne: string;
|
||||
deleteAll: string;
|
||||
capabilities: { images: "kitty" | "iterm2" | null; trueColor: boolean; hyperlinks: boolean };
|
||||
};
|
||||
expect(loaded.deleteOne).toContain("a=d,d=I,i=42,q=2");
|
||||
expect(loaded.deleteAll).toContain("a=d,d=A,q=2");
|
||||
expect(["kitty", "iterm2", null]).toContain(loaded.capabilities.images);
|
||||
expect(typeof loaded.capabilities.trueColor).toBe("boolean");
|
||||
expect(typeof loaded.capabilities.hyperlinks).toBe("boolean");
|
||||
});
|
||||
|
||||
it("preserves legacy defineTool root imports and usable coding tools", async () => {
|
||||
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "omp-legacy-coding-tools-"));
|
||||
tempRoots.push(dir);
|
||||
|
||||
@@ -850,6 +850,45 @@ describe("legacy-pi in-place module loading (issue #1674)", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("exposes a fresh legacy extension runtime through the package root", async () => {
|
||||
const dir = await writePackage({
|
||||
"package.json": JSON.stringify({ name: "legacy-extension-runtime-ext", version: "1.0.0" }),
|
||||
"index.ts": [
|
||||
'import { createExtensionRuntime } from "@earendil-works/pi-coding-agent";',
|
||||
"const first = createExtensionRuntime();",
|
||||
"const second = createExtensionRuntime();",
|
||||
"first.flagValues.set('sprite', true);",
|
||||
"let initializationError;",
|
||||
"try {",
|
||||
" first.getActiveTools();",
|
||||
"} catch (error) {",
|
||||
" initializationError = error instanceof Error ? error.message : String(error);",
|
||||
"}",
|
||||
"export const runtimeContract = {",
|
||||
" firstFlag: first.flagValues.get('sprite'),",
|
||||
" secondHasFlag: second.flagValues.has('sprite'),",
|
||||
" initializationError,",
|
||||
"};",
|
||||
"export default function (pi) { void pi; }",
|
||||
].join("\n"),
|
||||
});
|
||||
|
||||
const mod = (await loadLegacyPiModule(path.join(dir, "index.ts"))) as {
|
||||
runtimeContract: {
|
||||
firstFlag: boolean;
|
||||
secondHasFlag: boolean;
|
||||
initializationError: string;
|
||||
};
|
||||
};
|
||||
|
||||
expect(mod.runtimeContract).toEqual({
|
||||
firstFlag: true,
|
||||
secondHasFlag: false,
|
||||
initializationError:
|
||||
"Extension runtime not initialized. Action methods cannot be called during extension loading.",
|
||||
});
|
||||
});
|
||||
|
||||
it("honors legacy bash operations overrides", async () => {
|
||||
const dir = await writePackage({
|
||||
"package.json": JSON.stringify({ name: "legacy-bash-ops-ext", version: "1.0.0" }),
|
||||
|
||||
Reference in New Issue
Block a user