2026-09-14 20:35:53 -07:00
|
|
|
import fs from "node:fs/promises";
|
|
|
|
|
import path from "node:path";
|
2026-09-15 15:23:24 -07:00
|
|
|
import { contentDigest } from "../capability-model/evolution.js";
|
|
|
|
|
import { validateMigrationCatalog, type MigrationCatalog } from "../capability-model/migrations.js";
|
|
|
|
|
import { applyStructure, planStructure } from "./structural-plan.js";
|
2026-09-14 20:35:53 -07:00
|
|
|
|
|
|
|
|
/** Explicitly acknowledge edited migration code. This does not change retained
|
|
|
|
|
* contracts or grant activation approval; the immutable checker verifies it. */
|
|
|
|
|
export async function sealMigrations(directory: string) {
|
|
|
|
|
const root = await fs.realpath(directory);
|
|
|
|
|
const file = "quixos.migrations.json";
|
|
|
|
|
const before = await fs.readFile(path.join(root, file), "utf8");
|
|
|
|
|
const catalog = JSON.parse(before) as MigrationCatalog;
|
|
|
|
|
for (const migration of catalog.migrations) {
|
|
|
|
|
const implementation = await fs.realpath(path.join(root, migration.implementation.file));
|
|
|
|
|
if (!implementation.startsWith(root + path.sep)) throw new Error("Migration implementation escapes package");
|
|
|
|
|
migration.implementation.digest = contentDigest(await fs.readFile(implementation, "utf8"));
|
|
|
|
|
}
|
|
|
|
|
validateMigrationCatalog(catalog);
|
2026-09-15 15:23:24 -07:00
|
|
|
return applyStructure(
|
|
|
|
|
await planStructure(root, {
|
|
|
|
|
kind: "package",
|
|
|
|
|
validation: "syntax",
|
|
|
|
|
files: [{ file, expected: before, replace: JSON.stringify(catalog, null, 2) + "\n" }],
|
|
|
|
|
}),
|
|
|
|
|
);
|
2026-09-14 20:35:53 -07:00
|
|
|
}
|