@oh-my-pi/pi-coding-agent 16.1.17 → 16.1.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +19 -0
- package/dist/cli.js +16753 -16738
- package/dist/types/cli/usage-cli.d.ts +14 -0
- package/dist/types/commands/token.d.ts +9 -0
- package/dist/types/extensibility/plugins/legacy-pi-bundled-registry.d.ts +7 -0
- package/dist/types/extensibility/plugins/legacy-pi-compat.d.ts +31 -27
- package/dist/types/modes/components/extensions/extension-dashboard.d.ts +26 -10
- package/dist/types/modes/components/extensions/extension-list.d.ts +13 -0
- package/package.json +12 -12
- package/scripts/build-binary.ts +9 -16
- package/src/cli/usage-cli.ts +35 -4
- package/src/commands/token.ts +54 -0
- package/src/extensibility/plugins/legacy-pi-bundled-registry.ts +40 -0
- package/src/extensibility/plugins/legacy-pi-compat.ts +240 -122
- package/src/modes/components/extensions/extension-dashboard.ts +221 -165
- package/src/modes/components/extensions/extension-list.ts +66 -33
- package/src/modes/controllers/selector-controller.ts +4 -0
|
@@ -5,6 +5,144 @@ import { isCompiledBinary } from "@oh-my-pi/pi-utils";
|
|
|
5
5
|
|
|
6
6
|
const IS_COMPILED_BINARY = isCompiledBinary();
|
|
7
7
|
|
|
8
|
+
// === Bundled host-package registry (issue #3423) ===
|
|
9
|
+
//
|
|
10
|
+
// Bun 1.3.14 stopped exposing `--compile` extras through any filesystem-style
|
|
11
|
+
// API: `fs.existsSync`, `Bun.file().exists()`, `Bun.resolveSync`, and even
|
|
12
|
+
// `import("/$bunfs/...")` / `import("file:///$bunfs/...")` all fail for the
|
|
13
|
+
// embedded entries — only the main binary itself answers from
|
|
14
|
+
// `/$bunfs/root/<binary-name>`. The previous strategy of rewriting
|
|
15
|
+
// `@(scope)/pi-*` imports to a `file:///$bunfs/...` URL therefore breaks
|
|
16
|
+
// every legacy extension in compiled mode (issue #3423; see also issues
|
|
17
|
+
// #3329, #2168). Bun.plugin `onResolve` for bare specifiers also no longer
|
|
18
|
+
// fires for transitive imports inside runtime-loaded extensions, so the
|
|
19
|
+
// fallback hook in `installLegacyPiSpecifierShim()` cannot rescue them.
|
|
20
|
+
//
|
|
21
|
+
// Instead we keep a JS-heap reference to every bundled pi-* surface (the
|
|
22
|
+
// canonical host packages and the legacy shims) and re-export them through a
|
|
23
|
+
// Bun.plugin `onLoad` against a custom namespace. Extension source rewrites
|
|
24
|
+
// emit `omp-legacy-pi-bundled:<key>` specifiers that the synthetic loader
|
|
25
|
+
// resolves against the registry — no bunfs path ever leaves this module in
|
|
26
|
+
// compiled mode. Dev / source-link / installed-package modes keep the
|
|
27
|
+
// historical `file://` rewrite (the source files exist on disk and load fine
|
|
28
|
+
// through Bun's standard URL loader).
|
|
29
|
+
//
|
|
30
|
+
// The registry lives in a sibling file (`legacy-pi-bundled-registry.ts`)
|
|
31
|
+
// loaded via a conditional dynamic import: its transitive deps include the
|
|
32
|
+
// coding-agent root which pulls in generated artifacts (e.g.
|
|
33
|
+
// `export/html/tool-views.generated.js`) that only exist after a build, so a
|
|
34
|
+
// static import would crash every dev/test run that touches
|
|
35
|
+
// `legacy-pi-compat.ts`. This is the documented "conditional platform code"
|
|
36
|
+
// exception to the static-import rule.
|
|
37
|
+
const BUNDLED_VIRTUAL_SCHEME = "omp-legacy-pi-bundled:";
|
|
38
|
+
const BUNDLED_VIRTUAL_NAMESPACE = "omp-legacy-pi-bundled";
|
|
39
|
+
const BUNDLED_REGISTRY_GLOBAL = "__ompLegacyPiBundledRegistry";
|
|
40
|
+
const TYPEBOX_BUNDLED_REGISTRY_KEY = "typebox";
|
|
41
|
+
|
|
42
|
+
type BundledRegistry = Readonly<Record<string, Readonly<Record<string, unknown>>>>;
|
|
43
|
+
|
|
44
|
+
let bundledRegistryPromise: Promise<BundledRegistry> | null = null;
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Lazy-load the bundled host-package registry and stash it on `globalThis`
|
|
48
|
+
* for the synthetic loader emitted by `synthesizeBundledModuleSource`.
|
|
49
|
+
*
|
|
50
|
+
* `globalThis` is the bridge, not laziness: each synthesized
|
|
51
|
+
* `omp-legacy-pi-bundled:<key>` module is a *separate* ES module Bun compiles
|
|
52
|
+
* from a source string, so it cannot close over the registry in this file's
|
|
53
|
+
* lexical scope and the live (non-serializable) function/object exports cannot
|
|
54
|
+
* be inlined — the only runtime channel back to the host objects is a global.
|
|
55
|
+
*
|
|
56
|
+
* The dynamic import is gated by `IS_COMPILED_BINARY` so dev/test runs (where
|
|
57
|
+
* the registry's transitive deps include build-time-generated artifacts)
|
|
58
|
+
* never trigger the cascade.
|
|
59
|
+
*/
|
|
60
|
+
function ensureBundledRegistryLoaded(): Promise<BundledRegistry> {
|
|
61
|
+
if (!IS_COMPILED_BINARY) {
|
|
62
|
+
return Promise.reject(
|
|
63
|
+
new Error("omp:legacy-pi-shim: bundled registry is only available in compiled-binary mode"),
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
if (!bundledRegistryPromise) {
|
|
67
|
+
bundledRegistryPromise = import("./legacy-pi-bundled-registry").then(m => {
|
|
68
|
+
(globalThis as Record<string, unknown>)[BUNDLED_REGISTRY_GLOBAL] = m.BUNDLED_PI_REGISTRY;
|
|
69
|
+
return m.BUNDLED_PI_REGISTRY;
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
return bundledRegistryPromise;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function bundledRegistryVirtualSpecifier(registryKey: string): string {
|
|
76
|
+
return `${BUNDLED_VIRTUAL_SCHEME}${registryKey}`;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function isBundledVirtualSpecifier(value: string): boolean {
|
|
80
|
+
return value.startsWith(BUNDLED_VIRTUAL_SCHEME);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Build the synthetic ES module source for a `omp-legacy-pi-bundled:<key>`
|
|
85
|
+
* import against an explicit registry. Pure: takes the live module namespace
|
|
86
|
+
* and emits a string of ES exports rooted in `globalThis[BUNDLED_REGISTRY_GLOBAL]`.
|
|
87
|
+
* `synthesizeBundledModuleSource` wraps this with the lazy registry load —
|
|
88
|
+
* tests use this sync helper directly to assert export-shape preservation.
|
|
89
|
+
*/
|
|
90
|
+
function synthesizeBundledModuleSourceFromRegistry(registryKey: string, registry: BundledRegistry): string {
|
|
91
|
+
const mod = registry[registryKey];
|
|
92
|
+
if (!mod) {
|
|
93
|
+
throw new Error(`omp:legacy-pi-shim: no bundled module registered for ${registryKey}`);
|
|
94
|
+
}
|
|
95
|
+
const lines: string[] = [
|
|
96
|
+
`const __omp_bundled = globalThis[${JSON.stringify(BUNDLED_REGISTRY_GLOBAL)}][${JSON.stringify(registryKey)}];`,
|
|
97
|
+
];
|
|
98
|
+
let hasDefault = false;
|
|
99
|
+
for (const exportName in mod) {
|
|
100
|
+
if (exportName === "default") {
|
|
101
|
+
hasDefault = true;
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
lines.push(`export const ${exportName} = __omp_bundled[${JSON.stringify(exportName)}];`);
|
|
105
|
+
}
|
|
106
|
+
if (hasDefault) {
|
|
107
|
+
lines.push("export default __omp_bundled.default;");
|
|
108
|
+
}
|
|
109
|
+
lines.push("");
|
|
110
|
+
return lines.join("\n");
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Build the synthetic ES module source served for an
|
|
115
|
+
* `omp-legacy-pi-bundled:<key>` import. Enumerates the live module namespace
|
|
116
|
+
* so legacy extensions see the same named/default exports they would have
|
|
117
|
+
* gotten from a real `file://` load — without touching the inaccessible bunfs
|
|
118
|
+
* filesystem.
|
|
119
|
+
*/
|
|
120
|
+
async function synthesizeBundledModuleSource(registryKey: string): Promise<string> {
|
|
121
|
+
const registry = await ensureBundledRegistryLoaded();
|
|
122
|
+
return synthesizeBundledModuleSourceFromRegistry(registryKey, registry);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Test seam: builds the synthetic ES module source for a virtual specifier
|
|
127
|
+
* against an explicit registry. Pure (no globalThis read); the emitted source
|
|
128
|
+
* still routes runtime lookups through `globalThis[BUNDLED_REGISTRY_GLOBAL]`.
|
|
129
|
+
*/
|
|
130
|
+
export function __synthesizeLegacyPiBundledSourceWithRegistry(
|
|
131
|
+
registryKey: string,
|
|
132
|
+
registry: Readonly<Record<string, Readonly<Record<string, unknown>>>>,
|
|
133
|
+
): string {
|
|
134
|
+
return synthesizeBundledModuleSourceFromRegistry(registryKey, registry);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Test seam: returns the globalThis key the synthetic loader reads from. Tests
|
|
139
|
+
* assert that the emitted source addresses the exact stash key the install
|
|
140
|
+
* function writes to, so a rename can't break extension loads silently.
|
|
141
|
+
*/
|
|
142
|
+
export function __getLegacyPiBundledRegistryGlobal(): string {
|
|
143
|
+
return BUNDLED_REGISTRY_GLOBAL;
|
|
144
|
+
}
|
|
145
|
+
|
|
8
146
|
// Canonical scope for in-process pi packages. Plugins published against any of
|
|
9
147
|
// the aliased scopes below (mariozechner's original publish, earendil-works'
|
|
10
148
|
// fork, or the canonical @oh-my-pi scope itself) are remapped to this scope and
|
|
@@ -73,57 +211,14 @@ const PACKAGE_IMPORT_EXCLUDED = Symbol("packageImportExcluded");
|
|
|
73
211
|
// not provide and plugins relying on them must vendor TypeBox directly.
|
|
74
212
|
const TYPEBOX_SPECIFIER_FILTER = /^(?:@sinclair\/typebox|typebox)$/;
|
|
75
213
|
|
|
76
|
-
// Compat
|
|
77
|
-
//
|
|
78
|
-
//
|
|
79
|
-
//
|
|
80
|
-
//
|
|
81
|
-
//
|
|
82
|
-
//
|
|
83
|
-
//
|
|
84
|
-
// and a hardcoded POSIX literal would normalize to `\$bunfs\root\…` and fail
|
|
85
|
-
// to resolve. Compiled Bun modules currently report the bunfs root itself from
|
|
86
|
-
// `import.meta.dir`, so appending `packages` lands on the `--root ../..`
|
|
87
|
-
// package directory used by `scripts/build-binary.ts`.
|
|
88
|
-
//
|
|
89
|
-
// Every shim listed below must also be registered as an explicit `--compile`
|
|
90
|
-
// entrypoint in `scripts/build-binary.ts` or release builds fail with
|
|
91
|
-
// missing-module errors. Non-shim bundled packages are resolved via
|
|
92
|
-
// `Bun.resolveSync` (see `resolveCanonicalPiSpecifier`) outside compiled mode,
|
|
93
|
-
// so they keep working when on-disk layout differs from the monorepo tree.
|
|
94
|
-
/**
|
|
95
|
-
* Compute the bunfs package root from the compiled binary's `import.meta.dir`
|
|
96
|
-
* (or any stand-in supplied by tests). Bun compiled binaries report one of:
|
|
97
|
-
*
|
|
98
|
-
* - the bunfs mount root itself — `/$bunfs/root` or `<drive>:\~BUN\root` (Bun
|
|
99
|
-
* 1.2.x and early 1.3.x). Append `packages` for the canonical layout.
|
|
100
|
-
* - the bunfs mount root followed by the binary's basename — `//root/<bin>`
|
|
101
|
-
* on POSIX or `<drive>:\~BUN\root\<bin>.exe` on Windows (observed on Bun
|
|
102
|
-
* 1.3.14 with the cross-compiled `omp-darwin-arm64` release asset — issue
|
|
103
|
-
* #3329). The trailing segment is stripped so the result still lands on
|
|
104
|
-
* `<root>/packages`.
|
|
105
|
-
* - the module's own source directory if a future Bun release switches to
|
|
106
|
-
* module-specific `import.meta.dir` values:
|
|
107
|
-
* `<bunfs>/packages/coding-agent/src/extensibility/plugins`.
|
|
108
|
-
* The bunfs-root-with-binary branch slices the original `metaDir`, and
|
|
109
|
-
* `bunfsPath` uses a matching double-slash-preserving join, so the bunfs-native
|
|
110
|
-
* prefix is preserved verbatim — `path.posix.join` collapses `//root` to
|
|
111
|
-
* `/root`, but Bun's bunfs lookup is keyed on the exact `//root` form.
|
|
112
|
-
*
|
|
113
|
-
* Exported for tests; production callers use `BUNFS_PACKAGE_ROOT` below.
|
|
114
|
-
*/
|
|
115
|
-
export function __computeBunfsPackageRoot(metaDir: string, pathImpl: typeof path = path): string {
|
|
116
|
-
const pluginsDirSuffix = pathImpl.join("packages", "coding-agent", "src", "extensibility", "plugins");
|
|
117
|
-
const normalizedMetaDir = pathImpl.normalize(metaDir);
|
|
118
|
-
if (normalizedMetaDir.endsWith(pluginsDirSuffix)) {
|
|
119
|
-
return pathImpl.resolve(metaDir, "..", "..", "..", "..");
|
|
120
|
-
}
|
|
121
|
-
const parent = pathImpl.dirname(metaDir);
|
|
122
|
-
if (pathImpl.basename(pathImpl.normalize(parent)) === "root") {
|
|
123
|
-
return `${parent + pathImpl.sep}packages`;
|
|
124
|
-
}
|
|
125
|
-
return pathImpl.join(metaDir, "packages");
|
|
126
|
-
}
|
|
214
|
+
// Compat-shim path resolution. In compiled-binary mode every bundled surface
|
|
215
|
+
// is served through the `omp-legacy-pi-bundled:` virtual namespace (see the
|
|
216
|
+
// registry block above) — bunfs paths are unreachable on Bun 1.3.14+, so the
|
|
217
|
+
// pre-#3423 helpers that derived `/$bunfs/root/...` paths from
|
|
218
|
+
// `import.meta.dir` are gone. Dev / source-link / installed-package modes
|
|
219
|
+
// still need a real filesystem path for the source shims, which
|
|
220
|
+
// `sourceShimPath` computes either from the npm prebuilt `dist/cli.js`
|
|
221
|
+
// bundle (`PI_BUNDLED=true`) or directly from the monorepo source tree.
|
|
127
222
|
|
|
128
223
|
/**
|
|
129
224
|
* Compute the package root for the npm prebuilt `dist/cli.js` bundle.
|
|
@@ -147,35 +242,6 @@ export function __computeBundledSelfPackageRoot(metaDir: string, pathImpl: typeo
|
|
|
147
242
|
return pathImpl.resolve(metaDir);
|
|
148
243
|
}
|
|
149
244
|
|
|
150
|
-
const BUNFS_PACKAGE_ROOT = IS_COMPILED_BINARY ? __computeBunfsPackageRoot(import.meta.dir) : null;
|
|
151
|
-
|
|
152
|
-
/**
|
|
153
|
-
* Join a computed bunfs package root with descendants without collapsing
|
|
154
|
-
* Bun's POSIX `//root` mount prefix.
|
|
155
|
-
*
|
|
156
|
-
* Exported for tests; production callers use `bunfsPath` below.
|
|
157
|
-
*/
|
|
158
|
-
export function __joinBunfsPath(root: string, segments: readonly string[], pathImpl: typeof path = path): string {
|
|
159
|
-
const joined = pathImpl.join(root, ...segments);
|
|
160
|
-
const doubleRootPrefix = pathImpl.sep + pathImpl.sep;
|
|
161
|
-
const tripleRootPrefix = doubleRootPrefix + pathImpl.sep;
|
|
162
|
-
if (
|
|
163
|
-
root.startsWith(doubleRootPrefix) &&
|
|
164
|
-
!root.startsWith(tripleRootPrefix) &&
|
|
165
|
-
!joined.startsWith(doubleRootPrefix)
|
|
166
|
-
) {
|
|
167
|
-
return pathImpl.sep + joined;
|
|
168
|
-
}
|
|
169
|
-
return joined;
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
function bunfsPath(...segments: string[]): string {
|
|
173
|
-
if (!BUNFS_PACKAGE_ROOT) {
|
|
174
|
-
throw new Error("bunfsPath is only valid in compiled-binary mode");
|
|
175
|
-
}
|
|
176
|
-
return __joinBunfsPath(BUNFS_PACKAGE_ROOT, segments);
|
|
177
|
-
}
|
|
178
|
-
|
|
179
245
|
function resolveBundledSelfPackageRoot(): string | undefined {
|
|
180
246
|
if (!process.env.PI_BUNDLED) return undefined;
|
|
181
247
|
return __computeBundledSelfPackageRoot(import.meta.dir);
|
|
@@ -189,9 +255,36 @@ function sourceShimPath(file: string): string {
|
|
|
189
255
|
: path.resolve(import.meta.dir, "..", file);
|
|
190
256
|
}
|
|
191
257
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
258
|
+
/**
|
|
259
|
+
* Resolve the path the TypeBox compatibility shim ships at, then drop it when
|
|
260
|
+
* the source file is missing.
|
|
261
|
+
*
|
|
262
|
+
* In compiled-binary mode the shim is served through the
|
|
263
|
+
* `omp-legacy-pi-bundled:` virtual namespace (issue #3423) — bunfs paths are
|
|
264
|
+
* unreachable on Bun 1.3.14+, so the virtual specifier is always available and
|
|
265
|
+
* needs no filesystem probe. In dev / source-link / installed-package mode the
|
|
266
|
+
* shim is an on-disk source file; validation mirrors
|
|
267
|
+
* `__validateLegacyPiPackageRootOverrides` (#2168): if the computed candidate
|
|
268
|
+
* doesn't exist (e.g. an install that dropped the source — issue #3414),
|
|
269
|
+
* `resolveTypeBoxSpecifier` returns `undefined` and
|
|
270
|
+
* `rewriteLegacyExtensionSource` leaves bare `typebox` / `@sinclair/typebox`
|
|
271
|
+
* specifiers alone, so Bun falls through to native resolution against the
|
|
272
|
+
* extension's own `node_modules`.
|
|
273
|
+
*
|
|
274
|
+
* Exported for tests; production callers use `TYPEBOX_SHIM_PATH`.
|
|
275
|
+
*/
|
|
276
|
+
export function __resolveTypeBoxShimPath(
|
|
277
|
+
isCompiled: boolean,
|
|
278
|
+
sourcePath: string,
|
|
279
|
+
pathExistsSync: (p: string) => boolean = fs.existsSync,
|
|
280
|
+
): string | null {
|
|
281
|
+
if (isCompiled) {
|
|
282
|
+
return bundledRegistryVirtualSpecifier(TYPEBOX_BUNDLED_REGISTRY_KEY);
|
|
283
|
+
}
|
|
284
|
+
return pathExistsSync(sourcePath) ? sourcePath : null;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
const TYPEBOX_SHIM_PATH = __resolveTypeBoxShimPath(IS_COMPILED_BINARY, sourceShimPath("typebox.ts"));
|
|
195
288
|
|
|
196
289
|
// Legacy extensions historically imported `Type` (and `Static`/`TSchema`) from
|
|
197
290
|
// the package root of `@(scope)/pi-ai`. pi-ai 15.1.0 removed the runtime `Type`
|
|
@@ -201,59 +294,67 @@ const TYPEBOX_SHIM_PATH = BUNFS_PACKAGE_ROOT
|
|
|
201
294
|
// plus the borrowed `Type` runtime from the Zod-backed TypeBox shim. Subpath
|
|
202
295
|
// imports such as `@oh-my-pi/pi-ai/oauth` continue to resolve directly
|
|
203
296
|
// against the bundled pi-ai package.
|
|
204
|
-
const LEGACY_PI_AI_SHIM_PATH =
|
|
205
|
-
?
|
|
297
|
+
const LEGACY_PI_AI_SHIM_PATH = IS_COMPILED_BINARY
|
|
298
|
+
? bundledRegistryVirtualSpecifier(`${CANONICAL_PI_SCOPE}/pi-ai`)
|
|
206
299
|
: sourceShimPath("legacy-pi-ai-shim.ts");
|
|
207
300
|
|
|
208
301
|
// The coding-agent's own `./src/index.ts` cannot be listed as an extra
|
|
209
302
|
// `bun --compile` entrypoint alongside the CLI entry without breaking binary
|
|
210
|
-
// startup (issue #1474 follow-up).
|
|
211
|
-
//
|
|
212
|
-
//
|
|
213
|
-
|
|
214
|
-
|
|
303
|
+
// startup (issue #1474 follow-up). In compiled-binary mode the legacy
|
|
304
|
+
// `@(scope)/pi-coding-agent` root therefore resolves through the bundled
|
|
305
|
+
// registry shim; in dev / source-link / installed-package mode it points at
|
|
306
|
+
// the sibling source shim whose distinct file path avoids the #1474 collision
|
|
307
|
+
// while still re-exporting the canonical package surface.
|
|
308
|
+
const LEGACY_PI_CODING_AGENT_SHIM_PATH = IS_COMPILED_BINARY
|
|
309
|
+
? bundledRegistryVirtualSpecifier(`${CANONICAL_PI_SCOPE}/pi-coding-agent`)
|
|
215
310
|
: sourceShimPath("legacy-pi-coding-agent-shim.ts");
|
|
216
311
|
|
|
217
|
-
// Package-root overrides. Shim entries
|
|
218
|
-
//
|
|
219
|
-
//
|
|
220
|
-
//
|
|
221
|
-
//
|
|
222
|
-
//
|
|
223
|
-
//
|
|
312
|
+
// Package-root overrides. Shim entries (`pi-ai`, `pi-coding-agent`) always
|
|
313
|
+
// replace the canonical surface so the legacy `Type` runtime and the legacy
|
|
314
|
+
// helpers stay reachable. The bundled host packages (`pi-agent-core`,
|
|
315
|
+
// `pi-natives`, `pi-tui`, `pi-utils`) are added only in compiled-binary mode
|
|
316
|
+
// to route extensions onto the in-process module instance — in dev /
|
|
317
|
+
// source-link / installed-package mode the canonical specifier resolves
|
|
318
|
+
// cleanly through `Bun.resolveSync` and hardcoding a source-tree path would
|
|
319
|
+
// miss installs where the bundled packages live at `node_modules/@oh-my-pi/pi-*`.
|
|
224
320
|
//
|
|
225
|
-
//
|
|
226
|
-
//
|
|
227
|
-
//
|
|
228
|
-
//
|
|
229
|
-
//
|
|
230
|
-
// That catch leaves the specifier untouched so Bun resolves the canonical
|
|
231
|
-
// `@oh-my-pi/pi-*` import from the extension's own `node_modules` instead of
|
|
232
|
-
// emitting a bunfs `file://` URL to a module that isn't actually present.
|
|
321
|
+
// Compiled-binary entries are `omp-legacy-pi-bundled:<key>` specifiers handed
|
|
322
|
+
// to the synthetic onLoad in `installLegacyPiSpecifierShim()` — bunfs paths
|
|
323
|
+
// are unusable on Bun 1.3.14+ (issue #3423). Filesystem-shaped overrides are
|
|
324
|
+
// still validated against on-disk presence so a missing dev-mode shim falls
|
|
325
|
+
// through to `getResolvedSpecifier`.
|
|
233
326
|
|
|
234
327
|
/**
|
|
235
|
-
* Drop overrides whose targets are missing
|
|
236
|
-
* the canonical-resolution path.
|
|
328
|
+
* Drop overrides whose filesystem targets are missing so they can fall
|
|
329
|
+
* through to the canonical-resolution path. Virtual `omp-legacy-pi-bundled:`
|
|
330
|
+
* entries always pass — the bundled registry is the source of truth in
|
|
331
|
+
* compiled-binary mode where bunfs paths are unreachable (issue #3423).
|
|
237
332
|
*
|
|
238
|
-
* `pathExistsSync` defaults to `fs.existsSync`;
|
|
333
|
+
* `pathExistsSync` defaults to `fs.existsSync`; tests inject a stub to
|
|
239
334
|
* simulate the missing-entrypoint failure mode without touching the real FS.
|
|
240
335
|
*/
|
|
241
336
|
export function __validateLegacyPiPackageRootOverrides(
|
|
242
337
|
candidates: Record<string, string>,
|
|
243
338
|
pathExistsSync: (p: string) => boolean = fs.existsSync,
|
|
244
339
|
): Record<string, string> {
|
|
245
|
-
return Object.fromEntries(
|
|
340
|
+
return Object.fromEntries(
|
|
341
|
+
Object.entries(candidates).filter(
|
|
342
|
+
([, candidate]) => isBundledVirtualSpecifier(candidate) || pathExistsSync(candidate),
|
|
343
|
+
),
|
|
344
|
+
);
|
|
246
345
|
}
|
|
247
346
|
|
|
248
347
|
const LEGACY_PI_PACKAGE_ROOT_OVERRIDES = __validateLegacyPiPackageRootOverrides({
|
|
249
348
|
[`${CANONICAL_PI_SCOPE}/pi-ai`]: LEGACY_PI_AI_SHIM_PATH,
|
|
250
349
|
[`${CANONICAL_PI_SCOPE}/pi-coding-agent`]: LEGACY_PI_CODING_AGENT_SHIM_PATH,
|
|
251
|
-
...(
|
|
350
|
+
...(IS_COMPILED_BINARY
|
|
252
351
|
? {
|
|
253
|
-
[`${CANONICAL_PI_SCOPE}/pi-agent-core`]:
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
[`${CANONICAL_PI_SCOPE}/pi-
|
|
352
|
+
[`${CANONICAL_PI_SCOPE}/pi-agent-core`]: bundledRegistryVirtualSpecifier(
|
|
353
|
+
`${CANONICAL_PI_SCOPE}/pi-agent-core`,
|
|
354
|
+
),
|
|
355
|
+
[`${CANONICAL_PI_SCOPE}/pi-natives`]: bundledRegistryVirtualSpecifier(`${CANONICAL_PI_SCOPE}/pi-natives`),
|
|
356
|
+
[`${CANONICAL_PI_SCOPE}/pi-tui`]: bundledRegistryVirtualSpecifier(`${CANONICAL_PI_SCOPE}/pi-tui`),
|
|
357
|
+
[`${CANONICAL_PI_SCOPE}/pi-utils`]: bundledRegistryVirtualSpecifier(`${CANONICAL_PI_SCOPE}/pi-utils`),
|
|
257
358
|
}
|
|
258
359
|
: {}),
|
|
259
360
|
});
|
|
@@ -302,6 +403,12 @@ function resolveCanonicalPiSpecifier(remappedSpecifier: string): string {
|
|
|
302
403
|
}
|
|
303
404
|
|
|
304
405
|
function toImportSpecifier(resolvedPath: string): string {
|
|
406
|
+
// Virtual `omp-legacy-pi-bundled:` specifiers are served by the synthetic
|
|
407
|
+
// onLoad in `installLegacyPiSpecifierShim()`; wrapping them as `file://`
|
|
408
|
+
// would corrupt the scheme and bypass the bundled registry.
|
|
409
|
+
if (isBundledVirtualSpecifier(resolvedPath)) {
|
|
410
|
+
return resolvedPath;
|
|
411
|
+
}
|
|
305
412
|
return url.pathToFileURL(resolvedPath).href;
|
|
306
413
|
}
|
|
307
414
|
|
|
@@ -341,12 +448,17 @@ const TYPEBOX_IMPORT_SPECIFIER_REGEX = /((?:from\s+|import\s+|import\s*\(\s*)["'
|
|
|
341
448
|
*/
|
|
342
449
|
async function rewriteLegacyExtensionSource(source: string, importerPath: string): Promise<string> {
|
|
343
450
|
const withPi = rewriteLegacyPiImports(source);
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
451
|
+
// When the TypeBox shim is missing (release build dropped the entrypoint —
|
|
452
|
+
// issue #3414), leave bare specifiers untouched so Bun resolves a real
|
|
453
|
+
// `typebox` / `@sinclair/typebox` install from the extension's own
|
|
454
|
+
// `node_modules`. `resolveTypeBoxSpecifier` mirrors the fall-through.
|
|
455
|
+
const withTypeBox = TYPEBOX_SHIM_PATH
|
|
456
|
+
? withPi.replace(
|
|
457
|
+
TYPEBOX_IMPORT_SPECIFIER_REGEX,
|
|
458
|
+
(_match, prefix: string, _specifier: string, suffix: string) =>
|
|
459
|
+
`${prefix}${toImportSpecifier(TYPEBOX_SHIM_PATH)}${suffix}`,
|
|
460
|
+
)
|
|
461
|
+
: withPi;
|
|
350
462
|
return rewriteExtensionPackageImports(withTypeBox, importerPath);
|
|
351
463
|
}
|
|
352
464
|
|
|
@@ -719,8 +831,8 @@ function resolveLegacyPiSpecifier(args: { path: string; importer: string }): { p
|
|
|
719
831
|
}
|
|
720
832
|
}
|
|
721
833
|
|
|
722
|
-
function resolveTypeBoxSpecifier(): { path: string } {
|
|
723
|
-
return { path: TYPEBOX_SHIM_PATH };
|
|
834
|
+
function resolveTypeBoxSpecifier(): { path: string } | undefined {
|
|
835
|
+
return TYPEBOX_SHIM_PATH ? { path: TYPEBOX_SHIM_PATH } : undefined;
|
|
724
836
|
}
|
|
725
837
|
|
|
726
838
|
export function installLegacyPiSpecifierShim(): void {
|
|
@@ -734,6 +846,12 @@ export function installLegacyPiSpecifierShim(): void {
|
|
|
734
846
|
setup(build) {
|
|
735
847
|
build.onResolve({ filter: LEGACY_PI_SPECIFIER_FILTER, namespace: "file" }, resolveLegacyPiSpecifier);
|
|
736
848
|
build.onResolve({ filter: TYPEBOX_SPECIFIER_FILTER, namespace: "file" }, resolveTypeBoxSpecifier);
|
|
849
|
+
// Compiled-binary mode: serve `omp-legacy-pi-bundled:<key>` imports
|
|
850
|
+
// from the JS-heap registry. The rewrite path emits these specifiers
|
|
851
|
+
// in place of unreachable `file:///$bunfs/...` URLs (issue #3423).
|
|
852
|
+
build.onLoad({ filter: /.*/, namespace: BUNDLED_VIRTUAL_NAMESPACE }, async args => {
|
|
853
|
+
return { contents: await synthesizeBundledModuleSource(args.path), loader: "js" };
|
|
854
|
+
});
|
|
737
855
|
},
|
|
738
856
|
});
|
|
739
857
|
}
|