Extension command.execute can be accepted but never delivered, hanging slash-command invocation
- Lenguaje dominante
- Java
- Estrellas
- 10.5k
- Forks
- 1.5k
- Merge medio
- 1 d 11 h
- PR fusionados (30 d)
- 127
Descripción
> Drafted by GIthub Copilot with human review.
## Summary
An extension slash command can be recognized by Copilot CLI and dispatched as `command.execute`, yet never reach the owning extension handler. The invocation then hangs silently because the runtime waits indefinitely for `session.commands.handlePendingCommand` and no timeout or delivery error is surfaced.
This is exposed through the public extension SDK, but the captured failure occurs in runtime command-event routing before SDK handler entry. Please triage as a runtime-root-cause bug.
## Environment
- Copilot CLI: `1.0.84-8`
- OS: Windows 11
- Extension API: `@github/copilot-sdk/extension` via `joinSession({ commands: [...] })`
- Reproduced: September 15, 2026
## Reproduction
1. Load an extension that registers a slash command through `joinSession`, for example:
```js
await joinSession({
commands: [{
name: "bookmarks",
description: "Open the session bookmark manager",
handler: async () => {
// Instrument handler entry here.
},
}],
});
```
2. Reload extensions.
3. Confirm the extension reaches `=== ready ===` and can service another registered callback. In this reproduction, its canvas provider successfully handled rehydration.
4. Invoke `/bookmarks` interactively.
## Actual behavior
- CLI recognizes and invokes the registered slash command.
- Runtime emits `command.execute` event ID `537170aa-2e69-41b6-a37b-ad0e505ea166`.
- The detached host-delivery queue starts and reports successful completion.
- The owning extension never enters the command handler.
- No `command.completed` event is emitted.
- No `No client found for command` error is emitted.
- The invocation remains pending indefinitely without user-visible failure.
Relevant runtime timeline:
```text
2026-09-15T08:44:56.142Z slash_command_invoked
2026-09-15T08:44:56.143Z Detached host delivery started
delivery_kind="reserved_event"
event_type="command.execute"
event_id="537170aa-2e69-41b6-a37b-ad0e505ea166"
2026-09-15T08:44:56.146Z Detached host delivery completed
2026-09-15T08:44:56.146Z Detached host delivery retirement decision completed
```
Temporary instrumentation around command-handler entry, `session.rpc.canvas.open`, and the canvas provider confirmed that neither the command handler nor downstream canvas call was reached. The same extension process had successfully handled canvas-provider rehydration approximately 35 seconds earlier.
## Expected behavior
One of the following should happen deterministically:
1. `command.execute` reaches the registered owner, the handler runs, and `command.completed` resolves the invocation; or
2. Delivery failure/disconnection is detected and the pending invocation fails promptly with an actionable error.
A request-like control-plane event must not be considered successfully delivered merely because it was queued somewhere that may never drain.
## Suspected runtime area
Runtime source currently:
- resolves a targeted owner for `command.execute`;
- calls `publish_session_event` for that connection;
- treats an event queued in `post_response_notifications` behind a `gated_sessions` dispatch token as successfully published; and
- waits on the pending command response without a timeout.
This makes a stale or unreleased create/resume response gate one plausible mechanism: publication reports success, so no undelivered-command rejection occurs, but the owner never receives the event. The logs do not expose the connection ID or gate token, so this is a hypothesis rather than a proven precise race.
## Relationship to #2368
This appears to be a sibling or incomplete-fix path for #2368, not necessarily the identical implementation defect:
- #2368 concerned lost `external_tool.requested` events and SDK event-forwarder lag.
- This reproduction concerns targeted `command.execute` delivery after extension reload.
- Both turn a lost request-like event into an indefinite hang because no timeout or disconnect failure resolves the pending request.
## Requested fix
- Guarantee delivery or explicit rejection for targeted `command.execute` events.
- Do not treat indefinitely gated notifications as successful delivery.
- Add a bounded timeout/disconnection failure for pending command execution as defense in depth.
- Add a regression test covering extension reload/resume followed by immediate slash-command invocation.
Guía de contribución
Línea de trabajo
Start at the runtime command-event routing path, especially targeted-owner resolution, publish_session_event, post_response_notifications, gated_sessions, and the pending command response wait. Trace the extension reload/resume flow and add the requested regression coverage for immediate slash-command invocation; done means command.execute reaches its owner and completes, or delivery failure resolves promptly with an actionable error.
Escrito por el modelo de indexación a partir del texto del issue.
Evaluación
- Stack tecnológico
- javascript
- Área
- backend-api-design, distributed-systems
- Tipo de issue
- Error
- Dificultad
- 4/5
- Tiempo estimado
- 3-5 días
- Estado de actividad
- Activo
- Claridad
- Bastante claro
- Aptitud para principiantes
- 38/100