8000 feat(tabs): resume the just-closed tab's agent session on Ctrl+Shift+T by alejandronava562 · Pull Request #447 · amirlehmam/wmux · GitHub
[go: up one dir, main page]

Skip to content

feat(tabs): resume the just-closed tab's agent session on Ctrl+Shift+T - #447

Merged
amirlehmam merged 1 commit into
amirlehmam:masterfrom
alejandronava562:feat/reopen-agent-session
Nov 10, 2026
Merged

amirlehmam merged 1 commit into
amirlehmam:masterfrom
alejandronava562:feat/reopen-agent-session

Conversation

@alejandronava562
Copy link
Copy Markdown
Contributor

reopenClosedSurface (#64) brings back a closed terminal tab's shell, cwd, title and startup commands. A tab that was running an agent, though, comes back as a bare prompt. The conversation, which was the point of the tab, is gone, and the user has to claude --resume and pick it from the list by hand.

With this change, Ctrl+Shift+T on a tab that was hosting an agent session resumes that conversation, through the same resume path session restore already uses (#186).


Behavior

  • Only the most recently closed tab resumes. Each close strips the handle from every older entry on the reopen stack, so going further back gives plain shells. Undoing an accidental close should bring the conversation back. Ten closes later, an agent starting in a tab you no longer remember would be a surprise.
  • Every resumable provider: Claude, Codex, OpenCode, agy, Qwen, omp, pi. The handle is stored in the provider's existing SurfaceRef field (claudeSessionId, codexSessionId, …).
  • An agent that exited normally does not come back. If main's record for the surface has no session (the agent released it), the reopen is a plain shell, even if the tab carried a stamped handle from session.json.
  • A restored tab whose agent has not reported yet carries its stamped handle, the same precedence providerLookup applies at save time. If two providers' handles are stamped, the tab resumes neither.
  • The restore<Provider>Sessions preferences do not gate this. They are off by default so a restart doesn't start an agent in every pane at once. Ctrl+Shift+T asks for exactly one tab. The override is a one-shot, module-level set in claude-resume-command.ts. It is never stored, so nothing new is written to session.json.

Implementation

src/renderer/store/surface-slice.ts

  • ClosedSurface.agentSession?: { field, id }, captured in pushClosedSurface from the renderer's agentStates mirror, or from the surface's stamped field when main has no record yet.
  • pushClosedSurface now takes get (all three call sites updated) and clears agentSession from older entries before pushing.
  • reopenClosedSurface applies the field with updateSurface after addSurface. This is synchronous, before React mounts the terminal, so the first PTY create sees it. It then calls forceResumeOnSpawn.

src/renderer/hooks/claude-resume-command.ts

  • forceResumeOnSpawn(surfaceId) adds the surface to a set. withClaudeResume consumes the entry and treats every provider as enabled for that one call. Validation, the once-per-surface guard and launcher merging (mergeResume) are unchanged.

The command is not appended to startupCommands. Those are saved in session.json, so it would rerun on every restart even after the user quit the agent. The *SessionId fields are re-stamped or pruned by main at save time, as for 8000 any restored tab.

Tests

tests/unit/reopen-agent-session.test.ts (6 cases):

  • A live Claude session is stamped onto the reopened tab and resumes with the pref off.
  • A Codex session lands in codexSessionId only.
  • With an agent tab closed and then a plain tab, neither reopen resumes.
  • A released session is not resumed, even with a stamped id.
  • A restored tab with no live record carries its stamped handle.
  • A plain reopened tab is not force-resumed.

npm test: the only 3 failures (git-view, git-worktree-git, worktree-diff) fail identically on a clean checkout.
npm run lint: no findings in the changed files.

Manual, isolated dev instance (WMUX_INSTANCE, CDP-driven), 17/17 passed

  • A real Ctrl+Shift+T keypress reopens with the Claude session and spawns claude --resume <id>.
  • Codex / OpenCode / Qwen / agy handles each land in their own field and resume.
  • A released agent reopens plain.
  • With an agent tab closed and then a plain tab, both reopen plain.
  • "Close tabs to the right" across agent, plain, agent: only the last agent resumes, and the earlier one is stripped.
  • Reopening into a different workspace resumes there.
  • 40 close/reopen cycles each resume their own session, with no leaked tabs.
  • An empty stack returns null.
  • No renderer exceptions or console.error.
  • End to end with real Claude: claude "reply with just OK", close the tab, Ctrl+Shift+T, and the reopened tab resumes the same conversation (the same session id is reported again by Claude's own hook).

Known limits

  • If the agent's process was killed under it (PTY died while the tab stayed open) and the tab is closed afterwards, the reopen is a plain shell. clearAgentState broadcasts sessionId: null to the renderer while main keeps the handle as an orphan for restart restore. The renderer cannot tell this apart from a normal exit. That could be fixed by sending the orphaned handle across, but it is out of scope here.
  • A conversation that never had a message has no transcript, so claude --resume answers "No conversation found". Restart restore behaves the same way.

Reopening a closed terminal tab restored its shell but dropped the agent
conversation it was hosting. The reopen stack now keeps the agent session
handle (Claude, Codex, OpenCode, agy, Qwen, omp, pi) on the most recently
closed entry only, stamps it onto the reopened surface, and forces a
one-shot resume through withClaudeResume regardless of the
restore<Provider>Sessions preferences. Released sessions are not resumed.
@amirlehmam
amirlehmam merged commit fa97b16 into amirlehmam:master Nov 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

0