From 3b9b3422ceaada06d3638eadb2f36ca22ca7ed94 Mon Sep 17 00:00:00 2001 From: Alezander9 Date: Wed, 29 Apr 2026 23:50:47 -0700 Subject: [PATCH] fix(bcode-browser): detect compiled mode on Windows; pre-flight harnessDir The bunfs root is /$bunfs/ on POSIX but B:\~BUN\ on Windows (native separators), so `__dirname.startsWith("B:/~BUN/")` was always false in Windows compiled binaries. Result: isCompiled=false, resolveHarnessDir returned the dev path which doesn't exist on installs, the harness was never extracted, and every spawn failed with cwd=ENOENT. Bun's spawn attributes that ENOENT to path="uv", so isUvMissing matched and the agent reported a misleading 'uv not on PATH' error -- even though uv was installed and on PATH. Two fixes: 1. harness.ts: normalize __dirname to forward slashes before the bunfs prefix check, so the same comparison works on Windows and POSIX. 2. browser-execute.ts: fs.access(harnessDir) before spawn. If the directory is missing, fail with a clear message instead of falling into the spawn-ENOENT path that gets misclassified as uv-missing. Reproduced on Windows 11 with v0.0.5 binary (and a locally-built one). Pre-fix: ~/.cache/bcode/harness was never created; agent reported uv missing despite uv being installed and on PATH. Post-fix: harness extracts on first run, agent attaches to Chrome, end-to-end browser_execute works. --- packages/bcode-browser/src/browser-execute.ts | 7 +++++++ packages/bcode-browser/src/harness.ts | 10 +++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/packages/bcode-browser/src/browser-execute.ts b/packages/bcode-browser/src/browser-execute.ts index 944673dff..e5bc164d2 100644 --- a/packages/bcode-browser/src/browser-execute.ts +++ b/packages/bcode-browser/src/browser-execute.ts @@ -92,6 +92,13 @@ export const make = Effect.fn("BrowserExecute.make")(function* () { const execute = (args: Parameters, ctx: ExecuteContext) => Effect.gen(function* () { const harnessDir = yield* Effect.promise(() => resolveHarnessDir()) + // Pre-flight check on harnessDir: spawn ENOENT on a missing cwd surfaces + // with `path: "uv"` on Bun/Windows, which is indistinguishable from a + // truly-missing uv. Catch it here so the user gets the real cause + // instead of a misleading "uv not on PATH" hint. + if (!(yield* Effect.promise(() => fs.access(harnessDir).then(() => true, () => false)))) { + return yield* Effect.fail(new Error(`harness directory not found at ${harnessDir} — bcode build is broken; please reinstall`)) + } yield* Effect.promise(() => fs.mkdir(ctx.bhTmpDir, { recursive: true })) const uv = yield* locate const proc = ChildProcess.make( diff --git a/packages/bcode-browser/src/harness.ts b/packages/bcode-browser/src/harness.ts index f75d1d07e..8d3b03e6d 100644 --- a/packages/bcode-browser/src/harness.ts +++ b/packages/bcode-browser/src/harness.ts @@ -37,7 +37,15 @@ import path from "path" import { fileURLToPath } from "url" const __dirname = path.dirname(fileURLToPath(import.meta.url)) -const isCompiled = __dirname.startsWith("/$bunfs/") || __dirname.startsWith("B:/~BUN/") +// Bun's bunfs root is `/$bunfs/` on POSIX and `B:\~BUN\` on Windows (native +// separators). Normalize before comparing so the compiled-mode check works on +// both platforms — without this, the Windows compiled binary falls through to +// DEV_HARNESS_DIR (which doesn't exist on the user's machine) and every +// subsequent spawn fails with a misleading uv-missing error. +const isCompiled = (() => { + const d = __dirname.replaceAll("\\", "/") + return d.startsWith("/$bunfs/") || d.startsWith("B:/~BUN/") +})() const DEV_HARNESS_DIR = path.resolve(__dirname, "..", "harness") const cachedHarnessDir = path.join(os.homedir(), ".cache", "bcode", "harness")