Files
openclaw/src/plugins/installed-plugin-index.ts
Peter Steinberger ee6052a169 fix(bonjour): default LAN discovery on macOS only
Summary:
- add manifest-backed platform-specific default enablement for bundled plugins
- auto-start Bonjour LAN discovery on macOS hosts only
- keep Linux, Windows, and containerized Gateway deployments opt-in while preserving explicit enablement

Verification:
- pnpm test extensions/bonjour/src/advertiser.test.ts src/plugins/bundled-plugin-metadata.test.ts src/plugins/manifest-registry.test.ts src/plugins/channel-plugin-ids.test.ts
- pnpm exec oxfmt --check --threads=1 CHANGELOG.md docs/gateway/bonjour.md docs/gateway/configuration-reference.md docs/gateway/discovery.md docs/gateway/security/index.md docs/plugins/manifest.md extensions/bonjour/openclaw.plugin.json src/plugin-sdk/facade-activation-check.runtime.ts src/plugins/bundled-manifest-contract-plugins.ts src/plugins/bundled-plugin-metadata.test.ts src/plugins/channel-presence-policy.ts src/plugins/default-enablement.ts src/plugins/gateway-startup-plugin-ids.ts src/plugins/installed-plugin-index-record-builder.ts src/plugins/installed-plugin-index-store.ts src/plugins/installed-plugin-index-types.ts src/plugins/installed-plugin-index.ts src/plugins/loader.ts src/plugins/manifest-contract-eligibility.ts src/plugins/manifest-owner-policy.ts src/plugins/manifest-registry-installed.ts src/plugins/manifest-registry.test.ts src/plugins/manifest-registry.ts src/plugins/manifest.ts src/plugins/providers.ts
- git diff --check
- Testbox: pnpm check:changed via Blacksmith Testbox tbx_01kqqf3f8rbrt8afjtcg0ck7qs

Refs #74209
2026-05-03 19:07:27 +01:00

139 lines
5.0 KiB
TypeScript

import type { OpenClawConfig } from "../config/types.js";
import { resolveCompatibilityHostVersion } from "../version.js";
import { normalizePluginsConfig, resolveEffectivePluginActivationState } from "./config-state.js";
import { isPluginEnabledByDefaultForPlatform } from "./default-enablement.js";
import { normalizeInstallRecordMap } from "./installed-plugin-index-install-records.js";
import {
resolveCompatRegistryVersion,
resolveInstalledPluginIndexPolicyHash,
} from "./installed-plugin-index-policy.js";
import { buildInstalledPluginIndexRecords } from "./installed-plugin-index-record-builder.js";
import { loadInstalledPluginIndexInstallRecordsSync } from "./installed-plugin-index-record-reader.js";
import { resolveInstalledPluginIndexRegistry } from "./installed-plugin-index-registry.js";
import {
INSTALLED_PLUGIN_INDEX_MIGRATION_VERSION,
INSTALLED_PLUGIN_INDEX_VERSION,
INSTALLED_PLUGIN_INDEX_WARNING,
type InstalledPluginIndex,
type InstalledPluginIndexRecord,
type InstalledPluginIndexRefreshReason,
type LoadInstalledPluginIndexParams,
type RefreshInstalledPluginIndexParams,
} from "./installed-plugin-index-types.js";
export {
INSTALLED_PLUGIN_INDEX_MIGRATION_VERSION,
INSTALLED_PLUGIN_INDEX_VERSION,
INSTALLED_PLUGIN_INDEX_WARNING,
} from "./installed-plugin-index-types.js";
export type {
InstalledPluginIndex,
InstalledPluginIndexRecord,
InstalledPluginIndexRefreshReason,
InstalledPluginInstallRecordInfo,
InstalledPluginPackageChannelInfo,
InstalledPluginStartupInfo,
LoadInstalledPluginIndexParams,
RefreshInstalledPluginIndexParams,
} from "./installed-plugin-index-types.js";
export { extractPluginInstallRecordsFromInstalledPluginIndex } from "./installed-plugin-index-install-records.js";
export { diffInstalledPluginIndexInvalidationReasons } from "./installed-plugin-index-invalidation.js";
export { resolveInstalledPluginIndexPolicyHash } from "./installed-plugin-index-policy.js";
function buildInstalledPluginIndex(
params: LoadInstalledPluginIndexParams & { refreshReason?: InstalledPluginIndexRefreshReason },
): InstalledPluginIndex {
const env = params.env ?? process.env;
const { candidates, registry } = resolveInstalledPluginIndexRegistry(params);
const registryDiagnostics = registry.diagnostics ?? [];
const diagnostics = [...registryDiagnostics];
const generatedAtMs = (params.now?.() ?? new Date()).getTime();
const installRecords = normalizeInstallRecordMap(
params.installRecords ??
loadInstalledPluginIndexInstallRecordsSync({
env,
...(params.stateDir ? { stateDir: params.stateDir } : {}),
...(params.pluginIndexFilePath ? { filePath: params.pluginIndexFilePath } : {}),
}),
);
const plugins = buildInstalledPluginIndexRecords({
candidates,
registry,
config: params.config,
diagnostics,
installRecords,
});
return {
version: INSTALLED_PLUGIN_INDEX_VERSION,
warning: INSTALLED_PLUGIN_INDEX_WARNING,
hostContractVersion: resolveCompatibilityHostVersion(env),
compatRegistryVersion: resolveCompatRegistryVersion(),
migrationVersion: INSTALLED_PLUGIN_INDEX_MIGRATION_VERSION,
policyHash: resolveInstalledPluginIndexPolicyHash(params.config),
generatedAtMs,
...(params.refreshReason ? { refreshReason: params.refreshReason } : {}),
installRecords,
plugins,
diagnostics,
};
}
export function loadInstalledPluginIndex(
params: LoadInstalledPluginIndexParams = {},
): InstalledPluginIndex {
return buildInstalledPluginIndex(params);
}
export function refreshInstalledPluginIndex(
params: RefreshInstalledPluginIndexParams,
): InstalledPluginIndex {
return buildInstalledPluginIndex({ ...params, refreshReason: params.reason });
}
export function listInstalledPluginRecords(
index: InstalledPluginIndex,
): readonly InstalledPluginIndexRecord[] {
return index.plugins;
}
export function listEnabledInstalledPluginRecords(
index: InstalledPluginIndex,
config?: OpenClawConfig,
): readonly InstalledPluginIndexRecord[] {
if (!config) {
return index.plugins.filter((plugin) => plugin.enabled);
}
return index.plugins.filter((plugin) => isInstalledPluginEnabled(index, plugin.pluginId, config));
}
export function getInstalledPluginRecord(
index: InstalledPluginIndex,
pluginId: string,
): InstalledPluginIndexRecord | undefined {
return index.plugins.find((plugin) => plugin.pluginId === pluginId);
}
export function isInstalledPluginEnabled(
index: InstalledPluginIndex,
pluginId: string,
config?: OpenClawConfig,
): boolean {
const record = getInstalledPluginRecord(index, pluginId);
if (!record) {
return false;
}
if (!config) {
return record.enabled;
}
const normalizedConfig = normalizePluginsConfig(config?.plugins);
const state = resolveEffectivePluginActivationState({
id: record.pluginId,
origin: record.origin,
config: normalizedConfig,
rootConfig: config,
enabledByDefault: isPluginEnabledByDefaultForPlatform(record),
});
return state.enabled && (record.enabled || state.explicitlyEnabled);
}