refactor: share private QA bundled root override

This commit is contained in:
Gustavo Madeira Santana
2026-04-15 21:03:05 -04:00
parent b5a9179bc6
commit b8bf2b6be6
4 changed files with 91 additions and 35 deletions

View File

@@ -0,0 +1,31 @@
import fs from "node:fs";
import path from "node:path";
import { resolveOpenClawPackageRootSync } from "../infra/openclaw-root.js";
export function resolvePrivateQaBundledPluginsEnv(
env: NodeJS.ProcessEnv = process.env,
): NodeJS.ProcessEnv | undefined {
if (env.OPENCLAW_ENABLE_PRIVATE_QA_CLI !== "1") {
return undefined;
}
const packageRoot = resolveOpenClawPackageRootSync({
argv1: process.argv[1],
cwd: process.cwd(),
moduleUrl: import.meta.url,
});
if (!packageRoot) {
return undefined;
}
const sourceExtensionsDir = path.join(packageRoot, "extensions");
if (
!fs.existsSync(path.join(packageRoot, ".git")) ||
!fs.existsSync(path.join(packageRoot, "src")) ||
!fs.existsSync(sourceExtensionsDir)
) {
return undefined;
}
return {
...env,
OPENCLAW_BUNDLED_PLUGINS_DIR: sourceExtensionsDir,
};
}

View File

@@ -1,13 +1,11 @@
import fs from "node:fs";
import path from "node:path";
import type { Command } from "commander";
import { resolveOpenClawPackageRootSync } from "../infra/openclaw-root.js";
import type { PluginManifestRecord } from "../plugins/manifest-registry.js";
import { loadPluginManifestRegistry } from "../plugins/manifest-registry.js";
import {
loadBundledPluginPublicSurfaceModuleSync,
tryLoadActivatedBundledPluginPublicSurfaceModuleSync,
} from "./facade-runtime.js";
import { resolvePrivateQaBundledPluginsEnv } from "./private-qa-bundled-env.js";
export type QaRunnerCliRegistration = {
commandName: string;
@@ -56,7 +54,7 @@ function isMissingQaRuntimeError(error: unknown) {
}
export function loadQaRuntimeModule(): QaRuntimeSurface {
const env = resolvePrivateQaRunnerEnv();
const env = resolvePrivateQaBundledPluginsEnv();
return loadBundledPluginPublicSurfaceModuleSync<QaRuntimeSurface>({
dirName: ["qa", "lab"].join("-"),
artifactBasename: ["runtime-api", "js"].join("."),
@@ -76,36 +74,8 @@ export function isQaRuntimeAvailable(): boolean {
}
}
function resolvePrivateQaRunnerEnv(
env: NodeJS.ProcessEnv = process.env,
): NodeJS.ProcessEnv | undefined {
if (env.OPENCLAW_ENABLE_PRIVATE_QA_CLI !== "1") {
return undefined;
}
const packageRoot = resolveOpenClawPackageRootSync({
argv1: process.argv[1],
cwd: process.cwd(),
moduleUrl: import.meta.url,
});
if (!packageRoot) {
return undefined;
}
const sourceExtensionsDir = path.join(packageRoot, "extensions");
if (
!fs.existsSync(path.join(packageRoot, ".git")) ||
!fs.existsSync(path.join(packageRoot, "src")) ||
!fs.existsSync(sourceExtensionsDir)
) {
return undefined;
}
return {
...env,
OPENCLAW_BUNDLED_PLUGINS_DIR: sourceExtensionsDir,
};
}
function listDeclaredQaRunnerPlugins(
env: NodeJS.ProcessEnv | undefined = resolvePrivateQaRunnerEnv(),
env: NodeJS.ProcessEnv | undefined = resolvePrivateQaBundledPluginsEnv(),
): Array<
PluginManifestRecord & {
qaRunners: NonNullable<PluginManifestRecord["qaRunners"]>;
@@ -167,7 +137,7 @@ function loadQaRunnerRuntimeSurface(
}
export function listQaRunnerCliContributions(): readonly QaRunnerCliContribution[] {
const env = resolvePrivateQaRunnerEnv();
const env = resolvePrivateQaBundledPluginsEnv();
const contributions = new Map<string, QaRunnerCliContribution>();
for (const plugin of listDeclaredQaRunnerPlugins(env)) {

View File

@@ -1,14 +1,38 @@
import { beforeEach, describe, expect, it, vi } from "vitest";
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
const loadBundledPluginPublicSurfaceModuleSync = vi.hoisted(() => vi.fn());
const resolveOpenClawPackageRootSync = vi.hoisted(() => vi.fn());
vi.mock("./facade-runtime.js", () => ({
loadBundledPluginPublicSurfaceModuleSync,
}));
vi.mock("../infra/openclaw-root.js", () => ({
resolveOpenClawPackageRootSync,
}));
describe("plugin-sdk qa-runtime", () => {
const tempDirs: string[] = [];
const originalPrivateQaCli = process.env.OPENCLAW_ENABLE_PRIVATE_QA_CLI;
beforeEach(() => {
loadBundledPluginPublicSurfaceModuleSync.mockReset();
resolveOpenClawPackageRootSync.mockReset().mockReturnValue(null);
delete process.env.OPENCLAW_ENABLE_PRIVATE_QA_CLI;
});
afterEach(() => {
for (const dir of tempDirs.splice(0)) {
fs.rmSync(dir, { recursive: true, force: true });
}
if (originalPrivateQaCli === undefined) {
delete process.env.OPENCLAW_ENABLE_PRIVATE_QA_CLI;
} else {
process.env.OPENCLAW_ENABLE_PRIVATE_QA_CLI = originalPrivateQaCli;
}
});
it("stays cold until the runtime seam is used", async () => {
@@ -35,6 +59,34 @@ describe("plugin-sdk qa-runtime", () => {
});
});
it("uses the source bundled tree for qa-lab runtime loading in private qa mode", async () => {
const sourceRoot = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-qa-runtime-root-"));
tempDirs.push(sourceRoot);
fs.mkdirSync(path.join(sourceRoot, "src"), { recursive: true });
fs.mkdirSync(path.join(sourceRoot, "extensions"), { recursive: true });
fs.writeFileSync(path.join(sourceRoot, ".git"), "gitdir: /tmp/mock\n", "utf8");
process.env.OPENCLAW_ENABLE_PRIVATE_QA_CLI = "1";
resolveOpenClawPackageRootSync.mockReturnValue(sourceRoot);
const runtimeSurface = {
defaultQaRuntimeModelForMode: vi.fn(),
startQaLiveLaneGateway: vi.fn(),
};
loadBundledPluginPublicSurfaceModuleSync.mockReturnValue(runtimeSurface);
const module = await import("./qa-runtime.js");
expect(module.loadQaRuntimeModule()).toBe(runtimeSurface);
expect(loadBundledPluginPublicSurfaceModuleSync).toHaveBeenCalledWith({
dirName: "qa-lab",
artifactBasename: "runtime-api.js",
env: expect.objectContaining({
OPENCLAW_ENABLE_PRIVATE_QA_CLI: "1",
OPENCLAW_BUNDLED_PLUGINS_DIR: path.join(sourceRoot, "extensions"),
}),
});
});
it("reports the runtime as unavailable when the qa-lab surface is missing", async () => {
loadBundledPluginPublicSurfaceModuleSync.mockImplementation(() => {
throw new Error("Unable to resolve bundled plugin public surface qa-lab/runtime-api.js");

View File

@@ -1,4 +1,5 @@
import { loadBundledPluginPublicSurfaceModuleSync } from "./facade-runtime.js";
import { resolvePrivateQaBundledPluginsEnv } from "./private-qa-bundled-env.js";
type QaRuntimeSurface = {
defaultQaRuntimeModelForMode: (
@@ -20,9 +21,11 @@ function isMissingQaRuntimeError(error: unknown) {
}
export function loadQaRuntimeModule(): QaRuntimeSurface {
const env = resolvePrivateQaBundledPluginsEnv();
return loadBundledPluginPublicSurfaceModuleSync<QaRuntimeSurface>({
dirName: "qa-lab",
artifactBasename: "runtime-api.js",
...(env ? { env } : {}),
});
}