mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 10:30:44 +00:00
build: prepare external plugin beta publishing
This commit is contained in:
@@ -7,6 +7,7 @@ Docs: https://docs.openclaw.ai
|
||||
### Changes
|
||||
|
||||
- Plugins/source checkout: load bundled plugins from the `extensions/*` pnpm workspace tree in source checkouts, so plugin-local dependencies and edits are used directly while packaged installs keep using the built runtime tree. Thanks @vincentkoc.
|
||||
- Plugins/beta: prepare Brave, Codex, Feishu, Synology Chat, Tlon, and Twitch for `2026.5.1-beta.1` npm and ClawHub publishing. Thanks @vincentkoc.
|
||||
- Providers/xAI: add Grok 4.3 to the bundled catalog and make it the default xAI chat model.
|
||||
- Plugins/ClawHub: prefer versioned ClawPack artifacts when ClawHub publishes digest metadata, verifying the ClawPack response header and downloaded bytes before installing. Thanks @vincentkoc.
|
||||
- Plugins/ClawHub: persist ClawPack digest metadata on ClawHub plugin install and update records so registry refreshes and download verification can reuse stored artifact facts. Thanks @vincentkoc.
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
{
|
||||
"name": "@openclaw/brave-plugin",
|
||||
"version": "2026.4.25",
|
||||
"private": true,
|
||||
"version": "2026.5.1-beta.1",
|
||||
"description": "OpenClaw Brave plugin",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/openclaw/openclaw"
|
||||
},
|
||||
"type": "module",
|
||||
"devDependencies": {
|
||||
"@openclaw/plugin-sdk": "workspace:*"
|
||||
@@ -10,6 +13,21 @@
|
||||
"openclaw": {
|
||||
"extensions": [
|
||||
"./index.ts"
|
||||
]
|
||||
],
|
||||
"install": {
|
||||
"npmSpec": "@openclaw/brave-plugin",
|
||||
"defaultChoice": "npm",
|
||||
"minHostVersion": ">=2026.4.10"
|
||||
},
|
||||
"compat": {
|
||||
"pluginApi": ">=2026.4.10"
|
||||
},
|
||||
"build": {
|
||||
"openclawVersion": "2026.5.1-beta.1"
|
||||
},
|
||||
"release": {
|
||||
"publishToClawHub": true,
|
||||
"publishToNpm": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
{
|
||||
"name": "@openclaw/codex",
|
||||
"version": "2026.4.25",
|
||||
"version": "2026.5.1-beta.1",
|
||||
"description": "OpenClaw Codex harness and model provider plugin",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/openclaw/openclaw"
|
||||
},
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"@mariozechner/pi-coding-agent": "0.71.1",
|
||||
@@ -16,6 +20,21 @@
|
||||
"openclaw": {
|
||||
"extensions": [
|
||||
"./index.ts"
|
||||
]
|
||||
],
|
||||
"install": {
|
||||
"npmSpec": "@openclaw/codex",
|
||||
"defaultChoice": "npm",
|
||||
"minHostVersion": ">=2026.5.1-beta.1"
|
||||
},
|
||||
"compat": {
|
||||
"pluginApi": ">=2026.5.1-beta.1"
|
||||
},
|
||||
"build": {
|
||||
"openclawVersion": "2026.5.1-beta.1"
|
||||
},
|
||||
"release": {
|
||||
"publishToClawHub": true,
|
||||
"publishToNpm": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
{
|
||||
"name": "@openclaw/feishu",
|
||||
"version": "2026.4.25",
|
||||
"version": "2026.5.1-beta.1",
|
||||
"description": "OpenClaw Feishu/Lark channel plugin (community maintained by @m1heng)",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/openclaw/openclaw"
|
||||
},
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"@larksuiteoapi/node-sdk": "^1.62.1",
|
||||
@@ -46,7 +50,7 @@
|
||||
"pluginApi": ">=2026.4.25"
|
||||
},
|
||||
"build": {
|
||||
"openclawVersion": "2026.4.25"
|
||||
"openclawVersion": "2026.5.1-beta.1"
|
||||
},
|
||||
"release": {
|
||||
"publishToClawHub": true,
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
{
|
||||
"name": "@openclaw/synology-chat",
|
||||
"version": "2026.4.25",
|
||||
"version": "2026.5.1-beta.1",
|
||||
"description": "Synology Chat channel plugin for OpenClaw",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/openclaw/openclaw"
|
||||
},
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"zod": "^4.4.1"
|
||||
@@ -27,6 +31,16 @@
|
||||
"npmSpec": "@openclaw/synology-chat",
|
||||
"defaultChoice": "npm",
|
||||
"minHostVersion": ">=2026.4.10"
|
||||
},
|
||||
"compat": {
|
||||
"pluginApi": ">=2026.4.10"
|
||||
},
|
||||
"build": {
|
||||
"openclawVersion": "2026.5.1-beta.1"
|
||||
},
|
||||
"release": {
|
||||
"publishToClawHub": true,
|
||||
"publishToNpm": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
{
|
||||
"name": "@openclaw/tlon",
|
||||
"version": "2026.4.25",
|
||||
"version": "2026.5.1-beta.1",
|
||||
"description": "OpenClaw Tlon/Urbit channel plugin",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/openclaw/openclaw"
|
||||
},
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"@aws-sdk/client-s3": "3.1041.0",
|
||||
@@ -66,6 +70,16 @@
|
||||
"npmSpec": "@openclaw/tlon",
|
||||
"defaultChoice": "npm",
|
||||
"minHostVersion": ">=2026.4.10"
|
||||
},
|
||||
"compat": {
|
||||
"pluginApi": ">=2026.4.10"
|
||||
},
|
||||
"build": {
|
||||
"openclawVersion": "2026.5.1-beta.1"
|
||||
},
|
||||
"release": {
|
||||
"publishToClawHub": true,
|
||||
"publishToNpm": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,12 @@
|
||||
"defaultChoice": "npm",
|
||||
"minHostVersion": ">=2026.4.10"
|
||||
},
|
||||
"compat": {
|
||||
"pluginApi": ">=2026.4.10"
|
||||
},
|
||||
"build": {
|
||||
"openclawVersion": "2026.5.1-beta.1"
|
||||
},
|
||||
"channel": {
|
||||
"id": "twitch",
|
||||
"label": "Twitch",
|
||||
@@ -36,6 +42,7 @@
|
||||
]
|
||||
},
|
||||
"release": {
|
||||
"publishToClawHub": true,
|
||||
"publishToNpm": true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,6 +73,11 @@ export type PluginReleasePlan = {
|
||||
skippedPublished: PluginReleasePlanItem[];
|
||||
};
|
||||
|
||||
export type ClawHubPublishablePluginPackageFilters = {
|
||||
extensionIds?: readonly string[];
|
||||
packageNames?: readonly string[];
|
||||
};
|
||||
|
||||
const CLAWHUB_DEFAULT_REGISTRY = "https://clawhub.ai";
|
||||
const SAFE_EXTENSION_ID_RE = /^[a-z0-9][a-z0-9._-]*$/;
|
||||
const CLAWHUB_SHARED_RELEASE_INPUT_PATHS = [
|
||||
@@ -101,12 +106,24 @@ function getRegistryBaseUrl(explicit?: string) {
|
||||
|
||||
export function collectClawHubPublishablePluginPackages(
|
||||
rootDir = resolve("."),
|
||||
filters: ClawHubPublishablePluginPackageFilters = {},
|
||||
): PublishablePluginPackage[] {
|
||||
const publishable: PublishablePluginPackage[] = [];
|
||||
const validationErrors: string[] = [];
|
||||
const selectedExtensionIds = new Set(filters.extensionIds ?? []);
|
||||
const selectedPackageNames = new Set(filters.packageNames ?? []);
|
||||
const hasSelectedExtensionIds = Array.isArray(filters.extensionIds);
|
||||
const hasSelectedPackageNames = Array.isArray(filters.packageNames);
|
||||
|
||||
for (const candidate of collectExtensionPackageJsonCandidates(rootDir)) {
|
||||
const { extensionId, packageDir, packageJson } = candidate;
|
||||
if (hasSelectedExtensionIds && !selectedExtensionIds.has(extensionId)) {
|
||||
continue;
|
||||
}
|
||||
const packageName = packageJson.name?.trim() ?? "";
|
||||
if (hasSelectedPackageNames && !selectedPackageNames.has(packageName)) {
|
||||
continue;
|
||||
}
|
||||
if (packageJson.openclaw?.release?.publishToClawHub !== true) {
|
||||
continue;
|
||||
}
|
||||
@@ -147,7 +164,7 @@ export function collectClawHubPublishablePluginPackages(
|
||||
publishable.push({
|
||||
extensionId,
|
||||
packageDir,
|
||||
packageName: packageJson.name!.trim(),
|
||||
packageName,
|
||||
version,
|
||||
channel: parsedVersion.channel,
|
||||
publishTag: parsedVersion.channel === "beta" ? "beta" : "latest",
|
||||
@@ -342,13 +359,29 @@ export async function collectPluginClawHubReleasePlan(params?: {
|
||||
registryBaseUrl?: string;
|
||||
fetchImpl?: typeof fetch;
|
||||
}): Promise<PluginReleasePlan> {
|
||||
const allPublishable = collectClawHubPublishablePluginPackages(params?.rootDir);
|
||||
const rootDir = params?.rootDir;
|
||||
const selection = params?.selection ?? [];
|
||||
const changedPaths = params?.gitRange
|
||||
? collectPluginClawHubRelevantPathsFromGitRange({
|
||||
rootDir,
|
||||
gitRange: params.gitRange,
|
||||
})
|
||||
: [];
|
||||
const sharedInputChanged = hasSharedClawHubReleaseInputChanges(changedPaths);
|
||||
const extensionIds =
|
||||
params?.selectionMode === "all-publishable" || !params?.gitRange || sharedInputChanged
|
||||
? undefined
|
||||
: collectChangedExtensionIdsFromPaths(changedPaths);
|
||||
const allPublishable = collectClawHubPublishablePluginPackages(rootDir, {
|
||||
extensionIds,
|
||||
packageNames: selection.length > 0 ? selection : undefined,
|
||||
});
|
||||
const selectedPublishable = resolveSelectedClawHubPublishablePluginPackages({
|
||||
plugins: allPublishable,
|
||||
selection: params?.selection,
|
||||
selection,
|
||||
selectionMode: params?.selectionMode,
|
||||
gitRange: params?.gitRange,
|
||||
rootDir: params?.rootDir,
|
||||
rootDir,
|
||||
});
|
||||
|
||||
const all = await Promise.all(
|
||||
|
||||
@@ -10,7 +10,10 @@ import {
|
||||
|
||||
export async function runPluginClawHubReleaseCheck(argv: string[]) {
|
||||
const { selection, selectionMode, baseRef, headRef } = parsePluginReleaseArgs(argv);
|
||||
const publishable = collectClawHubPublishablePluginPackages();
|
||||
const publishable = collectClawHubPublishablePluginPackages(".", {
|
||||
packageNames:
|
||||
selectionMode === "all-publishable" || selection.length === 0 ? undefined : selection,
|
||||
});
|
||||
const gitRange = baseRef && headRef ? { baseRef, headRef } : undefined;
|
||||
const selected = resolveSelectedClawHubPublishablePluginPackages({
|
||||
plugins: publishable,
|
||||
|
||||
@@ -69,6 +69,35 @@ describe("collectClawHubPublishablePluginPackages", () => {
|
||||
"Demo Plugin: extension directory name must match",
|
||||
);
|
||||
});
|
||||
|
||||
it("validates only selected package names when filters are provided", () => {
|
||||
const repoDir = createTempPluginRepo({
|
||||
extraExtensionIds: ["broken-plugin"],
|
||||
});
|
||||
writeFileSync(
|
||||
join(repoDir, "extensions", "broken-plugin", "package.json"),
|
||||
JSON.stringify(
|
||||
{
|
||||
name: "@openclaw/broken-plugin",
|
||||
version: "2026.4.1",
|
||||
openclaw: {
|
||||
extensions: ["./index.ts"],
|
||||
release: {
|
||||
publishToClawHub: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
null,
|
||||
2,
|
||||
),
|
||||
);
|
||||
|
||||
expect(
|
||||
collectClawHubPublishablePluginPackages(repoDir, {
|
||||
packageNames: ["@openclaw/demo-plugin"],
|
||||
}).map((plugin) => plugin.packageName),
|
||||
).toEqual(["@openclaw/demo-plugin"]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("collectClawHubVersionGateErrors", () => {
|
||||
@@ -238,6 +267,38 @@ describe("collectPluginClawHubReleasePlan", () => {
|
||||
version: "2026.4.1",
|
||||
});
|
||||
});
|
||||
|
||||
it("plans selected packages without validating unrelated publishable packages", async () => {
|
||||
const repoDir = createTempPluginRepo({
|
||||
extraExtensionIds: ["broken-plugin"],
|
||||
});
|
||||
writeFileSync(
|
||||
join(repoDir, "extensions", "broken-plugin", "package.json"),
|
||||
JSON.stringify(
|
||||
{
|
||||
name: "@openclaw/broken-plugin",
|
||||
version: "2026.4.1",
|
||||
openclaw: {
|
||||
extensions: ["./index.ts"],
|
||||
release: {
|
||||
publishToClawHub: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
null,
|
||||
2,
|
||||
),
|
||||
);
|
||||
|
||||
const plan = await collectPluginClawHubReleasePlan({
|
||||
rootDir: repoDir,
|
||||
selection: ["@openclaw/demo-plugin"],
|
||||
fetchImpl: async () => new Response("{}", { status: 404 }),
|
||||
registryBaseUrl: "https://clawhub.ai",
|
||||
});
|
||||
|
||||
expect(plan.candidates.map((plugin) => plugin.packageName)).toEqual(["@openclaw/demo-plugin"]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("collectPluginClawHubReleasePathsFromGitRange", () => {
|
||||
|
||||
Reference in New Issue
Block a user