docs(desktop): rewrite Auto-Launch section to match new architecture

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.
This commit is contained in:
Jannis Braun
2026-04-27 13:01:35 +02:00
parent 113efcf583
commit e7413bb504
+39 -14
View File
@@ -102,28 +102,53 @@ Settings stored in `{userData}/auto-launch.json`:
```typescript ```typescript
interface AutoLaunchSettings { interface AutoLaunchSettings {
openAtLogin: boolean; // default: false openAtLogin: boolean; // default: false; disk cache, NOT source of truth
startMinimized: boolean; // default: true 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-Specific Implementation (`applyLoginItemSettings()`)
| Platform | Method | Minimized Launch | | Platform | Method | Key parameters | Rationale |
|----------|--------|-----------------| |----------|--------|----------------|-----------|
| macOS | `app.setLoginItemSettings({ openAtLogin, openAsHidden })` | `openAsHidden` flag | | 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, args, name })` | `--hidden` CLI arg | | 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, path, args })` | `--hidden` CLI arg; `path` set to `$APPIMAGE` for AppImage portability | | 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) if linux AND $APPIMAGE is set:
- `app.getLoginItemSettings().wasOpenedAsHidden` (macOS) 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 6. Create tray icon
7. Initialize auto-updater (10s delayed first check) 7. Initialize auto-updater (10s delayed first check)
8. Start activity detection (immediate first poll, 15s interval, background remote sync) 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 10. Check for deep link in launch args
### Shutdown Sequence (`before-quit`) ### Shutdown Sequence (`before-quit`)