pi-mono/packages/coding-agent/test/suite
Petr Houška 06aa6563e4
fix(coding-agent): report the shell exit code when bash times out after the shell exited (#11813)
Fixes #11613.

## Problem

The bash tool waits for stdout/stderr to close, not only for the shell
to exit (#5303). A background process that inherited those pipes and
keeps writing keeps the tool waiting after the shell exited. When the
timeout then hits, the tool reported only `Command timed out after N
seconds`.

Example, timeout 3s:

```bash
bash -c 'while true; do echo tick; sleep 0.05; done' & sleep 1; echo boom >&2; exit 1
```

The shell exits with code 1 after ~1s. The tool still times out at the
deadline, because the loop is still writing to its output. Both facts
are true: the command failed with code 1, and something it started was
still running at the timeout. The old message dropped the first, so the
model read a failed command as a slow one and retried with a longer
timeout, which never helps here.

## Fix

The timeout stays a timeout, since the tool did hit its deadline while
background processes were still writing. When the shell had already
exited before the deadline, the message now also says so:

```
Command timed out after 3 seconds. The shell exited with code 1 after 1.1 seconds, but background processes it started kept writing output until the timeout.
```

A shell still running at the deadline keeps the plain `Command timed out
after N seconds`.

The local backend throws a module-private `ShellTimeoutError` with the
message `timeout:<seconds>` as before, so custom `BashOperations` that
throw `timeout:N` are unaffected.

## Behavior per platform

- Linux and macOS: the shell runs in its own process group (`detached:
true`). At the deadline `kill(-pgid)` still reaches the background
processes after the shell exited, the pipes close, and the tool returns
at the deadline. Tested on Linux; macOS uses the same mechanism and
matches the macOS repros in the issue.
- Windows: still not fully solved. At the deadline `taskkill /T /PID
<shell>` fails with `process not found`, because the shell pid is gone.
Walking parent pids does not help: Git's `bin\bash.exe` is a launcher
for `usr\bin\bash.exe`, and the orphaned loop's parent is that
already-exited inner bash, not the pid pi holds. The tool keeps reading
until the output pauses for 100ms. Measured with Git Bash: the message
is now correct, but the tool returned after 14s instead of 3s; with a
loop that never pauses it never returns. This PR only fixes the
reporting.

## Same pattern elsewhere

- `packages/durable/src/env/node.ts` (`NodeExecutionEnv.exec`): same
code, same false `timeout:N` after the shell exited. Same Windows
limitation.
- `packages/coding-agent/src/core/exec.ts` (`pi.exec` for extensions):
the timeout sends SIGTERM/SIGKILL to the direct child only, no process
group. A descendant that keeps writing keeps the call waiting past the
timeout on every platform, and the result has `killed: true` even when
the child had already exited with its own code.
- `packages/coding-agent/src/core/package-manager.ts` (capture commands
for git/npm): waits for `close` and kills only the direct child on
timeout, so a descendant holding the pipes makes the timeout ineffective
on every platform, even when the descendant writes nothing.
- `packages/mcp/src/transports/stdio.ts`: on Windows, closing a server
that already exited skips taskkill, so children holding its pipes
survive. The code documents this as a known limitation.

Possible follow-up for Windows and the cases above: once the deadline
passed, stop waiting for the pipes (destroy our ends). On Windows this
also ends most writers, which die from a broken pipe (tested with Git
Bash).

## Tests

- `test/suite/regressions/11613-bash-timeout-after-shell-exit.test.ts`
(Unix only; it would hang on Windows for the reason above): background
writer after the shell exits with code 3, and a shell still running at
the deadline. The first case fails without the fix.
- Checked manually on Windows 11 with Git Bash through the built bundle:
both messages are as above.
- `npm run check`, `test/tools.test.ts`, the #5303 and #5208
regressions, `bash-close-hang-windows`, `powershell-tool`,
`shell-kill-process-tree`.

This PR description is AI-generated.
2026-11-04 23:47:16 +01:00
..
regressions fix(coding-agent): report the shell exit code when bash times out after the shell exited (#11813) 2026-11-04 23:47:16 +01:00
agent-session-bash-persistence.test.ts fix(coding-agent): strip ANSI sequences split across user bash output chunks 2026-10-07 15:02:59 +02:00
agent-session-boundaries.test.ts feat(tui,coding-agent): report program status via OSC 7501 2026-10-07 19:05:41 +00:00
agent-session-codemode.test.ts feat(ai,agent,coding-agent): validate tool arguments with pi-schema, drop TypeBox 2026-11-01 10:08:42 +00:00
agent-session-compaction-model-overrides.test.ts fix(coding-agent): remove fixed output limits from summary requests (#11036) 2026-10-16 13:53:16 +02:00
agent-session-compaction.test.ts feat(coding-agent): Virtual models (#10035) 2026-09-28 23:30:45 +02:00
agent-session-mcp-oauth.test.ts fix(coding-agent): cancel MCP OAuth sign-ins and stop refreshing on close 2026-10-07 16:18:46 +02:00
agent-session-mcp.test.ts feat(mcp): shared tool naming, schema, output limit and config helpers 2026-11-03 14:17:21 +01:00
agent-session-model-extension.test.ts feat(agent): add Pico storage foundation 2026-09-18 12:32:00 +02:00
agent-session-prompt.test.ts fix(coding-agent): emit before_agent_start for runs started by custom messages (#10739) 2026-10-12 09:53:24 +02:00
agent-session-queue.test.ts fix(coding-agent): fix CI type check and image-only steering test 2026-11-04 10:34:45 +00:00
agent-session-retry-events.test.ts fix(coding-agent): close compaction cancellation races 2026-09-19 19:18:18 +02:00
agent-session-runtime.test.ts fix(coding-agent): save new session file at the first user message 2026-09-25 16:27:51 +02:00
agent-session-tool-orchestration.test.ts feat(coding-agent): codemode and MCP 2026-09-29 09:12:50 +02:00
agent-session-tool-result-images.test.ts feat(ai,coding-agent): add image input limits (closes #9631) 2026-09-20 22:59:16 +02:00
harness.ts fix(ai): recover from Copilot request-size overflow 2026-10-19 22:46:26 +02:00
lax-message-content.test.ts fix(ai,agent,coding-agent): normalize null message content at ingestion boundaries (#6343) 2026-07-06 20:47:08 +02:00
mcp-oauth-server.ts fix(coding-agent): send provider tokens in pi mcp list 2026-11-04 17:59:41 +01:00
README.md docs(coding-agent): remove issue-specific regression test placement rule (#8775) 2026-08-28 16:39:28 +02:00
virtual-models.test.ts fix(coding-agent): remove fixed output limits from summary requests (#11036) 2026-10-16 13:53:16 +02:00

Coding agent suite tests

Use test/suite/ for the new harness-based test suite around AgentSession and AgentSessionRuntime.

Rules:

  • Use test/suite/harness.ts
  • Use the faux provider from packages/ai/src/providers/faux.ts
  • Do not use real provider APIs, real API keys, network calls, or paid tokens
  • Keep these tests CI-safe and deterministic
  • Do not use or extend the legacy test/test-harness.ts path unless a missing capability forces it