test: require bundled startup activation metadata

This commit is contained in:
Shakker
2026-04-28 03:24:23 +01:00
parent 86bdeb0561
commit 61ddddbe0f
2 changed files with 52 additions and 0 deletions

View File

@@ -16,6 +16,7 @@ Docs: https://docs.openclaw.ai
- Plugins/models: wire manifest `modelCatalog.aliases` and `modelCatalog.suppressions` into model-catalog planning and built-in model suppression, with stale Spark and Qwen Coding Plan suppressions now declared in plugin manifests instead of runtime fallback hooks. Thanks @shakkernerd.
- Channels/Yuanbao: register the Tencent Yuanbao external channel plugin (`openclaw-plugin-yuanbao`) in the official channel catalog, contract suites, and community plugin docs, with a new `docs/channels/yuanbao.md` quick-start guide for WebSocket bot DMs and group chats. (#72756) Thanks @loongfay.
- Channels/QQBot: add full group chat support (history tracking, @-mention gating, activation modes, per-group config, FIFO message queue with deliver debounce), C2C `stream_messages` streaming with a `StreamingController` lifecycle manager, unified `sendMedia` with chunked upload for large files, and refactor the engine into pipeline stages, focused outbound submodules, builtin slash-command modules, and explicit DI ports via `createEngineAdapters()`. (#70624) Thanks @cxyhhhhh.
- Plugins/startup: migrate bundled plugin manifests to explicit `activation.onStartup` declarations so Gateway startup imports only the bundled plugins that intentionally register startup-time runtime surfaces. Thanks @shakkernerd.
- Plugins/startup: add explicit `activation.onStartup` metadata so plugins can declare Gateway startup import behavior while the deprecated implicit sidecar fallback remains for legacy plugins. Thanks @shakkernerd.
- Gateway/startup: reuse lookup-table plugin manifests when loading startup plugins so Gateway boot avoids rebuilding plugin discovery and manifest metadata. Thanks @shakkernerd.
- CLI/models: declare fixed Qianfan, Xiaomi, NVIDIA, Cerebras, and Mistral model catalogs in plugin manifests so provider-filtered model listing can use the manifest fast path without loading provider runtime catalog code. Thanks @shakkernerd.

View File

@@ -24,6 +24,26 @@ import { collectBundledRuntimeSidecarPaths } from "./runtime-sidecar-paths-basel
import { BUNDLED_RUNTIME_SIDECAR_PATHS } from "./runtime-sidecar-paths.js";
const BUNDLED_PLUGIN_METADATA_TEST_TIMEOUT_MS = 300_000;
const EXPECTED_BUNDLED_STARTUP_PLUGIN_IDS = [
"acpx",
"active-memory",
"bonjour",
"browser",
"device-pair",
"diagnostics-otel",
"diagnostics-prometheus",
"diffs",
"google-meet",
"llm-task",
"lobster",
"memory-wiki",
"openshell",
"phone-control",
"talk-voice",
"thread-ownership",
"voice-call",
"webhooks",
] as const;
installGeneratedPluginTempRootCleanup();
@@ -88,6 +108,22 @@ function listRepoBundledPluginMetadata(): readonly BundledPluginMetadata[] {
});
}
function listRepoBundledPluginManifests() {
const bundledPluginsDir = path.join(repoRoot, "extensions");
return fs
.readdirSync(bundledPluginsDir, { withFileTypes: true })
.filter((entry) => entry.isDirectory())
.map((entry) => ({
dirName: entry.name,
manifest: loadPluginManifest(path.join(bundledPluginsDir, entry.name), false),
}))
.filter((entry) => entry.manifest.ok)
.map((entry) => ({
dirName: entry.dirName,
manifest: entry.manifest.manifest,
}));
}
function readPackageManifest(pluginDir: string): PackageManifest | undefined {
const packagePath = path.join(pluginDir, "package.json");
return fs.existsSync(packagePath)
@@ -276,6 +312,21 @@ describe("bundled plugin metadata", () => {
}
});
it("declares explicit startup activation on all bundled plugin manifests", () => {
const startupPluginIds: string[] = [];
for (const entry of listRepoBundledPluginManifests()) {
expect(typeof entry.manifest.activation?.onStartup).toBe("boolean");
if (entry.manifest.activation?.onStartup === true) {
startupPluginIds.push(entry.manifest.id);
}
}
expect(startupPluginIds.toSorted((left, right) => left.localeCompare(right))).toEqual(
EXPECTED_BUNDLED_STARTUP_PLUGIN_IDS,
);
});
it("prefers built generated paths when present and falls back to source paths", () => {
const tempRoot = createGeneratedPluginTempRoot("openclaw-bundled-plugin-metadata-");
const pluginRoot = path.join(tempRoot, "extensions", "plugin");