import { existsSync, readFileSync } from "node:fs";import { homedir } from "node:os";import path from "node:path";import { resolveDataDir } from "@/lib/data-dir";import type { PluginRow } from "./plugin-discovery"; export type PluginRuntimeCheck = { skillConfigured: boolean; mcpConfigured: boolean; appConfigured: boolean; mcpExecutableExists?: boolean; runtimeBlockedOutsideCodex?: boolean; runtimeCheckRequired?: boolean; note?: string;}; export type PluginsResponse = { plugins: PluginRow[]; validation: { browserUseAvailable: boolean; browserUse: PluginRow | null; browserUseRuntime: PluginRuntimeCheck | null; computerUseAvailable: boolean; computerUse: PluginRow | null; computerUseRuntime: PluginRuntimeCheck | null; };}; export function buildPluginsResponse( allPlugins: PluginRow[], options: { includeDisabled?: boolean } = {},): PluginsResponse { const plugins = options.includeDisabled ? allPlugins : allPlugins.filter((row) => row.enabled); const computerUse = plugins.find((row) => row.enabled && pluginMatches(row, "computer-use")) ?? null; const browserUse = plugins.find((row) => row.enabled && pluginMatches(row, "browser-use")) ?? null; return { plugins, validation: { browserUseAvailable: Boolean(browserUse), browserUse, browserUseRuntime: browserUse ? pluginRuntimeCheck(browserUse) : null, computerUseAvailable: Boolean(computerUse), computerUse, computerUseRuntime: computerUse ? pluginRuntimeCheck(computerUse) : null, }, };} function pluginRuntimeCheck(plugin: PluginRow): PluginRuntimeCheck { const mcpExecutable = plugin.mcpConfigPath ? allMcpExecutablesExist(plugin.mcpConfigPath) : undefined; const launchConstrained = plugin.mcpConfigPath ? mcpConfigUsesSkyComputerUseClient(plugin.mcpConfigPath) && !isLocalComputerUseHelper(plugin, plugin.mcpConfigPath) : false; return { skillConfigured: Boolean(plugin.skillPath && existsSync(plugin.skillPath)), mcpConfigured: Boolean(plugin.mcpConfigPath && existsSync(plugin.mcpConfigPath)), appConfigured: Boolean(plugin.appPath && existsSync(plugin.appPath)), ...(mcpExecutable === undefined ? {} : { mcpExecutableExists: mcpExecutable }), ...(launchConstrained ? { runtimeBlockedOutsideCodex: true } : {}), ...(pluginMatches(plugin, "computer-use") && plugin.mcpConfigPath ? { runtimeCheckRequired: true, note: launchConstrained ? "Computer-use is discovered and selectable. vLLM Studio skips its launch-constrained SkyComputerUseClient MCP by default outside the Codex-signed host, while still loading skill context and browser-tool fallback for browser tasks." : "Computer-use is wired through MCP; verify helper launch from an active session with mcp_plugin_status before desktop control.", } : {}), };} function isLocalComputerUseHelper(plugin: PluginRow, configPath: string): boolean { return ( pluginMatches(plugin, "computer-use") && localComputerUseRoots().some((root) => isPathInside(configPath, root)) );} function localComputerUseRoots(): string[] { return [ path.join(resolveDataDir(), "computer-use"), path.join(homedir(), ".codex", "computer-use"), ];} function pluginMatches(plugin: PluginRow, needle: string): boolean { return [plugin.id, plugin.name, plugin.displayName, plugin.path] .filter((value): value is string => Boolean(value)) .some((value) => value.toLowerCase().includes(needle));} function isPathInside(candidate: string, root: string): boolean { const relative = path.relative(path.resolve(root), path.resolve(candidate)); return relative === "" || (!relative.startsWith("..") && !path.isAbsolute(relative));} function allMcpExecutablesExist(configPath: string): boolean | undefined { try { const parsed = JSON.parse(readFileSync(configPath, "utf8")) as { mcpServers?: Record<string, { command?: unknown; cwd?: unknown }>; }; const servers = Object.values(parsed.mcpServers ?? {}).filter( (entry) => typeof entry.command === "string" && entry.command.trim(), ); if (!servers.length) return undefined; return servers.every((server) => { const command = String(server.command); const cwd = typeof server.cwd === "string" ? server.cwd : "."; const base = path.resolve(path.dirname(configPath), cwd); const resolved = command.startsWith(".") ? path.resolve(base, command) : command; return path.isAbsolute(resolved) ? existsSync(resolved) : true; }); } catch { return false; }} function mcpConfigUsesSkyComputerUseClient(configPath: string): boolean { try { const raw = readFileSync(configPath, "utf8"); return raw.toLowerCase().includes("skycomputeruseclient"); } catch { return false; }}
import { existsSync, readFileSync } from "node:fs";
import { homedir } from "node:os";
import path from "node:path";
import { resolveDataDir } from "@/lib/data-dir";
import type { PluginRow } from "./plugin-discovery";
export type PluginRuntimeCheck = {
skillConfigured: boolean;
mcpConfigured: boolean;
appConfigured: boolean;
mcpExecutableExists?: boolean;
runtimeBlockedOutsideCodex?: boolean;
runtimeCheckRequired?: boolean;
note?: string;
};
export type PluginsResponse = {
plugins: PluginRow[];
validation: {
browserUseAvailable: boolean;
browserUse: PluginRow | null;
browserUseRuntime: PluginRuntimeCheck | null;
computerUseAvailable: boolean;
computerUse: PluginRow | null;
computerUseRuntime: PluginRuntimeCheck | null;
};
};
export function buildPluginsResponse(
allPlugins: PluginRow[],
options: { includeDisabled?: boolean } = {},
): PluginsResponse {
const plugins = options.includeDisabled ? allPlugins : allPlugins.filter((row) => row.enabled);
const computerUse =
plugins.find((row) => row.enabled && pluginMatches(row, "computer-use")) ?? null;
const browserUse =
plugins.find((row) => row.enabled && pluginMatches(row, "browser-use")) ?? null;
return {
plugins,
validation: {
browserUseAvailable: Boolean(browserUse),
browserUse,
browserUseRuntime: browserUse ? pluginRuntimeCheck(browserUse) : null,
computerUseAvailable: Boolean(computerUse),
computerUse,
computerUseRuntime: computerUse ? pluginRuntimeCheck(computerUse) : null,
},
};
}
function pluginRuntimeCheck(plugin: PluginRow): PluginRuntimeCheck {
const mcpExecutable = plugin.mcpConfigPath
? allMcpExecutablesExist(plugin.mcpConfigPath)
: undefined;
const launchConstrained = plugin.mcpConfigPath
? mcpConfigUsesSkyComputerUseClient(plugin.mcpConfigPath) &&
!isLocalComputerUseHelper(plugin, plugin.mcpConfigPath)
: false;
return {
skillConfigured: Boolean(plugin.skillPath && existsSync(plugin.skillPath)),
mcpConfigured: Boolean(plugin.mcpConfigPath && existsSync(plugin.mcpConfigPath)),
appConfigured: Boolean(plugin.appPath && existsSync(plugin.appPath)),
...(mcpExecutable === undefined ? {} : { mcpExecutableExists: mcpExecutable }),
...(launchConstrained ? { runtimeBlockedOutsideCodex: true } : {}),
...(pluginMatches(plugin, "computer-use") && plugin.mcpConfigPath
? {
runtimeCheckRequired: true,
note: launchConstrained
? "Computer-use is discovered and selectable. vLLM Studio skips its launch-constrained SkyComputerUseClient MCP by default outside the Codex-signed host, while still loading skill context and browser-tool fallback for browser tasks."
: "Computer-use is wired through MCP; verify helper launch from an active session with mcp_plugin_status before desktop control.",
}
: {}),
};
}
function isLocalComputerUseHelper(plugin: PluginRow, configPath: string): boolean {
return (
pluginMatches(plugin, "computer-use") &&
localComputerUseRoots().some((root) => isPathInside(configPath, root))
);
}
function localComputerUseRoots(): string[] {
return [
path.join(resolveDataDir(), "computer-use"),
path.join(homedir(), ".codex", "computer-use"),
];
}
function pluginMatches(plugin: PluginRow, needle: string): boolean {
return [plugin.id, plugin.name, plugin.displayName, plugin.path]
.filter((value): value is string => Boolean(value))
.some((value) => value.toLowerCase().includes(needle));
}
function isPathInside(candidate: string, root: string): boolean {
const relative = path.relative(path.resolve(root), path.resolve(candidate));
return relative === "" || (!relative.startsWith("..") && !path.isAbsolute(relative));
}
function allMcpExecutablesExist(configPath: string): boolean | undefined {
try {
const parsed = JSON.parse(readFileSync(configPath, "utf8")) as {
mcpServers?: Record<string, { command?: unknown; cwd?: unknown }>;
};
const servers = Object.values(parsed.mcpServers ?? {}).filter(
(entry) => typeof entry.command === "string" && entry.command.trim(),
);
if (!servers.length) return undefined;
return servers.every((server) => {
const command = String(server.command);
const cwd = typeof server.cwd === "string" ? server.cwd : ".";
const base = path.resolve(path.dirname(configPath), cwd);
const resolved = command.startsWith(".") ? path.resolve(base, command) : command;
return path.isAbsolute(resolved) ? existsSync(resolved) : true;
});
} catch {
return false;
}
}
function mcpConfigUsesSkyComputerUseClient(configPath: string): boolean {
try {
const raw = readFileSync(configPath, "utf8");
return raw.toLowerCase().includes("skycomputeruseclient");
} catch {
return false;
}
}