UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

94 lines (93 loc) • 4.76 kB
import { c as isRecord } from "./record-coerce-TIsquoVR.mjs"; //#region src/config/recovery-policy.ts const PLUGIN_ENTRY_PATH_PREFIX = "plugins.entries."; const PLUGIN_POLICY_PATHS = /* @__PURE__ */ new Set(["plugins.allow", "plugins.deny"]); const COMPILED_RUNTIME_OUTPUT_DIAGNOSTIC = "compiled runtime output"; const PLUGIN_DIAGNOSTIC_PREFIX_PATTERN = /^plugin\s+([^:\s]+):\s/u; const PLUGIN_NOT_FOUND_PATTERN = /^plugin not found:\s*([^\s(]+)/u; function isPluginsPath(path) { return path === "plugins" || path.startsWith("plugins."); } function isPluginEntryIssue(issue) { const path = issue.path.trim(); if (!path.startsWith(PLUGIN_ENTRY_PATH_PREFIX)) return false; return path.slice(16).trim().length > 0; } function isPluginPolicyIssue(issue) { return PLUGIN_POLICY_PATHS.has(issue.path.trim()) && issue.message.trim().startsWith("plugin not found:"); } /** Return true for plugin validation issues caused by missing compiled runtime output. */ function isPluginPackagingRuntimeOutputIssue(issue) { const path = issue.path.trim(); const message = issue.message.trim().toLowerCase(); return isPluginsPath(path) && message.includes(COMPILED_RUNTIME_OUTPUT_DIAGNOSTIC); } function isPluginPackagingFalloutIssue(issue) { const path = issue.path.trim(); const message = issue.message.trim(); return isPluginsPath(path) && message.startsWith("plugin not found:"); } function normalizePluginIssueId(value) { const normalized = value?.trim().toLowerCase(); return normalized ? normalized : null; } function extractPluginPackagingRuntimeOutputPluginId(issue) { if (!isPluginPackagingRuntimeOutputIssue(issue)) return null; return normalizePluginIssueId(PLUGIN_DIAGNOSTIC_PREFIX_PATTERN.exec(issue.message.trim())?.[1]); } function extractPluginNotFoundIssuePluginId(issue) { if (!isPluginPackagingFalloutIssue(issue)) return null; return normalizePluginIssueId(PLUGIN_NOT_FOUND_PATTERN.exec(issue.message.trim())?.[1]); } /** * Return true when an invalid config snapshot is blocked only by plugin packaging fallout. * This lets callers show plugin repair hints instead of treating user config as corrupted. */ function isPluginPackagingRuntimeOutputInvalidConfigSnapshot(snapshot) { if (snapshot.valid || (snapshot.legacyIssues?.length ?? 0) > 0 || snapshot.issues.length === 0) return false; const packagingIssues = [...snapshot.issues, ...snapshot.warnings ?? []].filter(isPluginPackagingRuntimeOutputIssue); const packagingPluginIds = new Set(packagingIssues.map((issue) => extractPluginPackagingRuntimeOutputPluginId(issue)).filter((pluginId) => pluginId !== null)); return packagingIssues.length > 0 && snapshot.issues.every((issue) => { if (isPluginPackagingRuntimeOutputIssue(issue)) return true; const pluginId = extractPluginNotFoundIssuePluginId(issue); return pluginId !== null && packagingPluginIds.has(pluginId); }); } /** * Return true when an invalid config snapshot is scoped entirely to stale plugin refs. * Whole-file recovery is skipped for these snapshots so plugin cleanup can preserve user config. */ function isPluginLocalInvalidConfigSnapshot(snapshot) { if (snapshot.valid || snapshot.legacyIssues.length > 0 || snapshot.issues.length === 0) return false; return snapshot.issues.every((issue) => isPluginEntryIssue(issue) || isPluginPolicyIssue(issue)); } /** * Decide whether whole-file last-known-good recovery is appropriate for an invalid snapshot. * Plugin-local failures stay on the current file so targeted plugin cleanup can run. */ function shouldAttemptLastKnownGoodRecovery(snapshot) { if (snapshot.valid) return false; return !isPluginLocalInvalidConfigSnapshot(snapshot); } function isSensitiveConfigPath(pathLabel) { return /(^|\.)(api[-_]?key|auth|bearer|credential|password|private[-_]?key|secret|token)(\.|$)/i.test(pathLabel); } function collectPollutedSecretPlaceholders(value, pathLabel = "", output = []) { if (typeof value === "string") { const trimmed = value.trim(); if (trimmed === "***" || trimmed === "[redacted]") { output.push(pathLabel || "<root>"); return output; } if (isSensitiveConfigPath(pathLabel) && (trimmed.includes("...") || trimmed.includes("…"))) output.push(pathLabel || "<root>"); return output; } if (Array.isArray(value)) { value.forEach((item, index) => collectPollutedSecretPlaceholders(item, `${pathLabel}[${index}]`, output)); return output; } if (isRecord(value)) for (const [key, child] of Object.entries(value)) collectPollutedSecretPlaceholders(child, pathLabel ? `${pathLabel}.${key}` : key, output); return output; } //#endregion export { shouldAttemptLastKnownGoodRecovery as i, isPluginLocalInvalidConfigSnapshot as n, isPluginPackagingRuntimeOutputInvalidConfigSnapshot as r, collectPollutedSecretPlaceholders as t };