fix(restart): keep watching a CLI that is slow to quit, and hand over the resume line - #919
Merged
Merged
Conversation
… the resume line Issue #899: "Restart agent and shell" on a 19-hour cron session gave up at the 6 s exit poll. The CLI quit a moment later with nothing left watching, so the node sat at a bare shell with no agent and no resume, under a notice that said "Nothing was killed — check the pane". - performExitPhase takes an optional late window (lateExitMs). Past the base 6 s it keeps polling only while the pane still reads; a pane it cannot see ends the run exactly as before, and a query wedged inside the base window still lapses at the base deadline. - Both user-asked restart paths use it (RESTART_LATE_EXIT_MS, 60 s): performRestartResume by default and the restart-shell branch in TerminalNode. The Eco sweep and Pause keep the bare window: the sweep is serialized across the canvas. - The exit-timeout notice names the real window and carries the bare resume line (exitTimeoutNotice), for the case the late window still misses. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Merged
pull Bot
pushed a commit
to jw5812018/nodeterm
that referenced
this pull request
Sep 25, 2026
Version bump 0.3.13 → 0.3.14 — 14 PRs since v0.3.13. - **Appearance**: the Liquid Glass theme (eneskirca#908), off by default; an unthemed install sees only the colour clean-up that came with it. - **Windows**: persistent agent sessions go through the session host (eneskirca#916, scoped by eneskirca#929), and the macOS + Windows packages finally ship the Codex relay (eneskirca#839). - **Fixes that were losing work quietly**: a restart keeps watching a CLI slow to quit and hands over the resume line (eneskirca#919); a new agent on an SSH project no longer waits on the connection before typing its launch (eneskirca#931). - **Codex**: usage + context for SSH sessions (eneskirca#906), no empty mascot frames (eneskirca#910). - **Also**: ⌘K ranks before the 50-row cap (eneskirca#924), every phone size report on a session-host session is answered (eneskirca#921, eneskirca#920), the canvas-control skill trigger stops claiming in-process subagent requests (eneskirca#922), and the opencode context-link export is bounded (eneskirca#820). docs/release-notes/v0.3.14.md is the Highlights block. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #899.
What happened. "Restart agent and shell" on a long-running Claude node (a cron session open for 19 h, 28 MB transcript) reported:
The pane then showed Claude's own farewell and a clean shell prompt. So the CLI did quit, a moment after
performExitPhasestopped watching atRESTART_EXIT_TIMEOUT_MS(6 s). Nothing was left to send the resume line, and the node was left at a bare shell with no agent in it.Why the exit poll, not the detection, is the likely failure. Once claude quits,
#{pane_current_command}becomes the shell, andisShellCommandaccepts it on the very next poll. The pane query is a localtmux displaythat takes milliseconds. What remains is a CLI that took longer than 6 s to quit. Not measured: how long that exit really took, and why a large session is slower to quit.Change
performExitPhasetakes an optionallateExitMs. After the base window it keeps polling, but only while the pane still reads. A pane it cannot see ends the run exactly as before. A query that wedges inside the base window still lapses at the base deadline. When the option is absent, behavior is byte-identical.RESTART_LATE_EXIT_MS(60 s):performRestartResume, by default.TerminalNode, which is the action from the report.exitTimeoutNotice) names the window actually waited. It also carries the bare resume line (claude --resume <id>) for a CLI that quits after even the late window. A custom agent with no resume line gets "Check the pane." instead of a guessed command.Tests (
agent-restart.test.ts)performExitPhasehas no late window unless the caller asks for one.performRestartResumedefault turns 2 cases red.pane === nullstop turns 2 cases red, including the existing wedged-query case.npm run typecheckis clean. Full suite on Linux: 12886 passed, 53 skipped.Trade-off. The node stays held by
guardConcurrentRestartfor the whole wait, which is deliberate: a background watcher would release it, and a second/exitor restart could then collide with a late resume. The cost is that a node whose CLI never quits holds a bulk restart for up to 66 s instead of 6 s. Bulk restart only picks idle nodes, and those normally quit in well under a second.Not covered
Surfaces
🤖 Generated with Claude Code