From f4040131ed9e295fceac5b60286180e8ada1b20f Mon Sep 17 00:00:00 2001 From: ethan Date: Tue, 16 Dec 2025 14:17:32 +1100 Subject: [PATCH] =?UTF-8?q?=F0=9F=A4=96=20fix:=20support=20Electron=20flag?= =?UTF-8?q?s=20(--no-sandbox)=20in=20packaged=20AppImage?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Distinguish CLI flags (--help, --version) from Electron flags (--no-sandbox) - CLI flags show help/version; Electron flags launch desktop - Export CLI_GLOBAL_FLAGS constant with sync documentation - Add runtime sanity check in dev mode for flag consistency - Add tests for packaged Electron flag handling (31 total) --- src/cli/argv.test.ts | 36 +++++++++++++++++++++++++++++++++++- src/cli/argv.ts | 29 +++++++++++++++++++++++------ src/cli/index.ts | 13 +++++++++++++ 3 files changed, 71 insertions(+), 7 deletions(-) diff --git a/src/cli/argv.test.ts b/src/cli/argv.test.ts index 8a687fb23e..a9610c2446 100644 --- a/src/cli/argv.test.ts +++ b/src/cli/argv.test.ts @@ -1,5 +1,6 @@ import { describe, expect, test } from "bun:test"; import { + CLI_GLOBAL_FLAGS, detectCliEnvironment, getParseOptions, getSubcommand, @@ -8,6 +9,19 @@ import { isElectronLaunchArg, } from "./argv"; +describe("CLI_GLOBAL_FLAGS", () => { + test("contains expected help and version flags", () => { + expect(CLI_GLOBAL_FLAGS).toContain("--help"); + expect(CLI_GLOBAL_FLAGS).toContain("-h"); + expect(CLI_GLOBAL_FLAGS).toContain("--version"); + expect(CLI_GLOBAL_FLAGS).toContain("-v"); + }); + + test("has exactly 4 flags", () => { + expect(CLI_GLOBAL_FLAGS).toHaveLength(4); + }); +}); + describe("detectCliEnvironment", () => { test("bun/node: firstArgIndex=2", () => { const env = detectCliEnvironment({}, undefined); @@ -123,11 +137,26 @@ describe("isElectronLaunchArg", () => { const env = detectCliEnvironment({}, undefined); expect(isElectronLaunchArg(".", env)).toBe(false); expect(isElectronLaunchArg("--help", env)).toBe(false); + expect(isElectronLaunchArg("--no-sandbox", env)).toBe(false); + }); + + test("returns true for Electron flags in packaged mode (--no-sandbox, etc.)", () => { + const env = detectCliEnvironment({ electron: "33.0.0" }, undefined); + expect(isElectronLaunchArg("--no-sandbox", env)).toBe(true); + expect(isElectronLaunchArg("--disable-gpu", env)).toBe(true); + expect(isElectronLaunchArg("--enable-logging", env)).toBe(true); }); - test("returns false for packaged Electron (flags are real CLI args)", () => { + test("returns false for CLI flags in packaged mode (--help, --version)", () => { const env = detectCliEnvironment({ electron: "33.0.0" }, undefined); expect(isElectronLaunchArg("--help", env)).toBe(false); + expect(isElectronLaunchArg("-h", env)).toBe(false); + expect(isElectronLaunchArg("--version", env)).toBe(false); + expect(isElectronLaunchArg("-v", env)).toBe(false); + }); + + test("returns false for '.' in packaged mode", () => { + const env = detectCliEnvironment({ electron: "33.0.0" }, undefined); expect(isElectronLaunchArg(".", env)).toBe(false); }); @@ -154,6 +183,11 @@ describe("isElectronLaunchArg", () => { const env = detectCliEnvironment({ electron: "33.0.0" }, true); expect(isElectronLaunchArg(undefined, env)).toBe(false); }); + + test("returns false for undefined subcommand in packaged mode", () => { + const env = detectCliEnvironment({ electron: "33.0.0" }, undefined); + expect(isElectronLaunchArg(undefined, env)).toBe(false); + }); }); describe("isCommandAvailable", () => { diff --git a/src/cli/argv.ts b/src/cli/argv.ts index 6d6963465d..4efdee014e 100644 --- a/src/cli/argv.ts +++ b/src/cli/argv.ts @@ -70,20 +70,37 @@ export function getArgsAfterSplice( return argv.slice(env.firstArgIndex); } +/** + * Global CLI flags that should show help/version, not launch desktop. + * Commander auto-adds --help/-h. We add --version/-v in index.ts. + * + * IMPORTANT: If you add new global flags to the CLI in index.ts, + * add them here too so packaged Electron routes them correctly. + */ +export const CLI_GLOBAL_FLAGS = ["--help", "-h", "--version", "-v"] as const; + /** * Check if the subcommand is an Electron launch arg (not a real CLI command). - * In dev mode (electron --inspect .), argv may contain flags or "." before the subcommand. - * These should trigger desktop launch, not CLI processing. + * In dev mode, "." or flags before the app path should launch desktop. + * In packaged mode, Electron flags (--no-sandbox, etc.) should launch desktop, + * but CLI flags (--help, --version) should show CLI help. */ export function isElectronLaunchArg( subcommand: string | undefined, env: CliEnvironment = detectCliEnvironment() ): boolean { - if (env.isPackagedElectron || !env.isElectron) { - return false; + if (!env.isElectron) return false; + + if (env.isPackagedElectron) { + // In packaged: flags that aren't CLI flags should launch desktop + return Boolean( + subcommand?.startsWith("-") && + !CLI_GLOBAL_FLAGS.includes(subcommand as (typeof CLI_GLOBAL_FLAGS)[number]) + ); } - // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing -- intentional: false from startsWith should still check "." - return subcommand?.startsWith("-") || subcommand === "."; + + // Dev mode: "." or any flag launches desktop + return subcommand === "." || subcommand?.startsWith("-") === true; } /** diff --git a/src/cli/index.ts b/src/cli/index.ts index a321cd852e..7798f2d49a 100644 --- a/src/cli/index.ts +++ b/src/cli/index.ts @@ -23,6 +23,7 @@ import { Command } from "commander"; import { VERSION } from "../version"; import { + CLI_GLOBAL_FLAGS, detectCliEnvironment, getParseOptions, getSubcommand, @@ -79,11 +80,23 @@ if (subcommand === "run") { const gitCommit = typeof versionRecord.git_commit === "string" ? versionRecord.git_commit : "unknown"; + // Global flags are defined in CLI_GLOBAL_FLAGS (argv.ts) for routing logic. + // Commander auto-adds --help/-h. We define --version/-v below. program .name("mux") .description("Mux - AI agent orchestration") .version(`${gitDescribe} (${gitCommit})`, "-v, --version"); + // Sanity check: ensure version flags match CLI_GLOBAL_FLAGS + if (process.env.NODE_ENV !== "production") { + const versionFlags = ["-v", "--version"]; + for (const flag of versionFlags) { + if (!CLI_GLOBAL_FLAGS.includes(flag as (typeof CLI_GLOBAL_FLAGS)[number])) { + console.warn(`Warning: version flag "${flag}" not in CLI_GLOBAL_FLAGS`); + } + } + } + // Register subcommand stubs for help display (actual implementations are above) // `run` is only available via bun/node CLI, not bundled in Electron if (isCommandAvailable("run", env)) {