127 lines
3.8 KiB
TypeScript
127 lines
3.8 KiB
TypeScript
import type { ClawdbotConfig } from "../config/config.js";
|
|
import { defaultSlotIdForKey } from "./slots.js";
|
|
import type { PluginRecord } from "./registry.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?: ClawdbotConfig["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 ?? defaultSlotIdForKey("memory"),
|
|
},
|
|
entries: normalizePluginEntries(config?.entries),
|
|
};
|
|
};
|
|
|
|
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 };
|
|
}
|