Bun compatibility: top-level `node:sea` import in index.js and sdk/index.js fails resolve step
- Ngôn ngữ chính
- Shell
- Star
- 11.2k
- Fork
- 1.9k
- Merge trung bình
- 14 giờ 16 phút
- Pull request đã merge (30 ngày)
- 6
Mô tả
### 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.
Hướng dẫn đóng góp
Hướng nghiên cứu
Start with the top-level imports in index.js:7 and sdk/index.js:~4123, then inspect the auto-update checks described as ELt() and the existing createRequire patterns for vendored modules. Reproduce the failure with the Bun import command in the issue. Done means both entrypoints resolve under Bun, the SEA check reports false there, and the existing non-SEA update branch remains intact.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Đánh giá
- Công nghệ
- bun, javascript, node.js
- Lĩnh vực
- cli
- Loại issue
- Lỗi
- Độ khó
- 3/5
- Thời gian dự kiến
- 1-2 ngày
- Mức độ hoạt động
- Ít trao đổi
- Độ rõ ràng
- Khá rõ ràng
- Mức phù hợp với người mới
- 58/100