96 lines
2.9 KiB
TypeScript
96 lines
2.9 KiB
TypeScript
import { existsSync, readFileSync } from 'node:fs';
|
|
import { join } from 'node:path';
|
|
|
|
export interface RuntimePathInput {
|
|
isPackaged: boolean;
|
|
resourcesPath: string;
|
|
appPath: string;
|
|
platform: NodeJS.Platform;
|
|
arch?: NodeJS.Architecture;
|
|
}
|
|
|
|
export interface OpencodeRuntimePaths {
|
|
runtimeDir: string;
|
|
binPath: string;
|
|
packageJsonPath: string;
|
|
}
|
|
|
|
const OPENCODE_RUNTIME_PACKAGE = 'opencode-ai';
|
|
|
|
const nativePlatformNames: Partial<Record<NodeJS.Platform, string>> = {
|
|
darwin: 'darwin',
|
|
linux: 'linux',
|
|
win32: 'windows',
|
|
};
|
|
|
|
const nativeArchNames: Partial<Record<NodeJS.Architecture, string>> = {
|
|
x64: 'x64',
|
|
arm64: 'arm64',
|
|
arm: 'arm',
|
|
};
|
|
|
|
function getDevelopmentNativePackageCandidates(
|
|
platform: NodeJS.Platform,
|
|
arch: NodeJS.Architecture,
|
|
): string[] {
|
|
const platformName = nativePlatformNames[platform] ?? platform;
|
|
const archName = nativeArchNames[arch] ?? arch;
|
|
const base = `opencode-${platformName}-${archName}`;
|
|
|
|
// The baseline x64 package runs on CPUs with and without AVX2, so prefer
|
|
// it when available. This mirrors the packaged-runtime bundler while
|
|
// avoiding opencode-ai's postinstall-generated wrapper in pnpm dev trees.
|
|
return archName === 'x64' ? [`${base}-baseline`, base] : [base];
|
|
}
|
|
|
|
function getNativeOpencodeBinName(platform: NodeJS.Platform): string {
|
|
return platform === 'win32' ? 'opencode.exe' : 'opencode';
|
|
}
|
|
|
|
function resolveDevelopmentNativeBinPath(input: RuntimePathInput): string | undefined {
|
|
const arch = input.arch ?? process.arch;
|
|
for (const packageName of getDevelopmentNativePackageCandidates(input.platform, arch)) {
|
|
const binPath = join(input.appPath, 'node_modules', packageName, 'bin', getNativeOpencodeBinName(input.platform));
|
|
if (existsSync(binPath)) return binPath;
|
|
}
|
|
return undefined;
|
|
}
|
|
|
|
export function getOpencodeBinName(
|
|
platform: NodeJS.Platform = process.platform,
|
|
isPackaged = false,
|
|
): string {
|
|
if (isPackaged && platform === 'win32') {
|
|
return 'opencode.exe';
|
|
}
|
|
|
|
return 'opencode';
|
|
}
|
|
|
|
export function resolveOpencodeRuntimePaths(input: RuntimePathInput): OpencodeRuntimePaths {
|
|
const runtimeDir = input.isPackaged
|
|
? join(input.resourcesPath, OPENCODE_RUNTIME_PACKAGE)
|
|
: join(input.appPath, 'node_modules', OPENCODE_RUNTIME_PACKAGE);
|
|
const developmentNativeBinPath = input.isPackaged
|
|
? undefined
|
|
: resolveDevelopmentNativeBinPath(input);
|
|
|
|
return {
|
|
runtimeDir,
|
|
binPath: developmentNativeBinPath ?? join(runtimeDir, 'bin', getOpencodeBinName(input.platform, input.isPackaged)),
|
|
packageJsonPath: join(runtimeDir, 'package.json'),
|
|
};
|
|
}
|
|
|
|
export function readOpencodeRuntimeVersion(paths: OpencodeRuntimePaths): string | undefined {
|
|
if (!existsSync(paths.packageJsonPath)) {
|
|
return undefined;
|
|
}
|
|
|
|
const packageJson = JSON.parse(readFileSync(paths.packageJsonPath, 'utf8')) as {
|
|
version?: unknown;
|
|
};
|
|
|
|
return typeof packageJson.version === 'string' ? packageJson.version : undefined;
|
|
}
|