diff --git a/extensions/twitch/package.json b/extensions/twitch/package.json index 5f8353c3c58..cbe000bd505 100644 --- a/extensions/twitch/package.json +++ b/extensions/twitch/package.json @@ -1,6 +1,6 @@ { "name": "@openclaw/twitch", - "version": "2026.4.25", + "version": "2026.5.1-beta.1", "description": "OpenClaw Twitch channel plugin", "type": "module", "dependencies": { @@ -11,12 +11,22 @@ "devDependencies": { "@openclaw/plugin-sdk": "workspace:*" }, + "peerDependencies": { + "openclaw": ">=2026.4.10" + }, + "peerDependenciesMeta": { + "openclaw": { + "optional": true + } + }, "openclaw": { "extensions": [ "./index.ts" ], "setupEntry": "./setup-entry.ts", "install": { + "npmSpec": "@openclaw/twitch", + "defaultChoice": "npm", "minHostVersion": ">=2026.4.10" }, "channel": { @@ -28,6 +38,9 @@ "aliases": [ "twitch-chat" ] + }, + "release": { + "publishToNpm": true } } } diff --git a/scripts/lib/plugin-npm-release.ts b/scripts/lib/plugin-npm-release.ts index d375f39a15f..2f117581577 100644 --- a/scripts/lib/plugin-npm-release.ts +++ b/scripts/lib/plugin-npm-release.ts @@ -237,14 +237,31 @@ export function collectPublishablePluginPackageErrors( return errors; } +export type PublishablePluginPackageFilters = { + extensionIds?: readonly string[]; + packageNames?: readonly string[]; +}; + export function collectPublishablePluginPackages( rootDir = resolve("."), + filters: PublishablePluginPackageFilters = {}, ): PublishablePluginPackage[] { const publishable: PublishablePluginPackage[] = []; const validationErrors: string[] = []; + const selectedExtensionIds = new Set(filters.extensionIds ?? []); + const selectedPackageNames = new Set(filters.packageNames ?? []); + const hasSelectedExtensionIds = selectedExtensionIds.size > 0; + const hasSelectedPackageNames = selectedPackageNames.size > 0; 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?.publishToNpm !== true) { continue; } @@ -268,7 +285,7 @@ export function collectPublishablePluginPackages( publishable.push({ extensionId, packageDir, - packageName: packageJson.name!.trim(), + packageName, version, channel: parsedVersion.channel, publishTag: resolveNpmPublishPlan(version).publishTag, @@ -443,7 +460,16 @@ export function collectPluginReleasePlan(params?: { selectionMode?: PluginReleaseSelectionMode; gitRange?: GitRangeSelection; }): PluginReleasePlan { - const allPublishable = collectPublishablePluginPackages(params?.rootDir); + const changedExtensionIds = params?.gitRange + ? collectChangedExtensionIdsFromGitRange({ + rootDir: params.rootDir, + gitRange: params.gitRange, + }) + : []; + const allPublishable = collectPublishablePluginPackages(params?.rootDir, { + extensionIds: params?.selectionMode === "all-publishable" ? [] : changedExtensionIds, + packageNames: params?.selection, + }); const selectedPublishable = params?.selectionMode === "all-publishable" ? allPublishable @@ -455,10 +481,7 @@ export function collectPluginReleasePlan(params?: { : params?.gitRange ? resolveChangedPublishablePluginPackages({ plugins: allPublishable, - changedExtensionIds: collectChangedExtensionIdsFromGitRange({ - rootDir: params.rootDir, - gitRange: params.gitRange, - }), + changedExtensionIds, }) : allPublishable; diff --git a/scripts/plugin-npm-release-check.ts b/scripts/plugin-npm-release-check.ts index f1af5b75509..dddc71036da 100644 --- a/scripts/plugin-npm-release-check.ts +++ b/scripts/plugin-npm-release-check.ts @@ -11,7 +11,16 @@ import { export function runPluginNpmReleaseCheck(argv: string[]) { const { selection, selectionMode, baseRef, headRef } = parsePluginReleaseArgs(argv); - const publishable = collectPublishablePluginPackages(); + const changedExtensionIds = + baseRef && headRef + ? collectChangedExtensionIdsFromGitRange({ + gitRange: { baseRef, headRef }, + }) + : []; + const publishable = collectPublishablePluginPackages(".", { + extensionIds: selectionMode === "all-publishable" ? [] : changedExtensionIds, + packageNames: selection, + }); const selected = selectionMode === "all-publishable" ? publishable @@ -23,9 +32,7 @@ export function runPluginNpmReleaseCheck(argv: string[]) { : baseRef && headRef ? resolveChangedPublishablePluginPackages({ plugins: publishable, - changedExtensionIds: collectChangedExtensionIdsFromGitRange({ - gitRange: { baseRef, headRef }, - }), + changedExtensionIds, }) : publishable; diff --git a/test/plugin-npm-release.test.ts b/test/plugin-npm-release.test.ts index baa24bd9913..feb4ef99fbb 100644 --- a/test/plugin-npm-release.test.ts +++ b/test/plugin-npm-release.test.ts @@ -157,6 +157,45 @@ describe("collectPublishablePluginPackages", () => { }, ]); }); + + it("does not validate unselected publishable plugin manifests", () => { + const repoDir = makeTempRepoRoot(tempDirs, "openclaw-plugin-npm-release-"); + mkdirSync(join(repoDir, "extensions", "demo-plugin"), { recursive: true }); + writeJsonFile(join(repoDir, "extensions", "demo-plugin", "package.json"), { + name: "@openclaw/demo-plugin", + version: "2026.4.10-beta.1", + openclaw: { + extensions: ["./index.ts"], + release: { + publishToNpm: true, + }, + }, + }); + mkdirSync(join(repoDir, "extensions", "private-plugin"), { recursive: true }); + writeJsonFile(join(repoDir, "extensions", "private-plugin", "package.json"), { + name: "@openclaw/private-plugin", + version: "2026.4.10-beta.1", + private: true, + openclaw: { + extensions: ["./index.ts"], + release: { + publishToNpm: true, + }, + }, + }); + + expect( + collectPublishablePluginPackages(repoDir, { + packageNames: ["@openclaw/demo-plugin"], + }), + ).toEqual([ + expect.objectContaining({ + extensionId: "demo-plugin", + packageName: "@openclaw/demo-plugin", + publishTag: "beta", + }), + ]); + }); }); describe("resolveSelectedPublishablePluginPackages", () => {