diff --git a/CHANGELOG.md b/CHANGELOG.md index 1708ce4b12f..0402f5a0fb2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ Docs: https://docs.openclaw.ai - Control UI/Talk: fix Talk (OpenAI Realtime WebRTC) CORS failure by stripping server-side-only attribution headers (`originator`, `version`, `User-Agent`) from browser offer headers; `api.openai.com/v1/realtime/calls` only allows `authorization` and `content-type` in its CORS preflight, so forwarding these headers caused the browser SDP exchange to fail. Fixes #76435. Thanks @hclsys. - Plugins/onboarding: trust optional official plugin and web-search installs selected from the official catalog so npm security scanning treats them like other source-linked official install paths. Thanks @vincentkoc. - Tests/plugins: expose the Discord npm onboarding Docker lane as a package script and assert planned Docker lanes point at real scripts, so external-channel onboarding coverage can actually run. Thanks @vincentkoc. +- Plugins/ClawHub: explain unreleased ClawHub plugin artifacts as a rollout-state fallback to `npm:` installs instead of leaking raw archive metadata fields. Thanks @vincentkoc. - Microsoft Teams: persist sent-message markers across Gateway restarts so follow-up replies to recent bot messages keep resolving the original conversation instead of dropping out after restart, with marker TTLs preserved on best-effort recovery. (#75585) Thanks @amknight. - Matrix: persist pending approval reaction targets across Gateway restarts so room approvers can still approve or deny outstanding prompts after OpenClaw comes back online. (#75586) Thanks @amknight. - Channels/onboarding: map third-party official WeCom and Yuanbao catalog entries to their published plugin ids so npm installs pass expected-plugin validation. Thanks @vincentkoc. diff --git a/src/plugins/clawhub.test.ts b/src/plugins/clawhub.test.ts index 6d75275cb09..656e915c6e8 100644 --- a/src/plugins/clawhub.test.ts +++ b/src/plugins/clawhub.test.ts @@ -1038,7 +1038,7 @@ describe("installPluginFromClawHub", () => { ok: false, code: CLAWHUB_INSTALL_ERROR_CODE.MISSING_ARCHIVE_INTEGRITY, error: - 'ClawHub version metadata for "demo@2026.3.22" is missing sha256hash and usable files[] metadata for fallback archive verification.', + 'ClawHub package "demo@2026.3.22" does not expose a downloadable plugin artifact yet. Use "npm:demo@2026.3.22" for launch installs while ClawHub artifact routing is being rolled out.', }); expect(downloadClawHubPackageArchiveMock).not.toHaveBeenCalled(); }); @@ -1064,7 +1064,7 @@ describe("installPluginFromClawHub", () => { ok: false, code: CLAWHUB_INSTALL_ERROR_CODE.MISSING_ARCHIVE_INTEGRITY, error: - 'ClawHub version metadata for "demo@2026.3.22" is missing sha256hash and usable files[] metadata for fallback archive verification.', + 'ClawHub package "demo@2026.3.22" does not expose a downloadable plugin artifact yet. Use "npm:demo@2026.3.22" for launch installs while ClawHub artifact routing is being rolled out.', }); expect(downloadClawHubPackageArchiveMock).not.toHaveBeenCalled(); }); diff --git a/src/plugins/clawhub.ts b/src/plugins/clawhub.ts index d37ef6d36f5..606c70bee20 100644 --- a/src/plugins/clawhub.ts +++ b/src/plugins/clawhub.ts @@ -375,6 +375,13 @@ function formatClawHubClawPackDownloadError(params: { 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 formatClawHubMissingArtifactMetadataError(params: { + packageName: string; + version: string; +}): string { + return `ClawHub package "${params.packageName}@${params.version}" does not expose a downloadable plugin artifact yet. Use "npm:${params.packageName}@${params.version}" for launch installs while ClawHub artifact routing is being rolled out.`; +} + function resolveRequestedVersion(params: { detail: ClawHubPackageDetail; requestedVersion?: string; @@ -1079,13 +1086,16 @@ export async function installPluginFromClawHub( return validationFailure; } const expectedClawPackSha256 = resolveClawHubClawPackArtifactSha256(versionState.clawpack); + const canonicalPackageName = detail.package?.name ?? parsed.name; if (!versionState.verification && !expectedClawPackSha256) { return buildClawHubInstallFailure( - `ClawHub version metadata for "${parsed.name}@${versionState.version}" is missing sha256hash and usable files[] metadata for fallback archive verification.`, + formatClawHubMissingArtifactMetadataError({ + packageName: canonicalPackageName, + version: versionState.version, + }), CLAWHUB_INSTALL_ERROR_CODE.MISSING_ARCHIVE_INTEGRITY, ); } - const canonicalPackageName = detail.package?.name ?? parsed.name; logClawHubPackageSummary({ detail, version: versionState.version,