























@@ -19,6 +19,95 @@ vi.mock("../../plugins/bundled-dir.js", async (importOriginal) => {
1919};
2020});
212122+vi.mock("../../plugins/jiti-loader-cache.js", async (importOriginal) => {
23+const actual = await importOriginal<typeof import("../../plugins/jiti-loader-cache.js")>();
24+const { createRequire } = await import("node:module");
25+const require = createRequire(import.meta.url);
26+27+type LoaderConfig = {
28+plugins?: {
29+load?: { paths?: unknown };
30+};
31+};
32+type LoaderParams = {
33+config?: LoaderConfig;
34+onlyPluginIds?: readonly string[];
35+workspaceDir?: string;
36+};
37+38+function readJson(filePath: string): unknown {
39+return JSON.parse(fs.readFileSync(filePath, "utf-8"));
40+}
41+42+function isRecord(value: unknown): value is Record<string, unknown> {
43+return Boolean(value && typeof value === "object" && !Array.isArray(value));
44+}
45+46+function listCandidatePluginDirs(params: LoaderParams): string[] {
47+const paths = params.config?.plugins?.load?.paths;
48+const explicitPaths = Array.isArray(paths)
49+ ? paths.filter((entry): entry is string => typeof entry === "string")
50+ : [];
51+const workspaceExtensionsDir = params.workspaceDir
52+ ? path.join(params.workspaceDir, ".openclaw", "extensions")
53+ : undefined;
54+if (!workspaceExtensionsDir || !fs.existsSync(workspaceExtensionsDir)) {
55+return explicitPaths;
56+}
57+return explicitPaths.concat(
58+fs
59+.readdirSync(workspaceExtensionsDir, { withFileTypes: true })
60+.filter((entry) => entry.isDirectory())
61+.map((entry) => path.join(workspaceExtensionsDir, entry.name)),
62+);
63+}
64+65+function loadOpenClawPlugins(params: LoaderParams) {
66+const onlyPluginIds = new Set(params.onlyPluginIds ?? []);
67+const channelSetups = listCandidatePluginDirs(params).flatMap((pluginDir) => {
68+const manifestPath = path.join(pluginDir, "openclaw.plugin.json");
69+const packagePath = path.join(pluginDir, "package.json");
70+if (!fs.existsSync(manifestPath) || !fs.existsSync(packagePath)) {
71+return [];
72+}
73+const manifest = readJson(manifestPath);
74+if (!isRecord(manifest) || typeof manifest.id !== "string") {
75+return [];
76+}
77+if (onlyPluginIds.size > 0 && !onlyPluginIds.has(manifest.id)) {
78+return [];
79+}
80+const packageJson = readJson(packagePath);
81+const openclaw = isRecord(packageJson) ? packageJson.openclaw : undefined;
82+const setupEntry = isRecord(openclaw) ? openclaw.setupEntry : undefined;
83+if (typeof setupEntry !== "string") {
84+return [];
85+}
86+const setupModule = require(path.join(pluginDir, setupEntry));
87+const entry = setupModule.default ?? setupModule;
88+const plugin = entry.plugin;
89+return plugin ? [{ pluginId: manifest.id, plugin }] : [];
90+});
91+return { channelSetups };
92+}
93+94+return {
95+ ...actual,
96+getCachedPluginJitiLoader: ((params) => {
97+const actualLoader = actual.getCachedPluginJitiLoader(params);
98+return ((modulePath: string) => {
99+if (
100+modulePath.endsWith("/plugins/loader.js") ||
101+modulePath.endsWith("/plugins/loader.ts")
102+) {
103+return { loadOpenClawPlugins };
104+}
105+return actualLoader(modulePath);
106+}) as ReturnType<typeof actual.getCachedPluginJitiLoader>;
107+}) satisfies typeof actual.getCachedPluginJitiLoader,
108+};
109+});
110+22111function writeExternalSetupChannelPlugin(
23112options: {
24113setupEntry?: boolean;
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。