schematex 0.5.0 → 0.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. package/README.md +15 -7
  2. package/dist/ai/ai-sdk.cjs +18 -12
  3. package/dist/ai/ai-sdk.cjs.map +1 -1
  4. package/dist/ai/ai-sdk.d.cts +4 -3
  5. package/dist/ai/ai-sdk.d.ts +4 -3
  6. package/dist/ai/ai-sdk.js +14 -8
  7. package/dist/ai/ai-sdk.js.map +1 -1
  8. package/dist/ai/index.cjs +15 -11
  9. package/dist/ai/index.d.cts +20 -153
  10. package/dist/ai/index.d.ts +20 -153
  11. package/dist/ai/index.js +3 -3
  12. package/dist/api-C5SECOxZ.d.cts +69 -0
  13. package/dist/api-Cr_MxttI.d.ts +69 -0
  14. package/dist/browser.cjs +23 -5
  15. package/dist/browser.cjs.map +1 -1
  16. package/dist/browser.d.cts +12 -3
  17. package/dist/browser.d.ts +12 -3
  18. package/dist/browser.js +13 -5
  19. package/dist/browser.js.map +1 -1
  20. package/dist/{chunk-3YUUC6RN.cjs → chunk-4QPDZJAL.cjs} +1421 -37
  21. package/dist/chunk-4QPDZJAL.cjs.map +1 -0
  22. package/dist/{chunk-NWPCY65Z.cjs → chunk-HK56GQQP.cjs} +544 -61
  23. package/dist/chunk-HK56GQQP.cjs.map +1 -0
  24. package/dist/{chunk-GTDQAN2Z.js → chunk-OK5ZS3LU.js} +1419 -38
  25. package/dist/chunk-OK5ZS3LU.js.map +1 -0
  26. package/dist/{chunk-XRCY75UV.cjs → chunk-QMTWG6JL.cjs} +947 -916
  27. package/dist/chunk-QMTWG6JL.cjs.map +1 -0
  28. package/dist/{chunk-HUPDIRBX.js → chunk-VCH7RI5H.js} +947 -916
  29. package/dist/chunk-VCH7RI5H.js.map +1 -0
  30. package/dist/{chunk-IM4RCUHA.js → chunk-VKPCR7BG.js} +544 -62
  31. package/dist/chunk-VKPCR7BG.js.map +1 -0
  32. package/dist/diagrams/blockdiagram/index.d.cts +1 -1
  33. package/dist/diagrams/blockdiagram/index.d.ts +1 -1
  34. package/dist/diagrams/circuit/index.cjs +7 -7
  35. package/dist/diagrams/circuit/index.d.cts +1 -1
  36. package/dist/diagrams/circuit/index.d.ts +1 -1
  37. package/dist/diagrams/circuit/index.js +1 -1
  38. package/dist/diagrams/ecomap/index.d.cts +1 -1
  39. package/dist/diagrams/ecomap/index.d.ts +1 -1
  40. package/dist/diagrams/entity/index.d.cts +1 -1
  41. package/dist/diagrams/entity/index.d.ts +1 -1
  42. package/dist/diagrams/fishbone/index.d.cts +1 -1
  43. package/dist/diagrams/fishbone/index.d.ts +1 -1
  44. package/dist/diagrams/flowchart/index.d.cts +2 -2
  45. package/dist/diagrams/flowchart/index.d.ts +2 -2
  46. package/dist/diagrams/genogram/index.d.cts +1 -1
  47. package/dist/diagrams/genogram/index.d.ts +1 -1
  48. package/dist/diagrams/ladder/index.d.cts +1 -1
  49. package/dist/diagrams/ladder/index.d.ts +1 -1
  50. package/dist/diagrams/logic/index.d.cts +1 -1
  51. package/dist/diagrams/logic/index.d.ts +1 -1
  52. package/dist/diagrams/orgchart/index.d.cts +1 -1
  53. package/dist/diagrams/orgchart/index.d.ts +1 -1
  54. package/dist/diagrams/pedigree/index.d.cts +1 -1
  55. package/dist/diagrams/pedigree/index.d.ts +1 -1
  56. package/dist/diagrams/phylo/index.d.cts +1 -1
  57. package/dist/diagrams/phylo/index.d.ts +1 -1
  58. package/dist/diagrams/sld/index.d.cts +1 -1
  59. package/dist/diagrams/sld/index.d.ts +1 -1
  60. package/dist/diagrams/sociogram/index.d.cts +1 -1
  61. package/dist/diagrams/sociogram/index.d.ts +1 -1
  62. package/dist/diagrams/timing/index.d.cts +1 -1
  63. package/dist/diagrams/timing/index.d.ts +1 -1
  64. package/dist/diagrams/venn/index.d.cts +1 -1
  65. package/dist/diagrams/venn/index.d.ts +1 -1
  66. package/dist/{index-C9A0h-CB.d.cts → index-BD2yDfQM.d.cts} +1 -1
  67. package/dist/{index-CJai_TEZ.d.ts → index-C30zQWZI.d.ts} +1 -1
  68. package/dist/index.cjs +24 -12
  69. package/dist/index.d.cts +3 -3
  70. package/dist/index.d.ts +3 -3
  71. package/dist/index.js +2 -2
  72. package/dist/react.cjs +7 -9
  73. package/dist/react.cjs.map +1 -1
  74. package/dist/react.d.cts +3 -2
  75. package/dist/react.d.ts +3 -2
  76. package/dist/react.js +7 -9
  77. package/dist/react.js.map +1 -1
  78. package/dist/tools-BHWaJPOl.d.ts +153 -0
  79. package/dist/tools-DlpuE76u.d.cts +153 -0
  80. package/dist/{types-BOAsqHoU.d.cts → types-WTr9W5Ud.d.cts} +2 -2
  81. package/dist/{types-BOAsqHoU.d.ts → types-WTr9W5Ud.d.ts} +2 -2
  82. package/package.json +2 -2
  83. package/dist/api-C5UcmT7n.d.cts +0 -22
  84. package/dist/api-C5UcmT7n.d.ts +0 -22
  85. package/dist/chunk-3YUUC6RN.cjs.map +0 -1
  86. package/dist/chunk-GTDQAN2Z.js.map +0 -1
  87. package/dist/chunk-HUPDIRBX.js.map +0 -1
  88. package/dist/chunk-IM4RCUHA.js.map +0 -1
  89. package/dist/chunk-NWPCY65Z.cjs.map +0 -1
  90. package/dist/chunk-XRCY75UV.cjs.map +0 -1
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var chunk3YUUC6RN_cjs = require('./chunk-3YUUC6RN.cjs');
3
+ var chunk4QPDZJAL_cjs = require('./chunk-4QPDZJAL.cjs');
4
4
 
5
5
  // src/ai/registry.ts
6
6
  var DIAGRAM_REGISTRY = [
@@ -217,6 +217,15 @@ var DIAGRAM_REGISTRY = [
217
217
  standard: "OMG UML 2.5.1 \xA718 visual subset; see 29-USECASE-STANDARD.md",
218
218
  syntaxKey: "usecase"
219
219
  },
220
+ {
221
+ type: "sequence",
222
+ name: "UML sequence diagram",
223
+ tagline: "UML 2.5.1 \xA717 interaction \u2014 lifelines, messages over time, activations, and combined fragments.",
224
+ useWhen: "Use for time-ordered interactions between participants \u2014 API call flows, auth handshakes, distributed protocols, object collaborations, 'who calls whom in what order'. Lifelines run top\u2192bottom; messages run left\u2192right: `->` synchronous (filled head), `->>` asynchronous (open head), `-->` reply (dashed), `-x` lost, `o->` found. `+`/`-` suffixes open/close activation bars; `*Target` creates a participant and `destroy` ends one. All twelve UML combined fragments \u2014 `alt`/`opt`/`loop`/`par`/`break`/`critical`/`seq`/`strict`/`neg`/`ignore`/`consider`/`assert` \u2014 plus `ref` interaction-use frames. Participant kinds `actor`/`boundary`/`control`/`entity`/`database` render their UML/Jacobson symbols; `\xABstereotype\xBB` overrides the label. Distinct from `usecase` (system scope, not message order), `state` (one object's modes, not inter-object messages), `bpmn` (organisational process), and `flowchart` (no lifelines/time axis).",
225
+ cluster: "behavior-modeling",
226
+ standard: "OMG UML 2.5.1 \xA717 (Interactions); see 33-SEQUENCE-STANDARD.md",
227
+ syntaxKey: "sequence"
228
+ },
220
229
  // ── Research / evidence synthesis ────────────────────────────
221
230
  {
222
231
  type: "prisma",
@@ -286,46 +295,26 @@ var DIAGRAM_REGISTRY = [
286
295
  syntaxKey: "timeline"
287
296
  }
288
297
  ];
298
+ var TYPE_ALIASES = {
299
+ block: "blockdiagram",
300
+ "entity-structure": "entity",
301
+ graph: "flowchart",
302
+ statediagram: "state",
303
+ "statediagram-v2": "state",
304
+ sequencediagram: "sequence"
305
+ };
306
+ function resolveDiagramType(type) {
307
+ const normalized = type.trim().toLowerCase();
308
+ return DIAGRAM_REGISTRY.find((d) => d.type === normalized)?.type ?? TYPE_ALIASES[normalized];
309
+ }
289
310
  function getDiagramMeta(type) {
290
- return DIAGRAM_REGISTRY.find((d) => d.type === type);
311
+ const resolved = resolveDiagramType(type);
312
+ return DIAGRAM_REGISTRY.find((d) => d.type === resolved);
291
313
  }
292
314
  function getAllDiagramTypes() {
293
315
  return DIAGRAM_REGISTRY.map((d) => d.type);
294
316
  }
295
317
 
296
- // src/ai/errors.ts
297
- var ENGINE_BUG_NAMES = /* @__PURE__ */ new Set([
298
- "ReferenceError",
299
- "TypeError",
300
- "RangeError"
301
- ]);
302
- function extractError(err) {
303
- if (err instanceof Error) {
304
- const anyErr = err;
305
- const hasParseFields = typeof anyErr.line === "number";
306
- const isEngineBug = !hasParseFields && ENGINE_BUG_NAMES.has(err.name);
307
- const sourceHint = isEngineBug ? firstStackFrame(err.stack) : typeof anyErr.source === "string" ? anyErr.source : void 0;
308
- return {
309
- line: typeof anyErr.line === "number" ? anyErr.line : void 0,
310
- column: typeof anyErr.column === "number" ? anyErr.column : void 0,
311
- source: sourceHint,
312
- message: isEngineBug ? `[engine bug: ${err.name}] ${err.message}` : err.message,
313
- hint: typeof anyErr.hint === "string" ? anyErr.hint : isEngineBug ? "This looks like a Schematex internal error rather than a DSL syntax problem. Please file an issue with the failing DSL at https://github.com/SchemaTex/Schematex/issues." : void 0
314
- };
315
- }
316
- return { message: String(err) };
317
- }
318
- function firstStackFrame(stack) {
319
- if (!stack) return void 0;
320
- for (const line of stack.split("\n")) {
321
- const trimmed = line.trim();
322
- if (trimmed.startsWith("at ")) {
323
- return trimmed.replace(/\((?:.*\/)?([^/]+)\)/, "($1)");
324
- }
325
- }
326
- return void 0;
327
- }
328
-
329
318
  // src/ai/_generated.ts
330
319
  var EXAMPLES = [
331
320
  {
@@ -1251,6 +1240,56 @@ If the LED doesn't light up, three things to check, in order: LED polarity (the
1251
1240
  "dsl": 'phylo "Bacterial Diversity"\n newick: "((((Ecoli:0.1,Salmonella:0.12):0.05[&&NHX:B=98],Vibrio:0.2):0.08[&&NHX:B=85],((Bacillus:0.15,Staph:0.18):0.06[&&NHX:B=92],Listeria:0.22):0.1):0.15,((Myco_tb:0.3,Myco_leprae:0.28):0.12[&&NHX:B=100],(Strepto:0.25,Lactobacillus:0.2):0.08[&&NHX:B=78]):0.2);"\n clade Gamma = (Ecoli, Salmonella, Vibrio) [color: "#1E88E5", label: "\u03B3-Proteobacteria"]\n clade Firmi = (Bacillus, Staph, Listeria, Strepto, Lactobacillus) [color: "#E53935", label: "Firmicutes"]\n clade Actino = (Myco_tb, Myco_leprae) [color: "#43A047", label: "Actinobacteria"]\n scale "substitutions/site"',
1252
1241
  "notes": '## Scenario\n\nA microbiologist or bioinformatician pastes a Newick tree string exported from RAxML, IQ-TREE, or MEGA and immediately gets a publication-ready SVG with clade highlights and a branch-length scale bar \u2014 no manual layout required.\n\n## Annotation key\n\n- `newick: "..."` \u2014 standard Newick format tree string; branch lengths follow `:` after each taxon name\n- `[&&NHX:B=98]` \u2014 NHX annotation; `B=` is the bootstrap support value (0\u2013100), rendered on internal nodes\n- `clade id = (taxon, ...)` \u2014 defines a named clade by listing its leaf members\n- `[color: "#hex", label: "..."]` \u2014 colors the clade\'s subtree and adds a labeled arc\n- `scale "..."` \u2014 draws a calibrated scale bar with the given unit label\n\n## How to read\n\nThe tree shows three major bacterial clades. Blue (\u03B3-Proteobacteria): *E. coli*, *Salmonella*, and *Vibrio* cluster with 98% bootstrap support. Red (Firmicutes): *Bacillus*, *Staph*, *Listeria*, *Streptococcus*, and *Lactobacillus*. Green (Actinobacteria): the two *Mycobacterium* species form a highly supported clade (bootstrap 100). Branch lengths represent substitutions per site \u2014 longer branches indicate faster evolutionary rates.'
1253
1242
  },
1243
+ {
1244
+ "slug": "pid-pump-flow-control",
1245
+ "diagram": "pid",
1246
+ "title": "Pump with flow control loop (P&ID)",
1247
+ "description": "Classic centrifugal pump pulling from an atmospheric tank, with a flow transmitter (FT-101), flow indicating controller (FIC-101), and a fail-closed pneumatic control valve \u2014 the minimum viable P&ID that every process engineer recognises at a glance.",
1248
+ "standard": "ANSI/ISA-5.1-2009 + ISO 10628-1:2014",
1249
+ "tags": [
1250
+ "pid",
1251
+ "isa-5.1",
1252
+ "flow-control",
1253
+ "centrifugal-pump",
1254
+ "control-valve",
1255
+ "instrument-loop"
1256
+ ],
1257
+ "complexity": 1,
1258
+ "featured": true,
1259
+ "dsl": 'pid "Water Pump Flow Control"\n\nequip T-101 : tank_atm [tag: "Feed Tank"]\nequip P-101 : pump_centrifugal [tag: "Feed Pump"]\nequip V-101 : valve_control [actuator: "diaphragm", fail: "FC"]\nequip V-100 : valve_gate [tag: "Isolation"]\n\nline L1 from T-101.bottom to P-101.in [size: "4\\"", service: "water", type: "process"]\nline L2 from P-101.out to V-101.in [size: "4\\"", service: "water", type: "process"]\nline L3 from V-101.out to dest [size: "4\\"", type: "process"]\n\ninst FT-101 : field_discrete\n measures L2\ninst FIC-101 : cr_shared\n controls V-101\n\nline s1 from FT-101 to FIC-101 [type: "electric"]\nline s2 from FIC-101 to V-101 [type: "pneumatic"]',
1260
+ "notes": 'The pump-with-flow-control loop is to P&ID what the "hello world" program is to software: every process engineer has drawn one, every piping textbook uses it as chapter one, and once you understand it you understand the grammar of every more complex diagram.\n\n**What the diagram shows.** T-101 is an atmospheric tank (dome-roof symbol, open to atmosphere). The centrifugal pump P-101 pulls fluid from the bottom nozzle and pushes it downstream through a 4-inch water service line. The flow transmitter FT-101 \u2014 a field-mounted discrete instrument, drawn as a plain circle per ISA-5.1 \xA74.1 \u2014 sits on the discharge line L2 and measures the volumetric flow rate. Its 4\u201320 mA electric signal travels to FIC-101, the flow indicating controller in the main control room (drawn as a circle with a horizontal line through it, indicating it is panel-mounted and has a display). FIC-101 computes the error between the setpoint and the measured flow and drives V-101, a diaphragm-actuated control valve, open or closed via a pneumatic signal. V-100 is a manual gate valve upstream \u2014 the isolation valve you close when you need to pull the pump for maintenance.\n\n**ISA-5.1 signal line types.** The two non-process lines in this diagram are drawn differently from the main pipe: the electric signal between FT-101 and FIC-101 is a dashed line (`stroke-dasharray: 6 4`), and the pneumatic signal between FIC-101 and V-101 is a solid line with small perpendicular slash marks at regular intervals. These are not stylistic choices \u2014 they are ISA-5.1 \xA75.2 mandatory line type codes. An instrument technician reading the diagram needs to know, at a glance, whether a run of wire failed or an air supply pressure dropped. The line type tells them which.\n\n**Fail-safe position.** V-101 is marked `fail: "FC"` \u2014 fail-closed. When the air supply to the diaphragm actuator is lost (instrument air header trips, tubing rupture), the spring return pushes the valve shut. This is the correct failure mode for a pump discharge valve: loss of control should stop flow, not open it fully. If this were a cooling-water valve on a reactor, you\'d want fail-open instead. The choice of fail position is one of the first decisions in a safety instrumented system review (HAZOP, SIL assessment) and it belongs on the P&ID from day one.\n\n**Why not draw.io.** Process engineers currently draw P&IDs in AutoCAD P&ID, SmartPlant P&ID, or draw.io with stencil libraries \u2014 all of which require manual symbol placement and wiring. The Schematex DSL lets you describe the topology and generate a standards-compliant SVG. This is particularly useful when a process is described in prose (from a process description document or a licensor\'s PFD) and needs to be turned into a P&ID for HAZOP review \u2014 the conversion becomes a text transformation task that LLMs can assist with, producing a reviewable first draft rather than a blank canvas.'
1261
+ },
1262
+ {
1263
+ "slug": "pid-reactor-feed-system",
1264
+ "diagram": "pid",
1265
+ "title": "Reactor feed with multi-loop control and pressure safety (P&ID)",
1266
+ "description": "CSTR reactor system with centrifugal pump, shell-and-tube pre-heater, flow control on the feed line, temperature control on the product outlet, and a PSHH pressure switch interlock \u2014 four instrument loops in one diagram, covering the core vocabulary of ISA-5.1 P&ID engineering.",
1267
+ "standard": "ANSI/ISA-5.1-2009 + ISO 10628-1:2014",
1268
+ "tags": [
1269
+ "pid",
1270
+ "isa-5.1",
1271
+ "reactor",
1272
+ "heat-exchanger",
1273
+ "multi-loop",
1274
+ "pshh",
1275
+ "interlock",
1276
+ "safety"
1277
+ ],
1278
+ "complexity": 3,
1279
+ "featured": false,
1280
+ "dsl": 'pid "High-Pressure Reactor Feed"\n\nequip T-201 : tank_atm [tag: "Raw Material Tank"]\nequip P-201 : pump_centrifugal [tag: "Feed Pump P-201A/B"]\nequip E-201 : hx_shell_tube [tag: "Feed Pre-heater"]\nequip R-201 : reactor_cstr [tag: "Reactor R-201"]\nequip V-201 : valve_control [actuator: "diaphragm", fail: "FC"]\nequip V-202 : valve_control [actuator: "diaphragm", fail: "FO"]\nequip V-203 : valve_psv [set_pressure: "150 psig"]\n\nline L1 from T-201.bottom to P-201.in [size: "6\\"", service: "feed", type: "process"]\nline L2 from P-201.out to E-201.shell_in [size: "6\\"", service: "feed", type: "process"]\nline L3 from E-201.shell_out to V-201.in [size: "6\\"", service: "feed", type: "process"]\nline L4 from V-201.out to R-201.in [size: "6\\"", service: "feed", type: "process"]\nline L5 from R-201.out to V-202.in [size: "4\\"", service: "product", type: "process"]\n\ninst FT-201 : field_discrete\n measures L2\ninst FIC-201 : cr_shared\n controls V-201\n\ninst TT-201 : field_discrete\n measures R-201\ninst TIC-201 : cr_shared\n controls V-202\n\ninst PT-201 : field_discrete\n measures R-201\ninst PSHH-201 : field_discrete\n measures R-201\n\nline s1 from FT-201 to FIC-201 [type: "electric"]\nline s2 from FIC-201 to V-201 [type: "pneumatic"]\nline s3 from TT-201 to TIC-201 [type: "electric"]\nline s4 from TIC-201 to V-202 [type: "pneumatic"]\nline s5 from PT-201 to PSHH-201 [type: "electric"]',
1281
+ "notes": `Real process plants don't have one control loop \u2014 they have a web of them. This diagram shows a CSTR reactor system with four instrument loops and a safety instrument, which is about the minimum complexity for a unit operation that would appear in a HAZOP study. Understanding how to read this diagram cold is a core skill for every process, instrumentation, and safety engineer on the project team.
1282
+
1283
+ **The process path.** Raw material is stored in T-201 (atmospheric tank). The centrifugal pump P-201A/B (the A/B suffix is conventional for spared pumps \u2014 one online, one standby) pulls from the bottom nozzle and pushes through 6-inch feed line L2 to the shell-and-tube heat exchanger E-201, which pre-heats the feed before it enters the reactor. From E-201, the line continues through the feed control valve V-201 into the reactor R-201. The reactor product exits through L5 and the product control valve V-202.
1284
+
1285
+ **Loop 201 \u2014 flow control.** FT-201 (flow transmitter, field-mounted) sits on the pump discharge line L2 and sends a 4\u201320 mA signal to FIC-201 (flow indicating controller, control-room mounted, DCS shared \u2014 note the horizontal line through the circle). FIC-201 closes or opens V-201 to maintain the feed flow setpoint. V-201 is fail-closed: if instrument air is lost, the feed to the reactor stops. Starving a reactor on air loss is usually safer than flooding it.
1286
+
1287
+ **Loop 201T \u2014 temperature control.** TT-201 (temperature transmitter) measures the reactor body temperature and signals TIC-201, which throttles V-202 \u2014 the product outlet valve \u2014 to regulate residence time and therefore heat generation in the reactor. V-202 is fail-open: losing air means the product continues to drain out, preventing dangerous temperature accumulation inside the vessel. The fail-safe position is always chosen by answering the question: "which state causes less harm if control is lost?"
1288
+
1289
+ **Loop 201P \u2014 pressure monitoring and safety.** PT-201 is a field-mounted pressure transmitter \u2014 it sends the continuous pressure reading to the DCS historian. PSHH-201 is a pressure switch, high-high: a discrete field-mounted device that trips at the maximum allowable working pressure (MAWP). It is wired to the safety interlock system (SIS), not the DCS. The distinction matters: DCS loops control the process; SIS loops protect equipment and people. OSHA PSM (29 CFR 1910.119) requires the two to be functionally independent. V-203 is the pressure safety valve \u2014 a spring-loaded valve that opens automatically at the set pressure of 150 psig regardless of any control signal, providing the last line of mechanical protection.
1290
+
1291
+ **Why P&ID, not PFD.** A process flow diagram (PFD) shows the same equipment but only the major process streams, mass balances, and operating conditions. A P&ID adds every instrument, every valve, every signal line, and every utility connection \u2014 it is the engineering document used by instrument engineers to write I/O lists, by safety engineers to perform HAZOP, and by construction teams to verify field installation. The DSL lets you build this level of detail from text, making it tractable for AI-assisted first drafts and version-controlled review cycles.`
1292
+ },
1254
1293
  {
1255
1294
  "slug": "prisma-dual-pipeline",
1256
1295
  "diagram": "prisma",
@@ -1289,6 +1328,43 @@ If the LED doesn't light up, three things to check, in order: LED polarity (the
1289
1328
  "dsl": "prisma\nmode: 2020-single\ntitle: Effect of exercise on chronic low-back pain \u2014 SR\n\nidentification:\n databases:\n n: 1418\n sources: PubMed=600, Embase=450, Cochrane=184, Web of Science=184\n duplicates-removed: 318\n\nscreening:\n records-screened: 1100\n excluded:\n n: 870\n reasons: irrelevant title=750, non-English=120\n\neligibility:\n full-text-assessed: 230\n excluded:\n n: 195\n reasons: wrong population=80, wrong intervention=60, wrong outcome=55\n\nincluded:\n studies: 35\n reports: 38",
1290
1329
  "notes": '## Scenario\n\nA research librarian produces the PRISMA 2020 flow diagram for a Cochrane review submission. The journal **requires** the diagram in the exact four-row structure \u2014 Identification \u2192 Screening \u2192 Eligibility \u2192 Included \u2014 with the count `(n = \u2026)` shown in every box and the excluded boxes itemizing reasons. With the dedicated `prisma` engine the librarian writes only counts and reasons; the rigid layout, the "Records removed before screening" side-box, and the exclusion side-boxes are produced automatically and are correct by construction.\n\n## Annotation key\n\n- **`mode: 2020-single`** \u2014 one Identification column (databases & registers). Use `mode: 2020-dual` to add the "other methods" column.\n- **`identification.databases`** \u2014 `n:` is the mandatory total; `sources:` renders the per-database breakdown; `duplicates-removed:` splits out into the right-column "Records removed before screening" box automatically.\n- **`screening` / `eligibility` `excluded:` blocks** \u2014 each has its own `n:` total and an optional `reasons:` breakdown rendered in a side-box to the right, connected by a horizontal arrow.\n- **`included.studies` / `reports`** \u2014 one study can yield several reports, so both counts render.\n\n## How to read\n\nTop to bottom mirrors the PRISMA 2020 template exactly. The left capsule bands label the three canonical stages; the orange bar spans the Identification column group. Counts reconcile across stages (1418 \u2212 318 = 1100 screened; 1100 \u2212 870 = 230 assessed; 230 \u2212 195 = 35 included) \u2014 the engine warns if they don\'t.\n\n## Standard reference\n\nPage MJ, McKenzie JE, Bossuyt PM, et al. *The PRISMA 2020 statement: an updated guideline for reporting systematic reviews.* BMJ 2021;372:n71. Template: [prisma-statement.org/prisma-2020-flow-diagram](https://www.prisma-statement.org/prisma-2020-flow-diagram).'
1291
1330
  },
1331
+ {
1332
+ "slug": "sequence-microservices-saga",
1333
+ "diagram": "sequence",
1334
+ "title": "Microservices order saga",
1335
+ "description": "A distributed order-processing saga showing the parts of UML sequence notation that generic tools omit \u2014 a ref interaction-use frame, a par fragment for concurrent service calls, asynchronous event-bus messages, and an alt fragment with a compensating rollback on payment failure.",
1336
+ "standard": "OMG UML 2.5.1 \xA717 (Interactions)",
1337
+ "tags": [
1338
+ "sequence",
1339
+ "uml",
1340
+ "microservices",
1341
+ "saga",
1342
+ "async",
1343
+ "event-driven"
1344
+ ],
1345
+ "complexity": 3,
1346
+ "featured": false,
1347
+ "dsl": 'sequence "Order processing (saga)"\n actor Customer\n participant Gateway as "API Gateway"\n control Orders as "Order Service"\n participant Payment as "Payment Service"\n participant Inventory as "Inventory Service"\n queue Bus as "Event Bus"\n\n Customer -> Gateway : POST /orders\n Gateway ->+ Orders : createOrder()\n ref over Orders, Bus : Validate cart & price\n\n par\n Orders ->> Payment : charge(card)\n and\n Orders ->> Inventory : reserve(items)\n end\n\n alt [payment captured && stock reserved]\n Payment --> Orders : paid\n Inventory --> Orders : reserved\n Orders ->> Bus : OrderConfirmed\n Orders -->- Gateway : 201 Created\n Gateway --> Customer : confirmation\n else [payment failed]\n Orders ->> Inventory : release(items)\n Orders ->> Bus : OrderCancelled\n Orders -->- Gateway : 402 Payment Required\n Gateway --> Customer : declined\n end',
1348
+ "notes": "This is the case that separates a real UML engine from a flowchart with stick figures. A saga is concurrent, asynchronous, and has a compensating path \u2014 and Schematex has dedicated notation for each.\n\n**`ref` keeps the diagram composable.** \"Validate cart & price\" is its own interaction; inlining it here would bury the saga in detail. The `ref over Orders, Bus : \u2026` frame references it instead \u2014 notation most text-to-diagram tools simply don't have.\n\n**`par` shows true concurrency.** The order service charges the card and reserves stock *at the same time*. The `par` fragment's two operands say these run concurrently, not in sequence \u2014 a distinction a top-to-bottom message list cannot express.\n\n**Async vs. reply arrows are not cosmetic.** `->>` (open head) marks fire-and-forget calls and event-bus publishes; `-->` (dashed) marks the replies that come back. Reading the arrowheads tells you which steps block and which don't.\n\n**The compensation lives in the `alt`.** When payment fails, the second operand *releases* the previously reserved inventory and emits `OrderCancelled` \u2014 the saga's rollback, drawn right beside the happy path instead of in a separate diagram."
1349
+ },
1350
+ {
1351
+ "slug": "sequence-oauth-login",
1352
+ "diagram": "sequence",
1353
+ "title": "OAuth 2.0 authorization-code login",
1354
+ "description": "The canonical browser-based sign-in handshake as a UML sequence diagram \u2014 redirect to the auth server, user consent, code-for-token exchange, and an alt fragment for the success vs. failure branch, with activation bars tracking who is busy at each step.",
1355
+ "standard": "OMG UML 2.5.1 \xA717 (Interactions)",
1356
+ "tags": [
1357
+ "sequence",
1358
+ "uml",
1359
+ "oauth",
1360
+ "authentication",
1361
+ "api"
1362
+ ],
1363
+ "complexity": 2,
1364
+ "featured": true,
1365
+ "dsl": 'sequence "OAuth 2.0 Authorization Code"\n actor User\n boundary Browser\n control App as "Web App"\n participant Auth as "Auth Server"\n database DB as "User Store"\n\n User -> Browser : click "Sign in"\n Browser ->+ App : GET /login\n App --> Browser : 302 \u2192 Auth Server\n Browser ->+ Auth : GET /authorize\n Auth --> User : consent screen\n User -> Auth : approve\n Auth -->- Browser : 302 + auth code\n\n Browser ->+ App : GET /callback?code\n App ->+ Auth : POST /token (code)\n Auth ->+ DB : load user\n DB -->- Auth : profile\n Auth -->- App : access + refresh token\n alt [token exchange ok]\n App --> Browser : Set-Cookie: session\n Browser --> User : signed in\n else [exchange failed]\n App --> Browser : 401 Unauthorized\n Browser --> User : retry\n end\n deactivate App',
1366
+ "notes": "Almost every product ships this flow, and almost every whiteboard drawing of it is subtly wrong about *who is active when*. A sequence diagram makes the call order and the active spans explicit.\n\n**Lifeline kinds carry meaning.** The `boundary` Browser, the `control` App, and the `entity`/`database` user store render as their UML symbols, so a reviewer reads the architecture at a glance: the browser is the UI edge, the app orchestrates, the auth server and store are collaborators.\n\n**Activation bars track the redirect dance.** OAuth bounces the user between the app and the auth server twice. The `+`/`-` suffixes open and close execution-specification bars exactly where each party becomes busy and hands control back \u2014 the `Auth -->- Browser` reply both returns the auth code *and* closes the auth server's first activation.\n\n**The branch is a real fragment, not two diagrams.** The `alt` frame captures the success and failure paths in one place: a valid token exchange sets the session cookie; a failed one returns `401`. That is the single most common place sequence diagrams earn their keep \u2014 showing the unhappy path next to the happy one instead of hiding it."
1367
+ },
1292
1368
  {
1293
1369
  "slug": "sfc-bake-cool-concurrent",
1294
1370
  "diagram": "sfc",
@@ -1468,6 +1544,46 @@ If the LED doesn't light up, three things to check, in order: LED polarity (the
1468
1544
  "dsl": 'sociogram "Engineering team \u2014 informal influence"\n config: layout = force-directed\n group leads [label: "Tech leads", color: "#1976D2"]\n alex; sam\n group sr [label: "Senior ICs", color: "#66BB6A"]\n priya; jordan; kim; tao\n group jr [label: "Junior", color: "#FFA726"]\n lee; ravi; nina; dev\n alex <-> sam\n alex -> priya\n sam -> jordan\n priya <-> kim\n jordan <-> tao\n kim -> lee\n priya -> ravi\n tao -> nina\n dev -.- lee\n nina -.- priya',
1469
1545
  "notes": "## Scenario\n\nAn engineering manager runs an informal network analysis survey (\"Who do you go to when you're stuck?\") and maps the results to identify knowledge hubs, bridging individuals between seniority tiers, and team members who are drifting toward isolation before performance reviews surface the issue.\n\n## Annotation key\n\n- `group id [label:..., color:...]` \u2014 assigns individuals to organizational tiers, color-coded\n- `<->` \u2014 mutual influence; both nominated each other\n- `->` \u2014 one-way influence nomination\n- `-.-` \u2014 weak tie; neither party nominated the other in the survey\n- The force-directed layout clusters mutual-nomination groups and separates isolates\n\n## How to read\n\nAlex and Sam (tech leads) are mutually influential. Alex bridges down to Priya, Sam to Jordan \u2014 healthy knowledge flow across tiers. Priya and Kim form a strong senior IC hub. Dev and Nina have only weak ties (--. to the network), suggesting integration risk. Dev's only connection is a weak tie to Lee \u2014 a coaching opportunity before the next performance cycle."
1470
1546
  },
1547
+ {
1548
+ "slug": "state-ecommerce-order",
1549
+ "diagram": "state",
1550
+ "title": "E-commerce order lifecycle (state diagram)",
1551
+ "description": "Full order state machine \u2014 from Pending through payment routing (choice pseudo-state), composite Processing state with Picking/Packing/Shipped sub-states, delivery, refund, and cancellation paths. Demonstrates composite states, choice pseudo-states, guard conditions, entry actions, and UML notes.",
1552
+ "standard": "OMG UML 2.5.1 \xA714",
1553
+ "tags": [
1554
+ "state",
1555
+ "uml",
1556
+ "composite",
1557
+ "choice",
1558
+ "guard",
1559
+ "order-management",
1560
+ "e-commerce",
1561
+ "lifecycle"
1562
+ ],
1563
+ "complexity": 2,
1564
+ "featured": false,
1565
+ "dsl": 'state "E-Commerce Order Lifecycle"\n\ninitial i\ni -> Pending\n\nPending -> Confirmed : place_order [items_in_stock] / reserveInventory()\nPending -> Cancelled : cancel\n\nchoice PayRoute\nConfirmed -> PayRoute : pay\nPayRoute -> Processing : [method == "card"]\nPayRoute -> Processing : [method == "wallet"]\nPayRoute -> AwaitingTransfer : [method == "bank_transfer"]\n\nAwaitingTransfer -> Processing : transfer_received [amount_correct]\nAwaitingTransfer -> Cancelled : transfer_timeout\n\ncomposite Processing {\n initial pi\n final pf\n\n pi -> Picking\n Picking -> Packing : picked / updateWarehouse()\n Packing -> Shipped : label_printed\n Shipped -> pf : carrier_confirmed\n}\n\nProcessing -> Delivered : delivered / notifyCustomer()\nProcessing -> Failed : fulfillment_error\n\nDelivered -> Refunded : return_request [within_30_days] / initiateRefund()\nFailed -> Pending : retry [attempt < 3]\nFailed -> Cancelled : retry [attempt >= 3]\n\nfinal f\nDelivered -> f\nRefunded -> f\nCancelled -> f\n\nnote right_of AwaitingTransfer : SLA: 48 h before timeout.',
1566
+ "notes": 'Order state machines are one of the most common backend design artifacts, and one of the most commonly under-specified. Teams often start with a simple enum (`PENDING / PAID / SHIPPED / DELIVERED`) and then bolt on edge cases over time: partial shipments, payment holds, carrier errors, refund windows. Six months later the enum has twelve values, the transition logic is scattered across three services, and nobody can explain what sequence of events gets an order from `FAILED` to `CANCELLED` versus from `FAILED` back to `PENDING`. A UML state diagram catches all of this upfront.\n\n**Guard conditions on `place_order`.** The transition from `Pending` to `Confirmed` carries `[items_in_stock]` \u2014 a guard. Guards are boolean predicates that must be true for the transition to fire even when the trigger event (`place_order`) occurs. If the guard is false, the trigger is silently absorbed and the system stays in `Pending`. In practice this means inventory is checked synchronously during order placement, and the transition only proceeds if stock is available. The action `/ reserveInventory()` fires when the transition does go through, atomically.\n\n**Choice pseudo-state for payment routing.** `PayRoute` is a UML choice pseudo-state (drawn as a diamond). When the `pay` trigger fires from `Confirmed`, the machine immediately evaluates the guards on all outgoing transitions from `PayRoute`. If `method == "card"` or `method == "wallet"`, control goes directly to `Processing`. If `method == "bank_transfer"`, it goes to `AwaitingTransfer` \u2014 a waiting state with its own 48-hour SLA note. Choice pseudo-states do not dwell; they route. This is the correct model for "take different paths based on a value computed at runtime."\n\n**Composite state for fulfillment.** `Processing` is a composite state \u2014 it contains its own internal state machine with `Picking`, `Packing`, and `Shipped`. From the outside, the system is "in Processing" whether it\'s picking, packing, or confirming with the carrier. From the inside, the sub-machine tracks exactly where the warehouse is. The composite state has its own `initial` and `final` pseudo-states: the machine enters at `pi` (starts picking) and exits through `pf` (carrier confirmed), which fires the outer transition to `Delivered`. Cross-composite transitions to `Failed` are also valid \u2014 a fulfillment error at any sub-state terminates the Processing phase and moves to the outer `Failed` state.\n\n**Retry with bounded attempts.** `Failed` has two outgoing transitions back to `Pending` and `Cancelled`, both triggered by `retry` but guarded on `attempt`. This is the explicit model for "retry up to N times, then give up." Without the state diagram, this logic typically lives in a cron job or a dead-letter queue processor that nobody fully understands. Here it is the specification: anyone reading the diagram knows the retry policy without digging through queue configurations.\n\n**Final state convergence.** `Delivered`, `Refunded`, and `Cancelled` all transition to the same `final` pseudo-state. In implementation, "final" might mean the order record is archived, the event bus receives an `order.closed` event, and no further state transitions are accepted. The model is silent on what happens after final \u2014 that\'s intentional. The state machine is done; downstream processes (analytics, accounting, data retention) are separate concerns.'
1567
+ },
1568
+ {
1569
+ "slug": "state-traffic-light",
1570
+ "diagram": "state",
1571
+ "title": "Traffic light (state diagram)",
1572
+ "description": "A three-state finite state machine for a traffic signal \u2014 Red, Green, Yellow \u2014 with timer-driven transitions and a power_off exit to a final state. Introduces UML initial and final pseudo-states, transition labels, and the cyclic structure that makes state diagrams the right tool for reactive systems.",
1573
+ "standard": "OMG UML 2.5.1 \xA714",
1574
+ "tags": [
1575
+ "state",
1576
+ "uml",
1577
+ "fsm",
1578
+ "state-machine",
1579
+ "embedded",
1580
+ "reactive"
1581
+ ],
1582
+ "complexity": 1,
1583
+ "featured": true,
1584
+ "dsl": 'state "Traffic Light"\n\ninitial i\nfinal f\n\ni -> Red\nRed -> Green : timer\nGreen -> Yellow : timer\nYellow -> Red : timer\nRed -> f : power_off',
1585
+ "notes": "The traffic light is to state diagrams what the pump loop is to P&IDs: every textbook uses it, every engineer has drawn it, and if you understand it you understand the grammar of every more complex model.\n\n**Why a state diagram and not a flowchart.** A flowchart for a traffic light would show a loop: start \u2192 Red \u2192 (timer fires?) \u2192 Green \u2192 (timer fires?) \u2192 Yellow \u2192 back to Red. That works for describing an algorithm, but it misses the essential question: *what is the system doing right now?* A state machine makes the current state a first-class concept. The traffic light is not executing a loop \u2014 it *is* Red, or it *is* Green. Transitions are events that change what it is. This distinction matters the moment you add complexity: \"what happens if a pedestrian button is pressed while we're in Green?\" You answer that by looking at the transitions out of Green, not by tracing a flowchart path.\n\n**UML pseudo-states.** The filled black circle (`initial i`) and the bull's-eye circle (`final f`) are pseudo-states \u2014 they are not real states the system can dwell in, just notational entry and exit points. The initial pseudo-state shows where the machine starts; the arrow from `i` to Red tells you Red is the first real state. The final pseudo-state shows where the machine terminates. In the traffic light, termination is the `power_off` event from Red \u2014 the system shuts down from the Red state only (it wouldn't be safe to power off mid-Green).\n\n**Transition labels.** Each arrow is labeled with the trigger event that causes the transition. `timer` means \"the countdown for this phase has elapsed.\" In a real embedded implementation, this would be a hardware timer interrupt or a software watchdog expiry. Schematex doesn't execute the state machine \u2014 it renders the model. The labels are free text; you write exactly what your system calls the event.\n\n**Cyclic structure.** The three main states form a cycle: Red \u2192 Green \u2192 Yellow \u2192 Red. Most state diagrams describing continuous systems have cycles \u2014 the system runs until something external stops it. The `power_off` transition is the only way to reach the final state, and it is only modeled on Red because that is the safe state to stop in. If you wanted to model an emergency override (traffic officer stops the light mid-cycle), you would add `power_off` transitions from Green and Yellow too.\n\n**From model to code.** A UML state diagram maps directly to an enum + switch statement, a state table, or a state-machine framework (XState, Boost.MSM, Qt State Machine). The diagram is the specification; the implementation strategy is separate. Generating this diagram from a DSL means you can keep the spec in version control alongside the code, diff it in PRs, and regenerate it from an LLM prompt when requirements change."
1586
+ },
1471
1587
  {
1472
1588
  "slug": "timeline-company-milestones",
1473
1589
  "diagram": "timeline",
@@ -1711,6 +1827,10 @@ var SYNTAX = {
1711
1827
  "title": "UML Use Case Diagram",
1712
1828
  "content": '## 1. Your first diagram\n\nEvery document starts with the `usecase` keyword, then a header, then declarations and relationships:\n\n```\nusecase\nsystem: "Library"\n\nactor: Member\nusecase: "Borrow Book" as Borrow\n\nMember -- Borrow\n```\n\n`actor:` declares an actor (a stick figure), `usecase:` declares a use case (an ellipse), and `Member -- Borrow` draws a plain association between them. `system:` wraps the use cases in a labelled **subject** rectangle. The primary actor is placed on the left; supporting actors on the right.\n\nThe header accepts:\n\n- `title: "\u2026"` \u2014 a heading drawn above the diagram.\n- `system: "\u2026"` \u2014 the subject (system boundary) name. Omit it to let the use cases float free (Schematex warns if you omit it with \u22653 use cases).\n- `direction: LR | TB` \u2014 default `LR` (actors flank the subject horizontally).\n- `generalization: tree | individual` \u2014 whether to merge sibling generalization arrows (default `tree`).\n\n---\n\n## 2. Actors\n\n```\nactor: Customer\nactor: "Payment Gateway" as PG (external)\nactor: "Warehouse Staff" as WH\nactor: Admin (left)\n```\n\n- A bare or `"quoted"` name becomes the label; `as ID` gives it a short identifier for relationships.\n- `(external)` (or `(system)`) renders the actor as a **rectangle with an `\xABactor\xBB` stereotype** instead of a stick figure \u2014 use it for other software systems (payment gateways, third-party APIs).\n- `(business)` adds the Bittner & Spence diagonal slash across the stick figure.\n- `(left)` / `(right)` pins the actor to a side. By default the first actor goes left and the rest go right.\n\nCustom stereotypes go in guillemets after the declaration: `actor: "Audit Service" as Audit (external) \xABsystem\xBB`. The parser also accepts ASCII `<<system>>` and normalises it to `\xABsystem\xBB`.\n\n---\n\n## 3. Use cases\n\n```\nusecase: "Checkout" as Checkout {\n extension point: payment failed\n extension point: stock depleted\n}\n```\n\nA use case is an ellipse sized to fit its text. The optional `{ \u2026 }` block lists **extension points** in a compartment below the name, separated by a divider line. Stereotypes work here too: `usecase: "Validate Card" as ValidateCard \xABsecured\xBB`.\n\n---\n\n## 4. Relationships\n\nFour line types connect actors and use cases:\n\n| DSL | Meaning | Rendering |\n|-----|---------|-----------|\n| `A -- B` | association | solid line, no arrow |\n| `A --> B` | directed association | solid line, open arrow at B |\n| `A ..> B` | `A` **includes** `B` | dashed line, open arrow \u2192 B, `\xABinclude\xBB` pill |\n| `A <.. B` | `A` **extends** `B` | dashed line, open arrow \u2192 B (the base), `\xABextend\xBB` pill |\n| `A --\\|> B` | `A` is a specialisation of `B` | solid line, hollow triangle \u2192 parent B |\n\n```\nCustomer -- Checkout\nCheckout ..> Pay : \xABinclude\xBB\nPay ..> ValidateCard : \xABinclude\xBB\nCancel <.. Checkout : \xABextend\xBB [payment failed] (extension point: payment failed)\n```\n\n- **`\xABinclude\xBB`** points *toward the included use case* \u2014 the reusable behavior `A` always runs. Source includes target.\n- **`\xABextend\xBB`** points *toward the base* \u2014 `A` is the optional behavior, `B` is the base it extends. You can attach a `[condition]` and reference one of the base\'s `(extension point: \u2026)` entries. (The arrowhead is always drawn toward the base regardless of how you order the endpoints.)\n- An `\xABextend\xBB` line is drawn in the theme **accent color** so the rarer, more surprising relationship stands out.\n\nThe parser rejects the high-confidence mistakes humans and LLMs both make, with the offending line number: association between two actors or two use cases, `include`/`extend` touching an actor, generalization across metaclasses (actor \u2192 use case), reused identifiers, and extension-point references that don\'t exist on the base.\n\n---\n\n## 5. Generalization\n\n`--|>` works between two actors **or** between two use cases (never across the two \u2014 that\'s a hard error):\n\n```\nactor: User as U\nactor: "Premium User" as PU\nPU --|> U\n\nusecase: "Pay by Card" as PayCard\nusecase: "Pay by PayPal" as PayPaypal\nusecase: "Pay" as Pay\nPayCard --|> Pay\nPayPaypal --|> Pay\n```\n\nThe arrow carries a **hollow triangle** pointing at the parent. When three or more siblings share one parent, the arrows merge into a single shared head (UML 2.5 Figure 18.5 convention); set `generalization: individual` in the header to keep them separate. Actor hierarchies route as a clean bus on the outer edge of the actor stack.\n\n---\n\n## 6. Multiplicity\n\nQuote a multiplicity string immediately beside the endpoint it belongs to:\n\n```\nCustomer "1" -- "*" Checkout\nCashier "1..*" -- "1" Register\n```\n\n---\n\n## 7. PlantUML-style inline form\n\nComing from PlantUML? The inline declaration form works and mixes freely with the declarative form:\n\n```\nusecase\n:Customer: as C\n(Browse Catalog) as Browse\n(Add to Cart) as AddCart\n\nC -- Browse\nC -- AddCart\nBrowse ..> AddCart : \xABinclude\xBB\n```\n\n`:Name:` declares an actor, `(Name)` declares a use case, and `as ID` aliases either. Schematex is *inspired by* PlantUML, not a 1:1 transpiler \u2014 multiplicity and relationship syntax differ slightly.\n\n---\n\n## 8. Grammar (EBNF)\n\n```text\ndocument = "usecase" NEWLINE header_prop* statement*\nheader_prop = ("title:" | "system:") quoted_string\n | "direction:" ("LR" | "TB")\n | "generalization:" ("tree" | "individual")\n\nstatement = actor_decl | usecase_decl | plantuml_inline | relation | note\n\nactor_decl = "actor" ":" name ("as" IDENT)? actor_kind? stereotype?\nactor_kind = "(" ("external" | "system" | "business" | "left" | "right") ")"\nusecase_decl = "usecase" ":" quoted ("as" IDENT)? stereotype? extpoints?\nextpoints = "{" ("extension point:" TEXT)+ "}"\nplantuml_inline = ":" name ":" ("as" IDENT)? ; actor\n | "(" name ")" ("as" IDENT)? ; use case\n\nrelation = endpoint relop endpoint label_clause?\nendpoint = (IDENT | quoted) multiplicity? | multiplicity? (IDENT | quoted)\nrelop = "--" | "-->" | "..>" | "<.." | "--|>"\nlabel_clause = ":" stereotype? condition? extpoint_ref?\nstereotype = "\xAB" TEXT "\xBB" | "<<" TEXT ">>"\ncondition = "[" TEXT "]"\nextpoint_ref = "(extension point:" TEXT ")"\nmultiplicity = quoted_string ; "1", "*", "0..1", "1..*"\n```\n\n---'
1713
1829
  },
1830
+ "sequence": {
1831
+ "title": "UML Sequence Diagram",
1832
+ "content": '## 1. Your first diagram\n\nEvery document starts with the `sequence` keyword and an optional `"title"`. Participants don\'t need to be declared \u2014 the first time you mention one in a message, it becomes a lifeline:\n\n```\nsequence\n Alice -> Bob : Authentication Request\n Bob --> Alice : Authentication Response\n```\n\nLifelines appear left-to-right in first-use order. `->` is a synchronous call (solid line, filled arrowhead); `-->` is a reply (dashed line, open arrowhead). Text after `:` is the message label.\n\n---\n\n## 2. Participants\n\nDeclare a participant explicitly to set its **kind**, give it an **alias**, or fix its **order**:\n\n```\nsequence\n actor User\n participant Web as "Web App"\n boundary LoginUI\n control Auth\n entity Account\n database DB\n collections Sessions\n queue Events\n```\n\n| Kind | Rendered as |\n|------|-------------|\n| `participant` (default) | rounded classifier box |\n| `actor` | stick figure |\n| `boundary` / `control` / `entity` | the Jacobson robustness icons (\u22A2\u25EF / \u25EF with arrow / \u25EF with underline) |\n| `database` | cylinder |\n| `collections` / `queue` | box with the kind as a `\xABstereotype\xBB` |\n\n- `as "Label"` sets the display name (quotes optional; `\u300C\u2026\u300D` CJK quotes accepted).\n- A custom **stereotype** goes in guillemets or ASCII angle brackets after the declaration \u2014 it overrides the default label: `actor Printer \xABsystem\xBB`, `participant Bus as "Event Bus" <<service>>`.\n\n---\n\n## 3. Messages\n\nThe arrow token chooses the UML semantics:\n\n| DSL | Meaning | Rendering |\n|-----|---------|-----------|\n| `A -> B` | synchronous call | solid line, **filled** arrowhead |\n| `A ->> B` | asynchronous signal | solid line, **open** arrowhead |\n| `A --> B` | reply / return | **dashed** line, open arrowhead |\n| `A -x B` | lost message | line ending at a filled circle |\n| `o-> B` | found message | line starting from a filled circle |\n| `A -> A` | self message | bent loop back to the same lifeline |\n\nWhitespace around arrows is optional (`A->B` works), and labels are free text \u2014 including a return value, e.g. `aHotel -> aHotel : available(roomId, date): isRoom`.\n\n---\n\n## 4. Activations (execution specifications)\n\nThe thin bar on a lifeline shows it is active. Open and close it with explicit statements, or with `+` / `-` suffixes on the messages themselves:\n\n```\nsequence\n participant Client\n participant Server\n Client ->+ Server : request()\n Server ->> Server : validate()\n Server -->- Client : response\n```\n\n`+` after the arrow activates the **receiver** on arrival; `-` deactivates the **sender** after the message is sent. The explicit form is `activate X` / `deactivate X`. Overlapping bars on one lifeline nest with a horizontal offset.\n\n---\n\n## 5. Object creation & destruction\n\n```\nsequence\n participant Factory\n Factory -> *Worker : \xABcreate\xBB\n Factory -> Worker : work()\n destroy Worker\n```\n\nPrefix the receiver with `*` to make the message **instantiate** it \u2014 the new lifeline\'s head is drawn at the arrival row, not at the top. `destroy X` ends a lifeline with a \u2715 and stops its time axis.\n\n---\n\n## 6. Combined fragments\n\nA combined fragment is a labelled frame around a region. Schematex implements the full UML `InteractionOperatorKind` set:\n\n| Operator | Meaning | Operands |\n|----------|---------|----------|\n| `alt` | alternatives (if/else-if/else) | `else`, each guarded |\n| `opt` | runs iff the guard holds | one, guarded |\n| `loop` | repeat | one; guard may be `(min,max)` |\n| `par` | concurrent operands | `and` |\n| `break` | exceptional exit | one, guarded |\n| `critical` | atomic / no interleaving | one |\n| `seq` / `strict` | weak / strict sequencing | `and` |\n| `neg` | invalid traces (rendered tinted) | one |\n| `ignore` / `consider` | message-set filter `{m1, m2}` | one |\n| `assert` | the only valid continuation | one |\n\n```\nsequence\n actor User\n participant API\n User -> API : GET /resource\n alt [authorized]\n API --> User : 200 + body\n else [forbidden]\n API --> User : 403\n end\n```\n\nGuards go in `[brackets]` after the operator (and after `else`). Fragments nest, and inner frames inset automatically so they sit cleanly inside their parent.\n\n---\n\n## 7. Interaction use (`ref`)\n\nReference another interaction instead of inlining it \u2014 the way UML keeps large diagrams composable:\n\n```\nsequence\n participant A\n participant B\n ref over A, B : Establish session\n A -> B : poll()\n```\n\n`ref over <lifelines> : Name` draws a framed box across the named lifelines. Most tools omit this; it\'s how real systems decompose long flows.\n\n---\n\n## 8. Notes, dividers, invariants, numbering\n\n```\nsequence\n autonumber 1 1\n actor Shopper\n participant Cart\n == Phase 1: review ==\n Shopper -> Cart : view items\n note over Cart : cart persisted in Redis\n state Cart : ready\n```\n\n- `note over A` / `note over A, B` / `note left of A` / `note right of A` \u2014 folded-corner annotations.\n- `== text ==` \u2014 a full-width section divider.\n- `state X : text` \u2014 a state-invariant capsule on a lifeline.\n- `autonumber [start] [step]` \u2014 prefix every message with an incrementing number.\n\n---\n\n## 9. Grammar (EBNF)\n\n```text\ndiagram = "sequence" [ string ] NEWLINE statement*\nstatement = participant | message | activation | note\n | fragment | ref | divider | invariant | destroy | autonumber\n\nparticipant = kind IDENT ("as" label)? stereotype?\nkind = "participant" | "actor" | "boundary" | "control"\n | "entity" | "database" | "collections" | "queue"\nstereotype = "\xAB" TEXT "\xBB" | "<<" TEXT ">>"\n\nmessage = IDENT? act? arrow act? ("*")? IDENT? (":" TEXT)?\narrow = "->" | "->>" | "-->" | "-x" | "o->"\nact = "+" | "-"\nactivation = ("activate" | "deactivate") IDENT\n\nfragment = ("alt"|"opt"|"loop"|"par"|"break"|"critical"|"seq"\n |"strict"|"neg"|"ignore"|"consider"|"assert") guard? NEWLINE\n statement* (("else"|"and") guard? NEWLINE statement*)* "end"\nguard = "[" TEXT "]" | "(" NUMBER ("," NUMBER)? ")"\nref = "ref" "over" IDENT ("," IDENT)* ":" TEXT\nnote = "note" ("over"|"left of"|"right of") IDENT ("," IDENT)? ":" TEXT\ndivider = "==" TEXT "=="\ninvariant = "state" IDENT ":" TEXT\ndestroy = "destroy" IDENT\nautonumber = "autonumber" NUMBER? NUMBER?\n```\n\n---'
1833
+ },
1714
1834
  "prisma": {
1715
1835
  "title": "PRISMA 2020 flow diagram",
1716
1836
  "content": '## 1. Your first diagram\n\nThe minimum is the four stage blocks. Counts are mandatory; the parser refuses to lay out a diagram with a missing total.\n\n```\nprisma\n\nidentification:\n databases:\n n: 1000\n\nscreening:\n records-screened: 900\n excluded:\n n: 600\n\neligibility:\n full-text-assessed: 300\n excluded:\n n: 250\n\nincluded:\n studies: 50\n```\n\nIndentation is significant \u2014 **two spaces per level**, like genogram and SLD. The first non-blank line must be `prisma`. Comments use `#` or `//`.\n\n---\n\n## 2. Meta lines\n\nTop-level `key: value` lines, written before the stage blocks:\n\n```\nprisma\nmode: 2020-single\nkind: systematic-review\ntitle: My review\nvalidate-counts: warn\n```\n\n| Key | Values | Default | Meaning |\n|---|---|---|---|\n| `mode` | `2020-single` \xB7 `2020-dual` \xB7 `2009` | `2020-single` | Single column, or dual ("other methods") column. |\n| `kind` | `systematic-review` \xB7 `scoping-review` \xB7 `ipd` \xB7 `nma` | `systematic-review` | Swaps stage vocabulary (see \xA76). |\n| `title` | string | \u2014 | Rendered above the diagram. |\n| `validate-counts` | `warn` \xB7 `strict` \xB7 `off` | `warn` | Arithmetic checking (see \xA77). |\n| `direction` | `TB` / `TD` | `TB` | PRISMA is vertical by standard; horizontal is rejected. |\n\n---\n\n## 3. Identification\n\nThe `identification:` block holds a `databases:` sub-block (always) and an optional `other:` sub-block (dual mode).\n\n```\nidentification:\n databases:\n n: 1418\n sources: PubMed=600, Embase=450, Cochrane=184\n duplicates-removed: 318\n ineligible-automation: 0\n other-removed: 0\n```\n\n- `n:` \u2014 total records identified (**mandatory**).\n- `sources:` \u2014 `name=count` pairs, comma-separated. Rendered as an indented breakdown. Names with spaces or punctuation can be quoted: `"Web of Science"=184`.\n- `duplicates-removed:`, `ineligible-automation:`, `other-removed:` \u2014 optional removal counts. When any are present they render as a separate **"Records removed before screening"** box in the right column, connected by a horizontal arrow.\n\nLarge numbers may use commas: `n: 1,418` is the same as `n: 1418`.\n\n---\n\n## 4. Screening & Eligibility\n\nBoth stages carry a main count plus an `excluded:` block. The excluded block has its own `n:` and an optional `reasons:` breakdown.\n\n```\nscreening:\n records-screened: 1100\n excluded:\n n: 870\n reasons: irrelevant title=750, non-English=120\n reports-sought: 226 # optional\n reports-not-retrieved: 12 # optional\n\neligibility:\n full-text-assessed: 230\n excluded:\n n: 195\n reasons: wrong population=80, wrong intervention=60, wrong outcome=55\n```\n\n`reasons:` are `name=count` pairs. If you list more than 8, the renderer sorts them descending and aggregates the tail as `Other (n = \u2026)` so the side-box stays readable.\n\n---\n\n## 5. Included\n\n```\nincluded:\n studies: 35\n reports: 38 # one study may yield several reports\n participants: 28741 # PRISMA-IPD only\n```\n\n`studies:` is mandatory. `reports:` and `participants:` are optional extra count lines.\n\n---\n\n## 6. Dual pipeline & review kinds\n\n**Dual pipeline** \u2014 the PRISMA 2020 update added a second "Identification via other methods" column (citation searching, hand searches, expert recommendations). Add an `other:` block; the two columns merge into Screening via a Y-junction.\n\n```\nprisma\nmode: 2020-dual\n\nidentification:\n databases:\n n: 1234\n duplicates-removed: 254\n other:\n n: 56\n sources: citation-search=30, hand-search=20, expert-recommendation=6\n\nscreening:\n records-screened: 1036\n excluded:\n n: 810\n\neligibility:\n full-text-assessed: 226\n excluded:\n n: 195\n\nincluded:\n studies: 31\n```\n\n**Scoping review** \u2014 `kind: scoping-review` swaps "studies" \u2192 "sources of evidence" and re-labels the stages per Tricco et al. 2018, without changing geometry.\n\n**Updated review** \u2014 an optional `previous-studies:` block draws a dashed box on top that feeds into the identification section:\n\n```\nprevious-studies:\n n: 19\n sources: previous review=19\n```\n\n---\n\n## 7. Count arithmetic validation\n\nWith `validate-counts: warn` (default) the engine checks that the counts reconcile across stages \u2014 e.g. `databases.n + other.n \u2212 duplicates-removed = records-screened`, and that source/reason breakdowns sum to their totals. Mismatches render a small warning under the diagram (also surfaced in the SVG `<desc>` for screen readers).\n\n`validate-counts: strict` turns a mismatch into a parse error with an "off by N" message. `off` skips checking entirely.\n\n---\n\n## 8. Grammar (EBNF)\n\n```\nprisma-document = "prisma", { meta-line }, stage-block, { stage-block } ;\nmeta-line = ("mode:" | "kind:" | "title:" | "review-id:" | "validate-counts:" | "direction:") value ;\n\nstage-block = previous-block | identification-block | screening-block | eligibility-block | included-block ;\n\nprevious-block = "previous-studies:" , indent, "n:" int, [ "reports:" int ], { "sources:" pairs } ;\nidentification-block = "identification:" , indent,\n "databases:" , indent, "n:" int, { "sources:" pairs },\n [ "duplicates-removed:" int ], [ "ineligible-automation:" int ], [ "other-removed:" int ],\n [ "other:" , indent, "n:" int, { "sources:" pairs } ] ;\nscreening-block = "screening:" , indent, "records-screened:" int,\n "excluded:" , indent, "n:" int, { "reasons:" pairs },\n [ "reports-sought:" int ], [ "reports-not-retrieved:" int ] ;\neligibility-block = "eligibility:" , indent, "full-text-assessed:" int,\n "excluded:" , indent, "n:" int, { "reasons:" pairs } ;\nincluded-block = "included:" , indent, "studies:" int, [ "reports:" int ], [ "participants:" int ] ;\n\npairs = pair, { "," pair } ;\npair = (string | quoted) "=" int ;\nint = digit, { digit | "," } ; (* commas stripped: 1,234 == 1234 *)\n```\n\nIndentation is two spaces per level. Unknown keys inside a stage block are a parse error, keeping each stage well-defined.\n\n---'
@@ -1748,11 +1868,345 @@ function getExamplesForType(type, opts = {}) {
1748
1868
  return sorted.slice(0, limit);
1749
1869
  }
1750
1870
 
1871
+ // src/ai/profiles.ts
1872
+ var COMMON_GENERATION_RULES = [
1873
+ "Generate one diagram document with one selected diagram type.",
1874
+ "Use the canonical header and canonical forms from the generation profile first.",
1875
+ 'Use ASCII double quotes (") for generated labels and titles.',
1876
+ "Do not emit DSL comments unless the user explicitly asks for annotated source.",
1877
+ "Prefer explicit IDs and declarations when they make validation less ambiguous.",
1878
+ "Call validateDsl with the explicit selected type, fix reported errors, and validate again before returning DSL."
1879
+ ];
1880
+ var PROFILES = {
1881
+ genogram: {
1882
+ type: "genogram",
1883
+ header: 'genogram "Title"',
1884
+ mode: "family declarations + indented children",
1885
+ forms: [
1886
+ "personId [sex, birthYear, optionalAttrs]",
1887
+ 'parentA -- parentB "optional relationship label"',
1888
+ "indent children under the couple line"
1889
+ ],
1890
+ prefer: ["Declare people before emotional relationships.", 'Use `[label: "..."]` only where the syntax reference shows a label attribute.'],
1891
+ avoid: ["Avoid inline comments and speculative relationship operators."],
1892
+ repair: ["Unknown individuals usually need a declaration before the relationship line."]
1893
+ },
1894
+ ecomap: {
1895
+ type: "ecomap",
1896
+ header: 'ecomap "Title"',
1897
+ mode: "center + external systems",
1898
+ forms: [
1899
+ 'center: client [label: "Client"]',
1900
+ 'systemId [label: "System", category: family]',
1901
+ 'systemId === client [label: "support"]'
1902
+ ],
1903
+ prefer: ["Declare exactly one center.", "Declare outside systems before their connection lines."],
1904
+ avoid: ["Avoid borrowing genogram operators such as `--`."],
1905
+ repair: ["A valid render with a missing center is semantically wrong; add `center:` first."]
1906
+ },
1907
+ pedigree: {
1908
+ type: "pedigree",
1909
+ header: 'pedigree "Title"',
1910
+ mode: "clinical pedigree",
1911
+ forms: [
1912
+ "personId [sex, generationAttrs]",
1913
+ "parentA -- parentB",
1914
+ "indent offspring under the couple line"
1915
+ ],
1916
+ prefer: ["Use pedigree status/trait attributes from the syntax reference.", "Keep generation structure explicit."],
1917
+ avoid: ["Avoid genogram emotional-relationship lines in pedigree output."],
1918
+ repair: ["Declare every referenced individual before relationships."]
1919
+ },
1920
+ phylo: {
1921
+ type: "phylo",
1922
+ header: 'phylo "Title"',
1923
+ mode: "quoted Newick",
1924
+ forms: ['newick: "((A:0.1,B:0.2),C:0.3);"', 'clade Group = (A, B) [label: "Group"]'],
1925
+ prefer: ["Use Newick for first-shot generation.", "Quote the Newick string."],
1926
+ avoid: ["Avoid indent-tree mode unless the user wants a hand-authored tree."],
1927
+ repair: ["A phylo document needs exactly one tree definition: Newick or indent tree."]
1928
+ },
1929
+ sociogram: {
1930
+ type: "sociogram",
1931
+ header: 'sociogram "Title"',
1932
+ mode: "declared nodes + social ties",
1933
+ forms: ['nodeId [label: "Person"]', 'nodeA -> nodeB [label: "choice"]', "config: layout = circular"],
1934
+ prefer: ["Declare actors first.", "Use one supported layout/config value at a time."],
1935
+ avoid: ["Avoid unknown config values; some adapters keep defaults."],
1936
+ repair: ["Unknown edge endpoints need matching node declarations."]
1937
+ },
1938
+ timing: {
1939
+ type: "timing",
1940
+ header: 'timing "Title"',
1941
+ mode: "WaveDrom-compatible signals",
1942
+ forms: ["CLK: pppppppp", 'DATA: x======x data: ["A", "B"]'],
1943
+ prefer: ["Keep wave strings contiguous with no internal spaces.", "Use `data:` labels for bus segments."],
1944
+ avoid: ["Avoid unsupported WaveDrom annotation syntax."],
1945
+ repair: ["Invalid wave strings usually contain a character outside the timing wave table."]
1946
+ },
1947
+ logic: {
1948
+ type: "logic",
1949
+ header: 'logic "Title"',
1950
+ mode: "logic netlist",
1951
+ forms: ["INPUT A, B", "G1 = AND(A, B)", "OUTPUT Y = G1"],
1952
+ prefer: ["Use canonical gate names and explicit inputs/outputs."],
1953
+ avoid: ["Avoid circuit component names inside logic diagrams."],
1954
+ repair: ["Unknown gate kinds should be replaced with the closest listed logic primitive."]
1955
+ },
1956
+ circuit: {
1957
+ type: "circuit",
1958
+ header: 'circuit "Title" netlist',
1959
+ mode: "SPICE-style netlist",
1960
+ forms: ["V1 vcc 0 5V", "R1 vcc out 10k", "C1 out 0 100n"],
1961
+ prefer: ["Use netlist mode for generated schematics unless geometry is the task.", "Add explicit `type=` when an ID prefix is ambiguous."],
1962
+ avoid: ["Avoid positional cursor routing (`wire`, `at:`) for first-shot output."],
1963
+ repair: ["If a component type or pin count is ambiguous, make the symbol type explicit."]
1964
+ },
1965
+ blockdiagram: {
1966
+ type: "blockdiagram",
1967
+ header: 'blockdiagram "Title"',
1968
+ mode: "blocks, sums, signals",
1969
+ forms: ['ctrl = block("PID") [role: controller]', "err = sum(+r, -y)", "err -> ctrl -> plant"],
1970
+ prefer: ["Use named blocks and directed `->` chains."],
1971
+ avoid: ["Avoid unlabeled feedback intent; model the summing junction."],
1972
+ repair: ["Connections must point at declared blocks, sums, signals, or boundary IDs."]
1973
+ },
1974
+ ladder: {
1975
+ type: "ladder",
1976
+ header: 'ladder "Title"',
1977
+ mode: "rungs + IEC/Rockwell elements",
1978
+ forms: ['rung 1 "Run motor":', " XIC(START_PB)", " OTE(MOTOR_RUN)"],
1979
+ prefer: ["Use uppercase element names.", "Use `parallel:` + `branch:` only for OR branches."],
1980
+ avoid: ["Avoid variable declarations and ST syntax."],
1981
+ repair: ["Element typos are repairable from parser suggestions; keep the tag in parentheses."]
1982
+ },
1983
+ sld: {
1984
+ type: "sld",
1985
+ header: 'sld "Title"',
1986
+ mode: "equipment assignments + power-flow edges",
1987
+ forms: ['util = utility [label: "Grid"]', 'xfmr = transformer [rating: "500 kVA"]', "util -> xfmr -> load is not allowed; use one edge per line"],
1988
+ prefer: ["Declare equipment as `id = nodeType [attrs]`.", "Use one `from -> to` connection per line."],
1989
+ avoid: ["Avoid generic flowchart node syntax."],
1990
+ repair: ["Unknown equipment types often have a suggested canonical type or alias."]
1991
+ },
1992
+ entity: {
1993
+ type: "entity",
1994
+ header: 'entity-structure "Title"',
1995
+ mode: "legal entities + ownership edges",
1996
+ forms: ['entity holdco "HoldCo" corp@US', 'entity opco "OpCo" llc@DE', "holdco -> opco : 100%"],
1997
+ prefer: ["Use `entity` declarations before ownership edges.", "Keep legal form and jurisdiction explicit when known."],
1998
+ avoid: ["Avoid database schema terminology; use `erd` for tables and FKs."],
1999
+ repair: ["Unknown ownership endpoints need entity declarations."]
2000
+ },
2001
+ fishbone: {
2002
+ type: "fishbone",
2003
+ header: 'fishbone "Title"',
2004
+ mode: "effect + cause categories",
2005
+ forms: ['effect "Late Delivery"', 'category process "Process"', 'process: "Handoff delay"'],
2006
+ prefer: ["Use one effect and structured categories for generated DSL."],
2007
+ avoid: ["Avoid mixing compact alien syntax when a structured category form works."],
2008
+ repair: ["If a cause lands nowhere, add or reference its category explicitly."]
2009
+ },
2010
+ venn: {
2011
+ type: "venn",
2012
+ header: 'venn "Title"',
2013
+ mode: "declared-set region counts",
2014
+ forms: ['set A "Group A"', 'set B "Group B"', "A & B : 120", "A only : 80"],
2015
+ prefer: ["Use declared sets plus region counts for first-shot Venn output.", "Use Euler relations only when subset/disjoint structure is the request."],
2016
+ avoid: ["Avoid mixing enumeration mode with explicit region counts."],
2017
+ repair: ["Declare every set before region or Euler relation lines."]
2018
+ },
2019
+ flowchart: {
2020
+ type: "flowchart",
2021
+ header: 'flowchart TD "Title"',
2022
+ mode: "Mermaid-compatible nodes + edges",
2023
+ forms: ["start([Start]) --> check{Decision?}", "check -->|Yes| done([Done])"],
2024
+ prefer: ["Choose one direction in the header.", "Declare shapes explicitly when shape matters."],
2025
+ avoid: ["Avoid subgraph complexity unless grouping is part of the request."],
2026
+ repair: ["A bad header direction fails early; use TD, TB, BT, LR, or RL."]
2027
+ },
2028
+ mindmap: {
2029
+ type: "mindmap",
2030
+ header: "mindmap",
2031
+ mode: "Markdown headings + bullets",
2032
+ forms: ["# Root", "## Branch", "- Child item"],
2033
+ prefer: ["Use exactly one `#` root heading.", "Use bullets/headings instead of graph edges."],
2034
+ avoid: ["Avoid comments in the body."],
2035
+ repair: ["An orphan branch means the root `#` heading is missing."]
2036
+ },
2037
+ matrix: {
2038
+ type: "matrix",
2039
+ header: 'matrix "Title"',
2040
+ mode: "quadrant scatter",
2041
+ forms: ["x-axis: Low -> High", "y-axis: Low -> High", '"Item" at (0.25, 0.8)'],
2042
+ prefer: ["Use quadrant scatter for first-shot prioritization/portfolio requests.", "Use built-in templates when the framework is named."],
2043
+ avoid: ["Avoid heatmap, correlation, and table modes unless the user asks for that form."],
2044
+ repair: ["Point coordinates are normalized fractions; keep them in `[0,1]`."]
2045
+ },
2046
+ orgchart: {
2047
+ type: "orgchart",
2048
+ header: 'orgchart "Title"',
2049
+ mode: "indented hierarchy",
2050
+ forms: ['ceo: "Name" | CEO', ' cto: "Name" | CTO', ' eng: "Name" | Engineer'],
2051
+ prefer: ["Use indentation for the reporting tree.", "Use dotted explicit edges only for matrix reporting."],
2052
+ avoid: ["Avoid mixing explicit report edges with indentation unless needed."],
2053
+ repair: ["Duplicate IDs and unknown explicit edge endpoints are parse failures."]
2054
+ },
2055
+ decisiontree: {
2056
+ type: "decisiontree",
2057
+ header: 'decisiontree "Title"',
2058
+ mode: "taxonomy questions",
2059
+ forms: ['question "Question?"', ' yes: answer "Outcome"', ' no: answer "Other outcome"'],
2060
+ prefer: ["Use taxonomy mode for troubleshooting and triage.", "Select `decisiontree:decision` or `decisiontree:ml` only when expected value or ML is explicit."],
2061
+ avoid: ["Avoid mixing mode-specific keywords."],
2062
+ repair: ["Indent each child under its parent and use the branch prefix required by the selected mode."]
2063
+ },
2064
+ timeline: {
2065
+ type: "timeline",
2066
+ header: 'timeline "Title"',
2067
+ mode: "dated events",
2068
+ forms: ['2026-05-22: "Event"', '2026-06-01 - 2026-06-30: "Phase"', '2026-07-01: milestone "Launch"'],
2069
+ prefer: ["Use dated events/ranges and `milestone` for important points."],
2070
+ avoid: ["Avoid custom row keys when a date is known."],
2071
+ repair: ["Quote labels and keep the colon after the date/range."]
2072
+ },
2073
+ state: {
2074
+ type: "state",
2075
+ header: 'state "Title"',
2076
+ mode: "Schematex statechart core",
2077
+ forms: ["initial Start", "Start --> Running : event", "Running --> Done", "final Done"],
2078
+ prefer: ["Use `state` header for generated DSL.", "Use Mermaid `stateDiagram-v2` only when adapting Mermaid input."],
2079
+ avoid: ["Avoid composite/concurrent-state syntax until the request needs it."],
2080
+ repair: ["Use `-->` transitions and a named state between initial/final aliases."]
2081
+ },
2082
+ pid: {
2083
+ type: "pid",
2084
+ header: 'pid "Title"',
2085
+ mode: "equipment + process lines",
2086
+ forms: ["equip T-101 : tank_atm", "equip P-101 : pump_centrifugal", "line L1 from T-101.bottom to P-101.in"],
2087
+ prefer: ["Declare equipment first, then process/signal lines."],
2088
+ avoid: ["Avoid SLD electrical nodes in a P&ID."],
2089
+ repair: ["Unknown equipment and instrument categories must come from the catalog."]
2090
+ },
2091
+ erd: {
2092
+ type: "erd",
2093
+ header: "erd",
2094
+ mode: "table blocks + named cardinality refs",
2095
+ forms: ["table User { id int PK; email varchar }", "table Order { id int PK; user_id int FK -> User.id }", "ref Order.user_id many-mandatory -- one-mandatory User.id"],
2096
+ prefer: ["Use named cardinality tokens for generated refs.", "Keep FK targets explicit."],
2097
+ avoid: ["Avoid Mermaid cardinality glyphs unless converting Mermaid input."],
2098
+ repair: ["Unknown cardinality tokens and unterminated table blocks fail validation."]
2099
+ },
2100
+ breadboard: {
2101
+ type: "breadboard",
2102
+ header: "breadboard",
2103
+ mode: "parts + wires blocks",
2104
+ forms: ['title: "Prototype"', "parts", "wires"],
2105
+ prefer: ["Use physical parts and addressable tie points.", "Keep schematic tasks on `circuit` instead."],
2106
+ avoid: ["Avoid abstract netlist syntax in breadboard output."],
2107
+ repair: ["Missing parts or invalid breadboard connection endpoints need the breadboard syntax reference."]
2108
+ },
2109
+ bpmn: {
2110
+ type: "bpmn",
2111
+ header: "bpmn",
2112
+ mode: "pool/lane objects + flows",
2113
+ forms: ['pool "Service" {', ' lane "Worker" { A: start "Request" }', "flows", "A --> B"],
2114
+ prefer: ["Use pools, lanes, and a `flows` block.", "Use `~~>` only for cross-pool message flow."],
2115
+ avoid: ["Avoid generic flowchart syntax for BPMN semantics."],
2116
+ repair: ["Sequence flows cannot cross pools; switch to message flow when needed."]
2117
+ },
2118
+ fbd: {
2119
+ type: "fbd",
2120
+ header: 'fbd "Title"',
2121
+ mode: "networks + blocks",
2122
+ forms: ["var Start: bool", 'network "Logic":', "Motor = AND(Start, Safe)"],
2123
+ prefer: ["Use network/expression forms from the FBD syntax guide."],
2124
+ avoid: ["Avoid ladder rung syntax in FBD output."],
2125
+ repair: ["Invalid block calls need a supported block and valid arguments."]
2126
+ },
2127
+ sfc: {
2128
+ type: "sfc",
2129
+ header: 'sfc "Title"',
2130
+ mode: "steps + transitions",
2131
+ forms: ["step Idle [initial]", "transition Idle -> Run : Start", "step Run"],
2132
+ prefer: ["Use explicit steps and transitions before alternative/simultaneous branches."],
2133
+ avoid: ["Avoid UML state syntax in SFC output."],
2134
+ repair: ["Every transition step reference must resolve to a declared step."]
2135
+ },
2136
+ prisma: {
2137
+ type: "prisma",
2138
+ header: "prisma",
2139
+ mode: "PRISMA 2020 single pipeline",
2140
+ forms: ["identification:", " databases:", " n: 1000", "screening:", "included:"],
2141
+ prefer: ["Use the required four stages and mandatory counts.", "Use single-pipeline 2020 mode unless other-methods data is present."],
2142
+ avoid: ["Avoid generic flowchart boxes for PRISMA requests."],
2143
+ repair: ["Missing stage blocks or mandatory `n` fields are intentional parser errors."]
2144
+ },
2145
+ usecase: {
2146
+ type: "usecase",
2147
+ header: "usecase",
2148
+ mode: "declarative UML use cases",
2149
+ forms: ['system: "System"', "actor: Customer", 'usecase: "Checkout" as Checkout', "Customer -- Checkout"],
2150
+ prefer: ["Use declarative actor/usecase lines for generated DSL."],
2151
+ avoid: ["Avoid PlantUML inline form unless converting PlantUML-like input."],
2152
+ repair: ["Include/extend relations must connect use cases, not actors."]
2153
+ },
2154
+ pert: {
2155
+ type: "pert",
2156
+ header: "pert",
2157
+ mode: "AON tasks + dependencies",
2158
+ forms: ['task A "Spec" duration: 3', 'task B "Build" duration: 8 after: A'],
2159
+ prefer: ["Use AON network tasks first.", "Use time-scaled/AOA layouts only when requested."],
2160
+ avoid: ["Avoid writing computed ES/EF/LS/LF fields yourself."],
2161
+ repair: ["Task IDs must exist before they are used in `after:` lists."]
2162
+ },
2163
+ sequence: {
2164
+ type: "sequence",
2165
+ header: 'sequence "Title"',
2166
+ mode: "participants + messages",
2167
+ forms: ["actor User", 'participant API as "API"', "User -> API : request", "API --> User : response"],
2168
+ prefer: ["Start with participants/messages, then add fragments only if control flow matters."],
2169
+ avoid: ["Avoid Mermaid `sequenceDiagram` header; this parser uses `sequence`."],
2170
+ repair: ["Unmatched `end`, `else`, or activation statements are validation failures."]
2171
+ }
2172
+ };
2173
+ function getGenerationProfile(type) {
2174
+ return PROFILES[type];
2175
+ }
2176
+
1751
2177
  // src/ai/syntax.ts
1752
- function getSyntaxForType(syntaxKey) {
2178
+ function getSyntaxForType(syntaxKey, type, detail = "canonical") {
1753
2179
  const s = SYNTAX[syntaxKey];
1754
2180
  if (!s) return void 0;
1755
- return { key: syntaxKey, ...s };
2181
+ return {
2182
+ key: syntaxKey,
2183
+ title: s.title,
2184
+ detail,
2185
+ content: detail === "reference" ? s.content : buildCanonicalSyntax(getGenerationProfile(type))
2186
+ };
2187
+ }
2188
+ function buildCanonicalSyntax(profile) {
2189
+ return [
2190
+ "# Canonical generation syntax",
2191
+ "",
2192
+ 'Use this compact path for new DSL generation. Ask for `detail: "reference"` only when the request needs advanced forms or an imported adapter.',
2193
+ "",
2194
+ "## Generation profile",
2195
+ "",
2196
+ `- Canonical type: \`${profile.type}\``,
2197
+ `- Canonical header: \`${profile.header}\``,
2198
+ `- Preferred mode: ${profile.mode}`,
2199
+ bulletSection("Core forms", profile.forms),
2200
+ bulletSection("Prefer", profile.prefer),
2201
+ bulletSection("Avoid by default", profile.avoid),
2202
+ bulletSection("Repair checks", profile.repair),
2203
+ "## Shared generation rules",
2204
+ "",
2205
+ ...COMMON_GENERATION_RULES.map((rule) => `- ${rule}`)
2206
+ ].filter((part) => part !== "").join("\n");
2207
+ }
2208
+ function bulletSection(title, items) {
2209
+ return [`### ${title}`, "", ...items.map((item) => `- ${item}`), ""].join("\n");
1756
2210
  }
1757
2211
 
1758
2212
  // src/ai/tools.ts
@@ -1766,14 +2220,14 @@ function listDiagrams() {
1766
2220
  standard: d.standard
1767
2221
  }));
1768
2222
  }
1769
- function getSyntax(type) {
2223
+ function getSyntax(type, opts = {}) {
1770
2224
  const meta = getDiagramMeta(type);
1771
2225
  if (!meta) {
1772
2226
  throw new Error(
1773
2227
  `Unknown diagram type '${type}'. Call listDiagrams() for valid types.`
1774
2228
  );
1775
2229
  }
1776
- const syntax = getSyntaxForType(meta.syntaxKey);
2230
+ const syntax = getSyntaxForType(meta.syntaxKey, meta.type, opts.detail);
1777
2231
  if (!syntax) {
1778
2232
  throw new Error(`No syntax doc available for '${type}' (key: ${meta.syntaxKey}).`);
1779
2233
  }
@@ -1795,38 +2249,66 @@ function getExamples(type, opts = {}) {
1795
2249
  return { type: meta.type, count: examples.length, examples };
1796
2250
  }
1797
2251
  function validateDsl(type, dsl) {
1798
- const config = type ? { type } : void 0;
1799
- try {
1800
- chunk3YUUC6RN_cjs.parse(dsl, config);
1801
- return { ok: true, type: type ?? resolveTypeFromText(dsl) };
1802
- } catch (err) {
1803
- return {
1804
- ok: false,
1805
- type: type ?? resolveTypeFromText(dsl),
1806
- errors: [extractError(err)]
1807
- };
2252
+ const resolvedType = type ? resolveDiagramType(type) : void 0;
2253
+ const config = type ? { type: resolvedType ?? type } : void 0;
2254
+ const result = chunk4QPDZJAL_cjs.parseResult(dsl, config);
2255
+ if (result.ok) {
2256
+ return { ok: true, type: result.type };
1808
2257
  }
2258
+ return {
2259
+ ok: false,
2260
+ type: result.type ?? resolvedType ?? resolveTypeFromText(dsl),
2261
+ errors: result.diagnostics.map(
2262
+ (diagnostic) => toValidationError(diagnostic, result.type ?? resolvedType)
2263
+ )
2264
+ };
1809
2265
  }
1810
2266
  function renderDsl(type, dsl, options = {}) {
2267
+ const resolvedType = type ? resolveDiagramType(type) : void 0;
1811
2268
  const config = {
1812
2269
  ...options,
1813
- ...type ? { type } : {}
2270
+ ...type ? { type: resolvedType ?? type } : {}
1814
2271
  };
1815
- try {
1816
- const svg = chunk3YUUC6RN_cjs.render(dsl, config);
1817
- return { ok: true, type: type ?? resolveTypeFromText(dsl), svg };
1818
- } catch (err) {
2272
+ const result = chunk4QPDZJAL_cjs.renderResult(dsl, config);
2273
+ if (result.ok) {
1819
2274
  return {
1820
- ok: false,
1821
- type: type ?? resolveTypeFromText(dsl),
1822
- errors: [extractError(err)]
2275
+ ok: true,
2276
+ status: result.status,
2277
+ type: result.type,
2278
+ svg: result.svg
1823
2279
  };
1824
2280
  }
2281
+ return {
2282
+ ok: false,
2283
+ status: result.status,
2284
+ type: result.type ?? resolvedType ?? resolveTypeFromText(dsl),
2285
+ svg: result.svg,
2286
+ errors: result.diagnostics.map(
2287
+ (diagnostic) => toValidationError(diagnostic, result.type ?? resolvedType)
2288
+ )
2289
+ };
1825
2290
  }
1826
2291
  function resolveTypeFromText(text) {
1827
2292
  const first = text.trim().split(/\s+|\n/)[0]?.toLowerCase() ?? "";
1828
- const meta = DIAGRAM_REGISTRY.find((d) => d.type === first);
1829
- return meta?.type ?? null;
2293
+ return resolveDiagramType(first) ?? null;
2294
+ }
2295
+ function toValidationError(diagnostic, type) {
2296
+ return {
2297
+ line: diagnostic.line,
2298
+ column: diagnostic.column,
2299
+ source: diagnostic.source,
2300
+ message: diagnostic.message,
2301
+ hint: diagnostic.hint ?? repairHint(type)
2302
+ };
2303
+ }
2304
+ function repairHint(type) {
2305
+ const resolved = type ? resolveDiagramType(type) : void 0;
2306
+ const profile = resolved ? getGenerationProfile(resolved) : void 0;
2307
+ const typeHint = profile?.repair[0];
2308
+ return [
2309
+ typeHint,
2310
+ "Fix the reported DSL error, then call validateDsl again before rendering or returning DSL."
2311
+ ].filter(Boolean).join(" ");
1830
2312
  }
1831
2313
 
1832
2314
  exports.DIAGRAM_REGISTRY = DIAGRAM_REGISTRY;
@@ -1836,6 +2318,7 @@ exports.getExamples = getExamples;
1836
2318
  exports.getSyntax = getSyntax;
1837
2319
  exports.listDiagrams = listDiagrams;
1838
2320
  exports.renderDsl = renderDsl;
2321
+ exports.resolveDiagramType = resolveDiagramType;
1839
2322
  exports.validateDsl = validateDsl;
1840
- //# sourceMappingURL=chunk-NWPCY65Z.cjs.map
1841
- //# sourceMappingURL=chunk-NWPCY65Z.cjs.map
2323
+ //# sourceMappingURL=chunk-HK56GQQP.cjs.map
2324
+ //# sourceMappingURL=chunk-HK56GQQP.cjs.map