





















@@ -1209,6 +1209,67 @@ describe("repairMissingConfiguredPluginInstalls", () => {
12091209});
12101210});
121112111212+it("prefers npm over ClawHub during post-core repair", async () => {
1213+const npmRoot = makeTempDir();
1214+const packageDir = path.join(npmRoot, "node_modules", "@openclaw", "whatsapp");
1215+mocks.resolveDefaultPluginNpmDir.mockReturnValue(npmRoot);
1216+mocks.listChannelPluginCatalogEntries.mockReturnValue([
1217+{
1218+id: "whatsapp",
1219+pluginId: "whatsapp",
1220+meta: { label: "WhatsApp" },
1221+install: {
1222+clawhubSpec: "clawhub:@openclaw/whatsapp",
1223+npmSpec: "@openclaw/whatsapp",
1224+},
1225+},
1226+]);
1227+mocks.installPluginFromClawHub.mockResolvedValue({
1228+ok: false,
1229+error: 'Plugin "@openclaw/whatsapp" requires plugin API >=2026.5.18.',
1230+});
1231+mocks.installPluginFromNpmSpec.mockResolvedValue({
1232+ok: true,
1233+pluginId: "whatsapp",
1234+targetDir: packageDir,
1235+version: "1.2.3",
1236+npmResolution: {
1237+name: "@openclaw/whatsapp",
1238+version: "1.2.3",
1239+resolvedSpec: "@openclaw/whatsapp@1.2.3",
1240+integrity: "sha512-whatsapp",
1241+resolvedAt: "2026-05-01T00:00:00.000Z",
1242+},
1243+});
1244+1245+const { repairMissingConfiguredPluginInstalls } =
1246+await import("./missing-configured-plugin-install.js");
1247+const result = await repairMissingConfiguredPluginInstalls({
1248+cfg: {
1249+plugins: {
1250+entries: {
1251+whatsapp: { enabled: true },
1252+},
1253+},
1254+channels: {
1255+whatsapp: { enabled: true },
1256+},
1257+},
1258+env: {
1259+OPENCLAW_UPDATE_POST_CORE_CONVERGENCE: "1",
1260+},
1261+});
1262+1263+expect(mocks.installPluginFromClawHub).not.toHaveBeenCalled();
1264+expectRecordFields(mockCallArg(mocks.installPluginFromNpmSpec), {
1265+spec: expectedNpmInstallSpec("@openclaw/whatsapp"),
1266+npmDir: npmRoot,
1267+mode: "install",
1268+});
1269+expect(result.warnings).toEqual([]);
1270+expect(result.records.whatsapp?.installPath).toBe(packageDir);
1271+});
1272+12121273it("repairs missing external payload during post-core convergence even with OPENCLAW_UPDATE_IN_PROGRESS=1", async () => {
12131274const records = {
12141275discord: {
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。