feat(desktop): confirm before closing a terminal pane with a running process

Merged
KI
4mo ago
+607-37

What & why

Closing a terminal pane by mistake (Cmd+W) silently kills whatever is running in it. This adds a confirmation dialog that appears only when a foreground command is actually running, with a persisted "Don't ask again" checkbox. Closing at an idle shell prompt still closes instantly — no nag.

Covers every close route through the pane's onBeforeClose guard: Cmd+W (CLOSE_PANE), the close button, middle-click, context menu, and browser-pane Cmd+W.

How "a process is running" is detected

No such signal existed. It's computed on demand from the shell's controlling-terminal foreground process group via ps -o tpgid -o pgid:

  • idle prompt → terminal's foreground group == the shell's own group → not running
  • running command → the shell handed the terminal to the command's group → they differ → running

This is precise: unlike a "shell has child processes" check it does not false-positive on suspended/background jobs. Fails closed (returns false) on any ps error, missing tty, or if we can't reach the query — never blocks a close.

Changes

  • packages/pty-daemon/src/process-tree.ts — new hasRunningForegroundProcess(shellPid)
  • packages/host-service/…/terminal/terminal.ts — sessionHasRunningProcess(terminalId) (session pid → detection)
  • packages/host-service/…/trpc/router/terminal/terminal.ts — new terminal.hasRunningProcess query
  • packages/ui/…/Alert/Alert.tsx — alert() gains an optional checkbox + onDismiss (Escape/outside-click resolves as cancel instead of hanging)
  • apps/desktop/…/stores/terminal-close-confirm/store.ts — persisted suppression flag (localStorage)
  • apps/desktop/…/usePaneRegistry.tsx — terminal onBeforeClose guard

Verification

Driven end-to-end in the running desktop app (v2 workspace, over CDP):

ScenarioResult
Running sleep 300 + Cmd+WDialog appears with checkbox + Cancel / Close terminal
CancelPane stays open
Idle prompt (after Ctrl+C) + Cmd+WCloses instantly, no dialog
Don't-ask-again checked → CloseCloses, persists suppressed:true
Suppressed + running terminal + Cmd+WCloses instantly, no dialog
Browser (non-terminal) pane closeInstant, no dialog

Plus a real-pty integration test (test/foreground-process.test.ts) exercising idle→running→idle, mutation-verified to fail when the core comparison breaks. typecheck / lint / pty-daemon suite all pass.

Scope

Pane-level close only. Closing a whole tab (CLOSE_TAB, a different shortcut) that contains a running terminal does not warn yet — left as a follow-up.


Open in Stage

Summary by cubic

Adds a confirm dialog when closing a terminal pane or tab that has a running foreground command, with a “Don’t ask again” option. Also disposes host-service terminals on workspace close/delete and closed worktree delete, broadcasting cleanup to all local hosts and pruning disposed rows to prevent leaks.

  • New Features

    • Detects running foreground commands via ps (tpgid vs pgid) in @superset/pty-daemon (hasRunningForegroundProcess), returning false on errors.
    • Exposes status via sessionHasRunningProcess and tRPC terminal.hasRunningProcess (workspace-gated; probes live with staleTime: 0).
    • Shared confirm covers pane close and tab close (tab X, Close Others/All, CLOSE_TAB hotkey); skips backgrounded terminals; suppression persisted via useTerminalCloseConfirmStore. @superset/ui alert() adds optional checkbox, onDismiss, returns a boolean; probe or Alerter failures never block close.
  • Bug Fixes

    • Prevents leaked host-service sessions by disposing on workspace close/delete and closed worktree delete; disposal is best-effort and broadcast to every running local host-service across orgs.
    • After disposal, prunes non-active terminal rows in the host DB for both workspace and worktree paths. Security: terminal.hasRunningProcess enforces workspace ownership.

Summary by CodeRabbit

  • New Features
    • Added terminal-pane close confirmation when a foreground command is running.
    • Added a “Don’t ask again” checkbox to persist the preference.
    • Added workspace/tab close guarding that prompts only when needed, including via the close-tab hotkey.
  • Bug Fixes
    • Improved detection of whether foreground work is still running, reducing unnecessary blocking.
    • After deleting a workspace or worktree, added best-effort cleanup to prevent leftover terminal sessions.
  • Tests
    • Added an integration test covering foreground-process detection behavior.