Spaces:
Paused
Paused
| import type { OpenClawConfig } from "../config/config.js"; | |
| import type { PluginRecord } from "./registry.js"; | |
| import { defaultSlotIdForKey } from "./slots.js"; | |
| export type NormalizedPluginsConfig = { | |
| enabled: boolean; | |
| allow: string[]; | |
| deny: string[]; | |
| loadPaths: string[]; | |
| slots: { | |
| memory?: string | null; | |
| }; | |
| entries: Record<string, { enabled?: boolean; config?: unknown }>; | |
| }; | |
| export const BUNDLED_ENABLED_BY_DEFAULT = new Set<string>(); | |
| const normalizeList = (value: unknown): string[] => { | |
| if (!Array.isArray(value)) { | |
| return []; | |
| } | |
| return value.map((entry) => (typeof entry === "string" ? entry.trim() : "")).filter(Boolean); | |
| }; | |
| const normalizeSlotValue = (value: unknown): string | null | undefined => { | |
| if (typeof value !== "string") { | |
| return undefined; | |
| } | |
| const trimmed = value.trim(); | |
| if (!trimmed) { | |
| return undefined; | |
| } | |
| if (trimmed.toLowerCase() === "none") { | |
| return null; | |
| } | |
| return trimmed; | |
| }; | |
| const normalizePluginEntries = (entries: unknown): NormalizedPluginsConfig["entries"] => { | |
| if (!entries || typeof entries !== "object" || Array.isArray(entries)) { | |
| return {}; | |
| } | |
| const normalized: NormalizedPluginsConfig["entries"] = {}; | |
| for (const [key, value] of Object.entries(entries)) { | |
| if (!key.trim()) { | |
| continue; | |
| } | |
| if (!value || typeof value !== "object" || Array.isArray(value)) { | |
| normalized[key] = {}; | |
| continue; | |
| } | |
| const entry = value as Record<string, unknown>; | |
| normalized[key] = { | |
| enabled: typeof entry.enabled === "boolean" ? entry.enabled : undefined, | |
| config: "config" in entry ? entry.config : undefined, | |
| }; | |
| } | |
| return normalized; | |
| }; | |
| export const normalizePluginsConfig = ( | |
| config?: OpenClawConfig["plugins"], | |
| ): NormalizedPluginsConfig => { | |
| const memorySlot = normalizeSlotValue(config?.slots?.memory); | |
| return { | |
| enabled: config?.enabled !== false, | |
| allow: normalizeList(config?.allow), | |
| deny: normalizeList(config?.deny), | |
| loadPaths: normalizeList(config?.load?.paths), | |
| slots: { | |
| memory: memorySlot === undefined ? defaultSlotIdForKey("memory") : memorySlot, | |
| }, | |
| entries: normalizePluginEntries(config?.entries), | |
| }; | |
| }; | |
| const hasExplicitMemorySlot = (plugins?: OpenClawConfig["plugins"]) => | |
| Boolean(plugins?.slots && Object.prototype.hasOwnProperty.call(plugins.slots, "memory")); | |
| const hasExplicitMemoryEntry = (plugins?: OpenClawConfig["plugins"]) => | |
| Boolean(plugins?.entries && Object.prototype.hasOwnProperty.call(plugins.entries, "memory-core")); | |
| const hasExplicitPluginConfig = (plugins?: OpenClawConfig["plugins"]) => { | |
| if (!plugins) { | |
| return false; | |
| } | |
| if (typeof plugins.enabled === "boolean") { | |
| return true; | |
| } | |
| if (Array.isArray(plugins.allow) && plugins.allow.length > 0) { | |
| return true; | |
| } | |
| if (Array.isArray(plugins.deny) && plugins.deny.length > 0) { | |
| return true; | |
| } | |
| if (plugins.load?.paths && Array.isArray(plugins.load.paths) && plugins.load.paths.length > 0) { | |
| return true; | |
| } | |
| if (plugins.slots && Object.keys(plugins.slots).length > 0) { | |
| return true; | |
| } | |
| if (plugins.entries && Object.keys(plugins.entries).length > 0) { | |
| return true; | |
| } | |
| return false; | |
| }; | |
| export function applyTestPluginDefaults( | |
| cfg: OpenClawConfig, | |
| env: NodeJS.ProcessEnv = process.env, | |
| ): OpenClawConfig { | |
| if (!env.VITEST) { | |
| return cfg; | |
| } | |
| const plugins = cfg.plugins; | |
| const explicitConfig = hasExplicitPluginConfig(plugins); | |
| if (explicitConfig) { | |
| if (hasExplicitMemorySlot(plugins) || hasExplicitMemoryEntry(plugins)) { | |
| return cfg; | |
| } | |
| return { | |
| ...cfg, | |
| plugins: { | |
| ...plugins, | |
| slots: { | |
| ...plugins?.slots, | |
| memory: "none", | |
| }, | |
| }, | |
| }; | |
| } | |
| return { | |
| ...cfg, | |
| plugins: { | |
| ...plugins, | |
| enabled: false, | |
| slots: { | |
| ...plugins?.slots, | |
| memory: "none", | |
| }, | |
| }, | |
| }; | |
| } | |
| export function isTestDefaultMemorySlotDisabled( | |
| cfg: OpenClawConfig, | |
| env: NodeJS.ProcessEnv = process.env, | |
| ): boolean { | |
| if (!env.VITEST) { | |
| return false; | |
| } | |
| const plugins = cfg.plugins; | |
| if (hasExplicitMemorySlot(plugins) || hasExplicitMemoryEntry(plugins)) { | |
| return false; | |
| } | |
| return true; | |
| } | |
| export function resolveEnableState( | |
| id: string, | |
| origin: PluginRecord["origin"], | |
| config: NormalizedPluginsConfig, | |
| ): { enabled: boolean; reason?: string } { | |
| if (!config.enabled) { | |
| return { enabled: false, reason: "plugins disabled" }; | |
| } | |
| if (config.deny.includes(id)) { | |
| return { enabled: false, reason: "blocked by denylist" }; | |
| } | |
| if (config.allow.length > 0 && !config.allow.includes(id)) { | |
| return { enabled: false, reason: "not in allowlist" }; | |
| } | |
| if (config.slots.memory === id) { | |
| return { enabled: true }; | |
| } | |
| const entry = config.entries[id]; | |
| if (entry?.enabled === true) { | |
| return { enabled: true }; | |
| } | |
| if (entry?.enabled === false) { | |
| return { enabled: false, reason: "disabled in config" }; | |
| } | |
| if (origin === "bundled" && BUNDLED_ENABLED_BY_DEFAULT.has(id)) { | |
| return { enabled: true }; | |
| } | |
| if (origin === "bundled") { | |
| return { enabled: false, reason: "bundled (disabled by default)" }; | |
| } | |
| return { enabled: true }; | |
| } | |
| export function resolveMemorySlotDecision(params: { | |
| id: string; | |
| kind?: string; | |
| slot: string | null | undefined; | |
| selectedId: string | null; | |
| }): { enabled: boolean; reason?: string; selected?: boolean } { | |
| if (params.kind !== "memory") { | |
| return { enabled: true }; | |
| } | |
| if (params.slot === null) { | |
| return { enabled: false, reason: "memory slot disabled" }; | |
| } | |
| if (typeof params.slot === "string") { | |
| if (params.slot === params.id) { | |
| return { enabled: true, selected: true }; | |
| } | |
| return { | |
| enabled: false, | |
| reason: `memory slot set to "${params.slot}"`, | |
| }; | |
| } | |
| if (params.selectedId && params.selectedId !== params.id) { | |
| return { | |
| enabled: false, | |
| reason: `memory slot already filled by "${params.selectedId}"`, | |
| }; | |
| } | |
| return { enabled: true, selected: true }; | |
| } | |