File size: 5,064 Bytes
1dbc34b | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 | #!/usr/bin/env node
/**
* This script prepares the server for bundling with Electron.
* It copies the server dist and installs production dependencies
* in a way that works with npm workspaces.
*/
import { execSync } from 'child_process';
import { cpSync, existsSync, mkdirSync, rmSync, writeFileSync, readFileSync, lstatSync } from 'fs';
import { join, dirname, resolve } from 'path';
import { fileURLToPath } from 'url';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const APP_DIR = join(__dirname, '..');
const SERVER_DIR = join(APP_DIR, '..', 'server');
const LIBS_DIR = join(APP_DIR, '..', '..', 'libs');
const BUNDLE_DIR = join(APP_DIR, 'server-bundle');
// Local workspace packages that need to be bundled
const LOCAL_PACKAGES = [
'@automaker/types',
'@automaker/utils',
'@automaker/prompts',
'@automaker/platform',
'@automaker/model-resolver',
'@automaker/dependency-resolver',
'@automaker/git-utils',
];
console.log('π§ Preparing server for Electron bundling...\n');
// Step 1: Clean up previous bundle
if (existsSync(BUNDLE_DIR)) {
console.log('ποΈ Cleaning previous server-bundle...');
rmSync(BUNDLE_DIR, { recursive: true });
}
mkdirSync(BUNDLE_DIR, { recursive: true });
// Step 2: Build the server TypeScript
console.log('π¦ Building server TypeScript...');
execSync('npm run build', { cwd: SERVER_DIR, stdio: 'inherit' });
// Step 3: Copy server dist
console.log('π Copying server dist...');
cpSync(join(SERVER_DIR, 'dist'), join(BUNDLE_DIR, 'dist'), { recursive: true });
// Step 4: Copy local workspace packages
console.log('π¦ Copying local workspace packages...');
const bundleLibsDir = join(BUNDLE_DIR, 'libs');
mkdirSync(bundleLibsDir, { recursive: true });
for (const pkgName of LOCAL_PACKAGES) {
const pkgDir = pkgName.replace('@automaker/', '');
const srcDir = join(LIBS_DIR, pkgDir);
const destDir = join(bundleLibsDir, pkgDir);
if (!existsSync(srcDir)) {
console.warn(`β οΈ Warning: Package ${pkgName} not found at ${srcDir}`);
continue;
}
mkdirSync(destDir, { recursive: true });
// Copy dist folder
if (existsSync(join(srcDir, 'dist'))) {
cpSync(join(srcDir, 'dist'), join(destDir, 'dist'), { recursive: true });
}
// Copy package.json
if (existsSync(join(srcDir, 'package.json'))) {
cpSync(join(srcDir, 'package.json'), join(destDir, 'package.json'));
}
console.log(` β ${pkgName}`);
}
// Step 5: Create a minimal package.json for the server
console.log('π Creating server package.json...');
const serverPkg = JSON.parse(readFileSync(join(SERVER_DIR, 'package.json'), 'utf-8'));
// Replace local package versions with file: references
const dependencies = { ...serverPkg.dependencies };
for (const pkgName of LOCAL_PACKAGES) {
if (dependencies[pkgName]) {
const pkgDir = pkgName.replace('@automaker/', '');
dependencies[pkgName] = `file:libs/${pkgDir}`;
}
}
const bundlePkg = {
name: '@automaker/server-bundle',
version: serverPkg.version,
type: 'module',
main: 'dist/index.js',
dependencies,
};
writeFileSync(join(BUNDLE_DIR, 'package.json'), JSON.stringify(bundlePkg, null, 2));
// Step 6: Install production dependencies
console.log('π₯ Installing server production dependencies...');
execSync('npm install --omit=dev', {
cwd: BUNDLE_DIR,
stdio: 'inherit',
env: {
...process.env,
// Prevent npm from using workspace resolution
npm_config_workspace: '',
},
});
// Step 6b: Replace symlinks for local packages with real copies
// npm install creates symlinks for file: references, but these break when packaged by electron-builder
console.log('π Replacing symlinks with real directory copies...');
const nodeModulesAutomaker = join(BUNDLE_DIR, 'node_modules', '@automaker');
for (const pkgName of LOCAL_PACKAGES) {
const pkgDir = pkgName.replace('@automaker/', '');
const nmPkgPath = join(nodeModulesAutomaker, pkgDir);
try {
// lstatSync does not follow symlinks, allowing us to check for broken ones
if (lstatSync(nmPkgPath).isSymbolicLink()) {
const realPath = resolve(BUNDLE_DIR, 'libs', pkgDir);
rmSync(nmPkgPath);
cpSync(realPath, nmPkgPath, { recursive: true });
console.log(` β Replaced symlink: ${pkgName}`);
}
} catch (error) {
// If the path doesn't exist, lstatSync throws ENOENT. We can safely ignore this.
if (error.code !== 'ENOENT') {
throw error;
}
}
}
// Step 7: Rebuild native modules for current architecture
// This is critical for modules like node-pty that have native bindings
console.log('π¨ Rebuilding native modules for current architecture...');
try {
execSync('npm rebuild', {
cwd: BUNDLE_DIR,
stdio: 'inherit',
});
console.log('β
Native modules rebuilt successfully');
} catch (error) {
console.warn(
'β οΈ Warning: Failed to rebuild native modules. Terminal functionality may not work.'
);
console.warn(' Error:', error.message);
}
console.log('\nβ
Server prepared for bundling at:', BUNDLE_DIR);
|