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.

貢獻指南

開啟貢獻指南

研究方向

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.

由索引模型根據 Issue 內容生成。

評估

技術堆疊
bun, javascript, node.js
領域
cli
Issue 類型
缺陷
難度
3/5
預估耗時
1-2 天
活躍度
冷清
描述清晰度
基本清楚
新手友好度
58/100

把新 issue 寄到你的電子郵件信箱

精選適合新手參與的 GitHub issue 摘要。