diff --git a/package-lock.json b/package-lock.json index 2a549461..fcf10277 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1000,6 +1000,17 @@ "url": "https://github.com/sponsors/Borewit" } }, + "node_modules/@emnapi/core": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.8.1.tgz", + "integrity": "sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg==", + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.1.0", + "tslib": "^2.4.0" + } + }, "node_modules/@emnapi/runtime": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.8.1.tgz", @@ -1010,6 +1021,16 @@ "tslib": "^2.4.0" } }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.1.0.tgz", + "integrity": "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, "node_modules/@esbuild/aix-ppc64": { "version": "0.27.2", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.2.tgz", @@ -1979,6 +2000,17 @@ "node": ">=6.0.0" } }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.11", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.11.tgz", + "integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==", + "license": "MIT", + "optional": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" + } + }, "node_modules/@jridgewell/sourcemap-codec": { "version": "1.5.5", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", @@ -2245,6 +2277,19 @@ "node": ">= 10" } }, + "node_modules/@mariozechner/jiti": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/@mariozechner/jiti/-/jiti-2.6.2.tgz", + "integrity": "sha512-CcFowm/fDWcEMH/F47DQcdawpLQb0nw+WR+hZOv8mgAeACFJxE9uo3cXjUk/5Cl3j23t/oxvtxxUtlBCUIGeQg==", + "license": "MIT", + "dependencies": { + "std-env": "^3.10.0", + "yoctocolors": "^2.1.2" + }, + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, "node_modules/@mariozechner/mini-lit": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/@mariozechner/mini-lit/-/mini-lit-0.2.1.tgz", @@ -2583,6 +2628,18 @@ "url": "https://github.com/sponsors/Brooooooklyn" } }, + "node_modules/@napi-rs/wasm-runtime": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.0.7.tgz", + "integrity": "sha512-SeDnOO0Tk7Okiq6DbXmmBODgOAb9dp9gjlphokTUxmt8U3liIP1ZsozBahH69j/RJv+Rfs6IwUKHTgQYJ/HBAw==", + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.5.0", + "@emnapi/runtime": "^1.5.0", + "@tybys/wasm-util": "^0.10.1" + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -4314,6 +4371,16 @@ "integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==", "license": "MIT" }, + "node_modules/@tybys/wasm-util": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz", + "integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, "node_modules/@types/chai": { "version": "5.2.3", "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", @@ -4879,6 +4946,13 @@ "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", "license": "BSD-3-Clause" }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "license": "MIT", + "optional": true + }, "node_modules/cac": { "version": "6.7.14", "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", @@ -6460,15 +6534,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/jiti": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", - "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", - "license": "MIT", - "bin": { - "jiti": "lib/jiti-cli.mjs" - } - }, "node_modules/js-tokens": { "version": "9.0.1", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz", @@ -8039,6 +8104,16 @@ "simple-concat": "^1.0.0" } }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "license": "BSD-3-Clause", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/source-map-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", @@ -8048,6 +8123,17 @@ "node": ">=0.10.0" } }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "license": "MIT", + "optional": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, "node_modules/stackback": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", @@ -8059,7 +8145,6 @@ "version": "3.10.0", "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz", "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==", - "dev": true, "license": "MIT" }, "node_modules/string_decoder": { @@ -8338,6 +8423,32 @@ "node": ">=6" } }, + "node_modules/terser": { + "version": "5.44.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.44.1.tgz", + "integrity": "sha512-t/R3R/n0MSwnnazuPpPNVO60LX0SKL45pyl9YlvxIdkH0Of7D5qM2EVe+yASRIlY5pZ73nclYJfNANGWPwFDZw==", + "license": "BSD-2-Clause", + "optional": true, + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.15.0", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "license": "MIT", + "optional": true + }, "node_modules/thenify": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", @@ -9052,6 +9163,18 @@ "node": ">=8" } }, + "node_modules/yoctocolors": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yoctocolors/-/yoctocolors-2.1.2.tgz", + "integrity": "sha512-CzhO+pFNo8ajLM2d2IW/R93ipy99LWjtwblvC1RsoSUMZgyLbYFr221TnSNT7GjGdYui6P459mw9JH/g/zW2ug==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/zod": { "version": "4.3.5", "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.5.tgz", @@ -9157,6 +9280,7 @@ "license": "MIT", "dependencies": { "@mariozechner/clipboard": "^0.3.0", + "@mariozechner/jiti": "^2.6.2", "@mariozechner/pi-agent-core": "^0.45.2", "@mariozechner/pi-ai": "^0.45.2", "@mariozechner/pi-tui": "^0.45.2", @@ -9165,7 +9289,6 @@ "diff": "^8.0.2", "file-type": "^21.1.1", "glob": "^11.0.3", - "jiti": "^2.6.1", "marked": "^15.0.12", "minimatch": "^10.1.1", "proper-lockfile": "^4.1.2", @@ -9214,6 +9337,77 @@ "dev": true, "license": "MIT" }, + "packages/jiti": { + "version": "2.6.1", + "extraneous": true, + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + }, + "devDependencies": { + "@babel/core": "^7.28.4", + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-module-transforms": "^7.28.3", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-simple-access": "^7.27.1", + "@babel/plugin-proposal-decorators": "^7.28.0", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-import-assertions": "^7.27.1", + "@babel/plugin-syntax-jsx": "^7.27.1", + "@babel/plugin-transform-export-namespace-from": "^7.27.1", + "@babel/plugin-transform-react-jsx": "^7.27.1", + "@babel/plugin-transform-typescript": "^7.28.0", + "@babel/preset-typescript": "^7.27.1", + "@babel/template": "^7.27.2", + "@babel/traverse": "^7.28.4", + "@babel/types": "^7.28.4", + "@rspack/cli": "^1.5.8", + "@rspack/core": "^1.5.8", + "@types/babel__core": "^7.20.5", + "@types/babel__helper-module-imports": "^7.18.3", + "@types/babel__helper-plugin-utils": "^7.10.3", + "@types/babel__template": "^7.4.4", + "@types/babel__traverse": "^7.28.0", + "@types/node": "^24.6.1", + "@vitest/coverage-v8": "^3.2.4", + "acorn": "^8.15.0", + "babel-plugin-parameter-decorator": "^1.0.16", + "changelogen": "^0.6.2", + "config": "^4.1.1", + "consola": "^3.4.2", + "defu": "^6.1.4", + "destr": "^2.0.5", + "escape-string-regexp": "^5.0.0", + "eslint": "^9.36.0", + "eslint-config-unjs": "^0.5.0", + "estree-walker": "^3.0.3", + "etag": "^1.8.1", + "fast-glob": "^3.3.3", + "is-installed-globally": "^1.0.0", + "mime": "^4.1.0", + "mlly": "^1.8.0", + "moment-timezone": "^0.6.0", + "nano-jsx": "^0.2.0", + "pathe": "^2.0.3", + "pkg-types": "^2.3.0", + "preact": "^10.27.2", + "preact-render-to-string": "^6.6.2", + "prettier": "^3.6.2", + "react": "^19.1.1", + "react-dom": "^19.1.1", + "reflect-metadata": "^0.2.2", + "solid-js": "^1.9.9", + "std-env": "^3.9.0", + "terser-webpack-plugin": "^5.3.14", + "tinyexec": "^1.0.1", + "ts-loader": "^9.5.4", + "typescript": "^5.9.3", + "vitest": "^3.2.4", + "vue": "^3.5.22", + "yoctocolors": "^2.1.2", + "zod": "^4.1.11" + } + }, "packages/mom": { "name": "@mariozechner/pi-mom", "version": "0.45.2", diff --git a/packages/coding-agent/CHANGELOG.md b/packages/coding-agent/CHANGELOG.md index e0e90093..d1054966 100644 --- a/packages/coding-agent/CHANGELOG.md +++ b/packages/coding-agent/CHANGELOG.md @@ -6,7 +6,7 @@ ### Fixed -- Extensions now load correctly in compiled Bun binary by using jiti for module resolution with proper alias handling +- Extensions now load correctly in compiled Bun binary using `@mariozechner/jiti` fork with `virtualModules` support. Bundled packages (`@sinclair/typebox`, `@mariozechner/pi-tui`, `@mariozechner/pi-ai`, `@mariozechner/pi-coding-agent`) are accessible to extensions without filesystem node_modules. ## [0.45.1] - 2026-01-13 diff --git a/packages/coding-agent/package.json b/packages/coding-agent/package.json index 11c74233..883412cb 100644 --- a/packages/coding-agent/package.json +++ b/packages/coding-agent/package.json @@ -39,6 +39,7 @@ }, "dependencies": { "@mariozechner/clipboard": "^0.3.0", + "@mariozechner/jiti": "^2.6.2", "@mariozechner/pi-agent-core": "^0.45.2", "@mariozechner/pi-ai": "^0.45.2", "@mariozechner/pi-tui": "^0.45.2", @@ -47,7 +48,6 @@ "diff": "^8.0.2", "file-type": "^21.1.1", "glob": "^11.0.3", - "jiti": "^2.6.1", "marked": "^15.0.12", "minimatch": "^10.1.1", "proper-lockfile": "^4.1.2", diff --git a/packages/coding-agent/src/core/extensions/loader.ts b/packages/coding-agent/src/core/extensions/loader.ts index 05f97a7e..cb79e0a1 100644 --- a/packages/coding-agent/src/core/extensions/loader.ts +++ b/packages/coding-agent/src/core/extensions/loader.ts @@ -1,5 +1,7 @@ /** * Extension loader - loads TypeScript extension modules using jiti. + * + * Uses @mariozechner/jiti fork with virtualModules support for compiled Bun binaries. */ import * as fs from "node:fs"; @@ -7,9 +9,15 @@ import { createRequire } from "node:module"; import * as os from "node:os"; import * as path from "node:path"; import { fileURLToPath } from "node:url"; +import { createJiti } from "@mariozechner/jiti"; +import * as _bundledPiAi from "@mariozechner/pi-ai"; import type { KeyId } from "@mariozechner/pi-tui"; -import { createJiti } from "jiti"; -import { getAgentDir } from "../../config.js"; +import * as _bundledPiTui from "@mariozechner/pi-tui"; +// Static imports of packages that extensions may use. +// These MUST be static so Bun bundles them into the compiled binary. +// The virtualModules option then makes them available to extensions. +import * as _bundledTypebox from "@sinclair/typebox"; +import { getAgentDir, isBunBinary } from "../../config.js"; import { createEventBus, type EventBus } from "../event-bus.js"; import type { ExecOptions } from "../exec.js"; import { execCommand } from "../exec.js"; @@ -24,8 +32,28 @@ import type { ToolDefinition, } from "./types.js"; +/** Modules available to extensions via virtualModules (for compiled Bun binary) */ +let _lazyPiCodingAgent: unknown; +const VIRTUAL_MODULES: Record = { + "@sinclair/typebox": _bundledTypebox, + "@mariozechner/pi-tui": _bundledPiTui, + "@mariozechner/pi-ai": _bundledPiAi, + // Lazy-loaded to avoid circular dependency (loader.ts is part of pi-coding-agent) + get "@mariozechner/pi-coding-agent"() { + if (!_lazyPiCodingAgent) { + // Dynamic require after module initialization completes + _lazyPiCodingAgent = require("../../index.js"); + } + return _lazyPiCodingAgent; + }, +}; + const require = createRequire(import.meta.url); +/** + * Get aliases for jiti (used in Node.js/development mode). + * In Bun binary mode, virtualModules is used instead. + */ let _aliases: Record | null = null; function getAliases(): Record { if (_aliases) return _aliases; @@ -33,27 +61,16 @@ function getAliases(): Record { const __dirname = path.dirname(fileURLToPath(import.meta.url)); const packageIndex = path.resolve(__dirname, "../..", "index.js"); - // Debug: log what we're resolving - if (process.env.DEBUG_EXTENSIONS) { - console.error("[DEBUG] import.meta.url:", import.meta.url); - console.error("[DEBUG] __dirname:", __dirname); - } - const typeboxEntry = require.resolve("@sinclair/typebox"); const typeboxRoot = typeboxEntry.replace(/\/build\/cjs\/index\.js$/, ""); _aliases = { "@mariozechner/pi-coding-agent": packageIndex, - "@mariozechner/pi-coding-agent/extensions": path.resolve(__dirname, "index.js"), "@mariozechner/pi-tui": require.resolve("@mariozechner/pi-tui"), "@mariozechner/pi-ai": require.resolve("@mariozechner/pi-ai"), "@sinclair/typebox": typeboxRoot, }; - if (process.env.DEBUG_EXTENSIONS) { - console.error("[DEBUG] aliases:", JSON.stringify(_aliases, null, 2)); - } - return _aliases; } @@ -224,12 +241,15 @@ function createExtensionAPI( return api; } -async function loadExtensionModule(path: string) { +async function loadExtensionModule(extensionPath: string) { const jiti = createJiti(import.meta.url, { - alias: getAliases(), + // In Bun binary: use virtualModules for bundled packages (no filesystem resolution) + // Also disable tryNative so jiti handles ALL imports (not just the entry point) + // In Node.js/dev: use aliases to resolve to node_modules paths + ...(isBunBinary ? { virtualModules: VIRTUAL_MODULES, tryNative: false } : { alias: getAliases() }), }); - const module = await jiti.import(path, { default: true }); + const module = await jiti.import(extensionPath, { default: true }); const factory = module as ExtensionFactory; return typeof factory !== "function" ? undefined : factory; }