drawio-mcp-server 1.7.0 → 2.0.3

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 (52) hide show
  1. package/README.md +96 -425
  2. package/build/assets/downloader.js +96 -0
  3. package/build/assets/index.js +2 -0
  4. package/build/assets/manager.js +31 -0
  5. package/build/config.js +45 -0
  6. package/build/config.test.js +54 -0
  7. package/build/emitter_bus.js +2 -3
  8. package/build/index.js +305 -337
  9. package/build/plugin/mcp-plugin.js +2618 -0
  10. package/build/prefetch-assets.js +11 -0
  11. package/build/real-environment/add-cell-of-shape.test.js +51 -0
  12. package/build/real-environment/add-edge.test.js +86 -0
  13. package/build/real-environment/assertions.js +18 -0
  14. package/build/real-environment/delete-cell-by-id.test.js +45 -0
  15. package/build/real-environment/edge-editing.test.js +70 -0
  16. package/build/real-environment/edit-cell.test.js +64 -0
  17. package/build/real-environment/harness.js +175 -0
  18. package/build/real-environment/import-export.test.js +82 -0
  19. package/build/real-environment/layers-and-selection.test.js +70 -0
  20. package/build/real-environment/logger.js +25 -0
  21. package/build/real-environment/screenshot.js +46 -0
  22. package/build/real-environment/set-cell-parent.test.js +64 -0
  23. package/build/real-environment/shapes.test.js +153 -0
  24. package/build/real-environment/test-helpers.js +10 -0
  25. package/build/real-environment/tools.js +22 -0
  26. package/build/real-environment/types.js +1 -0
  27. package/build/tool.js +46 -0
  28. package/build/tools/add-cell-of-shape.js +42 -0
  29. package/build/tools/add-edge.js +33 -0
  30. package/build/tools/add-rectangle.js +41 -0
  31. package/build/tools/create-layer.js +8 -0
  32. package/build/tools/delete-cell-by-id.js +10 -0
  33. package/build/tools/edit-cell.js +28 -0
  34. package/build/tools/edit-edge.js +30 -0
  35. package/build/tools/export-diagram.js +96 -0
  36. package/build/tools/get-active-layer.js +5 -0
  37. package/build/tools/get-selected-cell.js +5 -0
  38. package/build/tools/get-shape-by-name.js +10 -0
  39. package/build/tools/get-shape-categories.js +5 -0
  40. package/build/tools/get-shapes-in-category.js +10 -0
  41. package/build/tools/import-diagram.js +22 -0
  42. package/build/tools/index.js +49 -0
  43. package/build/tools/list-layers.js +5 -0
  44. package/build/tools/list-paged-model.js +41 -0
  45. package/build/tools/move-cell-to-layer.js +11 -0
  46. package/build/tools/set-active-layer.js +8 -0
  47. package/build/tools/set-cell-data.js +14 -0
  48. package/build/tools/set-cell-parent.js +9 -0
  49. package/build/tools/set-cell-shape.js +13 -0
  50. package/build/tools/shared.js +7 -0
  51. package/build/tools/types.js +1 -0
  52. package/package.json +29 -22
@@ -0,0 +1,2618 @@
1
+ "use strict";
2
+ var DrawMcp = (() => {
3
+ // src/shape-library.ts
4
+ var shapeLibrary = {
5
+ rectangle: {
6
+ category: "general",
7
+ style: "rounded=0;whiteSpace=wrap;html=1;"
8
+ },
9
+ rounded_rectangle: {
10
+ category: "general",
11
+ style: "rounded=1;whiteSpace=wrap;html=1;"
12
+ },
13
+ text: {
14
+ category: "general",
15
+ style: "text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;"
16
+ },
17
+ ellipse: {
18
+ category: "general",
19
+ style: "ellipse;whiteSpace=wrap;html=1;"
20
+ },
21
+ square: {
22
+ category: "general",
23
+ style: "whiteSpace=wrap;html=1;aspect=fixed;"
24
+ },
25
+ circle: {
26
+ category: "general",
27
+ style: "ellipse;whiteSpace=wrap;html=1;aspect=fixed;"
28
+ },
29
+ process: {
30
+ category: "general",
31
+ style: "shape=process;whiteSpace=wrap;html=1;backgroundOutline=1;"
32
+ },
33
+ diamond: {
34
+ category: "general",
35
+ style: "rhombus;whiteSpace=wrap;html=1;"
36
+ },
37
+ parallelogram: {
38
+ category: "general",
39
+ style: "shape=parallelogram;perimeter=parallelogramPerimeter;whiteSpace=wrap;html=1;fixedSize=1;"
40
+ },
41
+ hexagon: {
42
+ category: "general",
43
+ style: "shape=hexagon;perimeter=hexagonPerimeter2;whiteSpace=wrap;html=1;fixedSize=1;"
44
+ },
45
+ triangle: {
46
+ category: "general",
47
+ style: "triangle;whiteSpace=wrap;html=1;"
48
+ },
49
+ cylinder3: {
50
+ category: "general",
51
+ style: "shape=cylinder3;whiteSpace=wrap;html=1;boundedLbl=1;backgroundOutline=1;size=15;"
52
+ },
53
+ cloud: {
54
+ category: "general",
55
+ style: "ellipse;shape=cloud;whiteSpace=wrap;html=1;"
56
+ },
57
+ document: {
58
+ category: "general",
59
+ style: "shape=document;whiteSpace=wrap;html=1;boundedLbl=1;"
60
+ },
61
+ internalStorage: {
62
+ category: "general",
63
+ style: "shape=internalStorage;whiteSpace=wrap;html=1;backgroundOutline=1;"
64
+ },
65
+ cube: {
66
+ category: "general",
67
+ style: "shape=cube;whiteSpace=wrap;html=1;boundedLbl=1;backgroundOutline=1;darkOpacity=0.05;darkOpacity2=0.1;"
68
+ },
69
+ step: {
70
+ category: "general",
71
+ style: "shape=step;perimeter=stepPerimeter;whiteSpace=wrap;html=1;fixedSize=1;"
72
+ },
73
+ trapezoid: {
74
+ category: "general",
75
+ style: "shape=trapezoid;perimeter=trapezoidPerimeter;whiteSpace=wrap;html=1;fixedSize=1;"
76
+ },
77
+ tape: {
78
+ category: "general",
79
+ style: "shape=tape;whiteSpace=wrap;html=1;"
80
+ },
81
+ note: {
82
+ category: "general",
83
+ style: "shape=note;whiteSpace=wrap;html=1;backgroundOutline=1;darkOpacity=0.05;"
84
+ },
85
+ card: {
86
+ category: "general",
87
+ style: "shape=card;whiteSpace=wrap;html=1;"
88
+ },
89
+ callout: {
90
+ category: "general",
91
+ style: "shape=callout;whiteSpace=wrap;html=1;perimeter=calloutPerimeter;"
92
+ },
93
+ umlActor: {
94
+ category: "general",
95
+ style: "shape=umlActor;verticalLabelPosition=bottom;verticalAlign=top;html=1;outlineConnect=0;"
96
+ },
97
+ xor: {
98
+ category: "general",
99
+ style: "shape=xor;whiteSpace=wrap;html=1;"
100
+ },
101
+ or: {
102
+ category: "general",
103
+ style: "shape=or;whiteSpace=wrap;html=1;"
104
+ },
105
+ dataStorage: {
106
+ category: "general",
107
+ style: "shape=dataStorage;whiteSpace=wrap;html=1;fixedSize=1;"
108
+ },
109
+ swimlane: {
110
+ category: "general",
111
+ title: "Container",
112
+ style: "swimlane;startSize=0;"
113
+ },
114
+ verticalContainer: {
115
+ category: "general",
116
+ title: "Vertical Container",
117
+ style: "swimlane;whiteSpace=wrap;html=1;"
118
+ },
119
+ horizontalContainer: {
120
+ category: "general",
121
+ title: "Horizontal Container",
122
+ style: "swimlane;horizontal=0;whiteSpace=wrap;html=1;"
123
+ },
124
+ list: {
125
+ category: "general",
126
+ title: "List",
127
+ style: "swimlane;fontStyle=0;childLayout=stackLayout;horizontal=1;startSize=30;horizontalStack=0;resizeParent=1;resizeParentMax=0;resizeLast=0;collapsible=1;marginBottom=0;whiteSpace=wrap;html=1;"
128
+ },
129
+ listItem: {
130
+ category: "general",
131
+ title: "List Item",
132
+ style: "text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;"
133
+ },
134
+ curve: {
135
+ category: "general",
136
+ style: "curved=1;endArrow=classic;html=1;rounded=0;fontSize=12;startSize=8;endSize=8;"
137
+ },
138
+ flexArrow: {
139
+ category: "general",
140
+ title: "Bidirectional Arrow",
141
+ style: "shape=flexArrow;endArrow=classic;startArrow=classic;html=1;rounded=0;fontSize=12;startSize=8;endSize=8;curved=1;"
142
+ },
143
+ arrow: {
144
+ category: "general",
145
+ title: "Arrow",
146
+ style: "shape=flexArrow;endArrow=classic;html=1;rounded=0;fontSize=12;startSize=8;endSize=8;curved=1;"
147
+ },
148
+ dashedLine: {
149
+ category: "general",
150
+ style: "endArrow=none;dashed=1;html=1;rounded=0;fontSize=12;startSize=8;endSize=8;curved=1;"
151
+ },
152
+ dottedLine: {
153
+ category: "general",
154
+ style: "endArrow=none;dashed=1;html=1;dashPattern=1 3;strokeWidth=2;rounded=0;fontSize=12;startSize=8;endSize=8;"
155
+ },
156
+ line: {
157
+ category: "general",
158
+ style: "endArrow=none;html=1;rounded=0;fontSize=12;startSize=8;endSize=8;curved=1;"
159
+ },
160
+ bidirectionalConnector: {
161
+ category: "general",
162
+ style: "endArrow=classic;startArrow=classic;html=1;rounded=0;fontSize=12;startSize=8;endSize=8;curved=1;"
163
+ },
164
+ directionalConnector: {
165
+ category: "general",
166
+ style: "endArrow=classic;html=1;rounded=0;fontSize=12;startSize=8;endSize=8;curved=1;"
167
+ },
168
+ // AWS / Analytics
169
+ "mxgraph.aws4.athena": {
170
+ category: "mxgraph.aws4.analytics",
171
+ style: "sketch=0;points=[[0,0,0],[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0,0],[0,1,0],[0.25,1,0],[0.5,1,0],[0.75,1,0],[1,1,0],[0,0.25,0],[0,0.5,0],[0,0.75,0],[1,0.25,0],[1,0.5,0],[1,0.75,0]];outlineConnect=0;fontColor=#232F3E;fillColor=#8C4FFF;strokeColor=#ffffff;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=12;fontStyle=0;aspect=fixed;shape=mxgraph.aws4.resourceIcon;resIcon=mxgraph.aws4.athena;"
172
+ },
173
+ "mxgraph.aws4.elasticsearch_service": {
174
+ category: "mxgraph.aws4.analytics",
175
+ style: "sketch=0;points=[[0,0,0],[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0,0],[0,1,0],[0.25,1,0],[0.5,1,0],[0.75,1,0],[1,1,0],[0,0.25,0],[0,0.5,0],[0,0.75,0],[1,0.25,0],[1,0.5,0],[1,0.75,0]];outlineConnect=0;fontColor=#232F3E;fillColor=#8C4FFF;strokeColor=#ffffff;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=12;fontStyle=0;aspect=fixed;shape=mxgraph.aws4.resourceIcon;resIcon=mxgraph.aws4.elasticsearch_service;"
176
+ },
177
+ "mxgraph.aws4.kinesis": {
178
+ category: "mxgraph.aws4.analytics",
179
+ style: "sketch=0;points=[[0,0,0],[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0,0],[0,1,0],[0.25,1,0],[0.5,1,0],[0.75,1,0],[1,1,0],[0,0.25,0],[0,0.5,0],[0,0.75,0],[1,0.25,0],[1,0.5,0],[1,0.75,0]];outlineConnect=0;fontColor=#232F3E;fillColor=#8C4FFF;strokeColor=#ffffff;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=12;fontStyle=0;aspect=fixed;shape=mxgraph.aws4.resourceIcon;resIcon=mxgraph.aws4.kinesis;"
180
+ },
181
+ "mxgraph.aws4.kinesis_data_analytics": {
182
+ category: "mxgraph.aws4.analytics",
183
+ style: "sketch=0;points=[[0,0,0],[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0,0],[0,1,0],[0.25,1,0],[0.5,1,0],[0.75,1,0],[1,1,0],[0,0.25,0],[0,0.5,0],[0,0.75,0],[1,0.25,0],[1,0.5,0],[1,0.75,0]];outlineConnect=0;fontColor=#232F3E;fillColor=#8C4FFF;strokeColor=#ffffff;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=12;fontStyle=0;aspect=fixed;shape=mxgraph.aws4.resourceIcon;resIcon=mxgraph.aws4.kinesis_data_analytics;"
184
+ },
185
+ "mxgraph.aws4.kinesis_data_firehose": {
186
+ category: "mxgraph.aws4.analytics",
187
+ style: "sketch=0;points=[[0,0,0],[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0,0],[0,1,0],[0.25,1,0],[0.5,1,0],[0.75,1,0],[1,1,0],[0,0.25,0],[0,0.5,0],[0,0.75,0],[1,0.25,0],[1,0.5,0],[1,0.75,0]];outlineConnect=0;fontColor=#232F3E;fillColor=#8C4FFF;strokeColor=#ffffff;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=12;fontStyle=0;aspect=fixed;shape=mxgraph.aws4.resourceIcon;resIcon=mxgraph.aws4.kinesis_data_firehose;"
188
+ },
189
+ "mxgraph.aws4.kinesis_data_streams": {
190
+ category: "mxgraph.aws4.analytics",
191
+ style: "sketch=0;points=[[0,0,0],[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0,0],[0,1,0],[0.25,1,0],[0.5,1,0],[0.75,1,0],[1,1,0],[0,0.25,0],[0,0.5,0],[0,0.75,0],[1,0.25,0],[1,0.5,0],[1,0.75,0]];outlineConnect=0;fontColor=#232F3E;fillColor=#8C4FFF;strokeColor=#ffffff;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=12;fontStyle=0;aspect=fixed;shape=mxgraph.aws4.resourceIcon;resIcon=mxgraph.aws4.kinesis_data_streams;"
192
+ },
193
+ "mxgraph.aws4.managed_service_for_apache_flink": {
194
+ category: "mxgraph.aws4.analytics",
195
+ style: "sketch=0;points=[[0,0,0],[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0,0],[0,1,0],[0.25,1,0],[0.5,1,0],[0.75,1,0],[1,1,0],[0,0.25,0],[0,0.5,0],[0,0.75,0],[1,0.25,0],[1,0.5,0],[1,0.75,0]];outlineConnect=0;fontColor=#232F3E;fillColor=#8C4FFF;strokeColor=#ffffff;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=12;fontStyle=0;aspect=fixed;shape=mxgraph.aws4.resourceIcon;resIcon=mxgraph.aws4.managed_service_for_apache_flink;"
196
+ },
197
+ "mxgraph.aws4.quicksight": {
198
+ category: "mxgraph.aws4.analytics",
199
+ style: "sketch=0;points=[[0,0,0],[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0,0],[0,1,0],[0.25,1,0],[0.5,1,0],[0.75,1,0],[1,1,0],[0,0.25,0],[0,0.5,0],[0,0.75,0],[1,0.25,0],[1,0.5,0],[1,0.75,0]];outlineConnect=0;fontColor=#232F3E;fillColor=#8C4FFF;strokeColor=#ffffff;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=12;fontStyle=0;aspect=fixed;shape=mxgraph.aws4.resourceIcon;resIcon=mxgraph.aws4.quicksight;"
200
+ },
201
+ "mxgraph.aws4.managed_streaming_for_kafka": {
202
+ category: "mxgraph.aws4.analytics",
203
+ style: "sketch=0;points=[[0,0,0],[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0,0],[0,1,0],[0.25,1,0],[0.5,1,0],[0.75,1,0],[1,1,0],[0,0.25,0],[0,0.5,0],[0,0.75,0],[1,0.25,0],[1,0.5,0],[1,0.75,0]];outlineConnect=0;fontColor=#232F3E;fillColor=#8C4FFF;strokeColor=#ffffff;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=12;fontStyle=0;aspect=fixed;shape=mxgraph.aws4.resourceIcon;resIcon=mxgraph.aws4.managed_streaming_for_kafka;"
204
+ },
205
+ "mxgraph.aws4.glue": {
206
+ category: "mxgraph.aws4.analytics",
207
+ style: "sketch=0;points=[[0,0,0],[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0,0],[0,1,0],[0.25,1,0],[0.5,1,0],[0.75,1,0],[1,1,0],[0,0.25,0],[0,0.5,0],[0,0.75,0],[1,0.25,0],[1,0.5,0],[1,0.75,0]];outlineConnect=0;fontColor=#232F3E;fillColor=#8C4FFF;strokeColor=#ffffff;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=12;fontStyle=0;aspect=fixed;shape=mxgraph.aws4.resourceIcon;resIcon=mxgraph.aws4.glue;"
208
+ },
209
+ // AWS / Compute
210
+ "mxgraph.aws4.compute": {
211
+ category: "mxgraph.aws4.compute",
212
+ style: "sketch=0;points=[[0,0,0],[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0,0],[0,1,0],[0.25,1,0],[0.5,1,0],[0.75,1,0],[1,1,0],[0,0.25,0],[0,0.5,0],[0,0.75,0],[1,0.25,0],[1,0.5,0],[1,0.75,0]];outlineConnect=0;fontColor=#232F3E;fillColor=#ED7100;strokeColor=#ffffff;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=12;fontStyle=0;aspect=fixed;shape=mxgraph.aws4.resourceIcon;resIcon=mxgraph.aws4.compute;"
213
+ },
214
+ "mxgraph.aws4.ec2": {
215
+ category: "mxgraph.aws4.compute",
216
+ style: "sketch=0;points=[[0,0,0],[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0,0],[0,1,0],[0.25,1,0],[0.5,1,0],[0.75,1,0],[1,1,0],[0,0.25,0],[0,0.5,0],[0,0.75,0],[1,0.25,0],[1,0.5,0],[1,0.75,0]];outlineConnect=0;fontColor=#232F3E;fillColor=#ED7100;strokeColor=#ffffff;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=12;fontStyle=0;aspect=fixed;shape=mxgraph.aws4.resourceIcon;resIcon=mxgraph.aws4.ec2;"
217
+ },
218
+ "mxgraph.aws4.lambda": {
219
+ category: "mxgraph.aws4.compute",
220
+ style: "sketch=0;points=[[0,0,0],[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0,0],[0,1,0],[0.25,1,0],[0.5,1,0],[0.75,1,0],[1,1,0],[0,0.25,0],[0,0.5,0],[0,0.75,0],[1,0.25,0],[1,0.5,0],[1,0.75,0]];outlineConnect=0;fontColor=#232F3E;fillColor=#ED7100;strokeColor=#ffffff;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=12;fontStyle=0;aspect=fixed;shape=mxgraph.aws4.resourceIcon;resIcon=mxgraph.aws4.lambda;"
221
+ },
222
+ // AWS / Containers
223
+ "mxgraph.aws4.containers": {
224
+ category: "mxgraph.aws4.containers",
225
+ style: "sketch=0;points=[[0,0,0],[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0,0],[0,1,0],[0.25,1,0],[0.5,1,0],[0.75,1,0],[1,1,0],[0,0.25,0],[0,0.5,0],[0,0.75,0],[1,0.25,0],[1,0.5,0],[1,0.75,0]];outlineConnect=0;fontColor=#232F3E;fillColor=#ED7100;strokeColor=#ffffff;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=12;fontStyle=0;aspect=fixed;shape=mxgraph.aws4.resourceIcon;resIcon=mxgraph.aws4.containers;"
226
+ },
227
+ "mxgraph.aws4.eks": {
228
+ category: "mxgraph.aws4.containers",
229
+ style: "sketch=0;points=[[0,0,0],[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0,0],[0,1,0],[0.25,1,0],[0.5,1,0],[0.75,1,0],[1,1,0],[0,0.25,0],[0,0.5,0],[0,0.75,0],[1,0.25,0],[1,0.5,0],[1,0.75,0]];outlineConnect=0;fontColor=#232F3E;fillColor=#ED7100;strokeColor=#ffffff;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=12;fontStyle=0;aspect=fixed;shape=mxgraph.aws4.resourceIcon;resIcon=mxgraph.aws4.eks;"
230
+ },
231
+ "mxgraph.aws4.ecr": {
232
+ category: "mxgraph.aws4.containers",
233
+ style: "sketch=0;points=[[0,0,0],[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0,0],[0,1,0],[0.25,1,0],[0.5,1,0],[0.75,1,0],[1,1,0],[0,0.25,0],[0,0.5,0],[0,0.75,0],[1,0.25,0],[1,0.5,0],[1,0.75,0]];outlineConnect=0;fontColor=#232F3E;fillColor=#ED7100;strokeColor=#ffffff;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=12;fontStyle=0;aspect=fixed;shape=mxgraph.aws4.resourceIcon;resIcon=mxgraph.aws4.ecr;"
234
+ },
235
+ "mxgraph.aws4.ecs": {
236
+ category: "mxgraph.aws4.containers",
237
+ style: "sketch=0;points=[[0,0,0],[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0,0],[0,1,0],[0.25,1,0],[0.5,1,0],[0.75,1,0],[1,1,0],[0,0.25,0],[0,0.5,0],[0,0.75,0],[1,0.25,0],[1,0.5,0],[1,0.75,0]];outlineConnect=0;fontColor=#232F3E;fillColor=#ED7100;strokeColor=#ffffff;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=12;fontStyle=0;aspect=fixed;shape=mxgraph.aws4.resourceIcon;resIcon=mxgraph.aws4.ecs;"
238
+ },
239
+ "mxgraph.aws4.fargate": {
240
+ category: "mxgraph.aws4.containers",
241
+ style: "sketch=0;points=[[0,0,0],[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0,0],[0,1,0],[0.25,1,0],[0.5,1,0],[0.75,1,0],[1,1,0],[0,0.25,0],[0,0.5,0],[0,0.75,0],[1,0.25,0],[1,0.5,0],[1,0.75,0]];outlineConnect=0;fontColor=#232F3E;fillColor=#ED7100;strokeColor=#ffffff;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=12;fontStyle=0;aspect=fixed;shape=mxgraph.aws4.resourceIcon;resIcon=mxgraph.aws4.fargate;"
242
+ },
243
+ // AWS / Network & Content Delivery
244
+ "mxgraph.aws4.api_gateway": {
245
+ category: "mxgraph.aws4.network",
246
+ style: "sketch=0;points=[[0,0,0],[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0,0],[0,1,0],[0.25,1,0],[0.5,1,0],[0.75,1,0],[1,1,0],[0,0.25,0],[0,0.5,0],[0,0.75,0],[1,0.25,0],[1,0.5,0],[1,0.75,0]];outlineConnect=0;fontColor=#232F3E;fillColor=#8C4FFF;strokeColor=#ffffff;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=12;fontStyle=0;aspect=fixed;shape=mxgraph.aws4.resourceIcon;resIcon=mxgraph.aws4.api_gateway;"
247
+ },
248
+ "mxgraph.aws4.cloudfront": {
249
+ category: "mxgraph.aws4.network",
250
+ style: "sketch=0;points=[[0,0,0],[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0,0],[0,1,0],[0.25,1,0],[0.5,1,0],[0.75,1,0],[1,1,0],[0,0.25,0],[0,0.5,0],[0,0.75,0],[1,0.25,0],[1,0.5,0],[1,0.75,0]];outlineConnect=0;fontColor=#232F3E;fillColor=#8C4FFF;strokeColor=#ffffff;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=12;fontStyle=0;aspect=fixed;shape=mxgraph.aws4.resourceIcon;resIcon=mxgraph.aws4.cloudfront;"
251
+ },
252
+ "mxgraph.aws4.route_53": {
253
+ category: "mxgraph.aws4.network",
254
+ style: "sketch=0;points=[[0,0,0],[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0,0],[0,1,0],[0.25,1,0],[0.5,1,0],[0.75,1,0],[1,1,0],[0,0.25,0],[0,0.5,0],[0,0.75,0],[1,0.25,0],[1,0.5,0],[1,0.75,0]];outlineConnect=0;fontColor=#232F3E;fillColor=#8C4FFF;strokeColor=#ffffff;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=12;fontStyle=0;aspect=fixed;shape=mxgraph.aws4.resourceIcon;resIcon=mxgraph.aws4.route_53;"
255
+ },
256
+ "mxgraph.aws4.vpc_privatelink": {
257
+ category: "mxgraph.aws4.network",
258
+ style: "sketch=0;points=[[0,0,0],[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0,0],[0,1,0],[0.25,1,0],[0.5,1,0],[0.75,1,0],[1,1,0],[0,0.25,0],[0,0.5,0],[0,0.75,0],[1,0.25,0],[1,0.5,0],[1,0.75,0]];outlineConnect=0;fontColor=#232F3E;fillColor=#8C4FFF;strokeColor=#ffffff;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=12;fontStyle=0;aspect=fixed;shape=mxgraph.aws4.resourceIcon;resIcon=mxgraph.aws4.vpc_privatelink;"
259
+ },
260
+ "mxgraph.aws4.vpc": {
261
+ category: "mxgraph.aws4.network",
262
+ style: "sketch=0;points=[[0,0,0],[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0,0],[0,1,0],[0.25,1,0],[0.5,1,0],[0.75,1,0],[1,1,0],[0,0.25,0],[0,0.5,0],[0,0.75,0],[1,0.25,0],[1,0.5,0],[1,0.75,0]];outlineConnect=0;fontColor=#232F3E;fillColor=#8C4FFF;strokeColor=#ffffff;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=12;fontStyle=0;aspect=fixed;shape=mxgraph.aws4.resourceIcon;resIcon=mxgraph.aws4.vpc;"
263
+ },
264
+ "mxgraph.aws4.elastic_load_balancing": {
265
+ category: "mxgraph.aws4.network",
266
+ style: "sketch=0;points=[[0,0,0],[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0,0],[0,1,0],[0.25,1,0],[0.5,1,0],[0.75,1,0],[1,1,0],[0,0.25,0],[0,0.5,0],[0,0.75,0],[1,0.25,0],[1,0.5,0],[1,0.75,0]];outlineConnect=0;fontColor=#232F3E;fillColor=#8C4FFF;strokeColor=#ffffff;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=12;fontStyle=0;aspect=fixed;shape=mxgraph.aws4.resourceIcon;resIcon=mxgraph.aws4.elastic_load_balancing;"
267
+ },
268
+ "mxgraph.aws4.endpoint": {
269
+ category: "mxgraph.aws4.network",
270
+ style: "sketch=0;outlineConnect=0;fontColor=#232F3E;gradientColor=none;fillColor=#8C4FFF;strokeColor=none;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=12;fontStyle=0;aspect=fixed;pointerEvents=1;shape=mxgraph.aws4.endpoint;"
271
+ },
272
+ "mxgraph.aws4.customer_gateway": {
273
+ category: "mxgraph.aws4.network",
274
+ style: "sketch=0;outlineConnect=0;fontColor=#232F3E;gradientColor=none;fillColor=#8C4FFF;strokeColor=none;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=12;fontStyle=0;aspect=fixed;pointerEvents=1;shape=mxgraph.aws4.customer_gateway;"
275
+ },
276
+ "mxgraph.aws4.application_load_balancer": {
277
+ category: "mxgraph.aws4.network",
278
+ style: "sketch=0;outlineConnect=0;fontColor=#232F3E;gradientColor=none;fillColor=#8C4FFF;strokeColor=none;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=12;fontStyle=0;aspect=fixed;pointerEvents=1;shape=mxgraph.aws4.application_load_balancer;"
279
+ },
280
+ "mxgraph.aws4.network_load_balancer": {
281
+ category: "mxgraph.aws4.network",
282
+ style: "sketch=0;outlineConnect=0;fontColor=#232F3E;gradientColor=none;fillColor=#8C4FFF;strokeColor=none;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=12;fontStyle=0;aspect=fixed;pointerEvents=1;shape=mxgraph.aws4.network_load_balancer;"
283
+ },
284
+ // AWS / Application Integration
285
+ "mxgraph.aws4.sns": {
286
+ category: "mxgraph.aws4.application_integration",
287
+ style: "sketch=0;points=[[0,0,0],[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0,0],[0,1,0],[0.25,1,0],[0.5,1,0],[0.75,1,0],[1,1,0],[0,0.25,0],[0,0.5,0],[0,0.75,0],[1,0.25,0],[1,0.5,0],[1,0.75,0]];outlineConnect=0;fontColor=#232F3E;fillColor=#E7157B;strokeColor=#ffffff;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=12;fontStyle=0;aspect=fixed;shape=mxgraph.aws4.resourceIcon;resIcon=mxgraph.aws4.sns;"
288
+ },
289
+ "mxgraph.aws4.sqs": {
290
+ category: "mxgraph.aws4.application_integration",
291
+ style: "sketch=0;points=[[0,0,0],[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0,0],[0,1,0],[0.25,1,0],[0.5,1,0],[0.75,1,0],[1,1,0],[0,0.25,0],[0,0.5,0],[0,0.75,0],[1,0.25,0],[1,0.5,0],[1,0.75,0]];outlineConnect=0;fontColor=#232F3E;fillColor=#E7157B;strokeColor=#ffffff;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=12;fontStyle=0;aspect=fixed;shape=mxgraph.aws4.resourceIcon;resIcon=mxgraph.aws4.sqs;"
292
+ },
293
+ "mxgraph.aws4.eventbridge": {
294
+ category: "mxgraph.aws4.application_integration",
295
+ style: "sketch=0;points=[[0,0,0],[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0,0],[0,1,0],[0.25,1,0],[0.5,1,0],[0.75,1,0],[1,1,0],[0,0.25,0],[0,0.5,0],[0,0.75,0],[1,0.25,0],[1,0.5,0],[1,0.75,0]];outlineConnect=0;fontColor=#232F3E;fillColor=#E7157B;strokeColor=#ffffff;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=12;fontStyle=0;aspect=fixed;shape=mxgraph.aws4.resourceIcon;resIcon=mxgraph.aws4.eventbridge;"
296
+ },
297
+ "mxgraph.aws4.managed_workflows_for_apache_airflow": {
298
+ category: "mxgraph.aws4.application_integration",
299
+ style: "sketch=0;points=[[0,0,0],[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0,0],[0,1,0],[0.25,1,0],[0.5,1,0],[0.75,1,0],[1,1,0],[0,0.25,0],[0,0.5,0],[0,0.75,0],[1,0.25,0],[1,0.5,0],[1,0.75,0]];outlineConnect=0;fontColor=#232F3E;fillColor=#E7157B;strokeColor=#ffffff;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=12;fontStyle=0;aspect=fixed;shape=mxgraph.aws4.resourceIcon;resIcon=mxgraph.aws4.managed_workflows_for_apache_airflow;"
300
+ },
301
+ // AWS / Database
302
+ "mxgraph.aws4.database": {
303
+ category: "mxgraph.aws4.database",
304
+ style: "sketch=0;points=[[0,0,0],[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0,0],[0,1,0],[0.25,1,0],[0.5,1,0],[0.75,1,0],[1,1,0],[0,0.25,0],[0,0.5,0],[0,0.75,0],[1,0.25,0],[1,0.5,0],[1,0.75,0]];outlineConnect=0;fontColor=#232F3E;fillColor=#C925D1;strokeColor=#ffffff;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=12;fontStyle=0;aspect=fixed;shape=mxgraph.aws4.resourceIcon;resIcon=mxgraph.aws4.database;"
305
+ },
306
+ "mxgraph.aws4.aurora": {
307
+ category: "mxgraph.aws4.database",
308
+ style: "sketch=0;points=[[0,0,0],[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0,0],[0,1,0],[0.25,1,0],[0.5,1,0],[0.75,1,0],[1,1,0],[0,0.25,0],[0,0.5,0],[0,0.75,0],[1,0.25,0],[1,0.5,0],[1,0.75,0]];outlineConnect=0;fontColor=#232F3E;fillColor=#C925D1;strokeColor=#ffffff;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=12;fontStyle=0;aspect=fixed;shape=mxgraph.aws4.resourceIcon;resIcon=mxgraph.aws4.aurora;"
309
+ },
310
+ "mxgraph.aws4.documentdb_with_mongodb_compatibility": {
311
+ category: "mxgraph.aws4.database",
312
+ style: "sketch=0;points=[[0,0,0],[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0,0],[0,1,0],[0.25,1,0],[0.5,1,0],[0.75,1,0],[1,1,0],[0,0.25,0],[0,0.5,0],[0,0.75,0],[1,0.25,0],[1,0.5,0],[1,0.75,0]];outlineConnect=0;fontColor=#232F3E;fillColor=#C925D1;strokeColor=#ffffff;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=12;fontStyle=0;aspect=fixed;shape=mxgraph.aws4.resourceIcon;resIcon=mxgraph.aws4.documentdb_with_mongodb_compatibility;"
313
+ },
314
+ "mxgraph.aws4.dynamodb": {
315
+ category: "mxgraph.aws4.database",
316
+ style: "sketch=0;points=[[0,0,0],[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0,0],[0,1,0],[0.25,1,0],[0.5,1,0],[0.75,1,0],[1,1,0],[0,0.25,0],[0,0.5,0],[0,0.75,0],[1,0.25,0],[1,0.5,0],[1,0.75,0]];outlineConnect=0;fontColor=#232F3E;fillColor=#C925D1;strokeColor=#ffffff;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=12;fontStyle=0;aspect=fixed;shape=mxgraph.aws4.resourceIcon;resIcon=mxgraph.aws4.dynamodb;"
317
+ },
318
+ "mxgraph.aws4.elasticache": {
319
+ category: "mxgraph.aws4.database",
320
+ style: "sketch=0;points=[[0,0,0],[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0,0],[0,1,0],[0.25,1,0],[0.5,1,0],[0.75,1,0],[1,1,0],[0,0.25,0],[0,0.5,0],[0,0.75,0],[1,0.25,0],[1,0.5,0],[1,0.75,0]];outlineConnect=0;fontColor=#232F3E;fillColor=#C925D1;strokeColor=#ffffff;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=12;fontStyle=0;aspect=fixed;shape=mxgraph.aws4.resourceIcon;resIcon=mxgraph.aws4.elasticache;"
321
+ },
322
+ "mxgraph.aws4.neptune": {
323
+ category: "mxgraph.aws4.database",
324
+ style: "sketch=0;points=[[0,0,0],[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0,0],[0,1,0],[0.25,1,0],[0.5,1,0],[0.75,1,0],[1,1,0],[0,0.25,0],[0,0.5,0],[0,0.75,0],[1,0.25,0],[1,0.5,0],[1,0.75,0]];outlineConnect=0;fontColor=#232F3E;fillColor=#C925D1;strokeColor=#ffffff;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=12;fontStyle=0;aspect=fixed;shape=mxgraph.aws4.resourceIcon;resIcon=mxgraph.aws4.neptune;"
325
+ },
326
+ "mxgraph.aws4.rds": {
327
+ category: "mxgraph.aws4.database",
328
+ style: "sketch=0;points=[[0,0,0],[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0,0],[0,1,0],[0.25,1,0],[0.5,1,0],[0.75,1,0],[1,1,0],[0,0.25,0],[0,0.5,0],[0,0.75,0],[1,0.25,0],[1,0.5,0],[1,0.75,0]];outlineConnect=0;fontColor=#232F3E;fillColor=#C925D1;strokeColor=#ffffff;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=12;fontStyle=0;aspect=fixed;shape=mxgraph.aws4.resourceIcon;resIcon=mxgraph.aws4.rds;"
329
+ },
330
+ "mxgraph.aws4.redshift": {
331
+ category: "mxgraph.aws4.database",
332
+ style: "sketch=0;points=[[0,0,0],[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0,0],[0,1,0],[0.25,1,0],[0.5,1,0],[0.75,1,0],[1,1,0],[0,0.25,0],[0,0.5,0],[0,0.75,0],[1,0.25,0],[1,0.5,0],[1,0.75,0]];outlineConnect=0;fontColor=#232F3E;fillColor=#C925D1;strokeColor=#ffffff;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=12;fontStyle=0;aspect=fixed;shape=mxgraph.aws4.resourceIcon;resIcon=mxgraph.aws4.redshift;"
333
+ },
334
+ "mxgraph.aws4.": {
335
+ category: "mxgraph.aws4.database",
336
+ style: ""
337
+ }
338
+ };
339
+
340
+ // src/websocketManager.ts
341
+ function createWebSocketManager(options) {
342
+ let socket = null;
343
+ let reconnectAttempts = 0;
344
+ let currentState = "disconnected";
345
+ let messageHandler = null;
346
+ let pingIntervalId = null;
347
+ let reconnectTimeoutId = null;
348
+ const {
349
+ url,
350
+ maxReconnectAttempts = 5,
351
+ reconnectDelay = 3e3,
352
+ pingInterval = 3e4
353
+ } = options;
354
+ const updateState = (newState) => {
355
+ if (currentState !== newState) {
356
+ console.debug(
357
+ `[websocketManager] State change: ${currentState} \u2192 ${newState}`
358
+ );
359
+ currentState = newState;
360
+ }
361
+ };
362
+ const connect = () => {
363
+ if (socket && socket.readyState === WebSocket.OPEN) {
364
+ console.debug("[websocketManager] Already connected");
365
+ return;
366
+ }
367
+ updateState("connecting");
368
+ try {
369
+ socket = new WebSocket(url);
370
+ socket.addEventListener("open", () => {
371
+ console.debug("[websocketManager] WebSocket connection established");
372
+ reconnectAttempts = 0;
373
+ updateState("connected");
374
+ startPing();
375
+ });
376
+ socket.addEventListener("message", (event) => {
377
+ try {
378
+ const parsedMessage = JSON.parse(event.data);
379
+ console.debug("[websocketManager] Received message:", parsedMessage);
380
+ if (messageHandler) {
381
+ messageHandler(parsedMessage);
382
+ }
383
+ } catch (error) {
384
+ console.error(
385
+ "[websocketManager] Failed to parse WebSocket message:",
386
+ error
387
+ );
388
+ }
389
+ });
390
+ socket.addEventListener("close", () => {
391
+ console.debug("[websocketManager] WebSocket connection closed");
392
+ updateState("disconnected");
393
+ stopPing();
394
+ attemptReconnect();
395
+ });
396
+ socket.addEventListener("error", (event) => {
397
+ console.error("[websocketManager] WebSocket error:", event);
398
+ updateState("disconnected");
399
+ });
400
+ } catch (error) {
401
+ console.error(
402
+ "[websocketManager] Failed to create WebSocket connection:",
403
+ error
404
+ );
405
+ updateState("disconnected");
406
+ }
407
+ };
408
+ const disconnect = () => {
409
+ if (reconnectTimeoutId) {
410
+ clearTimeout(reconnectTimeoutId);
411
+ reconnectTimeoutId = null;
412
+ }
413
+ stopPing();
414
+ reconnectAttempts = 0;
415
+ if (socket) {
416
+ console.debug("[websocketManager] Closing WebSocket connection");
417
+ socket.close();
418
+ socket = null;
419
+ }
420
+ updateState("disconnected");
421
+ };
422
+ const send = (message) => {
423
+ if (!socket || socket.readyState !== WebSocket.OPEN) {
424
+ console.warn(
425
+ "[websocketManager] Cannot send message: WebSocket not connected"
426
+ );
427
+ return;
428
+ }
429
+ try {
430
+ const serialized = JSON.stringify(message);
431
+ console.debug("[websocketManager] Sending message:", message);
432
+ socket.send(serialized);
433
+ } catch (error) {
434
+ console.error("[websocketManager] Failed to send message:", error);
435
+ }
436
+ };
437
+ const getState = () => currentState;
438
+ const onMessage = (handler) => {
439
+ messageHandler = handler;
440
+ };
441
+ const attemptReconnect = () => {
442
+ if (reconnectAttempts >= maxReconnectAttempts) {
443
+ console.error(
444
+ "[websocketManager] Max reconnection attempts reached. Giving up."
445
+ );
446
+ return;
447
+ }
448
+ reconnectAttempts++;
449
+ const delay = reconnectDelay * Math.pow(1.5, reconnectAttempts - 1);
450
+ console.log(
451
+ `[websocketManager] Attempting to reconnect in ${Math.round(delay / 1e3)} seconds... (attempt ${reconnectAttempts}/${maxReconnectAttempts})`
452
+ );
453
+ reconnectTimeoutId = window.setTimeout(() => {
454
+ reconnectTimeoutId = null;
455
+ connect();
456
+ }, delay);
457
+ };
458
+ const startPing = () => {
459
+ stopPing();
460
+ pingIntervalId = window.setInterval(() => {
461
+ if (getState() === "connected") {
462
+ send({ type: "PING" });
463
+ }
464
+ }, pingInterval);
465
+ };
466
+ const stopPing = () => {
467
+ if (pingIntervalId !== null) {
468
+ clearInterval(pingIntervalId);
469
+ pingIntervalId = null;
470
+ }
471
+ };
472
+ const ping = () => {
473
+ return new Promise((resolve) => {
474
+ if (getState() !== "connected") {
475
+ resolve(false);
476
+ return;
477
+ }
478
+ const timeoutId = setTimeout(() => {
479
+ resolve(false);
480
+ }, 5e3);
481
+ send({ type: "PING", message: "Ping from plugin" });
482
+ setTimeout(() => {
483
+ clearTimeout(timeoutId);
484
+ resolve(getState() === "connected");
485
+ }, 1e3);
486
+ });
487
+ };
488
+ return {
489
+ connect,
490
+ disconnect,
491
+ send,
492
+ getState,
493
+ onMessage,
494
+ ping
495
+ };
496
+ }
497
+
498
+ // src/pluginConfig.ts
499
+ var DEFAULT_PLUGIN_CONFIG = {
500
+ websocketPort: 3333,
501
+ serverUrl: ""
502
+ };
503
+ var PLUGIN_CONFIG_KEY = "drawio-mcp-plugin-config";
504
+ var cachedConfig = null;
505
+ async function fetchPluginConfig() {
506
+ if (cachedConfig) {
507
+ return cachedConfig;
508
+ }
509
+ try {
510
+ const response = await fetch("/api/config");
511
+ if (response.ok) {
512
+ const serverConfig = await response.json();
513
+ cachedConfig = {
514
+ websocketPort: serverConfig.websocketPort || DEFAULT_PLUGIN_CONFIG.websocketPort,
515
+ serverUrl: serverConfig.serverUrl || window.location.origin
516
+ };
517
+ writePluginConfig(cachedConfig);
518
+ return cachedConfig;
519
+ }
520
+ } catch (error) {
521
+ console.warn("[pluginConfig] Failed to fetch config from server:", error);
522
+ }
523
+ return readPluginConfig();
524
+ }
525
+ function readPluginConfig() {
526
+ try {
527
+ const stored = localStorage.getItem(PLUGIN_CONFIG_KEY);
528
+ if (stored) {
529
+ const parsed = JSON.parse(stored);
530
+ const validated = validatePluginConfig(parsed);
531
+ if (validated.isValid && validated.config) {
532
+ return validated.config;
533
+ }
534
+ }
535
+ } catch (error) {
536
+ console.warn("[pluginConfig] Failed to read from localStorage:", error);
537
+ }
538
+ return { ...DEFAULT_PLUGIN_CONFIG };
539
+ }
540
+ function writePluginConfig(config) {
541
+ try {
542
+ localStorage.setItem(PLUGIN_CONFIG_KEY, JSON.stringify(config));
543
+ cachedConfig = config;
544
+ } catch (error) {
545
+ console.error("[pluginConfig] Failed to write to localStorage:", error);
546
+ throw error;
547
+ }
548
+ }
549
+ function validatePluginConfig(config) {
550
+ if (!config || typeof config !== "object") {
551
+ return { isValid: false, error: "Configuration must be an object" };
552
+ }
553
+ const cfg = config;
554
+ if (typeof cfg.websocketPort !== "number") {
555
+ return { isValid: false, error: "websocketPort must be a number" };
556
+ }
557
+ if (cfg.websocketPort < 1024 || cfg.websocketPort > 65535) {
558
+ return {
559
+ isValid: false,
560
+ error: "websocketPort must be between 1024 and 65535"
561
+ };
562
+ }
563
+ return {
564
+ isValid: true,
565
+ config: {
566
+ websocketPort: cfg.websocketPort,
567
+ serverUrl: cfg.serverUrl || ""
568
+ }
569
+ };
570
+ }
571
+ function buildWebSocketUrl(config) {
572
+ const host = window.location.hostname;
573
+ return `ws://${host}:${config.websocketPort}`;
574
+ }
575
+
576
+ // src/settingsDialog.ts
577
+ function createDialogContainer() {
578
+ const container = document.createElement("div");
579
+ container.id = "mcp-settings-dialog";
580
+ container.style.cssText = `
581
+ position: fixed;
582
+ top: 0;
583
+ left: 0;
584
+ width: 100%;
585
+ height: 100%;
586
+ background-color: rgba(0, 0, 0, 0.5);
587
+ display: flex;
588
+ justify-content: center;
589
+ align-items: center;
590
+ z-index: 10000;
591
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
592
+ `;
593
+ container.addEventListener("click", (e) => {
594
+ if (e.target === container) {
595
+ e.stopPropagation();
596
+ }
597
+ });
598
+ return container;
599
+ }
600
+ function createDialogContent() {
601
+ const content = document.createElement("div");
602
+ content.className = "dialog-content";
603
+ content.style.cssText = `
604
+ background: white;
605
+ border-radius: 8px;
606
+ box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
607
+ max-width: 500px;
608
+ width: 90%;
609
+ max-height: 90vh;
610
+ overflow-y: auto;
611
+ position: relative;
612
+ `;
613
+ return content;
614
+ }
615
+ function createDialogHeader(title, onClose) {
616
+ const header = document.createElement("div");
617
+ header.className = "dialog-header";
618
+ header.style.cssText = `
619
+ padding: 16px 20px;
620
+ border-bottom: 1px solid #e0e0e0;
621
+ display: flex;
622
+ justify-content: space-between;
623
+ align-items: center;
624
+ `;
625
+ const titleEl = document.createElement("h2");
626
+ titleEl.textContent = title;
627
+ titleEl.style.cssText = `
628
+ margin: 0;
629
+ font-size: 18px;
630
+ font-weight: 600;
631
+ color: #333;
632
+ `;
633
+ const closeBtn = document.createElement("button");
634
+ closeBtn.textContent = "\xD7";
635
+ closeBtn.style.cssText = `
636
+ background: none;
637
+ border: none;
638
+ font-size: 24px;
639
+ cursor: pointer;
640
+ padding: 0;
641
+ width: 24px;
642
+ height: 24px;
643
+ display: flex;
644
+ align-items: center;
645
+ justify-content: center;
646
+ color: #666;
647
+ border-radius: 4px;
648
+ `;
649
+ closeBtn.title = "Close";
650
+ closeBtn.addEventListener("mouseenter", () => {
651
+ closeBtn.style.backgroundColor = "#f5f5f5";
652
+ });
653
+ closeBtn.addEventListener("mouseleave", () => {
654
+ closeBtn.style.backgroundColor = "transparent";
655
+ });
656
+ closeBtn.addEventListener("click", onClose);
657
+ header.appendChild(titleEl);
658
+ header.appendChild(closeBtn);
659
+ return header;
660
+ }
661
+ function createDialogBody(state, actions) {
662
+ const body = document.createElement("div");
663
+ body.className = "dialog-body";
664
+ body.style.cssText = `
665
+ padding: 20px;
666
+ `;
667
+ const statusSection = createStatusSection(state);
668
+ body.appendChild(statusSection);
669
+ const formSection = createFormSection(state, actions);
670
+ body.appendChild(formSection);
671
+ return body;
672
+ }
673
+ function createStatusSection(state) {
674
+ const section = document.createElement("div");
675
+ section.className = "status-section";
676
+ section.style.cssText = `
677
+ margin-bottom: 24px;
678
+ padding: 16px;
679
+ background: #f8f9fa;
680
+ border-radius: 6px;
681
+ border: 1px solid #e9ecef;
682
+ `;
683
+ const title = document.createElement("div");
684
+ title.style.cssText = `
685
+ font-weight: 600;
686
+ margin-bottom: 8px;
687
+ color: #333;
688
+ `;
689
+ title.textContent = "Connection Status";
690
+ const statusIndicator = document.createElement("div");
691
+ statusIndicator.className = "status-indicator";
692
+ statusIndicator.style.cssText = `
693
+ display: flex;
694
+ align-items: center;
695
+ gap: 8px;
696
+ margin-bottom: 4px;
697
+ `;
698
+ const indicator = document.createElement("div");
699
+ indicator.style.cssText = `
700
+ width: 12px;
701
+ height: 12px;
702
+ border-radius: 50%;
703
+ flex-shrink: 0;
704
+ `;
705
+ switch (state.connectionState) {
706
+ case "connected":
707
+ indicator.style.backgroundColor = "#28a745";
708
+ break;
709
+ case "connecting":
710
+ indicator.style.backgroundColor = "#ffc107";
711
+ break;
712
+ case "disconnected":
713
+ indicator.style.backgroundColor = "#dc3545";
714
+ break;
715
+ }
716
+ const statusText = document.createElement("span");
717
+ statusText.textContent = state.connectionState.charAt(0).toUpperCase() + state.connectionState.slice(1);
718
+ statusText.style.fontWeight = "500";
719
+ statusIndicator.appendChild(indicator);
720
+ statusIndicator.appendChild(statusText);
721
+ const portDisplay = document.createElement("div");
722
+ portDisplay.style.cssText = `
723
+ font-size: 14px;
724
+ color: #666;
725
+ `;
726
+ portDisplay.textContent = `Port: ${state.config.websocketPort}`;
727
+ section.appendChild(title);
728
+ section.appendChild(statusIndicator);
729
+ section.appendChild(portDisplay);
730
+ return section;
731
+ }
732
+ function createFormSection(state, actions) {
733
+ const section = document.createElement("div");
734
+ section.className = "form-section";
735
+ const portGroup = document.createElement("div");
736
+ portGroup.className = "form-group";
737
+ portGroup.style.cssText = `
738
+ margin-bottom: 16px;
739
+ `;
740
+ const label = document.createElement("label");
741
+ label.textContent = "WebSocket Port";
742
+ label.htmlFor = "mcp-port-input";
743
+ label.style.cssText = `
744
+ display: block;
745
+ margin-bottom: 6px;
746
+ font-weight: 500;
747
+ color: #333;
748
+ `;
749
+ const input = document.createElement("input");
750
+ input.id = "mcp-port-input";
751
+ input.type = "number";
752
+ input.min = "1024";
753
+ input.max = "65535";
754
+ input.value = state.formData.port;
755
+ input.style.cssText = `
756
+ width: 100%;
757
+ padding: 8px 12px;
758
+ border: 1px solid #ddd;
759
+ border-radius: 4px;
760
+ font-size: 14px;
761
+ box-sizing: border-box;
762
+ `;
763
+ if (state.errors.port) {
764
+ input.style.borderColor = "#dc3545";
765
+ }
766
+ input.addEventListener("input", (e) => {
767
+ const value = e.target.value;
768
+ window.dispatchEvent(
769
+ new CustomEvent("mcp-settings-message", {
770
+ detail: { type: "UPDATE_PORT", port: value }
771
+ })
772
+ );
773
+ });
774
+ const hint = document.createElement("div");
775
+ hint.textContent = "Port must be between 1024 and 65535";
776
+ hint.style.cssText = `
777
+ font-size: 12px;
778
+ color: #666;
779
+ margin-top: 4px;
780
+ `;
781
+ if (state.errors.port) {
782
+ const error = document.createElement("div");
783
+ error.textContent = state.errors.port;
784
+ error.style.cssText = `
785
+ font-size: 12px;
786
+ color: #dc3545;
787
+ margin-top: 4px;
788
+ `;
789
+ portGroup.appendChild(error);
790
+ }
791
+ portGroup.appendChild(label);
792
+ portGroup.appendChild(input);
793
+ portGroup.appendChild(hint);
794
+ section.appendChild(portGroup);
795
+ return section;
796
+ }
797
+ function createDialogFooter(state, actions) {
798
+ const footer = document.createElement("div");
799
+ footer.className = "dialog-footer";
800
+ footer.style.cssText = `
801
+ padding: 16px 20px;
802
+ border-top: 1px solid #e0e0e0;
803
+ display: flex;
804
+ justify-content: space-between;
805
+ gap: 12px;
806
+ flex-wrap: wrap;
807
+ `;
808
+ const leftActions = document.createElement("div");
809
+ leftActions.style.cssText = `
810
+ display: flex;
811
+ gap: 8px;
812
+ flex-wrap: wrap;
813
+ `;
814
+ const rightActions = document.createElement("div");
815
+ rightActions.style.cssText = `
816
+ display: flex;
817
+ gap: 8px;
818
+ `;
819
+ const cancelBtn = createButton("Cancel", "ghost", () => {
820
+ window.dispatchEvent(
821
+ new CustomEvent("mcp-settings-message", {
822
+ detail: { type: "CLOSE" }
823
+ })
824
+ );
825
+ });
826
+ const saveBtn = createButton(
827
+ state.isSaving ? "Saving..." : "Save",
828
+ "primary",
829
+ () => {
830
+ window.dispatchEvent(
831
+ new CustomEvent("mcp-settings-message", {
832
+ detail: { type: "SAVE" }
833
+ })
834
+ );
835
+ },
836
+ state.isSaving
837
+ );
838
+ rightActions.appendChild(cancelBtn);
839
+ rightActions.appendChild(saveBtn);
840
+ footer.appendChild(leftActions);
841
+ footer.appendChild(rightActions);
842
+ return footer;
843
+ }
844
+ function createButton(text, variant, onClick, disabled = false) {
845
+ const btn = document.createElement("button");
846
+ btn.textContent = text;
847
+ btn.disabled = disabled;
848
+ btn.style.cssText = `
849
+ padding: 8px 16px;
850
+ border-radius: 4px;
851
+ font-size: 14px;
852
+ cursor: pointer;
853
+ border: 1px solid transparent;
854
+ transition: all 0.2s;
855
+ `;
856
+ switch (variant) {
857
+ case "primary":
858
+ btn.style.cssText += `
859
+ background-color: #007bff;
860
+ color: white;
861
+ border-color: #007bff;
862
+ `;
863
+ btn.addEventListener("mouseenter", () => {
864
+ if (!disabled) btn.style.backgroundColor = "#0056b3";
865
+ });
866
+ btn.addEventListener("mouseleave", () => {
867
+ if (!disabled) btn.style.backgroundColor = "#007bff";
868
+ });
869
+ break;
870
+ case "secondary":
871
+ btn.style.cssText += `
872
+ background-color: #6c757d;
873
+ color: white;
874
+ border-color: #6c757d;
875
+ `;
876
+ btn.addEventListener("mouseenter", () => {
877
+ if (!disabled) btn.style.backgroundColor = "#545b62";
878
+ });
879
+ btn.addEventListener("mouseleave", () => {
880
+ if (!disabled) btn.style.backgroundColor = "#6c757d";
881
+ });
882
+ break;
883
+ case "ghost":
884
+ btn.style.cssText += `
885
+ background-color: transparent;
886
+ color: #6c757d;
887
+ border-color: #6c757d;
888
+ `;
889
+ btn.addEventListener("mouseenter", () => {
890
+ if (!disabled) {
891
+ btn.style.backgroundColor = "#f8f9fa";
892
+ }
893
+ });
894
+ btn.addEventListener("mouseleave", () => {
895
+ if (!disabled) btn.style.backgroundColor = "transparent";
896
+ });
897
+ break;
898
+ }
899
+ if (disabled) {
900
+ btn.style.cssText += `
901
+ opacity: 0.6;
902
+ cursor: not-allowed;
903
+ `;
904
+ }
905
+ btn.addEventListener("click", onClick);
906
+ return btn;
907
+ }
908
+ function createSettingsDialog(initialState, actions) {
909
+ let currentState = { ...initialState };
910
+ let dialogElement = null;
911
+ let isVisible = false;
912
+ const update = (newState) => {
913
+ currentState = { ...newState };
914
+ if (dialogElement && isVisible) {
915
+ render();
916
+ }
917
+ };
918
+ const render = () => {
919
+ if (dialogElement && dialogElement.parentNode) {
920
+ dialogElement.parentNode.removeChild(dialogElement);
921
+ }
922
+ const container = createDialogContainer();
923
+ const content = createDialogContent();
924
+ const header = createDialogHeader("MCP Settings", () => actions.onClose());
925
+ const body = createDialogBody(currentState, actions);
926
+ const footer = createDialogFooter(currentState, actions);
927
+ content.appendChild(header);
928
+ content.appendChild(body);
929
+ content.appendChild(footer);
930
+ container.appendChild(content);
931
+ dialogElement = container;
932
+ isVisible = true;
933
+ setupMessageListeners(container, actions);
934
+ return container;
935
+ };
936
+ const setupMessageListeners = (container, actions2) => {
937
+ const handleMessage = (event) => {
938
+ const message = event.detail;
939
+ switch (message.type) {
940
+ case "UPDATE_PORT":
941
+ currentState.formData.port = message.port;
942
+ delete currentState.errors.port;
943
+ break;
944
+ case "SAVE":
945
+ if (!validateAndSave()) {
946
+ update(currentState);
947
+ }
948
+ break;
949
+ case "CLOSE":
950
+ actions2.onClose();
951
+ break;
952
+ }
953
+ };
954
+ window.addEventListener(
955
+ "mcp-settings-message",
956
+ handleMessage
957
+ );
958
+ const observer = new MutationObserver((mutations) => {
959
+ mutations.forEach((mutation) => {
960
+ mutation.removedNodes.forEach((node) => {
961
+ if (node === container) {
962
+ window.removeEventListener(
963
+ "mcp-settings-message",
964
+ handleMessage
965
+ );
966
+ observer.disconnect();
967
+ }
968
+ });
969
+ });
970
+ });
971
+ if (container.parentNode) {
972
+ observer.observe(container.parentNode, { childList: true });
973
+ }
974
+ };
975
+ const validateAndSave = () => {
976
+ const portNum = parseInt(currentState.formData.port, 10);
977
+ if (isNaN(portNum)) {
978
+ currentState.errors.port = "Port must be a number";
979
+ return false;
980
+ }
981
+ if (portNum < 1024 || portNum > 65535) {
982
+ currentState.errors.port = "Port must be between 1024 and 65535";
983
+ return false;
984
+ }
985
+ currentState.errors = {};
986
+ currentState.isSaving = true;
987
+ const newConfig = {
988
+ websocketPort: portNum,
989
+ serverUrl: currentState.config.serverUrl
990
+ };
991
+ actions.onSave(newConfig);
992
+ return true;
993
+ };
994
+ const dialogProxy = {
995
+ get element() {
996
+ if (!dialogElement) {
997
+ render();
998
+ }
999
+ return dialogElement;
1000
+ },
1001
+ update
1002
+ };
1003
+ return dialogProxy;
1004
+ }
1005
+ function showSettingsDialog(dialog) {
1006
+ if (!dialog.element.parentNode) {
1007
+ document.body.appendChild(dialog.element);
1008
+ }
1009
+ }
1010
+ function hideSettingsDialog(dialog) {
1011
+ if (dialog.element.parentNode) {
1012
+ dialog.element.parentNode.removeChild(dialog.element);
1013
+ }
1014
+ }
1015
+
1016
+ // src/drawio-tools.ts
1017
+ function transform_NamedNodeMap_to_record(attributes) {
1018
+ const tstr = Object.prototype.toString.call(attributes);
1019
+ if (tstr !== "[object NamedNodeMap]") {
1020
+ return attributes;
1021
+ }
1022
+ if (attributes.length === void 0) {
1023
+ return attributes;
1024
+ }
1025
+ let transformed_attributes = {};
1026
+ for (let i = 0; i < attributes.length; i++) {
1027
+ const attr = attributes[i];
1028
+ if (attr && attr.name && attr.value !== void 0) {
1029
+ transformed_attributes[attr.name] = attr.value;
1030
+ }
1031
+ }
1032
+ return transformed_attributes;
1033
+ }
1034
+ function transform_cells_NamedNodeMap_to_attributes(cell) {
1035
+ if (cell.value.attributes && typeof cell.value.attributes === "object") {
1036
+ const attributes = cell.value.attributes;
1037
+ return transform_NamedNodeMap_to_record(attributes);
1038
+ }
1039
+ return {};
1040
+ }
1041
+ function remove_circular_dependencies(obj, visited = /* @__PURE__ */ new WeakSet(), path = []) {
1042
+ if (obj === null || typeof obj !== "object") {
1043
+ return obj;
1044
+ }
1045
+ if (Array.isArray(obj)) {
1046
+ if (visited.has(obj)) {
1047
+ return `[Circular ${path.join(".")}]`;
1048
+ }
1049
+ visited.add(obj);
1050
+ return obj.map(
1051
+ (item, index) => remove_circular_dependencies(item, visited, [...path, `[${index}]`])
1052
+ );
1053
+ }
1054
+ const tstr = Object.prototype.toString.call(obj);
1055
+ if (tstr === "[object NamedNodeMap]") {
1056
+ return transform_NamedNodeMap_to_record(obj);
1057
+ }
1058
+ if (tstr !== "[object Object]" && tstr !== "[object Element]") {
1059
+ return obj;
1060
+ }
1061
+ if (visited.has(obj)) {
1062
+ return `[Circular ${path.join(".")}]`;
1063
+ }
1064
+ visited.add(obj);
1065
+ const result = {};
1066
+ for (const key in obj) {
1067
+ const value = obj[key];
1068
+ if (typeof value !== "function" && key !== "children" && key !== "edges" && !key.startsWith("aria") && key !== "ownerDocument" && key !== "part" && key !== "classList" && key !== "childNodes" && key !== "shadowRoot" && key !== "innerHTML" && key !== "outerHTML" && key !== "scrollTop" && key !== "scrollLeft" && key !== "scrollWidth" && key !== "scrollHeight" && key !== "clientTop" && key !== "clientLeft" && key !== "clientWidth" && key !== "clientHeight" && key !== "onbeforecopy" && key !== "onbeforecut" && key !== "onbeforepaste" && key !== "onsearch" && key !== "elementTiming" && key !== "onfullscreenchange" && key !== "onfullscreenerror" && key !== "onwebkitfullscreenchange" && key !== "onwebkitfullscreenerror" && key !== "firstElementChild" && key !== "lastElementChild" && key !== "childElementCount" && key !== "previousElementSibling" && key !== "nextElementSibling" && key !== "currentCSSZoom" && key !== "parentNode" && key !== "parentElement" && key !== "firstChild" && key !== "lastChild" && key !== "previousSibling" && key !== "nextSibling" && key !== "nodeValue" && key !== "textContent" && key !== "ELEMENT_NODE" && key !== "ATTRIBUTE_NODE" && key !== "TEXT_NODE" && key !== "CDATA_SECTION_NODE" && key !== "ENTITY_REFERENCE_NODE" && key !== "ENTITY_NODE" && key !== "PROCESSING_INSTRUCTION_NODE" && key !== "COMMENT_NODE" && key !== "DOCUMENT_NODE" && key !== "DOCUMENT_TYPE_NODE" && key !== "DOCUMENT_FRAGMENT_NODE" && key !== "NOTATION_NODE" && key !== "DOCUMENT_POSITION_DISCONNECTED" && key !== "DOCUMENT_POSITION_PRECEDING" && key !== "DOCUMENT_POSITION_FOLLOWING" && key !== "DOCUMENT_POSITION_CONTAINS" && key !== "DOCUMENT_POSITION_CONTAINED_BY" && key !== "DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC") {
1069
+ let stripped_value = {};
1070
+ if ((key === "parent" || key === "source" || key === "target") && value !== void 0 && value !== null) {
1071
+ stripped_value = {
1072
+ id: value.id
1073
+ };
1074
+ } else {
1075
+ stripped_value = value;
1076
+ }
1077
+ result[key] = remove_circular_dependencies(stripped_value, visited, [
1078
+ ...path,
1079
+ key
1080
+ ]);
1081
+ }
1082
+ }
1083
+ return result;
1084
+ }
1085
+ function transform_cell_for_display(cell) {
1086
+ if (!cell || typeof cell !== "object") {
1087
+ return null;
1088
+ }
1089
+ const transformed = {
1090
+ id: cell.id || "",
1091
+ mxObjectId: cell.mxObjectId || "",
1092
+ value: "",
1093
+ geometry: cell.geometry,
1094
+ style: cell.style,
1095
+ edge: cell.edge,
1096
+ edges: cell.edges,
1097
+ parent: cell.parent,
1098
+ source: cell.source,
1099
+ target: cell.target
1100
+ };
1101
+ if (cell.value !== null && cell.value !== void 0) {
1102
+ if (typeof cell.value === "string") {
1103
+ transformed.value = cell.value;
1104
+ } else if (typeof cell.value === "object") {
1105
+ const transformed_attributes = transform_cells_NamedNodeMap_to_attributes(cell);
1106
+ transformed.value = {
1107
+ attributes: transformed_attributes,
1108
+ nodeName: cell.value.nodeName,
1109
+ localName: cell.value.localName,
1110
+ tagName: cell.value.tagName
1111
+ };
1112
+ }
1113
+ }
1114
+ return transformed;
1115
+ }
1116
+ function get_cell_layer(graph, cell) {
1117
+ if (!cell || !graph) {
1118
+ return null;
1119
+ }
1120
+ try {
1121
+ const layer = graph.getLayerForCell(cell);
1122
+ if (layer) {
1123
+ return {
1124
+ id: layer.id || "",
1125
+ name: layer.value || "Default Layer"
1126
+ };
1127
+ }
1128
+ } catch (error) {
1129
+ console.warn("Could not get layer for cell:", error);
1130
+ }
1131
+ return null;
1132
+ }
1133
+ function get_cell_tags(graph, cell) {
1134
+ if (!cell || !graph) {
1135
+ return [];
1136
+ }
1137
+ try {
1138
+ const tags = graph.getTagsForCell(cell);
1139
+ return tags || [];
1140
+ } catch (error) {
1141
+ console.warn("Could not get tags for cell:", error);
1142
+ return [];
1143
+ }
1144
+ }
1145
+ function mx_isRoot(root_cell) {
1146
+ return function(cell) {
1147
+ return null != cell && cell == root_cell;
1148
+ };
1149
+ }
1150
+ function mx_isLayer(root_cell) {
1151
+ return function(cell) {
1152
+ return mx_isRoot(root_cell)(cell.getParent());
1153
+ };
1154
+ }
1155
+ function resolve_parent(graph, parent_id) {
1156
+ if (parent_id) {
1157
+ const model = graph.getModel();
1158
+ const parent = model.getCell(parent_id);
1159
+ if (!parent) {
1160
+ throw new Error(`Parent cell '${parent_id}' not found`);
1161
+ }
1162
+ return parent;
1163
+ }
1164
+ return graph.getDefaultParent();
1165
+ }
1166
+ function normalize_shape_style(shapeName, style) {
1167
+ if (!style || !shapeName.startsWith("mxgraph.aws4.")) {
1168
+ return style;
1169
+ }
1170
+ const hasExplicitShape = style.includes("shape=");
1171
+ if (hasExplicitShape) {
1172
+ return style;
1173
+ }
1174
+ return `shape=${shapeName};${style}`;
1175
+ }
1176
+ function apply_style_to_cell(graph, cell, style) {
1177
+ if (!style || !cell) {
1178
+ return;
1179
+ }
1180
+ const model = graph.getModel();
1181
+ model.setStyle(cell, style);
1182
+ if (typeof cell.setStyle === "function") {
1183
+ cell.setStyle(style);
1184
+ }
1185
+ if (typeof graph.refresh === "function") {
1186
+ graph.refresh(cell);
1187
+ }
1188
+ }
1189
+ function create_shape_vertex(graph, options) {
1190
+ const mxCell = window.mxCell;
1191
+ const mxGeometry = window.mxGeometry;
1192
+ const cell = new mxCell(
1193
+ options.text,
1194
+ new mxGeometry(options.x, options.y, options.width, options.height),
1195
+ options.style
1196
+ );
1197
+ cell.vertex = true;
1198
+ graph.addCell(cell, options.parent);
1199
+ return cell;
1200
+ }
1201
+ function add_new_rectangle(ui2, options) {
1202
+ const { editor } = ui2;
1203
+ const { graph } = editor;
1204
+ const x = options.x || 100;
1205
+ const y = options.y || 100;
1206
+ const width = options.width || 120;
1207
+ const height = options.height || 60;
1208
+ const text = options.text || "";
1209
+ const style = options.style || "whiteSpace=wrap;html=1;fillColor=#ffffff;strokeColor=#000000;";
1210
+ const parent = resolve_parent(graph, options.parent_id);
1211
+ graph.getModel().beginUpdate();
1212
+ try {
1213
+ const vertex = graph.insertVertex(
1214
+ parent,
1215
+ null,
1216
+ text,
1217
+ x,
1218
+ y,
1219
+ width,
1220
+ height,
1221
+ style
1222
+ );
1223
+ return vertex;
1224
+ } finally {
1225
+ graph.getModel().endUpdate();
1226
+ }
1227
+ }
1228
+ function delete_cell_by_id(ui2, options) {
1229
+ const { editor } = ui2;
1230
+ const { graph } = editor;
1231
+ const cell_id = options.cell_id;
1232
+ const cell = graph.getModel().getCell(cell_id);
1233
+ if (!cell) {
1234
+ return false;
1235
+ }
1236
+ graph.getModel().beginUpdate();
1237
+ try {
1238
+ graph.removeCells([cell]);
1239
+ return true;
1240
+ } finally {
1241
+ graph.getModel().endUpdate();
1242
+ }
1243
+ }
1244
+ var SELF_CONNECTOR_DEFAULT_STYLE = "edgeStyle=loopEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=classic;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;";
1245
+ function add_edge(ui2, options) {
1246
+ const { editor } = ui2;
1247
+ const { graph } = editor;
1248
+ const model = graph.getModel();
1249
+ const source = model.getCell(options.source_id);
1250
+ const target = model.getCell(options.target_id);
1251
+ if (!source || !target) {
1252
+ return null;
1253
+ }
1254
+ const isSelfConnector = options.source_id === options.target_id;
1255
+ const defaultStyle = isSelfConnector ? SELF_CONNECTOR_DEFAULT_STYLE : "endArrow=classic;html=1;rounded=0;";
1256
+ const style = options.style || defaultStyle;
1257
+ const text = options.text || "";
1258
+ const parent = resolve_parent(graph, options.parent_id);
1259
+ model.beginUpdate();
1260
+ try {
1261
+ const edge = graph.insertEdge(parent, null, text, source, target, style);
1262
+ if (options.points && options.points.length > 0) {
1263
+ const geo = edge.getGeometry();
1264
+ const mxPoint = window.mxPoint;
1265
+ geo.points = options.points.map((p) => new mxPoint(p.x, p.y));
1266
+ model.setGeometry(edge, geo);
1267
+ }
1268
+ return edge;
1269
+ } finally {
1270
+ model.endUpdate();
1271
+ }
1272
+ }
1273
+ function edit_cell(ui2, options) {
1274
+ const { editor } = ui2;
1275
+ const { graph } = editor;
1276
+ const model = graph.getModel();
1277
+ const cell_id = options.cell_id;
1278
+ if (!cell_id) {
1279
+ throw new Error("edit_cell requires a cell_id");
1280
+ }
1281
+ const cell = model.getCell(cell_id);
1282
+ if (!cell) {
1283
+ throw new Error(`edit_cell could not find cell with id '${cell_id}'`);
1284
+ }
1285
+ model.beginUpdate();
1286
+ try {
1287
+ const has_position_change = options.x !== void 0 || options.y !== void 0;
1288
+ const has_size_change = options.width !== void 0 || options.height !== void 0;
1289
+ if (has_position_change || has_size_change) {
1290
+ const geometry = cell.geometry ? cell.geometry.clone() : null;
1291
+ if (!geometry) {
1292
+ throw new Error(
1293
+ `Cell '${cell_id}' does not support geometry updates (missing geometry)`
1294
+ );
1295
+ }
1296
+ if (options.x !== void 0) geometry.x = options.x;
1297
+ if (options.y !== void 0) geometry.y = options.y;
1298
+ if (options.width !== void 0) geometry.width = options.width;
1299
+ if (options.height !== void 0)
1300
+ geometry.height = options.height;
1301
+ model.setGeometry(cell, geometry);
1302
+ }
1303
+ if (options.text !== void 0) {
1304
+ graph.cellLabelChanged(cell, options.text, false);
1305
+ }
1306
+ if (options.style !== void 0) {
1307
+ graph.setCellStyle(options.style, [cell]);
1308
+ }
1309
+ } finally {
1310
+ model.endUpdate();
1311
+ }
1312
+ return cell;
1313
+ }
1314
+ function edit_edge(ui2, options) {
1315
+ const { editor } = ui2;
1316
+ const { graph } = editor;
1317
+ const model = graph.getModel();
1318
+ const cell_id = options.cell_id;
1319
+ if (!cell_id) {
1320
+ throw new Error("edit_edge requires a cell_id");
1321
+ }
1322
+ const edge = model.getCell(cell_id);
1323
+ if (!edge) {
1324
+ throw new Error(`edit_edge could not find edge with id '${cell_id}'`);
1325
+ }
1326
+ if (!edge.edge) {
1327
+ throw new Error(`Cell '${cell_id}' is not an edge`);
1328
+ }
1329
+ model.beginUpdate();
1330
+ try {
1331
+ if (options.source_id !== void 0) {
1332
+ const newSource = model.getCell(options.source_id);
1333
+ if (!newSource) {
1334
+ throw new Error(
1335
+ `edit_edge could not find source cell '${options.source_id}'`
1336
+ );
1337
+ }
1338
+ model.setTerminal(edge, newSource, true);
1339
+ }
1340
+ if (options.target_id !== void 0) {
1341
+ const newTarget = model.getCell(options.target_id);
1342
+ if (!newTarget) {
1343
+ throw new Error(
1344
+ `edit_edge could not find target cell '${options.target_id}'`
1345
+ );
1346
+ }
1347
+ model.setTerminal(edge, newTarget, false);
1348
+ }
1349
+ if (options.text !== void 0) {
1350
+ graph.cellLabelChanged(edge, options.text, false);
1351
+ }
1352
+ if (options.style !== void 0) {
1353
+ graph.setCellStyle(options.style, [edge]);
1354
+ }
1355
+ if (options.points !== void 0) {
1356
+ const geo = edge.getGeometry().clone();
1357
+ const mxPoint = window.mxPoint;
1358
+ geo.points = options.points.map((p) => new mxPoint(p.x, p.y));
1359
+ model.setGeometry(edge, geo);
1360
+ }
1361
+ } finally {
1362
+ model.endUpdate();
1363
+ }
1364
+ return edge;
1365
+ }
1366
+ function set_cell_shape(ui2, options) {
1367
+ const { editor } = ui2;
1368
+ const { graph } = editor;
1369
+ const model = graph.getModel();
1370
+ const cell_id = options.cell_id;
1371
+ const shape_name = options.shape_name;
1372
+ if (!cell_id) {
1373
+ throw new Error("set_cell_shape requires a cell_id");
1374
+ }
1375
+ if (!shape_name) {
1376
+ throw new Error("set_cell_shape requires a shape_name");
1377
+ }
1378
+ const cell = model.getCell(cell_id);
1379
+ if (!cell) {
1380
+ throw new Error(`set_cell_shape could not find cell with id '${cell_id}'`);
1381
+ }
1382
+ if (cell.edge) {
1383
+ throw new Error(
1384
+ `Cell '${cell_id}' is an edge; set_cell_shape expects a vertex`
1385
+ );
1386
+ }
1387
+ const style = shapeLibrary?.[shape_name]?.style;
1388
+ if (!style) {
1389
+ throw new Error(
1390
+ `set_cell_shape could not find a shape named '${shape_name}'`
1391
+ );
1392
+ }
1393
+ model.beginUpdate();
1394
+ try {
1395
+ apply_style_to_cell(graph, cell, style);
1396
+ } finally {
1397
+ model.endUpdate();
1398
+ }
1399
+ return cell;
1400
+ }
1401
+ function set_cell_data(ui2, options) {
1402
+ const { editor } = ui2;
1403
+ const { graph } = editor;
1404
+ const model = graph.getModel();
1405
+ const mxUtils = window.mxUtils;
1406
+ const cell_id = options.cell_id;
1407
+ const key = options.key;
1408
+ const value = options.value;
1409
+ if (!cell_id) {
1410
+ throw new Error("set_cell_data requires a cell_id");
1411
+ }
1412
+ if (!key) {
1413
+ throw new Error("set_cell_data requires a key");
1414
+ }
1415
+ if (value === void 0) {
1416
+ throw new Error("set_cell_data requires a value");
1417
+ }
1418
+ const cell = model.getCell(cell_id);
1419
+ if (!cell) {
1420
+ throw new Error(`set_cell_data could not find cell with id '${cell_id}'`);
1421
+ }
1422
+ model.beginUpdate();
1423
+ try {
1424
+ let d = graph.getModel().getValue(cell);
1425
+ if (!mxUtils.isNode(d)) {
1426
+ var h = mxUtils.createXmlDocument().createElement("object");
1427
+ h.setAttribute("label", d || "");
1428
+ d = h;
1429
+ }
1430
+ d = d.cloneNode(true);
1431
+ d.setAttribute(key, value);
1432
+ graph.getModel().setValue(cell, d);
1433
+ } catch (e) {
1434
+ console.error(`[set-cell-data] error`, e);
1435
+ } finally {
1436
+ model.endUpdate();
1437
+ }
1438
+ return cell;
1439
+ }
1440
+ function get_shape_categories(ui2) {
1441
+ const shapes = shapeLibrary;
1442
+ const categories = /* @__PURE__ */ new Set();
1443
+ for (const shape of Object.values(shapes)) {
1444
+ categories.add(shape.category || "General");
1445
+ }
1446
+ return [...categories];
1447
+ }
1448
+ function get_shapes_in_category(ui2, options) {
1449
+ const shapes = shapeLibrary;
1450
+ return Object.entries(shapes).filter(([_, shape]) => {
1451
+ return shape.category === options.category_id;
1452
+ }).map(([shape_key, shape_value]) => {
1453
+ return {
1454
+ id: shape_key,
1455
+ title: shape_value.title || shape_key
1456
+ };
1457
+ });
1458
+ }
1459
+ function get_shape_by_name(ui2, options) {
1460
+ const shapes = shapeLibrary;
1461
+ const shape = shapes[options.shape_name];
1462
+ if (!shape) return null;
1463
+ return {
1464
+ id: options.shape_name,
1465
+ ...shape
1466
+ };
1467
+ }
1468
+ function add_cell_of_shape(ui2, options) {
1469
+ const { editor } = ui2;
1470
+ const { graph } = editor;
1471
+ const shape_name = options.shape_name;
1472
+ if (!shape_name) {
1473
+ throw new Error("add_cell_of_shape requires a shape_name");
1474
+ }
1475
+ const x = options.x || 100;
1476
+ const y = options.y || 100;
1477
+ const width = options.width || 120;
1478
+ const height = options.height || 80;
1479
+ const text = options.text || "";
1480
+ const style = options.style || "";
1481
+ const parent = resolve_parent(graph, options.parent_id);
1482
+ const shape_entry = get_shape_by_name(ui2, { shape_name });
1483
+ if (!shape_entry) return null;
1484
+ const mergedStyle = normalize_shape_style(
1485
+ shape_name,
1486
+ [shape_entry.style, style].filter((entry) => typeof entry === "string" && entry.trim().length > 0).join(";")
1487
+ );
1488
+ graph.getModel().beginUpdate();
1489
+ try {
1490
+ const cell = create_shape_vertex(graph, {
1491
+ parent,
1492
+ text,
1493
+ x,
1494
+ y,
1495
+ width,
1496
+ height,
1497
+ style: mergedStyle
1498
+ });
1499
+ return cell;
1500
+ } finally {
1501
+ graph.getModel().endUpdate();
1502
+ }
1503
+ }
1504
+ function list_paged_model(ui2, options = {}) {
1505
+ const { editor } = ui2;
1506
+ const { graph } = editor;
1507
+ const model = graph.getModel();
1508
+ const cells = model.cells;
1509
+ if (!cells) {
1510
+ return [];
1511
+ }
1512
+ function parse_style_attributes(style) {
1513
+ const attributes = {};
1514
+ if (!style) return attributes;
1515
+ const pairs = style.split(";");
1516
+ for (const pair of pairs) {
1517
+ const [key, ...valueParts] = pair.split("=");
1518
+ if (key && valueParts.length > 0) {
1519
+ attributes[key.trim()] = valueParts.join("=").trim();
1520
+ }
1521
+ }
1522
+ return attributes;
1523
+ }
1524
+ function extract_cell_attributes(cell) {
1525
+ const attributes = {};
1526
+ attributes.id = cell.id || "";
1527
+ attributes.edge = cell.edge || false;
1528
+ if (cell.style) {
1529
+ Object.assign(attributes, parse_style_attributes(cell.style));
1530
+ }
1531
+ if (cell.value && typeof cell.value === "object" && cell.value.attributes) {
1532
+ const transformed_attributes = transform_cells_NamedNodeMap_to_attributes(cell);
1533
+ Object.assign(attributes, transformed_attributes);
1534
+ }
1535
+ if (cell.value && typeof cell.value === "string") {
1536
+ attributes.text = cell.value;
1537
+ }
1538
+ return attributes;
1539
+ }
1540
+ function evaluate_filter_expression(expression, attributes) {
1541
+ if (!Array.isArray(expression) || expression.length === 0) {
1542
+ return true;
1543
+ }
1544
+ const [operator, ...operands] = expression;
1545
+ switch (operator) {
1546
+ case "and":
1547
+ return operands.every(
1548
+ (op) => evaluate_filter_expression(op, attributes)
1549
+ );
1550
+ case "or":
1551
+ return operands.some(
1552
+ (op) => evaluate_filter_expression(op, attributes)
1553
+ );
1554
+ case "equal":
1555
+ if (operands.length !== 2) return false;
1556
+ const [key, value] = operands;
1557
+ return attributes[key] === value;
1558
+ default:
1559
+ return true;
1560
+ }
1561
+ }
1562
+ function matches_cell_type(cell, cell_type, isLayer) {
1563
+ switch (cell_type) {
1564
+ case "edge":
1565
+ return cell.edge === true || cell.edge === 1;
1566
+ case "vertex":
1567
+ return cell.edge === false;
1568
+ case "object":
1569
+ return cell.value?.nodeName === "object";
1570
+ case "group":
1571
+ return cell.style === "group";
1572
+ case "layer":
1573
+ return isLayer(cell);
1574
+ default:
1575
+ return true;
1576
+ }
1577
+ }
1578
+ let filtered_cells = Object.values(cells);
1579
+ if (options.filter) {
1580
+ const filter = options.filter;
1581
+ const allParentIds = [
1582
+ ...filter.parent_ids || [],
1583
+ ...filter.layer_ids || []
1584
+ ];
1585
+ filtered_cells = filtered_cells.filter((cell) => {
1586
+ if (options.filter?.cell_type && !matches_cell_type(
1587
+ cell,
1588
+ options.filter.cell_type,
1589
+ mx_isLayer(model.root)
1590
+ )) {
1591
+ return false;
1592
+ }
1593
+ if (options.filter?.attributes && options.filter.attributes.length > 0) {
1594
+ const cellAttributes = extract_cell_attributes(cell);
1595
+ if (!evaluate_filter_expression(options.filter.attributes, cellAttributes)) {
1596
+ return false;
1597
+ }
1598
+ }
1599
+ if (allParentIds.length > 0) {
1600
+ const parent = cell.parent;
1601
+ if (!parent || !parent.id || !allParentIds.includes(parent.id)) {
1602
+ return false;
1603
+ }
1604
+ }
1605
+ if (filter.ids && filter.ids.length > 0) {
1606
+ if (!filter.ids.includes(cell.id)) {
1607
+ return false;
1608
+ }
1609
+ }
1610
+ return true;
1611
+ });
1612
+ }
1613
+ const page = Math.max(0, options.page || 0);
1614
+ const page_size = Math.max(1, options.page_size || 50);
1615
+ const start_index = page * page_size;
1616
+ const cell_ids = filtered_cells.map((cell) => cell.id);
1617
+ const paginated_ids = cell_ids.slice(start_index, start_index + page_size);
1618
+ const transformed_cells = [];
1619
+ for (const cell_id of paginated_ids) {
1620
+ const cell = cells[cell_id];
1621
+ if (cell) {
1622
+ const sanitized_cell = remove_circular_dependencies(cell);
1623
+ const transformed_cell = transform_cell_for_display(sanitized_cell);
1624
+ if (transformed_cell) {
1625
+ const layer_info = get_cell_layer(graph, cell);
1626
+ if (layer_info) {
1627
+ transformed_cell.layer = layer_info;
1628
+ }
1629
+ const tags_info = get_cell_tags(graph, cell);
1630
+ if (tags_info && tags_info.length > 0) {
1631
+ transformed_cell.tags = tags_info;
1632
+ }
1633
+ transformed_cells.push(transformed_cell);
1634
+ }
1635
+ }
1636
+ }
1637
+ return transformed_cells;
1638
+ }
1639
+ function list_layers(ui2) {
1640
+ const { editor } = ui2;
1641
+ const { graph } = editor;
1642
+ const model = graph.getModel();
1643
+ const root = model.getRoot();
1644
+ const layers = [];
1645
+ for (let i = 0; i < model.getChildCount(root); i++) {
1646
+ const layer = model.getChildAt(root, i);
1647
+ if (layer) {
1648
+ layers.push({
1649
+ id: layer.getId(),
1650
+ name: layer.getValue() || `Layer ${i}`,
1651
+ visible: layer.isVisible(),
1652
+ locked: !layer.isConnectable()
1653
+ });
1654
+ }
1655
+ }
1656
+ return layers;
1657
+ }
1658
+ function set_active_layer(ui2, options) {
1659
+ const { editor } = ui2;
1660
+ const { graph } = editor;
1661
+ const model = graph.getModel();
1662
+ const layer = model.getCell(options.layer_id);
1663
+ if (!layer) {
1664
+ throw new Error(`Layer with ID ${options.layer_id} not found`);
1665
+ }
1666
+ graph.setDefaultParent(layer);
1667
+ return {
1668
+ id: layer.getId(),
1669
+ name: layer.getValue() || "Unnamed Layer"
1670
+ };
1671
+ }
1672
+ function move_cell_to_layer(ui2, options) {
1673
+ const { editor } = ui2;
1674
+ const { graph } = editor;
1675
+ const model = graph.getModel();
1676
+ const cell = model.getCell(options.cell_id);
1677
+ const targetLayer = model.getCell(options.target_layer_id);
1678
+ if (!cell) {
1679
+ throw new Error(`Cell with ID ${options.cell_id} not found`);
1680
+ }
1681
+ if (!targetLayer) {
1682
+ throw new Error(
1683
+ `Target layer with ID ${options.target_layer_id} not found`
1684
+ );
1685
+ }
1686
+ model.beginUpdate();
1687
+ try {
1688
+ model.add(targetLayer, cell);
1689
+ } finally {
1690
+ model.endUpdate();
1691
+ }
1692
+ return {
1693
+ moved_cell: options.cell_id,
1694
+ to_layer: options.target_layer_id
1695
+ };
1696
+ }
1697
+ function set_cell_parent(ui2, options) {
1698
+ const { editor } = ui2;
1699
+ const { graph } = editor;
1700
+ const model = graph.getModel();
1701
+ const cell = model.getCell(options.cell_id);
1702
+ if (!cell) {
1703
+ throw new Error(`Cell with ID ${options.cell_id} not found`);
1704
+ }
1705
+ const parent = model.getCell(options.parent_id);
1706
+ if (!parent) {
1707
+ throw new Error(`Parent cell with ID ${options.parent_id} not found`);
1708
+ }
1709
+ model.beginUpdate();
1710
+ try {
1711
+ model.add(parent, cell);
1712
+ } finally {
1713
+ model.endUpdate();
1714
+ }
1715
+ return {
1716
+ cell_id: options.cell_id,
1717
+ parent_id: options.parent_id
1718
+ };
1719
+ }
1720
+ function get_active_layer(ui2) {
1721
+ const { editor } = ui2;
1722
+ const { graph } = editor;
1723
+ const activeLayer = graph.getDefaultParent();
1724
+ return {
1725
+ id: activeLayer.getId(),
1726
+ name: activeLayer.getValue() || "Default Layer"
1727
+ };
1728
+ }
1729
+ function create_layer(ui2, options) {
1730
+ const { editor } = ui2;
1731
+ const { graph } = editor;
1732
+ const model = graph.getModel();
1733
+ const root = model.getRoot();
1734
+ model.beginUpdate();
1735
+ let newLayer;
1736
+ try {
1737
+ newLayer = new window.mxCell(options.name);
1738
+ newLayer.setId(null);
1739
+ model.add(root, newLayer);
1740
+ } finally {
1741
+ model.endUpdate();
1742
+ }
1743
+ return {
1744
+ id: newLayer.getId(),
1745
+ name: options.name
1746
+ };
1747
+ }
1748
+ var PNG_SIZE_WARNING_THRESHOLD = 5 * 1024 * 1024;
1749
+ function export_diagram(ui2, options) {
1750
+ const format = options.format || "xml";
1751
+ const scale = options.scale ?? 1;
1752
+ const border = options.border ?? 0;
1753
+ const background = options.transparent ? null : options.background ?? null;
1754
+ const includeShadow = options.shadow ?? false;
1755
+ const cropToDiagram = options.crop ?? true;
1756
+ const selectionOnly = options.selection_only ?? false;
1757
+ const embedXml = options.embed_xml ?? false;
1758
+ const size = options.size ?? "diagram";
1759
+ const dpi = options.dpi ?? 96;
1760
+ switch (format) {
1761
+ case "xml":
1762
+ return export_xml(ui2, { selectionOnly, size });
1763
+ case "svg":
1764
+ return export_svg(ui2, {
1765
+ scale,
1766
+ border,
1767
+ background,
1768
+ includeShadow,
1769
+ cropToDiagram,
1770
+ selectionOnly,
1771
+ embedXml,
1772
+ size
1773
+ });
1774
+ case "png":
1775
+ return export_png(ui2, {
1776
+ scale,
1777
+ border,
1778
+ background,
1779
+ includeShadow,
1780
+ cropToDiagram,
1781
+ selectionOnly,
1782
+ embedXml,
1783
+ size,
1784
+ dpi
1785
+ });
1786
+ default:
1787
+ throw new Error(`Unsupported export format: ${format}`);
1788
+ }
1789
+ }
1790
+ function export_xml(ui2, params) {
1791
+ const mxUtils = window.mxUtils;
1792
+ const { selectionOnly, size } = params;
1793
+ const ignoreSelection = !selectionOnly;
1794
+ const currentPage = size === "page" || size === "selection";
1795
+ const uncompressed = true;
1796
+ let xml;
1797
+ if (size === "selection" && selectionOnly) {
1798
+ const enc = new window.mxCodec();
1799
+ const node = enc.encode(ui2.editor.graph.getModel());
1800
+ xml = mxUtils.getXml(node);
1801
+ } else {
1802
+ const node = ui2.getXmlFileData(ignoreSelection, currentPage, uncompressed);
1803
+ xml = mxUtils.getXml(node);
1804
+ }
1805
+ return {
1806
+ format: "xml",
1807
+ mimeType: "application/xml",
1808
+ data: xml
1809
+ };
1810
+ }
1811
+ function export_svg(ui2, params) {
1812
+ const mxUtils = window.mxUtils;
1813
+ const Graph = window.Graph;
1814
+ const {
1815
+ scale,
1816
+ border,
1817
+ background,
1818
+ includeShadow,
1819
+ selectionOnly,
1820
+ embedXml,
1821
+ size
1822
+ } = params;
1823
+ const graph = ui2.editor.graph;
1824
+ const ignoreSelection = !selectionOnly && size !== "selection";
1825
+ const bg = background !== "none" ? background : null;
1826
+ if (embedXml) {
1827
+ const currentPage = size === "page" || size === "selection";
1828
+ const svgString2 = ui2.getFileData(
1829
+ false,
1830
+ true,
1831
+ null,
1832
+ null,
1833
+ ignoreSelection,
1834
+ currentPage
1835
+ );
1836
+ const bounds = graph.getGraphBounds();
1837
+ const w2 = Math.ceil(bounds.width * scale + bounds.x * scale + 2 * border);
1838
+ const h2 = Math.ceil(bounds.height * scale + bounds.y * scale + 2 * border);
1839
+ return {
1840
+ format: "svg",
1841
+ mimeType: "image/svg+xml",
1842
+ data: svgString2,
1843
+ width: w2,
1844
+ height: h2
1845
+ };
1846
+ }
1847
+ const svgRoot = graph.getSvg(
1848
+ bg,
1849
+ scale,
1850
+ border,
1851
+ !params.cropToDiagram,
1852
+ null,
1853
+ ignoreSelection
1854
+ );
1855
+ if (graph.shadowVisible || includeShadow) {
1856
+ graph.addSvgShadow(svgRoot, null, null, border === 0);
1857
+ }
1858
+ const svgString = (Graph.xmlDeclaration || '<?xml version="1.0" encoding="UTF-8"?>') + "\n" + (Graph.svgDoctype || "") + "\n" + mxUtils.getXml(svgRoot);
1859
+ const w = parseInt(svgRoot.getAttribute("width")) || 0;
1860
+ const h = parseInt(svgRoot.getAttribute("height")) || 0;
1861
+ return {
1862
+ format: "svg",
1863
+ mimeType: "image/svg+xml",
1864
+ data: svgString,
1865
+ width: w,
1866
+ height: h
1867
+ };
1868
+ }
1869
+ function export_png(ui2, params) {
1870
+ return new Promise((resolve, reject) => {
1871
+ const {
1872
+ scale,
1873
+ border,
1874
+ background,
1875
+ includeShadow,
1876
+ selectionOnly,
1877
+ embedXml,
1878
+ size,
1879
+ dpi,
1880
+ cropToDiagram
1881
+ } = params;
1882
+ const imageCache = {};
1883
+ const ignoreSelection = !selectionOnly && size !== "selection";
1884
+ let xml = null;
1885
+ if (embedXml) {
1886
+ xml = ui2.getFileData(
1887
+ true,
1888
+ null,
1889
+ null,
1890
+ null,
1891
+ ignoreSelection,
1892
+ size === "page" || size === "selection"
1893
+ );
1894
+ }
1895
+ ui2.exportToCanvas(
1896
+ (canvas) => {
1897
+ try {
1898
+ let dataUrl;
1899
+ if (xml != null) {
1900
+ dataUrl = ui2.createImageDataUri(canvas, xml, "png", dpi);
1901
+ } else {
1902
+ dataUrl = canvas.toDataURL("image/png");
1903
+ }
1904
+ const base64Data = dataUrl.replace(/^data:image\/png;base64,/, "");
1905
+ const result = {
1906
+ format: "png",
1907
+ mimeType: "image/png",
1908
+ data: base64Data,
1909
+ width: canvas.width,
1910
+ height: canvas.height
1911
+ };
1912
+ if (base64Data.length > PNG_SIZE_WARNING_THRESHOLD) {
1913
+ const sizeMB = (base64Data.length / (1024 * 1024)).toFixed(1);
1914
+ result.warning = `PNG export is large (${sizeMB} MB). Consider using SVG or reducing scale to reduce size.`;
1915
+ }
1916
+ resolve(result);
1917
+ } catch (err) {
1918
+ reject(err);
1919
+ }
1920
+ },
1921
+ null,
1922
+ imageCache,
1923
+ background,
1924
+ (err) => reject(err),
1925
+ null,
1926
+ ignoreSelection,
1927
+ scale,
1928
+ background === null,
1929
+ includeShadow,
1930
+ null,
1931
+ null,
1932
+ border,
1933
+ !cropToDiagram,
1934
+ false,
1935
+ null
1936
+ );
1937
+ });
1938
+ }
1939
+ function extractXmlFromSvg(svgContent) {
1940
+ try {
1941
+ const parser = new DOMParser();
1942
+ const svgDoc = parser.parseFromString(svgContent, "image/svg+xml");
1943
+ const metadata = svgDoc.querySelector("metadata");
1944
+ if (metadata) {
1945
+ const mxfile2 = metadata.querySelector("mxfile");
1946
+ if (mxfile2) {
1947
+ const serializer = new XMLSerializer();
1948
+ return serializer.serializeToString(mxfile2);
1949
+ }
1950
+ }
1951
+ const defs = svgDoc.querySelector("defs");
1952
+ if (defs) {
1953
+ const mxfile2 = defs.querySelector("mxfile");
1954
+ if (mxfile2) {
1955
+ const serializer = new XMLSerializer();
1956
+ return serializer.serializeToString(mxfile2);
1957
+ }
1958
+ }
1959
+ const mxfile = svgDoc.querySelector("mxfile");
1960
+ if (mxfile) {
1961
+ const serializer = new XMLSerializer();
1962
+ return serializer.serializeToString(mxfile);
1963
+ }
1964
+ return null;
1965
+ } catch (error) {
1966
+ console.error("[import-diagram] Error extracting XML from SVG:", error);
1967
+ return null;
1968
+ }
1969
+ }
1970
+ function extractXmlFromPng(base64Png) {
1971
+ try {
1972
+ const binaryString = atob(base64Png);
1973
+ const bytes = new Uint8Array(binaryString.length);
1974
+ for (let i = 0; i < binaryString.length; i++) {
1975
+ bytes[i] = binaryString.charCodeAt(i);
1976
+ }
1977
+ const pngSignature = [137, 80, 78, 71, 13, 10, 26, 10];
1978
+ for (let i = 0; i < 8; i++) {
1979
+ if (bytes[i] !== pngSignature[i]) {
1980
+ console.error("[import-diagram] Invalid PNG signature");
1981
+ return null;
1982
+ }
1983
+ }
1984
+ let offset = 8;
1985
+ while (offset < bytes.length) {
1986
+ const length = bytes[offset] << 24 | bytes[offset + 1] << 16 | bytes[offset + 2] << 8 | bytes[offset + 3];
1987
+ const chunkType = String.fromCharCode(
1988
+ bytes[offset + 4],
1989
+ bytes[offset + 5],
1990
+ bytes[offset + 6],
1991
+ bytes[offset + 7]
1992
+ );
1993
+ if (chunkType === "tEXt") {
1994
+ const chunkData = bytes.slice(offset + 8, offset + 8 + length);
1995
+ let nullIndex = -1;
1996
+ for (let i = 0; i < chunkData.length; i++) {
1997
+ if (chunkData[i] === 0) {
1998
+ nullIndex = i;
1999
+ break;
2000
+ }
2001
+ }
2002
+ if (nullIndex !== -1) {
2003
+ const keyword = String.fromCharCode(...chunkData.slice(0, nullIndex));
2004
+ const text = String.fromCharCode(...chunkData.slice(nullIndex + 1));
2005
+ if (keyword === "mxGraphModel" || keyword === "mxfile" || text.includes("<mxfile") || text.includes("<mxGraphModel")) {
2006
+ return text;
2007
+ }
2008
+ }
2009
+ }
2010
+ if (chunkType === "zTXt") {
2011
+ const chunkData = bytes.slice(offset + 8, offset + 8 + length);
2012
+ let nullIndex = -1;
2013
+ for (let i = 0; i < chunkData.length; i++) {
2014
+ if (chunkData[i] === 0) {
2015
+ nullIndex = i;
2016
+ break;
2017
+ }
2018
+ }
2019
+ if (nullIndex !== -1) {
2020
+ const keyword = String.fromCharCode(...chunkData.slice(0, nullIndex));
2021
+ const compressionMethod = chunkData[nullIndex + 1];
2022
+ if (compressionMethod === 0) {
2023
+ const compressedData = chunkData.slice(nullIndex + 2);
2024
+ if (typeof DecompressionStream !== "undefined") {
2025
+ console.warn(
2026
+ "[import-diagram] zTXt chunk found but decompression not implemented in sync context"
2027
+ );
2028
+ }
2029
+ }
2030
+ }
2031
+ }
2032
+ offset += 12 + length;
2033
+ }
2034
+ return null;
2035
+ } catch (error) {
2036
+ console.error("[import-diagram] Error extracting XML from PNG:", error);
2037
+ return null;
2038
+ }
2039
+ }
2040
+ function import_diagram(ui2, options) {
2041
+ const {
2042
+ data,
2043
+ format,
2044
+ mode = "replace",
2045
+ filename
2046
+ } = options;
2047
+ if (!data) {
2048
+ return { success: false, message: "No data provided" };
2049
+ }
2050
+ let xml = null;
2051
+ switch (format) {
2052
+ case "xml":
2053
+ xml = data;
2054
+ break;
2055
+ case "svg":
2056
+ let svgContent = data;
2057
+ if (!data.trim().startsWith("<")) {
2058
+ try {
2059
+ svgContent = atob(data);
2060
+ } catch (e) {
2061
+ return { success: false, message: "Invalid base64 SVG data" };
2062
+ }
2063
+ }
2064
+ xml = extractXmlFromSvg(svgContent);
2065
+ if (!xml) {
2066
+ return { success: false, message: "Could not extract XML from SVG" };
2067
+ }
2068
+ break;
2069
+ case "png":
2070
+ xml = extractXmlFromPng(data);
2071
+ if (!xml) {
2072
+ return { success: false, message: "Could not extract XML from PNG" };
2073
+ }
2074
+ break;
2075
+ default:
2076
+ return { success: false, message: `Unsupported format: ${format}` };
2077
+ }
2078
+ if (!xml) {
2079
+ return { success: false, message: "Failed to extract XML from input" };
2080
+ }
2081
+ const mxUtils = window.mxUtils;
2082
+ if (!mxUtils) {
2083
+ return { success: false, message: "mxUtils not available" };
2084
+ }
2085
+ try {
2086
+ const doc = mxUtils.parseXml(xml);
2087
+ if (!doc || !doc.documentElement) {
2088
+ return { success: false, message: "Invalid XML structure" };
2089
+ }
2090
+ const root = doc.documentElement;
2091
+ if (root.nodeName !== "mxfile" && root.nodeName !== "mxGraphModel") {
2092
+ return {
2093
+ success: false,
2094
+ message: `Invalid Draw.io XML: expected mxfile or mxGraphModel, got ${root.nodeName}`
2095
+ };
2096
+ }
2097
+ const { editor } = ui2;
2098
+ const { graph } = editor;
2099
+ const model = graph.getModel();
2100
+ let cellCount = 0;
2101
+ const cells = doc.getElementsByTagName("mxCell");
2102
+ cellCount = cells.length;
2103
+ switch (mode) {
2104
+ case "replace":
2105
+ let graphModelElement = doc.documentElement;
2106
+ if (graphModelElement.nodeName === "mxfile") {
2107
+ const diagram = graphModelElement.querySelector("diagram");
2108
+ if (diagram) {
2109
+ const mxGraphModel = diagram.querySelector("mxGraphModel");
2110
+ if (mxGraphModel) {
2111
+ graphModelElement = mxGraphModel;
2112
+ }
2113
+ }
2114
+ }
2115
+ if (editor.setGraphXml) {
2116
+ editor.setGraphXml(graphModelElement);
2117
+ graph.refresh();
2118
+ graph.fit();
2119
+ } else {
2120
+ model.clear();
2121
+ model.setRoot(new window.mxCell());
2122
+ const codec = new window.mxCodec(
2123
+ graphModelElement.ownerDocument
2124
+ );
2125
+ codec.decode(graphModelElement, model);
2126
+ }
2127
+ return {
2128
+ success: true,
2129
+ message: `Diagram replaced successfully${filename ? ` from ${filename}` : ""}`,
2130
+ cells: cellCount
2131
+ };
2132
+ case "add":
2133
+ model.beginUpdate();
2134
+ try {
2135
+ const importedDoc = mxUtils.parseXml(xml);
2136
+ const importedRoot = importedDoc.documentElement;
2137
+ let graphModel = importedRoot;
2138
+ if (importedRoot.nodeName === "mxfile") {
2139
+ const diagram = importedRoot.querySelector("diagram");
2140
+ if (diagram) {
2141
+ graphModel = diagram.querySelector("mxGraphModel") || diagram;
2142
+ }
2143
+ }
2144
+ const importedRootCell = graphModel.querySelector("root");
2145
+ if (importedRootCell) {
2146
+ const defaultParent = graph.getDefaultParent();
2147
+ const importedCells = importedRootCell.querySelectorAll("mxCell");
2148
+ const idMapping = {};
2149
+ importedCells.forEach((cell) => {
2150
+ const oldId = cell.getAttribute("id");
2151
+ if (oldId === "0" || oldId === "1") {
2152
+ return;
2153
+ }
2154
+ const newCell = new window.mxCell();
2155
+ newCell.setId(null);
2156
+ if (cell.hasAttribute("value")) {
2157
+ newCell.setValue(cell.getAttribute("value"));
2158
+ }
2159
+ if (cell.hasAttribute("style")) {
2160
+ newCell.setStyle(cell.getAttribute("style"));
2161
+ }
2162
+ if (cell.hasAttribute("vertex")) {
2163
+ newCell.vertex = cell.getAttribute("vertex") === "1";
2164
+ }
2165
+ if (cell.hasAttribute("edge")) {
2166
+ newCell.edge = cell.getAttribute("edge") === "1";
2167
+ }
2168
+ const geo = cell.querySelector("mxGeometry");
2169
+ if (geo) {
2170
+ const geometry = new window.mxGeometry(
2171
+ parseFloat(geo.getAttribute("x") || "0"),
2172
+ parseFloat(geo.getAttribute("y") || "0"),
2173
+ parseFloat(geo.getAttribute("width") || "0"),
2174
+ parseFloat(geo.getAttribute("height") || "0")
2175
+ );
2176
+ if (geo.getAttribute("relative") === "1") {
2177
+ geometry.relative = true;
2178
+ }
2179
+ newCell.setGeometry(geometry);
2180
+ }
2181
+ model.add(defaultParent, newCell);
2182
+ idMapping[oldId] = newCell.getId();
2183
+ });
2184
+ importedCells.forEach((cell) => {
2185
+ const oldId = cell.getAttribute("id");
2186
+ const newId = idMapping[oldId];
2187
+ if (!newId) return;
2188
+ const newCell = model.getCell(newId);
2189
+ if (!newCell) return;
2190
+ const parentId = cell.getAttribute("parent");
2191
+ if (parentId && idMapping[parentId]) {
2192
+ const parentCell = model.getCell(idMapping[parentId]);
2193
+ if (parentCell) {
2194
+ model.add(parentCell, newCell);
2195
+ }
2196
+ }
2197
+ if (newCell.edge) {
2198
+ const sourceId = cell.getAttribute("source");
2199
+ const targetId = cell.getAttribute("target");
2200
+ if (sourceId && idMapping[sourceId]) {
2201
+ const sourceCell = model.getCell(idMapping[sourceId]);
2202
+ if (sourceCell) {
2203
+ model.setTerminal(newCell, sourceCell, true);
2204
+ }
2205
+ }
2206
+ if (targetId && idMapping[targetId]) {
2207
+ const targetCell = model.getCell(idMapping[targetId]);
2208
+ if (targetCell) {
2209
+ model.setTerminal(newCell, targetCell, false);
2210
+ }
2211
+ }
2212
+ }
2213
+ });
2214
+ }
2215
+ } finally {
2216
+ model.endUpdate();
2217
+ }
2218
+ return {
2219
+ success: true,
2220
+ message: `Diagram imported successfully (added to current diagram)${filename ? ` from ${filename}` : ""}`,
2221
+ cells: cellCount
2222
+ };
2223
+ case "new-page":
2224
+ if (!ui2.pages || !ui2.insertPage) {
2225
+ return {
2226
+ success: false,
2227
+ message: "New page creation not supported in this Draw.io version"
2228
+ };
2229
+ }
2230
+ const newPage = ui2.insertPage();
2231
+ if (!newPage) {
2232
+ return { success: false, message: "Failed to create new page" };
2233
+ }
2234
+ ui2.selectPage(newPage);
2235
+ model.beginUpdate();
2236
+ try {
2237
+ let pageGraphModel = doc.documentElement;
2238
+ if (pageGraphModel.nodeName === "mxfile") {
2239
+ const diagram = pageGraphModel.querySelector("diagram");
2240
+ if (diagram) {
2241
+ const mxGraphModel = diagram.querySelector("mxGraphModel");
2242
+ if (mxGraphModel) {
2243
+ pageGraphModel = mxGraphModel;
2244
+ }
2245
+ }
2246
+ }
2247
+ if (editor.setGraphXml) {
2248
+ editor.setGraphXml(pageGraphModel);
2249
+ graph.refresh();
2250
+ graph.fit();
2251
+ } else {
2252
+ const codec = new window.mxCodec(
2253
+ pageGraphModel.ownerDocument
2254
+ );
2255
+ codec.decode(pageGraphModel, model);
2256
+ }
2257
+ } finally {
2258
+ model.endUpdate();
2259
+ }
2260
+ if (filename && newPage.setName) {
2261
+ const pageName = filename.replace(/\.[^/.]+$/, "");
2262
+ newPage.setName(pageName);
2263
+ }
2264
+ return {
2265
+ success: true,
2266
+ message: `Diagram imported successfully (new page created)${filename ? `: ${filename}` : ""}`,
2267
+ pages: ui2.pages.length,
2268
+ cells: cellCount
2269
+ };
2270
+ default:
2271
+ return { success: false, message: `Unsupported import mode: ${mode}` };
2272
+ }
2273
+ } catch (error) {
2274
+ console.error("[import-diagram] Error importing diagram:", error);
2275
+ return {
2276
+ success: false,
2277
+ message: `Import failed: ${error instanceof Error ? error.message : "Unknown error"}`
2278
+ };
2279
+ }
2280
+ }
2281
+
2282
+ // src/plugin.ts
2283
+ function reply_name(event_name, request_id) {
2284
+ return `${event_name}.${request_id}`;
2285
+ }
2286
+ var createToolHandler = (toolName, parameterKeys, executeFunction) => {
2287
+ return (request) => {
2288
+ const optionEntries = Object.entries(request).filter(([key, _value]) => {
2289
+ return parameterKeys.has(key);
2290
+ });
2291
+ const options = optionEntries.reduce(
2292
+ (acc, [key, value]) => {
2293
+ acc[key] = value;
2294
+ return acc;
2295
+ },
2296
+ {}
2297
+ );
2298
+ const sendReply = (result, success, error) => {
2299
+ const reply = {
2300
+ __event: reply_name(toolName, request.__request_id),
2301
+ __request_id: request.__request_id,
2302
+ success,
2303
+ result: success ? remove_circular_dependencies(result) : void 0,
2304
+ error: !success ? remove_circular_dependencies(error) : void 0
2305
+ };
2306
+ if (wsManager) {
2307
+ wsManager.send(reply);
2308
+ }
2309
+ return reply;
2310
+ };
2311
+ try {
2312
+ const result = executeFunction(ui, options);
2313
+ if (result instanceof Promise) {
2314
+ result.then(
2315
+ (resolved) => sendReply(resolved, true),
2316
+ (err) => {
2317
+ console.error(
2318
+ `[plugin] Tool ${toolName} failed for request ID ${request.__request_id}:`,
2319
+ err
2320
+ );
2321
+ sendReply(void 0, false, err);
2322
+ }
2323
+ );
2324
+ return void 0;
2325
+ }
2326
+ return sendReply(result, true);
2327
+ } catch (error) {
2328
+ console.error(
2329
+ `[plugin] Tool ${toolName} failed for request ID ${request.__request_id}:`,
2330
+ error
2331
+ );
2332
+ return sendReply(void 0, false, error);
2333
+ }
2334
+ };
2335
+ };
2336
+ var ui;
2337
+ var wsManager = null;
2338
+ var settingsDialog = null;
2339
+ var toolDefinitions = [
2340
+ {
2341
+ name: "get-selected-cell",
2342
+ params: /* @__PURE__ */ new Set([]),
2343
+ handler: (ui2, _options) => {
2344
+ return ui2.editor.graph.getSelectionCell() || "no cell selected";
2345
+ }
2346
+ },
2347
+ {
2348
+ name: "add-rectangle",
2349
+ params: /* @__PURE__ */ new Set(["x", "y", "width", "height", "text", "style", "parent_id"]),
2350
+ handler: add_new_rectangle
2351
+ },
2352
+ {
2353
+ name: "delete-cell-by-id",
2354
+ params: /* @__PURE__ */ new Set(["cell_id"]),
2355
+ handler: delete_cell_by_id
2356
+ },
2357
+ {
2358
+ name: "add-edge",
2359
+ params: /* @__PURE__ */ new Set(["source_id", "target_id", "style", "text", "parent_id", "points"]),
2360
+ handler: add_edge
2361
+ },
2362
+ {
2363
+ name: "get-shape-categories",
2364
+ params: /* @__PURE__ */ new Set([]),
2365
+ handler: get_shape_categories
2366
+ },
2367
+ {
2368
+ name: "get-shapes-in-category",
2369
+ params: /* @__PURE__ */ new Set(["category_id"]),
2370
+ handler: get_shapes_in_category
2371
+ },
2372
+ {
2373
+ name: "get-shape-by-name",
2374
+ params: /* @__PURE__ */ new Set(["shape_name"]),
2375
+ handler: get_shape_by_name
2376
+ },
2377
+ {
2378
+ name: "add-cell-of-shape",
2379
+ params: /* @__PURE__ */ new Set([
2380
+ "shape_name",
2381
+ "x",
2382
+ "y",
2383
+ "width",
2384
+ "height",
2385
+ "text",
2386
+ "style",
2387
+ "parent_id"
2388
+ ]),
2389
+ handler: add_cell_of_shape
2390
+ },
2391
+ {
2392
+ name: "set-cell-shape",
2393
+ params: /* @__PURE__ */ new Set(["cell_id", "shape_name"]),
2394
+ handler: set_cell_shape
2395
+ },
2396
+ {
2397
+ name: "set-cell-data",
2398
+ params: /* @__PURE__ */ new Set(["cell_id", "key", "value"]),
2399
+ handler: (ui2, options) => {
2400
+ return set_cell_data(ui2, options);
2401
+ }
2402
+ },
2403
+ {
2404
+ name: "list-paged-model",
2405
+ params: /* @__PURE__ */ new Set(["page", "page_size", "filter"]),
2406
+ handler: list_paged_model
2407
+ },
2408
+ {
2409
+ name: "edit-cell",
2410
+ params: /* @__PURE__ */ new Set(["cell_id", "text", "x", "y", "width", "height", "style"]),
2411
+ handler: edit_cell
2412
+ },
2413
+ {
2414
+ name: "edit-edge",
2415
+ params: /* @__PURE__ */ new Set(["cell_id", "text", "source_id", "target_id", "style", "points"]),
2416
+ handler: edit_edge
2417
+ },
2418
+ {
2419
+ name: "list-layers",
2420
+ params: /* @__PURE__ */ new Set([]),
2421
+ handler: list_layers
2422
+ },
2423
+ {
2424
+ name: "set-active-layer",
2425
+ params: /* @__PURE__ */ new Set(["layer_id"]),
2426
+ handler: set_active_layer
2427
+ },
2428
+ {
2429
+ name: "move-cell-to-layer",
2430
+ params: /* @__PURE__ */ new Set(["cell_id", "target_layer_id"]),
2431
+ handler: move_cell_to_layer
2432
+ },
2433
+ {
2434
+ name: "set-cell-parent",
2435
+ params: /* @__PURE__ */ new Set(["cell_id", "parent_id"]),
2436
+ handler: set_cell_parent
2437
+ },
2438
+ {
2439
+ name: "get-active-layer",
2440
+ params: /* @__PURE__ */ new Set([]),
2441
+ handler: get_active_layer
2442
+ },
2443
+ {
2444
+ name: "create-layer",
2445
+ params: /* @__PURE__ */ new Set(["name"]),
2446
+ handler: create_layer
2447
+ },
2448
+ {
2449
+ name: "export-diagram",
2450
+ params: /* @__PURE__ */ new Set([
2451
+ "format",
2452
+ "scale",
2453
+ "border",
2454
+ "background",
2455
+ "shadow",
2456
+ "crop",
2457
+ "selection_only",
2458
+ "transparent",
2459
+ "dpi",
2460
+ "embed_xml",
2461
+ "size"
2462
+ ]),
2463
+ handler: export_diagram
2464
+ },
2465
+ {
2466
+ name: "import-diagram",
2467
+ params: /* @__PURE__ */ new Set(["data", "format", "mode", "filename"]),
2468
+ handler: import_diagram
2469
+ }
2470
+ ];
2471
+ var toolHandlers = /* @__PURE__ */ new Map();
2472
+ var handleWebSocketMessage = (message) => {
2473
+ console.debug("[plugin] Received WebSocket message:", message);
2474
+ if (message.__event && toolHandlers.has(message.__event)) {
2475
+ const handler = toolHandlers.get(message.__event);
2476
+ if (handler) {
2477
+ handler(message);
2478
+ }
2479
+ }
2480
+ };
2481
+ var initializeWebSocket = async () => {
2482
+ const config = await fetchPluginConfig();
2483
+ const wsUrl = buildWebSocketUrl(config);
2484
+ wsManager = createWebSocketManager({
2485
+ url: wsUrl,
2486
+ maxReconnectAttempts: 5,
2487
+ reconnectDelay: 3e3,
2488
+ pingInterval: 3e4
2489
+ });
2490
+ wsManager.onMessage(handleWebSocketMessage);
2491
+ wsManager.connect();
2492
+ console.log(`[plugin] WebSocket initialized with URL: ${wsUrl}`);
2493
+ };
2494
+ var initializeSettingsDialog = () => {
2495
+ const config = readPluginConfig();
2496
+ const connectionState = wsManager ? wsManager.getState() : "disconnected";
2497
+ const initialState = {
2498
+ config: { ...config },
2499
+ connectionState,
2500
+ isSaving: false,
2501
+ formData: {
2502
+ port: config.websocketPort.toString()
2503
+ },
2504
+ errors: {}
2505
+ };
2506
+ const actions = {
2507
+ onSave: (newConfig) => {
2508
+ writePluginConfig(newConfig);
2509
+ if (wsManager) {
2510
+ wsManager.disconnect();
2511
+ }
2512
+ initializeWebSocket();
2513
+ if (settingsDialog) {
2514
+ settingsDialog.update({
2515
+ ...initialState,
2516
+ config: { ...newConfig },
2517
+ connectionState: wsManager ? wsManager.getState() : "disconnected",
2518
+ isSaving: false
2519
+ });
2520
+ }
2521
+ console.log("[plugin] Configuration saved and WebSocket reinitialized");
2522
+ },
2523
+ onClose: () => {
2524
+ if (settingsDialog) {
2525
+ hideSettingsDialog(settingsDialog);
2526
+ }
2527
+ },
2528
+ onPing: async () => {
2529
+ if (wsManager) {
2530
+ return await wsManager.ping();
2531
+ }
2532
+ return false;
2533
+ },
2534
+ onReconnect: () => {
2535
+ if (wsManager) {
2536
+ wsManager.disconnect();
2537
+ wsManager.connect();
2538
+ }
2539
+ }
2540
+ };
2541
+ settingsDialog = createSettingsDialog(initialState, actions);
2542
+ };
2543
+ var showSettings = () => {
2544
+ if (!settingsDialog) {
2545
+ initializeSettingsDialog();
2546
+ }
2547
+ if (settingsDialog) {
2548
+ const config = readPluginConfig();
2549
+ const connectionState = wsManager ? wsManager.getState() : "disconnected";
2550
+ settingsDialog.update({
2551
+ config: { ...config },
2552
+ connectionState,
2553
+ isSaving: false,
2554
+ formData: {
2555
+ port: config.websocketPort.toString()
2556
+ },
2557
+ errors: {}
2558
+ });
2559
+ showSettingsDialog(settingsDialog);
2560
+ }
2561
+ };
2562
+ var addMenuItem = (ui2) => {
2563
+ if (!ui2.menus) {
2564
+ console.warn(
2565
+ "[plugin] Menu bar not available, cannot add MCP Settings menu item"
2566
+ );
2567
+ return;
2568
+ }
2569
+ const menubar = ui2.menus;
2570
+ try {
2571
+ let targetMenu = menubar.get("extras") || menubar.get("file") || menubar.get("edit");
2572
+ if (!targetMenu) {
2573
+ console.warn("[plugin] Could not find suitable menu to add MCP Settings");
2574
+ return;
2575
+ }
2576
+ ui2.actions.addAction("Draw.io MCP", function() {
2577
+ showSettings();
2578
+ });
2579
+ var oldFunct = targetMenu.funct;
2580
+ targetMenu.funct = function(targetMenu2, parent) {
2581
+ oldFunct.apply(this, arguments);
2582
+ ui2.menus.addMenuItems(targetMenu2, ["Draw.io MCP"], parent);
2583
+ };
2584
+ } catch (error) {
2585
+ console.error("[plugin] Failed to add menu item:", error);
2586
+ }
2587
+ };
2588
+ function initPlugin() {
2589
+ console.debug("[plugin] Loading Draw.io MCP Plugin...");
2590
+ const checkInterval = setInterval(() => {
2591
+ if (window.Draw) {
2592
+ clearInterval(checkInterval);
2593
+ window.Draw.loadPlugin((drawioUI) => {
2594
+ console.debug("[plugin] Plugin loaded successfully");
2595
+ ui = drawioUI;
2596
+ if (window.__DRAWIO_MCP_TEST_HOOKS__ === true) {
2597
+ window.ui = drawioUI;
2598
+ }
2599
+ toolDefinitions.forEach((def) => {
2600
+ const handler = createToolHandler(def.name, def.params, def.handler);
2601
+ toolHandlers.set(def.name, handler);
2602
+ });
2603
+ initializeWebSocket();
2604
+ initializeSettingsDialog();
2605
+ addMenuItem(ui);
2606
+ console.info("[plugin] MCP Plugin fully initialized");
2607
+ });
2608
+ }
2609
+ }, 1e3);
2610
+ }
2611
+ if (typeof window !== "undefined") {
2612
+ if (document.readyState === "loading") {
2613
+ document.addEventListener("DOMContentLoaded", initPlugin);
2614
+ } else {
2615
+ initPlugin();
2616
+ }
2617
+ }
2618
+ })();