# DOX — packages/electron

Files in this directory. One row per source file.

| File | Purpose |
|------|---------|
| `forge.config.ts` | Electron Forge config: DMG, DEB, AppImage, NSIS makers, icon, extraResources. `extraResource` `./resources/git` when present. See change: embed-git-bash-on-windows. **NSIS naming overrides** (change: fix-electron-windows-installer-and-server-bootstrap): NSIS maker's `getAppBuilderConfig` pins `productName`, `appId`, `nsis.artifactName`, `nsis.shortcutName`, `nsis.uninstallDisplayName` all to `pi-dashboard`. Without override, electron-builder's NSIS install-dir fallback reads npm `name` slash-stripped + produces `@blackbelt-technologypi-dashboard-electron`. Locked by `forge-config-naming.test.ts`. **macOS deployment-target floor** (change: upgrade-electron-runtime, supersedes add-darwin-x64-build 6b): `packagerConfig.extendInfo.LSMinimumSystemVersion = "12.0"` pins minimum macOS version in `Info.plist`. Floor raised 10.15 → 12.0 with the Electron 32.3.3 → 43.4.1 bump (Electron dropped 10.15 at v33, 11 at v38). Pairs with `MACOSX_DEPLOYMENT_TARGET=12.0` from `Make Electron distributables` step in `_electron-build.yml` (governs Mach-Os the build COMPILES) + CI verification step that mounts DMG + asserts both match — runner-image upgrade or source-built native module cannot silently raise floor without failing job. The otool leg checks the renamed Electron PREBUILT, whose `minos` is baked upstream, so it is an upstream-floor tripwire, not a check on the env var; comparison is EQUALITY (below-floor became reachable at 12.0). Constants + predicate: `scripts/macos-floor.mjs`. **DMG + AppImage makers removed** (change: fix-electron-auto-update-pipeline): `@electron-forge/maker-dmg` + `@pengx17/electron-forge-maker-appimage` dropped; DMG + AppImage now built by electron-builder (see `electron-builder.yml`). Only deb maker remains in Forge. Arch-tagged DMG basename workaround (change: fix-darwin-dmg-arch-collision) + `forge-config-dmg-naming.test.ts` superseded; electron-builder `-c.mac.artifactName` template handles arch tagging. See change: fix-electron-auto-update-pipeline. **NSIS via electron-builder sidecar** (change: restore-windows-nsis-installer): Forge no longer produces Windows NSIS; per-user `Setup.exe` built by `electron-builder --win nsis` (config `packages/electron/electron-builder-nsis.json`, include `build/installer.nsh`) on `windows-latest` CI. Portable `.exe` target dropped. |
| `scripts/assert-bundled-plugins-complete.mjs` | Built-bundle plugin-completeness gate (change: add-nightly-verdaccio-build). Complements the SOURCE-list guard `packages/shared/src/__tests__/bundled-plugins-complete.test.ts`: asserts the built bundle's `resources/plugins/` (default `packages/electron/resources/server/resources/plugins`) contains every non-fixture runtime plugin in `packages/*` (predicate: `pi-dashboard-plugin` manifest present AND `fixture !== true` — a DATA decision, no hardcoded denylist). Flags kb-plugin-style omissions at build time on every leg before upload. Env-overridable `PACKAGES_DIR`/`BUNDLE_PLUGINS_DIR` for unit tests. Exports discoverRuntimePlugins/readBundledPlugins/computeMissing. Wired as a per-leg step in `_electron-build.yml` when `source_only_bundle == false`. |
| `scripts/assert-bundled-server-plugin-load.mjs` | Built-bundle plugin-LOAD gate (change: fix-browser-plugin-vendor-specifier-resolution, X13). The sibling asserts prove the bundle CONTAINS everything but boot nothing, so none catches a plugin that is present-but-dead: the bundle ships no `tsconfig.base.json` (bundle-server.mjs copies workspace source, not the repo tsconfig) and `JITI_TSCONFIG_PATHS` was deleted. Boots bundled node + `node_modules/jiti/lib/jiti-register.mjs` + `packages/server/src/cli.ts start` with the flag removed and a temp HOME whose config enables the browser plugin, waits for `/api/health`, then reads the server's own `[plugin-loader]` verdict for `Loaded plugin "browser"` plus zero `Failed to load plugin`. Refuses when `tsconfig.base.json` is present in the bundle (the gate would be green for the wrong reason). Node-native, Windows-safe (no bash). Env-overridable `SERVER_BUNDLE_DIR`. Exports `bundleRoot`/`bundleLayout`/`pluginLoadProblems`. Wired as a per-leg step in `_electron-build.yml` when `source_only_bundle == false`. |
| `scripts/bundle-server.mjs` | Bundles the dashboard server into `resources/server` for the Electron app: copies workspace + first-party-plugin package trees, runs an internal `npm install --omit=dev` (Column C — stays npm), materializes workspace symlinks, GO/NO-GO node-pty prebuild guard. Each recursive package-tree `cpSync` (workspace loop, plugin loop, symlink-materialization) uses a `node_modules`-excluding filter with a **Windows-safe** `src.split(/[\\/]/).includes("node_modules")` split (NOT `path.sep`) so pnpm store-symlinks aren't copied into the bundle and break node-pty prebuilds. See change: adopt-pnpm-for-dev-ci. First-party plugin list = `packages/server/package.json#piDashboard.bundledPlugins` via shared `runtime-overlay/materialize-plugins.mjs` (`readBundledPluginIds` + `materializeBundledPlugins`); no local `BUNDLED_PLUGINS` array. Stamps `resources/server/runtime-manifest.json` (origin `bundled`, `minShellVersion` from `piDashboard.minShellVersion`, `nodeEngines` = server `engines.node`, `piVersion` when installed; also in `--source-only`). See change: electron-runtime-overlay-updates. `bundledPlugins` includes `system-one-plugin` (its server imports the published `@blackbelt-technology/pi-system-one`, same pattern as kb-plugin → `pi-dashboard-kb`). See change: add-system-one-registry. |
| `scripts/inject-update-min-system-version.mjs` | CLI: injects `minimumSystemVersion` (from `scripts/macos-floor.mjs`) into an EMITTED `latest-mac.yml`. Post-build step in `_electron-build.yml` darwin leg. Refuses any basename other than `latest-mac.yml` — `checkIfUpdateSupported` has no platform guard, so the field in `latest-linux.yml`/`latest.yml` compares a Linux/Windows version against a Darwin value and denies updates to EVERY client there (fail-CLOSED). Line-based edit, idempotent; NOT a YAML round-trip. `electron-builder.yml mac.minimumSystemVersion` would be a no-op (update-info builder never writes it; `macPackager` skipped under `--prepackaged`). See change: upgrade-electron-runtime. |
| `scripts/macos-floor.mjs` | Single source of truth for the macOS floor + the pure predicates the CI floor check runs. Exports `MACOS_FLOOR_MARKETING` (`"12.0"` — `LSMinimumSystemVersion` / `MACOSX_DEPLOYMENT_TARGET`), `MACOS_FLOOR_MINOS_MAJOR` (`12` — expected `LC_BUILD_VERSION.minos` major of the Electron PREBUILT, observed empirically), `UPDATE_MINIMUM_SYSTEM_VERSION` (`"21.0.0"` — DARWIN triple; `"12.0"`/`"21"` make `semver.lt` throw, the throw is caught, and the gate silently dies), `extractMinosValues` (multi-slice safe; falls back to `LC_VERSION_MIN_MACOSX`), `checkMinosFloor` (EQUALITY, statuses `ok`/`mismatch`/`non-numeric`/`not-extractable`). Exists as a module so the CI injection step and the L1 tests cannot drift apart. Locked by `src/__tests__/macos-floor-check.test.ts` + `update-min-system-version.test.ts`. See change: upgrade-electron-runtime. |
| `scripts/verify-macos-floor.mjs` | CLI wrapper: `otool -l <mach-o>` → `checkMinosFloor`. Maps status to GitHub annotations — `mismatch` → `::error::` exit 1; `not-extractable`/`non-numeric` → `::warning::` exit 0 (robust to future Mach-O formats). Replaces the inline, untestable awk in `_electron-build.yml`. See change: upgrade-electron-runtime. |
| `scripts/verify-update-gate-scope.mjs` | CLI: asserts the emitted update metadata carries the macOS gate AND is correctly scoped. `latest-mac.yml` MUST equal `UPDATE_MINIMUM_SYSTEM_VERSION` (missing → fail-OPEN: below-floor clients enter a permanent failed-install retry loop); `latest-linux.yml`/`latest.yml` MUST NOT carry it (present → fail-CLOSED: no platform guard in `checkIfUpdateSupported`, so every client there loses updates). A darwin invocation with no `latest-mac.yml` FAILS rather than passing on an empty scan. Node not bash so the win32 legs need no shell (`eliminate-bash-on-windows-runners`). Final step of `_electron-build.yml`, after the Windows NSIS step writes `latest.yml`. See change: upgrade-electron-runtime. |
| `scripts/server-launch-helpers/README.md` | Manual server-launch helpers overview. Three self-locating scripts boot bundled server without Electron wrapper + without system Node: `start-server.cmd` (Windows), `start-server.ps1` (PowerShell), `start-server.sh` (Linux/macOS). `subcommand` defaults `start`; also `status`, `stop`, `restart`. Use when wrapper hangs or verifying CI artefact runnable. |
| `vite.main.config.ts` | Vite config for Electron main process build. Entry `src/main.ts`, ES output `.vite/build/main.js`. Externalizes Node builtins + `node:` prefixes + `electron` + `electron-updater`. |
| `vite.preload.config.ts` | Vite config for Electron preload build. Entry `src/preload.ts`, CJS output. Externalizes Node builtins + `node:` prefixes + `electron`. |
| `vitest.build-contract.config.ts` | SECOND vitest project for this package, scoped by explicit filename to the BUILD-CONTRACT tests (`electron-version-pin`, `macos-floor-check`, `update-min-system-version`, `build-config-parity`, `forge-config-windows-version`, `src/lib/__tests__/launch-source` — pure, probes injected; E4/E23; `runtime-overlay`, `server-watchdog` — injected I/O, E3 E11-E13 P1 X4-X9, see change: electron-runtime-overlay-updates). Registered in the ROOT `vitest.config.ts` — unlike `vitest.config.ts`, which is deliberately excluded because the package carries pre-existing orphaned tests needing ambient PATH/mocks. Rationale: these pin the shipped Electron pin, macOS floor and update gate, and a gate no CI job runs is not a gate. Entries must be pure (config/text/fixture + pure predicates, no ambient env, no Electron runtime). See change: upgrade-electron-runtime. Also collects `src/lib/__tests__/launch-source-heap.test.ts` (Electron heap stamp; only `launchDashboardServer` module-mocked). See change: guard-server-heap-and-store-coupling. |
| `vitest.config.ts` | Vitest config for electron package. Includes `src/**/__tests__/**/*.test.ts`, node env, `forks` pool, `maxWorkers: 1`, globalSetup from shared `setup-home.ts`. NOT registered at the repo root (pre-existing orphaned tests) — see `vitest.build-contract.config.ts` for the subset that is. |

