

























@@ -32,9 +32,10 @@ vi.mock("../plugins/install.js", () => ({
3232}));
33333434const enablePluginInConfig = vi.hoisted(() =>
35-vi.fn<(cfg: OpenClawConfig, pluginId: string) => PluginEnableResult>((cfg) => ({
35+vi.fn<(cfg: OpenClawConfig, pluginId: string) => PluginEnableResult>((cfg, pluginId) => ({
3636config: cfg,
3737enabled: true,
38+ pluginId,
3839})),
3940);
4041vi.mock("../plugins/enable.js", () => ({
@@ -342,6 +343,7 @@ describe("ensureOnboardingPluginInstalled", () => {
342343enablePluginInConfig.mockReturnValueOnce({
343344config: {},
344345enabled: false,
346+pluginId: "demo",
345347reason: "blocked by allowlist",
346348});
347349const note = vi.fn(async () => {});
@@ -484,65 +486,62 @@ describe("ensureOnboardingPluginInstalled", () => {
484486});
485487486488it("hides the npm download option for bundled plugins so the menu matches non-npm channels", async () => {
487-await withTempDir(
488-{ prefix: "openclaw-onboarding-install-bundled-prompt-" },
489-async (temp) => {
490-const bundledDir = path.join(temp, "dist", "extensions", "tlon");
491-await fs.mkdir(bundledDir, { recursive: true });
492-const realBundledDir = await fs.realpath(bundledDir);
493-// Both code paths that surface a bundled plugin to the install
494-// pipeline must agree on the local path: the catalog-driven
495-// resolver (used when an npm spec is present) and the pluginId
496-// fallback. We stub both so the prompt sees a stable bundled path.
497-resolveBundledInstallPlanForCatalogEntry.mockReturnValue({
498-bundledSource: { localPath: realBundledDir },
499-});
500-findBundledPluginSourceInMap.mockReturnValue({ localPath: realBundledDir });
489+await withTempDir({ prefix: "openclaw-onboarding-install-bundled-prompt-" }, async (temp) => {
490+const bundledDir = path.join(temp, "dist", "extensions", "tlon");
491+await fs.mkdir(bundledDir, { recursive: true });
492+const realBundledDir = await fs.realpath(bundledDir);
493+// Both code paths that surface a bundled plugin to the install
494+// pipeline must agree on the local path: the catalog-driven
495+// resolver (used when an npm spec is present) and the pluginId
496+// fallback. We stub both so the prompt sees a stable bundled path.
497+resolveBundledInstallPlanForCatalogEntry.mockReturnValue({
498+bundledSource: { localPath: realBundledDir },
499+});
500+findBundledPluginSourceInMap.mockReturnValue({ localPath: realBundledDir });
501501502- let captured:
503- | {
504- message: string;
505- options: Array<{ value: "npm" | "local" | "skip"; label: string; hint?: string }>;
506- initialValue: "npm" | "local" | "skip";
507- }
508- | undefined;
502+let captured:
503+| {
504+message: string;
505+options: Array<{ value: "npm" | "local" | "skip"; label: string; hint?: string }>;
506+initialValue: "npm" | "local" | "skip";
507+}
508+| undefined;
509509510-await ensureOnboardingPluginInstalled({
511-cfg: {},
512-entry: {
513-pluginId: "tlon",
514-label: "Tlon",
515-install: {
516-npmSpec: "@openclaw/tlon",
517-defaultChoice: "npm",
518-},
510+await ensureOnboardingPluginInstalled({
511+cfg: {},
512+entry: {
513+pluginId: "tlon",
514+label: "Tlon",
515+install: {
516+npmSpec: "@openclaw/tlon",
517+defaultChoice: "npm",
519518},
520-prompter: {
521-select: vi.fn(async (input) => {
522-captured = input;
523-return "skip";
524-}),
525-} as never,
526-runtime: {} as never,
527-});
519+},
520+prompter: {
521+select: vi.fn(async (input) => {
522+captured = input;
523+return "skip";
524+}),
525+} as never,
526+runtime: {} as never,
527+});
528528529-expect(captured).toBeDefined();
530-// "Download from npm (@openclaw/tlon)" must NOT appear: the bundled
531-// copy is what gets enabled, so the npm hint would only confuse
532-// users into thinking the plugin is missing.
533-expect(captured?.options).toEqual([
534-{
535-value: "local",
536-label: "Use local plugin path",
537-hint: realBundledDir,
538-},
539-{ value: "skip", label: "Skip for now" },
540-]);
541-expect(captured?.initialValue).toBe("local");
542-findBundledPluginSourceInMap.mockReset();
543-resolveBundledInstallPlanForCatalogEntry.mockReset();
544-},
545-);
529+expect(captured).toBeDefined();
530+// "Download from npm (@openclaw/tlon)" must NOT appear: the bundled
531+// copy is what gets enabled, so the npm hint would only confuse
532+// users into thinking the plugin is missing.
533+expect(captured?.options).toEqual([
534+{
535+value: "local",
536+label: "Use local plugin path",
537+hint: realBundledDir,
538+},
539+{ value: "skip", label: "Skip for now" },
540+]);
541+expect(captured?.initialValue).toBe("local");
542+findBundledPluginSourceInMap.mockReset();
543+resolveBundledInstallPlanForCatalogEntry.mockReset();
544+});
546545});
547546548547it("enables bundled plugins without adding their bundled directory as a local install", async () => {
@@ -564,6 +563,7 @@ describe("ensureOnboardingPluginInstalled", () => {
564563},
565564},
566565enabled: true,
566+pluginId: "discord",
567567});
568568569569const result = await ensureOnboardingPluginInstalled({
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。