fix(coding-agent): served bundled pi-* through virtual ns on bun 1.3.14

Bun 1.3.14 stopped exposing `--compile` extras through every filesystem-style API: `fs.existsSync`, `Bun.file().exists()`, `Bun.resolveSync`, and `await import()` on `/$bunfs/...` or `file:///$bunfs/...` all fail; only `/$bunfs/root/<binary-name>` itself answers. The pre-existing legacy-pi rewrite emitted `file:///$bunfs/...` URLs that Bun then could not load, so every legacy extension that imported `@oh-my-pi/pi-*` or `@sinclair/typebox` failed on the `omp-darwin-arm64` release binary.

`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` synthesizes a re-export module — no bunfs path ever leaves the module in compiled mode. Dev / source-link / installed-package modes keep the historical `file://` rewrite (source files exist on disk). The matching `--compile` extras in `scripts/build-binary.ts` are gone; `BUNFS_PACKAGE_ROOT`, `bunfsPath`, `__computeBunfsPackageRoot`, and `__joinBunfsPath` are deleted as dead code. `scripts/smoke-3423.ts` compiles a tiny binary that loads a fixture extension end-to-end through the new path.

Fixes #3423
This commit is contained in:
roboomp
2026-06-25 02:35:50 +00:00
parent 8d60776a6f
commit 294d41bd3b
8 changed files with 603 additions and 198 deletions
+181
View File
@@ -0,0 +1,181 @@
#!/usr/bin/env bun
/**
* Issue #3423 end-to-end smoke driver. Compiles the legacy-pi compat path
* into a tiny binary, runs it against a fixture extension, asserts the
* extension's `@(scope)/pi-*` and `@sinclair/typebox` imports all resolve
* through the bundled-virtual loader rather than the now-unreachable
* `/$bunfs/...` filesystem paths.
*
* Usage: `bun scripts/smoke-3423.ts` from the repo root.
*/
import * as fs from "node:fs/promises";
import * as os from "node:os";
import * as path from "node:path";
const repoRoot = path.resolve(import.meta.dir, "..");
const driverFile = path.join(repoRoot, ".omp-smoke-3423", "main.ts");
const outFile = path.join(repoRoot, ".omp-smoke-3423", "smoke");
await fs.mkdir(path.dirname(driverFile), { recursive: true });
// `legacy-pi-bundled-registry` cascades through the coding-agent root which
// pulls in `export/html/tool-views.generated.js` (a build artifact). The
// full release build runs `packages/collab-web/scripts/build-tool-views.ts`
// to produce it; for the smoke we stub an empty file so the bundler can
// resolve the `with { type: "text" }` import.
const toolViewsPlaceholder = path.join(
repoRoot,
"packages",
"coding-agent",
"src",
"export",
"html",
"tool-views.generated.js",
);
const hadToolViews = await Bun.file(toolViewsPlaceholder)
.exists()
.catch(() => false);
if (!hadToolViews) {
await Bun.write(toolViewsPlaceholder, "// smoke-3423 placeholder\n");
}
// pi-natives ships a platform-specific `.node` addon that lives outside the
// JS bundle; `embed:native` copies it next to the source so the bundler can
// pick it up. Without this step the compiled binary crashes at startup
// before the legacy-pi shim path is even exercised.
const embed = Bun.spawnSync(["bun", "--cwd=../natives", "run", "embed:native"], {
cwd: path.join(repoRoot, "packages", "coding-agent"),
stdout: "inherit",
stderr: "inherit",
});
if (embed.exitCode !== 0) {
throw new Error(`embed:native failed with exit code ${embed.exitCode}`);
}
const driver = `import * as fs from "node:fs/promises";
import * as os from "node:os";
import * as path from "node:path";
import {
installLegacyPiSpecifierShim,
loadLegacyPiModule,
} from "@oh-my-pi/pi-coding-agent/extensibility/plugins/legacy-pi-compat";
installLegacyPiSpecifierShim();
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "omp-3423-ext-"));
await fs.writeFile(
path.join(dir, "package.json"),
JSON.stringify({ name: "legacy-3423-ext", version: "1.0.0" }),
);
await fs.writeFile(
path.join(dir, "index.ts"),
[
'import { VERSION, defineTool, Type } from "@earendil-works/pi-coding-agent";',
'import { z } from "@mariozechner/pi-ai";',
'import { Type as TbxType } from "@sinclair/typebox";',
'import { logger } from "@oh-my-pi/pi-utils";',
"const sample = defineTool({",
' name: "smoke",',
' label: "smoke",',
' description: "issue 3423 smoke",',
" parameters: Type.Object({}),",
' execute: async () => ({ content: [{ type: "text", text: "ok" }] }),',
"});",
"export const probe = {",
" piCodingAgentVersion: VERSION,",
" zIsFunction: typeof z?.object === 'function',",
" tbxTypeIsObject: typeof TbxType === 'object',",
" loggerIsCallable: typeof logger?.info === 'function',",
" defineToolReturned: sample.name,",
"};",
].join("\\n"),
);
const mod = await loadLegacyPiModule(path.join(dir, "index.ts"));
console.log("PROBE", JSON.stringify(mod.probe));
console.log("OK");
`;
await fs.writeFile(driverFile, driver);
const build = Bun.spawnSync(
[
"bun",
"build",
"--compile",
"--no-compile-autoload-bunfig",
"--no-compile-autoload-dotenv",
"--no-compile-autoload-tsconfig",
"--no-compile-autoload-package-json",
"--keep-names",
"--define",
'process.env.PI_COMPILED="true"',
"--external",
"fastembed",
"--external",
"onnxruntime-node",
"--root",
".",
`./${path.relative(repoRoot, driverFile)}`,
"--outfile",
outFile,
],
{ cwd: repoRoot, stdout: "inherit", stderr: "inherit" },
);
if (build.exitCode !== 0) {
throw new Error(`bun build --compile failed with exit code ${build.exitCode}`);
}
const run = Bun.spawnSync([outFile], { cwd: repoRoot, stdout: "pipe", stderr: "pipe" });
const stdout = run.stdout.toString();
const stderr = run.stderr.toString();
console.log("--- driver stdout ---");
console.log(stdout);
if (stderr) {
console.log("--- driver stderr ---");
console.log(stderr);
}
if (run.exitCode !== 0) {
throw new Error(`compiled smoke binary exited with code ${run.exitCode}`);
}
if (!stdout.includes("OK")) {
throw new Error("driver did not print OK");
}
const probeMatch = stdout.match(/PROBE (\{.*\})/);
if (!probeMatch) {
throw new Error("driver did not print PROBE payload");
}
const probe = JSON.parse(probeMatch[1]) as {
piCodingAgentVersion: string;
zIsFunction: boolean;
tbxTypeIsObject: boolean;
loggerIsCallable: boolean;
defineToolReturned: string;
};
if (!probe.piCodingAgentVersion || !/^\d+\.\d+\.\d+/.test(probe.piCodingAgentVersion)) {
throw new Error(`pi-coding-agent VERSION not exposed: ${probe.piCodingAgentVersion}`);
}
if (!probe.zIsFunction) {
throw new Error("pi-ai z.object missing — shim did not re-export canonical surface");
}
if (!probe.tbxTypeIsObject) {
throw new Error("@sinclair/typebox Type missing — TypeBox shim did not load");
}
if (!probe.loggerIsCallable) {
throw new Error("pi-utils logger.info missing — canonical bundled package not reachable");
}
if (probe.defineToolReturned !== "smoke") {
throw new Error(`defineTool helper did not return the marked tool: ${probe.defineToolReturned}`);
}
console.log("issue #3423 smoke passed");
await fs.rm(path.dirname(driverFile), { recursive: true, force: true });
if (!hadToolViews) {
await fs.rm(toolViewsPlaceholder, { force: true });
}
Bun.spawnSync(["bun", "--cwd=../natives", "run", "embed:native", "--reset"], {
cwd: path.join(repoRoot, "packages", "coding-agent"),
stdout: "inherit",
stderr: "inherit",
});