mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-19 21:21:10 +00:00
fix(plugins): split setup registry runtime types
This commit is contained in:
@@ -3,21 +3,20 @@ import path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { normalizeProviderId } from "../agents/provider-id.js";
|
||||
import type { OpenClawConfig } from "../config/types.openclaw.js";
|
||||
import { buildPluginApi } from "./api-builder.js";
|
||||
import type { CliBackendPlugin } from "./cli-backend.types.js";
|
||||
import { collectPluginConfigContractMatches } from "./config-contracts.js";
|
||||
import { discoverOpenClawPlugins } from "./discovery.js";
|
||||
import { getCachedPluginJitiLoader, type PluginJitiLoaderCache } from "./jiti-loader-cache.js";
|
||||
import { loadPluginManifestRegistry } from "./manifest-registry.js";
|
||||
import { resolvePluginCacheInputs } from "./roots.js";
|
||||
import type { PluginRuntime } from "./runtime/types.js";
|
||||
import type {
|
||||
CliBackendPlugin,
|
||||
OpenClawPluginModule,
|
||||
PluginConfigMigration,
|
||||
PluginLogger,
|
||||
PluginSetupAutoEnableProbe,
|
||||
ProviderPlugin,
|
||||
} from "./types.js";
|
||||
SetupOnlyPluginApi,
|
||||
SetupOnlyPluginModule,
|
||||
SetupPluginAutoEnableProbe,
|
||||
SetupPluginConfigMigration,
|
||||
SetupPluginLogger,
|
||||
SetupProviderPlugin,
|
||||
} from "./setup-registry.types.js";
|
||||
|
||||
const SETUP_API_EXTENSIONS = [".js", ".mjs", ".cjs", ".ts", ".mts", ".cts"] as const;
|
||||
const CURRENT_MODULE_PATH = fileURLToPath(import.meta.url);
|
||||
@@ -27,7 +26,7 @@ const RUNNING_FROM_BUILT_ARTIFACT =
|
||||
|
||||
type SetupProviderEntry = {
|
||||
pluginId: string;
|
||||
provider: ProviderPlugin;
|
||||
provider: SetupProviderPlugin;
|
||||
};
|
||||
|
||||
type SetupCliBackendEntry = {
|
||||
@@ -37,12 +36,12 @@ type SetupCliBackendEntry = {
|
||||
|
||||
type SetupConfigMigrationEntry = {
|
||||
pluginId: string;
|
||||
migrate: PluginConfigMigration;
|
||||
migrate: SetupPluginConfigMigration;
|
||||
};
|
||||
|
||||
type SetupAutoEnableProbeEntry = {
|
||||
pluginId: string;
|
||||
probe: PluginSetupAutoEnableProbe;
|
||||
probe: SetupPluginAutoEnableProbe;
|
||||
};
|
||||
|
||||
type PluginSetupRegistry = {
|
||||
@@ -57,8 +56,8 @@ type SetupAutoEnableReason = {
|
||||
reason: string;
|
||||
};
|
||||
|
||||
const EMPTY_RUNTIME = {} as PluginRuntime;
|
||||
const NOOP_LOGGER: PluginLogger = {
|
||||
const EMPTY_SETUP_RUNTIME = {};
|
||||
const NOOP_LOGGER: SetupPluginLogger = {
|
||||
info() {},
|
||||
warn() {},
|
||||
error() {},
|
||||
@@ -66,7 +65,7 @@ const NOOP_LOGGER: PluginLogger = {
|
||||
|
||||
const jitiLoaders: PluginJitiLoaderCache = new Map();
|
||||
const setupRegistryCache = new Map<string, PluginSetupRegistry>();
|
||||
const setupProviderCache = new Map<string, ProviderPlugin | null>();
|
||||
const setupProviderCache = new Map<string, SetupProviderPlugin | null>();
|
||||
|
||||
export function clearPluginSetupRegistryCache(): void {
|
||||
jitiLoaders.clear();
|
||||
@@ -190,9 +189,9 @@ function resolveRelevantSetupMigrationPluginIds(params: {
|
||||
return [...ids].toSorted();
|
||||
}
|
||||
|
||||
function resolveRegister(mod: OpenClawPluginModule): {
|
||||
function resolveRegister(mod: SetupOnlyPluginModule): {
|
||||
definition?: { id?: string };
|
||||
register?: (api: ReturnType<typeof buildPluginApi>) => void | Promise<void>;
|
||||
register?: (api: SetupOnlyPluginApi) => void | Promise<void>;
|
||||
} {
|
||||
if (typeof mod === "function") {
|
||||
return { register: mod };
|
||||
@@ -206,7 +205,7 @@ function resolveRegister(mod: OpenClawPluginModule): {
|
||||
return {};
|
||||
}
|
||||
|
||||
function matchesProvider(provider: ProviderPlugin, providerId: string): boolean {
|
||||
function matchesProvider(provider: SetupProviderPlugin, providerId: string): boolean {
|
||||
const normalized = normalizeProviderId(providerId);
|
||||
if (normalizeProviderId(provider.id) === normalized) {
|
||||
return true;
|
||||
@@ -216,6 +215,73 @@ function matchesProvider(provider: ProviderPlugin, providerId: string): boolean
|
||||
);
|
||||
}
|
||||
|
||||
function createSetupOnlyPluginApi(params: {
|
||||
id: string;
|
||||
name: string;
|
||||
version?: string;
|
||||
description?: string;
|
||||
source: string;
|
||||
rootDir?: string;
|
||||
config?: OpenClawConfig;
|
||||
registerProvider?: (provider: SetupProviderPlugin) => void;
|
||||
registerCliBackend?: (backend: CliBackendPlugin) => void;
|
||||
registerConfigMigration?: (migrate: SetupPluginConfigMigration) => void;
|
||||
registerAutoEnableProbe?: (probe: SetupPluginAutoEnableProbe) => void;
|
||||
}): SetupOnlyPluginApi {
|
||||
const noop = (..._args: unknown[]) => {};
|
||||
return {
|
||||
id: params.id,
|
||||
name: params.name,
|
||||
version: params.version,
|
||||
description: params.description,
|
||||
source: params.source,
|
||||
rootDir: params.rootDir,
|
||||
registrationMode: "setup-only",
|
||||
config: params.config ?? ({} as OpenClawConfig),
|
||||
runtime: EMPTY_SETUP_RUNTIME,
|
||||
logger: NOOP_LOGGER,
|
||||
resolvePath: (input) => input,
|
||||
registerProvider: params.registerProvider ?? noop,
|
||||
registerCliBackend: params.registerCliBackend ?? noop,
|
||||
registerConfigMigration: params.registerConfigMigration ?? noop,
|
||||
registerAutoEnableProbe: params.registerAutoEnableProbe ?? noop,
|
||||
registerTool: noop,
|
||||
registerHook: noop,
|
||||
registerHttpRoute: noop,
|
||||
registerChannel: noop,
|
||||
registerGatewayMethod: noop,
|
||||
registerCli: noop,
|
||||
registerReload: noop,
|
||||
registerNodeHostCommand: noop,
|
||||
registerSecurityAuditCollector: noop,
|
||||
registerService: noop,
|
||||
registerTextTransforms: noop,
|
||||
registerSpeechProvider: noop,
|
||||
registerRealtimeTranscriptionProvider: noop,
|
||||
registerRealtimeVoiceProvider: noop,
|
||||
registerMediaUnderstandingProvider: noop,
|
||||
registerImageGenerationProvider: noop,
|
||||
registerVideoGenerationProvider: noop,
|
||||
registerMusicGenerationProvider: noop,
|
||||
registerWebFetchProvider: noop,
|
||||
registerWebSearchProvider: noop,
|
||||
registerInteractiveHandler: noop,
|
||||
onConversationBindingResolved: noop,
|
||||
registerCommand: noop,
|
||||
registerContextEngine: noop,
|
||||
registerCompactionProvider: noop,
|
||||
registerAgentHarness: noop,
|
||||
registerMemoryCapability: noop,
|
||||
registerMemoryPromptSection: noop,
|
||||
registerMemoryPromptSupplement: noop,
|
||||
registerMemoryCorpusSupplement: noop,
|
||||
registerMemoryFlushPlan: noop,
|
||||
registerMemoryRuntime: noop,
|
||||
registerMemoryEmbeddingProvider: noop,
|
||||
on: noop,
|
||||
};
|
||||
}
|
||||
|
||||
export function resolvePluginSetupRegistry(params?: {
|
||||
workspaceDir?: string;
|
||||
env?: NodeJS.ProcessEnv;
|
||||
@@ -275,14 +341,14 @@ export function resolvePluginSetupRegistry(params?: {
|
||||
continue;
|
||||
}
|
||||
|
||||
let mod: OpenClawPluginModule;
|
||||
let mod: SetupOnlyPluginModule;
|
||||
try {
|
||||
mod = getJiti(setupSource)(setupSource) as OpenClawPluginModule;
|
||||
mod = getJiti(setupSource)(setupSource) as SetupOnlyPluginModule;
|
||||
} catch {
|
||||
continue;
|
||||
}
|
||||
|
||||
const resolved = resolveRegister((mod as { default?: OpenClawPluginModule }).default ?? mod);
|
||||
const resolved = resolveRegister((mod as { default?: SetupOnlyPluginModule }).default ?? mod);
|
||||
if (!resolved.register) {
|
||||
continue;
|
||||
}
|
||||
@@ -290,53 +356,46 @@ export function resolvePluginSetupRegistry(params?: {
|
||||
continue;
|
||||
}
|
||||
|
||||
const api = buildPluginApi({
|
||||
const api = createSetupOnlyPluginApi({
|
||||
id: record.id,
|
||||
name: record.name ?? record.id,
|
||||
version: record.version,
|
||||
description: record.description,
|
||||
source: setupSource,
|
||||
rootDir: record.rootDir,
|
||||
registrationMode: "setup-only",
|
||||
config: {} as OpenClawConfig,
|
||||
runtime: EMPTY_RUNTIME,
|
||||
logger: NOOP_LOGGER,
|
||||
resolvePath: (input) => input,
|
||||
handlers: {
|
||||
registerProvider(provider) {
|
||||
const key = `${record.id}:${normalizeProviderId(provider.id)}`;
|
||||
if (providerKeys.has(key)) {
|
||||
return;
|
||||
}
|
||||
providerKeys.add(key);
|
||||
providers.push({
|
||||
pluginId: record.id,
|
||||
provider,
|
||||
});
|
||||
},
|
||||
registerCliBackend(backend) {
|
||||
const key = `${record.id}:${normalizeProviderId(backend.id)}`;
|
||||
if (cliBackendKeys.has(key)) {
|
||||
return;
|
||||
}
|
||||
cliBackendKeys.add(key);
|
||||
cliBackends.push({
|
||||
pluginId: record.id,
|
||||
backend,
|
||||
});
|
||||
},
|
||||
registerConfigMigration(migrate) {
|
||||
configMigrations.push({
|
||||
pluginId: record.id,
|
||||
migrate,
|
||||
});
|
||||
},
|
||||
registerAutoEnableProbe(probe) {
|
||||
autoEnableProbes.push({
|
||||
pluginId: record.id,
|
||||
probe,
|
||||
});
|
||||
},
|
||||
registerProvider(provider) {
|
||||
const key = `${record.id}:${normalizeProviderId(provider.id)}`;
|
||||
if (providerKeys.has(key)) {
|
||||
return;
|
||||
}
|
||||
providerKeys.add(key);
|
||||
providers.push({
|
||||
pluginId: record.id,
|
||||
provider,
|
||||
});
|
||||
},
|
||||
registerCliBackend(backend) {
|
||||
const key = `${record.id}:${normalizeProviderId(backend.id)}`;
|
||||
if (cliBackendKeys.has(key)) {
|
||||
return;
|
||||
}
|
||||
cliBackendKeys.add(key);
|
||||
cliBackends.push({
|
||||
pluginId: record.id,
|
||||
backend,
|
||||
});
|
||||
},
|
||||
registerConfigMigration(migrate) {
|
||||
configMigrations.push({
|
||||
pluginId: record.id,
|
||||
migrate,
|
||||
});
|
||||
},
|
||||
registerAutoEnableProbe(probe) {
|
||||
autoEnableProbes.push({
|
||||
pluginId: record.id,
|
||||
probe,
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
@@ -364,7 +423,7 @@ export function resolvePluginSetupProvider(params: {
|
||||
provider: string;
|
||||
workspaceDir?: string;
|
||||
env?: NodeJS.ProcessEnv;
|
||||
}): ProviderPlugin | undefined {
|
||||
}): SetupProviderPlugin | undefined {
|
||||
const cacheKey = buildSetupProviderCacheKey(params);
|
||||
if (setupProviderCache.has(cacheKey)) {
|
||||
return setupProviderCache.get(cacheKey) ?? undefined;
|
||||
@@ -398,15 +457,15 @@ export function resolvePluginSetupProvider(params: {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
let mod: OpenClawPluginModule;
|
||||
let mod: SetupOnlyPluginModule;
|
||||
try {
|
||||
mod = getJiti(setupSource)(setupSource) as OpenClawPluginModule;
|
||||
mod = getJiti(setupSource)(setupSource) as SetupOnlyPluginModule;
|
||||
} catch {
|
||||
setupProviderCache.set(cacheKey, null);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const resolved = resolveRegister((mod as { default?: OpenClawPluginModule }).default ?? mod);
|
||||
const resolved = resolveRegister((mod as { default?: SetupOnlyPluginModule }).default ?? mod);
|
||||
if (!resolved.register) {
|
||||
setupProviderCache.set(cacheKey, null);
|
||||
return undefined;
|
||||
@@ -416,33 +475,24 @@ export function resolvePluginSetupProvider(params: {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
let matchedProvider: ProviderPlugin | undefined;
|
||||
let matchedProvider: SetupProviderPlugin | undefined;
|
||||
const localProviderKeys = new Set<string>();
|
||||
const api = buildPluginApi({
|
||||
const api = createSetupOnlyPluginApi({
|
||||
id: record.id,
|
||||
name: record.name ?? record.id,
|
||||
version: record.version,
|
||||
description: record.description,
|
||||
source: setupSource,
|
||||
rootDir: record.rootDir,
|
||||
registrationMode: "setup-only",
|
||||
config: {} as OpenClawConfig,
|
||||
runtime: EMPTY_RUNTIME,
|
||||
logger: NOOP_LOGGER,
|
||||
resolvePath: (input) => input,
|
||||
handlers: {
|
||||
registerProvider(provider) {
|
||||
const key = normalizeProviderId(provider.id);
|
||||
if (localProviderKeys.has(key)) {
|
||||
return;
|
||||
}
|
||||
localProviderKeys.add(key);
|
||||
if (matchesProvider(provider, normalizedProvider)) {
|
||||
matchedProvider = provider;
|
||||
}
|
||||
},
|
||||
registerConfigMigration() {},
|
||||
registerAutoEnableProbe() {},
|
||||
registerProvider(provider) {
|
||||
const key = normalizeProviderId(provider.id);
|
||||
if (localProviderKeys.has(key)) {
|
||||
return;
|
||||
}
|
||||
localProviderKeys.add(key);
|
||||
if (matchesProvider(provider, normalizedProvider)) {
|
||||
matchedProvider = provider;
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
@@ -498,13 +548,13 @@ export function resolvePluginSetupCliBackend(params: {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
let mod: OpenClawPluginModule;
|
||||
let mod: SetupOnlyPluginModule;
|
||||
try {
|
||||
mod = getJiti(setupSource)(setupSource) as OpenClawPluginModule;
|
||||
mod = getJiti(setupSource)(setupSource) as SetupOnlyPluginModule;
|
||||
} catch {
|
||||
return undefined;
|
||||
}
|
||||
const resolved = resolveRegister((mod as { default?: OpenClawPluginModule }).default ?? mod);
|
||||
const resolved = resolveRegister((mod as { default?: SetupOnlyPluginModule }).default ?? mod);
|
||||
if (!resolved.register) {
|
||||
return undefined;
|
||||
}
|
||||
@@ -514,32 +564,22 @@ export function resolvePluginSetupCliBackend(params: {
|
||||
|
||||
let matchedBackend: CliBackendPlugin | undefined;
|
||||
const localBackendKeys = new Set<string>();
|
||||
const api = buildPluginApi({
|
||||
const api = createSetupOnlyPluginApi({
|
||||
id: record.id,
|
||||
name: record.name ?? record.id,
|
||||
version: record.version,
|
||||
description: record.description,
|
||||
source: setupSource,
|
||||
rootDir: record.rootDir,
|
||||
registrationMode: "setup-only",
|
||||
config: {} as OpenClawConfig,
|
||||
runtime: EMPTY_RUNTIME,
|
||||
logger: NOOP_LOGGER,
|
||||
resolvePath: (input) => input,
|
||||
handlers: {
|
||||
registerProvider() {},
|
||||
registerConfigMigration() {},
|
||||
registerAutoEnableProbe() {},
|
||||
registerCliBackend(backend) {
|
||||
const key = normalizeProviderId(backend.id);
|
||||
if (localBackendKeys.has(key)) {
|
||||
return;
|
||||
}
|
||||
localBackendKeys.add(key);
|
||||
if (key === normalized) {
|
||||
matchedBackend = backend;
|
||||
}
|
||||
},
|
||||
registerCliBackend(backend) {
|
||||
const key = normalizeProviderId(backend.id);
|
||||
if (localBackendKeys.has(key)) {
|
||||
return;
|
||||
}
|
||||
localBackendKeys.add(key);
|
||||
if (key === normalized) {
|
||||
matchedBackend = backend;
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
100
src/plugins/setup-registry.types.ts
Normal file
100
src/plugins/setup-registry.types.ts
Normal file
@@ -0,0 +1,100 @@
|
||||
import type { OpenClawConfig } from "../config/types.openclaw.js";
|
||||
import type { CliBackendPlugin } from "./cli-backend.types.js";
|
||||
|
||||
export type SetupPluginLogger = {
|
||||
debug?: (message: string) => void;
|
||||
info: (message: string) => void;
|
||||
warn: (message: string) => void;
|
||||
error: (message: string) => void;
|
||||
};
|
||||
|
||||
export type SetupProviderPlugin = {
|
||||
id: string;
|
||||
aliases?: string[];
|
||||
hookAliases?: string[];
|
||||
resolveConfigApiKey?: (params: {
|
||||
provider: string;
|
||||
env?: NodeJS.ProcessEnv;
|
||||
cfg?: OpenClawConfig;
|
||||
workspaceDir?: string;
|
||||
}) => string | null | undefined;
|
||||
};
|
||||
|
||||
export type SetupPluginConfigMigration = (config: OpenClawConfig) =>
|
||||
| {
|
||||
config: OpenClawConfig;
|
||||
changes: string[];
|
||||
}
|
||||
| null
|
||||
| undefined;
|
||||
|
||||
export type SetupPluginAutoEnableContext = {
|
||||
config: OpenClawConfig;
|
||||
env: NodeJS.ProcessEnv;
|
||||
};
|
||||
|
||||
export type SetupPluginAutoEnableProbe = (
|
||||
ctx: SetupPluginAutoEnableContext,
|
||||
) => string | string[] | null | undefined;
|
||||
|
||||
export type SetupOnlyPluginApi = {
|
||||
id: string;
|
||||
name: string;
|
||||
version?: string;
|
||||
description?: string;
|
||||
source: string;
|
||||
rootDir?: string;
|
||||
registrationMode: "setup-only";
|
||||
config: OpenClawConfig;
|
||||
pluginConfig?: Record<string, unknown>;
|
||||
runtime: Record<string, never>;
|
||||
logger: SetupPluginLogger;
|
||||
resolvePath: (input: string) => string;
|
||||
registerProvider: (provider: SetupProviderPlugin) => void;
|
||||
registerCliBackend: (backend: CliBackendPlugin) => void;
|
||||
registerConfigMigration: (migrate: SetupPluginConfigMigration) => void;
|
||||
registerAutoEnableProbe: (probe: SetupPluginAutoEnableProbe) => void;
|
||||
registerTool: (...args: unknown[]) => void;
|
||||
registerHook: (...args: unknown[]) => void;
|
||||
registerHttpRoute: (...args: unknown[]) => void;
|
||||
registerChannel: (...args: unknown[]) => void;
|
||||
registerGatewayMethod: (...args: unknown[]) => void;
|
||||
registerCli: (...args: unknown[]) => void;
|
||||
registerReload: (...args: unknown[]) => void;
|
||||
registerNodeHostCommand: (...args: unknown[]) => void;
|
||||
registerSecurityAuditCollector: (...args: unknown[]) => void;
|
||||
registerService: (...args: unknown[]) => void;
|
||||
registerTextTransforms: (...args: unknown[]) => void;
|
||||
registerSpeechProvider: (...args: unknown[]) => void;
|
||||
registerRealtimeTranscriptionProvider: (...args: unknown[]) => void;
|
||||
registerRealtimeVoiceProvider: (...args: unknown[]) => void;
|
||||
registerMediaUnderstandingProvider: (...args: unknown[]) => void;
|
||||
registerImageGenerationProvider: (...args: unknown[]) => void;
|
||||
registerVideoGenerationProvider: (...args: unknown[]) => void;
|
||||
registerMusicGenerationProvider: (...args: unknown[]) => void;
|
||||
registerWebFetchProvider: (...args: unknown[]) => void;
|
||||
registerWebSearchProvider: (...args: unknown[]) => void;
|
||||
registerInteractiveHandler: (...args: unknown[]) => void;
|
||||
onConversationBindingResolved: (...args: unknown[]) => void;
|
||||
registerCommand: (...args: unknown[]) => void;
|
||||
registerContextEngine: (...args: unknown[]) => void;
|
||||
registerCompactionProvider: (...args: unknown[]) => void;
|
||||
registerAgentHarness: (...args: unknown[]) => void;
|
||||
registerMemoryCapability: (...args: unknown[]) => void;
|
||||
registerMemoryPromptSection: (...args: unknown[]) => void;
|
||||
registerMemoryPromptSupplement: (...args: unknown[]) => void;
|
||||
registerMemoryCorpusSupplement: (...args: unknown[]) => void;
|
||||
registerMemoryFlushPlan: (...args: unknown[]) => void;
|
||||
registerMemoryRuntime: (...args: unknown[]) => void;
|
||||
registerMemoryEmbeddingProvider: (...args: unknown[]) => void;
|
||||
on: (...args: unknown[]) => void;
|
||||
};
|
||||
|
||||
export type SetupOnlyPluginDefinition = {
|
||||
id?: string;
|
||||
register?: (api: SetupOnlyPluginApi) => void | Promise<void>;
|
||||
};
|
||||
|
||||
export type SetupOnlyPluginModule =
|
||||
| SetupOnlyPluginDefinition
|
||||
| ((api: SetupOnlyPluginApi) => void | Promise<void>);
|
||||
Reference in New Issue
Block a user