Skip to content

[BUG] Antigravity GUI: Process hangs on close, second-instance window failure, and Linux updater bypass #599

Description

@renich

Bug Summary

On Linux (unpacked installations), the Antigravity Electron GUI application suffers from three critical issues:

  1. Process Hang on Close: When the GUI is closed, the main process and backend language server processes continue to run in the background (often leaving zombie/defunct child processes or fully orphaned processes).
  2. Failure to Open/Restore Window on Second Launch: Since RUN_IN_BACKGROUND is active by default on Linux, closing the window leaves the app running in the background. Launching a new instance detects the single-instance lock, exits the new instance, but the background instance fails to create or restore a window because the second-instance event handler assumes there is already a window active.
  3. Linux Auto-Updater Fails to Run: electron-updater's AppImageUpdater on Linux immediately aborts with the warning APPIMAGE env is not defined, current application is not an AppImage when run from an unpacked directory, disabling update checks.

Root Cause Analysis

1. Process Hang on Close

In main.js, the before-quit handler is an async function:

app.on('before-quit', async (event) => {
  if (isQuitting) return;
  if (!showQuitConfirmation) {
    event.preventDefault();
    isQuitting = true;
    // ... destroys windows, kills language server ...
    app.quit(); // <--- TRIGGERS before-quit AGAIN
    return;
  }
});

Calling app.quit() inside the async block triggers the before-quit event a second time. In the second call, isQuitting is true, so it returns immediately. However, since the first call had event.preventDefault(), the quitting sequence was aborted and the second call does not force the event loop to exit.

  • Fix: Use app.exit(0) instead of app.quit() at the end of the async cleanup block to bypass recursive quit events and terminate the process immediately.

2. Restore Window on Second Launch

In main.js, the second-instance handler only focuses windows if wins.length > 0:

app.on('second-instance', (event, commandLine) => {
  const wins = BrowserWindow.getAllWindows();
  if (wins.length > 0) {
    // ... restores and focuses wins[0] ...
  }
  // BUG: If wins.length === 0, no window is opened, and the app stays hidden in background
});
  • Fix: Re-create/open a new window if wins.length === 0 and the application is not headless.

3. Linux Auto-Updater Fails on Unpacked Runs

On Linux, AppImageUpdater aborts checks if process.env.APPIMAGE is undefined.

  • Fix: Programmatically fallback to process.execPath (i.e. process.env.APPIMAGE = process.env.APPIMAGE || process.execPath;) during updater initialization on Linux.

Proposed Patches

Patch for main.ts / main.js:

--- dist/main.js.orig
+++ dist/main.js
@@ -121,6 +121,10 @@
         wins[0].focus();
         electron_1.app.focus({ steal: true });
     }
+    else if (!HEADLESS) {
+        const url = DEV_URL ?? `${constants_1.WINDOW_ORIGIN}:${(0, languageServer_1.getLsPort)()}/`;
+        (0, utils_1.createWindow)(url);
+    }
     const url = commandLine.find((arg) => arg.startsWith(`${PROTOCOL}://`));
     if (url) {
         handleDeepLink(url);
@@ -327,7 +331,7 @@
             }),
             (0, languageServer_1.killLanguageServer)(),
         ]);
-        electron_1.app.quit();
+        electron_1.app.exit(0);
         return;
     }

Patch for updater.ts / updater.js:

--- dist/updater.js.orig
+++ dist/updater.js
@@ -133,6 +133,9 @@
 function initAutoUpdater(isHeadless, settingsService) {
+    if (process.platform === 'linux' && !process.env.APPIMAGE) {
+        process.env.APPIMAGE = process.execPath;
+    }
     // In dev mode (npm start), electron-updater skips checks because the app
     // isn't packaged. Force it to use the dev config file instead.
     if (!electron_1.app.isPackaged) {

AI Assistance Disclosure

This issue and patch were co-developed with Gemini AI. Under my direction, the agent extracted app.asar, analyzed the lifecycle hangs and lock logic, applied local modifications, and empirically verified the auto-updater functionality (via version downgrading). I have reviewed, tested, and take full responsibility for these changes.

Co-developed-by: Gemini AI renich+gemini@woralelandia.com
Signed-off-by: Rénich Bon Ćirić renich@woralelandia.com

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions