Skip to content

fix(terminal): settling a thread closes its idle shells - #13673

Merged
t3dotgg merged 4 commits into
mainfrom
t3code/clean-up-settled-thread-terminals
Sep 25, 2026
Merged

t3dotgg merged 4 commits into
mainfrom
t3code/clean-up-settled-thread-terminals

Conversation

@t3dotgg

@t3dotgg t3dotgg commented Sep 25, 2026 •

Copy link
Copy Markdown
Member

Settled threads kept their terminal shells open forever. The worktree setup shell stays at a prompt after its script ends. Also, zsh prompt themes (zsh-async and similar) fork a helper copy of the shell, and the terminal manager counted that copy as a running command. So every idle zsh shell showed the pulsing terminal icon in the sidebar, even on settled threads. A live terminal also blocks worktree cleanup for its checkout.

Earlier attempts stopped at "never close terminals on settle" (#5774, #4684) because closing every terminal can kill a dev server or an editor. This change closes only shells that wait at an idle prompt:

  • Idle detection: a child process that is a copy of the shell and has no children of its own is not a running command.
  • TerminalManager.closeIdle: closes a thread's terminals that wait at an idle prompt. It runs a fresh process check and does not use the last poll. A terminal that runs a command stays open. If the check fails, all terminals stay open.
  • Settle: the existing thread.settled hook in the provider command reactor calls closeIdle. That covers manual settle and auto-settle.
  • Setup script: after the script exits 0, the runner closes its setup shell if it is idle. A failed script keeps its shell open so the user can look at the error.

Closed terminals keep their output in the terminal history. A reopened terminal starts a new shell. No wire contract changed, so web, desktop, and mobile all get this from the server.

Proof: I ran the real TerminalManager with real node-pty zsh shells and ps. On main, an idle shell reported running: true (zsh) because of its prompt worker. On this branch, it reports false. closeIdle closed the idle shell and kept the shell that ran sleep 60. Focused tests cover detection, closeIdle, the settle hook, and the setup runner.

Made with Claude Opus 5.5 (1M context) in Claude Code, running in T3 Code.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Settling a thread now closes its idle terminals while preserving their output. Terminals running commands remain open.
    • Setup shells close after a successful script exit when idle; shells remain open after unsuccessful or incomplete runs.
  • Documentation
    • Updated thread guidance to explain which terminals close when a thread is settled.

@github-actions github-actions Bot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:M 30-99 changed lines (additions + deletions). labels Sep 25, 2026
@coderabbitai

coderabbitai Bot commented Sep 25, 2026

Copy link
Copy Markdown

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

✨ Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR

Comment @coderabbitai help to get the list of available commands.

Comment thread apps/server/src/terminal/Manager.ts
Comment thread apps/server/src/orchestration/Layers/ProviderCommandReactor.ts
Comment thread apps/server/src/orchestration/Layers/ProviderCommandReactor.ts
Comment thread apps/server/src/project/ProjectSetupScriptRunner.ts
Comment thread apps/server/src/terminal/Manager.ts Outdated
@github-actions

github-actions Bot commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

Provider Metric Main baseline This PR Impact PR ceiling
Codex Total thread wire 13.5 KiB 13.5 KiB +10 B (+0.1%) 15.1 KiB ✅
Codex Thread snapshot wire 7.1 KiB 7.1 KiB +1 B (+0.0%) 7.3 KiB ✅
Codex Live turn WebSocket wire 6.5 KiB 6.5 KiB +9 B (+0.1%) 7.8 KiB ✅
Codex Live turn WebSocket decoded 56.3 KiB 56.3 KiB 0 B (0.0%) 66.4 KiB ✅
Codex Live turn messages 10 10 0 (0.0%) 21 ✅
Claude Total thread wire 13.5 KiB 13.5 KiB +10 B (+0.1%) 15.1 KiB ✅
Claude Thread snapshot wire 7.1 KiB 7.1 KiB −1 B (−0.0%) 7.3 KiB ✅
Claude Live turn WebSocket wire 6.4 KiB 6.4 KiB +11 B (+0.2%) 7.8 KiB ✅
Claude Live turn WebSocket decoded 57.0 KiB 57.0 KiB 0 B (0.0%) 66.4 KiB ✅
Claude Live turn messages 9 9 0 (0.0%) 21 ✅

Baseline: fd996d1 · PR result: 25bd7cd · Source CI: success

Scenario and decoded snapshot size

10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.

  • Codex decoded thread snapshot: 114.0 KiB
  • Claude decoded thread snapshot: 114.7 KiB

Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed.

@github-actions github-actions Bot added size:L 100-499 changed lines (additions + deletions). and removed size:M 30-99 changed lines (additions + deletions). labels Sep 25, 2026
@macroscopeapp

macroscopeapp Bot commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — This PR changes production terminal lifecycles by closing idle shells during settlement and successful setup completion, using new process-tree detection and race-handling logic in shared terminal infrastructure. The behavior is intentionally narrow and tested, but its observable side effects and cross-component runtime impact merit human review.

No code changes detected at 25bd7cd. Prior analysis still applies.

You can add or adjust custom eligibility rules. Learn more.

t3dotgg and others added 4 commits September 25, 2026 13:03
Settled threads kept their terminal shells open forever. The worktree
setup shell stayed at a prompt after its script ended, and zsh prompt
themes fork a helper copy of the shell, so every idle shell reported a
running command. That kept the sidebar terminal icon pulsing on settled
threads and blocked worktree cleanup.

- Idle detection ignores a child that is a copy of the shell with no
  children of its own.
- TerminalManager.closeIdle closes a thread's terminals that wait at an
  idle prompt, after a fresh process check. Busy terminals stay open.
- thread.settled closes the thread's idle terminals.
- A setup script that exits 0 closes its idle setup shell.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- The settle hook skips a thread that was un-settled before its event ran.
- closeIdle keeps a terminal that printed output during the process
  check, because typing echoes output before the command's process
  appears in the snapshot.
- closeIdle logs the bounded error message, not the error object.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
write does not advance the event sequence, so a keystroke whose echo
arrives after the process check could still let closeIdle kill the
terminal. Sessions now count writes, and closeIdle skips a terminal when
its output sequence or input count changed during the check.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@t3dotgg
t3dotgg force-pushed the t3code/clean-up-settled-thread-terminals branch from 702a95a to 25bd7cd Compare September 25, 2026 20:04
@t3dotgg
t3dotgg merged commit 1a0c915 into main Sep 25, 2026
22 of 23 checks passed
@t3dotgg
t3dotgg deleted the t3code/clean-up-settled-thread-terminals branch September 25, 2026 20:09
github-actions Bot added a commit to omarcresp/t3code-flake that referenced this pull request Sep 25, 2026
## What's Changed
* feat(usage): read cursor, opencode, and antigravity history by @maria-rcks in pingdotgg/t3code#10409
* fix(sqlite): retry failed statement preparations by @yashranaway in pingdotgg/t3code#10584
* fix(mobile): scale Android controls with appearance text size by @none23 in pingdotgg/t3code#13356
* fix(web): return focus to the composer after saving a citation note by @mackinleysmith in pingdotgg/t3code#13450
* feat(observability): honor the standard OTLP endpoint, headers, and protocol variables by @yordis in pingdotgg/t3code#13492
* fix(terminal): settling a thread closes its idle shells by @t3dotgg in pingdotgg/t3code#13673
* fix(server): load Cursor keyring with createRequire by @Yash-Singh1 in pingdotgg/t3code#13678
* perf(server): avoid rereading unchanged files in review previews by @shivamhwp in pingdotgg/t3code#13395


**Full Changelog**: pingdotgg/t3code@v0.0.43-nightly.20260925.2251...v0.0.43-nightly.20260925.2269

Upstream release: https://github.com/pingdotgg/t3code/releases/tag/v0.0.43-nightly.20260925.2269
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L 100-499 changed lines (additions + deletions). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant