github / github/copilot-cli

[BUG]: extensions_reload and extensions_manage tools deadlock permanently when project has a joinSession() extension

Ouverte
#2,348 0 commentaires 0 réactions 0 personnes assignées Voir sur GitHub
area:plugins
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

Calling `extensions_reload` or `extensions_manage` tools in a session where a project-level extension (using `joinSession()` from `@github/copilot-sdk/extension`) is active results in a permanent hang that requires the user to manually cancel the tool call. The CLI never recovers from the hang — the tool call must be interrupted every time.

### Root cause analysis

The deadlock is caused by a circular IPC dependency during the reload sequence:

1. `extensions_reload` is invoked → the CLI main process **blocks synchronously**, waiting for the reload to complete.
2. The existing extension subprocess is terminated.
3. A new `extension_bootstrap.mjs` subprocess is spawned and loads the extension module.
4. The extension module calls `await joinSession()` at the top level — this sends a handshake message **back to the CLI main process** to register tools and establish the session.
5. The CLI main process **cannot respond** to the handshake because it is blocked in step 1.
6. → **Permanent deadlock**: parent waits for child, child waits for parent.

The same deadlock occurs with `extensions_manage` because it goes through the same extension management subsystem.

### Affected version

GitHub Copilot CLI `1.0.12`

### Steps to reproduce

1. Create a project-level extension in `.github/extensions/my-ext/extension.mjs` with a top-level `await joinSession(...)` call (standard SDK pattern from the documentation).
2. Start a Copilot CLI session in that project directory. The extension loads successfully.
3. In the session, call the `extensions_reload` tool (or `extensions_manage` with operation `list`/`inspect`).
4. Observe: the tool call **never returns**. The CLI is permanently unresponsive until the tool call is manually cancelled.
5. Repeat step 3 after cancelling — same result every time.

### Expected behavior

- `extensions_reload` should complete successfully and the extension should be re-registered.
- If the reload mechanism requires a subprocess handshake, the main process should handle IPC messages asynchronously (non-blocking) during the reload wait, so the new extension subprocess can complete its `joinSession()` registration.

### Additional context

**Environment:**
- OS: Linux (Ubuntu)
- Copilot CLI version: `1.0.12`
- Extension type: project-level (`.github/extensions/`), JS/ESM, using `@github/copilot-sdk/extension`

**Workaround:**
- Skills and agent `.md` files are effective immediately on save (no reload needed).
- For changes to `extension.mjs` JS code: close the terminal and re-open a new session.

**Process evidence** (at time of hang):
```
# Two extension_bootstrap.mjs subprocesses observed — both blocked
PID 230448 EXTENSION_PATH=.github/extensions/my-ext/extension.mjs COPILOT_LOADER_PID=230374
PID 245405 EXTENSION_PATH=.github/extensions/my-ext/extension.mjs COPILOT_LOADER_PID=210913

# stdin/stdout of each subprocess are sockets (IPC channels), confirming the
# joinSession() handshake is attempted but the parent is not reading from them.
fd 0 -> socket:[...]
fd 1 -> socket:[...]
```

Guide de contribution

Ouvrir le guide de contribution

Évaluation

Cette issue n'a pas encore été évaluée.

Recevez les nouvelles issues par e-mail

Un résumé court des issues GitHub adaptées aux débutants.