@prisma-next/cli 0.3.0-dev.16 → 0.3.0-dev.163

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 (242) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +381 -128
  3. package/dist/cli-errors-BDCYR5ap.mjs +4 -0
  4. package/dist/cli-errors-Dzs7Oxz7.d.mts +3 -0
  5. package/dist/cli.d.mts +1 -0
  6. package/dist/cli.js +1 -2671
  7. package/dist/cli.mjs +238 -0
  8. package/dist/cli.mjs.map +1 -0
  9. package/dist/client-yYtotiSX.mjs +1063 -0
  10. package/dist/client-yYtotiSX.mjs.map +1 -0
  11. package/dist/commands/contract-emit.d.mts +7 -0
  12. package/dist/commands/contract-emit.d.mts.map +1 -0
  13. package/dist/commands/contract-emit.mjs +4 -0
  14. package/dist/commands/contract-infer.d.mts +7 -0
  15. package/dist/commands/contract-infer.d.mts.map +1 -0
  16. package/dist/commands/contract-infer.mjs +4 -0
  17. package/dist/commands/db-init.d.mts +7 -0
  18. package/dist/commands/db-init.d.mts.map +1 -0
  19. package/dist/commands/db-init.mjs +124 -0
  20. package/dist/commands/db-init.mjs.map +1 -0
  21. package/dist/commands/db-schema.d.mts +7 -0
  22. package/dist/commands/db-schema.d.mts.map +1 -0
  23. package/dist/commands/db-schema.mjs +52 -0
  24. package/dist/commands/db-schema.mjs.map +1 -0
  25. package/dist/commands/db-sign.d.mts +7 -0
  26. package/dist/commands/db-sign.d.mts.map +1 -0
  27. package/dist/commands/db-sign.mjs +135 -0
  28. package/dist/commands/db-sign.mjs.map +1 -0
  29. package/dist/commands/db-update.d.mts +7 -0
  30. package/dist/commands/db-update.d.mts.map +1 -0
  31. package/dist/commands/db-update.mjs +121 -0
  32. package/dist/commands/db-update.mjs.map +1 -0
  33. package/dist/commands/db-verify.d.mts +7 -0
  34. package/dist/commands/db-verify.d.mts.map +1 -0
  35. package/dist/commands/db-verify.mjs +321 -0
  36. package/dist/commands/db-verify.mjs.map +1 -0
  37. package/dist/commands/migration-apply.d.mts +36 -0
  38. package/dist/commands/migration-apply.d.mts.map +1 -0
  39. package/dist/commands/migration-apply.mjs +243 -0
  40. package/dist/commands/migration-apply.mjs.map +1 -0
  41. package/dist/commands/migration-new.d.mts +8 -0
  42. package/dist/commands/migration-new.d.mts.map +1 -0
  43. package/dist/commands/migration-new.mjs +151 -0
  44. package/dist/commands/migration-new.mjs.map +1 -0
  45. package/dist/commands/migration-plan.d.mts +47 -0
  46. package/dist/commands/migration-plan.d.mts.map +1 -0
  47. package/dist/commands/migration-plan.mjs +312 -0
  48. package/dist/commands/migration-plan.mjs.map +1 -0
  49. package/dist/commands/migration-ref.d.mts +43 -0
  50. package/dist/commands/migration-ref.d.mts.map +1 -0
  51. package/dist/commands/migration-ref.mjs +194 -0
  52. package/dist/commands/migration-ref.mjs.map +1 -0
  53. package/dist/commands/migration-show.d.mts +28 -0
  54. package/dist/commands/migration-show.d.mts.map +1 -0
  55. package/dist/commands/migration-show.mjs +139 -0
  56. package/dist/commands/migration-show.mjs.map +1 -0
  57. package/dist/commands/migration-status.d.mts +86 -0
  58. package/dist/commands/migration-status.d.mts.map +1 -0
  59. package/dist/commands/migration-status.mjs +4 -0
  60. package/dist/commands/migration-verify.d.mts +16 -0
  61. package/dist/commands/migration-verify.d.mts.map +1 -0
  62. package/dist/commands/migration-verify.mjs +109 -0
  63. package/dist/commands/migration-verify.mjs.map +1 -0
  64. package/dist/config-loader-C4VXKl8f.mjs +43 -0
  65. package/dist/config-loader-C4VXKl8f.mjs.map +1 -0
  66. package/dist/{config-loader.d.ts → config-loader.d.mts} +8 -3
  67. package/dist/config-loader.d.mts.map +1 -0
  68. package/dist/config-loader.mjs +3 -0
  69. package/dist/contract-emit-Bk_eEDKu.mjs +187 -0
  70. package/dist/contract-emit-Bk_eEDKu.mjs.map +1 -0
  71. package/dist/contract-infer-suMDmFSG.mjs +89 -0
  72. package/dist/contract-infer-suMDmFSG.mjs.map +1 -0
  73. package/dist/exports/config-types.d.mts +2 -0
  74. package/dist/exports/config-types.mjs +3 -0
  75. package/dist/exports/control-api.d.mts +624 -0
  76. package/dist/exports/control-api.d.mts.map +1 -0
  77. package/dist/exports/control-api.mjs +109 -0
  78. package/dist/exports/control-api.mjs.map +1 -0
  79. package/dist/{load-ts-contract.d.ts → exports/index.d.mts} +12 -7
  80. package/dist/exports/index.d.mts.map +1 -0
  81. package/dist/exports/index.mjs +137 -0
  82. package/dist/exports/index.mjs.map +1 -0
  83. package/dist/extract-operation-statements-BVlb3jxp.mjs +13 -0
  84. package/dist/extract-operation-statements-BVlb3jxp.mjs.map +1 -0
  85. package/dist/extract-sql-ddl-6EVSOThm.mjs +26 -0
  86. package/dist/extract-sql-ddl-6EVSOThm.mjs.map +1 -0
  87. package/dist/framework-components-BAsliT4V.mjs +59 -0
  88. package/dist/framework-components-BAsliT4V.mjs.map +1 -0
  89. package/dist/inspect-live-schema-HMutsJYh.mjs +91 -0
  90. package/dist/inspect-live-schema-HMutsJYh.mjs.map +1 -0
  91. package/dist/migration-command-scaffold-Dg7CKKCg.mjs +105 -0
  92. package/dist/migration-command-scaffold-Dg7CKKCg.mjs.map +1 -0
  93. package/dist/migration-status-BqfVmC0w.mjs +1582 -0
  94. package/dist/migration-status-BqfVmC0w.mjs.map +1 -0
  95. package/dist/migrations-Bv8oeiY_.mjs +173 -0
  96. package/dist/migrations-Bv8oeiY_.mjs.map +1 -0
  97. package/dist/progress-adapter-D4x8SbJa.mjs +43 -0
  98. package/dist/progress-adapter-D4x8SbJa.mjs.map +1 -0
  99. package/dist/terminal-ui-N5tR-ob5.mjs +967 -0
  100. package/dist/terminal-ui-N5tR-ob5.mjs.map +1 -0
  101. package/dist/verify-WARh5TjK.mjs +385 -0
  102. package/dist/verify-WARh5TjK.mjs.map +1 -0
  103. package/package.json +88 -42
  104. package/src/cli.ts +113 -58
  105. package/src/commands/contract-emit.ts +237 -144
  106. package/src/commands/contract-infer-paths.ts +32 -0
  107. package/src/commands/contract-infer.ts +143 -0
  108. package/src/commands/db-init.ts +97 -219
  109. package/src/commands/db-schema.ts +77 -0
  110. package/src/commands/db-sign.ts +208 -229
  111. package/src/commands/db-update.ts +236 -0
  112. package/src/commands/db-verify.ts +504 -184
  113. package/src/commands/inspect-live-schema.ts +170 -0
  114. package/src/commands/migration-apply.ts +427 -0
  115. package/src/commands/migration-new.ts +260 -0
  116. package/src/commands/migration-plan.ts +519 -0
  117. package/src/commands/migration-ref.ts +305 -0
  118. package/src/commands/migration-show.ts +246 -0
  119. package/src/commands/migration-status.ts +864 -0
  120. package/src/commands/migration-verify.ts +180 -0
  121. package/src/config-loader.ts +13 -3
  122. package/src/control-api/client.ts +424 -72
  123. package/src/control-api/contract-enrichment.ts +119 -0
  124. package/src/control-api/errors.ts +9 -0
  125. package/src/control-api/operations/contract-emit.ts +174 -0
  126. package/src/control-api/operations/db-init.ts +53 -49
  127. package/src/control-api/operations/db-update.ts +220 -0
  128. package/src/control-api/operations/extract-operation-statements.ts +14 -0
  129. package/src/control-api/operations/extract-sql-ddl.ts +47 -0
  130. package/src/control-api/operations/migration-apply.ts +191 -0
  131. package/src/control-api/operations/migration-helpers.ts +49 -0
  132. package/src/control-api/types.ts +388 -18
  133. package/src/exports/config-types.ts +4 -3
  134. package/src/exports/control-api.ts +21 -2
  135. package/src/load-ts-contract.ts +30 -19
  136. package/src/utils/cli-errors.ts +14 -8
  137. package/src/utils/command-helpers.ts +302 -3
  138. package/src/utils/formatters/emit.ts +67 -0
  139. package/src/utils/formatters/errors.ts +82 -0
  140. package/src/utils/formatters/graph-migration-mapper.ts +240 -0
  141. package/src/utils/formatters/graph-render.ts +1323 -0
  142. package/src/utils/formatters/graph-types.ts +120 -0
  143. package/src/utils/formatters/help.ts +380 -0
  144. package/src/utils/formatters/helpers.ts +28 -0
  145. package/src/utils/formatters/migrations.ts +346 -0
  146. package/src/utils/formatters/styled.ts +212 -0
  147. package/src/utils/formatters/verify.ts +621 -0
  148. package/src/utils/framework-components.ts +13 -10
  149. package/src/utils/global-flags.ts +41 -23
  150. package/src/utils/migration-command-scaffold.ts +184 -0
  151. package/src/utils/migration-types.ts +12 -0
  152. package/src/utils/progress-adapter.ts +18 -29
  153. package/src/utils/result-handler.ts +12 -13
  154. package/src/utils/shutdown.ts +92 -0
  155. package/src/utils/suggest-command.ts +31 -0
  156. package/src/utils/terminal-ui.ts +276 -0
  157. package/dist/chunk-5MPKZYVI.js +0 -47
  158. package/dist/chunk-5MPKZYVI.js.map +0 -1
  159. package/dist/chunk-6EPKRATC.js +0 -91
  160. package/dist/chunk-6EPKRATC.js.map +0 -1
  161. package/dist/chunk-74IELXRA.js +0 -371
  162. package/dist/chunk-74IELXRA.js.map +0 -1
  163. package/dist/chunk-HWYQOCAJ.js +0 -47
  164. package/dist/chunk-HWYQOCAJ.js.map +0 -1
  165. package/dist/chunk-U6QI3AZ3.js +0 -133
  166. package/dist/chunk-U6QI3AZ3.js.map +0 -1
  167. package/dist/chunk-VI2YETW7.js +0 -38
  168. package/dist/chunk-VI2YETW7.js.map +0 -1
  169. package/dist/chunk-ZG5T6OB5.js +0 -923
  170. package/dist/chunk-ZG5T6OB5.js.map +0 -1
  171. package/dist/cli.d.ts +0 -2
  172. package/dist/cli.d.ts.map +0 -1
  173. package/dist/cli.js.map +0 -1
  174. package/dist/commands/contract-emit.d.ts +0 -3
  175. package/dist/commands/contract-emit.d.ts.map +0 -1
  176. package/dist/commands/contract-emit.js +0 -11
  177. package/dist/commands/contract-emit.js.map +0 -1
  178. package/dist/commands/db-init.d.ts +0 -3
  179. package/dist/commands/db-init.d.ts.map +0 -1
  180. package/dist/commands/db-init.js +0 -302
  181. package/dist/commands/db-init.js.map +0 -1
  182. package/dist/commands/db-introspect.d.ts +0 -3
  183. package/dist/commands/db-introspect.d.ts.map +0 -1
  184. package/dist/commands/db-introspect.js +0 -185
  185. package/dist/commands/db-introspect.js.map +0 -1
  186. package/dist/commands/db-schema-verify.d.ts +0 -3
  187. package/dist/commands/db-schema-verify.d.ts.map +0 -1
  188. package/dist/commands/db-schema-verify.js +0 -163
  189. package/dist/commands/db-schema-verify.js.map +0 -1
  190. package/dist/commands/db-sign.d.ts +0 -3
  191. package/dist/commands/db-sign.d.ts.map +0 -1
  192. package/dist/commands/db-sign.js +0 -198
  193. package/dist/commands/db-sign.js.map +0 -1
  194. package/dist/commands/db-verify.d.ts +0 -3
  195. package/dist/commands/db-verify.d.ts.map +0 -1
  196. package/dist/commands/db-verify.js +0 -172
  197. package/dist/commands/db-verify.js.map +0 -1
  198. package/dist/config-loader.d.ts.map +0 -1
  199. package/dist/config-loader.js +0 -7
  200. package/dist/config-loader.js.map +0 -1
  201. package/dist/control-api/client.d.ts +0 -13
  202. package/dist/control-api/client.d.ts.map +0 -1
  203. package/dist/control-api/operations/db-init.d.ts +0 -29
  204. package/dist/control-api/operations/db-init.d.ts.map +0 -1
  205. package/dist/control-api/types.d.ts +0 -256
  206. package/dist/control-api/types.d.ts.map +0 -1
  207. package/dist/exports/config-types.d.ts +0 -3
  208. package/dist/exports/config-types.d.ts.map +0 -1
  209. package/dist/exports/config-types.js +0 -6
  210. package/dist/exports/config-types.js.map +0 -1
  211. package/dist/exports/control-api.d.ts +0 -13
  212. package/dist/exports/control-api.d.ts.map +0 -1
  213. package/dist/exports/control-api.js +0 -9
  214. package/dist/exports/control-api.js.map +0 -1
  215. package/dist/exports/index.d.ts +0 -4
  216. package/dist/exports/index.d.ts.map +0 -1
  217. package/dist/exports/index.js +0 -177
  218. package/dist/exports/index.js.map +0 -1
  219. package/dist/load-ts-contract.d.ts.map +0 -1
  220. package/dist/utils/action.d.ts +0 -16
  221. package/dist/utils/action.d.ts.map +0 -1
  222. package/dist/utils/cli-errors.d.ts +0 -7
  223. package/dist/utils/cli-errors.d.ts.map +0 -1
  224. package/dist/utils/command-helpers.d.ts +0 -12
  225. package/dist/utils/command-helpers.d.ts.map +0 -1
  226. package/dist/utils/framework-components.d.ts +0 -70
  227. package/dist/utils/framework-components.d.ts.map +0 -1
  228. package/dist/utils/global-flags.d.ts +0 -25
  229. package/dist/utils/global-flags.d.ts.map +0 -1
  230. package/dist/utils/output.d.ts +0 -142
  231. package/dist/utils/output.d.ts.map +0 -1
  232. package/dist/utils/progress-adapter.d.ts +0 -26
  233. package/dist/utils/progress-adapter.d.ts.map +0 -1
  234. package/dist/utils/result-handler.d.ts +0 -15
  235. package/dist/utils/result-handler.d.ts.map +0 -1
  236. package/dist/utils/spinner.d.ts +0 -29
  237. package/dist/utils/spinner.d.ts.map +0 -1
  238. package/src/commands/db-introspect.ts +0 -254
  239. package/src/commands/db-schema-verify.ts +0 -231
  240. package/src/utils/action.ts +0 -43
  241. package/src/utils/output.ts +0 -1471
  242. package/src/utils/spinner.ts +0 -67
@@ -0,0 +1,240 @@
1
+ /**
2
+ * Maps MigrationGraph + status info to the generic graph renderer types.
3
+ */
4
+ import { EMPTY_CONTRACT_HASH } from '@prisma-next/migration-tools/constants';
5
+ import { findPath } from '@prisma-next/migration-tools/dag';
6
+ import type { MigrationGraph } from '@prisma-next/migration-tools/types';
7
+ import { ifDefined } from '@prisma-next/utils/defined';
8
+
9
+ import type { StatusRef } from '../migration-types';
10
+ import {
11
+ type GraphEdge,
12
+ type GraphNode,
13
+ type GraphRenderOptions,
14
+ type NodeMarker,
15
+ RenderGraph,
16
+ } from './graph-types';
17
+
18
+ export type EdgeStatusKind = 'applied' | 'pending' | 'unreachable';
19
+
20
+ const STATUS_ICON: Record<EdgeStatusKind, string> = {
21
+ applied: ' ✓',
22
+ pending: ' ⧗',
23
+ unreachable: ' ✗',
24
+ };
25
+
26
+ /** Shorten a contract hash for display: strip sha256: prefix, take 7 chars. */
27
+ function shortHash(hash: string): string {
28
+ const stripped = hash.startsWith('sha256:') ? hash.slice(7) : hash;
29
+ return stripped.slice(0, 7);
30
+ }
31
+
32
+ function toShortId(hash: string): string {
33
+ return hash === EMPTY_CONTRACT_HASH ? '∅' : shortHash(hash);
34
+ }
35
+
36
+ /** Minimal per-edge status from the CLI's status result. */
37
+ export interface EdgeStatus {
38
+ readonly dirName: string;
39
+ readonly status: EdgeStatusKind;
40
+ }
41
+
42
+ export interface DraftEdge {
43
+ readonly from: string;
44
+ readonly to: string;
45
+ readonly dirName: string;
46
+ }
47
+
48
+ export interface MigrationGraphInput {
49
+ readonly graph: MigrationGraph;
50
+ readonly mode: 'online' | 'offline';
51
+ readonly markerHash?: string | undefined;
52
+ readonly contractHash: string;
53
+ readonly refs?: readonly StatusRef[] | undefined;
54
+ readonly activeRefHash?: string | undefined;
55
+ readonly activeRefName?: string | undefined;
56
+ /**
57
+ * Per-edge applied/pending status from the ledger. When provided, status
58
+ * icons (✓/⧗) are baked into edge labels. Undefined in offline mode.
59
+ */
60
+ readonly edgeStatuses?: readonly EdgeStatus[] | undefined;
61
+ /** Draft migrations to render as dashed edges. */
62
+ readonly draftEdges?: readonly DraftEdge[] | undefined;
63
+ }
64
+
65
+ export interface MigrationRenderInput {
66
+ readonly graph: RenderGraph;
67
+ readonly options: GraphRenderOptions;
68
+ /** All relevant paths (root→contract, root→marker, root→ref). */
69
+ readonly relevantPaths: readonly (readonly string[])[];
70
+ }
71
+
72
+ /**
73
+ * Convert a MigrationGraph + status info into the generic graph renderer types.
74
+ */
75
+ export function migrationGraphToRenderInput(input: MigrationGraphInput): MigrationRenderInput {
76
+ const { graph, mode, markerHash, contractHash, refs, activeRefHash, edgeStatuses } = input;
77
+
78
+ const statusByDirName = new Map(edgeStatuses?.map((e) => [e.dirName, e.status]));
79
+
80
+ // Build nodes
81
+ const nodeList: GraphNode[] = [];
82
+ for (const nodeId of graph.nodes) {
83
+ const markers: NodeMarker[] = [];
84
+
85
+ // DB marker
86
+ if (mode === 'online' && markerHash === nodeId) {
87
+ markers.push({ kind: 'db' });
88
+ }
89
+
90
+ // Ref markers
91
+ if (refs) {
92
+ for (const ref of refs) {
93
+ if (ref.hash === nodeId) {
94
+ markers.push({ kind: 'ref', name: ref.name, active: ref.active });
95
+ }
96
+ }
97
+ }
98
+
99
+ // Contract marker
100
+ if (contractHash === nodeId && contractHash !== EMPTY_CONTRACT_HASH) {
101
+ markers.push({ kind: 'contract', planned: true });
102
+ }
103
+
104
+ nodeList.push({
105
+ id: toShortId(nodeId),
106
+ markers: markers.length > 0 ? markers : undefined,
107
+ });
108
+ }
109
+
110
+ // Build edges
111
+ const edgeList: GraphEdge[] = [];
112
+
113
+ for (const [, entries] of graph.forwardChain) {
114
+ for (const entry of entries) {
115
+ const status = statusByDirName.get(entry.dirName);
116
+ const icon = status ? STATUS_ICON[status] : '';
117
+ const label = `${entry.dirName}${icon}`;
118
+
119
+ edgeList.push({
120
+ from: toShortId(entry.from),
121
+ to: toShortId(entry.to),
122
+ label,
123
+ ...ifDefined('colorHint', status),
124
+ });
125
+ }
126
+ }
127
+
128
+ // Compute paths to all interesting targets so the default view shows the
129
+ // minimal subgraph that covers everything relevant: contract, DB marker, ref.
130
+ const relevantPaths: string[][] = [];
131
+ const rootId = EMPTY_CONTRACT_HASH;
132
+
133
+ function addPathFromRoot(targetHash: string): void {
134
+ if (!graph.nodes.has(targetHash)) return;
135
+ const raw = findPath(graph, rootId, targetHash);
136
+ if (raw && raw.length > 0) {
137
+ relevantPaths.push([toShortId(rootId), ...raw.map((e) => toShortId(e.to))]);
138
+ }
139
+ }
140
+
141
+ function addPathBetween(fromHash: string, toHash: string): void {
142
+ /* v8 ignore next -- @preserve */
143
+ if (!graph.nodes.has(fromHash) || !graph.nodes.has(toHash)) return;
144
+ const raw = findPath(graph, fromHash, toHash);
145
+ if (raw && raw.length > 0) {
146
+ relevantPaths.push([toShortId(fromHash), ...raw.map((e) => toShortId(e.to))]);
147
+ }
148
+ }
149
+
150
+ // 1. Path to the DB marker
151
+ if (mode === 'online' && markerHash) {
152
+ addPathFromRoot(markerHash);
153
+ }
154
+
155
+ // 2. Path to the ref
156
+ if (activeRefHash && activeRefHash !== markerHash) {
157
+ addPathFromRoot(activeRefHash);
158
+ }
159
+
160
+ // 3. Path(s) to the contract — prefer continuing from marker and/or ref
161
+ // rather than an independent root→contract (which BFS may route through
162
+ // an unrelated branch). When both marker and ref exist, try both paths
163
+ // so that the diamond (two branches converging at the contract) is visible.
164
+ if (contractHash !== EMPTY_CONTRACT_HASH) {
165
+ let contractReached = false;
166
+
167
+ if (markerHash && markerHash !== contractHash) {
168
+ const markerReaches = findPath(graph, markerHash, contractHash);
169
+ if (markerReaches) {
170
+ addPathBetween(markerHash, contractHash);
171
+ contractReached = true;
172
+ }
173
+ }
174
+
175
+ if (activeRefHash && activeRefHash !== markerHash && activeRefHash !== contractHash) {
176
+ const refReaches = findPath(graph, activeRefHash, contractHash);
177
+ if (refReaches) {
178
+ addPathBetween(activeRefHash, contractHash);
179
+ contractReached = true;
180
+ }
181
+ }
182
+
183
+ if (!contractReached && contractHash !== (markerHash ?? activeRefHash)) {
184
+ addPathFromRoot(contractHash);
185
+ }
186
+ }
187
+
188
+ // Fall back: if no paths were found, try the tip of the forward chain.
189
+ if (relevantPaths.length === 0) {
190
+ const lastEdge = [...graph.forwardChain.values()].flat().pop();
191
+ const fallbackHash = lastEdge?.to ?? EMPTY_CONTRACT_HASH;
192
+ addPathFromRoot(fallbackHash);
193
+ }
194
+
195
+ // Spine target for rendering (edge coloring, detached node alignment).
196
+ let spineTargetHash: string;
197
+
198
+ if (activeRefHash && graph.nodes.has(activeRefHash)) {
199
+ spineTargetHash = activeRefHash;
200
+ } else if (contractHash !== EMPTY_CONTRACT_HASH && graph.nodes.has(contractHash)) {
201
+ spineTargetHash = contractHash;
202
+ } else {
203
+ const lastEdge = [...graph.forwardChain.values()].flat().pop();
204
+ spineTargetHash = lastEdge?.to ?? EMPTY_CONTRACT_HASH;
205
+ }
206
+
207
+ // Contract not in attested graph — connect from spine target with a dashed edge
208
+ if (contractHash !== EMPTY_CONTRACT_HASH && !graph.nodes.has(contractHash)) {
209
+ const contractMarkers: NodeMarker[] = [];
210
+ if (mode === 'online' && markerHash === contractHash) {
211
+ contractMarkers.push({ kind: 'db' });
212
+ }
213
+ contractMarkers.push({ kind: 'contract', planned: false });
214
+ nodeList.push({
215
+ id: shortHash(contractHash),
216
+ markers: contractMarkers,
217
+ });
218
+
219
+ const matchingDraft = input.draftEdges?.find((d) => d.to === contractHash);
220
+ const fromHash = matchingDraft?.from ?? spineTargetHash;
221
+ if (graph.nodes.has(fromHash) || fromHash === spineTargetHash) {
222
+ edgeList.push({
223
+ from: toShortId(fromHash),
224
+ to: shortHash(contractHash),
225
+ ...ifDefined('label', matchingDraft ? `${matchingDraft.dirName} [draft]` : undefined),
226
+ style: 'dashed',
227
+ });
228
+ }
229
+ }
230
+
231
+ return {
232
+ graph: new RenderGraph(nodeList, edgeList),
233
+ options: {
234
+ spineTarget: toShortId(spineTargetHash),
235
+ rootId: '∅',
236
+ colorize: true,
237
+ },
238
+ relevantPaths,
239
+ };
240
+ }