






























@@ -320,6 +320,167 @@ describe("repairMissingConfiguredPluginInstalls", () => {
320320}
321321});
322322323+it("maps a missing configured plugin install to a structured finding and dry-run effect", async () => {
324+mocks.listChannelPluginCatalogEntries.mockReturnValue([
325+{
326+id: "matrix",
327+pluginId: "matrix",
328+meta: { label: "Matrix" },
329+install: {
330+npmSpec: "@openclaw/plugin-matrix@1.2.3",
331+expectedIntegrity: "sha512-test",
332+},
333+trustedSourceLinkedOfficialInstall: true,
334+},
335+]);
336+337+const {
338+ configuredPluginInstallIssueToHealthFinding,
339+ configuredPluginInstallIssueToRepairEffect,
340+ detectConfiguredPluginInstallHealthIssues,
341+} = await import("./missing-configured-plugin-install.js");
342+const [issue] = await detectConfiguredPluginInstallHealthIssues({
343+cfg: {
344+channels: {
345+matrix: { enabled: true, homeserver: "https://matrix.example.org" },
346+},
347+},
348+env: {},
349+});
350+351+expect(mocks.installPluginFromClawHub).not.toHaveBeenCalled();
352+expect(mocks.installPluginFromNpmSpec).not.toHaveBeenCalled();
353+expect(mocks.writePersistedInstalledPluginIndexInstallRecords).not.toHaveBeenCalled();
354+expect(issue).toEqual({
355+kind: "missing-install-record",
356+pluginId: "matrix",
357+installSpec: "@openclaw/plugin-matrix@1.2.3",
358+});
359+expect(configuredPluginInstallIssueToHealthFinding(issue)).toMatchObject({
360+checkId: "core/doctor/configured-plugin-installs",
361+severity: "warning",
362+target: "matrix",
363+fixHint: "Run `openclaw doctor --fix` to install @openclaw/plugin-matrix@1.2.3.",
364+});
365+expect(configuredPluginInstallIssueToRepairEffect(issue)).toEqual({
366+kind: "package",
367+action: "would-install-configured-plugin",
368+target: "matrix",
369+dryRunSafe: false,
370+});
371+});
372+373+it("maps package-update deferrals to structured findings without installing packages", async () => {
374+const missingDiscordPath = path.resolve("/missing/discord");
375+const records = {
376+discord: {
377+source: "npm",
378+spec: "@openclaw/discord",
379+installPath: missingDiscordPath,
380+},
381+};
382+mocks.loadInstalledPluginIndexInstallRecords.mockResolvedValue(records);
383+mocks.listChannelPluginCatalogEntries.mockReturnValue([
384+{
385+id: "discord",
386+pluginId: "discord",
387+meta: { label: "Discord" },
388+install: {
389+npmSpec: "@openclaw/discord",
390+},
391+},
392+]);
393+394+const {
395+ configuredPluginInstallIssueToHealthFinding,
396+ configuredPluginInstallIssueToRepairEffect,
397+ detectConfiguredPluginInstallHealthIssues,
398+} = await import("./missing-configured-plugin-install.js");
399+const [issue] = await detectConfiguredPluginInstallHealthIssues({
400+cfg: {
401+plugins: {
402+entries: {
403+discord: { enabled: true },
404+},
405+},
406+channels: {
407+discord: { enabled: true },
408+},
409+},
410+env: {
411+OPENCLAW_UPDATE_IN_PROGRESS: "1",
412+OPENCLAW_UPDATE_DEFER_CONFIGURED_PLUGIN_INSTALL_REPAIR: "1",
413+},
414+});
415+416+expect(mocks.installPluginFromClawHub).not.toHaveBeenCalled();
417+expect(mocks.installPluginFromNpmSpec).not.toHaveBeenCalled();
418+expect(issue).toEqual({
419+kind: "deferred-package-manager-repair",
420+pluginId: "discord",
421+installPath: missingDiscordPath,
422+});
423+expect(configuredPluginInstallIssueToHealthFinding(issue)).toMatchObject({
424+checkId: "core/doctor/configured-plugin-installs",
425+severity: "warning",
426+path: missingDiscordPath,
427+target: "discord",
428+});
429+expect(configuredPluginInstallIssueToRepairEffect(issue)).toEqual({
430+kind: "package",
431+action: "would-defer-configured-plugin-install-repair",
432+target: "discord",
433+dryRunSafe: true,
434+});
435+});
436+437+it("reports one finding when a configured plugin record points at a missing package", async () => {
438+const missingDiscordPath = path.resolve("/missing/discord");
439+const records = {
440+discord: {
441+source: "npm",
442+spec: "@openclaw/discord",
443+installPath: missingDiscordPath,
444+},
445+};
446+mocks.loadInstalledPluginIndexInstallRecords.mockResolvedValue(records);
447+mocks.listChannelPluginCatalogEntries.mockReturnValue([
448+{
449+id: "discord",
450+pluginId: "discord",
451+meta: { label: "Discord" },
452+install: {
453+npmSpec: "@openclaw/discord",
454+},
455+},
456+]);
457+458+const { detectConfiguredPluginInstallHealthIssues } =
459+await import("./missing-configured-plugin-install.js");
460+const issues = await detectConfiguredPluginInstallHealthIssues({
461+cfg: {
462+plugins: {
463+entries: {
464+discord: { enabled: true },
465+},
466+},
467+channels: {
468+discord: { enabled: true },
469+},
470+},
471+env: {},
472+});
473+474+expect(issues).toEqual([
475+{
476+kind: "missing-installed-payload",
477+pluginId: "discord",
478+installPath: missingDiscordPath,
479+installSpec: "@openclaw/discord",
480+},
481+]);
482+});
483+323484it("installs a missing configured OpenClaw channel plugin from npm by default", async () => {
324485mocks.listChannelPluginCatalogEntries.mockReturnValue([
325486{
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。