From c72b88cad41505ea0963699d1753f43276e8ed2e Mon Sep 17 00:00:00 2001 From: JUN Date: Mon, 28 Sep 2026 00:24:45 +0900 Subject: [PATCH] fix(standalone): recognize encoded Bun virtual module URLs Reimplements the isolated standalone URL detection fix from #6079 on dev. Hostless file URLs can decode one layer to recognize Windows ~BUN while source and network-host URLs remain outside the compiled-binary path. Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com> --- src/lib/standalone.ts | 10 +++++++++- structure/INDEX.md | 2 +- structure/manifest.json | 1 + structure/ops/service-and-sidecars.md | 9 ++++++--- tests/lib/standalone.test.ts | 13 +++++++++++++ 5 files changed, 30 insertions(+), 5 deletions(-) diff --git a/src/lib/standalone.ts b/src/lib/standalone.ts index 72cc9f36183..efd397bd3bc 100644 --- a/src/lib/standalone.ts +++ b/src/lib/standalone.ts @@ -7,7 +7,15 @@ export function isStandaloneBinary(): boolean { } export function isStandaloneModuleUrl(url: string): boolean { - return url.includes("/$bunfs/") || /^file:\/\/\/[A-Za-z]:\/~BUN\//.test(url); + try { + const parsed = new URL(url); + if (parsed.protocol !== "file:" || parsed.host !== "") return false; + // Bun may encode the Windows virtual root's tilde; decode one URL layer only. + const path = decodeURIComponent(parsed.pathname); + return path.startsWith("/$bunfs/") || /^\/[A-Za-z]:\/~BUN\//.test(path); + } catch { + return false; + } } /** Directory containing the compiled executable and its copied runtime assets. */ diff --git a/structure/INDEX.md b/structure/INDEX.md index d1a258a6810..a0dbbf3ea74 100644 --- a/structure/INDEX.md +++ b/structure/INDEX.md @@ -132,7 +132,7 @@ A source area can be described by more than one doc, because these docs are orga | `src/index.ts` | [`runtime.md`](runtime.md) | | `src/integrations/` | [`clients/integrations.md`](clients/integrations.md) | | `src/lab/` | [`runtime.md`](runtime.md)
[`adapters/compatibility-lab.md`](adapters/compatibility-lab.md) | -| `src/lib/` | [`overview.md`](overview.md)
[`runtime.md`](runtime.md)
[`transports/byte-accounting.md`](transports/byte-accounting.md)
[`transports/responses-wire-shapes.md`](transports/responses-wire-shapes.md)
[`transports/responses-failover.md`](transports/responses-failover.md)
[`transports/responses-spend.md`](transports/responses-spend.md)
[`transports/inventory.md`](transports/inventory.md)
[`gui-and-management-api.md`](gui-and-management-api.md)
[`dashboard-and-usage.md`](dashboard-and-usage.md)
[`clients/integrations.md`](clients/integrations.md)
[`ops/docs-and-release.md`](ops/docs-and-release.md) | +| `src/lib/` | [`overview.md`](overview.md)
[`runtime.md`](runtime.md)
[`transports/byte-accounting.md`](transports/byte-accounting.md)
[`transports/responses-wire-shapes.md`](transports/responses-wire-shapes.md)
[`transports/responses-failover.md`](transports/responses-failover.md)
[`transports/responses-spend.md`](transports/responses-spend.md)
[`transports/inventory.md`](transports/inventory.md)
[`gui-and-management-api.md`](gui-and-management-api.md)
[`dashboard-and-usage.md`](dashboard-and-usage.md)
[`clients/integrations.md`](clients/integrations.md)
[`ops/service-and-sidecars.md`](ops/service-and-sidecars.md)
[`ops/docs-and-release.md`](ops/docs-and-release.md) | | `src/link/` | [`remote-link.md`](remote-link.md) | | `src/oauth/` | [`runtime.md`](runtime.md)
[`transports/inventory.md`](transports/inventory.md)
[`providers-and-adapters.md`](providers-and-adapters.md)
[`providers/xai-grok.md`](providers/xai-grok.md) | | `src/plugins/` | [`ops/plugins.md`](ops/plugins.md) | diff --git a/structure/manifest.json b/structure/manifest.json index 5201bb9bf71..0057a6464e4 100644 --- a/structure/manifest.json +++ b/structure/manifest.json @@ -450,6 +450,7 @@ "title": "Background Service And Sidecars", "scope": "Service install/repair, platform launchers, tray, and sidecar processes.", "documents": [ + "src/lib/", "src/server/", "src/service-manager-probe.ts", "src/sidecar/", diff --git a/structure/ops/service-and-sidecars.md b/structure/ops/service-and-sidecars.md index 8a2d164a7f6..e2a6f218789 100644 --- a/structure/ops/service-and-sidecars.md +++ b/structure/ops/service-and-sidecars.md @@ -233,9 +233,12 @@ The service loads the optional `compactionRouting` block from persisted configur [Responses ingress](../transports/responses-failover.md#compaction-routing-overrides) applies it to individual compaction requests whose trigger the block names. -Standalone binaries use `src/lib/standalone.ts` to detect the Bun `$bunfs` runtime and -`src/service/state.ts` to compose durable service commands as ` start`, without a -source-tree CLI path. The copied `gui/dist` directory is located by `src/server/gui-static.ts`; +Standalone binaries use `src/lib/standalone.ts` to recognize hostless `file:` module URLs +whose decoded pathname begins at Bun's `$bunfs` or Windows `~BUN` virtual root. The helper +decodes one URL layer, so encoded Windows tildes work while network-host and nested source +paths do not impersonate a bundled module. `src/service/state.ts` composes durable service +commands as ` start`, without a source-tree CLI path. The copied `gui/dist` +directory is located by `src/server/gui-static.ts`; `OPENCODEX_GUI_DIST` remains an explicit override. ## Bun updater ownership transaction diff --git a/tests/lib/standalone.test.ts b/tests/lib/standalone.test.ts index d58c3a7aa0d..b8d29b70a6e 100644 --- a/tests/lib/standalone.test.ts +++ b/tests/lib/standalone.test.ts @@ -17,6 +17,19 @@ test("compiled module URL markers are recognized on POSIX and Windows", () => { expect(isStandaloneModuleUrl("file:///Users/x/src/lib/standalone.ts")).toBe(false); }); +test("encoded Windows Bun virtual roots are recognized once", () => { + expect(isStandaloneModuleUrl("file:///B:/%7EBUN/root/ocx.exe")).toBe(true); + expect(isStandaloneModuleUrl("file:///B:/%7eBUN/root/ocx.exe")).toBe(true); + expect(isStandaloneModuleUrl("file:///B:/%257EBUN/root/ocx.exe")).toBe(false); +}); + +test("network hosts and nested Bun markers remain source URLs", () => { + expect(isStandaloneModuleUrl("file://server/$bunfs/root/index.ts")).toBe(false); + expect(isStandaloneModuleUrl("file:///Users/x/$bunfs/root/index.ts")).toBe(false); + expect(isStandaloneModuleUrl("https://example.test/$bunfs/root/index.ts")).toBe(false); + expect(isStandaloneModuleUrl("file:///B:/%XXBUN/root/index.ts")).toBe(false); +}); + test("standaloneRoot follows the running executable", () => { expect(standaloneRoot()).toBe(dirname(realpathSync(process.execPath))); });