Makelore 2.0 initial clean snapshot
This commit is contained in:
137
scripts/bundle-opencode.mjs
Normal file
137
scripts/bundle-opencode.mjs
Normal file
@@ -0,0 +1,137 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import { createRequire } from 'node:module';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
const root = path.resolve(__dirname, '..');
|
||||
const require = createRequire(import.meta.url);
|
||||
const outputDir = path.join(root, 'build', 'opencode-ai');
|
||||
|
||||
function fail(message) {
|
||||
console.error(`[bundle-opencode] ${message}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
function resolvePackageRoot(packageName) {
|
||||
try {
|
||||
return path.dirname(require.resolve(`${packageName}/package.json`, {
|
||||
paths: [root],
|
||||
}));
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
const packageRoot = resolvePackageRoot('opencode-ai');
|
||||
if (!packageRoot) {
|
||||
fail('Missing dependency "opencode-ai". Run npm install or pnpm install before packaging.');
|
||||
}
|
||||
|
||||
const packageJsonPath = path.join(packageRoot, 'package.json');
|
||||
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
|
||||
const packageRequire = createRequire(packageJsonPath);
|
||||
const bin = packageJson.bin;
|
||||
const hasOpencodeBin = typeof bin === 'string'
|
||||
|| (bin && typeof bin === 'object' && typeof bin.opencode === 'string');
|
||||
|
||||
if (!hasOpencodeBin) {
|
||||
fail('Installed "opencode-ai" package does not expose an "opencode" binary.');
|
||||
}
|
||||
|
||||
fs.rmSync(outputDir, { recursive: true, force: true });
|
||||
fs.mkdirSync(path.dirname(outputDir), { recursive: true });
|
||||
fs.cpSync(packageRoot, outputDir, {
|
||||
recursive: true,
|
||||
dereference: true,
|
||||
filter: (src) => {
|
||||
if (src.includes(`${path.sep}.git${path.sep}`)) return false;
|
||||
if (path.relative(packageRoot, src).split(path.sep)[0] === 'node_modules') return false;
|
||||
return true;
|
||||
},
|
||||
});
|
||||
|
||||
const runtimeDependencies = {
|
||||
...(packageJson.dependencies && typeof packageJson.dependencies === 'object' ? packageJson.dependencies : {}),
|
||||
...(packageJson.optionalDependencies && typeof packageJson.optionalDependencies === 'object' ? packageJson.optionalDependencies : {}),
|
||||
};
|
||||
|
||||
const platformMap = {
|
||||
darwin: 'darwin',
|
||||
linux: 'linux',
|
||||
win32: 'windows',
|
||||
};
|
||||
const archMap = {
|
||||
x64: 'x64',
|
||||
arm64: 'arm64',
|
||||
arm: 'arm',
|
||||
};
|
||||
|
||||
function copyRuntimeDependency(packageName) {
|
||||
let dependencyPackageJsonPath;
|
||||
try {
|
||||
dependencyPackageJsonPath = packageRequire.resolve(`${packageName}/package.json`);
|
||||
} catch {
|
||||
console.warn(`[bundle-opencode] optional dependency not installed: ${packageName}`);
|
||||
return false;
|
||||
}
|
||||
|
||||
const dependencyRoot = path.dirname(dependencyPackageJsonPath);
|
||||
const outputPackageDir = path.join(outputDir, 'node_modules', ...packageName.split('/'));
|
||||
fs.rmSync(outputPackageDir, { recursive: true, force: true });
|
||||
fs.mkdirSync(path.dirname(outputPackageDir), { recursive: true });
|
||||
fs.cpSync(dependencyRoot, outputPackageDir, {
|
||||
recursive: true,
|
||||
dereference: true,
|
||||
filter: (src) => !src.includes(`${path.sep}.git${path.sep}`),
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
function getNativePackageCandidates() {
|
||||
const platform = platformMap[process.platform] ?? process.platform;
|
||||
const arch = archMap[process.arch] ?? process.arch;
|
||||
const base = `opencode-${platform}-${arch}`;
|
||||
|
||||
if (arch === 'x64') {
|
||||
return [`${base}-baseline`, base];
|
||||
}
|
||||
|
||||
return [base];
|
||||
}
|
||||
|
||||
function bundleNativeLauncher() {
|
||||
const binaryName = process.platform === 'win32' ? 'opencode.exe' : 'opencode';
|
||||
const outputBinary = path.join(outputDir, 'bin', binaryName);
|
||||
|
||||
for (const packageName of getNativePackageCandidates()) {
|
||||
let dependencyPackageJsonPath;
|
||||
try {
|
||||
dependencyPackageJsonPath = packageRequire.resolve(`${packageName}/package.json`);
|
||||
} catch {
|
||||
continue;
|
||||
}
|
||||
|
||||
const dependencyRoot = path.dirname(dependencyPackageJsonPath);
|
||||
const nativeBinary = path.join(dependencyRoot, 'bin', binaryName);
|
||||
if (!fs.existsSync(nativeBinary)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
fs.copyFileSync(nativeBinary, outputBinary);
|
||||
fs.chmodSync(outputBinary, 0o755);
|
||||
return { packageName, outputBinary };
|
||||
}
|
||||
|
||||
fail(
|
||||
`Missing native opencode binary for ${process.platform}/${process.arch}. Tried ${getNativePackageCandidates().join(', ')}.`,
|
||||
);
|
||||
}
|
||||
|
||||
const copiedDependencies = Object.keys(runtimeDependencies).filter(copyRuntimeDependency);
|
||||
const nativeLauncher = bundleNativeLauncher();
|
||||
console.log(
|
||||
`[bundle-opencode] bundled opencode-ai@${packageJson.version ?? 'unknown'} with ${copiedDependencies.length} runtime dependency package(s) and native launcher ${nativeLauncher.packageName} -> ${path.relative(root, outputDir)}`,
|
||||
);
|
||||
Reference in New Issue
Block a user