@prisma-next/cli 0.5.0-dev.4 → 0.5.0-dev.41

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (165) hide show
  1. package/README.md +56 -21
  2. package/dist/agent-skill-mongo.md +63 -31
  3. package/dist/agent-skill-postgres.md +1 -1
  4. package/dist/cli-errors-By1iVE3z.mjs +34 -0
  5. package/dist/cli-errors-By1iVE3z.mjs.map +1 -0
  6. package/dist/{cli-errors-C0JhVj0c.d.mts → cli-errors-DDeVsP2Y.d.mts} +1 -0
  7. package/dist/cli.mjs +123 -15
  8. package/dist/cli.mjs.map +1 -1
  9. package/dist/{client-TG7rbCWT.mjs → client-1JqqkiC7.mjs} +45 -20
  10. package/dist/client-1JqqkiC7.mjs.map +1 -0
  11. package/dist/commands/contract-emit.d.mts.map +1 -1
  12. package/dist/commands/contract-emit.mjs +2 -2
  13. package/dist/commands/contract-infer.d.mts.map +1 -1
  14. package/dist/commands/contract-infer.mjs +2 -2
  15. package/dist/commands/db-init.d.mts.map +1 -1
  16. package/dist/commands/db-init.mjs +10 -9
  17. package/dist/commands/db-init.mjs.map +1 -1
  18. package/dist/commands/db-schema.mjs +5 -5
  19. package/dist/commands/db-sign.mjs +7 -7
  20. package/dist/commands/db-update.mjs +9 -9
  21. package/dist/commands/db-update.mjs.map +1 -1
  22. package/dist/commands/db-verify.mjs +9 -9
  23. package/dist/commands/migration-apply.d.mts +5 -2
  24. package/dist/commands/migration-apply.d.mts.map +1 -1
  25. package/dist/commands/migration-apply.mjs +55 -56
  26. package/dist/commands/migration-apply.mjs.map +1 -1
  27. package/dist/commands/migration-new.d.mts.map +1 -1
  28. package/dist/commands/migration-new.mjs +26 -32
  29. package/dist/commands/migration-new.mjs.map +1 -1
  30. package/dist/commands/migration-plan.d.mts +14 -5
  31. package/dist/commands/migration-plan.d.mts.map +1 -1
  32. package/dist/commands/migration-plan.mjs +45 -48
  33. package/dist/commands/migration-plan.mjs.map +1 -1
  34. package/dist/commands/migration-ref.d.mts +1 -1
  35. package/dist/commands/migration-ref.d.mts.map +1 -1
  36. package/dist/commands/migration-ref.mjs +6 -10
  37. package/dist/commands/migration-ref.mjs.map +1 -1
  38. package/dist/commands/migration-show.d.mts +13 -7
  39. package/dist/commands/migration-show.d.mts.map +1 -1
  40. package/dist/commands/migration-show.mjs +27 -29
  41. package/dist/commands/migration-show.mjs.map +1 -1
  42. package/dist/commands/migration-status.d.mts +23 -5
  43. package/dist/commands/migration-status.d.mts.map +1 -1
  44. package/dist/commands/migration-status.mjs +3 -3
  45. package/dist/{config-loader-_W4T21X1.mjs → config-loader-ih8ViDb_.mjs} +2 -2
  46. package/dist/config-loader-ih8ViDb_.mjs.map +1 -0
  47. package/dist/config-loader.mjs +1 -1
  48. package/dist/contract-emit-LjzCoicC.mjs +4 -0
  49. package/dist/contract-emit-RZBWzkop.mjs +329 -0
  50. package/dist/contract-emit-RZBWzkop.mjs.map +1 -0
  51. package/dist/contract-emit-rt_Nmdwq.mjs +150 -0
  52. package/dist/contract-emit-rt_Nmdwq.mjs.map +1 -0
  53. package/dist/{contract-enrichment-CGW6mm-E.mjs → contract-enrichment-4Ptgw3Pe.mjs} +1 -1
  54. package/dist/{contract-enrichment-CGW6mm-E.mjs.map → contract-enrichment-4Ptgw3Pe.mjs.map} +1 -1
  55. package/dist/{contract-infer-BS4kIX9c.mjs → contract-infer-Cf5J2wVg.mjs} +11 -19
  56. package/dist/contract-infer-Cf5J2wVg.mjs.map +1 -0
  57. package/dist/exports/control-api.d.mts +86 -21
  58. package/dist/exports/control-api.d.mts.map +1 -1
  59. package/dist/exports/control-api.mjs +5 -5
  60. package/dist/exports/index.mjs +3 -3
  61. package/dist/exports/init-output.d.mts +39 -0
  62. package/dist/exports/init-output.d.mts.map +1 -0
  63. package/dist/exports/init-output.mjs +3 -0
  64. package/dist/{framework-components-DfZKQBQ2.mjs → framework-components-Bgcre3Z6.mjs} +2 -2
  65. package/dist/{framework-components-DfZKQBQ2.mjs.map → framework-components-Bgcre3Z6.mjs.map} +1 -1
  66. package/dist/init-C7dE9KOJ.mjs +2062 -0
  67. package/dist/init-C7dE9KOJ.mjs.map +1 -0
  68. package/dist/{inspect-live-schema-BsoFVoS1.mjs → inspect-live-schema-LWtXfxm_.mjs} +9 -9
  69. package/dist/inspect-live-schema-LWtXfxm_.mjs.map +1 -0
  70. package/dist/migration-cli.d.mts +41 -11
  71. package/dist/migration-cli.d.mts.map +1 -1
  72. package/dist/migration-cli.mjs +308 -84
  73. package/dist/migration-cli.mjs.map +1 -1
  74. package/dist/{migration-command-scaffold-DOXnheFa.mjs → migration-command-scaffold-CU452v9h.mjs} +7 -7
  75. package/dist/{migration-command-scaffold-DOXnheFa.mjs.map → migration-command-scaffold-CU452v9h.mjs.map} +1 -1
  76. package/dist/{migration-status-Ry3TnEya.mjs → migration-status-DoPrFIOQ.mjs} +114 -57
  77. package/dist/migration-status-DoPrFIOQ.mjs.map +1 -0
  78. package/dist/{migrations-fU0xoKjS.mjs → migrations-MEoKMiV5.mjs} +42 -21
  79. package/dist/migrations-MEoKMiV5.mjs.map +1 -0
  80. package/dist/output-BpcQrnnq.mjs +103 -0
  81. package/dist/output-BpcQrnnq.mjs.map +1 -0
  82. package/dist/{progress-adapter-B-YvmcDu.mjs → progress-adapter-DgRGldpT.mjs} +1 -1
  83. package/dist/{progress-adapter-B-YvmcDu.mjs.map → progress-adapter-DgRGldpT.mjs.map} +1 -1
  84. package/dist/quick-reference-mongo.md +34 -13
  85. package/dist/quick-reference-postgres.md +11 -9
  86. package/dist/{result-handler-BJwA7ufw.mjs → result-handler-Ch6hVnOo.mjs} +35 -93
  87. package/dist/result-handler-Ch6hVnOo.mjs.map +1 -0
  88. package/dist/{terminal-ui-C5k88MmW.mjs → terminal-ui-u2YgKghu.mjs} +76 -2
  89. package/dist/terminal-ui-u2YgKghu.mjs.map +1 -0
  90. package/dist/{verify-bl__PkXk.mjs → verify-BT9tgCOH.mjs} +2 -2
  91. package/dist/{verify-bl__PkXk.mjs.map → verify-BT9tgCOH.mjs.map} +1 -1
  92. package/package.json +22 -16
  93. package/src/cli.ts +32 -6
  94. package/src/commands/contract-emit.ts +67 -163
  95. package/src/commands/contract-infer.ts +7 -20
  96. package/src/commands/db-init.ts +1 -0
  97. package/src/commands/db-update.ts +1 -1
  98. package/src/commands/init/detect-pnpm-catalog.ts +141 -0
  99. package/src/commands/init/errors.ts +254 -0
  100. package/src/commands/init/exit-codes.ts +62 -0
  101. package/src/commands/init/hygiene-gitattributes.ts +97 -0
  102. package/src/commands/init/hygiene-gitignore.ts +48 -0
  103. package/src/commands/init/hygiene-package-scripts.ts +91 -0
  104. package/src/commands/init/index.ts +112 -7
  105. package/src/commands/init/init.ts +766 -144
  106. package/src/commands/init/inputs.ts +421 -0
  107. package/src/commands/init/output.ts +147 -0
  108. package/src/commands/init/probe-db.ts +308 -0
  109. package/src/commands/init/reinit-cleanup.ts +83 -0
  110. package/src/commands/init/templates/agent-skill-mongo.md +63 -31
  111. package/src/commands/init/templates/agent-skill-postgres.md +1 -1
  112. package/src/commands/init/templates/agent-skill.ts +25 -3
  113. package/src/commands/init/templates/code-templates.ts +125 -32
  114. package/src/commands/init/templates/env.ts +80 -0
  115. package/src/commands/init/templates/quick-reference-mongo.md +34 -13
  116. package/src/commands/init/templates/quick-reference-postgres.md +11 -9
  117. package/src/commands/init/templates/quick-reference.ts +42 -3
  118. package/src/commands/init/templates/tsconfig.ts +167 -5
  119. package/src/commands/inspect-live-schema.ts +10 -5
  120. package/src/commands/migration-apply.ts +84 -63
  121. package/src/commands/migration-new.ts +28 -34
  122. package/src/commands/migration-plan.ts +80 -56
  123. package/src/commands/migration-ref.ts +8 -7
  124. package/src/commands/migration-show.ts +53 -36
  125. package/src/commands/migration-status.ts +194 -58
  126. package/src/config-path-validation.ts +0 -1
  127. package/src/control-api/client.ts +21 -0
  128. package/src/control-api/operations/contract-emit.ts +198 -115
  129. package/src/control-api/operations/db-init.ts +10 -6
  130. package/src/control-api/operations/db-update.ts +10 -6
  131. package/src/control-api/operations/migration-apply.ts +30 -9
  132. package/src/control-api/types.ts +69 -7
  133. package/src/exports/control-api.ts +2 -1
  134. package/src/exports/init-output.ts +10 -0
  135. package/src/migration-cli.ts +445 -122
  136. package/src/utils/cli-errors.ts +49 -2
  137. package/src/utils/command-helpers.ts +45 -23
  138. package/src/utils/emit-queue.ts +26 -0
  139. package/src/utils/formatters/graph-migration-mapper.ts +7 -3
  140. package/src/utils/formatters/migrations.ts +62 -26
  141. package/src/utils/publish-contract-artifact-pair.ts +134 -0
  142. package/dist/cli-errors-DHq6GQGu.mjs +0 -5
  143. package/dist/client-TG7rbCWT.mjs.map +0 -1
  144. package/dist/config-loader-_W4T21X1.mjs.map +0 -1
  145. package/dist/contract-emit-CQfj7xJn.mjs +0 -122
  146. package/dist/contract-emit-CQfj7xJn.mjs.map +0 -1
  147. package/dist/contract-emit-DpPjuFy-.mjs +0 -195
  148. package/dist/contract-emit-DpPjuFy-.mjs.map +0 -1
  149. package/dist/contract-emit-fhNwwhkQ.mjs +0 -4
  150. package/dist/contract-infer-BS4kIX9c.mjs.map +0 -1
  151. package/dist/extract-operation-statements-DZUJNmL3.mjs +0 -13
  152. package/dist/extract-operation-statements-DZUJNmL3.mjs.map +0 -1
  153. package/dist/extract-sql-ddl-DDMX-9mz.mjs +0 -26
  154. package/dist/extract-sql-ddl-DDMX-9mz.mjs.map +0 -1
  155. package/dist/init-CQfo_4Ro.mjs +0 -430
  156. package/dist/init-CQfo_4Ro.mjs.map +0 -1
  157. package/dist/inspect-live-schema-BsoFVoS1.mjs.map +0 -1
  158. package/dist/migration-status-Ry3TnEya.mjs.map +0 -1
  159. package/dist/migrations-fU0xoKjS.mjs.map +0 -1
  160. package/dist/result-handler-BJwA7ufw.mjs.map +0 -1
  161. package/dist/terminal-ui-C5k88MmW.mjs.map +0 -1
  162. package/dist/validate-contract-deps-esa-VQ0h.mjs +0 -37
  163. package/dist/validate-contract-deps-esa-VQ0h.mjs.map +0 -1
  164. package/src/control-api/operations/extract-operation-statements.ts +0 -14
  165. package/src/control-api/operations/extract-sql-ddl.ts +0 -47
@@ -1,16 +1,16 @@
1
- import { t as loadConfig } from "./config-loader-_W4T21X1.mjs";
2
- import { _ as errorUnexpected, m as errorRuntime } from "./cli-errors-DHq6GQGu.mjs";
3
- import { t as createControlClient } from "./client-TG7rbCWT.mjs";
4
- import { _ as formatStyledHeader, a as maskConnectionUrl, c as resolveMigrationPaths, d as setCommandExamples, i as loadAllBundles, m as parseGlobalFlags, n as addGlobalOptions, o as readContractEnvelope, p as toPathDecisionResult, t as handleResult, u as setCommandDescriptions } from "./result-handler-BJwA7ufw.mjs";
5
- import { t as TerminalUI } from "./terminal-ui-C5k88MmW.mjs";
1
+ import { t as loadConfig } from "./config-loader-ih8ViDb_.mjs";
2
+ import { _ as errorUnexpected, m as errorRuntime, v as mapMigrationToolsError } from "./cli-errors-By1iVE3z.mjs";
3
+ import { t as TerminalUI } from "./terminal-ui-u2YgKghu.mjs";
4
+ import { a as loadMigrationPackages, d as setCommandDescriptions, f as setCommandExamples, g as parseGlobalFlags, h as toStructuralEdge, l as resolveMigrationPaths, m as toPathDecisionResult, n as addGlobalOptions, o as maskConnectionUrl, r as collectDeclaredInvariants, s as readContractEnvelope, t as handleResult, y as formatStyledHeader } from "./result-handler-Ch6hVnOo.mjs";
5
+ import { t as createControlClient } from "./client-1JqqkiC7.mjs";
6
6
  import { Command } from "commander";
7
- import { notOk, ok } from "@prisma-next/utils/result";
8
7
  import { ifDefined } from "@prisma-next/utils/defined";
9
- import { EMPTY_CONTRACT_HASH } from "@prisma-next/migration-tools/constants";
10
- import { findPath, findPathWithDecision, findReachableLeaves } from "@prisma-next/migration-tools/dag";
8
+ import { notOk, ok } from "@prisma-next/utils/result";
9
+ import { findPath, findPathWithDecision, findReachableLeaves } from "@prisma-next/migration-tools/migration-graph";
11
10
  import { bold, cyan, dim, magenta, yellow } from "colorette";
11
+ import { EMPTY_CONTRACT_HASH } from "@prisma-next/migration-tools/constants";
12
+ import { MigrationToolsError, errorNoInvariantPath, errorUnknownInvariant } from "@prisma-next/migration-tools/errors";
12
13
  import { readRefs, resolveRef } from "@prisma-next/migration-tools/refs";
13
- import { MigrationToolsError } from "@prisma-next/migration-tools/types";
14
14
  import dagre from "@dagrejs/dagre";
15
15
 
16
16
  //#region src/utils/formatters/graph-types.ts
@@ -100,7 +100,8 @@ function migrationGraphToRenderInput(input) {
100
100
  for (const [, entries] of graph.forwardChain) for (const entry of entries) {
101
101
  const status = statusByDirName.get(entry.dirName);
102
102
  const icon = status ? STATUS_ICON[status] : "";
103
- const label = `${entry.dirName}${icon}`;
103
+ const invariantsSuffix = entry.invariants.length > 0 ? ` provides [${entry.invariants.map((id) => JSON.stringify(id)).join(", ")}]` : "";
104
+ const label = `${entry.dirName}${icon}${invariantsSuffix}`;
104
105
  edgeList.push({
105
106
  from: toShortId(entry.from),
106
107
  to: toShortId(entry.to),
@@ -1194,7 +1195,7 @@ function buildMigrationEntries(chain, packages, mode, markerHash, edgeStatuses)
1194
1195
  dirName: migration.dirName,
1195
1196
  from: migration.from,
1196
1197
  to: migration.to,
1197
- migrationId: migration.migrationId,
1198
+ migrationHash: migration.migrationHash,
1198
1199
  operationCount: ops.length,
1199
1200
  operationSummary: summary,
1200
1201
  hasDestructive,
@@ -1246,30 +1247,25 @@ async function executeMigrationStatusCommand(options, flags, ui) {
1246
1247
  const hasDriver = !!config.driver;
1247
1248
  let activeRefName;
1248
1249
  let activeRefHash;
1250
+ let activeRefEntry;
1249
1251
  let allRefs = {};
1250
1252
  try {
1251
1253
  allRefs = await readRefs(refsDir);
1252
1254
  } catch (error) {
1253
- if (MigrationToolsError.is(error)) return notOk(errorRuntime(error.message, {
1254
- why: error.why,
1255
- fix: error.fix,
1256
- meta: { code: error.code }
1257
- }));
1255
+ if (MigrationToolsError.is(error)) return notOk(mapMigrationToolsError(error));
1258
1256
  throw error;
1259
1257
  }
1260
1258
  if (options.ref) {
1261
1259
  activeRefName = options.ref;
1262
1260
  try {
1263
- activeRefHash = resolveRef(allRefs, activeRefName).hash;
1261
+ activeRefEntry = resolveRef(allRefs, activeRefName);
1262
+ activeRefHash = activeRefEntry.hash;
1264
1263
  } catch (error) {
1265
- if (MigrationToolsError.is(error)) return notOk(errorRuntime(error.message, {
1266
- why: error.why,
1267
- fix: error.fix,
1268
- meta: { code: error.code }
1269
- }));
1264
+ if (MigrationToolsError.is(error)) return notOk(mapMigrationToolsError(error));
1270
1265
  throw error;
1271
1266
  }
1272
1267
  }
1268
+ const requiredInvariants = [...activeRefEntry?.invariants ?? []].sort();
1273
1269
  const statusRefs = Object.entries(allRefs).map(([name, entry]) => ({
1274
1270
  name,
1275
1271
  hash: entry.hash,
@@ -1291,6 +1287,10 @@ async function executeMigrationStatusCommand(options, flags, ui) {
1291
1287
  label: "ref",
1292
1288
  value: activeRefName
1293
1289
  });
1290
+ if (activeRefEntry && activeRefEntry.invariants.length > 0) details.push({
1291
+ label: "required",
1292
+ value: formatInvariantList(activeRefEntry.invariants)
1293
+ });
1294
1294
  const header = formatStyledHeader({
1295
1295
  command: "migration status",
1296
1296
  description: "Show migration history and applied status",
@@ -1314,13 +1314,9 @@ async function executeMigrationStatusCommand(options, flags, ui) {
1314
1314
  let bundles;
1315
1315
  let graph;
1316
1316
  try {
1317
- ({bundles, graph} = await loadAllBundles(migrationsDir));
1317
+ ({bundles, graph} = await loadMigrationPackages(migrationsDir));
1318
1318
  } catch (error) {
1319
- if (MigrationToolsError.is(error)) return notOk(errorRuntime(error.message, {
1320
- why: error.why,
1321
- fix: error.fix,
1322
- meta: { code: error.code }
1323
- }));
1319
+ if (MigrationToolsError.is(error)) return notOk(mapMigrationToolsError(error));
1324
1320
  return notOk(errorUnexpected(error instanceof Error ? error.message : String(error), { why: `Failed to read migrations directory: ${error instanceof Error ? error.message : String(error)}` }));
1325
1321
  }
1326
1322
  if (bundles.length === 0) {
@@ -1337,7 +1333,8 @@ async function executeMigrationStatusCommand(options, flags, ui) {
1337
1333
  targetHash: EMPTY_CONTRACT_HASH,
1338
1334
  contractHash,
1339
1335
  summary: "No migrations found",
1340
- diagnostics
1336
+ diagnostics,
1337
+ requiredInvariants
1341
1338
  });
1342
1339
  }
1343
1340
  let targetHash;
@@ -1354,6 +1351,7 @@ async function executeMigrationStatusCommand(options, flags, ui) {
1354
1351
  });
1355
1352
  }
1356
1353
  let markerHash;
1354
+ let markerInvariants = [];
1357
1355
  let mode = "offline";
1358
1356
  if (dbConnection && hasDriver) {
1359
1357
  const client = createControlClient({
@@ -1365,7 +1363,9 @@ async function executeMigrationStatusCommand(options, flags, ui) {
1365
1363
  });
1366
1364
  try {
1367
1365
  await client.connect(dbConnection);
1368
- markerHash = (await client.readMarker())?.storageHash;
1366
+ const marker = await client.readMarker();
1367
+ markerHash = marker?.storageHash;
1368
+ markerInvariants = marker?.invariants ?? [];
1369
1369
  mode = "online";
1370
1370
  } catch {
1371
1371
  if (!flags.json && !flags.quiet) ui.warn("Could not connect to database — showing offline status");
@@ -1373,6 +1373,17 @@ async function executeMigrationStatusCommand(options, flags, ui) {
1373
1373
  await client.close();
1374
1374
  }
1375
1375
  }
1376
+ if (activeRefEntry && activeRefEntry.invariants.length > 0) {
1377
+ const declared = collectDeclaredInvariants(graph);
1378
+ const known = new Set(declared);
1379
+ if (mode === "online") for (const id of markerInvariants) known.add(id);
1380
+ const unknown = activeRefEntry.invariants.filter((id) => !known.has(id));
1381
+ if (unknown.length > 0) return notOk(mapMigrationToolsError(errorUnknownInvariant({
1382
+ ...ifDefined("refName", activeRefName),
1383
+ unknown,
1384
+ declared: [...declared].sort()
1385
+ })));
1386
+ }
1376
1387
  if (mode === "online" && markerHash !== void 0 && !graph.nodes.has(markerHash) && markerHash !== contractHash) {
1377
1388
  const hints = [];
1378
1389
  if (graph.nodes.has(contractHash)) hints.push("Run 'prisma-next db sign' to overwrite the marker if the database already matches the contract", "Run 'prisma-next db update' to push the current contract to the database", "Run 'prisma-next contract infer' to make your contract match the database", "Run 'prisma-next db verify' to inspect the database state");
@@ -1392,6 +1403,7 @@ async function executeMigrationStatusCommand(options, flags, ui) {
1392
1403
  summary: `${bundles.length} migration(s) on disk`,
1393
1404
  diagnostics,
1394
1405
  markerHash,
1406
+ requiredInvariants,
1395
1407
  ...statusRefs.length > 0 ? { refs: statusRefs } : {}
1396
1408
  });
1397
1409
  }
@@ -1416,6 +1428,7 @@ async function executeMigrationStatusCommand(options, flags, ui) {
1416
1428
  summary: `${bundles.length} migration(s) on disk`,
1417
1429
  diagnostics,
1418
1430
  ...ifDefined("markerHash", markerHash),
1431
+ requiredInvariants,
1419
1432
  ...statusRefs.length > 0 ? { refs: statusRefs } : {},
1420
1433
  graph,
1421
1434
  bundles,
@@ -1430,35 +1443,68 @@ async function executeMigrationStatusCommand(options, flags, ui) {
1430
1443
  const entries = buildMigrationEntries(chain, bundles, mode, markerHash, edgeStatuses);
1431
1444
  const pendingCount = edgeStatuses.filter((e) => e.status === "pending").length;
1432
1445
  const appliedCount = edgeStatuses.filter((e) => e.status === "applied").length;
1446
+ let appliedInvariants;
1447
+ let missingInvariants;
1448
+ let effectiveRequired = /* @__PURE__ */ new Set();
1449
+ if (mode === "online") {
1450
+ const markerSet = new Set(markerInvariants);
1451
+ effectiveRequired = new Set(requiredInvariants.filter((id) => !markerSet.has(id)));
1452
+ appliedInvariants = requiredInvariants.filter((id) => markerSet.has(id));
1453
+ missingInvariants = [...effectiveRequired].sort();
1454
+ }
1455
+ const hasInvariantWork = effectiveRequired.size > 0;
1456
+ const missingList = [...effectiveRequired].sort().join(", ");
1433
1457
  let summary;
1434
1458
  if (mode === "online") if (markerHash !== void 0 && !graph.nodes.has(markerHash) && markerHash === contractHash) summary = `${bundles.length} migration(s) on disk`;
1435
- else if (activeRefHash && markerHash !== void 0) summary = summarizeRefDistance(graph, markerHash, activeRefHash, activeRefName);
1436
- else if (pendingCount === 0) summary = `Database is up to date (${appliedCount} migration${appliedCount !== 1 ? "s" : ""} applied)`;
1459
+ else if (activeRefHash && markerHash !== void 0) {
1460
+ const distance = summarizeRefDistance(graph, markerHash, activeRefHash, activeRefName);
1461
+ summary = hasInvariantWork ? `${distance} — missing invariant(s): ${missingList}` : distance;
1462
+ } else if (pendingCount === 0 && !hasInvariantWork) summary = `Database is up to date (${appliedCount} migration${appliedCount !== 1 ? "s" : ""} applied)`;
1463
+ else if (pendingCount === 0 && hasInvariantWork) summary = `Missing invariant(s): ${missingList} — run 'prisma-next migration apply --ref ${activeRefName ?? "<ref>"}' to apply`;
1437
1464
  else if (markerHash === void 0) summary = `${pendingCount} pending migration(s) — database has no marker`;
1438
1465
  else summary = `${pendingCount} pending migration(s) — run 'prisma-next migration apply' to apply`;
1439
1466
  else summary = `${entries.length} migration(s) on disk`;
1440
- if (mode === "online") if (markerHash !== void 0 && !graph.nodes.has(markerHash) && markerHash === contractHash) diagnostics.push({
1441
- code: "MIGRATION.MARKER_NOT_IN_HISTORY",
1442
- severity: "warn",
1443
- message: "Database matches the current contract but was updated directly (not via migration apply)",
1444
- hints: ["Run 'prisma-next migration plan' to plan a migration to your current contract"]
1445
- });
1446
- else if (pendingCount > 0) diagnostics.push({
1447
- code: "MIGRATION.DATABASE_BEHIND",
1448
- severity: "info",
1449
- message: `${pendingCount} migration(s) pending`,
1450
- hints: ["Run 'prisma-next migration apply' to apply pending migrations"]
1451
- });
1452
- else diagnostics.push({
1453
- code: "MIGRATION.UP_TO_DATE",
1454
- severity: "info",
1455
- message: "Database is up to date",
1456
- hints: []
1457
- });
1458
1467
  let pathDecision;
1459
- if (mode === "online" && markerHash !== void 0) {
1460
- const decision = findPathWithDecision(graph, markerHash, targetHash, activeRefName);
1461
- if (decision) pathDecision = toPathDecisionResult(decision);
1468
+ let routingUnreachable = false;
1469
+ if (mode === "online") {
1470
+ const outcome = findPathWithDecision(graph, markerHash ?? EMPTY_CONTRACT_HASH, targetHash, {
1471
+ ...ifDefined("refName", activeRefName),
1472
+ required: effectiveRequired
1473
+ });
1474
+ if (outcome.kind === "ok") pathDecision = toPathDecisionResult(outcome.decision);
1475
+ else if (outcome.kind === "unsatisfiable") return notOk(mapMigrationToolsError(errorNoInvariantPath({
1476
+ ...ifDefined("refName", activeRefName),
1477
+ required: [...effectiveRequired].sort(),
1478
+ missing: outcome.missing,
1479
+ structuralPath: outcome.structuralPath.map(toStructuralEdge)
1480
+ })));
1481
+ else routingUnreachable = true;
1482
+ }
1483
+ if (mode === "online") {
1484
+ if (markerHash !== void 0 && !graph.nodes.has(markerHash) && markerHash === contractHash) diagnostics.push({
1485
+ code: "MIGRATION.MARKER_NOT_IN_HISTORY",
1486
+ severity: "warn",
1487
+ message: "Database matches the current contract but was updated directly (not via migration apply)",
1488
+ hints: ["Run 'prisma-next migration plan' to plan a migration to your current contract"]
1489
+ });
1490
+ else if (pendingCount > 0) diagnostics.push({
1491
+ code: "MIGRATION.DATABASE_BEHIND",
1492
+ severity: "info",
1493
+ message: `${pendingCount} migration(s) pending`,
1494
+ hints: ["Run 'prisma-next migration apply' to apply pending migrations"]
1495
+ });
1496
+ else if (hasInvariantWork) diagnostics.push({
1497
+ code: "MIGRATION.INVARIANTS_PENDING",
1498
+ severity: "info",
1499
+ message: `Missing required invariant(s): ${missingList}`,
1500
+ hints: [`Run 'prisma-next migration apply --ref ${activeRefName ?? "<ref>"}' to apply a path that covers the required invariants`]
1501
+ });
1502
+ else if (!routingUnreachable) diagnostics.push({
1503
+ code: "MIGRATION.UP_TO_DATE",
1504
+ severity: "info",
1505
+ message: "Database is up to date",
1506
+ hints: []
1507
+ });
1462
1508
  }
1463
1509
  return ok({
1464
1510
  ok: true,
@@ -1469,6 +1515,9 @@ async function executeMigrationStatusCommand(options, flags, ui) {
1469
1515
  summary,
1470
1516
  diagnostics,
1471
1517
  ...ifDefined("markerHash", markerHash),
1518
+ requiredInvariants,
1519
+ ...ifDefined("appliedInvariants", appliedInvariants),
1520
+ ...ifDefined("missingInvariants", missingInvariants),
1472
1521
  ...statusRefs.length > 0 ? { refs: statusRefs } : {},
1473
1522
  ...ifDefined("pathDecision", pathDecision),
1474
1523
  graph,
@@ -1490,7 +1539,7 @@ function createMigrationStatusCommand() {
1490
1539
  });
1491
1540
  const exitCode = handleResult(await executeMigrationStatusCommand(options, flags, ui), flags, ui, (statusResult) => {
1492
1541
  if (flags.json) {
1493
- const { graph: _g, bundles: _b, edgeStatuses: _es, activeRefHash: _arh, activeRefName: _arn, diverged: _d, ...jsonResult } = statusResult;
1542
+ const { graph: _graph, bundles: _bundles, edgeStatuses: _edgeStatuses, activeRefHash: _activeRefHash, activeRefName: _activeRefName, diverged: _diverged, ...jsonResult } = statusResult;
1494
1543
  ui.output(JSON.stringify(jsonResult, null, 2));
1495
1544
  } else if (!flags.quiet) {
1496
1545
  const colorize = flags.color !== false;
@@ -1540,10 +1589,15 @@ function formatStatusSummary(result, colorize) {
1540
1589
  const hasUnknown = result.migrations.some((e) => e.status === "unknown");
1541
1590
  const pendingCount = result.migrations.filter((e) => e.status === "pending").length;
1542
1591
  const hasWarnings = result.diagnostics?.some((d) => d.severity === "warn") ?? false;
1592
+ const hasInvariantPending = result.diagnostics?.some((d) => d.code === "MIGRATION.INVARIANTS_PENDING") ?? false;
1543
1593
  if (result.mode === "online") if (hasUnknown || hasWarnings) lines.push(`${c(yellow, "⚠")} ${result.summary}`);
1544
- else if (pendingCount === 0) lines.push(`${c(cyan, "✔")} ${result.summary}`);
1594
+ else if (pendingCount === 0 && !hasInvariantPending) lines.push(`${c(cyan, "✔")} ${result.summary}`);
1545
1595
  else lines.push(`${c(yellow, "⧗")} ${result.summary}`);
1546
1596
  else lines.push(result.summary);
1597
+ if (result.requiredInvariants.length > 0) if (result.appliedInvariants !== void 0 && result.missingInvariants !== void 0) {
1598
+ lines.push(`${c(dim, "applied ")}${formatInvariantList(result.appliedInvariants)}`);
1599
+ lines.push(`${c(dim, "missing ")}${formatInvariantList(result.missingInvariants)}`);
1600
+ } else lines.push(`${c(dim, "applied ")}(unknown — connect a database to evaluate)`);
1547
1601
  const warnings = result.diagnostics?.filter((d) => d.severity === "warn") ?? [];
1548
1602
  for (const diag of warnings) {
1549
1603
  lines.push(`${c(yellow, "⚠")} ${diag.message}`);
@@ -1551,6 +1605,9 @@ function formatStatusSummary(result, colorize) {
1551
1605
  }
1552
1606
  return lines.join("\n");
1553
1607
  }
1608
+ function formatInvariantList(ids) {
1609
+ return ids.length === 0 ? "(none)" : ids.join(", ");
1610
+ }
1554
1611
  function summarizeRefDistance(graph, markerHash, refHash, refName) {
1555
1612
  if (markerHash === refHash) return `At ref "${refName}" target`;
1556
1613
  const pathToRef = findPath(graph, markerHash, refHash);
@@ -1561,5 +1618,5 @@ function summarizeRefDistance(graph, markerHash, refHash, refName) {
1561
1618
  }
1562
1619
 
1563
1620
  //#endregion
1564
- export { deriveEdgeStatuses as n, createMigrationStatusCommand as t };
1565
- //# sourceMappingURL=migration-status-Ry3TnEya.mjs.map
1621
+ export { deriveEdgeStatuses as n, formatStatusSummary as r, createMigrationStatusCommand as t };
1622
+ //# sourceMappingURL=migration-status-DoPrFIOQ.mjs.map