@prisma-next/cli 0.16.0-dev.4 → 0.16.0-dev.5

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 (61) hide show
  1. package/README.md +3 -4
  2. package/dist/cli.mjs +6 -6
  3. package/dist/commands/db-sign.d.mts.map +1 -1
  4. package/dist/commands/db-sign.mjs +4 -6
  5. package/dist/commands/db-sign.mjs.map +1 -1
  6. package/dist/commands/db-update.d.mts.map +1 -1
  7. package/dist/commands/db-update.mjs +5 -8
  8. package/dist/commands/db-update.mjs.map +1 -1
  9. package/dist/commands/migrate.mjs +2 -2
  10. package/dist/commands/migration-check.d.mts +3 -1
  11. package/dist/commands/migration-check.d.mts.map +1 -1
  12. package/dist/commands/migration-check.mjs +1 -1
  13. package/dist/commands/migration-graph.mjs +1 -1
  14. package/dist/commands/migration-list.d.mts.map +1 -1
  15. package/dist/commands/migration-list.mjs +1 -1
  16. package/dist/commands/migration-new.d.mts.map +1 -1
  17. package/dist/commands/migration-new.mjs +12 -36
  18. package/dist/commands/migration-new.mjs.map +1 -1
  19. package/dist/commands/migration-plan.d.mts.map +1 -1
  20. package/dist/commands/migration-plan.mjs +1 -1
  21. package/dist/commands/migration-status.mjs +1 -1
  22. package/dist/commands/ref.d.mts.map +1 -1
  23. package/dist/commands/ref.mjs +7 -9
  24. package/dist/commands/ref.mjs.map +1 -1
  25. package/dist/{contract-at-errors-D9gEjYtg.mjs → contract-at-errors-CTtzKR6q.mjs} +6 -10
  26. package/dist/contract-at-errors-CTtzKR6q.mjs.map +1 -0
  27. package/dist/exports/init-output.d.mts.map +1 -1
  28. package/dist/exports/init-output.mjs +1 -1
  29. package/dist/{init-C3JhkHg-.mjs → init-CgKEi_t5.mjs} +53 -45
  30. package/dist/init-CgKEi_t5.mjs.map +1 -0
  31. package/dist/{migration-check-MHT3w7_v.mjs → migration-check-CcuayFB2.mjs} +49 -22
  32. package/dist/migration-check-CcuayFB2.mjs.map +1 -0
  33. package/dist/{migration-list-BAKujUjh.mjs → migration-list-6z6vuXHa.mjs} +3 -3
  34. package/dist/migration-list-6z6vuXHa.mjs.map +1 -0
  35. package/dist/{migration-plan-CreSVtWZ.mjs → migration-plan-DuMEUejG.mjs} +46 -54
  36. package/dist/migration-plan-DuMEUejG.mjs.map +1 -0
  37. package/dist/{migration-status-YgEvXf-u.mjs → migration-status-B61YOaMl.mjs} +3 -2
  38. package/dist/{migration-status-YgEvXf-u.mjs.map → migration-status-B61YOaMl.mjs.map} +1 -1
  39. package/dist/{output-mEQ74_nd.mjs → output-DWNYqZGc.mjs} +5 -6
  40. package/dist/output-DWNYqZGc.mjs.map +1 -0
  41. package/package.json +21 -21
  42. package/src/commands/db-sign.ts +6 -4
  43. package/src/commands/db-update.ts +13 -6
  44. package/src/commands/init/hygiene-gitattributes.ts +37 -21
  45. package/src/commands/init/init.ts +6 -6
  46. package/src/commands/init/output.ts +4 -5
  47. package/src/commands/init/reinit-cleanup.ts +16 -17
  48. package/src/commands/migration-check.ts +69 -32
  49. package/src/commands/migration-list.ts +1 -5
  50. package/src/commands/migration-new.ts +15 -39
  51. package/src/commands/migration-plan.ts +54 -76
  52. package/src/commands/ref.ts +18 -7
  53. package/src/utils/contract-at-errors.ts +9 -13
  54. package/src/utils/contract-space-seed-phase.ts +8 -6
  55. package/src/utils/plan-resolution.ts +1 -4
  56. package/dist/contract-at-errors-D9gEjYtg.mjs.map +0 -1
  57. package/dist/init-C3JhkHg-.mjs.map +0 -1
  58. package/dist/migration-check-MHT3w7_v.mjs.map +0 -1
  59. package/dist/migration-list-BAKujUjh.mjs.map +0 -1
  60. package/dist/migration-plan-CreSVtWZ.mjs.map +0 -1
  61. package/dist/output-mEQ74_nd.mjs.map +0 -1
@@ -5,11 +5,11 @@ import { Command } from "commander";
5
5
  import { loadConfig } from "@prisma-next/config-loader";
6
6
  import { notOk, ok } from "@prisma-next/utils/result";
7
7
  import { join } from "pathe";
8
- import { readFile } from "node:fs/promises";
9
8
  import { EMPTY_CONTRACT_HASH } from "@prisma-next/migration-tools/constants";
10
9
  import { MigrationToolsError } from "@prisma-next/migration-tools/errors";
11
10
  import { findLatestMigration, isGraphNode } from "@prisma-next/migration-tools/migration-graph";
12
11
  import { deleteRefPaired, readRefs, validateRefName, validateRefValue, writeRefPaired } from "@prisma-next/migration-tools/refs";
12
+ import { contractSnapshotDir, readContractSnapshotJson } from "@prisma-next/migration-tools/contract-snapshot-store";
13
13
  import { parseContractRef } from "@prisma-next/migration-tools/ref-resolution";
14
14
  //#region src/commands/ref.ts
15
15
  function mapError(error) {
@@ -47,17 +47,15 @@ async function executeRefSetCommand(name, contractInput, options) {
47
47
  const graphTip = findLatestMigration(graph)?.to ?? null;
48
48
  return notOk(errorRefSetHashNotInGraph(resolvedHash, [...graph.nodes].sort(), graphTip));
49
49
  }
50
- const matchingBundle = bundles.find((bundle) => bundle.metadata.to === resolvedHash);
51
- if (!matchingBundle) return notOk(errorRefSetBundleNotFound(resolvedHash));
52
- const contractJsonPath = join(matchingBundle.dirPath, "end-contract.json");
50
+ if (!bundles.find((bundle) => bundle.metadata.to === resolvedHash)) return notOk(errorRefSetBundleNotFound(resolvedHash));
51
+ const contractJsonPath = join(contractSnapshotDir(migrationsDir, resolvedHash), "contract.json");
53
52
  let contractJson;
54
53
  try {
55
- const raw = await readFile(contractJsonPath, "utf-8");
56
- contractJson = JSON.parse(raw);
54
+ contractJson = await readContractSnapshotJson(migrationsDir, resolvedHash);
57
55
  } catch (readError) {
58
- if (readError instanceof Error && readError.code === "ENOENT") return notOk(errorFileNotFound(contractJsonPath, {
59
- why: `Migration bundle for hash ${resolvedHash} is missing its end-contract snapshot at ${contractJsonPath}`,
60
- fix: "Run `pnpm fixtures:check`, or re-emit the migration so its end-contract.json is restored."
56
+ if (MigrationToolsError.is(readError) && readError.code === "MIGRATION.CONTRACT_SNAPSHOT_MISSING") return notOk(errorFileNotFound(contractJsonPath, {
57
+ why: `Migration bundle for hash ${resolvedHash} is missing its contract snapshot at ${contractJsonPath}`,
58
+ fix: "Restore migrations/snapshots/ from version control, or re-run the command that produced this migration to regenerate its snapshot."
61
59
  }));
62
60
  throw readError;
63
61
  }
@@ -1 +1 @@
1
- {"version":3,"file":"ref.mjs","names":[],"sources":["../../src/commands/ref.ts"],"sourcesContent":["import { readFile } from 'node:fs/promises';\nimport { loadConfig } from '@prisma-next/config-loader';\nimport { EMPTY_CONTRACT_HASH } from '@prisma-next/migration-tools/constants';\nimport { MigrationToolsError } from '@prisma-next/migration-tools/errors';\nimport { findLatestMigration, isGraphNode } from '@prisma-next/migration-tools/migration-graph';\nimport { parseContractRef } from '@prisma-next/migration-tools/ref-resolution';\nimport type { RefEntry } from '@prisma-next/migration-tools/refs';\nimport {\n deleteRefPaired,\n readRefs,\n validateRefName,\n validateRefValue,\n writeRefPaired,\n} from '@prisma-next/migration-tools/refs';\nimport { notOk, ok, type Result } from '@prisma-next/utils/result';\nimport { Command } from 'commander';\nimport { join } from 'pathe';\nimport {\n CliStructuredError,\n errorFileNotFound,\n errorRefSetBundleNotFound,\n errorRefSetEmptySentinel,\n errorRefSetHashNotInGraph,\n errorRuntime,\n errorUnexpected,\n mapMigrationToolsError,\n mapRefResolutionError,\n} from '../utils/cli-errors';\nimport {\n addGlobalOptions,\n resolveMigrationPaths,\n setCommandDescriptions,\n} from '../utils/command-helpers';\nimport { buildReadAggregate } from '../utils/contract-space-aggregate-loader';\nimport { formatCommandHelp } from '../utils/formatters/help';\nimport { parseGlobalFlags, parseGlobalFlagsOrExit } from '../utils/global-flags';\nimport { readContractIR } from '../utils/ref-advancement';\nimport { handleResult } from '../utils/result-handler';\nimport { createTerminalUI } from '../utils/terminal-ui';\n\ninterface RefSetResult {\n readonly ok: true;\n readonly ref: string;\n readonly hash: string;\n readonly invariants: readonly string[];\n}\n\ninterface RefDeleteResult {\n readonly ok: true;\n readonly ref: string;\n readonly deleted: true;\n}\n\ninterface RefListResult {\n readonly ok: true;\n readonly refs: Record<string, RefEntry>;\n}\n\nfunction mapError(error: unknown): CliStructuredError {\n if (MigrationToolsError.is(error)) {\n return mapMigrationToolsError(error);\n }\n return errorUnexpected(error instanceof Error ? error.message : String(error));\n}\n\nfunction cliErrorInvalidRefName(name: string): CliStructuredError {\n return errorRuntime(`Invalid ref name \"${name}\"`, {\n why: `Ref name \"${name}\" does not match the required format`,\n fix: 'Ref names must be lowercase alphanumeric with hyphens or forward slashes, no `.` or `..` segments',\n });\n}\n\nexport async function executeRefSetCommand(\n name: string,\n contractInput: string,\n options: { config?: string },\n): Promise<Result<RefSetResult, CliStructuredError>> {\n if (!validateRefName(name)) {\n return notOk(cliErrorInvalidRefName(name));\n }\n\n try {\n const config = await loadConfig(options.config);\n const { migrationsDir, refsDir } = resolveMigrationPaths(options.config, config);\n const loaded = await buildReadAggregate(config, { migrationsDir });\n if (!loaded.ok) {\n return notOk(loaded.failure);\n }\n const graph = loaded.value.aggregate.app.graph();\n const bundles = loaded.value.aggregate.app.packages;\n const refs = loaded.value.aggregate.app.refs;\n\n let resolvedHash: string;\n if (validateRefValue(contractInput)) {\n resolvedHash = contractInput;\n } else {\n const refResult = parseContractRef(contractInput, { graph, refs });\n if (!refResult.ok) {\n return notOk(mapRefResolutionError(refResult.failure));\n }\n resolvedHash = refResult.value.hash;\n }\n\n if (resolvedHash === EMPTY_CONTRACT_HASH) {\n return notOk(errorRefSetEmptySentinel(resolvedHash));\n }\n if (!isGraphNode(resolvedHash, graph)) {\n const graphTip = findLatestMigration(graph)?.to ?? null;\n return notOk(errorRefSetHashNotInGraph(resolvedHash, [...graph.nodes].sort(), graphTip));\n }\n\n const matchingBundle = bundles.find((bundle) => bundle.metadata.to === resolvedHash);\n if (!matchingBundle) {\n return notOk(errorRefSetBundleNotFound(resolvedHash));\n }\n\n const contractJsonPath = join(matchingBundle.dirPath, 'end-contract.json');\n let contractJson: Record<string, unknown>;\n try {\n const raw = await readFile(contractJsonPath, 'utf-8');\n contractJson = JSON.parse(raw) as Record<string, unknown>;\n } catch (readError) {\n if (readError instanceof Error && (readError as NodeJS.ErrnoException).code === 'ENOENT') {\n return notOk(\n errorFileNotFound(contractJsonPath, {\n why: `Migration bundle for hash ${resolvedHash} is missing its end-contract snapshot at ${contractJsonPath}`,\n fix: 'Run `pnpm fixtures:check`, or re-emit the migration so its end-contract.json is restored.',\n }),\n );\n }\n throw readError;\n }\n\n const contractIR = await readContractIR(contractJson, contractJsonPath);\n const entry: RefEntry = { hash: resolvedHash, invariants: [] };\n await writeRefPaired(refsDir, name, entry, contractIR);\n return ok({ ok: true as const, ref: name, hash: resolvedHash, invariants: [] });\n } catch (error) {\n if (error instanceof CliStructuredError) return notOk(error);\n return notOk(mapError(error));\n }\n}\n\nexport async function executeRefDeleteCommand(\n name: string,\n options: { config?: string },\n): Promise<Result<RefDeleteResult, CliStructuredError>> {\n try {\n const config = await loadConfig(options.config);\n const { refsDir } = resolveMigrationPaths(options.config, config);\n await deleteRefPaired(refsDir, name);\n return ok({ ok: true as const, ref: name, deleted: true as const });\n } catch (error) {\n if (error instanceof CliStructuredError) return notOk(error);\n return notOk(mapError(error));\n }\n}\n\nexport async function executeRefListCommand(options: {\n config?: string;\n}): Promise<Result<RefListResult, CliStructuredError>> {\n try {\n const config = await loadConfig(options.config);\n const { refsDir } = resolveMigrationPaths(options.config, config);\n const refs = await readRefs(refsDir);\n return ok({ ok: true as const, refs });\n } catch (error) {\n if (error instanceof CliStructuredError) return notOk(error);\n return notOk(mapError(error));\n }\n}\n\nfunction createRefSetCommand(): Command {\n const command = new Command('set');\n setCommandDescriptions(\n command,\n 'Set a ref to a contract reference',\n 'Sets a named ref to point to a resolved contract reference (hash, alias, or path) in migrations/refs/.',\n );\n addGlobalOptions(command)\n .argument('<name>', 'Ref name (e.g., staging, production)')\n .argument(\n '<contract>',\n 'Contract reference (hash, prefix, ref name, migration dir name, <dir>^, or ./path)',\n )\n .option('--config <path>', 'Path to prisma-next.config.ts')\n .action(\n async (\n name: string,\n hash: string,\n options: { config?: string; json?: string | boolean; quiet?: boolean },\n ) => {\n const flags = parseGlobalFlagsOrExit(options);\n const ui = createTerminalUI(flags);\n const result = await executeRefSetCommand(name, hash, options);\n const exitCode = handleResult(result, flags, ui, (value) => {\n if (flags.json) {\n ui.output(JSON.stringify(value));\n } else if (!flags.quiet) {\n ui.output(`Set ref \"${value.ref}\" → ${value.hash}`);\n }\n });\n process.exit(exitCode);\n },\n );\n return command;\n}\n\nfunction createRefDeleteCommand(): Command {\n const command = new Command('delete');\n setCommandDescriptions(command, 'Delete a ref', 'Removes a named ref from migrations/refs/.');\n addGlobalOptions(command)\n .argument('<name>', 'Ref name to delete')\n .option('--config <path>', 'Path to prisma-next.config.ts')\n .action(\n async (\n name: string,\n options: { config?: string; json?: string | boolean; quiet?: boolean },\n ) => {\n const flags = parseGlobalFlagsOrExit(options);\n const ui = createTerminalUI(flags);\n const result = await executeRefDeleteCommand(name, options);\n const exitCode = handleResult(result, flags, ui, (value) => {\n if (flags.json) {\n ui.output(JSON.stringify(value));\n } else if (!flags.quiet) {\n ui.output(`Deleted ref \"${value.ref}\"`);\n }\n });\n process.exit(exitCode);\n },\n );\n return command;\n}\n\nfunction createRefListCommand(): Command {\n const command = new Command('list');\n setCommandDescriptions(command, 'List all refs', 'Lists all named refs from migrations/refs/.');\n addGlobalOptions(command)\n .option('--config <path>', 'Path to prisma-next.config.ts')\n .action(async (options: { config?: string; json?: string | boolean; quiet?: boolean }) => {\n const flags = parseGlobalFlagsOrExit(options);\n const ui = createTerminalUI(flags);\n const result = await executeRefListCommand(options);\n const exitCode = handleResult(result, flags, ui, (value) => {\n if (flags.json) {\n ui.output(JSON.stringify(value));\n } else if (!flags.quiet) {\n const entries = Object.entries(value.refs);\n if (entries.length === 0) {\n ui.output('No refs defined');\n } else {\n for (const [refName, entry] of entries) {\n const invariantsSuffix =\n entry.invariants.length > 0 ? ` [invariants: ${entry.invariants.join(', ')}]` : '';\n ui.output(`${refName} → ${entry.hash}${invariantsSuffix}`);\n }\n }\n }\n });\n process.exit(exitCode);\n });\n return command;\n}\n\nexport function createRefCommand(): Command {\n const command = new Command('ref');\n setCommandDescriptions(\n command,\n 'Manage contract refs',\n 'Manage named refs in migrations/refs/. Refs map logical environment\\n' +\n 'names (e.g., staging, production) to contract hashes.',\n );\n addGlobalOptions(command).configureHelp({\n formatHelp: (cmd) => formatCommandHelp({ command: cmd, flags: parseGlobalFlags({}) }),\n subcommandDescription: () => '',\n });\n command.addCommand(createRefSetCommand());\n command.addCommand(createRefDeleteCommand());\n command.addCommand(createRefListCommand());\n return command;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"ref.mjs","names":[],"sources":["../../src/commands/ref.ts"],"sourcesContent":["import { loadConfig } from '@prisma-next/config-loader';\nimport { EMPTY_CONTRACT_HASH } from '@prisma-next/migration-tools/constants';\nimport {\n contractSnapshotDir,\n readContractSnapshotJson,\n} from '@prisma-next/migration-tools/contract-snapshot-store';\nimport { MigrationToolsError } from '@prisma-next/migration-tools/errors';\nimport { findLatestMigration, isGraphNode } from '@prisma-next/migration-tools/migration-graph';\nimport { parseContractRef } from '@prisma-next/migration-tools/ref-resolution';\nimport type { RefEntry } from '@prisma-next/migration-tools/refs';\nimport {\n deleteRefPaired,\n readRefs,\n validateRefName,\n validateRefValue,\n writeRefPaired,\n} from '@prisma-next/migration-tools/refs';\nimport { notOk, ok, type Result } from '@prisma-next/utils/result';\nimport { Command } from 'commander';\nimport { join } from 'pathe';\nimport {\n CliStructuredError,\n errorFileNotFound,\n errorRefSetBundleNotFound,\n errorRefSetEmptySentinel,\n errorRefSetHashNotInGraph,\n errorRuntime,\n errorUnexpected,\n mapMigrationToolsError,\n mapRefResolutionError,\n} from '../utils/cli-errors';\nimport {\n addGlobalOptions,\n resolveMigrationPaths,\n setCommandDescriptions,\n} from '../utils/command-helpers';\nimport { buildReadAggregate } from '../utils/contract-space-aggregate-loader';\nimport { formatCommandHelp } from '../utils/formatters/help';\nimport { parseGlobalFlags, parseGlobalFlagsOrExit } from '../utils/global-flags';\nimport { readContractIR } from '../utils/ref-advancement';\nimport { handleResult } from '../utils/result-handler';\nimport { createTerminalUI } from '../utils/terminal-ui';\n\ninterface RefSetResult {\n readonly ok: true;\n readonly ref: string;\n readonly hash: string;\n readonly invariants: readonly string[];\n}\n\ninterface RefDeleteResult {\n readonly ok: true;\n readonly ref: string;\n readonly deleted: true;\n}\n\ninterface RefListResult {\n readonly ok: true;\n readonly refs: Record<string, RefEntry>;\n}\n\nfunction mapError(error: unknown): CliStructuredError {\n if (MigrationToolsError.is(error)) {\n return mapMigrationToolsError(error);\n }\n return errorUnexpected(error instanceof Error ? error.message : String(error));\n}\n\nfunction cliErrorInvalidRefName(name: string): CliStructuredError {\n return errorRuntime(`Invalid ref name \"${name}\"`, {\n why: `Ref name \"${name}\" does not match the required format`,\n fix: 'Ref names must be lowercase alphanumeric with hyphens or forward slashes, no `.` or `..` segments',\n });\n}\n\nexport async function executeRefSetCommand(\n name: string,\n contractInput: string,\n options: { config?: string },\n): Promise<Result<RefSetResult, CliStructuredError>> {\n if (!validateRefName(name)) {\n return notOk(cliErrorInvalidRefName(name));\n }\n\n try {\n const config = await loadConfig(options.config);\n const { migrationsDir, refsDir } = resolveMigrationPaths(options.config, config);\n const loaded = await buildReadAggregate(config, { migrationsDir });\n if (!loaded.ok) {\n return notOk(loaded.failure);\n }\n const graph = loaded.value.aggregate.app.graph();\n const bundles = loaded.value.aggregate.app.packages;\n const refs = loaded.value.aggregate.app.refs;\n\n let resolvedHash: string;\n if (validateRefValue(contractInput)) {\n resolvedHash = contractInput;\n } else {\n const refResult = parseContractRef(contractInput, { graph, refs });\n if (!refResult.ok) {\n return notOk(mapRefResolutionError(refResult.failure));\n }\n resolvedHash = refResult.value.hash;\n }\n\n if (resolvedHash === EMPTY_CONTRACT_HASH) {\n return notOk(errorRefSetEmptySentinel(resolvedHash));\n }\n if (!isGraphNode(resolvedHash, graph)) {\n const graphTip = findLatestMigration(graph)?.to ?? null;\n return notOk(errorRefSetHashNotInGraph(resolvedHash, [...graph.nodes].sort(), graphTip));\n }\n\n const matchingBundle = bundles.find((bundle) => bundle.metadata.to === resolvedHash);\n if (!matchingBundle) {\n return notOk(errorRefSetBundleNotFound(resolvedHash));\n }\n\n const contractJsonPath = join(\n contractSnapshotDir(migrationsDir, resolvedHash),\n 'contract.json',\n );\n let contractJson: Record<string, unknown>;\n try {\n contractJson = (await readContractSnapshotJson(migrationsDir, resolvedHash)) as Record<\n string,\n unknown\n >;\n } catch (readError) {\n if (\n MigrationToolsError.is(readError) &&\n readError.code === 'MIGRATION.CONTRACT_SNAPSHOT_MISSING'\n ) {\n return notOk(\n errorFileNotFound(contractJsonPath, {\n why: `Migration bundle for hash ${resolvedHash} is missing its contract snapshot at ${contractJsonPath}`,\n fix: 'Restore migrations/snapshots/ from version control, or re-run the command that produced this migration to regenerate its snapshot.',\n }),\n );\n }\n throw readError;\n }\n\n const contractIR = await readContractIR(contractJson, contractJsonPath);\n const entry: RefEntry = { hash: resolvedHash, invariants: [] };\n await writeRefPaired(refsDir, name, entry, contractIR);\n return ok({ ok: true as const, ref: name, hash: resolvedHash, invariants: [] });\n } catch (error) {\n if (error instanceof CliStructuredError) return notOk(error);\n return notOk(mapError(error));\n }\n}\n\nexport async function executeRefDeleteCommand(\n name: string,\n options: { config?: string },\n): Promise<Result<RefDeleteResult, CliStructuredError>> {\n try {\n const config = await loadConfig(options.config);\n const { refsDir } = resolveMigrationPaths(options.config, config);\n await deleteRefPaired(refsDir, name);\n return ok({ ok: true as const, ref: name, deleted: true as const });\n } catch (error) {\n if (error instanceof CliStructuredError) return notOk(error);\n return notOk(mapError(error));\n }\n}\n\nexport async function executeRefListCommand(options: {\n config?: string;\n}): Promise<Result<RefListResult, CliStructuredError>> {\n try {\n const config = await loadConfig(options.config);\n const { refsDir } = resolveMigrationPaths(options.config, config);\n const refs = await readRefs(refsDir);\n return ok({ ok: true as const, refs });\n } catch (error) {\n if (error instanceof CliStructuredError) return notOk(error);\n return notOk(mapError(error));\n }\n}\n\nfunction createRefSetCommand(): Command {\n const command = new Command('set');\n setCommandDescriptions(\n command,\n 'Set a ref to a contract reference',\n 'Sets a named ref to point to a resolved contract reference (hash, alias, or path) in migrations/refs/.',\n );\n addGlobalOptions(command)\n .argument('<name>', 'Ref name (e.g., staging, production)')\n .argument(\n '<contract>',\n 'Contract reference (hash, prefix, ref name, migration dir name, <dir>^, or ./path)',\n )\n .option('--config <path>', 'Path to prisma-next.config.ts')\n .action(\n async (\n name: string,\n hash: string,\n options: { config?: string; json?: string | boolean; quiet?: boolean },\n ) => {\n const flags = parseGlobalFlagsOrExit(options);\n const ui = createTerminalUI(flags);\n const result = await executeRefSetCommand(name, hash, options);\n const exitCode = handleResult(result, flags, ui, (value) => {\n if (flags.json) {\n ui.output(JSON.stringify(value));\n } else if (!flags.quiet) {\n ui.output(`Set ref \"${value.ref}\" → ${value.hash}`);\n }\n });\n process.exit(exitCode);\n },\n );\n return command;\n}\n\nfunction createRefDeleteCommand(): Command {\n const command = new Command('delete');\n setCommandDescriptions(command, 'Delete a ref', 'Removes a named ref from migrations/refs/.');\n addGlobalOptions(command)\n .argument('<name>', 'Ref name to delete')\n .option('--config <path>', 'Path to prisma-next.config.ts')\n .action(\n async (\n name: string,\n options: { config?: string; json?: string | boolean; quiet?: boolean },\n ) => {\n const flags = parseGlobalFlagsOrExit(options);\n const ui = createTerminalUI(flags);\n const result = await executeRefDeleteCommand(name, options);\n const exitCode = handleResult(result, flags, ui, (value) => {\n if (flags.json) {\n ui.output(JSON.stringify(value));\n } else if (!flags.quiet) {\n ui.output(`Deleted ref \"${value.ref}\"`);\n }\n });\n process.exit(exitCode);\n },\n );\n return command;\n}\n\nfunction createRefListCommand(): Command {\n const command = new Command('list');\n setCommandDescriptions(command, 'List all refs', 'Lists all named refs from migrations/refs/.');\n addGlobalOptions(command)\n .option('--config <path>', 'Path to prisma-next.config.ts')\n .action(async (options: { config?: string; json?: string | boolean; quiet?: boolean }) => {\n const flags = parseGlobalFlagsOrExit(options);\n const ui = createTerminalUI(flags);\n const result = await executeRefListCommand(options);\n const exitCode = handleResult(result, flags, ui, (value) => {\n if (flags.json) {\n ui.output(JSON.stringify(value));\n } else if (!flags.quiet) {\n const entries = Object.entries(value.refs);\n if (entries.length === 0) {\n ui.output('No refs defined');\n } else {\n for (const [refName, entry] of entries) {\n const invariantsSuffix =\n entry.invariants.length > 0 ? ` [invariants: ${entry.invariants.join(', ')}]` : '';\n ui.output(`${refName} → ${entry.hash}${invariantsSuffix}`);\n }\n }\n }\n });\n process.exit(exitCode);\n });\n return command;\n}\n\nexport function createRefCommand(): Command {\n const command = new Command('ref');\n setCommandDescriptions(\n command,\n 'Manage contract refs',\n 'Manage named refs in migrations/refs/. Refs map logical environment\\n' +\n 'names (e.g., staging, production) to contract hashes.',\n );\n addGlobalOptions(command).configureHelp({\n formatHelp: (cmd) => formatCommandHelp({ command: cmd, flags: parseGlobalFlags({}) }),\n subcommandDescription: () => '',\n });\n command.addCommand(createRefSetCommand());\n command.addCommand(createRefDeleteCommand());\n command.addCommand(createRefListCommand());\n return command;\n}\n"],"mappings":";;;;;;;;;;;;;;AA6DA,SAAS,SAAS,OAAoC;CACpD,IAAI,oBAAoB,GAAG,KAAK,GAC9B,OAAO,uBAAuB,KAAK;CAErC,OAAO,gBAAgB,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;AAC/E;AAEA,SAAS,uBAAuB,MAAkC;CAChE,OAAO,aAAa,qBAAqB,KAAK,IAAI;EAChD,KAAK,aAAa,KAAK;EACvB,KAAK;CACP,CAAC;AACH;AAEA,eAAsB,qBACpB,MACA,eACA,SACmD;CACnD,IAAI,CAAC,gBAAgB,IAAI,GACvB,OAAO,MAAM,uBAAuB,IAAI,CAAC;CAG3C,IAAI;EACF,MAAM,SAAS,MAAM,WAAW,QAAQ,MAAM;EAC9C,MAAM,EAAE,eAAe,YAAY,sBAAsB,QAAQ,QAAQ,MAAM;EAC/E,MAAM,SAAS,MAAM,mBAAmB,QAAQ,EAAE,cAAc,CAAC;EACjE,IAAI,CAAC,OAAO,IACV,OAAO,MAAM,OAAO,OAAO;EAE7B,MAAM,QAAQ,OAAO,MAAM,UAAU,IAAI,MAAM;EAC/C,MAAM,UAAU,OAAO,MAAM,UAAU,IAAI;EAC3C,MAAM,OAAO,OAAO,MAAM,UAAU,IAAI;EAExC,IAAI;EACJ,IAAI,iBAAiB,aAAa,GAChC,eAAe;OACV;GACL,MAAM,YAAY,iBAAiB,eAAe;IAAE;IAAO;GAAK,CAAC;GACjE,IAAI,CAAC,UAAU,IACb,OAAO,MAAM,sBAAsB,UAAU,OAAO,CAAC;GAEvD,eAAe,UAAU,MAAM;EACjC;EAEA,IAAI,iBAAiB,qBACnB,OAAO,MAAM,yBAAyB,YAAY,CAAC;EAErD,IAAI,CAAC,YAAY,cAAc,KAAK,GAAG;GACrC,MAAM,WAAW,oBAAoB,KAAK,CAAC,EAAE,MAAM;GACnD,OAAO,MAAM,0BAA0B,cAAc,CAAC,GAAG,MAAM,KAAK,CAAC,CAAC,KAAK,GAAG,QAAQ,CAAC;EACzF;EAGA,IAAI,CADmB,QAAQ,MAAM,WAAW,OAAO,SAAS,OAAO,YACrD,GAChB,OAAO,MAAM,0BAA0B,YAAY,CAAC;EAGtD,MAAM,mBAAmB,KACvB,oBAAoB,eAAe,YAAY,GAC/C,eACF;EACA,IAAI;EACJ,IAAI;GACF,eAAgB,MAAM,yBAAyB,eAAe,YAAY;EAI5E,SAAS,WAAW;GAClB,IACE,oBAAoB,GAAG,SAAS,KAChC,UAAU,SAAS,uCAEnB,OAAO,MACL,kBAAkB,kBAAkB;IAClC,KAAK,6BAA6B,aAAa,uCAAuC;IACtF,KAAK;GACP,CAAC,CACH;GAEF,MAAM;EACR;EAEA,MAAM,aAAa,MAAM,eAAe,cAAc,gBAAgB;EAEtE,MAAM,eAAe,SAAS,MAAM;GADV,MAAM;GAAc,YAAY,CAAC;EACnB,GAAG,UAAU;EACrD,OAAO,GAAG;GAAE,IAAI;GAAe,KAAK;GAAM,MAAM;GAAc,YAAY,CAAC;EAAE,CAAC;CAChF,SAAS,OAAO;EACd,IAAI,iBAAiB,oBAAoB,OAAO,MAAM,KAAK;EAC3D,OAAO,MAAM,SAAS,KAAK,CAAC;CAC9B;AACF;AAEA,eAAsB,wBACpB,MACA,SACsD;CACtD,IAAI;EACF,MAAM,SAAS,MAAM,WAAW,QAAQ,MAAM;EAC9C,MAAM,EAAE,YAAY,sBAAsB,QAAQ,QAAQ,MAAM;EAChE,MAAM,gBAAgB,SAAS,IAAI;EACnC,OAAO,GAAG;GAAE,IAAI;GAAe,KAAK;GAAM,SAAS;EAAc,CAAC;CACpE,SAAS,OAAO;EACd,IAAI,iBAAiB,oBAAoB,OAAO,MAAM,KAAK;EAC3D,OAAO,MAAM,SAAS,KAAK,CAAC;CAC9B;AACF;AAEA,eAAsB,sBAAsB,SAEW;CACrD,IAAI;EACF,MAAM,SAAS,MAAM,WAAW,QAAQ,MAAM;EAC9C,MAAM,EAAE,YAAY,sBAAsB,QAAQ,QAAQ,MAAM;EAEhE,OAAO,GAAG;GAAE,IAAI;GAAe,MAAA,MADZ,SAAS,OAAO;EACC,CAAC;CACvC,SAAS,OAAO;EACd,IAAI,iBAAiB,oBAAoB,OAAO,MAAM,KAAK;EAC3D,OAAO,MAAM,SAAS,KAAK,CAAC;CAC9B;AACF;AAEA,SAAS,sBAA+B;CACtC,MAAM,UAAU,IAAI,QAAQ,KAAK;CACjC,uBACE,SACA,qCACA,wGACF;CACA,iBAAiB,OAAO,CAAC,CACtB,SAAS,UAAU,sCAAsC,CAAC,CAC1D,SACC,cACA,oFACF,CAAC,CACA,OAAO,mBAAmB,+BAA+B,CAAC,CAC1D,OACC,OACE,MACA,MACA,YACG;EACH,MAAM,QAAQ,uBAAuB,OAAO;EAC5C,MAAM,KAAK,iBAAiB,KAAK;EAEjC,MAAM,WAAW,aAAa,MADT,qBAAqB,MAAM,MAAM,OAAO,GACvB,OAAO,KAAK,UAAU;GAC1D,IAAI,MAAM,MACR,GAAG,OAAO,KAAK,UAAU,KAAK,CAAC;QAC1B,IAAI,CAAC,MAAM,OAChB,GAAG,OAAO,YAAY,MAAM,IAAI,MAAM,MAAM,MAAM;EAEtD,CAAC;EACD,QAAQ,KAAK,QAAQ;CACvB,CACF;CACF,OAAO;AACT;AAEA,SAAS,yBAAkC;CACzC,MAAM,UAAU,IAAI,QAAQ,QAAQ;CACpC,uBAAuB,SAAS,gBAAgB,4CAA4C;CAC5F,iBAAiB,OAAO,CAAC,CACtB,SAAS,UAAU,oBAAoB,CAAC,CACxC,OAAO,mBAAmB,+BAA+B,CAAC,CAC1D,OACC,OACE,MACA,YACG;EACH,MAAM,QAAQ,uBAAuB,OAAO;EAC5C,MAAM,KAAK,iBAAiB,KAAK;EAEjC,MAAM,WAAW,aAAa,MADT,wBAAwB,MAAM,OAAO,GACpB,OAAO,KAAK,UAAU;GAC1D,IAAI,MAAM,MACR,GAAG,OAAO,KAAK,UAAU,KAAK,CAAC;QAC1B,IAAI,CAAC,MAAM,OAChB,GAAG,OAAO,gBAAgB,MAAM,IAAI,EAAE;EAE1C,CAAC;EACD,QAAQ,KAAK,QAAQ;CACvB,CACF;CACF,OAAO;AACT;AAEA,SAAS,uBAAgC;CACvC,MAAM,UAAU,IAAI,QAAQ,MAAM;CAClC,uBAAuB,SAAS,iBAAiB,6CAA6C;CAC9F,iBAAiB,OAAO,CAAC,CACtB,OAAO,mBAAmB,+BAA+B,CAAC,CAC1D,OAAO,OAAO,YAA2E;EACxF,MAAM,QAAQ,uBAAuB,OAAO;EAC5C,MAAM,KAAK,iBAAiB,KAAK;EAEjC,MAAM,WAAW,aAAa,MADT,sBAAsB,OAAO,GACZ,OAAO,KAAK,UAAU;GAC1D,IAAI,MAAM,MACR,GAAG,OAAO,KAAK,UAAU,KAAK,CAAC;QAC1B,IAAI,CAAC,MAAM,OAAO;IACvB,MAAM,UAAU,OAAO,QAAQ,MAAM,IAAI;IACzC,IAAI,QAAQ,WAAW,GACrB,GAAG,OAAO,iBAAiB;SAE3B,KAAK,MAAM,CAAC,SAAS,UAAU,SAAS;KACtC,MAAM,mBACJ,MAAM,WAAW,SAAS,IAAI,iBAAiB,MAAM,WAAW,KAAK,IAAI,EAAE,KAAK;KAClF,GAAG,OAAO,GAAG,QAAQ,KAAK,MAAM,OAAO,kBAAkB;IAC3D;GAEJ;EACF,CAAC;EACD,QAAQ,KAAK,QAAQ;CACvB,CAAC;CACH,OAAO;AACT;AAEA,SAAgB,mBAA4B;CAC1C,MAAM,UAAU,IAAI,QAAQ,KAAK;CACjC,uBACE,SACA,wBACA,4HAEF;CACA,iBAAiB,OAAO,CAAC,CAAC,cAAc;EACtC,aAAa,QAAQ,kBAAkB;GAAE,SAAS;GAAK,OAAO,iBAAiB,CAAC,CAAC;EAAE,CAAC;EACpF,6BAA6B;CAC/B,CAAC;CACD,QAAQ,WAAW,oBAAoB,CAAC;CACxC,QAAQ,WAAW,uBAAuB,CAAC;CAC3C,QAAQ,WAAW,qBAAqB,CAAC;CACzC,OAAO;AACT"}
@@ -1,6 +1,5 @@
1
1
  import { B as errorContractValidationFailed, F as CliStructuredError, W as errorFileNotFound, ct as errorUnexpected, it as errorSnapshotMissing, lt as mapMigrationToolsError } from "./command-helpers-Cpq44aVa.mjs";
2
2
  import { notOk } from "@prisma-next/utils/result";
3
- import { join } from "pathe";
4
3
  import { MigrationToolsError } from "@prisma-next/migration-tools/errors";
5
4
  //#region src/utils/contract-at-errors.ts
6
5
  function mapContractAtError(error, options) {
@@ -21,14 +20,11 @@ function mapContractAtError(error, options) {
21
20
  why: error.why,
22
21
  fix: error.fix
23
22
  }));
24
- case "MIGRATION.FILE_MISSING": {
25
- const file = typeof error.details?.["file"] === "string" ? error.details["file"] : "end-contract.json";
26
- const dir = typeof error.details?.["dir"] === "string" ? error.details["dir"] : "";
27
- const jsonPath = dir ? join(dir, "end-contract.json") : file;
28
- const role = options?.artifactRole ?? "from";
29
- return notOk(errorFileNotFound(jsonPath, {
30
- why: role === "to" ? `Target migration is missing its destination contract snapshot at ${jsonPath}` : `Predecessor migration is missing its destination contract snapshot at ${jsonPath}`,
31
- fix: role === "to" ? "Re-emit the target migration so its sibling `end-contract.json` / `end-contract.d.ts` are restored, then re-run this command." : "Re-emit the predecessor migration (`prisma-next migration plan` from its source) so its sibling `end-contract.json` is restored, then re-run this command."
23
+ case "MIGRATION.CONTRACT_SNAPSHOT_MISSING": {
24
+ const expectedPath = typeof error.details?.["expectedPath"] === "string" ? error.details["expectedPath"] : "migrations/snapshots/";
25
+ return notOk(errorFileNotFound(expectedPath, {
26
+ why: (options?.artifactRole ?? "from") === "to" ? `Target migration is missing its contract snapshot at ${expectedPath}` : `Predecessor migration is missing its contract snapshot at ${expectedPath}`,
27
+ fix: "Restore migrations/snapshots/ from version control, or re-run the command that produced this migration to regenerate its snapshot."
32
28
  }));
33
29
  }
34
30
  default: return notOk(mapMigrationToolsError(error));
@@ -39,4 +35,4 @@ function mapContractAtError(error, options) {
39
35
  //#endregion
40
36
  export { mapContractAtError as t };
41
37
 
42
- //# sourceMappingURL=contract-at-errors-D9gEjYtg.mjs.map
38
+ //# sourceMappingURL=contract-at-errors-CTtzKR6q.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contract-at-errors-CTtzKR6q.mjs","names":[],"sources":["../src/utils/contract-at-errors.ts"],"sourcesContent":["import { MigrationToolsError } from '@prisma-next/migration-tools/errors';\nimport { notOk, type Result } from '@prisma-next/utils/result';\nimport {\n CliStructuredError,\n errorContractValidationFailed,\n errorFileNotFound,\n errorSnapshotMissing,\n errorUnexpected,\n mapMigrationToolsError,\n} from './cli-errors';\n\nexport function mapContractAtError(\n error: unknown,\n options?: { readonly artifactRole?: 'from' | 'to' },\n): Result<never, CliStructuredError> {\n if (MigrationToolsError.is(error)) {\n switch (error.code) {\n case 'MIGRATION.SNAPSHOT_MISSING': {\n const refName =\n typeof error.details?.['refName'] === 'string'\n ? error.details['refName']\n : typeof error.details?.['identifier'] === 'string'\n ? error.details['identifier']\n : 'unknown';\n return notOk(errorSnapshotMissing(refName));\n }\n case 'MIGRATION.CONTRACT_DESERIALIZATION_FAILED': {\n const filePath =\n typeof error.details?.['filePath'] === 'string'\n ? error.details['filePath']\n : 'ref-snapshot';\n const message =\n typeof error.details?.['message'] === 'string' ? error.details['message'] : error.message;\n const isRefSnapshot = filePath.endsWith('.contract.json');\n return notOk(\n errorContractValidationFailed(\n isRefSnapshot\n ? `Ref snapshot contract failed to deserialize: ${message}`\n : `Predecessor contract at ${filePath} failed to deserialize: ${message}`,\n { where: { path: isRefSnapshot ? 'ref-snapshot' : filePath } },\n ),\n );\n }\n case 'MIGRATION.INVALID_JSON': {\n const filePath =\n typeof error.details?.['filePath'] === 'string' ? error.details['filePath'] : 'unknown';\n const message =\n typeof error.details?.['parseError'] === 'string'\n ? error.details['parseError']\n : error.message;\n const role = options?.artifactRole ?? 'from';\n return notOk(\n errorContractValidationFailed(\n role === 'to'\n ? `Target contract at ${filePath} failed to deserialize: ${message}`\n : `Predecessor contract at ${filePath} failed to deserialize: ${message}`,\n { where: { path: filePath } },\n ),\n );\n }\n case 'MIGRATION.BUNDLE_NOT_FOUND_FOR_GRAPH_NODE':\n return notOk(\n errorUnexpected(error.message, {\n why: error.why,\n fix: error.fix,\n }),\n );\n case 'MIGRATION.CONTRACT_SNAPSHOT_MISSING': {\n const expectedPath =\n typeof error.details?.['expectedPath'] === 'string'\n ? error.details['expectedPath']\n : 'migrations/snapshots/';\n const role = options?.artifactRole ?? 'from';\n return notOk(\n errorFileNotFound(expectedPath, {\n why:\n role === 'to'\n ? `Target migration is missing its contract snapshot at ${expectedPath}`\n : `Predecessor migration is missing its contract snapshot at ${expectedPath}`,\n fix: 'Restore migrations/snapshots/ from version control, or re-run the command that produced this migration to regenerate its snapshot.',\n }),\n );\n }\n default:\n return notOk(mapMigrationToolsError(error));\n }\n }\n if (CliStructuredError.is(error)) {\n return notOk(error);\n }\n throw error;\n}\n"],"mappings":";;;;AAWA,SAAgB,mBACd,OACA,SACmC;CACnC,IAAI,oBAAoB,GAAG,KAAK,GAC9B,QAAQ,MAAM,MAAd;EACE,KAAK,8BAOH,OAAO,MAAM,qBALX,OAAO,MAAM,UAAU,eAAe,WAClC,MAAM,QAAQ,aACd,OAAO,MAAM,UAAU,kBAAkB,WACvC,MAAM,QAAQ,gBACd,SACiC,CAAC;EAE5C,KAAK,6CAA6C;GAChD,MAAM,WACJ,OAAO,MAAM,UAAU,gBAAgB,WACnC,MAAM,QAAQ,cACd;GACN,MAAM,UACJ,OAAO,MAAM,UAAU,eAAe,WAAW,MAAM,QAAQ,aAAa,MAAM;GACpF,MAAM,gBAAgB,SAAS,SAAS,gBAAgB;GACxD,OAAO,MACL,8BACE,gBACI,gDAAgD,YAChD,2BAA2B,SAAS,0BAA0B,WAClE,EAAE,OAAO,EAAE,MAAM,gBAAgB,iBAAiB,SAAS,EAAE,CAC/D,CACF;EACF;EACA,KAAK,0BAA0B;GAC7B,MAAM,WACJ,OAAO,MAAM,UAAU,gBAAgB,WAAW,MAAM,QAAQ,cAAc;GAChF,MAAM,UACJ,OAAO,MAAM,UAAU,kBAAkB,WACrC,MAAM,QAAQ,gBACd,MAAM;GAEZ,OAAO,MACL,+BAFW,SAAS,gBAAgB,YAGzB,OACL,sBAAsB,SAAS,0BAA0B,YACzD,2BAA2B,SAAS,0BAA0B,WAClE,EAAE,OAAO,EAAE,MAAM,SAAS,EAAE,CAC9B,CACF;EACF;EACA,KAAK,6CACH,OAAO,MACL,gBAAgB,MAAM,SAAS;GAC7B,KAAK,MAAM;GACX,KAAK,MAAM;EACb,CAAC,CACH;EACF,KAAK,uCAAuC;GAC1C,MAAM,eACJ,OAAO,MAAM,UAAU,oBAAoB,WACvC,MAAM,QAAQ,kBACd;GAEN,OAAO,MACL,kBAAkB,cAAc;IAC9B,MAHS,SAAS,gBAAgB,YAIvB,OACL,wDAAwD,iBACxD,6DAA6D;IACnE,KAAK;GACP,CAAC,CACH;EACF;EACA,SACE,OAAO,MAAM,uBAAuB,KAAK,CAAC;CAC9C;CAEF,IAAI,mBAAmB,GAAG,KAAK,GAC7B,OAAO,MAAM,KAAK;CAEpB,MAAM;AACR"}
@@ -1 +1 @@
1
- {"version":3,"file":"init-output.d.mts","names":[],"sources":["../../src/commands/init/output.ts"],"mappings":";;;;;;;;;;;;;;;;cAkBa,gEAAgB;;;;;;;;;;;;;;;;KAwBjB,oBAAoB,iBAAiB"}
1
+ {"version":3,"file":"init-output.d.mts","names":[],"sources":["../../src/commands/init/output.ts"],"mappings":";;;;;;;;;;;;;;;;cAkBa,gEAAgB;;;;;;;;;;;;;;;;KAuBjB,oBAAoB,iBAAiB"}
@@ -1,2 +1,2 @@
1
- import { t as InitOutputSchema } from "../output-mEQ74_nd.mjs";
1
+ import { t as InitOutputSchema } from "../output-DWNYqZGc.mjs";
2
2
  export { InitOutputSchema };
@@ -1,6 +1,6 @@
1
1
  import { F as CliStructuredError, _ as createTerminalUI, b as formatErrorJson, x as formatErrorOutput } from "./command-helpers-Cpq44aVa.mjs";
2
2
  import { a as starterSchema, c as version, i as schemaSample, n as dbFile, o as targetLabel, r as defaultSchemaPath, s as targetPackageName, t as configFile } from "./cli.mjs";
3
- import { i as renderInitOutro, n as buildNextSteps, r as formatInitJson, t as InitOutputSchema } from "./output-mEQ74_nd.mjs";
3
+ import { i as renderInitOutro, n as buildNextSteps, r as formatInitJson, t as InitOutputSchema } from "./output-DWNYqZGc.mjs";
4
4
  import { createRequire } from "node:module";
5
5
  import { basename, dirname, extname, isAbsolute, join, normalize } from "pathe";
6
6
  import { blindCast } from "@prisma-next/utils/casts";
@@ -413,50 +413,59 @@ function errorInitSkillInstallFailed(options) {
413
413
  //#endregion
414
414
  //#region src/commands/init/hygiene-gitattributes.ts
415
415
  /**
416
- * The schema-relative `.gitattributes` entries written for a freshly
417
- * initialised project (FR3.4). Mirrors the relevant subset of the
418
- * repo-root [`.gitattributes`](../../../../../../../../.gitattributes):
416
+ * The `.gitattributes` entries written for a freshly initialised project
417
+ * (FR3.4). Mirrors the relevant subset of the repo-root
418
+ * [`.gitattributes`](../../../../../../../../.gitattributes):
419
419
  *
420
420
  * - **Today**: `contract.json`, `contract.d.ts` are emitted on every
421
421
  * `prisma-next contract emit`. Marking them `linguist-generated`
422
422
  * keeps GitHub's diff stats honest and collapses the file in code
423
423
  * review by default.
424
- * - **Forward-looking**: `end-contract.*`, `start-contract.*`, `ops.json`,
425
- * `migration.json` are not yet emitted by `init` flows but will be
426
- * produced by adjacent commands (lower / migration tooling). Adding
427
- * them now matches Decision 5 (forward-looking subset) so the file
428
- * does not need to be amended every time a new artefact lands.
429
- *
430
- * Patterns are written relative to the schema directory so a user
431
- * who runs `init --schema-path db/contract.prisma` gets
432
- * `db/contract.json linguist-generated` — not the workspace-glob form
433
- * `<glob>/contract.json` (which would over-match any unrelated
424
+ * - **Forward-looking**: `ops.json`, `migration.json` are not yet emitted
425
+ * by `init` flows but will be produced by adjacent commands (lower /
426
+ * migration tooling). Adding them now matches Decision 5
427
+ * (forward-looking subset) so the file does not need to be amended
428
+ * every time a new artifact lands.
429
+ *
430
+ * `ARTIFACT_FILENAMES` entries are written relative to the schema
431
+ * directory so a user who runs `init --schema-path db/contract.prisma`
432
+ * gets `db/contract.json linguist-generated` — not the workspace-glob
433
+ * form `<glob>/contract.json` (which would over-match any unrelated
434
434
  * `contract.json` the user has elsewhere) and not the absolute
435
- * `DEFAULT_CONTRACT_SOURCE_DIR/contract.json` (which would silently break for a non-default
436
- * schema path).
435
+ * `DEFAULT_CONTRACT_SOURCE_DIR/contract.json` (which would silently
436
+ * break for a non-default schema path).
437
+ *
438
+ * The migration contract snapshot store (`migrations/snapshots/<hex>/`)
439
+ * is anchored to the migrations root instead, not the schema directory:
440
+ * migration package depth under `migrations/` varies (`app/<pkg>`,
441
+ * `<space>/<pkg>`, or a bare `<pkg>` in extension source repos), so no
442
+ * single schema-dir-relative pattern can reach every snapshot. See
443
+ * `STORE_GITATTRIBUTES_LINES` below.
437
444
  */
438
- const ARTEFACT_FILENAMES$1 = [
445
+ const ARTIFACT_FILENAMES$1 = [
439
446
  "contract.json",
440
447
  "contract.d.ts",
441
- "end-contract.json",
442
- "end-contract.d.ts",
443
- "start-contract.json",
444
- "start-contract.d.ts",
445
448
  "ops.json",
446
449
  "migration.json"
447
450
  ];
448
451
  const ATTRIBUTE = "linguist-generated";
449
452
  /**
453
+ * Full `.gitattributes` lines for the migration contract snapshot store,
454
+ * already anchored to the migrations root — unlike `ARTIFACT_FILENAMES`,
455
+ * these are not combined with the schema-relative prefix.
456
+ */
457
+ const STORE_GITATTRIBUTES_LINES = [`migrations/snapshots/**/contract.json ${ATTRIBUTE}`, `migrations/snapshots/**/contract.d.ts ${ATTRIBUTE}`];
458
+ /**
450
459
  * Computes the `.gitattributes` lines this scaffold expects to own. Each
451
460
  * line has the shape `<path> linguist-generated`. The `target` parameter
452
461
  * is currently unused but accepted for symmetry with the other hygiene
453
462
  * helpers and to leave room for target-specific entries (e.g. a future
454
- * Mongo-only artefact) without a signature break.
463
+ * family-specific artifact) without a signature break.
455
464
  */
456
465
  function requiredGitattributesLines(schemaDir, _target) {
457
466
  const dir = schemaDir === "." ? "" : schemaDir.replace(/\/+$/, "");
458
467
  const prefix = dir === "" ? "" : `${dir}/`;
459
- return ARTEFACT_FILENAMES$1.map((file) => `${prefix}${file} ${ATTRIBUTE}`);
468
+ return [...ARTIFACT_FILENAMES$1.map((file) => `${prefix}${file} ${ATTRIBUTE}`), ...STORE_GITATTRIBUTES_LINES];
460
469
  }
461
470
  /**
462
471
  * Idempotent `.gitattributes` merge (FR3.4 / FR9.3). Returns the new file
@@ -1037,40 +1046,39 @@ function requirePeer(moduleId, baseDir, overrides) {
1037
1046
  /**
1038
1047
  * Filenames the contract pipeline emits next to the user's schema source
1039
1048
  * (`<schemaDir>/contract.json`, `<schemaDir>/contract.d.ts`, …). Mirrors
1040
- * `ARTEFACT_FILENAMES` in `hygiene-gitattributes.ts`; kept as a separate
1041
- * constant here because the cleanup contract is target-agnostic and we
1042
- * deliberately do not want a stale `start-contract.json` from a previous
1043
- * target lingering after a re-init.
1044
- *
1045
- * If a future emit pipeline produces an additional artefact, add it here
1046
- * **and** to the gitattributes list — the two stay in lockstep so the
1047
- * file `init` advertises as `linguist-generated` is exactly the file
1048
- * `init` is willing to delete on re-init.
1049
- */
1050
- const ARTEFACT_FILENAMES = [
1049
+ * the schema-dir-relative `ARTIFACT_FILENAMES` in `hygiene-gitattributes.ts`
1050
+ * (not that file's migrations-root-anchored store lines, which are outside
1051
+ * this command's scope reinit only ever touches `schemaDir`); kept as a
1052
+ * separate constant here because the cleanup contract is target-agnostic
1053
+ * and we deliberately do not want a stale artifact from a previous target
1054
+ * lingering after a re-init.
1055
+ *
1056
+ * If a future emit pipeline produces an additional schema-dir artifact,
1057
+ * add it here **and** to `ARTIFACT_FILENAMES` in `hygiene-gitattributes.ts`
1058
+ * — the two stay in lockstep so the file `init` advertises as
1059
+ * `linguist-generated` is exactly the file `init` is willing to delete on
1060
+ * re-init.
1061
+ */
1062
+ const ARTIFACT_FILENAMES = [
1051
1063
  "contract.json",
1052
1064
  "contract.d.ts",
1053
- "end-contract.json",
1054
- "end-contract.d.ts",
1055
- "start-contract.json",
1056
- "start-contract.d.ts",
1057
1065
  "ops.json",
1058
1066
  "migration.json"
1059
1067
  ];
1060
1068
  /**
1061
- * Returns the schema-relative paths of stale contract artefacts the
1069
+ * Returns the schema-relative paths of stale contract artifacts the
1062
1070
  * previous `init` run (or a `contract emit`) left behind in `schemaDir`.
1063
1071
  * Paths are returned relative to `baseDir` so the caller can plumb them
1064
1072
  * into `filesWritten`-style logging without re-deriving the path.
1065
1073
  *
1066
1074
  * Pure function: no filesystem mutation. Used by `runInit`'s precondition
1067
1075
  * phase (FR6.2 / NFR3 atomicity) so a downstream parse failure leaves
1068
- * the artefacts on disk and the project byte-identical to its pre-init
1076
+ * the artifacts on disk and the project byte-identical to its pre-init
1069
1077
  * state.
1070
1078
  */
1071
- function findStaleArtefacts(baseDir, schemaDir) {
1079
+ function findStaleArtifacts(baseDir, schemaDir) {
1072
1080
  const result = [];
1073
- for (const filename of ARTEFACT_FILENAMES) {
1081
+ for (const filename of ARTIFACT_FILENAMES) {
1074
1082
  const rel = join(schemaDir, filename);
1075
1083
  if (existsSync(join(baseDir, rel))) result.push(rel);
1076
1084
  }
@@ -1669,7 +1677,7 @@ async function runInit(baseDir, runOptions) {
1669
1677
  content: envExampleContent(inputs.target)
1670
1678
  }
1671
1679
  ];
1672
- const filesToDelete = inputs.reinit ? [...findStaleArtefacts(baseDir, schemaDir)] : [];
1680
+ const filesToDelete = inputs.reinit ? [...findStaleArtifacts(baseDir, schemaDir)] : [];
1673
1681
  if (existsSync(join(baseDir, ".agents/skills/prisma-next/SKILL.md"))) filesToDelete.push(LEGACY_SKILL_FILE);
1674
1682
  if (inputs.writeEnv) if (!existsSync(join(baseDir, ".env"))) filesToWrite.push({
1675
1683
  path: ".env",
@@ -2081,7 +2089,7 @@ function formatCatalogWarning(workspaceFile, entries) {
2081
2089
  /**
2082
2090
  * Recognised pnpm error signatures that justify a fallback to npm.
2083
2091
  *
2084
- * These patterns indicate the published artefact itself is at fault
2092
+ * These patterns indicate the published artifact itself is at fault
2085
2093
  * (a leaked `workspace:*` or `catalog:` specifier), not the user's
2086
2094
  * environment — pnpm is faithfully reporting "I cannot resolve this
2087
2095
  * registry version", and npm is willing to install it because npm
@@ -2193,4 +2201,4 @@ function sanitisePackageName(raw) {
2193
2201
  //#endregion
2194
2202
  export { runInit };
2195
2203
 
2196
- //# sourceMappingURL=init-C3JhkHg-.mjs.map
2204
+ //# sourceMappingURL=init-CgKEi_t5.mjs.map