fix(plugins): clarify unavailable clawhub artifacts

This commit is contained in:
Vincent Koc
2026-05-02 14:06:36 -07:00
parent fd83c49cff
commit cd710bcfb2
3 changed files with 67 additions and 1 deletions

View File

@@ -12,6 +12,7 @@ Docs: https://docs.openclaw.ai
### Fixes
- Plugins/ClawHub: explain unavailable explicit ClawHub ClawPack artifact downloads with a temporary npm install hint while ClawHub artifact routing rolls out. Thanks @vincentkoc.
- Onboarding/search: install official external web-search plugins such as Brave before saving provider config, and make doctor repair reconcile selected external search providers whose npm payload is missing. Thanks @vincentkoc.
- Plugins/externalization: add official npm-first catalogs for externalized channel, provider, and generic plugins, keep unpublished ACPX/Google Chat/LINE bundled, and make missing-plugin repair honor npm-first metadata while ClawHub pack files roll out. Thanks @vincentkoc.
- Plugins/update: detect tracked plugin install records whose package directories disappeared during `openclaw update`, reinstall them before normal plugin updates, and fail the update if any install record still points at missing disk payloads.

View File

@@ -555,6 +555,49 @@ describe("installPluginFromClawHub", () => {
expect(archiveCleanupMock).toHaveBeenCalledTimes(1);
});
it("points explicit ClawHub ClawPack download failures at npm during launch rollout", async () => {
fetchClawHubPackageVersionMock.mockResolvedValueOnce({
version: {
version: "2026.3.22",
createdAt: 0,
changelog: "",
compatibility: {
pluginApiRange: ">=2026.3.22",
minGatewayVersion: "2026.3.0",
},
artifact: {
kind: "npm-pack",
format: "tgz",
sha256: DEMO_CLAWPACK_SHA256,
},
},
});
downloadClawHubPackageArchiveMock.mockRejectedValueOnce(
new ClawHubRequestError({
path: "/api/v1/packages/demo/versions/2026.3.22/artifact/download",
status: 404,
body: "Not Found",
}),
);
const result = await installPluginFromClawHub({
spec: "clawhub:demo",
baseUrl: "https://clawhub.ai",
});
expect(result).toMatchObject({
ok: false,
error:
'ClawHub artifact download for "demo@2026.3.22" is not available yet (ClawHub /api/v1/packages/demo/versions/2026.3.22/artifact/download failed (404): Not Found). Use "npm:demo@2026.3.22" for launch installs while ClawHub artifact routing is being rolled out.',
});
expect(downloadClawHubPackageArchiveMock).toHaveBeenCalledWith(
expect.objectContaining({
artifact: "clawpack",
}),
);
expect(installPluginFromArchiveMock).not.toHaveBeenCalled();
});
it("does not persist package-level ClawPack metadata for version records without ClawPack facts", async () => {
parseClawHubPluginSpecMock.mockReturnValueOnce({ name: "demo", version: "2026.3.21" });
fetchClawHubPackageDetailMock.mockResolvedValueOnce({

View File

@@ -330,6 +330,18 @@ function mapClawHubRequestError(
return buildClawHubInstallFailure(formatErrorMessage(error));
}
function formatClawHubClawPackDownloadError(params: {
error: unknown;
packageName: string;
version: string;
}): string {
const message = formatErrorMessage(params.error);
if (!(params.error instanceof ClawHubRequestError)) {
return message;
}
return `ClawHub artifact download for "${params.packageName}@${params.version}" is not available yet (${message}). Use "npm:${params.packageName}@${params.version}" for launch installs while ClawHub artifact routing is being rolled out.`;
}
function resolveRequestedVersion(params: {
detail: ClawHubPackageDetail;
requestedVersion?: string;
@@ -1037,7 +1049,17 @@ export async function installPluginFromClawHub(
timeoutMs: params.timeoutMs,
});
} catch (error) {
return buildClawHubInstallFailure(formatErrorMessage(error));
// Fix-me(clawhub): remove this npm hint once ClawHub ClawPack artifact
// routing is live for official package installs.
return buildClawHubInstallFailure(
expectedClawPackSha256
? formatClawHubClawPackDownloadError({
error,
packageName: canonicalPackageName,
version: versionState.version,
})
: formatErrorMessage(error),
);
}
try {
if (expectedClawPackSha256) {