






















@@ -0,0 +1,145 @@
1+import { beforeEach, describe, expect, it, vi } from "vitest";
2+import type { InstalledPluginIndex } from "../plugins/installed-plugin-index.js";
3+import type { PluginManifestRegistry } from "../plugins/manifest-registry.js";
4+5+const readPersistedInstalledPluginIndexMock = vi.fn();
6+const loadPluginManifestRegistryForInstalledIndexMock = vi.fn();
7+8+vi.mock("../plugins/installed-plugin-index-store.js", () => ({
9+readPersistedInstalledPluginIndex: (...args: unknown[]) =>
10+readPersistedInstalledPluginIndexMock(...args),
11+}));
12+13+vi.mock("../plugins/manifest-registry-installed.js", () => ({
14+loadPluginManifestRegistryForInstalledIndex: (...args: unknown[]) =>
15+loadPluginManifestRegistryForInstalledIndexMock(...args),
16+}));
17+18+const { listPersistedBundledPluginLocationBridges } = await import("./plugins-location-bridges.js");
19+20+function makeIndex(record: InstalledPluginIndex["plugins"][number]): InstalledPluginIndex {
21+return {
22+version: 1,
23+hostContractVersion: "2026.5.2",
24+compatRegistryVersion: "test",
25+migrationVersion: 1,
26+policyHash: "test",
27+generatedAtMs: 1,
28+refreshReason: "test",
29+installRecords: {},
30+plugins: [record],
31+};
32+}
33+34+function makeRegistry(pluginId: string): PluginManifestRegistry {
35+return {
36+plugins: [
37+{
38+id: pluginId,
39+name: pluginId,
40+rootDir: `/app/dist/extensions/${pluginId}`,
41+source: `/app/dist/extensions/${pluginId}/index.js`,
42+origin: "bundled",
43+channels: [pluginId],
44+providers: [],
45+cliBackends: [],
46+syntheticAuthRefs: [],
47+nonSecretAuthMarkers: [],
48+skills: [],
49+settingsFiles: [],
50+hooks: [],
51+configContracts: [],
52+activation: {},
53+startup: {},
54+packageInstall: {
55+clawhubSpec: `clawhub:@openclaw/${pluginId}`,
56+npmSpec: `@openclaw/${pluginId}`,
57+defaultChoice: "clawhub",
58+},
59+},
60+],
61+diagnostics: [],
62+} as unknown as PluginManifestRegistry;
63+}
64+65+describe("listPersistedBundledPluginLocationBridges", () => {
66+beforeEach(() => {
67+readPersistedInstalledPluginIndexMock.mockReset();
68+loadPluginManifestRegistryForInstalledIndexMock.mockReset();
69+});
70+71+it("keeps persisted bundled relocations npm-first for launch", async () => {
72+readPersistedInstalledPluginIndexMock.mockResolvedValue(
73+makeIndex({
74+pluginId: "diagnostics-otel",
75+manifestPath: "/app/dist/extensions/diagnostics-otel/openclaw.plugin.json",
76+manifestHash: "hash",
77+source: "/app/dist/extensions/diagnostics-otel/index.js",
78+rootDir: "/app/dist/extensions/diagnostics-otel",
79+origin: "bundled",
80+enabled: true,
81+startup: {},
82+compat: [],
83+packageInstall: {
84+defaultChoice: "clawhub",
85+clawhub: {
86+spec: "clawhub:@openclaw/diagnostics-otel",
87+packageName: "@openclaw/diagnostics-otel",
88+exactVersion: false,
89+},
90+npm: {
91+spec: "@openclaw/diagnostics-otel",
92+packageName: "@openclaw/diagnostics-otel",
93+selectorKind: "none",
94+exactVersion: false,
95+pinState: "floating-without-integrity",
96+},
97+warnings: [],
98+},
99+}),
100+);
101+loadPluginManifestRegistryForInstalledIndexMock.mockReturnValue(
102+makeRegistry("diagnostics-otel"),
103+);
104+105+await expect(listPersistedBundledPluginLocationBridges({})).resolves.toEqual([
106+{
107+bundledPluginId: "diagnostics-otel",
108+pluginId: "diagnostics-otel",
109+preferredSource: "npm",
110+npmSpec: "@openclaw/diagnostics-otel",
111+channelIds: ["diagnostics-otel"],
112+},
113+]);
114+});
115+116+it("does not create a relocation bridge without npm metadata", async () => {
117+readPersistedInstalledPluginIndexMock.mockResolvedValue(
118+makeIndex({
119+pluginId: "diagnostics-otel",
120+manifestPath: "/app/dist/extensions/diagnostics-otel/openclaw.plugin.json",
121+manifestHash: "hash",
122+source: "/app/dist/extensions/diagnostics-otel/index.js",
123+rootDir: "/app/dist/extensions/diagnostics-otel",
124+origin: "bundled",
125+enabled: true,
126+startup: {},
127+compat: [],
128+packageInstall: {
129+defaultChoice: "clawhub",
130+clawhub: {
131+spec: "clawhub:@openclaw/diagnostics-otel",
132+packageName: "@openclaw/diagnostics-otel",
133+exactVersion: false,
134+},
135+warnings: [],
136+},
137+}),
138+);
139+loadPluginManifestRegistryForInstalledIndexMock.mockReturnValue(
140+makeRegistry("diagnostics-otel"),
141+);
142+143+await expect(listPersistedBundledPluginLocationBridges({})).resolves.toEqual([]);
144+});
145+});
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。