openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
376 lines (375 loc) • 18.6 kB
JavaScript
import { f as withPluginCache, i as createPluginCache, l as getProcessPluginCache } from "./plugin-cache-DGWspMEc.js";
import { l as normalizeOptionalString } from "./string-coerce-CIXf7egm.js";
import { y as resolveIsNixMode } from "./paths-D2sRr1a_.js";
import { o as redactSensitiveUrlLikeString } from "./redact-sensitive-url-BN1NZvXG.js";
import { a as getProcessGatewayPluginMetadataSnapshot } from "./current-plugin-metadata-state-B1UoAr4G.js";
import { i as isInstalledPluginEnabled, t as createInstalledPluginEnabledPredicate } from "./installed-plugin-index-wrDsjyMD.js";
import { a as projectPluginDependencyHealth, r as buildPluginDependencyStatus } from "./discovery-D_VDsZuY.js";
import { o as getOfficialExternalPluginCatalogManifest, p as listOfficialExternalPluginCatalogEntries, v as resolveOfficialExternalPluginId, x as resolveOfficialExternalPluginLabel } from "./official-external-plugin-catalog-Dzu7dwBN.js";
import { a as loadPluginMetadataSnapshot, c as resolvePluginMetadataSnapshot } from "./plugin-metadata-snapshot-w-4EjxI4.js";
import { n as resolvePluginControlPlaneWorkspace, t as appendPluginControlPlaneWorkspaceDiagnostic } from "./control-plane-workspace-BWhgt2gz.js";
import { t as createInstalledPluginOwnershipResolver } from "./installed-plugin-package-ownership-DGTVMT4h.js";
import { n as resolveConfigWidePluginMetadataSnapshot } from "./io.plugin-metadata-BruF5izX.js";
import { t as ManagedPluginLifecycleError } from "./management-lifecycle-error-BlJhejU6.js";
import { a as tracksPluginDependencyStatus } from "./official-external-plugin-repair-hints-CXeFydKX.js";
import { r as resolveManifestProviderAuthChoices } from "./provider-auth-choices-DsRM415K.js";
import { t as listRecommendedToolInstalls } from "./recommended-tool-installs-Bwv75ix-.js";
import { a as formatPluginCapabilityConsentRequired, c as resolvePluginInstallRecordIntegrity, l as resolvePluginInstallRecordTrust, n as buildPluginCapabilitySummary, r as computeDeclaredSurfaceHash, s as resolveAcceptedSurfaceCurrent, u as resolvePluginPackageDeclaredSurface } from "./capability-summary-BLe-gZ01.js";
import { i as resolvePendingPluginCapabilityReview } from "./capability-consent-DAQVy0Fy.js";
import { a as getManagedPluginCache, c as normalizeFeaturedAt, d as prepareCatalogEntry, f as resolveInstalledHostedOfficialEntry, h as withManagedPluginCache, i as firstPluginError, l as normalizeKinds, m as resolveOfficialEntryById, n as compareCatalogEntries, o as loadOfficialCatalog, p as resolveInstalledPluginPresentation, r as derivePluginCategory, s as normalizeCatalogMetadata, u as prepareCatalogEntries } from "./management-catalog-CoNziW12.js";
//#region src/plugins/management-service.ts
function resolveManagedPluginDiagnostics(snapshot, config) {
const dependencies = getManagedPluginCache().dependencyStatus;
const isEnabled = createInstalledPluginEnabledPredicate(snapshot.index.plugins, config);
const { diagnostics } = projectPluginDependencyHealth({
plugins: snapshot.index.plugins.map((record) => {
const manifest = snapshot.byPluginId.get(record.pluginId);
const enabled = isEnabled(record.pluginId);
if (manifest && !dependencies.has(manifest) && tracksPluginDependencyStatus(record)) dependencies.set(manifest, buildPluginDependencyStatus({
rootDir: record.rootDir,
dependencies: manifest.packageDependencies,
optionalDependencies: manifest.packageOptionalDependencies
}));
return {
id: record.pluginId,
source: manifest?.source ?? record.source ?? record.manifestPath,
enabled,
status: enabled ? "loaded" : "disabled",
dependencyStatus: manifest ? dependencies.get(manifest) : void 0
};
}),
diagnostics: [...snapshot.diagnostics]
});
return diagnostics;
}
function resolvePluginIconSource(params) {
const normalizedPluginId = params.metadata.normalizePluginId(params.pluginId);
const manifest = params.metadata.byPluginId.get(normalizedPluginId);
const localIconPath = normalizeOptionalString(manifest?.iconPath);
if (localIconPath && manifest) return {
kind: "file",
path: localIconPath,
rootPath: manifest.rootDir
};
}
function resolveManagedPluginMetadataParams(config, env) {
const workspace = resolvePluginControlPlaneWorkspace({
config,
env
});
return {
config,
env,
...workspace.workspaceDir !== void 0 ? { workspaceDir: workspace.workspaceDir } : {}
};
}
function resolveManagedPluginMetadata(config, env) {
const boot = getProcessGatewayPluginMetadataSnapshot();
const candidate = getProcessPluginCache().desiredMetadata;
return candidate && candidate.boot === boot ? candidate.snapshot : resolvePluginMetadataSnapshot(resolveManagedPluginMetadataParams(config, env));
}
function loadFreshManagedPluginMetadata(config, env) {
return getProcessGatewayPluginMetadataSnapshot() ? resolveConfigWidePluginMetadataSnapshot({
config,
env,
allowCurrent: false
}) : loadPluginMetadataSnapshot({
...resolveManagedPluginMetadataParams(config, env),
allowCurrent: false
});
}
/** Publish desired install state for management without replacing the Gateway's boot facts. */
function refreshManagedPluginMetadata(params) {
const env = params.env ?? process.env;
const boot = getProcessGatewayPluginMetadataSnapshot();
const cache = createPluginCache();
const snapshot = withPluginCache(cache, () => loadFreshManagedPluginMetadata(params.config, env));
if (boot) getProcessPluginCache().desiredMetadata = {
boot,
cache,
snapshot
};
return snapshot;
}
/** Resolve the current package-local icon without accepting caller-provided input. */
const resolveManagedPluginIconSource = withManagedPluginCache(async (params) => {
const env = params.env ?? process.env;
return resolvePluginIconSource({
metadata: resolveManagedPluginMetadata(params.config, env),
pluginId: params.pluginId
});
});
function normalizeManagedCatalogIconUrl(value) {
const normalized = normalizeOptionalString(value);
if (!normalized || normalized.length > 2048) return;
try {
const url = new URL(normalized);
return url.protocol === "https:" && url.hostname && !url.username && !url.password && !url.hash ? url.href : void 0;
} catch {
return;
}
}
/** Resolve only URLs currently owned by a manifest or bundled presentation catalog. */
function resolveManagedSetupCatalogIconUrl(params) {
const requested = normalizeManagedCatalogIconUrl(params.iconUrl);
if (!requested) return;
const env = params.env ?? process.env;
return [...resolveManifestProviderAuthChoices({
config: params.config,
env,
includeUntrustedWorkspacePlugins: false,
includeWorkspacePlugins: false
}).map((choice) => choice.icon), ...listRecommendedToolInstalls().map((install) => install.icon)].some((iconUrl) => normalizeManagedCatalogIconUrl(iconUrl) === requested) ? requested : void 0;
}
/** Build cold installed state merged with the hosted official catalog and bundled curation. */
const listManagedPlugins = withManagedPluginCache(async (params) => {
const env = params.env ?? process.env;
const workspace = resolvePluginControlPlaneWorkspace({
config: params.config,
env
});
const metadata = params.metadata ?? resolveManagedPluginMetadata(params.config, env);
const pluginDiagnostics = resolveManagedPluginDiagnostics(metadata, params.config);
const officialCatalog = params.officialCatalog ?? await loadOfficialCatalog();
const officialEntries = prepareCatalogEntries(officialCatalog.entries);
const bundledOfficialEntries = prepareCatalogEntries(listOfficialExternalPluginCatalogEntries());
const installedIconsById = /* @__PURE__ */ new Map();
const installedClawHubPackages = /* @__PURE__ */ new Set();
const capabilityConsentDiagnostics = [];
const isEnabled = createInstalledPluginEnabledPredicate(metadata.index.plugins, params.config, env);
const ownershipResolver = createInstalledPluginOwnershipResolver(metadata.index);
const plugins = metadata.index.plugins.map((record) => {
const enabled = isEnabled(record.pluginId);
const manifest = metadata.byPluginId.get(record.pluginId);
const localCatalog = normalizeCatalogMetadata(manifest?.catalog);
const ownership = ownershipResolver.resolvePackage(record.pluginId);
const installOwner = ownership.ok ? ownership.value.installOwner : void 0;
const installRecord = installOwner ? metadata.index.installRecords[installOwner] : void 0;
if (enabled && record.origin !== "bundled" && !manifest?.trustedOfficialInstall && ownership.ok && installRecord) {
const declared = resolvePluginPackageDeclaredSurface(ownership.value, metadata.byPluginId);
if (!declared || !resolveAcceptedSurfaceCurrent(installRecord, declared)) capabilityConsentDiagnostics.push({
level: "warn",
pluginId: record.pluginId,
message: formatPluginCapabilityConsentRequired(record.pluginId)
});
}
const { entry: officialEntry, clawhubPackage } = resolveInstalledHostedOfficialEntry({
record,
...installOwner ? { installOwner } : {},
installRecord,
officialEntries,
bundledOfficialEntries
});
if (clawhubPackage) installedClawHubPackages.add(clawhubPackage);
const officialCatalogMetadata = officialEntry ? normalizeCatalogMetadata(getOfficialExternalPluginCatalogManifest(officialEntry)?.catalog) : void 0;
const catalog = clawhubPackage && officialCatalog.hostedFeaturedAuthoritative ? {
...localCatalog,
...officialCatalogMetadata,
featured: officialEntry?.featured === true
} : officialCatalogMetadata ? {
...localCatalog,
...officialCatalogMetadata
} : localCatalog;
const error = firstPluginError(pluginDiagnostics, record.pluginId);
const kind = normalizeKinds(manifest?.kind);
const category = derivePluginCategory(manifest);
const removable = record.origin !== "bundled" && Boolean(installOwner);
const hostedListingAuthoritative = Boolean(clawhubPackage) && officialCatalog.hostedFeaturedAuthoritative === true;
const featuredAt = hostedListingAuthoritative && catalog?.featured === true ? normalizeFeaturedAt(officialEntry?.featuredAt) : void 0;
const presentation = resolveInstalledPluginPresentation({
record,
manifest,
officialEntry,
hostedListingAuthoritative
});
const plugin = {
id: record.pluginId,
name: presentation.name,
installed: true,
enabled,
state: error ? "error" : enabled ? "enabled" : "disabled",
removable
};
if (record.packageName) plugin.packageName = record.packageName;
if (presentation.description) plugin.description = presentation.description;
if (presentation.version) plugin.version = presentation.version;
if (kind) plugin.kind = kind;
if (record.origin) plugin.origin = record.origin;
if (catalog?.featured !== void 0) plugin.featured = catalog.featured;
if (featuredAt !== void 0) plugin.featuredAt = featuredAt;
if (catalog?.order !== void 0) plugin.order = catalog.order;
const normalizedPluginId = metadata.normalizePluginId(record.pluginId);
if (!installedIconsById.has(normalizedPluginId)) installedIconsById.set(normalizedPluginId, resolvePluginIconSource({
metadata,
pluginId: record.pluginId
}));
if (installedIconsById.get(normalizedPluginId)) plugin.hasIcon = true;
if (error) plugin.error = error;
if (category) plugin.category = category;
return plugin;
});
const installedIds = new Set(plugins.map((plugin) => plugin.id));
const installedPackageNames = new Set(plugins.flatMap((plugin) => plugin.packageName ? [plugin.packageName] : []));
for (const facts of officialEntries()) {
const { entry, clawhub, npmPackage } = facts;
const pluginId = resolveOfficialExternalPluginId(entry);
const manifest = getOfficialExternalPluginCatalogManifest(entry);
const manifestCatalog = normalizeCatalogMetadata(manifest?.catalog);
const catalog = manifestCatalog || typeof entry.featured === "boolean" ? {
...manifestCatalog,
...manifestCatalog?.featured === void 0 && typeof entry.featured === "boolean" ? { featured: entry.featured } : {}
} : void 0;
if (!pluginId || !catalog || installedIds.has(pluginId) || clawhub && (installedPackageNames.has(clawhub.name) || installedClawHubPackages.has(clawhub.name)) || npmPackage && installedPackageNames.has(npmPackage)) continue;
const kind = normalizeKinds(entry.kind);
const install = facts.selectedSource?.source === "clawhub" && clawhub && !clawhub.version ? {
source: "clawhub",
packageName: clawhub.name
} : facts.install ? {
source: "official",
pluginId
} : void 0;
const packageName = npmPackage ?? clawhub?.name;
const description = normalizeOptionalString(entry.description);
const version = normalizeOptionalString(entry.version);
const featuredAt = catalog.featured === true ? normalizeFeaturedAt(entry.featuredAt) : void 0;
plugins.push({
id: pluginId,
name: resolveOfficialExternalPluginLabel(entry),
...packageName ? { packageName } : {},
...description ? { description } : {},
...version ? { version } : {},
...kind ? { kind } : {},
origin: "official",
installed: false,
enabled: false,
state: "not-installed",
...catalog.featured !== void 0 ? { featured: catalog.featured } : {},
...featuredAt !== void 0 ? { featuredAt } : {},
...catalog.order !== void 0 ? { order: catalog.order } : {},
...install ? { install } : {}
});
}
const diagnostics = getProcessGatewayPluginMetadataSnapshot() ? [...pluginDiagnostics, ...capabilityConsentDiagnostics] : appendPluginControlPlaneWorkspaceDiagnostic([...pluginDiagnostics, ...capabilityConsentDiagnostics], workspace);
if (officialCatalog.error) diagnostics.push({
level: "warn",
message: `Official plugin catalog fallback: ${officialCatalog.error}`
});
return {
plugins: plugins.toSorted(compareCatalogEntries),
diagnostics,
mutationAllowed: !resolveIsNixMode(env)
};
});
/** Inspect one plugin's manifest, operator grants, and recorded install provenance. */
const inspectManagedPlugin = withManagedPluginCache(async (params) => {
const env = params.env ?? process.env;
const metadata = resolveManagedPluginMetadata(params.config, env);
const pluginId = metadata.normalizePluginId(params.pluginId);
const record = metadata.index.plugins.find((candidate) => candidate.pluginId === pluginId);
const enabled = isInstalledPluginEnabled(metadata.index, pluginId, params.config);
const pendingReview = resolvePendingPluginCapabilityReview(pluginId);
if (pendingReview) return {
ok: true,
plugin: {
id: pluginId,
name: pendingReview.name,
...pendingReview.version ? { version: pendingReview.version } : {},
...record?.origin ? { origin: record.origin } : {},
installed: Boolean(record),
enabled
},
declared: pendingReview.declared,
grants: pendingReview.grants,
reviewToken: pendingReview.reviewToken,
...pendingReview.source ? { source: pendingReview.source } : {},
...pendingReview.trust ? { trust: pendingReview.trust } : {}
};
const officialCatalog = await loadOfficialCatalog();
if (record) {
const manifest = metadata.byPluginId.get(pluginId);
const ownership = createInstalledPluginOwnershipResolver(metadata.index, env).resolvePackage(pluginId);
const installOwner = ownership.ok ? ownership.value.installOwner : void 0;
const installRecord = installOwner ? metadata.index.installRecords[installOwner] : void 0;
const { entry: officialEntry, clawhubPackage } = resolveInstalledHostedOfficialEntry({
record,
...installOwner ? { installOwner } : {},
installRecord,
officialEntries: prepareCatalogEntries(officialCatalog.entries),
bundledOfficialEntries: prepareCatalogEntries(listOfficialExternalPluginCatalogEntries())
});
const spec = installRecord?.resolvedSpec ?? installRecord?.spec;
const packageName = installRecord?.clawhubPackage ?? record.packageName;
const source = installRecord ? {
kind: installRecord.source,
...spec ? { spec: redactSensitiveUrlLikeString(spec) } : {},
...packageName ? { packageName } : {},
...resolvePluginInstallRecordIntegrity(installRecord)
} : record.origin === "bundled" ? { kind: "bundled" } : void 0;
const trust = resolvePluginInstallRecordTrust(installRecord);
const summary = buildPluginCapabilitySummary({
manifest: manifest ?? {},
origin: record.origin,
entryConfig: params.config.plugins?.entries?.[pluginId]
});
const declared = ownership.ok ? resolvePluginPackageDeclaredSurface(ownership.value, metadata.byPluginId) : summary.declared;
if (!declared) throw new ManagedPluginLifecycleError(`Plugin package "${installOwner}" has incomplete manifest metadata.`);
return {
ok: true,
plugin: {
id: pluginId,
...resolveInstalledPluginPresentation({
record,
manifest,
officialEntry,
hostedListingAuthoritative: Boolean(clawhubPackage) && officialCatalog.hostedFeaturedAuthoritative === true
}),
origin: record.origin,
installed: true,
enabled
},
...source ? { source } : {},
...summary,
declared,
reviewToken: computeDeclaredSurfaceHash(declared),
...trust ? { trust } : {}
};
}
const entry = resolveOfficialEntryById(officialCatalog.entries, pluginId);
if (!entry) throw new ManagedPluginLifecycleError(`Plugin "${pluginId}" not found.`, { kind: "invalid-request" });
const manifest = getOfficialExternalPluginCatalogManifest(entry);
const { selectedSource, clawhub, npmPackage } = prepareCatalogEntry(entry);
const packageName = npmPackage ?? clawhub?.name;
const spec = selectedSource?.spec;
const description = normalizeOptionalString(entry.description);
const version = normalizeOptionalString(entry.version);
const summary = buildPluginCapabilitySummary({
manifest: manifest ?? {},
origin: "official",
entryConfig: params.config.plugins?.entries?.[pluginId]
});
return {
ok: true,
plugin: {
id: pluginId,
name: resolveOfficialExternalPluginLabel(entry),
...version ? { version } : {},
...description ? { description } : {},
origin: "official",
installed: false,
enabled: false
},
source: {
kind: "official-catalog",
...spec ? { spec: redactSensitiveUrlLikeString(spec) } : {},
...packageName ? { packageName } : {},
...selectedSource?.expectedIntegrity ? {
integrity: selectedSource.expectedIntegrity,
integrityKind: selectedSource.source === "clawhub" ? "sha256" : "ssri"
} : {}
},
...summary,
reviewToken: computeDeclaredSurfaceHash(summary.declared)
};
});
//#endregion
export { resolveManagedPluginIconSource as a, refreshManagedPluginMetadata as i, listManagedPlugins as n, resolveManagedSetupCatalogIconUrl as o, loadFreshManagedPluginMetadata as r, inspectManagedPlugin as t };