Bun compatibility: top-level `node:sea` import in index.js and sdk/index.js fails resolve step
- Langage dominant
- Shell
- Étoiles
- 11.2k
- Forks
- 1.9k
- Merge moyen
- 14 h 16 min
- PR mergées (30 j)
- 6
Description
### Describe the bug
`@github/copilot@1.0.34` has unconditional top-level imports of `node:sea` in both of its entrypoint files:
- `index.js:7` is the CLI main entry, used when `npm-loader.js` falls back to `import("./index.js")` (the non-SEA install path).
- `sdk/index.js:~4123` is exposed via the `"./sdk"` field in `exports`. That subpath is the resolve target `@github/copilot-sdk`'s `getBundledCliPath()` uses to locate the CLI.
Both imports serve a single purpose: `X.isSea()` is called by the auto-update logic (`ELt()` in `sdk/index.js`, similar in `index.js`) to short-circuit with `"Update not supported when running js directly"` when the CLI is not running from a Single Executable Application.
Because the import is top-level, non-Node runtimes that don't implement `node:sea` fail at resolve time, before any code runs. A try/catch around the import does not help: this is a module-graph error, not a runtime exception. Bun's current [nodejs-compat doc](https://github.com/oven-sh/bun/blob/main/docs/runtime/nodejs-compat.mdx) does not list `node:sea` (SEA is a Node-specific packaging API, so this is expected).
### Affected version
`@github/copilot@1.0.34` (latest as of 2026-04-22).
Reproduced on: Bun 1.3.13 Linux x64, Node subprocess chain working normally but index.js loaded under Bun.
### Steps to reproduce
Minimum:
```bash
mkdir bun-copilot-repro && cd bun-copilot-repro
bun init -y
bun add @github/copilot
bun -e 'await import("./node_modules/@github/copilot/index.js")'
```
Output:
```
error: No such built-in module: node:sea
Bun v1.3.13 (Linux x64)
```
User-facing symptom from the wild: [cassidoo/emoji-list-generator#1](https://github.com/cassidoo/emoji-list-generator/issues/1). Reporter runs `bun start` on a TUI project that depends on `@github/copilot-sdk`. When the CLI subprocess is invoked, stderr shows:
```
error: Could not resolve: "node:sea". Maybe you need to "bun install"?
at .../node_modules/@github/copilot/index.js:7:390
```
The SDK already contains a Bun workaround: `getNodeExecPath()` in `@github/copilot-sdk`'s `client.js` returns `"node"` (as a PATH lookup) when `process.versions.bun` is set, so it tries to spawn actual Node. This works on systems where `node` in PATH really is Node. It breaks when `node` is aliased or shimmed to `bun`, which is common on Bun-first Mac setups, and leaves the CLI's index.js being parsed by Bun at the `node:sea` import.
### Expected behavior
The `node:sea` import should not prevent the module from being resolved on runtimes where `node:sea` is not implemented. Under those runtimes, `isSea()` should return `false` (SEA is Node-only by definition) and the auto-updater should take its existing "not running SEA" branch.
### Suggested fix
Three shapes, least invasive first:
1. **Lazy `createRequire`.** Replace the top-level import with a function-scoped resolver:
```js
import { createRequire } from "node:module";
function getSeaModule() {
try { return createRequire(import.meta.url)("node:sea"); }
catch { return null; }
}
function isSea() { return getSeaModule()?.isSea() ?? false; }
```
`node:module` resolves fine on Bun; the inner require returns `null` on runtimes where `node:sea` isn't available.
2. **Dynamic import inside the checker.** `async function isSea() { try { const sea = await import("node:sea"); return sea.isSea(); } catch { return false; } }`. More invasive because callers become async.
3. **Top-level runtime guard.** `if (!globalThis.Bun && !process.versions.bun) { /* import node:sea here */ }` with conditional module-scope binding. Reads cleaner at the top of the file but doesn't cover hypothetical future non-Node runtimes that also lack SEA.
Option (1) is the smallest change and matches the `createRequire` pattern already used for vendored native modules (`sharp`, `clipboard`) in `sdk/index.js`.
### Additional context
- Adjacent Bun-compat rough edge in the same bundle (separate issue, not covered by the above fix): the bundled `undici` feature-detection at `sdk/index.js:~211` wraps `require("node:sqlite")` in a try/catch that only recognizes `ERR_UNKNOWN_BUILTIN_MODULE` / `ERR_NO_CRYPTO`. Bun throws a different error shape ("No such built-in module") without those codes, so the catch doesn't degrade gracefully. Loading `sdk/index.js` under Bun fails on the `node:sqlite` layer first; fixing `node:sea` alone would surface the `node:sqlite` error next. Worth a second issue against undici upstream if the scope here is CLI-only.
- Reference pattern in the wild: [mcp-use/mcp-use#1382](https://github.com/mcp-use/mcp-use/pull/1382) applies the `globalThis.Bun || process.versions.bun` two-check guard for a different Node-only dependency (`tsx/esm/api` loader hooks); same shape, different builtin.
- OS: macOS arm64 (reporter) / Linux x86_64 (my repro). Both hit the same `index.js:7` failure.
Guide de contribution
Ouvrir le guide de contribution
Piste de recherche
Commencez par les imports de niveau supérieur dans index.js:7 et sdk/index.js:~4123, puis examinez les vérifications de mise à jour automatique décrites comme ELt() ainsi que les patterns createRequire existants pour les vendored modules. Reproduisez l’échec avec la commande d’importation Bun indiquée dans l’issue. C’est terminé lorsque les deux entrypoints se résolvent sous Bun, que la vérification SEA renvoie false dans ce contexte et que la branche de mise à jour existante pour le non-SEA reste intacte.
Rédigé par le modèle d'indexation à partir du texte de l'issue.
Évaluation
- Stack technique
- bun, javascript, node.js
- Domaine
- cli
- Type d'issue
- Bug
- Difficulté
- 3/5
- Temps estimé
- 1-2 jours
- Activité
- Calme
- Clarté
- Plutôt claire
- Accessibilité débutants
- 58/100