@@ -118,7 +118,39 @@ const cliBun = join(outdir, 'cli-bun.js')
118118const cliNode = join ( outdir , 'cli-node.js' )
119119
120120await writeFile ( cliBun , '#!/usr/bin/env bun\nimport "./cli.js"\n' )
121- await writeFile ( cliNode , '#!/usr/bin/env node\nimport "./cli.js"\n' )
121+
122+ // Node.js entry needs a Bun API polyfill because Bun.build({ target: 'bun' })
123+ // emits globalThis.Bun references (e.g. Bun.$ shell tag in computer-use-input,
124+ // Bun.which in chunk-ys6smqg9) that crash at import time under plain Node.js.
125+ const NODE_BUN_POLYFILL = `#!/usr/bin/env node
126+ // Bun API polyfill for Node.js runtime
127+ if (typeof globalThis.Bun === "undefined") {
128+ const { execFileSync } = await import("child_process");
129+ const { resolve, delimiter } = await import("path");
130+ const { accessSync, constants: { X_OK } } = await import("fs");
131+ function which(bin) {
132+ const isWin = process.platform === "win32";
133+ const pathExt = isWin ? (process.env.PATHEXT || ".EXE").split(";") : [""];
134+ for (const dir of (process.env.PATH || "").split(delimiter)) {
135+ for (const ext of pathExt) {
136+ const candidate = resolve(dir, bin + ext);
137+ try { accessSync(candidate, X_OK); return candidate; } catch {}
138+ }
139+ }
140+ return null;
141+ }
142+ // Bun.$ is the shell template tag (e.g. $\`osascript ...\`). Only used by
143+ // computer-use-input/darwin — stub it so the top-level destructuring
144+ // \`var { $ } = globalThis.Bun\` doesn't crash.
145+ function $(parts, ...args) {
146+ throw new Error("Bun.$ shell API is not available in Node.js. Use Bun runtime for this feature.");
147+ }
148+ globalThis.Bun = { which, $ };
149+ }
150+ import "./cli.js"
151+ `
152+ await writeFile ( cliNode , NODE_BUN_POLYFILL )
153+ // NOTE: when new Bun-specific globals appear in bundled output, add them here.
122154
123155// Make both executable
124156const { chmodSync } = await import ( 'fs' )
0 commit comments