@buun_group/plotwork-mcp 0.1.0-beta.4 → 0.1.0-beta.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.
package/plotwork-mcp.mjs CHANGED
@@ -51,7 +51,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
51
51
  var package_default;
52
52
  var init_package = __esm({
53
53
  "package.json"() {
54
- package_default = { version: "0.1.0-beta.4" };
54
+ package_default = { version: "0.1.0-beta.5" };
55
55
  }
56
56
  });
57
57
 
@@ -273,6 +273,21 @@ var init_overlays = __esm({
273
273
  }
274
274
  });
275
275
 
276
+ // ../../packages/diagrams/src/constants/node-change.ts
277
+ var NODE_CHANGES, NODE_CHANGE_SPECS;
278
+ var init_node_change = __esm({
279
+ "../../packages/diagrams/src/constants/node-change.ts"() {
280
+ "use strict";
281
+ NODE_CHANGES = ["create", "update", "replace", "destroy"];
282
+ NODE_CHANGE_SPECS = {
283
+ create: { tone: "green", sign: "+", meaning: "made by the change" },
284
+ update: { tone: "amber", sign: "~", meaning: "changed in place" },
285
+ replace: { tone: "orange", sign: "\xB1", meaning: "destroyed and made again" },
286
+ destroy: { tone: "red", sign: "\u2212", meaning: "destroyed by the change" }
287
+ };
288
+ }
289
+ });
290
+
276
291
  // ../../packages/diagrams/src/constants/node-stack.ts
277
292
  var STACK_LIMIT;
278
293
  var init_node_stack = __esm({
@@ -628,12 +643,30 @@ var init_view_links = __esm({
628
643
  };
629
644
  CLI_RELEASE = {
630
645
  packageName: "@buun_group/plotwork",
631
- version: "0.1.0-beta.2",
646
+ version: "0.1.0-beta.6",
632
647
  onNpm: true
633
648
  };
634
649
  }
635
650
  });
636
651
 
652
+ // ../../packages/diagrams/src/constants/mcp-release.ts
653
+ function mcpPackagePin(release = MCP_RELEASE) {
654
+ return `${release.packageName}@${release.version}`;
655
+ }
656
+ function mcpCommand(release = MCP_RELEASE) {
657
+ return `npx -y ${mcpPackagePin(release)}`;
658
+ }
659
+ var MCP_RELEASE;
660
+ var init_mcp_release = __esm({
661
+ "../../packages/diagrams/src/constants/mcp-release.ts"() {
662
+ "use strict";
663
+ MCP_RELEASE = {
664
+ packageName: "@buun_group/plotwork-mcp",
665
+ version: "0.1.0-beta.4"
666
+ };
667
+ }
668
+ });
669
+
637
670
  // ../../packages/diagrams/src/constants/layout-limits.ts
638
671
  var LAYOUT_LIMITS;
639
672
  var init_layout_limits = __esm({
@@ -736,6 +769,8 @@ var init_generate = __esm({
736
769
  maxOverrideEntries: 500,
737
770
  /** The address of the JSON Schema of an overrides file, for editors; the docs app serves it, and Plotwork never fetches it. */
738
771
  overridesSchemaUrl: "https://docs.plotwork.dev/schemas/plotwork.overrides.json",
772
+ /** The address of the JSON Schema of the report `generate --format json` and the Action's `report-file` write; the docs app serves it. */
773
+ reportSchemaUrl: "https://docs.plotwork.dev/schemas/plotwork.report.json",
739
774
  /** The first words of the comment a generated diagram starts with, by which it is told apart from a hand-written one. */
740
775
  banner: "# Generated by plotwork generate",
741
776
  /** The trailer of a commit the GitHub Action writes, by which its next run knows the push was its own and stops a loop. */
@@ -3515,6 +3550,7 @@ var init_constants = __esm({
3515
3550
  init_flow_node_types();
3516
3551
  init_group_types();
3517
3552
  init_overlays();
3553
+ init_node_change();
3518
3554
  init_node_stack();
3519
3555
  init_line_options();
3520
3556
  init_line_roles();
@@ -3525,6 +3561,7 @@ var init_constants = __esm({
3525
3561
  init_editing();
3526
3562
  init_diagram_links();
3527
3563
  init_view_links();
3564
+ init_mcp_release();
3528
3565
  init_layout_limits();
3529
3566
  init_lint_limits();
3530
3567
  init_style_rules();
@@ -4022,20 +4059,20 @@ function customIconNamedBy(text3) {
4022
4059
  if (index2 === null) return null;
4023
4060
  const phrase2 = normalizePhrase(text3);
4024
4061
  if (phrase2 === "") return null;
4025
- const hits = [...index2.phrases].filter(([, names7]) => names7.has(phrase2)).map(([name2]) => name2);
4062
+ const hits = [...index2.phrases].filter(([, names8]) => names8.has(phrase2)).map(([name2]) => name2);
4026
4063
  return hits.length === 1 ? `${ORG_ICON_SET}:${hits[0]}` : null;
4027
4064
  }
4028
4065
  function scoreCustomIcons(phrase2, words2, scores2) {
4029
4066
  const index2 = activeIndex();
4030
4067
  if (index2 === null || words2.length === 0) return [];
4031
4068
  const found = [];
4032
- for (const [name2, names7] of index2.phrases) {
4069
+ for (const [name2, names8] of index2.phrases) {
4033
4070
  const ref = `${ORG_ICON_SET}:${name2}`;
4034
- if (names7.has(phrase2)) {
4071
+ if (names8.has(phrase2)) {
4035
4072
  found.push({ ref, score: scores2.exact });
4036
4073
  continue;
4037
4074
  }
4038
- const all = [...names7];
4075
+ const all = [...names8];
4039
4076
  if (words2.length > 1 && all.some((candidate2) => ` ${candidate2} `.includes(` ${phrase2} `))) {
4040
4077
  found.push({ ref, score: scores2.phrase });
4041
4078
  continue;
@@ -6733,8 +6770,8 @@ var init_search_scores = __esm({
6733
6770
  // ../../packages/diagrams/src/icons/search.ts
6734
6771
  function buildConceptEntries() {
6735
6772
  const entries2 = /* @__PURE__ */ new Map();
6736
- for (const [phrase2, names7] of Object.entries(ICON_CONCEPTS)) {
6737
- names7.forEach((name2, position) => {
6773
+ for (const [phrase2, names8] of Object.entries(ICON_CONCEPTS)) {
6774
+ names8.forEach((name2, position) => {
6738
6775
  const existing = entries2.get(name2);
6739
6776
  entries2.set(name2, {
6740
6777
  words: [...existing?.words ?? [], ...phrase2.split(/\s+/)],
@@ -101544,6 +101581,14 @@ var init_metrics = __esm({
101544
101581
  stackGap: 6,
101545
101582
  stackTop: 8,
101546
101583
  borderWidth: 1,
101584
+ /** A node with `change=`: its outline in the change's tone, this wide, and a round badge on its top edge with the change's sign. */
101585
+ changeBorderWidth: 2,
101586
+ changeBadgeRadius: 8,
101587
+ /** From the card's right edge to the badge's centre; the badge sits in the top padding, so it never covers text. */
101588
+ changeBadgeInset: 18,
101589
+ /** Half the length of each stroke of the sign in the badge. */
101590
+ changeSignHalf: 4,
101591
+ changeSignWidth: 1.75,
101547
101592
  maxLabelLines: 3,
101548
101593
  /** Pills, used for terminal nodes such as "Done" or "Access denied". */
101549
101594
  pillPaddingX: 22,
@@ -104817,9 +104862,9 @@ function providerSetFor(guess) {
104817
104862
  return CLOUD_SETS.find((set2) => set2 === lowered || CLOUD_PROVIDER_SPECS[set2].misspellings.includes(lowered));
104818
104863
  }
104819
104864
  function nearestIcon(set2, name2) {
104820
- const names7 = listSetNames(set2);
104821
- const handWritten = names7.filter((candidate2) => findIcon(`${set2}:${candidate2}`)?.vendor === void 0);
104822
- const spelled = suggest(name2, handWritten) ?? suggest(name2, names7, VENDOR_SPELLING_DISTANCE);
104865
+ const names8 = listSetNames(set2);
104866
+ const handWritten = names8.filter((candidate2) => findIcon(`${set2}:${candidate2}`)?.vendor === void 0);
104867
+ const spelled = suggest(name2, handWritten) ?? suggest(name2, names8, VENDOR_SPELLING_DISTANCE);
104823
104868
  if (spelled !== null) return { ref: `${set2}:${spelled}`, isSpelling: true };
104824
104869
  const found = searchIcons(name2.replace(/-/g, " "), 3);
104825
104870
  const best = found.find((ref) => ref.startsWith(`${set2}:`)) ?? found[0];
@@ -104842,11 +104887,11 @@ function orgIconHint(name2) {
104842
104887
  if (!hasCustomIcons()) {
104843
104888
  return `org: icons are an organisation's own icons. They draw only on the hosted service, for a caller in an organisation that uploaded them; the local package has none. ${FIND_HINT}`;
104844
104889
  }
104845
- const names7 = listCustomIconNames();
104846
- const spelled = suggest(name2, names7);
104890
+ const names8 = listCustomIconNames();
104891
+ const spelled = suggest(name2, names8);
104847
104892
  if (spelled !== null) return `Did you mean "${ORG_ICON_SET}:${spelled}"?`;
104848
- const shown = names7.slice(0, ORG_NAMES_IN_HINT).map((candidate2) => `${ORG_ICON_SET}:${candidate2}`);
104849
- const more = names7.length > shown.length ? ` and ${names7.length - shown.length} more` : "";
104893
+ const shown = names8.slice(0, ORG_NAMES_IN_HINT).map((candidate2) => `${ORG_ICON_SET}:${candidate2}`);
104894
+ const more = names8.length > shown.length ? ` and ${names8.length - shown.length} more` : "";
104850
104895
  return `Your organisation has no icon named "${name2}". Its icons: ${shown.join(", ")}${more}. ${FIND_HINT}`;
104851
104896
  }
104852
104897
  function iconHint(value) {
@@ -105258,13 +105303,13 @@ function parseRelationship(cursor, state, line3) {
105258
105303
  function resolveRelationships(state) {
105259
105304
  const elementIds = new Set(state.elements.map((element) => element.id));
105260
105305
  const boundaryIds = new Set(state.boundaries.map((boundary) => boundary.id));
105261
- const names7 = [...elementIds];
105306
+ const names8 = [...elementIds];
105262
105307
  const resolved = [];
105263
105308
  let suggested = 0;
105264
105309
  for (const pending of state.pending) {
105265
105310
  const missing = [pending.from, pending.to].filter((end) => !elementIds.has(end.text));
105266
105311
  for (const end of missing) {
105267
- const guess = suggested < SUGGESTIONS ? `${didYouMean(end.text, names7)} ` : "";
105312
+ const guess = suggested < SUGGESTIONS ? `${didYouMean(end.text, names8)} ` : "";
105268
105313
  suggested += 1;
105269
105314
  const message2 = boundaryIds.has(end.text) ? `"${end.text}" is a boundary, and a relationship joins elements` : `Unknown element "${end.text}"`;
105270
105315
  state.report.push(errorAt(DIAGNOSTIC_CODES.unknownNode, message2, spanOf2(end), `${guess}Declare it first with: container ${end.text} "Name"`));
@@ -106746,9 +106791,9 @@ function runsAlongside(moved3, others, axis) {
106746
106791
  if (!isRun && !isBar) continue;
106747
106792
  const own2 = isRun ? [axis.along(a), axis.along(b)] : [axis.cross(a), axis.cross(b)];
106748
106793
  const theirs = isRun ? [axis.along(c), axis.along(d)] : [axis.cross(c), axis.cross(d)];
106749
- const overlaps7 = Math.min(...own2) < Math.max(...theirs) - 2 && Math.max(...own2) > Math.min(...theirs) + 2;
106794
+ const overlaps8 = Math.min(...own2) < Math.max(...theirs) - 2 && Math.max(...own2) > Math.min(...theirs) + 2;
106750
106795
  const gap2 = isRun ? Math.abs(axis.cross(a) - axis.cross(c)) : Math.abs(axis.along(a) - axis.along(c));
106751
- if (overlaps7 && gap2 < PARALLEL_GAP) return true;
106796
+ if (overlaps8 && gap2 < PARALLEL_GAP) return true;
106752
106797
  }
106753
106798
  }
106754
106799
  }
@@ -109454,6 +109499,60 @@ var init_fan_order = __esm({
109454
109499
  }
109455
109500
  });
109456
109501
 
109502
+ // ../../packages/diagrams/src/layout/flow/label-separation.ts
109503
+ function changeBadgeRect(card5) {
109504
+ const r = NODE_METRICS.changeBadgeRadius;
109505
+ return { x: card5.x + card5.width - NODE_METRICS.changeBadgeInset - r, y: card5.y - r, width: 2 * r, height: 2 * r };
109506
+ }
109507
+ function straddles(label, frame) {
109508
+ if (!overlaps3(label, frame, 0)) return false;
109509
+ const inside = label.x >= frame.x && label.y >= frame.y && label.x + label.width <= frame.x + frame.width && label.y + label.height <= frame.y + frame.height;
109510
+ const holds = frame.x >= label.x && frame.y >= label.y && frame.x + frame.width <= label.x + label.width && frame.y + frame.height <= label.y + label.height;
109511
+ return !inside && !holds;
109512
+ }
109513
+ function placesOn(points, rect, from) {
109514
+ const out = [];
109515
+ for (let index2 = 1; index2 < points.length; index2 += 1) {
109516
+ const a = points[index2 - 1];
109517
+ const b = points[index2];
109518
+ const vertical = Math.abs(a.x - b.x) < 1;
109519
+ if (!vertical && Math.abs(a.y - b.y) >= 1) continue;
109520
+ const half = (vertical ? rect.height : rect.width) / 2 + RUN_END_ROOM;
109521
+ const [low, high] = vertical ? [Math.min(a.y, b.y), Math.max(a.y, b.y)] : [Math.min(a.x, b.x), Math.max(a.x, b.x)];
109522
+ for (let at3 = low + half; at3 <= high - half; at3 += STEP) out.push(vertical ? { x: a.x, y: at3 } : { x: at3, y: a.y });
109523
+ }
109524
+ const distance4 = (point) => Math.abs(point.x - from.x) + Math.abs(point.y - from.y);
109525
+ return out.sort((p, q) => distance4(p) - distance4(q) || p.y - q.y || p.x - q.x);
109526
+ }
109527
+ function separateLabels(edges, obstacles) {
109528
+ const settled = [];
109529
+ const clear = (rect, gap2) => !settled.some((other) => overlaps3(rect, other, gap2)) && !obstacles.nodes.some((node3) => overlaps3(rect, node3, gap2)) && !obstacles.tabs.some((tab) => overlaps3(rect, tab, gap2)) && !(obstacles.badges ?? []).some((badge) => overlaps3(rect, badge, gap2)) && !obstacles.frames.some((frame) => straddles(rect, frame));
109530
+ return edges.map((edge) => {
109531
+ if (edge.label === null) return edge;
109532
+ const rect = edge.label.rect;
109533
+ if (clear(rect, 0)) {
109534
+ settled.push(rect);
109535
+ return edge;
109536
+ }
109537
+ const place2 = placesOn(edge.points, rect, centreOf(rect)).map((point) => centredAt(rect, point)).find((candidate2) => clear(candidate2, LABEL_GAP4));
109538
+ settled.push(place2 ?? rect);
109539
+ return place2 === void 0 ? edge : { ...edge, label: { ...edge.label, rect: place2 } };
109540
+ });
109541
+ }
109542
+ var LABEL_GAP4, RUN_END_ROOM, STEP, overlaps3, centreOf, centredAt;
109543
+ var init_label_separation = __esm({
109544
+ "../../packages/diagrams/src/layout/flow/label-separation.ts"() {
109545
+ "use strict";
109546
+ init_theme();
109547
+ LABEL_GAP4 = 4;
109548
+ RUN_END_ROOM = 6;
109549
+ STEP = 4;
109550
+ overlaps3 = (a, b, gap2) => a.x < b.x + b.width + gap2 && b.x < a.x + a.width + gap2 && a.y < b.y + b.height + gap2 && b.y < a.y + a.height + gap2;
109551
+ centreOf = (rect) => ({ x: rect.x + rect.width / 2, y: rect.y + rect.height / 2 });
109552
+ centredAt = (rect, point) => ({ ...rect, x: point.x - rect.width / 2, y: point.y - rect.height / 2 });
109553
+ }
109554
+ });
109555
+
109457
109556
  // ../../packages/diagrams/src/layout/flow/level-edges.ts
109458
109557
  function ancestorsOf(diagram, edge, id) {
109459
109558
  const found = /* @__PURE__ */ new Set();
@@ -109633,14 +109732,14 @@ var init_canvas_room = __esm({
109633
109732
  });
109634
109733
 
109635
109734
  // ../../packages/diagrams/src/layout/flow/overlay-tab.ts
109636
- function overlaps3(a, b) {
109735
+ function overlaps4(a, b) {
109637
109736
  return a.x < b.x + b.width && b.x < a.x + a.width && a.y < b.y + b.height && b.y < a.y + a.height;
109638
109737
  }
109639
109738
  function grown(frame, amount) {
109640
109739
  return { x: frame.x - amount, y: frame.y - amount, width: frame.width + amount * 2, height: frame.height + amount * 2 };
109641
109740
  }
109642
109741
  function freeStretch(frame, size, obstacles, clearance) {
109643
- const blocker = (x2) => obstacles.find((other) => overlaps3({ x: x2, y: frame.y, width: size.width, height: size.height }, grown(other, clearance)));
109742
+ const blocker = (x2) => obstacles.find((other) => overlaps4({ x: x2, y: frame.y, width: size.width, height: size.height }, grown(other, clearance)));
109644
109743
  let x = frame.x;
109645
109744
  for (let found = blocker(x); found !== void 0; found = blocker(x)) {
109646
109745
  x = found.x + found.width + GROUP_METRICS.overlayTabGap;
@@ -109651,7 +109750,7 @@ function freeStretch(frame, size, obstacles, clearance) {
109651
109750
  function grazes(frame, groups) {
109652
109751
  const near3 = (a, b) => Math.abs(a - b) < FRAME_CLEARANCE;
109653
109752
  return groups.some((group2) => {
109654
- if (!overlaps3(frame, group2)) return false;
109753
+ if (!overlaps4(frame, group2)) return false;
109655
109754
  const sides = [frame.x, frame.x + frame.width];
109656
109755
  const groupSides = [group2.x, group2.x + group2.width];
109657
109756
  const tops = [frame.y, frame.y + frame.height];
@@ -109959,6 +110058,10 @@ function placeLevelEdges(diagram, level2, nodes, direction) {
109959
110058
  return placed === null ? [] : [placed];
109960
110059
  });
109961
110060
  }
110061
+ function changeBadges(diagram, nodes) {
110062
+ const changed = new Set(diagram.nodes.filter((node3) => node3.change !== void 0).map((node3) => node3.id));
110063
+ return nodes.filter((node3) => changed.has(node3.id)).map((node3) => changeBadgeRect(node3.rect));
110064
+ }
109962
110065
  async function layoutWith2(diagram, boxes2, direction) {
109963
110066
  const level2 = levelEdgeIds(diagram);
109964
110067
  const laidOut2 = await runElk3(diagram, boxes2, direction, level2);
@@ -109983,7 +110086,8 @@ async function layoutWith2(diagram, boxes2, direction) {
109983
110086
  overlays,
109984
110087
  overlayCovers: spanned.covers,
109985
110088
  // A stretch moved off a tab can land past a sibling edge's stub; that stub then steps past it, so the two do not cross by their node.
109986
- edges: orderStubs(routes.map((edge) => routeAroundTabs2(edge, tabRects, nodeRects)), nodeRects, tabRects)
110089
+ // Last, so no later step moves a label back onto another: two labels never cover each other, a node, a tab, or a frame's border.
110090
+ edges: separateLabels(orderStubs(routes.map((edge) => routeAroundTabs2(edge, tabRects, nodeRects)), nodeRects, tabRects), { nodes: nodeRects, tabs: tabRects, frames: shapes2.groups.map((group2) => group2.rect), badges: changeBadges(diagram, shapes2.nodes) })
109987
110091
  };
109988
110092
  return makeRoomFor(layout, [...spanned.grown, ...layout.edges.flatMap((edge) => edge.label === null ? [] : [edge.label.rect])]);
109989
110093
  }
@@ -110008,6 +110112,7 @@ var init_layout_flow = __esm({
110008
110112
  init_end_room();
110009
110113
  init_elk_graph();
110010
110114
  init_fan_order();
110115
+ init_label_separation();
110011
110116
  init_large_diagram();
110012
110117
  init_level_edges();
110013
110118
  init_level_route();
@@ -110028,7 +110133,8 @@ var init_layout_flow = __esm({
110028
110133
  function nodeLine(node3) {
110029
110134
  const detail = node3.sub === null ? "" : ` (${node3.sub})`;
110030
110135
  const stack = node3.stack.length === 0 ? "" : `, stack: ${markNames(node3.stack)}`;
110031
- return `${node3.label}${detail}, ${node3.type}${stack}`;
110136
+ const change = node3.change === void 0 ? "" : `, change: ${node3.change}`;
110137
+ return `${node3.label}${detail}, ${node3.type}${stack}${change}`;
110032
110138
  }
110033
110139
  function groupLine(group2) {
110034
110140
  const kind = group2.type === null ? "Group" : GROUP_TYPE_SPECS[group2.type].title;
@@ -110327,11 +110433,12 @@ function parseNodeStatement(cursor, state, line3, group2) {
110327
110433
  const labelToken = cursor.peek();
110328
110434
  const label = readLabel(cursor, state, line3, "label");
110329
110435
  const options3 = readOptions(cursor, NODE_OPTIONS, state.report, { lists: ["stack"] });
110330
- rejectTrailing(cursor, state, 'A node is: node id type "Label" sub="..." icon=lucide:name tone=blue stack=simple:angular,simple:typescript');
110436
+ rejectTrailing(cursor, state, 'A node is: node id type "Label" sub="..." icon=lucide:name tone=blue stack=simple:angular,simple:typescript change=update');
110331
110437
  if (id === null || type === void 0 || label === null) return;
110332
110438
  const defaults = FLOW_NODE_TYPE_DEFAULTS[type];
110333
110439
  const sub = findOption(options3, "sub")?.value ?? null;
110334
110440
  const iconOption2 = findOption(options3, "icon");
110441
+ const change = resolveChange(findOption(options3, "change"), state);
110335
110442
  state.nodes.push({
110336
110443
  id: toNodeId(id.text),
110337
110444
  type,
@@ -110341,10 +110448,17 @@ function parseNodeStatement(cursor, state, line3, group2) {
110341
110448
  icon: nodeIcon(iconOption2, type, [label, sub], group2, state),
110342
110449
  hasOwnIcon: iconOption2 !== void 0,
110343
110450
  stack: resolveStack(findOption(options3, "stack"), state, defaults.shape === "card"),
110451
+ ...change === null ? {} : { change },
110344
110452
  group: group2,
110345
110453
  labelAt: spanOf4(labelToken)
110346
110454
  });
110347
110455
  }
110456
+ function resolveChange(option, state) {
110457
+ if (option === void 0) return null;
110458
+ const found = NODE_CHANGES.find((candidate2) => candidate2 === option.value);
110459
+ if (found === void 0) state.report.push(errorAt(DIAGNOSTIC_CODES.badOptionValue, `Unknown change "${option.value}"`, option.valueToken, didYouMean(option.value, NODE_CHANGES)));
110460
+ return found ?? null;
110461
+ }
110348
110462
  function providerAround(group2, state) {
110349
110463
  if (group2 === null) return state.provider;
110350
110464
  return state.groups.find((candidate2) => candidate2.id === group2)?.provider ?? state.provider;
@@ -110453,7 +110567,7 @@ var init_flow_statements = __esm({
110453
110567
  init_statement_helpers();
110454
110568
  init_suggest();
110455
110569
  init_token_cursor();
110456
- NODE_OPTIONS = ["sub", "icon", "tone", "stack"];
110570
+ NODE_OPTIONS = ["sub", "icon", "tone", "stack", "change"];
110457
110571
  MOVED_GROUP_OPTIONS = { boundary: "A trust boundary is now a group type: write type=trust-boundary." };
110458
110572
  EDGE_OPTIONS = ["icon", "role", ...LINE_MOTION_OPTIONS];
110459
110573
  HEADER_OPTIONS2 = ["direction", "desc", "provider", "legend", "icons", ...HEADER_MOTION_OPTIONS];
@@ -110672,7 +110786,7 @@ function runsOf2(edges) {
110672
110786
  }
110673
110787
  return { horizontal, vertical };
110674
110788
  }
110675
- function overlaps4(a, b, margin) {
110789
+ function overlaps5(a, b, margin) {
110676
110790
  return a.x - margin < b.x + b.width && a.x + a.width + margin > b.x && a.y - margin < b.y + b.height && a.y + a.height + margin > b.y;
110677
110791
  }
110678
110792
  function findFlowHops(edges, nodes) {
@@ -110697,7 +110811,7 @@ function findFlowHops(edges, nodes) {
110697
110811
  const key = `${run3.edge}|${run3.y.toFixed(2)}|${x.toFixed(2)}`;
110698
110812
  if (seen.has(key)) continue;
110699
110813
  const arc = { x: x - radius, y: run3.y - radius, width: radius * 2, height: radius };
110700
- if (obstacles.some((obstacle) => overlaps4(arc, obstacle, BREATHING))) continue;
110814
+ if (obstacles.some((obstacle) => overlaps5(arc, obstacle, BREATHING))) continue;
110701
110815
  const isCrowded = vertical.some((side) => side !== other && Math.abs(side.x - x) >= SAME_LINE5 && Math.abs(side.x - x) < radius * 2 + BREATHING && run3.y > side.low && run3.y < side.high);
110702
110816
  if (isCrowded) continue;
110703
110817
  const isTrunk = horizontal.some((side) => side.edge !== run3.edge && Math.abs(side.y - run3.y) < BREATHING && x > side.low && x < side.high);
@@ -110723,13 +110837,36 @@ var init_crossings = __esm({
110723
110837
  // ../../packages/diagrams/src/render/flow/paint-node.ts
110724
110838
  function outlineAttrs(frame, stroke) {
110725
110839
  const defaults = FLOW_NODE_TYPE_DEFAULTS[frame.node.type];
110840
+ const change = frame.node.change;
110726
110841
  return {
110727
- stroke,
110728
- "stroke-width": NODE_METRICS.borderWidth,
110842
+ stroke: change === void 0 ? stroke : frame.theme.tones[NODE_CHANGE_SPECS[change].tone].outline,
110843
+ "stroke-width": change === void 0 ? NODE_METRICS.borderWidth : NODE_METRICS.changeBorderWidth,
110729
110844
  "stroke-dasharray": defaults.isDashed ? "4 3" : null,
110730
110845
  filter: defaults.isDashed ? null : LIFT
110731
110846
  };
110732
110847
  }
110848
+ function signPath(change, x, y) {
110849
+ const h = NODE_METRICS.changeSignHalf;
110850
+ switch (NODE_CHANGE_SPECS[change].sign) {
110851
+ case "+":
110852
+ return `M${x - h} ${y}H${x + h}M${x} ${y - h}V${y + h}`;
110853
+ case "\u2212":
110854
+ return `M${x - h} ${y}H${x + h}`;
110855
+ case "\xB1":
110856
+ return `M${x - h} ${y - 1}H${x + h}M${x} ${y - h - 1}V${y + h - 3}M${x - h} ${y + h}H${x + h}`;
110857
+ case "~":
110858
+ return `M${x - h - 0.5} ${y + 1}q${h / 2 + 0.25} ${-h + 0.5} ${h + 0.5} -1t${h + 0.5} -1`;
110859
+ }
110860
+ }
110861
+ function paintChangeBadge(change, rect, theme) {
110862
+ const badge = changeBadgeRect(rect);
110863
+ const cx = badge.x + badge.width / 2;
110864
+ const fill = theme.tones[NODE_CHANGE_SPECS[change].tone].outline;
110865
+ return el("g", { "data-change": change }, [
110866
+ el("circle", { cx, cy: rect.y, r: NODE_METRICS.changeBadgeRadius, fill, stroke: theme.surface, "stroke-width": NODE_METRICS.borderWidth * 1.5 }),
110867
+ el("path", { d: signPath(change, cx, rect.y), fill: "none", stroke: theme.surface, "stroke-width": NODE_METRICS.changeSignWidth, "stroke-linecap": "round", "stroke-linejoin": "round" })
110868
+ ]);
110869
+ }
110733
110870
  function isTintedCard(node3) {
110734
110871
  const defaults = FLOW_NODE_TYPE_DEFAULTS[node3.type];
110735
110872
  return defaults.isTinted || defaults.icon === null && node3.icon === null && node3.tone !== "neutral";
@@ -110765,6 +110902,7 @@ function paintCard(frame) {
110765
110902
  parts.push(paintTextBlock({ x: x + textLeft, top: subTop, lines: placed.subLines, role: "sub", color: theme.inkSecondary }));
110766
110903
  }
110767
110904
  if (node3.stack.length > 0) parts.push(...paintMarks(node3.stack, x + textLeft, top + textHeight3 + NODE_METRICS.stackTop, theme, theme.tones.neutral.chipFill));
110905
+ if (node3.change !== void 0) parts.push(paintChangeBadge(node3.change, placed.rect, theme));
110768
110906
  return el("g", { "data-node": node3.id, "data-type": node3.type }, parts);
110769
110907
  }
110770
110908
  function paintPill(frame) {
@@ -110782,6 +110920,7 @@ function paintPill(frame) {
110782
110920
  const textX2 = inset2 + NODE_METRICS.pillPaddingX + NODE_METRICS.iconSize + NODE_METRICS.pillIconGap;
110783
110921
  parts.push(paintTextBlock({ x: textX2, top, lines: placed.labelLines, role: "label", color: theme.ink }));
110784
110922
  }
110923
+ if (node3.change !== void 0) parts.push(paintChangeBadge(node3.change, placed.rect, theme));
110785
110924
  return el("g", { "data-node": node3.id, "data-type": node3.type }, parts);
110786
110925
  }
110787
110926
  function paintNode(node3, placed, theme) {
@@ -110798,6 +110937,7 @@ var init_paint_node = __esm({
110798
110937
  init_core();
110799
110938
  init_icons();
110800
110939
  init_theme();
110940
+ init_label_separation();
110801
110941
  init_size_node();
110802
110942
  init_svg2();
110803
110943
  init_paint_marks();
@@ -112457,8 +112597,8 @@ var init_flowchart_statements = __esm({
112457
112597
  function resolve(declaration) {
112458
112598
  const fill = [...declaration.properties].reverse().find((property) => property.name === "fill")?.value ?? null;
112459
112599
  const tone = fill === null ? null : toneForColour(fill);
112460
- const names7 = declaration.properties.map((property) => property.name).filter((name2) => name2 !== "fill");
112461
- const leftOut = [...new Set(names7)];
112600
+ const names8 = declaration.properties.map((property) => property.name).filter((name2) => name2 !== "fill");
112601
+ const leftOut = [...new Set(names8)];
112462
112602
  if (fill !== null && tone === null) leftOut.unshift(`fill ${fill} has no tone`);
112463
112603
  return { tone, fill, leftOut };
112464
112604
  }
@@ -113885,12 +114025,12 @@ function readTick(rest) {
113885
114025
  return { unit: null, note: count3 === 1 ? `a step of one ${name2} is shorter than a day` : `a step of ${count3} ${name2}s has no Plotwork form` };
113886
114026
  }
113887
114027
  function readExcludes(rest, reader, statement, ctx) {
113888
- const names7 = rest.toLowerCase().split(/[\s,]+/).filter((name2) => name2 !== "");
114028
+ const names8 = rest.toLowerCase().split(/[\s,]+/).filter((name2) => name2 !== "");
113889
114029
  const days = [];
113890
114030
  const weekdays = /* @__PURE__ */ new Set();
113891
114031
  const unread = [];
113892
114032
  let weekends = false;
113893
- for (const name2 of names7) {
114033
+ for (const name2 of names8) {
113894
114034
  const day = reader(name2);
113895
114035
  if (name2 === "weekends") weekends = true;
113896
114036
  else if (WEEKDAYS.some((weekday) => weekday === name2)) weekdays.add(name2);
@@ -114607,8 +114747,8 @@ function reportCycles(items2, waiting, report3) {
114607
114747
  const loop = path.slice(path.indexOf(current));
114608
114748
  const closing = loop[loop.length - 1];
114609
114749
  const token = closing.after.find((candidate2) => candidate2.text === current?.idToken.text) ?? closing.idToken;
114610
- const names7 = [...loop, current].map((item) => item.idToken.text).join(" -> ");
114611
- report3.push(errorAt(DIAGNOSTIC_CODES.ganttCycle, `Tasks wait for each other in a circle: ${names7}`, token, "Remove one after= so the chain has a first task that starts on a fixed day."));
114750
+ const names8 = [...loop, current].map((item) => item.idToken.text).join(" -> ");
114751
+ report3.push(errorAt(DIAGNOSTIC_CODES.ganttCycle, `Tasks wait for each other in a circle: ${names8}`, token, "Remove one after= so the chain has a first task that starts on a fixed day."));
114612
114752
  for (const item of path) covered.add(item.idToken.text);
114613
114753
  }
114614
114754
  }
@@ -117366,10 +117506,10 @@ function initialsCandidates(name2) {
117366
117506
  const candidates2 = [upper(lead), capital2, `${capital2}${first.slice(2, 3).join("").toLowerCase()}`, upper(words2.slice(0, 3).map((word2) => word2[0] ?? ""))];
117367
117507
  return candidates2.filter((candidate2, index2) => candidate2 !== "" && candidates2.indexOf(candidate2) === index2);
117368
117508
  }
117369
- function assignInitials(names7) {
117509
+ function assignInitials(names8) {
117370
117510
  const taken = /* @__PURE__ */ new Set();
117371
117511
  const counters = /* @__PURE__ */ new Map();
117372
- return names7.map((name2) => {
117512
+ return names8.map((name2) => {
117373
117513
  const candidates2 = initialsCandidates(name2);
117374
117514
  let chosen = candidates2.find((candidate2) => !taken.has(candidate2));
117375
117515
  const base = candidates2[0] ?? "?";
@@ -117384,10 +117524,10 @@ function assignInitials(names7) {
117384
117524
  return chosen;
117385
117525
  });
117386
117526
  }
117387
- function lookalikePairs(names7) {
117527
+ function lookalikePairs(names8) {
117388
117528
  const pairs = [];
117389
- names7.forEach((name2, index2) => {
117390
- for (const other of names7.slice(index2 + 1)) {
117529
+ names8.forEach((name2, index2) => {
117530
+ for (const other of names8.slice(index2 + 1)) {
117391
117531
  const [a, b] = [actorKey(name2), actorKey(other)];
117392
117532
  const isLong = Math.min(a.length, b.length) >= JOURNEY_LINT.lookalikeMinLength;
117393
117533
  if (isLong && a !== b && suggest(a, [b], 1) !== null) pairs.push([name2, other]);
@@ -117510,8 +117650,8 @@ function linesOf(ctx) {
117510
117650
  }
117511
117651
  function readActors(ctx, text3, span) {
117512
117652
  if (text3 === void 0 || text3.trim() === "") return { names: [], hasEmptyName: false };
117513
- const names7 = text3.split(",").map((piece) => describeLabel(ctx.reporter, piece, span, { allowSub: false }).label);
117514
- return { names: names7.filter((name2) => name2 !== ""), hasEmptyName: names7.some((name2) => name2 === "") };
117653
+ const names8 = text3.split(",").map((piece) => describeLabel(ctx.reporter, piece, span, { allowSub: false }).label);
117654
+ return { names: names8.filter((name2) => name2 !== ""), hasEmptyName: names8.some((name2) => name2 === "") };
117515
117655
  }
117516
117656
  function readTask2(ctx, line3, text3) {
117517
117657
  const span = spanOf9(line3, text3);
@@ -117742,7 +117882,7 @@ function resolveCast(state) {
117742
117882
  const tones = assignTones(entries2.map((entry2) => entry2.tone));
117743
117883
  const initials = assignInitials(entries2.map((entry2) => entry2.name));
117744
117884
  const actors = entries2.map((entry2, index2) => ({ name: entry2.name, tone: tones[index2] ?? "neutral", initials: initials[index2] ?? "?", isDeclared: entry2.isDeclared }));
117745
- const names7 = new Map(entries2.map((entry2) => [actorKey(entry2.name), entry2.name]));
117885
+ const names8 = new Map(entries2.map((entry2) => [actorKey(entry2.name), entry2.name]));
117746
117886
  const known3 = entries2.map((entry2) => entry2.name);
117747
117887
  const resolve5 = (section) => ({
117748
117888
  label: section.label,
@@ -117754,7 +117894,7 @@ function resolveCast(state) {
117754
117894
  score: task.score,
117755
117895
  labelAt: task.labelAt,
117756
117896
  actors: task.names.flatMap((ref) => {
117757
- const name2 = names7.get(actorKey(ref.name));
117897
+ const name2 = names8.get(actorKey(ref.name));
117758
117898
  if (name2 !== void 0) return [name2];
117759
117899
  state.report.push(errorAt(DIAGNOSTIC_CODES.unknownNode, `Unknown actor "${ref.name}"`, ref.at, `${didYouMean(ref.name, known3)} Or declare it with: actor "${ref.name}"`));
117760
117900
  return [];
@@ -117968,10 +118108,10 @@ function parseTaskStatement2(cursor, state, line3) {
117968
118108
  const options3 = readOptions(cursor, TASK_OPTIONS2, state.report, { lists: ["actors"] });
117969
118109
  rejectTrailing(cursor, state, TASK_SYNTAX);
117970
118110
  const score = readScore(findOption(options3, "score"), name2?.at ?? cursor.endPosition(line3), state);
117971
- const names7 = readActors2(findOption(options3, "actors"), state);
118111
+ const names8 = readActors2(findOption(options3, "actors"), state);
117972
118112
  if (name2 === null || score === null) return;
117973
118113
  const sub = findOption(options3, "sub");
117974
- currentTasks(state).push({ label: name2.text, sub: sub === void 0 || cleanName(sub.value) === "" ? null : cleanName(sub.value), score, names: names7, labelAt: name2.at });
118114
+ currentTasks(state).push({ label: name2.text, sub: sub === void 0 || cleanName(sub.value) === "" ? null : cleanName(sub.value), score, names: names8, labelAt: name2.at });
117975
118115
  }
117976
118116
  var TASK_OPTIONS2, TASK_SYNTAX, SCORE_HINT, NUMBER2, textOf2;
117977
118117
  var init_parse_task = __esm({
@@ -119774,13 +119914,13 @@ function layoutTable(diagram) {
119774
119914
  const heads = diagram.columns.map(placeHead);
119775
119915
  heads.forEach((head, place2) => head.block.isShortened && cuts.push(`the column "${diagram.columns[place2]?.label ?? ""}"`));
119776
119916
  const texts = diagram.rows.map((row) => row.cells.map((cell2) => cell2.kind === "text" ? fitBlock2(cell2.text, "sub", M4.textWidth, M4.textHardWidth, M4.textLines) : null));
119777
- const names7 = diagram.rows.map((row) => fitBlock2(row.label, "label", M4.nameWidth, M4.nameHardWidth, M4.nameLines));
119917
+ const names8 = diagram.rows.map((row) => fitBlock2(row.label, "label", M4.nameWidth, M4.nameHardWidth, M4.nameLines));
119778
119918
  const subs = diagram.rows.map((row) => row.sub === null ? null : fitBlock2(row.sub, "sub", M4.nameWidth, M4.nameHardWidth, 1));
119779
119919
  diagram.rows.forEach((row, at3) => {
119780
- if (names7[at3]?.isShortened === true || subs[at3]?.isShortened === true) cuts.push(`the row "${row.label}"`);
119920
+ if (names8[at3]?.isShortened === true || subs[at3]?.isShortened === true) cuts.push(`the row "${row.label}"`);
119781
119921
  row.cells.forEach((cell2, place2) => texts[at3]?.[place2]?.isShortened === true && cuts.push(`the cell of "${row.label}" under "${diagram.columns[place2]?.label ?? ""}"`));
119782
119922
  });
119783
- const firstWidth = Math.max(M4.nameMin, ...diagram.rows.map((row, at3) => nameLead(row) + Math.max(names7[at3]?.width ?? 0, subs[at3]?.width ?? 0) + M4.namePaddingX));
119923
+ const firstWidth = Math.max(M4.nameMin, ...diagram.rows.map((row, at3) => nameLead(row) + Math.max(names8[at3]?.width ?? 0, subs[at3]?.width ?? 0) + M4.namePaddingX));
119784
119924
  const widths = columnWidths(diagram, heads, texts);
119785
119925
  const totalWidth = totals === null ? 0 : M4.totalWidth;
119786
119926
  const frameX = M4.padding;
@@ -119800,7 +119940,7 @@ function layoutTable(diagram) {
119800
119940
  let y = headerTop + headerHeight;
119801
119941
  const rows = diagram.rows.map((row, at3) => {
119802
119942
  const isRecommended = diagram.recommended === at3;
119803
- const textHeight3 = (names7[at3]?.lines.length ?? 0) * TYPE_ROLES.label.lineHeight + (subs[at3] === null ? 0 : NODE_METRICS.subGap + TYPE_ROLES.sub.lineHeight);
119943
+ const textHeight3 = (names8[at3]?.lines.length ?? 0) * TYPE_ROLES.label.lineHeight + (subs[at3] === null ? 0 : NODE_METRICS.subGap + TYPE_ROLES.sub.lineHeight);
119804
119944
  const content = Math.max(textHeight3, row.icon === null ? 0 : M4.chipSize, ...row.cells.map((cell2, place2) => contentHeight(cell2, texts[at3]?.[place2] ?? null)));
119805
119945
  const bodyHeight = Math.max(M4.rowMin, content + M4.cellPadY * 2);
119806
119946
  const band = isRecommended ? M4.cardInset + M4.tabHeight : 0;
@@ -119813,7 +119953,7 @@ function layoutTable(diagram) {
119813
119953
  isBanded: at3 % 2 === 1,
119814
119954
  isRecommended,
119815
119955
  tone: toneOf2(diagram, row, isRecommended),
119816
- name: names7[at3],
119956
+ name: names8[at3],
119817
119957
  sub: subs[at3] ?? null,
119818
119958
  texts: texts[at3] ?? [],
119819
119959
  tabWidth: isRecommended ? tabWidth2 : 0,
@@ -120406,15 +120546,15 @@ function parseLevels(cursor, state, line3) {
120406
120546
  state.report.push(errorAt(DIAGNOSTIC_CODES.badOptionValue, "Expected which axis the levels name", axis ?? cursor.endPosition(line3), axis?.kind === "word" ? `${didYouMean(axis.text, axes)} ${LEVELS_HINT}` : LEVELS_HINT));
120407
120547
  return;
120408
120548
  }
120409
- const names7 = [];
120410
- for (let token = cursor.peek(); token?.kind === "string"; token = cursor.peek()) names7.push(cursor.next());
120549
+ const names8 = [];
120550
+ for (let token = cursor.peek(); token?.kind === "string"; token = cursor.peek()) names8.push(cursor.next());
120411
120551
  const options3 = readOptions(cursor, LEVELS_OPTIONS, state.report);
120412
120552
  rejectTrailing(cursor, state, LEVELS_HINT);
120413
120553
  const title = findOption(options3, "title")?.value.trim() ?? "";
120414
- const levels = names7.map((token) => token.kind === "string" ? token.text.trim() : "");
120554
+ const levels = names8.map((token) => token.kind === "string" ? token.text.trim() : "");
120415
120555
  const earlier = state.levelsLines.get(axis.text);
120416
- if (names7.length !== GRID_LEVELS || levels.includes("")) {
120417
- state.report.push(errorAt(DIAGNOSTIC_CODES.syntax, `The ${axis.text} levels need ${GRID_LEVELS} names with some text, found ${names7.length}`, names7[0] ?? keyword, LEVELS_HINT));
120556
+ if (names8.length !== GRID_LEVELS || levels.includes("")) {
120557
+ state.report.push(errorAt(DIAGNOSTIC_CODES.syntax, `The ${axis.text} levels need ${GRID_LEVELS} names with some text, found ${names8.length}`, names8[0] ?? keyword, LEVELS_HINT));
120418
120558
  return;
120419
120559
  }
120420
120560
  if (earlier !== void 0) {
@@ -121463,8 +121603,8 @@ function sideMiddle(topic, heading) {
121463
121603
  function endsAlong(parent, child, heading) {
121464
121604
  const end = sideMiddle(child, { x: -heading.x, y: -heading.y });
121465
121605
  if (parent.depth > 0 || heading.y !== 0) return { start: sideMiddle(parent, heading), end, leaving: heading, entering: heading };
121466
- const leaving = unitBetween(centreOf(parent.rect), end);
121467
- return { start: along3(centreOf(parent.rect), leaving, edgeDistance(parent.shape, parent.rect.width, parent.rect.height, leaving)), end, leaving, entering: heading };
121606
+ const leaving = unitBetween(centreOf2(parent.rect), end);
121607
+ return { start: along3(centreOf2(parent.rect), leaving, edgeDistance(parent.shape, parent.rect.width, parent.rect.height, leaving)), end, leaving, entering: heading };
121468
121608
  }
121469
121609
  function headingOf(child, arrangement, directions) {
121470
121610
  if (arrangement === "down") return { x: 0, y: 1 };
@@ -121504,14 +121644,14 @@ function routeLinks3(topics2, arrangement, directions) {
121504
121644
  };
121505
121645
  });
121506
121646
  }
121507
- var TUCK, centreOf, along3, dot, unitBetween, farSide, columnKey;
121647
+ var TUCK, centreOf2, along3, dot, unitBetween, farSide, columnKey;
121508
121648
  var init_links = __esm({
121509
121649
  "../../packages/diagrams/src/kinds/mindmap/layout/links.ts"() {
121510
121650
  "use strict";
121511
121651
  init_metrics9();
121512
121652
  init_shapes2();
121513
121653
  TUCK = 1.5;
121514
- centreOf = (rect) => ({ x: rect.x + rect.width / 2, y: rect.y + rect.height / 2 });
121654
+ centreOf2 = (rect) => ({ x: rect.x + rect.width / 2, y: rect.y + rect.height / 2 });
121515
121655
  along3 = (from, direction, distance4) => ({ x: from.x + direction.x * distance4, y: from.y + direction.y * distance4 });
121516
121656
  dot = (a, b) => a.x * b.x + a.y * b.y;
121517
121657
  unitBetween = (from, to) => {
@@ -123252,7 +123392,7 @@ function readSlice(ctx, line3, text3, match) {
123252
123392
  function parsePieMermaid(ctx) {
123253
123393
  const head = readHeaderRest2(ctx);
123254
123394
  const slices = [];
123255
- const names7 = /* @__PURE__ */ new Set();
123395
+ const names8 = /* @__PURE__ */ new Set();
123256
123396
  let showData = head.showData;
123257
123397
  for (const line3 of [...head.line === null ? [] : [head.line], ...ctx.prepared.body]) {
123258
123398
  const text3 = line3.text.trim();
@@ -123268,11 +123408,11 @@ function parsePieMermaid(ctx) {
123268
123408
  } else {
123269
123409
  const slice = readSlice(ctx, line3, text3, data);
123270
123410
  if (slice === null) continue;
123271
- if (names7.has(nameKey(slice.label))) {
123411
+ if (names8.has(nameKey(slice.label))) {
123272
123412
  ctx.reporter.add(DIAGNOSTIC_CODES.mermaidDuplicateDropped, slice.span, `A second slice named "${slice.label}" was dropped; the first is kept.`, "Add the two values in the Mermaid first if both should count, or tell the slices apart in their names.", "pie-duplicate");
123273
123413
  continue;
123274
123414
  }
123275
- names7.add(nameKey(slice.label));
123415
+ names8.add(nameKey(slice.label));
123276
123416
  slices.push(slice);
123277
123417
  }
123278
123418
  if (slices.length > PIE_LIMITS.maxSlices) {
@@ -124000,7 +124140,7 @@ var init_layout_axes = __esm({
124000
124140
  function around(center, half) {
124001
124141
  return { x: center.x - half, y: center.y - half, width: half * 2, height: half * 2 };
124002
124142
  }
124003
- function overlaps5(a, b, margin = 0) {
124143
+ function overlaps6(a, b, margin = 0) {
124004
124144
  return a.x < b.x + b.width + margin && b.x < a.x + a.width + margin && a.y < b.y + b.height + margin && b.y < a.y + a.height + margin;
124005
124145
  }
124006
124146
  function isWithin(inner, outer, inset2 = 0) {
@@ -124041,11 +124181,11 @@ function candidatesFor2(request, gap2) {
124041
124181
  }
124042
124182
  function isFree(rect, request, world, placed, mayLeaveZone) {
124043
124183
  const isInZone = isWithin(rect, request.zone, M9.edgeInset);
124044
- const reachesAcross = mayLeaveZone && isWithin(rect, world.plot, M9.edgeInset) && overlaps5(rect, request.zone);
124184
+ const reachesAcross = mayLeaveZone && isWithin(rect, world.plot, M9.edgeInset) && overlaps6(rect, request.zone);
124045
124185
  if (!isInZone && !reachesAcross) return false;
124046
- if (world.chips.some((chip2, index2) => index2 !== request.index && overlaps5(rect, chip2, M9.keepOff - 1))) return false;
124047
- if (world.tabs.some((tab) => overlaps5(rect, tab, M9.keepOff))) return false;
124048
- return !placed.some((other) => overlaps5(rect, other, M9.keepOff));
124186
+ if (world.chips.some((chip2, index2) => index2 !== request.index && overlaps6(rect, chip2, M9.keepOff - 1))) return false;
124187
+ if (world.tabs.some((tab) => overlaps6(rect, tab, M9.keepOff))) return false;
124188
+ return !placed.some((other) => overlaps6(rect, other, M9.keepOff));
124049
124189
  }
124050
124190
  function placeLabels2(requests, world) {
124051
124191
  const freeCount = (request) => candidatesFor2(request, M9.labelGap).filter((candidate2) => isFree(candidate2.rect, request, world, [], false)).length;
@@ -124057,7 +124197,7 @@ function placeLabels2(requests, world) {
124057
124197
  for (const attempt of ATTEMPTS) {
124058
124198
  const found = candidatesFor2(request, attempt.gap).find((candidate2) => isFree(candidate2.rect, request, world, placed, attempt.mayLeaveZone));
124059
124199
  if (found === void 0) continue;
124060
- const hasHalo = world.lines.some((line3) => overlaps5(found.rect, line3, M9.keepOff));
124200
+ const hasHalo = world.lines.some((line3) => overlaps6(found.rect, line3, M9.keepOff));
124061
124201
  label = { lines: request.lines, rect: found.rect, anchor: found.anchor, hasHalo, isShortened: request.isShortened };
124062
124202
  placed.push(found.rect);
124063
124203
  break;
@@ -124093,7 +124233,7 @@ function sizeZoneTab(zone, zoneWidth) {
124093
124233
  }
124094
124234
  function placeZoneTab(zone, size, chips) {
124095
124235
  const rectAt = (offset2) => ({ x: zone.x + offset2, y: zone.y, width: size.width, height: GROUP_METRICS.tabHeight });
124096
- const underTab = (rect) => chips.flatMap((chip2, index2) => overlaps5(rect, chip2, M10.tabClearance) ? [index2] : []);
124236
+ const underTab = (rect) => chips.flatMap((chip2, index2) => overlaps6(rect, chip2, M10.tabClearance) ? [index2] : []);
124097
124237
  const byLeft = [...chips.keys()].sort((a, b) => (chips[a]?.x ?? 0) - (chips[b]?.x ?? 0));
124098
124238
  let offset = 0;
124099
124239
  for (let attempt = 0; attempt <= chips.length; attempt += 1) {
@@ -124166,7 +124306,7 @@ function collisionsOf(chips) {
124166
124306
  const pairs = [];
124167
124307
  chips.forEach((chip2, first) => {
124168
124308
  for (let second = first + 1; second < chips.length; second += 1) {
124169
- if (overlaps5(chip2, chips[second], 2)) pairs.push([first, second]);
124309
+ if (overlaps6(chip2, chips[second], 2)) pairs.push([first, second]);
124170
124310
  }
124171
124311
  });
124172
124312
  return pairs;
@@ -125890,9 +126030,9 @@ var init_layout11 = __esm({
125890
126030
  });
125891
126031
 
125892
126032
  // ../../packages/diagrams/src/kinds/sankey/lint.ts
125893
- function nameList(names7) {
125894
- const shown = names7.slice(0, LISTED3).map((name2) => `"${oneLine6(name2)}"`).join(", ");
125895
- return names7.length > LISTED3 ? `${shown}, and ${names7.length - LISTED3} more` : shown;
126033
+ function nameList(names8) {
126034
+ const shown = names8.slice(0, LISTED3).map((name2) => `"${oneLine6(name2)}"`).join(", ");
126035
+ return names8.length > LISTED3 ? `${shown}, and ${names8.length - LISTED3} more` : shown;
125896
126036
  }
125897
126037
  function balanceWarnings(diagram) {
125898
126038
  const totals = totalsOf2(diagram);
@@ -126029,11 +126169,11 @@ function addFlow(ctx, flows, flow) {
126029
126169
  }
126030
126170
  function removeLoops(ctx, flows) {
126031
126171
  for (let guard = 0; guard <= flows.length; guard += 1) {
126032
- const names7 = [...new Set(flows.flatMap((flow) => [flow.from, flow.to]))];
126033
- const { cycle } = layerNodes(names7.length, flows.map((flow) => ({ from: names7.indexOf(flow.from), to: names7.indexOf(flow.to) })), "justify");
126172
+ const names8 = [...new Set(flows.flatMap((flow) => [flow.from, flow.to]))];
126173
+ const { cycle } = layerNodes(names8.length, flows.map((flow) => ({ from: names8.indexOf(flow.from), to: names8.indexOf(flow.to) })), "justify");
126034
126174
  if (cycle === null) return true;
126035
- const from = names7[cycle[cycle.length - 1] ?? 0];
126036
- const to = names7[cycle[0] ?? 0];
126175
+ const from = names8[cycle[cycle.length - 1] ?? 0];
126176
+ const to = names8[cycle[0] ?? 0];
126037
126177
  const at3 = flows.findIndex((flow) => flow.from === from && flow.to === to);
126038
126178
  const closing = flows[at3];
126039
126179
  if (closing === void 0) return false;
@@ -126351,9 +126491,9 @@ function wholeSourceErrors(state, header) {
126351
126491
  }
126352
126492
  const { cycle } = layerNodes(state.nodes.length, state.flows, state.align);
126353
126493
  if (cycle !== null) {
126354
- const names7 = [...cycle, cycle[0] ?? 0].map((node3) => `"${state.nodes[node3]?.label ?? ""}"`).join(" -> ");
126494
+ const names8 = [...cycle, cycle[0] ?? 0].map((node3) => `"${state.nodes[node3]?.label ?? ""}"`).join(" -> ");
126355
126495
  const closing = state.flows.find((flow) => flow.from === cycle[cycle.length - 1] && flow.to === cycle[0]);
126356
- found.push(errorAt(DIAGNOSTIC_CODES.syntax, `These flows go round in a loop: ${names7}`, closing?.at ?? state.nodes[cycle[0] ?? 0]?.at ?? { line: 1, column: 1, length: 1 }, 'A sankey only goes forward, so a loop cannot be drawn. Remove the flow that goes back, or split the stage in two, for example "Orders" and "Orders retried".'));
126496
+ found.push(errorAt(DIAGNOSTIC_CODES.syntax, `These flows go round in a loop: ${names8}`, closing?.at ?? state.nodes[cycle[0] ?? 0]?.at ?? { line: 1, column: 1, length: 1 }, 'A sankey only goes forward, so a loop cannot be drawn. Remove the flow that goes back, or split the stage in two, for example "Orders" and "Orders retried".'));
126357
126497
  }
126358
126498
  return found;
126359
126499
  }
@@ -131099,7 +131239,7 @@ function lineage(id, byId) {
131099
131239
  return chain2;
131100
131240
  }
131101
131241
  function resolveTransitions(state, byId) {
131102
- const names7 = state.nodes.filter((node3) => node3.kind === "state" || node3.kind === "composite" || node3.kind === "choice" || node3.kind === "fork" || node3.kind === "join" || node3.kind === "history").map((node3) => node3.id);
131242
+ const names8 = state.nodes.filter((node3) => node3.kind === "state" || node3.kind === "composite" || node3.kind === "choice" || node3.kind === "fork" || node3.kind === "join" || node3.kind === "history").map((node3) => node3.id);
131103
131243
  const resolved = [];
131104
131244
  let suggested = 0;
131105
131245
  for (const pending of state.transitions) {
@@ -131108,7 +131248,7 @@ function resolveTransitions(state, byId) {
131108
131248
  { id: pending.to, token: pending.toToken }
131109
131249
  ].filter((end) => !byId.has(end.id));
131110
131250
  for (const end of missing) {
131111
- const guess = suggested < SUGGESTIONS2 ? `${didYouMean(end.id, names7)} ` : "";
131251
+ const guess = suggested < SUGGESTIONS2 ? `${didYouMean(end.id, names8)} ` : "";
131112
131252
  suggested += 1;
131113
131253
  reportAt(state, DIAGNOSTIC_CODES.unknownNode, `Unknown state "${end.id}"`, spanOfToken(end.token), `${guess}Declare it first with: state ${end.id} "Label"`);
131114
131254
  }
@@ -131128,7 +131268,7 @@ function resolveTransitions(state, byId) {
131128
131268
  return resolved;
131129
131269
  }
131130
131270
  function resolveNotes2(state, byId) {
131131
- const names7 = state.nodes.filter((node3) => node3.kind === "state" || node3.kind === "composite" || node3.kind === "choice").map((node3) => node3.id);
131271
+ const names8 = state.nodes.filter((node3) => node3.kind === "state" || node3.kind === "composite" || node3.kind === "choice").map((node3) => node3.id);
131132
131272
  const notes = [];
131133
131273
  let suggested = 0;
131134
131274
  for (const pending of state.notes) {
@@ -131138,7 +131278,7 @@ function resolveNotes2(state, byId) {
131138
131278
  continue;
131139
131279
  }
131140
131280
  if (target === void 0) {
131141
- const guess = suggested < SUGGESTIONS2 ? `${didYouMean(pending.target, names7)} ` : "";
131281
+ const guess = suggested < SUGGESTIONS2 ? `${didYouMean(pending.target, names8)} ` : "";
131142
131282
  suggested += 1;
131143
131283
  state.report.push(errorAt(DIAGNOSTIC_CODES.unknownNode, `Unknown state "${pending.target}"`, spanOfToken(pending.targetToken), `${guess}A note attaches to a state that is declared.`));
131144
131284
  continue;
@@ -131952,21 +132092,21 @@ function placePills2(routes, runs, extents, items2, forced) {
131952
132092
  });
131953
132093
  const costed = spots.map(({ at: at3, rank, middle: middle2 }) => {
131954
132094
  const pill2 = pillAt2(flow, at3);
131955
- return { at: at3, cost: lines.filter((line3) => line3.flow !== flow && overlaps6(pill2, line3.box)).length * COST.line + placed.filter((other) => overlaps6(pill2, other)).length * COST.pill + items2.filter((item) => overlaps6(pill2, item)).length * COST.item + rank * COST.otherRun + Math.abs(at3.x - middle2) * 1e-3 };
132095
+ return { at: at3, cost: lines.filter((line3) => line3.flow !== flow && overlaps7(pill2, line3.box)).length * COST.line + placed.filter((other) => overlaps7(pill2, other)).length * COST.pill + items2.filter((item) => overlaps7(pill2, item)).length * COST.item + rank * COST.otherRun + Math.abs(at3.x - middle2) * 1e-3 };
131956
132096
  });
131957
132097
  const chosen = costed.reduce((best, spot) => best === null || spot.cost < best.cost ? spot : best, null);
131958
132098
  if (chosen !== null) placed.push(pillAt2(flow, chosen.at));
131959
132099
  return chosen === null ? null : chosen.at;
131960
132100
  });
131961
132101
  }
131962
- var GUTTER, COST, overlaps6;
132102
+ var GUTTER, COST, overlaps7;
131963
132103
  var init_pills = __esm({
131964
132104
  "../../packages/diagrams/src/kinds/swimlane/layout/pills.ts"() {
131965
132105
  "use strict";
131966
132106
  init_theme();
131967
132107
  GUTTER = { base: 52, stub: 20, pitch: 12, corner: 10, headClear: 14, pillGap: 6, roundRoom: 24, endRun: EDGE_METRICS.endRun };
131968
132108
  COST = { line: 3, pill: 60, item: 1e3, otherRun: 0.4 };
131969
- overlaps6 = (a, b) => a.x < b.x + b.width && b.x < a.x + a.width && a.y < b.y + b.height && b.y < a.y + a.height;
132109
+ overlaps7 = (a, b) => a.x < b.x + b.width && b.x < a.x + a.width && a.y < b.y + b.height && b.y < a.y + a.height;
131970
132110
  }
131971
132111
  });
131972
132112
 
@@ -132405,13 +132545,13 @@ function parseFlow2(cursor, p, line3) {
132405
132545
  p.pending.push({ from, to, label, line: style, step: look.step, at: spanOfLine6(line3) });
132406
132546
  }
132407
132547
  function resolveFlows(p) {
132408
- const names7 = p.items.map((item) => item.id);
132548
+ const names8 = p.items.map((item) => item.id);
132409
132549
  const resolved = [];
132410
132550
  let suggested = 0;
132411
132551
  for (const pending of p.pending) {
132412
- const missing = [pending.from, pending.to].filter((end) => !names7.includes(end.text));
132552
+ const missing = [pending.from, pending.to].filter((end) => !names8.includes(end.text));
132413
132553
  for (const end of missing) {
132414
- const guess = suggested < SUGGESTIONS3 ? `${didYouMean(end.text, names7)} ` : "";
132554
+ const guess = suggested < SUGGESTIONS3 ? `${didYouMean(end.text, names8)} ` : "";
132415
132555
  suggested += 1;
132416
132556
  fail(p, `Unknown step "${end.text}"`, spanOf22(end), `${guess}Declare it first inside a lane: step ${end.text} "Label"`, DIAGNOSTIC_CODES.unknownNode);
132417
132557
  }
@@ -136291,9 +136431,9 @@ var init_layout16 = __esm({
136291
136431
  });
136292
136432
 
136293
136433
  // ../../packages/diagrams/src/kinds/treemap/lint.ts
136294
- function nameList2(names7) {
136295
- const shown = names7.slice(0, LISTED4).map((name2) => `"${name2.replace(/\s+/g, " ").trim()}"`).join(", ");
136296
- return names7.length > LISTED4 ? `${shown}, and ${names7.length - LISTED4} more` : shown;
136434
+ function nameList2(names8) {
136435
+ const shown = names8.slice(0, LISTED4).map((name2) => `"${name2.replace(/\s+/g, " ").trim()}"`).join(", ");
136436
+ return names8.length > LISTED4 ? `${shown}, and ${names8.length - LISTED4} more` : shown;
136297
136437
  }
136298
136438
  function densityWarning11(items2) {
136299
136439
  if (items2 <= TREEMAP_LIMITS.warnItems) return null;
@@ -137663,7 +137803,7 @@ function layoutXychartNow(diagram) {
137663
137803
  const { scale } = shaped;
137664
137804
  const isHorizontal3 = diagram.direction === "horizontal";
137665
137805
  const unit3 = diagram.y.unit;
137666
- const names7 = placeNames(diagram, shaped);
137806
+ const names8 = placeNames(diagram, shaped);
137667
137807
  const mode = labelMode(diagram, isHorizontal3);
137668
137808
  const cut = [];
137669
137809
  const seriesPill = (index2, withValue) => {
@@ -137675,7 +137815,7 @@ function layoutXychartNow(diagram) {
137675
137815
  const directPills = mode === "direct" ? shaped.series.map((_, index2) => seriesPill(index2, true)) : [];
137676
137816
  const legendPills = mode === "legend" ? shaped.series.map((_, index2) => seriesPill(index2, false)) : [];
137677
137817
  const gutterWidth = isHorizontal3 ? 0 : Math.max(0, ...directPills.map((pill2) => pill2.width), ...thresholdPills.map((pill2) => pill2.width));
137678
- const rowLabels = isHorizontal3 ? fitRowLabels(names7) : null;
137818
+ const rowLabels = isHorizontal3 ? fitRowLabels(names8) : null;
137679
137819
  const reach2 = valueLabelReach(diagram, shaped);
137680
137820
  const left = XYCHART_METRICS.padding + (rowLabels === null ? tickWidth(scale, unit3) + XYCHART_METRICS.tickGap : rowLabels.width + XYCHART_METRICS.rowLabelGap);
137681
137821
  const right = XYCHART_METRICS.padding + (isHorizontal3 ? reach2 === 0 ? 0 : reach2 + XYCHART_METRICS.valueGap + 4 : gutterWidth === 0 ? 0 : gutterWidth + XYCHART_METRICS.gutterGap);
@@ -137685,7 +137825,7 @@ function layoutXychartNow(diagram) {
137685
137825
  const plotHeight = isHorizontal3 ? Math.max(XYCHART_METRICS.plot.minHeight / 2, shaped.count * pitch) : XYCHART_METRICS.plot.height;
137686
137826
  const frameWidth = Math.ceil(left + plotWidth + right);
137687
137827
  const aim = placeFrame(diagram, shaped, { x: left, y: 0, width: plotWidth, height: plotHeight }, isHorizontal3);
137688
- const fitted = isHorizontal3 || diagram.x?.kind !== "category" ? null : fitPlaces(names7, aim.slot, aim.center, { left: XYCHART_METRICS.padding, right: frameWidth - XYCHART_METRICS.padding });
137828
+ const fitted = isHorizontal3 || diagram.x?.kind !== "category" ? null : fitPlaces(names8, aim.slot, aim.center, { left: XYCHART_METRICS.padding, right: frameWidth - XYCHART_METRICS.padding });
137689
137829
  const vTitleText = isHorizontal3 ? diagram.x?.title ?? null : valueAxisTitle(diagram.y.title, unit3);
137690
137830
  const hTitleText = isHorizontal3 ? valueAxisTitle(diagram.y.title, unit3) : diagram.x?.title ?? null;
137691
137831
  const vTitleContent = oneLine9(vTitleText ?? "") === "" ? null : measurePill2({ key: "none", tone: null, icon: null, name: vTitleText ?? "", value: null, index: -1 });
@@ -137740,7 +137880,7 @@ function layoutXychartNow(diagram) {
137740
137880
  let labelStep = 1;
137741
137881
  if (rowLabels !== null) {
137742
137882
  places = rowLabels.texts.map((text3, index2) => ({ lines: [text3], x: plot.x - XYCHART_METRICS.rowLabelGap, top: frame.center(index2) - SUB_LINE2 / 2, anchor: "end" }));
137743
- rowLabels.isCut.forEach((isCut, index2) => isCut && cut.push(names7[index2] ?? ""));
137883
+ rowLabels.isCut.forEach((isCut, index2) => isCut && cut.push(names8[index2] ?? ""));
137744
137884
  placesBottom = Math.max(...ticks.map((tick) => tick.label.top + SUB_LINE2));
137745
137885
  } else if (diagram.x?.kind === "number") {
137746
137886
  places = placeNumberTicks(shaped, frame, placesTop);
@@ -137748,7 +137888,7 @@ function layoutXychartNow(diagram) {
137748
137888
  } else if (fitted !== null) {
137749
137889
  labelStep = fitted.step;
137750
137890
  places = fitted.lines.flatMap((lines2, index2) => index2 % labelStep === 0 ? [{ lines: lines2, x: fitted.x[index2] ?? frame.center(index2), top: placesTop, anchor: "middle" }] : []);
137751
- fitted.isCut.forEach((isCut, index2) => isCut && index2 % labelStep === 0 && cut.push(names7[index2] ?? ""));
137891
+ fitted.isCut.forEach((isCut, index2) => isCut && index2 % labelStep === 0 && cut.push(names8[index2] ?? ""));
137752
137892
  placesBottom = placesTop + SUB_LINE2 * Math.max(1, ...places.map((place2) => place2.lines.length));
137753
137893
  }
137754
137894
  const hTitleName = oneLine9(hTitleText ?? "");
@@ -138020,11 +138160,11 @@ function summarizeXychart(diagram) {
138020
138160
  const description = diagram.meta.description === null ? "" : ` ${oneLine9(diagram.meta.description)}`;
138021
138161
  return `${xychartTitle(diagram)}: ${countOf(diagram.series.length, "series", "series")} (${kinds2}) over ${countOf(shaped.count, "place")} on the ${axis} axis, on a scale of ${scale}.${description}`;
138022
138162
  }
138023
- function crossings(diagram, names7) {
138163
+ function crossings(diagram, names8) {
138024
138164
  return diagram.thresholds.flatMap((threshold) => {
138025
138165
  if (threshold.breach === "none") return [];
138026
138166
  const found = diagram.series.flatMap((series) => {
138027
- const places = series.values.flatMap((value, place2) => (threshold.breach === "above" ? value > threshold.value : value < threshold.value) ? [names7[place2] ?? ""] : []);
138167
+ const places = series.values.flatMap((value, place2) => (threshold.breach === "above" ? value > threshold.value : value < threshold.value) ? [names8[place2] ?? ""] : []);
138028
138168
  return places.length === 0 ? [] : [`${oneLine9(series.label)} in ${joinWords(places, "and")}`];
138029
138169
  });
138030
138170
  return [`- Crossed ${threshold.breach} ${oneLine9(threshold.label)}: ${found.length === 0 ? "nothing" : found.join("; ")}`];
@@ -138032,19 +138172,19 @@ function crossings(diagram, names7) {
138032
138172
  }
138033
138173
  function outlineXychart(diagram) {
138034
138174
  const shaped = shapeChart(diagram);
138035
- const names7 = placeNames(diagram, shaped);
138175
+ const names8 = placeNames(diagram, shaped);
138036
138176
  const unit3 = diagram.y.unit;
138037
138177
  const axis = diagram.x;
138038
- const at3 = (value, place2) => `${names7[place2] ?? ""} ${formatValue4(value, unit3)}`;
138178
+ const at3 = (value, place2) => `${names8[place2] ?? ""} ${formatValue4(value, unit3)}`;
138039
138179
  const lines = [summarizeXychart(diagram)];
138040
- if (axis?.kind === "category") lines.push(`X axis, ${axis.title === null ? "places" : oneLine9(axis.title)}: ${names7.join(", ")}.`);
138180
+ if (axis?.kind === "category") lines.push(`X axis, ${axis.title === null ? "places" : oneLine9(axis.title)}: ${names8.join(", ")}.`);
138041
138181
  if (axis?.kind === "number") lines.push(`X axis, ${axis.title === null ? "number" : oneLine9(axis.title)}: ${formatNumber4(axis.from)} to ${formatNumber4(axis.to)}, with the ${shaped.count} values spread evenly over it.`);
138042
138182
  lines.push(`Y axis${diagram.y.title === null ? "" : `, ${oneLine9(diagram.y.title)}`}: ${formatValue4(shaped.scale.min, unit3)} to ${formatValue4(shaped.scale.max, unit3)}.`);
138043
138183
  lines.push(`Drawn with the places ${diagram.direction === "horizontal" ? "down the side" : "along the bottom"}.`, shaped.isStacked ? "Series (the bars are stacked):" : "Series:");
138044
138184
  for (const series of diagram.series) lines.push(`- ${oneLine9(series.label)} (${series.kind}): ${series.values.map(at3).join(", ")}`);
138045
138185
  if (shaped.isStacked) lines.push(`- Bar totals: ${shaped.totals.map(at3).join(", ")}`);
138046
- if (diagram.thresholds.length > 0) lines.push("Thresholds:", ...diagram.thresholds.map((threshold) => `- ${oneLine9(threshold.label)}: ${formatValue4(threshold.value, unit3)}`), ...crossings(diagram, names7));
138047
- if (diagram.notes.length > 0) lines.push("Notes:", ...diagram.notes.map((note) => `- ${axis?.kind === "category" ? names7[note.where] ?? "" : formatNumber4(note.where)}: ${oneLine9(note.text)}`));
138186
+ if (diagram.thresholds.length > 0) lines.push("Thresholds:", ...diagram.thresholds.map((threshold) => `- ${oneLine9(threshold.label)}: ${formatValue4(threshold.value, unit3)}`), ...crossings(diagram, names8));
138187
+ if (diagram.notes.length > 0) lines.push("Notes:", ...diagram.notes.map((note) => `- ${axis?.kind === "category" ? names8[note.where] ?? "" : formatNumber4(note.where)}: ${oneLine9(note.text)}`));
138048
138188
  return lines;
138049
138189
  }
138050
138190
  var xychartTitle;
@@ -139659,13 +139799,13 @@ function renamedName(element, rename2) {
139659
139799
  function entriesOf3(source, rename2) {
139660
139800
  const { elements } = scanSource(source);
139661
139801
  const seen = /* @__PURE__ */ new Map();
139662
- const parentOf3 = (element) => element.parent === null ? null : renamedName(elements[element.parent], rename2);
139802
+ const parentOf4 = (element) => element.parent === null ? null : renamedName(elements[element.parent], rename2);
139663
139803
  return elements.map((element) => {
139664
139804
  const own2 = renamedName(element, rename2);
139665
- const base = element.role === "row" && element.keyword === null ? `${parentOf3(element) ?? ""}.${own2}` : own2;
139805
+ const base = element.role === "row" && element.keyword === null ? `${parentOf4(element) ?? ""}.${own2}` : own2;
139666
139806
  const count3 = (seen.get(base) ?? 0) + 1;
139667
139807
  seen.set(base, count3);
139668
- return { key: count3 === 1 ? base : `${base}#${count3}`, element, subject: subjectOf(element), parent: parentOf3(element) };
139808
+ return { key: count3 === 1 ? base : `${base}#${count3}`, element, subject: subjectOf(element), parent: parentOf4(element) };
139669
139809
  });
139670
139810
  }
139671
139811
  function valueChange(before, after) {
@@ -143155,7 +143295,7 @@ var init_schemas = __esm({
143155
143295
  }
143156
143296
  return propValues;
143157
143297
  });
143158
- const isObject4 = isObject;
143298
+ const isObject5 = isObject;
143159
143299
  const catchall = def.catchall;
143160
143300
  let value;
143161
143301
  const memo3 = globalConfig.memoizer;
@@ -143163,7 +143303,7 @@ var init_schemas = __esm({
143163
143303
  inst._zod.parse = (payload, ctx) => {
143164
143304
  value ?? (value = _normalized.value);
143165
143305
  const input2 = payload.value;
143166
- if (!isObject4(input2)) {
143306
+ if (!isObject5(input2)) {
143167
143307
  payload.issues.push({
143168
143308
  expected: "object",
143169
143309
  code: "invalid_type",
@@ -143299,7 +143439,7 @@ var init_schemas = __esm({
143299
143439
  return doc.compile();
143300
143440
  };
143301
143441
  let fastpass;
143302
- const isObject4 = isObject;
143442
+ const isObject5 = isObject;
143303
143443
  const jit = !globalConfig.jitless;
143304
143444
  const allowsEval2 = allowsEval;
143305
143445
  const fastEnabled = jit && allowsEval2.value;
@@ -143308,7 +143448,7 @@ var init_schemas = __esm({
143308
143448
  inst._zod.parse = (payload, ctx) => {
143309
143449
  value ?? (value = _normalized.value);
143310
143450
  const input2 = payload.value;
143311
- if (!isObject4(input2)) {
143451
+ if (!isObject5(input2)) {
143312
143452
  payload.issues.push({
143313
143453
  expected: "object",
143314
143454
  code: "invalid_type",
@@ -155895,12 +156035,12 @@ function rewriteKeyNames(ctx) {
155895
156035
  const rewrites = /* @__PURE__ */ new Map();
155896
156036
  for (const record2 of pendingRecords.get(ctx) ?? []) {
155897
156037
  const seen = ctx.seen.get(record2);
155898
- const names7 = (seen?.def ?? seen?.schema)?.propertyNames;
155899
- if (!names7 || names7 === true || rewrites.has(names7))
156038
+ const names8 = (seen?.def ?? seen?.schema)?.propertyNames;
156039
+ if (!names8 || names8 === true || rewrites.has(names8))
155900
156040
  continue;
155901
- const rewritten = stringifyKeyNames(bySchema, names7, /* @__PURE__ */ new Set());
155902
- if (rewritten !== names7)
155903
- rewrites.set(names7, rewritten);
156041
+ const rewritten = stringifyKeyNames(bySchema, names8, /* @__PURE__ */ new Set());
156042
+ if (rewritten !== names8)
156043
+ rewrites.set(names8, rewritten);
155904
156044
  }
155905
156045
  if (!rewrites.size)
155906
156046
  return;
@@ -161992,13 +162132,13 @@ function detourOf(lines) {
161992
162132
  function measureScene(scene) {
161993
162133
  const boxes2 = solidBoxes(scene.boxes);
161994
162134
  const over = linesOverBoxes(scene.lines, boxes2);
161995
- const overlaps7 = overlappingLabels(scene.labels, boxes2);
162135
+ const overlaps8 = overlappingLabels(scene.labels, boxes2);
161996
162136
  const biggest = [...scene.groups].sort((a, b) => b.boxes - a.boxes || a.id.localeCompare(b.id))[0];
161997
162137
  return {
161998
162138
  measures: {
161999
162139
  crossings: countCrossings(scene.lines),
162000
162140
  lineOverBox: over.count,
162001
- labelOverlaps: overlaps7.count,
162141
+ labelOverlaps: overlaps8.count,
162002
162142
  smallestTextPx: round(smallestText(scene), 1),
162003
162143
  aspectRatio: scene.height > 0 ? round(scene.width / scene.height, 2) : 0,
162004
162144
  emptySpace: round(emptyShare(scene), 2),
@@ -162011,7 +162151,7 @@ function measureScene(scene) {
162011
162151
  slices: scene.slices
162012
162152
  },
162013
162153
  lineOverBox: over.first,
162014
- labelPair: overlaps7.first,
162154
+ labelPair: overlaps8.first,
162015
162155
  biggestGroup: biggest === void 0 || biggest.boxes === 0 ? null : { id: biggest.id, boxes: biggest.boxes }
162016
162156
  };
162017
162157
  }
@@ -168742,9 +168882,9 @@ var init_ajvProvider_CEoC_sr = __esm({
168742
168882
  }
168743
168883
  get names() {
168744
168884
  var _a3;
168745
- return (_a3 = this._names) !== null && _a3 !== void 0 ? _a3 : this._names = this._items.reduce((names7, c) => {
168746
- if (c instanceof Name) names7[c.str] = (names7[c.str] || 0) + 1;
168747
- return names7;
168885
+ return (_a3 = this._names) !== null && _a3 !== void 0 ? _a3 : this._names = this._items.reduce((names8, c) => {
168886
+ if (c instanceof Name) names8[c.str] = (names8[c.str] || 0) + 1;
168887
+ return names8;
168748
168888
  }, {});
168749
168889
  }
168750
168890
  };
@@ -169079,9 +169219,9 @@ var init_ajvProvider_CEoC_sr = __esm({
169079
169219
  const rhs = this.rhs === void 0 ? "" : ` = ${this.rhs}`;
169080
169220
  return `${varKind} ${this.name}${rhs};` + _n;
169081
169221
  }
169082
- optimizeNames(names7, constants) {
169083
- if (!names7[this.name.str]) return;
169084
- if (this.rhs) this.rhs = optimizeExpr(this.rhs, names7, constants);
169222
+ optimizeNames(names8, constants) {
169223
+ if (!names8[this.name.str]) return;
169224
+ if (this.rhs) this.rhs = optimizeExpr(this.rhs, names8, constants);
169085
169225
  return this;
169086
169226
  }
169087
169227
  get names() {
@@ -169098,9 +169238,9 @@ var init_ajvProvider_CEoC_sr = __esm({
169098
169238
  render({ _n }) {
169099
169239
  return `${this.lhs} = ${this.rhs};` + _n;
169100
169240
  }
169101
- optimizeNames(names7, constants) {
169102
- if (this.lhs instanceof code_1.Name && !names7[this.lhs.str] && !this.sideEffects) return;
169103
- this.rhs = optimizeExpr(this.rhs, names7, constants);
169241
+ optimizeNames(names8, constants) {
169242
+ if (this.lhs instanceof code_1.Name && !names8[this.lhs.str] && !this.sideEffects) return;
169243
+ this.rhs = optimizeExpr(this.rhs, names8, constants);
169104
169244
  return this;
169105
169245
  }
169106
169246
  get names() {
@@ -169159,8 +169299,8 @@ var init_ajvProvider_CEoC_sr = __esm({
169159
169299
  optimizeNodes() {
169160
169300
  return `${this.code}` ? this : void 0;
169161
169301
  }
169162
- optimizeNames(names7, constants) {
169163
- this.code = optimizeExpr(this.code, names7, constants);
169302
+ optimizeNames(names8, constants) {
169303
+ this.code = optimizeExpr(this.code, names8, constants);
169164
169304
  return this;
169165
169305
  }
169166
169306
  get names() {
@@ -169186,19 +169326,19 @@ var init_ajvProvider_CEoC_sr = __esm({
169186
169326
  }
169187
169327
  return nodes.length > 0 ? this : void 0;
169188
169328
  }
169189
- optimizeNames(names7, constants) {
169329
+ optimizeNames(names8, constants) {
169190
169330
  const { nodes } = this;
169191
169331
  let i = nodes.length;
169192
169332
  while (i--) {
169193
169333
  const n = nodes[i];
169194
- if (n.optimizeNames(names7, constants)) continue;
169195
- subtractNames(names7, n.names);
169334
+ if (n.optimizeNames(names8, constants)) continue;
169335
+ subtractNames(names8, n.names);
169196
169336
  nodes.splice(i, 1);
169197
169337
  }
169198
169338
  return nodes.length > 0 ? this : void 0;
169199
169339
  }
169200
169340
  get names() {
169201
- return this.nodes.reduce((names7, n) => addNames(names7, n.names), {});
169341
+ return this.nodes.reduce((names8, n) => addNames(names8, n.names), {});
169202
169342
  }
169203
169343
  };
169204
169344
  var BlockNode = class extends ParentNode {
@@ -169238,18 +169378,18 @@ var init_ajvProvider_CEoC_sr = __esm({
169238
169378
  if (cond === false || !this.nodes.length) return void 0;
169239
169379
  return this;
169240
169380
  }
169241
- optimizeNames(names7, constants) {
169381
+ optimizeNames(names8, constants) {
169242
169382
  var _a3;
169243
- this.else = (_a3 = this.else) === null || _a3 === void 0 ? void 0 : _a3.optimizeNames(names7, constants);
169244
- if (!(super.optimizeNames(names7, constants) || this.else)) return;
169245
- this.condition = optimizeExpr(this.condition, names7, constants);
169383
+ this.else = (_a3 = this.else) === null || _a3 === void 0 ? void 0 : _a3.optimizeNames(names8, constants);
169384
+ if (!(super.optimizeNames(names8, constants) || this.else)) return;
169385
+ this.condition = optimizeExpr(this.condition, names8, constants);
169246
169386
  return this;
169247
169387
  }
169248
169388
  get names() {
169249
- const names7 = super.names;
169250
- addExprNames(names7, this.condition);
169251
- if (this.else) addNames(names7, this.else.names);
169252
- return names7;
169389
+ const names8 = super.names;
169390
+ addExprNames(names8, this.condition);
169391
+ if (this.else) addNames(names8, this.else.names);
169392
+ return names8;
169253
169393
  }
169254
169394
  };
169255
169395
  If.kind = "if";
@@ -169264,9 +169404,9 @@ var init_ajvProvider_CEoC_sr = __esm({
169264
169404
  render(opts) {
169265
169405
  return `for(${this.iteration})` + super.render(opts);
169266
169406
  }
169267
- optimizeNames(names7, constants) {
169268
- if (!super.optimizeNames(names7, constants)) return;
169269
- this.iteration = optimizeExpr(this.iteration, names7, constants);
169407
+ optimizeNames(names8, constants) {
169408
+ if (!super.optimizeNames(names8, constants)) return;
169409
+ this.iteration = optimizeExpr(this.iteration, names8, constants);
169270
169410
  return this;
169271
169411
  }
169272
169412
  get names() {
@@ -169301,9 +169441,9 @@ var init_ajvProvider_CEoC_sr = __esm({
169301
169441
  render(opts) {
169302
169442
  return `for(${this.varKind} ${this.name} ${this.loop} ${this.iterable})` + super.render(opts);
169303
169443
  }
169304
- optimizeNames(names7, constants) {
169305
- if (!super.optimizeNames(names7, constants)) return;
169306
- this.iterable = optimizeExpr(this.iterable, names7, constants);
169444
+ optimizeNames(names8, constants) {
169445
+ if (!super.optimizeNames(names8, constants)) return;
169446
+ this.iterable = optimizeExpr(this.iterable, names8, constants);
169307
169447
  return this;
169308
169448
  }
169309
169449
  get names() {
@@ -169342,18 +169482,18 @@ var init_ajvProvider_CEoC_sr = __esm({
169342
169482
  (_b = this.finally) === null || _b === void 0 || _b.optimizeNodes();
169343
169483
  return this;
169344
169484
  }
169345
- optimizeNames(names7, constants) {
169485
+ optimizeNames(names8, constants) {
169346
169486
  var _a3, _b;
169347
- super.optimizeNames(names7, constants);
169348
- (_a3 = this.catch) === null || _a3 === void 0 || _a3.optimizeNames(names7, constants);
169349
- (_b = this.finally) === null || _b === void 0 || _b.optimizeNames(names7, constants);
169487
+ super.optimizeNames(names8, constants);
169488
+ (_a3 = this.catch) === null || _a3 === void 0 || _a3.optimizeNames(names8, constants);
169489
+ (_b = this.finally) === null || _b === void 0 || _b.optimizeNames(names8, constants);
169350
169490
  return this;
169351
169491
  }
169352
169492
  get names() {
169353
- const names7 = super.names;
169354
- if (this.catch) addNames(names7, this.catch.names);
169355
- if (this.finally) addNames(names7, this.finally.names);
169356
- return names7;
169493
+ const names8 = super.names;
169494
+ if (this.catch) addNames(names8, this.catch.names);
169495
+ if (this.finally) addNames(names8, this.finally.names);
169496
+ return names8;
169357
169497
  }
169358
169498
  };
169359
169499
  var Catch = class extends BlockNode {
@@ -169588,14 +169728,14 @@ var init_ajvProvider_CEoC_sr = __esm({
169588
169728
  }
169589
169729
  };
169590
169730
  exports.CodeGen = CodeGen;
169591
- function addNames(names7, from) {
169592
- for (const n in from) names7[n] = (names7[n] || 0) + (from[n] || 0);
169593
- return names7;
169731
+ function addNames(names8, from) {
169732
+ for (const n in from) names8[n] = (names8[n] || 0) + (from[n] || 0);
169733
+ return names8;
169594
169734
  }
169595
- function addExprNames(names7, from) {
169596
- return from instanceof code_1._CodeOrName ? addNames(names7, from.names) : names7;
169735
+ function addExprNames(names8, from) {
169736
+ return from instanceof code_1._CodeOrName ? addNames(names8, from.names) : names8;
169597
169737
  }
169598
- function optimizeExpr(expr, names7, constants) {
169738
+ function optimizeExpr(expr, names8, constants) {
169599
169739
  if (expr instanceof code_1.Name) return replaceName(expr);
169600
169740
  if (!canOptimize(expr)) return expr;
169601
169741
  return new code_1._Code(expr._items.reduce((items2, c) => {
@@ -169606,16 +169746,16 @@ var init_ajvProvider_CEoC_sr = __esm({
169606
169746
  }, []));
169607
169747
  function replaceName(n) {
169608
169748
  const c = constants[n.str];
169609
- if (c === void 0 || names7[n.str] !== 1) return n;
169610
- delete names7[n.str];
169749
+ if (c === void 0 || names8[n.str] !== 1) return n;
169750
+ delete names8[n.str];
169611
169751
  return c;
169612
169752
  }
169613
169753
  function canOptimize(e) {
169614
- return e instanceof code_1._Code && e._items.some((c) => c instanceof code_1.Name && names7[c.str] === 1 && constants[c.str] !== void 0);
169754
+ return e instanceof code_1._Code && e._items.some((c) => c instanceof code_1.Name && names8[c.str] === 1 && constants[c.str] !== void 0);
169615
169755
  }
169616
169756
  }
169617
- function subtractNames(names7, from) {
169618
- for (const n in from) names7[n] = (names7[n] || 0) - (from[n] || 0);
169757
+ function subtractNames(names8, from) {
169758
+ for (const n in from) names8[n] = (names8[n] || 0) - (from[n] || 0);
169619
169759
  }
169620
169760
  function not(x) {
169621
169761
  return typeof x == "boolean" || typeof x == "number" || x === null ? !x : (0, code_1._)`!${par(x)}`;
@@ -169780,7 +169920,7 @@ var init_ajvProvider_CEoC_sr = __esm({
169780
169920
  require_names = /* @__PURE__ */ __commonJSMin(((exports) => {
169781
169921
  Object.defineProperty(exports, "__esModule", { value: true });
169782
169922
  const codegen_1 = require_codegen();
169783
- const names7 = {
169923
+ const names8 = {
169784
169924
  data: new codegen_1.Name("data"),
169785
169925
  valCxt: new codegen_1.Name("valCxt"),
169786
169926
  instancePath: new codegen_1.Name("instancePath"),
@@ -169798,7 +169938,7 @@ var init_ajvProvider_CEoC_sr = __esm({
169798
169938
  jsonLen: new codegen_1.Name("jsonLen"),
169799
169939
  jsonPart: new codegen_1.Name("jsonPart")
169800
169940
  };
169801
- exports.default = names7;
169941
+ exports.default = names8;
169802
169942
  }));
169803
169943
  require_errors = /* @__PURE__ */ __commonJSMin(((exports) => {
169804
169944
  Object.defineProperty(exports, "__esModule", { value: true });
@@ -177906,7 +178046,7 @@ var IMPORT_FORMATS, IMPORT_VIEWS, IMPORT_CHARTS, IMPORT_GROUP_BY, NO_STATS;
177906
178046
  var init_types2 = __esm({
177907
178047
  "../../packages/diagrams/src/importers/types.ts"() {
177908
178048
  "use strict";
177909
- IMPORT_FORMATS = ["sql", "prisma", "drizzle", "openapi", "terraform", "bicep", "arm", "pulumi", "cloudformation", "compose", "kubernetes", "github-actions", "csv", "json", "tree", "git-log"];
178049
+ IMPORT_FORMATS = ["sql", "prisma", "drizzle", "openapi", "terraform", "terraform-plan", "bicep", "arm", "pulumi", "cloudformation", "compose", "kubernetes", "github-actions", "csv", "json", "tree", "git-log"];
177910
178050
  IMPORT_VIEWS = ["endpoints", "map", "sequence", "git", "timeline"];
177911
178051
  IMPORT_CHARTS = ["auto", "xychart", "pie", "sankey", "treemap", "matrix"];
177912
178052
  IMPORT_GROUP_BY = ["module", "network", "file"];
@@ -178520,7 +178660,7 @@ var init_import_source = __esm({
178520
178660
  init_kinds2();
178521
178661
  init_workflows();
178522
178662
  ImportSourceInputSchema = external_exports.object({
178523
- format: external_exports.enum(IMPORT_FORMATS).describe("What the text is. sql, prisma, drizzle: a schema. openapi: endpoints or a sequence. terraform, bicep, arm, pulumi, cloudformation, compose, kubernetes, github-actions: a flow. csv, json: a chart. tree: a tree. git-log: a git graph or timeline."),
178663
+ format: external_exports.enum(IMPORT_FORMATS).describe("What the text is. sql, prisma, drizzle: a schema. openapi: endpoints or a sequence. terraform, terraform-plan (terraform show -json), bicep, arm, pulumi, cloudformation, compose, kubernetes, github-actions: a flow. csv, json: a chart. tree: a tree. git-log: a git graph or timeline."),
178524
178664
  // Neither text nor files has a length here: a call over the limits is answered with I102 and a hint, as data.
178525
178665
  text: external_exports.string().optional().describe("The file content, as text. Send text or files, not both."),
178526
178666
  files: external_exports.array(
@@ -181026,6 +181166,7 @@ var init_detect = __esm({
181026
181166
  { format: "prisma", test: (text3) => /^\s*model\s+\w+\s*\{/m.test(text3) && /@id\b|@relation\b|^\s*datasource\s+\w+\s*\{/m.test(text3) },
181027
181167
  { format: "drizzle", test: (text3) => /\b(?:pgTable|sqliteTable|mysqlTable)\s*\(/.test(text3) },
181028
181168
  { format: "openapi", test: (text3) => /^\s*["']?openapi["']?\s*:\s*["']?3\./m.test(text3) || /"openapi"\s*:\s*"3\./.test(text3) },
181169
+ { format: "terraform-plan", test: (text3) => /^\s*\{\s*"format_version"\s*:/.test(text3) && /"terraform_version"\s*:/.test(text3) && /"(?:planned_values|resource_changes|root_module)"\s*:/.test(text3) },
181029
181170
  { format: "terraform", test: (text3) => /^\s*resource\s+"[A-Za-z0-9_]+"\s+"[^"]+"\s*\{/m.test(text3) },
181030
181171
  { format: "bicep", test: (text3) => /^\s*(?:resource|module)\s+[A-Za-z_]\w*\s+'[^'\n]+'\s*(?:existing\s*)?=/m.test(text3) || /^\s*targetScope\s*=\s*'/m.test(text3) },
181031
181172
  { format: "arm", test: (text3) => /"\$schema"\s*:\s*"https?:\/\/schema\.management\.azure\.com\/schemas\/[^"]*(?:deploymentTemplate|DeploymentTemplate)/.test(text3) },
@@ -181044,6 +181185,7 @@ var init_detect = __esm({
181044
181185
  { format: "compose", words: /\b(?:docker[- ]compose|compose (?:file|yaml|yml|stack))\b/i },
181045
181186
  { format: "kubernetes", words: /\b(?:kubernetes|k8s)\b/i },
181046
181187
  { format: "github-actions", words: /\b(?:github actions?|workflow (?:file|yaml|yml)|ci workflow)\b/i },
181188
+ { format: "terraform-plan", words: /\b(?:terraform|tofu) (?:plan|state|show -json)\b|\bplan\.json\b/i },
181047
181189
  { format: "terraform", words: /\b(?:terraform|opentofu|hcl|\.tf files?)\b/i },
181048
181190
  { format: "bicep", words: /\b(?:bicep|\.bicep files?)\b/i },
181049
181191
  { format: "arm", words: /\b(?:arm templates?|azure resource manager|azuredeploy\.json)\b/i },
@@ -181058,7 +181200,7 @@ var init_detect = __esm({
181058
181200
  { format: "json", words: /\bjson (?:data|file|records|export)\b/i },
181059
181201
  { format: "tree", words: /\b(?:tree output|folder (?:structure|tree|listing)|directory (?:tree|listing))\b/i }
181060
181202
  ];
181061
- SURE_FROM_DATA = /* @__PURE__ */ new Set(["sql", "prisma", "drizzle", "openapi", "terraform", "bicep", "arm", "pulumi", "cloudformation", "compose", "kubernetes", "github-actions", "git-log"]);
181203
+ SURE_FROM_DATA = /* @__PURE__ */ new Set(["sql", "prisma", "drizzle", "openapi", "terraform", "terraform-plan", "bicep", "arm", "pulumi", "cloudformation", "compose", "kubernetes", "github-actions", "git-log"]);
181062
181204
  }
181063
181205
  });
181064
181206
 
@@ -181499,8 +181641,8 @@ function fewer(parts, most, biggest) {
181499
181641
  return out;
181500
181642
  }
181501
181643
  function titleOf2(units) {
181502
- const names7 = [...new Set(units.map((unit3) => unit3.name))];
181503
- return names7.length <= 2 ? names7.join(" and ") : `${names7.slice(0, 2).join(", ")}, and ${names7.length - 2} more`;
181644
+ const names8 = [...new Set(units.map((unit3) => unit3.name))];
181645
+ return names8.length <= 2 ? names8.join(" and ") : `${names8.slice(0, 2).join(", ")}, and ${names8.length - 2} more`;
181504
181646
  }
181505
181647
  function bundleLabel(edges) {
181506
181648
  const counts = /* @__PURE__ */ new Map();
@@ -181673,7 +181815,7 @@ function writeOneFlow(draft, report3) {
181673
181815
  const nodeLine4 = (node3, depth) => {
181674
181816
  const named2 = node3.type === "decision" || node3.type === "terminal" ? null : iconNamedBy(node3.label, draft.provider ?? null) ?? (node3.sub === void 0 || node3.sub === null ? null : iconNamedBy(node3.sub, draft.provider ?? null));
181675
181817
  const icon = known2(node3.icon ?? null) ?? known2(named2);
181676
- lines.add(`node ${ids.idFor(`node:${node3.key}`)} ${node3.type} ${quote(node3.label)}${options2({ sub: node3.sub ?? null, icon, tone: node3.tone ?? null })}`, depth);
181818
+ lines.add(`node ${ids.idFor(`node:${node3.key}`)} ${node3.type} ${quote(node3.label)}${options2({ sub: node3.sub ?? null, icon, tone: node3.tone ?? null, change: node3.change ?? null })}`, depth);
181677
181819
  };
181678
181820
  const writtenGroups = new Set(groups.map((group2) => group2.key));
181679
181821
  const effective = /* @__PURE__ */ new Map();
@@ -181685,11 +181827,11 @@ function writeOneFlow(draft, report3) {
181685
181827
  }
181686
181828
  effective.set(group2.key, parent);
181687
181829
  }
181688
- const parentOf3 = (group2) => effective.get(group2.key) ?? null;
181689
- const children = (parent) => groups.filter((group2) => parentOf3(group2) === parent);
181830
+ const parentOf4 = (group2) => effective.get(group2.key) ?? null;
181831
+ const children = (parent) => groups.filter((group2) => parentOf4(group2) === parent);
181690
181832
  const writeGroup = (group2, depth) => {
181691
181833
  lines.gap();
181692
- lines.add(`group ${ids.idFor(`group:${group2.key}`)} ${quote(group2.label)}${options2({ type: group2.type ?? namedType(group2.label), icon: known2(group2.icon ?? null), sub: group2.sub ?? null })} {`, depth);
181834
+ lines.add(`group ${ids.idFor(`group:${group2.key}`)} ${quote(group2.label)}${options2({ type: group2.type ?? namedType(group2.label), icon: known2(group2.icon ?? null), sub: group2.sub ?? null, tone: group2.tone ?? null })} {`, depth);
181693
181835
  for (const node3 of kept2) if ((node3.group ?? null) === group2.key) nodeLine4(node3, depth + 1);
181694
181836
  for (const child of children(group2.key)) writeGroup(child, depth + 1);
181695
181837
  lines.add("}", depth);
@@ -181777,8 +181919,8 @@ function chosenTables(tables, patterns, report3) {
181777
181919
  if (patterns === void 0 || patterns.length === 0) return tables;
181778
181920
  const chosen = tables.filter((table2) => patterns.some((pattern3) => matches2(table2, pattern3)));
181779
181921
  if (chosen.length === 0) {
181780
- const names7 = tables.slice(0, 12).map((table2) => table2.key);
181781
- report3.add(DIAGNOSTIC_CODES.importNotFound, START, `No table matches ${patterns.map((pattern3) => `"${pattern3}"`).join(", ")}.`, `Name tables the file has, such as ${names7.join(", ")}${tables.length > names7.length ? ", and more" : ""}, or a prefix such as ${names7[0] ?? "users"}*.`);
181922
+ const names8 = tables.slice(0, 12).map((table2) => table2.key);
181923
+ report3.add(DIAGNOSTIC_CODES.importNotFound, START, `No table matches ${patterns.map((pattern3) => `"${pattern3}"`).join(", ")}.`, `Name tables the file has, such as ${names8.join(", ")}${tables.length > names8.length ? ", and more" : ""}, or a prefix such as ${names8[0] ?? "users"}*.`);
181782
181924
  return null;
181783
181925
  }
181784
181926
  return chosen;
@@ -181826,11 +181968,11 @@ function clusterOrder(tables, relations) {
181826
181968
  return [...tables.filter((table2) => hubs.has(fold(table2.key))), ...areasOf(tables, relations).flatMap((area) => area.members)];
181827
181969
  }
181828
181970
  function partOf(area) {
181829
- const names7 = area.members.map((table2) => fold(table2.key));
181971
+ const names8 = area.members.map((table2) => fold(table2.key));
181830
181972
  const firstWord2 = (name2) => name2.split("_")[0] ?? name2;
181831
- const prefix = firstWord2(names7[0] ?? "");
181832
- const shared = names7.length > 1 && prefix !== "" && names7.every((name2) => firstWord2(name2) === prefix && name2.includes("_"));
181833
- const written3 = [...area.hubs.map((table2) => fold(table2.key)), ...shared ? [`${prefix}_*`] : names7];
181973
+ const prefix = firstWord2(names8[0] ?? "");
181974
+ const shared = names8.length > 1 && prefix !== "" && names8.every((name2) => firstWord2(name2) === prefix && name2.includes("_"));
181975
+ const written3 = [...area.hubs.map((table2) => fold(table2.key)), ...shared ? [`${prefix}_*`] : names8];
181834
181976
  const shown = written3.slice(0, NAMES_PER_PART).map((name2) => `"${name2}"`);
181835
181977
  return `[${shown.join(", ")}${written3.length > shown.length ? ", ..." : ""}]`;
181836
181978
  }
@@ -181989,8 +182131,8 @@ function writeSchema(draft, report3) {
181989
182131
  if (chosen === null) return null;
181990
182132
  const allTables = draft.tables.length;
181991
182133
  const filtered = chosen.length < draft.tables.length;
181992
- const names7 = new Set(chosen.map((table2) => fold3(table2.key)));
181993
- const inside = draft.relations.filter((relation2) => names7.has(fold3(relation2.fromTable)) && names7.has(fold3(relation2.toTable)));
182134
+ const names8 = new Set(chosen.map((table2) => fold3(table2.key)));
182135
+ const inside = draft.relations.filter((relation2) => names8.has(fold3(relation2.fromTable)) && names8.has(fold3(relation2.toTable)));
181994
182136
  const outside = filtered ? draft.relations.length - inside.length : 0;
181995
182137
  const ordered = clusterOrder(chosen, inside);
181996
182138
  if (ordered.length <= WORKFLOW_LIMITS.maxImportTables) adviseSplit(ordered, inside, filtered, report3);
@@ -182028,14 +182170,14 @@ function writeOneSchema(draft, report3, cap2, allTables, outside) {
182028
182170
  const id = tableIds.idFor(fold3(table2.key), table2.key);
182029
182171
  named[table2.key] = id;
182030
182172
  const label = table2.label === id ? "" : ` ${quote(table2.label)}`;
182031
- const names7 = new IdAllocator(false);
182173
+ const names8 = new IdAllocator(false);
182032
182174
  const byName = /* @__PURE__ */ new Map();
182033
182175
  columnIds.set(fold3(table2.key), byName);
182034
182176
  lines.gap();
182035
182177
  lines.add(`table ${id}${label} {`);
182036
182178
  for (const column of table2.columns) {
182037
182179
  if (byName.has(fold3(column.name))) continue;
182038
- const name2 = names7.idFor(fold3(column.name), column.name);
182180
+ const name2 = names8.idFor(fold3(column.name), column.name);
182039
182181
  byName.set(fold3(column.name), name2);
182040
182182
  const flags = [column.pk === true ? "pk" : "", column.fk === true ? "fk" : "", column.unique === true && column.pk !== true ? "unique" : "", column.nullable === true && column.pk !== true ? "nullable" : ""].filter((flag) => flag !== "");
182041
182183
  const note = column.note ?? (name2 === column.name ? null : column.name);
@@ -183206,10 +183348,10 @@ var init_plan9 = __esm({
183206
183348
  /** The variable a placement attribute names for a frame of a type, when it names no resource. */
183207
183349
  variableFrame(resource, attribute2) {
183208
183350
  const type = PLACEMENT_GROUP_TYPES[attribute2];
183209
- const names7 = resource.vars.get(attribute2) ?? [];
183210
- if (type === void 0 || names7.length === 0 || (resource.byAttribute.get(attribute2) ?? []).length > 0) return null;
183351
+ const names8 = resource.vars.get(attribute2) ?? [];
183352
+ if (type === void 0 || names8.length === 0 || (resource.byAttribute.get(attribute2) ?? []).length > 0) return null;
183211
183353
  const words2 = VARIABLE_WORDS[type];
183212
- const name2 = names7.length === 1 ? names7[0] : names7.find((candidate2) => words2?.test(candidate2) === true);
183354
+ const name2 = names8.length === 1 ? names8[0] : names8.find((candidate2) => words2?.test(candidate2) === true);
183213
183355
  if (name2 === void 0) return null;
183214
183356
  const value = this.variableValue(name2);
183215
183357
  const same = value === null ? void 0 : [...this.resources.values()].find((other) => this.shapes.get(other.key) === "frame" && other.key !== resource.key && this.frameType(other.key) !== null && sameKind(this.frameType(other.key), type) && other.values.get("name") === value);
@@ -183653,6 +183795,35 @@ var init_module_frames = __esm({
183653
183795
  }
183654
183796
  });
183655
183797
 
183798
+ // ../../packages/diagrams/src/importers/terraform/network-layer.ts
183799
+ function layerNetworks(plan) {
183800
+ let moved3 = false;
183801
+ for (const [key, parent] of [...plan.parents]) {
183802
+ const resource = plan.resources.get(key.replace(/^(?:frame|anchor):/, ""));
183803
+ if (resource === void 0 || NETWORK_TYPE.test(resource.type)) continue;
183804
+ let target = parent;
183805
+ for (let depth = 0; target !== void 0 && depth < MAX_DEPTH5; depth += 1) {
183806
+ const type = plan.frameType(target);
183807
+ if (type === null || !NETWORK_FRAMES.has(type)) break;
183808
+ target = plan.parents.get(target);
183809
+ }
183810
+ if (target === parent) continue;
183811
+ if (target === void 0) plan.parents.delete(key);
183812
+ else plan.parents.set(key, target);
183813
+ moved3 = true;
183814
+ }
183815
+ return moved3;
183816
+ }
183817
+ var MAX_DEPTH5, NETWORK_FRAMES, NETWORK_TYPE;
183818
+ var init_network_layer = __esm({
183819
+ "../../packages/diagrams/src/importers/terraform/network-layer.ts"() {
183820
+ "use strict";
183821
+ MAX_DEPTH5 = 16;
183822
+ NETWORK_FRAMES = /* @__PURE__ */ new Set(["network", "subnet", "public-subnet", "private-subnet", "management-subnet", "isolated-subnet"]);
183823
+ NETWORK_TYPE = /^(?:azurerm_(?:virtual_network|subnet|network_|route|nat_gateway|public_ip|firewall|application_gateway|lb$|lb_|private_dns)|aws_(?:vpc|subnet|security_group|network_acl|route|internet_gateway|nat_gateway|eip|egress_only)|google_compute_(?:network|subnetwork|firewall|router|route|address))/;
183824
+ }
183825
+ });
183826
+
183656
183827
  // ../../packages/diagrams/src/importers/terraform/module-icons.ts
183657
183828
  function moduleWords(name2, source) {
183658
183829
  const segments = source.replace(/[?#].*$/, "").replace(/\.git$/, "").split(/[/:]/).filter((part) => part !== "" && !NOISE.has(part.toLowerCase()));
@@ -183794,9 +183965,9 @@ function picture(plan, context, groupType) {
183794
183965
  if (near3 !== void 0 && near3 !== null) plan.parents.set(key, near3);
183795
183966
  }
183796
183967
  plan.wrapAccounts();
183797
- const names7 = /* @__PURE__ */ new Map();
183798
- for (const resource of resources.values()) if (plan.isBox(resource.key) || plan.shapes.get(resource.key) === "frame") names7.set(resource.name, (names7.get(resource.name) ?? 0) + 1);
183799
- const shared = new Set([...names7].filter(([, count3]) => count3 > 1).map(([name2]) => name2));
183968
+ const names8 = /* @__PURE__ */ new Map();
183969
+ for (const resource of resources.values()) if (plan.isBox(resource.key) || plan.shapes.get(resource.key) === "frame") names8.set(resource.name, (names8.get(resource.name) ?? 0) + 1);
183970
+ const shared = new Set([...names8].filter(([, count3]) => count3 > 1).map(([name2]) => name2));
183800
183971
  const files = /* @__PURE__ */ new Map();
183801
183972
  const fileFrame = (resource) => {
183802
183973
  const path = fileOf(resource, context.files);
@@ -183807,7 +183978,7 @@ function picture(plan, context, groupType) {
183807
183978
  const groups = [];
183808
183979
  const nodes = [];
183809
183980
  const drawn = /* @__PURE__ */ new Set();
183810
- const parentOf3 = (key, resource) => {
183981
+ const parentOf4 = (key, resource) => {
183811
183982
  if (!byFile) return plan.parents.get(key) ?? null;
183812
183983
  const holder = plan.holder.get(resource.key);
183813
183984
  const holderResource = holder === void 0 ? void 0 : resources.get(holder);
@@ -183833,12 +184004,12 @@ function picture(plan, context, groupType) {
183833
184004
  const box = boxOf2(resource, plan, shared);
183834
184005
  if (shape === "container") {
183835
184006
  const frame = containerFrame(resource.key);
183836
- const parent = byFile ? parentOf3(frame, resource) : plan.parents.get(frame) ?? null;
184007
+ const parent = byFile ? parentOf4(frame, resource) : plan.parents.get(frame) ?? null;
183837
184008
  groups.push({ key: frame, label: box.label, type: null, icon: box.icon ?? null, sub: null, parent, idHint: `${resource.name}_group` });
183838
184009
  const product = role.role === "node" ? productOf2(resource, plan) : box.label;
183839
184010
  nodes.push({ ...box, label: box.label === product ? box.label : product, sub: box.label === product ? box.sub ?? null : withParts(literalDetails(resource), multiplicity(resource), resource.kind === "data" && !plan.compatible ? "existing" : null), group: frame });
183840
184011
  } else {
183841
- nodes.push({ ...box, group: parentOf3(resource.key, resource) });
184012
+ nodes.push({ ...box, group: parentOf4(resource.key, resource) });
183842
184013
  }
183843
184014
  drawn.add(resource.key);
183844
184015
  } else if (shape === "nested") {
@@ -183867,7 +184038,7 @@ function picture(plan, context, groupType) {
183867
184038
  }
183868
184039
  for (const [key, path] of files) groups.push({ key, label: path === "" ? "main.tf" : path, type: null, icon: "lucide:file-code", sub: null, parent: null, idHint: path.replace(/\.tf$/, "") });
183869
184040
  if (byFile) {
183870
- for (const [child, holder] of plan.holder) if (parentOf3(child, resources.get(child)) !== containerFrame(holder)) arrows.push({ from: child, to: holder, label: "in", grant: false, via: child });
184041
+ for (const [child, holder] of plan.holder) if (parentOf4(child, resources.get(child)) !== containerFrame(holder)) arrows.push({ from: child, to: holder, label: "in", grant: false, via: child });
183871
184042
  for (const [subject, host] of plan.attached) for (const via of plan.attachedBy.get(subject) ?? []) arrows.push({ from: subject, to: anchorOf(host), label: "attached", grant: false, via });
183872
184043
  }
183873
184044
  return { groups, nodes, arrows, drawn };
@@ -183916,8 +184087,8 @@ function anchorBox(plan, key, groupType, byFile) {
183916
184087
  }
183917
184088
  function literalDetails(resource) {
183918
184089
  const role = resource.role;
183919
- const names7 = role.role === "node" ? role.detail ?? [] : ["sku_name", "os_type", "sku"];
183920
- const values = names7.map((name2) => literal2(resource, name2)).filter((value) => value !== null && value !== "");
184090
+ const names8 = role.role === "node" ? role.detail ?? [] : ["sku_name", "os_type", "sku"];
184091
+ const values = names8.map((name2) => literal2(resource, name2)).filter((value) => value !== null && value !== "");
183921
184092
  return values.length === 0 ? null : values.join(" ");
183922
184093
  }
183923
184094
  var ACCOUNT_NAMES;
@@ -183944,6 +184115,7 @@ function drawStack(input2) {
183944
184115
  const resources = compatible ? new Map([...input2.resources].map(([key, resource]) => [key, withoutNewNames(resource)])) : input2.resources;
183945
184116
  const plan = new StackPlan(resources, groupType, input2.providers, input2.variableName, input2.variableValue, compatible ? void 0 : input2.regionOf);
183946
184117
  plan.compatible = compatible;
184118
+ const layered = input2.layered === true && input2.modules.length === 0 && layerNetworks(plan);
183947
184119
  if (context.options.groupBy === void 0 || context.options.groupBy === "module") frameModules(plan, input2.modules);
183948
184120
  const frameless = ![...plan.shapes.values()].some((shape) => shape === "frame" || shape === "container") && ![...plan.outer.values()].some((outer) => outer.type !== "account") && plan.modules.size === 0;
183949
184121
  const boxCount = [...plan.shapes.values()].filter((shape) => shape === "node").length;
@@ -183957,7 +184129,11 @@ function drawStack(input2) {
183957
184129
  for (const arrow of written3) drawn.add(arrow.via);
183958
184130
  const bundled = bundleArrows(drafted.nodes, drafted.groups, joinArrows(written3), (frame) => plan.resources.has(frame) || plan.outer.has(frame) ? anchorBox(plan, frame, groupType, context.options.groupBy === "file") : null, !compatible);
183959
184131
  const edges = bundled.edges;
183960
- const { nodes, groups } = withoutIdleBoxes(bundled.nodes, drafted.groups, edges);
184132
+ const idle = withoutIdleBoxes(bundled.nodes, drafted.groups, edges);
184133
+ const changeOf = input2.change;
184134
+ const groups = changeOf === void 0 ? idle.groups : idle.groups.map((group2) => withChange(group2, changeOf(itemKey(group2.key))));
184135
+ const framed = new Set(idle.groups.map((group2) => itemKey(group2.key)));
184136
+ const nodes = changeOf === void 0 ? idle.nodes : idle.nodes.map((node3) => withMark(withChange(node3, changeOf(itemKey(node3.key)), !framed.has(itemKey(node3.key))), changeOf(itemKey(node3.key))));
183961
184137
  let total = 0;
183962
184138
  let counted2 = 0;
183963
184139
  for (const resource of resources.values()) {
@@ -183969,11 +184145,11 @@ function drawStack(input2) {
183969
184145
  const provider = providers.size === 1 ? [...providers][0] : providers.size === 0 ? input2.cloud ?? null : null;
183970
184146
  const owner = provider === null ? null : SHORT_NAMES2[provider] ?? CLOUD_PROVIDER_SPECS[provider].title;
183971
184147
  const where = owner === null ? "on more than one cloud" : `on ${owner}`;
183972
- const nesting2 = context.options.groupBy === "file" ? "framed by the file that declares them" : plan.modules.size > 0 ? "framed by the module that declares them and nested in the groups, networks, and subnets that hold them" : "nested in the groups, networks, and subnets that hold them";
183973
- const title = context.title ?? (owner === null ? "Cloud infrastructure" : `${owner} infrastructure`);
184148
+ const nesting2 = context.options.groupBy === "file" ? "framed by the file that declares them" : plan.modules.size > 0 ? "framed by the module that declares them and nested in the groups, networks, and subnets that hold them" : layered ? "nested in the groups that hold them, beside the network, with an arrow to the subnet each one sits in" : "nested in the groups, networks, and subnets that hold them";
184149
+ const title = context.title ?? `${owner === null ? "Cloud infrastructure" : `${owner} infrastructure`}${input2.summary === void 0 ? "" : `: ${input2.summary}`}`;
183974
184150
  const draft = {
183975
184151
  title,
183976
- desc: `${countOf2(total, "resource")} ${where}, ${nesting2}, imported from ${input2.tool}. An arrow means one resource refers to another, and its label says how: a role, a private link, logs, or a secret.`,
184152
+ desc: `${countOf2(total, "resource")} ${where}, ${nesting2}, imported from ${input2.tool}. An arrow means one resource refers to another, and its label says how: a role, a private link, logs, or a secret.${input2.note === void 0 ? "" : ` ${input2.note}`}`,
183977
184153
  // Modules read as layers, from the root's callers down to what they use.
183978
184154
  direction: plan.modules.size > 0 ? "down" : directionOf4(nodes.map((node3) => node3.key), edges),
183979
184155
  provider,
@@ -183992,6 +184168,12 @@ function drawStack(input2) {
183992
184168
  const whole2 = writeFlow({ ...draft, cap: Number.POSITIVE_INFINITY }, new ImportReporter());
183993
184169
  return renamed({ ...whole2, source: parts[0]?.source ?? whole2.source, parts });
183994
184170
  }
184171
+ function withChange(item, change, worded = true) {
184172
+ return change === null ? item : { ...item, tone: change.tone, sub: worded ? withParts(item.sub ?? null, change.word) : item.sub ?? null };
184173
+ }
184174
+ function withMark(node3, change) {
184175
+ return change?.mark === void 0 ? node3 : { ...node3, change: change.mark };
184176
+ }
183995
184177
  function withoutNewNames(resource) {
183996
184178
  const values = new Map(resource.values);
183997
184179
  values.delete("tags.Name");
@@ -184019,7 +184201,7 @@ function joinRoots(drafts2) {
184019
184201
  ids: parts[0]?.ids ?? {}
184020
184202
  };
184021
184203
  }
184022
- var SHORT_NAMES2;
184204
+ var SHORT_NAMES2, itemKey;
184023
184205
  var init_draw = __esm({
184024
184206
  "../../packages/diagrams/src/importers/terraform/draw.ts"() {
184025
184207
  "use strict";
@@ -184029,10 +184211,12 @@ var init_draw = __esm({
184029
184211
  init_edges2();
184030
184212
  init_labels();
184031
184213
  init_module_frames();
184214
+ init_network_layer();
184032
184215
  init_picture();
184033
184216
  init_plan9();
184034
184217
  init_resources();
184035
184218
  SHORT_NAMES2 = { aws: "AWS", azure: "Azure", gcp: "Google Cloud" };
184219
+ itemKey = (key) => key.replace(/^(?:anchor|frame):/, "");
184036
184220
  }
184037
184221
  });
184038
184222
 
@@ -184257,13 +184441,13 @@ function lastPart(value) {
184257
184441
  if (!value.includes("/")) return value;
184258
184442
  return value.split("/").filter((part) => part !== "").pop() ?? value;
184259
184443
  }
184260
- var MAX_DEPTH5, MAX_VALUE_LENGTH, MAX_ENTRIES, ValueResolver;
184444
+ var MAX_DEPTH6, MAX_VALUE_LENGTH, MAX_ENTRIES, ValueResolver;
184261
184445
  var init_values2 = __esm({
184262
184446
  "../../packages/diagrams/src/importers/terraform/values.ts"() {
184263
184447
  "use strict";
184264
184448
  init_expressions();
184265
184449
  init_parse21();
184266
- MAX_DEPTH5 = 8;
184450
+ MAX_DEPTH6 = 8;
184267
184451
  MAX_VALUE_LENGTH = 600;
184268
184452
  MAX_ENTRIES = 64;
184269
184453
  ValueResolver = class _ValueResolver {
@@ -184321,7 +184505,7 @@ var init_values2 = __esm({
184321
184505
  }
184322
184506
  /** The value of an expression as written, or null when it cannot be known from the text. */
184323
184507
  value(raw, depth = 0) {
184324
- if (depth > MAX_DEPTH5) return null;
184508
+ if (depth > MAX_DEPTH6) return null;
184325
184509
  const text3 = raw.trim();
184326
184510
  const memoKey = `${depth}\0${text3}`;
184327
184511
  if (this.memo.has(memoKey)) return this.memo.get(memoKey) ?? null;
@@ -184342,7 +184526,7 @@ var init_values2 = __esm({
184342
184526
  const part = (expression2) => this.value(expression2, depth + 1) ?? this.readable(expression2, depth + 1) ?? `{${shortName(expression2)}}`;
184343
184527
  if (text3.startsWith('"') && text3.endsWith('"') && text3.length >= 2 && interpolationsClosed(text3)) return this.template(text3.slice(1, -1), depth, part);
184344
184528
  const call = /^(format|join|lower|upper)\(([\s\S]*)\)$/.exec(text3);
184345
- if (call === null || depth > MAX_DEPTH5) return null;
184529
+ if (call === null || depth > MAX_DEPTH6) return null;
184346
184530
  const args = argumentsOf(call[2] ?? "");
184347
184531
  if (args === null || args.length === 0) return null;
184348
184532
  if (call[1] === "format") {
@@ -184368,7 +184552,7 @@ var init_values2 = __esm({
184368
184552
  * `toset`, `tolist`, `keys`, `values`, `merge`, `each.value`, and a `for` over a known map or list. Null when unknown.
184369
184553
  */
184370
184554
  collection(raw, depth = 0) {
184371
- if (depth > MAX_DEPTH5) return null;
184555
+ if (depth > MAX_DEPTH6) return null;
184372
184556
  const text3 = raw.trim();
184373
184557
  if (text3.startsWith("{") && text3.endsWith("}")) {
184374
184558
  const forMap = /^\{\s*for\s+([A-Za-z_]\w*)\s*(?:,\s*([A-Za-z_]\w*)\s*)?in\s+([^:]+):\s*([A-Za-z_]\w*)\s*=>/.exec(text3);
@@ -184462,7 +184646,7 @@ var init_values2 = __esm({
184462
184646
  fieldOf(base, fields, depth) {
184463
184647
  let current = base;
184464
184648
  for (const field of fields) {
184465
- if (current === null || depth > MAX_DEPTH5) return null;
184649
+ if (current === null || depth > MAX_DEPTH6) return null;
184466
184650
  const map2 = current.scope.collection(current.raw, depth + 1);
184467
184651
  if (map2?.kind !== "map") return null;
184468
184652
  current = map2.entries.find(([key]) => key === field)?.[1] ?? null;
@@ -184742,6 +184926,10 @@ function providerName(block, type, scope) {
184742
184926
  const written3 = block.attributes.find((attribute2) => attribute2.name === "provider")?.raw.trim() ?? type.split("_")[0] ?? "";
184743
184927
  return scope.providers.get(written3) ?? written3;
184744
184928
  }
184929
+ function copyName(name2, key) {
184930
+ if (key === null) return name2;
184931
+ return (PLAIN_NAMES.has(name2.toLowerCase()) ? key : `${name2} ${key}`).replace(/[^A-Za-z0-9_-]+/g, "_");
184932
+ }
184745
184933
  function readResources(root) {
184746
184934
  const bySite = new Map(allScopes(root).map((scope) => [scope.prefix, scope]));
184747
184935
  const readers = /* @__PURE__ */ new Map();
@@ -184805,12 +184993,11 @@ function readResources(root) {
184805
184993
  const tags = block.attributes.find((attribute2) => attribute2.name === "tags");
184806
184994
  const tagName3 = tags === void 0 ? null : resolver.fieldValue(tags.raw, "Name");
184807
184995
  if (tagName3 !== null) values.set("tags.Name", tagName3);
184808
- const name2 = copy.key === null ? id.name : PLAIN_NAMES.has(id.name.toLowerCase()) ? copy.key : `${id.name} ${copy.key}`;
184809
184996
  resources.set(key, {
184810
184997
  key,
184811
184998
  kind: id.kind,
184812
184999
  type: id.type,
184813
- name: copy.key === null ? name2 : name2.replace(/[^A-Za-z0-9_-]+/g, "_"),
185000
+ name: copyName(id.name, copy.key),
184814
185001
  block,
184815
185002
  role,
184816
185003
  refs: from((attribute2) => !PLACEMENT_ATTRIBUTES.has(attribute2.name)),
@@ -184852,7 +185039,7 @@ function readResources(root) {
184852
185039
  }
184853
185040
  return { resources, modules, empty };
184854
185041
  }
184855
- var MAX_DEPTH6, TYPE, unique, ScopeReader, isItem2, PLAIN_NAMES, NAMED;
185042
+ var MAX_DEPTH7, TYPE, unique, ScopeReader, isItem2, PLAIN_NAMES, NAMED;
184856
185043
  var init_graph4 = __esm({
184857
185044
  "../../packages/diagrams/src/importers/terraform/graph.ts"() {
184858
185045
  "use strict";
@@ -184862,7 +185049,7 @@ var init_graph4 = __esm({
184862
185049
  init_modules2();
184863
185050
  init_parse21();
184864
185051
  init_resources();
184865
- MAX_DEPTH6 = 6;
185052
+ MAX_DEPTH7 = 6;
184866
185053
  TYPE = /^[a-z][a-z0-9]*_[a-z0-9_]+$/;
184867
185054
  unique = (values) => [...new Set(values)];
184868
185055
  ScopeReader = class {
@@ -184882,7 +185069,7 @@ var init_graph4 = __esm({
184882
185069
  }
184883
185070
  /** Every address a text names, with `var.` names for the variables that name no item: `aws_vpc.main`, `module.network.azurerm_subnet.this["app"]`, `var.region`. */
184884
185071
  read(text3, depth = 0) {
184885
- if (depth > MAX_DEPTH6) return [];
185072
+ if (depth > MAX_DEPTH7) return [];
184886
185073
  const out = [];
184887
185074
  for (const steps of references(text3)) out.push(...this.interpret(steps, depth));
184888
185075
  return out;
@@ -184971,7 +185158,7 @@ var init_graph4 = __esm({
184971
185158
 
184972
185159
  // ../../packages/diagrams/src/importers/terraform/json-syntax.ts
184973
185160
  function expression(value, depth) {
184974
- if (depth > MAX_DEPTH7) return "null";
185161
+ if (depth > MAX_DEPTH8) return "null";
184975
185162
  if (typeof value === "string") return JSON.stringify(value);
184976
185163
  if (typeof value === "number" || typeof value === "boolean") return String(value);
184977
185164
  if (value === null) return "null";
@@ -184980,13 +185167,13 @@ function expression(value, depth) {
184980
185167
  }
184981
185168
  function body5(object2, depth, lines) {
184982
185169
  for (const [key, value] of Object.entries(object2)) {
184983
- const isObject4 = (item) => typeof item === "object" && item !== null && !Array.isArray(item);
184984
- if (key === "locals" || key === "tags" || key === "labels" || key === "app_settings" || key === "default" || depth > MAX_DEPTH7) lines.push(`${keyOf(key)} = ${expression(value, depth)}`);
184985
- else if (isObject4(value)) {
185170
+ const isObject5 = (item) => typeof item === "object" && item !== null && !Array.isArray(item);
185171
+ if (key === "locals" || key === "tags" || key === "labels" || key === "app_settings" || key === "default" || depth > MAX_DEPTH8) lines.push(`${keyOf(key)} = ${expression(value, depth)}`);
185172
+ else if (isObject5(value)) {
184986
185173
  lines.push(`${keyOf(key)} {`);
184987
185174
  body5(value, depth + 1, lines);
184988
185175
  lines.push("}");
184989
- } else if (Array.isArray(value) && value.length > 0 && value.every(isObject4)) {
185176
+ } else if (Array.isArray(value) && value.length > 0 && value.every(isObject5)) {
184990
185177
  for (const item of value) {
184991
185178
  lines.push(`${keyOf(key)} {`);
184992
185179
  body5(item, depth + 1, lines);
@@ -185047,13 +185234,13 @@ function readJsonFiles(text3, context, index2) {
185047
185234
  }
185048
185235
  return { text: blanked, blocks: out };
185049
185236
  }
185050
- var MAX_DEPTH7, LABELS, keyOf;
185237
+ var MAX_DEPTH8, LABELS, keyOf;
185051
185238
  var init_json_syntax = __esm({
185052
185239
  "../../packages/diagrams/src/importers/terraform/json-syntax.ts"() {
185053
185240
  "use strict";
185054
185241
  init_core();
185055
185242
  init_parse21();
185056
- MAX_DEPTH7 = 24;
185243
+ MAX_DEPTH8 = 24;
185057
185244
  LABELS = { resource: 2, data: 2, module: 1, variable: 1, output: 1, provider: 1 };
185058
185245
  keyOf = (key) => /^[A-Za-z_][A-Za-z0-9_-]*$/.test(key) ? key : JSON.stringify(key);
185059
185246
  }
@@ -185103,12 +185290,12 @@ function readVariableFiles(text3, files, context, index2, folder = null) {
185103
185290
  } else {
185104
185291
  chosen = [];
185105
185292
  if (others.length > 1) {
185106
- const names7 = others.map((span) => span.path);
185293
+ const names8 = others.map((span) => span.path);
185107
185294
  context.report.add(
185108
185295
  DIAGNOSTIC_CODES.importSkipped,
185109
185296
  START,
185110
- `${countOf2(others.length, "variables file")} ${others.length === 1 ? "is" : "are"} not applied, because Terraform loads none of them on its own and they set the same variables: ${names7.slice(0, LISTED5).join(", ")}${names7.length > LISTED5 ? ", and more" : ""}.`,
185111
- `Set options.varFiles to the environment to draw, such as ["${names7[0] ?? ""}"]; until then, variables show their defaults or their names.`
185297
+ `${countOf2(others.length, "variables file")} ${others.length === 1 ? "is" : "are"} not applied, because Terraform loads none of them on its own and they set the same variables: ${names8.slice(0, LISTED5).join(", ")}${names8.length > LISTED5 ? ", and more" : ""}.`,
185298
+ `Set options.varFiles to the environment to draw, such as ["${names8[0] ?? ""}"]; until then, variables show their defaults or their names.`
185112
185299
  );
185113
185300
  }
185114
185301
  }
@@ -185192,11 +185379,46 @@ function scopeOfVariable(scopes, name2) {
185192
185379
  const root = scopes[0];
185193
185380
  return root === void 0 ? null : { scope: root, name: name2 };
185194
185381
  }
185382
+ function withoutUndeclared(resources, scopes) {
185383
+ const declared2 = new Map(scopes.map((scope) => [scope, declaredVariables(scope.blocks)]));
185384
+ const undeclared = /* @__PURE__ */ new Map();
185385
+ const isDeclared = (name2) => {
185386
+ const found = scopeOfVariable(scopes, name2);
185387
+ const names8 = found === null ? void 0 : declared2.get(found.scope);
185388
+ return found === null || names8 === void 0 || names8.size === 0 || names8.has(found.name.split(".")[0] ?? "");
185389
+ };
185390
+ const out = /* @__PURE__ */ new Map();
185391
+ for (const [key, resource] of resources) {
185392
+ const vars = /* @__PURE__ */ new Map();
185393
+ let changed = false;
185394
+ for (const [attribute2, names8] of resource.vars) {
185395
+ const kept2 = names8.filter((name2) => isDeclared(name2));
185396
+ for (const name2 of names8) if (!kept2.includes(name2) && !undeclared.has(name2)) undeclared.set(name2, key);
185397
+ if (kept2.length > 0) vars.set(attribute2, kept2);
185398
+ changed ||= kept2.length < names8.length;
185399
+ }
185400
+ out.set(key, changed ? { ...resource, vars } : resource);
185401
+ }
185402
+ return { resources: out, undeclared };
185403
+ }
185195
185404
  function drawRoot(text3, folders, root, blocks2, context, index2) {
185196
185405
  const variableFiles = readVariableFiles(text3, context.files, context, index2, folders.roots.length > 1 || root !== "" ? root : null);
185197
185406
  const scope = buildScope(folders, root, variableFiles.assigned);
185198
185407
  const scopes = allScopes(scope);
185199
- const { resources, modules, empty } = readResources(scope);
185408
+ const read = readResources(scope);
185409
+ const { modules, empty } = read;
185410
+ const { resources, undeclared } = withoutUndeclared(read.resources, scopes);
185411
+ const [firstName, firstKey] = [...undeclared][0] ?? [];
185412
+ if (firstName !== void 0 && firstKey !== void 0) {
185413
+ const names8 = [...undeclared.keys()];
185414
+ const block = resources.get(firstKey)?.block;
185415
+ context.report.add(
185416
+ DIAGNOSTIC_CODES.importUnresolved,
185417
+ index2.span(block?.start ?? 0, block?.type.length ?? 1),
185418
+ `${names8.length === 1 ? "A variable is" : `${names8.length} variables are`} named but never declared, so nothing is framed by ${names8.length === 1 ? "it" : "them"}: ${names8.slice(0, 3).map((name2) => `var.${cleanText(name2)}`).join(", ")}.`,
185419
+ `Declare ${names8.length === 1 ? "it" : "each"} with a variable block, such as variable "${cleanText(firstName.split(".").pop() ?? firstName)}" {}, or send the file that declares ${names8.length === 1 ? "it" : "them"}.`
185420
+ );
185421
+ }
185200
185422
  for (const item of empty.slice(0, 1)) {
185201
185423
  context.report.add(DIAGNOSTIC_CODES.importSkipped, index2.span(item.block.start, item.block.type.length), `${countWord(empty.length)} make${empty.length === 1 ? "s" : ""} no copy with the values given (count or for_each is empty), so ${empty.length === 1 ? "it is" : "they are"} not drawn: ${empty.slice(0, 3).map((entry2) => entry2.key).join(", ")}.`, "Set the variable that turns it on, in a variables file or options.varFiles, to draw it.");
185202
185424
  }
@@ -185348,13 +185570,13 @@ function bodyObject(value) {
185348
185570
  if (value.kind === "if" || value.kind === "for") return bodyObject(value.body);
185349
185571
  return null;
185350
185572
  }
185351
- var MAX_DEPTH8, MAX_ITEMS, Env, Evaluator;
185573
+ var MAX_DEPTH9, MAX_ITEMS, Env, Evaluator;
185352
185574
  var init_evaluate = __esm({
185353
185575
  "../../packages/diagrams/src/importers/bicep/evaluate.ts"() {
185354
185576
  "use strict";
185355
185577
  init_value();
185356
185578
  init_value();
185357
- MAX_DEPTH8 = 24;
185579
+ MAX_DEPTH9 = 24;
185358
185580
  MAX_ITEMS = 256;
185359
185581
  Env = class _Env {
185360
185582
  constructor(unit3, inputs, loop, prefix, children) {
@@ -185377,7 +185599,7 @@ var init_evaluate = __esm({
185377
185599
  Evaluator = class {
185378
185600
  memo = /* @__PURE__ */ new Map();
185379
185601
  evaluate(expr, env, depth = 0) {
185380
- if (depth > MAX_DEPTH8) return new Unknown(shortOf(expr));
185602
+ if (depth > MAX_DEPTH9) return new Unknown(shortOf(expr));
185381
185603
  switch (expr.kind) {
185382
185604
  case "literal":
185383
185605
  return expr.value;
@@ -186256,8 +186478,8 @@ var init_references = __esm({
186256
186478
  }
186257
186479
  const nested2 = rest[0];
186258
186480
  if (nested2?.kind === "member" && nested2.nested) {
186259
- const names7 = slots.flatMap((slot) => (this.slots.get(`${slot.name}::${nested2.name}`) ?? []).map((child) => child.name));
186260
- return names7.length > 0 ? names7 : slots.map((slot) => slot.name);
186481
+ const names8 = slots.flatMap((slot) => (this.slots.get(`${slot.name}::${nested2.name}`) ?? []).map((child) => child.name));
186482
+ return names8.length > 0 ? names8 : slots.map((slot) => slot.name);
186261
186483
  }
186262
186484
  const [properties, subnets, position] = rest;
186263
186485
  if (properties?.kind === "member" && properties.name === "properties" && subnets?.kind === "member" && subnets.name === "subnets" && position?.kind === "index") {
@@ -186301,14 +186523,14 @@ var init_references = __esm({
186301
186523
  const values = expr.args.map((arg) => textOf5(this.evaluator.evaluate(arg, env)));
186302
186524
  const typeAt = values.findIndex((value) => value !== null && value.includes("/"));
186303
186525
  const type = typeAt === -1 ? null : values[typeAt].toLowerCase();
186304
- const names7 = values.slice(typeAt + 1);
186305
- const last = names7[names7.length - 1];
186526
+ const names8 = values.slice(typeAt + 1);
186527
+ const last = names8[names8.length - 1];
186306
186528
  if (type !== null && last !== null && last !== void 0) {
186307
186529
  for (const list of this.slots.values()) {
186308
186530
  for (const slot of list) {
186309
186531
  const own2 = nameOf7(slot, this.evaluator);
186310
- if (slot.armType.toLowerCase() === type && (own2 === last || own2 === names7.join("/"))) return [slot.name];
186311
- if (type === `${slot.armType.toLowerCase()}/subnets` && nameOf7(slot, this.evaluator) === names7[names7.length - 2]) {
186532
+ if (slot.armType.toLowerCase() === type && (own2 === last || own2 === names8.join("/"))) return [slot.name];
186533
+ if (type === `${slot.armType.toLowerCase()}/subnets` && nameOf7(slot, this.evaluator) === names8[names8.length - 2]) {
186312
186534
  const subnet = slot.subnets.find((entry2) => entry2.display === last || entry2.label === last);
186313
186535
  if (subnet !== void 0) return [subnet.name];
186314
186536
  }
@@ -186646,12 +186868,12 @@ function parseExpression(text3) {
186646
186868
  throw error62;
186647
186869
  }
186648
186870
  }
186649
- var MAX_DEPTH9, SKIPPED, PRECEDENCE, ReadError, BicepReader;
186871
+ var MAX_DEPTH10, SKIPPED, PRECEDENCE, ReadError, BicepReader;
186650
186872
  var init_parse22 = __esm({
186651
186873
  "../../packages/diagrams/src/importers/bicep/parse.ts"() {
186652
186874
  "use strict";
186653
186875
  init_tokens2();
186654
- MAX_DEPTH9 = 64;
186876
+ MAX_DEPTH10 = 64;
186655
186877
  SKIPPED = /* @__PURE__ */ new Set(["import", "type", "func", "metadata", "extension", "provider", "assert"]);
186656
186878
  PRECEDENCE = { "??": 1, "||": 2, "&&": 3, "==": 4, "!=": 4, "=~": 4, "!~": 4, "<": 5, ">": 5, "<=": 5, ">=": 5, "+": 6, "-": 6, "*": 7, "/": 7, "%": 7 };
186657
186879
  ReadError = class extends Error {
@@ -186836,7 +187058,7 @@ var init_parse22 = __esm({
186836
187058
  }
186837
187059
  /** An expression: a conditional over binary operators over unary ones over postfix chains. */
186838
187060
  expression(depth) {
186839
- if (depth > MAX_DEPTH9) this.fail("The expression is nested too deep.", `Keep nesting under ${MAX_DEPTH9} levels.`);
187061
+ if (depth > MAX_DEPTH10) this.fail("The expression is nested too deep.", `Keep nesting under ${MAX_DEPTH10} levels.`);
186840
187062
  const test = this.binary(0, depth + 1);
186841
187063
  if (this.isSign("=>")) {
186842
187064
  this.index += 1;
@@ -186936,15 +187158,15 @@ var init_parse22 = __esm({
186936
187158
  this.skipNewlines();
186937
187159
  const inner = this.expression(depth + 1);
186938
187160
  this.skipNewlines();
186939
- const names7 = [inner];
187161
+ const names8 = [inner];
186940
187162
  while (this.isSign(",")) {
186941
187163
  this.index += 1;
186942
187164
  this.skipNewlines();
186943
- names7.push(this.expression(depth + 1));
187165
+ names8.push(this.expression(depth + 1));
186944
187166
  this.skipNewlines();
186945
187167
  }
186946
187168
  this.expectSign(")", "Close the bracket.");
186947
- return names7.length === 1 ? inner : { kind: "array", items: names7, start: token.start };
187169
+ return names8.length === 1 ? inner : { kind: "array", items: names8, start: token.start };
186948
187170
  }
186949
187171
  if (token.kind === "sign" && token.text === "{") return this.object(depth + 1);
186950
187172
  if (token.kind === "sign" && token.text === "[") return this.array(depth + 1);
@@ -186960,7 +187182,7 @@ var init_parse22 = __esm({
186960
187182
  return value;
186961
187183
  }
186962
187184
  object(depth) {
186963
- if (depth > MAX_DEPTH9) this.fail("The objects are nested too deep.", `Keep nesting under ${MAX_DEPTH9} levels.`);
187185
+ if (depth > MAX_DEPTH10) this.fail("The objects are nested too deep.", `Keep nesting under ${MAX_DEPTH10} levels.`);
186964
187186
  const open2 = this.expectSign("{", "An object is written { key: value }.");
186965
187187
  const entries2 = [];
186966
187188
  const nested2 = [];
@@ -186998,7 +187220,7 @@ var init_parse22 = __esm({
186998
187220
  }
186999
187221
  }
187000
187222
  array(depth) {
187001
- if (depth > MAX_DEPTH9) this.fail("The lists are nested too deep.", `Keep nesting under ${MAX_DEPTH9} levels.`);
187223
+ if (depth > MAX_DEPTH10) this.fail("The lists are nested too deep.", `Keep nesting under ${MAX_DEPTH10} levels.`);
187002
187224
  const open2 = this.expectSign("[", "A list is written [ a, b ].");
187003
187225
  this.skipNewlines();
187004
187226
  if (this.isWord("for")) return this.loop(open2, depth);
@@ -187224,7 +187446,7 @@ function bicepQuotes(text3) {
187224
187446
  return out;
187225
187447
  }
187226
187448
  function exprOf(value, start2, depth = 0) {
187227
- if (depth > MAX_DEPTH10) return { kind: "literal", value: null, start: start2 };
187449
+ if (depth > MAX_DEPTH11) return { kind: "literal", value: null, start: start2 };
187228
187450
  if (typeof value === "string") {
187229
187451
  if (value.startsWith("[[")) return { kind: "string", parts: [value.slice(1)], start: start2 };
187230
187452
  if (value.startsWith("[") && value.endsWith("]")) {
@@ -187262,10 +187484,10 @@ function dependsOnOf(value, start2, symbols) {
187262
187484
  if (symbols.has(item)) return { kind: "name", name: item, start: start2 };
187263
187485
  const parts = item.split("/");
187264
187486
  const type = parts.slice(0, 2).join("/");
187265
- const names7 = parts.slice(2);
187266
- const childTypes = names7.length > 1 ? names7.filter((_part, index2) => index2 % 2 === 1) : [];
187487
+ const names8 = parts.slice(2);
187488
+ const childTypes = names8.length > 1 ? names8.filter((_part, index2) => index2 % 2 === 1) : [];
187267
187489
  const typed = [type, ...childTypes].join("/");
187268
- const named = names7.filter((_part, index2) => index2 % 2 === 0);
187490
+ const named = names8.filter((_part, index2) => index2 % 2 === 0);
187269
187491
  return { kind: "call", callee: { kind: "name", name: "resourceId", start: start2 }, name: "resourceId", args: [typed, ...named].map((part) => ({ kind: "string", parts: [part], start: start2 })), start: start2 };
187270
187492
  }),
187271
187493
  start: start2
@@ -187318,13 +187540,13 @@ function templateDeclarations(template, offsetOf) {
187318
187540
  for (const [name2, output2] of Object.entries(outputs)) if (isRecord2(output2)) declarations.push({ kind: "output", name: name2, value: exprOf(output2["value"], offsetOf(name2)), start: offsetOf(name2) });
187319
187541
  return declarations;
187320
187542
  }
187321
- var COPY_INDEX, MAX_DEPTH10, isRecord2;
187543
+ var COPY_INDEX, MAX_DEPTH11, isRecord2;
187322
187544
  var init_convert2 = __esm({
187323
187545
  "../../packages/diagrams/src/importers/arm/convert.ts"() {
187324
187546
  "use strict";
187325
187547
  init_parse22();
187326
187548
  COPY_INDEX = "copyIndex";
187327
- MAX_DEPTH10 = 48;
187549
+ MAX_DEPTH11 = 48;
187328
187550
  isRecord2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
187329
187551
  }
187330
187552
  });
@@ -187732,13 +187954,13 @@ function parseYaml(text3) {
187732
187954
  }
187733
187955
  return { documents, error: null };
187734
187956
  }
187735
- var MAX_DEPTH11, MAX_JOINED_LINES, YamlProblem, isItem3, BlockReader;
187957
+ var MAX_DEPTH12, MAX_JOINED_LINES, YamlProblem, isItem3, BlockReader;
187736
187958
  var init_parse23 = __esm({
187737
187959
  "../../packages/diagrams/src/importers/shared/yaml/parse.ts"() {
187738
187960
  "use strict";
187739
187961
  init_lines();
187740
187962
  init_scalars();
187741
- MAX_DEPTH11 = 64;
187963
+ MAX_DEPTH12 = 64;
187742
187964
  MAX_JOINED_LINES = 200;
187743
187965
  YamlProblem = class extends Error {
187744
187966
  constructor(line3, column, message2, hint2) {
@@ -187774,7 +187996,7 @@ var init_parse23 = __esm({
187774
187996
  /** A block that starts at the current line, indented `indent` spaces: a sequence, a mapping, or a scalar. */
187775
187997
  block(indent, depth) {
187776
187998
  const line3 = this.lines[this.index];
187777
- if (depth > MAX_DEPTH11) throw this.problem(line3, "The YAML is nested too deep.", `Keep nesting under ${MAX_DEPTH11} levels.`);
187999
+ if (depth > MAX_DEPTH12) throw this.problem(line3, "The YAML is nested too deep.", `Keep nesting under ${MAX_DEPTH12} levels.`);
187778
188000
  if (isItem3(line3.text)) return this.sequence(indent, depth);
187779
188001
  if (splitKey(line3.text) !== null) return this.mapping(indent, depth);
187780
188002
  this.index += 1;
@@ -188119,14 +188341,14 @@ function templateItems(template, offsetOf) {
188119
188341
  }
188120
188342
  return { items: items2, empty };
188121
188343
  }
188122
- var MAX_DEPTH12, PSEUDO, entryOf, scalarOf, itemsOf, subNames, Template;
188344
+ var MAX_DEPTH13, PSEUDO, entryOf, scalarOf, itemsOf, subNames, Template;
188123
188345
  var init_template = __esm({
188124
188346
  "../../packages/diagrams/src/importers/cloudformation/template.ts"() {
188125
188347
  "use strict";
188126
188348
  init_attributes();
188127
188349
  init_type_names();
188128
188350
  init_value();
188129
- MAX_DEPTH12 = 16;
188351
+ MAX_DEPTH13 = 16;
188130
188352
  PSEUDO = {
188131
188353
  "AWS::Region": "region",
188132
188354
  "AWS::AccountId": "account",
@@ -188156,7 +188378,7 @@ var init_template = __esm({
188156
188378
  }
188157
188379
  /** The value of a node as far as the template's defaults give it. */
188158
188380
  evaluate(node3, depth = 0) {
188159
- if (node3 === void 0 || depth > MAX_DEPTH12) return new Unknown("value");
188381
+ if (node3 === void 0 || depth > MAX_DEPTH13) return new Unknown("value");
188160
188382
  const intrinsic = intrinsicOf(node3);
188161
188383
  if (intrinsic !== null) return this.call(intrinsic, depth);
188162
188384
  if (node3.kind === "scalar") return node3.isNull ? null : node3.value;
@@ -188264,7 +188486,7 @@ var init_template = __esm({
188264
188486
  }
188265
188487
  /** The resources a node names: `Ref`, `GetAtt`, and `${ }` of `Sub`, and only the branch an `If` takes when its condition is known. */
188266
188488
  refs(node3, depth = 0) {
188267
- if (node3 === void 0 || depth > MAX_DEPTH12) return [];
188489
+ if (node3 === void 0 || depth > MAX_DEPTH13) return [];
188268
188490
  const intrinsic = intrinsicOf(node3);
188269
188491
  if (intrinsic !== null) {
188270
188492
  const argument = intrinsic.argument;
@@ -188294,7 +188516,7 @@ var init_template = __esm({
188294
188516
  }
188295
188517
  /** Every reference a node holds, by the keys that lead to it. */
188296
188518
  refsByPath(node3, path, out, depth = 0) {
188297
- if (node3 === void 0 || depth > MAX_DEPTH12) return;
188519
+ if (node3 === void 0 || depth > MAX_DEPTH13) return;
188298
188520
  if (intrinsicOf(node3) === null && node3.kind === "map") {
188299
188521
  for (const entry2 of node3.entries) this.refsByPath(entry2.value, [...path, entry2.key], out, depth + 1);
188300
188522
  return;
@@ -188862,14 +189084,14 @@ function writeMatrix(table2, title, report3) {
188862
189084
  const columnPages = pages(columns.map((_, index2) => index2), columnPlan);
188863
189085
  const rowPlan = paging(table2.rows.length, WORKFLOW_LIMITS.maxImportRows, MAX_ROWS, Math.max(1, Math.floor(WORKFLOW_LIMITS.maxImportParts / columnPages.length)));
188864
189086
  const rowPages = pages(table2.rows.map((_, index2) => index2), rowPlan);
188865
- const names7 = [];
189087
+ const names8 = [];
188866
189088
  const taken = /* @__PURE__ */ new Set();
188867
189089
  for (const [index2, row] of table2.rows.entries()) {
188868
189090
  const base = cleanText(row[0] ?? "", `Row ${index2 + 1}`);
188869
189091
  let name2 = base;
188870
189092
  for (let seen = 2; taken.has(name2.toLowerCase()); seen += 1) name2 = `${base} (${seen})`;
188871
189093
  taken.add(name2.toLowerCase());
188872
- names7.push(name2);
189094
+ names8.push(name2);
188873
189095
  }
188874
189096
  const marks = table2.rows.map(
188875
189097
  (row, index2) => columns.map((_, column) => {
@@ -188895,7 +189117,7 @@ function writeMatrix(table2, title, report3) {
188895
189117
  for (const row of rowPage) {
188896
189118
  const cells = columnPage.map((column) => marks[row]?.[column] ?? "na");
188897
189119
  for (const cell2 of cells) used.add(cell2);
188898
- lines.add(`row ${quote(names7[row] ?? "")} : ${cells.join(", ")}`);
189120
+ lines.add(`row ${quote(names8[row] ?? "")} : ${cells.join(", ")}`);
188899
189121
  }
188900
189122
  lines.gap();
188901
189123
  const legend2 = ["yes", "partial", "no", "na"].filter((mark) => used.has(mark));
@@ -190025,13 +190247,13 @@ function cleanName2(name2) {
190025
190247
  return clean === "" ? "branch" : clean.slice(0, 40);
190026
190248
  }
190027
190249
  function namesOf(runs) {
190028
- const names7 = /* @__PURE__ */ new Map();
190250
+ const names8 = /* @__PURE__ */ new Map();
190029
190251
  const taken = /* @__PURE__ */ new Set();
190030
190252
  const claim2 = (run3, wanted2) => {
190031
190253
  let name2 = cleanName2(wanted2);
190032
190254
  for (let count3 = 2; taken.has(name2.toLowerCase()); count3 += 1) name2 = `${cleanName2(wanted2)}-${count3}`;
190033
190255
  taken.add(name2.toLowerCase());
190034
- names7.set(run3, name2);
190256
+ names8.set(run3, name2);
190035
190257
  };
190036
190258
  const [main2, ...others] = runs;
190037
190259
  if (main2 !== void 0) {
@@ -190044,7 +190266,7 @@ function namesOf(runs) {
190044
190266
  const merged = run3.mergedBy === null ? null : mergedName(run3.mergedBy.message);
190045
190267
  claim2(run3, decorated ?? merged ?? `branch-${run3.lane}`);
190046
190268
  }
190047
- return names7;
190269
+ return names8;
190048
190270
  }
190049
190271
  function commitOptions(commit, id) {
190050
190272
  const tags = commit.tags.slice(0, MAX_TAGS).map((tag) => cleanText(tag, ""));
@@ -190052,13 +190274,13 @@ function commitOptions(commit, id) {
190052
190274
  }
190053
190275
  function writeGit(rows, title, dropped) {
190054
190276
  const { runs, runOf, merges } = readLanes(rows);
190055
- const names7 = namesOf(runs);
190277
+ const names8 = namesOf(runs);
190056
190278
  const forkIds = /* @__PURE__ */ new Map();
190057
190279
  for (const run3 of runs) if (run3.forkFrom !== null) forkIds.set(run3.forkFrom, `c${run3.forkFrom.hash.slice(0, 7)}`);
190058
190280
  const main2 = runs[0];
190059
190281
  const commits = rows.flatMap((row) => row.kind === "commit" ? [row.commit] : []).reverse();
190060
190282
  const linear = runs.length === 1 ? linearBranches(commits) : null;
190061
- const mainName = linear === null ? names7.get(main2) ?? "main" : cleanName2(linear.first);
190283
+ const mainName = linear === null ? names8.get(main2) ?? "main" : cleanName2(linear.first);
190062
190284
  let linearBranchCount = 0;
190063
190285
  const created = /* @__PURE__ */ new Set([main2]);
190064
190286
  const hasCommits = /* @__PURE__ */ new Set();
@@ -190073,13 +190295,13 @@ function writeGit(rows, title, dropped) {
190073
190295
  if (hasCommits.size === 0) run3 = main2;
190074
190296
  if (!created.has(run3)) {
190075
190297
  const fork = run3.forkFrom !== null && emitted.has(run3.forkFrom) ? forkIds.get(run3.forkFrom) : void 0;
190076
- const parent = run3.parent !== null && hasCommits.has(run3.parent) ? names7.get(run3.parent) : void 0;
190298
+ const parent = run3.parent !== null && hasCommits.has(run3.parent) ? names8.get(run3.parent) : void 0;
190077
190299
  const from = fork ?? parent ?? mainName;
190078
- body6.add(`branch ${word(names7.get(run3) ?? "branch")}${from === names7.get(current) ? "" : options2({ from })}`);
190300
+ body6.add(`branch ${word(names8.get(run3) ?? "branch")}${from === names8.get(current) ? "" : options2({ from })}`);
190079
190301
  created.add(run3);
190080
190302
  current = run3;
190081
190303
  } else if (run3 !== current) {
190082
- body6.add(`checkout ${word(names7.get(run3) ?? mainName)}`);
190304
+ body6.add(`checkout ${word(names8.get(run3) ?? mainName)}`);
190083
190305
  current = run3;
190084
190306
  }
190085
190307
  const merged = merges.get(commit);
@@ -190088,7 +190310,7 @@ function writeGit(rows, title, dropped) {
190088
190310
  if (merged !== void 0 && hasCommits.has(merged) && !done.has(merged) && merged !== run3) {
190089
190311
  done.add(merged);
190090
190312
  mergeCount += 1;
190091
- body6.add(`merge ${word(names7.get(merged) ?? "branch")}${mergeMessage(commit.message)}${commitOptions(commit, id)}`);
190313
+ body6.add(`merge ${word(names8.get(merged) ?? "branch")}${mergeMessage(commit.message)}${commitOptions(commit, id)}`);
190092
190314
  } else {
190093
190315
  body6.add(`commit ${quote(message(commit.message))}${commitOptions(commit, id)}`);
190094
190316
  }
@@ -191185,8 +191407,8 @@ function chunkTitle(title, index2, count3) {
191185
191407
  return `${title} (${index2 + 1} of ${count3})`;
191186
191408
  }
191187
191409
  function chunkTags(chunk) {
191188
- const names7 = chunk.map(pieceName);
191189
- return names7.length <= 2 ? names7.join(" and ") : `${names7.slice(0, -1).join(", ")}, and ${names7[names7.length - 1] ?? ""}`;
191410
+ const names8 = chunk.map(pieceName);
191411
+ return names8.length <= 2 ? names8.join(" and ") : `${names8.slice(0, -1).join(", ")}, and ${names8[names8.length - 1] ?? ""}`;
191190
191412
  }
191191
191413
  function wanted(operation, tags, paths) {
191192
191414
  const tagged2 = tags === void 0 || tags.length === 0 || operation.tags.some((tag) => tags.some((want) => want.toLowerCase() === tag.toLowerCase()));
@@ -191495,8 +191717,8 @@ function short2(text3) {
191495
191717
  function needs(operation, schemes) {
191496
191718
  const first = operation.security?.find((requirement) => requirement.size > 0);
191497
191719
  if (first === void 0) return { token: false, names: [], scopes: [] };
191498
- const names7 = [...first.keys()];
191499
- return { token: names7.some((name2) => TOKEN_SCHEMES.has(schemes.get(name2)?.type ?? "")), names: names7, scopes: [...first.values()].flat() };
191720
+ const names8 = [...first.keys()];
191721
+ return { token: names8.some((name2) => TOKEN_SCHEMES.has(schemes.get(name2)?.type ?? "")), names: names8, scopes: [...first.values()].flat() };
191500
191722
  }
191501
191723
  function sequenceSource(operation, need, api, title, responses, page) {
191502
191724
  const lines = new SourceLines();
@@ -191922,14 +192144,14 @@ function piecesOf4(value) {
191922
192144
  }
191923
192145
  return out;
191924
192146
  }
191925
- var MAX_DEPTH13, Program;
192147
+ var MAX_DEPTH14, Program;
191926
192148
  var init_program = __esm({
191927
192149
  "../../packages/diagrams/src/importers/pulumi/program.ts"() {
191928
192150
  "use strict";
191929
192151
  init_value();
191930
192152
  init_yaml();
191931
192153
  init_item();
191932
- MAX_DEPTH13 = 16;
192154
+ MAX_DEPTH14 = 16;
191933
192155
  Program = class {
191934
192156
  constructor(root, config2, stack, project) {
191935
192157
  this.config = config2;
@@ -191957,7 +192179,7 @@ var init_program = __esm({
191957
192179
  }
191958
192180
  /** The value of a node as far as the program and the stack give it. */
191959
192181
  evaluate(node3, depth = 0) {
191960
- if (node3 === void 0 || depth > MAX_DEPTH13) return new Unknown("value");
192182
+ if (node3 === void 0 || depth > MAX_DEPTH14) return new Unknown("value");
191961
192183
  if (node3.kind === "scalar") {
191962
192184
  if (node3.isNull) return null;
191963
192185
  if (!node3.value.includes("${")) return node3.value;
@@ -192042,7 +192264,7 @@ var init_program = __esm({
192042
192264
  }
192043
192265
  /** The resources a node names, through the variables it uses. */
192044
192266
  refs(node3, depth = 0) {
192045
- if (node3 === void 0 || depth > MAX_DEPTH13) return [];
192267
+ if (node3 === void 0 || depth > MAX_DEPTH14) return [];
192046
192268
  if (node3.kind === "scalar") {
192047
192269
  if (!node3.value.includes("${")) return [];
192048
192270
  return piecesOf4(node3.value).flatMap((piece) => {
@@ -192065,7 +192287,7 @@ var init_program = __esm({
192065
192287
  }
192066
192288
  /** Every reference a node holds, by the keys that lead to it. */
192067
192289
  refsByPath(node3, path, out, depth) {
192068
- if (node3 === void 0 || depth > MAX_DEPTH13) return;
192290
+ if (node3 === void 0 || depth > MAX_DEPTH14) return;
192069
192291
  if (node3.kind === "map" && !(node3.entries.length === 1 && node3.entries[0]?.key.startsWith("fn::"))) {
192070
192292
  for (const entry2 of node3.entries) this.refsByPath(entry2.value, [...path, entry2.key], out, depth + 1);
192071
192293
  return;
@@ -192354,7 +192576,9 @@ function drawSource(source, context, index2) {
192354
192576
  return item === void 0 ? { line: 1, column: 1, length: 1 } : index2.span(item.start);
192355
192577
  },
192356
192578
  tool: "Pulumi",
192357
- stableName: stack.stableName
192579
+ stableName: stack.stableName,
192580
+ // A YAML program has no component to layer it by; a state's components, when it has them, frame it instead.
192581
+ layered: true
192358
192582
  });
192359
192583
  }
192360
192584
  var LISTED9, stackOf, pulumiImporter;
@@ -192510,8 +192734,8 @@ function readNameList(tokens, open2) {
192510
192734
  if (!isSign(tokens[open2], "(")) return null;
192511
192735
  const close2 = closeOf2(tokens, open2);
192512
192736
  if (close2 === -1) return null;
192513
- const names7 = splitParts2(tokens, open2 + 1, close2).map((part) => part.find((token) => isName(token))?.text).filter((name2) => name2 !== void 0);
192514
- return { names: names7, next: close2 + 1 };
192737
+ const names8 = splitParts2(tokens, open2 + 1, close2).map((part) => part.find((token) => isName(token))?.text).filter((name2) => name2 !== void 0);
192738
+ return { names: names8, next: close2 + 1 };
192515
192739
  }
192516
192740
  function tableOf(schema, name2) {
192517
192741
  const key = name2.toLowerCase();
@@ -192557,7 +192781,7 @@ function renameColumn(schema, table2, from, to) {
192557
192781
  table2.byName.delete(column.name.toLowerCase());
192558
192782
  column.name = to;
192559
192783
  table2.byName.set(to.toLowerCase(), column);
192560
- const rename2 = (names7) => names7.map((name2) => name2.toLowerCase() === from.toLowerCase() ? to : name2);
192784
+ const rename2 = (names8) => names8.map((name2) => name2.toLowerCase() === from.toLowerCase() ? to : name2);
192561
192785
  for (const foreign of schema.keys) {
192562
192786
  if (foreign.fromTable === table2.key) foreign.fromColumns = rename2(foreign.fromColumns);
192563
192787
  if (foreign.toTable.toLowerCase() === table2.key) foreign.toColumns = rename2(foreign.toColumns);
@@ -192861,6 +193085,623 @@ var init_sql = __esm({
192861
193085
  }
192862
193086
  });
192863
193087
 
193088
+ // ../../packages/diagrams/src/importers/terraform-plan/document.ts
193089
+ function moduleOfAddress(address, type, mode) {
193090
+ const own2 = `${mode === "data" ? "data." : ""}${type}.`;
193091
+ const at3 = address.lastIndexOf(own2);
193092
+ return at3 <= 0 ? "" : address.slice(0, at3 - 1);
193093
+ }
193094
+ function resourceOf3(raw, module) {
193095
+ if (!isObject4(raw) || typeof raw["address"] !== "string" || typeof raw["type"] !== "string" || typeof raw["name"] !== "string") return null;
193096
+ const mode = raw["mode"] === "data" ? "data" : "managed";
193097
+ const index2 = typeof raw["index"] === "string" || typeof raw["index"] === "number" ? raw["index"] : null;
193098
+ return {
193099
+ address: raw["address"],
193100
+ mode,
193101
+ type: raw["type"],
193102
+ name: raw["name"],
193103
+ index: index2,
193104
+ module: module === "" ? moduleOfAddress(raw["address"], raw["type"], mode) : module,
193105
+ values: isObject4(raw["values"]) ? raw["values"] : {},
193106
+ sensitive: isObject4(raw["sensitive_values"]) ? raw["sensitive_values"] : {},
193107
+ dependsOn: strings2(raw["depends_on"])
193108
+ };
193109
+ }
193110
+ function moduleResources(raw, depth = 0) {
193111
+ if (!isObject4(raw) || depth > MAX_MODULE_DEPTH2) return [];
193112
+ const address = typeof raw["address"] === "string" ? raw["address"] : "";
193113
+ const own2 = (Array.isArray(raw["resources"]) ? raw["resources"] : []).map((entry2) => resourceOf3(entry2, address)).filter((entry2) => entry2 !== null);
193114
+ const children = Array.isArray(raw["child_modules"]) ? raw["child_modules"].flatMap((child) => moduleResources(child, depth + 1)) : [];
193115
+ return [...own2, ...children];
193116
+ }
193117
+ function variablesOf(raw, sensitive) {
193118
+ const out = /* @__PURE__ */ new Map();
193119
+ if (!isObject4(raw)) return out;
193120
+ for (const [name2, entry2] of Object.entries(raw)) {
193121
+ if (sensitive.has(name2) || !isObject4(entry2)) continue;
193122
+ const value = entry2["value"];
193123
+ if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") out.set(name2, String(value));
193124
+ }
193125
+ return out;
193126
+ }
193127
+ function sensitiveVariables(configuration) {
193128
+ const out = /* @__PURE__ */ new Set();
193129
+ const root = configuration === null ? null : configuration["root_module"];
193130
+ const variables = isObject4(root) && isObject4(root["variables"]) ? root["variables"] : {};
193131
+ for (const [name2, entry2] of Object.entries(variables)) if (isObject4(entry2) && entry2["sensitive"] === true) out.add(name2);
193132
+ return out;
193133
+ }
193134
+ function changesOf(raw) {
193135
+ const out = /* @__PURE__ */ new Map();
193136
+ if (!Array.isArray(raw)) return out;
193137
+ for (const entry2 of raw) {
193138
+ if (!isObject4(entry2) || typeof entry2["address"] !== "string" || !isObject4(entry2["change"])) continue;
193139
+ const change = entry2["change"];
193140
+ out.set(entry2["address"], { actions: strings2(change["actions"]), previous: typeof entry2["previous_address"] === "string" ? entry2["previous_address"] : null, before: isObject4(change["before"]) ? change["before"] : null });
193141
+ }
193142
+ return out;
193143
+ }
193144
+ function readPlanDocument(json2) {
193145
+ if (!isObject4(json2)) return null;
193146
+ const configuration = isObject4(json2["configuration"]) ? json2["configuration"] : null;
193147
+ const providers = configuration !== null && isObject4(configuration["provider_config"]) ? configuration["provider_config"] : {};
193148
+ const variables = variablesOf(json2["variables"], sensitiveVariables(configuration));
193149
+ if (isObject4(json2["planned_values"]) || Array.isArray(json2["resource_changes"])) {
193150
+ const planned = isObject4(json2["planned_values"]) ? moduleResources(json2["planned_values"]["root_module"]) : [];
193151
+ const prior = isObject4(json2["prior_state"]) && isObject4(json2["prior_state"]["values"]) ? moduleResources(json2["prior_state"]["values"]["root_module"]) : [];
193152
+ const changes = changesOf(json2["resource_changes"]);
193153
+ const kept2 = new Set(planned.map((resource) => resource.address));
193154
+ const data = prior.filter((resource) => resource.mode === "data" && !kept2.has(resource.address));
193155
+ const destroyed = [];
193156
+ const priorOf = new Map(prior.map((resource) => [resource.address, resource]));
193157
+ for (const [address, change] of changes) {
193158
+ if (!destroys(change) || kept2.has(address)) continue;
193159
+ const known3 = priorOf.get(address);
193160
+ if (known3 !== void 0) destroyed.push(known3);
193161
+ }
193162
+ const drift = /* @__PURE__ */ new Set();
193163
+ if (Array.isArray(json2["resource_drift"])) {
193164
+ for (const entry2 of json2["resource_drift"]) if (isObject4(entry2) && typeof entry2["address"] === "string") drift.add(entry2["address"]);
193165
+ }
193166
+ return { kind: "plan", resources: [...planned, ...data], destroyed, changes, drift, configuration, providers, variables };
193167
+ }
193168
+ if (isObject4(json2["values"]) && isObject4(json2["values"]["root_module"])) {
193169
+ return { kind: "state", resources: moduleResources(json2["values"]["root_module"]), destroyed: [], changes: /* @__PURE__ */ new Map(), drift: /* @__PURE__ */ new Set(), configuration, providers, variables };
193170
+ }
193171
+ if (Array.isArray(json2["resources"]) && typeof json2["version"] === "number") return { kind: "state", resources: rawStateResources(json2["resources"]), destroyed: [], changes: /* @__PURE__ */ new Map(), drift: /* @__PURE__ */ new Set(), configuration: null, providers: {}, variables: /* @__PURE__ */ new Map() };
193172
+ return null;
193173
+ }
193174
+ function rawStateResources(raw) {
193175
+ const out = [];
193176
+ for (const block of raw) {
193177
+ if (!isObject4(block) || typeof block["type"] !== "string" || typeof block["name"] !== "string" || !Array.isArray(block["instances"])) continue;
193178
+ const module = typeof block["module"] === "string" ? block["module"] : "";
193179
+ const mode = block["mode"] === "data" ? "data" : "managed";
193180
+ const base = `${module === "" ? "" : `${module}.`}${mode === "data" ? "data." : ""}${block["type"]}.${block["name"]}`;
193181
+ for (const instance of block["instances"]) {
193182
+ if (!isObject4(instance)) continue;
193183
+ const key = instance["index_key"];
193184
+ const index2 = typeof key === "string" || typeof key === "number" ? key : null;
193185
+ const address = `${base}${index2 === null ? "" : typeof index2 === "number" ? `[${index2}]` : `[${JSON.stringify(index2)}]`}`;
193186
+ const sensitive = {};
193187
+ if (Array.isArray(instance["sensitive_attributes"])) {
193188
+ for (const path of instance["sensitive_attributes"]) {
193189
+ const first = Array.isArray(path) ? path[0] : null;
193190
+ if (isObject4(first) && typeof first["value"] === "string") sensitive[first["value"]] = true;
193191
+ }
193192
+ }
193193
+ out.push({ address, mode, type: block["type"], name: block["name"], index: index2, module, values: isObject4(instance["attributes"]) ? instance["attributes"] : {}, sensitive, dependsOn: strings2(instance["dependencies"]) });
193194
+ }
193195
+ }
193196
+ return out;
193197
+ }
193198
+ var MAX_MODULE_DEPTH2, isObject4, strings2, destroys;
193199
+ var init_document3 = __esm({
193200
+ "../../packages/diagrams/src/importers/terraform-plan/document.ts"() {
193201
+ "use strict";
193202
+ MAX_MODULE_DEPTH2 = 16;
193203
+ isObject4 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
193204
+ strings2 = (value) => Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
193205
+ destroys = (change) => change !== void 0 && change.actions.length === 1 && change.actions[0] === "delete";
193206
+ }
193207
+ });
193208
+
193209
+ // ../../packages/diagrams/src/importers/terraform-plan/references.ts
193210
+ function attributesOf3(expressions, depth = 0) {
193211
+ if (!isObject4(expressions) || depth > MAX_NESTING) return [];
193212
+ const out = [];
193213
+ for (const [name2, value] of Object.entries(expressions)) {
193214
+ if (isObject4(value) && ("references" in value || "constant_value" in value)) {
193215
+ const refs = strings3(value["references"]);
193216
+ out.push({ name: name2, refs: refs.filter((ref) => !SAME_INSTANCE.has(ref)), paired: refs.some((ref) => SAME_INSTANCE.has(ref)) });
193217
+ } else if (Array.isArray(value)) for (const block of value) out.push(...attributesOf3(block, depth + 1));
193218
+ else if (isObject4(value)) out.push(...attributesOf3(value, depth + 1));
193219
+ }
193220
+ return out;
193221
+ }
193222
+ function suffixOf2(step) {
193223
+ if (step?.kind !== "index") return null;
193224
+ if (/^[0-9]+$/.test(step.text)) return `[${step.text}]`;
193225
+ return /^"(?:[^"\\]|\\.)*"$/.test(step.text) ? `[${step.text}]` : null;
193226
+ }
193227
+ function callsOf2(address) {
193228
+ const steps = references(address)[0] ?? [];
193229
+ const out = [];
193230
+ for (let index2 = 0; index2 < steps.length; index2 += 1) {
193231
+ if (steps[index2]?.text !== "module" || steps[index2]?.kind !== "name") continue;
193232
+ const name2 = steps[index2 + 1];
193233
+ if (name2?.kind !== "name") break;
193234
+ const key = steps[index2 + 2];
193235
+ out.push({ name: name2.text, suffix: key?.kind === "index" ? `[${key.text}]` : "" });
193236
+ }
193237
+ return out;
193238
+ }
193239
+ function parentOf3(module) {
193240
+ const at3 = module.lastIndexOf(".module.");
193241
+ return at3 === -1 ? "" : module.slice(0, at3);
193242
+ }
193243
+ var MAX_DEPTH15, MAX_NESTING, TYPE2, SAME_INSTANCE, strings3, Configuration;
193244
+ var init_references2 = __esm({
193245
+ "../../packages/diagrams/src/importers/terraform-plan/references.ts"() {
193246
+ "use strict";
193247
+ init_address();
193248
+ init_document3();
193249
+ MAX_DEPTH15 = 8;
193250
+ MAX_NESTING = 8;
193251
+ TYPE2 = /^[a-z][a-z0-9]*_[a-z0-9_]+$/;
193252
+ SAME_INSTANCE = /* @__PURE__ */ new Set(["each.key", "each.value", "count.index"]);
193253
+ strings3 = (value) => Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
193254
+ Configuration = class {
193255
+ constructor(root, instances) {
193256
+ this.root = root;
193257
+ this.instances = instances;
193258
+ }
193259
+ root;
193260
+ instances;
193261
+ /** The configuration of the module a module instance runs, or null when the plan has none. */
193262
+ moduleAt(address) {
193263
+ let module = this.root;
193264
+ for (const call of callsOf2(address)) {
193265
+ const calls = isObject4(module) && isObject4(module["module_calls"]) ? module["module_calls"] : null;
193266
+ const entry2 = calls === null ? null : calls[call.name];
193267
+ module = isObject4(entry2) ? entry2["module"] : null;
193268
+ }
193269
+ return isObject4(module) ? module : null;
193270
+ }
193271
+ /** The call of a module instance, as its parent's configuration writes it: its source, version, and the values it passes. */
193272
+ callAt(address) {
193273
+ const calls = callsOf2(address);
193274
+ const last = calls[calls.length - 1];
193275
+ if (last === void 0) return null;
193276
+ const parent = this.moduleAt(parentOf3(address));
193277
+ const entry2 = parent !== null && isObject4(parent["module_calls"]) ? parent["module_calls"][last.name] : null;
193278
+ return isObject4(entry2) ? entry2 : null;
193279
+ }
193280
+ /** The configured block of a resource, by the module instance it is in and its address inside the module. */
193281
+ resourceAt(module, local2) {
193282
+ const config2 = this.moduleAt(module);
193283
+ const list = config2 !== null && Array.isArray(config2["resources"]) ? config2["resources"] : [];
193284
+ const found = list.find((entry2) => isObject4(entry2) && entry2["address"] === local2);
193285
+ if (found === void 0) return null;
193286
+ return { attributes: attributesOf3(found["expressions"]), dependsOn: strings3(found["depends_on"]), providerKey: typeof found["provider_config_key"] === "string" ? found["provider_config_key"] : null };
193287
+ }
193288
+ /** What a reference written in a module instance names, followed through module outputs and the variables its call passes. */
193289
+ resolve(ref, module, depth = 0) {
193290
+ if (depth > MAX_DEPTH15) return [];
193291
+ const steps = references(ref)[0] ?? [];
193292
+ const [first, second, third, fourth] = steps;
193293
+ const name2 = (step) => step?.kind === "name" ? step.text : null;
193294
+ const prefix = module === "" ? "" : `${module}.`;
193295
+ const head = name2(first);
193296
+ if (head === null) return [];
193297
+ if (head === "data" && TYPE2.test(name2(second) ?? "") && name2(third) !== null) return [{ kind: "item", address: `${prefix}data.${name2(second)}.${name2(third)}`, index: suffixOf2(fourth) }];
193298
+ if (TYPE2.test(head) && name2(second) !== null && name2(second) !== "*") return [{ kind: "item", address: `${prefix}${head}.${name2(second)}`, index: suffixOf2(third) }];
193299
+ if (head === "module" && name2(second) !== null) return this.output(module, name2(second), steps.slice(2), depth);
193300
+ if (head === "var" && name2(second) !== null) return this.variable(module, name2(second), depth);
193301
+ return [];
193302
+ }
193303
+ /** `module.name.output`: what the output's expression names in each instance of the call, or in the one the key chooses. */
193304
+ output(module, call, rest, depth) {
193305
+ const prefix = module === "" ? "" : `${module}.`;
193306
+ const key = suffixOf2(rest[0]);
193307
+ const after = rest[0]?.kind === "index" ? rest.slice(1) : rest;
193308
+ const output2 = after[0]?.kind === "name" ? after[0].text : null;
193309
+ if (output2 === null) return [];
193310
+ const base = `${prefix}module.${call}`;
193311
+ const chosen = this.instances.filter((address) => key === null ? address === base || address.startsWith(`${base}[`) && !address.slice(base.length).includes(".") : address === `${base}${key}`);
193312
+ const out = [];
193313
+ for (const instance of chosen) {
193314
+ const config2 = this.moduleAt(instance);
193315
+ const outputs = config2 !== null && isObject4(config2["outputs"]) ? config2["outputs"] : {};
193316
+ const entry2 = outputs[output2];
193317
+ const expression2 = isObject4(entry2) && isObject4(entry2["expression"]) ? entry2["expression"] : null;
193318
+ for (const inner of strings3(expression2?.["references"])) out.push(...this.resolve(inner, instance, depth + 1));
193319
+ }
193320
+ return out;
193321
+ }
193322
+ /** `var.name` in a module: what its call passes, read where the call is written; at the root, the variable itself. */
193323
+ variable(module, variable, depth) {
193324
+ if (module === "") return [{ kind: "var", name: variable }];
193325
+ const call = this.callAt(module);
193326
+ const expressions = call !== null && isObject4(call["expressions"]) ? call["expressions"] : {};
193327
+ const passed = expressions[variable];
193328
+ const refs = isObject4(passed) ? strings3(passed["references"]).filter((ref) => !SAME_INSTANCE.has(ref)) : [];
193329
+ return refs.flatMap((ref) => this.resolve(ref, parentOf3(module), depth + 1));
193330
+ }
193331
+ };
193332
+ }
193333
+ });
193334
+
193335
+ // ../../packages/diagrams/src/importers/terraform-plan/resources.ts
193336
+ function rawOf(value) {
193337
+ if (isObject4(value)) {
193338
+ const entries2 = Object.entries(value).filter((entry2) => typeof entry2[1] === "string");
193339
+ return `{ ${entries2.map(([key, entry2]) => `${key} = ${JSON.stringify(entry2)}`).join(", ")} }`;
193340
+ }
193341
+ return JSON.stringify(value);
193342
+ }
193343
+ function valuesOf2(resource) {
193344
+ const out = /* @__PURE__ */ new Map();
193345
+ for (const [name2, value] of Object.entries(resource.values)) {
193346
+ if (resource.sensitive[name2] === true || SKIPPED2.has(name2)) continue;
193347
+ if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") out.set(name2, String(value));
193348
+ }
193349
+ const tags = resource.values["tags"];
193350
+ const hidden = resource.sensitive["tags"];
193351
+ if (isObject4(tags) && typeof tags["Name"] === "string" && !(isObject4(hidden) && hidden["Name"] === true) && hidden !== true) out.set("tags.Name", tags["Name"]);
193352
+ return out;
193353
+ }
193354
+ function blockOf2(resource, values, start2) {
193355
+ const attributes2 = [];
193356
+ for (const [name2, value] of Object.entries(resource.values)) {
193357
+ if (resource.sensitive[name2] === true || SKIPPED2.has(name2) || value === null) continue;
193358
+ if (name2 === "tags" && !values.has("tags.Name")) continue;
193359
+ attributes2.push({ name: name2, raw: rawOf(value), literal: values.get(name2) ?? null });
193360
+ }
193361
+ return { type: resource.mode === "data" ? "data" : "resource", labels: [resource.type, resource.name], start: start2, body: "", attributes: attributes2, blocks: [] };
193362
+ }
193363
+ function stringsOf(values, sensitive) {
193364
+ const out = [];
193365
+ const walk = (value, name2, hidden, depth) => {
193366
+ if (out.length >= MAX_VALUES || depth > MAX_VALUE_DEPTH || hidden === true) return;
193367
+ if (typeof value === "string") out.push({ name: name2, value });
193368
+ else if (Array.isArray(value)) value.forEach((item, index2) => walk(item, name2, Array.isArray(hidden) ? hidden[index2] : void 0, depth + 1));
193369
+ else if (isObject4(value)) for (const [key, entry2] of Object.entries(value)) walk(entry2, key, isObject4(hidden) ? hidden[key] : void 0, depth + 1);
193370
+ };
193371
+ for (const [name2, value] of Object.entries(values)) if (!OWN_IDS.has(name2) && !SKIPPED2.has(name2) && name2 !== "tags") walk(value, name2, sensitive[name2], 0);
193372
+ return out;
193373
+ }
193374
+ function planResources(document2, text3) {
193375
+ const all = [...document2.resources, ...document2.destroyed.filter((resource) => !document2.resources.some((kept2) => kept2.address === resource.address))];
193376
+ const byBase = /* @__PURE__ */ new Map();
193377
+ for (const resource of all) byBase.set(baseOf(resource), [...byBase.get(baseOf(resource)) ?? [], resource]);
193378
+ const keyOf5 = /* @__PURE__ */ new Map();
193379
+ for (const resource of all) {
193380
+ const copies = byBase.get(baseOf(resource)) ?? [];
193381
+ keyOf5.set(resource.address, copies.length === 1 && resource.index === 0 ? baseOf(resource) : resource.address);
193382
+ }
193383
+ const alias = /* @__PURE__ */ new Map();
193384
+ for (const resource of all) {
193385
+ if (resource.mode !== "data") continue;
193386
+ const same = `${resource.module === "" ? "" : `${resource.module}.`}${resource.type}.${resource.name}`;
193387
+ if (byBase.has(same)) alias.set(baseOf(resource), same);
193388
+ }
193389
+ const instances = [...new Set(all.map((resource) => resource.module).filter((module) => module !== "").flatMap((module) => callsOf2(module).map((_call, index2, calls) => calls.slice(0, index2 + 1).map((call) => `module.${call.name}${call.suffix}`).join("."))))];
193390
+ const configuration = new Configuration(document2.configuration === null ? null : isObject4(document2.configuration["root_module"]) ? document2.configuration["root_module"] : null, instances);
193391
+ const expand2 = (target, own2, paired) => {
193392
+ if (target.kind !== "item") return [];
193393
+ const base = alias.get(target.address) ?? target.address;
193394
+ const copies = byBase.get(base) ?? [];
193395
+ const chosen = target.index !== null ? copies.filter((copy) => indexSuffix(copy.index) === target.index) : paired && own2 !== null && copies.some((copy) => copy.index === own2) ? copies.filter((copy) => copy.index === own2) : copies;
193396
+ return chosen.map((copy) => keyOf5.get(copy.address) ?? copy.address);
193397
+ };
193398
+ const byId = /* @__PURE__ */ new Map();
193399
+ const idsOf2 = /* @__PURE__ */ new Map();
193400
+ const byName = /* @__PURE__ */ new Map();
193401
+ for (const resource of all) {
193402
+ const key = keyOf5.get(resource.address) ?? resource.address;
193403
+ for (const attribute2 of ID_ATTRIBUTES) {
193404
+ const value = resource.values[attribute2];
193405
+ if (typeof value !== "string" || value.length < MIN_ID_LENGTH) continue;
193406
+ byId.set(value, byId.has(value) && byId.get(value) !== key ? null : key);
193407
+ idsOf2.set(key, /* @__PURE__ */ new Set([...idsOf2.get(key) ?? [], value]));
193408
+ }
193409
+ const name2 = resource.values["name"];
193410
+ if (typeof name2 === "string" && name2 !== "") byName.set(name2, [...byName.get(name2) ?? [], { type: resource.type, key }]);
193411
+ }
193412
+ const chosenBy = (keys, value) => {
193413
+ if (keys.length < 2 || value === void 0) return [...keys];
193414
+ const held = keys.filter((target) => [...idsOf2.get(target) ?? []].some((id) => value.has(id)));
193415
+ return held.length === 0 ? [...keys] : held;
193416
+ };
193417
+ const resources = /* @__PURE__ */ new Map();
193418
+ const offsets2 = /* @__PURE__ */ new Map();
193419
+ const throughLocals = [];
193420
+ const fromState = /* @__PURE__ */ new Set();
193421
+ for (const resource of all) {
193422
+ const key = keyOf5.get(resource.address) ?? resource.address;
193423
+ if (resource.mode === "data" && alias.has(baseOf(resource))) continue;
193424
+ const start2 = Math.max(0, text3.indexOf(JSON.stringify(resource.address)));
193425
+ offsets2.set(key, start2);
193426
+ const byAttribute = /* @__PURE__ */ new Map();
193427
+ const vars = /* @__PURE__ */ new Map();
193428
+ const add2 = (map2, name2, refs) => {
193429
+ const kept2 = refs.filter((ref) => ref !== key);
193430
+ if (kept2.length > 0) map2.set(name2, [.../* @__PURE__ */ new Set([...map2.get(name2) ?? [], ...kept2])]);
193431
+ };
193432
+ const local2 = `${resource.mode === "data" ? "data." : ""}${resource.type}.${resource.name}`;
193433
+ const configured = document2.destroyed.includes(resource) ? null : configuration.resourceAt(resource.module, local2);
193434
+ if (configured !== null) {
193435
+ if (configured.attributes.some((attribute2) => attribute2.refs.some((ref) => ref.startsWith("local.")))) throughLocals.push(key);
193436
+ const known3 = /* @__PURE__ */ new Map();
193437
+ for (const { name: name2, value } of stringsOf(resource.values, resource.sensitive)) known3.set(name2, /* @__PURE__ */ new Set([...known3.get(name2) ?? [], value]));
193438
+ for (const attribute2 of configured.attributes) {
193439
+ for (const ref of attribute2.refs) {
193440
+ for (const target of configuration.resolve(ref, resource.module)) {
193441
+ if (target.kind === "var") add2(vars, attribute2.name, [target.name]);
193442
+ else add2(byAttribute, attribute2.name, chosenBy(expand2(target, resource.index, attribute2.paired), known3.get(attribute2.name)));
193443
+ }
193444
+ }
193445
+ }
193446
+ const order = configured.dependsOn.flatMap((ref) => configuration.resolve(ref, resource.module)).flatMap((target) => expand2(target, null, false));
193447
+ add2(byAttribute, "depends_on", order);
193448
+ } else {
193449
+ const allowed = (target) => resource.dependsOn.length === 0 || resource.dependsOn.some((written3) => names7(written3, target));
193450
+ for (const { name: name2, value } of stringsOf(resource.values, resource.sensitive)) {
193451
+ const byIdKey = value.length >= MIN_ID_LENGTH ? byId.get(value) : void 0;
193452
+ if (byIdKey !== void 0 && byIdKey !== null && allowed(byIdKey)) {
193453
+ add2(byAttribute, name2, [byIdKey]);
193454
+ continue;
193455
+ }
193456
+ const stem2 = /^(.+)_name$/.exec(name2)?.[1];
193457
+ const named = stem2 === void 0 ? [] : (byName.get(value) ?? []).filter((entry2) => entry2.type.endsWith(`_${stem2}`) && allowed(entry2.key));
193458
+ if (named.length === 1 && named[0] !== void 0) add2(byAttribute, name2, [named[0].key]);
193459
+ }
193460
+ const joined2 = new Set([...byAttribute.values()].flat());
193461
+ const order = [...keyOf5.values()].filter((other) => resource.dependsOn.some((entry2) => !isModuleAddress(entry2) && names7(entry2, other)) && !joined2.has(other));
193462
+ add2(byAttribute, "depends_on", order);
193463
+ if (order.length > 0) fromState.add(key);
193464
+ }
193465
+ const values = valuesOf2(resource);
193466
+ const from = (placement) => [...new Set([...byAttribute].filter(([name2]) => PLACEMENT_ATTRIBUTES.has(name2) === placement).flatMap(([, refs]) => refs))];
193467
+ const providerKey = configured?.providerKey ?? null;
193468
+ resources.set(key, {
193469
+ key,
193470
+ kind: resource.mode === "data" ? "data" : "resource",
193471
+ type: resource.type,
193472
+ name: copyName(resource.name, key === baseOf(resource) ? null : String(resource.index)),
193473
+ block: blockOf2(resource, values, start2),
193474
+ role: roleOf2(resource.type),
193475
+ refs: from(false),
193476
+ placement: from(true),
193477
+ byAttribute,
193478
+ vars,
193479
+ values,
193480
+ readable: /* @__PURE__ */ new Map(),
193481
+ local: local2,
193482
+ scope: resource.module === "" ? "" : `${resource.module}.`,
193483
+ instance: key !== baseOf(resource),
193484
+ provider: providerKey === null ? resource.type.split("_")[0] ?? "" : providerKey.split(":").pop() ?? providerKey
193485
+ });
193486
+ }
193487
+ for (const key of fromState) {
193488
+ const resource = resources.get(key);
193489
+ if (resource !== void 0) resources.set(key, withoutIndirectOrder(resource, resources));
193490
+ }
193491
+ return { resources, modules: moduleFrames(instances, configuration, text3), offsets: offsets2, throughLocals };
193492
+ }
193493
+ function withoutIndirectOrder(resource, resources) {
193494
+ const order = resource.byAttribute.get("depends_on") ?? [];
193495
+ const direct = [...new Set([...resource.byAttribute.values()].flat())];
193496
+ const reachable = /* @__PURE__ */ new Set();
193497
+ let frontier = direct.flatMap((key) => [...resources.get(key)?.byAttribute.values() ?? []].flat());
193498
+ for (let depth = 0; frontier.length > 0 && depth < MAX_ORDER_DEPTH; depth += 1) {
193499
+ const next = frontier.filter((key) => key !== resource.key && !reachable.has(key));
193500
+ for (const key of next) reachable.add(key);
193501
+ frontier = next.flatMap((key) => [...resources.get(key)?.byAttribute.values() ?? []].flat());
193502
+ }
193503
+ const kept2 = order.filter((key) => !reachable.has(key));
193504
+ if (kept2.length === order.length) return resource;
193505
+ const byAttribute = new Map(resource.byAttribute);
193506
+ if (kept2.length === 0) byAttribute.delete("depends_on");
193507
+ else byAttribute.set("depends_on", kept2);
193508
+ const from = (placement) => [...new Set([...byAttribute].filter(([name2]) => PLACEMENT_ATTRIBUTES.has(name2) === placement).flatMap(([, refs]) => refs))];
193509
+ return { ...resource, byAttribute, refs: from(false), placement: from(true) };
193510
+ }
193511
+ function moduleFrames(instances, configuration, text3) {
193512
+ return instances.map((address) => {
193513
+ const calls = callsOf2(address);
193514
+ const last = calls[calls.length - 1];
193515
+ const call = configuration.callAt(address);
193516
+ const source = call !== null && typeof call["source"] === "string" ? call["source"] : "";
193517
+ const name2 = last?.name ?? address;
193518
+ const key = last?.suffix ?? "";
193519
+ const instance = key === "" ? null : key.replace(/^\["?|"?\]$/g, "");
193520
+ const start2 = Math.max(0, text3.indexOf(`"${address.replace(/"/g, '\\"')}"`));
193521
+ return { prefix: `${address}.`, key: address, name: name2, instance, source, block: { type: "module", labels: [name2], start: start2, body: "", attributes: [], blocks: [] } };
193522
+ });
193523
+ }
193524
+ var MAX_VALUE_DEPTH, MAX_VALUES, MIN_ID_LENGTH, OWN_IDS, ID_ATTRIBUTES, SKIPPED2, baseOf, names7, MAX_ORDER_DEPTH, isModuleAddress;
193525
+ var init_resources2 = __esm({
193526
+ "../../packages/diagrams/src/importers/terraform-plan/resources.ts"() {
193527
+ "use strict";
193528
+ init_address();
193529
+ init_generic();
193530
+ init_graph4();
193531
+ init_resources();
193532
+ init_document3();
193533
+ init_references2();
193534
+ MAX_VALUE_DEPTH = 6;
193535
+ MAX_VALUES = 400;
193536
+ MIN_ID_LENGTH = 6;
193537
+ OWN_IDS = /* @__PURE__ */ new Set(["id", "arn", "self_link", "unique_id"]);
193538
+ ID_ATTRIBUTES = ["id", "arn", "self_link"];
193539
+ SKIPPED2 = /* @__PURE__ */ new Set(["tags_all", "timeouts"]);
193540
+ baseOf = (resource) => `${resource.module === "" ? "" : `${resource.module}.`}${resource.mode === "data" ? "data." : ""}${resource.type}.${resource.name}`;
193541
+ names7 = (written3, address) => address === written3 || address.startsWith(`${written3}[`) || address.startsWith(`${written3}.`);
193542
+ MAX_ORDER_DEPTH = 32;
193543
+ isModuleAddress = (address) => !/(?:^|\.)[a-z][a-z0-9]*_[a-z0-9_]+\.[A-Za-z0-9_-]+(?:\[[^\]]*\])?$/.test(address);
193544
+ }
193545
+ });
193546
+
193547
+ // ../../packages/diagrams/src/importers/terraform-plan/index.ts
193548
+ function changeName(change, importing) {
193549
+ if (change === void 0) return null;
193550
+ const actions = change.actions.join(",");
193551
+ if (actions === "create") return "create";
193552
+ if (actions === "update") return importing ? "import" : "update";
193553
+ if (actions === "delete,create" || actions === "create,delete") return "replace";
193554
+ if (actions === "delete") return "destroy";
193555
+ if (actions === "forget") return "forget";
193556
+ if (actions === "no-op") return importing ? "import" : change.previous !== null ? "move" : null;
193557
+ return null;
193558
+ }
193559
+ function importedOf(json2) {
193560
+ const out = /* @__PURE__ */ new Set();
193561
+ const changes = json2["resource_changes"];
193562
+ if (Array.isArray(changes)) {
193563
+ for (const entry2 of changes) if (isObject4(entry2) && isObject4(entry2["change"]) && entry2["change"]["importing"] !== void 0 && typeof entry2["address"] === "string") out.add(entry2["address"]);
193564
+ }
193565
+ return out;
193566
+ }
193567
+ function accountsOf(document2, types) {
193568
+ const out = /* @__PURE__ */ new Map();
193569
+ for (const entry2 of Object.values(document2.providers)) {
193570
+ if (!isObject4(entry2) || typeof entry2["name"] !== "string") continue;
193571
+ const cloud = providerOf2(`${entry2["name"]}_x`);
193572
+ if (cloud === null || out.get(cloud) !== void 0) continue;
193573
+ const expressions = isObject4(entry2["expressions"]) ? entry2["expressions"] : {};
193574
+ const project = isObject4(expressions["project"]) ? expressions["project"]["constant_value"] : void 0;
193575
+ out.set(cloud, cloud === "gcp" && typeof project === "string" ? project : null);
193576
+ }
193577
+ for (const type of types) {
193578
+ const cloud = providerOf2(type);
193579
+ if (cloud !== null && !out.has(cloud)) out.set(cloud, null);
193580
+ }
193581
+ return out;
193582
+ }
193583
+ function regionsOf2(document2) {
193584
+ const out = /* @__PURE__ */ new Map();
193585
+ const byProvider = /* @__PURE__ */ new Map();
193586
+ for (const [key, entry2] of Object.entries(document2.providers)) {
193587
+ if (!isObject4(entry2) || typeof entry2["name"] !== "string" || key.includes(":")) continue;
193588
+ const expressions = isObject4(entry2["expressions"]) ? entry2["expressions"] : {};
193589
+ const region = isObject4(expressions["region"]) ? expressions["region"]["constant_value"] : void 0;
193590
+ if (typeof region !== "string" || region === "") continue;
193591
+ out.set(key, region);
193592
+ byProvider.set(entry2["name"], /* @__PURE__ */ new Set([...byProvider.get(entry2["name"]) ?? [], region]));
193593
+ }
193594
+ for (const [key] of out) if ((byProvider.get(key.split(".")[0] ?? "")?.size ?? 0) < 2) out.delete(key);
193595
+ return out;
193596
+ }
193597
+ function summaryOf(document2, imported) {
193598
+ let add2 = 0;
193599
+ let change = 0;
193600
+ let destroy = 0;
193601
+ let importing = 0;
193602
+ for (const [address, entry2] of document2.changes) {
193603
+ const actions = entry2.actions.join(",");
193604
+ if (actions === "create" || actions === "delete,create" || actions === "create,delete") add2 += 1;
193605
+ if (actions === "update") change += 1;
193606
+ if (actions === "delete" || actions === "delete,create" || actions === "create,delete") destroy += 1;
193607
+ if (imported.has(address)) importing += 1;
193608
+ }
193609
+ if (add2 + change + destroy + importing === 0) return "no changes";
193610
+ return `${importing > 0 ? `${importing} to import, ` : ""}${add2} to add, ${change} to change, ${destroy} to destroy`;
193611
+ }
193612
+ function readTerraformPlan(text3, context) {
193613
+ const index2 = new LineIndex(text3);
193614
+ let json2;
193615
+ try {
193616
+ json2 = JSON.parse(text3);
193617
+ } catch (error62) {
193618
+ context.report.add(DIAGNOSTIC_CODES.importUnreadable, START, `The text is not JSON: ${error62 instanceof Error ? error62.message : "it cannot be read"}.`, "Send the output of terraform show -json plan.out, or of terraform show -json for the state, as it is written.");
193619
+ return null;
193620
+ }
193621
+ const document2 = readPlanDocument(json2);
193622
+ if (document2 === null || !isObject4(json2)) {
193623
+ context.report.add(DIAGNOSTIC_CODES.importNoShape, START, "The JSON is neither a plan (planned_values and resource_changes) nor a state (values.root_module).", "Run terraform plan -out=plan.out, then send the output of terraform show -json plan.out; or send terraform show -json for the state.");
193624
+ return null;
193625
+ }
193626
+ if (json2["errored"] === true) context.report.add(DIAGNOSTIC_CODES.importChanged, START, "The plan stopped on an error, so it may hold only part of the stack.", "Fix the error terraform plan reports, and send the plan again.");
193627
+ const missing = [...document2.changes].filter(([address, change]) => destroys(change) && !document2.destroyed.some((resource) => resource.address === address)).map(([address]) => address);
193628
+ if (missing.length > 0) context.report.add(DIAGNOSTIC_CODES.importSkipped, START, `${countOf2(missing.length, "resource")} the plan destroys ${missing.length === 1 ? "is" : "are"} not in its prior state, so ${missing.length === 1 ? "it is" : "they are"} not drawn: ${missing.slice(0, 3).map((address) => cleanText(address)).join(", ")}.`, "Send the plan as terraform show -json writes it, with prior_state.");
193629
+ const stack = planResources(document2, text3);
193630
+ if (![...stack.resources.values()].some((resource) => resource.kind !== "data")) {
193631
+ context.report.add(DIAGNOSTIC_CODES.importNoShape, START, `The ${document2.kind} holds no managed resource.`, document2.kind === "plan" ? "Send the plan of a stack with resource blocks." : "Send the state of a stack that has been applied.");
193632
+ return null;
193633
+ }
193634
+ const first = stack.throughLocals[0];
193635
+ if (first !== void 0) {
193636
+ context.report.add(DIAGNOSTIC_CODES.importUnresolved, index2.span(stack.offsets.get(first) ?? 0), `${countOf2(stack.throughLocals.length, "resource")} name${stack.throughLocals.length === 1 ? "s" : ""} other resources through local values, which the plan's JSON does not expand, so those arrows are not drawn: ${stack.throughLocals.slice(0, 3).join(", ")}.`, "Import the .tf files with format terraform for those arrows, or reference the resources directly.");
193637
+ }
193638
+ const imported = importedOf(json2);
193639
+ const tones = /* @__PURE__ */ new Set();
193640
+ const changeOf = (key) => {
193641
+ const address = document2.changes.has(key) ? key : `${key}[0]`;
193642
+ const name2 = changeName(document2.changes.get(address), imported.has(address));
193643
+ const drifted2 = document2.drift.has(address);
193644
+ if (name2 === null) return drifted2 ? { tone: "neutral", word: "drifted" } : null;
193645
+ const look = CHANGES[name2];
193646
+ if (look === void 0) return null;
193647
+ tones.add(name2);
193648
+ return { tone: look.tone, word: drifted2 ? `${look.word}, drifted` : look.word, ...look.mark === void 0 ? {} : { mark: look.mark } };
193649
+ };
193650
+ for (const key of stack.resources.keys()) changeOf(key);
193651
+ const said = Object.keys(CHANGES).filter((name2) => tones.has(name2)).map((name2, at3) => (CHANGES[name2]?.said ?? "").replace(/^(?:a box|one) /, at3 === 0 ? "a box " : "one "));
193652
+ const drifted = [...document2.drift].length;
193653
+ const note = document2.kind === "state" ? "It is drawn from the state, as the stack was last applied." : `It is drawn as the plan leaves the stack${said.length === 0 ? ", which the plan does not change" : `: ${joinWords2(said)}`}.${drifted > 0 ? ` ${countOf2(drifted, "resource")} changed outside Terraform since the last apply, marked drifted.` : ""}`;
193654
+ const variable = (name2) => {
193655
+ const value = document2.variables.get(name2);
193656
+ return value === void 0 || value === "" ? null : lastPart(value);
193657
+ };
193658
+ const regions = regionsOf2(document2);
193659
+ const keyed = [...stack.resources.values()];
193660
+ return drawStack({
193661
+ resources: stack.resources,
193662
+ modules: stack.modules,
193663
+ compatible: stack.modules.length === 0 && !keyed.some((resource) => resource.instance === true),
193664
+ regionOf: (resource) => regions.get(resource.provider ?? "") ?? null,
193665
+ providers: accountsOf(document2, keyed.map((resource) => resource.type)),
193666
+ variableName: (name2) => variable(name2) ?? variableLabel(name2),
193667
+ variableValue: variable,
193668
+ context,
193669
+ span: (key) => index2.span(stack.offsets.get(key) ?? 0),
193670
+ tool: "Terraform",
193671
+ change: changeOf,
193672
+ ...document2.kind === "plan" ? { summary: summaryOf(document2, imported) } : {},
193673
+ note
193674
+ });
193675
+ }
193676
+ function joinWords2(words2) {
193677
+ if (words2.length < 3) return words2.join(" or ");
193678
+ return `${words2.slice(0, -1).join(", ")}, or ${words2[words2.length - 1] ?? ""}`;
193679
+ }
193680
+ var CHANGES, terraformPlanImporter;
193681
+ var init_terraform_plan = __esm({
193682
+ "../../packages/diagrams/src/importers/terraform-plan/index.ts"() {
193683
+ "use strict";
193684
+ init_core();
193685
+ init_shared2();
193686
+ init_terraform();
193687
+ init_labels();
193688
+ init_resources();
193689
+ init_values2();
193690
+ init_document3();
193691
+ init_resources2();
193692
+ CHANGES = {
193693
+ create: { tone: "green", word: "create", said: "one marked + is created", mark: "create" },
193694
+ update: { tone: "amber", word: "update", said: "one marked ~ is changed in place", mark: "update" },
193695
+ replace: { tone: "orange", word: "replace", said: "one marked \xB1 is replaced", mark: "replace" },
193696
+ destroy: { tone: "red", word: "destroy", said: "one marked \u2212 is destroyed", mark: "destroy" },
193697
+ import: { tone: "aqua", word: "import", said: "one in aqua is imported" },
193698
+ move: { tone: "aqua", word: "move", said: "one in aqua is moved" },
193699
+ forget: { tone: "violet", word: "forget", said: "one in violet is removed from the state and kept in the cloud" }
193700
+ };
193701
+ terraformPlanImporter = { format: "terraform-plan", kinds: ["flow"], joins: null, extensions: [".json"], read: readTerraformPlan };
193702
+ }
193703
+ });
193704
+
192864
193705
  // ../../packages/diagrams/src/importers/tree/read.ts
192865
193706
  function childOf(parent, name2, line3) {
192866
193707
  const existing = parent.find((entry3) => entry3.name === name2);
@@ -193176,6 +194017,7 @@ var init_registry4 = __esm({
193176
194017
  init_pulumi();
193177
194018
  init_sql();
193178
194019
  init_terraform();
194020
+ init_terraform_plan();
193179
194021
  init_tree5();
193180
194022
  IMPORTERS = {
193181
194023
  sql: sqlImporter,
@@ -193183,6 +194025,7 @@ var init_registry4 = __esm({
193183
194025
  drizzle: drizzleImporter,
193184
194026
  openapi: openapiImporter,
193185
194027
  terraform: terraformImporter,
194028
+ "terraform-plan": terraformPlanImporter,
193186
194029
  bicep: bicepImporter,
193187
194030
  arm: armImporter,
193188
194031
  pulumi: pulumiImporter,
@@ -193299,7 +194142,7 @@ function importSource(format, input2, title = null, options3 = {}, limits = HOST
193299
194142
  const report3 = new ImportReporter();
193300
194143
  const files = typeof input2 === "string" ? [{ path: "", text: input2 }] : input2;
193301
194144
  const characters = files.reduce((total, file2) => total + file2.text.length, 0);
193302
- const local2 = limits.maxLength < WORKFLOW_LIMITS.maxImportLocalLength ? ` The local server (npx -y @buun_group/plotwork-mcp) runs on your own machine and reads far more.` : "";
194145
+ const local2 = limits.maxLength < WORKFLOW_LIMITS.maxImportLocalLength ? ` The local server (${mcpCommand()}) runs on your own machine and reads far more.` : "";
193303
194146
  if (characters > limits.maxText || files.length > limits.maxFiles) {
193304
194147
  report3.add(
193305
194148
  DIAGNOSTIC_CODES.importTooLarge,
@@ -193578,13 +194421,13 @@ var init_definitions = __esm({
193578
194421
 
193579
194422
  // ../../packages/diagrams/src/edit/find.ts
193580
194423
  function namesIn2(scan) {
193581
- const names7 = /* @__PURE__ */ new Set();
194424
+ const names8 = /* @__PURE__ */ new Set();
193582
194425
  for (const element of scan.elements) {
193583
194426
  if (!NAMED_ROLES.has(element.role)) continue;
193584
- if (element.id !== null) names7.add(element.id);
193585
- if (element.label !== null) names7.add(element.label);
194427
+ if (element.id !== null) names8.add(element.id);
194428
+ if (element.label !== null) names8.add(element.label);
193586
194429
  }
193587
- return [...names7];
194430
+ return [...names8];
193588
194431
  }
193589
194432
  function unknownHint(scan, target) {
193590
194433
  const close2 = suggest(target, namesIn2(scan));
@@ -193697,7 +194540,7 @@ function spliced(line3, splices) {
193697
194540
  return [...splices].sort((a, b) => b.start - a.start).reduce((text3, splice) => `${text3.slice(0, splice.start)}${splice.text}${text3.slice(splice.end)}`, line3);
193698
194541
  }
193699
194542
  var TYPE_WORDS2;
193700
- var init_references2 = __esm({
194543
+ var init_references3 = __esm({
193701
194544
  "../../packages/diagrams/src/edit/references.ts"() {
193702
194545
  "use strict";
193703
194546
  init_constants();
@@ -193771,23 +194614,23 @@ function remove(scan, op) {
193771
194614
  const element = scan.elements[found.index];
193772
194615
  if (element.role === "header") return refused2("The header cannot be removed.", "Change it with set, or replace_text.");
193773
194616
  const gone = [found.index, ...descendantsOf(scan, found.index)];
193774
- const names7 = new Set(gone.map((index2) => referenceName(scan.elements[index2])).filter((name2) => name2 !== null));
194617
+ const names8 = new Set(gone.map((index2) => referenceName(scan.elements[index2])).filter((name2) => name2 !== null));
193775
194618
  const block = element.parent === null ? null : scan.elements[element.parent];
193776
- if (element.role === "row" && element.id !== null && block !== null) names7.add(`${block.id ?? block.label ?? ""}.${element.id}`);
194619
+ if (element.role === "row" && element.id !== null && block !== null) names8.add(`${block.id ?? block.label ?? ""}.${element.id}`);
193777
194620
  const drop = /* @__PURE__ */ new Set();
193778
194621
  for (let line3 = element.start; line3 <= element.end; line3 += 1) drop.add(line3);
193779
194622
  const left = [];
193780
194623
  let edges = 0;
193781
194624
  let others = 0;
193782
- const isGone = (end) => end !== null && [...names7].some((name2) => end === name2 || end.startsWith(`${name2}.`));
194625
+ const isGone = (end) => end !== null && [...names8].some((name2) => end === name2 || end.startsWith(`${name2}.`));
193783
194626
  scan.elements.forEach((candidate2) => {
193784
194627
  if (drop.has(candidate2.start) || candidate2.role === "header") return;
193785
194628
  const tokens = scan.tokens.get(candidate2.start) ?? [];
193786
- if (candidate2.role === "edge" ? isGone(candidate2.from) || isGone(candidate2.to) : candidate2.role === "other" && [...names7].some((name2) => idReferences(tokens, name2, false).length > 0 || tokens.some((token) => token.kind === "string" && token.text === name2))) {
194629
+ if (candidate2.role === "edge" ? isGone(candidate2.from) || isGone(candidate2.to) : candidate2.role === "other" && [...names8].some((name2) => idReferences(tokens, name2, false).length > 0 || tokens.some((token) => token.kind === "string" && token.text === name2))) {
193787
194630
  if (candidate2.role === "edge") edges += 1;
193788
194631
  else others += 1;
193789
194632
  for (let line3 = candidate2.start; line3 <= candidate2.end; line3 += 1) drop.add(line3);
193790
- } else if (candidate2.options.some((option) => REFERENCE_OPTIONS.has(option.key) && option.value.split(",").some((value) => names7.has(value.trim())))) {
194633
+ } else if (candidate2.options.some((option) => REFERENCE_OPTIONS.has(option.key) && option.value.split(",").some((value) => names8.has(value.trim())))) {
193791
194634
  left.push(candidate2.start);
193792
194635
  }
193793
194636
  });
@@ -193836,7 +194679,7 @@ var init_structure = __esm({
193836
194679
  "use strict";
193837
194680
  init_find();
193838
194681
  init_outcome();
193839
- init_references2();
194682
+ init_references3();
193840
194683
  init_scan2();
193841
194684
  init_source_text();
193842
194685
  NODE_STATEMENTS = {
@@ -194034,7 +194877,7 @@ var init_rename_set = __esm({
194034
194877
  "use strict";
194035
194878
  init_find();
194036
194879
  init_outcome();
194037
- init_references2();
194880
+ init_references3();
194038
194881
  init_source_text();
194039
194882
  }
194040
194883
  });
@@ -194660,7 +195503,7 @@ var init_import_source3 = __esm({
194660
195503
  importSourceWorkflow = defineWorkflow({
194661
195504
  name: "import_source",
194662
195505
  title: "Import source",
194663
- description: "Workflow. Turns a file into a finished diagram in one call: SQL DDL, Prisma, or Drizzle into a schema; an OpenAPI document into an endpoint access matrix, a map of its endpoints by tag, or one operation as a sequence; Terraform, Bicep, ARM, Pulumi, CloudFormation, Compose, Kubernetes, or a GitHub Actions workflow into a flow with icons and frames; CSV or JSON data into the chart its shape suits; tree output or paths into a tree; a git log into a git graph or timeline. Prefer it to writing the diagram by hand whenever the person has such a file: send its text, never a path, or for a Terraform or Bicep stack, SQL migrations, or Kubernetes manifests send every file of the folder in files. Returns the source, diagnostics pointing into the file for anything left out, coverage of the file, parts (every diagram of a split file), the validation, an outline, viewUrl, and saveCommand. It runs no code and reads no file or URL. Replaces reading the file, writing the source by hand, validate_diagram and outline_diagram.",
195506
+ description: "Workflow. Turns a file into a finished diagram in one call: SQL DDL, Prisma, or Drizzle into a schema; an OpenAPI document into an endpoint access matrix, a map of its endpoints by tag, or one operation as a sequence; Terraform, Bicep, ARM, Pulumi, CloudFormation, Compose, Kubernetes, or a GitHub Actions workflow into a flow with icons and frames; CSV or JSON data into the chart its shape suits; tree output or paths into a tree; a git log into a git graph or timeline. Prefer it to writing the diagram by hand whenever the person has such a file: send its text, never a path, or for a stack, migrations, or manifests send every file of the folder in files. Returns the source, diagnostics pointing into the file for anything left out, coverage of the file, parts (every diagram of a split file), the validation, an outline, viewUrl, and saveCommand. It runs no code and reads no file or URL. Replaces writing the source by hand, validate_diagram and outline_diagram.",
194664
195507
  input: ImportSourceInputSchema,
194665
195508
  output: ImportSourceResponseSchema,
194666
195509
  steps: [{ call: "importSource" }, { call: "validate", optional: true }, { call: "outline", optional: true }],
@@ -195359,8 +196202,8 @@ function readMaterial(text3, cap2) {
195359
196202
  }
195360
196203
  closeTable2();
195361
196204
  if (table2 === null && items2.length === 0) table2 = delimitedTable(plain3.filter((line3) => line3.trim() !== ""));
195362
- const names7 = namesInSentence(plain3.join(" "));
195363
- return { items: items2, numbered: items2.length > 0 && numbered * 2 >= items2.length, labelled: labelled2, table: table2, figures, seriesName: series.name, movements, dated, names: names7, relations, actorSteps };
196205
+ const names8 = namesInSentence(plain3.join(" "));
196206
+ return { items: items2, numbered: items2.length > 0 && numbered * 2 >= items2.length, labelled: labelled2, table: table2, figures, seriesName: series.name, movements, dated, names: names8, relations, actorSteps };
195364
196207
  }
195365
196208
  function readShapes(body6, into, cap2) {
195366
196209
  if (body6.length > SHAPE_LINE_CHARACTERS) return;
@@ -195492,8 +196335,8 @@ ${body6.join("\n")}
195492
196335
  `;
195493
196336
  }
195494
196337
  function entitiesOf(material) {
195495
- const names7 = distinctLabels(material.names);
195496
- if (names7.length >= 2) return names7;
196338
+ const names8 = distinctLabels(material.names);
196339
+ if (names8.length >= 2) return names8;
195497
196340
  const items2 = topItems(material);
195498
196341
  if (items2.length >= 2) return items2;
195499
196342
  const labels2 = distinctLabels(material.labelled.map((line3) => line3.label));
@@ -195587,7 +196430,7 @@ var init_charts = __esm({
195587
196430
  return sourceOf(`pie ${quoted4(title)}`, slices.map((slice) => `slice ${quoted4(slice.label)} ${slice.value}`));
195588
196431
  },
195589
196432
  quadrant: (material, title) => {
195590
- const names7 = orDefault(entitiesOf(material), ["Saved filters", "Mobile app", "Footer links", "Rewrite in Rust"], 2, MOST);
196433
+ const names8 = orDefault(entitiesOf(material), ["Saved filters", "Mobile app", "Footer links", "Rewrite in Rust"], 2, MOST);
195591
196434
  const places = [[0.2, 0.8], [0.75, 0.8], [0.25, 0.25], [0.75, 0.25], [0.4, 0.62], [0.6, 0.4], [0.12, 0.5], [0.88, 0.58]];
195592
196435
  return sourceOf(`quadrant ${quoted4(title)} highlight=top-left`, [
195593
196436
  'x "Effort" low="Low effort" high="High effort"',
@@ -195598,7 +196441,7 @@ var init_charts = __esm({
195598
196441
  'zone bottom-left "Fill-ins"',
195599
196442
  'zone bottom-right "Time sinks"',
195600
196443
  "",
195601
- ...names7.map((name2, index2) => `point ${quoted4(name2)} x=${places[index2]?.[0] ?? 0.5} y=${places[index2]?.[1] ?? 0.5}`)
196444
+ ...names8.map((name2, index2) => `point ${quoted4(name2)} x=${places[index2]?.[0] ?? 0.5} y=${places[index2]?.[1] ?? 0.5}`)
195602
196445
  ]);
195603
196446
  },
195604
196447
  sankey: (material, title) => {
@@ -195639,9 +196482,9 @@ function gridOf(material, columnDefaults, rowDefaults) {
195639
196482
  if (table2 !== null && table2.header.length >= 2 && table2.rows.length >= 1) {
195640
196483
  const columns = distinctLabels(table2.header.slice(1)).slice(0, MOST);
195641
196484
  const rows2 = table2.rows.slice(0, MOST);
195642
- const names7 = rows2.map((row, index2) => cleanLabel2(row[0] ?? "") || `Row ${index2 + 1}`);
195643
- if (columns.length === Math.min(table2.header.length - 1, MOST) && new Set(names7.map((name2) => name2.toLowerCase())).size === names7.length) {
195644
- return { rows: names7, columns, cells: rows2.map((row) => columns.map((_, index2) => row[index2 + 1] ?? "")) };
196485
+ const names8 = rows2.map((row, index2) => cleanLabel2(row[0] ?? "") || `Row ${index2 + 1}`);
196486
+ if (columns.length === Math.min(table2.header.length - 1, MOST) && new Set(names8.map((name2) => name2.toLowerCase())).size === names8.length) {
196487
+ return { rows: names8, columns, cells: rows2.map((row) => columns.map((_, index2) => row[index2 + 1] ?? "")) };
195645
196488
  }
195646
196489
  }
195647
196490
  const lists = listsOf(material);
@@ -195741,11 +196584,11 @@ var init_matrix3 = __esm({
195741
196584
  return matrixSource2(title, "raci", grid, cellsOf2(grid, raciCell));
195742
196585
  },
195743
196586
  "matrix-risk": (material, title) => {
195744
- const names7 = orDefault(entitiesOf(material), ["Data loss", "Vendor outage", "Key person leaves", "Cost overrun"], 2, MOST);
196587
+ const names8 = orDefault(entitiesOf(material), ["Data loss", "Vendor outage", "Key person leaves", "Cost overrun"], 2, MOST);
195745
196588
  const places = [[4, 5], [2, 4], [3, 3], [5, 2], [1, 5], [3, 4], [2, 2], [4, 3]];
195746
196589
  return sourceOf(
195747
196590
  `matrix ${quoted4(title)} style=risk`,
195748
- names7.map((name2, index2) => `item ${quoted4(name2)} likelihood=${places[index2]?.[0] ?? 3} impact=${places[index2]?.[1] ?? 3}`)
196591
+ names8.map((name2, index2) => `item ${quoted4(name2)} likelihood=${places[index2]?.[0] ?? 3} impact=${places[index2]?.[1] ?? 3}`)
195749
196592
  );
195750
196593
  }
195751
196594
  };
@@ -195945,9 +196788,9 @@ function layersOf(material) {
195945
196788
  }
195946
196789
  return layers.filter((layer2) => layer2.name !== "").slice(0, 6);
195947
196790
  }
195948
- const names7 = orDefault(entitiesOf(material), ["Web app", "API", "Database"], 2, MOST);
196791
+ const names8 = orDefault(entitiesOf(material), ["Web app", "API", "Database"], 2, MOST);
195949
196792
  const tiers = ["Experience", "Services", "Data"];
195950
- return tiers.map((name2, index2) => ({ name: name2, blocks: names7.filter((_, place2) => place2 % tiers.length === index2) }));
196793
+ return tiers.map((name2, index2) => ({ name: name2, blocks: names8.filter((_, place2) => place2 % tiers.length === index2) }));
195951
196794
  }
195952
196795
  function partType(name2) {
195953
196796
  if (/\b(postgres(ql)?|mysql|database|db|dynamo(db)?|sql|mongo(db)?|redis|cache|s3|bucket|storage|store)\b/i.test(name2)) return /\b(redis|cache)\b/i.test(name2) ? "cache" : /\b(s3|bucket|storage)\b/i.test(name2) ? "storage" : "database";
@@ -196433,8 +197276,8 @@ function nextFor2(suggestions, cloud) {
196433
197276
  }
196434
197277
  function suggestDiagrams(request, data, check2) {
196435
197278
  const read = readMaterial(data ?? "", WORKFLOW_LIMITS.maxStarterItems);
196436
- const names7 = read.names.length >= 2 ? read.names : namesInSentence(request);
196437
- const material = { ...read, names: names7 };
197279
+ const names8 = read.names.length >= 2 ? read.names : namesInSentence(request);
197280
+ const material = { ...read, names: names8 };
196438
197281
  const ranked = rankIntents(
196439
197282
  [
196440
197283
  { text: request, weight: 2 },
@@ -196943,7 +197786,21 @@ function rebaseFileLinks(value, base) {
196943
197786
  const moved3 = files.map((file2) => isRecord5(file2) && typeof file2["viewUrl"] === "string" && file2["viewUrl"].startsWith(`${engine2}#`) ? { ...file2, viewUrl: `${base}${file2["viewUrl"].slice(engine2.length)}` } : file2);
196944
197787
  return { ...value, files: moved3 };
196945
197788
  }
196946
- var SOURCE_OF, VIEW_LINK_TOOLS;
197789
+ function stripViewLinks(value) {
197790
+ if (!isRecord5(value)) return value;
197791
+ const kept2 = { ...value };
197792
+ for (const field of VIEW_LINK_FIELDS) delete kept2[field];
197793
+ const files = kept2["files"];
197794
+ if (Array.isArray(files)) {
197795
+ kept2["files"] = files.map((file2) => {
197796
+ if (!isRecord5(file2) || !("viewUrl" in file2)) return file2;
197797
+ const { viewUrl: _viewUrl, ...rest } = file2;
197798
+ return rest;
197799
+ });
197800
+ }
197801
+ return kept2;
197802
+ }
197803
+ var SOURCE_OF, VIEW_LINK_TOOLS, VIEW_LINK_FIELDS;
196947
197804
  var init_view_link = __esm({
196948
197805
  "../../packages/diagrams/src/tools/view-link.ts"() {
196949
197806
  "use strict";
@@ -196959,6 +197816,7 @@ var init_view_link = __esm({
196959
197816
  import_source: (_args, answer) => answer["validation"]?.["valid"] === true ? answer["source"] : null
196960
197817
  };
196961
197818
  VIEW_LINK_TOOLS = Object.keys(SOURCE_OF);
197819
+ VIEW_LINK_FIELDS = ["viewUrl", "pngUrl", "svgUrl", "saveCommand"];
196962
197820
  }
196963
197821
  });
196964
197822
 
@@ -197331,6 +198189,12 @@ function savingInstructions(release = CLI_RELEASE) {
197331
198189
  `To save a valid diagram into the person's repository, run the saveCommand a drawing tool returns in a shell, changing --out to the path you want (add --theme dark for the dark picture): the Plotwork command line reads the diagram from the link on that machine, fetches nothing, and writes the SVG with its source embedded, so you never copy the SVG yourself. With no shell, draw with svg "always" and embedSource true and write the returned svg. ${people}`
197332
198190
  ];
197333
198191
  }
198192
+ function libraryInstructions(library) {
198193
+ return `This connection publishes to the private library of ${JSON.stringify(library.name)}, which only its members can open. So, unlike a public link, a finished diagram is saved there without asking: once the person is happy with a diagram, call publish_diagram with its source and leave organization out, then give the person the viewUrl it returns. Pass personal true only when the person asks for a public link.`;
198194
+ }
198195
+ function librarySaveStep(library) {
198196
+ return `When the diagram is finished, save it to the private library of ${JSON.stringify(library.name)} with publish_diagram (no need to ask: only members can open it).`;
198197
+ }
197334
198198
  var SERVER_INFO, SAVING_INSTRUCTIONS, SERVER_INSTRUCTIONS, HOSTED_INSTRUCTIONS;
197335
198199
  var init_server_info = __esm({
197336
198200
  "src/server-info.ts"() {
@@ -197362,7 +198226,7 @@ var init_server_info = __esm({
197362
198226
  "Use validate_diagram, outline_diagram, render_diagram, and search_icons only for one fine-grained step.",
197363
198227
  "Choose node types and tones for meaning; colors are chosen by the theme and cannot be set."
197364
198228
  ].join(" ");
197365
- HOSTED_INSTRUCTIONS = "When the person asks to share a finished diagram or wants a link to it, call publish_diagram with the valid source: it returns a public link and a Markdown image to paste, and publishing the same diagram again returns the same link. Publish only when asked, because anyone with the link can see the picture. After you edit a published diagram, call publish_diagram again: an edited diagram is a new picture with a new link, so replace the old link wherever it is used. Set embedSource true on publish_diagram when someone may want to edit the diagram later, and tell the person that the source is then part of the public picture. A drawing too big to return in an answer is also the case for publish_diagram: it gives a link in place of the picture. To keep a diagram inside a team instead, pass organization with the slug or id of an organisation, but only when the person names an organisation or asks for a team diagram: it is stored in that organisation's private library and the answer has a viewUrl for members in place of a public link, so there is no Markdown image. Never guess an organisation, and if it is not found, ask the person which one they mean. An owner may restrict a folder, and a reader may not publish: when the answer says the folder is restricted or the role does not allow it, ask the person which folder they may use instead of trying others or publishing elsewhere. Call list_diagrams when the person asks what they have published or to get a diagram id; it changes nothing. Call delete_diagram only after the person has said which diagram to delete, by name, and tell them what you deleted; never delete on a guess, in bulk, or to make room for a publish unless they asked, and a locked diagram cannot be deleted until the owner unlocks it.";
198229
+ HOSTED_INSTRUCTIONS = "When the person asks to share a finished diagram or wants a link to it, call publish_diagram with the valid source: it returns a public link and a Markdown image to paste, and publishing the same diagram again returns the same link. Publish only when asked, because anyone with the link can see the picture. After you edit a published diagram, call publish_diagram again: an edited diagram is a new picture with a new link, so replace the old link wherever it is used. Set embedSource true on publish_diagram when someone may want to edit the diagram later, and tell the person that the source is then part of the public picture. A drawing too big to return in an answer is also the case for publish_diagram: it gives a link in place of the picture. To keep a diagram inside a team instead, pass organization with the slug or id of an organisation, but only when the person names an organisation or asks for a team diagram: it is stored in that organisation's private library and the answer has a viewUrl for members in place of a public link, so there is no Markdown image. Never guess an organisation, and if it is not found, ask the person which one they mean. An organisation can also send its members' diagrams to its library when organization is left out: the answer then names it and says why, and the person must be told the diagram is in that library, not at a public link. Pass personal true only when the person asks for a public link anyway; an organisation that requires its library refuses it, and then tell the person. An owner may restrict a folder, and a reader may not publish: when the answer says the folder is restricted or the role does not allow it, ask the person which folder they may use instead of trying others or publishing elsewhere. Call list_diagrams when the person asks what they have published or to get a diagram id; it changes nothing. Call delete_diagram only after the person has said which diagram to delete, by name, and tell them what you deleted; never delete on a guess, in bulk, or to make room for a publish unless they asked, and a locked diagram cannot be deleted until the owner unlocks it.";
197366
198230
  }
197367
198231
  });
197368
198232
 
@@ -197633,8 +198497,9 @@ async function callTool(tool, args, log, caller, activity, run3, budget2, answer
197633
198497
  const inputBytes = inputSize(args);
197634
198498
  try {
197635
198499
  const ran = await run3(tool, args);
197636
- const linked = ran.ok ? await attachViewUrl(tool.name, args, ran.value, answers2.viewBase) : null;
197637
- const fitted = linked === null ? null : fitAnswer(linked, args, budget2);
198500
+ const linked = !ran.ok ? null : answers2.viewLinks === false ? stripViewLinks(ran.value) : await attachViewUrl(tool.name, args, ran.value, answers2.viewBase);
198501
+ const saving = linked === null || answers2.library === void 0 || answers2.library === null ? linked : withSaveStep(tool.name, linked, answers2.library);
198502
+ const fitted = saving === null ? null : fitAnswer(saving, args, budget2);
197638
198503
  const shown = fitted === null || answers2.open === void 0 ? fitted : await answers2.open(tool.name, fitted);
197639
198504
  const outcome = ran.ok ? { ok: true, value: shown } : ran;
197640
198505
  logToolCall({ tool: tool.name, outcome: outcome.ok ? "ok" : outcome.error.kind, durationMs: performance.now() - started, inputBytes, caller }, log);
@@ -197648,6 +198513,13 @@ async function callTool(tool, args, log, caller, activity, run3, budget2, answer
197648
198513
  return internalErrorResult();
197649
198514
  }
197650
198515
  }
198516
+ function withSaveStep(tool, value, library) {
198517
+ if (!SAVABLE_TOOLS.has(tool) || typeof value !== "object" || value === null) return value;
198518
+ const answer = value;
198519
+ if (answer["valid"] === false) return value;
198520
+ const next = typeof answer["next"] === "string" && answer["next"] !== "" ? `${answer["next"]} ` : "";
198521
+ return { ...answer, next: `${next}${librarySaveStep(library)}` };
198522
+ }
197651
198523
  async function callHostedTool(tool, args, log, caller) {
197652
198524
  const started = performance.now();
197653
198525
  const inputBytes = inputSize(args);
@@ -197682,7 +198554,8 @@ function createDiagramsServer(options3 = {}, log = logToConsole, caller, hostedT
197682
198554
  if (taken.has(tool.name)) throw new TypeError(`A tool named ${tool.name} is already registered`);
197683
198555
  taken.add(tool.name);
197684
198556
  }
197685
- const instructions = hostedTools.length === 0 ? SERVER_INSTRUCTIONS : `${SERVER_INSTRUCTIONS} ${HOSTED_INSTRUCTIONS}`;
198557
+ const hosted = hostedTools.length === 0 ? SERVER_INSTRUCTIONS : `${SERVER_INSTRUCTIONS} ${HOSTED_INSTRUCTIONS}`;
198558
+ const instructions = hostedTools.length > 0 && answers2.library !== void 0 && answers2.library !== null ? `${hosted} ${libraryInstructions(answers2.library)}` : hosted;
197686
198559
  const server = new McpServer(SERVER_INFO, { instructions, ...options3 });
197687
198560
  for (const tool of hostedTools) {
197688
198561
  server.registerTool(
@@ -197717,7 +198590,7 @@ function createDiagramsServer(options3 = {}, log = logToConsole, caller, hostedT
197717
198590
  registerDiagramPrompts(server, options3.jsonSchemaValidator);
197718
198591
  return server;
197719
198592
  }
197720
- var DEFAULT_VALIDATOR2, wrappers2;
198593
+ var SAVABLE_TOOLS, DEFAULT_VALIDATOR2, wrappers2;
197721
198594
  var init_create_server = __esm({
197722
198595
  "src/create-server.ts"() {
197723
198596
  "use strict";
@@ -197731,6 +198604,7 @@ var init_create_server = __esm({
197731
198604
  init_server_info();
197732
198605
  init_tool_result();
197733
198606
  init_viewer_app();
198607
+ SAVABLE_TOOLS = new Set(VIEW_LINK_TOOLS.filter((name2) => name2 !== "sync_markdown"));
197734
198608
  DEFAULT_VALIDATOR2 = {};
197735
198609
  wrappers2 = /* @__PURE__ */ new WeakMap();
197736
198610
  }