




















@@ -1,9 +1,18 @@
1+import fsSync from "node:fs";
12import fs from "node:fs/promises";
23import os from "node:os";
34import path from "node:path";
45import { afterAll, afterEach, beforeAll, describe, expect, it, vi } from "vitest";
6+import type { OpenClawConfig } from "../config/types.openclaw.js";
57import { resetLogger, setLoggerOverride } from "../logging/logger.js";
68import { loggingState } from "../logging/state.js";
9+import {
10+clearCurrentPluginMetadataSnapshot,
11+setCurrentPluginMetadataSnapshot,
12+} from "../plugins/current-plugin-metadata-snapshot.js";
13+import { resolveInstalledPluginIndexPolicyHash } from "../plugins/installed-plugin-index-policy.js";
14+import type { PluginManifestRecord, PluginManifestRegistry } from "../plugins/manifest-registry.js";
15+import type { PluginMetadataSnapshot } from "../plugins/plugin-metadata-snapshot.js";
716import { writeSkill, writeWorkspaceSkills } from "./skills.e2e-test-helpers.js";
817import {
918restoreMockSkillsHomeEnv,
@@ -52,6 +61,103 @@ let envSnapshot: SkillsHomeEnvSnapshot;
5261let tempRoot = "";
5362let workspaceCaseIndex = 0;
546364+function createWorkspacePluginRegistry(workspaceDir: string): PluginManifestRegistry {
65+const extensionsRoot = path.join(workspaceDir, ".openclaw", "extensions");
66+const plugins: PluginManifestRecord[] = [];
67+for (const id of ["open-prose", "browser"]) {
68+const rootDir = path.join(extensionsRoot, id);
69+const manifestPath = path.join(rootDir, "openclaw.plugin.json");
70+if (!fsSync.existsSync(manifestPath)) {
71+continue;
72+}
73+const manifest = JSON.parse(fsSync.readFileSync(manifestPath, "utf8")) as {
74+id?: string;
75+enabledByDefault?: boolean;
76+skills?: string[];
77+configSchema?: Record<string, unknown>;
78+};
79+plugins.push({
80+id: manifest.id ?? id,
81+origin: id === "browser" ? "bundled" : "workspace",
82+enabledByDefault: manifest.enabledByDefault,
83+channels: [],
84+providers: [],
85+cliBackends: [],
86+legacyPluginIds: [],
87+kind: [],
88+skills: manifest.skills ?? ["./skills"],
89+hooks: [],
90+ rootDir,
91+source: rootDir,
92+ manifestPath,
93+configSchema: manifest.configSchema,
94+});
95+}
96+return { plugins, diagnostics: [] };
97+}
98+99+function createWorkspacePluginMetadataSnapshot(params: {
100+workspaceDir: string;
101+config?: OpenClawConfig;
102+manifestRegistry: PluginManifestRegistry;
103+}): PluginMetadataSnapshot {
104+const policyHash = resolveInstalledPluginIndexPolicyHash(params.config);
105+return {
106+ policyHash,
107+workspaceDir: params.workspaceDir,
108+index: {
109+version: 1,
110+hostContractVersion: "test",
111+compatRegistryVersion: "test",
112+migrationVersion: 1,
113+ policyHash,
114+generatedAtMs: 1,
115+installRecords: {},
116+plugins: [],
117+diagnostics: [],
118+},
119+registryDiagnostics: [],
120+manifestRegistry: params.manifestRegistry,
121+plugins: params.manifestRegistry.plugins,
122+diagnostics: params.manifestRegistry.diagnostics,
123+byPluginId: new Map(params.manifestRegistry.plugins.map((plugin) => [plugin.id, plugin])),
124+normalizePluginId: (pluginId) => pluginId,
125+owners: {
126+channels: new Map(),
127+channelConfigs: new Map(),
128+providers: new Map(),
129+modelCatalogProviders: new Map(),
130+cliBackends: new Map(),
131+setupProviders: new Map(),
132+commandAliases: new Map(),
133+contracts: new Map(),
134+},
135+metrics: {
136+registrySnapshotMs: 0,
137+manifestRegistryMs: 0,
138+ownerMapsMs: 0,
139+totalMs: 0,
140+indexPluginCount: 0,
141+manifestPluginCount: params.manifestRegistry.plugins.length,
142+},
143+};
144+}
145+146+function setWorkspacePluginMetadataSnapshot(workspaceDir: string, config?: OpenClawConfig): void {
147+const manifestRegistry = createWorkspacePluginRegistry(workspaceDir);
148+setCurrentPluginMetadataSnapshot(
149+createWorkspacePluginMetadataSnapshot({
150+ workspaceDir,
151+ manifestRegistry,
152+ ...(config === undefined ? {} : { config }),
153+}),
154+{
155+ workspaceDir,
156+ ...(config === undefined ? {} : { config }),
157+},
158+);
159+}
160+55161function collectMatching<T>(items: readonly T[], predicate: (item: T) => boolean): T[] {
56162const matches: T[] = [];
57163for (const item of items) {
@@ -99,6 +205,7 @@ function loadTestWorkspaceSkillEntries(
99205workspaceDir: string,
100206opts?: Parameters<typeof loadWorkspaceSkillEntries>[1],
101207) {
208+setWorkspacePluginMetadataSnapshot(workspaceDir, opts?.config);
102209return loadWorkspaceSkillEntries(workspaceDir, {
103210managedSkillsDir: path.join(workspaceDir, ".managed"),
104211bundledSkillsDir: "",
@@ -115,6 +222,7 @@ beforeAll(async () => {
115222});
116223117224afterEach(async () => {
225+clearCurrentPluginMetadataSnapshot();
118226setLoggerOverride(null);
119227loggingState.rawConsole = null;
120228resetLogger();
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。