Skip to content

Continue in Chat UI opens the chat before closing the terminal, and stops a CLI still starting - #37227

Merged
brennanb2025 merged 4 commits into
mainfrom
brennanb2025/continue-in-chat-no-gap
Nov 2, 2026
Merged

brennanb2025 merged 4 commits into
mainfrom
brennanb2025/continue-in-chat-no-gap

Conversation

@brennanb2025

@brennanb2025 brennanb2025 commented Nov 1, 2026 •

Copy link
Copy Markdown
Contributor
Files Added Deleted Net
Test 3 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​453 $\color{#cf222e}{\Huge{\mathbf{−}}}$​283 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​170
Prod 14 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​510 $\color{#cf222e}{\Huge{\mathbf{−}}}$​182 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​328

The problem

Clicking Continue in Chat UI on a terminal running Claude, Codex or another agent closed the terminal tab first and opened the chat only after the agent had exited and the host had started the chat. For a few seconds — longer for a large conversation — the user saw no terminal, no chat and no explanation: the sidebar row lost its agent and looked asleep, and when the terminal was the workspace's only tab the screen went blank until the chat finally appeared. This came in with "close the terminal before continuing its conversation in chat" (#36732).

A second problem from the same change: a CLI clicked within a few seconds of starting (for example one just reopened from Session History or restored after a restart) was treated as "already quit", because Orca had not yet received its first status update. The terminal was left running and a chat opened beside it that refused every message with "Claude is already running this conversation in another terminal".

What changes for users

  • The chat tab opens right after the terminal and is selected before the terminal closes, showing its starting state. The terminal then closes behind it, and the chat starts once the CLI has exited. The workspace is never empty.
  • A terminal is kept only when the host shows its shell is running nothing (the agent already quit). A CLI that is still starting is stopped and its terminal closed, so two writers never share a conversation.
  • If the close is cancelled or refused, the pending chat goes away and the terminal stays. If the chat can't start after the terminal closed (the host refuses it, or Orca can't confirm the CLI stopped), the chat that took the terminal's place stays and says why with its usual Retry, so the failure is said once and the workspace is never left blank.
  • If the user ran something else in that shell after the agent quit (an editor, a dev server, another agent), the ordinary "close running terminal?" prompt asks before it is stopped; cancelling keeps the terminal and removes the pending chat.
  • If a chat for the same conversation is already opening in that workspace, Continue answers as it does for a chat that already holds the conversation: the pane header shows that chat, the tab menu says so, and the terminal stays. Nothing is re-sent for that chat.

How it works

  • runCliChatResume begins the chat's provisional launch (not deferred) with afterTabId set to the terminal, waits for the tab to open, then runs the existing terminal close and exit proof.
  • The launch takes a new optional createAfter promise, awaited once before the host create. The run resolves it after the exit is proven, with false to abandon the create when the terminal stays, or with a refusal that fails the chat with its reason when the terminal closed but its exit wasn't proven.
  • The live-agent check now uses the existing running-work probe (the host's process read the terminal close guard already uses) instead of the renderer's status row. The probe now also reports the host's foreground process name; when it isn't this conversation's agent, the close goes through the terminal's ordinary running-process prompt. The close checks moved into cli-chat-resume-close-admission.ts. The tests were split along the close path to stay under the file-size limit.
  • No saved field or wire change. Older paired servers without the close capability keep today's behavior.

Compatibility and differences

Intended:

  • Destination before source. The chat appears at the action and the terminal is retired after it, as in the common pattern for opening a new conversation view. On paired servers the chat tab appears after the host admits it (one round trip); the terminal stays visible until then, so there is still no gap.
  • Split terminals with other running work. Their existing "close running terminal?" prompt appears with the pending chat already open; cancelling removes the chat.
  • Unverifiable hosts close. When the host can't say whether the pane's shell is idle (older servers, lost connection, or a pane not yet bound to its terminal on this client), the terminal is closed, preferring a stopped CLI over two writers. The host's exit proof still gates the chat.
  • A failure after the close keeps the chat. It shows the failure in the chat with Retry, as any failed chat start does, instead of the earlier toasts; Retry is what those toasts sent the user to Session History to do.
  • Closing a pending chat sends the host the ordinary close for a chat that was never created, as for any pending chat.
  • The same agent's CLI is stopped without a prompt. Clicking Continue in Chat UI is the user's consent to move that conversation, and one conversation can have only one writer. A different job in the pane (an editor, a dev server) still gets the ordinary "close running terminal?" prompt, as the common terminal pattern does for any running child.
  • The exit wait is bounded (15 s). The host can be remote or disconnected, so an unbounded wait could leave the chat pending forever. When the exit can't be confirmed, the chat says so with Retry.
  • The tab menu answers a chat that is already opening this conversation with main's toast, and the pane header opens that chat, as on main for a chat that already holds the conversation. Nothing new is created in either case.
  • A failure while the user is on another tab shows only in the chat and its tab's status dot. That's the surface every pending chat in Orca uses for a failed start (Session History "Resume in new chat" too). Adding a toast here would report the failure twice once the user opens the chat.
  • When the agent already quit, the chat tab appears once the host commits it, as on main. The terminal stays in that case, so there is no gap to cover.

Temporary (follow-ups for the chat/terminal switch rollout, tracked in STA-13388):

  • Continuing a conversation that already has a chat swaps the new chat tab for the existing one by removing the new tab first, so the workspace has no tab for about 0.2 s (main: about 6.7 s). Follow-up: replace the tab in place (tracked in STA-13388).
  • Codex clicked about 1 s after reopening from Session History can open a chat whose sends are refused with "Codex is still holding this conversation open." Follow-up: wait for the host to release the conversation before the chat starts (tracked in STA-13388).
  • A new Claude conversation started in a pane whose previous Claude conversation ended, if clicked before the new one's first status (a few seconds), closes that terminal and continues the previous conversation. Nothing has been sent in the new conversation yet at that point. Follow-up: ask before closing when the running agent hasn't confirmed the conversation (tracked in STA-13388).

Verification

  • Named tests: cli-chat-resume-run.test.ts, cli-chat-resume-run-close.test.ts (new: the chat tab exists and is selected before the close runs, with no create until after it; a CLI with no status row yet is closed; a pane whose shell runs nothing keeps its terminal; another job in the pane asks first; an unbound pane or unverifiable read closes; a failure after the close stays in the chat; a tab picked during the close stays selected; another agent in the pane asks first; a pending or unconfirmed chat already opening the conversation is shown, nothing is re-sent and the terminal kept), plus the launch, provisional-tab and probe suites.
  • Running-app QA (Claude and Codex) follows in the review loop: the CLI as the workspace's only tab, with other tabs, clicked within two seconds of starting, a pane whose agent quit, and a large conversation first reproduced on main.

Tracked in STA-13234 (ships with the #36732 cherry-pick).

Tracked in STA-13349.

…tops a CLI still starting

The chat tab now opens right after the terminal and is selected before the terminal closes; its create waits for proof the CLI exited, so the workspace never sits empty while a large conversation loads. The terminal is kept only when the host proves its shell runs nothing, so a CLI clicked before its first status update is stopped instead of left writing beside a chat that can't send.
…ready opening, and keeps a failed chat in place

A job started in the shell after the agent quit now goes through the terminal's running-process prompt instead of being stopped silently. A pane not bound to its terminal on this client is treated as unverifiable and closed, like any unverifiable read. When a chat for the same conversation is already opening, Continue shows it and keeps the terminal rather than handing the terminal into a launch it doesn't own. After the terminal closed, a failed start stays in the chat that took its place and says why once, including when the CLI's exit couldn't be confirmed, so the workspace is never left blank. A launch that ended before its tab opened reports its failure again, and a tab picked during the close stays selected.
@brennanb2025
brennanb2025 marked this pull request as ready for review November 2, 2026 00:07
@coderabbitai

coderabbitai Bot commented Nov 2, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

No actionable comments were generated in the recent review.

Recent review info
Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Repository UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: b1fd80b8-2ea5-4b58-a18c-0e48820f0472
Commits

Reviewing files that changed from the base of the PR and between 8fa8c9f and 5e1b5ec.

Files selected for processing: 17
  • src/renderer/src/components/tab-bar/cli-chat-resume-close-admission.ts
  • src/renderer/src/components/tab-bar/cli-chat-resume-close-terminal.ts
  • src/renderer/src/components/tab-bar/cli-chat-resume-feedback.ts
  • src/renderer/src/components/tab-bar/cli-chat-resume-run-close.test.ts
  • src/renderer/src/components/tab-bar/cli-chat-resume-run.test-fixture.ts
  • src/renderer/src/components/tab-bar/cli-chat-resume-run.test.ts
  • src/renderer/src/components/tab-bar/cli-chat-resume-run.ts
  • src/renderer/src/i18n/locales/en.json
  • src/renderer/src/lib/agent-session/launch/structured-agent-session-launch-callers.ts
  • src/renderer/src/lib/agent-session/launch/structured-agent-session-launch-create-call.ts
  • src/renderer/src/lib/agent-session/launch/structured-agent-session-launch-errors.ts
  • src/renderer/src/lib/agent-session/launch/structured-agent-session-launch-failure.ts
  • src/renderer/src/lib/agent-session/launch/structured-agent-session-launch.ts
  • src/renderer/src/lib/launch-structured-agent-session.ts
  • src/renderer/src/lib/structured-agent-launch-settlement.ts
  • src/shared/pty-running-work-probe.test.ts
  • src/shared/pty-running-work-probe.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 9 remain after this review.

Walkthrough

CLI chat resume now checks whether to keep or close the source terminal, opens a provisional chat, and delays session creation until terminal closure is confirmed. If closure is abandoned or the source changes, the flow does not proceed with the create. The PTY probe now reports the foreground process when available. Added tests cover close decisions, gated creation, ownership, and host capability cases.

Merge Risk: Minimal · up to 5e1b5

Continue in Chat now opens the chat before the terminal closes and waits for confirmed exit before creating the session. If closing is cancelled or refused, the pending chat is removed and the terminal stays. If chat startup fails after the terminal closes, the chat stays in place with Retry. The review found no concrete merge-blocking defect, so the change looks safe to merge with the usual checks.

Pre-merge checks: Passed 3 · Failed 2

Failed Failed checks: 2 warnings

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documenta… Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check Warning The description clearly explains the problem, user-visible behavior, implementation, compatibility, testing, and tracked issues. It does not follow the required template fully: the ELI5, Linked Issue … Add the missing template sections. Provide an actual linked issue under Linked Issue, attach before/after visual proof or state N/A with a reason, document risk level and rollback steps, complete the Review, Notes, and Checklist sections, a…
Passed Passed checks: 3 passed
Check name Status Explanation
Title check Passed The title names the two main user-visible changes: the chat opens before the terminal closes, and a CLI that is still starting gets stopped. The raw summary and objectives both cover these points, so …
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.
Full details: Title check

Explanation

The title names the two main user-visible changes: the chat opens before the terminal closes, and a CLI that is still starting gets stopped. The raw summary and objectives both cover these points, so the title matches the changeset. It is long, at 94 characters, but it is specific and not vague.

Full details: Docstring Coverage

Explanation

Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documentation-only edits and deletions within surviving functions are included; unchanged diff context and fully deleted functions are excluded. Analyzed 14 functions across 16 files. (1 skipped: 1 unsupported.)

Resolution

Write docstrings for the functions missing them to satisfy the coverage threshold.

Full details: Description check

Explanation

The description clearly explains the problem, user-visible behavior, implementation, compatibility, testing, and tracked issues. It does not follow the required template fully: the ELI5, Linked Issue with an actual issue link, Visual Proof, Risk with level and rollback, Review, Notes, and Checklist sections are missing or incomplete. Running-app QA is also described as planned rather than completed.

Resolution

Add the missing template sections. Provide an actual linked issue under Linked Issue, attach before/after visual proof or state N/A with a reason, document risk level and rollback steps, complete the Review, Notes, and Checklist sections, and state which verification steps have passed versus remain planned.

Finishing Touches
Generate docstrings
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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

…rs a chat still opening without joining it

Only the conversation's own agent is stopped without the running-process prompt; another agent started in that shell is asked about like any other job. A chat already opening the same conversation is found before the new chat starts and shown (or named, from the tab menu) with the terminal kept, so an unconfirmed chat's create is never re-sent beside the running CLI. The in-chat message for an unconfirmed stop no longer points at a host connection. Test timestamps are fixed values.
# Conflicts:
#	src/renderer/src/i18n/en-runtime-required.json
@brennanb2025

Copy link
Copy Markdown
Contributor Author

Review status

Problem. "Continue in Chat UI" on a terminal running Claude or Codex closed the terminal first and opened the chat seconds later. With a large conversation as the workspace's only tab, the workspace sat empty (and could look asleep, with a blank screen until clicked). A CLI clicked in its first seconds could also be left running beside a chat that refused every send.

What changes for users. The chat tab opens right after the terminal and is selected before the terminal closes; the chat starts once the CLI has exited. A CLI clicked just after it started is stopped instead of left running.

Verified (M4Air, real Claude and Codex through the team load balancers, PR head 5e1b5ec):

  • Large conversation (~6,000 messages) as the workspace's only tab: main left the workspace with no tab for 6,723 ms; the branch kept the chat on screen throughout with Codex, and with Claude except the case below. Replies worked in every passing flow.
  • Only-tab continue: Claude and Codex pass. Resume from Session History then continue: Claude passes. Agent already quit: terminal stays, chat opens (Claude). Brennan also hand-tested Claude on this Mac.
  • CI green; final-head code check and reference comparison done.

Known, accepted for this release (follow-ups for the chat/terminal switch rollout, listed as Temporary in the description):

  • A conversation whose earlier chat still holds it: the new chat tab is removed before that chat opens, so the workspace has no tab for about 0.2 s (main: 6.7 s). Fix: open the holder first, then drop the new tab (about 12 lines).
  • Codex started outside Orca's codex wrapper joins Codex's shared server, which keeps the conversation locked for up to about 60 s after the CLI quits; a chat started inside that window has its sends refused. Exists on main.
  • A new Claude conversation started in a pane whose previous one ended, clicked before its first status: the terminal closes and the earlier conversation continues.
  • Codex after /quit isn't offered Continue in Chat UI (offer logic unchanged by this PR).

Not exercised: the sub-300 ms "pick another tab while the chat opens" race (the later pick held in both agents); the "close running terminal?" prompt for a non-agent job (the test pane's conversation already had a chat, which opened instead, as on main).

For Brennan's review

Main, large conversation after the gap:
f5-main-claude-reply.png
Branch, large conversation, Claude and Codex:
f5-claude-reply.png
f5-codex-reply.png
Branch, only tab, Codex:
f1-codex-reply.png
Branch, agent already quit, shell stays:
f4-claude-shell-stays.png

Spots worth a look: src/renderer/src/components/tab-bar/cli-chat-resume-run.ts:196, src/renderer/src/components/tab-bar/cli-chat-resume-close-admission.ts:35, src/renderer/src/components/tab-bar/cli-chat-resume-feedback.ts:46.

@brennanb2025
brennanb2025 merged commit a94f784 into main Nov 2, 2026
51 checks passed
audichuang pushed a commit to audichuang/orca that referenced this pull request Nov 2, 2026
…tops a CLI still starting (stablyai#37227)

* Continue in Chat UI opens the chat before closing the terminal, and stops a CLI still starting

The chat tab now opens right after the terminal and is selected before the terminal closes; its create waits for proof the CLI exited, so the workspace never sits empty while a large conversation loads. The terminal is kept only when the host proves its shell runs nothing, so a CLI clicked before its first status update is stopped instead of left writing beside a chat that can't send.

* Continue in Chat UI asks before stopping another job, shows a chat already opening, and keeps a failed chat in place

A job started in the shell after the agent quit now goes through the terminal's running-process prompt instead of being stopped silently. A pane not bound to its terminal on this client is treated as unverifiable and closed, like any unverifiable read. When a chat for the same conversation is already opening, Continue shows it and keeps the terminal rather than handing the terminal into a launch it doesn't own. After the terminal closed, a failed start stays in the chat that took its place and says why once, including when the CLI's exit couldn't be confirmed, so the workspace is never left blank. A launch that ended before its tab opened reports its failure again, and a tab picked during the close stays selected.

* Continue in Chat UI asks before stopping a different agent, and answers a chat still opening without joining it

Only the conversation's own agent is stopped without the running-process prompt; another agent started in that shell is asked about like any other job. A chat already opening the same conversation is found before the new chat starts and shown (or named, from the tab menu) with the terminal kept, so an unconfirmed chat's create is never re-sent beside the running CLI. The in-chat message for an unconfirmed stop no longer points at a host connection. Test timestamps are fixed values.
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