openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
127 lines (126 loc) • 5.58 kB
JavaScript
import { l as normalizePluginsConfig, u as resolveEffectiveEnableState } from "./config-state-BkU1frVq.js";
import { c as resolveOpenClawReleaseCohortVersion, o as parseRegistryNpmSpec } from "./npm-registry-spec-CM_p1_uq.js";
import { t as parseClawHubPluginSpec } from "./clawhub-spec-Er3Np6VI.js";
import { l as resolveTrustedSourceLinkedOfficialNpmSpec, o as resolveTrustedSourceLinkedOfficialClawHubInstall } from "./official-external-install-records-DClkub0e.js";
import { t as fetchNpmPackageTargetStatus } from "./update-check-package-target-Dqu75aaM.js";
//#region src/plugins/plugin-version-drift.ts
function resolveExactNpmPinPackageName(entry) {
if (entry.source !== "npm" || !entry.spec) return;
const parsed = parseRegistryNpmSpec(entry.spec);
if (parsed?.selectorKind !== "exact-version") return;
return parsed.name;
}
/** Exact npm pins need a registry-confirmed package@version target; id-only updates preserve pins. */
function resolvePluginVersionDriftUpdateCommand(entry) {
const exactNpmPackageName = resolveExactNpmPinPackageName(entry);
if (exactNpmPackageName) {
if (entry.targetResolution?.status !== "resolved" || entry.targetResolution.packageName !== exactNpmPackageName || entry.targetResolution.requestedTarget !== resolveOpenClawReleaseCohortVersion(entry.gatewayVersion)) return;
const exactNpmTarget = `${exactNpmPackageName}@${entry.targetResolution.version}`;
if (parseRegistryNpmSpec(exactNpmTarget)?.selectorKind === "exact-version") return `openclaw plugins update ${exactNpmTarget}`;
return;
}
return `openclaw plugins update ${entry.pluginId}`;
}
async function resolveEntryTarget(entry) {
const packageName = resolveExactNpmPinPackageName(entry);
if (!packageName) return entry;
const requestedTarget = resolveOpenClawReleaseCohortVersion(entry.gatewayVersion);
const requestedSpec = `${packageName}@${requestedTarget}`;
const result = parseRegistryNpmSpec(requestedSpec)?.selectorKind === "exact-version" ? await fetchNpmPackageTargetStatus({
packageName,
target: requestedTarget
}) : {
version: null,
error: "gateway release cohort is not an exact npm version"
};
const targetResolution = result.version === requestedTarget ? {
status: "resolved",
packageName,
requestedTarget,
version: requestedTarget
} : {
status: "unresolved",
packageName,
requestedTarget,
error: `npm registry did not resolve ${requestedSpec}: ${result.error ?? `returned ${JSON.stringify(result.version)}`}`
};
return {
...entry,
targetResolution
};
}
/** Resolve exact npm repair targets only for diagnostics that display repair guidance. */
async function resolvePluginVersionDriftTargets(report) {
return {
...report,
drifts: await Promise.all(report.drifts.map(resolveEntryTarget))
};
}
function isPluginEnabled(config, pluginId) {
const normalizedPluginConfig = normalizePluginsConfig(config?.plugins);
return resolveEffectiveEnableState({
id: pluginId,
origin: "global",
config: normalizedPluginConfig,
rootConfig: config
}).enabled;
}
function shouldCompareOfficialInstallToGateway(params) {
const officialNpmSpec = resolveTrustedSourceLinkedOfficialNpmSpec(params);
if (officialNpmSpec) return parseRegistryNpmSpec(officialNpmSpec)?.selectorKind !== "exact-version";
const officialClawHubInstall = resolveTrustedSourceLinkedOfficialClawHubInstall(params);
if (officialClawHubInstall) {
if (officialClawHubInstall.clawhubSpec) return !parseClawHubPluginSpec(officialClawHubInstall.clawhubSpec)?.version;
return parseRegistryNpmSpec(officialClawHubInstall.npmSpec ?? "")?.selectorKind !== "exact-version";
}
return false;
}
function hasOfficialPluginVersionCandidates(params) {
return Object.entries(params.installRecords).some(([pluginId, record]) => Boolean(record) && isPluginEnabled(params.config, pluginId) && shouldCompareOfficialInstallToGateway({
pluginId,
record
}));
}
/**
* Compare active official external plugin installs against an OpenClaw host
* version and return any mismatches.
*
* @param params.gatewayVersion The host version the plugins must match.
* @param params.installRecords The full set of recorded plugin installs (as
* produced by `loadInstalledPluginIndexInstallRecords`).
* @param params.config The merged daemon-side OpenClawConfig (optional).
* Plugins inactive under the effective activation policy are skipped.
*
* The returned `drifts` list is sorted by `pluginId` for stable output.
*/
function detectPluginVersionDrift(params) {
const { gatewayVersion, installRecords, config } = params;
const normalizedGateway = resolveOpenClawReleaseCohortVersion(gatewayVersion);
const drifts = [];
for (const [pluginId, record] of Object.entries(installRecords)) {
if (!record) continue;
if (!isPluginEnabled(config, pluginId)) continue;
if (!shouldCompareOfficialInstallToGateway({
pluginId,
record
})) continue;
const installedVersion = record.resolvedVersion ?? record.version;
if (!installedVersion) continue;
if (resolveOpenClawReleaseCohortVersion(installedVersion) === normalizedGateway) continue;
drifts.push({
pluginId,
installedVersion,
gatewayVersion,
source: record.source,
...record.resolvedName ? { packageName: record.resolvedName } : {},
...record.spec ? { spec: record.spec } : {}
});
}
drifts.sort((a, b) => a.pluginId.localeCompare(b.pluginId));
return {
gatewayVersion,
drifts
};
}
//#endregion
export { resolvePluginVersionDriftUpdateCommand as i, hasOfficialPluginVersionCandidates as n, resolvePluginVersionDriftTargets as r, detectPluginVersionDrift as t };