openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
551 lines (550 loc) • 29.4 kB
JavaScript
import { c as normalizeOptionalLowercaseString } from "./string-coerce-6kR-86XC.mjs";
import { o as resolveUserPath } from "./home-dir-CjKH62jd.mjs";
import { r as asNullableRecord } from "./record-coerce-TIsquoVR.mjs";
import "./utils-DUAwk2p5.mjs";
import { o as resolveCompatibilityHostVersion } from "./version-Dx-YMDJx.mjs";
import { o as parseRegistryNpmSpec, t as compareOpenClawReleaseVersions } from "./npm-registry-spec-CwucyVOH.mjs";
import { c as normalizeUpdateChannel, d as resolveRegistryUpdateChannel } from "./update-channels-YuXTW0De.mjs";
import { a as safeRealpathSync } from "./path-safety-DRBJanJw.mjs";
import { l as normalizePluginsConfig, u as resolveEffectiveEnableState } from "./config-state-1t-kMQI9.mjs";
import { l as readLegacyNpmPluginDeclaration } from "./discovery-TE84EnHS.mjs";
import { a as resolveDefaultPluginExtensionsDir, c as resolvePluginInstallDir } from "./install-paths-CQIvSOuc.mjs";
import { n as isBundledPluginInsideDevSourceRoot } from "./dev-source-root-B4IA7d5A.mjs";
import { i as normalizePluginDependencySpecs, r as findMissingRequiredPluginDependencies } from "./status-dependencies-core-B3nwlrO9.mjs";
import { S as resolveOfficialExternalWebProviderContractPluginIdsForEnv, a as isExternallyDistributedPlugin, b as resolveOfficialExternalProviderPluginIds, h as resolveOfficialExternalPluginLabel, l as listOfficialExternalPluginCatalogEntries, p as resolveOfficialExternalPluginInstall, x as resolveOfficialExternalProviderPluginIdsForEnv, y as resolveOfficialExternalProviderContractPluginIds } from "./official-external-plugin-catalog-CZ7h6ORJ.mjs";
import { r as loadInstalledPluginIndexInstallRecords } from "./installed-plugin-index-record-reader--X-E60FV.mjs";
import { o as resolveRetainedManagedNpmInstallPackageInfo } from "./managed-npm-retention-CFCUY_j6.mjs";
import { g as resolveOfficialExternalPluginId } from "./official-external-plugin-catalog-source-CqaCy6HX.mjs";
import { t as loadPluginManifestRegistryCore } from "./manifest-registry-BDeOg_e6.mjs";
import { t as createInstalledPluginOwnershipResolver } from "./installed-plugin-package-ownership-CTxkgTfv.mjs";
import { u as resolveConfiguredChannelPresencePolicy } from "./channel-presence-policy-DyxxRfG3.mjs";
import { n as resolveWebSearchInstallCatalogEntriesForEnv, r as resolveWebSearchInstallCatalogEntry } from "./web-search-install-catalog-D0dXY_SO.mjs";
import { i as isNativeSessionCatalogOptOutOnly } from "./native-session-catalog-config-Cw2NJHbW.mjs";
import { c as loadManifestMetadataSnapshot } from "./manifest-contract-eligibility-CVKBkXZ7.mjs";
import { r as removePluginInstallRecordFromRecords } from "./installed-plugin-index-records-CH0xW_k-.mjs";
import { v as collectConfiguredMemoryEmbeddingProviderIds } from "./gateway-startup-plugin-config-J-HqkJwK.mjs";
import { t as collectConfiguredSpeechProviderIds } from "./gateway-startup-speech-providers-D2_4jw3X.mjs";
import "./gateway-startup-plugin-ids-CXPV_6da.mjs";
import "./channel-plugin-ids-BpFuIDEj.mjs";
import { t as listDoctorConfiguredChannelIds } from "./configured-channel-ids-DbzC7xIV.mjs";
import { n as VERSION_BOUND_RUNTIME_PLUGIN_IDS, t as CONFIGURED_RUNTIME_PLUGIN_INSTALL_CANDIDATES } from "./configured-runtime-plugin-installs-F3Exu4DH.mjs";
import { n as isPayloadMissing } from "./payload-verification-C2ZVncEI.mjs";
import { r as listRawChannelPluginCatalogEntries } from "./catalog-C6eZwcjP.mjs";
import { n as resolveProviderInstallCatalogEntries } from "./provider-install-catalog-Dm2vJFRw.mjs";
import { n as collectConfiguredModelProviderSelectionIds, r as collectConfiguredProviderSelectionIds, t as collectConfiguredMediaProviderSelectionIds } from "./configured-provider-selection-ids-BVgkjeXE.mjs";
import { t as collectConfiguredRuntimePluginIds } from "./configured-runtime-plugin-owners-CglIfcXH.mjs";
import path from "node:path";
//#region src/commands/doctor/shared/missing-configured-plugin-install.dependency-health.ts
/** Collects dependency failures only for enabled, canonically recorded npm installs. */
async function collectInstalledPluginMissingRequiredDependencies(params) {
const missing = /* @__PURE__ */ new Map();
const config = normalizePluginsConfig(params.cfg.plugins);
for (const plugin of params.snapshot.plugins) {
const record = Object.hasOwn(params.installRecords, plugin.id) ? params.installRecords[plugin.id] : void 0;
if (!params.isRepairTarget(plugin.id) || plugin.origin === "bundled" || params.blockedPluginIds?.has(plugin.id) || record?.source !== "npm" || !record.installPath?.trim() || !record.spec?.trim()) continue;
const spec = parseRegistryNpmSpec(record.spec);
if (!spec || plugin.packageName !== spec.name || record.resolvedName && record.resolvedName !== spec.name || !resolveEffectiveEnableState({
id: plugin.id,
origin: plugin.origin,
config,
rootConfig: params.cfg,
enabledByDefault: plugin.enabledByDefault,
channelIds: plugin.channels
}).enabled) continue;
const rootDir = params.resolvePathIdentity(plugin.rootDir);
if (rootDir !== params.resolvePathIdentity(record.installPath)) continue;
const missingRequired = await findMissingRequiredPluginDependencies({
rootDir,
dependencyRootDir: resolveRetainedManagedNpmInstallPackageInfo(rootDir)?.projectRoot ?? rootDir,
...normalizePluginDependencySpecs({
dependencies: plugin.packageDependencies,
optionalDependencies: plugin.packageOptionalDependencies
})
});
if (missingRequired.length > 0) missing.set(plugin.id, {
rootDir,
missingRequired
});
}
return missing;
}
//#endregion
//#region src/commands/doctor/shared/configured-provider-plugin-ids.ts
/** Lists official external provider plugins without loading installed plugin registries. */
function collectConfiguredOfficialProviderPluginIds(params) {
const configuredProviderIds = collectConfiguredModelProviderSelectionIds(params.cfg);
const configuredMediaProviderIds = collectConfiguredMediaProviderSelectionIds(params.cfg);
const pluginIds = new Set(resolveOfficialExternalProviderPluginIds({ providerIds: configuredProviderIds }));
for (const pluginId of resolveOfficialExternalProviderPluginIdsForEnv(params.env ?? process.env)) pluginIds.add(pluginId);
for (const pluginId of resolveOfficialExternalProviderContractPluginIds({
contract: "mediaUnderstandingProviders",
providerIds: configuredMediaProviderIds
})) pluginIds.add(pluginId);
for (const pluginId of resolveOfficialExternalProviderContractPluginIds({
contract: "speechProviders",
providerIds: configuredProviderIds
})) pluginIds.add(pluginId);
return [...pluginIds].toSorted((left, right) => left.localeCompare(right));
}
//#endregion
//#region src/commands/doctor/shared/configured-provider-plugin-installs.ts
/** Lists external provider plugins implied by configured auth profiles and model refs. */
function collectConfiguredProviderPluginIds(params) {
const selectedProviderIds = collectConfiguredProviderSelectionIds(params.cfg);
const pluginIds = new Set(collectConfiguredOfficialProviderPluginIds(params));
if (selectedProviderIds.size > 0) {
for (const entry of resolveProviderInstallCatalogEntries({
config: params.cfg,
env: params.env,
includeUntrustedWorkspacePlugins: false
})) if ([entry.providerId, ...entry.providerAliases ?? []].some((providerId) => selectedProviderIds.has(providerId.toLowerCase()))) pluginIds.add(entry.pluginId);
}
return [...pluginIds].toSorted((left, right) => left.localeCompare(right));
}
//#endregion
//#region src/commands/doctor/shared/missing-configured-plugin-install.ids.ts
function addConfiguredPluginId(ids, value) {
if (typeof value !== "string") return;
const pluginId = value.trim();
if (pluginId) ids.add(pluginId);
}
function addConfiguredMemoryEmbeddingProviderPluginIds(ids, cfg) {
const configuredProviderIds = collectConfiguredMemoryEmbeddingProviderIds(cfg);
if (configuredProviderIds.size === 0) return;
for (const pluginId of resolveOfficialExternalProviderContractPluginIds({
contract: "embeddingProviders",
providerIds: configuredProviderIds
})) ids.add(pluginId);
}
function addConfiguredSpeechProviderPluginIds(ids, cfg) {
for (const pluginId of resolveOfficialExternalProviderContractPluginIds({
contract: "speechProviders",
providerIds: collectConfiguredSpeechProviderIds(cfg)
})) ids.add(pluginId);
}
function addConfiguredWebFetchProviderPluginIds(ids, cfg) {
const webFetch = cfg.tools?.web?.fetch;
if (webFetch?.enabled === false) return;
const providerId = normalizeOptionalLowercaseString(webFetch?.provider);
if (!providerId) return;
for (const pluginId of resolveOfficialExternalProviderContractPluginIds({
contract: "webFetchProviders",
providerIds: /* @__PURE__ */ new Set([providerId])
})) ids.add(pluginId);
}
function addEnvWebFetchProviderPluginIds(ids, cfg, env) {
if (cfg.tools?.web?.fetch?.enabled === false) return;
for (const pluginId of resolveOfficialExternalWebProviderContractPluginIdsForEnv({
contract: "webFetchProviders",
env: env ?? process.env
})) ids.add(pluginId);
}
function collectConfiguredPluginIds(cfg, env) {
const ids = /* @__PURE__ */ new Set();
const plugins = asNullableRecord(cfg.plugins);
if (plugins?.enabled === false) return ids;
const entries = asNullableRecord(plugins?.entries);
for (const [pluginId, entry] of Object.entries(entries ?? {})) {
if (asNullableRecord(entry)?.enabled === false || isNativeSessionCatalogOptOutOnly(pluginId, entry)) continue;
addConfiguredPluginId(ids, pluginId);
}
const searchProvider = normalizeOptionalLowercaseString(cfg.tools?.web?.search?.provider);
if (cfg.tools?.web?.search?.enabled !== false && searchProvider) {
const installEntry = resolveWebSearchInstallCatalogEntry({ providerId: searchProvider });
if (installEntry?.pluginId) ids.add(installEntry.pluginId);
} else if (cfg.tools?.web?.search?.enabled !== false) for (const entry of resolveWebSearchInstallCatalogEntriesForEnv(env ?? process.env)) ids.add(entry.pluginId);
for (const pluginId of collectConfiguredRuntimePluginIds(cfg, { env })) ids.add(pluginId);
for (const pluginId of collectConfiguredProviderPluginIds({
cfg,
env
})) ids.add(pluginId);
addConfiguredMemoryEmbeddingProviderPluginIds(ids, cfg);
addConfiguredSpeechProviderPluginIds(ids, cfg);
addConfiguredWebFetchProviderPluginIds(ids, cfg);
addEnvWebFetchProviderPluginIds(ids, cfg, env);
return ids;
}
function collectBlockedPluginIds(cfg) {
const ids = /* @__PURE__ */ new Set();
const deny = cfg.plugins?.deny;
if (Array.isArray(deny)) {
for (const pluginId of deny) if (typeof pluginId === "string" && pluginId.trim()) ids.add(pluginId.trim());
}
const entries = asNullableRecord(cfg.plugins?.entries);
for (const [pluginId, entry] of Object.entries(entries ?? {})) if (pluginId.trim() && asNullableRecord(entry)?.enabled === false) ids.add(pluginId.trim());
return ids;
}
function collectConfiguredChannelIds(cfg, env) {
if (asNullableRecord(cfg.plugins)?.enabled === false) return /* @__PURE__ */ new Set();
const candidateChannelIds = listRawChannelPluginCatalogEntries({
env,
excludeWorkspace: true
}).map((entry) => entry.id);
return new Set(listDoctorConfiguredChannelIds(cfg, {
configEntryPolicy: "meaningful",
env: env ?? process.env,
candidateChannelIds,
skipWhenPluginsDisabled: true,
excludeExplicitlyDisabled: true
}));
}
function collectEffectiveConfiguredChannelOwnerPluginIds(params) {
const owners = /* @__PURE__ */ new Map();
const configuredChannelIds = new Set([...params.configuredChannelIds].map((channelId) => normalizeOptionalLowercaseString(channelId)).filter((channelId) => Boolean(channelId)));
if (configuredChannelIds.size === 0) return owners;
for (const entry of resolveConfiguredChannelPresencePolicy({
config: params.cfg,
env: params.env,
includePersistedAuthState: false,
manifestRecords: params.snapshot.plugins
})) {
if (!entry.effective || !configuredChannelIds.has(entry.channelId)) continue;
const pluginIds = new Set(entry.pluginIds);
if (pluginIds.size > 0) owners.set(entry.channelId, pluginIds);
}
return owners;
}
//#endregion
//#region src/commands/doctor/shared/missing-configured-plugin-install.candidates.ts
/** Keep doctor diagnostics and actual package repair on the same discovery snapshot. */
async function resolveConfiguredPluginInstallContext(params) {
const realpathCache = /* @__PURE__ */ new Map();
const resolvePathIdentity = (value) => {
const resolved = path.resolve(resolveUserPath(value, params.env));
return safeRealpathSync(resolved, realpathCache) ?? resolved;
};
const snapshot = loadManifestMetadataSnapshot({
config: params.cfg,
env: params.env
});
const currentBundledPlugins = loadPluginManifestRegistryCore({
config: params.cfg,
env: params.env,
installRecords: {}
}).plugins.filter((plugin) => plugin.origin === "bundled");
const knownIds = /* @__PURE__ */ new Set([...snapshot.plugins.filter((plugin) => plugin.origin !== "bundled").map((plugin) => plugin.id), ...currentBundledPlugins.map((plugin) => plugin.id)]);
const configuredChannelOwnerPluginIds = collectEffectiveConfiguredChannelOwnerPluginIds({
cfg: params.cfg,
env: params.env,
snapshot,
configuredChannelIds: params.configuredChannelIds
});
const bundledPluginsById = new Map(currentBundledPlugins.flatMap((plugin) => {
const external = isExternallyDistributedPlugin({
pluginId: plugin.id,
packageName: plugin.packageName,
packageBuild: plugin.packageManifest?.build
});
const sourceCheckout = isBundledPluginInsideDevSourceRoot({
rootDir: plugin.rootDir,
env: params.env
});
return !external || sourceCheckout ? [[plugin.id, {
packageName: plugin.packageName,
preserveExternalInstallRecord: external && sourceCheckout
}]] : [];
}));
const configuredPluginIdsWithStaleDescriptors = collectConfiguredPluginIdsWithMissingChannelConfigDescriptors({
snapshot,
configuredPluginIds: params.configuredPluginIds,
configuredChannelIds: params.configuredChannelIds
});
const records = params.baselineRecords ?? await loadInstalledPluginIndexInstallRecords({ env: params.env });
const operatorManagedPluginIds = /* @__PURE__ */ new Set();
if (params.cfg.plugins?.load?.paths?.length) {
const ownership = createInstalledPluginOwnershipResolver({
...snapshot.index,
installRecords: records
}, params.env);
for (const plugin of snapshot.index.plugins) {
const update = ownership.resolveUpdate(plugin.pluginId);
if (update.ok && update.value.kind === "operator-managed") {
operatorManagedPluginIds.add(plugin.pluginId);
if (update.value.shadowedInstallOwner) operatorManagedPluginIds.add(update.value.shadowedInstallOwner);
}
}
}
const currentVersion = params.coreVersion ?? resolveCompatibilityHostVersion(params.env);
const updateChannel = resolveRegistryUpdateChannel({
configChannel: normalizeUpdateChannel(params.cfg.update?.channel),
currentVersion
});
const installedPluginIdsWithRepairablePackageDiagnostics = collectInstalledPluginIdsWithRepairablePackageDiagnostics({
snapshot,
installRecords: records,
resolvePathIdentity
});
const installedPluginIdsWithStaleVersionBoundRuntimePackages = collectInstalledPluginIdsWithStaleVersionBoundRuntimePackages({
snapshot,
installRecords: records,
configuredPluginIds: params.configuredPluginIds,
currentVersion
});
const installedPluginMissingRequiredDependencies = await collectInstalledPluginMissingRequiredDependencies({
cfg: params.cfg,
isRepairTarget: (pluginId) => isConfiguredPluginRepairTarget({
pluginId,
configuredPluginIds: params.configuredPluginIds,
configuredChannelIds: params.configuredChannelIds,
configuredChannelOwnerPluginIds
}),
snapshot,
installRecords: records,
blockedPluginIds: params.blockedPluginIds,
resolvePathIdentity
});
const installedPluginIdsWithRepairablePackages = /* @__PURE__ */ new Set([
...installedPluginIdsWithRepairablePackageDiagnostics,
...installedPluginIdsWithStaleVersionBoundRuntimePackages,
...installedPluginMissingRequiredDependencies.keys()
]);
const officialReplacementPluginIds = new Set(collectOfficialReplacementInstallCandidates({
cfg: params.cfg,
env: params.env,
repairablePluginIds: new Set([...installedPluginIdsWithRepairablePackages].filter((pluginId) => !installedPluginMissingRequiredDependencies.has(pluginId))),
configuredPluginIds: params.configuredPluginIds,
configuredChannelIds: params.configuredChannelIds,
configuredChannelOwnerPluginIds,
blockedPluginIds: params.blockedPluginIds
}).keys());
const configuredLoadPathIdentities = new Set(snapshot.discovery?.candidates.filter((candidate) => candidate.configSelected).flatMap((candidate) => [candidate.rootDir, candidate.source]).map(resolvePathIdentity));
const configuredLoadPathPluginsById = /* @__PURE__ */ new Map();
for (const plugin of snapshot.plugins) if (plugin.origin === "config" || configuredLoadPathIdentities.size > 0 && [plugin.rootDir, plugin.source].some((value) => configuredLoadPathIdentities.has(resolvePathIdentity(value)))) configuredLoadPathPluginsById.set(plugin.id, plugin.rootDir);
const stalePathInstallPluginIds = /* @__PURE__ */ new Set();
for (const [pluginId, record] of Object.entries(records)) {
if (installedPluginIdsWithRepairablePackages.has(pluginId)) continue;
const configPluginRoot = configuredLoadPathPluginsById.get(pluginId);
const recordedPaths = [record.installPath, record.sourcePath].filter((value) => Boolean(value?.trim()));
if (!configPluginRoot || record.source !== "path" || recordedPaths.length === 0) continue;
const configRootIdentity = resolvePathIdentity(configPluginRoot);
if (isPayloadMissing(params.env, record.installPath) && recordedPaths.every((value) => resolvePathIdentity(value) !== configRootIdentity)) stalePathInstallPluginIds.add(pluginId);
}
let effectiveRecords = records;
for (const pluginId of stalePathInstallPluginIds) effectiveRecords = removePluginInstallRecordFromRecords(effectiveRecords, pluginId);
return {
knownIds,
configuredChannelOwnerPluginIds,
bundledPluginsById,
configuredPluginIdsWithStaleDescriptors,
operatorManagedPluginIds,
stalePathInstallPluginIds,
records: effectiveRecords,
persistedRecords: records,
updateChannel,
installedPluginIdsWithRepairablePackageDiagnostics,
installedPluginIdsWithStaleVersionBoundRuntimePackages,
installedPluginIdsWithRepairablePackages,
installedPluginMissingRequiredDependencies,
officialReplacementPluginIds
};
}
const MISSING_CHANNEL_CONFIG_DESCRIPTOR_DIAGNOSTIC = "without channelConfigs metadata";
const REPAIRABLE_PACKAGE_ENTRY_DIAGNOSTIC_MARKERS = [
"extension entry not found",
"extension entry escapes package directory",
"extension entry unreadable",
"requires compiled runtime output"
];
function setDownloadableInstallCandidate(params) {
const npmSpec = params.install.npmSpec?.trim();
const clawhubSpec = params.install.clawhubSpec?.trim();
if (!npmSpec && !clawhubSpec) return;
params.candidates.set(params.pluginId, {
pluginId: params.pluginId,
label: params.label,
...npmSpec ? { npmSpec } : {},
...clawhubSpec ? { clawhubSpec } : {},
...params.install.expectedIntegrity ? { expectedIntegrity: params.install.expectedIntegrity } : {},
...params.trustedSourceLinkedOfficialInstall ? { trustedSourceLinkedOfficialInstall: true } : {},
...params.install.defaultChoice ? { defaultChoice: params.install.defaultChoice } : {}
});
}
function collectDownloadableInstallCandidates(params) {
const configuredPluginIds = params.configuredPluginIds ?? collectConfiguredPluginIds(params.cfg, params.env);
const configuredChannelIds = params.configuredChannelIds ?? collectConfiguredChannelIds(params.cfg, params.env);
if (params.missingPluginIds.size === 0 && configuredPluginIds.size === 0 && configuredChannelIds.size === 0) return [];
const candidates = /* @__PURE__ */ new Map();
for (const entry of listRawChannelPluginCatalogEntries({
env: params.env,
excludeWorkspace: true
})) {
if (entry.origin === "bundled") continue;
const pluginId = entry.pluginId ?? entry.id;
const channelId = normalizeOptionalLowercaseString(entry.id);
if (params.blockedPluginIds?.has(pluginId)) continue;
const selectedOnlyByChannel = !params.missingPluginIds.has(pluginId) && !configuredPluginIds.has(pluginId) && (channelId ? configuredChannelIds.has(channelId) : configuredChannelIds.has(entry.id));
const configuredChannelOwnerPluginIds = channelId ? params.configuredChannelOwnerPluginIds?.get(channelId) : void 0;
if (selectedOnlyByChannel && configuredChannelOwnerPluginIds && configuredChannelOwnerPluginIds.size > 0 && !configuredChannelOwnerPluginIds.has(pluginId)) continue;
if (!params.missingPluginIds.has(pluginId) && !configuredPluginIds.has(pluginId) && !configuredChannelIds.has(entry.id)) continue;
setDownloadableInstallCandidate({
candidates,
pluginId,
label: entry.meta.label,
install: entry.install,
trustedSourceLinkedOfficialInstall: entry.trustedSourceLinkedOfficialInstall
});
}
for (const entry of resolveProviderInstallCatalogEntries({
config: params.cfg,
env: params.env,
includeUntrustedWorkspacePlugins: false
})) {
if (!configuredPluginIds.has(entry.pluginId) && !params.missingPluginIds.has(entry.pluginId)) continue;
if (params.blockedPluginIds?.has(entry.pluginId)) continue;
setDownloadableInstallCandidate({
candidates,
pluginId: entry.pluginId,
label: entry.label,
install: entry.install,
trustedSourceLinkedOfficialInstall: entry.origin === "bundled"
});
}
for (const entry of listOfficialExternalPluginCatalogEntries()) {
const pluginId = resolveOfficialExternalPluginId(entry);
if (!pluginId || candidates.has(pluginId) || params.blockedPluginIds?.has(pluginId)) continue;
if (!configuredPluginIds.has(pluginId) && !params.missingPluginIds.has(pluginId)) continue;
const install = resolveOfficialExternalPluginInstall(entry);
if (!install) continue;
setDownloadableInstallCandidate({
candidates,
pluginId,
label: resolveOfficialExternalPluginLabel(entry),
install,
trustedSourceLinkedOfficialInstall: true
});
}
for (const entry of CONFIGURED_RUNTIME_PLUGIN_INSTALL_CANDIDATES) {
if (!configuredPluginIds.has(entry.pluginId) && !params.missingPluginIds.has(entry.pluginId)) continue;
if (params.blockedPluginIds?.has(entry.pluginId)) continue;
const existing = candidates.get(entry.pluginId);
if (existing && entry.versionBoundToOpenClaw) candidates.set(entry.pluginId, {
...existing,
versionBoundToOpenClaw: true
});
else if (!existing) candidates.set(entry.pluginId, entry);
}
for (const candidate of collectLegacyNpmDeclarationInstallCandidates({
cfg: params.cfg,
env: params.env,
configuredPluginIds,
missingPluginIds: params.missingPluginIds,
blockedPluginIds: params.blockedPluginIds
})) if (!candidates.has(candidate.pluginId)) candidates.set(candidate.pluginId, candidate);
return [...candidates.values()].toSorted((left, right) => left.pluginId.localeCompare(right.pluginId));
}
function collectLegacyNpmDeclarationInstallCandidates(params) {
const candidates = /* @__PURE__ */ new Map();
const addCandidate = (pluginDir) => {
const declaration = readLegacyNpmPluginDeclaration(pluginDir);
if (!declaration || params.blockedPluginIds?.has(declaration.pluginId) || !params.configuredPluginIds.has(declaration.pluginId) && !params.missingPluginIds.has(declaration.pluginId)) return;
candidates.set(declaration.pluginId, {
pluginId: declaration.pluginId,
label: declaration.pluginId,
npmSpec: declaration.npmSpec,
defaultChoice: "npm"
});
};
const env = params.env ?? process.env;
const loadPaths = params.cfg.plugins?.load?.paths;
if (Array.isArray(loadPaths)) for (const rawPath of loadPaths) {
if (typeof rawPath !== "string" || !rawPath.trim()) continue;
addCandidate(resolveUserPath(rawPath, env));
}
const extensionsDir = resolveDefaultPluginExtensionsDir(env);
const configuredOrMissingPluginIds = /* @__PURE__ */ new Set([...params.configuredPluginIds, ...params.missingPluginIds]);
for (const pluginId of configuredOrMissingPluginIds) try {
addCandidate(resolvePluginInstallDir(pluginId, extensionsDir));
} catch {
continue;
}
return [...candidates.values()].toSorted((left, right) => left.pluginId.localeCompare(right.pluginId));
}
function collectUpdateDeferredPluginIds(params) {
const pluginIds = new Set(params.configuredPluginIds);
for (const candidate of collectDownloadableInstallCandidates({
cfg: params.cfg,
env: params.env,
missingPluginIds: /* @__PURE__ */ new Set(),
configuredPluginIds: params.configuredPluginIds,
configuredChannelIds: params.configuredChannelIds,
configuredChannelOwnerPluginIds: params.configuredChannelOwnerPluginIds,
blockedPluginIds: params.blockedPluginIds
})) pluginIds.add(candidate.pluginId);
return pluginIds;
}
function collectConfiguredPluginIdsWithMissingChannelConfigDescriptors(params) {
const stalePluginIds = /* @__PURE__ */ new Set();
const pluginsById = new Map(params.snapshot.plugins.map((plugin) => [plugin.id, plugin]));
for (const diagnostic of params.snapshot.diagnostics) {
const pluginId = diagnostic.pluginId?.trim();
if (!pluginId || !diagnostic.message.includes(MISSING_CHANNEL_CONFIG_DESCRIPTOR_DIAGNOSTIC)) continue;
const ownsConfiguredChannel = pluginsById.get(pluginId)?.channels.some((channelId) => params.configuredChannelIds.has(channelId));
if (params.configuredPluginIds.has(pluginId) || ownsConfiguredChannel) stalePluginIds.add(pluginId);
}
return stalePluginIds;
}
function collectInstalledPluginIdsWithRepairablePackageDiagnostics(params) {
const pluginIds = /* @__PURE__ */ new Set();
for (const diagnostic of params.snapshot.diagnostics) {
const pluginId = diagnostic.pluginId?.trim();
if (!pluginId || !Object.hasOwn(params.installRecords, pluginId)) continue;
const installPath = params.installRecords[pluginId]?.installPath;
if (installPath && diagnostic.source && params.resolvePathIdentity(diagnostic.source) === params.resolvePathIdentity(installPath) && REPAIRABLE_PACKAGE_ENTRY_DIAGNOSTIC_MARKERS.some((marker) => diagnostic.message.includes(marker))) pluginIds.add(pluginId);
}
return pluginIds;
}
function resolveInstalledRuntimePackageVersion(params) {
const plugin = params.snapshot.byPluginId?.get(params.pluginId) ?? params.snapshot.plugins.find((entry) => entry.id === params.pluginId);
return normalizeOptionalLowercaseString(params.record.resolvedVersion ?? params.record.version ?? plugin?.packageVersion ?? plugin?.version);
}
function installedRuntimePackageVersionIsStale(params) {
if (!params.installedVersion) return false;
const comparison = compareOpenClawReleaseVersions(params.installedVersion, params.currentVersion);
return comparison === null ? params.installedVersion !== params.currentVersion : comparison < 0;
}
function collectInstalledPluginIdsWithStaleVersionBoundRuntimePackages(params) {
const pluginIds = /* @__PURE__ */ new Set();
const currentVersion = normalizeOptionalLowercaseString(params.currentVersion);
if (!currentVersion) return pluginIds;
for (const candidate of CONFIGURED_RUNTIME_PLUGIN_INSTALL_CANDIDATES) {
if (!VERSION_BOUND_RUNTIME_PLUGIN_IDS.has(candidate.pluginId) || !params.configuredPluginIds.has(candidate.pluginId)) continue;
const record = params.installRecords[candidate.pluginId];
if (!record) continue;
if (installedRuntimePackageVersionIsStale({
installedVersion: resolveInstalledRuntimePackageVersion({
pluginId: candidate.pluginId,
snapshot: params.snapshot,
record
}),
currentVersion
})) pluginIds.add(candidate.pluginId);
}
return pluginIds;
}
function isConfiguredPluginRepairTarget(params) {
if (params.configuredPluginIds.has(params.pluginId)) return true;
if (params.configuredChannelIds.has(params.pluginId)) return true;
for (const ownerIds of params.configuredChannelOwnerPluginIds.values()) if (ownerIds.has(params.pluginId)) return true;
return false;
}
function collectOfficialReplacementInstallCandidates(params) {
const repairableConfiguredPluginIds = new Set([...params.repairablePluginIds].filter((pluginId) => isConfiguredPluginRepairTarget({
pluginId,
configuredPluginIds: params.configuredPluginIds,
configuredChannelIds: params.configuredChannelIds,
configuredChannelOwnerPluginIds: params.configuredChannelOwnerPluginIds
})));
if (repairableConfiguredPluginIds.size === 0) return /* @__PURE__ */ new Map();
const candidates = collectDownloadableInstallCandidates({
cfg: params.cfg,
env: params.env,
missingPluginIds: repairableConfiguredPluginIds,
configuredPluginIds: params.configuredPluginIds,
configuredChannelIds: params.configuredChannelIds,
configuredChannelOwnerPluginIds: params.configuredChannelOwnerPluginIds,
blockedPluginIds: params.blockedPluginIds
});
return new Map(candidates.filter((candidate) => repairableConfiguredPluginIds.has(candidate.pluginId) && candidate.trustedSourceLinkedOfficialInstall).map((candidate) => [candidate.pluginId, candidate]));
}
//#endregion
export { collectConfiguredChannelIds as a, collectBlockedPluginIds as i, collectUpdateDeferredPluginIds as n, collectConfiguredPluginIds as o, resolveConfiguredPluginInstallContext as r, collectConfiguredProviderPluginIds as s, collectDownloadableInstallCandidates as t };