198 lines · 6.7 KB · TypeScript
RawDownload
import { mkdtempSync, mkdirSync, writeFileSync } from "node:fs";import { tmpdir } from "node:os";import path from "node:path";import { describe, expect, it } from "vitest";import { __resetDataDirCacheForTests } from "@/lib/data-dir";import type { PluginRow } from "./plugin-discovery";import { buildPluginsResponse } from "./plugin-response"; const plugin = (patch: Partial<PluginRow>): PluginRow => ({  id: patch.name ?? "plugin",  name: patch.name ?? "plugin",  path: `/plugins/${patch.name ?? "plugin"}`,  installed: true,  enabled: true,  ...patch,}); describe("buildPluginsResponse", () => {  it("returns only enabled plugins for composer/runtime selection by default", () => {    const response = buildPluginsResponse([      plugin({ name: "browser-use" }),      plugin({ name: "computer-use", enabled: false }),    ]);     expect(response.plugins.map((row) => row.name)).toEqual(["browser-use"]);    expect(response.validation.browserUseAvailable).toBe(true);    expect(response.validation.computerUseAvailable).toBe(false);  });   it("can include disabled plugins for the settings registry without marking them available", () => {    const response = buildPluginsResponse(      [plugin({ name: "browser-use", enabled: false }), plugin({ name: "computer-use" })],      { includeDisabled: true },    );     expect(response.plugins.map((row) => row.name)).toEqual(["browser-use", "computer-use"]);    expect(response.validation.browserUseAvailable).toBe(false);    expect(response.validation.computerUseAvailable).toBe(true);  });   it("recognizes core plugin availability from display metadata case-insensitively", () => {    const response = buildPluginsResponse([      plugin({ id: "browser", name: "BrowserUse", displayName: "Browser-Use" }),      plugin({ id: "computer", name: "ComputerUse", displayName: "Computer-Use" }),    ]);     expect(response.validation.browserUseAvailable).toBe(true);    expect(response.validation.computerUseAvailable).toBe(true);  });   it("reports runtime resource checks for MCP-backed plugins", () => {    const root = mkdtempSync(path.join(tmpdir(), "plugin-response-"));    mkdirSync(path.join(root, "bin"));    writeFileSync(path.join(root, "bin", "server"), "#!/bin/sh\n");    writeFileSync(      path.join(root, ".mcp.json"),      JSON.stringify({ mcpServers: { demo: { command: "./bin/server", cwd: "." } } }),    );     const response = buildPluginsResponse([      plugin({        name: "computer-use",        path: root,        mcpConfigPath: path.join(root, ".mcp.json"),        appPath: root,      }),    ]);     expect(response.validation.computerUseRuntime).toMatchObject({      mcpConfigured: true,      appConfigured: true,      mcpExecutableExists: true,      runtimeCheckRequired: true,    });    expect(response.validation.computerUseRuntime?.note).toContain("mcp_plugin_status");  });   it("reports Codex Computer Use launch constraints truthfully", () => {    const root = mkdtempSync(path.join(tmpdir(), "plugin-response-"));    mkdirSync(path.join(root, "Codex Computer Use.app", "Contents", "SharedSupport"), {      recursive: true,    });    writeFileSync(      path.join(root, ".mcp.json"),      JSON.stringify({        mcpServers: {          "computer-use": {            command:              "./Codex Computer Use.app/Contents/SharedSupport/SkyComputerUseClient.app/Contents/MacOS/SkyComputerUseClient",            args: ["mcp"],            cwd: ".",          },        },      }),    );     const response = buildPluginsResponse([      plugin({ name: "computer-use", path: root, mcpConfigPath: path.join(root, ".mcp.json") }),    ]);     expect(response.validation.computerUseRuntime).toMatchObject({      runtimeBlockedOutsideCodex: true,      runtimeCheckRequired: true,    });    expect(response.validation.computerUseRuntime?.note).toContain("launch-constrained");  });   it("does not mark the local Computer Use helper as blocked outside Codex", () => {    const root = mkdtempSync(path.join(tmpdir(), "plugin-response-"));    const previousDataDir = process.env.VLLM_STUDIO_DATA_DIR;    try {      process.env.VLLM_STUDIO_DATA_DIR = root;      __resetDataDirCacheForTests();      const helper = path.join(root, "computer-use");      mkdirSync(        path.join(          helper,          "Codex Computer Use.app",          "Contents",          "SharedSupport",          "SkyComputerUseClient.app",          "Contents",          "MacOS",        ),        { recursive: true },      );      const executable = path.join(        helper,        "Codex Computer Use.app",        "Contents",        "SharedSupport",        "SkyComputerUseClient.app",        "Contents",        "MacOS",        "SkyComputerUseClient",      );      writeFileSync(executable, "#!/bin/sh\n");      writeFileSync(        path.join(helper, ".mcp.json"),        JSON.stringify({          mcpServers: {            "computer-use": {              command:                "./Codex Computer Use.app/Contents/SharedSupport/SkyComputerUseClient.app/Contents/MacOS/SkyComputerUseClient",              args: ["mcp"],              cwd: ".",            },          },        }),      );       const response = buildPluginsResponse([        plugin({          name: "computer-use",          path: helper,          appPath: path.join(helper, "Codex Computer Use.app"),          mcpConfigPath: path.join(helper, ".mcp.json"),        }),      ]);       expect(response.validation.computerUseRuntime).toMatchObject({        mcpConfigured: true,        appConfigured: true,        mcpExecutableExists: true,        runtimeCheckRequired: true,      });      expect(response.validation.computerUseRuntime?.runtimeBlockedOutsideCodex).toBeUndefined();    } finally {      if (previousDataDir === undefined) delete process.env.VLLM_STUDIO_DATA_DIR;      else process.env.VLLM_STUDIO_DATA_DIR = previousDataDir;      __resetDataDirCacheForTests();    }  });   it("marks MCP runtime incomplete when any configured server executable is missing", () => {    const root = mkdtempSync(path.join(tmpdir(), "plugin-response-"));    mkdirSync(path.join(root, "bin"));    writeFileSync(path.join(root, "bin", "server"), "#!/bin/sh\n");    writeFileSync(      path.join(root, ".mcp.json"),      JSON.stringify({        mcpServers: {          ready: { command: "./bin/server", cwd: "." },          missing: { command: "./bin/missing", cwd: "." },        },      }),    );     const response = buildPluginsResponse([      plugin({ name: "computer-use", path: root, mcpConfigPath: path.join(root, ".mcp.json") }),    ]);     expect(response.validation.computerUseRuntime).toMatchObject({      mcpConfigured: true,      mcpExecutableExists: false,    });  });});