UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

96 lines (95 loc) 5.15 kB
import { a as asOptionalRecord } from "../../record-coerce-DItp3I4t.js"; import "../../string-coerce-runtime-GQa0ehRA.js"; //#region extensions/crabbox/doctor-contract-api.ts const imageFields = /* @__PURE__ */ new Set([ "checkpointId", "kind", "state", "createdAtMs", "lastUsedAtMs", "baseCommit", "operation" ]); const captureFields = /* @__PURE__ */ new Set([ "type", "id", "startedAtMs", "leaseId", "provider", "phase" ]); const retirementFields = /* @__PURE__ */ new Set(["type", "checkpointId"]); const nonempty = (value) => typeof value === "string" && value.trim().length > 0; const timestamp = (value) => typeof value === "number" && Number.isFinite(value); function isLegacyOperation(value) { if (value === void 0) return true; const operation = asOptionalRecord(value); if (!operation) return false; if (operation.type === "retire") return Object.keys(operation).every((key) => retirementFields.has(key)) && nonempty(operation.checkpointId); return operation.type === "capture" && Object.keys(operation).every((key) => captureFields.has(key)) && nonempty(operation.id) && timestamp(operation.startedAtMs) && (operation.leaseId === void 0 || nonempty(operation.leaseId)) && (operation.provider === void 0 || nonempty(operation.provider)) && (operation.phase === "scrubbing" || operation.phase === "creating" || operation.phase === "uncertain"); } function isLegacyImage(value) { const image = asOptionalRecord(value); return Boolean(image && Object.keys(image).every((key) => imageFields.has(key)) && typeof image.checkpointId === "string" && typeof image.kind === "string" && (image.state === "pending" || image.state === "available") && timestamp(image.createdAtMs) && timestamp(image.lastUsedAtMs) && (image.baseCommit === void 0 || nonempty(image.baseCommit)) && (image.checkpointId ? nonempty(image.checkpointId) && nonempty(image.kind) : image.kind === "" && image.state === "pending") && isLegacyOperation(image.operation)); } const stateMigrations = [{ id: "crabbox-warm-profile-v2", label: "Crabbox warm profiles", doctorOnly: true, async detectLegacyState({ context, env }) { const { WARM_IMAGE_MAX_ENTRIES, listCrabboxLegacyWarmLeases } = await import("../../crabbox-worker-warm-image-store-B5GxQliq.js"); const pending = (await context.openPluginStateKeyedStore({ namespace: "warm-images", maxEntries: WARM_IMAGE_MAX_ENTRIES, overflowPolicy: "reject-new" }).entries()).filter(({ value }) => asOptionalRecord(value)?.version !== 2).length; const leases = listCrabboxLegacyWarmLeases(env); return pending || leases.length ? { preview: [...pending ? [`- ${pending} legacy Crabbox warm-image row(s) require profile-envelope migration.`] : [], ...leases.map((lease) => `- Legacy Crabbox lease ${lease.leaseId} requires provider cleanup acknowledgement: openclaw crabbox warm-images --recover ${lease.selector} --acknowledge-provider-cleanup`)] } : null; }, async migrateLegacyState({ context, env }) { const { WARM_IMAGE_MAX_ENTRIES, crabboxLegacyWarmImageCaptureSelector, listCrabboxLegacyWarmLeases } = await import("../../crabbox-worker-warm-image-store-B5GxQliq.js"); const changes = []; const warnings = []; const store = context.openPluginStateKeyedStore({ namespace: "warm-images", maxEntries: WARM_IMAGE_MAX_ENTRIES, overflowPolicy: "reject-new" }); for (const { key, value } of await store.entries()) { if (asOptionalRecord(value)?.version === 2) continue; if (!isLegacyImage(value)) { warnings.push(`Crabbox warm profile ${key} has an unsupported record; left it unchanged for manual repair.`); continue; } const { operation, ...image } = value; const migrated = { version: 2, ...image.checkpointId ? { image } : {}, allocations: {}, ...operation ? { operation } : !image.checkpointId ? { operation: { type: "capture", id: crabboxLegacyWarmImageCaptureSelector(key, value), startedAtMs: image.createdAtMs, phase: "uncertain" } } : {} }; try { if (await store.update?.(key, (current) => JSON.stringify(current) === JSON.stringify(value) ? migrated : void 0)) changes.push(`Migrated Crabbox warm profile ${key} without inventing an allocation choice.`); else warnings.push(`Crabbox warm profile ${key} changed or atomic update is unavailable; left it unchanged.`); } catch (error) { warnings.push(`Failed migrating Crabbox warm profile ${key}; left it unchanged: ${String(error)}`); } } const leases = listCrabboxLegacyWarmLeases(env); if (leases.length) { warnings.push(`${leases.length} legacy Crabbox lease row(s) still block warm-profile admission; their original cold/checkpoint choices are unknown.`); for (const lease of leases) warnings.push(`Resolve lease ${lease.leaseId} through its original Gateway or provider, stop the original Gateway/capture processes, and confirm provider cleanup before running: openclaw crabbox warm-images --recover ${lease.selector} --acknowledge-provider-cleanup. Then rerun openclaw doctor --fix. The row was not changed.`); } return { changes, warnings }; } }]; //#endregion export { stateMigrations };