mirror of
https://github.com/moltbot/moltbot.git
synced 2026-04-26 07:57:40 +00:00
refactor: keep plugin legacy repair in doctor
This commit is contained in:
@@ -27,7 +27,6 @@ export type BuildPluginApiParams = {
|
||||
| "registerService"
|
||||
| "registerCliBackend"
|
||||
| "registerConfigMigration"
|
||||
| "registerLegacyConfigMigration"
|
||||
| "registerAutoEnableProbe"
|
||||
| "registerProvider"
|
||||
| "registerSpeechProvider"
|
||||
@@ -60,8 +59,6 @@ const noopRegisterCli: OpenClawPluginApi["registerCli"] = () => {};
|
||||
const noopRegisterService: OpenClawPluginApi["registerService"] = () => {};
|
||||
const noopRegisterCliBackend: OpenClawPluginApi["registerCliBackend"] = () => {};
|
||||
const noopRegisterConfigMigration: OpenClawPluginApi["registerConfigMigration"] = () => {};
|
||||
const noopRegisterLegacyConfigMigration: OpenClawPluginApi["registerLegacyConfigMigration"] =
|
||||
() => {};
|
||||
const noopRegisterAutoEnableProbe: OpenClawPluginApi["registerAutoEnableProbe"] = () => {};
|
||||
const noopRegisterProvider: OpenClawPluginApi["registerProvider"] = () => {};
|
||||
const noopRegisterSpeechProvider: OpenClawPluginApi["registerSpeechProvider"] = () => {};
|
||||
@@ -112,8 +109,6 @@ export function buildPluginApi(params: BuildPluginApiParams): OpenClawPluginApi
|
||||
registerService: handlers.registerService ?? noopRegisterService,
|
||||
registerCliBackend: handlers.registerCliBackend ?? noopRegisterCliBackend,
|
||||
registerConfigMigration: handlers.registerConfigMigration ?? noopRegisterConfigMigration,
|
||||
registerLegacyConfigMigration:
|
||||
handlers.registerLegacyConfigMigration ?? noopRegisterLegacyConfigMigration,
|
||||
registerAutoEnableProbe: handlers.registerAutoEnableProbe ?? noopRegisterAutoEnableProbe,
|
||||
registerProvider: handlers.registerProvider ?? noopRegisterProvider,
|
||||
registerSpeechProvider: handlers.registerSpeechProvider ?? noopRegisterSpeechProvider,
|
||||
|
||||
153
src/plugins/doctor-contract-registry.ts
Normal file
153
src/plugins/doctor-contract-registry.ts
Normal file
@@ -0,0 +1,153 @@
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { createJiti } from "jiti";
|
||||
import type { LegacyConfigRule } from "../config/legacy.shared.js";
|
||||
import { discoverOpenClawPlugins } from "./discovery.js";
|
||||
import { loadPluginManifestRegistry } from "./manifest-registry.js";
|
||||
import { resolvePluginCacheInputs } from "./roots.js";
|
||||
import {
|
||||
buildPluginLoaderAliasMap,
|
||||
buildPluginLoaderJitiOptions,
|
||||
shouldPreferNativeJiti,
|
||||
} from "./sdk-alias.js";
|
||||
|
||||
const CONTRACT_API_EXTENSIONS = [".js", ".mjs", ".cjs", ".ts", ".mts", ".cts"] as const;
|
||||
const CURRENT_MODULE_PATH = fileURLToPath(import.meta.url);
|
||||
const RUNNING_FROM_BUILT_ARTIFACT =
|
||||
CURRENT_MODULE_PATH.includes(`${path.sep}dist${path.sep}`) ||
|
||||
CURRENT_MODULE_PATH.includes(`${path.sep}dist-runtime${path.sep}`);
|
||||
|
||||
type PluginDoctorContractModule = {
|
||||
legacyConfigRules?: unknown;
|
||||
};
|
||||
|
||||
type PluginDoctorContractEntry = {
|
||||
pluginId: string;
|
||||
rules: LegacyConfigRule[];
|
||||
};
|
||||
|
||||
const jitiLoaders = new Map<string, ReturnType<typeof createJiti>>();
|
||||
const doctorContractCache = new Map<string, PluginDoctorContractEntry[]>();
|
||||
|
||||
function getJiti(modulePath: string) {
|
||||
const aliasMap = buildPluginLoaderAliasMap(modulePath, process.argv[1], import.meta.url);
|
||||
const cacheKey = JSON.stringify({
|
||||
tryNative: shouldPreferNativeJiti(modulePath),
|
||||
aliasMap: Object.entries(aliasMap).toSorted(([left], [right]) => left.localeCompare(right)),
|
||||
});
|
||||
const cached = jitiLoaders.get(cacheKey);
|
||||
if (cached) {
|
||||
return cached;
|
||||
}
|
||||
const loader = createJiti(modulePath, buildPluginLoaderJitiOptions(aliasMap));
|
||||
jitiLoaders.set(cacheKey, loader);
|
||||
return loader;
|
||||
}
|
||||
|
||||
function buildDoctorContractCacheKey(params: {
|
||||
workspaceDir?: string;
|
||||
env?: NodeJS.ProcessEnv;
|
||||
}): string {
|
||||
const { roots, loadPaths } = resolvePluginCacheInputs({
|
||||
workspaceDir: params.workspaceDir,
|
||||
env: params.env,
|
||||
});
|
||||
return JSON.stringify({
|
||||
roots,
|
||||
loadPaths,
|
||||
});
|
||||
}
|
||||
|
||||
function resolveContractApiPath(rootDir: string): string | null {
|
||||
const orderedExtensions = RUNNING_FROM_BUILT_ARTIFACT
|
||||
? CONTRACT_API_EXTENSIONS
|
||||
: ([...CONTRACT_API_EXTENSIONS.slice(3), ...CONTRACT_API_EXTENSIONS.slice(0, 3)] as const);
|
||||
for (const extension of orderedExtensions) {
|
||||
const candidate = path.join(rootDir, `contract-api${extension}`);
|
||||
if (fs.existsSync(candidate)) {
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function coerceLegacyConfigRules(value: unknown): LegacyConfigRule[] {
|
||||
if (!Array.isArray(value)) {
|
||||
return [];
|
||||
}
|
||||
return value.filter((entry) => {
|
||||
if (!entry || typeof entry !== "object") {
|
||||
return false;
|
||||
}
|
||||
const candidate = entry as { path?: unknown; message?: unknown };
|
||||
return Array.isArray(candidate.path) && typeof candidate.message === "string";
|
||||
}) as LegacyConfigRule[];
|
||||
}
|
||||
|
||||
function resolvePluginDoctorContracts(params?: {
|
||||
workspaceDir?: string;
|
||||
env?: NodeJS.ProcessEnv;
|
||||
}): PluginDoctorContractEntry[] {
|
||||
const env = params?.env ?? process.env;
|
||||
const cacheKey = buildDoctorContractCacheKey({
|
||||
workspaceDir: params?.workspaceDir,
|
||||
env,
|
||||
});
|
||||
const cached = doctorContractCache.get(cacheKey);
|
||||
if (cached) {
|
||||
return cached;
|
||||
}
|
||||
|
||||
const discovery = discoverOpenClawPlugins({
|
||||
workspaceDir: params?.workspaceDir,
|
||||
env,
|
||||
cache: true,
|
||||
});
|
||||
const manifestRegistry = loadPluginManifestRegistry({
|
||||
workspaceDir: params?.workspaceDir,
|
||||
env,
|
||||
cache: true,
|
||||
candidates: discovery.candidates,
|
||||
diagnostics: discovery.diagnostics,
|
||||
});
|
||||
|
||||
const entries: PluginDoctorContractEntry[] = [];
|
||||
for (const record of manifestRegistry.plugins) {
|
||||
const contractSource = resolveContractApiPath(record.rootDir);
|
||||
if (!contractSource) {
|
||||
continue;
|
||||
}
|
||||
let mod: PluginDoctorContractModule;
|
||||
try {
|
||||
mod = getJiti(contractSource)(contractSource) as PluginDoctorContractModule;
|
||||
} catch {
|
||||
continue;
|
||||
}
|
||||
const rules = coerceLegacyConfigRules(
|
||||
(mod as { default?: PluginDoctorContractModule }).default?.legacyConfigRules ??
|
||||
mod.legacyConfigRules,
|
||||
);
|
||||
if (rules.length === 0) {
|
||||
continue;
|
||||
}
|
||||
entries.push({
|
||||
pluginId: record.id,
|
||||
rules,
|
||||
});
|
||||
}
|
||||
|
||||
doctorContractCache.set(cacheKey, entries);
|
||||
return entries;
|
||||
}
|
||||
|
||||
export function clearPluginDoctorContractRegistryCache(): void {
|
||||
doctorContractCache.clear();
|
||||
}
|
||||
|
||||
export function listPluginDoctorLegacyConfigRules(params?: {
|
||||
workspaceDir?: string;
|
||||
env?: NodeJS.ProcessEnv;
|
||||
}): LegacyConfigRule[] {
|
||||
return resolvePluginDoctorContracts(params).flatMap((entry) => entry.rules);
|
||||
}
|
||||
@@ -18,7 +18,6 @@ import type {
|
||||
CliBackendPlugin,
|
||||
OpenClawPluginModule,
|
||||
PluginConfigMigration,
|
||||
PluginLegacyConfigMigration,
|
||||
PluginLogger,
|
||||
PluginSetupAutoEnableProbe,
|
||||
ProviderPlugin,
|
||||
@@ -45,11 +44,6 @@ type SetupConfigMigrationEntry = {
|
||||
migrate: PluginConfigMigration;
|
||||
};
|
||||
|
||||
type SetupLegacyConfigMigrationEntry = {
|
||||
pluginId: string;
|
||||
migrate: PluginLegacyConfigMigration;
|
||||
};
|
||||
|
||||
type SetupAutoEnableProbeEntry = {
|
||||
pluginId: string;
|
||||
probe: PluginSetupAutoEnableProbe;
|
||||
@@ -59,7 +53,6 @@ type PluginSetupRegistry = {
|
||||
providers: SetupProviderEntry[];
|
||||
cliBackends: SetupCliBackendEntry[];
|
||||
configMigrations: SetupConfigMigrationEntry[];
|
||||
legacyConfigMigrations: SetupLegacyConfigMigrationEntry[];
|
||||
autoEnableProbes: SetupAutoEnableProbeEntry[];
|
||||
};
|
||||
|
||||
@@ -167,7 +160,6 @@ export function resolvePluginSetupRegistry(params?: {
|
||||
const providers: SetupProviderEntry[] = [];
|
||||
const cliBackends: SetupCliBackendEntry[] = [];
|
||||
const configMigrations: SetupConfigMigrationEntry[] = [];
|
||||
const legacyConfigMigrations: SetupLegacyConfigMigrationEntry[] = [];
|
||||
const autoEnableProbes: SetupAutoEnableProbeEntry[] = [];
|
||||
const providerKeys = new Set<string>();
|
||||
const cliBackendKeys = new Set<string>();
|
||||
@@ -247,12 +239,6 @@ export function resolvePluginSetupRegistry(params?: {
|
||||
migrate,
|
||||
});
|
||||
},
|
||||
registerLegacyConfigMigration(migrate) {
|
||||
legacyConfigMigrations.push({
|
||||
pluginId: record.id,
|
||||
migrate,
|
||||
});
|
||||
},
|
||||
registerAutoEnableProbe(probe) {
|
||||
autoEnableProbes.push({
|
||||
pluginId: record.id,
|
||||
@@ -276,7 +262,6 @@ export function resolvePluginSetupRegistry(params?: {
|
||||
providers,
|
||||
cliBackends,
|
||||
configMigrations,
|
||||
legacyConfigMigrations,
|
||||
autoEnableProbes,
|
||||
} satisfies PluginSetupRegistry;
|
||||
setupRegistryCache.set(cacheKey, registry);
|
||||
@@ -327,17 +312,6 @@ export function runPluginSetupConfigMigrations(params: {
|
||||
return { config: next, changes };
|
||||
}
|
||||
|
||||
export function runPluginSetupLegacyConfigMigrations(params: {
|
||||
raw: Record<string, unknown>;
|
||||
changes: string[];
|
||||
workspaceDir?: string;
|
||||
env?: NodeJS.ProcessEnv;
|
||||
}): void {
|
||||
for (const entry of resolvePluginSetupRegistry(params).legacyConfigMigrations) {
|
||||
entry.migrate(params.raw, params.changes);
|
||||
}
|
||||
}
|
||||
|
||||
export function resolvePluginSetupAutoEnableReasons(params: {
|
||||
config: OpenClawConfig;
|
||||
workspaceDir?: string;
|
||||
|
||||
@@ -1996,8 +1996,6 @@ export type PluginConfigMigration = (config: OpenClawConfig) =>
|
||||
| null
|
||||
| undefined;
|
||||
|
||||
export type PluginLegacyConfigMigration = (raw: Record<string, unknown>, changes: string[]) => void;
|
||||
|
||||
export type PluginSetupAutoEnableContext = {
|
||||
config: OpenClawConfig;
|
||||
env: NodeJS.ProcessEnv;
|
||||
@@ -2070,8 +2068,6 @@ export type OpenClawPluginApi = {
|
||||
registerCliBackend: (backend: CliBackendPlugin) => void;
|
||||
/** Register a lightweight config migration that can run before plugin runtime loads. */
|
||||
registerConfigMigration: (migrate: PluginConfigMigration) => void;
|
||||
/** Register a lightweight raw legacy-config migration for pre-schema config repair. */
|
||||
registerLegacyConfigMigration: (migrate: PluginLegacyConfigMigration) => void;
|
||||
/** Register a lightweight config probe that can auto-enable this plugin generically. */
|
||||
registerAutoEnableProbe: (probe: PluginSetupAutoEnableProbe) => void;
|
||||
/** Register a native model/provider plugin (text inference capability). */
|
||||
|
||||
Reference in New Issue
Block a user