




















@@ -1902,7 +1902,7 @@ describe("updateNpmInstalledPlugins", () => {
19021902});
19031903});
190419041905-it("falls through to npm reinstall when metadata probing fails", async () => {
1905+it("falls through to npm reinstall when metadata probing fails for valid specs", async () => {
19061906const warn = vi.fn();
19071907const installPath = createInstalledPackageDir({
19081908name: "@martian-engineering/lossless-claw",
@@ -1937,6 +1937,107 @@ describe("updateNpmInstalledPlugins", () => {
19371937expect(installPluginFromNpmSpecMock).toHaveBeenCalledTimes(1);
19381938});
193919391940+it("records range metadata probing failures without falling through to npm reinstall", async () => {
1941+const warn = vi.fn();
1942+const installPath = createInstalledPackageDir({
1943+name: "@martian-engineering/lossless-claw",
1944+version: "0.9.0",
1945+});
1946+runCommandWithTimeoutMock.mockResolvedValueOnce({
1947+code: 1,
1948+stdout: "",
1949+stderr: "registry timeout",
1950+});
1951+const result = await updateNpmInstalledPlugins({
1952+config: createNpmInstallConfig({
1953+pluginId: "lossless-claw",
1954+spec: "@martian-engineering/lossless-claw@^0.9.0",
1955+ installPath,
1956+}),
1957+pluginIds: ["lossless-claw"],
1958+logger: { warn },
1959+});
1960+1961+expect(warn).not.toHaveBeenCalled();
1962+expect(installPluginFromNpmSpecMock).not.toHaveBeenCalled();
1963+expect(result.changed).toBe(false);
1964+expect(result.outcomes).toEqual([
1965+{
1966+pluginId: "lossless-claw",
1967+status: "error",
1968+message: "Failed to check lossless-claw: npm view failed: registry timeout",
1969+},
1970+]);
1971+});
1972+1973+it("uses failure cleanup when metadata probing fails and disableOnFailure is enabled", async () => {
1974+const warn = vi.fn();
1975+const installPath = createInstalledPackageDir({
1976+name: "@martian-engineering/lossless-claw",
1977+version: "0.9.0",
1978+});
1979+runCommandWithTimeoutMock.mockResolvedValueOnce({
1980+code: 1,
1981+stdout: "",
1982+stderr: "registry timeout",
1983+});
1984+1985+const result = await updateNpmInstalledPlugins({
1986+config: {
1987+plugins: {
1988+allow: ["lossless-claw", "keep"],
1989+deny: ["lossless-claw", "blocked"],
1990+slots: {
1991+memory: "lossless-claw",
1992+contextEngine: "lossless-claw",
1993+},
1994+entries: {
1995+"lossless-claw": {
1996+enabled: true,
1997+config: { preserved: true },
1998+},
1999+},
2000+installs: {
2001+"lossless-claw": {
2002+source: "npm",
2003+spec: "@martian-engineering/lossless-claw@^0.9.0",
2004+ installPath,
2005+resolvedName: "@martian-engineering/lossless-claw",
2006+resolvedVersion: "0.9.0",
2007+resolvedSpec: "@martian-engineering/lossless-claw@0.9.0",
2008+},
2009+},
2010+},
2011+},
2012+pluginIds: ["lossless-claw"],
2013+disableOnFailure: true,
2014+logger: { warn },
2015+});
2016+2017+const message =
2018+'Disabled "lossless-claw" after plugin update failure; OpenClaw will continue without it. Failed to check lossless-claw: npm view failed: registry timeout';
2019+expect(warn).toHaveBeenCalledWith(message);
2020+expect(installPluginFromNpmSpecMock).not.toHaveBeenCalled();
2021+expect(result.changed).toBe(true);
2022+expect(result.config.plugins?.entries?.["lossless-claw"]).toEqual({
2023+enabled: false,
2024+config: { preserved: true },
2025+});
2026+expect(result.config.plugins?.allow).toEqual(["keep"]);
2027+expect(result.config.plugins?.deny).toEqual(["blocked"]);
2028+expect(result.config.plugins?.slots).toEqual({
2029+memory: "memory-core",
2030+contextEngine: "legacy",
2031+});
2032+expect(result.outcomes).toEqual([
2033+{
2034+pluginId: "lossless-claw",
2035+status: "skipped",
2036+ message,
2037+},
2038+]);
2039+});
2040+19402041it.each([
19412042{
19422043source: "npm",
@@ -3864,6 +3965,7 @@ describe("updateNpmInstalledPlugins", () => {
38643965it("reuses the recorded managed extensions root when updating external plugins", async () => {
38653966const installPath = "/var/openclaw/extensions/demo";
38663967const extensionsDir = "/var/openclaw/extensions";
3968+const expectedExtensionsDir = path.resolve(extensionsDir);
38673969installPluginFromNpmSpecMock.mockResolvedValue(
38683970createSuccessfulNpmUpdateResult({
38693971pluginId: "demo",
@@ -3947,7 +4049,6 @@ describe("updateNpmInstalledPlugins", () => {
39474049pluginIds: ["demo"],
39484050});
394940513950-const expectedExtensionsDir = path.resolve(extensionsDir);
39514052expect(npmInstallCall()?.extensionsDir).toBe(expectedExtensionsDir);
39524053expect(clawHubInstallCall()?.extensionsDir).toBe(expectedExtensionsDir);
39534054expect(marketplaceInstallCall()?.extensionsDir).toBe(expectedExtensionsDir);
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。