@elizaos/plugin-registry 2.0.3-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/api/app-plugins-routes.ts"],"sourcesContent":["import fs from \"node:fs\";\nimport type http from \"node:http\";\nimport { createRequire } from \"node:module\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n// Consolidated from packages/app-core/src/api/plugins-routes.ts.\n// Moved from packages/app-core/src/api/plugins-routes.ts into the\n// @elizaos/plugin-registry plugin. Both agent-internal helpers\n// (@elizaos/agent) and app-core-internal helpers (@elizaos/app-core) are\n// imported through their respective public package surfaces; no more\n// `../registry`, `../services/*`, `./auth`, `./compat-route-shared`, or\n// `./response` cross-package deep imports.\nimport {\n type AdvancedCapabilityPluginId,\n applyPluginRuntimeMutation,\n CONNECTOR_ENV_MAP,\n discoverPluginsFromManifest,\n findPrimaryEnvKey,\n isAdvancedCapabilityPluginId,\n isVaultRef,\n loadElizaConfig,\n type PluginRuntimeApplyResult,\n parseVaultRef,\n readBundledPluginPackageMetadata,\n resolveAdvancedCapabilitiesEnabled,\n saveElizaConfig,\n} from \"@elizaos/agent\";\nimport {\n ensureCompatSensitiveRouteAuthorized,\n ensureRouteAuthorized,\n} from \"@elizaos/app-core/api/auth\";\nimport {\n type CompatRuntimeState,\n readCompatJsonBody,\n scheduleCompatRuntimeRestart,\n} from \"@elizaos/app-core/api/compat-route-shared\";\nimport {\n sendJsonError as sendJsonErrorResponse,\n sendJson as sendJsonResponse,\n} from \"@elizaos/app-core/api/response\";\nimport {\n type ConfigField,\n loadRegistry,\n type RegistryEntry,\n} from \"@elizaos/app-core/registry\";\nimport {\n _resetSharedVaultForTesting,\n mirrorPluginSensitiveToVault,\n sharedVault,\n} from \"@elizaos/app-core/services/vault-mirror\";\nimport { type AgentRuntime, logger } from \"@elizaos/core\";\nimport {\n asRecord,\n CONNECTOR_PLUGINS,\n STREAMING_PLUGINS,\n} from \"@elizaos/shared\";\nimport { VaultMissError } from \"@elizaos/vault\";\n\nconst require = createRequire(import.meta.url);\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\ntype PluginCategory =\n | \"ai-provider\"\n | \"connector\"\n | \"streaming\"\n | \"database\"\n | \"app\"\n | \"feature\";\n\ninterface ManifestPluginParameter {\n type?: string;\n description?: string;\n required?: boolean;\n optional?: boolean;\n sensitive?: boolean;\n default?: string | number | boolean;\n options?: string[];\n}\n\ninterface ManifestPluginEntry {\n id: string;\n dirName?: string;\n name?: string;\n npmName?: string;\n description?: string;\n tags?: string[];\n category?: string;\n envKey?: string;\n configKeys?: string[];\n version?: string;\n pluginDeps?: string[];\n pluginParameters?: Record<string, ManifestPluginParameter>;\n configUiHints?: Record<string, Record<string, unknown>>;\n icon?: string | null;\n logoUrl?: string | null;\n homepage?: string;\n repository?: string;\n setupGuideUrl?: string;\n}\n\ninterface PluginManifestFile {\n plugins?: ManifestPluginEntry[];\n}\n\nconst FIELD_TYPE_TO_LEGACY: Record<ConfigField[\"type\"], string> = {\n string: \"string\",\n secret: \"string\",\n url: \"string\",\n \"file-path\": \"string\",\n textarea: \"string\",\n json: \"string\",\n select: \"string\",\n multiselect: \"string\",\n boolean: \"boolean\",\n number: \"number\",\n};\n\nfunction pluginSubtypeToCategory(entry: RegistryEntry): string {\n if (entry.kind !== \"plugin\") return entry.kind;\n if (entry.subtype === \"ai-provider\") return \"ai-provider\";\n if (entry.subtype === \"database\") return \"database\";\n return \"feature\";\n}\n\nfunction connectorSubtypeToCategory(entry: RegistryEntry): string {\n if (entry.kind !== \"connector\") return \"connector\";\n if (entry.subtype === \"streaming\") return \"streaming\";\n return \"connector\";\n}\n\nfunction categoryForRegistryEntry(entry: RegistryEntry): string {\n if (entry.kind === \"plugin\") return pluginSubtypeToCategory(entry);\n if (entry.kind === \"connector\") return connectorSubtypeToCategory(entry);\n return entry.kind;\n}\n\nfunction envKeyForRegistryEntry(entry: RegistryEntry): string | undefined {\n if (entry.kind === \"connector\" && entry.auth) {\n const [first] = entry.auth.credentialKeys;\n if (first) return first;\n }\n for (const [key, field] of Object.entries(entry.config) as Array<\n [string, ConfigField]\n >) {\n if (field.required && (field.type === \"secret\" || field.sensitive)) {\n return key;\n }\n }\n return undefined;\n}\n\nfunction fieldToManifestParameter(field: ConfigField): ManifestPluginParameter {\n const param: ManifestPluginParameter = {\n type: FIELD_TYPE_TO_LEGACY[field.type],\n description: field.help ?? field.label ?? \"\",\n required: field.required,\n sensitive: field.sensitive ?? field.type === \"secret\",\n };\n if (field.default !== undefined && field.default !== null) {\n param.default = String(field.default);\n }\n if (field.options) {\n param.options = field.options.map((option) => option.value);\n }\n return param;\n}\n\nfunction registryEntryToManifest(entry: RegistryEntry): ManifestPluginEntry {\n const pluginParameters: Record<string, ManifestPluginParameter> = {};\n for (const [key, field] of Object.entries(entry.config)) {\n pluginParameters[key] = fieldToManifestParameter(field);\n }\n\n return {\n id: entry.id,\n dirName: entry.npmName?.replace(/^@[^/]+\\//, \"\"),\n name: entry.name,\n npmName: entry.npmName,\n description: entry.description,\n tags: entry.tags,\n category: categoryForRegistryEntry(entry),\n envKey: envKeyForRegistryEntry(entry),\n configKeys: Object.keys(entry.config),\n version: entry.version,\n pluginParameters,\n icon: entry.render.icon ?? null,\n homepage: entry.resources.homepage,\n repository: entry.resources.repository,\n setupGuideUrl: entry.resources.setupGuideUrl,\n };\n}\n\ninterface RuntimePluginLike {\n name?: string;\n description?: string;\n}\n\ninterface CompatPluginParameter {\n key: string;\n type: string;\n description: string;\n required: boolean;\n sensitive: boolean;\n default?: string;\n options?: string[];\n currentValue: string | null;\n isSet: boolean;\n}\n\ninterface CompatPluginRecord {\n id: string;\n name?: string;\n description?: string;\n enabled?: boolean;\n configured?: boolean;\n envKey?: string | null;\n category?: PluginCategory;\n source?: string;\n parameters: CompatPluginParameter[];\n validationErrors: Array<{ field: string; message: string }>;\n validationWarnings?: Array<{ field?: string; message: string }>;\n npmName?: string;\n version?: string;\n isActive?: boolean;\n tags?: string[];\n configKeys?: string[];\n pluginDeps?: string[];\n configUiHints?: Record<string, unknown>;\n icon?: string | null;\n homepage?: string;\n repository?: string;\n setupGuideUrl?: string;\n // Registry-sourced render hints. Replaces frontend lookups against\n // VISIBLE_CONNECTOR_IDS / DEFAULT_ICONS / FEATURE_SUBGROUP /\n // SUBGROUP_DISPLAY_ORDER. Optional during migration; required once the\n // frontend constants are deleted.\n iconName?: string;\n group?: string;\n groupOrder?: number;\n visible?: boolean;\n}\n\ntype PluginDriftFlag =\n | \"entries_vs_compat\"\n | \"entries_vs_allowlist\"\n | \"inactive_but_enabled\"\n | \"active_but_disabled\";\n\ninterface PluginDriftDiagnostic {\n pluginId: string;\n npmName: string | null;\n category: PluginCategory;\n enabled_ui: boolean;\n enabled_allowlist: boolean | null;\n is_active: boolean;\n drift_flags: PluginDriftFlag[];\n}\n\ninterface PluginDriftDiagnosticsSummary {\n total: number;\n withDrift: number;\n byFlag: Record<PluginDriftFlag, number>;\n}\n\ninterface PluginDriftDiagnosticsReport {\n summary: PluginDriftDiagnosticsSummary;\n plugins: PluginDriftDiagnostic[];\n}\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\nconst CAPABILITY_FEATURE_IDS = new Set([\n \"vision\",\n \"browser\",\n \"computeruse\",\n \"coding-agent\",\n]);\n\nconst ADVANCED_CAPABILITY_SERVICE_BY_PLUGIN_ID: Partial<\n Record<AdvancedCapabilityPluginId, string>\n> = {\n experience: \"EXPERIENCE\",\n personality: \"CHARACTER_MANAGEMENT\",\n};\n\n// Key prefixes that contain wallet private keys or other high-value secrets\n// require the hardened sensitive-route auth (loopback + elevated checks).\nconst SENSITIVE_KEY_PREFIXES = [\"SOLANA_\", \"ETHEREUM_\", \"EVM_\", \"WALLET_\"];\n\nconst REVEALABLE_KEY_PREFIXES = [\n \"OPENAI_\",\n \"ANTHROPIC_\",\n \"GOOGLE_\",\n \"GROQ_\",\n \"MISTRAL_\",\n \"PERPLEXITY_\",\n \"COHERE_\",\n \"TOGETHER_\",\n \"FIREWORKS_\",\n \"REPLICATE_\",\n \"HUGGINGFACE_\",\n \"ELEVENLABS_\",\n \"DISCORD_\",\n \"TELEGRAM_\",\n \"TWITTER_\",\n \"SLACK_\",\n \"GITHUB_\",\n \"REDIS_\",\n \"POSTGRES_\",\n \"DATABASE_\",\n \"SUPABASE_\",\n \"PINECONE_\",\n \"QDRANT_\",\n \"WEAVIATE_\",\n \"CHROMADB_\",\n \"AWS_\",\n \"AZURE_\",\n \"CLOUDFLARE_\",\n \"ELIZA_\",\n \"PLUGIN_\",\n \"XAI_\",\n \"DEEPSEEK_\",\n \"OLLAMA_\",\n \"FAL_\",\n \"LETZAI_\",\n \"GAIANET_\",\n \"LIVEPEER_\",\n ...SENSITIVE_KEY_PREFIXES,\n];\n\nconst DRIFT_LOG_THROTTLE_MS = 5 * 60 * 1000;\nlet _lastDriftWarningAt = 0;\nlet _lastDriftWarningFingerprint = \"\";\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\n// Re-exported so existing call sites keep working. The implementations\n// live in services/vault-mirror.ts so unit tests can import them\n// without dragging in the @elizaos/agent runtime through this file.\nexport { _resetSharedVaultForTesting, mirrorPluginSensitiveToVault };\n\nfunction maskValue(value: string): string {\n if (value.length <= 8) return \"****\";\n return `${value.slice(0, 4)}...${value.slice(-4)}`;\n}\n\nfunction normalizePluginCategory(value: string | undefined): PluginCategory {\n switch (value) {\n case \"ai-provider\":\n case \"connector\":\n case \"streaming\":\n case \"database\":\n case \"app\":\n return value;\n default:\n return \"feature\";\n }\n}\n\nfunction normalizePluginId(rawName: string): string {\n const scopedPackage = rawName.match(/^@[^/]+\\/(?:plugin|app)-(.+)$/);\n if (scopedPackage) {\n return scopedPackage[1] ?? rawName;\n }\n return rawName.replace(/^@[^/]+\\//, \"\").replace(/^(plugin|app)-/, \"\");\n}\n\nfunction decodePluginPathSegment(rawSegment: string): string | null {\n try {\n return decodeURIComponent(rawSegment);\n } catch {\n return null;\n }\n}\n\nfunction resolveCompatConfigKey(\n pluginId: string,\n npmName: string | undefined,\n pluginMap: Record<string, string>,\n): string | null {\n const candidates = new Set<string>([pluginId, normalizePluginId(pluginId)]);\n if (typeof npmName === \"string\" && npmName.length > 0) {\n candidates.add(npmName);\n candidates.add(normalizePluginId(npmName));\n }\n\n for (const [configKey, packageName] of Object.entries(pluginMap)) {\n if (\n candidates.has(configKey) ||\n candidates.has(packageName) ||\n candidates.has(normalizePluginId(packageName))\n ) {\n return configKey;\n }\n }\n\n return null;\n}\n\nfunction readCompatSectionEnabled(\n section: unknown,\n configKey: string | null,\n): boolean | undefined {\n if (!configKey) {\n return undefined;\n }\n\n const sectionRecord = asRecord(section);\n if (!sectionRecord) {\n return undefined;\n }\n\n const targetRecord = asRecord(sectionRecord[configKey]);\n if (!targetRecord || typeof targetRecord.enabled !== \"boolean\") {\n return undefined;\n }\n\n return targetRecord.enabled;\n}\n\nfunction writeCompatSectionEnabled(\n parent: Record<string, unknown>,\n sectionKey: string,\n configKey: string | null,\n enabled: boolean,\n): void {\n if (!configKey) {\n return;\n }\n\n const section = asRecord(parent[sectionKey]) ?? {};\n const entry = asRecord(section[configKey]) ?? {};\n entry.enabled = enabled;\n section[configKey] = entry;\n parent[sectionKey] = section;\n}\n\nfunction syncCompatConnectorConfigValues(\n config: Record<string, unknown>,\n pluginId: string,\n npmName: string | undefined,\n values: Record<string, string>,\n): void {\n const connectorKey = resolveCompatConfigKey(\n pluginId,\n npmName,\n CONNECTOR_PLUGINS,\n );\n if (!connectorKey) {\n return;\n }\n\n const envMap =\n CONNECTOR_ENV_MAP[connectorKey as keyof typeof CONNECTOR_ENV_MAP];\n if (!envMap) {\n return;\n }\n const typedEnvMap = envMap as Record<string, string>;\n\n const connectors = asRecord(config.connectors) ?? {};\n const connectorEntry = asRecord(connectors[connectorKey]) ?? {};\n const envToField = new Map<string, string>();\n\n for (const [field, envKey] of Object.entries(typedEnvMap)) {\n if (!envToField.has(envKey)) {\n envToField.set(envKey, field);\n }\n }\n\n let touched = false;\n for (const [envKey, field] of envToField.entries()) {\n if (!(envKey in values)) {\n continue;\n }\n\n touched = true;\n const value = values[envKey];\n if (value.trim()) {\n connectorEntry[field] = value;\n } else {\n delete connectorEntry[field];\n }\n }\n\n // Canonicalize Discord onto `connectors.discord.token`; keep the legacy\n // `botToken` alias cleared so the config does not drift between fields.\n if (connectorKey === \"discord\" && \"DISCORD_API_TOKEN\" in values) {\n touched = true;\n const tokenValue = values.DISCORD_API_TOKEN.trim();\n if (tokenValue) {\n connectorEntry.token = tokenValue;\n } else {\n delete connectorEntry.token;\n }\n delete connectorEntry.botToken;\n }\n\n if (!touched) {\n return;\n }\n\n connectors[connectorKey] = connectorEntry;\n config.connectors = connectors;\n}\n\nfunction resolvePersistedPluginEnabled(\n pluginId: string,\n category: PluginCategory,\n npmName: string | undefined,\n configEntries: Record<string, { enabled?: unknown }>,\n config: Record<string, unknown>,\n): boolean | undefined {\n const pluginEnabled =\n typeof configEntries[pluginId]?.enabled === \"boolean\"\n ? Boolean(configEntries[pluginId]?.enabled)\n : undefined;\n\n if (category === \"connector\") {\n const connectorEnabled = readCompatSectionEnabled(\n config.connectors,\n resolveCompatConfigKey(pluginId, npmName, CONNECTOR_PLUGINS),\n );\n return connectorEnabled ?? pluginEnabled;\n }\n\n if (category === \"streaming\") {\n const streamingEnabled = readCompatSectionEnabled(\n config.streaming,\n resolveCompatConfigKey(pluginId, npmName, STREAMING_PLUGINS),\n );\n return streamingEnabled ?? pluginEnabled;\n }\n\n return pluginEnabled;\n}\n\nexport function resolveCompatPluginEnabledForList(\n active: boolean,\n persistedEnabled: boolean | undefined,\n advancedCapabilityEnabled?: boolean,\n): boolean {\n return advancedCapabilityEnabled ?? persistedEnabled ?? active;\n}\n\nfunction shortPluginIdFromNpmName(npmName: string | null): string | null {\n if (!npmName || typeof npmName !== \"string\") {\n return null;\n }\n if (npmName.startsWith(\"@elizaos/app-\")) {\n return npmName.slice(\"@elizaos/\".length);\n }\n if (npmName.startsWith(\"@elizaos/plugin-\")) {\n return npmName.slice(\"@elizaos/plugin-\".length);\n }\n return normalizePluginId(npmName);\n}\n\nexport function analyzePluginStateDrift(\n pluginList: CompatPluginRecord[],\n configRecord: Record<string, unknown>,\n configEntries: Record<string, { enabled?: unknown }>,\n allowList: Set<string> | null,\n): PluginDriftDiagnosticsReport {\n const diagnostics = pluginList.map((plugin): PluginDriftDiagnostic => {\n const pluginId = String(plugin.id);\n const category = normalizePluginCategory(plugin.category);\n const npmName =\n typeof plugin.npmName === \"string\" && plugin.npmName.length > 0\n ? plugin.npmName\n : null;\n const shortId = shortPluginIdFromNpmName(npmName) ?? pluginId;\n const uiEnabled = Boolean(plugin.enabled);\n const compatEnabled =\n category === \"connector\"\n ? readCompatSectionEnabled(\n configRecord.connectors,\n resolveCompatConfigKey(\n pluginId,\n npmName ?? undefined,\n CONNECTOR_PLUGINS,\n ),\n )\n : category === \"streaming\"\n ? readCompatSectionEnabled(\n configRecord.streaming,\n resolveCompatConfigKey(\n pluginId,\n npmName ?? undefined,\n STREAMING_PLUGINS,\n ),\n )\n : undefined;\n const entryEnabled =\n typeof configEntries[pluginId]?.enabled === \"boolean\"\n ? Boolean(configEntries[pluginId]?.enabled)\n : undefined;\n const enabledAllowList =\n allowList === null || npmName == null\n ? null\n : allowList.has(npmName) || allowList.has(shortId);\n const isActive = Boolean(plugin.isActive);\n const driftFlags: PluginDriftFlag[] = [];\n\n if (\n compatEnabled !== undefined &&\n entryEnabled !== undefined &&\n compatEnabled !== entryEnabled\n ) {\n driftFlags.push(\"entries_vs_compat\");\n }\n if (enabledAllowList !== null && entryEnabled !== undefined) {\n if (enabledAllowList !== entryEnabled) {\n driftFlags.push(\"entries_vs_allowlist\");\n }\n }\n if (uiEnabled && !isActive) {\n driftFlags.push(\"inactive_but_enabled\");\n }\n if (!uiEnabled && isActive) {\n driftFlags.push(\"active_but_disabled\");\n }\n\n return {\n pluginId,\n npmName,\n category,\n enabled_ui: uiEnabled,\n enabled_allowlist: enabledAllowList,\n is_active: isActive,\n drift_flags: driftFlags,\n };\n });\n\n const withDrift = diagnostics.filter(\n (plugin) => plugin.drift_flags.length > 0,\n );\n const byFlag: Record<PluginDriftFlag, number> = {\n entries_vs_compat: 0,\n entries_vs_allowlist: 0,\n inactive_but_enabled: 0,\n active_but_disabled: 0,\n };\n for (const plugin of withDrift) {\n for (const flag of plugin.drift_flags) {\n byFlag[flag] += 1;\n }\n }\n\n return {\n summary: {\n total: diagnostics.length,\n withDrift: withDrift.length,\n byFlag,\n },\n plugins: diagnostics,\n };\n}\n\nfunction buildPluginDriftDiagnostics(\n runtime: AgentRuntime | null,\n): PluginDriftDiagnosticsReport {\n const pluginList = buildPluginListResponse(runtime).plugins;\n const config = loadElizaConfig();\n const configRecord = config as Record<string, unknown>;\n const configEntries = config.plugins?.entries ?? {};\n const allowList = Array.isArray(config.plugins?.allow)\n ? new Set(config.plugins.allow)\n : null;\n\n return analyzePluginStateDrift(\n pluginList,\n configRecord,\n configEntries,\n allowList,\n );\n}\n\nfunction maybeLogPluginStateDrift(report: PluginDriftDiagnosticsReport): void {\n if (report.summary.withDrift === 0) {\n return;\n }\n const drifted = report.plugins\n .filter((plugin) => plugin.drift_flags.length > 0)\n .map((plugin) => `${plugin.pluginId}:${plugin.drift_flags.join(\"+\")}`)\n .sort();\n const fingerprint = drifted.join(\"|\");\n const now = Date.now();\n if (\n fingerprint === _lastDriftWarningFingerprint &&\n now - _lastDriftWarningAt < DRIFT_LOG_THROTTLE_MS\n ) {\n return;\n }\n _lastDriftWarningAt = now;\n _lastDriftWarningFingerprint = fingerprint;\n logger.warn(\n {\n src: \"api:plugins\",\n driftCount: report.summary.withDrift,\n byFlag: report.summary.byFlag,\n plugins: drifted,\n },\n \"Plugin enable-state drift detected between /api/plugins and /api/plugins/core models\",\n );\n}\n\n// ── Enabled-state drift reconciliation ────────────────────────────────\n//\n// The write path (persistCompatPluginMutation) always updates both\n// plugins.entries[id].enabled AND the compat connector/streaming section.\n// However drift can occur if the config file is edited externally or a\n// migration only touched one location. This pass detects any mismatch\n// and re-synchronises the compat section from plugins.entries, which is\n// the canonical source for the Settings UI.\n//\n// Runs once per process on the first buildPluginListResponse() call.\n\nlet _enabledStateReconciled = false;\n\nfunction reconcilePluginEnabledStates(): void {\n if (_enabledStateReconciled) return;\n _enabledStateReconciled = true;\n\n const config = loadElizaConfig();\n const configRecord = config as Record<string, unknown>;\n const entries = (config.plugins?.entries ?? {}) as Record<\n string,\n { enabled?: unknown }\n >;\n\n let dirty = false;\n\n for (const [pluginId, entry] of Object.entries(entries)) {\n if (typeof entry.enabled !== \"boolean\") continue;\n\n // Check connector section\n const connectorKey = resolveCompatConfigKey(\n pluginId,\n undefined,\n CONNECTOR_PLUGINS,\n );\n if (connectorKey) {\n const sectionEnabled = readCompatSectionEnabled(\n configRecord.connectors,\n connectorKey,\n );\n if (sectionEnabled !== undefined && sectionEnabled !== entry.enabled) {\n writeCompatSectionEnabled(\n configRecord,\n \"connectors\",\n connectorKey,\n entry.enabled,\n );\n dirty = true;\n }\n }\n\n // Check streaming section\n const streamingKey = resolveCompatConfigKey(\n pluginId,\n undefined,\n STREAMING_PLUGINS,\n );\n if (streamingKey) {\n const sectionEnabled = readCompatSectionEnabled(\n configRecord.streaming,\n streamingKey,\n );\n if (sectionEnabled !== undefined && sectionEnabled !== entry.enabled) {\n writeCompatSectionEnabled(\n configRecord,\n \"streaming\",\n streamingKey,\n entry.enabled,\n );\n dirty = true;\n }\n }\n }\n\n if (dirty) {\n saveElizaConfig(config);\n logger.info(\"[plugins] Reconciled drifted plugin enabled states in config\");\n }\n}\n\nfunction compatMutationRequiresRestart(\n plugin: CompatPluginRecord,\n body: Record<string, unknown>,\n): boolean {\n if (typeof body.enabled === \"boolean\") {\n return true;\n }\n\n if (\n body.config !== undefined &&\n (plugin.category === \"connector\" || plugin.category === \"streaming\")\n ) {\n return true;\n }\n\n return false;\n}\n\nfunction createCompatRuntimeApplyFallback(\n reason: string,\n requiresRestart: boolean,\n): PluginRuntimeApplyResult {\n return {\n mode: requiresRestart ? \"restart_required\" : \"none\",\n requiresRestart,\n restartedRuntime: false,\n loadedPackages: [],\n unloadedPackages: [],\n reloadedPackages: [],\n appliedConfigPackage: null,\n reason,\n };\n}\n\nasync function applyCompatRuntimeMutation(options: {\n state: CompatRuntimeState;\n pluginId: string;\n plugin: CompatPluginRecord;\n body: Record<string, unknown>;\n previousConfig: ReturnType<typeof loadElizaConfig>;\n nextConfig: ReturnType<typeof loadElizaConfig>;\n}): Promise<PluginRuntimeApplyResult> {\n const { state, pluginId, plugin, body, previousConfig, nextConfig } = options;\n const reason =\n typeof body.enabled === \"boolean\"\n ? `Plugin toggle: ${pluginId}`\n : `Plugin config updated: ${pluginId}`;\n const requiresRestartFallback = compatMutationRequiresRestart(plugin, body);\n\n if (!state.current) {\n return createCompatRuntimeApplyFallback(reason, requiresRestartFallback);\n }\n\n try {\n return await applyPluginRuntimeMutation({\n runtime: state.current,\n previousConfig,\n nextConfig,\n changedPluginId: pluginId,\n changedPluginPackage: plugin.npmName,\n config:\n body.config &&\n typeof body.config === \"object\" &&\n !Array.isArray(body.config)\n ? (body.config as Record<string, string>)\n : undefined,\n expectRuntimeGraphChange: typeof body.enabled === \"boolean\",\n reason,\n });\n } catch (error) {\n logger.warn(\n `[api/plugins] Live runtime apply failed for \"${pluginId}\": ${\n error instanceof Error ? error.message : String(error)\n }`,\n );\n return createCompatRuntimeApplyFallback(reason, true);\n }\n}\n\nfunction titleCasePluginId(id: string): string {\n return id\n .split(\"-\")\n .filter((segment) => segment.length > 0)\n .map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1))\n .join(\" \");\n}\n\nfunction inferSensitiveConfigKey(key: string): boolean {\n return /(?:_API_KEY|_SECRET|_TOKEN|_PASSWORD|_PRIVATE_KEY|_SIGNING_|ENCRYPTION_)/i.test(\n key,\n );\n}\n\nfunction buildPluginParamDefs(\n parameters: Record<string, ManifestPluginParameter> | undefined,\n savedValues?: Record<string, string>,\n): Array<{\n key: string;\n type: string;\n description: string;\n required: boolean;\n sensitive: boolean;\n default?: string;\n options?: string[];\n currentValue: string | null;\n isSet: boolean;\n}> {\n if (!parameters) {\n return [];\n }\n\n // Drop generic fallback model keys (SMALL_MODEL, LARGE_MODEL, IMAGE_MODEL,\n // EMBEDDING_MODEL) when a provider-prefixed equivalent (e.g.\n // GOOGLE_SMALL_MODEL) is also declared. Plugins like @elizaos/plugin-google-genai\n // declare both — surfacing both creates confusing duplicate fields in the UI.\n const allKeys = Object.keys(parameters);\n const GENERIC_FALLBACK_SUFFIXES = [\n \"SMALL_MODEL\",\n \"LARGE_MODEL\",\n \"IMAGE_MODEL\",\n \"EMBEDDING_MODEL\",\n ];\n const filteredEntries = Object.entries(parameters).filter(([key]) => {\n if (!GENERIC_FALLBACK_SUFFIXES.includes(key)) return true;\n return !allKeys.some((other) => other !== key && other.endsWith(`_${key}`));\n });\n\n return filteredEntries.map(([key, definition]) => {\n const envValue = process.env[key]?.trim() || undefined;\n const savedValue = savedValues?.[key];\n const effectiveValue =\n envValue ?? (savedValue ? savedValue.trim() || undefined : undefined);\n const isSet = Boolean(effectiveValue);\n const sensitive =\n typeof definition.sensitive === \"boolean\"\n ? definition.sensitive\n : inferSensitiveConfigKey(key);\n const currentValue =\n !isSet || !effectiveValue\n ? null\n : sensitive\n ? maskValue(effectiveValue)\n : effectiveValue;\n\n return {\n key,\n type: definition.type ?? \"string\",\n description: definition.description ?? \"\",\n required:\n definition.required === true ||\n (definition.optional === false && definition.required !== false),\n sensitive,\n default:\n definition.default === undefined\n ? undefined\n : String(definition.default),\n options: Array.isArray(definition.options)\n ? definition.options\n : undefined,\n currentValue,\n isSet,\n };\n });\n}\n\nfunction findNearestFile(\n startDir: string,\n fileName: string,\n maxDepth = 12,\n): string | null {\n let dir = path.resolve(startDir);\n\n for (let depth = 0; depth <= maxDepth; depth += 1) {\n const candidate = path.join(dir, fileName);\n if (fs.existsSync(candidate)) {\n return candidate;\n }\n const parent = path.dirname(dir);\n if (parent === dir) {\n break;\n }\n dir = parent;\n }\n\n return null;\n}\n\nexport function resolvePluginManifestPath(): string | null {\n const moduleDir = path.dirname(fileURLToPath(import.meta.url));\n const candidates = [\n process.cwd(),\n moduleDir,\n path.dirname(process.execPath),\n path.join(path.dirname(process.execPath), \"..\", \"Resources\", \"app\"),\n ];\n\n for (const candidate of candidates) {\n const manifestPath = findNearestFile(candidate, \"plugins.json\");\n if (manifestPath) {\n return manifestPath;\n }\n }\n\n return null;\n}\n\nfunction resolveInstalledPackageVersion(\n packageName: string | undefined,\n): string | null {\n if (!packageName) {\n return null;\n }\n\n try {\n const packageJsonPath = require.resolve(`${packageName}/package.json`);\n const pkg = JSON.parse(fs.readFileSync(packageJsonPath, \"utf8\")) as {\n version?: unknown;\n };\n return typeof pkg.version === \"string\" ? pkg.version : null;\n } catch {\n return null;\n }\n}\n\nfunction resolveLoadedPluginNames(runtime: AgentRuntime | null): Set<string> {\n const loadedNames = new Set<string>();\n\n for (const plugin of runtime?.plugins ?? []) {\n const name = (plugin as RuntimePluginLike).name;\n if (typeof name === \"string\" && name.length > 0) {\n loadedNames.add(name);\n }\n }\n\n return loadedNames;\n}\n\nfunction isPluginLoaded(\n pluginId: string,\n npmName: string | undefined,\n loadedNames: Set<string>,\n): boolean {\n const expectedNames = new Set<string>([\n pluginId,\n `plugin-${pluginId}`,\n `app-${pluginId}`,\n npmName ?? \"\",\n ]);\n\n for (const loadedName of loadedNames) {\n if (expectedNames.has(loadedName)) {\n return true;\n }\n if (\n loadedName.endsWith(`/plugin-${pluginId}`) ||\n loadedName.endsWith(`/app-${pluginId}`)\n ) {\n return true;\n }\n }\n\n return false;\n}\n\nexport function resolveAdvancedCapabilityCompatStatus(\n pluginId: string,\n config: ReturnType<typeof loadElizaConfig>,\n runtime: Pick<AgentRuntime, \"getService\"> | null,\n): { enabled: boolean; isActive: boolean } | null {\n if (!isAdvancedCapabilityPluginId(pluginId)) {\n return null;\n }\n\n const enabled = resolveAdvancedCapabilitiesEnabled(config);\n if (!enabled) {\n return { enabled: false, isActive: false };\n }\n\n const serviceType = ADVANCED_CAPABILITY_SERVICE_BY_PLUGIN_ID[pluginId];\n return {\n enabled: true,\n isActive: serviceType\n ? Boolean(runtime?.getService(serviceType))\n : Boolean(runtime),\n };\n}\n\nexport function buildPluginListResponse(runtime: AgentRuntime | null): {\n plugins: CompatPluginRecord[];\n} {\n reconcilePluginEnabledStates();\n const config = loadElizaConfig();\n const configRecord = config as Record<string, unknown>;\n const loadedNames = resolveLoadedPluginNames(runtime);\n // Primary source: registry entries. Workspace plugin discovery fills gaps\n // for local first-party plugin packages that have not been registered yet.\n const registry = loadRegistry();\n const manifestRoot = resolvePluginManifestPath()\n ? path.dirname(resolvePluginManifestPath() ?? \"\")\n : process.cwd();\n const manifest: PluginManifestFile = {\n plugins: registry.all.map(registryEntryToManifest),\n };\n\n const configEntries = config.plugins?.entries ?? {};\n const installEntries = config.plugins?.installs ?? {};\n const plugins = new Map<string, CompatPluginRecord>();\n\n for (const entry of manifest.plugins ?? []) {\n const pluginId = normalizePluginId(entry.id);\n const category = normalizePluginCategory(entry.category);\n const bundledMeta =\n entry.dirName && manifestRoot\n ? readBundledPluginPackageMetadata(\n manifestRoot,\n entry.dirName,\n entry.npmName,\n )\n : undefined;\n const configKeys =\n Array.isArray(entry.configKeys) && entry.configKeys.length > 0\n ? entry.configKeys\n : (bundledMeta?.configKeys ?? []);\n const envKey = entry.envKey ?? findPrimaryEnvKey(configKeys);\n const parameters = buildPluginParamDefs(\n entry.pluginParameters ?? bundledMeta?.pluginParameters,\n );\n const advancedCapabilityStatus = resolveAdvancedCapabilityCompatStatus(\n pluginId,\n config,\n runtime,\n );\n const active =\n advancedCapabilityStatus?.isActive ??\n isPluginLoaded(pluginId, entry.npmName, loadedNames);\n const persistedEnabled = resolvePersistedPluginEnabled(\n pluginId,\n category,\n entry.npmName,\n configEntries,\n configRecord,\n );\n const enabled = resolveCompatPluginEnabledForList(\n active,\n persistedEnabled,\n advancedCapabilityStatus?.enabled,\n );\n const validationErrors = parameters\n .filter((parameter) => parameter.required && !parameter.isSet)\n .map((parameter) => ({\n field: parameter.key,\n message: \"Required value is not configured.\",\n }));\n\n const registryEntry = registry.byId.get(pluginId);\n plugins.set(pluginId, {\n id: pluginId,\n name: entry.name ?? titleCasePluginId(pluginId),\n description: entry.description ?? bundledMeta?.description ?? \"\",\n tags: entry.tags ?? [],\n enabled,\n configured: validationErrors.length === 0,\n envKey,\n category,\n source: \"bundled\",\n configKeys,\n parameters,\n validationErrors,\n validationWarnings: [],\n npmName: entry.npmName,\n version:\n resolveInstalledPackageVersion(entry.npmName) ??\n entry.version ??\n undefined,\n pluginDeps: entry.pluginDeps,\n isActive: active,\n configUiHints: entry.configUiHints ?? bundledMeta?.configUiHints,\n icon: entry.logoUrl ?? bundledMeta?.icon ?? null,\n homepage: entry.homepage ?? bundledMeta?.homepage,\n repository: entry.repository ?? bundledMeta?.repository,\n setupGuideUrl: entry.setupGuideUrl,\n iconName: registryEntry?.render.icon,\n group: registryEntry?.render.group,\n groupOrder: registryEntry?.render.groupOrder,\n visible: registryEntry?.render.visible ?? true,\n });\n }\n\n for (const entry of discoverPluginsFromManifest()) {\n const pluginId = normalizePluginId(entry.id);\n const category = normalizePluginCategory(entry.category);\n if (category === \"app\" || plugins.has(pluginId)) {\n continue;\n }\n\n const active = isPluginLoaded(pluginId, entry.npmName, loadedNames);\n const persistedEnabled = resolvePersistedPluginEnabled(\n pluginId,\n category,\n entry.npmName,\n configEntries,\n configRecord,\n );\n\n plugins.set(pluginId, {\n id: pluginId,\n name: entry.name,\n description: entry.description,\n tags: entry.tags,\n enabled: resolveCompatPluginEnabledForList(active, persistedEnabled),\n configured: entry.configured,\n envKey: entry.envKey,\n category,\n source: entry.source,\n configKeys: entry.configKeys,\n parameters: entry.parameters,\n validationErrors: entry.validationErrors,\n validationWarnings: entry.validationWarnings,\n npmName: entry.npmName,\n version:\n resolveInstalledPackageVersion(entry.npmName) ??\n entry.version ??\n undefined,\n pluginDeps: entry.pluginDeps,\n isActive: active,\n configUiHints: entry.configUiHints,\n icon: entry.icon ?? null,\n homepage: entry.homepage,\n repository: entry.repository,\n setupGuideUrl: entry.setupGuideUrl,\n visible: true,\n });\n }\n\n for (const plugin of runtime?.plugins ?? []) {\n const pluginName =\n typeof (plugin as RuntimePluginLike).name === \"string\"\n ? (plugin as RuntimePluginLike).name\n : \"\";\n if (!pluginName) {\n continue;\n }\n\n const pluginId = normalizePluginId(pluginName);\n const existing = plugins.get(pluginId);\n if (existing) {\n existing.isActive = true;\n if (\n existing.enabled !== true &&\n configEntries[pluginId]?.enabled == null\n ) {\n existing.enabled = true;\n }\n if (!existing.version) {\n existing.version =\n resolveInstalledPackageVersion(pluginName) ?? undefined;\n }\n continue;\n }\n\n plugins.set(pluginId, {\n id: pluginId,\n name: titleCasePluginId(pluginId),\n description:\n (plugin as RuntimePluginLike).description ??\n \"Loaded runtime plugin discovered without manifest metadata.\",\n tags: [],\n enabled:\n typeof configEntries[pluginId]?.enabled === \"boolean\"\n ? Boolean(configEntries[pluginId]?.enabled)\n : true,\n configured: true,\n envKey: null,\n category: \"feature\",\n source: \"bundled\",\n parameters: [],\n validationErrors: [],\n validationWarnings: [],\n npmName: pluginName,\n version: resolveInstalledPackageVersion(pluginName) ?? undefined,\n isActive: true,\n icon: null,\n });\n }\n\n for (const [pluginName, installRecord] of Object.entries(installEntries)) {\n const pluginId = normalizePluginId(pluginName);\n if (plugins.has(pluginId)) {\n continue;\n }\n\n plugins.set(pluginId, {\n id: pluginId,\n name: titleCasePluginId(pluginId),\n description: \"Installed store plugin.\",\n tags: [],\n enabled:\n typeof configEntries[pluginId]?.enabled === \"boolean\"\n ? Boolean(configEntries[pluginId]?.enabled)\n : false,\n configured: true,\n envKey: null,\n category: \"feature\",\n source: \"store\",\n parameters: [],\n validationErrors: [],\n validationWarnings: [],\n npmName: pluginName,\n version:\n typeof installRecord.version === \"string\"\n ? installRecord.version\n : (resolveInstalledPackageVersion(pluginName) ?? undefined),\n isActive: isPluginLoaded(pluginId, pluginName, loadedNames),\n icon: null,\n });\n }\n\n const pluginList = Array.from(plugins.values()).sort((left, right) =>\n String(left.name ?? \"\").localeCompare(String(right.name ?? \"\")),\n );\n return { plugins: pluginList };\n}\n\nfunction validateCompatPluginConfig(\n plugin: CompatPluginRecord,\n config: Record<string, unknown>,\n): {\n errors: Array<{ field: string; message: string }>;\n values: Record<string, string>;\n} {\n const paramMap = new Map(\n plugin.parameters.map((parameter) => [parameter.key, parameter]),\n );\n const errors: Array<{ field: string; message: string }> = [];\n const values: Record<string, string> = {};\n\n for (const [key, rawValue] of Object.entries(config)) {\n const parameter = paramMap.get(key);\n if (!parameter) {\n errors.push({\n field: key,\n message: `${key} is not a declared config key for this plugin`,\n });\n continue;\n }\n\n if (typeof rawValue !== \"string\") {\n errors.push({\n field: key,\n message: \"Plugin config values must be strings.\",\n });\n continue;\n }\n\n const trimmed = rawValue.trim();\n if (parameter.required && trimmed.length === 0) {\n errors.push({\n field: key,\n message: \"Required value is not configured.\",\n });\n continue;\n }\n\n values[key] = rawValue;\n }\n\n return { errors, values };\n}\n\nexport function persistCompatPluginMutation(\n pluginId: string,\n body: Record<string, unknown>,\n plugin: CompatPluginRecord,\n): {\n status: number;\n payload: Record<string, unknown>;\n} {\n const config = loadElizaConfig();\n const configRecord = config as Record<string, unknown>;\n config.plugins ??= {};\n config.plugins.entries ??= {};\n config.plugins.entries[pluginId] ??= {};\n const pluginEntry = config.plugins.entries[pluginId] as Record<\n string,\n unknown\n >;\n\n if (typeof body.enabled === \"boolean\") {\n pluginEntry.enabled = body.enabled;\n\n if (CAPABILITY_FEATURE_IDS.has(pluginId)) {\n config.features ??= {};\n config.features[pluginId] = body.enabled;\n }\n\n if (plugin.category === \"connector\") {\n writeCompatSectionEnabled(\n configRecord,\n \"connectors\",\n resolveCompatConfigKey(pluginId, plugin.npmName, CONNECTOR_PLUGINS),\n body.enabled,\n );\n }\n\n if (plugin.category === \"streaming\") {\n writeCompatSectionEnabled(\n configRecord,\n \"streaming\",\n resolveCompatConfigKey(pluginId, plugin.npmName, STREAMING_PLUGINS),\n body.enabled,\n );\n }\n }\n\n if (body.config !== undefined) {\n if (\n !body.config ||\n typeof body.config !== \"object\" ||\n Array.isArray(body.config)\n ) {\n return {\n status: 400,\n payload: { ok: false, error: \"Plugin config must be a JSON object.\" },\n };\n }\n\n const configObject = body.config as Record<string, unknown>;\n const { errors, values } = validateCompatPluginConfig(plugin, configObject);\n if (errors.length > 0) {\n return {\n status: 422,\n payload: { ok: false, plugin, validationErrors: errors },\n };\n }\n\n const nextConfig =\n pluginEntry.config &&\n typeof pluginEntry.config === \"object\" &&\n !Array.isArray(pluginEntry.config)\n ? { ...(pluginEntry.config as Record<string, unknown>) }\n : {};\n\n config.env ??= {};\n for (const [key, value] of Object.entries(values)) {\n if (value.trim()) {\n config.env[key] = value;\n nextConfig[key] = value;\n } else {\n delete config.env[key];\n delete nextConfig[key];\n }\n }\n\n pluginEntry.config = nextConfig;\n if (plugin.category === \"connector\") {\n syncCompatConnectorConfigValues(\n configRecord,\n pluginId,\n plugin.npmName,\n values,\n );\n }\n\n saveElizaConfig(config);\n\n for (const [key, value] of Object.entries(values)) {\n try {\n if (value.trim()) {\n process.env[key] = value;\n } else {\n delete process.env[key];\n }\n } catch {\n // process.env may be read-only in sandboxed or frozen environments.\n // Config is already persisted to disk above, so this is non-fatal.\n }\n }\n } else {\n saveElizaConfig(config);\n }\n\n const refreshed = buildPluginListResponse(null).plugins.find(\n (candidate) => candidate.id === pluginId,\n );\n\n return {\n status: 200,\n payload: {\n ok: true,\n plugin: refreshed ?? plugin,\n },\n };\n}\n\n// ---------------------------------------------------------------------------\n// Route handler\n// ---------------------------------------------------------------------------\n\n/**\n * Plugin management routes.\n *\n * Contract note:\n * - `/api/plugins` is the Settings/UI model.\n * - `/api/plugins/core` is the optional-core allow-list model.\n * - These can drift; use `/api/plugins/diagnostics` to inspect mismatches.\n *\n * - `GET /api/plugins` — returns filtered plugin list\n * - `GET /api/plugins/diagnostics` — returns drift diagnostics\n * - `PUT /api/plugins/:id` — updates plugin config, writes env vars\n * - `POST /api/plugins/:id/test` — tests plugin connectivity\n * - `POST /api/plugins/:id/reveal` — reveals plugin env var value\n */\nexport async function handlePluginsCompatRoutes(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n state: CompatRuntimeState,\n): Promise<boolean> {\n const method = (req.method ?? \"GET\").toUpperCase();\n const url = new URL(req.url ?? \"/\", \"http://localhost\");\n\n if (!url.pathname.startsWith(\"/api/plugins\")) {\n return false;\n }\n\n if (method === \"GET\" && url.pathname === \"/api/plugins\") {\n if (!(await ensureRouteAuthorized(req, res, state))) {\n return true;\n }\n\n const pluginResponse = buildPluginListResponse(state.current);\n logger.debug(\n `[api/plugins] source=registry total=${pluginResponse.plugins.length} runtime=${state.current ? \"active\" : \"null\"}`,\n );\n maybeLogPluginStateDrift(buildPluginDriftDiagnostics(state.current));\n sendJsonResponse(res, 200, pluginResponse);\n return true;\n }\n\n if (method === \"GET\" && url.pathname === \"/api/plugins/diagnostics\") {\n if (!(await ensureRouteAuthorized(req, res, state))) {\n return true;\n }\n const diagnostics = buildPluginDriftDiagnostics(state.current);\n maybeLogPluginStateDrift(diagnostics);\n sendJsonResponse(res, 200, diagnostics);\n return true;\n }\n\n if (method === \"PUT\" && url.pathname.startsWith(\"/api/plugins/\")) {\n if (!(await ensureRouteAuthorized(req, res, state))) {\n return true;\n }\n\n const body = await readCompatJsonBody(req, res);\n if (body == null) {\n return true;\n }\n\n const decodedPluginId = decodePluginPathSegment(\n url.pathname.slice(\"/api/plugins/\".length),\n );\n if (decodedPluginId === null) {\n sendJsonErrorResponse(res, 400, \"Invalid plugin path\");\n return true;\n }\n\n const pluginId = normalizePluginId(decodedPluginId);\n const plugin = buildPluginListResponse(state.current).plugins.find(\n (candidate) => candidate.id === pluginId,\n );\n\n if (!plugin) {\n sendJsonErrorResponse(res, 404, `Plugin \"${pluginId}\" not found`);\n return true;\n }\n\n const previousConfig = structuredClone(loadElizaConfig());\n const result = persistCompatPluginMutation(pluginId, body, plugin);\n if (result.status === 200) {\n const nextConfig = loadElizaConfig();\n const runtimeApply = await applyCompatRuntimeMutation({\n state,\n pluginId,\n plugin,\n body,\n previousConfig,\n nextConfig,\n });\n\n if (runtimeApply.requiresRestart) {\n scheduleCompatRuntimeRestart(state, runtimeApply.reason);\n }\n\n const refreshed = buildPluginListResponse(state.current).plugins.find(\n (candidate) => candidate.id === pluginId,\n );\n\n result.payload.plugin = refreshed ?? result.payload.plugin ?? plugin;\n result.payload.applied = runtimeApply.mode;\n result.payload.requiresRestart = runtimeApply.requiresRestart;\n result.payload.restartedRuntime = runtimeApply.restartedRuntime;\n result.payload.loadedPackages = runtimeApply.loadedPackages;\n result.payload.unloadedPackages = runtimeApply.unloadedPackages;\n result.payload.reloadedPackages = runtimeApply.reloadedPackages;\n\n // Write-through mirror to @elizaos/vault. Sensitive fields are\n // copied into the vault (encrypted at rest via the OS-keychain master\n // key). The config.env writes above also persist — vault mirrors them.\n //\n // If vault.set throws (keychain locked, ENOSPC, missing master key,\n // etc.), the save is NOT rolled back — config storage already\n // succeeded. Failed keys are surfaced as `vaultMirrorFailures` so\n // the UI can warn the user rather than silently showing \"Saved\".\n const mirrorResult = await mirrorPluginSensitiveToVault(plugin, body);\n if (mirrorResult.failures.length > 0) {\n result.payload.vaultMirrorFailures = mirrorResult.failures;\n }\n const diagnostics = buildPluginDriftDiagnostics(state.current);\n if (diagnostics.summary.withDrift > 0) {\n result.payload.diagnostics = diagnostics;\n }\n }\n sendJsonResponse(res, result.status, result.payload);\n return true;\n }\n\n const testMatch =\n method === \"POST\" && url.pathname.match(/^\\/api\\/plugins\\/([^/]+)\\/test$/);\n if (testMatch) {\n if (!(await ensureRouteAuthorized(req, res, state))) return true;\n const decodedTestPluginId = decodePluginPathSegment(testMatch[1]);\n if (decodedTestPluginId === null) {\n sendJsonErrorResponse(res, 400, \"Invalid plugin path\");\n return true;\n }\n const testPluginId = normalizePluginId(decodedTestPluginId);\n const startMs = Date.now();\n\n if (testPluginId === \"telegram\") {\n const token = process.env.TELEGRAM_BOT_TOKEN;\n if (!token) {\n sendJsonResponse(res, 422, {\n success: false,\n pluginId: testPluginId,\n error: \"No bot token configured\",\n durationMs: Date.now() - startMs,\n });\n return true;\n }\n try {\n const apiRoot =\n process.env.TELEGRAM_API_ROOT || \"https://api.telegram.org\";\n const tgResp = await fetch(`${apiRoot}/bot${token}/getMe`);\n const tgData = (await tgResp.json()) as {\n ok: boolean;\n result?: { username?: string };\n description?: string;\n };\n sendJsonResponse(res, tgData.ok ? 200 : 422, {\n success: tgData.ok,\n pluginId: testPluginId,\n message: tgData.ok\n ? `Connected as @${tgData.result?.username}`\n : `Telegram API error: ${tgData.description}`,\n durationMs: Date.now() - startMs,\n });\n } catch (err) {\n sendJsonResponse(res, 422, {\n success: false,\n pluginId: testPluginId,\n error: err instanceof Error ? err.message : String(err),\n durationMs: Date.now() - startMs,\n });\n }\n return true;\n }\n\n sendJsonResponse(res, 200, {\n success: true,\n pluginId: testPluginId,\n message: \"Plugin is loaded (no custom test available)\",\n durationMs: Date.now() - startMs,\n });\n return true;\n }\n\n const revealMatch =\n method === \"POST\" &&\n url.pathname.match(/^\\/api\\/plugins\\/([^/]+)\\/reveal$/);\n if (revealMatch) {\n if (!(await ensureRouteAuthorized(req, res, state))) return true;\n const revealBody = await readCompatJsonBody(req, res);\n if (revealBody == null) return true;\n const key = (revealBody.key as string)?.trim();\n if (!key) {\n sendJsonErrorResponse(res, 400, \"Missing key parameter\");\n return true;\n }\n const upperKey = key.toUpperCase();\n if (\n !REVEALABLE_KEY_PREFIXES.some((prefix) => upperKey.startsWith(prefix))\n ) {\n sendJsonErrorResponse(\n res,\n 403,\n \"Key is not in the allowlist of revealable plugin config keys\",\n );\n return true;\n }\n // Wallet / private-key prefixes require elevated auth to prevent\n // accidental exposure through the general plugin config UI.\n if (SENSITIVE_KEY_PREFIXES.some((prefix) => upperKey.startsWith(prefix))) {\n if (!ensureCompatSensitiveRouteAuthorized(req, res)) return true;\n }\n // Prefer the vault. Fall back to env/config when the vault has no\n // entry; vault/keychain failures surface instead of silently falling\n // back to env.\n try {\n const decodedRevealPluginId = decodePluginPathSegment(revealMatch[1]);\n if (decodedRevealPluginId === null) {\n sendJsonErrorResponse(res, 400, \"Invalid plugin path\");\n return true;\n }\n const vaultValue = await sharedVault().reveal(\n key,\n `plugins:${decodedRevealPluginId}:reveal`,\n );\n sendJsonResponse(res, 200, { ok: true, value: vaultValue });\n return true;\n } catch (err) {\n if (!(err instanceof VaultMissError)) {\n logger.warn(\n `[api/plugins] Vault reveal failed for ${key}: ${\n err instanceof Error ? err.message : String(err)\n }`,\n );\n sendJsonErrorResponse(res, 500, \"Vault reveal failed\");\n return true;\n }\n }\n const config = loadElizaConfig();\n const fallbackValue =\n process.env[key] ??\n (config.env as Record<string, string> | undefined)?.[key] ??\n null;\n // The env/config fallback may itself be a `vault://KEY` sentinel. Resolve\n // it once. If the vault still misses, return null rather than the sentinel.\n if (typeof fallbackValue === \"string\" && isVaultRef(fallbackValue)) {\n const innerKey = parseVaultRef(fallbackValue);\n if (innerKey) {\n try {\n const inner = await sharedVault().get(innerKey);\n if (inner) {\n sendJsonResponse(res, 200, { ok: true, value: inner });\n return true;\n }\n } catch {\n // fall through to null\n }\n }\n sendJsonResponse(res, 200, { ok: true, value: null });\n return true;\n }\n sendJsonResponse(res, 200, { ok: true, value: fallbackValue });\n return true;\n }\n\n return false;\n}\n"],"mappings":"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","names":["require"]}
@@ -0,0 +1,140 @@
1
+ import type http from "node:http";
2
+ import { type CoreManagerLike, type ElizaConfig, type PluginManagerLike, type PluginWidgetDeclarationServer } from "@elizaos/agent";
3
+ import type { AgentRuntime } from "@elizaos/core";
4
+ import type { PluginParamDef, ReadJsonBodyOptions } from "@elizaos/shared";
5
+ interface PluginEntry {
6
+ id: string;
7
+ name: string;
8
+ description: string;
9
+ tags: string[];
10
+ enabled: boolean;
11
+ configured: boolean;
12
+ envKey: string | null;
13
+ category: "ai-provider" | "connector" | "streaming" | "database" | "app" | "feature";
14
+ source: "bundled" | "store";
15
+ configKeys: string[];
16
+ parameters: PluginParamDef[];
17
+ validationErrors: Array<{
18
+ field: string;
19
+ message: string;
20
+ }>;
21
+ validationWarnings: Array<{
22
+ field: string;
23
+ message: string;
24
+ }>;
25
+ npmName?: string;
26
+ directory?: string | null;
27
+ registryKind?: string;
28
+ origin?: "builtin" | "third-party" | string;
29
+ registrySource?: string;
30
+ support?: "first-party" | "community" | string;
31
+ builtIn?: boolean;
32
+ firstParty?: boolean;
33
+ thirdParty?: boolean;
34
+ status?: string;
35
+ version?: string;
36
+ releaseStream?: "latest" | "beta";
37
+ requestedVersion?: string;
38
+ latestVersion?: string | null;
39
+ betaVersion?: string | null;
40
+ pluginDeps?: string[];
41
+ isActive?: boolean;
42
+ loadError?: string;
43
+ configUiHints?: Record<string, Record<string, unknown>>;
44
+ icon?: string | null;
45
+ homepage?: string;
46
+ repository?: string;
47
+ setupGuideUrl?: string;
48
+ autoEnabled?: boolean;
49
+ managementMode?: "standard" | "core-optional";
50
+ capabilityStatus?: "loaded" | "auto-enabled" | "blocked" | "missing-prerequisites" | "disabled";
51
+ capabilityReason?: string | null;
52
+ prerequisites?: Array<{
53
+ label: string;
54
+ met: boolean;
55
+ }>;
56
+ /** Widget declarations for this plugin (rendered by the UI widget system). */
57
+ widgets?: PluginWidgetDeclarationServer[];
58
+ /** App metadata (nav tabs, developer-only, app-store visibility). */
59
+ app?: {
60
+ displayName?: string;
61
+ category?: string;
62
+ icon?: string | null;
63
+ developerOnly?: boolean;
64
+ visibleInAppStore?: boolean;
65
+ navTabs?: Array<{
66
+ id: string;
67
+ label: string;
68
+ icon?: string;
69
+ path: string;
70
+ order?: number;
71
+ developerOnly?: boolean;
72
+ group?: string;
73
+ componentExport?: string;
74
+ }>;
75
+ };
76
+ }
77
+ interface SecretEntry {
78
+ key: string;
79
+ description: string;
80
+ category: string;
81
+ sensitive: boolean;
82
+ required: boolean;
83
+ isSet: boolean;
84
+ maskedValue: string | null;
85
+ usedBy: Array<{
86
+ pluginId: string;
87
+ pluginName: string;
88
+ enabled: boolean;
89
+ }>;
90
+ }
91
+ export interface PluginRouteContext {
92
+ req: http.IncomingMessage;
93
+ res: http.ServerResponse;
94
+ method: string;
95
+ pathname: string;
96
+ url: URL;
97
+ state: {
98
+ runtime: AgentRuntime | null;
99
+ config: ElizaConfig;
100
+ plugins: PluginEntry[];
101
+ broadcastWs: ((data: object) => void) | null;
102
+ };
103
+ json: (res: http.ServerResponse, data: unknown, status?: number) => void;
104
+ error: (res: http.ServerResponse, message: string, status?: number) => void;
105
+ readJsonBody: <T extends object>(req: http.IncomingMessage, res: http.ServerResponse, options?: ReadJsonBodyOptions) => Promise<T | null>;
106
+ scheduleRuntimeRestart: (reason: string) => void;
107
+ restartRuntime?: (reason: string) => Promise<boolean>;
108
+ BLOCKED_ENV_KEYS: Set<string>;
109
+ discoverInstalledPlugins: (config: ElizaConfig, bundledIds: Set<string>) => PluginEntry[];
110
+ maskValue: (value: string) => string;
111
+ aggregateSecrets: (plugins: PluginEntry[]) => SecretEntry[];
112
+ readProviderCache: (providerId: string) => {
113
+ models: Array<{
114
+ id: string;
115
+ name: string;
116
+ category: string;
117
+ }>;
118
+ } | null;
119
+ paramKeyToCategory: (paramKey: string) => string;
120
+ buildPluginEvmDiagnosticEntry: (opts: {
121
+ config: ElizaConfig;
122
+ runtime: AgentRuntime | null;
123
+ }) => PluginEntry;
124
+ EVM_PLUGIN_PACKAGE: string;
125
+ applyWhatsAppQrOverride: (plugins: PluginEntry[], workspaceDir: string) => void;
126
+ applySignalQrOverride: (plugins: PluginEntry[], workspaceDir: string) => void;
127
+ resolvePluginConfigMutationRejections: (parameters: PluginParamDef[], configObj: Record<string, string>) => Array<{
128
+ field: string;
129
+ message: string;
130
+ }>;
131
+ requirePluginManager: (runtime: AgentRuntime | null) => PluginManagerLike;
132
+ requireCoreManager: (runtime: AgentRuntime | null) => CoreManagerLike;
133
+ }
134
+ /**
135
+ * Handle plugin management routes (/api/plugins/*, /api/secrets, /api/core/*).
136
+ * Returns `true` if the request was handled.
137
+ */
138
+ export declare function handlePluginRoutes(ctx: PluginRouteContext): Promise<boolean>;
139
+ export {};
140
+ //# sourceMappingURL=plugin-routes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin-routes.d.ts","sourceRoot":"","sources":["../../src/api/plugin-routes.ts"],"names":[],"mappings":"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"}