























@@ -1,139 +1,52 @@
1-import fs from "node:fs";
2-import os from "node:os";
3-import path from "node:path";
41import { afterEach, describe, expect, it } from "vitest";
5-import type { OpenClawConfig } from "../config/types.openclaw.js";
62import { clearPluginDiscoveryCache } from "../plugins/discovery.js";
73import { clearPluginManifestRegistryCache } from "../plugins/manifest-registry.js";
84import { refreshPluginRegistry } from "../plugins/plugin-registry.js";
5+import {
6+createColdPluginConfig,
7+createColdPluginFixture,
8+createColdPluginHermeticEnv,
9+isColdPluginRuntimeLoaded,
10+} from "../plugins/test-helpers/cold-plugin-fixtures.js";
11+import { cleanupTrackedTempDirs, makeTrackedTempDir } from "../plugins/test-helpers/fs-fixtures.js";
912import { buildAuthChoiceOptions, formatAuthChoiceChoicesForCli } from "./auth-choice-options.js";
1013import { listManifestInstalledChannelIds } from "./channel-setup/discovery.js";
1114import { resolveProviderCatalogPluginIdsForFilter } from "./models/list.provider-catalog.js";
12151316const tempDirs: string[] = [];
14171518function makeTempDir() {
16-const dir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-command-cold-imports-"));
17-tempDirs.push(dir);
18-return dir;
19-}
20-21-function hermeticEnv(
22-homeDir: string,
23-options: { disablePersistedRegistry?: boolean } = {},
24-): NodeJS.ProcessEnv {
25-return {
26- ...process.env,
27-OPENCLAW_HOME: path.join(homeDir, "home"),
28-OPENCLAW_BUNDLED_PLUGINS_DIR: undefined,
29-OPENCLAW_DISABLE_PERSISTED_PLUGIN_REGISTRY:
30-options.disablePersistedRegistry === false ? undefined : "1",
31-OPENCLAW_DISABLE_PLUGIN_DISCOVERY_CACHE: "1",
32-OPENCLAW_DISABLE_PLUGIN_MANIFEST_CACHE: "1",
33-OPENCLAW_VERSION: "2026.4.25",
34-VITEST: "true",
35-};
36-}
37-38-function createColdControlPlanePlugin() {
39-const rootDir = makeTempDir();
40-const runtimeMarker = path.join(rootDir, "runtime-loaded.txt");
41-fs.writeFileSync(
42-path.join(rootDir, "package.json"),
43-JSON.stringify(
44-{
45-name: "@example/openclaw-cold-control-plane",
46-version: "1.0.0",
47-openclaw: { extensions: ["./index.cjs"] },
48-},
49-null,
50-2,
51-),
52-"utf8",
53-);
54-fs.writeFileSync(
55-path.join(rootDir, "openclaw.plugin.json"),
56-JSON.stringify(
57-{
58-id: "cold-control-plane",
59-name: "Cold Control Plane",
60-configSchema: { type: "object" },
61-providers: ["cold-model-provider"],
62-channels: ["cold-channel"],
63-channelConfigs: {
64-"cold-channel": {
65-schema: { type: "object" },
66-},
67-},
68-providerAuthChoices: [
69-{
70-provider: "cold-model-provider",
71-method: "api-key",
72-choiceId: "cold-provider-api-key",
73-choiceLabel: "Cold Provider API key",
74-groupId: "cold-model-provider",
75-groupLabel: "Cold Provider",
76-optionKey: "coldProviderApiKey",
77-cliFlag: "--cold-provider-api-key",
78-cliOption: "--cold-provider-api-key <key>",
79-onboardingScopes: ["text-inference"],
80-},
81-],
82-},
83-null,
84-2,
85-),
86-"utf8",
87-);
88-fs.writeFileSync(
89-path.join(rootDir, "index.cjs"),
90-`require("node:fs").writeFileSync(${JSON.stringify(runtimeMarker)}, "loaded", "utf8");\nthrow new Error("runtime entry should not load for command control-plane discovery");\n`,
91-"utf8",
92-);
93-return { rootDir, runtimeMarker };
94-}
95-96-function createColdConfig(pluginDir: string): OpenClawConfig {
97-return {
98-plugins: {
99-load: { paths: [pluginDir] },
100-entries: {
101-"cold-control-plane": { enabled: true },
102-},
103-},
104-};
19+return makeTrackedTempDir("openclaw-command-cold-imports", tempDirs);
10520}
1062110722afterEach(() => {
10823clearPluginDiscoveryCache();
10924clearPluginManifestRegistryCache();
110-for (const dir of tempDirs.splice(0)) {
111-fs.rmSync(dir, { recursive: true, force: true });
112-}
25+cleanupTrackedTempDirs(tempDirs);
11326});
1142711528describe("command control-plane plugin discovery", () => {
11629it("resolves channel setup metadata without importing plugin runtime", () => {
117-const plugin = createColdControlPlanePlugin();
30+const plugin = createColdPluginFixture({ rootDir: makeTempDir() });
11831const workspaceDir = makeTempDir();
119-const cfg = createColdConfig(plugin.rootDir);
120-const env = hermeticEnv(workspaceDir);
32+const cfg = createColdPluginConfig(plugin.rootDir, plugin.pluginId);
33+const env = createColdPluginHermeticEnv(workspaceDir);
1213412235expect(
12336listManifestInstalledChannelIds({
12437 cfg,
12538 workspaceDir,
12639 env,
12740}),
128-).toContain("cold-channel");
129-expect(fs.existsSync(plugin.runtimeMarker)).toBe(false);
41+).toContain(plugin.channelId);
42+expect(isColdPluginRuntimeLoaded(plugin)).toBe(false);
13043});
1314413245it("builds onboarding auth choices from manifest metadata without importing plugin runtime", () => {
133-const plugin = createColdControlPlanePlugin();
46+const plugin = createColdPluginFixture({ rootDir: makeTempDir() });
13447const workspaceDir = makeTempDir();
135-const cfg = createColdConfig(plugin.rootDir);
136-const env = hermeticEnv(workspaceDir);
48+const cfg = createColdPluginConfig(plugin.rootDir, plugin.pluginId);
49+const env = createColdPluginHermeticEnv(workspaceDir);
1375013851expect(
13952buildAuthChoiceOptions({
@@ -145,9 +58,9 @@ describe("command control-plane plugin discovery", () => {
14558}),
14659).toContainEqual(
14760expect.objectContaining({
148-value: "cold-provider-api-key",
61+value: plugin.authChoiceId,
14962label: "Cold Provider API key",
150-groupId: "cold-model-provider",
63+groupId: plugin.providerId,
15164}),
15265);
15366expect(
@@ -156,31 +69,31 @@ describe("command control-plane plugin discovery", () => {
15669 workspaceDir,
15770 env,
15871}).split("|"),
159-).toContain("cold-provider-api-key");
160-expect(fs.existsSync(plugin.runtimeMarker)).toBe(false);
72+).toContain(plugin.authChoiceId);
73+expect(isColdPluginRuntimeLoaded(plugin)).toBe(false);
16174});
1627516376it("resolves models-list provider ownership without importing plugin runtime", async () => {
164-const plugin = createColdControlPlanePlugin();
77+const plugin = createColdPluginFixture({ rootDir: makeTempDir() });
16578const workspaceDir = makeTempDir();
166-const cfg = createColdConfig(plugin.rootDir);
167-const env = hermeticEnv(workspaceDir, { disablePersistedRegistry: false });
79+const cfg = createColdPluginConfig(plugin.rootDir, plugin.pluginId);
80+const env = createColdPluginHermeticEnv(workspaceDir, { disablePersistedRegistry: false });
1688116982await refreshPluginRegistry({
17083config: cfg,
17184 workspaceDir,
17285 env,
17386reason: "manual",
17487});
175-expect(fs.existsSync(plugin.runtimeMarker)).toBe(false);
88+expect(isColdPluginRuntimeLoaded(plugin)).toBe(false);
1768917790await expect(
17891resolveProviderCatalogPluginIdsForFilter({
17992 cfg,
18093 env,
181-providerFilter: "cold-model-provider",
94+providerFilter: plugin.providerId,
18295}),
183-).resolves.toEqual(["cold-control-plane"]);
184-expect(fs.existsSync(plugin.runtimeMarker)).toBe(false);
96+).resolves.toEqual([plugin.pluginId]);
97+expect(isColdPluginRuntimeLoaded(plugin)).toBe(false);
18598});
18699});
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。