diff --git a/package.json b/package.json index 5b4e6a76..8d8b2ea4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "agent-company", - "version": "0.4.53", + "version": "0.4.54", "private": true, "type": "module", "description": "Cross-platform Electron desktop control plane for local-first AI agent companies.", @@ -12,6 +12,7 @@ "build:verify": "electron-vite build", "build": "electron-vite build && node scripts/build-desktop.mjs", "build:dir": "electron-vite build && node scripts/build-desktop.mjs --dir", + "build:all": "node scripts/build-all-platforms.mjs", "lint": "eslint .", "lint:fix": "eslint . --fix", "typecheck": "tsc --noEmit", diff --git a/scripts/build-all-platforms.mjs b/scripts/build-all-platforms.mjs new file mode 100644 index 00000000..def863fc --- /dev/null +++ b/scripts/build-all-platforms.mjs @@ -0,0 +1,118 @@ +#!/usr/bin/env node +/** + * build-all-platforms.mjs + * Builds Electron app artifacts for the current platform and reports + * which platforms still need native builds on their respective hosts. + * + * Usage: node scripts/build-all-platforms.mjs [--skip-vite] + * + * Per D-07: All three platforms (macOS, Windows, Linux) must produce + * valid build artifacts. + * + * electron-builder does NOT support true cross-compilation for all targets: + * - macOS DMG/zip requires macOS + * - Windows NSIS/portable requires Windows (or Wine) + * - Linux AppImage requires Linux (or Docker) + * + * This script builds for the CURRENT platform, verifies artifacts, and + * documents remaining platforms that must be built on their native hosts. + */ +import { execFileSync } from "node:child_process"; +import { existsSync } from "node:fs"; +import { readdir } from "node:fs/promises"; +import { join, dirname } from "node:path"; +import { fileURLToPath } from "node:url"; + +const __dirname = dirname(fileURLToPath(import.meta.url)); +const rootDir = join(__dirname, ".."); +const releaseDir = join(rootDir, "build", "release"); +const skipVite = process.argv.includes("--skip-vite"); + +const PLATFORM_FLAGS = { + darwin: "--mac", + win32: "--win", + linux: "--linux", +}; + +const PLATFORM_NAMES = { + darwin: "macOS", + win32: "Windows", + linux: "Linux", +}; + +const EXPECTED_EXTENSIONS = { + darwin: [".dmg", ".zip"], + win32: [".exe"], + linux: [".AppImage"], +}; + +const currentPlatform = process.platform; +const platformFlag = PLATFORM_FLAGS[currentPlatform]; + +if (!platformFlag) { + console.error(`[build-all] Unsupported platform: ${currentPlatform}`); + process.exit(1); +} + +console.log(`[build-all] Building for ${PLATFORM_NAMES[currentPlatform]} (${currentPlatform})...`); + +// Step 1: Run electron-vite build (unless --skip-vite) +if (!skipVite) { + console.log("[build-all] Running electron-vite build..."); + execFileSync("pnpm", ["electron-vite", "build"], { + stdio: "inherit", + cwd: rootDir, + shell: currentPlatform === "win32", + }); +} + +// Step 2: Run build-desktop.mjs with the current platform flag +console.log(`[build-all] Running electron-builder ${platformFlag}...`); +execFileSync("node", [join(__dirname, "build-desktop.mjs"), platformFlag], { + stdio: "inherit", + cwd: rootDir, + env: { + ...process.env, + CSC_IDENTITY_AUTO_DISCOVERY: process.env.CSC_IDENTITY_AUTO_DISCOVERY ?? "false", + }, + shell: currentPlatform === "win32", +}); + +// Step 3: Verify build artifacts exist +if (!existsSync(releaseDir)) { + console.error(`[build-all] ERROR: Release directory not found: ${releaseDir}`); + process.exit(1); +} + +const files = await readdir(releaseDir); +const expectedExts = EXPECTED_EXTENSIONS[currentPlatform]; +const foundArtifacts = files.filter((f) => + expectedExts.some((ext) => f.endsWith(ext)), +); + +if (foundArtifacts.length === 0) { + console.error( + `[build-all] ERROR: No ${PLATFORM_NAMES[currentPlatform]} artifacts found in ${releaseDir}. ` + + `Expected files with extensions: ${expectedExts.join(", ")}`, + ); + process.exit(1); +} + +console.log(`\n[build-all] SUCCESS: ${PLATFORM_NAMES[currentPlatform]} build artifacts:`); +for (const artifact of foundArtifacts) { + console.log(` - ${artifact}`); +} + +// Step 4: Report remaining platforms +const otherPlatforms = Object.entries(PLATFORM_NAMES) + .filter(([key]) => key !== currentPlatform) + .map(([, name]) => name); + +if (otherPlatforms.length > 0) { + console.log(`\n[build-all] NOTE: Build on these platforms for full D-07 coverage:`); + for (const name of otherPlatforms) { + console.log(` - ${name}: run 'pnpm build:all' on a ${name} host`); + } +} + +console.log("\n[build-all] Done.");