UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

179 lines (178 loc) 7.55 kB
import { m as loadPluginRegistrySnapshotWithMetadata } from "./plugin-registry-ChcJPHWl.js"; import { i as loadPluginMetadataSnapshot } from "./plugin-metadata-snapshot-Ctk9Oarq.js"; import { i as getRuntimeConfig } from "./io-Gi7-pyU-.js"; import "./config-C9RxTsn1.js"; import "./registry-CYsBNH12.js"; import { I as createEmptyPluginRegistry } from "./runtime-B2ROiq5l.js"; import fs from "node:fs"; import path from "node:path"; //#region src/plugins/status-snapshot-dependencies.ts /** Builds dependency install status for plugin status snapshots without importing discovery. */ function dependencyPathSegments(name) { const segments = name.split("/"); if (segments.length === 1 && segments[0]) return [segments[0]]; if (segments.length === 2 && segments[0]?.startsWith("@") && segments[1]) return segments; return null; } function findDependencyPackageDir(params) { const segments = dependencyPathSegments(params.name); if (!segments) return; let current = path.resolve(params.fromDir); while (true) { const candidate = path.join(current, "node_modules", ...segments); if (fs.existsSync(candidate)) return candidate; const parent = path.dirname(current); if (parent === current) return; current = parent; } } function buildDependencyEntries(params) { return Object.entries(params.dependencies).toSorted(([left], [right]) => left.localeCompare(right)).map(([name, spec]) => { const resolvedPath = params.rootDir ? findDependencyPackageDir({ fromDir: params.rootDir, name }) : void 0; const entry = { name, spec, installed: resolvedPath !== void 0, optional: params.optional }; if (resolvedPath) entry.resolvedPath = resolvedPath; return entry; }); } /** Resolves required and optional dependency status for one plugin root. */ function buildSnapshotPluginDependencyStatus(params) { const dependencies = buildDependencyEntries({ rootDir: params.rootDir, dependencies: params.dependencies ?? {}, optional: false }); const optionalDependencies = buildDependencyEntries({ rootDir: params.rootDir, dependencies: params.optionalDependencies ?? {}, optional: true }); const missing = dependencies.filter((entry) => !entry.installed).map((entry) => entry.name); const missingOptional = optionalDependencies.filter((entry) => !entry.installed).map((entry) => entry.name); const requiredInstalled = missing.length === 0; const optionalInstalled = missingOptional.length === 0; return { hasDependencies: dependencies.length > 0 || optionalDependencies.length > 0, installed: requiredInstalled, requiredInstalled, optionalInstalled, missing, missingOptional, dependencies, optionalDependencies }; } //#endregion //#region src/plugins/status-snapshot.ts /** Builds plugin status reports from persisted metadata without importing full plugin runtimes. */ function isPluginLifecycleTraceEnabled() { const raw = process.env.OPENCLAW_PLUGIN_LIFECYCLE_TRACE?.trim().toLowerCase(); return raw === "1" || raw === "true" || raw === "yes"; } function formatTraceValue(value) { if (typeof value === "number" || typeof value === "boolean") return String(value); return JSON.stringify(value); } function tracePluginLifecyclePhase(phase, fn, details) { if (!isPluginLifecycleTraceEnabled()) return fn(); const start = process.hrtime.bigint(); let status; try { const result = fn(); status = "ok"; return result; } catch (error) { status = "error"; throw error; } finally { const elapsedMs = Number(process.hrtime.bigint() - start) / 1e6; const detailText = Object.entries(details ?? {}).filter((entry) => entry[1] !== void 0).map(([key, value]) => `${key}=${formatTraceValue(value)}`).join(" "); const suffix = detailText ? ` ${detailText}` : ""; console.error(`[plugins:lifecycle] phase=${JSON.stringify(phase)} ms=${elapsedMs.toFixed(2)} status=${status ?? "error"}${suffix}`); } } function buildPluginRecordFromInstalledIndex(plugin, manifest) { const format = plugin.format ?? manifest?.format ?? "openclaw"; const bundleFormat = plugin.bundleFormat ?? manifest?.bundleFormat; return { id: plugin.pluginId, name: manifest?.name ?? plugin.packageName ?? plugin.pluginId, ...plugin.packageVersion || manifest?.version ? { version: plugin.packageVersion ?? manifest?.version } : {}, ...manifest?.description ? { description: manifest.description } : {}, format, ...bundleFormat ? { bundleFormat } : {}, ...manifest?.kind ? { kind: manifest.kind } : {}, source: plugin.source ?? plugin.manifestPath, rootDir: plugin.rootDir, origin: plugin.origin, enabled: plugin.enabled, compat: plugin.compat, syntheticAuthRefs: [...plugin.syntheticAuthRefs ?? manifest?.syntheticAuthRefs ?? []], status: plugin.enabled ? "loaded" : "disabled", toolNames: [], hookNames: [], channelIds: [...manifest?.channels ?? []], cliBackendIds: [...manifest?.cliBackends ?? [], ...manifest?.setup?.cliBackends ?? []], providerIds: [...manifest?.providers ?? []], embeddingProviderIds: [...manifest?.contracts?.embeddingProviders ?? []], speechProviderIds: [...manifest?.contracts?.speechProviders ?? []], realtimeTranscriptionProviderIds: [...manifest?.contracts?.realtimeTranscriptionProviders ?? []], realtimeVoiceProviderIds: [...manifest?.contracts?.realtimeVoiceProviders ?? []], mediaUnderstandingProviderIds: [...manifest?.contracts?.mediaUnderstandingProviders ?? []], transcriptSourceProviderIds: [...manifest?.contracts?.transcriptSourceProviders ?? []], imageGenerationProviderIds: [...manifest?.contracts?.imageGenerationProviders ?? []], videoGenerationProviderIds: [...manifest?.contracts?.videoGenerationProviders ?? []], musicGenerationProviderIds: [...manifest?.contracts?.musicGenerationProviders ?? []], webFetchProviderIds: [...manifest?.contracts?.webFetchProviders ?? []], webSearchProviderIds: [...manifest?.contracts?.webSearchProviders ?? []], migrationProviderIds: [...manifest?.contracts?.migrationProviders ?? []], memoryEmbeddingProviderIds: [...manifest?.contracts?.memoryEmbeddingProviders ?? []], agentHarnessIds: [], cliCommands: [], services: [], gatewayDiscoveryServiceIds: [], commands: [...manifest?.commandAliases?.map((alias) => alias.name) ?? []], httpRoutes: 0, hookCount: 0, configSchema: false, contracts: manifest?.contracts, dependencyStatus: buildSnapshotPluginDependencyStatus({ rootDir: plugin.rootDir, dependencies: manifest?.packageDependencies, optionalDependencies: manifest?.packageOptionalDependencies }) }; } /** Resolves the best available plugin registry snapshot and annotates dependency status. */ function buildPluginRegistrySnapshotReport(params) { const config = params?.config ?? getRuntimeConfig(); const result = tracePluginLifecyclePhase("plugin registry snapshot", () => loadPluginRegistrySnapshotWithMetadata({ config, env: params?.env, workspaceDir: params?.workspaceDir }), { surface: "status" }); const env = params?.env ?? process.env; const manifestByPluginId = loadPluginMetadataSnapshot({ index: result.snapshot, config, env, workspaceDir: params?.workspaceDir }).byPluginId; return { workspaceDir: params?.workspaceDir, ...createEmptyPluginRegistry(), plugins: result.snapshot.plugins.map((plugin) => buildPluginRecordFromInstalledIndex(plugin, manifestByPluginId.get(plugin.pluginId))), diagnostics: [...result.snapshot.diagnostics], registrySource: result.source, registryDiagnostics: result.diagnostics }; } //#endregion export { buildPluginRegistrySnapshotReport as t };