File size: 3,195 Bytes
fcd8223 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 | // Provides test support for bundled MCP plugin packaging checks.
import fs from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import { withEnvAsync } from "../test-utils/env.js";
export function createBundleMcpTempHarness() {
const tempDirs: string[] = [];
return {
async createTempDir(prefix: string): Promise<string> {
const dir = await fs.mkdtemp(path.join(os.tmpdir(), prefix));
tempDirs.push(dir);
return dir;
},
async cleanup() {
await Promise.all(
tempDirs.splice(0).map((dir) => fs.rm(dir, { recursive: true, force: true })),
);
},
};
}
export function resolveBundlePluginRoot(homeDir: string, pluginId: string) {
return path.join(homeDir, ".openclaw", "extensions", pluginId);
}
export async function writeBundleTextFiles(
pluginRoot: string,
files: Record<string, string>,
): Promise<void> {
await Promise.all(
Object.entries(files).map(async ([relativePath, content]) => {
const filePath = path.join(pluginRoot, relativePath);
await fs.mkdir(path.dirname(filePath), { recursive: true });
await fs.writeFile(filePath, content, "utf-8");
}),
);
}
export async function writeClaudeBundleManifest(params: {
homeDir: string;
pluginId: string;
manifest: Record<string, unknown>;
}) {
const pluginRoot = resolveBundlePluginRoot(params.homeDir, params.pluginId);
await fs.mkdir(path.join(pluginRoot, ".claude-plugin"), { recursive: true });
await fs.writeFile(
path.join(pluginRoot, ".claude-plugin", "plugin.json"),
`${JSON.stringify(params.manifest, null, 2)}\n`,
"utf-8",
);
return pluginRoot;
}
export function createEnabledPluginEntries(pluginIds: readonly string[]) {
return Object.fromEntries(pluginIds.map((pluginId) => [pluginId, { enabled: true }]));
}
export async function createBundleProbePlugin(homeDir: string) {
const pluginRoot = resolveBundlePluginRoot(homeDir, "bundle-probe");
const serverPath = path.join(pluginRoot, "servers", "probe.mjs");
await fs.mkdir(path.dirname(serverPath), { recursive: true });
await fs.writeFile(serverPath, "export {};\n", "utf-8");
await writeClaudeBundleManifest({
homeDir,
pluginId: "bundle-probe",
manifest: { name: "bundle-probe" },
});
await fs.writeFile(
path.join(pluginRoot, ".mcp.json"),
`${JSON.stringify(
{
mcpServers: {
bundleProbe: {
command: "node",
args: ["./servers/probe.mjs"],
},
},
},
null,
2,
)}\n`,
"utf-8",
);
return { pluginRoot, serverPath };
}
export async function withBundleHomeEnv<T>(
tempHarness: { createTempDir: (prefix: string) => Promise<string> },
prefix: string,
run: (params: { homeDir: string; workspaceDir: string }) => Promise<T>,
): Promise<T> {
const homeDir = await tempHarness.createTempDir(`${prefix}-home-`);
const workspaceDir = await tempHarness.createTempDir(`${prefix}-workspace-`);
return withEnvAsync(
{
HOME: homeDir,
USERPROFILE: homeDir,
OPENCLAW_HOME: undefined,
OPENCLAW_STATE_DIR: undefined,
},
() => run({ homeDir, workspaceDir }),
);
}
|