mirror of https://github.com/openclaw/openclaw.git
fix: use runtime version for ClawHub plugin API checks (#53157) (thanks @futhgar)
This commit is contained in:
parent
447e074bf4
commit
5b4fd6bf31
|
|
@ -12,6 +12,7 @@ Docs: https://docs.openclaw.ai
|
|||
|
||||
### Fixes
|
||||
|
||||
- Plugins/ClawHub: resolve plugin API compatibility against the active runtime version at install time, and add regression coverage for current `>=2026.3.22` ClawHub package checks so installs no longer fail behind the stale `1.2.0` constant. (#53157) Thanks @futhgar.
|
||||
- CLI/channel auth: auto-select the single login-capable configured channel for `channels login`/`logout` instead of relying on the outbound message-channel resolver, so env-only or non-auth channels no longer cause false ambiguity errors. (#53254) Thanks @BunsDev.
|
||||
- Control UI/auth: preserve operator scopes through the device-auth bypass path, ignore cached under-scoped operator tokens, and show a clear `operator.read` fallback message when a connection really lacks read scope, so operator sessions stop failing or blanking on read-backed pages. (#53110) Thanks @BunsDev.
|
||||
- Plugins/uninstall: accept installed `clawhub:` specs and versionless ClawHub package names as uninstall targets, so `openclaw plugins uninstall clawhub:<package>` works again even when the recorded install was pinned to a version.
|
||||
|
|
|
|||
|
|
@ -61,19 +61,19 @@ describe("installPluginFromClawHub", () => {
|
|||
createdAt: 0,
|
||||
updatedAt: 0,
|
||||
compatibility: {
|
||||
pluginApiRange: "^1.2.0",
|
||||
pluginApiRange: ">=2026.3.22",
|
||||
minGatewayVersion: "2026.3.0",
|
||||
},
|
||||
},
|
||||
});
|
||||
resolveLatestVersionFromPackageMock.mockReturnValue("1.2.3");
|
||||
resolveLatestVersionFromPackageMock.mockReturnValue("2026.3.22");
|
||||
fetchClawHubPackageVersionMock.mockResolvedValue({
|
||||
version: {
|
||||
version: "1.2.3",
|
||||
version: "2026.3.22",
|
||||
createdAt: 0,
|
||||
changelog: "",
|
||||
compatibility: {
|
||||
pluginApiRange: "^1.2.0",
|
||||
pluginApiRange: ">=2026.3.22",
|
||||
minGatewayVersion: "2026.3.0",
|
||||
},
|
||||
},
|
||||
|
|
@ -89,7 +89,7 @@ describe("installPluginFromClawHub", () => {
|
|||
ok: true,
|
||||
pluginId: "demo",
|
||||
targetDir: "/tmp/openclaw/plugins/demo",
|
||||
version: "1.2.3",
|
||||
version: "2026.3.22",
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -116,7 +116,7 @@ describe("installPluginFromClawHub", () => {
|
|||
expect(fetchClawHubPackageVersionMock).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
name: "demo",
|
||||
version: "1.2.3",
|
||||
version: "2026.3.22",
|
||||
}),
|
||||
);
|
||||
expect(installPluginFromArchiveMock).toHaveBeenCalledWith(
|
||||
|
|
@ -127,7 +127,7 @@ describe("installPluginFromClawHub", () => {
|
|||
expect(result).toMatchObject({
|
||||
ok: true,
|
||||
pluginId: "demo",
|
||||
version: "1.2.3",
|
||||
version: "2026.3.22",
|
||||
clawhub: {
|
||||
source: "clawhub",
|
||||
clawhubPackage: "demo",
|
||||
|
|
@ -136,11 +136,27 @@ describe("installPluginFromClawHub", () => {
|
|||
integrity: "sha256-demo",
|
||||
},
|
||||
});
|
||||
expect(info).toHaveBeenCalledWith("ClawHub code-plugin demo@1.2.3 channel=official");
|
||||
expect(info).toHaveBeenCalledWith("Compatibility: pluginApi=^1.2.0 minGateway=2026.3.0");
|
||||
expect(satisfiesPluginApiRangeMock).toHaveBeenCalledWith("2026.3.22", ">=2026.3.22");
|
||||
expect(satisfiesGatewayMinimumMock).toHaveBeenCalledWith("2026.3.22", "2026.3.0");
|
||||
expect(info).toHaveBeenCalledWith("ClawHub code-plugin demo@2026.3.22 channel=official");
|
||||
expect(info).toHaveBeenCalledWith("Compatibility: pluginApi=>=2026.3.22 minGateway=2026.3.0");
|
||||
expect(warn).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("rejects packages whose plugin API range exceeds the runtime version", async () => {
|
||||
resolveRuntimeServiceVersionMock.mockReturnValueOnce("2026.3.21");
|
||||
satisfiesPluginApiRangeMock.mockReturnValueOnce(false);
|
||||
|
||||
await expect(installPluginFromClawHub({ spec: "clawhub:demo" })).resolves.toMatchObject({
|
||||
ok: false,
|
||||
code: CLAWHUB_INSTALL_ERROR_CODE.INCOMPATIBLE_PLUGIN_API,
|
||||
error:
|
||||
'Plugin "demo" requires plugin API >=2026.3.22, but this OpenClaw runtime exposes 2026.3.21.',
|
||||
});
|
||||
|
||||
expect(satisfiesPluginApiRangeMock).toHaveBeenCalledWith("2026.3.21", ">=2026.3.22");
|
||||
});
|
||||
|
||||
it("rejects skill families and redirects to skills install", async () => {
|
||||
fetchClawHubPackageDetailMock.mockResolvedValueOnce({
|
||||
package: {
|
||||
|
|
|
|||
|
|
@ -15,8 +15,6 @@ import {
|
|||
} from "../infra/clawhub.js";
|
||||
import { resolveRuntimeServiceVersion } from "../version.js";
|
||||
import { installPluginFromArchive, type InstallPluginResult } from "./install.js";
|
||||
|
||||
export const OPENCLAW_PLUGIN_API_VERSION = resolveRuntimeServiceVersion();
|
||||
export const CLAWHUB_INSTALL_ERROR_CODE = {
|
||||
INVALID_SPEC: "invalid_spec",
|
||||
PACKAGE_NOT_FOUND: "package_not_found",
|
||||
|
|
@ -175,17 +173,17 @@ function validateClawHubPluginPackage(params: {
|
|||
}
|
||||
|
||||
const compatibility = params.compatibility;
|
||||
const runtimeVersion = resolveRuntimeServiceVersion();
|
||||
if (
|
||||
compatibility?.pluginApiRange &&
|
||||
!satisfiesPluginApiRange(OPENCLAW_PLUGIN_API_VERSION, compatibility.pluginApiRange)
|
||||
!satisfiesPluginApiRange(runtimeVersion, compatibility.pluginApiRange)
|
||||
) {
|
||||
return buildClawHubInstallFailure(
|
||||
`Plugin "${pkg.name}" requires plugin API ${compatibility.pluginApiRange}, but this OpenClaw runtime exposes ${OPENCLAW_PLUGIN_API_VERSION}.`,
|
||||
`Plugin "${pkg.name}" requires plugin API ${compatibility.pluginApiRange}, but this OpenClaw runtime exposes ${runtimeVersion}.`,
|
||||
CLAWHUB_INSTALL_ERROR_CODE.INCOMPATIBLE_PLUGIN_API,
|
||||
);
|
||||
}
|
||||
|
||||
const runtimeVersion = resolveRuntimeServiceVersion();
|
||||
if (
|
||||
compatibility?.minGatewayVersion &&
|
||||
!satisfiesGatewayMinimum(runtimeVersion, compatibility.minGatewayVersion)
|
||||
|
|
|
|||
Loading…
Reference in New Issue