diff --git a/src/plugins/contracts/inventory/bundled-capability-metadata.ts b/src/plugins/contracts/inventory/bundled-capability-metadata.ts index 7872c6e9f47..d624967fa2e 100644 --- a/src/plugins/contracts/inventory/bundled-capability-metadata.ts +++ b/src/plugins/contracts/inventory/bundled-capability-metadata.ts @@ -5,7 +5,13 @@ import { normalizeBundledPluginStringList, resolveBundledPluginScanDir, } from "../../bundled-plugin-scan.js"; -import { PLUGIN_MANIFEST_FILENAME, type PluginManifest } from "../../manifest.js"; +import { + getPackageManifestMetadata, + isPackageIncludedInCoreBundle, + PLUGIN_MANIFEST_FILENAME, + type PackageManifest, + type PluginManifest, +} from "../../manifest.js"; import { resolveLoaderPackageRoot } from "../../sdk-alias.js"; import { uniqueStrings } from "../shared.js"; @@ -65,17 +71,7 @@ function readJsonRecord(filePath: string): Record | undefined { } function isExplicitlyDownloadablePlugin(packageJson: Record | undefined): boolean { - const openclaw = packageJson?.openclaw; - if (!openclaw || typeof openclaw !== "object" || Array.isArray(openclaw)) { - return false; - } - const bundle = (openclaw as { bundle?: unknown }).bundle; - return ( - bundle !== null && - typeof bundle === "object" && - !Array.isArray(bundle) && - (bundle as { includeInCore?: unknown }).includeInCore === false - ); + return !isPackageIncludedInCoreBundle(getPackageManifestMetadata(packageJson as PackageManifest)); } function readBundledCapabilityManifest(pluginDir: string): BundledCapabilityManifest | undefined { diff --git a/src/plugins/contracts/registry.contract.test.ts b/src/plugins/contracts/registry.contract.test.ts index a9e953d02e0..c058cb0235b 100644 --- a/src/plugins/contracts/registry.contract.test.ts +++ b/src/plugins/contracts/registry.contract.test.ts @@ -1,6 +1,7 @@ import { describe, expect, it } from "vitest"; import { uniqueSortedStrings } from "../../plugin-sdk/test-helpers/string-utils.js"; import { loadPluginManifestRegistry } from "../manifest-registry.js"; +import { isPackageIncludedInCoreBundle } from "../manifest.js"; import { resolveManifestContractPluginIds } from "../plugin-registry.js"; import { pluginRegistrationContractRegistry, @@ -44,7 +45,11 @@ describe("plugin contract registry", () => { }) => boolean, ) { return loadPluginManifestRegistry({}) - .plugins.filter(predicate) + .plugins.filter( + (plugin) => + (plugin.origin !== "bundled" || isPackageIncludedInCoreBundle(plugin.packageManifest)) && + predicate(plugin), + ) .map((plugin) => plugin.id) .toSorted((left, right) => left.localeCompare(right)); } diff --git a/src/plugins/manifest.ts b/src/plugins/manifest.ts index 956906ea87f..cd281eaba2e 100644 --- a/src/plugins/manifest.ts +++ b/src/plugins/manifest.ts @@ -1530,6 +1530,10 @@ export type OpenClawPackageSetupFeatures = { legacySessionSurfaces?: boolean; }; +export type OpenClawPackageBundle = { + includeInCore?: boolean; +}; + export type OpenClawPackageManifest = { extensions?: string[]; runtimeExtensions?: string[]; @@ -1538,6 +1542,7 @@ export type OpenClawPackageManifest = { setupFeatures?: OpenClawPackageSetupFeatures; channel?: PluginPackageChannel; install?: PluginPackageInstall; + bundle?: OpenClawPackageBundle; startup?: OpenClawPackageStartup; }; @@ -1570,6 +1575,12 @@ export function getPackageManifestMetadata( return manifest[MANIFEST_KEY]; } +export function isPackageIncludedInCoreBundle( + manifest: OpenClawPackageManifest | undefined, +): boolean { + return manifest?.bundle?.includeInCore !== false; +} + export function resolvePackageExtensionEntries( manifest: PackageManifest | undefined, ): PackageExtensionResolution { diff --git a/src/plugins/plugin-registry-contributions.ts b/src/plugins/plugin-registry-contributions.ts index 342029f73c2..1b2107b8637 100644 --- a/src/plugins/plugin-registry-contributions.ts +++ b/src/plugins/plugin-registry-contributions.ts @@ -12,6 +12,7 @@ import type { PluginManifestRecord, PluginManifestRegistry, } from "./manifest-registry.js"; +import { isPackageIncludedInCoreBundle } from "./manifest.js"; import type { PluginOrigin } from "./plugin-origin.types.js"; import { createPluginRegistryIdNormalizer, @@ -119,6 +120,10 @@ function sortUnique(values: Iterable): string[] { ); } +function isCoreBundledManifestSurface(plugin: PluginManifestRecord): boolean { + return plugin.origin !== "bundled" || isPackageIncludedInCoreBundle(plugin.packageManifest); +} + function collectObjectKeys(value: Record | undefined): readonly string[] { return value ? Object.keys(value) : []; } @@ -415,6 +420,7 @@ export function resolveManifestContractPluginIds( .plugins.filter( (plugin) => (!params.origin || plugin.origin === params.origin) && + isCoreBundledManifestSurface(plugin) && listManifestContractValues(plugin, params.contract).length > 0, ) .map((plugin) => plugin.id) @@ -432,6 +438,7 @@ export function resolveManifestContractPluginIdsByCompatibilityRuntimePath( .plugins.filter( (plugin) => (!params.origin || plugin.origin === params.origin) && + isCoreBundledManifestSurface(plugin) && listManifestContractValues(plugin, params.contract).length > 0 && (plugin.configContracts?.compatibilityRuntimePaths ?? []).includes(normalizedPath), ) diff --git a/src/plugins/providers.ts b/src/plugins/providers.ts index 1459a9cb380..50686434a59 100644 --- a/src/plugins/providers.ts +++ b/src/plugins/providers.ts @@ -9,6 +9,7 @@ import { } from "./manifest-owner-policy.js"; import { loadPluginManifestRegistryForInstalledIndex } from "./manifest-registry-installed.js"; import { type PluginManifestRecord, type PluginManifestRegistry } from "./manifest-registry.js"; +import { isPackageIncludedInCoreBundle } from "./manifest.js"; import { loadPluginRegistrySnapshot, normalizePluginsConfigWithRegistry, @@ -71,10 +72,16 @@ function resolveProviderSurfacePluginIdSet( resolveManifestRegistry({ ...params, includeDisabled: true, - }).plugins.flatMap((plugin) => (plugin.providers.length > 0 ? [plugin.id] : [])), + }).plugins.flatMap((plugin) => + plugin.providers.length > 0 && isCoreBundledManifestSurface(plugin) ? [plugin.id] : [], + ), ); } +function isCoreBundledManifestSurface(plugin: PluginManifestRecord): boolean { + return plugin.origin !== "bundled" || isPackageIncludedInCoreBundle(plugin.packageManifest); +} + function resolveProviderOwnerPluginIds( params: ProviderRegistryLoadParams & { pluginIds: readonly string[]; @@ -139,6 +146,7 @@ export function resolveBundledProviderCompatPluginIds(params: { .filter( (plugin) => plugin.origin === "bundled" && + isCoreBundledManifestSurface(plugin) && plugin.providers.length > 0 && (!onlyPluginIdSet || onlyPluginIdSet.has(plugin.id)), )