




























@@ -470,16 +470,35 @@ describe("discoverOpenClawPlugins", () => {
470470const stateDir = makeTempDir();
471471const workspaceDir = path.join(stateDir, "workspace");
472472473-const globalExt = path.join(stateDir, "extensions");
474-mkdirSafe(globalExt);
475-fs.writeFileSync(path.join(globalExt, "alpha.ts"), "export default function () {}", "utf-8");
473+createPackagePluginWithEntry({
474+packageDir: path.join(stateDir, "extensions", "alpha"),
475+packageName: "@openclaw/alpha",
476+pluginId: "alpha",
477+});
478+createPackagePluginWithEntry({
479+packageDir: path.join(workspaceDir, ".openclaw", "extensions", "beta"),
480+packageName: "@openclaw/beta",
481+pluginId: "beta",
482+});
476483484+const { candidates } = await discoverWithStateDir(stateDir, { workspaceDir });
485+expectCandidateIds(candidates, { includes: ["alpha", "beta"] });
486+});
487+488+it("ignores standalone helper scripts in auto-discovered extension roots", async () => {
489+const stateDir = makeTempDir();
490+const workspaceDir = path.join(stateDir, "workspace");
491+const globalExt = path.join(stateDir, "extensions");
477492const workspaceExt = path.join(workspaceDir, ".openclaw", "extensions");
493+mkdirSafe(globalExt);
478494mkdirSafe(workspaceExt);
479-fs.writeFileSync(path.join(workspaceExt, "beta.ts"), "export default function () {}", "utf-8");
495+fs.writeFileSync(path.join(globalExt, "my-helper.mjs"), "export default {}", "utf-8");
496+fs.writeFileSync(path.join(workspaceExt, "workspace-helper.js"), "export default {}", "utf-8");
480497481-const { candidates } = await discoverWithStateDir(stateDir, { workspaceDir });
482-expectCandidateIds(candidates, { includes: ["alpha", "beta"] });
498+const { candidates, diagnostics } = await discoverWithStateDir(stateDir, { workspaceDir });
499+500+expectCandidateIds(candidates, { excludes: ["my-helper", "workspace-helper"] });
501+expect(diagnostics).toStrictEqual([]);
483502});
484503485504it("warns without blocking when a plugin requires a missing plugin", async () => {
@@ -637,9 +656,11 @@ describe("discoverOpenClawPlugins", () => {
637656const stateDir = makeTempDir();
638657const homeDir = makeTempDir();
639658const workspaceRoot = path.join(homeDir, "workspace");
640-const workspaceExt = path.join(workspaceRoot, ".openclaw", "extensions");
641-mkdirSafe(workspaceExt);
642-fs.writeFileSync(path.join(workspaceExt, "tilde-workspace.ts"), "export default {}", "utf-8");
659+createPackagePluginWithEntry({
660+packageDir: path.join(workspaceRoot, ".openclaw", "extensions", "tilde-workspace"),
661+packageName: "@openclaw/tilde-workspace",
662+pluginId: "tilde-workspace",
663+});
643664644665const result = discoverOpenClawPlugins({
645666workspaceDir: "~/workspace",
@@ -722,7 +743,11 @@ describe("discoverOpenClawPlugins", () => {
722743path.join(bundledDir, "music-generation-providers.live.test.ts"),
723744"export default {}",
724745);
725-writeStandalonePlugin(path.join(bundledDir, "real-plugin.ts"), "export default {}");
746+createPackagePluginWithEntry({
747+packageDir: path.join(bundledDir, "real-plugin"),
748+packageName: "@openclaw/real-plugin",
749+pluginId: "real-plugin",
750+});
726751727752const { candidates, diagnostics } = withOpenClawPackageArgv(packageRoot, () =>
728753discoverOpenClawPlugins({
@@ -2259,11 +2284,13 @@ describe("discoverOpenClawPlugins", () => {
2259228422602285it.runIf(process.platform !== "win32")("blocks world-writable plugin paths", async () => {
22612286const stateDir = makeTempDir();
2262-const globalExt = path.join(stateDir, "extensions");
2263-mkdirSafe(globalExt);
2264-const pluginPath = path.join(globalExt, "world-open.ts");
2265-fs.writeFileSync(pluginPath, "export default function () {}", "utf-8");
2266-fs.chmodSync(pluginPath, 0o777);
2287+const pluginDir = path.join(stateDir, "extensions", "world-open");
2288+createPackagePluginWithEntry({
2289+packageDir: pluginDir,
2290+packageName: "@openclaw/world-open",
2291+pluginId: "world-open",
2292+});
2293+fs.chmodSync(pluginDir, 0o777);
2267229422682295const result = await discoverWithStateDir(stateDir, {});
22692296@@ -2305,13 +2332,11 @@ describe("discoverOpenClawPlugins", () => {
23052332"blocks suspicious ownership when uid mismatch is detected",
23062333async () => {
23072334const stateDir = makeTempDir();
2308-const globalExt = path.join(stateDir, "extensions");
2309-mkdirSafe(globalExt);
2310-fs.writeFileSync(
2311-path.join(globalExt, "owner-mismatch.ts"),
2312-"export default function () {}",
2313-"utf-8",
2314-);
2335+createPackagePluginWithEntry({
2336+packageDir: path.join(stateDir, "extensions", "owner-mismatch"),
2337+packageName: "@openclaw/owner-mismatch",
2338+pluginId: "owner-mismatch",
2339+});
2315234023162341const actualUid = (process as NodeJS.Process & { getuid: () => number }).getuid();
23172342const result = await discoverWithStateDir(stateDir, { ownershipUid: actualUid + 1 });
@@ -2393,16 +2418,18 @@ describe("discoverOpenClawPlugins", () => {
2393241823942419it("reflects plugin root changes on the next discovery call", () => {
23952420const stateDir = makeTempDir();
2396-const globalExt = path.join(stateDir, "extensions");
2397-mkdirSafe(globalExt);
2398-const pluginPath = path.join(globalExt, "fresh.ts");
2399-fs.writeFileSync(pluginPath, "export default function () {}", "utf-8");
2421+const pluginDir = path.join(stateDir, "extensions", "fresh");
2422+createPackagePluginWithEntry({
2423+packageDir: pluginDir,
2424+packageName: "@openclaw/fresh",
2425+pluginId: "fresh",
2426+});
2400242724012428const env = buildDiscoveryEnvWithOverrides(stateDir);
24022429const first = discoverWithEnv({ env });
24032430expect(first.candidates.map((candidate) => candidate.idHint)).toContain("fresh");
240424312405-fs.rmSync(pluginPath, { force: true });
2432+fs.rmSync(pluginDir, { recursive: true, force: true });
2406243324072434const second = discoverWithEnv({ env });
24082435expect(second.candidates.map((candidate) => candidate.idHint)).not.toContain("fresh");
@@ -2465,8 +2492,16 @@ describe("discoverOpenClawPlugins", () => {
24652492setup: () => {
24662493const stateDirA = makeTempDir();
24672494const stateDirB = makeTempDir();
2468-writeStandalonePlugin(path.join(stateDirA, "extensions", "alpha.ts"));
2469-writeStandalonePlugin(path.join(stateDirB, "extensions", "beta.ts"));
2495+createPackagePluginWithEntry({
2496+packageDir: path.join(stateDirA, "extensions", "alpha"),
2497+packageName: "@openclaw/alpha",
2498+pluginId: "alpha",
2499+});
2500+createPackagePluginWithEntry({
2501+packageDir: path.join(stateDirB, "extensions", "beta"),
2502+packageName: "@openclaw/beta",
2503+pluginId: "beta",
2504+});
24702505return {
24712506first: discoverWithEnv({ env: buildDiscoveryEnvWithOverrides(stateDirA) }),
24722507second: discoverWithEnv({ env: buildDiscoveryEnvWithOverrides(stateDirB) }),
@@ -2514,6 +2549,20 @@ describe("discoverOpenClawPlugins", () => {
25142549assert(first, second);
25152550});
251625512552+it("discovers standalone files from configured load-path directories", () => {
2553+const stateDir = makeTempDir();
2554+const pluginDir = path.join(stateDir, "plugins");
2555+const pluginPath = path.join(pluginDir, "alpha.ts");
2556+writeStandalonePlugin(pluginPath, "export default {}");
2557+2558+const result = discoverWithEnv({
2559+extraPaths: [pluginDir],
2560+env: buildDiscoveryEnvWithOverrides(stateDir),
2561+});
2562+2563+expectCandidateSource(result.candidates, "alpha", pluginPath);
2564+});
2565+25172566it("preserves configured load-path order", () => {
25182567const stateDir = makeTempDir();
25192568const pluginA = path.join(stateDir, "plugins", "alpha.ts");
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。