agent-ecosystem/src/main/services/runtime/openCodeBridgeRuntimeEnv.ts

106 lines
3.3 KiB
TypeScript

import { existsSync, statSync } from 'node:fs';
import path from 'node:path';
import { getErrorMessage } from '@shared/utils/errorHandling';
import {
applyOpenCodeRuntimeBinaryEnv,
OPENCODE_LEGACY_BINARY_PATH_ENV,
OPENCODE_RUNTIME_BINARY_PATH_ENV,
} from './openCodeRuntimeBinaryEnv';
export interface EnsureOpenCodeBridgeRuntimeBinaryEnvOptions {
targetEnv: NodeJS.ProcessEnv;
bridgeEnv?: NodeJS.ProcessEnv;
resolveVerifiedOpenCodeRuntimeBinaryPath: () => Promise<string | null>;
onWarning?: (message: string) => void;
}
function resolveExistingFilePath(filePath: string): string | null {
const resolvedPath = path.resolve(filePath.trim());
if (!existsSync(resolvedPath)) {
return null;
}
try {
return statSync(resolvedPath).isFile() ? resolvedPath : null;
} catch {
return null;
}
}
function getOpenCodeRuntimeBinaryEnvValues(env: NodeJS.ProcessEnv): string[] {
return [
env[OPENCODE_RUNTIME_BINARY_PATH_ENV]?.trim(),
env[OPENCODE_LEGACY_BINARY_PATH_ENV]?.trim(),
].filter((value): value is string => Boolean(value));
}
function resolveExistingOpenCodeRuntimeBinaryEnvPath(env: NodeJS.ProcessEnv): string | null {
for (const value of getOpenCodeRuntimeBinaryEnvValues(env)) {
const resolvedPath = resolveExistingFilePath(value);
if (resolvedPath) {
return resolvedPath;
}
}
return null;
}
function clearOpenCodeRuntimeBinaryEnvValues(
env: NodeJS.ProcessEnv,
invalidValues: Set<string>
): void {
for (const key of [OPENCODE_RUNTIME_BINARY_PATH_ENV, OPENCODE_LEGACY_BINARY_PATH_ENV]) {
const value = env[key]?.trim();
if (value && invalidValues.has(value)) {
delete env[key];
}
}
}
export async function ensureOpenCodeBridgeRuntimeBinaryEnv({
targetEnv,
bridgeEnv = targetEnv,
resolveVerifiedOpenCodeRuntimeBinaryPath,
onWarning,
}: EnsureOpenCodeBridgeRuntimeBinaryEnvOptions): Promise<void> {
if (
targetEnv[OPENCODE_RUNTIME_BINARY_PATH_ENV]?.trim() ||
targetEnv[OPENCODE_LEGACY_BINARY_PATH_ENV]?.trim()
) {
const existingBinaryPath = resolveExistingOpenCodeRuntimeBinaryEnvPath(targetEnv);
if (!existingBinaryPath) {
const invalidValues = new Set(getOpenCodeRuntimeBinaryEnvValues(targetEnv));
clearOpenCodeRuntimeBinaryEnvValues(targetEnv, invalidValues);
if (targetEnv !== bridgeEnv) {
clearOpenCodeRuntimeBinaryEnvValues(bridgeEnv, invalidValues);
}
} else {
targetEnv[OPENCODE_RUNTIME_BINARY_PATH_ENV] = existingBinaryPath;
targetEnv[OPENCODE_LEGACY_BINARY_PATH_ENV] = existingBinaryPath;
applyOpenCodeRuntimeBinaryEnv(targetEnv, existingBinaryPath);
return;
}
}
if (
targetEnv[OPENCODE_RUNTIME_BINARY_PATH_ENV]?.trim() ||
targetEnv[OPENCODE_LEGACY_BINARY_PATH_ENV]?.trim()
) {
applyOpenCodeRuntimeBinaryEnv(targetEnv, null);
return;
}
try {
const openCodeBinary = await resolveVerifiedOpenCodeRuntimeBinaryPath();
applyOpenCodeRuntimeBinaryEnv(targetEnv, openCodeBinary);
if (
targetEnv !== bridgeEnv &&
targetEnv[OPENCODE_RUNTIME_BINARY_PATH_ENV] &&
!bridgeEnv[OPENCODE_RUNTIME_BINARY_PATH_ENV]
) {
applyOpenCodeRuntimeBinaryEnv(bridgeEnv, targetEnv[OPENCODE_RUNTIME_BINARY_PATH_ENV]);
}
} catch (error) {
onWarning?.(`[OpenCode] Runtime adapter OpenCode binary unresolved: ${getErrorMessage(error)}`);
}
}