Skip to content

Fix PTY terminal read and shell session ergonomics#649

Merged
arul28 merged 3 commits into
mainfrom
ade/read-transcript-chat-review-sync-2f34f932
Jun 25, 2026
Merged

Fix PTY terminal read and shell session ergonomics#649
arul28 merged 3 commits into
mainfrom
ade/read-transcript-chat-review-sync-2f34f932

Conversation

@arul28

@arul28 arul28 commented Jun 25, 2026

Copy link
Copy Markdown
Owner

Summary

Describe the change.

What Changed

Key files and behaviors.

Validation

How you tested.

Risks

Anything to watch.

ADE   Open in ADE  ·  ade/read-transcript-chat-review-sync-2f34f932 branch  ·  PR #649

Summary by CodeRabbit

  • New Features

    • You can now read terminal scrollback using a PTY identifier with ade terminal read --pty <pty-id>.
    • Shell session creation output now includes clearer session and PTY details, plus a suggested command for reading the session when available.
  • Bug Fixes

    • Fixed duplicate terminal tabs from being created when clicking “New terminal” multiple times or when the same terminal is restored/revealed again.
    • Improved terminal read handling so PTY-based sessions are recognized consistently across desktop and CLI flows.

Greptile Summary

This PR adds PTY-id-based terminal read lookup (--pty <pty-id> in the CLI and ptyId in the IPC contract), fixes duplicate terminal tabs from rapid "New terminal" clicks and from restore/reveal re-entry, and improves shell session ergonomics by emitting a suggested ade terminal read command after shell start.

  • PTY read alias: resolveTerminalId now accepts ptyId directly and also falls back to a PTY lookup when terminalId doesn't match a known session, making --pty and --terminal <ptyId> both work from the CLI.
  • Duplicate-tab fix: createTabFlightRef serialises concurrent createTab calls and tab IDs are now derived from created.sessionId, so backend-returned duplicates are caught both at flight-guard time and inside the setTabs updater.
  • Shell env ergonomics: resolveShellCandidates gains a clean flag (skips startup files for command-backed shells), withResolvedCliLaunchPath augments PATH with interactive-shell and known-CLI directories, and isNodeModulesBinPath now excludes the user's yarn global bin so it isn't demoted to last resort.

Confidence Score: 4/5

Safe to merge after addressing the stale-flight race in ChatTerminalDrawer; all other changes are additive and well-tested.

The createTabFlightRef is not reset when chatSessionId changes, which means a terminal create that's in-flight for the old chat session can resolve after the user has switched to a new session, append the old session's tab into the new session's drawer, and prevent the new session from auto-creating its own terminal. Every other change — the ptyId IPC path, the CLI formatter, the shell-env helpers, and the deduplication logic itself — is solid and covered by tests.

apps/desktop/src/renderer/components/chat/ChatTerminalDrawer.tsx — the chatSessionId-change cleanup effect should reset createTabFlightRef.current to null.

Important Files Changed

Filename Overview
apps/desktop/src/renderer/components/chat/ChatTerminalDrawer.tsx Duplicate-tab prevention via createTabFlightRef is solid for rapid clicks, but the ref is not cleared on chatSessionId change, which can leak an old session's terminal into a new session's drawer on fast chat switches.
apps/desktop/src/main/services/pty/ptyService.ts Adds resolveTerminalId ptyId path and withResolvedCliLaunchPath helper; logic is correct with the noted asymmetry on disposed PTYs already called out in previous threads.
apps/ade-cli/src/cli.ts Adds --pty flag to terminal read, pty-create formatter, and shell-help read-command hint; all changes are additive and well-tested.
apps/desktop/src/main/services/pty/ptyService.test.ts New tests cover ptyId terminal read aliasing, command-backed shell clean startup, and updated PATH ordering assertions; coverage is thorough.
apps/desktop/src/renderer/components/chat/ChatTerminalDrawer.test.tsx New test verifies rapid double-click deduplication but does not cover the chatSessionId-change race that leaks a stale tab.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant User
    participant Drawer as ChatTerminalDrawer
    participant IPC as registerIpc
    participant PtyService
    participant SessionService

    User->>Drawer: click "New terminal"
    Drawer->>Drawer: createTabFlightRef set → guard active
    Drawer->>IPC: "window.ade.pty.create({ chatSessionId, toolType: "shell" })"
    IPC->>PtyService: create(args)
    PtyService-->>IPC: "{ sessionId, ptyId, pid }"
    IPC-->>Drawer: created
    Drawer->>Drawer: "tabId = chat-term-{sessionId}"
    Drawer->>Drawer: setTabs (dedup by sessionId/ptyId)
    Drawer->>Drawer: "createTabFlightRef = null"

    User->>Drawer: "ade terminal read --pty <pty-id>"
    Drawer->>IPC: "terminal.read({ ptyId })"
    IPC->>PtyService: "readTerminal({ ptyId })"
    PtyService->>PtyService: resolveTerminalId → ptys.get(ptyId)?.sessionId
    PtyService->>SessionService: get(sessionId)
    SessionService-->>PtyService: session
    PtyService-->>IPC: "{ terminalId, data }"
    IPC-->>Drawer: result
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant User
    participant Drawer as ChatTerminalDrawer
    participant IPC as registerIpc
    participant PtyService
    participant SessionService

    User->>Drawer: click "New terminal"
    Drawer->>Drawer: createTabFlightRef set → guard active
    Drawer->>IPC: "window.ade.pty.create({ chatSessionId, toolType: "shell" })"
    IPC->>PtyService: create(args)
    PtyService-->>IPC: "{ sessionId, ptyId, pid }"
    IPC-->>Drawer: created
    Drawer->>Drawer: "tabId = chat-term-{sessionId}"
    Drawer->>Drawer: setTabs (dedup by sessionId/ptyId)
    Drawer->>Drawer: "createTabFlightRef = null"

    User->>Drawer: "ade terminal read --pty <pty-id>"
    Drawer->>IPC: "terminal.read({ ptyId })"
    IPC->>PtyService: "readTerminal({ ptyId })"
    PtyService->>PtyService: resolveTerminalId → ptys.get(ptyId)?.sessionId
    PtyService->>SessionService: get(sessionId)
    SessionService-->>PtyService: session
    PtyService-->>IPC: "{ terminalId, data }"
    IPC-->>Drawer: result
Loading

Comments Outside Diff (1)

  1. apps/desktop/src/renderer/components/chat/ChatTerminalDrawer.tsx, line 170-179 (link)

    P1 Stale flight leaks into new chat session on fast session switch

    When chatSessionId changes, this cleanup effect resets most refs and clears tabs, but does not reset createTabFlightRef.current. If a window.ade.pty.create(...) call is in-flight for Session A when the user switches to Session B, the flight resolves after the switch, appending the Session-A terminal entry into Session B's now-empty tabs via setTabs. Because tabs.length > 0, the auto-create guard for Session B (if (!autoCreateOnOpen || revealActive || tabs.length > 0)) short-circuits and Session B never gets its own terminal — it just shows Session A's PTY. Adding createTabFlightRef.current = null here would cancel the in-progress guard and let the old flight's setTabs call be ignored (or at least let Session B detect stale state).

    Prompt To Fix With AI
    This is a comment left during a code review.
    Path: apps/desktop/src/renderer/components/chat/ChatTerminalDrawer.tsx
    Line: 170-179
    
    Comment:
    **Stale flight leaks into new chat session on fast session switch**
    
    When `chatSessionId` changes, this cleanup effect resets most refs and clears `tabs`, but does **not** reset `createTabFlightRef.current`. If a `window.ade.pty.create(...)` call is in-flight for Session A when the user switches to Session B, the flight resolves after the switch, appending the Session-A terminal entry into Session B's now-empty `tabs` via `setTabs`. Because `tabs.length > 0`, the auto-create guard for Session B (`if (!autoCreateOnOpen || revealActive || tabs.length > 0)`) short-circuits and Session B never gets its own terminal — it just shows Session A's PTY. Adding `createTabFlightRef.current = null` here would cancel the in-progress guard and let the old flight's `setTabs` call be ignored (or at least let Session B detect stale state).
    
    How can I resolve this? If you propose a fix, please make it concise.

    Fix in Claude Code

Fix All in Claude Code

Prompt To Fix All With AI
Fix the following 1 code review issue. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 1
apps/desktop/src/renderer/components/chat/ChatTerminalDrawer.tsx:170-179
**Stale flight leaks into new chat session on fast session switch**

When `chatSessionId` changes, this cleanup effect resets most refs and clears `tabs`, but does **not** reset `createTabFlightRef.current`. If a `window.ade.pty.create(...)` call is in-flight for Session A when the user switches to Session B, the flight resolves after the switch, appending the Session-A terminal entry into Session B's now-empty `tabs` via `setTabs`. Because `tabs.length > 0`, the auto-create guard for Session B (`if (!autoCreateOnOpen || revealActive || tabs.length > 0)`) short-circuits and Session B never gets its own terminal — it just shows Session A's PTY. Adding `createTabFlightRef.current = null` here would cancel the in-progress guard and let the old flight's `setTabs` call be ignored (or at least let Session B detect stale state).

Reviews (3): Last reviewed commit: "Preserve interactive PATH for clean PTY ..." | Re-trigger Greptile

@vercel

vercel Bot commented Jun 25, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
ade Ignored Ignored Preview Jun 25, 2026 2:15am

@mintlify

mintlify Bot commented Jun 25, 2026

Copy link
Copy Markdown

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
ade-ac1c6011 🟢 Ready View Preview Jun 25, 2026, 1:44 AM

💡 Tip: Enable Workflows to automatically generate PRs for you.

@arul28

arul28 commented Jun 25, 2026

Copy link
Copy Markdown
Owner Author

@copilot review but do not make fixes

@coderabbitai

coderabbitai Bot commented Jun 25, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The PR adds PTY-scoped terminal read support through the CLI, IPC, and PTY service layers, updates shell session creation output and spawn behavior, and changes the chat terminal drawer to deduplicate concurrent or restored tabs by session and PTY identifiers.

Changes

PTY session routing and terminal UI

Layer / File(s) Summary
Terminal read contract and routing
apps/desktop/src/shared/types/sessions.ts, apps/desktop/src/main/services/ipc/registerIpc.ts, apps/desktop/src/main/services/pty/*, apps/ade-cli/src/cli.ts, apps/ade-cli/src/cli.test.ts
ChatTerminalReadArgs, CLI/IPC parsing, and PTY service routing now carry ptyId; readTerminal resolves live PTYs back to session ids, and tests cover PTY-backed reads plus the updated plan args.
Shell create output and startup behavior
apps/desktop/src/main/services/pty/*, apps/ade-cli/src/cli.ts, apps/ade-cli/src/cli.test.ts
shell start uses the pty-create formatter, renders shell session identifiers and read guidance, and selects clean shell candidates when direct or startup commands are present; tests cover the formatter output and startup-command spawn behavior.
Terminal drawer creation deduplication
apps/desktop/src/renderer/components/chat/ChatTerminalDrawer.tsx, apps/desktop/src/renderer/components/chat/ChatTerminalDrawer.test.tsx
ChatTerminalDrawer serializes concurrent terminal creation and deduplicates tabs by sessionId and ptyId during create, restore, and reveal flows.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • arul28/ADE#222: Shares the ChatTerminalDrawer.tsx PTY/session identity and duplicate terminal creation handling.

Suggested labels

desktop

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly reflects the main change: PTY terminal read support and shell session UX improvements.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch ade/read-transcript-chat-review-sync-2f34f932

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/desktop/src/main/services/pty/ptyService.ts`:
- Around line 3726-3730: `launchEnv` used by `ptyService` for `startupCommand`
sessions may be missing the full executable PATH because clean shells skip user
rc/profile setup. Review the shell launch flow around `resolveShellCandidates`
and the `startupCommand`/`directCommand` path so that the environment passed
into the spawned PTY already contains a complete PATH (including user-managed
tool shims like nvm/asdf) before execution, rather than relying on shell
initialization to populate it.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 3c6eb569-1643-44e6-aa68-bc8f8007d571

📥 Commits

Reviewing files that changed from the base of the PR and between 40de7ad and 83c59ca.

⛔ Files ignored due to path filters (1)
  • docs/features/computer-use/app-control.md is excluded by !docs/**
📒 Files selected for processing (8)
  • apps/ade-cli/src/cli.test.ts
  • apps/ade-cli/src/cli.ts
  • apps/desktop/src/main/services/ipc/registerIpc.ts
  • apps/desktop/src/main/services/pty/ptyService.test.ts
  • apps/desktop/src/main/services/pty/ptyService.ts
  • apps/desktop/src/renderer/components/chat/ChatTerminalDrawer.test.tsx
  • apps/desktop/src/renderer/components/chat/ChatTerminalDrawer.tsx
  • apps/desktop/src/shared/types/sessions.ts

Comment thread apps/desktop/src/main/services/pty/ptyService.ts
Comment thread apps/desktop/src/main/services/pty/ptyService.ts
@arul28 arul28 changed the title Review Sync Main Sst Fix PTY terminal read and shell session ergonomics Jun 25, 2026
@arul28

arul28 commented Jun 25, 2026

Copy link
Copy Markdown
Owner Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f321aa624a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread apps/desktop/src/main/services/pty/ptyService.ts
@arul28

arul28 commented Jun 25, 2026

Copy link
Copy Markdown
Owner Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Nice work!

Reviewed commit: 9e996d0447

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@arul28 arul28 merged commit aac0a96 into main Jun 25, 2026
27 checks passed
@arul28 arul28 deleted the ade/read-transcript-chat-review-sync-2f34f932 branch June 25, 2026 02:28
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