#!/usr/bin/env node import { builtinModules } from 'node:module'; import { readFileSync } from 'node:fs'; import { join } from 'node:path'; import { fileURLToPath } from 'node:url'; const __dirname = fileURLToPath(new URL('.', import.meta.url)); const ROOT = join(__dirname, '..'); const MAIN_BUNDLE = join(ROOT, 'dist-electron', 'main', 'index.js'); const PACKAGE_JSON = join(ROOT, 'package.json'); const ignoredRuntimeSpecifiers = new Set([ 'electron', ...builtinModules, ...builtinModules.map((name) => `node:${name}`), ]); const packageJson = JSON.parse(readFileSync(PACKAGE_JSON, 'utf8')); const mainBundle = readFileSync(MAIN_BUNDLE, 'utf8'); function packageNameFromSpecifier(specifier) { if ( !specifier || specifier.startsWith('.') || specifier.startsWith('/') || ignoredRuntimeSpecifiers.has(specifier) ) { return undefined; } const parts = specifier.split('/'); return specifier.startsWith('@') ? parts.slice(0, 2).join('/') : parts[0]; } function collectRuntimeDependencies() { const specs = new Set(); const patterns = [ /require\((['"])([^'"]+)\1\)/g, /import\((['"])([^'"]+)\1\)/g, ]; for (const pattern of patterns) { let match; while ((match = pattern.exec(mainBundle))) { specs.add(match[2]); } } return new Set( [...specs] .map(packageNameFromSpecifier) .filter(Boolean), ); } const required = collectRuntimeDependencies(); const packaged = new Set(Object.keys(packageJson.dependencies ?? {})); const missing = [...required].filter((name) => !packaged.has(name)).sort(); const redundant = [...packaged].filter((name) => !required.has(name)).sort(); if (missing.length || redundant.length) { console.error('Electron runtime dependency boundary is not clean.'); if (missing.length) { console.error(`Missing package.json dependencies:\n${missing.map((name) => ` - ${name}`).join('\n')}`); } if (redundant.length) { console.error(`Redundant package.json dependencies that will be double-packed:\n${redundant.map((name) => ` - ${name}`).join('\n')}`); } console.error('\nKeep OpenClaw/agent dependencies in devDependencies; bundle-openclaw.mjs copies them into resources/openclaw.'); process.exit(1); } console.log(`Electron runtime dependency boundary OK (${packaged.size} package dependencies).`);