Skip to content

feat(desktop): add tray "Quit Superset Completely" for full shutdown#4212

Merged
Kitenite merged 4 commits into
mainfrom
macos-tray-quit-all
May 7, 2026
Merged

feat(desktop): add tray "Quit Superset Completely" for full shutdown#4212
Kitenite merged 4 commits into
mainfrom
macos-tray-quit-all

Conversation

@Kitenite
Copy link
Copy Markdown
Collaborator

@Kitenite Kitenite commented May 7, 2026

Summary

  • Adds a new macOS tray entry "Quit Superset Completely" that nukes everything: the Electron app, all running host-services, and the pty-daemon/terminal-host.
  • The existing "Quit Superset" remains a soft quit — services keep running so the next launch re-adopts them via manifest. Auto-update behavior is unchanged.
  • Reuses the existing runDevQuitCleanup() shutdown sequence (coordinator.stopAll() + terminalHostClient.shutdownIfRunning({ killSessions: true })) by gating it on a new forceFullCleanup flag inside the before-quit handler.

Test plan

  • Dev: bun dev in apps/desktop, sign in to an org, click tray → Quit Superset. App and services exit cleanly (no regression).
  • Packaged build, Quit Superset Completely: confirm pgrep -f host-service is empty and the pty-daemon socket is gone after quit.
  • Packaged build, Quit Superset (soft): host-service PID survives Electron exit and is re-adopted on next launch.
  • Tray Host Service → Restart / Stop still flips status correctly.
  • Auto-update swap does not tear down host-service / pty-daemon.
  • bun run lint and bun run typecheck exit 0.

Summary by cubic

Add a macOS tray option “Quit Superset Completely” to fully shut down the app and all background services, with a confirmation prompt. The soft path is now “Close Superset” and keeps services running for re-adoption.

  • New Features
    • Adds “Quit Superset Completely” via quitAppCompletely() + forceFullCleanup, reusing runDevQuitCleanup() to stop host-service(s) and the pty-daemon/terminal-host.
    • Shows a warning dialog before full shutdown (Cancel default) and catches dialog errors; adds a separator before the action and removes an unused tray tooltip.
    • Renames soft quit to “Close Superset”; behavior unchanged and auto-update still leaves services running.

Written for commit 45f9d2b. Summary will update on new commits.

Summary by CodeRabbit

  • New Features
    • Added a "Quit Superset Completely" menu/tray option that performs a full cleanup of background services and resources before exiting.
    • The existing quit option is now labeled "Close Superset" to distinguish it from the full-quit behavior.
    • The full-quit option shows a confirmation prompt ("Quit Superset Completely") before proceeding to prevent accidental full shutdowns.

Adds a nuclear-quit tray entry that kills host-service(s) and the
pty-daemon/terminal-host alongside the Electron app. The existing
"Quit Superset" remains a soft quit so services survive for re-adoption.

Reuses runDevQuitCleanup() via a forceFullCleanup flag in before-quit.
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 7, 2026

Review Change Stack
No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 32f12180-e73e-490d-a61b-24d8980a33d3

📥 Commits

Reviewing files that changed from the base of the PR and between b7df10e and 45f9d2b.

📒 Files selected for processing (1)
  • apps/desktop/src/main/lib/tray/index.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/desktop/src/main/lib/tray/index.ts

📝 Walkthrough

Walkthrough

This PR adds a "Quit Superset Completely" feature: a new exported quitAppCompletely() sets forceFullCleanup and triggers quit; the before-quit handler runs full host/terminal cleanup when that flag is set; the tray menu adds a confirmed "Quit Superset Completely" entry wired to this API.

Changes

Complete App Quit Flow

Layer / File(s) Summary
Core Quit API
apps/desktop/src/main/index.ts
Module-level forceFullCleanup flag and quitAppCompletely() function that sets the flag, skips confirmation, and triggers app.quit().
Quit Handler Logic
apps/desktop/src/main/index.ts
Before-quit handler now treats forceFullCleanup like development mode, running full host/terminal cleanup instead of service re-adoption.
Documentation
apps/desktop/src/main/index.ts
Docstring for runDevQuitCleanup() updated to reflect broader usage beyond pure development contexts.
Tray Imports
apps/desktop/src/main/lib/tray/index.ts
Tray module imports dialog and quitAppCompletely alongside existing utilities.
Tray Confirmation Helper
apps/desktop/src/main/lib/tray/index.ts
Added confirmAndQuitCompletely() which shows a warning dialog and calls quitAppCompletely() on confirmation; errors are caught and logged.
Tray Menu Items
apps/desktop/src/main/lib/tray/index.ts
Tray context menu replaced single "Quit Superset" item with "Close Superset" (calls quitApp()) and "Quit Superset Completely" (invokes confirmation helper).

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant TrayMenu
  participant Dialog
  participant QuitAPI
  participant ElectronApp
  User->>TrayMenu: click "Quit Superset Completely"
  TrayMenu->>Dialog: show confirmation
  Dialog-->>TrayMenu: user confirms
  TrayMenu->>QuitAPI: invoke quitAppCompletely()
  QuitAPI->>ElectronApp: app.quit()
  ElectronApp->>QuitAPI: before-quit handler checks forceFullCleanup
Loading

Estimated Code Review Effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 I thump the desk, a button to flee,
"Quit Completely" — no service left to be,
A dialog warns, you click with glee,
The host cleans up, terminals set free,
Hop, hop, the app exits — tidy and free.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 37.50% 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
Title check ✅ Passed The title accurately describes the main change: adding a tray menu entry for complete app shutdown with a clear, specific focus on the new feature.
Description check ✅ Passed The description includes a comprehensive summary, detailed test plan with checkboxes, and an auto-generated section covering new features and behavior changes. All major required sections are present and well-filled.
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.

✏️ 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 macos-tray-quit-all

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.

@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented May 7, 2026

Greptile Summary

This PR adds a "Quit Superset Completely" tray menu entry that performs a full shutdown — killing host-services and the pty-daemon — by reusing the existing runDevQuitCleanup() path gated on a new forceFullCleanup module flag. The existing soft-quit path is unchanged.

  • quitAppCompletely() sets forceFullCleanup = true, calls setSkipQuitConfirmation(), and invokes app.quit(); the before-quit handler then routes to runDevQuitCleanup() instead of releaseAll().
  • The tray menu in lib/tray/index.ts adds the new item directly after "Quit Superset" and imports the new export from main/index.
  • The toolTip string on the new menu item will be silently ignored by macOS tray context menus; consider surfacing this text as a sublabel or in the item label itself if discoverability matters.

Confidence Score: 4/5

Safe to merge; the new quit path correctly reuses the established cleanup sequence and cannot interfere with the soft-quit or auto-update flows.

The logic change is small and well-contained — a boolean flag plus one extra branch in before-quit. The only concerns are presentational: the two quit items sit adjacent without a separator (easy accidental click on the destructive action), and the toolTip string is invisible in macOS tray context menus.

apps/desktop/src/main/lib/tray/index.ts — menu item layout and the unused tooltip.

Important Files Changed

Filename Overview
apps/desktop/src/main/index.ts Adds forceFullCleanup module flag and quitAppCompletely() export; gates runDevQuitCleanup() on `isDev
apps/desktop/src/main/lib/tray/index.ts Adds "Quit Superset Completely" menu item wired to quitAppCompletely(). Missing separator between the two quit items makes accidental destructive click easy; toolTip is silently ignored by macOS tray context menus.

Sequence Diagram

sequenceDiagram
    participant User
    participant Tray
    participant Main as main/index.ts
    participant Coordinator as HostServiceCoordinator
    participant TermHost as TerminalHostClient

    Note over User,TermHost: Soft quit path (existing)
    User->>Tray: click "Quit Superset"
    Tray->>Main: quitApp()
    Main->>Main: setSkipQuitConfirmation()
    Main->>Main: "app.quit() -> before-quit"
    Main->>Coordinator: releaseAll() [services survive]
    Main->>Main: app.exit(0)

    Note over User,TermHost: Nuclear quit path (new)
    User->>Tray: click "Quit Superset Completely"
    Tray->>Main: quitAppCompletely()
    Main->>Main: "forceFullCleanup = true"
    Main->>Main: setSkipQuitConfirmation()
    Main->>Main: "app.quit() -> before-quit"
    Main->>Coordinator: stopAll() [services killed]
    Main->>TermHost: "shutdownIfRunning({ killSessions: true })"
    Main->>Main: disposeTerminalHostClient()
    Main->>Main: app.exit(0)
Loading

Comments Outside Diff (1)

  1. apps/desktop/src/main/lib/tray/index.ts, line 231-239 (link)

    P2 No visual separator before the destructive quit action

    "Quit Superset Completely" immediately follows "Quit Superset" with no separator, making it easy to accidentally click the destructive action (which kills all background services). A separator line gives the user a visual pause and distinguishes the soft quit from the nuclear one.

    Prompt To Fix With AI
    This is a comment left during a code review.
    Path: apps/desktop/src/main/lib/tray/index.ts
    Line: 231-239
    
    Comment:
    **No visual separator before the destructive quit action**
    
    "Quit Superset Completely" immediately follows "Quit Superset" with no separator, making it easy to accidentally click the destructive action (which kills all background services). A separator line gives the user a visual pause and distinguishes the soft quit from the nuclear one.
    
    
    
    How can I resolve this? If you propose a fix, please make it concise.

    Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

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

---

### Issue 1 of 2
apps/desktop/src/main/lib/tray/index.ts:236-239
**`toolTip` not visible in macOS tray context menus**

The `toolTip` property on a `MenuItemConstructorOptions` object is not rendered by macOS when the menu is displayed as a tray context menu (or any `NSMenu`-backed context menu). macOS only shows item tooltips in the main menu bar, not in pop-up/context menus. The descriptive string `"Quit and stop all background services (host-service, daemon)"` will therefore never be visible to users, regardless of whether Electron silently accepts the property.

### Issue 2 of 2
apps/desktop/src/main/lib/tray/index.ts:231-239
**No visual separator before the destructive quit action**

"Quit Superset Completely" immediately follows "Quit Superset" with no separator, making it easy to accidentally click the destructive action (which kills all background services). A separator line gives the user a visual pause and distinguishes the soft quit from the nuclear one.

```suggestion
		{
			label: "Quit Superset",
			click: () => quitApp(),
		},
		{ type: "separator" },
		{
			label: "Quit Superset Completely",
			toolTip: "Quit and stop all background services (host-service, daemon)",
			click: () => quitAppCompletely(),
		},
```

Reviews (1): Last reviewed commit: "feat(desktop): add tray "Quit Superset C..." | Re-trigger Greptile

Comment thread apps/desktop/src/main/lib/tray/index.ts
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

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

1 issue found across 2 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="apps/desktop/src/main/index.ts">

<violation number="1" location="apps/desktop/src/main/index.ts:225">
P1: The new `forceFullCleanup` production path uses best-effort cleanup and still exits on cleanup failure, so "Quit Superset Completely" can leave host/terminal processes running.

(Based on your team's feedback about treating “Kill Sessions” as a hard outcome.) [FEEDBACK_USED]</violation>
</file>

Tip: cubic used a learning from your PR history. Let your coding agent read cubic learnings directly with the cubic MCP.

isQuitting = true;
try {
if (isDev) {
if (isDev || forceFullCleanup) {
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.

P1: The new forceFullCleanup production path uses best-effort cleanup and still exits on cleanup failure, so "Quit Superset Completely" can leave host/terminal processes running.

(Based on your team's feedback about treating “Kill Sessions” as a hard outcome.)

View Feedback

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/desktop/src/main/index.ts, line 225:

<comment>The new `forceFullCleanup` production path uses best-effort cleanup and still exits on cleanup failure, so "Quit Superset Completely" can leave host/terminal processes running.

(Based on your team's feedback about treating “Kill Sessions” as a hard outcome.) </comment>

<file context>
@@ -214,7 +222,7 @@ app.on("before-quit", async (event) => {
 	isQuitting = true;
 	try {
-		if (isDev) {
+		if (isDev || forceFullCleanup) {
 			await runDevQuitCleanup();
 		} else {
</file context>

Quit Superset Completely now shows a warning dialog noting that all
terminal sessions will be killed; cancel by default. The soft path is
renamed to "Close Superset" to make the distinction obvious — closing
leaves background services running for re-adoption on next launch.
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

🤖 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/lib/tray/index.ts`:
- Around line 87-101: confirmAndQuitCompletely currently awaits
dialog.showMessageBox and can throw, causing unhandled rejections when callers
intentionally discard its promise; wrap the await in a local try/catch inside
confirmAndQuitCompletely, catch any error, log it (using the same logger used
elsewhere in this module) and return void so errors are contained, and ensure
that when response === 0 you still call quitAppCompletely(); apply the same
pattern (local try/catch + logging) to the other menu-click handler(s) that call
dialog.showMessageBox (the similar call around the other Quit/Close flow).
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: e2df9505-a252-4395-966d-51a62b825b3f

📥 Commits

Reviewing files that changed from the base of the PR and between 65dbf6d and b7df10e.

📒 Files selected for processing (1)
  • apps/desktop/src/main/lib/tray/index.ts

Comment thread apps/desktop/src/main/lib/tray/index.ts
@Kitenite Kitenite merged commit b378add into main May 7, 2026
10 checks passed
@Kitenite Kitenite deleted the macos-tray-quit-all branch May 7, 2026 22:15
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 7, 2026

🧹 Preview Cleanup Complete

The following preview resources have been cleaned up:

  • ✅ Neon database branch

Thank you for your contribution! 🎉

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