github / github/copilot-cli

Bun compatibility: top-level `node:sea` import in index.js and sdk/index.js fails resolve step

未关闭
#2,894 0 条评论 1 个 reaction 已指派 0 人 在 GitHub 查看
area:installation
主要语言
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

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。