github / github/copilot-cli

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

Abierto
#2,348 0 comentarios 0 reacciones 0 asignados Ver en GitHub
area:plugins
Lenguaje dominante
Shell
Estrellas
11.2k
Forks
1.9k
Merge medio
14 h 16 min
PR fusionados (30 d)
6

Descripción

### 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:[...]
```

Guía de contribución

Abrir la guía de contribución

Evaluación

Este issue todavía no se ha evaluado.

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.