From e7413bb504c70112ed0a2a9f2c303d3f18eaf8da Mon Sep 17 00:00:00 2001 From: Jannis Braun <151788261+TheZwiss@users.noreply.github.com> Date: Mon, 27 Apr 2026 13:01:35 +0200 Subject: [PATCH] docs(desktop): rewrite Auto-Launch section to match new architecture MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replaces the stale Auto-Launch section with an accurate description of the Tasks 3–7 implementation: OS-authoritative read model, platform-specific applyLoginItemSettings() contract, Linux/AppImage-only conditional re-apply, defence-in-depth hidden-launch detection, and the pure helpers in autoLaunch.ts. Also updates Startup Sequence step 9 to reflect that unconditional re-apply is gone. --- docs/systems/desktop.md | 53 ++++++++++++++++++++++++++++++----------- 1 file changed, 39 insertions(+), 14 deletions(-) diff --git a/docs/systems/desktop.md b/docs/systems/desktop.md index 7207a135..b0da0526 100644 --- a/docs/systems/desktop.md +++ b/docs/systems/desktop.md @@ -102,28 +102,53 @@ Settings stored in `{userData}/auto-launch.json`: ```typescript interface AutoLaunchSettings { - openAtLogin: boolean; // default: false - startMinimized: boolean; // default: true + openAtLogin: boolean; // default: false; disk cache, NOT source of truth + startMinimized: boolean; // default: true; disk cache; OS-authoritative on Windows } ``` +### Source of Truth + +The OS is the source of truth for `openAtLogin` on all platforms. Disk is used only to recover values Electron does not expose: +- **Windows:** OS-authoritative for both `openAtLogin` (via `executableWillLaunchAtLogin`, which honours Task Manager's `StartupApproved\Run` disable) and `startMinimized` (derived from `launchItems[].args`). +- **macOS:** OS-authoritative for `openAtLogin`. Disk-cached for `startMinimized` (no introspection available). +- **Linux:** OS-authoritative for `openAtLogin`. Disk-cached for `startMinimized` (we deliberately do not parse `Exec=` lines from `.desktop` files; out-of-band edits are rare and parsing shell-quoted strings is fragile). + ### Platform-Specific Implementation (`applyLoginItemSettings()`) -| Platform | Method | Minimized Launch | -|----------|--------|-----------------| -| macOS | `app.setLoginItemSettings({ openAtLogin, openAsHidden })` | `openAsHidden` flag | -| Windows | `app.setLoginItemSettings({ openAtLogin, args, name })` | `--hidden` CLI arg | -| Linux | `app.setLoginItemSettings({ openAtLogin, path, args })` | `--hidden` CLI arg; `path` set to `$APPIMAGE` for AppImage portability | +| Platform | Method | Key parameters | Rationale | +|----------|--------|----------------|-----------| +| macOS | `app.setLoginItemSettings({ openAtLogin, openAsHidden, args })` | `openAsHidden: startMinimized`; `args: ['--hidden']` when `startMinimized` | Both detection paths covered (legacy `wasOpenedAsHidden` for macOS < 13 and `--hidden` argv for macOS 13+) | +| Windows | `app.setLoginItemSettings({ openAtLogin, enabled, path, args, name })` | `enabled: openAtLogin`; `path: process.execPath`; `args: ['--hidden']` when `startMinimized`; `name: 'Backspace'` | `enabled` is required to clear Task Manager's `StartupApproved\Run` disable when re-enabling. `path`/`args` enable correct matching in subsequent `getLoginItemSettings`. | +| Linux | `app.setLoginItemSettings({ openAtLogin, name, path?, args? })` | `name: 'backspace'` (deterministic `.desktop` filename); `path: $APPIMAGE` when running as AppImage; `args: ['--hidden']` when `startMinimized` | `name` ensures stable `~/.config/autostart/backspace.desktop` path. AppImage path tracks updates. | -On startup, settings are re-applied to the OS (`applyLoginItemSettings`) to refresh the login item path (important for AppImage updates where the path changes). +### Startup Re-Apply -### Launch Detection +The unconditional startup re-apply was removed (it was overwriting user changes made via Task Manager / System Settings). Today the only re-apply happens on Linux/AppImage and only when needed: -Hidden launch is detected at `ready-to-show` via: -- `process.argv.includes('--hidden')` (Windows/Linux) -- `app.getLoginItemSettings().wasOpenedAsHidden` (macOS) +``` +if linux AND $APPIMAGE is set: + read ~/.config/autostart/backspace.desktop → recordedExecPath + if saved.openAtLogin AND $APPIMAGE != recordedExecPath: + re-apply to refresh the autostart entry's Exec= path +``` -If launched hidden, the window is created but never shown (stays in tray). +This keeps AppImage updates working (the AppImage moved to a new path → autostart entry needs the new path) without overriding any user-level OS state on Windows or macOS. + +### Hidden-Launch Detection + +At `ready-to-show`: +- `process.argv.includes('--hidden')` — primary signal on all platforms (we pass `args: ['--hidden']` everywhere when `startMinimized`). +- `app.getLoginItemSettings().wasOpenedAsHidden` — macOS-only fallback for the legacy `openAsHidden` path (macOS < 13). + +If either is true, the window is created but not shown (stays in tray). + +### Pure Helpers + +Pure logic lives in `packages/desktop/src/autoLaunch.ts` with vitest coverage in `autoLaunch.test.ts`: +- `deriveStartMinimizedFromArgs(args)` — used by both IPC handlers on Windows. +- `parseExecPathFromDesktopFile(content)` — used by the Linux/AppImage path-refresh. +- `shouldReapplyAppImage(currentAppImagePath, recordedExecPath)` — used by the Linux/AppImage path-refresh. --- @@ -765,7 +790,7 @@ GitHub releases are the update source. The `electron-updater` library handles ch 6. Create tray icon 7. Initialize auto-updater (10s delayed first check) 8. Start activity detection (immediate first poll, 15s interval, background remote sync) -9. Sync auto-launch settings with OS +9. Linux/AppImage path-refresh: re-apply autostart entry if `$APPIMAGE` path changed (conditional; no-op on Windows/macOS) 10. Check for deep link in launch args ### Shutdown Sequence (`before-quit`)