UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

168 lines (167 loc) • 7.81 kB
import "./src-SskUVPJG.mjs"; import { t as expectDefined } from "./expect-lbe3Hgrh.mjs"; import { c as isRecord } from "./record-coerce-TIsquoVR.mjs"; import { t as isBlockedObjectKey } from "./prototype-keys-CuYw53fZ.mjs"; import { t as parseConfigPathArrayIndex } from "./path-array-index-CvEcUJa-.mjs"; import { o as toDotPath, r as parseConcreteConfigPath } from "./dot-path-CVD5Jolm.mjs"; import { r as formatDeferredPluginMigration } from "./deferred-plugin-migrations-ByuOtOz3.mjs"; import { t as inheritLegacyDefaultAgentId } from "./legacy.default-agent-owner-DlHTJ13Y.mjs"; import { t as collectPluginConfigContractMatches } from "./config-contract-matches-Bt3IQDAl.mjs"; import { isDeepStrictEqual } from "node:util"; //#region src/config/config-path-mutation.ts const MANAGED_CONFIG_UNSET_PATHS = [["plugins", "installs"]]; const WRITE_PRUNED_OBJECT = Symbol("write-pruned-object"); function unsetPathForWriteAt(value, pathSegments, depth) { if (depth >= pathSegments.length) return { changed: false, value }; const segment = expectDefined(pathSegments[depth], "path segments entry at depth"); const isLeaf = depth === pathSegments.length - 1; if (Array.isArray(value)) { const index = parseConfigPathArrayIndex(segment); if (index === void 0 || index >= value.length) return { changed: false, value }; const child = isLeaf ? { changed: true, value: WRITE_PRUNED_OBJECT } : unsetPathForWriteAt(value[index], pathSegments, depth + 1); if (!child.changed) return { changed: false, value }; const next = value.slice(); if (child.value === WRITE_PRUNED_OBJECT) next.splice(index, 1); else next[index] = child.value; return { changed: true, value: next }; } if (isBlockedObjectKey(segment) || !isRecord(value) || !Object.hasOwn(value, segment)) return { changed: false, value }; const child = isLeaf ? { changed: true, value: WRITE_PRUNED_OBJECT } : unsetPathForWriteAt(value[segment], pathSegments, depth + 1); if (!child.changed) return { changed: false, value }; const next = { ...value }; if (child.value === WRITE_PRUNED_OBJECT) delete next[segment]; else next[segment] = child.value; return { changed: true, value: Object.keys(next).length === 0 ? WRITE_PRUNED_OBJECT : next }; } function applyUnsetPathsForWrite(root, unsetPaths) { let next = root; for (const unsetPath of unsetPaths ?? []) { if (!Array.isArray(unsetPath) || unsetPath.length === 0) continue; const unsetResult = unsetPathForWriteAt(next, unsetPath, 0); if (unsetResult.changed) { if (unsetResult.value === WRITE_PRUNED_OBJECT) next = {}; else if (isRecord(unsetResult.value)) next = unsetResult.value; } } return next; } function resolveManagedUnsetPathsForWrite(unsetPaths) { const next = []; for (const managedPath of MANAGED_CONFIG_UNSET_PATHS) next.push(Array.from(managedPath)); for (const unsetPath of unsetPaths ?? []) { if (!Array.isArray(unsetPath) || unsetPath.length === 0) continue; if (next.some((existing) => isDeepStrictEqual(existing, unsetPath))) continue; next.push([...unsetPath]); } return next; } //#endregion //#region src/config/deferred-plugin-migration-config.ts const snapshotMigrationFacts = /* @__PURE__ */ new WeakMap(); /** Revalidation consumes the same pending generation that admitted this source snapshot. */ function setDeferredPluginMigrationConfigFacts(source, pending) { if (pending?.length) snapshotMigrationFacts.set(source, structuredClone(pending)); } function getDeferredPluginMigrationConfigFacts(source) { return isRecord(source) ? snapshotMigrationFacts.get(source) : void 0; } function readPathValue(value, segments) { let current = value; for (const segment of segments) { if (isBlockedObjectKey(segment)) return; if (Array.isArray(current)) { const index = parseConfigPathArrayIndex(segment); current = index === void 0 ? void 0 : current[index]; } else current = isRecord(current) && Object.hasOwn(current, segment) ? current[segment] : void 0; } return current; } function uniquePaths(paths) { return [...new Map(paths.map((path) => [JSON.stringify(path), path])).values()]; } /** Preserve only current source inputs owned by the deferred plugin or the shared session locator. */ function resolveDeferredPluginMigrationConfigPaths(params) { const compatibilityPaths = (params.compatibilityMigrationPaths ?? []).flatMap((pathPattern) => collectPluginConfigContractMatches({ root: params.config, pathPattern }).map(({ path }) => parseConcreteConfigPath(path))); const configPaths = uniquePaths([ [ "plugins", "entries", params.pluginId, "config" ], ["session", "store"], ...compatibilityPaths ]).filter((path) => readPathValue(params.config, path) !== void 0); return { ...configPaths.length > 0 ? { configPaths } : {}, ...compatibilityPaths.length > 0 ? { validationExcludedPaths: uniquePaths(compatibilityPaths) } : {} }; } function restorePath(source, candidate, segments) { const [segment, ...rest] = segments; if (segment === void 0) return structuredClone(source); if (isBlockedObjectKey(segment)) return candidate; if (Array.isArray(source)) { const index = parseConfigPathArrayIndex(segment); if (index === void 0 || index >= source.length) return candidate; const next = Array.isArray(candidate) ? [...candidate] : []; next[index] = restorePath(source[index], next[index], rest); return next; } if (!isRecord(source) || !Object.hasOwn(source, segment)) return candidate; const next = isRecord(candidate) ? { ...candidate } : {}; next[segment] = restorePath(source[segment], next[segment], rest); return next; } /** Explicit edits must not report success after preservation restores their old values. */ function assertDeferredPluginMigrationConfigEditAllowed(params) { for (const pending of params.pending) for (const retainedPath of pending.configPaths ?? []) if (params.editedPaths.some((editedPath) => retainedPath.every((segment, index) => editedPath[index] === segment) || editedPath.every((segment, index) => retainedPath[index] === segment)) && !isDeepStrictEqual(readPathValue(params.sourceConfig, retainedPath), readPathValue(params.nextConfig, retainedPath))) throw new Error(`Cannot edit retained config at "${toDotPath(retainedPath)}". ${formatDeferredPluginMigration(pending)}`); } /** The current config snapshot owns retained values; migration receipts contain paths only. */ function preserveDeferredPluginMigrationConfig(params) { const { explicitSetPaths, unsetPaths, auditOrigin } = params.writeOptions ?? {}; if (params.pending.length > 0) assertDeferredPluginMigrationConfigEditAllowed({ ...params, nextConfig: applyUnsetPathsForWrite(params.nextConfig, unsetPaths), editedPaths: auditOrigin === "config-rpc" ? [[]] : [...explicitSetPaths ?? [], ...unsetPaths ?? []] }); let next = params.nextConfig; for (const pending of params.pending) for (const path of pending.configPaths ?? []) if (path.length > 0) next = restorePath(params.sourceConfig, next, path); return isRecord(next) ? inheritLegacyDefaultAgentId(params.nextConfig, next) : params.nextConfig; } /** Retained plugin-owned legacy fields are inert until their migration owner becomes available. */ function omitDeferredPluginMigrationConfig(raw, pending) { return isRecord(raw) ? inheritLegacyDefaultAgentId(raw, applyUnsetPathsForWrite(raw, pending?.flatMap((entry) => entry.validationExcludedPaths ?? []))) : raw; } //#endregion export { resolveDeferredPluginMigrationConfigPaths as a, resolveManagedUnsetPathsForWrite as c, preserveDeferredPluginMigrationConfig as i, getDeferredPluginMigrationConfigFacts as n, setDeferredPluginMigrationConfigFacts as o, omitDeferredPluginMigrationConfig as r, applyUnsetPathsForWrite as s, assertDeferredPluginMigrationConfigEditAllowed as t };