# electron-builder configuration for Claude Code Agent Monitor (macOS + Windows). # # Defaults to ad-hoc signing so the project can build distributable DMGs # without a paid Apple Developer account. When the following environment # variables are set in CI (typically as repository secrets), the same # config produces a Developer ID–signed and Apple-notarized DMG: # # APPLE_ID Apple ID email # APPLE_TEAM_ID Developer team identifier # APPLE_APP_SPECIFIC_PASSWORD App-specific password for notarytool # CSC_LINK Base64-encoded .p12 cert (optional) # CSC_KEY_PASSWORD Password for the .p12 (optional) # # No code changes are required to enable notarization later. appId: com.vn.smartgift.ccam.desktop productName: Claude Code Monitor copyright: Copyright (c) 2026 SmartGift. All rights reserved. directories: output: release buildResources: assets # We pre-build with tsc into out/, and we ship the existing server/ and # client/dist/ from the parent repo as extraResources. Keeping the bundle # small: no source maps, no parent node_modules tree. files: - "out/**/*" - "package.json" extraResources: - from: "../server" to: "app/server" filter: - "**/*" - "!__tests__/**" - "!**/*.test.js" - from: "../client/dist" to: "app/client/dist" filter: ["**/*"] - from: "../scripts" to: "app/scripts" filter: - "**/*" - "!**/*.test.js" - from: "../package.json" to: "app/package.json" - from: "../node_modules" to: "app/node_modules" filter: - "**/*" - "!**/*.md" - "!**/test/**" - "!**/tests/**" - "!**/*.d.ts" # better-sqlite3 ships from desktop/node_modules (per-arch rebuilt by # install-app-deps). The root copy is built for the system Node and # would trip @electron/universal's identical-file detector. - "!**/better-sqlite3/**" # Tray icon images need to live OUTSIDE the asar archive: `nativeImage` can't # always read them from an asar path, and `files` here (out/**, package.json) # would otherwise leave them out of the bundle entirely. Ship them as plain # files at `Resources/assets/`; `trayImagePath()` reads them via # `process.resourcesPath` in production. macOS uses the template PNGs; Windows # uses the colored `icon.ico` (a template/black glyph would vanish on the # dark Windows taskbar). - from: "assets" to: "assets" filter: - "tray-icon-Template*.png" - "icon.ico" asar: true asarUnpack: # better-sqlite3 native bindings cannot live inside asar. - "**/node_modules/better-sqlite3/**" mac: category: public.app-category.developer-tools icon: assets/icon.icns hardenedRuntime: true gatekeeperAssess: false # Ad-hoc signed by default: the `package` npm script sets # CSC_IDENTITY_AUTO_DISCOVERY=false so a code-signing cert already in the # contributor's keychain is never picked up (it would fail distribution # signing). Real Developer ID signing activates only when CSC_LINK (an # explicit .p12) is provided — that path is unaffected by the flag. # No `arch:` here on purpose. Pinning the arch list in the config makes # electron-builder build *every* listed architecture regardless of the CLI # flag, so `electron-builder --mac --arm64` would still emit an x64 DMG too. # With arch left unspecified, the `--arm64` / `--x64` / `--universal` flags # the `dmg:*` npm scripts pass are what decide which single DMG is produced. target: - dmg extendInfo: LSUIElement: false NSHighResolutionCapable: true NSRequiresAquaSystemAppearance: false dmg: artifactName: "ClaudeCodeMonitor-${version}-${arch}.dmg" # The mounted-volume title carries the architecture so that, when a release/ # directory holds more than one DMG, the Finder windows are distinguishable # and nobody drags an x64 build onto Apple Silicon (which triggers a Rosetta # prompt). The arch label is NOT set here: the `${arch}` macro expands # inconsistently inside `title` — it yields `-arm64` / an empty string rather # than `arm64` / `x64`. The per-arch `dmg:*` scripts in package.json override # `dmg.title` with an explicit, clean label instead. title: "Claude Code Monitor" icon: assets/icon.icns contents: # Left slot: the .app bundle. Do NOT set `type: file` here — electron-builder # auto-fills the app at this slot when type/path are omitted. With an # explicit `type: file` and no `path`, recent electron-builder resolves # `path: ""` against the project dir and stat's `/desktop`, then # bombs with `/desktop not a file`. Omitting both is the canonical # form documented in the electron-builder DMG layout examples. - x: 130 y: 220 - x: 410 y: 220 type: link path: /Applications window: width: 540 height: 380 win: # Multi-size BMP icon generated by `scripts/build-win-icon.ps1` from the same # `icon.png` the macOS pipeline renders — see that script's header. Embedded # in the .exe and reused for the installer + taskbar. icon: assets/icon.ico # Emit both an NSIS installer (.exe) and a no-install portable .exe. The # `win` / `win:portable` npm scripts pass an explicit target so each produces # exactly one artifact; a bare `electron-builder --win` builds both. No # `arch:` is pinned here for the same reason as macOS above — the per-arch # CLI flag (`--x64`) is what decides the architecture. target: - nsis - portable # Unsigned by default. Unlike macOS there is no keychain identity to suppress: # Windows signing activates only when an explicit certificate is provided via # CSC_LINK + CSC_KEY_PASSWORD (or win.certificateFile). Unsigned builds run # fine; SmartScreen may show a "more info" prompt on first launch. nsis: # A two-step installer (not oneClick) so the user can pick the install dir. # Per-user install (perMachine: false) writes to %LOCALAPPDATA%\Programs and # needs no administrator elevation. oneClick: false perMachine: false allowToChangeInstallationDirectory: true createDesktopShortcut: true createStartMenuShortcut: true shortcutName: "Claude Code Monitor" uninstallDisplayName: "Claude Code Monitor ${version}" artifactName: "ClaudeCodeMonitor-Setup-${version}-${arch}.${ext}" # Keep the per-user SQLite database + settings (under userData) on uninstall, # mirroring macOS where dragging the .app to Trash never touches user data. deleteAppDataOnUninstall: false portable: artifactName: "ClaudeCodeMonitor-${version}-${arch}-portable.${ext}" # Notarization runs only when the Apple credentials are present (macOS only; # the hook is a no-op on Windows). afterSign: scripts/notarize.js