|
|
import esbuild from 'esbuild'; |
|
|
import { execSync } from 'child_process'; |
|
|
import fs from 'fs'; |
|
|
import path from 'path'; |
|
|
import { fileURLToPath } from 'url'; |
|
|
|
|
|
const __dirname = path.dirname(fileURLToPath(import.meta.url)); |
|
|
const rootDir = path.join(__dirname, '..'); |
|
|
const distDir = path.join(rootDir, 'dist'); |
|
|
const bundleDir = path.join(distDir, 'bundle'); |
|
|
|
|
|
|
|
|
const toSlash = (p) => p.replace(/\\/g, '/'); |
|
|
|
|
|
|
|
|
if (!fs.existsSync(distDir)) { |
|
|
fs.mkdirSync(distDir, { recursive: true }); |
|
|
} |
|
|
if (!fs.existsSync(bundleDir)) { |
|
|
fs.mkdirSync(bundleDir, { recursive: true }); |
|
|
} |
|
|
|
|
|
|
|
|
const args = process.argv.slice(2); |
|
|
const targetArg = args.find(arg => arg.startsWith('--target=')); |
|
|
const target = targetArg ? targetArg.split('=')[1] : 'node18-win-x64'; |
|
|
|
|
|
|
|
|
const targetMap = { |
|
|
'win': 'node18-win-x64', |
|
|
'win-x64': 'node18-win-x64', |
|
|
'linux': 'node18-linux-x64', |
|
|
'linux-x64': 'node18-linux-x64', |
|
|
'linux-arm64': 'node18-linux-arm64', |
|
|
'macos': 'node18-macos-x64', |
|
|
'macos-x64': 'node18-macos-x64', |
|
|
'macos-arm64': 'node18-macos-arm64', |
|
|
'all': 'node18-win-x64,node18-linux-x64,node18-linux-arm64,node18-macos-x64,node18-macos-arm64' |
|
|
}; |
|
|
|
|
|
const resolvedTarget = targetMap[target] || target; |
|
|
|
|
|
|
|
|
const outputNameMap = { |
|
|
'node18-win-x64': 'antigravity-win-x64.exe', |
|
|
'node18-linux-x64': 'antigravity-linux-x64', |
|
|
'node18-linux-arm64': 'antigravity-linux-arm64', |
|
|
'node18-macos-x64': 'antigravity-macos-x64', |
|
|
'node18-macos-arm64': 'antigravity-macos-arm64' |
|
|
}; |
|
|
|
|
|
|
|
|
const binFileMap = { |
|
|
'node18-win-x64': 'antigravity_requester_windows_amd64.exe', |
|
|
'node18-linux-x64': 'antigravity_requester_linux_amd64', |
|
|
'node18-linux-arm64': 'antigravity_requester_android_arm64', |
|
|
'node18-macos-x64': 'antigravity_requester_linux_amd64', |
|
|
'node18-macos-arm64': 'antigravity_requester_android_arm64' |
|
|
}; |
|
|
|
|
|
console.log('📦 Step 1: Bundling with esbuild...'); |
|
|
|
|
|
|
|
|
await esbuild.build({ |
|
|
entryPoints: ['src/server/index.js'], |
|
|
bundle: true, |
|
|
platform: 'node', |
|
|
target: 'node18', |
|
|
format: 'cjs', |
|
|
outfile: path.join(bundleDir, 'server.cjs'), |
|
|
external: [], |
|
|
minify: false, |
|
|
sourcemap: false, |
|
|
|
|
|
define: { |
|
|
'import.meta.url': 'importMetaUrl' |
|
|
}, |
|
|
banner: { |
|
|
js: ` |
|
|
const importMetaUrl = require('url').pathToFileURL(__filename).href; |
|
|
const __importMetaDirname = __dirname; |
|
|
` |
|
|
}, |
|
|
|
|
|
loader: { |
|
|
'.node': 'copy' |
|
|
} |
|
|
}); |
|
|
|
|
|
console.log('✅ Bundle created: dist/bundle/server.cjs'); |
|
|
|
|
|
|
|
|
|
|
|
const pkgJson = { |
|
|
name: 'antigravity-to-openai', |
|
|
version: '1.0.0', |
|
|
bin: 'server.cjs', |
|
|
pkg: { |
|
|
assets: [ |
|
|
toSlash(path.join(rootDir, 'public', '**/*')), |
|
|
toSlash(path.join(rootDir, 'public', '*.html')), |
|
|
toSlash(path.join(rootDir, 'public', '*.css')), |
|
|
toSlash(path.join(rootDir, 'public', 'js', '*.js')), |
|
|
toSlash(path.join(rootDir, 'public', 'assets', '*')), |
|
|
toSlash(path.join(rootDir, 'src', 'bin', '*')) |
|
|
] |
|
|
} |
|
|
}; |
|
|
|
|
|
fs.writeFileSync( |
|
|
path.join(bundleDir, 'package.json'), |
|
|
JSON.stringify(pkgJson, null, 2) |
|
|
); |
|
|
|
|
|
console.log('📦 Step 2: Building executable with pkg...'); |
|
|
|
|
|
|
|
|
function runPkg(args) { |
|
|
|
|
|
const quotedArgs = args.map(arg => { |
|
|
if (arg.includes(' ') || arg.includes('\\')) { |
|
|
return `"${arg.replace(/\\/g, '/')}"`; |
|
|
} |
|
|
return arg; |
|
|
}); |
|
|
|
|
|
const cmd = `npx pkg ${quotedArgs.join(' ')}`; |
|
|
console.log(`Running: ${cmd}`); |
|
|
|
|
|
try { |
|
|
execSync(cmd, { |
|
|
cwd: rootDir, |
|
|
stdio: 'inherit', |
|
|
shell: true |
|
|
}); |
|
|
} catch (error) { |
|
|
throw new Error(`pkg failed: ${error.message}`); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
const targets = resolvedTarget.split(','); |
|
|
const isMultiTarget = targets.length > 1; |
|
|
|
|
|
try { |
|
|
const pkgJsonPath = path.join(bundleDir, 'package.json'); |
|
|
|
|
|
|
|
|
if (isMultiTarget) { |
|
|
for (const t of targets) { |
|
|
const oldFile = path.join(distDir, outputNameMap[t] || 'antigravity'); |
|
|
if (fs.existsSync(oldFile)) { |
|
|
console.log(`🗑️ Removing old file: ${oldFile}`); |
|
|
fs.unlinkSync(oldFile); |
|
|
} |
|
|
} |
|
|
} else { |
|
|
const outputName = outputNameMap[resolvedTarget] || 'antigravity'; |
|
|
const oldFile = path.join(distDir, outputName); |
|
|
if (fs.existsSync(oldFile)) { |
|
|
console.log(`🗑️ Removing old file: ${oldFile}`); |
|
|
fs.unlinkSync(oldFile); |
|
|
} |
|
|
} |
|
|
|
|
|
if (isMultiTarget) { |
|
|
|
|
|
runPkg([pkgJsonPath, '--target', resolvedTarget, '--compress', 'GZip', '--out-path', distDir]); |
|
|
} else { |
|
|
|
|
|
const outputName = outputNameMap[resolvedTarget] || 'antigravity'; |
|
|
const outputPath = path.join(distDir, outputName); |
|
|
|
|
|
|
|
|
const isArm64 = resolvedTarget.includes('arm64'); |
|
|
const isWindows = process.platform === 'win32'; |
|
|
const compressArgs = (isArm64 && isWindows) ? [] : ['--compress', 'GZip']; |
|
|
|
|
|
runPkg([pkgJsonPath, '--target', resolvedTarget, ...compressArgs, '--output', outputPath]); |
|
|
} |
|
|
|
|
|
console.log('✅ Build complete!'); |
|
|
|
|
|
|
|
|
console.log('📁 Copying runtime files...'); |
|
|
|
|
|
|
|
|
const publicSrcDir = path.join(rootDir, 'public'); |
|
|
const publicDestDir = path.join(distDir, 'public'); |
|
|
console.log(` Source: ${publicSrcDir}`); |
|
|
console.log(` Dest: ${publicDestDir}`); |
|
|
console.log(` Source exists: ${fs.existsSync(publicSrcDir)}`); |
|
|
|
|
|
if (fs.existsSync(publicSrcDir)) { |
|
|
try { |
|
|
if (fs.existsSync(publicDestDir)) { |
|
|
console.log(' Removing existing public directory...'); |
|
|
fs.rmSync(publicDestDir, { recursive: true, force: true }); |
|
|
} |
|
|
|
|
|
console.log(' Copying public directory...'); |
|
|
if (process.platform === 'win32') { |
|
|
execSync(`xcopy /E /I /Y /Q "${publicSrcDir}" "${publicDestDir}"`, { stdio: 'pipe', shell: true }); |
|
|
} else { |
|
|
fs.mkdirSync(publicDestDir, { recursive: true }); |
|
|
execSync(`cp -r "${publicSrcDir}"/* "${publicDestDir}/"`, { stdio: 'pipe', shell: true }); |
|
|
} |
|
|
|
|
|
const imagesDir = path.join(publicDestDir, 'images'); |
|
|
if (fs.existsSync(imagesDir)) { |
|
|
fs.rmSync(imagesDir, { recursive: true, force: true }); |
|
|
} |
|
|
console.log(' ✓ Copied public directory'); |
|
|
} catch (err) { |
|
|
console.error(' ❌ Failed to copy public directory:', err.message); |
|
|
throw err; |
|
|
} |
|
|
} else { |
|
|
console.error(' ❌ Source public directory not found!'); |
|
|
} |
|
|
|
|
|
|
|
|
const binSrcDir = path.join(rootDir, 'src', 'bin'); |
|
|
const binDestDir = path.join(distDir, 'bin'); |
|
|
if (fs.existsSync(binSrcDir)) { |
|
|
if (fs.existsSync(binDestDir)) { |
|
|
fs.rmSync(binDestDir, { recursive: true, force: true }); |
|
|
} |
|
|
fs.mkdirSync(binDestDir, { recursive: true }); |
|
|
|
|
|
|
|
|
const targetBinFiles = isMultiTarget |
|
|
? [...new Set(targets.map(t => binFileMap[t]).filter(Boolean))] |
|
|
: [binFileMap[resolvedTarget]].filter(Boolean); |
|
|
|
|
|
if (targetBinFiles.length > 0) { |
|
|
for (const binFile of targetBinFiles) { |
|
|
const srcPath = path.join(binSrcDir, binFile); |
|
|
const destPath = path.join(binDestDir, binFile); |
|
|
if (fs.existsSync(srcPath)) { |
|
|
fs.copyFileSync(srcPath, destPath); |
|
|
console.log(` ✓ Copied bin/${binFile}`); |
|
|
} else { |
|
|
console.warn(` ⚠ Warning: bin/${binFile} not found`); |
|
|
} |
|
|
} |
|
|
} else { |
|
|
|
|
|
try { |
|
|
if (process.platform === 'win32') { |
|
|
execSync(`xcopy /E /I /Y "${binSrcDir}" "${binDestDir}"`, { stdio: 'pipe', shell: true }); |
|
|
} else { |
|
|
execSync(`cp -r "${binSrcDir}"/* "${binDestDir}/"`, { stdio: 'pipe', shell: true }); |
|
|
} |
|
|
console.log(' ✓ Copied all bin files'); |
|
|
} catch (err) { |
|
|
console.error(' ⚠ Warning: Failed to copy bin directory:', err.message); |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
const configSrcPath = path.join(rootDir, 'config.json'); |
|
|
const configDestPath = path.join(distDir, 'config.json'); |
|
|
if (fs.existsSync(configSrcPath)) { |
|
|
fs.copyFileSync(configSrcPath, configDestPath); |
|
|
console.log(' ✓ Copied config.json'); |
|
|
} |
|
|
|
|
|
console.log(''); |
|
|
console.log('🎉 Build successful!'); |
|
|
console.log(''); |
|
|
console.log('📋 Usage:'); |
|
|
console.log(' 1. Copy the dist folder to your target machine'); |
|
|
console.log(' 2. Run the executable (will auto-generate random credentials if not configured)'); |
|
|
console.log(' 3. Optionally create .env file to customize settings'); |
|
|
console.log(''); |
|
|
|
|
|
} catch (error) { |
|
|
console.error('❌ Build failed:', error.message); |
|
|
process.exit(1); |
|
|
} finally { |
|
|
|
|
|
if (fs.existsSync(bundleDir)) { |
|
|
fs.rmSync(bundleDir, { recursive: true, force: true }); |
|
|
console.log('🧹 Cleaned up temporary files'); |
|
|
} |
|
|
} |