#!/usr/bin/env node /** * cli:efcore-apply — Apply EF Core migrations to the database, GATED by the 3-tier * migration policy (migration-policy.ts) — provenance before topology. * * 🟢 loopback-local DB (any branch), OR the working DB named by * appsettings.Local.json on a feature/* branch (whatever its host) * → applies pending migrations autonomously * 🟡 down-migration, OR appsettings.Local.json on develop/release/hotfix * → needs "confirm": true * 🔴 env var ConnectionStrings__DefaultConnection, committed file to a * non-local host, no connection string, or main * → refused ({ blocked: true }) — NO token; the * envelope's `remediation` names the exit * * "dryRun": true measures on EVERY tier (before the gate): configSource + * per-context pending, `wouldApply`. `configSource` says which layer named the DB. * * Usage: * npx --prefer-offline tsx skills/efcore/cli/apply/index.ts --spec '{ * "cwd": "D:/path/to/worktree" * }' * # revert (down-migration), requires confirm: * ... --spec '{"cwd":"...","targetMigration":"","confirm":true}' */ import { parseArgs } from 'node:util'; import { existsSync, readFileSync } from 'node:fs'; import { validate } from './validate.js'; import { execute } from './execute.js'; async function main(): Promise { const { values } = parseArgs({ options: { spec: { type: 'string' }, help: { type: 'boolean', short: 'h' }, }, }); if (values.help || !values.spec) { console.log(`Usage: npx --prefer-offline tsx skills/efcore/cli/apply/index.ts --spec '{"cwd":"..."}'`); process.exit(values.help ? 0 : 1); } let raw: unknown; try { raw = existsSync(values.spec!) ? JSON.parse(readFileSync(values.spec!, 'utf-8')) : JSON.parse(values.spec!); } catch (err) { console.log(JSON.stringify({ success: false, errors: [`Invalid JSON: ${(err as Error).message}`], warnings: [] }, null, 2)); process.exit(1); } const validation = validate(raw); if (!validation.valid || !validation.data) { console.log(JSON.stringify({ success: false, errors: validation.blockers, warnings: validation.warnings }, null, 2)); process.exit(1); } const result = await execute(validation.data); console.log(JSON.stringify(result, null, 2)); process.exit(result.success ? 0 : 1); } void main();