UNPKG

trellis

Version:

Agentic State Engine — event-sourced causal graph with branching, decision traces, and realtime sync for AI-native applications

150 lines (148 loc) 4.63 kB
import { compareVersions, readLockfile } from "./chunk-QQF4WF7W.js"; import "./chunk-2ESYSVXG.js"; // src/registry/migrate.ts function findFieldsByName(current, name) { return current.filter((f) => f.name === name); } function compareSchemas(current, pinned, newFields) { const diff = { schemaId: current["@id"], oldVersion: current.version, newVersion: pinned.version, addedFields: [], removedFields: [], changedFields: [], compatible: true }; if (current.version === pinned.version) { return diff; } if (compareVersions(current.version, pinned.version) > 0) { diff.compatible = false; diff.reason = `Current version (${current.version}) is newer than pinned (${pinned.version}) \u2014 downgrade not supported`; return diff; } if (newFields && newFields.length > 0) { const currentNames = new Set(current.fields.map((f) => f.name)); for (const pf of newFields) { const existing = findFieldsByName(current.fields, pf.name); if (existing.length === 0) { diff.addedFields.push(pf); } else { const match = existing[0]; if (match.valueType !== pf.valueType) { diff.compatible = false; diff.reason = `Field ${pf.name} type changed from ${match.valueType} to ${pf.valueType}`; diff.changedFields.push({ name: pf.name, from: String(match.valueType), to: String(pf.valueType) }); } else if (pf.required && !match.required) { diff.changedFields.push({ name: pf.name, from: "optional", to: "required" }); } } } const newNames = new Set(newFields.map((f) => f.name)); for (const cf of current.fields) { if (!newNames.has(cf.name)) { diff.removedFields.push(cf); if (diff.compatible) { diff.compatible = false; diff.reason = `Field ${cf.name} removed in new version`; } } } } return diff; } function applyMigration(kernel, diff, newFields) { const current = kernel.getOntology(diff.schemaId); if (!current) { throw new Error(`Schema ${diff.schemaId} not found in graph`); } let mergedFields = [...current.fields]; if (newFields && diff.addedFields.length > 0) { const existingNames = new Set(current.fields.map((f) => f.name)); for (const f of diff.addedFields) { if (!existingNames.has(f.name)) { mergedFields.push(f); } } } kernel.updateOntology(diff.schemaId, { version: diff.newVersion, fields: mergedFields }); const migrationFact = { e: diff.schemaId, a: "migration", v: JSON.stringify({ from: diff.oldVersion, to: diff.newVersion, at: (/* @__PURE__ */ new Date()).toISOString(), fieldsAdded: diff.addedFields.map((f) => f.name), changes: diff.changedFields.length > 0 ? diff.changedFields : void 0 }) }; kernel.store?.addFacts?.([migrationFact]); } function migrateLockfileSchemas(kernel, lockfile, client, scopeFilter, dryRun) { const report = { migrated: [], skipped: [], incompatible: [], errors: [] }; for (const [pkgName, pkgEntry] of Object.entries(lockfile.resolved)) { if (scopeFilter && !pkgName.includes(scopeFilter)) { continue; } for (const [schemaId, locked] of Object.entries(pkgEntry.schemas)) { try { const current = kernel.getOntology(schemaId); if (!current) { report.errors.push(`${schemaId}: not found in graph \u2014 skipping`); continue; } const diff = compareSchemas(current, locked); if (!diff.compatible) { report.incompatible.push(schemaId); continue; } if (diff.oldVersion === diff.newVersion) { report.skipped.push(schemaId); continue; } if (!dryRun) { if (diff.addedFields.length > 0 || diff.changedFields.length > 0) { applyMigration(kernel, diff, diff.addedFields); } else { applyMigration(kernel, diff); } } report.migrated.push(schemaId); } catch (err) { report.errors.push(`${schemaId}: ${err.message}`); } } } return report; } function createMigrateHandler(rootPath, kernel, client, scope, dryRun) { const lockfile = readLockfile(rootPath); if (!lockfile) { return { migrated: [], skipped: [], incompatible: [], errors: ["No lockfile found"] }; } return migrateLockfileSchemas(kernel, lockfile, client, scope, dryRun); } export { applyMigration, compareSchemas, createMigrateHandler, migrateLockfileSchemas };