Merge branch 'farm/6a62fa2b/fix-bunfs-override-validation-fallback'
Serve bundled pi-* and TypeBox through an in-process virtual namespace on Bun 1.3.14+ where `--compile` extras are unreachable via any filesystem API (issue #3423). Merge resolution: - Reconciled `TYPEBOX_SHIM_PATH` with main's #3414 fall-through: `__resolveTypeBoxShimPath(isCompiled, sourcePath, exists)` returns the `omp-legacy-pi-bundled:` virtual specifier in compiled mode (no FS probe) and the on-disk source path otherwise, dropping to null when the shim file is missing so bare typebox imports fall through to native resolution. - Removed the now-dead `--compile` extras path: dropped `LEGACY_COMPAT_BUILD_ENTRYPOINTS` usage from both build-binary.ts and ci-release-build-binaries.ts and deleted scripts/binary-entrypoints.ts; the bundler reaches every surface via legacy-pi-bundled-registry.ts. - Deleted obsolete tests for the removed bunfs machinery (legacy-pi-compat-entrypoints, legacy-pi-typebox-shim-validation) and added regression coverage for __resolveTypeBoxShimPath. - Dropped the binary-compiling smoke driver per maintainer request. Verified: bun check clean; 77 extensibility tests pass; instrumented compiled-binary run confirmed onLoad fires for all bundled specifiers.
This commit is contained in:
@@ -16,7 +16,9 @@
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed `omp install` of legacy pi extensions failing with `Cannot find module '/$bunfs/root/packages/coding-agent/src/extensibility/typebox.js'` on every released `omp-<platform>-<arch>` binary. Commit `dc5c93462f` removed worker entrypoints from `scripts/ci-release-build-binaries.ts`; the inline comment then claimed the legacy-shim and package-barrel entrypoints (`typebox.ts`, `legacy-pi-{ai,coding-agent}-shim.ts`, `packages/{agent,natives,tui,utils}/...`) were "still" passed to `bun build --compile`, but they had never been re-added. The release binaries shipped without those files in bunfs, so `legacy-pi-compat.ts` redirected `typebox` imports to a bunfs path that didn't exist. The two build scripts (release CI + local dev) now share `scripts/binary-entrypoints.ts` so the lists cannot drift apart, and `__resolveTypeBoxShimPath` mirrors `__validateLegacyPiPackageRootOverrides` (#2168) by dropping the override when the shim file is missing so future regressions fall through to native `node_modules` resolution instead of emitting a dead bunfs URL ([#3414](https://github.com/can1357/oh-my-pi/issues/3414)).
|
||||
- Fixed `omp install` of legacy pi extensions failing with `Cannot find module '/$bunfs/root/packages/coding-agent/src/extensibility/typebox.js'` on every released `omp-<platform>-<arch>` binary. Commit `dc5c93462f` removed worker entrypoints from `scripts/ci-release-build-binaries.ts`; the inline comment then claimed the legacy-shim and package-barrel entrypoints (`typebox.ts`, `legacy-pi-{ai,coding-agent}-shim.ts`, `packages/{agent,natives,tui,utils}/...`) were "still" passed to `bun build --compile`, but they had never been re-added. The release binaries shipped without those files in bunfs, so `legacy-pi-compat.ts` redirected `typebox` imports to a bunfs path that didn't exist. `__resolveTypeBoxShimPath` now mirrors `__validateLegacyPiPackageRootOverrides` (#2168) by dropping the override when the shim file is missing, so a missing shim falls through to native `node_modules` resolution instead of emitting a dead bunfs URL ([#3414](https://github.com/can1357/oh-my-pi/issues/3414)).
|
||||
|
||||
- Fixed every legacy `@(scope)/pi-*` and `@sinclair/typebox` import failing to load on the `omp-darwin-arm64` release binary (and any other `omp` built with Bun 1.3.14). `__validateLegacyPiPackageRootOverrides` and the `rewriteLegacyPiImports` emit path both depended on `--compile` extras being reachable as `/$bunfs/root/...` filesystem entries, but Bun 1.3.14 stopped exposing them through every API (`fs.existsSync`, `Bun.file().exists()`, `Bun.resolveSync`, `await import()` on the bunfs path or its `file://` URL all fail; only `/$bunfs/root/<binary-name>` itself answers). `legacy-pi-compat.ts` now keeps a JS-heap reference to every bundled pi-* surface in a lazy-loaded sibling `legacy-pi-bundled-registry.ts` and serves them through an `omp-legacy-pi-bundled:` virtual namespace whose `Bun.plugin().onLoad` returns synthetic re-exports — no bunfs path ever leaves the module in compiled mode, and dev / source-link / installed-package modes keep the historical `file://` rewrite. The matching `--compile` extras in `scripts/build-binary.ts`, the shared `scripts/binary-entrypoints.ts` list, and the dead `BUNFS_PACKAGE_ROOT` / `bunfsPath` / `__computeBunfsPackageRoot` / `__joinBunfsPath` helpers are gone. ([#3423](https://github.com/can1357/oh-my-pi/issues/3423))
|
||||
|
||||
## [16.1.17] - 2026-06-24
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
import { createRequire } from "node:module";
|
||||
import * as path from "node:path";
|
||||
import { LEGACY_COMPAT_BUILD_ENTRYPOINTS } from "../../../scripts/binary-entrypoints";
|
||||
|
||||
const packageDir = path.join(import.meta.dir, "..");
|
||||
const repoRoot = path.join(packageDir, "..", "..");
|
||||
@@ -83,7 +82,15 @@ async function main(): Promise<void> {
|
||||
"--root",
|
||||
".",
|
||||
"./packages/coding-agent/src/cli.ts",
|
||||
...LEGACY_COMPAT_BUILD_ENTRYPOINTS,
|
||||
// Legacy pi-* extension compat surfaces (host packages + shims)
|
||||
// were previously listed as explicit `--compile` entries so the
|
||||
// rewrite path could emit `/$bunfs/root/...` URLs against them.
|
||||
// Bun 1.3.14 made bunfs files unreachable at runtime (issue
|
||||
// #3423), so `legacy-pi-compat.ts` now serves them through a
|
||||
// virtual namespace backed by `legacy-pi-bundled-registry.ts`,
|
||||
// which static-imports each surface — the bundler already
|
||||
// includes them via the main module graph, so no `--compile`
|
||||
// extras are required.
|
||||
"--outfile",
|
||||
`packages/coding-agent/dist/${outName}`,
|
||||
],
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* Static handles on every bundled `@oh-my-pi/pi-*` surface a legacy extension
|
||||
* may import. Loaded lazily by `legacy-pi-compat.ts` in compiled-binary mode
|
||||
* (issue #3423) and re-exported through the `omp-legacy-pi-bundled:` virtual
|
||||
* namespace — bunfs paths cannot be resolved at runtime on Bun 1.3.14+, so
|
||||
* the only way to re-route extension imports onto the host's in-process copy
|
||||
* is via live module references captured at compile time.
|
||||
*
|
||||
* This module is split out from `legacy-pi-compat.ts` so dev/test runs that
|
||||
* touch the compat layer never trigger the cascade through
|
||||
* `legacy-pi-coding-agent-shim.ts → ../index → export/html/...` (which
|
||||
* requires generated artifacts that only exist after a `bun run build`).
|
||||
*
|
||||
* The bundler reaches every entry below via standard static-import analysis,
|
||||
* so the matching `--compile` extras can be dropped from
|
||||
* `scripts/build-binary.ts`.
|
||||
*/
|
||||
import * as bundledPiAgentCore from "@oh-my-pi/pi-agent-core";
|
||||
import * as bundledPiNatives from "@oh-my-pi/pi-natives";
|
||||
import * as bundledPiTui from "@oh-my-pi/pi-tui";
|
||||
import * as bundledPiUtils from "@oh-my-pi/pi-utils";
|
||||
import * as bundledLegacyPiAiShim from "../legacy-pi-ai-shim";
|
||||
import * as bundledLegacyPiCodingAgentShim from "../legacy-pi-coding-agent-shim";
|
||||
import * as bundledTypeBoxShim from "../typebox";
|
||||
|
||||
/**
|
||||
* Canonical specifier → live module namespace. Keys MUST match the right-hand
|
||||
* side of `bundledRegistryVirtualSpecifier(...)` calls in
|
||||
* `legacy-pi-compat.ts`; the synthesizer enumerates each namespace's own
|
||||
* enumerable exports at extension load time.
|
||||
*/
|
||||
export const BUNDLED_PI_REGISTRY: Readonly<Record<string, Readonly<Record<string, unknown>>>> = {
|
||||
"@oh-my-pi/pi-agent-core": bundledPiAgentCore,
|
||||
"@oh-my-pi/pi-ai": bundledLegacyPiAiShim,
|
||||
"@oh-my-pi/pi-coding-agent": bundledLegacyPiCodingAgentShim,
|
||||
"@oh-my-pi/pi-natives": bundledPiNatives,
|
||||
"@oh-my-pi/pi-tui": bundledPiTui,
|
||||
"@oh-my-pi/pi-utils": bundledPiUtils,
|
||||
typebox: bundledTypeBoxShim,
|
||||
};
|
||||
@@ -5,6 +5,156 @@ import { isCompiledBinary } from "@oh-my-pi/pi-utils";
|
||||
|
||||
const IS_COMPILED_BINARY = isCompiledBinary();
|
||||
|
||||
// === Bundled host-package registry (issue #3423) ===
|
||||
//
|
||||
// Bun 1.3.14 stopped exposing `--compile` extras through any filesystem-style
|
||||
// API: `fs.existsSync`, `Bun.file().exists()`, `Bun.resolveSync`, and even
|
||||
// `import("/$bunfs/...")` / `import("file:///$bunfs/...")` all fail for the
|
||||
// embedded entries — only the main binary itself answers from
|
||||
// `/$bunfs/root/<binary-name>`. The previous strategy of rewriting
|
||||
// `@(scope)/pi-*` imports to a `file:///$bunfs/...` URL therefore breaks
|
||||
// every legacy extension in compiled mode (issue #3423; see also issues
|
||||
// #3329, #2168). Bun.plugin `onResolve` for bare specifiers also no longer
|
||||
// fires for transitive imports inside runtime-loaded extensions, so the
|
||||
// fallback hook in `installLegacyPiSpecifierShim()` cannot rescue them.
|
||||
//
|
||||
// Instead we keep a JS-heap reference to every bundled pi-* surface (the
|
||||
// canonical host packages and the legacy shims) and re-export them through a
|
||||
// Bun.plugin `onLoad` against a custom namespace. Extension source rewrites
|
||||
// emit `omp-legacy-pi-bundled:<key>` specifiers that the synthetic loader
|
||||
// resolves against the registry — no bunfs path ever leaves this module in
|
||||
// compiled mode. Dev / source-link / installed-package modes keep the
|
||||
// historical `file://` rewrite (the source files exist on disk and load fine
|
||||
// through Bun's standard URL loader).
|
||||
//
|
||||
// The registry lives in a sibling file (`legacy-pi-bundled-registry.ts`)
|
||||
// loaded via a conditional dynamic import: its transitive deps include the
|
||||
// coding-agent root which pulls in generated artifacts (e.g.
|
||||
// `export/html/tool-views.generated.js`) that only exist after a build, so a
|
||||
// static import would crash every dev/test run that touches
|
||||
// `legacy-pi-compat.ts`. This is the documented "conditional platform code"
|
||||
// exception to the static-import rule.
|
||||
const BUNDLED_VIRTUAL_SCHEME = "omp-legacy-pi-bundled:";
|
||||
const BUNDLED_VIRTUAL_NAMESPACE = "omp-legacy-pi-bundled";
|
||||
const BUNDLED_REGISTRY_GLOBAL = "__ompLegacyPiBundledRegistry";
|
||||
const TYPEBOX_BUNDLED_REGISTRY_KEY = "typebox";
|
||||
|
||||
type BundledRegistry = Readonly<Record<string, Readonly<Record<string, unknown>>>>;
|
||||
|
||||
let bundledRegistryPromise: Promise<BundledRegistry> | null = null;
|
||||
|
||||
/**
|
||||
* Lazy-load the bundled host-package registry and stash it on `globalThis`
|
||||
* for the synthetic loader emitted by `synthesizeBundledModuleSource`. The
|
||||
* dynamic import is gated by `IS_COMPILED_BINARY` so dev/test runs (where
|
||||
* the registry's transitive deps include build-time-generated artifacts)
|
||||
* never trigger the cascade.
|
||||
*/
|
||||
function ensureBundledRegistryLoaded(): Promise<BundledRegistry> {
|
||||
if (!IS_COMPILED_BINARY) {
|
||||
return Promise.reject(
|
||||
new Error("omp:legacy-pi-shim: bundled registry is only available in compiled-binary mode"),
|
||||
);
|
||||
}
|
||||
if (!bundledRegistryPromise) {
|
||||
bundledRegistryPromise = import("./legacy-pi-bundled-registry").then(m => {
|
||||
(globalThis as Record<string, unknown>)[BUNDLED_REGISTRY_GLOBAL] = m.BUNDLED_PI_REGISTRY;
|
||||
return m.BUNDLED_PI_REGISTRY;
|
||||
});
|
||||
}
|
||||
return bundledRegistryPromise;
|
||||
}
|
||||
|
||||
function bundledRegistryVirtualSpecifier(registryKey: string): string {
|
||||
return `${BUNDLED_VIRTUAL_SCHEME}${registryKey}`;
|
||||
}
|
||||
|
||||
function isBundledVirtualSpecifier(value: string): boolean {
|
||||
return value.startsWith(BUNDLED_VIRTUAL_SCHEME);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the synthetic ES module source for a `omp-legacy-pi-bundled:<key>`
|
||||
* import against an explicit registry. Pure: takes the live module namespace
|
||||
* and emits a string of ES exports rooted in `globalThis[BUNDLED_REGISTRY_GLOBAL]`.
|
||||
* `synthesizeBundledModuleSource` wraps this with the lazy registry load —
|
||||
* tests use this sync helper directly to assert export-shape preservation.
|
||||
*/
|
||||
function synthesizeBundledModuleSourceFromRegistry(registryKey: string, registry: BundledRegistry): string {
|
||||
const mod = registry[registryKey];
|
||||
if (!mod) {
|
||||
throw new Error(`omp:legacy-pi-shim: no bundled module registered for ${registryKey}`);
|
||||
}
|
||||
const lines: string[] = [
|
||||
`const __omp_bundled = globalThis[${JSON.stringify(BUNDLED_REGISTRY_GLOBAL)}][${JSON.stringify(registryKey)}];`,
|
||||
];
|
||||
let hasDefault = false;
|
||||
for (const exportName in mod) {
|
||||
if (exportName === "default") {
|
||||
hasDefault = true;
|
||||
continue;
|
||||
}
|
||||
lines.push(`export const ${exportName} = __omp_bundled[${JSON.stringify(exportName)}];`);
|
||||
}
|
||||
if (hasDefault) {
|
||||
lines.push("export default __omp_bundled.default;");
|
||||
}
|
||||
lines.push("");
|
||||
return lines.join("\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the synthetic ES module source served for an
|
||||
* `omp-legacy-pi-bundled:<key>` import. Enumerates the live module namespace
|
||||
* so legacy extensions see the same named/default exports they would have
|
||||
* gotten from a real `file://` load — without touching the inaccessible bunfs
|
||||
* filesystem.
|
||||
*/
|
||||
async function synthesizeBundledModuleSource(registryKey: string): Promise<string> {
|
||||
const registry = await ensureBundledRegistryLoaded();
|
||||
return synthesizeBundledModuleSourceFromRegistry(registryKey, registry);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test seam: lazily loads the canonical-specifier → live module registry used
|
||||
* by the compiled-binary virtual loader. The synthesizer enumerates this at
|
||||
* extension load time, so the test only needs to confirm registry shape +
|
||||
* identity. In non-compiled mode this rejects — callers MUST guard.
|
||||
*/
|
||||
export function __getLegacyPiBundledRegistry(): Promise<BundledRegistry> {
|
||||
return ensureBundledRegistryLoaded();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test seam: builds the synthetic ES module source for a virtual specifier
|
||||
* against an explicit registry. Pure (no globalThis read); the emitted source
|
||||
* still routes runtime lookups through `globalThis[BUNDLED_REGISTRY_GLOBAL]`.
|
||||
*/
|
||||
export function __synthesizeLegacyPiBundledSourceWithRegistry(
|
||||
registryKey: string,
|
||||
registry: Readonly<Record<string, Readonly<Record<string, unknown>>>>,
|
||||
): string {
|
||||
return synthesizeBundledModuleSourceFromRegistry(registryKey, registry);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test seam: returns the synthetic ES module source served for a virtual
|
||||
* specifier. Convenience wrapper around the lazy registry load + synth path
|
||||
* for tests that already run in compiled-binary mode.
|
||||
*/
|
||||
export function __synthesizeLegacyPiBundledSource(registryKey: string): Promise<string> {
|
||||
return synthesizeBundledModuleSource(registryKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test seam: returns the globalThis key the synthetic loader reads from. Tests
|
||||
* assert that the emitted source addresses the exact stash key the install
|
||||
* function writes to, so a rename can't break extension loads silently.
|
||||
*/
|
||||
export function __getLegacyPiBundledRegistryGlobal(): string {
|
||||
return BUNDLED_REGISTRY_GLOBAL;
|
||||
}
|
||||
|
||||
// Canonical scope for in-process pi packages. Plugins published against any of
|
||||
// the aliased scopes below (mariozechner's original publish, earendil-works'
|
||||
// fork, or the canonical @oh-my-pi scope itself) are remapped to this scope and
|
||||
@@ -73,57 +223,14 @@ const PACKAGE_IMPORT_EXCLUDED = Symbol("packageImportExcluded");
|
||||
// not provide and plugins relying on them must vendor TypeBox directly.
|
||||
const TYPEBOX_SPECIFIER_FILTER = /^(?:@sinclair\/typebox|typebox)$/;
|
||||
|
||||
// Compat shim and bundled-package paths used in compiled-binary mode. The shim
|
||||
// paths must point at files that ship inside the bunfs root; in dev /
|
||||
// source-link / installed-package mode the canonical specifier resolves via
|
||||
// `Bun.resolveSync` so only the shim files need explicit paths there.
|
||||
//
|
||||
// `BUNFS_PACKAGE_ROOT` is derived from `import.meta.dir` rather than hardcoded
|
||||
// as `/$bunfs/root/packages` so the prefix stays platform-native: on Windows
|
||||
// the bunfs mount appears as `<drive>:\~BUN\root\…` (see oven-sh/bun#15766),
|
||||
// and a hardcoded POSIX literal would normalize to `\$bunfs\root\…` and fail
|
||||
// to resolve. Compiled Bun modules currently report the bunfs root itself from
|
||||
// `import.meta.dir`, so appending `packages` lands on the `--root ../..`
|
||||
// package directory used by `scripts/build-binary.ts`.
|
||||
//
|
||||
// Every shim listed below must also be registered as an explicit `--compile`
|
||||
// entrypoint in `scripts/build-binary.ts` or release builds fail with
|
||||
// missing-module errors. Non-shim bundled packages are resolved via
|
||||
// `Bun.resolveSync` (see `resolveCanonicalPiSpecifier`) outside compiled mode,
|
||||
// so they keep working when on-disk layout differs from the monorepo tree.
|
||||
/**
|
||||
* Compute the bunfs package root from the compiled binary's `import.meta.dir`
|
||||
* (or any stand-in supplied by tests). Bun compiled binaries report one of:
|
||||
*
|
||||
* - the bunfs mount root itself — `/$bunfs/root` or `<drive>:\~BUN\root` (Bun
|
||||
* 1.2.x and early 1.3.x). Append `packages` for the canonical layout.
|
||||
* - the bunfs mount root followed by the binary's basename — `//root/<bin>`
|
||||
* on POSIX or `<drive>:\~BUN\root\<bin>.exe` on Windows (observed on Bun
|
||||
* 1.3.14 with the cross-compiled `omp-darwin-arm64` release asset — issue
|
||||
* #3329). The trailing segment is stripped so the result still lands on
|
||||
* `<root>/packages`.
|
||||
* - the module's own source directory if a future Bun release switches to
|
||||
* module-specific `import.meta.dir` values:
|
||||
* `<bunfs>/packages/coding-agent/src/extensibility/plugins`.
|
||||
* The bunfs-root-with-binary branch slices the original `metaDir`, and
|
||||
* `bunfsPath` uses a matching double-slash-preserving join, so the bunfs-native
|
||||
* prefix is preserved verbatim — `path.posix.join` collapses `//root` to
|
||||
* `/root`, but Bun's bunfs lookup is keyed on the exact `//root` form.
|
||||
*
|
||||
* Exported for tests; production callers use `BUNFS_PACKAGE_ROOT` below.
|
||||
*/
|
||||
export function __computeBunfsPackageRoot(metaDir: string, pathImpl: typeof path = path): string {
|
||||
const pluginsDirSuffix = pathImpl.join("packages", "coding-agent", "src", "extensibility", "plugins");
|
||||
const normalizedMetaDir = pathImpl.normalize(metaDir);
|
||||
if (normalizedMetaDir.endsWith(pluginsDirSuffix)) {
|
||||
return pathImpl.resolve(metaDir, "..", "..", "..", "..");
|
||||
}
|
||||
const parent = pathImpl.dirname(metaDir);
|
||||
if (pathImpl.basename(pathImpl.normalize(parent)) === "root") {
|
||||
return `${parent + pathImpl.sep}packages`;
|
||||
}
|
||||
return pathImpl.join(metaDir, "packages");
|
||||
}
|
||||
// Compat-shim path resolution. In compiled-binary mode every bundled surface
|
||||
// is served through the `omp-legacy-pi-bundled:` virtual namespace (see the
|
||||
// registry block above) — bunfs paths are unreachable on Bun 1.3.14+, so the
|
||||
// pre-#3423 helpers that derived `/$bunfs/root/...` paths from
|
||||
// `import.meta.dir` are gone. Dev / source-link / installed-package modes
|
||||
// still need a real filesystem path for the source shims, which
|
||||
// `sourceShimPath` computes either from the npm prebuilt `dist/cli.js`
|
||||
// bundle (`PI_BUNDLED=true`) or directly from the monorepo source tree.
|
||||
|
||||
/**
|
||||
* Compute the package root for the npm prebuilt `dist/cli.js` bundle.
|
||||
@@ -147,35 +254,6 @@ export function __computeBundledSelfPackageRoot(metaDir: string, pathImpl: typeo
|
||||
return pathImpl.resolve(metaDir);
|
||||
}
|
||||
|
||||
const BUNFS_PACKAGE_ROOT = IS_COMPILED_BINARY ? __computeBunfsPackageRoot(import.meta.dir) : null;
|
||||
|
||||
/**
|
||||
* Join a computed bunfs package root with descendants without collapsing
|
||||
* Bun's POSIX `//root` mount prefix.
|
||||
*
|
||||
* Exported for tests; production callers use `bunfsPath` below.
|
||||
*/
|
||||
export function __joinBunfsPath(root: string, segments: readonly string[], pathImpl: typeof path = path): string {
|
||||
const joined = pathImpl.join(root, ...segments);
|
||||
const doubleRootPrefix = pathImpl.sep + pathImpl.sep;
|
||||
const tripleRootPrefix = doubleRootPrefix + pathImpl.sep;
|
||||
if (
|
||||
root.startsWith(doubleRootPrefix) &&
|
||||
!root.startsWith(tripleRootPrefix) &&
|
||||
!joined.startsWith(doubleRootPrefix)
|
||||
) {
|
||||
return pathImpl.sep + joined;
|
||||
}
|
||||
return joined;
|
||||
}
|
||||
|
||||
function bunfsPath(...segments: string[]): string {
|
||||
if (!BUNFS_PACKAGE_ROOT) {
|
||||
throw new Error("bunfsPath is only valid in compiled-binary mode");
|
||||
}
|
||||
return __joinBunfsPath(BUNFS_PACKAGE_ROOT, segments);
|
||||
}
|
||||
|
||||
function resolveBundledSelfPackageRoot(): string | undefined {
|
||||
if (!process.env.PI_BUNDLED) return undefined;
|
||||
return __computeBundledSelfPackageRoot(import.meta.dir);
|
||||
@@ -190,34 +268,35 @@ function sourceShimPath(file: string): string {
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the path the TypeBox compatibility shim ships at — bunfs in compiled
|
||||
* mode, on-disk source elsewhere — then drop it when the file is missing.
|
||||
* Resolve the path the TypeBox compatibility shim ships at, then drop it when
|
||||
* the source file is missing.
|
||||
*
|
||||
* Validation mirrors `__validateLegacyPiPackageRootOverrides` (#2168): if the
|
||||
* computed candidate doesn't exist (e.g. a release build silently omitted the
|
||||
* `--compile` entrypoint — issue #3414), `resolveTypeBoxSpecifier` returns
|
||||
* `undefined` and `rewriteLegacyExtensionSource` leaves bare `typebox` /
|
||||
* `@sinclair/typebox` specifiers alone, so Bun falls through to native
|
||||
* resolution against the extension's own `node_modules`.
|
||||
* In compiled-binary mode the shim is served through the
|
||||
* `omp-legacy-pi-bundled:` virtual namespace (issue #3423) — bunfs paths are
|
||||
* unreachable on Bun 1.3.14+, so the virtual specifier is always available and
|
||||
* needs no filesystem probe. In dev / source-link / installed-package mode the
|
||||
* shim is an on-disk source file; validation mirrors
|
||||
* `__validateLegacyPiPackageRootOverrides` (#2168): if the computed candidate
|
||||
* doesn't exist (e.g. an install that dropped the source — issue #3414),
|
||||
* `resolveTypeBoxSpecifier` returns `undefined` and
|
||||
* `rewriteLegacyExtensionSource` leaves bare `typebox` / `@sinclair/typebox`
|
||||
* specifiers alone, so Bun falls through to native resolution against the
|
||||
* extension's own `node_modules`.
|
||||
*
|
||||
* Exported for tests; production callers use `TYPEBOX_SHIM_PATH`.
|
||||
*/
|
||||
export function __resolveTypeBoxShimPath(
|
||||
bunfsRoot: string | null,
|
||||
bundledSelfRoot: string | undefined,
|
||||
metaDir: string,
|
||||
isCompiled: boolean,
|
||||
sourcePath: string,
|
||||
pathExistsSync: (p: string) => boolean = fs.existsSync,
|
||||
pathImpl: typeof path = path,
|
||||
): string | null {
|
||||
const candidate = bunfsRoot
|
||||
? __joinBunfsPath(bunfsRoot, ["coding-agent", "src", "extensibility", "typebox.js"], pathImpl)
|
||||
: bundledSelfRoot
|
||||
? pathImpl.join(bundledSelfRoot, "src", "extensibility", "typebox.ts")
|
||||
: pathImpl.resolve(metaDir, "..", "typebox.ts");
|
||||
return pathExistsSync(candidate) ? candidate : null;
|
||||
if (isCompiled) {
|
||||
return bundledRegistryVirtualSpecifier(TYPEBOX_BUNDLED_REGISTRY_KEY);
|
||||
}
|
||||
return pathExistsSync(sourcePath) ? sourcePath : null;
|
||||
}
|
||||
|
||||
const TYPEBOX_SHIM_PATH = __resolveTypeBoxShimPath(BUNFS_PACKAGE_ROOT, BUNDLED_SELF_PACKAGE_ROOT, import.meta.dir);
|
||||
const TYPEBOX_SHIM_PATH = __resolveTypeBoxShimPath(IS_COMPILED_BINARY, sourceShimPath("typebox.ts"));
|
||||
|
||||
// Legacy extensions historically imported `Type` (and `Static`/`TSchema`) from
|
||||
// the package root of `@(scope)/pi-ai`. pi-ai 15.1.0 removed the runtime `Type`
|
||||
@@ -227,59 +306,67 @@ const TYPEBOX_SHIM_PATH = __resolveTypeBoxShimPath(BUNFS_PACKAGE_ROOT, BUNDLED_S
|
||||
// plus the borrowed `Type` runtime from the Zod-backed TypeBox shim. Subpath
|
||||
// imports such as `@oh-my-pi/pi-ai/oauth` continue to resolve directly
|
||||
// against the bundled pi-ai package.
|
||||
const LEGACY_PI_AI_SHIM_PATH = BUNFS_PACKAGE_ROOT
|
||||
? bunfsPath("coding-agent", "src", "extensibility", "legacy-pi-ai-shim.js")
|
||||
const LEGACY_PI_AI_SHIM_PATH = IS_COMPILED_BINARY
|
||||
? bundledRegistryVirtualSpecifier(`${CANONICAL_PI_SCOPE}/pi-ai`)
|
||||
: sourceShimPath("legacy-pi-ai-shim.ts");
|
||||
|
||||
// The coding-agent's own `./src/index.ts` cannot be listed as an extra
|
||||
// `bun --compile` entrypoint alongside the CLI entry without breaking binary
|
||||
// startup (issue #1474 follow-up). Legacy `@(scope)/pi-coding-agent` root
|
||||
// imports therefore resolve through a sibling shim whose distinct file path
|
||||
// avoids that collision while re-exporting the canonical package surface.
|
||||
const LEGACY_PI_CODING_AGENT_SHIM_PATH = BUNFS_PACKAGE_ROOT
|
||||
? bunfsPath("coding-agent", "src", "extensibility", "legacy-pi-coding-agent-shim.js")
|
||||
// startup (issue #1474 follow-up). In compiled-binary mode the legacy
|
||||
// `@(scope)/pi-coding-agent` root therefore resolves through the bundled
|
||||
// registry shim; in dev / source-link / installed-package mode it points at
|
||||
// the sibling source shim whose distinct file path avoids the #1474 collision
|
||||
// while still re-exporting the canonical package surface.
|
||||
const LEGACY_PI_CODING_AGENT_SHIM_PATH = IS_COMPILED_BINARY
|
||||
? bundledRegistryVirtualSpecifier(`${CANONICAL_PI_SCOPE}/pi-coding-agent`)
|
||||
: sourceShimPath("legacy-pi-coding-agent-shim.ts");
|
||||
|
||||
// Package-root overrides. Shim entries are always applied because they replace
|
||||
// (or augment) the canonical surface even in non-compiled installs. The bunfs
|
||||
// entries are added only in compiled-binary mode — in dev / source-link /
|
||||
// installed-package mode the canonical specifier resolves cleanly through
|
||||
// `Bun.resolveSync`, and hardcoding a relative source-tree path would break
|
||||
// installs where the bundled packages live at `node_modules/@oh-my-pi/pi-*`
|
||||
// rather than `packages/*`.
|
||||
// Package-root overrides. Shim entries (`pi-ai`, `pi-coding-agent`) always
|
||||
// replace the canonical surface so the legacy `Type` runtime and the legacy
|
||||
// helpers stay reachable. The bundled host packages (`pi-agent-core`,
|
||||
// `pi-natives`, `pi-tui`, `pi-utils`) are added only in compiled-binary mode
|
||||
// to route extensions onto the in-process module instance — in dev /
|
||||
// source-link / installed-package mode the canonical specifier resolves
|
||||
// cleanly through `Bun.resolveSync` and hardcoding a source-tree path would
|
||||
// miss installs where the bundled packages live at `node_modules/@oh-my-pi/pi-*`.
|
||||
//
|
||||
// Every override target is validated against the on-disk filesystem at module
|
||||
// init: any entry whose file is missing (e.g. a compiled binary where Bun's
|
||||
// `--compile` quietly dropped an additional entrypoint — issue #2168) is left
|
||||
// out so `resolveCanonicalPiSpecifier` falls through to `getResolvedSpecifier`,
|
||||
// which throws under bunfs and triggers the catch in `rewriteLegacyPiImports`.
|
||||
// That catch leaves the specifier untouched so Bun resolves the canonical
|
||||
// `@oh-my-pi/pi-*` import from the extension's own `node_modules` instead of
|
||||
// emitting a bunfs `file://` URL to a module that isn't actually present.
|
||||
// Compiled-binary entries are `omp-legacy-pi-bundled:<key>` specifiers handed
|
||||
// to the synthetic onLoad in `installLegacyPiSpecifierShim()` — bunfs paths
|
||||
// are unusable on Bun 1.3.14+ (issue #3423). Filesystem-shaped overrides are
|
||||
// still validated against on-disk presence so a missing dev-mode shim falls
|
||||
// through to `getResolvedSpecifier`.
|
||||
|
||||
/**
|
||||
* Drop overrides whose targets are missing on disk so they can fall through to
|
||||
* the canonical-resolution path. Exported for the test seam in #2168.
|
||||
* Drop overrides whose filesystem targets are missing so they can fall
|
||||
* through to the canonical-resolution path. Virtual `omp-legacy-pi-bundled:`
|
||||
* entries always pass — the bundled registry is the source of truth in
|
||||
* compiled-binary mode where bunfs paths are unreachable (issue #3423).
|
||||
*
|
||||
* `pathExistsSync` defaults to `fs.existsSync`; the tests inject a stub to
|
||||
* `pathExistsSync` defaults to `fs.existsSync`; tests inject a stub to
|
||||
* simulate the missing-entrypoint failure mode without touching the real FS.
|
||||
*/
|
||||
export function __validateLegacyPiPackageRootOverrides(
|
||||
candidates: Record<string, string>,
|
||||
pathExistsSync: (p: string) => boolean = fs.existsSync,
|
||||
): Record<string, string> {
|
||||
return Object.fromEntries(Object.entries(candidates).filter(([, candidate]) => pathExistsSync(candidate)));
|
||||
return Object.fromEntries(
|
||||
Object.entries(candidates).filter(
|
||||
([, candidate]) => isBundledVirtualSpecifier(candidate) || pathExistsSync(candidate),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
const LEGACY_PI_PACKAGE_ROOT_OVERRIDES = __validateLegacyPiPackageRootOverrides({
|
||||
[`${CANONICAL_PI_SCOPE}/pi-ai`]: LEGACY_PI_AI_SHIM_PATH,
|
||||
[`${CANONICAL_PI_SCOPE}/pi-coding-agent`]: LEGACY_PI_CODING_AGENT_SHIM_PATH,
|
||||
...(BUNFS_PACKAGE_ROOT
|
||||
...(IS_COMPILED_BINARY
|
||||
? {
|
||||
[`${CANONICAL_PI_SCOPE}/pi-agent-core`]: bunfsPath("agent", "src", "index.js"),
|
||||
[`${CANONICAL_PI_SCOPE}/pi-natives`]: bunfsPath("natives", "native", "index.js"),
|
||||
[`${CANONICAL_PI_SCOPE}/pi-tui`]: bunfsPath("tui", "src", "index.js"),
|
||||
[`${CANONICAL_PI_SCOPE}/pi-utils`]: bunfsPath("utils", "src", "index.js"),
|
||||
[`${CANONICAL_PI_SCOPE}/pi-agent-core`]: bundledRegistryVirtualSpecifier(
|
||||
`${CANONICAL_PI_SCOPE}/pi-agent-core`,
|
||||
),
|
||||
[`${CANONICAL_PI_SCOPE}/pi-natives`]: bundledRegistryVirtualSpecifier(`${CANONICAL_PI_SCOPE}/pi-natives`),
|
||||
[`${CANONICAL_PI_SCOPE}/pi-tui`]: bundledRegistryVirtualSpecifier(`${CANONICAL_PI_SCOPE}/pi-tui`),
|
||||
[`${CANONICAL_PI_SCOPE}/pi-utils`]: bundledRegistryVirtualSpecifier(`${CANONICAL_PI_SCOPE}/pi-utils`),
|
||||
}
|
||||
: {}),
|
||||
});
|
||||
@@ -328,6 +415,12 @@ function resolveCanonicalPiSpecifier(remappedSpecifier: string): string {
|
||||
}
|
||||
|
||||
function toImportSpecifier(resolvedPath: string): string {
|
||||
// Virtual `omp-legacy-pi-bundled:` specifiers are served by the synthetic
|
||||
// onLoad in `installLegacyPiSpecifierShim()`; wrapping them as `file://`
|
||||
// would corrupt the scheme and bypass the bundled registry.
|
||||
if (isBundledVirtualSpecifier(resolvedPath)) {
|
||||
return resolvedPath;
|
||||
}
|
||||
return url.pathToFileURL(resolvedPath).href;
|
||||
}
|
||||
|
||||
@@ -765,6 +858,12 @@ export function installLegacyPiSpecifierShim(): void {
|
||||
setup(build) {
|
||||
build.onResolve({ filter: LEGACY_PI_SPECIFIER_FILTER, namespace: "file" }, resolveLegacyPiSpecifier);
|
||||
build.onResolve({ filter: TYPEBOX_SPECIFIER_FILTER, namespace: "file" }, resolveTypeBoxSpecifier);
|
||||
// Compiled-binary mode: serve `omp-legacy-pi-bundled:<key>` imports
|
||||
// from the JS-heap registry. The rewrite path emits these specifiers
|
||||
// in place of unreachable `file:///$bunfs/...` URLs (issue #3423).
|
||||
build.onLoad({ filter: /.*/, namespace: BUNDLED_VIRTUAL_NAMESPACE }, async args => {
|
||||
return { contents: await synthesizeBundledModuleSource(args.path), loader: "js" };
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
import { describe, expect, it } from "bun:test";
|
||||
import {
|
||||
__getLegacyPiBundledRegistryGlobal,
|
||||
__synthesizeLegacyPiBundledSourceWithRegistry,
|
||||
} from "@oh-my-pi/pi-coding-agent/extensibility/plugins/legacy-pi-compat";
|
||||
|
||||
// Regression for issue #3423: Bun 1.3.14 made `--compile` extras unreachable
|
||||
// via every filesystem-style API, so `legacy-pi-compat.ts` now routes
|
||||
// canonical `@oh-my-pi/pi-*` imports through a virtual specifier whose body
|
||||
// re-exports a live registry entry from `globalThis`. The synthesizer must
|
||||
// preserve every named export (and a default if present) so legacy
|
||||
// extensions see the same surface they would have through a real `file://`
|
||||
// load — otherwise `import { foo } from "@oh-my-pi/pi-coding-agent"` raises
|
||||
// `Export named 'foo' not found in module ...`.
|
||||
describe("legacy-pi bundled virtual module synthesizer (issue #3423)", () => {
|
||||
const registry = {
|
||||
"@oh-my-pi/pi-coding-agent": {
|
||||
VERSION: "16.1.17",
|
||||
defineTool: () => undefined,
|
||||
Type: { Object: () => undefined },
|
||||
},
|
||||
"@oh-my-pi/pi-utils": {
|
||||
isCompiledBinary: () => false,
|
||||
default: () => "default-export",
|
||||
VERSION: "16.1.17",
|
||||
},
|
||||
typebox: {
|
||||
Type: { Object: () => undefined },
|
||||
},
|
||||
};
|
||||
const globalKey = __getLegacyPiBundledRegistryGlobal();
|
||||
|
||||
it("emits one ES named export per enumerable namespace key", () => {
|
||||
const src = __synthesizeLegacyPiBundledSourceWithRegistry("@oh-my-pi/pi-coding-agent", registry);
|
||||
expect(src).toContain(
|
||||
`const __omp_bundled = globalThis[${JSON.stringify(globalKey)}]["@oh-my-pi/pi-coding-agent"];`,
|
||||
);
|
||||
expect(src).toContain('export const VERSION = __omp_bundled["VERSION"];');
|
||||
expect(src).toContain('export const defineTool = __omp_bundled["defineTool"];');
|
||||
expect(src).toContain('export const Type = __omp_bundled["Type"];');
|
||||
// Every named export emerges from a live registry lookup — never the FS.
|
||||
expect(src).not.toMatch(/\$bunfs|file:\/\//);
|
||||
});
|
||||
|
||||
it("forwards `default` through `export default` so default imports survive", () => {
|
||||
const src = __synthesizeLegacyPiBundledSourceWithRegistry("@oh-my-pi/pi-utils", registry);
|
||||
expect(src).toContain("export default __omp_bundled.default;");
|
||||
// Default and named exports coexist on the same module.
|
||||
expect(src).toContain('export const VERSION = __omp_bundled["VERSION"];');
|
||||
expect(src).toContain('export const isCompiledBinary = __omp_bundled["isCompiledBinary"];');
|
||||
});
|
||||
|
||||
it("omits `default` line when the registered namespace has no default export", () => {
|
||||
const src = __synthesizeLegacyPiBundledSourceWithRegistry("@oh-my-pi/pi-coding-agent", registry);
|
||||
expect(src).not.toContain("export default");
|
||||
});
|
||||
|
||||
it("throws when asked to synthesize a key the registry does not cover", () => {
|
||||
expect(() => __synthesizeLegacyPiBundledSourceWithRegistry("@oh-my-pi/pi-not-bundled", registry)).toThrow(
|
||||
/no bundled module registered for @oh-my-pi\/pi-not-bundled/,
|
||||
);
|
||||
});
|
||||
|
||||
it("addresses the same globalThis key the install function would stash to", () => {
|
||||
// The emitted source MUST read from the exact key the install function
|
||||
// writes to — a rename of either side breaks every legacy extension
|
||||
// load with a `Cannot read properties of undefined` at first import.
|
||||
const src = __synthesizeLegacyPiBundledSourceWithRegistry("typebox", registry);
|
||||
expect(src.startsWith(`const __omp_bundled = globalThis[${JSON.stringify(globalKey)}]["typebox"];`)).toBe(true);
|
||||
});
|
||||
|
||||
it("end-to-end: synthesized source resolves named bindings against a runtime globalThis entry", () => {
|
||||
// Evaluate the synthesized source in isolation. Bun's loader normally
|
||||
// turns it into an ES module; here we use `new Function` to exercise
|
||||
// the inner globalThis lookup + property-getter pattern in isolation —
|
||||
// it would `throw` if the emitted code addressed the wrong stash key
|
||||
// or skipped an enumerable export.
|
||||
(globalThis as Record<string, unknown>)[globalKey] = registry;
|
||||
try {
|
||||
const src = __synthesizeLegacyPiBundledSourceWithRegistry("@oh-my-pi/pi-coding-agent", registry);
|
||||
// Strip the ES export prefix and run the body as a plain script so
|
||||
// we can read `__omp_bundled` from the returned closure.
|
||||
const body = src
|
||||
.split("\n")
|
||||
.filter(line => line.startsWith("const __omp_bundled"))
|
||||
.join("\n");
|
||||
const fn = new Function(`${body}; return __omp_bundled;`);
|
||||
const live = fn() as Record<string, unknown>;
|
||||
expect(live.VERSION).toBe("16.1.17");
|
||||
expect(typeof live.defineTool).toBe("function");
|
||||
expect(typeof live.Type).toBe("object");
|
||||
} finally {
|
||||
delete (globalThis as Record<string, unknown>)[globalKey];
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -1,85 +1,36 @@
|
||||
import { describe, expect, it } from "bun:test";
|
||||
import * as path from "node:path";
|
||||
import {
|
||||
__computeBundledSelfPackageRoot,
|
||||
__computeBunfsPackageRoot,
|
||||
__joinBunfsPath,
|
||||
} from "@oh-my-pi/pi-coding-agent/extensibility/plugins/legacy-pi-compat";
|
||||
|
||||
// Regression for issue #1514: legacy pi compat shim paths were built from a
|
||||
// hardcoded POSIX literal `/$bunfs/root/packages`. On Windows the bunfs root
|
||||
// mounts at `<drive>:\~BUN\root\…` (oven-sh/bun#15766) and the POSIX literal
|
||||
// normalises to `\$bunfs\root\…`, which is unresolvable. The fix derives the
|
||||
// package root from the compiled binary's `import.meta.dir`, so the host OS's
|
||||
// separators are preserved end-to-end.
|
||||
describe("legacy pi compat bunfs root computation (issue #1514)", () => {
|
||||
it("appends packages to the Windows-native compiled bunfs root", () => {
|
||||
const winMetaDir = "B:\\~BUN\\root";
|
||||
const root = __computeBunfsPackageRoot(winMetaDir, path.win32);
|
||||
expect(root).toBe("B:\\~BUN\\root\\packages");
|
||||
// The shim path joined from this root must still live under the bunfs
|
||||
// mount, never collapse onto the working drive (which is what
|
||||
// `path.win32.resolve("/$bunfs/root/packages/...")` would produce).
|
||||
expect(path.win32.join(root, "coding-agent", "src", "extensibility", "legacy-pi-ai-shim.js")).toBe(
|
||||
"B:\\~BUN\\root\\packages\\coding-agent\\src\\extensibility\\legacy-pi-ai-shim.js",
|
||||
);
|
||||
});
|
||||
|
||||
it("appends packages to the POSIX compiled bunfs root on Linux and macOS", () => {
|
||||
expect(__computeBunfsPackageRoot("/$bunfs/root", path.posix)).toBe("/$bunfs/root/packages");
|
||||
});
|
||||
|
||||
it("also supports module-specific import.meta.dir values if Bun changes compiled semantics", () => {
|
||||
const winMetaDir = "B:\\~BUN\\root\\packages\\coding-agent\\src\\extensibility\\plugins";
|
||||
expect(__computeBunfsPackageRoot(winMetaDir, path.win32)).toBe("B:\\~BUN\\root\\packages");
|
||||
const posixMetaDir = "/$bunfs/root/packages/coding-agent/src/extensibility/plugins";
|
||||
expect(__computeBunfsPackageRoot(posixMetaDir, path.posix)).toBe("/$bunfs/root/packages");
|
||||
});
|
||||
|
||||
it("preserves the double-slash bunfs prefix through production shim path joins (issue #3329)", () => {
|
||||
// Bun 1.3.14 on the cross-compiled `omp-darwin-arm64` release asset
|
||||
// reports `import.meta.dir` as `//root/omp-darwin-arm64`. The leading
|
||||
// `//` is part of Bun's bunfs identifier, so both the root computation
|
||||
// and the production shim-path join must preserve it.
|
||||
const root = __computeBunfsPackageRoot("//root/omp-darwin-arm64", path.posix);
|
||||
expect(root).toBe("//root/packages");
|
||||
expect(__joinBunfsPath(root, ["coding-agent", "src", "extensibility", "typebox.js"], path.posix)).toBe(
|
||||
"//root/packages/coding-agent/src/extensibility/typebox.js",
|
||||
);
|
||||
|
||||
// `$bunfs`-prefixed variant is also handled.
|
||||
expect(__computeBunfsPackageRoot("/$bunfs/root/omp", path.posix)).toBe("/$bunfs/root/packages");
|
||||
// Windows variant: bunfs mount at `<drive>:\~BUN\root` with the binary
|
||||
// basename appended.
|
||||
expect(__computeBunfsPackageRoot("B:\\~BUN\\root\\omp.exe", path.win32)).toBe("B:\\~BUN\\root\\packages");
|
||||
});
|
||||
|
||||
it("uses the current host path implementation for production calls", () => {
|
||||
const metaDir = path.join("/", "anywhere", "root");
|
||||
expect(__computeBunfsPackageRoot(metaDir)).toBe(path.join("/", "anywhere", "root", "packages"));
|
||||
});
|
||||
import { __computeBundledSelfPackageRoot } from "@oh-my-pi/pi-coding-agent/extensibility/plugins/legacy-pi-compat";
|
||||
|
||||
// Issue #3423 removed the runtime bunfs-path computation (`__computeBunfsPackageRoot`,
|
||||
// `__joinBunfsPath`, `bunfsPath`): Bun 1.3.14 stopped exposing `--compile`
|
||||
// extras through any filesystem API, so the compat layer now routes the
|
||||
// bundled host packages and shims through the `omp-legacy-pi-bundled:`
|
||||
// virtual namespace (see `legacy-pi-bundled-virtual.test.ts`). The bunfs
|
||||
// path computation is dead and its regression tests (issues #1514, #3329)
|
||||
// retired alongside the code.
|
||||
//
|
||||
// The npm-prebuilt `dist/cli.js` self-package-root computation is still in
|
||||
// use by `sourceShimPath` in installed-package mode, so its contract stays
|
||||
// pinned below.
|
||||
describe("legacy pi compat bundled-self package root computation", () => {
|
||||
it("derives the npm prebuilt bundle package root from dist import.meta.dir", () => {
|
||||
const computeBundledSelfPackageRoot = __computeBundledSelfPackageRoot;
|
||||
|
||||
const winMetaDir = "C:\\Users\\me\\.bun\\install\\global\\node_modules\\@oh-my-pi\\pi-coding-agent\\dist";
|
||||
expect(computeBundledSelfPackageRoot(winMetaDir, path.win32)).toBe(
|
||||
expect(__computeBundledSelfPackageRoot(winMetaDir, path.win32)).toBe(
|
||||
"C:\\Users\\me\\.bun\\install\\global\\node_modules\\@oh-my-pi\\pi-coding-agent",
|
||||
);
|
||||
|
||||
const posixMetaDir = "/home/me/.bun/install/global/node_modules/@oh-my-pi/pi-coding-agent/dist";
|
||||
expect(computeBundledSelfPackageRoot(posixMetaDir, path.posix)).toBe(
|
||||
expect(__computeBundledSelfPackageRoot(posixMetaDir, path.posix)).toBe(
|
||||
"/home/me/.bun/install/global/node_modules/@oh-my-pi/pi-coding-agent",
|
||||
);
|
||||
});
|
||||
|
||||
it("derives the source package root when PI_BUNDLED is used outside dist", () => {
|
||||
const computeBundledSelfPackageRoot = __computeBundledSelfPackageRoot;
|
||||
|
||||
const winMetaDir = "C:\\repo\\packages\\coding-agent\\src\\extensibility\\plugins";
|
||||
expect(computeBundledSelfPackageRoot(winMetaDir, path.win32)).toBe("C:\\repo\\packages\\coding-agent");
|
||||
expect(__computeBundledSelfPackageRoot(winMetaDir, path.win32)).toBe("C:\\repo\\packages\\coding-agent");
|
||||
|
||||
const posixMetaDir = "/repo/packages/coding-agent/src/extensibility/plugins";
|
||||
expect(computeBundledSelfPackageRoot(posixMetaDir, path.posix)).toBe("/repo/packages/coding-agent");
|
||||
expect(__computeBundledSelfPackageRoot(posixMetaDir, path.posix)).toBe("/repo/packages/coding-agent");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,104 +0,0 @@
|
||||
import { describe, expect, it } from "bun:test";
|
||||
import * as path from "node:path";
|
||||
import { LEGACY_COMPAT_BUILD_ENTRYPOINTS } from "../../../../scripts/binary-entrypoints";
|
||||
|
||||
/**
|
||||
* Regression for issue #3414.
|
||||
*
|
||||
* `legacy-pi-compat.ts` redirects bare `typebox` / `@sinclair/typebox` imports
|
||||
* and the legacy `@(scope)/pi-*` package roots onto computed bunfs paths under
|
||||
* `/$bunfs/root/packages/coding-agent/src/extensibility/` and
|
||||
* `/$bunfs/root/packages/<barrel>/...`. Bun's `--compile` static analyzer
|
||||
* never visits those literals, so each shim must be passed to `bun build` as
|
||||
* an extra entrypoint or it is silently omitted from bunfs and plugin loads
|
||||
* fail with `Cannot find module '/$bunfs/root/.../typebox.js'`.
|
||||
*
|
||||
* Commit `dc5c93462f` removed the worker entrypoints from
|
||||
* `scripts/ci-release-build-binaries.ts` but its inline comment falsely
|
||||
* claimed the legacy-shim entrypoints were "still" listed — they had never
|
||||
* been re-added. Released `omp-darwin-arm64` and `omp-linux-x64` shipped
|
||||
* without the shims, breaking every legacy pi plugin install.
|
||||
*
|
||||
* Contract pinned here:
|
||||
* - Both build scripts (release CI + local dev) feed the SAME entrypoint
|
||||
* list to `bun build --compile`, sourced from `binary-entrypoints.ts`.
|
||||
* - That list covers every shim referenced by `legacy-pi-compat.ts`.
|
||||
*/
|
||||
describe("legacy pi-compat --compile entrypoints (issue #3414)", () => {
|
||||
const repoRoot = path.resolve(import.meta.dir, "../../../..");
|
||||
const ciScriptPath = path.join(repoRoot, "scripts/ci-release-build-binaries.ts");
|
||||
const devScriptPath = path.join(repoRoot, "packages/coding-agent/scripts/build-binary.ts");
|
||||
const compatPath = path.join(repoRoot, "packages/coding-agent/src/extensibility/plugins/legacy-pi-compat.ts");
|
||||
|
||||
it("declares every shim file legacy-pi-compat redirects to as a --compile entrypoint", () => {
|
||||
// The shared constant must list every bunfs file the resolver hands back
|
||||
// to Bun. Drop one here and the corresponding plugin import breaks at
|
||||
// runtime with `Cannot find module '/$bunfs/root/...'`.
|
||||
expect(LEGACY_COMPAT_BUILD_ENTRYPOINTS).toEqual([
|
||||
"./packages/agent/src/index.ts",
|
||||
"./packages/natives/native/index.js",
|
||||
"./packages/tui/src/index.ts",
|
||||
"./packages/utils/src/index.ts",
|
||||
"./packages/coding-agent/src/extensibility/typebox.ts",
|
||||
"./packages/coding-agent/src/extensibility/legacy-pi-ai-shim.ts",
|
||||
"./packages/coding-agent/src/extensibility/legacy-pi-coding-agent-shim.ts",
|
||||
]);
|
||||
});
|
||||
|
||||
it("release and dev build scripts both source entrypoints from binary-entrypoints.ts", async () => {
|
||||
const releaseSource = await Bun.file(ciScriptPath).text();
|
||||
const devSource = await Bun.file(devScriptPath).text();
|
||||
|
||||
// Both scripts import the shared constant rather than inlining their
|
||||
// own copy, so the two halves of the contract cannot drift apart.
|
||||
expect(releaseSource).toContain("import { LEGACY_COMPAT_BUILD_ENTRYPOINTS } from");
|
||||
expect(releaseSource).toContain("binary-entrypoints");
|
||||
expect(releaseSource).toContain("...LEGACY_COMPAT_BUILD_ENTRYPOINTS");
|
||||
|
||||
expect(devSource).toContain("import { LEGACY_COMPAT_BUILD_ENTRYPOINTS } from");
|
||||
expect(devSource).toContain("binary-entrypoints");
|
||||
expect(devSource).toContain("...LEGACY_COMPAT_BUILD_ENTRYPOINTS");
|
||||
});
|
||||
|
||||
it("each entrypoint actually exists on disk under the repo root", async () => {
|
||||
// `--compile` silently swallows a missing entrypoint when run without
|
||||
// `--root .` mismatches, then drops the file from bunfs and ships a
|
||||
// broken binary. Make every path a real file so the build fails loudly
|
||||
// if the constant ever lists a stale path.
|
||||
for (const relative of LEGACY_COMPAT_BUILD_ENTRYPOINTS) {
|
||||
const abs = path.join(repoRoot, relative.replace(/^\.\//, ""));
|
||||
expect(await Bun.file(abs).exists()).toBe(true);
|
||||
}
|
||||
});
|
||||
|
||||
it("legacy-pi-compat.ts only redirects to shims declared in the entrypoint list", async () => {
|
||||
// Every `bunfsPath("<pkg>", "<entry>", ..., "<file>.js")` and
|
||||
// `bunfsPath("coding-agent", "src", "extensibility", "<shim>.js")` in
|
||||
// the compat module must have a corresponding `.ts` (or `.js`) entry
|
||||
// in `LEGACY_COMPAT_BUILD_ENTRYPOINTS`. Otherwise a plugin import goes
|
||||
// to a bunfs file that wasn't compiled in.
|
||||
const compatSource = await Bun.file(compatPath).text();
|
||||
const bunfsPathPattern = /bunfsPath\(([^)]+)\)/g;
|
||||
const segmentsList = [...compatSource.matchAll(bunfsPathPattern)]
|
||||
.map(match => match[1])
|
||||
.filter((segment): segment is string => typeof segment === "string");
|
||||
expect(segmentsList.length).toBeGreaterThan(0);
|
||||
|
||||
for (const segmentsExpr of segmentsList) {
|
||||
const segments = [...segmentsExpr.matchAll(/"([^"]+)"/g)]
|
||||
.map(match => match[1])
|
||||
.filter((seg): seg is string => typeof seg === "string");
|
||||
if (segments.length === 0) continue;
|
||||
|
||||
// Convert the bunfs path tail (e.g. `tui/src/index.js`) to the
|
||||
// matching repo-root build entrypoint (`./packages/tui/src/index.{ts,js}`).
|
||||
const bunfsTail = segments.join("/");
|
||||
const matched = LEGACY_COMPAT_BUILD_ENTRYPOINTS.some(entry => {
|
||||
const stripped = entry.replace(/^\.\/packages\//, "").replace(/\.(ts|js)$/, "");
|
||||
const bunfsExpected = bunfsTail.replace(/\.(js|ts)$/, "");
|
||||
return stripped === bunfsExpected;
|
||||
});
|
||||
expect(matched, `bunfsPath(${segmentsExpr}) has no matching --compile entrypoint`).toBe(true);
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -1,5 +1,8 @@
|
||||
import { describe, expect, it } from "bun:test";
|
||||
import { __validateLegacyPiPackageRootOverrides } from "@oh-my-pi/pi-coding-agent/extensibility/plugins/legacy-pi-compat";
|
||||
import {
|
||||
__resolveTypeBoxShimPath,
|
||||
__validateLegacyPiPackageRootOverrides,
|
||||
} from "@oh-my-pi/pi-coding-agent/extensibility/plugins/legacy-pi-compat";
|
||||
|
||||
// Regression for issue #2168: in compiled-binary mode the package-root
|
||||
// override branch of `resolveCanonicalPiSpecifier` returned a bunfs path
|
||||
@@ -10,8 +13,14 @@ import { __validateLegacyPiPackageRootOverrides } from "@oh-my-pi/pi-coding-agen
|
||||
// `getResolvedSpecifier` path. The fix validates each override at module
|
||||
// init so missing entries fall through to canonical resolution and Bun
|
||||
// resolves the import from the extension's own `node_modules`.
|
||||
//
|
||||
// Follow-up (issue #3423): on Bun 1.3.14 the compiled binary's
|
||||
// `/$bunfs/...` paths are unreachable via every filesystem API, so
|
||||
// compiled-binary mode now routes through `omp-legacy-pi-bundled:` virtual
|
||||
// specifiers instead. Those entries must always pass validation because
|
||||
// the bundled registry — not the filesystem — is the source of truth.
|
||||
describe("legacy pi compat package-root override validation (issue #2168)", () => {
|
||||
it("keeps overrides whose targets exist", () => {
|
||||
it("keeps overrides whose filesystem targets exist", () => {
|
||||
const candidates = {
|
||||
"@oh-my-pi/pi-ai": "/tmp/exists-ai.js",
|
||||
"@oh-my-pi/pi-utils": "/tmp/exists-utils.js",
|
||||
@@ -20,7 +29,7 @@ describe("legacy pi compat package-root override validation (issue #2168)", () =
|
||||
expect(result).toEqual(candidates);
|
||||
});
|
||||
|
||||
it("drops overrides whose targets are missing on disk", () => {
|
||||
it("drops overrides whose filesystem targets are missing on disk", () => {
|
||||
const candidates = {
|
||||
"@oh-my-pi/pi-ai": "/tmp/exists-ai.js",
|
||||
"@oh-my-pi/pi-coding-agent": "/tmp/exists-shim.js",
|
||||
@@ -41,7 +50,7 @@ describe("legacy pi compat package-root override validation (issue #2168)", () =
|
||||
expect(result).not.toHaveProperty("@oh-my-pi/pi-tui");
|
||||
});
|
||||
|
||||
it("drops every override when none of the targets exist", () => {
|
||||
it("drops every override when none of the filesystem targets exist", () => {
|
||||
const candidates = {
|
||||
"@oh-my-pi/pi-utils": "/$bunfs/root/packages/utils/src/index.js",
|
||||
"@oh-my-pi/pi-tui": "/$bunfs/root/packages/tui/src/index.js",
|
||||
@@ -49,4 +58,68 @@ describe("legacy pi compat package-root override validation (issue #2168)", () =
|
||||
const result = __validateLegacyPiPackageRootOverrides(candidates, () => false);
|
||||
expect(result).toEqual({});
|
||||
});
|
||||
|
||||
it("keeps virtual omp-legacy-pi-bundled: entries without touching the filesystem (issue #3423)", () => {
|
||||
// Bun 1.3.14 `fs.existsSync` returns false for every bunfs path, so the
|
||||
// pre-#3423 fix dropped every override in compiled mode. The new
|
||||
// virtual scheme is the source of truth in compiled-binary mode; the
|
||||
// validator MUST short-circuit before any filesystem probe.
|
||||
let probed = false;
|
||||
const candidates = {
|
||||
"@oh-my-pi/pi-ai": "omp-legacy-pi-bundled:@oh-my-pi/pi-ai",
|
||||
"@oh-my-pi/pi-coding-agent": "omp-legacy-pi-bundled:@oh-my-pi/pi-coding-agent",
|
||||
"@oh-my-pi/pi-agent-core": "omp-legacy-pi-bundled:@oh-my-pi/pi-agent-core",
|
||||
"@oh-my-pi/pi-natives": "omp-legacy-pi-bundled:@oh-my-pi/pi-natives",
|
||||
"@oh-my-pi/pi-tui": "omp-legacy-pi-bundled:@oh-my-pi/pi-tui",
|
||||
"@oh-my-pi/pi-utils": "omp-legacy-pi-bundled:@oh-my-pi/pi-utils",
|
||||
};
|
||||
const result = __validateLegacyPiPackageRootOverrides(candidates, () => {
|
||||
probed = true;
|
||||
return false;
|
||||
});
|
||||
expect(result).toEqual(candidates);
|
||||
expect(probed).toBe(false);
|
||||
});
|
||||
|
||||
it("mixes virtual and filesystem entries: virtuals always pass, filesystems gated", () => {
|
||||
const candidates = {
|
||||
"@oh-my-pi/pi-ai": "omp-legacy-pi-bundled:@oh-my-pi/pi-ai",
|
||||
"@oh-my-pi/pi-coding-agent": "/dev/source/legacy-pi-coding-agent-shim.ts",
|
||||
"@oh-my-pi/pi-tui": "/missing/path.ts",
|
||||
};
|
||||
const missing = new Set(["/missing/path.ts"]);
|
||||
const result = __validateLegacyPiPackageRootOverrides(candidates, p => !missing.has(p));
|
||||
expect(result).toEqual({
|
||||
"@oh-my-pi/pi-ai": "omp-legacy-pi-bundled:@oh-my-pi/pi-ai",
|
||||
"@oh-my-pi/pi-coding-agent": "/dev/source/legacy-pi-coding-agent-shim.ts",
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// Regression for the merge of issue #3414 (typebox shim fall-through) and
|
||||
// issue #3423 (compiled-binary virtual namespace). `__resolveTypeBoxShimPath`
|
||||
// must serve the virtual specifier in compiled mode without probing the FS,
|
||||
// and in dev/install mode drop the shim to `null` when the source file is
|
||||
// missing so `resolveTypeBoxSpecifier` returns `undefined` and bare
|
||||
// `typebox` / `@sinclair/typebox` imports fall through to native resolution.
|
||||
describe("legacy pi compat typebox shim path resolution (issues #3414, #3423)", () => {
|
||||
it("returns the virtual specifier in compiled-binary mode without touching the filesystem", () => {
|
||||
let probed = false;
|
||||
const result = __resolveTypeBoxShimPath(true, "/ignored/source/typebox.ts", () => {
|
||||
probed = true;
|
||||
return false;
|
||||
});
|
||||
expect(result).toBe("omp-legacy-pi-bundled:typebox");
|
||||
expect(probed).toBe(false);
|
||||
});
|
||||
|
||||
it("returns the on-disk source path in dev mode when the shim file exists", () => {
|
||||
const result = __resolveTypeBoxShimPath(false, "/dev/src/typebox.ts", () => true);
|
||||
expect(result).toBe("/dev/src/typebox.ts");
|
||||
});
|
||||
|
||||
it("drops the shim to null in dev mode when the source file is missing (issue #3414)", () => {
|
||||
const result = __resolveTypeBoxShimPath(false, "/dev/src/typebox.ts", () => false);
|
||||
expect(result).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,74 +0,0 @@
|
||||
import { describe, expect, it } from "bun:test";
|
||||
import * as path from "node:path";
|
||||
import { __resolveTypeBoxShimPath } from "@oh-my-pi/pi-coding-agent/extensibility/plugins/legacy-pi-compat";
|
||||
|
||||
/**
|
||||
* Defensive tier for issue #3414.
|
||||
*
|
||||
* Even with the entrypoint list pinned in `binary-entrypoints.ts`, a future
|
||||
* Bun `--compile` regression (cf. #2168) can silently drop the typebox shim
|
||||
* file from bunfs. Without runtime validation the resolver would emit a
|
||||
* `file://` URL to a path that no longer exists and plugin loads fail with
|
||||
* `Cannot find module '/$bunfs/root/.../typebox.js'`.
|
||||
*
|
||||
* `__resolveTypeBoxShimPath` mirrors the `__validateLegacyPiPackageRootOverrides`
|
||||
* fallback already in place for the legacy package-root overrides: if the
|
||||
* computed candidate is missing, return `null` so the rewriter leaves bare
|
||||
* `typebox` / `@sinclair/typebox` specifiers alone and Bun resolves a real
|
||||
* install from the extension's own `node_modules`.
|
||||
*/
|
||||
describe("legacy pi-compat typebox shim path validation (issue #3414)", () => {
|
||||
const stubMetaDir = "/repo/packages/coding-agent/src/extensibility/plugins";
|
||||
|
||||
it("returns the bunfs candidate when --compile bundled the shim", () => {
|
||||
const result = __resolveTypeBoxShimPath(
|
||||
"/$bunfs/root/packages",
|
||||
undefined,
|
||||
"/$bunfs/root",
|
||||
() => true,
|
||||
path.posix,
|
||||
);
|
||||
expect(result).toBe("/$bunfs/root/packages/coding-agent/src/extensibility/typebox.js");
|
||||
});
|
||||
|
||||
it("drops the bunfs candidate when --compile silently omitted the shim", () => {
|
||||
const result = __resolveTypeBoxShimPath(
|
||||
"/$bunfs/root/packages",
|
||||
undefined,
|
||||
"/$bunfs/root",
|
||||
() => false,
|
||||
path.posix,
|
||||
);
|
||||
expect(result).toBeNull();
|
||||
});
|
||||
|
||||
it("preserves the double-slash bunfs prefix on cross-compiled darwin-arm64 (issue #3329)", () => {
|
||||
// `BUNFS_PACKAGE_ROOT` on the cross-compiled release is `//root/packages`.
|
||||
// The shim path must keep that exact double-slash mount prefix so Bun's
|
||||
// bunfs lookup matches.
|
||||
const result = __resolveTypeBoxShimPath(
|
||||
"//root/packages",
|
||||
undefined,
|
||||
"//root/omp-darwin-arm64",
|
||||
() => true,
|
||||
path.posix,
|
||||
);
|
||||
expect(result).toBe("//root/packages/coding-agent/src/extensibility/typebox.js");
|
||||
});
|
||||
|
||||
it("returns the npm prebuilt dist path when PI_BUNDLED is set", () => {
|
||||
const bundledRoot = "/home/me/.bun/install/global/node_modules/@oh-my-pi/pi-coding-agent";
|
||||
const result = __resolveTypeBoxShimPath(null, bundledRoot, stubMetaDir, () => true, path.posix);
|
||||
expect(result).toBe(`${bundledRoot}/src/extensibility/typebox.ts`);
|
||||
});
|
||||
|
||||
it("returns the dev source path when neither bunfs nor bundled is set", () => {
|
||||
const result = __resolveTypeBoxShimPath(null, undefined, stubMetaDir, () => true, path.posix);
|
||||
expect(result).toBe("/repo/packages/coding-agent/src/extensibility/typebox.ts");
|
||||
});
|
||||
|
||||
it("returns null when the dev source path is missing too", () => {
|
||||
const result = __resolveTypeBoxShimPath(null, undefined, stubMetaDir, () => false, path.posix);
|
||||
expect(result).toBeNull();
|
||||
});
|
||||
});
|
||||
@@ -1,30 +0,0 @@
|
||||
/**
|
||||
* Extra `bun build --compile` entrypoints that must land in bunfs at
|
||||
* `/$bunfs/root/packages/<pkg>/...`.
|
||||
*
|
||||
* `legacy-pi-compat.ts` redirects bare TypeBox imports and the legacy
|
||||
* `@(scope)/pi-*` package roots onto computed bunfs paths — Bun's `--compile`
|
||||
* static analyzer cannot trace those, so each shim and bundled package barrel
|
||||
* must be passed as an explicit additional entrypoint or the file is silently
|
||||
* omitted from bunfs and plugin loads fail with `Cannot find module
|
||||
* '/$bunfs/root/...'` (issue #3414).
|
||||
*
|
||||
* The coding-agent's own `./src/index.ts` is intentionally NOT listed: bun
|
||||
* --compile silently breaks the CLI entry when the same package's barrel
|
||||
* appears as an extra entrypoint (issue #1474), so legacy `pi-coding-agent`
|
||||
* imports resolve through `legacy-pi-coding-agent-shim.ts` instead.
|
||||
*
|
||||
* Repo-root-relative — both `scripts/ci-release-build-binaries.ts` (release)
|
||||
* and `packages/coding-agent/scripts/build-binary.ts` (dev) invoke
|
||||
* `bun build --compile --root .` so the paths land at the same bunfs
|
||||
* locations the runtime computes.
|
||||
*/
|
||||
export const LEGACY_COMPAT_BUILD_ENTRYPOINTS: readonly string[] = [
|
||||
"./packages/agent/src/index.ts",
|
||||
"./packages/natives/native/index.js",
|
||||
"./packages/tui/src/index.ts",
|
||||
"./packages/utils/src/index.ts",
|
||||
"./packages/coding-agent/src/extensibility/typebox.ts",
|
||||
"./packages/coding-agent/src/extensibility/legacy-pi-ai-shim.ts",
|
||||
"./packages/coding-agent/src/extensibility/legacy-pi-coding-agent-shim.ts",
|
||||
];
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
import * as fs from "node:fs/promises";
|
||||
import * as path from "node:path";
|
||||
import { LEGACY_COMPAT_BUILD_ENTRYPOINTS } from "./binary-entrypoints";
|
||||
|
||||
interface BinaryTarget {
|
||||
id: string;
|
||||
@@ -15,14 +14,11 @@ interface BinaryTarget {
|
||||
const repoRoot = path.join(import.meta.dir, "..");
|
||||
const binariesDir = path.join(repoRoot, "packages", "coding-agent", "binaries");
|
||||
const entrypoint = "./packages/coding-agent/src/cli.ts";
|
||||
// Legacy extension shims and package barrels reached via computed bunfs paths.
|
||||
// Declared in `binary-entrypoints.ts` so the dev build script
|
||||
// (`packages/coding-agent/scripts/build-binary.ts`) and this release script
|
||||
// stay in sync — drifting them silently strips the shims from the release
|
||||
// `omp-<platform>` assets and breaks `omp install` for legacy pi extensions
|
||||
// (issue #3414). Worker threads spawn `new Worker(Bun.main, { argv })` — they
|
||||
// re-enter the binary's own entry module — so no separate worker modules
|
||||
// are compiled.
|
||||
// Worker threads spawn `new Worker(Bun.main, { argv })` — they re-enter the
|
||||
// binary's own entry module — so no separate worker modules are compiled.
|
||||
// Legacy pi-* extension compat surfaces are served through an in-process
|
||||
// virtual namespace (`legacy-pi-compat.ts`), reached via the main module
|
||||
// graph, so no extra `--compile` entrypoints are required (issue #3423).
|
||||
const isDryRun = process.argv.includes("--dry-run");
|
||||
const targets: BinaryTarget[] = [
|
||||
{
|
||||
@@ -115,7 +111,7 @@ async function buildBinary(target: BinaryTarget): Promise<void> {
|
||||
console.log(`Building ${target.outfile}...`);
|
||||
await embedNative(target);
|
||||
if (isDryRun) {
|
||||
console.log(`DRY RUN bun build --compile --no-compile-autoload-bunfig --no-compile-autoload-dotenv --no-compile-autoload-tsconfig --no-compile-autoload-package-json --minify-identifiers --keep-names --define process.env.PI_COMPILED="true" --root . --target=${target.target} ${entrypoint} ${LEGACY_COMPAT_BUILD_ENTRYPOINTS.join(" ")} --outfile ${target.outfile}`);
|
||||
console.log(`DRY RUN bun build --compile --no-compile-autoload-bunfig --no-compile-autoload-dotenv --no-compile-autoload-tsconfig --no-compile-autoload-package-json --minify-identifiers --keep-names --define process.env.PI_COMPILED="true" --root . --target=${target.target} ${entrypoint} --outfile ${target.outfile}`);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -140,7 +136,6 @@ async function buildBinary(target: BinaryTarget): Promise<void> {
|
||||
"--target",
|
||||
target.target,
|
||||
entrypoint,
|
||||
...LEGACY_COMPAT_BUILD_ENTRYPOINTS,
|
||||
"--outfile",
|
||||
target.outfile,
|
||||
],
|
||||
|
||||
Reference in New Issue
Block a user