@buun_group/plotwork-mcp 0.1.0-beta.9 → 0.1.0

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
@@ -65,7 +65,7 @@ var init_icon_art_folder = __esm({
65
65
  var package_default;
66
66
  var init_package = __esm({
67
67
  "package.json"() {
68
- package_default = { version: "0.1.0-beta.9" };
68
+ package_default = { version: "0.1.0" };
69
69
  }
70
70
  });
71
71
 
@@ -722,12 +722,26 @@ var init_view_links = __esm({
722
722
  };
723
723
  CLI_RELEASE = {
724
724
  packageName: "@buun_group/plotwork",
725
- version: "0.1.0-beta.10",
725
+ version: "0.1.0-beta.13",
726
726
  onNpm: true
727
727
  };
728
728
  }
729
729
  });
730
730
 
731
+ // ../../packages/diagrams/src/constants/action-release.ts
732
+ var ACTION_REPOSITORY, ACTION_RELEASE, PINNED_ACTION_LINE;
733
+ var init_action_release = __esm({
734
+ "../../packages/diagrams/src/constants/action-release.ts"() {
735
+ "use strict";
736
+ ACTION_REPOSITORY = "plotwork-official/plotwork-action";
737
+ ACTION_RELEASE = {
738
+ version: "1.0.0-beta.14",
739
+ sha: "dcec4036897b73bd3ea724b3991f4fd0ac880757"
740
+ };
741
+ PINNED_ACTION_LINE = `uses: ${ACTION_REPOSITORY}@${ACTION_RELEASE.sha} # v${ACTION_RELEASE.version}`;
742
+ }
743
+ });
744
+
731
745
  // ../../packages/diagrams/src/constants/mcp-release.ts
732
746
  function mcpPackagePin(release = MCP_RELEASE) {
733
747
  return `${release.packageName}@${release.version}`;
@@ -741,7 +755,7 @@ var init_mcp_release = __esm({
741
755
  "use strict";
742
756
  MCP_RELEASE = {
743
757
  packageName: "@buun_group/plotwork-mcp",
744
- version: "0.1.0-beta.8"
758
+ version: "0.1.0-beta.10"
745
759
  };
746
760
  }
747
761
  });
@@ -3633,7 +3647,7 @@ var init_label_vocabulary = __esm({
3633
3647
  patches: { icon: "lucide:replace", role: null }
3634
3648
  };
3635
3649
  LABEL_VERB_PHRASES = {
3636
- reads: ["reads", "read", "reading", "reads from", "read from", "queries", "query", "querying", "looks up", "look up", "selects", "select from", "loads from", "fetches from"],
3650
+ reads: ["reads", "read", "reading", "reads from", "read from", "queries", "query", "querying", "looks up", "look up", "selects", "select from", "loads from", "fetches from", "read by", "queried by", "looked up by", "loaded from", "fetched from"],
3637
3651
  writes: [
3638
3652
  "writes",
3639
3653
  "write",
@@ -3657,10 +3671,22 @@ var init_label_vocabulary = __esm({
3657
3671
  "uploads",
3658
3672
  "upload",
3659
3673
  "uploads to",
3660
- "upload to"
3674
+ "upload to",
3675
+ "written to",
3676
+ "written by",
3677
+ "written into",
3678
+ "inserted into",
3679
+ "updated by",
3680
+ "saved to",
3681
+ "saved in",
3682
+ "persisted to",
3683
+ "persisted in",
3684
+ "deleted from",
3685
+ "uploaded to",
3686
+ "uploaded by"
3661
3687
  ],
3662
- stores: ["stores", "store", "stores in", "store in", "caches", "caches in", "reads and writes", "reads writes", "read write", "read and write"],
3663
- mounts: ["mounts", "mount"],
3688
+ stores: ["stores", "store", "stores in", "store in", "caches", "caches in", "reads and writes", "reads writes", "read write", "read and write", "stored in", "stored by", "cached in", "cached by"],
3689
+ mounts: ["mounts", "mount", "mounted by", "mounted at", "mounted in", "mounted on"],
3664
3690
  sends: [
3665
3691
  "sends",
3666
3692
  "send",
@@ -3679,15 +3705,27 @@ var init_label_vocabulary = __esm({
3679
3705
  "pushes to",
3680
3706
  "notifies",
3681
3707
  "notify",
3682
- "fires"
3708
+ "fires",
3709
+ "sent to",
3710
+ "sent by",
3711
+ "published to",
3712
+ "published by",
3713
+ "emitted to",
3714
+ "emitted by",
3715
+ "produced to",
3716
+ "enqueued to",
3717
+ "enqueued in",
3718
+ "enqueued on",
3719
+ "pushed to",
3720
+ "notified by"
3683
3721
  ],
3684
- receives: ["receives", "receive", "consumes", "consume", "consumes from", "subscribes", "subscribes to", "subscribe to", "listens to", "listens on", "polls", "dequeues"],
3685
- calls: ["calls", "call", "invokes", "invoke", "requests", "request", "fetches", "fetch", "queries api", "http", "https", "grpc", "rest", "graphql"],
3686
- routes: ["routes", "routes to", "route to", "forwards", "forwards to", "forward to", "proxies", "proxies to", "redirects to", "load balances"],
3687
- "depends-on": ["depends on", "depend on", "requires", "needs"],
3688
- provides: ["provides", "exposes", "serves"],
3689
- triggers: ["triggers", "trigger", "starts", "kicks off", "schedules", "wakes"],
3690
- deploys: ["deploys", "deploy", "deploys to", "deploy to", "releases to", "ships to", "promotes to", "rolls out", "rolls out to"],
3722
+ receives: ["receives", "receive", "consumes", "consume", "consumes from", "subscribes", "subscribes to", "subscribe to", "listens to", "listens on", "polls", "dequeues", "received by", "received from", "consumed by", "consumed from", "subscribed to", "polled by", "polled from", "dequeued by"],
3723
+ calls: ["calls", "call", "invokes", "invoke", "requests", "request", "fetches", "fetch", "queries api", "http", "https", "grpc", "rest", "graphql", "called by", "invoked by", "requested by", "requested from", "fetched by"],
3724
+ routes: ["routes", "routes to", "route to", "forwards", "forwards to", "forward to", "proxies", "proxies to", "redirects to", "load balances", "routed to", "routed by", "routed through", "forwarded to", "forwarded by", "proxied to", "proxied by", "proxied through", "redirected to", "load balanced by"],
3725
+ "depends-on": ["depends on", "depend on", "requires", "needs", "required by", "needed by", "depended on by"],
3726
+ provides: ["provides", "exposes", "serves", "provided by", "exposed by", "served by", "served from"],
3727
+ triggers: ["triggers", "trigger", "starts", "kicks off", "schedules", "wakes", "triggered by", "started by", "kicked off by", "scheduled by", "woken by"],
3728
+ deploys: ["deploys", "deploy", "deploys to", "deploy to", "releases to", "ships to", "promotes to", "rolls out", "rolls out to", "deployed to", "deployed by", "deployed on", "released to", "shipped to", "promoted to", "rolled out to", "rolled out by"],
3691
3729
  grants: [
3692
3730
  "authenticates",
3693
3731
  "authenticate",
@@ -3715,7 +3753,16 @@ var init_label_vocabulary = __esm({
3715
3753
  "logs out",
3716
3754
  "log out",
3717
3755
  "signs out",
3718
- "sign out"
3756
+ "sign out",
3757
+ "authenticated by",
3758
+ "authenticated with",
3759
+ "authenticated against",
3760
+ "authorized by",
3761
+ "authorised by",
3762
+ "granted by",
3763
+ "granted to",
3764
+ "assumed by",
3765
+ "issued by"
3719
3766
  ],
3720
3767
  secret: ["reads secret", "reads secrets", "read secret", "read secrets", "read credentials", "fetches secret", "fetches secrets", "reads credentials", "gets secret", "gets secrets"],
3721
3768
  reports: [
@@ -3738,9 +3785,12 @@ var init_label_vocabulary = __esm({
3738
3785
  "exports metrics",
3739
3786
  "exports traces",
3740
3787
  "emits metrics",
3741
- "emits logs"
3788
+ "emits logs",
3789
+ "reported to",
3790
+ "reported by",
3791
+ "logged to"
3742
3792
  ],
3743
- pulls: ["pulls image", "pulls images", "pulls images from", "pulls image from"]
3793
+ pulls: ["pulls image", "pulls images", "pulls images from", "pulls image from", "pulled from"]
3744
3794
  };
3745
3795
  LABEL_VERB_MAX_WORDS = 5;
3746
3796
  NOT_VERB_PHRASES = [
@@ -3830,6 +3880,7 @@ var init_constants = __esm({
3830
3880
  init_editing();
3831
3881
  init_diagram_links();
3832
3882
  init_view_links();
3883
+ init_action_release();
3833
3884
  init_mcp_release();
3834
3885
  init_layout_limits();
3835
3886
  init_lint_limits();
@@ -121600,6 +121651,10 @@ var init_metrics = __esm({
121600
121651
  blockBranchHeader: 30,
121601
121652
  blockBottomPadding: 10,
121602
121653
  blockRadius: 10,
121654
+ /** Room from the frame's left edge to its operator ("alt", "else"), and the least room after its condition to the right edge. */
121655
+ blockHeaderInset: 12,
121656
+ /** Room between the operator and its condition. */
121657
+ blockKeywordGap: 8,
121603
121658
  lifelineDash: "4 5",
121604
121659
  lifelineOvershoot: 22
121605
121660
  };
@@ -121737,7 +121792,7 @@ function bareGlyphColor(theme, tone) {
121737
121792
  function getTheme(name2) {
121738
121793
  return name2 === "dark" ? DARK_THEME : LIGHT_THEME;
121739
121794
  }
121740
- var THEME_NAMES, PICTURE_SCHEMES, GRAPHIC_CONTRAST, SCHEME_INPUTS, LIGHT_THEME, DARK_THEME, BARE_GLYPH_CONTRAST;
121795
+ var THEME_NAMES, PICTURE_SCHEMES, PICTURE_FILE_SCHEMES, GRAPHIC_CONTRAST, SCHEME_INPUTS, LIGHT_THEME, DARK_THEME, BARE_GLYPH_CONTRAST;
121741
121796
  var init_themes = __esm({
121742
121797
  "../../packages/diagrams/src/theme/themes.ts"() {
121743
121798
  "use strict";
@@ -121746,6 +121801,7 @@ var init_themes = __esm({
121746
121801
  init_palette();
121747
121802
  THEME_NAMES = ["light", "dark"];
121748
121803
  PICTURE_SCHEMES = [...THEME_NAMES, "auto"];
121804
+ PICTURE_FILE_SCHEMES = ["light-and-dark", "auto"];
121749
121805
  GRAPHIC_CONTRAST = 3;
121750
121806
  SCHEME_INPUTS = {
121751
121807
  light: { name: "light", surfaces: LIGHT_SURFACES, tones: LIGHT_TONES, tint: 0.12, pushToward: "#000000" },
@@ -121771,7 +121827,7 @@ function hueDistance(a, b) {
121771
121827
  }
121772
121828
  function fitToScheme(color, scheme) {
121773
121829
  const input2 = SCHEME_INPUTS[scheme];
121774
- return ensureContrast(color, input2.surfaces.surface, GRAPHIC_CONTRAST2, input2.pushToward);
121830
+ return ensureContrast(color, input2.surfaces.surface, GRAPHIC_CONTRAST, input2.pushToward);
121775
121831
  }
121776
121832
  function checkBrand(input2) {
121777
121833
  const issues = [];
@@ -121836,7 +121892,7 @@ function brandTheme(scheme, brand) {
121836
121892
  const input2 = SCHEME_INPUTS[scheme];
121837
121893
  const wash = NEUTRAL_WASH[scheme];
121838
121894
  const surfaces = input2.surfaces;
121839
- const edge = ensureContrast(mix(brand.primary, surfaces.edge, wash.edge), surfaces.surface, GRAPHIC_CONTRAST2, input2.pushToward);
121895
+ const edge = ensureContrast(mix(brand.primary, surfaces.edge, wash.edge), surfaces.surface, GRAPHIC_CONTRAST, input2.pushToward);
121840
121896
  return buildTheme({
121841
121897
  ...input2,
121842
121898
  tones: brandTones(scheme, brand),
@@ -121860,7 +121916,7 @@ function themeFor(scheme, brand) {
121860
121916
  CACHE.set(key, theme);
121861
121917
  return theme;
121862
121918
  }
121863
- var BRAND_ROLES, HUE_STEP, TONE_OF_ROLE, STATUS_HUES, STATUS_HUE_DISTANCE, STATUS_SATURATION, DISTINCT_CONTRAST, GRAPHIC_CONTRAST2, NEUTRAL_WASH, CACHE, CACHE_LIMIT;
121919
+ var BRAND_ROLES, HUE_STEP, TONE_OF_ROLE, STATUS_HUES, STATUS_HUE_DISTANCE, STATUS_SATURATION, DISTINCT_CONTRAST, NEUTRAL_WASH, CACHE, CACHE_LIMIT;
121864
121920
  var init_brand = __esm({
121865
121921
  "../../packages/diagrams/src/theme/brand.ts"() {
121866
121922
  "use strict";
@@ -121876,7 +121932,6 @@ var init_brand = __esm({
121876
121932
  STATUS_HUE_DISTANCE = 16;
121877
121933
  STATUS_SATURATION = 0.45;
121878
121934
  DISTINCT_CONTRAST = 1.15;
121879
- GRAPHIC_CONTRAST2 = 3;
121880
121935
  NEUTRAL_WASH = {
121881
121936
  light: { group: 0.035, border: 0.1, edge: 0.3 },
121882
121937
  dark: { group: 0.05, border: 0.12, edge: 0.3 }
@@ -123115,9 +123170,9 @@ function sceneOf(shapes2, input2) {
123115
123170
  const source = diagram.edges[Number(route.id.slice(1))];
123116
123171
  return source === void 0 ? [] : [{ id: route.id, from: source.from, to: source.to, points: route.points, label: route.label?.rect ?? null }];
123117
123172
  });
123118
- const bounds = boundsOf([...shapes2.nodes.map((node3) => node3.rect), ...shapes2.groups.map((group2) => group2.rect), ...shapes2.overlays.map((overlay) => overlay.rect)]) ?? { x: 0, y: 0, width: 0, height: 0 };
123173
+ const bounds2 = boundsOf([...shapes2.nodes.map((node3) => node3.rect), ...shapes2.groups.map((group2) => group2.rect), ...shapes2.overlays.map((overlay) => overlay.rect)]) ?? { x: 0, y: 0, width: 0, height: 0 };
123119
123174
  const finish = (points, label, boxes2) => giveEndRoom(points, EDGE_METRICS.endRun, boxes2, label === null ? null : centerOf(label));
123120
- const scene = { isVertical: direction === "down" || direction === "up", alongSign: ALONG_SIGN[direction], nodes, frames, edges, bounds, finish };
123175
+ const scene = { isVertical: direction === "down" || direction === "up", alongSign: ALONG_SIGN[direction], nodes, frames, edges, bounds: bounds2, finish };
123121
123176
  return scene;
123122
123177
  }
123123
123178
  function balanceFlow(shapes2, input2) {
@@ -124820,12 +124875,15 @@ function declareId(cursor, ctx, kind, line3) {
124820
124875
  ctx.declared.set(token.text, { kind, line: line3 });
124821
124876
  return token;
124822
124877
  }
124823
- function readLabel(cursor, ctx, line3, what) {
124824
- const token = cursor.next();
124825
- if (token?.kind === "string") return token.text;
124826
- ctx.report.push(
124827
- errorAt(DIAGNOSTIC_CODES.syntax, `Expected a quoted ${what}`, token ?? cursor.endPosition(line3), 'Labels are always in double quotes, for example "Auth server".')
124828
- );
124878
+ function readLabel(cursor, ctx, line3, what, form) {
124879
+ const token = cursor.peek();
124880
+ if (token?.kind === "string") {
124881
+ cursor.next();
124882
+ return token.text;
124883
+ }
124884
+ if (!(token?.kind === "word" && cursor.peek(1)?.kind === "equals") && !(token?.kind === "lbrace")) cursor.next();
124885
+ const hint2 = `Labels are always in double quotes, for example "Auth server".${form === void 0 ? "" : ` The statement is: ${form}`}`;
124886
+ ctx.report.push(errorAt(DIAGNOSTIC_CODES.syntax, `Expected a quoted ${what}`, token ?? cursor.endPosition(line3), hint2));
124829
124887
  return null;
124830
124888
  }
124831
124889
  function resolveTone(option, fallback, ctx) {
@@ -129029,30 +129087,29 @@ function paintNote(note, theme) {
129029
129087
  ]);
129030
129088
  }
129031
129089
  function paintHeader2(keyword, label, x, bandTop, bandHeight, theme) {
129032
- const chipWidth2 = measureRole(keyword, "groupLabel") + CHIP_PADDING * 2;
129033
- const chipY = bandTop + (bandHeight - CHIP_HEIGHT) / 2;
129034
- const textTop4 = chipY + (CHIP_HEIGHT - TYPE_ROLES.groupLabel.lineHeight) / 2;
129035
- return [
129036
- el("rect", { x, y: chipY, width: chipWidth2, height: CHIP_HEIGHT, rx: CHIP_RADIUS, fill: theme.surfaceGroup, stroke: theme.borderGroup, "stroke-width": 1 }),
129037
- paintTextBlock({ x: x + CHIP_PADDING, top: textTop4, lines: [keyword], role: "groupLabel", color: theme.ink }),
129038
- paintTextBlock({ x: x + chipWidth2 + HEADER_TEXT_GAP, top: textTop4, lines: [label], role: "edgeLabel", color: theme.inkSecondary })
129039
- ];
129090
+ const textTop4 = bandTop + (bandHeight - TYPE_ROLES.groupLabel.lineHeight) / 2;
129091
+ const parts = [paintTextBlock({ x, top: textTop4, lines: [keyword], role: "groupLabel", color: theme.inkSecondary })];
129092
+ if (label !== "") {
129093
+ const labelX = x + measureRole(keyword, "groupLabel") + SEQUENCE_METRICS.blockKeywordGap;
129094
+ parts.push(paintTextBlock({ x: labelX, top: textTop4, lines: [label], role: "edgeLabel", color: theme.inkSecondary }));
129095
+ }
129096
+ return parts;
129040
129097
  }
129041
129098
  function paintBlock(block, theme) {
129042
129099
  const { x, y, width, height } = block.rect;
129043
129100
  const parts = [
129044
129101
  el("rect", { x, y, width, height, rx: SEQUENCE_METRICS.blockRadius, fill: "none", stroke: theme.borderGroup, "stroke-width": 1 }),
129045
- ...paintHeader2(block.blockType, block.label, x + HEADER_LEFT, y, SEQUENCE_METRICS.blockHeader, theme)
129102
+ ...paintHeader2(block.blockType, block.label, x + SEQUENCE_METRICS.blockHeaderInset, y, SEQUENCE_METRICS.blockHeader, theme)
129046
129103
  ];
129047
129104
  for (const divider of block.dividers) {
129048
129105
  parts.push(
129049
129106
  el("line", { x1: x, y1: divider.y, x2: x + width, y2: divider.y, stroke: theme.borderGroup, "stroke-width": 1, "stroke-dasharray": "5 4" }),
129050
- ...paintHeader2(divider.keyword, divider.label, x + HEADER_LEFT, divider.y, SEQUENCE_METRICS.blockBranchHeader, theme)
129107
+ ...paintHeader2(divider.keyword, divider.label, x + SEQUENCE_METRICS.blockHeaderInset, divider.y, SEQUENCE_METRICS.blockBranchHeader, theme)
129051
129108
  );
129052
129109
  }
129053
129110
  return el("g", { "data-block": block.blockType }, parts);
129054
129111
  }
129055
- var NOTE_FILL_TINT, NOTE_BORDER_TINT, CHIP_HEIGHT, CHIP_PADDING, CHIP_RADIUS, HEADER_TEXT_GAP, HEADER_LEFT;
129112
+ var NOTE_FILL_TINT, NOTE_BORDER_TINT;
129056
129113
  var init_paint_parts = __esm({
129057
129114
  "../../packages/diagrams/src/render/sequence/paint-parts.ts"() {
129058
129115
  "use strict";
@@ -129061,11 +129118,6 @@ var init_paint_parts = __esm({
129061
129118
  init_svg2();
129062
129119
  NOTE_FILL_TINT = 0.12;
129063
129120
  NOTE_BORDER_TINT = 0.5;
129064
- CHIP_HEIGHT = 20;
129065
- CHIP_PADDING = 8;
129066
- CHIP_RADIUS = 6;
129067
- HEADER_TEXT_GAP = 10;
129068
- HEADER_LEFT = 12;
129069
129121
  }
129070
129122
  });
129071
129123
 
@@ -130370,7 +130422,7 @@ function parseNodeStatement(cursor, state, line3, group2) {
130370
130422
  state.report.push(errorAt(DIAGNOSTIC_CODES.unknownNodeType, `Unknown node type "${typeToken.text}"`, typeToken, didYouMean(typeToken.text, FLOW_NODE_TYPES)));
130371
130423
  }
130372
130424
  const labelToken = cursor.peek();
130373
- const label = readLabel(cursor, state, line3, "label");
130425
+ const label = readLabel(cursor, state, line3, "label", 'node <id> <type> "Label" icon=<set:name>.');
130374
130426
  const options3 = readOptions(cursor, NODE_OPTIONS, state.report, { lists: ["stack"] });
130375
130427
  rejectTrailing(cursor, state, 'A node is: node id type "Label" sub="..." icon=lucide:name tone=blue stack=simple:angular,simple:typescript change=update');
130376
130428
  if (id === null || type === void 0 || label === null) return;
@@ -130411,7 +130463,7 @@ function parseGroupStatement(cursor, state, line3, parent) {
130411
130463
  cursor.next();
130412
130464
  const id = declareId(cursor, state, "group", line3);
130413
130465
  const labelToken = cursor.peek();
130414
- const label = readLabel(cursor, state, line3, "label");
130466
+ const label = readLabel(cursor, state, line3, "label", 'group <id> "Label" type=<group type> {, then its nodes, then } on its own line.');
130415
130467
  const options3 = readOptions(cursor, GROUP_OPTIONS, state.report, { lists: ["stack"], moved: MOVED_GROUP_OPTIONS });
130416
130468
  const brace = cursor.next();
130417
130469
  if (brace?.kind !== "lbrace") {
@@ -130605,7 +130657,7 @@ function dispatchStatement(line3, state, scopes) {
130605
130657
  DIAGNOSTIC_CODES.unknownStatement,
130606
130658
  `Unknown statement "${first.text}"`,
130607
130659
  first,
130608
- `${didYouMean(first.text, STATEMENT_KEYWORDS2)} Edges look like: from -> to : "label"`
130660
+ first.text === "flow" ? 'The header is one line, the first: put the title and every header option on it together, such as flow "Checkout" direction=right.' : first.text === "title" ? `There is no title statement: the title is the quoted text after the kind on the first line, such as flow "Checkout".` : line3.tokens[1]?.kind === "equals" ? `An option such as ${first.text}= goes at the end of the line of the node or edge it sets, not on a line of its own: node cdn service "CloudFront" ${first.text}=...` : FLOW_NODE_TYPES.includes(first.text) ? `A box is declared with node and its type comes after the id: node <id> ${first.text} "Label". Edges look like: from -> to : "label"` : `${didYouMean(first.text, STATEMENT_KEYWORDS2)} Edges look like: from -> to : "label"`
130609
130661
  )
130610
130662
  );
130611
130663
  } else {
@@ -138746,19 +138798,19 @@ function separatePorts(plans) {
138746
138798
  if (!moved3) return;
138747
138799
  }
138748
138800
  }
138749
- function placeRuns(plan, bounds) {
138801
+ function placeRuns(plan, bounds2) {
138750
138802
  const runs = runsOf3(plan);
138751
138803
  const length = (run3) => run3 === void 0 ? 0 : Math.abs(run3.a - run3.b);
138752
138804
  plan.labelLeg = length(runs[0]) > length(runs[1]) ? 0 : runs.length - 1;
138753
138805
  const labelRun = runs[plan.labelLeg];
138754
138806
  const half = (plan.label?.width ?? 0) / 2;
138755
- plan.labelCenter = clamp4((labelRun.a + labelRun.b) / 2, bounds.left + half + 8, bounds.right - half - 8);
138807
+ plan.labelCenter = clamp4((labelRun.a + labelRun.b) / 2, bounds2.left + half + 8, bounds2.right - half - 8);
138756
138808
  plan.legs = runs.map((run3, position) => {
138757
138809
  const reach2 = position === plan.labelLeg && plan.label !== null ? [plan.labelCenter - half - 6, plan.labelCenter + half + 6] : [];
138758
138810
  return { band: run3.band, use: useBand(run3.band, Math.min(run3.a, run3.b, ...reach2), Math.max(run3.a, run3.b, ...reach2), run3.ups.map((tip) => tip.x), run3.downs.map((tip) => tip.x)) };
138759
138811
  });
138760
138812
  }
138761
- function planLinks(links, where, bounds) {
138813
+ function planLinks(links, where, bounds2) {
138762
138814
  let lanes = 0;
138763
138815
  const plans = [];
138764
138816
  links.forEach((link2, index2) => {
@@ -138767,7 +138819,7 @@ function planLinks(links, where, bounds) {
138767
138819
  if (from === void 0 || to === void 0) return;
138768
138820
  const kind = from.row === to.row ? "under" : Math.abs(from.row - to.row) === 1 ? "step" : "lane";
138769
138821
  const down = to.row > from.row;
138770
- const laneX = kind === "lane" ? bounds.right + (LAYERS_METRICS.laneOffsets[lanes++ % LAYERS_METRICS.laneOffsets.length] ?? 0) : null;
138822
+ const laneX = kind === "lane" ? bounds2.right + (LAYERS_METRICS.laneOffsets[lanes++ % LAYERS_METRICS.laneOffsets.length] ?? 0) : null;
138771
138823
  const one = link2.label?.replace(/\s+/g, " ").trim();
138772
138824
  const fitted = one === void 0 ? null : fitLine(one.slice(0, 400), "edgeLabel", LAYERS_METRICS.maxLabelText);
138773
138825
  const label = one === void 0 || fitted === null ? null : { text: fitted, width: Math.ceil(measureRole(fitted, "edgeLabel")) + 2 * EDGE_METRICS.labelPaddingX, isShortened: fitted !== one };
@@ -138775,7 +138827,7 @@ function planLinks(links, where, bounds) {
138775
138827
  });
138776
138828
  placePorts(plans);
138777
138829
  separatePorts(plans);
138778
- for (const plan of plans) placeRuns(plan, bounds);
138830
+ for (const plan of plans) placeRuns(plan, bounds2);
138779
138831
  return plans;
138780
138832
  }
138781
138833
  function pointsOf(plan) {
@@ -143749,17 +143801,17 @@ var init_paint_hole = __esm({
143749
143801
  // ../../packages/diagrams/src/kinds/pie/look.ts
143750
143802
  function sliceLook(theme, tone) {
143751
143803
  const outline2 = theme.tones[tone].outline;
143752
- const segment = tone === "neutral" ? ensureContrast(mix(outline2, theme.surface, NEUTRAL_SHARE), theme.surface, GRAPHIC_CONTRAST3, theme.ink) : outline2;
143804
+ const segment = tone === "neutral" ? ensureContrast(mix(outline2, theme.surface, NEUTRAL_SHARE), theme.surface, GRAPHIC_CONTRAST2, theme.ink) : outline2;
143753
143805
  return { segment, leader: mix(segment, theme.surface, LEADER_SHARE), icon: bareGlyphColor(theme, tone) };
143754
143806
  }
143755
- var LEADER_SHARE, NEUTRAL_SHARE, GRAPHIC_CONTRAST3;
143807
+ var LEADER_SHARE, NEUTRAL_SHARE, GRAPHIC_CONTRAST2;
143756
143808
  var init_look4 = __esm({
143757
143809
  "../../packages/diagrams/src/kinds/pie/look.ts"() {
143758
143810
  "use strict";
143759
143811
  init_theme();
143760
143812
  LEADER_SHARE = 0.92;
143761
143813
  NEUTRAL_SHARE = 0.62;
143762
- GRAPHIC_CONTRAST3 = 3;
143814
+ GRAPHIC_CONTRAST2 = 3;
143763
143815
  }
143764
143816
  });
143765
143817
 
@@ -148060,8 +148112,26 @@ function labelGap(message2) {
148060
148112
  y2: Math.max(message2.labelY, badge === void 0 ? Number.NEGATIVE_INFINITY : badge.y + badge.height) + LABEL_CLEARANCE2
148061
148113
  };
148062
148114
  }
148063
- function buildLifelines(actors, messages, top, bottom) {
148064
- const gaps = messages.map(labelGap);
148115
+ function headerGap(x, bandTop, bandHeight, keyword, label) {
148116
+ const left = x + SEQUENCE_METRICS.blockHeaderInset;
148117
+ const condition = label === "" ? 0 : SEQUENCE_METRICS.blockKeywordGap + measureRole(label, "edgeLabel");
148118
+ const top = bandTop + (bandHeight - TYPE_ROLES.groupLabel.lineHeight) / 2;
148119
+ return {
148120
+ x1: left - LABEL_CLEARANCE2,
148121
+ x2: left + measureRole(keyword, "groupLabel") + condition + LABEL_CLEARANCE2,
148122
+ y1: top - LABEL_CLEARANCE2 / 2,
148123
+ y2: top + TYPE_ROLES.groupLabel.lineHeight + LABEL_CLEARANCE2 / 2
148124
+ };
148125
+ }
148126
+ function blockGaps(block) {
148127
+ const { x, y } = block.rect;
148128
+ return [
148129
+ headerGap(x, y, SEQUENCE_METRICS.blockHeader, block.blockType, block.label),
148130
+ ...block.dividers.map((divider) => headerGap(x, divider.y, SEQUENCE_METRICS.blockBranchHeader, divider.keyword, divider.label))
148131
+ ];
148132
+ }
148133
+ function buildLifelines(actors, messages, blocks2, top, bottom) {
148134
+ const gaps = [...messages.map(labelGap), ...blocks2.flatMap(blockGaps)];
148065
148135
  return actors.map((actor) => {
148066
148136
  const crossing = gaps.filter((gap2) => gap2.x1 < actor.centerX && actor.centerX < gap2.x2).sort((a, b) => a.y1 - b.y1);
148067
148137
  const segments = [];
@@ -148154,6 +148224,10 @@ function placeNote(item, ctx, y) {
148154
148224
  ctx.notes.push({ rect: { x, y, width, height }, lines });
148155
148225
  return { y: y + height + SEQUENCE_METRICS.noteGap, extent: { minX: x, maxX: x + width } };
148156
148226
  }
148227
+ function blockHeaderWidth(keyword, label) {
148228
+ const condition = label === "" ? 0 : SEQUENCE_METRICS.blockKeywordGap + measureRole(label, "edgeLabel");
148229
+ return SEQUENCE_METRICS.blockHeaderInset * 2 + measureRole(keyword, "groupLabel") + condition;
148230
+ }
148157
148231
  function placeBlock2(item, ctx, y) {
148158
148232
  const first = item.branches[0];
148159
148233
  const dividers = [];
@@ -148171,9 +148245,9 @@ function placeBlock2(item, ctx, y) {
148171
148245
  cursor += SEQUENCE_METRICS.blockBottomPadding;
148172
148246
  const reach2 = extent2 ?? { minX: ctx.centers[0] ?? 0, maxX: ctx.centers[ctx.centers.length - 1] ?? 0 };
148173
148247
  const label = first?.label ?? "";
148174
- const tabWidth2 = measureRole(`${item.blockType} ${label}`, "groupLabel") + TAB_PADDING;
148248
+ const headerWidth = Math.max(blockHeaderWidth(item.blockType, label), ...dividers.map((divider) => blockHeaderWidth(divider.keyword, divider.label)));
148175
148249
  const x = reach2.minX - SEQUENCE_METRICS.blockPadding;
148176
- const width = Math.max(reach2.maxX - reach2.minX + SEQUENCE_METRICS.blockPadding * 2, tabWidth2);
148250
+ const width = Math.max(reach2.maxX - reach2.minX + SEQUENCE_METRICS.blockPadding * 2, headerWidth);
148177
148251
  ctx.blocks.push({ blockType: item.blockType, rect: { x, y, width, height: cursor - y }, label, dividers });
148178
148252
  return { y: cursor + SEQUENCE_METRICS.noteGap, extent: { minX: x, maxX: x + width } };
148179
148253
  }
@@ -148187,7 +148261,7 @@ function placeItems3(items2, ctx, startY) {
148187
148261
  }
148188
148262
  return { y, extent: extent2 };
148189
148263
  }
148190
- var HOP_LABEL_MARGIN, NOTE_OVERHANG, TAB_PADDING, leadOf2;
148264
+ var HOP_LABEL_MARGIN, NOTE_OVERHANG, leadOf2;
148191
148265
  var init_rows2 = __esm({
148192
148266
  "../../packages/diagrams/src/layout/sequence/rows.ts"() {
148193
148267
  "use strict";
@@ -148197,7 +148271,6 @@ var init_rows2 = __esm({
148197
148271
  init_columns();
148198
148272
  HOP_LABEL_MARGIN = 4;
148199
148273
  NOTE_OVERHANG = 16;
148200
- TAB_PADDING = 28;
148201
148274
  leadOf2 = (step) => stepBadgeWidth(step) + STEP_METRICS.labelGap;
148202
148275
  }
148203
148276
  });
@@ -148237,7 +148310,7 @@ function layoutSequence(diagram) {
148237
148310
  return {
148238
148311
  size: { width: Math.ceil(right + CANVAS_METRICS.padding), height: Math.ceil(lifelineBottom + CANVAS_METRICS.padding) },
148239
148312
  actors,
148240
- lifelines: buildLifelines(actors, messages, lifelineTop, lifelineBottom),
148313
+ lifelines: buildLifelines(actors, messages, blocks2, lifelineTop, lifelineBottom),
148241
148314
  blocks: blocks2,
148242
148315
  notes,
148243
148316
  messages
@@ -148357,7 +148430,7 @@ function parseActorStatement2(cursor, state, line3) {
148357
148430
  if (type === void 0) {
148358
148431
  state.report.push(errorAt(DIAGNOSTIC_CODES.unknownNodeType, `Unknown actor type "${typeToken.text}"`, typeToken, didYouMean(typeToken.text, ACTOR_TYPES)));
148359
148432
  }
148360
- const label = readLabel(cursor, state, line3, "label");
148433
+ const label = readLabel(cursor, state, line3, "label", 'actor <id> <type> "Label", such as actor db database "Users DB".');
148361
148434
  const options3 = readOptions(cursor, ACTOR_OPTIONS, state.report);
148362
148435
  rejectTrailing(cursor, state, 'An actor is: actor id type "Label" sub="..." icon=lucide:name tone=blue');
148363
148436
  if (id === null || type === void 0 || label === null) return;
@@ -148499,7 +148572,7 @@ function dispatchStatement4(line3, state) {
148499
148572
  DIAGNOSTIC_CODES.unknownStatement,
148500
148573
  `Unknown statement "${first.text}"`,
148501
148574
  first,
148502
- `${didYouMean(first.text, STATEMENT_KEYWORDS5)} Messages look like: from -> to : "label"`
148575
+ first.text === "sequence" ? 'The header is one line, the first: put the title and every header option on it together, such as sequence "Checkout" direction=right.' : first.text === "title" ? `There is no title statement: the title is the quoted text after the kind on the first line, such as sequence "Checkout".` : line3.tokens[1]?.kind === "equals" ? `An option such as ${first.text}= goes at the end of the line of the actor or message it sets, not on a line of its own: actor api service "API" ${first.text}=...` : FLOW_NODE_TYPES.includes(first.text) ? `A participant is declared with actor and its type comes after the id: actor <id> ${first.text} "Label". Messages look like: from -> to : "label"` : `${didYouMean(first.text, STATEMENT_KEYWORDS5)} Messages look like: from -> to : "label"`
148503
148576
  )
148504
148577
  );
148505
148578
  }
@@ -154783,12 +154856,12 @@ function place({ diagram, flat: flat3, cards, hang: hang2 }) {
154783
154856
  top += sized.height + TREE_METRICS.hangGap;
154784
154857
  }
154785
154858
  }
154786
- const bounds = rects.reduce((box, rect) => ({ left: Math.min(box.left, rect.x), top: Math.min(box.top, rect.y), right: Math.max(box.right, rect.x + rect.width), bottom: Math.max(box.bottom, rect.y + rect.height) }), { left: Number.POSITIVE_INFINITY, top: Number.POSITIVE_INFINITY, right: Number.NEGATIVE_INFINITY, bottom: Number.NEGATIVE_INFINITY });
154787
- const shift2 = { x: TREE_METRICS.canvasPadding - bounds.left, y: TREE_METRICS.canvasPadding - bounds.top };
154859
+ const bounds2 = rects.reduce((box, rect) => ({ left: Math.min(box.left, rect.x), top: Math.min(box.top, rect.y), right: Math.max(box.right, rect.x + rect.width), bottom: Math.max(box.bottom, rect.y + rect.height) }), { left: Number.POSITIVE_INFINITY, top: Number.POSITIVE_INFINITY, right: Number.NEGATIVE_INFINITY, bottom: Number.NEGATIVE_INFINITY });
154860
+ const shift2 = { x: TREE_METRICS.canvasPadding - bounds2.left, y: TREE_METRICS.canvasPadding - bounds2.top };
154788
154861
  const moved3 = rects.map((rect) => ({ x: rect.x + shift2.x, y: rect.y + shift2.y, width: rect.width, height: rect.height }));
154789
154862
  return {
154790
154863
  kind: "org",
154791
- size: { width: Math.ceil(bounds.right - bounds.left + 2 * TREE_METRICS.canvasPadding), height: Math.ceil(bounds.bottom - bounds.top + 2 * TREE_METRICS.canvasPadding) },
154864
+ size: { width: Math.ceil(bounds2.right - bounds2.left + 2 * TREE_METRICS.canvasPadding), height: Math.ceil(bounds2.bottom - bounds2.top + 2 * TREE_METRICS.canvasPadding) },
154792
154865
  cards: flat3.map((entry2) => cardOf(entry2, size(entry2.index), moved3[entry2.index], isHung[entry2.index] === true)),
154793
154866
  links: flat3.flatMap((entry2) => linksOf2(entry2, moved3, isDown, isHanging, isHung)),
154794
154867
  facts: { cut: flat3.flatMap((entry2) => size(entry2.index).name.isCut || size(entry2.index).note?.isCut === true ? [`"${entry2.path}"`] : []), rows: flat3.length }
@@ -157440,7 +157513,7 @@ function valueAxisTitle(title, unit3) {
157440
157513
  if (!isWordUnit(unit3)) return title === null ? null : oneLine9(title);
157441
157514
  return title === null ? unit3 : `${oneLine9(title)} (${unit3})`;
157442
157515
  }
157443
- function fitPlaces(labels2, slot, centerOf3, bounds) {
157516
+ function fitPlaces(labels2, slot, centerOf3, bounds2) {
157444
157517
  const longest = Math.max(0, ...labels2.flatMap((label) => label.split(" ").map((word2) => measureRole(word2, "sub"))));
157445
157518
  let step = 1;
157446
157519
  while (step < labels2.length && step * slot - XYCHART_METRICS.pill.gap < longest) step += 1;
@@ -157448,7 +157521,7 @@ function fitPlaces(labels2, slot, centerOf3, bounds) {
157448
157521
  const room = Math.max(8, step * slot - XYCHART_METRICS.pill.gap);
157449
157522
  const fitted = labels2.map((label) => fitText(label, "sub", room, room, 2));
157450
157523
  const half = fitted.map((entry2) => Math.max(...entry2.lines.map((line3) => measureRole(line3, "sub"))) / 2);
157451
- const x = fitted.map((_, index2) => Math.min(Math.max(centerOf3(index2), bounds.left + (half[index2] ?? 0)), Math.max(bounds.left + (half[index2] ?? 0), bounds.right - (half[index2] ?? 0))));
157524
+ const x = fitted.map((_, index2) => Math.min(Math.max(centerOf3(index2), bounds2.left + (half[index2] ?? 0)), Math.max(bounds2.left + (half[index2] ?? 0), bounds2.right - (half[index2] ?? 0))));
157452
157525
  const shown = fitted.flatMap((_, index2) => index2 % step === 0 ? [index2] : []);
157453
157526
  const isApart = shown.every((index2, at3) => {
157454
157527
  const before = shown[at3 - 1];
@@ -158526,16 +158599,16 @@ var init_parse19 = __esm({
158526
158599
 
158527
158600
  // ../../packages/diagrams/src/kinds/xychart/look.ts
158528
158601
  function seriesLook(theme, tone) {
158529
- const outline2 = ensureContrast(theme.tones[tone].outline, theme.surfaceGroup, GRAPHIC_CONTRAST4, theme.ink);
158530
- const mark = tone === "neutral" ? ensureContrast(mix(outline2, theme.surfaceGroup, 0.62), theme.surfaceGroup, GRAPHIC_CONTRAST4, theme.ink) : outline2;
158602
+ const outline2 = ensureContrast(theme.tones[tone].outline, theme.surfaceGroup, GRAPHIC_CONTRAST3, theme.ink);
158603
+ const mark = tone === "neutral" ? ensureContrast(mix(outline2, theme.surfaceGroup, 0.62), theme.surfaceGroup, GRAPHIC_CONTRAST3, theme.ink) : outline2;
158531
158604
  return { mark, rim: mix(mark, theme.ink, 0.86), leader: mix(mark, theme.surfaceGroup, 0.55), washOpacity: 0.16 };
158532
158605
  }
158533
- var GRAPHIC_CONTRAST4, chartLook;
158606
+ var GRAPHIC_CONTRAST3, chartLook;
158534
158607
  var init_look9 = __esm({
158535
158608
  "../../packages/diagrams/src/kinds/xychart/look.ts"() {
158536
158609
  "use strict";
158537
158610
  init_theme();
158538
- GRAPHIC_CONTRAST4 = 3;
158611
+ GRAPHIC_CONTRAST3 = 3;
158539
158612
  chartLook = (theme) => ({
158540
158613
  plate: theme.surfaceGroup,
158541
158614
  grid: mix(theme.border, theme.surfaceGroup, 0.55),
@@ -159297,19 +159370,19 @@ function lexLine(text3, line3, diagnostics) {
159297
159370
  tokens.push({ kind: "word", text: word2, line: line3, column, length: word2.length });
159298
159371
  index2 += word2.length;
159299
159372
  } else {
159300
- diagnostics.push(
159301
- errorAt(
159302
- DIAGNOSTIC_CODES.syntax,
159303
- `Unexpected character "${char}"`,
159304
- { line: line3, column, length: 1 },
159305
- 'Labels go in double quotes; ids use letters, digits, "_" and "-".'
159306
- )
159307
- );
159373
+ diagnostics.push(errorAt(DIAGNOSTIC_CODES.syntax, `Unexpected character "${char}"`, { line: line3, column, length: 1 }, unexpectedCharacterHint(char, tokens[tokens.length - 1], text3[index2 + 1])));
159308
159374
  index2 += 1;
159309
159375
  }
159310
159376
  }
159311
159377
  return tokens;
159312
159378
  }
159379
+ function unexpectedCharacterHint(char, previous, following) {
159380
+ if (char === "\\" && following === '"') return 'The source has \\" where a plain " belongs: a label is written "Label" in the source. In JSON, escape that quote once, as \\", never as \\\\\\".';
159381
+ if (char === "\\" && following === "u" || char === "-" && following === "\\") return "The source has a JSON escape written out, such as \\u003e: write the character it stands for instead (\\u003e is >, \\u003c is <, \\u0026 is &), so an arrow is -> and not -\\u003e.";
159382
+ if (char === "\\" && following === "n") return "The source has a written \\n where a line should end: each statement goes on its own line. In JSON, write a line break inside the string as \\n, not \\\\n.";
159383
+ if (previous?.kind === "arrow" || char === ">" || char === "<") return ARROW_HINT;
159384
+ return 'Labels go in double quotes; ids use letters, digits, "_" and "-".';
159385
+ }
159313
159386
  function lex(source) {
159314
159387
  const diagnostics = [];
159315
159388
  const lines = [];
@@ -159320,7 +159393,7 @@ function lex(source) {
159320
159393
  });
159321
159394
  return { lines, diagnostics };
159322
159395
  }
159323
- var STRING_ESCAPES, isWordStart, isWordPart;
159396
+ var STRING_ESCAPES, isWordStart, isWordPart, ARROW_HINT;
159324
159397
  var init_lexer = __esm({
159325
159398
  "../../packages/diagrams/src/parse/lexer.ts"() {
159326
159399
  "use strict";
@@ -159329,6 +159402,7 @@ var init_lexer = __esm({
159329
159402
  STRING_ESCAPES = { '"': '"', "\\": "\\", n: "\n", t: " " };
159330
159403
  isWordStart = (char) => /[A-Za-z0-9_]/.test(char);
159331
159404
  isWordPart = (char) => /[A-Za-z0-9_]/.test(char);
159405
+ ARROW_HINT = "An arrow is one of ->, -->, ..>, <->, <-->, or --, written from the sender to the receiver (a -> b). Mermaid's ->> and -->> are -> and --> here, and a reply is b --> a, never a <-- b.";
159332
159406
  }
159333
159407
  });
159334
159408
 
@@ -159350,7 +159424,7 @@ function parseDiagram(source) {
159350
159424
  DIAGNOSTIC_CODES.missingHeader,
159351
159425
  `The first line must name the diagram kind, found "${text3}"`,
159352
159426
  header,
159353
- `${didYouMean(text3, implementedKinds())} Start with: ${headerHint()}`
159427
+ text3 === "title" ? 'There is no title statement: the title is the quoted text after the kind on the first line, such as flow "Checkout" or sequence "Sign in".' : `${didYouMean(text3, implementedKinds())} Start with: ${headerHint()}`
159354
159428
  )
159355
159429
  );
159356
159430
  return err(report3);
@@ -159528,7 +159602,7 @@ async function readCapped(response, maxBytes) {
159528
159602
  }
159529
159603
  return new TextDecoder().decode(bytes);
159530
159604
  }
159531
- async function fetchDiagramLink(text3, fetchLink = (url2, init) => fetch(url2, init)) {
159605
+ async function fetchDiagramLink(text3, fetchLink = (url2, init) => fetch(url2, { ...init, signal: init.signal })) {
159532
159606
  const refusal = refusalOfLink(text3);
159533
159607
  if (refusal !== null) return REFUSED(refusal);
159534
159608
  const seconds = READ_LIMITS.timeoutMs / 1e3;
@@ -160405,6 +160479,13 @@ var init_render_pair = __esm({
160405
160479
  }
160406
160480
  });
160407
160481
 
160482
+ // ../../packages/diagrams/src/markdown/dark-pictures.ts
160483
+ var init_dark_pictures = __esm({
160484
+ "../../packages/diagrams/src/markdown/dark-pictures.ts"() {
160485
+ "use strict";
160486
+ }
160487
+ });
160488
+
160408
160489
  // ../../packages/diagrams/src/services/render-diagram-svg.ts
160409
160490
  async function renderDiagramSource(input2, brand = null) {
160410
160491
  const parsed = parseDiagram(input2.source);
@@ -160828,12 +160909,11 @@ function attr(text3) {
160828
160909
  function buildBlock(content) {
160829
160910
  const isListLine = (line3) => line3.startsWith("- ") || line3.startsWith(" ");
160830
160911
  const outline2 = content.outline.flatMap((line3) => isListLine(line3) ? [line3] : ["", `**${line3}**`, ""]);
160912
+ const image = `<img alt="${attr(content.alt)}" src="${attr(content.lightSrc)}">`;
160913
+ const picture2 = content.darkSrc === null ? [image] : ["<picture>", ` <source media="(prefers-color-scheme: dark)" srcset="${attr(content.darkSrc)}">`, ` ${image}`, "</picture>"];
160831
160914
  return [
160832
160915
  `${BLOCK_START} id="${content.id}" hash="${content.hash}" -->`,
160833
- "<picture>",
160834
- ` <source media="(prefers-color-scheme: dark)" srcset="${attr(content.darkSrc)}">`,
160835
- ` <img alt="${attr(content.alt)}" src="${attr(content.lightSrc)}">`,
160836
- "</picture>",
160916
+ ...picture2,
160837
160917
  "",
160838
160918
  "<details>",
160839
160919
  "<summary>Text description</summary>",
@@ -160927,11 +161007,11 @@ var init_locate_block = __esm({
160927
161007
 
160928
161008
  // ../../packages/diagrams/src/markdown/sync-markdown.ts
160929
161009
  import { createHash } from "node:crypto";
160930
- function hashBlock(source, pair2) {
161010
+ function hashBlock(source, pair2, schemes = "light-and-dark") {
160931
161011
  return createHash("sha256").update(`${BLOCK_FORMAT_VERSION}
160932
161012
  ${source}
160933
161013
  ${pair2.light}
160934
- ${pair2.dark}`).digest("hex").slice(0, 12);
161014
+ ${pair2.dark}${schemes === "auto" ? "\nauto" : ""}`).digest("hex").slice(0, 12);
160935
161015
  }
160936
161016
  function slugify2(text3) {
160937
161017
  const slug = text3.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
@@ -160974,7 +161054,8 @@ async function syncMarkdown(markdown, stem2, hooks) {
160974
161054
  continue;
160975
161055
  }
160976
161056
  const { pair: pair2 } = outcome;
160977
- const hash2 = hashBlock(fence.source, pair2);
161057
+ const merged = hooks.schemes === "auto" ? mergeSchemes(pair2.light, pair2.dark, id) : null;
161058
+ const hash2 = hashBlock(fence.source, pair2, merged === null ? "light-and-dark" : "auto");
160978
161059
  const isFresh = place2.block !== null && readBlockHash(lines[place2.block.start] ?? "") === hash2;
160979
161060
  if (isFresh && !needsWrap) {
160980
161061
  unchangedCount += 1;
@@ -160982,8 +161063,8 @@ async function syncMarkdown(markdown, stem2, hooks) {
160982
161063
  }
160983
161064
  stale.push({ fenceLine: fence.openLine + 1, reason: place2.block === null ? "missing" : isFresh ? "unwrapped" : "changed" });
160984
161065
  const lightSrc = `${hooks.assetDir}/${id}.svg`;
160985
- const darkSrc = `${hooks.assetDir}/${id}.dark.svg`;
160986
- assets.push({ path: lightSrc, content: pair2.light }, { path: darkSrc, content: pair2.dark });
161066
+ const darkSrc = merged === null ? `${hooks.assetDir}/${id}.dark.svg` : null;
161067
+ assets.push({ path: lightSrc, content: merged ?? pair2.light }, ...darkSrc === null ? [] : [{ path: darkSrc, content: pair2.dark }]);
160987
161068
  const block = buildBlock({ id, hash: hash2, alt: pair2.summary, outline: pair2.outline, lightSrc, darkSrc }).split("\n");
160988
161069
  if (needsWrap) {
160989
161070
  const source = lines.slice(fence.openLine, fence.closeLine + 1);
@@ -161008,6 +161089,7 @@ var BLOCK_FORMAT_VERSION;
161008
161089
  var init_sync_markdown = __esm({
161009
161090
  "../../packages/diagrams/src/markdown/sync-markdown.ts"() {
161010
161091
  "use strict";
161092
+ init_merge_schemes();
161011
161093
  init_diagram_block();
161012
161094
  init_extract_fences();
161013
161095
  init_locate_block();
@@ -161021,6 +161103,7 @@ var init_markdown = __esm({
161021
161103
  "use strict";
161022
161104
  init_diagram_block();
161023
161105
  init_extract_fences();
161106
+ init_dark_pictures();
161024
161107
  init_sync_markdown();
161025
161108
  }
161026
161109
  });
@@ -161302,6 +161385,7 @@ async function runSync(document2, settings, ops, cache, limit) {
161302
161385
  const result = await syncMarkdown(document2, settings.stem, {
161303
161386
  render,
161304
161387
  assetDir: settings.assetDir,
161388
+ ...settings.defaults?.schemes === void 0 ? {} : { schemes: settings.defaults.schemes },
161305
161389
  ...settings.prefix === void 0 ? {} : { idPrefix: settings.prefix }
161306
161390
  });
161307
161391
  return { result, calls };
@@ -161723,13 +161807,13 @@ function shareAnEnd(a, b) {
161723
161807
  return ends.some((end) => end === b.from || end === b.to);
161724
161808
  }
161725
161809
  function countCrossings(lines) {
161726
- const bounds = lines.map((line3) => boundsOf2(line3.points));
161810
+ const bounds2 = lines.map((line3) => boundsOf2(line3.points));
161727
161811
  const segments = lines.map(segmentsOf2);
161728
161812
  let crossings2 = 0;
161729
161813
  for (let i = 0; i < lines.length; i += 1) {
161730
161814
  for (let j = i + 1; j < lines.length; j += 1) {
161731
161815
  if (shareAnEnd(lines[i], lines[j])) continue;
161732
- if (!rectsCollide(inflate(bounds[i], 3), inflate(bounds[j], 3))) continue;
161816
+ if (!rectsCollide(inflate(bounds2[i], 3), inflate(bounds2[j], 3))) continue;
161733
161817
  const ends = [...endsOf2(lines[i]), ...endsOf2(lines[j])];
161734
161818
  for (const [a, b] of segments[i]) {
161735
161819
  for (const [c, d] of segments[j]) {
@@ -162309,6 +162393,7 @@ var init_services = __esm({
162309
162393
  init_render_pair();
162310
162394
  init_source_metadata();
162311
162395
  init_picture_facts();
162396
+ init_dark_pictures();
162312
162397
  init_render_diagram_svg();
162313
162398
  init_search_icon_names();
162314
162399
  init_sync_document();
@@ -166038,8 +166123,8 @@ function enforceDeletedFields(method, result) {
166038
166123
  }
166039
166124
  return next;
166040
166125
  };
166041
- const tools = result.tools;
166042
- if (method === "tools/list" && Array.isArray(tools) && tools.some((tool) => isPlainObject$4(tool) && "execution" in tool)) copy().tools = tools.map((tool) => {
166126
+ const tools2 = result.tools;
166127
+ if (method === "tools/list" && Array.isArray(tools2) && tools2.some((tool) => isPlainObject$4(tool) && "execution" in tool)) copy().tools = tools2.map((tool) => {
166043
166128
  if (!isPlainObject$4(tool) || !("execution" in tool)) return tool;
166044
166129
  const rest = { ...tool };
166045
166130
  delete rest["execution"];
@@ -166894,11 +166979,11 @@ var init_src_BHSMhZ_W = __esm({
166894
166979
  },
166895
166980
  encodeResult(method, result) {
166896
166981
  if (method !== "tools/list") return result;
166897
- const tools = result.tools;
166898
- if (!Array.isArray(tools) || !tools.some((t) => toolNeedsLegacyWrap(t))) return result;
166982
+ const tools2 = result.tools;
166983
+ if (!Array.isArray(tools2) || !tools2.some((t) => toolNeedsLegacyWrap(t))) return result;
166899
166984
  return {
166900
166985
  ...result,
166901
- tools: tools.map((t) => toolNeedsLegacyWrap(t) ? {
166986
+ tools: tools2.map((t) => toolNeedsLegacyWrap(t) ? {
166902
166987
  ...t,
166903
166988
  outputSchema: wrapOutputSchemaForLegacy(t.outputSchema)
166904
166989
  } : t)
@@ -177809,6 +177894,7 @@ var init_sources2 = __esm({
177809
177894
  options: SourceOptionsSchema.optional(),
177810
177895
  overrides: repositoryPath.refine((path) => path.endsWith(".json"), { message: "An overrides file is a .json file" }).optional().describe("The overrides file, applied after every import. Left out: the out path with .overrides.json in place of .diagram, or <file>.<fence id>.overrides.json beside a Markdown file."),
177811
177896
  pictures: external_exports.boolean().optional().describe("For a .diagram out: also write its light and dark SVG beside it. On when left out."),
177897
+ schemes: external_exports.enum(PICTURE_FILE_SCHEMES).optional().describe("The pictures this source writes: light-and-dark writes <name>.svg and <name>.dark.svg; auto writes one <name>.svg that follows the reader's light or dark setting. defaults.schemes, then light-and-dark, when left out."),
177812
177898
  publish: SourcePublishSchema.optional()
177813
177899
  }).meta({ id: "Source", description: "One diagram generated from files of the repository and kept in step with them." });
177814
177900
  }
@@ -177834,6 +177920,7 @@ var init_schema4 = __esm({
177834
177920
  numbered: external_exports.enum(SWITCH_VALUES).optional().describe("numbered= on every header that takes it: on numbers every line in the order written."),
177835
177921
  theme: external_exports.enum(PICTURE_SCHEMES).optional().describe("The color scheme the command line and the GitHub Action draw a single picture in."),
177836
177922
  embedSource: external_exports.boolean().optional().describe("Write the source into every SVG the command line, the GitHub Action, and the drawing tools save."),
177923
+ schemes: external_exports.enum(PICTURE_FILE_SCHEMES).optional().describe("The pictures generate and sync write: light-and-dark (the default) writes <name>.svg and <name>.dark.svg; auto writes one <name>.svg that holds both and follows the reader's light or dark setting, so GitHub shows it right in either theme."),
177837
177924
  kinds: external_exports.partialRecord(external_exports.enum(DIAGRAM_KINDS), external_exports.record(optionKey, optionValue)).optional().describe('Header options for one kind, such as { "mindmap": { "layout": "radial" } }. A value the kind refuses is left out with warning S200.')
177838
177925
  }).meta({ id: "SettingsDefaults", description: "Header options a diagram gets when its header does not set them." });
177839
177926
  SettingsBrandSchema = external_exports.strictObject({
@@ -179033,6 +179120,182 @@ var init_tool_settings = __esm({
179033
179120
  }
179034
179121
  });
179035
179122
 
179123
+ // ../../packages/diagrams/src/tools/json-schema.ts
179124
+ function referencedDefs(node3) {
179125
+ return [...JSON.stringify(node3).matchAll(DEF_REF)].map((match) => match[1] ?? "");
179126
+ }
179127
+ function reachableDefs(root, defs) {
179128
+ const reached = /* @__PURE__ */ new Set();
179129
+ const pending = referencedDefs(root);
179130
+ for (let name2 = pending.pop(); name2 !== void 0; name2 = pending.pop()) {
179131
+ const def = defs[name2];
179132
+ if (def === void 0 || reached.has(name2)) continue;
179133
+ reached.add(name2);
179134
+ pending.push(...referencedDefs(def));
179135
+ }
179136
+ return Object.fromEntries(Object.entries(defs).filter(([name2]) => reached.has(name2)));
179137
+ }
179138
+ function inlineRootRef(schema) {
179139
+ const ref = schema["$ref"];
179140
+ const defs = schema["$defs"];
179141
+ if (typeof ref !== "string" || typeof defs !== "object" || defs === null) return schema;
179142
+ const target = defs[ref.replace("#/$defs/", "")];
179143
+ if (target === void 0) return schema;
179144
+ const { $ref: _removed, $defs: _defs, ...header } = schema;
179145
+ const root = { ...header, ...target };
179146
+ const kept2 = reachableDefs(root, defs);
179147
+ return Object.keys(kept2).length === 0 ? root : { ...root, $defs: kept2 };
179148
+ }
179149
+ function remembered(cache, key, make) {
179150
+ const known3 = cache.get(key);
179151
+ if (known3 !== void 0) return known3;
179152
+ const made = make();
179153
+ cache.set(key, made);
179154
+ return made;
179155
+ }
179156
+ function inputJsonSchema(tool) {
179157
+ return inputJsonSchemaOf(tool.inputSchema);
179158
+ }
179159
+ function inputJsonSchemaOf(schema) {
179160
+ return remembered(inputSchemas, schema, () => portable(withoutSafeBounds(inlineRootRef(external_exports.toJSONSchema(schema, { target: TARGET, io: "input" })))));
179161
+ }
179162
+ function portable(node3) {
179163
+ if (Array.isArray(node3)) return node3.map(portable);
179164
+ if (typeof node3 !== "object" || node3 === null) return node3;
179165
+ return Object.fromEntries(
179166
+ Object.entries(node3).filter(([key, value]) => !(key === "propertyNames" && JSON.stringify(value) === '{"type":"string"}')).map(([key, value]) => [key, key === "additionalProperties" && JSON.stringify(value) === "{}" ? true : portable(value)])
179167
+ );
179168
+ }
179169
+ function withoutSafeBounds(node3) {
179170
+ if (Array.isArray(node3)) return node3.map(withoutSafeBounds);
179171
+ if (typeof node3 !== "object" || node3 === null) return node3;
179172
+ return Object.fromEntries(
179173
+ Object.entries(node3).filter(([key, value]) => !(key === "minimum" && value === Number.MIN_SAFE_INTEGER || key === "maximum" && value === Number.MAX_SAFE_INTEGER)).map(([key, value]) => [key, withoutSafeBounds(value)])
179174
+ );
179175
+ }
179176
+ function openObjects(node3) {
179177
+ if (Array.isArray(node3)) return node3.map(openObjects);
179178
+ if (typeof node3 !== "object" || node3 === null) return node3;
179179
+ return Object.fromEntries(
179180
+ Object.entries(node3).filter(([key, value]) => !(key === "additionalProperties" && value === false)).map(([key, value]) => [key, openObjects(value)])
179181
+ );
179182
+ }
179183
+ function outputJsonSchema(tool) {
179184
+ return remembered(outputSchemas, tool.outputSchema, () => withoutSafeBounds(openObjects(inlineRootRef(external_exports.toJSONSchema(tool.outputSchema, { target: TARGET, io: "output" })))));
179185
+ }
179186
+ function withoutProse(node3, isProperties = false) {
179187
+ if (Array.isArray(node3)) return node3.map((item) => withoutProse(item));
179188
+ if (typeof node3 !== "object" || node3 === null) return node3;
179189
+ return Object.fromEntries(
179190
+ Object.entries(node3).filter(([key]) => isProperties || !LEFT_OUT.has(key)).map(([key, value]) => [key, withoutProse(value, !isProperties && (key === "properties" || key === "$defs"))])
179191
+ );
179192
+ }
179193
+ function listedOutputSchema(schema) {
179194
+ return remembered(listedSchemas, schema, () => withoutProse(withoutSafeBounds(schema)));
179195
+ }
179196
+ function listedOutputJsonSchema(tool) {
179197
+ return listedOutputSchema(outputJsonSchema(tool));
179198
+ }
179199
+ var TARGET, DEF_REF, inputSchemas, outputSchemas, listedSchemas, LEFT_OUT;
179200
+ var init_json_schema2 = __esm({
179201
+ "../../packages/diagrams/src/tools/json-schema.ts"() {
179202
+ "use strict";
179203
+ init_zod();
179204
+ TARGET = "draft-2020-12";
179205
+ DEF_REF = /"\$ref":"#\/\$defs\/([^"]+)"/g;
179206
+ inputSchemas = /* @__PURE__ */ new WeakMap();
179207
+ outputSchemas = /* @__PURE__ */ new WeakMap();
179208
+ listedSchemas = /* @__PURE__ */ new WeakMap();
179209
+ LEFT_OUT = /* @__PURE__ */ new Set(["description", "$schema", "title", "enum"]);
179210
+ }
179211
+ });
179212
+
179213
+ // ../../packages/diagrams/src/tools/input-hint.ts
179214
+ function asObject(value) {
179215
+ return typeof value === "object" && value !== null && !Array.isArray(value) ? value : null;
179216
+ }
179217
+ function bounds(schema) {
179218
+ const low = schema["minimum"] ?? schema["minLength"] ?? schema["minItems"];
179219
+ const high = schema["maximum"] ?? schema["maxLength"] ?? schema["maxItems"];
179220
+ const unit3 = schema["type"] === "string" ? " characters" : schema["type"] === "array" ? " items" : "";
179221
+ if (typeof high === "number" && low === 1 && unit3 !== "") return `, at most ${high}${unit3}`;
179222
+ if (typeof low === "number" && typeof high === "number") return `, ${low} to ${high}${unit3}`;
179223
+ if (typeof high === "number") return `, at most ${high}${unit3}`;
179224
+ if (typeof low === "number" && low > 0) return `, at least ${low}${unit3}`;
179225
+ return "";
179226
+ }
179227
+ function fieldType(node3) {
179228
+ const schema = asObject(node3);
179229
+ if (schema === null) return "any value";
179230
+ const values = schema["enum"];
179231
+ if (Array.isArray(values)) {
179232
+ const listed2 = values.slice(0, ENUM_LISTED).map((value) => JSON.stringify(value));
179233
+ return `one of ${listed2.join(", ")}${values.length > ENUM_LISTED ? `, and ${values.length - ENUM_LISTED} more` : ""}`;
179234
+ }
179235
+ if ("const" in schema) return JSON.stringify(schema["const"]);
179236
+ const union2 = schema["anyOf"] ?? schema["oneOf"];
179237
+ if (Array.isArray(union2)) return [...new Set(union2.map(fieldType))].join(" or ");
179238
+ const type = schema["type"];
179239
+ if (Array.isArray(type)) return type.join(" or ");
179240
+ if (type === "array") return `array of ${fieldType(schema["items"])}${bounds(schema)}`;
179241
+ if (type === "object") {
179242
+ const properties = Object.keys(asObject(schema["properties"]) ?? {});
179243
+ return properties.length === 0 ? "object" : `object with ${properties.join(", ")}`;
179244
+ }
179245
+ return typeof type === "string" ? `${type}${bounds(schema)}` : "any value";
179246
+ }
179247
+ function shortExample(example, required2) {
179248
+ const call = asObject(example);
179249
+ if (call === null) return null;
179250
+ const full = JSON.stringify(call);
179251
+ if (full.length <= EXAMPLE_CHARACTERS) return full;
179252
+ return JSON.stringify(Object.fromEntries(Object.entries(call).filter(([key]) => required2.includes(key))));
179253
+ }
179254
+ function namedFields(issues) {
179255
+ return [...new Set(issues.map((issue3) => issue3.path[0]).filter((key) => typeof key === "string"))];
179256
+ }
179257
+ function unknownKeys(issues) {
179258
+ return issues.flatMap((issue3) => issue3.code === "unrecognized_keys" && issue3.path.length === 0 ? issue3.keys : []);
179259
+ }
179260
+ function wrapperOf(args, properties) {
179261
+ const call = asObject(args);
179262
+ if (call === null) return null;
179263
+ const keys = Object.keys(call);
179264
+ const only = keys.length === 1 ? keys[0] : void 0;
179265
+ if (only === void 0 || !WRAPPER_KEYS.includes(only) || Object.hasOwn(properties, only)) return null;
179266
+ const inner = call[only];
179267
+ if (typeof inner === "string") return only;
179268
+ const wrapped2 = asObject(inner);
179269
+ return wrapped2 !== null && (Object.keys(wrapped2).length === 0 || Object.keys(wrapped2).some((key) => Object.hasOwn(properties, key))) ? only : null;
179270
+ }
179271
+ function inputHint(tool, args, issues) {
179272
+ const schema = inputJsonSchemaOf(tool.inputSchema);
179273
+ const properties = asObject(schema["properties"]) ?? {};
179274
+ const required2 = Array.isArray(schema["required"]) ? schema["required"] : [];
179275
+ const sentences = [];
179276
+ const wrapper = wrapperOf(args, properties);
179277
+ if (asObject(args) === null) sentences.push(`Pass the arguments as a JSON object, not ${args === null || args === void 0 ? "nothing" : typeof args}.`);
179278
+ if (wrapper !== null) sentences.push(`Put the fields at the top level of the arguments, not inside "${wrapper}".`);
179279
+ if (required2.length > 0) sentences.push(`${tool.name} needs ${required2.map((key) => `${key} (${fieldType(properties[key])})`).join(", ")}.`);
179280
+ const wrong = namedFields(issues).filter((key) => !required2.includes(key) && Object.hasOwn(properties, key));
179281
+ if (wrong.length > 0) sentences.push(`${wrong.map((key) => `${key} takes ${fieldType(properties[key])}`).join("; ")}.`);
179282
+ const unknown2 = unknownKeys(issues).filter((key) => key !== wrapper);
179283
+ if (unknown2.length > 0) sentences.push(`It does not take ${unknown2.join(", ")}; its fields are ${Object.keys(properties).join(", ")}.`);
179284
+ const example = shortExample(tool.callExample, required2);
179285
+ if (example !== null) sentences.push(`Example call: ${tool.name} ${example}`);
179286
+ return sentences.join(" ");
179287
+ }
179288
+ var WRAPPER_KEYS, ENUM_LISTED, EXAMPLE_CHARACTERS;
179289
+ var init_input_hint = __esm({
179290
+ "../../packages/diagrams/src/tools/input-hint.ts"() {
179291
+ "use strict";
179292
+ init_json_schema2();
179293
+ WRAPPER_KEYS = ["arguments", "args", "input", "params", "parameters", "kwargs"];
179294
+ ENUM_LISTED = 8;
179295
+ EXAMPLE_CHARACTERS = 320;
179296
+ }
179297
+ });
179298
+
179036
179299
  // ../../packages/diagrams/src/tools/settings-ops.ts
179037
179300
  function defaultedOps(ops, defaults) {
179038
179301
  if (defaults === void 0) return ops;
@@ -191566,7 +191829,7 @@ function readColumn(text3) {
191566
191829
  const chain2 = readChain(value, close2 + 1);
191567
191830
  const has = (method) => chain2.some((entry2) => entry2.name === method);
191568
191831
  const references2 = chain2.find((entry2) => entry2.name === "references");
191569
- const target = references2 === void 0 ? null : TARGET.exec(references2.args);
191832
+ const target = references2 === void 0 ? null : TARGET2.exec(references2.args);
191570
191833
  return {
191571
191834
  key,
191572
191835
  name: name2 ?? key,
@@ -191594,13 +191857,13 @@ function callsOf(text3, name2) {
191594
191857
  }
191595
191858
  return calls;
191596
191859
  }
191597
- var BUILDER, TARGET, SERIALS;
191860
+ var BUILDER, TARGET2, SERIALS;
191598
191861
  var init_columns2 = __esm({
191599
191862
  "../../packages/diagrams/src/importers/drizzle/columns.ts"() {
191600
191863
  "use strict";
191601
191864
  init_scan3();
191602
191865
  BUILDER = /^([A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*)*)\s*\(/;
191603
- TARGET = /=>\s*([A-Za-z_$][\w$]*)\.([A-Za-z_$][\w$]*)/;
191866
+ TARGET2 = /=>\s*([A-Za-z_$][\w$]*)\.([A-Za-z_$][\w$]*)/;
191604
191867
  SERIALS = /* @__PURE__ */ new Set(["serial", "bigserial", "smallserial"]);
191605
191868
  }
191606
191869
  });
@@ -196727,17 +196990,22 @@ var init_ops = __esm({
196727
196990
  function settingsOf(input2) {
196728
196991
  return input2?.settings;
196729
196992
  }
196730
- function invalidInput(issues) {
196993
+ function invalidInput(tool, args, issues) {
196731
196994
  return {
196732
196995
  kind: "invalid-input",
196733
- message: "The arguments did not match the input schema.",
196734
- issues: issues.map((issue3) => ({ path: issue3.path.join("."), message: issue3.message }))
196996
+ message: `The arguments did not match the input schema of ${tool.name}.`,
196997
+ issues: issues.map((issue3) => ({ path: issue3.path.join("."), message: issue3.message })),
196998
+ hint: inputHint({ name: tool.name, inputSchema: tool.input, callExample: tool.callExample }, args, issues)
196735
196999
  };
196736
197000
  }
197001
+ function checkToolInput(tool, args) {
197002
+ const parsed = tool.inputSchema.safeParse(args);
197003
+ return parsed.success ? null : invalidInput({ name: tool.name, input: tool.inputSchema, callExample: tool.callExample }, args, parsed.error.issues);
197004
+ }
196737
197005
  function defineTool(spec) {
196738
197006
  const runWith = async (args, ops) => {
196739
197007
  const parsed = spec.input.safeParse(args);
196740
- if (!parsed.success) return err(invalidInput(parsed.error.issues));
197008
+ if (!parsed.success) return err(invalidInput({ ...spec, callExample: spec.callExample ?? null }, args, parsed.error.issues));
196741
197009
  const settled = settleToolInput(parsed.data);
196742
197010
  const answer = await spec.execute(settled.input, defaultedOps(ops, settingsOf(parsed.data)?.defaults));
196743
197011
  return answer.ok ? ok(settled.finish(answer.value)) : answer;
@@ -196754,6 +197022,8 @@ function defineTool(spec) {
196754
197022
  maxCalls: 1,
196755
197023
  example: null,
196756
197024
  prompts: [],
197025
+ callExample: spec.callExample ?? null,
197026
+ compact: spec.compact ?? null,
196757
197027
  run: (args) => runWith(args, ENGINE_OPS),
196758
197028
  runWith
196759
197029
  };
@@ -196761,7 +197031,7 @@ function defineTool(spec) {
196761
197031
  function defineWorkflow(spec) {
196762
197032
  const runWith = async (args, ops) => {
196763
197033
  const parsed = spec.input.safeParse(args);
196764
- if (!parsed.success) return err(invalidInput(parsed.error.issues));
197034
+ if (!parsed.success) return err(invalidInput({ ...spec, callExample: spec.callExample ?? spec.example }, args, parsed.error.issues));
196765
197035
  const settled = settleToolInput(parsed.data, { rewriteSource: false });
196766
197036
  return ok(settled.finish(await spec.execute(settled.input, defaultedOps(ops, settingsOf(parsed.data)?.defaults))));
196767
197037
  };
@@ -196777,6 +197047,8 @@ function defineWorkflow(spec) {
196777
197047
  maxCalls: spec.maxCalls,
196778
197048
  example: spec.example,
196779
197049
  prompts: spec.prompts,
197050
+ callExample: spec.callExample ?? spec.example,
197051
+ compact: spec.compact ?? null,
196780
197052
  run: (args) => runWith(args, ENGINE_OPS),
196781
197053
  runWith
196782
197054
  };
@@ -196787,6 +197059,7 @@ var init_define_tool = __esm({
196787
197059
  "use strict";
196788
197060
  init_core();
196789
197061
  init_tool_settings();
197062
+ init_input_hint();
196790
197063
  init_settings_ops();
196791
197064
  init_ops();
196792
197065
  READ_ONLY_ANNOTATIONS = {
@@ -196819,6 +197092,7 @@ var init_definitions = __esm({
196819
197092
  name: "validate_diagram",
196820
197093
  title: "Validate diagram",
196821
197094
  description: "Check diagram source without drawing it: every error in one pass, each with line, column, and a fix hint, plus quality warnings. An icon a label names for certain is drawn already; W204 gives the exact icon=provider:name for a node whose label names a product it does not draw (a brand whose name is also an everyday word, or every match under icons=off), W205 the type= for a group whose name matches a group type, and W206 flags an overlay framing a node that is not its member. These suggestions are not applied for you: add one, or icon=none to keep a node plain, and validate again. Prefer draw_diagram, which checks, describes, and draws in one call.",
197095
+ callExample: { source: 'flow\nnode api service "API"\nnode db database "DB"\napi -> db : "reads"' },
196822
197096
  input: DiagramSourceInputSchema,
196823
197097
  output: ValidateResponseSchema,
196824
197098
  execute: async (input2) => ok(await validateDiagramSource(input2.source))
@@ -196827,6 +197101,7 @@ var init_definitions = __esm({
196827
197101
  name: "render_diagram",
196828
197102
  title: "Render diagram",
196829
197103
  description: "Render valid source to a self-contained, accessible SVG in the light or dark theme, with its pixel size and quality warnings. Source with errors fails with its diagnostics. Set embedSource true to save the SVG in a repository, so read_diagram can give the source back. Prefer draw_diagram, which validates, outlines, and renders in one call.",
197104
+ callExample: { source: 'flow\nnode api service "API"\nnode db database "DB"\napi -> db : "reads"' },
196830
197105
  input: RenderInputSchema,
196831
197106
  output: RenderResponseSchema,
196832
197107
  execute: async (input2, ops) => {
@@ -196838,6 +197113,7 @@ var init_definitions = __esm({
196838
197113
  name: "outline_diagram",
196839
197114
  title: "Outline diagram",
196840
197115
  description: "Describe valid diagram source as plain text: participants, steps, tables, and connections in reading order, to check the diagram says what you meant or to use as alt text. Source with errors fails with diagnostics. Does not render. Prefer draw_diagram, which returns the outline with the check and the pictures.",
197116
+ callExample: { source: 'flow\nnode api service "API"\nnode db database "DB"\napi -> db : "reads"' },
196841
197117
  input: DiagramSourceInputSchema,
196842
197118
  output: OutlineResponseSchema,
196843
197119
  execute: async (input2) => {
@@ -196849,6 +197125,7 @@ var init_definitions = __esm({
196849
197125
  name: "search_icons",
196850
197126
  title: "Search icons",
196851
197127
  description: 'Find bundled icon names by keyword, idea, product, or abbreviation ("postgres", "token exchange", "s3", "cosmos db"). Returns set:name references, best first, at most 100, such as lucide:database, simple:postgresql, aws:lambda. Cloud products are in one set per provider (aws, gcp, azure, alibaba, oci, ibm, cloudflare, digitalocean, vercel), with every official aws, azure, and gcp icon; <provider>:cloud is the provider, for a group. Use it before setting icon= or a name in stack=. Search with the product name exactly as the user wrote it and take the first result; never invent a name, because an unknown icon is an error. For several names prefer map_icons: up to 40 in one call, and it never guesses. Hosted calls also find the organisation icons, as org:name.',
197128
+ callExample: { q: "postgres" },
196852
197129
  input: IconSearchQuerySchema,
196853
197130
  output: IconSearchResponseSchema,
196854
197131
  execute: async (input2) => ok(searchIconNames(input2))
@@ -196857,6 +197134,11 @@ var init_definitions = __esm({
196857
197134
  name: "get_diagram_syntax",
196858
197135
  title: "Get diagram syntax",
196859
197136
  description: "Read the diagram language as data. Call it once with no kind before your first diagram: the overview, the tables every kind shares (node types, arrows including dotted ..> for asynchronous calls, animated and numbered lines, icon sets, size limits, how to edit an existing SVG), and one line about each kind. For one kind in full, call it again with kind set to it: its statements, limits, and a tested example. kind flow adds the group types (type=), overlays, stack= marks, and a complete cloud architecture example; build the group tree top-down with type=, one node per service, and icons from map_icons or search_icons. For a common architecture, find_pattern gives a checked diagram to adapt. topic import-formats lists what import_source reads.",
197137
+ callExample: { kind: "sequence" },
197138
+ compact: {
197139
+ description: "Returns the diagram language as data. Call it with kind set to the kind you draw (such as sequence or flow): its statements, limits, and a tested example to copy. With no kind it returns the shared overview, which is long.",
197140
+ inputs: { kind: "The kind to read in full, such as sequence or flow." }
197141
+ },
196860
197142
  input: SyntaxInputSchema,
196861
197143
  output: SyntaxResponseSchema,
196862
197144
  execute: async (input2) => ok(buildSyntax(input2.kind, input2.topic))
@@ -196865,6 +197147,7 @@ var init_definitions = __esm({
196865
197147
  name: "read_diagram",
196866
197148
  title: "Read diagram",
196867
197149
  description: "Read the source of an existing Plotwork SVG so you can edit the diagram. Send the text of an .svg file as svg, or a hosted link (https://cdn.plotwork.dev/d/<22 characters>.svg) as url. Returns the exact source, its kind, the stored diagram id if it was published, and a parse check. Call it first when asked to change a diagram that already exists, then edit the source and call draw_diagram (or edit_diagram); next says how to save or publish it again. Only a picture saved with embedSource true (or by sync_markdown) carries its source; otherwise status is no-source, with the title, outline, and labels to rebuild it from. A text that is not an SVG and a refused or unreachable link come back as data. Only cdn.plotwork.dev and cdn-preview.plotwork.dev are fetched (https, no redirects, 5 seconds, 1 MB); svg reads nothing from the network.",
197150
+ callExample: { svg: '<svg xmlns="http://www.w3.org/2000/svg">...</svg>' },
196868
197151
  input: ReadDiagramInputSchema,
196869
197152
  output: ReadDiagramResponseSchema,
196870
197153
  annotations: { openWorldHint: true },
@@ -197397,6 +197680,7 @@ var init_compare_diagrams3 = __esm({
197397
197680
  name: "compare_diagrams",
197398
197681
  title: "Compare diagrams",
197399
197682
  description: "Compare two versions of a diagram by meaning, for a pull request review. Send before and after, each as source, the text of a Plotwork SVG that carries its source, or a cdn.plotwork.dev link. Returns every statement added, removed, renamed (by id or label), moved to another block, or changed (options, type, edge arrow or label), with counts and a plain-language summary; markdown true adds a block ready to paste as a comment. Reordered or reformatted lines are no change. A side with no source is reported, not an error. Lays nothing out; fetches only a link.",
197683
+ callExample: { before: 'flow\nnode a service "API"', after: 'flow\nnode a service "API"\nnode b database "DB"\na -> b' },
197400
197684
  input: CompareDiagramsInputSchema,
197401
197685
  output: CompareDiagramsResponseSchema,
197402
197686
  annotations: { openWorldHint: true },
@@ -197495,6 +197779,10 @@ var init_convert_mermaid2 = __esm({
197495
197779
  name: "convert_mermaid",
197496
197780
  title: "Convert Mermaid",
197497
197781
  description: "Workflow. Converts one Mermaid diagram (" + mermaidTypesList() + ") to Plotwork source. Returns the source, a diagnostic with a hint for everything dropped or changed (styling, links, activations), the check of the result with its icon and group-type suggestions, and an outline; render true also draws it, with picturesOmitted, viewUrl, pngUrl, and saveCommand as in draw_diagram. A Mermaid type Plotwork does not draw comes back as one diagnostic saying what to do instead. Deterministic: never throws on bad input, does not fetch URLs or read files. For a whole Markdown document use sync_markdown with convertMermaid true. Replaces the convert, validate_diagram, outline_diagram and render_diagram calls.",
197782
+ compact: {
197783
+ description: "Converts one Mermaid diagram (flowchart, sequenceDiagram, erDiagram, and more) to Plotwork source and checks it. When ok is true its source is valid: save it as it is, and check any change you make with draw_diagram before saving.",
197784
+ inputs: { lenient: "true skips a line it cannot read, with a warning.", render: "Also draw the converted diagram." }
197785
+ },
197498
197786
  input: ConvertMermaidInputSchema,
197499
197787
  output: ConvertMermaidResponseSchema,
197500
197788
  steps: [{ call: "convertMermaid" }, { call: "validate", optional: true }, { call: "outline", optional: true }, { call: "render", optional: true }],
@@ -197570,6 +197858,10 @@ var init_draw_diagram2 = __esm({
197570
197858
  name: "draw_diagram",
197571
197859
  title: "Draw diagram",
197572
197860
  description: 'Workflow. Checks, describes, and draws a diagram. With errors it returns each one with line, column, and a fix hint and draws nothing: fix the source and call again. When valid it returns the quality warnings (take the icon and group-type suggestions), an outline to check the meaning, the size, and the SVG for light, dark, or both. The pictures are most of an answer and you cannot see them: pass svg "never" to check, and draw only to save, show, or publish. Give viewUrl to the person, even after svg "never"; pngUrl and svgUrl download it; saveCommand, when given, saves it in a repository. A big drawing (about 30 nodes) loses its SVGs, dark first, and picturesOmitted says so; svg "always" forces them. Set embedSource true to save an SVG in a repository or publish one to edit later, so read_diagram gives the source back (anyone with the file can read it). detail "full" adds the whole outline. To change an existing diagram use edit_diagram, or read_diagram for a picture. Saves no file; never throws on bad source. Replaces the validate_diagram, outline_diagram and render_diagram calls.',
197861
+ compact: {
197862
+ description: 'Checks diagram source and draws it in one call. Returns every error with line, column, and hint, and draws nothing until the source is valid, so fix each error and call again. svg "never" only checks and keeps the answer small; "always" returns the light and dark SVG to save.',
197863
+ inputs: { svg: "never: check only. always: return the SVGs.", themes: "", embedSource: "Write the source into the SVG, for a file saved in a repository." }
197864
+ },
197573
197865
  input: DrawDiagramInputSchema,
197574
197866
  output: DrawDiagramResponseSchema,
197575
197867
  steps: [{ call: "validate" }, { call: "outline", optional: true }, { call: "render", optional: true }],
@@ -197731,6 +198023,10 @@ var init_edit_diagram2 = __esm({
197731
198023
  name: "edit_diagram",
197732
198024
  title: "Edit diagram",
197733
198025
  description: 'Workflow. Changes diagram source with typed operations, on every kind, and checks the result. Each op and its fields: rename (target, to: an id everywhere it is used, or a label), set (target, or from and to for an edge, or target "header"; option, value, null removes it), add_node (id, label, type, options; into a block or after a statement; statement for a whole line), remove (target, with its block and edges), add_edge (from, to, label, arrow, options), remove_edge (from, to, label), move (target, into: a block, or null for the top level), replace_text (find, replace, all). Untouched lines keep their comments and layout. Each op reports applied, or why not with a hint, and a failed one is skipped. svg "never" (the default) lays nothing out; auto or always draws as draw_diagram does, with viewUrl and saveCommand. Replaces rewriting the source by hand and the draw_diagram check.',
198026
+ compact: {
198027
+ description: "Changes diagram source with typed operations and checks the result, without rewriting it by hand. Each operation is an object with op and its own fields: rename (target, to), set (target, option, value), add_node (id, type, label), remove (target), add_edge (from, to, label), remove_edge (from, to), move (target, into), replace_text (find, replace).",
198028
+ inputs: { svg: "never (default) draws nothing; auto or always draws." }
198029
+ },
197734
198030
  input: EditDiagramInputSchema,
197735
198031
  output: EditDiagramResponseSchema,
197736
198032
  steps: [{ call: "parse", optional: true }, { call: "outline", optional: true }, { call: "validate", optional: true }, { call: "render", optional: true }],
@@ -197744,6 +198040,7 @@ var init_edit_diagram2 = __esm({
197744
198040
  { op: "add_edge", from: "gateway", to: "cache", label: "store session" }
197745
198041
  ]
197746
198042
  },
198043
+ callExample: { source: 'flow\nnode api service "API"', operations: [{ op: "rename", target: "api", to: "gateway" }] },
197747
198044
  prompts: ["Rename the Auth API node to gateway and add a session cache it writes to.", "Move the database into the data group and remove the old queue."],
197748
198045
  execute: editDiagram
197749
198046
  });
@@ -197958,6 +198255,10 @@ var init_import_source3 = __esm({
197958
198255
  name: "import_source",
197959
198256
  title: "Import source",
197960
198257
  description: "Workflow. Turns a file into a finished diagram in one call: a database schema, an API spec, infrastructure as code, manifests, a software catalog, a CI workflow, CSV or JSON data, a folder listing, or a git log. get_diagram_syntax with topic import-formats says what each format reads, draws, and takes. Prefer it to drawing by hand whenever the person has such a file: send its text, never a path, or every file of a folder in files. Returns the source, diagnostics pointing into the file for anything left out, coverage, 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 validate_diagram and outline_diagram.",
198258
+ compact: {
198259
+ description: "Builds a whole diagram from a file in one call: SQL, Prisma, OpenAPI, Terraform, docker-compose, Kubernetes, GitHub Actions, CSV, a folder listing, a git log, and more. Send the file content as text and its format. When ok is true its source is valid: save it as it is. The diagnostics say what was left out.",
198260
+ inputs: { text: "The file content.", title: "" }
198261
+ },
197961
198262
  input: ImportSourceInputSchema,
197962
198263
  output: ImportSourceResponseSchema,
197963
198264
  steps: [{ call: "importSource" }, { call: "validate", optional: true }, { call: "outline", optional: true }],
@@ -198080,6 +198381,10 @@ var init_map_icons2 = __esm({
198080
198381
  name: "map_icons",
198081
198382
  title: "Map icons",
198082
198383
  description: `Workflow. Finds an icon for each of up to 40 service or product names in one call, such as the services of an architecture. For every name it returns the best provider:name icon with a confidence (exact, strong, or ambiguous) and up to 3 alternatives. It never guesses: a name that could mean several icons (a kind of service several clouds offer, or a match by idea only) comes back with resolved false and candidates to choose from, and a name that matches nothing is listed in gaps with a neutral fallback icon. Set provider to the cloud the architecture runs on, so "queue" finds that cloud's product first. Reads the bundled icons and, when hosted, the organisation icons (org:name). Replaces up to 40 search_icons calls.`,
198384
+ compact: {
198385
+ description: 'Finds the icon for each of up to 40 service or product names in one call ("S3", "Postgres", "load balancer"), for icon= on a node. It never guesses: for an ambiguous name choose from its candidates, and never invent an icon name.',
198386
+ inputs: { provider: "The cloud the names belong to, such as aws." }
198387
+ },
198083
198388
  input: MapIconsInputSchema,
198084
198389
  output: MapIconsResponseSchema,
198085
198390
  steps: [{ call: "searchIcons" }],
@@ -199923,6 +200228,7 @@ var init_plan_document_diagrams = __esm({
199923
200228
  steps: [{ call: "parse", optional: true }],
199924
200229
  maxCalls: WORKFLOW_MAX_CALLS.plan_document_diagrams,
199925
200230
  example: { document: EXAMPLE_DOCUMENT },
200231
+ callExample: { document: "# Refunds\n\n## Process\n\nCustomer: asks for a refund\nSupport: checks the order" },
199926
200232
  prompts: ["Which parts of this design doc need a diagram?", "Add pictures to this Confluence page.", "Plan the diagrams for our onboarding guide."],
199927
200233
  execute: planDocumentDiagrams
199928
200234
  });
@@ -199946,6 +200252,10 @@ var init_suggest_diagram = __esm({
199946
200252
  name: "suggest_diagram",
199947
200253
  title: "Suggest diagram",
199948
200254
  description: 'Workflow. Picks the kind of diagram for a request in plain words, such as "permission matrix for these endpoints and roles" or "where our cloud spend goes", with optional pasted data (a table, a list, numbers by period). Returns up to 3 kinds, best first, each with a one-sentence reason, a confidence, the statements to use, and a short starter source that parses, built from the names and numbers in the request and data. Call it when you are unsure which kind fits, then edit the starter and call draw_diagram. Replaces reading every kind in get_diagram_syntax to choose one.',
200255
+ compact: {
200256
+ description: "Ranks the diagram kinds for a request in plain words, with a starter source for each that already parses. Call it first when unsure which kind fits, then pass the starter to draw_diagram.",
200257
+ inputs: { request: "What the picture is for, in plain words.", data: "Optional table, list, or notes to draw from." }
200258
+ },
199949
200259
  input: SuggestDiagramInputSchema,
199950
200260
  output: SuggestDiagramResponseSchema,
199951
200261
  steps: [{ call: "parse", optional: true }],
@@ -199974,6 +200284,10 @@ var init_sync_markdown3 = __esm({
199974
200284
  name: "sync_markdown",
199975
200285
  title: "Sync Markdown",
199976
200286
  description: `Workflow. Turns the diagram fences of a Markdown document into pictures, as data. Send the whole document and its path. Returns the rewritten document (each fence folded into a "Diagram source" section with the picture and a text description, the rest byte for byte unchanged), the light and dark SVG files to write (paths from the repository root), and a report per fence with errors at lines of your document. convertMermaid true first turns each convertible mermaid fence into a diagram fence; one that cannot convert or has errors is left as it was and reported. Then write markdown to documentPath and each file to its path, and review the diff. mode "check" only reports. The SVGs can be large: files "none" returns each file's path, bytes, sha256, and viewUrl instead, and page with pageSize returns the files a page at a time. Writes no file itself. Limits: ${WORKFLOW_LIMITS.maxMarkdownLength} characters, ${WORKFLOW_LIMITS.maxDiagrams} diagrams, ${WORKFLOW_LIMITS.maxOutputBytes} bytes of output; caps says when one stopped work. Replaces the convert, validate, render and sync steps for every fence in a document.`,
200287
+ compact: {
200288
+ description: "Draws every diagram fence of a Markdown document: returns the rewritten document and the SVG files to write. convertMermaid true also turns mermaid fences into diagram fences first.",
200289
+ inputs: { convertMermaid: "", mode: "sync writes; check only reports stale pictures.", files: "inline returns each SVG; none keeps the answer small." }
200290
+ },
199977
200291
  input: SyncMarkdownInputSchema,
199978
200292
  output: SyncMarkdownResponseSchema,
199979
200293
  steps: [{ call: "convertMermaidFences", optional: true }, { call: "renderPair" }],
@@ -200034,83 +200348,66 @@ var init_workflows2 = __esm({
200034
200348
  }
200035
200349
  });
200036
200350
 
200037
- // ../../packages/diagrams/src/tools/json-schema.ts
200038
- function referencedDefs(node3) {
200039
- return [...JSON.stringify(node3).matchAll(DEF_REF)].map((match) => match[1] ?? "");
200040
- }
200041
- function reachableDefs(root, defs) {
200042
- const reached = /* @__PURE__ */ new Set();
200043
- const pending = referencedDefs(root);
200044
- for (let name2 = pending.pop(); name2 !== void 0; name2 = pending.pop()) {
200045
- const def = defs[name2];
200046
- if (def === void 0 || reached.has(name2)) continue;
200047
- reached.add(name2);
200048
- pending.push(...referencedDefs(def));
200049
- }
200050
- return Object.fromEntries(Object.entries(defs).filter(([name2]) => reached.has(name2)));
200051
- }
200052
- function inlineRootRef(schema) {
200053
- const ref = schema["$ref"];
200054
- const defs = schema["$defs"];
200055
- if (typeof ref !== "string" || typeof defs !== "object" || defs === null) return schema;
200056
- const target = defs[ref.replace("#/$defs/", "")];
200057
- if (target === void 0) return schema;
200058
- const { $ref: _removed, $defs: _defs, ...header } = schema;
200059
- const root = { ...header, ...target };
200060
- const kept2 = reachableDefs(root, defs);
200061
- return Object.keys(kept2).length === 0 ? root : { ...root, $defs: kept2 };
200062
- }
200063
- function remembered(cache, key, make) {
200064
- const known3 = cache.get(key);
200065
- if (known3 !== void 0) return known3;
200066
- const made = make();
200067
- cache.set(key, made);
200068
- return made;
200069
- }
200070
- function inputJsonSchema(tool) {
200071
- return remembered(inputSchemas, tool.inputSchema, () => withoutSafeBounds(inlineRootRef(external_exports.toJSONSchema(tool.inputSchema, { target: TARGET2, io: "input" }))));
200072
- }
200073
- function withoutSafeBounds(node3) {
200074
- if (Array.isArray(node3)) return node3.map(withoutSafeBounds);
200075
- if (typeof node3 !== "object" || node3 === null) return node3;
200076
- return Object.fromEntries(
200077
- Object.entries(node3).filter(([key, value]) => !(key === "minimum" && value === Number.MIN_SAFE_INTEGER || key === "maximum" && value === Number.MAX_SAFE_INTEGER)).map(([key, value]) => [key, withoutSafeBounds(value)])
200078
- );
200079
- }
200080
- function openObjects(node3) {
200081
- if (Array.isArray(node3)) return node3.map(openObjects);
200082
- if (typeof node3 !== "object" || node3 === null) return node3;
200083
- return Object.fromEntries(
200084
- Object.entries(node3).filter(([key, value]) => !(key === "additionalProperties" && value === false)).map(([key, value]) => [key, openObjects(value)])
200085
- );
200351
+ // ../../packages/diagrams/src/tools/profiles.ts
200352
+ function readToolProfile(value) {
200353
+ const name2 = value?.trim().toLowerCase() ?? "";
200354
+ if (name2 === "") return "full";
200355
+ return TOOL_PROFILES.includes(name2) ? name2 : null;
200086
200356
  }
200087
- function outputJsonSchema(tool) {
200088
- return remembered(outputSchemas, tool.outputSchema, () => withoutSafeBounds(openObjects(inlineRootRef(external_exports.toJSONSchema(tool.outputSchema, { target: TARGET2, io: "output" })))));
200357
+ function toolsForProfile(tools2, profile) {
200358
+ if (profile === "full") return tools2;
200359
+ return CORE_TOOLS.flatMap((name2) => tools2.filter((tool) => tool.name === name2));
200089
200360
  }
200090
- function withoutProse(node3, isProperties = false) {
200091
- if (Array.isArray(node3)) return node3.map((item) => withoutProse(item));
200361
+ function withoutProse2(node3, isProperties = false) {
200362
+ if (Array.isArray(node3)) return node3.map((item) => withoutProse2(item));
200092
200363
  if (typeof node3 !== "object" || node3 === null) return node3;
200093
200364
  return Object.fromEntries(
200094
- Object.entries(node3).filter(([key]) => isProperties || !LEFT_OUT.has(key)).map(([key, value]) => [key, withoutProse(value, !isProperties && (key === "properties" || key === "$defs"))])
200365
+ Object.entries(node3).filter(([key]) => isProperties || !COMPACT_LEFT_OUT.has(key)).map(([key, value]) => [key, withoutProse2(value, !isProperties && (key === "properties" || key === "$defs"))])
200095
200366
  );
200096
200367
  }
200097
- function listedOutputSchema(schema) {
200098
- return remembered(listedSchemas, schema, () => withoutProse(withoutSafeBounds(schema)));
200368
+ function compactInputJsonSchema(tool) {
200369
+ const known3 = compactSchemas.get(tool);
200370
+ if (known3 !== void 0) return known3;
200371
+ const full = inputJsonSchema(tool);
200372
+ const properties = full["properties"] ?? {};
200373
+ const required2 = Array.isArray(full["required"]) ? full["required"] : [];
200374
+ const described2 = tool.compact?.inputs ?? {};
200375
+ const kept2 = Object.keys(properties).filter((key) => required2.includes(key) || Object.hasOwn(described2, key));
200376
+ const schema = {
200377
+ type: "object",
200378
+ properties: Object.fromEntries(
200379
+ kept2.map((key) => {
200380
+ const field = withoutProse2(properties[key]);
200381
+ const text3 = described2[key];
200382
+ return [key, text3 === void 0 || text3 === "" ? field : { ...field, description: text3 }];
200383
+ })
200384
+ ),
200385
+ ...required2.length > 0 ? { required: required2 } : {},
200386
+ ..."additionalProperties" in full ? { additionalProperties: full["additionalProperties"] } : {}
200387
+ };
200388
+ compactSchemas.set(tool, schema);
200389
+ return schema;
200099
200390
  }
200100
- function listedOutputJsonSchema(tool) {
200101
- return listedOutputSchema(outputJsonSchema(tool));
200391
+ function listedFor(tool, profile) {
200392
+ if (profile === "core" && tool.compact !== null) return { description: tool.compact.description, inputSchema: compactInputJsonSchema(tool), withOutputSchema: false };
200393
+ return { description: tool.description, inputSchema: inputJsonSchema(tool), withOutputSchema: true };
200102
200394
  }
200103
- var TARGET2, DEF_REF, inputSchemas, outputSchemas, listedSchemas, LEFT_OUT;
200104
- var init_json_schema2 = __esm({
200105
- "../../packages/diagrams/src/tools/json-schema.ts"() {
200395
+ var TOOL_PROFILES, CORE_TOOLS, CORE_INSTRUCTIONS, COMPACT_LEFT_OUT, compactSchemas;
200396
+ var init_profiles = __esm({
200397
+ "../../packages/diagrams/src/tools/profiles.ts"() {
200106
200398
  "use strict";
200107
- init_zod();
200108
- TARGET2 = "draft-2020-12";
200109
- DEF_REF = /"\$ref":"#\/\$defs\/([^"]+)"/g;
200110
- inputSchemas = /* @__PURE__ */ new WeakMap();
200111
- outputSchemas = /* @__PURE__ */ new WeakMap();
200112
- listedSchemas = /* @__PURE__ */ new WeakMap();
200113
- LEFT_OUT = /* @__PURE__ */ new Set(["description", "$schema", "title", "enum"]);
200399
+ init_json_schema2();
200400
+ TOOL_PROFILES = ["full", "core"];
200401
+ CORE_TOOLS = ["suggest_diagram", "get_diagram_syntax", "draw_diagram", "edit_diagram", "import_source", "convert_mermaid", "sync_markdown", "map_icons"];
200402
+ CORE_INSTRUCTIONS = [
200403
+ "Draws flow, sequence, schema, state, class, and other diagrams from a small line-oriented text language.",
200404
+ 'To draw: if unsure which kind fits, call suggest_diagram; call get_diagram_syntax once with kind set to the kind you draw; write the source and call draw_diagram with svg "never" to check it, fix every error by its line, column, and hint, and call again until it is valid; call draw_diagram with svg "always" only when the SVG will be saved.',
200405
+ "To change a diagram, call edit_diagram. From a file (SQL, OpenAPI, Terraform, docker-compose, Kubernetes, CSV, and more), call import_source; from Mermaid, convert_mermaid; for every diagram fence of a Markdown file, sync_markdown.",
200406
+ "Save or hand over only source that a tool has said is valid, and check it again with draw_diagram after any change.",
200407
+ "Use map_icons for icon names and never invent one. Pass the arguments as one JSON object with the fields at the top level."
200408
+ ].join(" ");
200409
+ COMPACT_LEFT_OUT = /* @__PURE__ */ new Set(["description", "$schema", "title", "default", "examples", "minLength", "maxLength", "minItems", "maxItems", "pattern", "propertyNames"]);
200410
+ compactSchemas = /* @__PURE__ */ new WeakMap();
200114
200411
  }
200115
200412
  });
200116
200413
 
@@ -200290,6 +200587,8 @@ var init_tools = __esm({
200290
200587
  init_compare_diagrams3();
200291
200588
  init_workflows2();
200292
200589
  init_define_tool();
200590
+ init_input_hint();
200591
+ init_profiles();
200293
200592
  init_json_schema2();
200294
200593
  init_fit_answer();
200295
200594
  init_layout_tools();
@@ -200699,7 +200998,8 @@ function failureLines(failure3) {
200699
200998
  (diagnostic) => `${diagnostic.code} at line ${diagnostic.line}, column ${diagnostic.column}: ${diagnostic.message}${diagnostic.hint === null ? "" : ` (${diagnostic.hint})`}`
200700
200999
  );
200701
201000
  }
200702
- return failure3.issues.map((issue3) => `${issue3.path === "" ? "arguments" : issue3.path}: ${issue3.message}`);
201001
+ const issues = failure3.issues.map((issue3) => `${issue3.path === "" ? "arguments" : issue3.path}: ${issue3.message}`);
201002
+ return failure3.hint === void 0 || failure3.hint === "" ? issues : [...issues, failure3.hint];
200703
201003
  }
200704
201004
  function toCallToolResult(outcome) {
200705
201005
  if (outcome.ok) {
@@ -200958,6 +201258,11 @@ async function callTool(tool, args, log, caller, activity, run3, budget2, answer
200958
201258
  const started = performance.now();
200959
201259
  const inputBytes = inputSize(args);
200960
201260
  try {
201261
+ const refused4 = checkToolInput(tool, args);
201262
+ if (refused4 !== null) {
201263
+ logToolCall({ tool: tool.name, outcome: refused4.kind, durationMs: performance.now() - started, inputBytes, caller }, log);
201264
+ return toCallToolResult({ ok: false, error: refused4 });
201265
+ }
200961
201266
  const ran = await run3(tool, args);
200962
201267
  const linked = !ran.ok ? null : answers2.viewLinks === false ? stripViewLinks(ran.value) : await attachViewUrl(tool.name, args, ran.value, answers2.viewBase);
200963
201268
  const saving = linked === null || answers2.library === void 0 || answers2.library === null ? linked : withSaveStep(tool.name, linked, answers2.library);
@@ -200995,6 +201300,14 @@ async function callHostedTool(tool, args, log, caller) {
200995
201300
  return internalErrorResult();
200996
201301
  }
200997
201302
  }
201303
+ function listedInput(schema) {
201304
+ let wrapper = listedInputs.get(schema);
201305
+ if (wrapper === void 0) {
201306
+ wrapper = { "~standard": { version: 1, vendor: "plotwork", jsonSchema: { input: () => schema, output: () => schema }, validate: (value) => ({ value }) } };
201307
+ listedInputs.set(schema, wrapper);
201308
+ }
201309
+ return wrapper;
201310
+ }
200998
201311
  function wrapped(schema, validator) {
200999
201312
  const key = validator ?? DEFAULT_VALIDATOR2;
201000
201313
  let bySchema = wrappers2.get(key);
@@ -201009,14 +201322,15 @@ function wrapped(schema, validator) {
201009
201322
  }
201010
201323
  return wrapper;
201011
201324
  }
201012
- function createDiagramsServer(options3 = {}, log = logToConsole, caller, hostedTools = [], activity, run3 = runInPlace, budget2 = ANSWER_BUDGET_CHARACTERS, answers2 = {}) {
201325
+ function createDiagramsServer(options3 = {}, log = logToConsole, caller, hostedTools = [], activity, run3 = runInPlace, budget2 = ANSWER_BUDGET_CHARACTERS, answers2 = {}, profile = "full") {
201013
201326
  const finish = { ...answers2, viewBase: answers2.viewBase ?? viewBaseFor() };
201014
201327
  const taken = new Set(TOOLS.map((tool) => tool.name));
201015
201328
  for (const tool of hostedTools) {
201016
201329
  if (taken.has(tool.name)) throw new TypeError(`A tool named ${tool.name} is already registered`);
201017
201330
  taken.add(tool.name);
201018
201331
  }
201019
- const hosted = hostedTools.length === 0 ? SERVER_INSTRUCTIONS : `${SERVER_INSTRUCTIONS} ${HOSTED_INSTRUCTIONS}`;
201332
+ const base = profile === "core" ? CORE_INSTRUCTIONS : SERVER_INSTRUCTIONS;
201333
+ const hosted = hostedTools.length === 0 ? base : `${base} ${HOSTED_INSTRUCTIONS}`;
201020
201334
  const instructions = hostedTools.length > 0 && answers2.library !== void 0 && answers2.library !== null ? `${hosted} ${libraryInstructions(answers2.library)}` : hosted;
201021
201335
  const server = new McpServer(SERVER_INFO, { instructions, ...options3 });
201022
201336
  for (const tool of hostedTools) {
@@ -201032,14 +201346,15 @@ function createDiagramsServer(options3 = {}, log = logToConsole, caller, hostedT
201032
201346
  (args) => callHostedTool(tool, args, log, caller)
201033
201347
  );
201034
201348
  }
201035
- for (const tool of TOOLS) {
201349
+ for (const tool of toolsForProfile(TOOLS, profile)) {
201350
+ const listed2 = listedFor(tool, profile);
201036
201351
  server.registerTool(
201037
201352
  tool.name,
201038
201353
  {
201039
201354
  title: tool.title,
201040
- description: tool.description,
201041
- inputSchema: wrapped(inputJsonSchema(tool), options3.jsonSchemaValidator),
201042
- outputSchema: wrapped(listedOutputJsonSchema(tool), options3.jsonSchemaValidator),
201355
+ description: listed2.description,
201356
+ inputSchema: listedInput(listed2.inputSchema),
201357
+ ...listed2.withOutputSchema ? { outputSchema: wrapped(listedOutputJsonSchema(tool), options3.jsonSchemaValidator) } : {},
201043
201358
  annotations: tool.annotations,
201044
201359
  ...VIEWER_APP_TOOLS.includes(tool.name) ? { _meta: VIEWER_APP_TOOL_META } : {}
201045
201360
  },
@@ -201052,7 +201367,7 @@ function createDiagramsServer(options3 = {}, log = logToConsole, caller, hostedT
201052
201367
  registerDiagramPrompts(server, options3.jsonSchemaValidator);
201053
201368
  return server;
201054
201369
  }
201055
- var SAVABLE_TOOLS, DEFAULT_VALIDATOR2, wrappers2;
201370
+ var SAVABLE_TOOLS, listedInputs, DEFAULT_VALIDATOR2, wrappers2;
201056
201371
  var init_create_server = __esm({
201057
201372
  "src/create-server.ts"() {
201058
201373
  "use strict";
@@ -201067,6 +201382,7 @@ var init_create_server = __esm({
201067
201382
  init_tool_result();
201068
201383
  init_viewer_app();
201069
201384
  SAVABLE_TOOLS = new Set(VIEW_LINK_TOOLS.filter((name2) => name2 !== "sync_markdown"));
201385
+ listedInputs = /* @__PURE__ */ new WeakMap();
201070
201386
  DEFAULT_VALIDATOR2 = {};
201071
201387
  wrappers2 = /* @__PURE__ */ new WeakMap();
201072
201388
  }
@@ -201507,6 +201823,22 @@ var init_start = __esm({
201507
201823
  }
201508
201824
  });
201509
201825
 
201826
+ // src/tool-profile.ts
201827
+ function chooseToolProfile(env, argv) {
201828
+ const flagAt = argv.findIndex((arg) => arg === "--tools" || arg.startsWith("--tools="));
201829
+ const flag = flagAt === -1 ? void 0 : argv[flagAt]?.startsWith("--tools=") === true ? argv[flagAt]?.slice("--tools=".length) : argv[flagAt + 1];
201830
+ const asked = flag ?? env["PLOTWORK_TOOLS"];
201831
+ const profile = readToolProfile(asked);
201832
+ if (profile !== null) return { profile, problem: null };
201833
+ return { profile: "full", problem: `Plotwork tool profile "${asked ?? ""}" is not one of ${TOOL_PROFILES.join(", ")}; listing the full set.` };
201834
+ }
201835
+ var init_tool_profile = __esm({
201836
+ "src/tool-profile.ts"() {
201837
+ "use strict";
201838
+ init_tools();
201839
+ }
201840
+ });
201841
+
201510
201842
  // src/viewer-address.ts
201511
201843
  function viewerAddress(env = {}) {
201512
201844
  const raw = env[VIEWER_URL_VARIABLE]?.trim();
@@ -201529,7 +201861,7 @@ var init_viewer_address = __esm({
201529
201861
 
201530
201862
  // src/stdio.ts
201531
201863
  var stdio_exports = {};
201532
- var usage, budget, answers, local;
201864
+ var usage, budget, answers, local, tools;
201533
201865
  var init_stdio2 = __esm({
201534
201866
  "src/stdio.ts"() {
201535
201867
  "use strict";
@@ -201543,6 +201875,7 @@ var init_stdio2 = __esm({
201543
201875
  init_local_open();
201544
201876
  init_local_settings();
201545
201877
  init_start();
201878
+ init_tool_profile();
201546
201879
  init_viewer_address();
201547
201880
  useIconArtFolder(iconArtFolder());
201548
201881
  usage = startLocalUsage();
@@ -201551,7 +201884,9 @@ var init_stdio2 = __esm({
201551
201884
  local = readLocalSettings(process.cwd(), process.env);
201552
201885
  if (local.problem !== null) console.error(`Plotwork settings in ${local.path ?? ""} were not applied:
201553
201886
  ${local.problem}`);
201554
- serveStdio(() => createDiagramsServer({}, logToStderr, void 0, [], usage.sink, withLocalSettings(runLocally, local.settings), budget, answers));
201887
+ tools = chooseToolProfile(process.env, process.argv.slice(2));
201888
+ if (tools.problem !== null) console.error(tools.problem);
201889
+ serveStdio(() => createDiagramsServer({}, logToStderr, void 0, [], usage.sink, withLocalSettings(runLocally, local.settings), budget, answers, tools.profile));
201555
201890
  }
201556
201891
  });
201557
201892
 
@@ -201597,6 +201932,10 @@ Usage
201597
201932
  ${BIN} --version Print the version and exit.
201598
201933
  ${BIN} --help Print this text and exit.
201599
201934
 
201935
+ Tool profile
201936
+ ${BIN} --tools core List only the eight workflow tools, with short descriptions, for an open
201937
+ or self-hosted model with a small context. PLOTWORK_TOOLS=core does the same.
201938
+
201600
201939
  Usage counts (off unless you turn them on)
201601
201940
  PLOTWORK_USAGE=local Count calls on this device, in one file. Nothing is sent.
201602
201941
  PLOTWORK_USAGE=share Also send pseudonymous daily totals to Plotwork: tool, diagram kind,
@@ -201627,7 +201966,7 @@ async function main(args) {
201627
201966
  process.stdout.write(HELP);
201628
201967
  return;
201629
201968
  }
201630
- if (first !== void 0 && first !== "usage") {
201969
+ if (first !== void 0 && first !== "usage" && first !== "--tools" && !first.startsWith("--tools=")) {
201631
201970
  process.stderr.write(`${BIN}: unknown argument "${first}". Run ${BIN} --help.
201632
201971
  `);
201633
201972
  process.exitCode = 2;