fix(coding-agent): dispose session runtime after startup benchmark (#11736)

With `PI_STARTUP_BENCHMARK=1`, pi initializes interactive mode, stops
the TUI, prints the timings and returns. It never disposed the session
runtime, so extensions never got `session_shutdown`. If an extension
cleans up a timer or a socket in that handler, the resource stays open
and the process never exits after printing the timings.

This change calls `await runtime.dispose()` right after
`interactiveMode.stop()` in the benchmark path. That is the same order a
normal interactive quit uses: stop the TUI, then dispose the runtime.

No test was added. Nothing in the test suite covers the startup
benchmark path, and that path needs a real TTY.

Testing:
- `npm run check` passes.
- I wrote an extension that starts a `setInterval` in `session_start`
and clears it in `session_shutdown`. Then I ran `PI_STARTUP_BENCHMARK=1
PI_TIMING=1 pi --offline -ne -e ./ext.ts` in a terminal, wrapped in
`timeout --foreground 15`:
- before the change: the timings print, then the process hangs until the
timeout (exit 124);
  - after the change: it exits 0.
- Without extensions it exits 0 both before and after.

Fixes #11693

Requested by @badlogic

Co-authored-by: triagent <triagent@localhost>
This commit is contained in:
robopipi[bot] 2026-11-03 22:11:40 +01:00 • committed by GitHub
parent 9a19539617
commit efb45b51d4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -979,6 +979,7 @@ export async function main(args: string[], options?: MainOptions) {
// (Kitty keyboard protocol, device attributes, cell size) before restoring the terminal.
await new Promise((resolve) => setTimeout(resolve, 150));
interactiveMode.stop();
await runtime.dispose();
stopThemeWatcher();
printTimings();
if (process.stdout.writableLength > 0) {