openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
236 lines (235 loc) • 13.1 kB
JavaScript
import { o as resolveUserPath } from "./home-dir-Dc6nN6HB.mjs";
import "./utils-CitNzLyF.mjs";
import { t as formatCliCommand } from "./command-format-DwEdrDKL.mjs";
import { o as resolveCompatibilityHostVersion } from "./version-D0DaWqMn.mjs";
import { c as resolveOpenClawReleaseCohortVersion, o as parseRegistryNpmSpec } from "./npm-registry-spec-B_IER0ZB.mjs";
import { f as shouldDeferConfiguredPluginInstallRepair } from "./update-phase-YMT_h9sM.mjs";
import { f as resolveEffectiveEnableState, u as normalizePluginsConfig } from "./config-state-Ba1MVBAI.mjs";
import { a as resolveDefaultPluginExtensionsDir, c as resolvePluginInstallDir, d as resolvePluginNpmPackageDir, s as resolveDefaultPluginNpmDir } from "./install-paths-Ik5BUD8W.mjs";
import { A as resolvePluginInstallSources, l as listOfficialExternalPluginCatalogEntries, p as resolveOfficialExternalPluginInstall } from "./official-external-plugin-catalog-BKfROutK.mjs";
import { t as parseClawHubPluginSpec } from "./clawhub-spec-C_XvO17V.mjs";
import { g as resolveOfficialExternalPluginId } from "./official-external-plugin-catalog-source-8hS3NARf.mjs";
import { o as resolveTrustedSourceLinkedOfficialNpmInstall } from "./official-external-install-records-CLRWqPnV.mjs";
import { n as expectedIntegrityForUpdate, r as isPackageVersionDowngrade } from "./package-update-utils-BhTxVhIA.mjs";
import { n as isPayloadMissing } from "./payload-verification-DvsDjVkq.mjs";
import { r as resolveOfficialPluginCohortNpmSpecs, t as detectPluginVersionDrift, x as resolveNpmUpdateTarget } from "./plugin-version-drift-CvcdJs30.mjs";
import { a as collectConfiguredChannelIds, i as collectBlockedPluginIds, o as collectConfiguredPluginIds, r as resolveConfiguredPluginInstallContext, t as collectDownloadableInstallCandidates } from "./missing-configured-plugin-install.candidates-qmENeuGS.mjs";
import path from "node:path";
//#region src/commands/doctor/shared/missing-configured-plugin-install.records.ts
function forceNpmInstallRecordRepair(record) {
if (record.source !== "npm") return record;
const next = { ...record };
delete next.resolvedSpec;
delete next.resolvedVersion;
return next;
}
function installPathsEqual(left, right) {
return path.resolve(left) === path.resolve(right);
}
function resolveLegacyNpmPackageInstallPath(params) {
return path.join(params.npmRoot, "node_modules", ...params.packageName.split("/"));
}
function collectInstalledRecordPackageNames(record) {
const names = record.source === "npm" ? [
record.resolvedName,
record.spec ? parseRegistryNpmSpec(record.spec)?.name : void 0,
record.resolvedSpec ? parseRegistryNpmSpec(record.resolvedSpec)?.name : void 0
] : record.source === "clawhub" ? [record.clawhubPackage, record.spec ? parseClawHubPluginSpec(record.spec)?.name : void 0] : [];
return new Set(names.filter((name) => Boolean(name)));
}
function isTrustedOfficialInstallRecordForCandidate(params) {
const { record, candidate } = params;
if (!record || record.source !== "npm" && record.source !== "clawhub") return false;
if (record.source === "clawhub" && record.clawhubChannel !== "official") return false;
const candidatePackageNames = new Set([candidate.npmSpec ? parseRegistryNpmSpec(candidate.npmSpec)?.name : void 0, candidate.clawhubSpec ? parseClawHubPluginSpec(candidate.clawhubSpec)?.name : void 0].filter((name) => Boolean(name)));
return candidatePackageNames.size > 0 && [...collectInstalledRecordPackageNames(record)].some((name) => candidatePackageNames.has(name));
}
function resolveSafeBrokenOfficialInstallRemovalPath(params) {
const installPath = params.record?.installPath?.trim();
if (!installPath) return null;
const resolvedInstallPath = resolveUserPath(installPath, params.env);
try {
const extensionsDir = resolveDefaultPluginExtensionsDir(params.env);
if (installPathsEqual(resolvedInstallPath, resolvePluginInstallDir(params.pluginId, extensionsDir))) return resolvedInstallPath;
} catch {}
const parsedNpmSpec = params.candidate.npmSpec ? parseRegistryNpmSpec(params.candidate.npmSpec) : null;
if (!parsedNpmSpec?.name) return null;
const npmRoot = resolveDefaultPluginNpmDir(params.env);
return [resolvePluginNpmPackageDir({
packageName: parsedNpmSpec.name,
npmDir: npmRoot
}), resolveLegacyNpmPackageInstallPath({
packageName: parsedNpmSpec.name,
npmRoot
})].some((expectedPath) => installPathsEqual(resolvedInstallPath, expectedPath)) ? resolvedInstallPath : null;
}
function recordMatchesBundledPackage(record, bundled) {
const packageName = bundled.packageName?.trim();
return Boolean(packageName && collectInstalledRecordPackageNames(record).has(packageName));
}
//#endregion
//#region src/commands/doctor/shared/missing-configured-plugin-install.targets.ts
function resolveConfiguredPluginRepairVersions(params) {
const { env } = params;
const { records, updateChannel, operatorManagedPluginIds, bundledPluginsById, officialReplacementPluginIds } = params.context;
const coreVersion = resolveCompatibilityHostVersion(env);
const cohortSpecs = resolveOfficialPluginCohortNpmSpecs({
gatewayVersion: coreVersion,
installRecords: records,
config: params.cfg
});
return {
coreVersion,
cohortSpecs,
newerRecordedPluginIds: new Set(updateChannel === "stable" || updateChannel === "beta" ? Object.keys(cohortSpecs).filter((pluginId) => {
const version = records[pluginId]?.resolvedVersion ?? records[pluginId]?.version;
return version && isPackageVersionDowngrade(resolveOpenClawReleaseCohortVersion(version), resolveOpenClawReleaseCohortVersion(coreVersion));
}) : []),
driftedPluginIds: new Set(params.repairVersionDrift && !shouldDeferConfiguredPluginInstallRepair(env) ? detectPluginVersionDrift({
gatewayVersion: coreVersion,
installRecords: records,
config: params.cfg
}).drifts.flatMap(({ pluginId }) => {
const record = records[pluginId];
if (!record || !cohortSpecs[pluginId] || operatorManagedPluginIds.has(pluginId) || bundledPluginsById.has(pluginId) || officialReplacementPluginIds.has(pluginId)) return [];
if (resolveTrustedSourceLinkedOfficialNpmInstall({
pluginId,
record
})?.replacementPluginId) {
params.onWarning(`Plugin "${pluginId}" needs a package-id migration. Run ${formatCliCommand(`openclaw plugins update ${cohortSpecs[pluginId]}`, env)}.`, pluginId);
return [];
}
return [pluginId];
}) : [])
};
}
function resolveRecordedInstallCandidate(params) {
const record = params.record;
if (!record && params.candidate.trustedSourceLinkedOfficialInstall) {
const packageName = parseRegistryNpmSpec(params.candidate.npmSpec ?? "")?.name;
if (packageName?.startsWith("@openclaw/") && listOfficialExternalPluginCatalogEntries().some((entry) => entry.source === "official" && entry.name === packageName && resolveOfficialExternalPluginId(entry) === params.candidate.pluginId && parseRegistryNpmSpec(resolveOfficialExternalPluginInstall(entry)?.npmSpec ?? "")?.name === packageName)) return {
...params.candidate,
versionBoundToOpenClaw: true
};
}
const recordedSource = record?.source === "npm" || record?.source === "clawhub" ? record.source : void 0;
const parseSpec = recordedSource === "npm" ? parseRegistryNpmSpec : parseClawHubPluginSpec;
const candidateSpec = recordedSource === "npm" ? params.candidate.npmSpec : params.candidate.clawhubSpec;
const staleRuntimeRepair = params.repairReason === "stale-version-bound-runtime";
const declaredSource = recordedSource ? resolvePluginInstallSources(params.candidate, recordedSource)[0] : void 0;
const recordedSpec = staleRuntimeRepair ? declaredSource?.spec : record?.spec ?? declaredSource?.spec;
return record && recordedSource ? {
...params.candidate,
defaultChoice: recordedSource,
...recordedSource === "npm" ? {
npmSpec: recordedSpec,
clawhubSpec: void 0
} : {
clawhubSpec: recordedSpec,
npmSpec: void 0
},
expectedIntegrity: staleRuntimeRepair ? declaredSource?.expectedIntegrity : expectedIntegrityForUpdate(record.spec, record.integrity),
trustedSourceLinkedOfficialInstall: params.candidate.trustedSourceLinkedOfficialInstall && (!record.spec || parseSpec(record.spec)?.name === parseSpec(candidateSpec ?? "")?.name)
} : params.candidate;
}
/** Keep stale-runtime pin replacement behind the same repair admission as doctor. */
function resolveConfiguredPluginCandidateRepair(params) {
const { candidate, context } = params;
if (context.bundledPluginsById.has(candidate.pluginId)) return;
const shouldReplaceBrokenOfficialInstall = context.officialReplacementPluginIds.has(candidate.pluginId);
const record = params.records[candidate.pluginId];
if (shouldReplaceBrokenOfficialInstall && (!candidate.trustedSourceLinkedOfficialInstall || !isTrustedOfficialInstallRecordForCandidate({
record,
candidate
}))) return;
const hasRecord = Object.hasOwn(params.records, candidate.pluginId);
const hasUsableRecord = hasRecord && !isPayloadMissing(params.env, record?.installPath);
if (!shouldReplaceBrokenOfficialInstall && (hasUsableRecord || context.knownIds.has(candidate.pluginId) && !hasRecord)) return;
return {
shouldReplaceBrokenOfficialInstall,
...context.installedPluginIdsWithStaleVersionBoundRuntimePackages.has(candidate.pluginId) && !context.installedPluginIdsWithRepairablePackageDiagnostics.has(candidate.pluginId) && !context.configuredPluginIdsWithStaleDescriptors.has(candidate.pluginId) && hasUsableRecord ? { repairReason: "stale-version-bound-runtime" } : {}
};
}
/** Metadata-only inventory for the same npm targets used by post-core sync and repair. */
async function collectConfiguredNpmPluginTargets(params) {
const configuredPluginIds = collectConfiguredPluginIds(params.config, params.env);
const configuredChannelIds = collectConfiguredChannelIds(params.config, params.env);
if (configuredPluginIds.size === 0 && configuredChannelIds.size === 0) return [];
const blockedPluginIds = collectBlockedPluginIds(params.config);
const context = await resolveConfiguredPluginInstallContext({
cfg: params.config,
env: params.env,
configuredPluginIds,
configuredChannelIds,
blockedPluginIds,
baselineRecords: params.installRecords,
coreVersion: params.targetVersion
});
const candidates = new Map(collectDownloadableInstallCandidates({
cfg: params.config,
env: params.env,
configuredPluginIds,
configuredChannelIds,
configuredChannelOwnerPluginIds: context.configuredChannelOwnerPluginIds,
blockedPluginIds,
missingPluginIds: /* @__PURE__ */ new Set()
}).map((candidate) => [candidate.pluginId, candidate]));
const normalizedConfig = normalizePluginsConfig(params.config.plugins);
const targets = [];
const pluginIds = /* @__PURE__ */ new Set([
...configuredPluginIds,
...candidates.keys(),
...[...context.configuredChannelOwnerPluginIds.values()].flatMap((ids) => Array.from(ids))
]);
for (const pluginId of pluginIds) {
const record = context.records[pluginId];
if (context.operatorManagedPluginIds.has(pluginId) || context.bundledPluginsById.has(pluginId) || record && (record.source !== "npm" || record.artifactKind || record.sourcePath) || !resolveEffectiveEnableState({
id: pluginId,
origin: "global",
config: normalizedConfig,
rootConfig: params.config
}).enabled) continue;
const candidate = candidates.get(pluginId);
const repair = candidate && resolveConfiguredPluginCandidateRepair({
candidate,
records: context.records,
env: params.env,
context
});
if (candidate && repair) {
const selected = resolveRecordedInstallCandidate({
candidate,
record,
repairReason: repair.repairReason
});
const source = resolvePluginInstallSources(selected, record?.source === "npm" ? "npm" : void 0)[0];
if (source?.source === "npm" && parseRegistryNpmSpec(source.spec)) targets.push({
pluginId,
spec: source.spec,
updateChannel: params.channel,
coreVersion: params.targetVersion,
officialPackageName: selected.trustedSourceLinkedOfficialInstall ? parseRegistryNpmSpec(source.spec)?.name : void 0,
versionBoundToCore: selected.versionBoundToOpenClaw
});
} else if (record?.source === "npm") {
const { target } = resolveNpmUpdateTarget({
record,
trustedOfficialInstall: resolveTrustedSourceLinkedOfficialNpmInstall({
pluginId,
record
}),
syncOfficialPluginInstalls: true,
updateChannel: params.channel,
coreVersion: params.targetVersion,
versionBoundToCore: candidate?.versionBoundToOpenClaw
});
if (target && parseRegistryNpmSpec(target.spec)) targets.push({
pluginId,
...target
});
}
}
return targets.toSorted((left, right) => left.pluginId.localeCompare(right.pluginId));
}
//#endregion
export { forceNpmInstallRecordRepair as a, resolveLegacyNpmPackageInstallPath as c, resolveRecordedInstallCandidate as i, resolveSafeBrokenOfficialInstallRemovalPath as l, resolveConfiguredPluginCandidateRepair as n, installPathsEqual as o, resolveConfiguredPluginRepairVersions as r, recordMatchesBundledPackage as s, collectConfiguredNpmPluginTargets as t };