UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

203 lines (202 loc) 10.3 kB
import { n as resolveOpenClawPackageRootSync } from "../openclaw-root-CfYY-fyD.js"; import { n as loadPluginManifestRegistryCore, t as loadBundledPluginManifestRegistry } from "../manifest-registry-DCCgYk7q.js"; import { a as tryLoadActivatedBundledPluginPublicSurfaceModuleSync, r as loadBundledPluginPublicSurfaceModuleSync } from "../facade-runtime-BjmVS_9G.js"; import fs from "node:fs"; import path from "node:path"; //#region src/plugin-sdk/private-qa-bundled-env.ts /** * Runtime helper for private QA CLI source-checkout bundled plugin resolution. */ /** Returns an env override that points bundled plugin loading at source extensions. */ function resolvePrivateQaBundledPluginsEnv(env = process.env) { if (env.OPENCLAW_ENABLE_PRIVATE_QA_CLI !== "1") return; const packageRoot = resolveOpenClawPackageRootSync({ argv1: process.argv[1], cwd: process.cwd(), moduleUrl: import.meta.url }); if (!packageRoot) return; const sourceExtensionsDir = path.join(packageRoot, "extensions"); if (!fs.existsSync(path.join(packageRoot, ".git")) || !fs.existsSync(path.join(packageRoot, "src")) || !fs.existsSync(sourceExtensionsDir)) return; return { ...env, OPENCLAW_BUNDLED_PLUGINS_DIR: sourceExtensionsDir }; } //#endregion //#region src/plugin-sdk/qa-runner-runtime.ts /** Memoize a lazy CLI runtime import so repeated command paths share one loaded module. */ function createLazyCliRuntimeLoader(load) { let promise = null; return async () => { promise ??= load(); return await promise; }; } function collectLiveTransportQaStringOption(value, previous) { const trimmed = value.trim(); return trimmed ? [...previous, trimmed] : previous; } function mapLiveTransportQaCommanderOptions(opts) { return { repoRoot: opts.repoRoot, outputDir: opts.outputDir, providerMode: opts.providerMode, primaryModel: opts.model, alternateModel: opts.altModel, fastMode: opts.fast, allowFailures: opts.allowFailures, failFast: opts.failFast, profile: opts.profile, scenarioIds: opts.scenario, listScenarios: opts.listScenarios, sutAccountId: opts.sutAccount, credentialFile: opts.credentialFile, credentialSource: opts.credentialSource, credentialRole: opts.credentialRole }; } function registerLiveTransportQaCli(params) { const command = params.qa.command(params.commandName).description(params.description).option("--repo-root <path>", "Repository root to target when running from a neutral cwd").option("--output-dir <path>", params.outputDirHelp).option("--provider-mode <mode>", params.providerModeHelp, params.defaultProviderMode).option("--model <ref>", "Primary provider/model ref").option("--alt-model <ref>", "Alternate provider/model ref").option("--scenario <id>", params.scenarioHelp, collectLiveTransportQaStringOption, []).option("--fast", "Enable provider fast mode where supported"); if (params.allowFailuresHelp) command.option("--allow-failures", params.allowFailuresHelp, false); command.option("--sut-account <id>", params.sutAccountHelp, "sut"); if (params.credentialFileHelp) command.option("--credential-file <path>", params.credentialFileHelp); if (params.listScenariosHelp) command.option("--list-scenarios", params.listScenariosHelp, false); if (params.profileHelp) command.option("--profile <profile>", params.profileHelp); if (params.failFastHelp) command.option("--fail-fast", params.failFastHelp, false); if (params.credentialOptions) { command.option("--credential-source <source>", params.credentialOptions.sourceDescription ?? "Credential source for live lanes: env or convex (default: env)"); if (params.credentialOptions.roleDescription) command.option("--credential-role <role>", params.credentialOptions.roleDescription); } command.action(async (opts) => { await params.run(mapLiveTransportQaCommanderOptions(opts)); }); } /** Build a Commander registration object for one live-transport QA command. */ function createLiveTransportQaCliRegistration(params) { return { commandName: params.commandName, adapterFactory: params.adapterFactory, register(qa) { registerLiveTransportQaCli({ ...params, qa }); } }; } const QA_RUNNER_API_ARTIFACT_BASENAME = "qa-runner-api.js"; const LEGACY_QA_RUNNER_API_ARTIFACT_BASENAME = "runtime-api.js"; function isMissingQaRuntimeError(error) { if (!(error instanceof Error)) return false; return error.message.includes("qa-lab") && (error.message.includes("runtime-api.js") || error.message.startsWith("Unable to open bundled plugin public surface ")); } /** Load the private QA Lab runtime facade used by QA runner commands. */ function loadQaRuntimeModule() { const env = resolvePrivateQaBundledPluginsEnv(); return loadBundledPluginPublicSurfaceModuleSync({ dirName: ["qa", "lab"].join("-"), artifactBasename: ["runtime-api", "js"].join("."), ...env ? { env } : {} }); } /** Load a bundled QA runner plugin test API facade by plugin id. */ function loadQaRunnerBundledPluginTestApi(pluginId) { const env = resolvePrivateQaBundledPluginsEnv(); return loadBundledPluginPublicSurfaceModuleSync({ dirName: pluginId, artifactBasename: "test-api.js", ...env ? { env } : {} }); } /** Returns whether the private QA Lab runtime facade is available in this build. */ function isQaRuntimeAvailable() { try { loadQaRuntimeModule(); return true; } catch (error) { if (isMissingQaRuntimeError(error)) return false; throw error; } } /** Run a plugin-owned transport adapter through QA Lab's shared suite host. */ async function runLiveTransportQaSuiteCommand(params) { return await loadQaRuntimeModule().runLiveTransportQaSuiteCommand(params); } function listDeclaredQaRunnerPlugins(env = resolvePrivateQaBundledPluginsEnv()) { return (env ? loadBundledPluginManifestRegistry({ env }) : loadPluginManifestRegistryCore()).plugins.filter((plugin) => Array.isArray(plugin.qaRunners) && plugin.qaRunners.length > 0).toSorted((left, right) => { const idCompare = left.id.localeCompare(right.id); if (idCompare !== 0) return idCompare; return left.rootDir.localeCompare(right.rootDir); }); } function indexRuntimeRegistrations(pluginId, surface) { const registrations = surface.qaRunnerCliRegistrations ?? []; const registrationByCommandName = /* @__PURE__ */ new Map(); for (const registration of registrations) { if (!registration?.commandName || typeof registration.register !== "function") throw new Error(`QA runner plugin "${pluginId}" exported an invalid CLI registration`); if (registrationByCommandName.has(registration.commandName)) throw new Error(`QA runner plugin "${pluginId}" exported duplicate CLI registration "${registration.commandName}"`); registrationByCommandName.set(registration.commandName, registration); } return registrationByCommandName; } function loadQaRunnerSurface(plugin, env) { if (plugin.origin === "bundled") return loadBundledPluginPublicSurfaceModuleSync({ dirName: plugin.id, artifactBasename: QA_RUNNER_API_ARTIFACT_BASENAME, ...env ? { env } : {} }); try { return tryLoadActivatedBundledPluginPublicSurfaceModuleSync({ dirName: plugin.id, artifactBasename: QA_RUNNER_API_ARTIFACT_BASENAME, ...env ? { env } : {} }); } catch (error) { if (!(error instanceof Error) || error.message !== `Unable to resolve bundled plugin public surface ${plugin.id}/${QA_RUNNER_API_ARTIFACT_BASENAME}`) throw error; } return tryLoadActivatedBundledPluginPublicSurfaceModuleSync({ dirName: plugin.id, artifactBasename: LEGACY_QA_RUNNER_API_ARTIFACT_BASENAME, ...env ? { env } : {} }); } /** List QA runner CLI contributions declared by manifests and backed by runtime registrations. */ function listQaRunnerCliContributions() { const env = resolvePrivateQaBundledPluginsEnv(); const contributions = /* @__PURE__ */ new Map(); for (const plugin of listDeclaredQaRunnerPlugins(env)) { const runnerSurface = loadQaRunnerSurface(plugin, env); const runtimeRegistrationByCommandName = runnerSurface ? indexRuntimeRegistrations(plugin.id, runnerSurface) : null; const declaredCommandNames = new Set(plugin.qaRunners.map((runner) => runner.commandName)); for (const runner of plugin.qaRunners) { const previous = contributions.get(runner.commandName); if (previous && previous.pluginId !== plugin.id) throw new Error(`QA runner command "${runner.commandName}" declared by both "${previous.pluginId}" and "${plugin.id}"`); const registration = runtimeRegistrationByCommandName?.get(runner.commandName); if (!runnerSurface) { contributions.set(runner.commandName, { pluginId: plugin.id, commandName: runner.commandName, ...runner.description ? { description: runner.description } : {}, status: "blocked" }); continue; } if (!registration) throw new Error(`QA runner plugin "${plugin.id}" declared "${runner.commandName}" in openclaw.plugin.json but did not export a matching CLI registration from its QA runner surface`); const adapterFactory = registration.adapterFactory; const supportsModuleFlows = adapterFactory ? Reflect.get(adapterFactory, "supportsModuleFlows") : void 0; if (adapterFactory && (adapterFactory.id !== runner.commandName || supportsModuleFlows !== void 0 && supportsModuleFlows !== true || adapterFactory.isolatesInstances !== void 0 && typeof adapterFactory.isolatesInstances !== "boolean" || typeof adapterFactory.matches !== "function" || typeof adapterFactory.create !== "function")) throw new Error(`QA runner plugin "${plugin.id}" exported an invalid transport factory for "${runner.commandName}"`); contributions.set(runner.commandName, { pluginId: plugin.id, commandName: runner.commandName, ...runner.description ? { description: runner.description } : {}, status: "available", registration }); } for (const commandName of runtimeRegistrationByCommandName?.keys() ?? []) if (!declaredCommandNames.has(commandName)) throw new Error(`QA runner plugin "${plugin.id}" exported "${commandName}" from its QA runner surface but did not declare it in openclaw.plugin.json`); } return [...contributions.values()]; } //#endregion export { createLazyCliRuntimeLoader, createLiveTransportQaCliRegistration, isQaRuntimeAvailable, listQaRunnerCliContributions, loadQaRunnerBundledPluginTestApi, loadQaRuntimeModule, runLiveTransportQaSuiteCommand };