Skip to content

Confirm before closing terminals with running processes#687

Merged
sbertix merged 14 commits into
supabitapp:mainfrom
adamgall:confirm-running-tab-close
Jul 21, 2026
Merged

Confirm before closing terminals with running processes#687
sbertix merged 14 commits into
supabitapp:mainfrom
adamgall:confirm-running-tab-close

Conversation

@adamgall

@adamgall adamgall commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Closes #684

Summary

  • Add a default-enabled Confirm before Closing Terminals setting under Settings → General → Advanced.
  • Use Ghostty's native close flow end to end: embedded surfaces always evaluate confirm-close-surface, explicit surface closes consume Ghostty's processAlive callback, and tab closes preflight every pane with ghostty_surface_needs_confirm_quit.
  • Route explicit surface closes and user-facing single/bulk tab closes through one pending-confirmation model. Every guarded close uses the same Close Terminal? alert and Close Terminal destructive action.
  • Preserve the target of an active confirmation: another close request while the alert is open is ignored instead of retargeting the destructive action.
  • Keep internal/programmatic teardown immediate, persist the Supacode setting as the UI-policy switch, and default missing legacy values to enabled.

Type of change

  • Bug fix (the linked issue is a bug report)
  • Feature (the linked issue is a feature request marked ready)
  • Documentation
  • Other (please describe)

How was this tested?

Automated

  • Focused WorktreeTerminalManagerTests, AgentBusyStateTests, SettingsFeatureTests, SettingsFilePersistenceTests, and GhosttyRuntimeBundledOverridesTests passed after the surface-routing rework.
  • Coverage includes: matching generic confirmation copy for surface and tab closes, split-pane-specific removal, native explicit-surface confirmation and cancellation, active-confirmation target preservation under overlapping pane close requests, idle/disabled bypass, all-pane tab preflight, bulk tab operations, setting persistence/defaulting, notification cleanup after surface close, and the bundled Ghostty override.
  • make check passed (format + lint).
  • make test passed: 2,671 tests, 0 failures (2,655 passed and 16 expected failures).
  • make build-app passed.

Manual

Before the review-driven internal routing change, the feature branch was stacked temporarily onto the existing isolated Supacode Dev implementation from #510 so it could run beside production without sharing ~/.supacode, restored layouts, app identity, or CLI socket routing. The isolation commits are not included in this pull request.

Confirmed end to end through the final implementation:

  1. The setting appears in Settings → General → Advanced and is enabled by default.
  2. An idle tab closes immediately without an alert.
  3. A tab running sleep 300 shows the confirmation alert.
  4. Cancel preserves both the tab and running process; the destructive close action removes the tab.
  5. A running process in a non-focused pane of a split tab still triggers confirmation for the whole tab.
  6. Disabling the setting makes a busy tab close immediately without confirmation.
  7. With busy processes in both panes, invoking ⌘W in one pane shows the alert; focusing the other pane and invoking ⌘W makes no visual change; confirming the existing alert closes only the originally targeted pane.

The final native surface-routing and active-target-preservation behavior is covered by the focused and full automated suites and the two-pane manual scenario above.

  • make check passes (format + lint)
  • make test passes
  • I built and ran the app to confirm the user-facing behavior

AI tool disclosure (optional)

  • Model(s): OpenAI GPT-5.6 Sol
  • Harness / tools: Oh My Pi (OMP) in Supacode; Xcode/xcodebuild and Swift Testing for verification

Checklist

  • This pull request is linked to an issue with Closes # above.
  • For a feature, the linked issue is labeled ready.
  • I am the author of this work and accountable for it; no commit is authored or co-authored by an AI agent.
  • I have read the Contributing guide and the Code of Conduct.

Comment thread supacodeTests/PullRequestMergeQueueStatusTests.swift Outdated
…-close

# Conflicts:
#	supacodeTests/PullRequestMergeQueueStatusTests.swift
@adamgall
adamgall requested a review from sbertix July 15, 2026 18:15

@sbertix sbertix left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I played with this a bit, and I feel like there's been a misunderstanding. I should have been more specific in the issue reply (my bad, sorry 🙇‍♂️), but confirm-close-surface was inviting a surface-based approach, the same as Ghostty, instead of a tab-based one.

For instance, this tab-based approach doesn’t prompt for the number-one use case (imho): ⌘W on a single-surface tab, since that is always a surface close, not a tab close.

Would you be interested in reworking the PR/closing this and opening a new one so the flag actually implements a confirm-close-surface 1:1 equivalent for Supacode? Cause that's the thing we should mirror (as we don't enforce that), and adding it without tying it to Ghostty config makes it extendable in the future to any node leaf.

@adamgall adamgall changed the title Confirm before closing tabs with running processes Confirm before closing terminals with running processes Jul 15, 2026
@adamgall
adamgall marked this pull request as draft July 15, 2026 20:33
@adamgall
adamgall marked this pull request as ready for review July 15, 2026 21:34
@adamgall
adamgall marked this pull request as draft July 15, 2026 21:47
@adamgall
adamgall marked this pull request as ready for review July 15, 2026 22:39
@adamgall
adamgall requested a review from sbertix July 15, 2026 22:40
@sbertix

sbertix commented Jul 15, 2026

Copy link
Copy Markdown
Collaborator

Thank you 🙇‍♂️ I'll try and get back to this tomorrow (so we can 100% have it in the next release)

adamgall and others added 4 commits July 15, 2026 20:38
Drive the confirmation alert off the pending target's captured payload so a
dismissal written back through the SwiftUINavigation item binding can no longer
race the button actions: confirm closes the captured target even if the
published value was cleared first, and cancel reliably clears the surface's
explicit-close flag so a later unexpected zmx exit still reattaches instead of
tearing down.

Route every user-facing close command through the confirmation. Ghostty's
palette/keybind close-tab now honors its scope, so "close others" and "close
to the right" confirm like the context menu instead of collapsing to a
single-tab close. Bypass the confirmation only for programmatic surface
destroys, which the deeplink/CLI layer already gates upstream, so their
acknowledgement is not blocked on an interactive alert.

Fold the identical alert copy onto the type, drop the now-dead closeOtherTabs,
closeTabsToRight, and closeAllTabs, and log the two silent close paths.

Cover the bypass path, captured-payload confirm and cancel, the bulk-close
wrappers, the Ghostty close-tab modes, multi-tab confirmation, and
destroyed-while-pending cleanup.
@sbertix
sbertix enabled auto-merge (squash) July 21, 2026 22:02

@sbertix sbertix left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thanks 🙇‍♂️ I pushed a hardening pass on top to close a confirm/cancel race in the alert and route the missing close commands (Ghostty's palette close-others / close-to-the-right, which weren't wired up) through the confirmation.

@sbertix
sbertix merged commit cf6aadd into supabitapp:main Jul 21, 2026
3 checks passed
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.

Closing a tab terminates running processes without confirmation

2 participants