Skip to content

fix(desktop): auto-start shell on session restore without popup#1076

Closed
Kitenite wants to merge 2 commits intomainfrom
remove-session-restored-popup
Closed

fix(desktop): auto-start shell on session restore without popup#1076
Kitenite wants to merge 2 commits intomainfrom
remove-session-restored-popup

Conversation

@Kitenite
Copy link
Copy Markdown
Collaborator

@Kitenite Kitenite commented Jan 31, 2026

Summary

  • Remove the "Session restored" popup overlay that required user interaction
  • Auto-start the shell immediately when a terminal session is cold-restored
  • Preserve previous scrollback while starting the new shell in the background

Test plan

  • Restart the desktop app with terminal sessions open
  • Verify no popup appears after restart
  • Verify the terminal is immediately usable with the previous scrollback preserved
  • Verify the shell starts automatically in the correct directory

Summary by CodeRabbit

  • Refactor
    • Streamlined terminal cold-start restoration: the terminal now starts the shell directly with the appropriate working directory (when available) and no longer shows an intermediate restoration overlay, resulting in faster, smoother startup and focus behavior.

✏️ Tip: You can customize this high-level summary in your review settings.

Remove the "Session restored" popup overlay that required user
interaction to start a new shell. Now when a terminal session is
cold-restored after an app restart, the shell starts automatically
in the background while preserving the previous scrollback.
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jan 31, 2026

📝 Walkthrough

Walkthrough

Removes the RestoredModeOverlay and changes the cold-restore flow so restored sessions start the shell directly via an updated handleStartShell(cwd?) API instead of setting restored-mode state flags and rendering an overlay.

Changes

Cohort / File(s) Summary
Terminal Component UI
apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Terminal.tsx
Removed RestoredModeOverlay import and JSX. Restoration paths now call handleStartShell with the restored cwd instead of setting setIsRestoredMode/setRestoredCwd.
Cold Restore Hook
apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/hooks/useTerminalColdRestore.ts
Changed handleStartShell signature to accept `cwd?: string
Minor comment tidy-ups
apps/desktop/src/lib/trpc/routers/workspaces/utils/workspace-init.ts, apps/desktop/src/renderer/screens/main/components/WorkspaceView/WorkspaceInitializingView/WorkspaceInitializingView.tsx
Removed explanatory comments only; no behavioral changes.

Sequence Diagram(s)

sequenceDiagram
  participant Terminal as Terminal UI
  participant Hook as useTerminalColdRestore
  participant SessionSvc as SessionManager
  participant Focus as UI Focus/Renderer

  Terminal->>Hook: notify stored restore / coldRestoreResult (cwd)
  Hook->>Hook: determine cwdToUse = cwdArg ?? restoredCwdRef.current
  Hook->>SessionSvc: create/attach session (cwdToUse)
  SessionSvc-->>Hook: onSuccess(session)
  Hook->>Terminal: report session started
  Hook->>Focus: schedule focus after start
  Focus-->>Terminal: focus applied
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

🐰 I hopped through lines of code today,
Overlays tucked quietly away,
CWD in paw, I start shells fast,
No flagged-restores from the past,
Smooth starts, quick hops — hooray! 🥕

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Description check ⚠️ Warning The description lacks required template sections (Related Issues, Type of Change, Testing details, Screenshots) and the test plan items are unchecked with minimal detail, making it incomplete against the repository template. Complete the missing sections: specify related issues, mark the appropriate change type (likely Bug fix or Refactor), provide concrete testing steps, and check off completed test plan items.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: removing the popup overlay and auto-starting the shell on session restore, which aligns with the primary objective of the changeset.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch remove-session-restored-popup

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In
`@apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Terminal.tsx`:
- Around line 486-496: During cold-restore, input can be dropped because
isRestoredModeRef is never set and writes occur while the old session is gone;
fix by enabling a gating flag during the restore-and-attach window and flushing
buffered writes only after the new session is attached: set
isRestoredModeRef.current = true (or set isStreamReadyRef.current = false)
before calling xterm.write(...) in the cold-restore branch (the block that reads
coldRestoreState and calls handleStartShell/createOrAttachRef), keep the flag
set until createOrAttachRef() (or the promise returned by handleStartShell)
completes successfully, then clear the flag and flush the PtyWriteQueue so
manager.write() is only attempted when the new session is live; update
handleTerminalInput to check isRestoredModeRef (or isStreamReadyRef) and queue
inputs instead of calling manager.write when the gate is active.

Comment on lines 486 to 496
const storedColdRestore = coldRestoreState.get(paneId);
if (storedColdRestore?.isRestored) {
setIsRestoredMode(true);
setRestoredCwd(storedColdRestore.cwd);
if (storedColdRestore.scrollback && xterm) {
xterm.write(
storedColdRestore.scrollback,
scheduleScrollToBottom,
);
}
didFirstRenderRef.current = true;
handleStartShell(storedColdRestore.cwd);
return;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Inspect write buffering / readiness handling around terminal writes
rg -n --type=ts -C3 'useTerminalConnection' apps/desktop/src/renderer
rg -n --type=ts -C3 'writeRef\.current|write\(' apps/desktop/src/renderer
rg -n --type=ts -C3 'isStreamReadyRef' apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal

Repository: superset-sh/superset

Length of output: 50376


🏁 Script executed:

#!/bin/bash
# Get the exact lines in question
sed -n '480,515p' apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Terminal.tsx

# Look for the writeRef usage context - check if it's subject to readiness gating
rg -n 'writeRef\.current\(' apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Terminal.tsx -A 2 -B 2

# Check how events are flushed and understand the queuing mechanism
rg -n 'flushPendingEvents|pendingEventsRef' apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/hooks/useTerminalStream.ts -A 2 -B 2

Repository: superset-sh/superset

Length of output: 2416


🏁 Script executed:

#!/bin/bash
# Find the writeMutation definition and see if it has any buffering/gating
rg -n 'writeMutation|useMutation' apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/hooks/useTerminalConnection.ts -A 5 -B 2

# Check if there's any check for session readiness before accepting writes
rg -n 'isStreamReady|session.*ready|attach' apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Terminal.tsx -B 2 -A 2 | head -100

# Look for any input buffering or queueing in the component
rg -n 'buffer|queue.*input|input.*queue' apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal -i

Repository: superset-sh/superset

Length of output: 16215


🏁 Script executed:

#!/bin/bash
# Check attach-scheduler to see if it manages session readiness
cat apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/attach-scheduler.ts

# Check handleStartShell to see when it subscribes to the stream
rg -n 'handleStartShell' apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Terminal.tsx -A 15 | head -50

# Look for any input validation/buffering in handleWrite or before writeRef is called
rg -n 'const handleWrite|handleKeyPress|onData' apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Terminal.tsx -A 10 | head -80

Repository: superset-sh/superset

Length of output: 9287


🏁 Script executed:

#!/bin/bash
# Check if there's any gating of writeRef calls based on session readiness
rg -n 'handleTerminalInput|onData' apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Terminal.tsx -B 5 -A 10 | head -80

# Look at the actual terminal input handler
rg -n 'const handleTerminalInput' apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Terminal.tsx -A 8

Repository: superset-sh/superset

Length of output: 1846


🏁 Script executed:

#!/bin/bash
# Check if there's any buffering on the tRPC write mutation or backend
# First, let's see if tRPC mutation implementation has any built-in buffering
rg -n 'terminal.write' apps/desktop/src -l

# Check the backend implementation if available
fd -t f -e ts 'router' apps/main/src | head -5

Repository: superset-sh/superset

Length of output: 564


🏁 Script executed:

#!/bin/bash
# Check the backend write implementation
cat apps/desktop/src/lib/trpc/routers/terminal/terminal.ts | head -200

# Look for session.write or input handling
rg -n 'write.*session|session.*write|input.*buffer|buffer.*input' apps/desktop/src/lib/trpc/routers/terminal/terminal.ts -B 2 -A 5

Repository: superset-sh/superset

Length of output: 5902


🏁 Script executed:

#!/bin/bash
# Get more of the write implementation
sed -n '185,230p' apps/desktop/src/lib/trpc/routers/terminal/terminal.ts

# Check the stream subscription to understand when isStreamReadyRef gets set to true
rg -n 'stream.*subscription|stream.*mutate' apps/desktop/src/lib/trpc/routers/terminal/terminal.ts -B 3 -A 15 | head -100

# Check the underlying terminal.write implementation
rg -n 'terminal\.write' apps/desktop/src/main/lib/terminal -l

Repository: superset-sh/superset

Length of output: 1084


🏁 Script executed:

#!/bin/bash
# Check handleStartShell to see if/when stream subscription starts
rg -n 'const handleStartShell' apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/hooks/useTerminalColdRestore.ts -A 30

# Check when stream subscription is enabled/started
rg -n 'useSubscription\|enabled.*true' apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Terminal.tsx -B 3 -A 3

Repository: superset-sh/superset

Length of output: 2094


🏁 Script executed:

#!/bin/bash
# Get the complete handleStartShell function
sed -n '172,240p' apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/hooks/useTerminalColdRestore.ts

# Check when useSubscription actually subscribes (before or after createOrAttach)
sed -n '240,250p' apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Terminal.tsx

# Look for how the terminal.write backend handles session initialization
cat apps/desktop/src/main/lib/terminal.ts | head -100

Repository: superset-sh/superset

Length of output: 2414


🏁 Script executed:

#!/bin/bash
# Find the terminal implementation
find apps/desktop/src/main -name "*terminal*" -type f | head -10

# Check if there's buffering in the pty implementation
rg -n 'write.*pty|pty.*write|input.*buffer' apps/desktop/src/main/lib -i

Repository: superset-sh/superset

Length of output: 2407


🏁 Script executed:

#!/bin/bash
# Examine the PtyWriteQueue implementation
cat apps/desktop/src/main/lib/terminal/pty-write-queue.ts

# Check how manager.write() handles non-existent sessions
rg -n 'write.*session|write\(' apps/desktop/src/main/lib/terminal/manager.ts -B 2 -A 8 | head -100

Repository: superset-sh/superset

Length of output: 4942


🏁 Script executed:

#!/bin/bash
# Check if isRestoredModeRef is properly set during cold restore
rg -n 'isRestoredModeRef' apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Terminal.tsx -B 1 -A 1

# Check when isRestoredModeRef is set/cleared
rg -n 'isRestoredModeRef.*true|isRestoredModeRef.*false' apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/hooks/useTerminalColdRestore.ts -B 1 -A 1

# Check the handleTerminalInput gate more carefully
sed -n '399,407p' apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Terminal.tsx

Repository: superset-sh/superset

Length of output: 901


🏁 Script executed:

#!/bin/bash
# Check when isRestoredMode is set/used during cold restore
rg -n 'isRestoredMode\|setIsRestoredMode' apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal -B 2 -A 2 | head -150

# Check if there's any readiness gate between scrollback write and session creation
sed -n '486,520p' apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Terminal.tsx

Repository: superset-sh/superset

Length of output: 1173


🏁 Script executed:

#!/bin/bash
# Find where isRestoredMode state is defined and initialized
rg -n 'useState.*isRestoredMode\|const.*isRestoredMode.*useState' apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal

# Check the full useTerminalColdRestore return to see if it manages isRestoredMode state
rg -n 'setIsRestoredMode' apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/hooks/useTerminalColdRestore.ts -B 3 -A 1

# See the complete picture - check if isRestoredMode is a return value from the hook
sed -n '50,70p' apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/hooks/useTerminalColdRestore.ts

Repository: superset-sh/superset

Length of output: 1481


🏁 Script executed:

#!/bin/bash
# Check if isRestoredMode is ever set to true before cold restore processing
rg -n 'setIsRestoredMode.*true' apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal

# Check the complete flow - when/where does cold restore mode get activated?
rg -n 'coldRestoreState\|isColdRestore' apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Terminal.tsx -B 1 -A 1 | head -100

# Verify: is isRestoredMode supposed to be set to true somewhere?
rg -n 'setIsRestoredMode.*true' apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/hooks -B 3 -A 1

Repository: superset-sh/superset

Length of output: 46


Input loss window during cold restore session transition.

While PtyWriteQueue does buffer outgoing writes, user keystrokes between xterm.write(scrollback) and new session creation can be lost. The gate isRestoredModeRef.current in handleTerminalInput (line 400) never evaluates to true—isRestoredMode is initialized to false and only reset to false; it's never set to true. This leaves input unguarded during the createOrAttachRef() async transition, causing writes to fail when manager.write() cannot find the old session (throwing "Terminal session not found or not alive"). The error is caught and emitted, but the keystroke is dropped. Consider actually enabling isRestoredMode during cold restore or adding explicit isStreamReadyRef gating to prevent writes until the new session is fully attached.

🤖 Prompt for AI Agents
In
`@apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Terminal.tsx`
around lines 486 - 496, During cold-restore, input can be dropped because
isRestoredModeRef is never set and writes occur while the old session is gone;
fix by enabling a gating flag during the restore-and-attach window and flushing
buffered writes only after the new session is attached: set
isRestoredModeRef.current = true (or set isStreamReadyRef.current = false)
before calling xterm.write(...) in the cold-restore branch (the block that reads
coldRestoreState and calls handleStartShell/createOrAttachRef), keep the flag
set until createOrAttachRef() (or the promise returned by handleStartShell)
completes successfully, then clear the flag and flush the PtyWriteQueue so
manager.write() is only attempted when the new session is live; update
handleTerminalInput to check isRestoredModeRef (or isStreamReadyRef) and queue
inputs instead of calling manager.write when the gate is active.

@Kitenite Kitenite closed this Feb 2, 2026
@Kitenite Kitenite deleted the remove-session-restored-popup branch February 5, 2026 01:35
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.

1 participant