
























@@ -1,3 +1,4 @@
1+import { spawnSync } from "node:child_process";
12import fs from "node:fs";
23import path from "node:path";
34@@ -9,36 +10,95 @@ export function readIfExists(filePath) {
910}
1011}
111212-export function collectBundledPluginSources(params = {}) {
13-const repoRoot = path.resolve(params.repoRoot ?? process.cwd());
13+function collectTrackedBundledPluginSourceCandidates(repoRoot) {
14+const result = spawnSync(
15+"git",
16+[
17+"ls-files",
18+"--",
19+":(glob)extensions/*/openclaw.plugin.json",
20+":(glob)extensions/*/package.json",
21+],
22+{
23+cwd: repoRoot,
24+encoding: "utf8",
25+stdio: ["ignore", "pipe", "ignore"],
26+},
27+);
28+if (result.status !== 0) {
29+return null;
30+}
31+32+const candidatesByDir = new Map();
33+for (const rawLine of result.stdout.split("\n")) {
34+const line = rawLine.trim().replaceAll("\\", "/");
35+const match = /^extensions\/([^/]+)\/(openclaw\.plugin\.json|package\.json)$/u.exec(line);
36+if (!match?.[1] || !match[2]) {
37+continue;
38+}
39+const current = candidatesByDir.get(match[1]) ?? {
40+dirName: match[1],
41+manifestPath: null,
42+packageJsonPath: null,
43+pluginDir: path.join(repoRoot, "extensions", match[1]),
44+};
45+if (match[2] === "openclaw.plugin.json") {
46+current.manifestPath = path.join(repoRoot, line);
47+} else {
48+current.packageJsonPath = path.join(repoRoot, line);
49+}
50+candidatesByDir.set(match[1], current);
51+}
52+53+return [...candidatesByDir.values()].toSorted((left, right) =>
54+left.dirName.localeCompare(right.dirName),
55+);
56+}
57+58+function collectBundledPluginSourceCandidatesFromDirectory(repoRoot) {
1459const extensionsRoot = path.join(repoRoot, "extensions");
1560if (!fs.existsSync(extensionsRoot)) {
1661return [];
1762}
186364+return fs
65+.readdirSync(extensionsRoot, { withFileTypes: true })
66+.filter((dirent) => dirent.isDirectory())
67+.map((dirent) => {
68+const pluginDir = path.join(extensionsRoot, dirent.name);
69+const manifestPath = path.join(pluginDir, "openclaw.plugin.json");
70+const packageJsonPath = path.join(pluginDir, "package.json");
71+return {
72+dirName: dirent.name,
73+manifestPath: fs.existsSync(manifestPath) ? manifestPath : null,
74+packageJsonPath: fs.existsSync(packageJsonPath) ? packageJsonPath : null,
75+ pluginDir,
76+};
77+})
78+.toSorted((left, right) => left.dirName.localeCompare(right.dirName));
79+}
80+81+export function collectBundledPluginSources(params = {}) {
82+const repoRoot = path.resolve(params.repoRoot ?? process.cwd());
1983const requirePackageJson = params.requirePackageJson === true;
2084const entries = [];
21-for (const dirent of fs.readdirSync(extensionsRoot, { withFileTypes: true })) {
22-if (!dirent.isDirectory()) {
23-continue;
24-}
25-26-const pluginDir = path.join(extensionsRoot, dirent.name);
27-const manifestPath = path.join(pluginDir, "openclaw.plugin.json");
28-const packageJsonPath = path.join(pluginDir, "package.json");
29-if (!fs.existsSync(manifestPath)) {
85+const candidates =
86+collectTrackedBundledPluginSourceCandidates(repoRoot) ??
87+collectBundledPluginSourceCandidatesFromDirectory(repoRoot);
88+for (const { dirName, manifestPath, packageJsonPath, pluginDir } of candidates) {
89+if (!manifestPath) {
3090continue;
3191}
32-if (requirePackageJson && !fs.existsSync(packageJsonPath)) {
92+if (requirePackageJson && !packageJsonPath) {
3393continue;
3494}
35953696entries.push({
37-dirName: dirent.name,
97+ dirName,
3898 pluginDir,
3999 manifestPath,
40100manifest: JSON.parse(fs.readFileSync(manifestPath, "utf8")),
41- ...(fs.existsSync(packageJsonPath)
101+ ...(packageJsonPath
42102 ? {
43103 packageJsonPath,
44104packageJson: JSON.parse(fs.readFileSync(packageJsonPath, "utf8")),
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。