Bun compatibility: top-level `node:sea` import in index.js and sdk/index.js fails resolve step
- 主要语言
- Shell
- 星标
- 11.2k
- 派生
- 1.9k
- 平均合并
- 14 小时 16 分钟
- 30 天内合并 PR
- 6
描述
### 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.
贡献指南
调研方向
从 index.js:7 和 sdk/index.js:~4123 中的顶层 imports 开始,然后检查描述为 ELt() 的自动更新检查,以及现有的、用于 vendored modules 的 createRequire 模式。使用 issue 中的 Bun import 命令重现该故障。完成的标准是:两个 entrypoints 都能在 Bun 下解析,SEA 检查在其中报告 false,并且现有的 non-SEA 更新分支保持不变。
由索引模型根据 Issue 内容生成。
评估
- 技术栈
- bun, javascript, node.js
- 领域
- cli
- Issue 类型
- 缺陷
- 难度
- 3/5
- 预计耗时
- 1-2 天
- 活跃度
- 冷清
- 描述清晰度
- 基本清楚
- 新手友好度
- 58/100