From 70098e6825af209926b4cc1e14481e1b8d8d85b3 Mon Sep 17 00:00:00 2001 From: Ame Date: Fri, 19 Jun 2026 17:04:24 +0800 Subject: [PATCH] fix(desktop): drop in-window menu bar on Win/Linux + surface real bootstrap errors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two papercuts found dogfooding the packaged Windows build: - The default Electron File/Edit/View/Window/Help menu renders *inside* the window on Windows/Linux (it never shows on macOS, where menus live in the system bar) — meaningless clutter for a single-window web-UI app. Set a minimal menu on macOS (keeps copy/paste accelerators), none elsewhere. - Workspace bootstrap failures showed 'exited with code unknown' (a null exit code from a spawn failure) instead of the actual reason, which was already sitting in result.stderr (e.g. the 'bash not found, install Git for Windows' hint). Surface the stderr tail in the message. Co-Authored-By: Claude Opus 4.8 (1M context) --- apps/desktop/src/main.ts | 13 ++++++++++++- src/workspaces/workspace-creator.ts | 11 ++++++++++- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/apps/desktop/src/main.ts b/apps/desktop/src/main.ts index 4d7d5fc3..85cb1c60 100644 --- a/apps/desktop/src/main.ts +++ b/apps/desktop/src/main.ts @@ -21,7 +21,7 @@ * code signing, blocked by Squirrel.Mac), multi-window, native menus. */ -import { app, BrowserWindow, dialog, shell } from 'electron' +import { app, BrowserWindow, dialog, shell, Menu } from 'electron' import { spawn, spawnSync, type ChildProcess } from 'node:child_process' import { mkdir, readFile, watch } from 'node:fs/promises' import { fileURLToPath } from 'node:url' @@ -285,6 +285,17 @@ app.whenReady().then(async () => { // + respawn UTA without restarting Alice (mirrors prod.mjs). ──────────── void startFlagWatcher(homeEnv.OPENALICE_HOME, utaUrl, spawnUTA) + // No in-window menu bar on Windows/Linux — Electron's default + // File/Edit/View/Window/Help renders *inside* the window there and is + // meaningless for a single-window web-UI app (it never shows on macOS, + // where menus live in the system bar). macOS keeps a minimal menu so the + // app menu + copy/paste/select-all accelerators still work. + Menu.setApplicationMenu( + process.platform === 'darwin' + ? Menu.buildFromTemplate([{ role: 'appMenu' }, { role: 'editMenu' }, { role: 'windowMenu' }]) + : null, + ) + const win = new BrowserWindow({ width: 1280, height: 800, diff --git a/src/workspaces/workspace-creator.ts b/src/workspaces/workspace-creator.ts index e5a0f0f4..c1da6aa1 100644 --- a/src/workspaces/workspace-creator.ts +++ b/src/workspaces/workspace-creator.ts @@ -157,10 +157,19 @@ export class WorkspaceCreator { exitCode: result.exitCode, stderr: result.stderr.slice(0, 4000), }); + // Surface the actual reason in the message, not just the exit code — + // a null exit code (spawn failure: bash-not-found on Windows, timeout) + // rendered as "code unknown" tells the user nothing, while result.stderr + // already carries the why (e.g. the Git-for-Windows install hint). + const reason = result.stderr.trim(); + const headline = + result.exitCode === null + ? 'bootstrap could not start' + : `bootstrap script exited with code ${result.exitCode}`; return { ok: false, code: 'bootstrap_failed', - message: `bootstrap script exited with code ${result.exitCode ?? 'unknown'}`, + message: reason ? `${headline}:\n${reason.slice(-500)}` : headline, stderr: result.stderr, ...(result.exitCode !== null ? { exitCode: result.exitCode } : {}), };