From 933c7968dc4fda9a01d14e6d8a0a24e3d377ab06 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Tue, 28 Apr 2026 20:36:15 +0100 Subject: [PATCH] fix(ci): stabilize full release validation lanes --- extensions/qa-lab/package.json | 1 - extensions/qa-lab/src/runtime-api.ts | 2 +- pnpm-lock.yaml | 3 -- ...lugin-sdk-private-local-only-subpaths.json | 2 +- .../doctor-bundled-plugin-runtime-deps.ts | 37 ++------------ src/plugins/discovery.test.ts | 4 +- src/plugins/sdk-alias.test.ts | 51 +++++++++++++++++-- 7 files changed, 58 insertions(+), 42 deletions(-) diff --git a/extensions/qa-lab/package.json b/extensions/qa-lab/package.json index 95fb99b3bc1..7e864ab2de3 100644 --- a/extensions/qa-lab/package.json +++ b/extensions/qa-lab/package.json @@ -7,7 +7,6 @@ "dependencies": { "@copilotkit/aimock": "1.15.1", "@modelcontextprotocol/sdk": "1.29.0", - "@openclaw/qa-channel": "workspace:*", "playwright-core": "1.59.1", "yaml": "^2.8.3", "zod": "^4.3.6" diff --git a/extensions/qa-lab/src/runtime-api.ts b/extensions/qa-lab/src/runtime-api.ts index de44ddf1bdf..07e7da977de 100644 --- a/extensions/qa-lab/src/runtime-api.ts +++ b/extensions/qa-lab/src/runtime-api.ts @@ -20,7 +20,7 @@ export { searchQaBusMessages, sendQaBusMessage, setQaChannelRuntime, -} from "@openclaw/qa-channel/api.js"; +} from "openclaw/plugin-sdk/qa-channel"; export type { QaBusAttachment, QaBusConversation, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 242eba3ad4b..e6758a1e05b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1117,9 +1117,6 @@ importers: '@modelcontextprotocol/sdk': specifier: 1.29.0 version: 1.29.0(zod@4.3.6) - '@openclaw/qa-channel': - specifier: workspace:* - version: link:../qa-channel playwright-core: specifier: 1.59.1 version: 1.59.1 diff --git a/scripts/lib/plugin-sdk-private-local-only-subpaths.json b/scripts/lib/plugin-sdk-private-local-only-subpaths.json index 6b4a7af24a7..5e7ea8c64ca 100644 --- a/scripts/lib/plugin-sdk-private-local-only-subpaths.json +++ b/scripts/lib/plugin-sdk-private-local-only-subpaths.json @@ -1 +1 @@ -["qa-lab", "qa-runtime"] +["qa-channel", "qa-channel-protocol", "qa-lab", "qa-runtime"] diff --git a/src/commands/doctor-bundled-plugin-runtime-deps.ts b/src/commands/doctor-bundled-plugin-runtime-deps.ts index 2ec040d4f55..f019b675dcb 100644 --- a/src/commands/doctor-bundled-plugin-runtime-deps.ts +++ b/src/commands/doctor-bundled-plugin-runtime-deps.ts @@ -3,7 +3,6 @@ import path from "node:path"; import { formatCliCommand } from "../cli/command-format.js"; import type { OpenClawConfig } from "../config/types.openclaw.js"; import { resolveOpenClawPackageRootSync } from "../infra/openclaw-root.js"; -import { resolveBundledPluginsDir } from "../plugins/bundled-dir.js"; import { createBundledRuntimeDepsWritableInstallSpecs, repairBundledRuntimeDepsInstallRootAsync, @@ -12,7 +11,6 @@ import { type BundledRuntimeDepsInstallParams, } from "../plugins/bundled-runtime-deps.js"; import { normalizePluginsConfig } from "../plugins/config-state.js"; -import { resolveEffectivePluginIds } from "../plugins/effective-plugin-ids.js"; import { passesManifestOwnerBasePolicy } from "../plugins/manifest-owner-policy.js"; import type { RuntimeEnv } from "../runtime.js"; import { note } from "../terminal/note.js"; @@ -20,19 +18,6 @@ import type { DoctorPrompter } from "./doctor-prompter.js"; const RUNTIME_DEPS_INSTALL_HEARTBEAT_MS = 15_000; -function filterPluginIdsPresentInBundledTree( - bundledPluginsDir: string, - pluginIds: readonly string[], -): string[] | undefined { - const present = pluginIds.filter((pluginId) => { - if (path.basename(pluginId) !== pluginId) { - return false; - } - return fs.existsSync(path.join(bundledPluginsDir, pluginId)); - }); - return present.length > 0 ? present : undefined; -} - function collectPackagedRuntimeDepsRepairPluginIds(params: { bundledPluginsDir: string; config: OpenClawConfig; @@ -143,23 +128,11 @@ export async function maybeRepairBundledPluginRuntimeDeps(params: { const env = params.env ?? process.env; const bundledPluginsDir = path.join(packageRoot, "dist", "extensions"); const effectivePluginIds = params.config - ? resolveBundledPluginsDir({ ...env, OPENCLAW_BUNDLED_PLUGINS_DIR: bundledPluginsDir }) === - bundledPluginsDir - ? filterPluginIdsPresentInBundledTree( - bundledPluginsDir, - resolveEffectivePluginIds({ - config: params.config, - env: { - ...env, - OPENCLAW_BUNDLED_PLUGINS_DIR: bundledPluginsDir, - }, - }), - ) - : collectPackagedRuntimeDepsRepairPluginIds({ - bundledPluginsDir, - config: params.config, - includeConfiguredChannels: params.includeConfiguredChannels, - }) + ? collectPackagedRuntimeDepsRepairPluginIds({ + bundledPluginsDir, + config: params.config, + includeConfiguredChannels: params.includeConfiguredChannels, + }) : undefined; const { deps, missing, conflicts } = scanBundledPluginRuntimeDeps({ packageRoot, diff --git a/src/plugins/discovery.test.ts b/src/plugins/discovery.test.ts index d686c09881d..949495fd6ed 100644 --- a/src/plugins/discovery.test.ts +++ b/src/plugins/discovery.test.ts @@ -64,11 +64,13 @@ function hasDiagnosticSourceSuffix( } function buildDiscoveryEnv(stateDir: string): NodeJS.ProcessEnv { + const bundledPluginsDir = path.join(stateDir, "empty-bundled-plugins"); + mkdirSafe(bundledPluginsDir); return { OPENCLAW_STATE_DIR: stateDir, OPENCLAW_HOME: undefined, OPENCLAW_DISABLE_BUNDLED_PLUGINS: "1", - OPENCLAW_BUNDLED_PLUGINS_DIR: "/nonexistent/bundled/plugins", + OPENCLAW_BUNDLED_PLUGINS_DIR: bundledPluginsDir, }; } diff --git a/src/plugins/sdk-alias.test.ts b/src/plugins/sdk-alias.test.ts index f3f77fe0dd3..c5b423cba99 100644 --- a/src/plugins/sdk-alias.test.ts +++ b/src/plugins/sdk-alias.test.ts @@ -101,7 +101,7 @@ function createPluginSdkAliasFixture(params?: { mkdirSafeDir(path.join(root, "scripts", "lib")); fs.writeFileSync( path.join(root, "scripts", "lib", "plugin-sdk-private-local-only-subpaths.json"), - JSON.stringify(["qa-lab", "qa-runtime"], null, 2), + JSON.stringify(["qa-channel", "qa-channel-protocol", "qa-lab", "qa-runtime"], null, 2), "utf-8", ); fs.writeFileSync(srcFile, params?.srcBody ?? "export {};\n", "utf-8"); @@ -530,6 +530,16 @@ describe("plugin sdk alias helpers", () => { "./plugin-sdk/core": { default: "./dist/plugin-sdk/core.js" }, }, }); + fs.writeFileSync( + path.join(fixture.root, "src", "plugin-sdk", "qa-channel.ts"), + "export const qaChannel = true;\n", + "utf-8", + ); + fs.writeFileSync( + path.join(fixture.root, "src", "plugin-sdk", "qa-channel-protocol.ts"), + "export const qaChannelProtocol = true;\n", + "utf-8", + ); fs.writeFileSync( path.join(fixture.root, "src", "plugin-sdk", "qa-runtime.ts"), "export const qaRuntime = true;\n", @@ -546,7 +556,7 @@ describe("plugin sdk alias helpers", () => { modulePath: path.join(fixture.root, "src", "plugins", "loader.ts"), }), ); - expect(subpaths).toEqual(["core", "qa-lab", "qa-runtime"]); + expect(subpaths).toEqual(["core", "qa-channel", "qa-channel-protocol", "qa-lab", "qa-runtime"]); }); it("does not reuse a non-private cached subpath list after private qa gets enabled", () => { @@ -555,6 +565,16 @@ describe("plugin sdk alias helpers", () => { "./plugin-sdk/core": { default: "./dist/plugin-sdk/core.js" }, }, }); + fs.writeFileSync( + path.join(fixture.root, "src", "plugin-sdk", "qa-channel.ts"), + "export const qaChannel = true;\n", + "utf-8", + ); + fs.writeFileSync( + path.join(fixture.root, "src", "plugin-sdk", "qa-channel-protocol.ts"), + "export const qaChannelProtocol = true;\n", + "utf-8", + ); fs.writeFileSync( path.join(fixture.root, "src", "plugin-sdk", "qa-runtime.ts"), "export const qaRuntime = true;\n", @@ -577,7 +597,13 @@ describe("plugin sdk alias helpers", () => { modulePath: path.join(fixture.root, "src", "plugins", "loader.ts"), }), ); - expect(privateSubpaths).toEqual(["core", "qa-lab", "qa-runtime"]); + expect(privateSubpaths).toEqual([ + "core", + "qa-channel", + "qa-channel-protocol", + "qa-lab", + "qa-runtime", + ]); }); it.each([ @@ -657,9 +683,22 @@ describe("plugin sdk alias helpers", () => { }, }); const sourceRootAlias = path.join(fixture.root, "src", "plugin-sdk", "root-alias.cjs"); + const sourceQaChannelPath = path.join(fixture.root, "src", "plugin-sdk", "qa-channel.ts"); + const sourceQaChannelProtocolPath = path.join( + fixture.root, + "src", + "plugin-sdk", + "qa-channel-protocol.ts", + ); const sourceQaRuntimePath = path.join(fixture.root, "src", "plugin-sdk", "qa-runtime.ts"); const distQaLabPath = path.join(fixture.root, "dist", "plugin-sdk", "qa-lab.js"); fs.writeFileSync(sourceRootAlias, "module.exports = {};\n", "utf-8"); + fs.writeFileSync(sourceQaChannelPath, "export const qaChannel = true;\n", "utf-8"); + fs.writeFileSync( + sourceQaChannelProtocolPath, + "export const qaChannelProtocol = true;\n", + "utf-8", + ); fs.writeFileSync(sourceQaRuntimePath, "export const qaRuntime = true;\n", "utf-8"); fs.writeFileSync(distQaLabPath, "export const qaLab = true;\n", "utf-8"); const sourcePluginEntry = writePluginEntry( @@ -677,6 +716,12 @@ describe("plugin sdk alias helpers", () => { expect(fs.realpathSync(aliases["openclaw/plugin-sdk/qa-runtime"] ?? "")).toBe( fs.realpathSync(sourceQaRuntimePath), ); + expect(fs.realpathSync(aliases["openclaw/plugin-sdk/qa-channel"] ?? "")).toBe( + fs.realpathSync(sourceQaChannelPath), + ); + expect(fs.realpathSync(aliases["openclaw/plugin-sdk/qa-channel-protocol"] ?? "")).toBe( + fs.realpathSync(sourceQaChannelProtocolPath), + ); expect(fs.realpathSync(aliases["openclaw/plugin-sdk/qa-lab"] ?? "")).toBe( fs.realpathSync(distQaLabPath), );