import { resolveAgentWorkspaceDir, resolveDefaultAgentId } from "../agents/agent-scope.js"; import { initSubagentRegistry } from "../agents/subagent-registry.js"; import { applyPluginAutoEnable } from "../config/plugin-auto-enable.js"; import type { OpenClawConfig } from "../config/types.openclaw.js"; import { loadPluginLookUpTable } from "../plugins/plugin-lookup-table.js"; import type { PluginMetadataSnapshot } from "../plugins/plugin-metadata-snapshot.js"; import type { PluginRegistryParams } from "../plugins/registry-types.js"; import { createEmptyPluginRegistry } from "../plugins/registry.js"; import { getActivePluginRegistry, setActivePluginRegistry } from "../plugins/runtime.js"; import { listCoreGatewayMethodNames } from "./methods/core-descriptors.js"; import { mergeActivationSectionsIntoRuntimeConfig } from "./plugin-activation-runtime-config.js"; import { listGatewayMethods } from "./server-methods-list.js"; type GatewayPluginBootstrapLog = { info: (message: string) => void; warn: (message: string) => void; error: (message: string) => void; debug: (message: string) => void; }; type GatewayStartupTrace = { detail: (name: string, metrics: ReadonlyArray) => void; }; export function resolveGatewayStartupMaintenanceConfig(params: { cfgAtStart: OpenClawConfig; startupRuntimeConfig: OpenClawConfig; }): OpenClawConfig { return params.cfgAtStart.channels === undefined && params.startupRuntimeConfig.channels !== undefined ? { ...params.cfgAtStart, channels: params.startupRuntimeConfig.channels, } : params.cfgAtStart; } export async function prepareGatewayPluginBootstrap(params: { cfgAtStart: OpenClawConfig; activationSourceConfig?: OpenClawConfig; startupRuntimeConfig: OpenClawConfig; pluginMetadataSnapshot?: PluginMetadataSnapshot; minimalTestGateway: boolean; log: GatewayPluginBootstrapLog; loadRuntimePlugins?: boolean; }) { const activationSourceConfig = params.activationSourceConfig ?? params.cfgAtStart; const startupMaintenanceConfig = resolveGatewayStartupMaintenanceConfig({ cfgAtStart: params.cfgAtStart, startupRuntimeConfig: params.startupRuntimeConfig, }); const shouldRunStartupMaintenance = !params.minimalTestGateway || startupMaintenanceConfig.channels !== undefined; if (shouldRunStartupMaintenance) { const { runChannelPluginStartupMaintenance } = await import("../channels/plugins/lifecycle-startup.js"); const startupTasks = [ runChannelPluginStartupMaintenance({ cfg: startupMaintenanceConfig, env: process.env, log: params.log, }), ]; if (!params.minimalTestGateway) { const { runStartupSessionMigration } = await import("./server-startup-session-migration.js"); startupTasks.push( runStartupSessionMigration({ cfg: params.cfgAtStart, env: process.env, log: params.log, }), ); } await Promise.all(startupTasks); } initSubagentRegistry(); const gatewayPluginConfig = params.minimalTestGateway ? params.cfgAtStart : mergeActivationSectionsIntoRuntimeConfig({ runtimeConfig: params.cfgAtStart, activationConfig: applyPluginAutoEnable({ config: activationSourceConfig, env: process.env, ...(params.pluginMetadataSnapshot?.manifestRegistry ? { manifestRegistry: params.pluginMetadataSnapshot.manifestRegistry } : {}), }).config, }); const pluginsGloballyDisabled = gatewayPluginConfig.plugins?.enabled === false; const defaultAgentId = resolveDefaultAgentId(gatewayPluginConfig); const defaultWorkspaceDir = resolveAgentWorkspaceDir(gatewayPluginConfig, defaultAgentId); const pluginLookUpTable = params.minimalTestGateway || pluginsGloballyDisabled ? undefined : loadPluginLookUpTable({ config: gatewayPluginConfig, workspaceDir: defaultWorkspaceDir, env: process.env, activationSourceConfig, metadataSnapshot: params.pluginMetadataSnapshot, }); const deferredConfiguredChannelPluginIds = [ ...(pluginLookUpTable?.startup.configuredDeferredChannelPluginIds ?? []), ]; const startupPluginIds = [...(pluginLookUpTable?.startup.pluginIds ?? [])]; const baseMethods = listGatewayMethods(); const coreGatewayMethodNames = listCoreGatewayMethodNames(); const emptyPluginRegistry = createEmptyPluginRegistry(); let pluginRegistry = emptyPluginRegistry; let baseGatewayMethods = baseMethods; const shouldLoadRuntimePlugins = params.loadRuntimePlugins !== false; if (!params.minimalTestGateway && shouldLoadRuntimePlugins) { ({ pluginRegistry, gatewayMethods: baseGatewayMethods } = await loadGatewayStartupPluginRuntime( { cfg: gatewayPluginConfig, activationSourceConfig, workspaceDir: defaultWorkspaceDir, log: params.log, baseMethods, coreGatewayMethodNames, startupPluginIds, pluginLookUpTable, preferSetupRuntimeForChannelPlugins: deferredConfiguredChannelPluginIds.length > 0, suppressPluginInfoLogs: deferredConfiguredChannelPluginIds.length > 0, }, )); } else { pluginRegistry = params.minimalTestGateway ? (getActivePluginRegistry() ?? emptyPluginRegistry) : emptyPluginRegistry; setActivePluginRegistry(pluginRegistry); } return { gatewayPluginConfigAtStart: gatewayPluginConfig, defaultWorkspaceDir, deferredConfiguredChannelPluginIds, startupPluginIds, pluginLookUpTable, baseMethods, pluginRegistry, baseGatewayMethods, runtimePluginsLoaded: !params.minimalTestGateway && shouldLoadRuntimePlugins, }; } export async function loadGatewayStartupPluginRuntime(params: { cfg: OpenClawConfig; activationSourceConfig?: OpenClawConfig; workspaceDir: string; log: GatewayPluginBootstrapLog; baseMethods: string[]; coreGatewayMethodNames?: readonly string[]; hostServices?: PluginRegistryParams["hostServices"]; startupPluginIds: string[]; pluginLookUpTable?: ReturnType; preferSetupRuntimeForChannelPlugins?: boolean; suppressPluginInfoLogs?: boolean; startupTrace?: GatewayStartupTrace; }) { const { loadGatewayStartupPlugins } = await import("./server-plugin-bootstrap.js"); return loadGatewayStartupPlugins({ cfg: params.cfg, activationSourceConfig: params.activationSourceConfig, workspaceDir: params.workspaceDir, log: params.log, coreGatewayMethodNames: params.coreGatewayMethodNames ?? params.baseMethods, baseMethods: params.baseMethods, ...(params.hostServices !== undefined && { hostServices: params.hostServices, }), pluginIds: params.startupPluginIds, pluginLookUpTable: params.pluginLookUpTable, preferSetupRuntimeForChannelPlugins: params.preferSetupRuntimeForChannelPlugins, suppressPluginInfoLogs: params.suppressPluginInfoLogs, startupTrace: params.startupTrace, }); }