github / github/copilot-cli

Hook `async` property silently ignored — postToolUse hooks block tool completion

Aberta
#3,063 0 comentários 0 reações 0 responsáveis Ver no GitHub
area:plugins area:tools
Linguagem predominante
Shell
Estrelas
11.2k
Forks
1.9k
Merge médio
14h 16min
PRs com merge (30d)
6

Descrição

## Describe the bug

The `async` property on command hooks in `hooks.json` is silently ignored. Hooks with `"async": true` still block tool completion because `executeHooks()` unconditionally `await`s every hook in a sequential `for` loop.

Claude Code [documents `async`](https://docs.anthropic.com/en/docs/claude-code/hooks) as a supported hook field:

> **`async`** — If `true`, runs in the background without blocking.

Since plugins share the same `hooks.json` format across both Claude Code and Copilot CLI, authors reasonably expect `"async": true` to work. Instead, it is parsed by the Zod schema (via `.passthrough()`) but never read by the execution path.

## Impact

In a real session, a `postToolUse` hook with `"async": true` blocked for **13.5 seconds** on first invocation because it triggered a package auto-update (resolving 419 packages via `uv`). This added ~14s of latency to the first tool call of the session despite the hook being marked async.

**Timeline from session events:**
```
18:57:09.756 hook.start postToolUse
18:57:22.186 [hook stdout] Resolved 419 packages in 6.91s
18:57:22.803 [hook stdout] Installed 2 packages
18:57:23.216 hook.end ← 13.46s blocked
```

## Root cause

In `sdk/index.js`, the `executeHooks` function (`Yg` in minified source):

```javascript
async function executeHooks(hooks, input, logger, hookType, emitter) {
// ...
for (let hook of hooks) {
let result = await hook(input); // ← always awaits, ignores async flag
// ...
}
}
```

And in `processToolExecutionResult`:
```javascript
await executeHooks(this.getEffectiveHooks()?.postToolUse, ...) // blocks tool completion
```

The `async` property from the hook config is never propagated to the execution layer.

## Expected behavior

When a hook specifies `"async": true`, it should run in the background without blocking tool completion — matching Claude Code's documented behavior. Ideally also support `asyncRewake` for parity.

## Workaround

Plugin authors can append `&` to the shell command to background it manually, but this loses stdout/stderr capture and exit code handling.

## Environment

- Copilot CLI: 1.0.40-2
- OS: macOS (Darwin arm64)

## Related issues

- #2893 — hooks serialized + timeout fail-open (related hook execution model concerns)

Guia de contribuição

Abrir o guia de contribuição

Direção de pesquisa

Start by tracing executeHooks in sdk/index.js and its call from processToolExecutionResult, then inspect how hook configuration reaches the execution layer. Confirm how async hooks should complete in the background and what output, errors, and tool completion should look like; done means async hooks no longer block while synchronous hooks retain their current behavior.

Escrita pelo modelo de indexação a partir do texto da issue.

Avaliação

Stack de tecnologia
javascript
Domínio
cli
Tipo de issue
Bug
Dificuldade
4/5
Tempo estimado
3-5 dias
Status de atividade
Pouca atividade
Clareza
Razoavelmente clara
Facilidade para iniciantes
48/100

Receba novas issues na sua caixa de entrada

Um resumo curto de issues do GitHub para quem está começando.