# OpenChamber Desktop Electron desktop runtime for OpenChamber on macOS and Windows. This package owns the native shell: windows, menus, deep links, native notifications, auto-updates, host switching, SSH connections, tunnel helpers, and packaged desktop builds. The web UI and OpenChamber server logic still live in `packages/web` and shared React UI lives in `packages/ui`. ## How It Runs Desktop starts the OpenChamber web server in the same Electron main process. There is no separate sidecar subprocess for the OpenChamber server. `main.mjs` imports `@openchamber/web/server/index.js` and calls `startWebUiServer()`. The Electron window then loads the UI from the local server in development, or from packaged `resources/web-dist` assets in packaged builds. The preload bridge exposes desktop-only APIs to the web UI through `window.__OPENCHAMBER_DESKTOP__`. Privileged commands are checked in `main.mjs`, not only in the UI. ## Main Files | File | Purpose | |------|---------| | `main.mjs` | Electron main process, app lifecycle, windows, menus, deep links, native IPC handlers, updates, local server startup | | `preload.mjs` | Safe bridge from the rendered UI to Electron IPC | | `ssh-manager.mjs` | SSH host import, connection lifecycle, tunnel/port forwarding helpers | | `scripts/electron-dev.mjs` | Desktop dev launcher with Vite HMR support | | `scripts/build-web-assets.mjs` | Builds `packages/web` and stages UI assets into `resources/web-dist` | | `scripts/bundle-main.mjs` | Bundles Electron main code into `dist-bundle/main.mjs` for packaging | | `scripts/rebuild-native.mjs` | Rebuilds native modules against the Electron runtime | | `scripts/package.mjs` | Runs `electron-builder`, with unsigned Windows builds when signing env is missing | | `resources/` | Packaged web assets, icons, and macOS entitlements | ## Development From the repo root: ```bash bun install bun run electron:dev ``` `bun run electron:dev` starts the web dev server with HMR, then launches Electron against `packages/electron/main.mjs`. Useful variants: ```bash bun run electron:dev:bundled bun run type-check:electron bun run lint:electron ``` `electron:dev:bundled` builds and uses packaged web assets instead of the HMR server. Use it when testing behavior closer to a packaged app. ## Packaging From the repo root: ```bash bun run electron:build ``` That runs, in order: 1. `build:web-assets` to build the web UI and copy it into `packages/electron/resources/web-dist`. 2. `bundle:main` to create `packages/electron/dist-bundle/main.mjs`. 3. `rebuild:native` to rebuild native modules for Electron. 4. `package.mjs` to run `electron-builder`. Build output goes to `packages/electron/dist`. macOS builds produce `dmg` and `zip` artifacts. Windows builds produce an NSIS installer. ## Platform Notes macOS packaging needs Xcode/build tools for notarized builds and icon asset compilation. Windows packaging needs NSIS support through `electron-builder`. If no Windows signing env is set, `package.mjs` disables code signing and builds an unsigned installer. The package supports macOS and Windows desktop features. Some native discovery helpers are platform-specific. For example, app icon fetching and app filtering currently only work on macOS, while opening files in installed apps works on macOS and Windows. ## Common Env Vars | Variable | Use | |----------|-----| | `OPENCHAMBER_ELECTRON_DEV=1` | Marks the runtime as desktop development mode | | `OPENCHAMBER_ELECTRON_USE_BUNDLED_UI=1` | Uses staged web assets instead of the HMR dev server | | `OPENCHAMBER_HMR_UI_PORT` | Preferred Vite UI port for desktop dev, default `5173` | | `OPENCHAMBER_HMR_API_PORT` | Preferred API port for desktop dev, default `3901` | | `OPENCHAMBER_RUNTIME=desktop` | Set by Electron before starting the web server | | `OPENCHAMBER_DESKTOP_NOTIFY=true` | Enables desktop notification flow in the web server | | `OPENCHAMBER_SKIP_API_COMPRESSION=true` | Defaulted by Desktop to reduce local CPU overhead | | `OPENCODE_HOST` / `OPENCODE_PORT` / `OPENCODE_SKIP_START` | Connect Desktop to an external OpenCode server instead of starting one locally | ## Native Features Owned Here - Floating Mini Chat windows. - Multiple native windows. - Native notifications. - One-click open/reveal/open-in-app actions. - Desktop host switcher and deep-link imports. - Local and remote instance handling. - SSH host import, connections, logs, and port forwarding. - Tunnel lifecycle integration through the web server runtime. - Auto-update checks, downloads, and restart/apply flow. ## IPC Pattern Renderer code should call the desktop bridge exposed by `preload.mjs`. Do not import Electron from shared UI code. Add new native capabilities in this order: 1. Add or update the `preload.mjs` bridge only if a new renderer-facing shape is needed. 2. Add the real command handling in `main.mjs` under `openchamber:invoke`. 3. Gate privileged commands in main process logic so remote pages cannot access local filesystem or shell capabilities. 4. Keep shared UI runtime contracts in `packages/ui` and server/runtime APIs in `packages/web` when the behavior is not inherently native. ## Logs And Data Electron uses `electron-log`. In development, console logs are also visible in the terminal. In packaged apps, logs are written through the platform log path for the `OpenChamber` app name. Development builds use a separate user data directory named `OpenChamber Dev`, so dev state does not overwrite normal packaged app state. ## Things To Be Careful With - Keep desktop-specific code in this package. Do not move OpenCode feature backend logic into Electron. - Use hidden Windows process launches for background helpers. Avoid visible console flashes. - Keep `@openchamber/web`, `bun-pty`, `node-pty`, and native modules external in `bundle-main.mjs`; bundling them can break Electron startup. - Rebuild native modules after dependency or Electron version changes. - Test both HMR dev mode and bundled UI mode when changing startup, preload, routing, or packaged asset behavior. ## Quick Checks ```bash bun run type-check:electron bun run lint:electron bun run electron:dev:bundled ``` For full repo validation before shipping: ```bash bun run type-check bun run lint ```