Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 12 additions & 3 deletions apps/desktop/src/main/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@ app.on("open-url", async (event, url) => {

let isQuitting = false;
let skipQuitConfirmation = false;
let forceFullCleanup = false;

export function setSkipQuitConfirmation(): void {
skipQuitConfirmation = true;
Expand All @@ -173,6 +174,13 @@ export function quitApp(): void {
app.quit();
}

/** Nuclear quit: also kills host-service(s) and pty-daemon/terminal-host. */
export function quitAppCompletely(): void {
forceFullCleanup = true;
setSkipQuitConfirmation();
app.quit();
}

/** Bypasses before-quit — services are left running for re-adoption on next launch. */
export function exitImmediately(): void {
app.exit(0);
Expand Down Expand Up @@ -214,7 +222,7 @@ app.on("before-quit", async (event) => {

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>

await runDevQuitCleanup();
} else {
// Prod: leave services running so the next launch re-adopts via manifest.
Expand All @@ -229,8 +237,9 @@ app.on("before-quit", async (event) => {
});

/**
* Dev only — kill host-service + terminal-host children. They're spawned
* attached + ref'd in dev, so they'd reparent to init without an explicit stop.
* Full cleanup — kill host-service + terminal-host children. Used in dev (where
* they'd reparent to init without an explicit stop) and on the tray's
* "Quit Superset Completely" path in prod.
*/
async function runDevQuitCleanup(): Promise<void> {
getHostServiceCoordinator().stopAll();
Expand Down
32 changes: 30 additions & 2 deletions apps/desktop/src/main/lib/tray/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@ import { existsSync } from "node:fs";
import { join } from "node:path";
import {
app,
dialog,
Menu,
type MenuItemConstructorOptions,
nativeImage,
Tray,
} from "electron";
import { loadToken } from "lib/trpc/routers/auth/utils/auth-functions";
import { env } from "main/env.main";
import { focusMainWindow, quitApp } from "main/index";
import { focusMainWindow, quitApp, quitAppCompletely } from "main/index";
import {
getHostServiceCoordinator,
type HostServiceStatusEvent,
Expand Down Expand Up @@ -83,6 +84,26 @@ function openSettings(): void {
menuEmitter.emit("open-settings");
}

async function confirmAndQuitCompletely(): Promise<void> {
try {
const { response } = await dialog.showMessageBox({
type: "warning",
buttons: ["Quit Completely", "Cancel"],
defaultId: 1,
cancelId: 1,
title: "Quit Superset Completely",
message: "Quit Superset and stop all background services?",
detail:
"All open terminal sessions will be killed and any running host-services will be stopped. Use “Close Superset” instead if you want services to keep running for the next launch.",
});
if (response === 0) {
quitAppCompletely();
}
} catch (error) {
console.error("[Tray] Quit-completely confirmation failed:", error);
}
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.

interface HostInfo {
organizationName: string;
version: string;
Expand Down Expand Up @@ -229,9 +250,16 @@ async function updateTrayMenu(): Promise<void> {
},
{ type: "separator" },
{
label: "Quit Superset",
label: "Close Superset",
click: () => quitApp(),
},
{ type: "separator" },
{
label: "Quit Superset Completely",
click: () => {
void confirmAndQuitCompletely();
},
},
Comment thread
Kitenite marked this conversation as resolved.
]);

tray.setContextMenu(menu);
Expand Down
Loading