fix(extensibility): guarantee string getPackageDir in compiled shim builds
omp's canonical getPackageDir() returns undefined inside a bun --compile binary (import.meta.dir is /$bunfs/root, no owning package.json — issue #1423). Re-exporting it directly broke pi's string-valued contract: legacy extensions doing path.join(getPackageDir(), ...) crashed at runtime in the shipped binary, the primary distribution. Wrap the canonical helper so the shim always returns a string, falling back to the executable's directory in compiled mode (where the binary is the install root). PI_PACKAGE_DIR and dev/source/npm-dist walk-up still win. Test covers the compiled-mode fallback via isCompiledBinary spy. Fixes #5968
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed legacy pi extensions failing extension validation when importing `getPackageDir` or `getProjectDir` from `@earendil-works/pi-coding-agent` (aliased to the legacy shim). The shim only re-exported `getAgentDir`; the two missing path helpers now resolve — `getProjectDir` from `@oh-my-pi/pi-utils` and `getPackageDir` from omp's canonical package-root helper — so extensions like `@gotgenes/pi-permission-system` install and load ([#5968](https://github.com/can1357/oh-my-pi/issues/5968)).
|
||||
- Fixed legacy pi extensions failing extension validation when importing `getPackageDir` or `getProjectDir` from `@earendil-works/pi-coding-agent` (aliased to the legacy shim). The shim only re-exported `getAgentDir`; the two missing path helpers now resolve — `getProjectDir` from `@oh-my-pi/pi-utils`, and `getPackageDir` as a string-valued wrapper over omp's canonical package-root helper that falls back to the executable's directory inside `bun --compile` binaries (where the canonical helper returns `undefined`), matching pi's string contract. Extensions like `@gotgenes/pi-permission-system` install and load, and `path.join(getPackageDir(), …)` no longer crashes in the shipped binary ([#5968](https://github.com/can1357/oh-my-pi/issues/5968)).
|
||||
|
||||
## [17.0.4] - 2026-07-18
|
||||
|
||||
|
||||
@@ -22,8 +22,10 @@ import {
|
||||
getAgentDbPath,
|
||||
getAgentDir,
|
||||
getProjectDir,
|
||||
isCompiledBinary,
|
||||
parseFrontmatter as parseOmpFrontmatter,
|
||||
} from "@oh-my-pi/pi-utils";
|
||||
import { getPackageDir as getOmpPackageDir } from "../config";
|
||||
import type { PromptTemplate } from "../config/prompt-templates";
|
||||
import { type SettingPath, Settings } from "../config/settings";
|
||||
import { EditTool } from "../edit";
|
||||
@@ -1336,12 +1338,28 @@ export function readStoredCredential(provider: string): AuthCredential | undefin
|
||||
|
||||
// Pi SDK path helpers. `export * from "../index"` above only forwards
|
||||
// `getAgentDir`; `getProjectDir` (a `@oh-my-pi/pi-utils` helper) and
|
||||
// `getPackageDir` (omp's canonical coding-agent package-root helper, matching
|
||||
// pi's "install directory of the coding-agent package" semantics) are absent
|
||||
// from that barrel, so legacy extensions importing either fail Bun's static
|
||||
// export check during validation (issue #5968).
|
||||
// `getPackageDir` are absent from that barrel, so legacy extensions importing
|
||||
// either fail Bun's static export check during validation (issue #5968).
|
||||
export { getProjectDir } from "@oh-my-pi/pi-utils";
|
||||
export { getPackageDir } from "../config";
|
||||
|
||||
/**
|
||||
* Coding-agent package install directory, matching pi's string-valued
|
||||
* `getPackageDir()` contract (extensions do `path.join(getPackageDir(), ...)`
|
||||
* to auto-allow bundled docs/resources).
|
||||
*
|
||||
* omp's canonical `getPackageDir()` (`../config`) returns `undefined` inside a
|
||||
* `bun --compile` binary — `import.meta.dir` is `/$bunfs/root` and no owning
|
||||
* `package.json` exists (issue #1423). Returning `undefined` there would crash
|
||||
* every legacy `path.join(getPackageDir(), ...)` at runtime in the shipped
|
||||
* binary, the primary distribution. So fall back to the executable's own
|
||||
* directory in compiled mode, where the binary *is* the install root. The
|
||||
* `PI_PACKAGE_DIR` override and dev/source/npm-dist walk-up still win via the
|
||||
* canonical helper.
|
||||
*/
|
||||
export function getPackageDir(): string {
|
||||
return getOmpPackageDir() ?? (isCompiledBinary() ? path.dirname(process.execPath) : process.cwd());
|
||||
}
|
||||
|
||||
export * from "../index";
|
||||
export { formatBytes as formatSize } from "../tools/render-utils";
|
||||
export { Type } from "./typebox";
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { describe, expect, it } from "bun:test";
|
||||
import { afterEach, describe, expect, it, spyOn, vi } from "bun:test";
|
||||
import * as path from "node:path";
|
||||
import * as configModule from "@oh-my-pi/pi-coding-agent/config";
|
||||
import * as shim from "@oh-my-pi/pi-coding-agent/extensibility/legacy-pi-coding-agent-shim";
|
||||
import * as utils from "@oh-my-pi/pi-utils";
|
||||
|
||||
// Issue #5968: pi extensions import the SDK path helpers (`getAgentDir`,
|
||||
// `getProjectDir`, `getPackageDir`) from `@earendil-works/pi-coding-agent`,
|
||||
@@ -10,17 +12,37 @@ import * as shim from "@oh-my-pi/pi-coding-agent/extensibility/legacy-pi-coding-
|
||||
// error and any importing extension failed validation. These pin the full
|
||||
// path-helper surface through the public package specifier.
|
||||
describe("legacy shim path helpers", () => {
|
||||
afterEach(() => vi.restoreAllMocks());
|
||||
|
||||
it("exports the three pi SDK path helpers as callable functions", () => {
|
||||
expect(typeof shim.getAgentDir).toBe("function");
|
||||
expect(typeof shim.getProjectDir).toBe("function");
|
||||
expect(typeof shim.getPackageDir).toBe("function");
|
||||
});
|
||||
|
||||
it("getPackageDir resolves the coding-agent package root", () => {
|
||||
it("getPackageDir resolves the coding-agent package root in source mode", () => {
|
||||
// omp's canonical helper returns the package root containing package.json
|
||||
// (pi's "install directory of the coding-agent package" semantics).
|
||||
const dir = shim.getPackageDir();
|
||||
expect(dir).toBeDefined();
|
||||
expect(path.basename(dir as string)).toBe("coding-agent");
|
||||
expect(path.basename(dir)).toBe("coding-agent");
|
||||
});
|
||||
|
||||
// Pi's getPackageDir() is string-valued: extensions do
|
||||
// `path.join(getPackageDir(), ...)`. omp's canonical helper returns
|
||||
// `undefined` inside a `bun --compile` binary (import.meta.dir is
|
||||
// /$bunfs/root, no package.json — issue #1423), which would crash every
|
||||
// such call in the shipped binary. The shim MUST fall back to a real
|
||||
// directory instead of forwarding undefined.
|
||||
it("getPackageDir returns a string even when the canonical helper yields undefined", () => {
|
||||
spyOn(configModule, "getPackageDir").mockReturnValue(undefined);
|
||||
const dir = shim.getPackageDir();
|
||||
expect(typeof dir).toBe("string");
|
||||
expect(dir.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it("getPackageDir falls back to the executable directory in compiled-binary mode", () => {
|
||||
spyOn(configModule, "getPackageDir").mockReturnValue(undefined);
|
||||
spyOn(utils, "isCompiledBinary").mockReturnValue(true);
|
||||
expect(shim.getPackageDir()).toBe(path.dirname(process.execPath));
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user