drawio-mcp-server 2.0.3 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/README.md +29 -3
  2. package/build/assets/downloader.js +16 -17
  3. package/build/config.js +253 -5
  4. package/build/config.test.js +449 -1
  5. package/build/emitter_bus.js +3 -0
  6. package/build/emitter_bus.test.js +7 -0
  7. package/build/index.capabilities.test.js +45 -0
  8. package/build/index.js +496 -106
  9. package/build/install-desktop-plugin.js +56 -0
  10. package/build/install-desktop-plugin.test.js +66 -0
  11. package/build/multi-transport.test.js +277 -0
  12. package/build/plugin/mcp-plugin.js +2180 -1105
  13. package/build/prefetch-assets.js +6 -5
  14. package/build/real-environment/document-targeting.test.js +124 -0
  15. package/build/real-environment/export-diagram.test.js +473 -0
  16. package/build/real-environment/harness.js +120 -32
  17. package/build/real-environment/import-mermaid.test.js +81 -0
  18. package/build/real-environment/pages-and-concurrency.test.js +448 -0
  19. package/build/real-environment/shapes.test.js +58 -0
  20. package/build/real-environment/tools.js +51 -6
  21. package/build/register-tool.js +31 -0
  22. package/build/request_queue.js +29 -0
  23. package/build/request_queue.test.js +98 -0
  24. package/build/stdio-transport-purity.test.js +88 -0
  25. package/build/strip-schema.js +61 -0
  26. package/build/tls/expiry.js +14 -0
  27. package/build/tls/expiry.test.js +54 -0
  28. package/build/tls/generate.js +123 -0
  29. package/build/tls/generate.test.js +115 -0
  30. package/build/tls/index.js +80 -0
  31. package/build/tls/index.test.js +141 -0
  32. package/build/tls/install-hint.js +45 -0
  33. package/build/tls/install-hint.test.js +32 -0
  34. package/build/tls/load.js +18 -0
  35. package/build/tls/load.test.js +40 -0
  36. package/build/tls/paths.js +30 -0
  37. package/build/tls/paths.test.js +53 -0
  38. package/build/tls/san.js +27 -0
  39. package/build/tls/san.test.js +72 -0
  40. package/build/tool-registry.test.js +823 -0
  41. package/build/tool.js +74 -15
  42. package/build/tool.test.js +250 -7
  43. package/build/tools/add-cell-of-shape.js +4 -2
  44. package/build/tools/add-edge.js +3 -1
  45. package/build/tools/add-rectangle.js +4 -2
  46. package/build/tools/copy-page.js +13 -0
  47. package/build/tools/create-layer.js +4 -2
  48. package/build/tools/create-page.js +8 -0
  49. package/build/tools/delete-cell-by-id.js +4 -2
  50. package/build/tools/edit-cell.js +3 -1
  51. package/build/tools/edit-edge.js +3 -1
  52. package/build/tools/export-diagram.js +7 -3
  53. package/build/tools/get-active-layer.js +4 -1
  54. package/build/tools/get-current-page.js +5 -0
  55. package/build/tools/get-selected-cell.js +4 -1
  56. package/build/tools/import-diagram.js +12 -2
  57. package/build/tools/import-mermaid.js +31 -0
  58. package/build/tools/index.js +14 -0
  59. package/build/tools/list-documents.js +17 -0
  60. package/build/tools/list-layers.js +4 -1
  61. package/build/tools/list-paged-model.js +4 -3
  62. package/build/tools/list-pages.js +5 -0
  63. package/build/tools/move-cell-to-layer.js +3 -1
  64. package/build/tools/rename-page.js +10 -0
  65. package/build/tools/set-active-layer.js +4 -2
  66. package/build/tools/set-cell-data.js +3 -1
  67. package/build/tools/set-cell-parent.js +3 -1
  68. package/build/tools/set-cell-shape.js +3 -1
  69. package/build/tools/shared.js +35 -0
  70. package/build/tools/shared.test.js +29 -0
  71. package/package.json +22 -14
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  var DrawMcp = (() => {
3
3
  // src/shape-library.ts
4
- var shapeLibrary = {
4
+ var generalShapes = {
5
5
  rectangle: {
6
6
  category: "general",
7
7
  style: "rounded=0;whiteSpace=wrap;html=1;"
@@ -164,923 +164,776 @@ var DrawMcp = (() => {
164
164
  directionalConnector: {
165
165
  category: "general",
166
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
167
  }
338
168
  };
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
- };
169
+ var runtimeCatalog = /* @__PURE__ */ new Map();
170
+ function setRuntimeCatalog(map) {
171
+ runtimeCatalog = map;
496
172
  }
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;
173
+ function getShape(name) {
174
+ if (Object.prototype.hasOwnProperty.call(generalShapes, name)) {
175
+ return generalShapes[name];
508
176
  }
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;
177
+ const r = runtimeCatalog.get(name);
178
+ if (!r) return void 0;
179
+ return { category: r.category, style: r.style, title: r.name || void 0 };
180
+ }
181
+ function getCategories() {
182
+ const set = /* @__PURE__ */ new Set();
183
+ for (const s of Object.values(generalShapes)) set.add(s.category);
184
+ for (const r of runtimeCatalog.values()) set.add(r.category);
185
+ return [...set];
186
+ }
187
+ function getShapesByCategory(category) {
188
+ const out = [];
189
+ for (const [name, s] of Object.entries(generalShapes)) {
190
+ if (s.category === category) {
191
+ out.push({ id: name, title: s.title || name });
519
192
  }
520
- } catch (error) {
521
- console.warn("[pluginConfig] Failed to fetch config from server:", error);
522
193
  }
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
- }
194
+ for (const [name, r] of runtimeCatalog) {
195
+ if (r.category === category) {
196
+ out.push({ id: name, title: r.name || name });
534
197
  }
535
- } catch (error) {
536
- console.warn("[pluginConfig] Failed to read from localStorage:", error);
537
198
  }
538
- return { ...DEFAULT_PLUGIN_CONFIG };
199
+ return out;
539
200
  }
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;
201
+
202
+ // src/drawio-tools.ts
203
+ var active_document_id = null;
204
+ function normalize_optional_string(value) {
205
+ if (value === void 0 || value === null || value === "") {
206
+ return null;
547
207
  }
208
+ return String(value);
548
209
  }
549
- function validatePluginConfig(config) {
550
- if (!config || typeof config !== "object") {
551
- return { isValid: false, error: "Configuration must be an object" };
210
+ function set_active_document_id(document_id) {
211
+ active_document_id = document_id;
212
+ }
213
+ function assert_target_document_active(target_document) {
214
+ const targetDocumentId = typeof target_document?.id === "string" && target_document.id.length > 0 ? target_document.id : null;
215
+ if (!targetDocumentId) {
216
+ throw new Error("`target_document.id` is required");
552
217
  }
553
- const cfg = config;
554
- if (typeof cfg.websocketPort !== "number") {
555
- return { isValid: false, error: "websocketPort must be a number" };
218
+ if (!active_document_id) {
219
+ throw new Error("No active Draw.io document is registered in this tab");
556
220
  }
557
- if (cfg.websocketPort < 1024 || cfg.websocketPort > 65535) {
558
- return {
559
- isValid: false,
560
- error: "websocketPort must be between 1024 and 65535"
221
+ if (targetDocumentId !== active_document_id) {
222
+ throw new Error(
223
+ `Target document ${targetDocumentId} is no longer active in this Draw.io tab; call list-documents and retry`
224
+ );
225
+ }
226
+ }
227
+ function import_mermaid(ui2, options) {
228
+ const opts = options;
229
+ const mermaidSource = opts.mermaid_source;
230
+ const mode = opts.mode ?? "native";
231
+ const insertMode = opts.insert_mode ?? "add";
232
+ if (!mermaidSource || typeof mermaidSource !== "string") {
233
+ return Promise.resolve({
234
+ success: false,
235
+ message: "mermaid_source must be a non-empty string"
236
+ });
237
+ }
238
+ if (typeof ui2?.parseMermaidDiagram !== "function") {
239
+ return Promise.resolve({
240
+ success: false,
241
+ message: "ui.parseMermaidDiagram is not available; this Draw.io build does not expose Mermaid support."
242
+ });
243
+ }
244
+ const enableParser = mode === "native";
245
+ return new Promise((resolve) => {
246
+ let settled = false;
247
+ const settle = (result) => {
248
+ if (settled) {
249
+ return;
250
+ }
251
+ settled = true;
252
+ resolve(result);
561
253
  };
254
+ try {
255
+ ui2.parseMermaidDiagram(
256
+ mermaidSource,
257
+ void 0,
258
+ (xml) => {
259
+ if (!xml || typeof xml !== "string") {
260
+ settle({
261
+ success: false,
262
+ message: "Mermaid parser returned empty XML"
263
+ });
264
+ return;
265
+ }
266
+ try {
267
+ const importResult = import_diagram(ui2, {
268
+ data: xml,
269
+ format: "xml",
270
+ mode: insertMode
271
+ });
272
+ if (!importResult.success) {
273
+ settle({
274
+ success: false,
275
+ message: `Mermaid converted, but inserting into the diagram failed: ${importResult.message}`
276
+ });
277
+ return;
278
+ }
279
+ settle({
280
+ success: true,
281
+ mode,
282
+ message: importResult.message,
283
+ cells: importResult.cells,
284
+ xml
285
+ });
286
+ } catch (err) {
287
+ settle({
288
+ success: false,
289
+ message: `Insert after Mermaid conversion failed: ${err instanceof Error ? err.message : String(err)}`
290
+ });
291
+ }
292
+ },
293
+ (err) => {
294
+ settle({
295
+ success: false,
296
+ message: `Mermaid render failed: ${err?.message ?? String(err)}`
297
+ });
298
+ },
299
+ (err) => {
300
+ settle({
301
+ success: false,
302
+ message: `Mermaid parse error: ${err?.message ?? String(err)}`
303
+ });
304
+ },
305
+ enableParser
306
+ );
307
+ } catch (err) {
308
+ settle({
309
+ success: false,
310
+ message: `parseMermaidDiagram threw: ${err instanceof Error ? err.message : String(err)}`
311
+ });
312
+ }
313
+ });
314
+ }
315
+ function transform_NamedNodeMap_to_record(attributes) {
316
+ const tstr = Object.prototype.toString.call(attributes);
317
+ if (tstr !== "[object NamedNodeMap]") {
318
+ return attributes;
562
319
  }
563
- return {
564
- isValid: true,
565
- config: {
566
- websocketPort: cfg.websocketPort,
567
- serverUrl: cfg.serverUrl || ""
320
+ if (attributes.length === void 0) {
321
+ return attributes;
322
+ }
323
+ let transformed_attributes = {};
324
+ for (let i = 0; i < attributes.length; i++) {
325
+ const attr = attributes[i];
326
+ if (attr && attr.name && attr.value !== void 0) {
327
+ transformed_attributes[attr.name] = attr.value;
568
328
  }
569
- };
329
+ }
330
+ return transformed_attributes;
570
331
  }
571
- function buildWebSocketUrl(config) {
572
- const host = window.location.hostname;
573
- return `ws://${host}:${config.websocketPort}`;
332
+ function transform_cells_NamedNodeMap_to_attributes(cell) {
333
+ if (cell.value.attributes && typeof cell.value.attributes === "object") {
334
+ const attributes = cell.value.attributes;
335
+ return transform_NamedNodeMap_to_record(attributes);
336
+ }
337
+ return {};
574
338
  }
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();
339
+ function remove_circular_dependencies(obj, visited = /* @__PURE__ */ new WeakSet(), path = []) {
340
+ if (obj === null || typeof obj !== "object") {
341
+ return obj;
342
+ }
343
+ if (Array.isArray(obj)) {
344
+ if (visited.has(obj)) {
345
+ return `[Circular ${path.join(".")}]`;
596
346
  }
597
- });
598
- return container;
347
+ visited.add(obj);
348
+ return obj.map(
349
+ (item, index) => remove_circular_dependencies(item, visited, [...path, `[${index}]`])
350
+ );
351
+ }
352
+ const tstr = Object.prototype.toString.call(obj);
353
+ if (tstr === "[object NamedNodeMap]") {
354
+ return transform_NamedNodeMap_to_record(obj);
355
+ }
356
+ if (tstr !== "[object Object]" && tstr !== "[object Element]") {
357
+ return obj;
358
+ }
359
+ if (visited.has(obj)) {
360
+ return `[Circular ${path.join(".")}]`;
361
+ }
362
+ visited.add(obj);
363
+ const result = {};
364
+ for (const key in obj) {
365
+ const value = obj[key];
366
+ 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") {
367
+ let stripped_value = {};
368
+ if ((key === "parent" || key === "source" || key === "target") && value !== void 0 && value !== null) {
369
+ stripped_value = {
370
+ id: value.id
371
+ };
372
+ } else {
373
+ stripped_value = value;
374
+ }
375
+ result[key] = remove_circular_dependencies(stripped_value, visited, [
376
+ ...path,
377
+ key
378
+ ]);
379
+ }
380
+ }
381
+ return result;
599
382
  }
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;
383
+ function ensure_pages_api(ui2, selector_name) {
384
+ if (!Array.isArray(ui2?.pages) || ui2.pages.length === 0) {
385
+ throw new Error(
386
+ `Draw.io pages are unavailable; cannot resolve \`${selector_name}\``
387
+ );
388
+ }
614
389
  }
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;
390
+ function get_page_id(page) {
391
+ if (typeof page?.getId === "function") {
392
+ return String(page.getId());
393
+ }
394
+ const id = page?.id ?? page?.node?.getAttribute?.("id");
395
+ if (id === void 0 || id === null || id === "") {
396
+ throw new Error("Target page does not expose a stable ID");
397
+ }
398
+ return String(id);
660
399
  }
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;
400
+ function get_page_name(page, index) {
401
+ if (typeof page?.getName === "function") {
402
+ const name = page.getName();
403
+ if (name !== void 0 && name !== null && name !== "") {
404
+ return String(name);
405
+ }
406
+ }
407
+ const fallback = page?.name ?? page?.node?.getAttribute?.("name");
408
+ if (fallback !== void 0 && fallback !== null && fallback !== "") {
409
+ return String(fallback);
410
+ }
411
+ return `Page-${index + 1}`;
672
412
  }
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;
413
+ function get_page_rename_probe(ui2, explicit_page) {
414
+ if (explicit_page) {
415
+ return explicit_page;
715
416
  }
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;
417
+ if (ui2?.currentPage) {
418
+ return ui2.currentPage;
419
+ }
420
+ if (Array.isArray(ui2?.pages) && ui2.pages.length > 0) {
421
+ return ui2.pages[0];
422
+ }
423
+ return null;
731
424
  }
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
- })
425
+ function assert_page_rename_supported(ui2, action, explicit_page) {
426
+ const page = get_page_rename_probe(ui2, explicit_page);
427
+ if (typeof page?.setName !== "function") {
428
+ throw new Error(
429
+ `Draw.io page renaming is not supported in this version; cannot ${action}`
772
430
  );
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
431
  }
791
- portGroup.appendChild(label);
792
- portGroup.appendChild(input);
793
- portGroup.appendChild(hint);
794
- section.appendChild(portGroup);
795
- return section;
432
+ return page;
796
433
  }
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;
434
+ function rollback_created_page(ui2, page) {
435
+ if (!page || typeof ui2?.removePage !== "function") {
436
+ return;
437
+ }
438
+ try {
439
+ ui2.removePage(page);
440
+ } catch (error) {
441
+ console.warn("Could not roll back created page:", error);
442
+ }
843
443
  }
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;
444
+ function get_drawio_runtime_ctor(name) {
445
+ const maybeWindow = typeof window === "undefined" ? void 0 : window;
446
+ const globalCtor = globalThis?.[name] ?? maybeWindow?.[name];
447
+ return typeof globalCtor === "function" ? globalCtor : null;
448
+ }
449
+ function change_page_without_switch(ui2, page, index) {
450
+ const ChangePage = get_drawio_runtime_ctor("ChangePage");
451
+ const execute = ui2?.editor?.graph?.model?.execute;
452
+ if (typeof ChangePage !== "function" || typeof execute !== "function") {
453
+ return false;
898
454
  }
899
- if (disabled) {
900
- btn.style.cssText += `
901
- opacity: 0.6;
902
- cursor: not-allowed;
903
- `;
455
+ execute.call(ui2.editor.graph.model, new ChangePage(ui2, page, page, index, true));
456
+ return true;
457
+ }
458
+ function insert_page_without_switch(ui2, page, index) {
459
+ return change_page_without_switch(ui2, page, index);
460
+ }
461
+ function move_page_without_switch(ui2, oldIndex, newIndex) {
462
+ if (typeof ui2?.movePage === "function") {
463
+ ui2.movePage(oldIndex, newIndex);
464
+ return true;
904
465
  }
905
- btn.addEventListener("click", onClick);
906
- return btn;
466
+ const MovePage = get_drawio_runtime_ctor("MovePage");
467
+ const execute = ui2?.editor?.graph?.model?.execute;
468
+ if (typeof MovePage !== "function" || typeof execute !== "function") {
469
+ return false;
470
+ }
471
+ execute.call(ui2.editor.graph.model, new MovePage(ui2, oldIndex, newIndex));
472
+ return true;
907
473
  }
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();
474
+ function rename_page_without_switch(ui2, page, name) {
475
+ const RenamePage = get_drawio_runtime_ctor("RenamePage");
476
+ const execute = ui2?.editor?.graph?.model?.execute;
477
+ if (typeof RenamePage === "function" && typeof execute === "function") {
478
+ execute.call(ui2.editor.graph.model, new RenamePage(ui2, page, name));
479
+ return true;
480
+ }
481
+ if (typeof page?.setName !== "function") {
482
+ return false;
483
+ }
484
+ page.setName(name);
485
+ return true;
486
+ }
487
+ function find_page_index_by_id(ui2, pageId) {
488
+ if (!Array.isArray(ui2?.pages)) {
489
+ return -1;
490
+ }
491
+ return ui2.pages.findIndex((page) => {
492
+ try {
493
+ return get_page_id(page) === pageId;
494
+ } catch {
495
+ return false;
916
496
  }
497
+ });
498
+ }
499
+ function move_page_to_end(ui2, page) {
500
+ const pageId = get_page_id(page);
501
+ const currentIndex = find_page_index_by_id(ui2, pageId);
502
+ if (currentIndex === -1) {
503
+ throw new Error("Copied page is not present in the page list");
504
+ }
505
+ const lastIndex = ui2.pages.length - 1;
506
+ if (currentIndex === lastIndex) {
507
+ return currentIndex;
508
+ }
509
+ if (!move_page_without_switch(ui2, currentIndex, lastIndex)) {
510
+ throw new Error(
511
+ "Draw.io page reordering is not supported in this version; cannot move the copied page to the end"
512
+ );
513
+ }
514
+ const movedIndex = find_page_index_by_id(ui2, pageId);
515
+ if (movedIndex !== lastIndex) {
516
+ throw new Error("Failed to move the copied page to the end");
517
+ }
518
+ return movedIndex;
519
+ }
520
+ function can_insert_page_without_switch(ui2) {
521
+ const graph = ui2?.editor?.graph;
522
+ if (!graph || typeof graph.isEnabled !== "function" || graph.isEnabled() !== true) {
523
+ return false;
524
+ }
525
+ if (typeof graph.isEditing === "function" && graph.isEditing() === true) {
526
+ graph.stopEditing?.(false);
527
+ }
528
+ return true;
529
+ }
530
+ function serialize_page_info(ui2, page, index, isCurrent = (() => {
531
+ if (ui2?.currentPage === void 0 || ui2?.currentPage === null) {
532
+ return false;
533
+ }
534
+ try {
535
+ return get_page_id(page) === get_page_id(ui2.currentPage);
536
+ } catch {
537
+ return false;
538
+ }
539
+ })()) {
540
+ return {
541
+ index,
542
+ id: get_page_id(page),
543
+ name: get_page_name(page, index),
544
+ is_current: isCurrent
917
545
  };
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;
546
+ }
547
+ function serialize_document_info(ui2, document_id) {
548
+ const file = ui2?.getCurrentFile?.();
549
+ const pages = Array.isArray(ui2?.pages) ? ui2.pages : [];
550
+ const currentId = ui2?.currentPage !== void 0 && ui2?.currentPage !== null ? get_page_id(ui2.currentPage) : null;
551
+ const currentIndex = pages.findIndex(
552
+ (page) => currentId !== null && get_page_id(page) === currentId
553
+ );
554
+ return {
555
+ id: document_id,
556
+ title: normalize_optional_string(file?.getTitle?.()),
557
+ mode: normalize_optional_string(file?.getMode?.()),
558
+ hash: normalize_optional_string(file?.getHash?.()),
559
+ file_url: normalize_optional_string(file?.getFileUrl?.()),
560
+ page_count: pages.length,
561
+ current_page: currentIndex >= 0 && ui2?.currentPage ? serialize_page_info(ui2, ui2.currentPage, currentIndex, true) : null
935
562
  };
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
563
+ }
564
+ function resolve_target_page(ui2, target_page, selector_name = "target_page") {
565
+ ensure_pages_api(ui2, selector_name);
566
+ if (!target_page || typeof target_page !== "object") {
567
+ throw new Error(`\`${selector_name}\` is required`);
568
+ }
569
+ const hasIndex = Number.isInteger(target_page.index);
570
+ const hasId = typeof target_page.id === "string" && target_page.id.length > 0;
571
+ if (hasIndex === hasId) {
572
+ throw new Error(
573
+ `\`${selector_name}\` must include exactly one of \`index\` or \`id\``
957
574
  );
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;
575
+ }
576
+ if (hasIndex) {
577
+ const index2 = Number(target_page.index);
578
+ if (index2 < 0 || index2 >= ui2.pages.length) {
579
+ throw new Error(
580
+ `\`${selector_name}.index\` ${index2} is out of range for ${ui2.pages.length} pages`
581
+ );
980
582
  }
981
- if (portNum < 1024 || portNum > 65535) {
982
- currentState.errors.port = "Port must be between 1024 and 65535";
583
+ return {
584
+ page: ui2.pages[index2],
585
+ index: index2
586
+ };
587
+ }
588
+ const index = ui2.pages.findIndex((page) => {
589
+ try {
590
+ return get_page_id(page) === target_page.id;
591
+ } catch {
983
592
  return false;
984
593
  }
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;
594
+ });
595
+ if (index === -1) {
596
+ throw new Error(`Page with ID ${target_page.id} was not found`);
597
+ }
598
+ return {
599
+ page: ui2.pages[index],
600
+ index
993
601
  };
994
- const dialogProxy = {
995
- get element() {
996
- if (!dialogElement) {
997
- render();
998
- }
999
- return dialogElement;
1000
- },
1001
- update
602
+ }
603
+ function switch_to_target_page(ui2, page) {
604
+ const currentId = ui2?.currentPage !== void 0 && ui2?.currentPage !== null ? get_page_id(ui2.currentPage) : null;
605
+ const targetId = get_page_id(page);
606
+ if (currentId !== null && currentId === targetId) {
607
+ return;
608
+ }
609
+ if (typeof ui2?.selectPage !== "function") {
610
+ throw new Error("Draw.io page switching is not supported in this version");
611
+ }
612
+ ui2.selectPage(page);
613
+ }
614
+ function create_noop_execution(ui2, page, index) {
615
+ return {
616
+ ui: ui2,
617
+ page,
618
+ index,
619
+ is_background: false,
620
+ did_change: () => false,
621
+ cleanup: () => {
622
+ }
1002
623
  };
1003
- return dialogProxy;
1004
624
  }
1005
- function showSettingsDialog(dialog) {
1006
- if (!dialog.element.parentNode) {
1007
- document.body.appendChild(dialog.element);
625
+ function sync_live_current_page_state(ui2) {
626
+ if (!ui2?.currentPage || !ui2?.editor?.graph) {
627
+ return;
628
+ }
629
+ const liveGraph = ui2.editor.graph;
630
+ const model = typeof liveGraph?.getModel === "function" ? liveGraph.getModel() : null;
631
+ if (!model?.root) {
632
+ return;
633
+ }
634
+ ui2.currentPage.root = model.root;
635
+ ui2.currentPage.graphModelNode = null;
636
+ if (typeof liveGraph?.getViewState === "function") {
637
+ ui2.currentPage.viewState = liveGraph.getViewState();
1008
638
  }
639
+ ui2.currentPage.needsUpdate = true;
1009
640
  }
1010
- function hideSettingsDialog(dialog) {
1011
- if (dialog.element.parentNode) {
1012
- dialog.element.parentNode.removeChild(dialog.element);
641
+ function create_background_page_ui(ui2, page) {
642
+ const runtimeWindow = globalThis.window;
643
+ const runtimeDocument = globalThis.document;
644
+ const liveGraph = ui2?.editor?.graph;
645
+ if (!liveGraph || typeof liveGraph?.getStylesheet !== "function" || typeof ui2?.createTemporaryGraph !== "function" || typeof ui2?.updatePageRoot !== "function") {
646
+ return null;
647
+ }
648
+ const resolvedPage = ui2.updatePageRoot(page);
649
+ const tempGraph = ui2.createTemporaryGraph(liveGraph.getStylesheet());
650
+ if (!tempGraph || typeof tempGraph?.getModel !== "function") {
651
+ return null;
652
+ }
653
+ const tempModel = tempGraph.getModel();
654
+ if (!tempModel || typeof tempModel?.setRoot !== "function") {
655
+ return null;
656
+ }
657
+ let didChange = false;
658
+ const mxEvent = runtimeWindow?.mxEvent;
659
+ const changeEventName = mxEvent?.CHANGE ?? "change";
660
+ const changeListener = () => {
661
+ didChange = true;
662
+ };
663
+ if (typeof tempModel?.addListener === "function") {
664
+ tempModel.addListener(changeEventName, changeListener);
665
+ }
666
+ let containerAttached = false;
667
+ const cleanup = () => {
668
+ if (typeof tempModel?.removeListener === "function") {
669
+ tempModel.removeListener(changeListener);
670
+ }
671
+ if (typeof tempGraph?.destroy === "function") {
672
+ try {
673
+ tempGraph.destroy();
674
+ } catch (error) {
675
+ console.warn("Could not destroy temporary draw.io graph:", error);
676
+ }
677
+ }
678
+ if (containerAttached && tempGraph.container?.parentNode) {
679
+ try {
680
+ tempGraph.container.parentNode.removeChild(tempGraph.container);
681
+ } catch (error) {
682
+ console.warn("Could not detach temporary draw.io graph container:", error);
683
+ }
684
+ }
685
+ };
686
+ try {
687
+ if (runtimeDocument?.body && tempGraph.container && tempGraph.container.parentNode == null) {
688
+ runtimeDocument.body.appendChild(tempGraph.container);
689
+ containerAttached = true;
690
+ }
691
+ tempModel.setRoot(resolvedPage.root);
692
+ if (typeof tempGraph?.setViewState === "function" && resolvedPage.viewState) {
693
+ tempGraph.setViewState(resolvedPage.viewState);
694
+ } else if (resolvedPage.viewState?.defaultParent && typeof tempGraph?.setDefaultParent === "function") {
695
+ tempGraph.setDefaultParent(resolvedPage.viewState.defaultParent);
696
+ }
697
+ if (typeof tempGraph?.setAdaptiveColors === "function") {
698
+ tempGraph.setAdaptiveColors(resolvedPage.viewState?.adaptiveColors ?? null);
699
+ }
700
+ if (typeof tempGraph?.setBackgroundImage === "function") {
701
+ tempGraph.setBackgroundImage(resolvedPage.viewState?.backgroundImage ?? null);
702
+ }
703
+ if (resolvedPage.viewState?.background !== void 0) {
704
+ tempGraph.background = resolvedPage.viewState.background;
705
+ }
706
+ } catch (error) {
707
+ cleanup();
708
+ throw error;
1013
709
  }
710
+ const scopedUi = Object.create(ui2);
711
+ scopedUi.editor = Object.create(ui2.editor);
712
+ scopedUi.editor.graph = tempGraph;
713
+ scopedUi.currentPage = resolvedPage;
714
+ return {
715
+ ui: scopedUi,
716
+ page: resolvedPage,
717
+ index: -1,
718
+ is_background: true,
719
+ did_change: () => didChange,
720
+ cleanup
721
+ };
1014
722
  }
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;
723
+ function create_page_export_graph(ui2, sourceGraph, page) {
724
+ const runtimeDocument = globalThis.document;
725
+ if (!page || typeof ui2?.createTemporaryGraph !== "function" || typeof ui2?.updatePageRoot !== "function" || typeof sourceGraph?.getStylesheet !== "function") {
726
+ return null;
1021
727
  }
1022
- if (attributes.length === void 0) {
1023
- return attributes;
728
+ const resolvedPage = ui2.updatePageRoot(page);
729
+ const tempGraph = ui2.createTemporaryGraph(sourceGraph.getStylesheet());
730
+ const tempModel = tempGraph?.getModel?.();
731
+ if (!tempGraph || !tempModel || typeof tempModel?.setRoot !== "function") {
732
+ return null;
1024
733
  }
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;
734
+ const pageIndex = Array.isArray(ui2?.pages) ? ui2.pages.findIndex((candidate) => {
735
+ try {
736
+ return get_page_id(candidate) === get_page_id(resolvedPage);
737
+ } catch {
738
+ return false;
1030
739
  }
740
+ }) : -1;
741
+ const fallbackGetGlobalVariable = typeof sourceGraph?.getGlobalVariable === "function" ? sourceGraph.getGlobalVariable : null;
742
+ if (fallbackGetGlobalVariable) {
743
+ tempGraph.getGlobalVariable = function(name) {
744
+ if (name === "pagenumber" && pageIndex >= 0) {
745
+ return pageIndex + 1;
746
+ }
747
+ if (name === "page") {
748
+ return get_page_name(resolvedPage, Math.max(pageIndex, 0));
749
+ }
750
+ return fallbackGetGlobalVariable.apply(this, arguments);
751
+ };
1031
752
  }
1032
- return transformed_attributes;
753
+ if (typeof tempGraph?.setAdaptiveColors === "function") {
754
+ tempGraph.setAdaptiveColors(resolvedPage.viewState?.adaptiveColors ?? null);
755
+ }
756
+ if (typeof tempGraph?.setBackgroundImage === "function") {
757
+ tempGraph.setBackgroundImage(resolvedPage.viewState?.backgroundImage ?? null);
758
+ }
759
+ if (resolvedPage.viewState?.background !== void 0) {
760
+ tempGraph.background = resolvedPage.viewState.background;
761
+ }
762
+ let containerAttached = false;
763
+ try {
764
+ if (runtimeDocument?.body && tempGraph.container && tempGraph.container.parentNode == null) {
765
+ runtimeDocument.body.appendChild(tempGraph.container);
766
+ containerAttached = true;
767
+ }
768
+ } catch (error) {
769
+ console.warn(
770
+ "Could not attach temporary draw.io export graph container:",
771
+ error
772
+ );
773
+ }
774
+ tempModel.setRoot(resolvedPage.root);
775
+ return {
776
+ graph: tempGraph,
777
+ cleanup: () => {
778
+ if (typeof tempGraph?.destroy === "function") {
779
+ try {
780
+ tempGraph.destroy();
781
+ } catch (error) {
782
+ console.warn("Could not destroy temporary draw.io export graph:", error);
783
+ }
784
+ }
785
+ if (containerAttached && tempGraph.container?.parentNode) {
786
+ try {
787
+ tempGraph.container.parentNode.removeChild(tempGraph.container);
788
+ } catch (error) {
789
+ console.warn(
790
+ "Could not detach temporary draw.io export graph container:",
791
+ error
792
+ );
793
+ }
794
+ }
795
+ }
796
+ };
1033
797
  }
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);
798
+ function prepare_target_page_execution(ui2, target_page, options = {}) {
799
+ const resolved = resolve_target_page(ui2, target_page);
800
+ const currentId = ui2?.currentPage !== void 0 && ui2?.currentPage !== null ? get_page_id(ui2.currentPage) : null;
801
+ const targetId = get_page_id(resolved.page);
802
+ if (options.prefer_background && currentId !== null && currentId !== targetId) {
803
+ const backgroundExecution = create_background_page_ui(ui2, resolved.page);
804
+ if (backgroundExecution) {
805
+ if (options.sync_live_current_page_state) {
806
+ sync_live_current_page_state(ui2);
807
+ }
808
+ return {
809
+ ...backgroundExecution,
810
+ index: resolved.index
811
+ };
812
+ }
1038
813
  }
1039
- return {};
814
+ if (currentId !== targetId) {
815
+ switch_to_target_page(ui2, resolved.page);
816
+ }
817
+ return create_noop_execution(ui2, resolved.page, resolved.index);
1040
818
  }
1041
- function remove_circular_dependencies(obj, visited = /* @__PURE__ */ new WeakSet(), path = []) {
1042
- if (obj === null || typeof obj !== "object") {
1043
- return obj;
819
+ function mark_page_execution_modified(ui2, execution) {
820
+ if (!execution.is_background || !execution.did_change()) {
821
+ return;
1044
822
  }
1045
- if (Array.isArray(obj)) {
1046
- if (visited.has(obj)) {
1047
- return `[Circular ${path.join(".")}]`;
823
+ const page = execution.page;
824
+ page.needsUpdate = true;
825
+ page.graphModelNode = null;
826
+ if (typeof page?.setDiagramModified === "function") {
827
+ page.setDiagramModified(true);
828
+ }
829
+ try {
830
+ ui2.getCurrentFile?.()?.fileChanged?.();
831
+ } catch (error) {
832
+ console.warn("Could not notify draw.io file change after background mutation:", error);
833
+ }
834
+ }
835
+ function get_selected_cell(ui2) {
836
+ return ui2.editor.graph.getSelectionCell() || "no cell selected";
837
+ }
838
+ function list_pages(ui2) {
839
+ ensure_pages_api(ui2, "pages");
840
+ return ui2.pages.map(
841
+ (page, index) => serialize_page_info(ui2, page, index)
842
+ );
843
+ }
844
+ function get_current_page(ui2) {
845
+ ensure_pages_api(ui2, "current page");
846
+ const currentId = ui2?.currentPage !== void 0 && ui2?.currentPage !== null ? get_page_id(ui2.currentPage) : null;
847
+ const currentIndex = ui2.pages.findIndex(
848
+ (page) => currentId !== null && get_page_id(page) === currentId
849
+ );
850
+ if (currentIndex === -1 || !ui2.currentPage) {
851
+ throw new Error("Current page is not available");
852
+ }
853
+ return serialize_page_info(ui2, ui2.currentPage, currentIndex, true);
854
+ }
855
+ function create_page(ui2, options) {
856
+ if (typeof ui2?.insertPage !== "function") {
857
+ throw new Error("Draw.io page creation is not supported in this version");
858
+ }
859
+ if (options.name) {
860
+ assert_page_rename_supported(ui2, "create a named page");
861
+ }
862
+ const pageIndex = Array.isArray(ui2.pages) ? ui2.pages.length : 0;
863
+ let newPage = null;
864
+ if (typeof ui2?.createPage === "function" && typeof ui2?.createPageId === "function" && can_insert_page_without_switch(ui2)) {
865
+ newPage = ui2.createPage(options.name ?? null, ui2.createPageId());
866
+ if (!insert_page_without_switch(ui2, newPage, pageIndex)) {
867
+ newPage = null;
1048
868
  }
1049
- visited.add(obj);
1050
- return obj.map(
1051
- (item, index) => remove_circular_dependencies(item, visited, [...path, `[${index}]`])
1052
- );
1053
869
  }
1054
- const tstr = Object.prototype.toString.call(obj);
1055
- if (tstr === "[object NamedNodeMap]") {
1056
- return transform_NamedNodeMap_to_record(obj);
870
+ if (!newPage) {
871
+ newPage = ui2.insertPage(null, pageIndex);
872
+ if (!newPage) {
873
+ throw new Error("Failed to create a new page");
874
+ }
875
+ if (options.name) {
876
+ try {
877
+ assert_page_rename_supported(ui2, "create a named page", newPage);
878
+ newPage.setName(options.name);
879
+ } catch (error) {
880
+ rollback_created_page(ui2, newPage);
881
+ throw error;
882
+ }
883
+ }
1057
884
  }
1058
- if (tstr !== "[object Object]" && tstr !== "[object Element]") {
1059
- return obj;
885
+ const newPageId = get_page_id(newPage);
886
+ const index = Array.isArray(ui2.pages) ? ui2.pages.findIndex((page) => get_page_id(page) === newPageId) : -1;
887
+ if (index === -1) {
888
+ throw new Error("Created page is not present in the page list");
1060
889
  }
1061
- if (visited.has(obj)) {
1062
- return `[Circular ${path.join(".")}]`;
890
+ return serialize_page_info(ui2, newPage, index);
891
+ }
892
+ function copy_page(ui2, options) {
893
+ const page_selector = typeof options.page === "number" ? { index: options.page } : options.page;
894
+ const resolved = resolve_target_page(ui2, page_selector, "page");
895
+ if (typeof ui2?.duplicatePage !== "function") {
896
+ throw new Error("Draw.io page copying is not supported in this version");
897
+ }
898
+ const currentId = ui2?.currentPage !== void 0 && ui2?.currentPage !== null ? get_page_id(ui2.currentPage) : null;
899
+ const requestedName = typeof options.name === "string" && options.name.length > 0 ? options.name : void 0;
900
+ const copiedPage = ui2.duplicatePage(resolved.page, requestedName);
901
+ if (!copiedPage) {
902
+ throw new Error("Failed to copy the target page");
903
+ }
904
+ if (requestedName && get_page_name(copiedPage, resolved.index) !== requestedName) {
905
+ assert_page_rename_supported(ui2, "rename the copied page", copiedPage);
906
+ if (!rename_page_without_switch(ui2, copiedPage, requestedName)) {
907
+ throw new Error("Failed to rename the copied page");
908
+ }
1063
909
  }
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;
910
+ const index = move_page_to_end(ui2, copiedPage);
911
+ if (currentId !== null) {
912
+ const currentPage = ui2.pages.find((page) => {
913
+ try {
914
+ return get_page_id(page) === currentId;
915
+ } catch {
916
+ return false;
1076
917
  }
1077
- result[key] = remove_circular_dependencies(stripped_value, visited, [
1078
- ...path,
1079
- key
1080
- ]);
918
+ });
919
+ const visiblePageId = ui2?.currentPage !== void 0 && ui2?.currentPage !== null ? get_page_id(ui2.currentPage) : null;
920
+ if (currentPage && visiblePageId !== null && visiblePageId !== currentId && typeof ui2?.selectPage === "function") {
921
+ ui2.selectPage(currentPage);
1081
922
  }
1082
923
  }
1083
- return result;
924
+ return serialize_page_info(ui2, copiedPage, index);
925
+ }
926
+ function rename_page(ui2, options) {
927
+ const page_selector = typeof options.page === "number" ? { index: options.page } : options.page;
928
+ const resolved = resolve_target_page(ui2, page_selector, "page");
929
+ if (!options.name) {
930
+ throw new Error("`name` is required");
931
+ }
932
+ assert_page_rename_supported(ui2, "rename a page", resolved.page);
933
+ if (!rename_page_without_switch(ui2, resolved.page, options.name)) {
934
+ throw new Error("Failed to rename the target page");
935
+ }
936
+ return serialize_page_info(ui2, resolved.page, resolved.index);
1084
937
  }
1085
938
  function transform_cell_for_display(cell) {
1086
939
  if (!cell || typeof cell !== "object") {
@@ -1384,7 +1237,7 @@ var DrawMcp = (() => {
1384
1237
  `Cell '${cell_id}' is an edge; set_cell_shape expects a vertex`
1385
1238
  );
1386
1239
  }
1387
- const style = shapeLibrary?.[shape_name]?.style;
1240
+ const style = getShape(shape_name)?.style;
1388
1241
  if (!style) {
1389
1242
  throw new Error(
1390
1243
  `set_cell_shape could not find a shape named '${shape_name}'`
@@ -1437,28 +1290,14 @@ var DrawMcp = (() => {
1437
1290
  }
1438
1291
  return cell;
1439
1292
  }
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];
1293
+ function get_shape_categories(_ui) {
1294
+ return getCategories();
1447
1295
  }
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
- });
1296
+ function get_shapes_in_category(_ui, options) {
1297
+ return getShapesByCategory(options.category_id);
1458
1298
  }
1459
- function get_shape_by_name(ui2, options) {
1460
- const shapes = shapeLibrary;
1461
- const shape = shapes[options.shape_name];
1299
+ function get_shape_by_name(_ui, options) {
1300
+ const shape = getShape(options.shape_name);
1462
1301
  if (!shape) return null;
1463
1302
  return {
1464
1303
  id: options.shape_name,
@@ -1825,24 +1664,58 @@ var DrawMcp = (() => {
1825
1664
  const bg = background !== "none" ? background : null;
1826
1665
  if (embedXml) {
1827
1666
  const currentPage = size === "page" || size === "selection";
1828
- const svgString2 = ui2.getFileData(
1829
- false,
1667
+ const xml = ui2.getFileData(
1830
1668
  true,
1831
1669
  null,
1832
1670
  null,
1671
+ null,
1833
1672
  ignoreSelection,
1834
1673
  currentPage
1835
1674
  );
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
- };
1675
+ const exportGraphSession = create_page_export_graph(ui2, graph, ui2.currentPage);
1676
+ const renderGraph = exportGraphSession?.graph ?? graph;
1677
+ try {
1678
+ const svgString2 = typeof ui2.getEmbeddedSvg === "function" ? ui2.getEmbeddedSvg(
1679
+ xml,
1680
+ renderGraph,
1681
+ null,
1682
+ false,
1683
+ null,
1684
+ ignoreSelection,
1685
+ null,
1686
+ void 0,
1687
+ bg,
1688
+ scale,
1689
+ border,
1690
+ includeShadow
1691
+ ) : (() => {
1692
+ const svgRoot2 = renderGraph.getSvg(
1693
+ bg,
1694
+ scale,
1695
+ border,
1696
+ !params.cropToDiagram,
1697
+ null,
1698
+ ignoreSelection
1699
+ );
1700
+ if (renderGraph.shadowVisible || includeShadow) {
1701
+ renderGraph.addSvgShadow(svgRoot2, null, null, border === 0);
1702
+ }
1703
+ svgRoot2.setAttribute("content", xml);
1704
+ return (Graph.xmlDeclaration || '<?xml version="1.0" encoding="UTF-8"?>') + "\n" + (Graph.svgFileComment || "") + "\n" + (Graph.svgDoctype || "") + "\n" + mxUtils.getXml(svgRoot2);
1705
+ })();
1706
+ const bounds = renderGraph.getGraphBounds();
1707
+ const w2 = Math.ceil(bounds.width * scale + bounds.x * scale + 2 * border);
1708
+ const h2 = Math.ceil(bounds.height * scale + bounds.y * scale + 2 * border);
1709
+ return {
1710
+ format: "svg",
1711
+ mimeType: "image/svg+xml",
1712
+ data: svgString2,
1713
+ width: w2,
1714
+ height: h2
1715
+ };
1716
+ } finally {
1717
+ exportGraphSession?.cleanup();
1718
+ }
1846
1719
  }
1847
1720
  const svgRoot = graph.getSvg(
1848
1721
  bg,
@@ -2227,10 +2100,40 @@ var DrawMcp = (() => {
2227
2100
  message: "New page creation not supported in this Draw.io version"
2228
2101
  };
2229
2102
  }
2103
+ const importedPageName = filename ? filename.replace(/\.[^/.]+$/, "") : null;
2104
+ if (importedPageName) {
2105
+ try {
2106
+ assert_page_rename_supported(
2107
+ ui2,
2108
+ "create a named imported page"
2109
+ );
2110
+ } catch (error) {
2111
+ return {
2112
+ success: false,
2113
+ message: error instanceof Error ? error.message : "Page renaming is not supported"
2114
+ };
2115
+ }
2116
+ }
2230
2117
  const newPage = ui2.insertPage();
2231
2118
  if (!newPage) {
2232
2119
  return { success: false, message: "Failed to create new page" };
2233
2120
  }
2121
+ if (importedPageName) {
2122
+ try {
2123
+ assert_page_rename_supported(
2124
+ ui2,
2125
+ "create a named imported page",
2126
+ newPage
2127
+ );
2128
+ newPage.setName(importedPageName);
2129
+ } catch (error) {
2130
+ rollback_created_page(ui2, newPage);
2131
+ return {
2132
+ success: false,
2133
+ message: error instanceof Error ? error.message : "Page renaming is not supported"
2134
+ };
2135
+ }
2136
+ }
2234
2137
  ui2.selectPage(newPage);
2235
2138
  model.beginUpdate();
2236
2139
  try {
@@ -2257,225 +2160,1398 @@ var DrawMcp = (() => {
2257
2160
  } finally {
2258
2161
  model.endUpdate();
2259
2162
  }
2260
- if (filename && newPage.setName) {
2261
- const pageName = filename.replace(/\.[^/.]+$/, "");
2262
- newPage.setName(pageName);
2163
+ return {
2164
+ success: true,
2165
+ message: `Diagram imported successfully (new page created)${filename ? `: ${filename}` : ""}`,
2166
+ pages: ui2.pages.length,
2167
+ cells: cellCount
2168
+ };
2169
+ default:
2170
+ return { success: false, message: `Unsupported import mode: ${mode}` };
2171
+ }
2172
+ } catch (error) {
2173
+ console.error("[import-diagram] Error importing diagram:", error);
2174
+ return {
2175
+ success: false,
2176
+ message: `Import failed: ${error instanceof Error ? error.message : "Unknown error"}`
2177
+ };
2178
+ }
2179
+ }
2180
+
2181
+ // src/events.ts
2182
+ function reply_name(event_name, request_id) {
2183
+ return `${event_name}.${request_id}`;
2184
+ }
2185
+
2186
+ // src/shape-extractor.ts
2187
+ var ADDER_TO_PALETTE = {
2188
+ addAWS4Palette: "aws4",
2189
+ addGCP2Palette: "gcp2",
2190
+ addAzure2Palette: "azure2",
2191
+ addCisco19Palette: "cisco19",
2192
+ addCiscoSafePalette: "cisco_safe"
2193
+ };
2194
+ function extractShapesFromSidebar(ui2) {
2195
+ const Sidebar = window.Sidebar;
2196
+ if (!Sidebar?.prototype) {
2197
+ throw new Error("drawio Sidebar prototype not available on window");
2198
+ }
2199
+ if (!ui2?.sidebar) {
2200
+ throw new Error("ui.sidebar not constructed yet");
2201
+ }
2202
+ const recorded = [];
2203
+ let currentPalette = "unknown";
2204
+ let currentSection = "";
2205
+ const dummy = Object.assign(
2206
+ Object.create(Sidebar.prototype),
2207
+ ui2.sidebar,
2208
+ {
2209
+ taglist: {},
2210
+ palettes: {},
2211
+ entries: [],
2212
+ createVertexTemplateEntry(style, w, h, _value, title) {
2213
+ recorded.push({
2214
+ style,
2215
+ width: w,
2216
+ height: h,
2217
+ name: String(title ?? ""),
2218
+ paletteId: currentPalette,
2219
+ category: `mxgraph.${currentPalette}.${slug(currentSection || "default")}`
2220
+ });
2221
+ return () => null;
2222
+ },
2223
+ addPalette(_id, title, _expanded, onInit) {
2224
+ if (title) currentSection = title;
2225
+ try {
2226
+ onInit({ appendChild() {
2227
+ } });
2228
+ } catch {
2229
+ }
2230
+ },
2231
+ addPaletteFunctions(_id, title, _expanded, fns) {
2232
+ if (title) currentSection = title;
2233
+ const fake = { appendChild() {
2234
+ } };
2235
+ for (const fn of fns) {
2236
+ try {
2237
+ fn(fake);
2238
+ } catch {
2239
+ }
2240
+ }
2241
+ },
2242
+ setCurrentSearchEntryLibrary() {
2243
+ },
2244
+ createEdgeTemplateEntry: () => () => null,
2245
+ addEntry: (_tags, fn) => fn,
2246
+ createTitle: () => typeof document !== "undefined" ? document.createElement("div") : {}
2247
+ }
2248
+ );
2249
+ for (const [adder, paletteId] of Object.entries(ADDER_TO_PALETTE)) {
2250
+ if (typeof dummy[adder] !== "function") {
2251
+ console.warn(
2252
+ `[shape-extractor] Sidebar.prototype.${adder} missing \u2014 vendor '${paletteId}' skipped`
2253
+ );
2254
+ continue;
2255
+ }
2256
+ currentPalette = paletteId;
2257
+ currentSection = "";
2258
+ try {
2259
+ dummy[adder]();
2260
+ } catch (err) {
2261
+ console.warn(`[shape-extractor] ${adder} threw during extraction`, err);
2262
+ }
2263
+ }
2264
+ const out = /* @__PURE__ */ new Map();
2265
+ for (const s of recorded) {
2266
+ const key = deriveKey(s.style);
2267
+ if (key) out.set(key, s);
2268
+ }
2269
+ for (const v of Object.values(ADDER_TO_PALETTE)) {
2270
+ const n = [...out.keys()].filter(
2271
+ (k) => k.startsWith(`mxgraph.${v}.`)
2272
+ ).length;
2273
+ if (n === 0) {
2274
+ console.warn(`[shape-extractor] captured 0 shapes for vendor '${v}'`);
2275
+ }
2276
+ }
2277
+ return out;
2278
+ }
2279
+ function deriveKey(style) {
2280
+ if (!style) return null;
2281
+ const res = /resIcon=([^;]+)/.exec(style);
2282
+ if (res && res[1].startsWith("mxgraph.")) return res[1];
2283
+ const shapeMatch = /shape=mxgraph\.([a-z0-9_]+)\.([a-z0-9_]+)/i.exec(style);
2284
+ const prIconMatch = /prIcon=([a-z0-9_]+)/i.exec(style);
2285
+ if (shapeMatch && prIconMatch) {
2286
+ return `mxgraph.${shapeMatch[1].toLowerCase()}.${prIconMatch[1].toLowerCase()}`;
2287
+ }
2288
+ if (shapeMatch) {
2289
+ return `mxgraph.${shapeMatch[1].toLowerCase()}.${shapeMatch[2].toLowerCase()}`;
2290
+ }
2291
+ const imgMatch = /image=img\/lib\/([^/;]+)\/(?:(.+)\/)?([^/;]+?)\.(?:svg|png|jpe?g)/i.exec(
2292
+ style
2293
+ );
2294
+ if (imgMatch) {
2295
+ const vendor = slug(imgMatch[1]);
2296
+ const middle = imgMatch[2] ? slug(imgMatch[2]) : "";
2297
+ const file = slug(imgMatch[3]);
2298
+ if (!vendor || !file) return null;
2299
+ return middle ? `mxgraph.${vendor}.${middle}.${file}` : `mxgraph.${vendor}.${file}`;
2300
+ }
2301
+ return null;
2302
+ }
2303
+ function slug(s) {
2304
+ return s.toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_|_$/g, "") || "default";
2305
+ }
2306
+
2307
+ // src/tool-registry.ts
2308
+ var VISIBLE_PAGE_EXECUTION = {
2309
+ mode: "visible-page"
2310
+ };
2311
+ var VISIBLE_PAGE_MUTATION_EXECUTION = {
2312
+ mode: "visible-page",
2313
+ mutates: true
2314
+ };
2315
+ var BACKGROUND_PAGE_EXECUTION = {
2316
+ mode: "background-page"
2317
+ };
2318
+ var BACKGROUND_PAGE_MUTATION_EXECUTION = {
2319
+ mode: "background-page",
2320
+ mutates: true
2321
+ };
2322
+ function can_export_in_background(options) {
2323
+ const format = options.format ?? "xml";
2324
+ const hasEmbeddedPng = options.embed_xml === true && format === "png";
2325
+ return options.selection_only !== true && options.size !== "selection" && !hasEmbeddedPng;
2326
+ }
2327
+ var EXPORT_PAGE_EXECUTION = {
2328
+ mode: "hybrid-page",
2329
+ allow_background: can_export_in_background,
2330
+ sync_live_current_page_state: true
2331
+ };
2332
+ function skip_page_execution_for_new_page_import(options) {
2333
+ return options.mode === "new-page";
2334
+ }
2335
+ function skip_page_execution_for_new_page_mermaid(options) {
2336
+ return options.insert_mode === "new-page";
2337
+ }
2338
+ function with_target_page(handler, options) {
2339
+ return (ui2, rawOptions) => {
2340
+ const drawioOptions = rawOptions;
2341
+ if (!options?.skip?.(drawioOptions)) {
2342
+ const pageExecution = options?.pageExecution;
2343
+ const preferBackground = pageExecution?.mode === "background-page" || pageExecution?.mode === "hybrid-page" && pageExecution.allow_background?.(drawioOptions) === true;
2344
+ const execution = prepare_target_page_execution(
2345
+ ui2,
2346
+ drawioOptions.target_page,
2347
+ {
2348
+ prefer_background: preferBackground,
2349
+ sync_live_current_page_state: pageExecution?.sync_live_current_page_state === true
2350
+ }
2351
+ );
2352
+ try {
2353
+ const result = handler(execution.ui, drawioOptions);
2354
+ if (result && typeof result === "object" && typeof result.finally === "function") {
2355
+ return result.finally(() => {
2356
+ if (pageExecution?.mutates) {
2357
+ mark_page_execution_modified(ui2, execution);
2358
+ }
2359
+ execution.cleanup();
2360
+ });
2361
+ }
2362
+ if (pageExecution?.mutates) {
2363
+ mark_page_execution_modified(ui2, execution);
2364
+ }
2365
+ execution.cleanup();
2366
+ return result;
2367
+ } catch (error) {
2368
+ if (pageExecution?.mutates) {
2369
+ mark_page_execution_modified(ui2, execution);
2370
+ }
2371
+ execution.cleanup();
2372
+ throw error;
2373
+ }
2374
+ }
2375
+ return handler(ui2, drawioOptions);
2376
+ };
2377
+ }
2378
+ function page_tool({
2379
+ handler,
2380
+ pageExecution,
2381
+ skip,
2382
+ ...definition
2383
+ }) {
2384
+ const options = { pageExecution };
2385
+ if (skip) {
2386
+ options.skip = skip;
2387
+ }
2388
+ return {
2389
+ ...definition,
2390
+ handler: with_target_page(handler, options),
2391
+ pageExecution
2392
+ };
2393
+ }
2394
+ function with_target_document(handler) {
2395
+ return (ui2, rawOptions) => {
2396
+ const drawioOptions = rawOptions;
2397
+ assert_target_document_active(drawioOptions.target_document);
2398
+ return handler(ui2, rawOptions);
2399
+ };
2400
+ }
2401
+ var rawToolDefinitions = [
2402
+ page_tool({
2403
+ name: "get-selected-cell",
2404
+ params: /* @__PURE__ */ new Set(["target_page"]),
2405
+ handler: get_selected_cell,
2406
+ pageExecution: VISIBLE_PAGE_EXECUTION
2407
+ }),
2408
+ page_tool({
2409
+ name: "add-rectangle",
2410
+ params: /* @__PURE__ */ new Set([
2411
+ "x",
2412
+ "y",
2413
+ "width",
2414
+ "height",
2415
+ "text",
2416
+ "style",
2417
+ "parent_id",
2418
+ "target_page"
2419
+ ]),
2420
+ handler: add_new_rectangle,
2421
+ pageExecution: BACKGROUND_PAGE_MUTATION_EXECUTION
2422
+ }),
2423
+ page_tool({
2424
+ name: "add-edge",
2425
+ params: /* @__PURE__ */ new Set([
2426
+ "source_id",
2427
+ "target_id",
2428
+ "style",
2429
+ "text",
2430
+ "parent_id",
2431
+ "points",
2432
+ "target_page"
2433
+ ]),
2434
+ handler: add_edge,
2435
+ pageExecution: BACKGROUND_PAGE_MUTATION_EXECUTION
2436
+ }),
2437
+ page_tool({
2438
+ name: "delete-cell-by-id",
2439
+ params: /* @__PURE__ */ new Set(["cell_id", "target_page"]),
2440
+ handler: delete_cell_by_id,
2441
+ pageExecution: BACKGROUND_PAGE_MUTATION_EXECUTION
2442
+ }),
2443
+ {
2444
+ name: "get-shape-categories",
2445
+ params: /* @__PURE__ */ new Set([]),
2446
+ handler: get_shape_categories
2447
+ },
2448
+ {
2449
+ name: "get-shapes-in-category",
2450
+ params: /* @__PURE__ */ new Set(["category_id"]),
2451
+ handler: get_shapes_in_category
2452
+ },
2453
+ {
2454
+ name: "get-shape-by-name",
2455
+ params: /* @__PURE__ */ new Set(["shape_name"]),
2456
+ handler: get_shape_by_name
2457
+ },
2458
+ page_tool({
2459
+ name: "add-cell-of-shape",
2460
+ params: /* @__PURE__ */ new Set([
2461
+ "shape_name",
2462
+ "x",
2463
+ "y",
2464
+ "width",
2465
+ "height",
2466
+ "text",
2467
+ "style",
2468
+ "parent_id",
2469
+ "target_page"
2470
+ ]),
2471
+ handler: add_cell_of_shape,
2472
+ pageExecution: BACKGROUND_PAGE_MUTATION_EXECUTION
2473
+ }),
2474
+ page_tool({
2475
+ name: "set-cell-shape",
2476
+ params: /* @__PURE__ */ new Set(["cell_id", "shape_name", "target_page"]),
2477
+ handler: set_cell_shape,
2478
+ pageExecution: BACKGROUND_PAGE_MUTATION_EXECUTION
2479
+ }),
2480
+ page_tool({
2481
+ name: "set-cell-data",
2482
+ params: /* @__PURE__ */ new Set(["cell_id", "key", "value", "target_page"]),
2483
+ handler: set_cell_data,
2484
+ pageExecution: BACKGROUND_PAGE_MUTATION_EXECUTION
2485
+ }),
2486
+ page_tool({
2487
+ name: "list-paged-model",
2488
+ params: /* @__PURE__ */ new Set(["page", "page_size", "filter", "target_page"]),
2489
+ handler: list_paged_model,
2490
+ pageExecution: BACKGROUND_PAGE_EXECUTION
2491
+ }),
2492
+ page_tool({
2493
+ name: "edit-cell",
2494
+ params: /* @__PURE__ */ new Set([
2495
+ "cell_id",
2496
+ "text",
2497
+ "x",
2498
+ "y",
2499
+ "width",
2500
+ "height",
2501
+ "style",
2502
+ "target_page"
2503
+ ]),
2504
+ handler: edit_cell,
2505
+ pageExecution: BACKGROUND_PAGE_MUTATION_EXECUTION
2506
+ }),
2507
+ page_tool({
2508
+ name: "edit-edge",
2509
+ params: /* @__PURE__ */ new Set([
2510
+ "cell_id",
2511
+ "text",
2512
+ "source_id",
2513
+ "target_id",
2514
+ "style",
2515
+ "points",
2516
+ "target_page"
2517
+ ]),
2518
+ handler: edit_edge,
2519
+ pageExecution: BACKGROUND_PAGE_MUTATION_EXECUTION
2520
+ }),
2521
+ page_tool({
2522
+ name: "list-layers",
2523
+ params: /* @__PURE__ */ new Set(["target_page"]),
2524
+ handler: list_layers,
2525
+ pageExecution: BACKGROUND_PAGE_EXECUTION
2526
+ }),
2527
+ page_tool({
2528
+ name: "set-active-layer",
2529
+ params: /* @__PURE__ */ new Set(["layer_id", "target_page"]),
2530
+ handler: set_active_layer,
2531
+ pageExecution: VISIBLE_PAGE_MUTATION_EXECUTION
2532
+ }),
2533
+ page_tool({
2534
+ name: "move-cell-to-layer",
2535
+ params: /* @__PURE__ */ new Set(["cell_id", "target_layer_id", "target_page"]),
2536
+ handler: move_cell_to_layer,
2537
+ pageExecution: BACKGROUND_PAGE_MUTATION_EXECUTION
2538
+ }),
2539
+ page_tool({
2540
+ name: "set-cell-parent",
2541
+ params: /* @__PURE__ */ new Set(["cell_id", "parent_id", "target_page"]),
2542
+ handler: set_cell_parent,
2543
+ pageExecution: BACKGROUND_PAGE_MUTATION_EXECUTION
2544
+ }),
2545
+ page_tool({
2546
+ name: "get-active-layer",
2547
+ params: /* @__PURE__ */ new Set(["target_page"]),
2548
+ handler: get_active_layer,
2549
+ pageExecution: VISIBLE_PAGE_EXECUTION
2550
+ }),
2551
+ page_tool({
2552
+ name: "create-layer",
2553
+ params: /* @__PURE__ */ new Set(["name", "target_page"]),
2554
+ handler: create_layer,
2555
+ pageExecution: BACKGROUND_PAGE_MUTATION_EXECUTION
2556
+ }),
2557
+ page_tool({
2558
+ name: "export-diagram",
2559
+ params: /* @__PURE__ */ new Set([
2560
+ "format",
2561
+ "scale",
2562
+ "border",
2563
+ "background",
2564
+ "shadow",
2565
+ "crop",
2566
+ "selection_only",
2567
+ "transparent",
2568
+ "dpi",
2569
+ "embed_xml",
2570
+ "size",
2571
+ "target_page"
2572
+ ]),
2573
+ handler: export_diagram,
2574
+ pageExecution: EXPORT_PAGE_EXECUTION
2575
+ }),
2576
+ page_tool({
2577
+ name: "import-diagram",
2578
+ params: /* @__PURE__ */ new Set(["data", "format", "mode", "filename", "target_page"]),
2579
+ handler: import_diagram,
2580
+ pageExecution: VISIBLE_PAGE_MUTATION_EXECUTION,
2581
+ skip: skip_page_execution_for_new_page_import
2582
+ }),
2583
+ page_tool({
2584
+ name: "import-mermaid",
2585
+ params: /* @__PURE__ */ new Set(["mermaid_source", "mode", "insert_mode", "target_page"]),
2586
+ handler: import_mermaid,
2587
+ pageExecution: VISIBLE_PAGE_MUTATION_EXECUTION,
2588
+ skip: skip_page_execution_for_new_page_mermaid
2589
+ }),
2590
+ {
2591
+ name: "list-pages",
2592
+ params: /* @__PURE__ */ new Set([]),
2593
+ handler: list_pages
2594
+ },
2595
+ {
2596
+ name: "get-current-page",
2597
+ params: /* @__PURE__ */ new Set([]),
2598
+ handler: get_current_page
2599
+ },
2600
+ {
2601
+ name: "create-page",
2602
+ params: /* @__PURE__ */ new Set(["name"]),
2603
+ handler: create_page
2604
+ },
2605
+ {
2606
+ name: "copy-page",
2607
+ params: /* @__PURE__ */ new Set(["page", "name"]),
2608
+ handler: copy_page
2609
+ },
2610
+ {
2611
+ name: "rename-page",
2612
+ params: /* @__PURE__ */ new Set(["page", "name"]),
2613
+ handler: rename_page
2614
+ }
2615
+ ];
2616
+ var toolDefinitions = rawToolDefinitions.map(
2617
+ (definition) => ({
2618
+ ...definition,
2619
+ params: /* @__PURE__ */ new Set(["target_document", ...definition.params]),
2620
+ handler: with_target_document(definition.handler)
2621
+ })
2622
+ );
2623
+
2624
+ // src/bootstrap.ts
2625
+ var SHAPE_EXTRACTION_MAX_ATTEMPTS = 10;
2626
+ var SHAPE_EXTRACTION_INTERVAL_MS = 1e3;
2627
+ function generateDocumentId() {
2628
+ if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
2629
+ return crypto.randomUUID();
2630
+ }
2631
+ return `document-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
2632
+ }
2633
+ function bootstrapPlugin(opts) {
2634
+ const {
2635
+ ui: ui2,
2636
+ transport: transport2,
2637
+ enableDocumentState = true,
2638
+ enableShapeExtraction = true
2639
+ } = opts;
2640
+ let currentDocumentId = null;
2641
+ let currentFileRef = null;
2642
+ let detachFileListener = null;
2643
+ const cleanups = [];
2644
+ const syncDocumentState = () => {
2645
+ if (!enableDocumentState) return;
2646
+ if (!ui2?.getCurrentFile?.() || !currentDocumentId) return;
2647
+ transport2.send({
2648
+ __control: "document-state",
2649
+ document: serialize_document_info(ui2, currentDocumentId)
2650
+ });
2651
+ };
2652
+ const detachCurrentFileListener = () => {
2653
+ if (detachFileListener) {
2654
+ detachFileListener();
2655
+ detachFileListener = null;
2656
+ }
2657
+ currentFileRef = null;
2658
+ };
2659
+ const bindCurrentFileListener = (file) => {
2660
+ detachCurrentFileListener();
2661
+ currentFileRef = file;
2662
+ if (!file?.addListener || !file?.removeListener) return;
2663
+ const onDescriptorChanged = () => syncDocumentState();
2664
+ file.addListener("descriptorChanged", onDescriptorChanged);
2665
+ detachFileListener = () => {
2666
+ try {
2667
+ file.removeListener?.("descriptorChanged", onDescriptorChanged);
2668
+ } catch (error) {
2669
+ console.warn(
2670
+ "[plugin] Failed to remove file descriptor listener:",
2671
+ error
2672
+ );
2673
+ }
2674
+ };
2675
+ };
2676
+ const refreshActiveDocument = (forceNewId) => {
2677
+ const file = ui2?.getCurrentFile?.() ?? null;
2678
+ if (!file) {
2679
+ currentDocumentId = null;
2680
+ set_active_document_id(null);
2681
+ detachCurrentFileListener();
2682
+ return;
2683
+ }
2684
+ if (forceNewId || !currentDocumentId || file !== currentFileRef) {
2685
+ currentDocumentId = generateDocumentId();
2686
+ set_active_document_id(currentDocumentId);
2687
+ bindCurrentFileListener(file);
2688
+ return;
2689
+ }
2690
+ if (file !== currentFileRef) {
2691
+ bindCurrentFileListener(file);
2692
+ }
2693
+ };
2694
+ const handleDocumentStateChange = (forceNewId) => {
2695
+ refreshActiveDocument(forceNewId);
2696
+ syncDocumentState();
2697
+ };
2698
+ const registerDocumentStateListeners = () => {
2699
+ const listen = (eventName, forceNewId) => {
2700
+ ui2.editor?.addListener?.(eventName, () => {
2701
+ handleDocumentStateChange(forceNewId);
2702
+ });
2703
+ };
2704
+ listen("fileLoaded", true);
2705
+ listen("pageSelected", false);
2706
+ listen("pageRenamed", false);
2707
+ listen("pageMoved", false);
2708
+ listen("pagesPatched", false);
2709
+ refreshActiveDocument(false);
2710
+ };
2711
+ const buildToolHandler = (toolName, parameterKeys, executeFunction) => {
2712
+ return (request) => {
2713
+ const options = Object.entries(request).reduce(
2714
+ (acc, [key, value]) => {
2715
+ if (parameterKeys.has(key)) {
2716
+ acc[key] = value;
2717
+ }
2718
+ return acc;
2719
+ },
2720
+ {}
2721
+ );
2722
+ const sendReply = (success, payload) => {
2723
+ const reply = {
2724
+ __event: reply_name(toolName, request.__request_id),
2725
+ __request_id: request.__request_id,
2726
+ success
2727
+ };
2728
+ if (success) {
2729
+ reply.result = remove_circular_dependencies(payload);
2730
+ } else {
2731
+ reply.error = remove_circular_dependencies(payload);
2732
+ }
2733
+ transport2.send(reply);
2734
+ if (success) {
2735
+ syncDocumentState();
2736
+ }
2737
+ };
2738
+ try {
2739
+ const result = executeFunction(ui2, options);
2740
+ if (result instanceof Promise) {
2741
+ result.then(
2742
+ (resolved) => sendReply(true, resolved),
2743
+ (error) => {
2744
+ console.error(
2745
+ `[plugin] Async tool ${toolName} failed for request ID ${request.__request_id}:`,
2746
+ error
2747
+ );
2748
+ sendReply(false, error);
2749
+ }
2750
+ );
2751
+ return;
2752
+ }
2753
+ sendReply(true, result);
2754
+ } catch (error) {
2755
+ console.error(
2756
+ `[plugin] Tool ${toolName} failed for request ID ${request.__request_id}:`,
2757
+ error
2758
+ );
2759
+ sendReply(false, error);
2760
+ }
2761
+ };
2762
+ };
2763
+ const toolHandlers = /* @__PURE__ */ new Map();
2764
+ toolDefinitions.forEach((def) => {
2765
+ toolHandlers.set(
2766
+ def.name,
2767
+ buildToolHandler(def.name, def.params, def.handler)
2768
+ );
2769
+ console.debug(`[plugin] registered tool ${def.name}`);
2770
+ });
2771
+ transport2.onMessage((message) => {
2772
+ if (!message) return;
2773
+ if (message.__control === "sync-document-state") {
2774
+ handleDocumentStateChange(false);
2775
+ return;
2776
+ }
2777
+ const handler = typeof message.__event === "string" ? toolHandlers.get(message.__event) : void 0;
2778
+ if (handler) {
2779
+ handler(message);
2780
+ }
2781
+ });
2782
+ if (enableDocumentState) {
2783
+ registerDocumentStateListeners();
2784
+ }
2785
+ if (enableShapeExtraction) {
2786
+ const tryExtractShapes = () => {
2787
+ try {
2788
+ if (!ui2?.sidebar) return false;
2789
+ const map = extractShapesFromSidebar(ui2);
2790
+ if (map.size === 0) return false;
2791
+ const runtime = new Map(
2792
+ [...map].map(
2793
+ ([k, v]) => [
2794
+ k,
2795
+ { style: v.style, category: v.category, name: v.name }
2796
+ ]
2797
+ )
2798
+ );
2799
+ setRuntimeCatalog(runtime);
2800
+ console.info(
2801
+ `[plugin] extracted ${map.size} vendor shapes from drawio sidebar`
2802
+ );
2803
+ return true;
2804
+ } catch (err) {
2805
+ console.warn("[plugin] shape extraction attempt failed", err);
2806
+ return false;
2807
+ }
2808
+ };
2809
+ if (!tryExtractShapes()) {
2810
+ let attempts = 0;
2811
+ const intervalId = setInterval(() => {
2812
+ attempts += 1;
2813
+ if (tryExtractShapes() || attempts >= SHAPE_EXTRACTION_MAX_ATTEMPTS) {
2814
+ clearInterval(intervalId);
2815
+ if (attempts >= SHAPE_EXTRACTION_MAX_ATTEMPTS) {
2816
+ console.error(
2817
+ "[plugin] shape extraction gave up after retries; vendor shapes unavailable"
2818
+ );
2819
+ }
2820
+ }
2821
+ }, SHAPE_EXTRACTION_INTERVAL_MS);
2822
+ cleanups.push(() => clearInterval(intervalId));
2823
+ }
2824
+ }
2825
+ return {
2826
+ syncDocumentState,
2827
+ dispose: () => {
2828
+ detachCurrentFileListener();
2829
+ cleanups.forEach((fn) => fn());
2830
+ cleanups.length = 0;
2831
+ }
2832
+ };
2833
+ }
2834
+
2835
+ // src/websocketManager.ts
2836
+ function createWebSocketManager(options) {
2837
+ let socket = null;
2838
+ let reconnectAttempts = 0;
2839
+ let currentState = "disconnected";
2840
+ let messageHandler = null;
2841
+ let pingIntervalId = null;
2842
+ let reconnectTimeoutId = null;
2843
+ const {
2844
+ url,
2845
+ maxReconnectAttempts = 5,
2846
+ reconnectDelay = 3e3,
2847
+ pingInterval = 3e4
2848
+ } = options;
2849
+ const updateState = (newState) => {
2850
+ if (currentState !== newState) {
2851
+ console.debug(
2852
+ `[websocketManager] State change: ${currentState} \u2192 ${newState}`
2853
+ );
2854
+ currentState = newState;
2855
+ }
2856
+ };
2857
+ const connect = () => {
2858
+ if (socket && socket.readyState === WebSocket.OPEN) {
2859
+ console.debug("[websocketManager] Already connected");
2860
+ return;
2861
+ }
2862
+ updateState("connecting");
2863
+ try {
2864
+ socket = new WebSocket(url);
2865
+ socket.addEventListener("open", () => {
2866
+ console.debug("[websocketManager] WebSocket connection established");
2867
+ reconnectAttempts = 0;
2868
+ updateState("connected");
2869
+ startPing();
2870
+ });
2871
+ socket.addEventListener("message", (event) => {
2872
+ try {
2873
+ const parsedMessage = JSON.parse(event.data);
2874
+ console.debug("[websocketManager] Received message:", parsedMessage);
2875
+ if (messageHandler) {
2876
+ messageHandler(parsedMessage);
2877
+ }
2878
+ } catch (error) {
2879
+ console.error(
2880
+ "[websocketManager] Failed to parse WebSocket message:",
2881
+ error
2882
+ );
2883
+ }
2884
+ });
2885
+ socket.addEventListener("close", () => {
2886
+ console.debug("[websocketManager] WebSocket connection closed");
2887
+ updateState("disconnected");
2888
+ stopPing();
2889
+ attemptReconnect();
2890
+ });
2891
+ socket.addEventListener("error", (event) => {
2892
+ console.error("[websocketManager] WebSocket error:", event);
2893
+ updateState("disconnected");
2894
+ });
2895
+ } catch (error) {
2896
+ console.error(
2897
+ "[websocketManager] Failed to create WebSocket connection:",
2898
+ error
2899
+ );
2900
+ updateState("disconnected");
2901
+ }
2902
+ };
2903
+ const disconnect = () => {
2904
+ if (reconnectTimeoutId) {
2905
+ clearTimeout(reconnectTimeoutId);
2906
+ reconnectTimeoutId = null;
2907
+ }
2908
+ stopPing();
2909
+ reconnectAttempts = 0;
2910
+ if (socket) {
2911
+ console.debug("[websocketManager] Closing WebSocket connection");
2912
+ socket.close();
2913
+ socket = null;
2914
+ }
2915
+ updateState("disconnected");
2916
+ };
2917
+ const send = (message) => {
2918
+ if (!socket || socket.readyState !== WebSocket.OPEN) {
2919
+ console.warn(
2920
+ "[websocketManager] Cannot send message: WebSocket not connected"
2921
+ );
2922
+ return;
2923
+ }
2924
+ try {
2925
+ const serialized = JSON.stringify(message);
2926
+ console.debug("[websocketManager] Sending message:", message);
2927
+ socket.send(serialized);
2928
+ } catch (error) {
2929
+ console.error("[websocketManager] Failed to send message:", error);
2930
+ }
2931
+ };
2932
+ const getState = () => currentState;
2933
+ const onMessage = (handler) => {
2934
+ messageHandler = handler;
2935
+ };
2936
+ const attemptReconnect = () => {
2937
+ if (reconnectAttempts >= maxReconnectAttempts) {
2938
+ console.error(
2939
+ "[websocketManager] Max reconnection attempts reached. Giving up."
2940
+ );
2941
+ return;
2942
+ }
2943
+ reconnectAttempts++;
2944
+ const delay = reconnectDelay * Math.pow(1.5, reconnectAttempts - 1);
2945
+ console.log(
2946
+ `[websocketManager] Attempting to reconnect in ${Math.round(delay / 1e3)} seconds... (attempt ${reconnectAttempts}/${maxReconnectAttempts})`
2947
+ );
2948
+ reconnectTimeoutId = window.setTimeout(() => {
2949
+ reconnectTimeoutId = null;
2950
+ connect();
2951
+ }, delay);
2952
+ };
2953
+ const startPing = () => {
2954
+ stopPing();
2955
+ pingIntervalId = window.setInterval(() => {
2956
+ if (getState() === "connected") {
2957
+ send({ type: "PING" });
2958
+ }
2959
+ }, pingInterval);
2960
+ };
2961
+ const stopPing = () => {
2962
+ if (pingIntervalId !== null) {
2963
+ clearInterval(pingIntervalId);
2964
+ pingIntervalId = null;
2965
+ }
2966
+ };
2967
+ const ping = () => {
2968
+ return new Promise((resolve) => {
2969
+ if (getState() !== "connected") {
2970
+ resolve(false);
2971
+ return;
2972
+ }
2973
+ const timeoutId = setTimeout(() => {
2974
+ resolve(false);
2975
+ }, 5e3);
2976
+ send({ type: "PING", message: "Ping from plugin" });
2977
+ setTimeout(() => {
2978
+ clearTimeout(timeoutId);
2979
+ resolve(getState() === "connected");
2980
+ }, 1e3);
2981
+ });
2982
+ };
2983
+ return {
2984
+ connect,
2985
+ disconnect,
2986
+ send,
2987
+ getState,
2988
+ onMessage,
2989
+ ping
2990
+ };
2991
+ }
2992
+
2993
+ // src/pluginConfig.ts
2994
+ var DEFAULT_PLUGIN_CONFIG = {
2995
+ websocketPort: 3333,
2996
+ serverUrl: ""
2997
+ };
2998
+ function isValidWebSocketUrl(value) {
2999
+ if (typeof value !== "string" || value.length === 0) {
3000
+ return false;
3001
+ }
3002
+ try {
3003
+ const parsed = new URL(value);
3004
+ return parsed.protocol === "ws:" || parsed.protocol === "wss:";
3005
+ } catch {
3006
+ return false;
3007
+ }
3008
+ }
3009
+ var PLUGIN_CONFIG_KEY = "drawio-mcp-plugin-config";
3010
+ var cachedConfig = null;
3011
+ function isFileOrigin() {
3012
+ return typeof window !== "undefined" && window.location.protocol === "file:";
3013
+ }
3014
+ async function fetchPluginConfig() {
3015
+ if (cachedConfig) {
3016
+ return cachedConfig;
3017
+ }
3018
+ if (isFileOrigin()) {
3019
+ const stored = readPluginConfig();
3020
+ cachedConfig = stored;
3021
+ return stored;
3022
+ }
3023
+ try {
3024
+ const response = await fetch("/api/config");
3025
+ if (response.ok) {
3026
+ const serverConfig = await response.json();
3027
+ cachedConfig = {
3028
+ websocketPort: serverConfig.websocketPort || DEFAULT_PLUGIN_CONFIG.websocketPort,
3029
+ serverUrl: serverConfig.serverUrl || window.location.origin,
3030
+ websocketUrl: isValidWebSocketUrl(serverConfig.websocketUrl) ? serverConfig.websocketUrl : void 0
3031
+ };
3032
+ writePluginConfig(cachedConfig);
3033
+ return cachedConfig;
3034
+ }
3035
+ } catch (error) {
3036
+ console.warn("[pluginConfig] Failed to fetch config from server:", error);
3037
+ }
3038
+ return readPluginConfig();
3039
+ }
3040
+ function readPluginConfig() {
3041
+ try {
3042
+ const stored = localStorage.getItem(PLUGIN_CONFIG_KEY);
3043
+ if (stored) {
3044
+ const parsed = JSON.parse(stored);
3045
+ const validated = validatePluginConfig(parsed);
3046
+ if (validated.isValid && validated.config) {
3047
+ return validated.config;
3048
+ }
3049
+ }
3050
+ } catch (error) {
3051
+ console.warn("[pluginConfig] Failed to read from localStorage:", error);
3052
+ }
3053
+ return { ...DEFAULT_PLUGIN_CONFIG };
3054
+ }
3055
+ function writePluginConfig(config) {
3056
+ try {
3057
+ localStorage.setItem(PLUGIN_CONFIG_KEY, JSON.stringify(config));
3058
+ cachedConfig = config;
3059
+ } catch (error) {
3060
+ console.error("[pluginConfig] Failed to write to localStorage:", error);
3061
+ throw error;
3062
+ }
3063
+ }
3064
+ function validatePluginConfig(config) {
3065
+ if (!config || typeof config !== "object") {
3066
+ return { isValid: false, error: "Configuration must be an object" };
3067
+ }
3068
+ const cfg = config;
3069
+ if (typeof cfg.websocketPort !== "number") {
3070
+ return { isValid: false, error: "websocketPort must be a number" };
3071
+ }
3072
+ if (cfg.websocketPort < 1024 || cfg.websocketPort > 65535) {
3073
+ return {
3074
+ isValid: false,
3075
+ error: "websocketPort must be between 1024 and 65535"
3076
+ };
3077
+ }
3078
+ const websocketUrl = isValidWebSocketUrl(cfg.websocketUrl) ? cfg.websocketUrl : void 0;
3079
+ return {
3080
+ isValid: true,
3081
+ config: {
3082
+ websocketPort: cfg.websocketPort,
3083
+ serverUrl: cfg.serverUrl || "",
3084
+ websocketUrl
3085
+ }
3086
+ };
3087
+ }
3088
+ function buildWebSocketUrl(config) {
3089
+ if (config.websocketUrl) {
3090
+ return config.websocketUrl;
3091
+ }
3092
+ const isFile = isFileOrigin();
3093
+ const scheme = !isFile && window.location.protocol === "https:" ? "wss:" : "ws:";
3094
+ const hostname = window.location.hostname;
3095
+ const host = isFile || hostname.length === 0 ? "localhost" : hostname;
3096
+ return `${scheme}//${host}:${config.websocketPort}`;
3097
+ }
3098
+
3099
+ // src/settingsDialog.ts
3100
+ function defaultUrlFor(config) {
3101
+ return buildWebSocketUrl({ ...config, websocketUrl: void 0 });
3102
+ }
3103
+ function effectiveUrlFor(config) {
3104
+ return buildWebSocketUrl(config);
3105
+ }
3106
+ function createDialogContainer() {
3107
+ const container = document.createElement("div");
3108
+ container.id = "mcp-settings-dialog";
3109
+ container.style.cssText = `
3110
+ position: fixed;
3111
+ top: 0;
3112
+ left: 0;
3113
+ width: 100%;
3114
+ height: 100%;
3115
+ background-color: rgba(0, 0, 0, 0.5);
3116
+ display: flex;
3117
+ justify-content: center;
3118
+ align-items: center;
3119
+ z-index: 10000;
3120
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
3121
+ `;
3122
+ container.addEventListener("click", (e) => {
3123
+ if (e.target === container) {
3124
+ e.stopPropagation();
3125
+ }
3126
+ });
3127
+ return container;
3128
+ }
3129
+ function createDialogContent() {
3130
+ const content = document.createElement("div");
3131
+ content.className = "dialog-content";
3132
+ content.style.cssText = `
3133
+ background: white;
3134
+ border-radius: 8px;
3135
+ box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
3136
+ max-width: 500px;
3137
+ width: 90%;
3138
+ max-height: 90vh;
3139
+ overflow-y: auto;
3140
+ position: relative;
3141
+ `;
3142
+ return content;
3143
+ }
3144
+ function createDialogHeader(title, onClose) {
3145
+ const header = document.createElement("div");
3146
+ header.className = "dialog-header";
3147
+ header.style.cssText = `
3148
+ padding: 16px 20px;
3149
+ border-bottom: 1px solid #e0e0e0;
3150
+ display: flex;
3151
+ justify-content: space-between;
3152
+ align-items: center;
3153
+ `;
3154
+ const titleEl = document.createElement("h2");
3155
+ titleEl.textContent = title;
3156
+ titleEl.style.cssText = `
3157
+ margin: 0;
3158
+ font-size: 18px;
3159
+ font-weight: 600;
3160
+ color: #333;
3161
+ `;
3162
+ const closeBtn = document.createElement("button");
3163
+ closeBtn.textContent = "\xD7";
3164
+ closeBtn.style.cssText = `
3165
+ background: none;
3166
+ border: none;
3167
+ font-size: 24px;
3168
+ cursor: pointer;
3169
+ padding: 0;
3170
+ width: 24px;
3171
+ height: 24px;
3172
+ display: flex;
3173
+ align-items: center;
3174
+ justify-content: center;
3175
+ color: #666;
3176
+ border-radius: 4px;
3177
+ `;
3178
+ closeBtn.title = "Close";
3179
+ closeBtn.addEventListener("mouseenter", () => {
3180
+ closeBtn.style.backgroundColor = "#f5f5f5";
3181
+ });
3182
+ closeBtn.addEventListener("mouseleave", () => {
3183
+ closeBtn.style.backgroundColor = "transparent";
3184
+ });
3185
+ closeBtn.addEventListener("click", onClose);
3186
+ header.appendChild(titleEl);
3187
+ header.appendChild(closeBtn);
3188
+ return header;
3189
+ }
3190
+ function createDialogBody(state) {
3191
+ const body = document.createElement("div");
3192
+ body.className = "dialog-body";
3193
+ body.style.cssText = `
3194
+ padding: 20px;
3195
+ `;
3196
+ const statusSection = createStatusSection(state);
3197
+ body.appendChild(statusSection);
3198
+ const formSection = createFormSection(state);
3199
+ body.appendChild(formSection);
3200
+ return body;
3201
+ }
3202
+ function createStatusSection(state) {
3203
+ const section = document.createElement("div");
3204
+ section.className = "status-section";
3205
+ section.style.cssText = `
3206
+ margin-bottom: 24px;
3207
+ padding: 16px;
3208
+ background: #f8f9fa;
3209
+ border-radius: 6px;
3210
+ border: 1px solid #e9ecef;
3211
+ `;
3212
+ const title = document.createElement("div");
3213
+ title.style.cssText = `
3214
+ font-weight: 600;
3215
+ margin-bottom: 8px;
3216
+ color: #333;
3217
+ `;
3218
+ title.textContent = "Connection Status";
3219
+ const statusIndicator = document.createElement("div");
3220
+ statusIndicator.className = "status-indicator";
3221
+ statusIndicator.style.cssText = `
3222
+ display: flex;
3223
+ align-items: center;
3224
+ gap: 8px;
3225
+ margin-bottom: 4px;
3226
+ `;
3227
+ const indicator = document.createElement("div");
3228
+ indicator.style.cssText = `
3229
+ width: 12px;
3230
+ height: 12px;
3231
+ border-radius: 50%;
3232
+ flex-shrink: 0;
3233
+ `;
3234
+ switch (state.connectionState) {
3235
+ case "connected":
3236
+ indicator.style.backgroundColor = "#28a745";
3237
+ break;
3238
+ case "connecting":
3239
+ indicator.style.backgroundColor = "#ffc107";
3240
+ break;
3241
+ case "disconnected":
3242
+ indicator.style.backgroundColor = "#dc3545";
3243
+ break;
3244
+ }
3245
+ const statusText = document.createElement("span");
3246
+ statusText.textContent = state.connectionState.charAt(0).toUpperCase() + state.connectionState.slice(1);
3247
+ statusText.style.fontWeight = "500";
3248
+ statusIndicator.appendChild(indicator);
3249
+ statusIndicator.appendChild(statusText);
3250
+ const urlDisplay = document.createElement("div");
3251
+ urlDisplay.style.cssText = `
3252
+ font-size: 14px;
3253
+ color: #666;
3254
+ word-break: break-all;
3255
+ `;
3256
+ urlDisplay.textContent = `URL: ${effectiveUrlFor(state.config)}`;
3257
+ section.appendChild(title);
3258
+ section.appendChild(statusIndicator);
3259
+ section.appendChild(urlDisplay);
3260
+ return section;
3261
+ }
3262
+ function createFormSection(state) {
3263
+ const section = document.createElement("div");
3264
+ section.className = "form-section";
3265
+ const urlGroup = document.createElement("div");
3266
+ urlGroup.className = "form-group";
3267
+ urlGroup.style.cssText = `
3268
+ margin-bottom: 16px;
3269
+ `;
3270
+ const label = document.createElement("label");
3271
+ label.textContent = "WebSocket URL";
3272
+ label.htmlFor = "mcp-url-input";
3273
+ label.style.cssText = `
3274
+ display: block;
3275
+ margin-bottom: 6px;
3276
+ font-weight: 500;
3277
+ color: #333;
3278
+ `;
3279
+ const input = document.createElement("input");
3280
+ input.id = "mcp-url-input";
3281
+ input.type = "text";
3282
+ input.spellcheck = false;
3283
+ input.autocomplete = "off";
3284
+ input.value = state.formData.url;
3285
+ input.placeholder = defaultUrlFor(state.config);
3286
+ input.style.cssText = `
3287
+ width: 100%;
3288
+ padding: 8px 12px;
3289
+ border: 1px solid #ddd;
3290
+ border-radius: 4px;
3291
+ font-size: 14px;
3292
+ font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
3293
+ box-sizing: border-box;
3294
+ `;
3295
+ if (state.errors.url) {
3296
+ input.style.borderColor = "#dc3545";
3297
+ }
3298
+ input.addEventListener("input", (e) => {
3299
+ const value = e.target.value;
3300
+ window.dispatchEvent(
3301
+ new CustomEvent("mcp-settings-message", {
3302
+ detail: { type: "UPDATE_URL", url: value }
3303
+ })
3304
+ );
3305
+ });
3306
+ const hint = document.createElement("div");
3307
+ hint.textContent = `Leave blank to use the default (${defaultUrlFor(state.config)}). Must start with ws:// or wss://`;
3308
+ hint.style.cssText = `
3309
+ font-size: 12px;
3310
+ color: #666;
3311
+ margin-top: 4px;
3312
+ word-break: break-all;
3313
+ `;
3314
+ urlGroup.appendChild(label);
3315
+ urlGroup.appendChild(input);
3316
+ urlGroup.appendChild(hint);
3317
+ if (state.errors.url) {
3318
+ const error = document.createElement("div");
3319
+ error.textContent = state.errors.url;
3320
+ error.style.cssText = `
3321
+ font-size: 12px;
3322
+ color: #dc3545;
3323
+ margin-top: 4px;
3324
+ `;
3325
+ urlGroup.appendChild(error);
3326
+ }
3327
+ section.appendChild(urlGroup);
3328
+ return section;
3329
+ }
3330
+ function createDialogFooter(state) {
3331
+ const footer = document.createElement("div");
3332
+ footer.className = "dialog-footer";
3333
+ footer.style.cssText = `
3334
+ padding: 16px 20px;
3335
+ border-top: 1px solid #e0e0e0;
3336
+ display: flex;
3337
+ justify-content: space-between;
3338
+ gap: 12px;
3339
+ flex-wrap: wrap;
3340
+ `;
3341
+ const leftActions = document.createElement("div");
3342
+ leftActions.style.cssText = `
3343
+ display: flex;
3344
+ gap: 8px;
3345
+ flex-wrap: wrap;
3346
+ `;
3347
+ const rightActions = document.createElement("div");
3348
+ rightActions.style.cssText = `
3349
+ display: flex;
3350
+ gap: 8px;
3351
+ `;
3352
+ const cancelBtn = createButton("Cancel", "ghost", () => {
3353
+ window.dispatchEvent(
3354
+ new CustomEvent("mcp-settings-message", {
3355
+ detail: { type: "CLOSE" }
3356
+ })
3357
+ );
3358
+ });
3359
+ const saveBtn = createButton(
3360
+ state.isSaving ? "Saving..." : "Save",
3361
+ "primary",
3362
+ () => {
3363
+ window.dispatchEvent(
3364
+ new CustomEvent("mcp-settings-message", {
3365
+ detail: { type: "SAVE" }
3366
+ })
3367
+ );
3368
+ },
3369
+ state.isSaving
3370
+ );
3371
+ rightActions.appendChild(cancelBtn);
3372
+ rightActions.appendChild(saveBtn);
3373
+ footer.appendChild(leftActions);
3374
+ footer.appendChild(rightActions);
3375
+ return footer;
3376
+ }
3377
+ function createButton(text, variant, onClick, disabled = false) {
3378
+ const btn = document.createElement("button");
3379
+ btn.textContent = text;
3380
+ btn.disabled = disabled;
3381
+ btn.style.cssText = `
3382
+ padding: 8px 16px;
3383
+ border-radius: 4px;
3384
+ font-size: 14px;
3385
+ cursor: pointer;
3386
+ border: 1px solid transparent;
3387
+ transition: all 0.2s;
3388
+ `;
3389
+ switch (variant) {
3390
+ case "primary":
3391
+ btn.style.cssText += `
3392
+ background-color: #007bff;
3393
+ color: white;
3394
+ border-color: #007bff;
3395
+ `;
3396
+ btn.addEventListener("mouseenter", () => {
3397
+ if (!disabled) btn.style.backgroundColor = "#0056b3";
3398
+ });
3399
+ btn.addEventListener("mouseleave", () => {
3400
+ if (!disabled) btn.style.backgroundColor = "#007bff";
3401
+ });
3402
+ break;
3403
+ case "secondary":
3404
+ btn.style.cssText += `
3405
+ background-color: #6c757d;
3406
+ color: white;
3407
+ border-color: #6c757d;
3408
+ `;
3409
+ btn.addEventListener("mouseenter", () => {
3410
+ if (!disabled) btn.style.backgroundColor = "#545b62";
3411
+ });
3412
+ btn.addEventListener("mouseleave", () => {
3413
+ if (!disabled) btn.style.backgroundColor = "#6c757d";
3414
+ });
3415
+ break;
3416
+ case "ghost":
3417
+ btn.style.cssText += `
3418
+ background-color: transparent;
3419
+ color: #6c757d;
3420
+ border-color: #6c757d;
3421
+ `;
3422
+ btn.addEventListener("mouseenter", () => {
3423
+ if (!disabled) {
3424
+ btn.style.backgroundColor = "#f8f9fa";
2263
3425
  }
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
- };
3426
+ });
3427
+ btn.addEventListener("mouseleave", () => {
3428
+ if (!disabled) btn.style.backgroundColor = "transparent";
3429
+ });
3430
+ break;
2279
3431
  }
3432
+ if (disabled) {
3433
+ btn.style.cssText += `
3434
+ opacity: 0.6;
3435
+ cursor: not-allowed;
3436
+ `;
3437
+ }
3438
+ btn.addEventListener("click", onClick);
3439
+ return btn;
2280
3440
  }
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);
3441
+ function createSettingsDialog(initialState, actions) {
3442
+ let currentState = { ...initialState };
3443
+ let dialogElement = null;
3444
+ let isVisible = false;
3445
+ const update = (newState) => {
3446
+ currentState = { ...newState };
3447
+ if (dialogElement && isVisible) {
3448
+ render();
3449
+ }
3450
+ };
3451
+ const render = () => {
3452
+ if (dialogElement && dialogElement.parentNode) {
3453
+ dialogElement.parentNode.removeChild(dialogElement);
3454
+ }
3455
+ const container = createDialogContainer();
3456
+ const content = createDialogContent();
3457
+ const header = createDialogHeader("MCP Settings", () => actions.onClose());
3458
+ const body = createDialogBody(currentState);
3459
+ const footer = createDialogFooter(currentState);
3460
+ content.appendChild(header);
3461
+ content.appendChild(body);
3462
+ content.appendChild(footer);
3463
+ container.appendChild(content);
3464
+ dialogElement = container;
3465
+ isVisible = true;
3466
+ setupMessageListeners(container, actions);
3467
+ return container;
3468
+ };
3469
+ const setupMessageListeners = (container, actions2) => {
3470
+ const handleMessage = (event) => {
3471
+ const message = event.detail;
3472
+ switch (message.type) {
3473
+ case "UPDATE_URL":
3474
+ currentState.formData.url = message.url;
3475
+ delete currentState.errors.url;
3476
+ break;
3477
+ case "SAVE":
3478
+ if (!validateAndSave()) {
3479
+ update(currentState);
3480
+ }
3481
+ break;
3482
+ case "CLOSE":
3483
+ actions2.onClose();
3484
+ break;
2308
3485
  }
2309
- return reply;
2310
3486
  };
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
3487
+ window.addEventListener(
3488
+ "mcp-settings-message",
3489
+ handleMessage
3490
+ );
3491
+ const observer = new MutationObserver((mutations) => {
3492
+ mutations.forEach((mutation) => {
3493
+ mutation.removedNodes.forEach((node) => {
3494
+ if (node === container) {
3495
+ window.removeEventListener(
3496
+ "mcp-settings-message",
3497
+ handleMessage
2320
3498
  );
2321
- sendReply(void 0, false, err);
3499
+ observer.disconnect();
2322
3500
  }
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);
3501
+ });
3502
+ });
3503
+ });
3504
+ if (container.parentNode) {
3505
+ observer.observe(container.parentNode, { childList: true });
2333
3506
  }
2334
3507
  };
2335
- };
3508
+ const validateAndSave = () => {
3509
+ const trimmed = currentState.formData.url.trim();
3510
+ if (trimmed.length > 0 && !isValidWebSocketUrl(trimmed)) {
3511
+ currentState.errors.url = "URL must start with ws:// or wss://";
3512
+ return false;
3513
+ }
3514
+ currentState.errors = {};
3515
+ currentState.isSaving = true;
3516
+ const newConfig = {
3517
+ ...currentState.config,
3518
+ websocketUrl: trimmed.length > 0 ? trimmed : void 0
3519
+ };
3520
+ actions.onSave(newConfig);
3521
+ return true;
3522
+ };
3523
+ const dialogProxy = {
3524
+ get element() {
3525
+ if (!dialogElement) {
3526
+ render();
3527
+ }
3528
+ return dialogElement;
3529
+ },
3530
+ update
3531
+ };
3532
+ return dialogProxy;
3533
+ }
3534
+ function showSettingsDialog(dialog) {
3535
+ if (!dialog.element.parentNode) {
3536
+ document.body.appendChild(dialog.element);
3537
+ }
3538
+ }
3539
+ function hideSettingsDialog(dialog) {
3540
+ if (dialog.element.parentNode) {
3541
+ dialog.element.parentNode.removeChild(dialog.element);
3542
+ }
3543
+ }
3544
+
3545
+ // src/plugin.ts
2336
3546
  var ui;
2337
3547
  var wsManager = null;
3548
+ var bootstrapListener = null;
2338
3549
  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
- }
3550
+ var transport = {
3551
+ send: (message) => wsManager?.send(message),
3552
+ onMessage: (listener) => {
3553
+ bootstrapListener = listener;
3554
+ wsManager?.onMessage(listener);
2479
3555
  }
2480
3556
  };
2481
3557
  var initializeWebSocket = async () => {
@@ -2487,7 +3563,9 @@ var DrawMcp = (() => {
2487
3563
  reconnectDelay: 3e3,
2488
3564
  pingInterval: 3e4
2489
3565
  });
2490
- wsManager.onMessage(handleWebSocketMessage);
3566
+ if (bootstrapListener) {
3567
+ wsManager.onMessage(bootstrapListener);
3568
+ }
2491
3569
  wsManager.connect();
2492
3570
  console.log(`[plugin] WebSocket initialized with URL: ${wsUrl}`);
2493
3571
  };
@@ -2499,7 +3577,7 @@ var DrawMcp = (() => {
2499
3577
  connectionState,
2500
3578
  isSaving: false,
2501
3579
  formData: {
2502
- port: config.websocketPort.toString()
3580
+ url: config.websocketUrl ?? ""
2503
3581
  },
2504
3582
  errors: {}
2505
3583
  };
@@ -2509,7 +3587,7 @@ var DrawMcp = (() => {
2509
3587
  if (wsManager) {
2510
3588
  wsManager.disconnect();
2511
3589
  }
2512
- initializeWebSocket();
3590
+ void initializeWebSocket();
2513
3591
  if (settingsDialog) {
2514
3592
  settingsDialog.update({
2515
3593
  ...initialState,
@@ -2552,7 +3630,7 @@ var DrawMcp = (() => {
2552
3630
  connectionState,
2553
3631
  isSaving: false,
2554
3632
  formData: {
2555
- port: config.websocketPort.toString()
3633
+ url: config.websocketUrl ?? ""
2556
3634
  },
2557
3635
  errors: {}
2558
3636
  });
@@ -2596,11 +3674,8 @@ var DrawMcp = (() => {
2596
3674
  if (window.__DRAWIO_MCP_TEST_HOOKS__ === true) {
2597
3675
  window.ui = drawioUI;
2598
3676
  }
2599
- toolDefinitions.forEach((def) => {
2600
- const handler = createToolHandler(def.name, def.params, def.handler);
2601
- toolHandlers.set(def.name, handler);
2602
- });
2603
- initializeWebSocket();
3677
+ bootstrapPlugin({ ui, transport });
3678
+ void initializeWebSocket();
2604
3679
  initializeSettingsDialog();
2605
3680
  addMenuItem(ui);
2606
3681
  console.info("[plugin] MCP Plugin fully initialized");