excalidrop 0.1.1

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 (234) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +411 -0
  3. package/dist/cli.d.ts +24 -0
  4. package/dist/cli.d.ts.map +1 -0
  5. package/dist/cli.js +533 -0
  6. package/dist/cli.js.map +1 -0
  7. package/dist/frontend/assets/Assistant-Bold-gm-uSS1B.woff2 +0 -0
  8. package/dist/frontend/assets/Assistant-Medium-DrcxCXg3.woff2 +0 -0
  9. package/dist/frontend/assets/Assistant-Regular-DVxZuzxb.woff2 +0 -0
  10. package/dist/frontend/assets/Assistant-SemiBold-SCI4bEL9.woff2 +0 -0
  11. package/dist/frontend/assets/Tableau10-B-NsZVaP.js +1 -0
  12. package/dist/frontend/assets/_commonjs-dynamic-modules-TDtrdbi3.js +1 -0
  13. package/dist/frontend/assets/advancedFormat-bKUmsig-.js +1 -0
  14. package/dist/frontend/assets/ar-SA-G6X2FPQ2-C7K_UR3P.js +10 -0
  15. package/dist/frontend/assets/arc-BI_FJWE7.js +1 -0
  16. package/dist/frontend/assets/array-BKyUJesY.js +1 -0
  17. package/dist/frontend/assets/az-AZ-76LH7QW2-PkhuRuSr.js +1 -0
  18. package/dist/frontend/assets/band-dPffDWoQ.js +1 -0
  19. package/dist/frontend/assets/bg-BG-XCXSNQG7-CgLRSYTl.js +5 -0
  20. package/dist/frontend/assets/blockDiagram-38ab4fdb-BFdBRYSn.js +118 -0
  21. package/dist/frontend/assets/blockDiagram-68f4deed-Ynbqr7bQ.js +118 -0
  22. package/dist/frontend/assets/bn-BD-2XOGV67Q-CEvkU0mz.js +5 -0
  23. package/dist/frontend/assets/c4Diagram-15b5d702-Dm7F1Pn_.js +10 -0
  24. package/dist/frontend/assets/c4Diagram-3d4e48cf-COkK-e67.js +10 -0
  25. package/dist/frontend/assets/ca-ES-6MX7JW3Y-DzP6q9bE.js +8 -0
  26. package/dist/frontend/assets/channel-BqCiG5n3.js +1 -0
  27. package/dist/frontend/assets/classDiagram-70f12bd4-CRzulwvH.js +2 -0
  28. package/dist/frontend/assets/classDiagram-d40c83e7-DNbA-n-a.js +2 -0
  29. package/dist/frontend/assets/classDiagram-v2-d5a6b087-l-GglywH.js +2 -0
  30. package/dist/frontend/assets/classDiagram-v2-f2320105-B_TY1zoc.js +2 -0
  31. package/dist/frontend/assets/clone-B6Jqcrku.js +1 -0
  32. package/dist/frontend/assets/createText-2e5e7dd3-DB_k52Pn.js +5 -0
  33. package/dist/frontend/assets/createText-d213de94-D-G49giw.js +5 -0
  34. package/dist/frontend/assets/cs-CZ-2BRQDIVT-Bf4TOzpR.js +11 -0
  35. package/dist/frontend/assets/cytoscape-cose-bilkent-DQYypj0P.js +331 -0
  36. package/dist/frontend/assets/da-DK-5WZEPLOC-jO-5kyXb.js +5 -0
  37. package/dist/frontend/assets/de-DE-XR44H4JA-BkNXWOVh.js +8 -0
  38. package/dist/frontend/assets/directory-open-01563666-DWU9wJ6I.js +1 -0
  39. package/dist/frontend/assets/directory-open-4ed118d0-BzWybGaI.js +1 -0
  40. package/dist/frontend/assets/edges-332bd1c7-CVvMtkTa.js +4 -0
  41. package/dist/frontend/assets/edges-e0da2a9e-DQBAvC8-.js +4 -0
  42. package/dist/frontend/assets/el-GR-BZB4AONW-Dv7Y9hMk.js +10 -0
  43. package/dist/frontend/assets/elk.bundled-YVS3PsMH.js +26 -0
  44. package/dist/frontend/assets/erDiagram-880f2ed8-BjBeR38f.js +51 -0
  45. package/dist/frontend/assets/erDiagram-9861fffd-B2Bi3R45.js +51 -0
  46. package/dist/frontend/assets/es-ES-U4NZUMDT-CWhs0SQY.js +9 -0
  47. package/dist/frontend/assets/eu-ES-A7QVB2H4-BfkFwc3e.js +11 -0
  48. package/dist/frontend/assets/fa-IR-HGAKTJCU-BgWzSj46.js +8 -0
  49. package/dist/frontend/assets/fi-FI-Z5N7JZ37-CUyvkum-.js +6 -0
  50. package/dist/frontend/assets/file-open-002ab408-DIuFHtCF.js +1 -0
  51. package/dist/frontend/assets/file-open-7c801643-684qeFg4.js +1 -0
  52. package/dist/frontend/assets/file-save-3189631c-x92wctJd.js +1 -0
  53. package/dist/frontend/assets/file-save-745eba88-Bb9F9Kg7.js +1 -0
  54. package/dist/frontend/assets/flowDb-7c981674-BSZyyVBf.js +10 -0
  55. package/dist/frontend/assets/flowDb-956e92f1-BC3-CLkF.js +10 -0
  56. package/dist/frontend/assets/flowDiagram-66a62f08-H57DAvmM.js +4 -0
  57. package/dist/frontend/assets/flowDiagram-cbd28bf7-Bw4Z2nBD.js +4 -0
  58. package/dist/frontend/assets/flowDiagram-v2-96b9c2cf-CBjbm_oB.js +1 -0
  59. package/dist/frontend/assets/flowDiagram-v2-ffc7f31a-CoQufPp2.js +1 -0
  60. package/dist/frontend/assets/flowchart-elk-definition-36e2d292-1kZNdf3X.js +114 -0
  61. package/dist/frontend/assets/flowchart-elk-definition-4a651766-DDhG2Esi.js +114 -0
  62. package/dist/frontend/assets/fr-FR-RHASNOE6-7xzoRwbd.js +9 -0
  63. package/dist/frontend/assets/ganttDiagram-04f9e578-CtUSsXCz.js +257 -0
  64. package/dist/frontend/assets/ganttDiagram-c361ad54-K42AklFY.js +257 -0
  65. package/dist/frontend/assets/gitGraphDiagram-21fc4d3e-uW6XA6Y6.js +70 -0
  66. package/dist/frontend/assets/gitGraphDiagram-72cf32ee-CCNbhnBg.js +70 -0
  67. package/dist/frontend/assets/gl-ES-HMX3MZ6V-CXuDDwNP.js +10 -0
  68. package/dist/frontend/assets/graph-CYOmcSYN.js +1 -0
  69. package/dist/frontend/assets/graph-o42dOfI7.js +1 -0
  70. package/dist/frontend/assets/he-IL-6SHJWFNN-O9dzh9EM.js +10 -0
  71. package/dist/frontend/assets/hi-IN-IWLTKZ5I-DlrOXhWs.js +4 -0
  72. package/dist/frontend/assets/hu-HU-A5ZG7DT2-C3eNg-uI.js +7 -0
  73. package/dist/frontend/assets/id-ID-SAP4L64H-6iM4pI5c.js +10 -0
  74. package/dist/frontend/assets/image-blob-reduce.esm-B6b2_-a4.js +7 -0
  75. package/dist/frontend/assets/index-3862675e-DrvLhypC.js +1 -0
  76. package/dist/frontend/assets/index-6079d271-BgVTRqg2.js +1 -0
  77. package/dist/frontend/assets/index-BRA5OktX.css +1 -0
  78. package/dist/frontend/assets/index-D-cr7jpJ.js +349 -0
  79. package/dist/frontend/assets/index-DGmpr33w.js +3 -0
  80. package/dist/frontend/assets/index-HkUXslJy.js +87 -0
  81. package/dist/frontend/assets/infoDiagram-4a4f5b27-ZxmAcaW1.js +7 -0
  82. package/dist/frontend/assets/infoDiagram-f8f76790-Bn-PhiFG.js +7 -0
  83. package/dist/frontend/assets/init-Gi6I4Gst.js +1 -0
  84. package/dist/frontend/assets/it-IT-JPQ66NNP-B26NQzGp.js +11 -0
  85. package/dist/frontend/assets/ja-JP-DBVTYXUO-CB0fvnYJ.js +8 -0
  86. package/dist/frontend/assets/journeyDiagram-29694f62-ggDKs06f.js +139 -0
  87. package/dist/frontend/assets/journeyDiagram-49397b02-pdDS-n-z.js +139 -0
  88. package/dist/frontend/assets/kaa-6HZHGXH3-YNdBdcwJ.js +1 -0
  89. package/dist/frontend/assets/kab-KAB-ZGHBKWFO-D86pwZO0.js +8 -0
  90. package/dist/frontend/assets/katex-ChWnQ-fc.js +261 -0
  91. package/dist/frontend/assets/kk-KZ-P5N5QNE5-CpG5oheM.js +1 -0
  92. package/dist/frontend/assets/km-KH-HSX4SM5Z-DYOZ3Azw.js +11 -0
  93. package/dist/frontend/assets/ko-KR-MTYHY66A-BHorm6lC.js +9 -0
  94. package/dist/frontend/assets/ku-TR-6OUDTVRD-CM9RgEHv.js +9 -0
  95. package/dist/frontend/assets/layout-CCtkxrAf.js +1 -0
  96. package/dist/frontend/assets/layout-DW9Qf-At.js +1 -0
  97. package/dist/frontend/assets/line-DvZfgg9P.js +1 -0
  98. package/dist/frontend/assets/linear-FwFrGRfa.js +1 -0
  99. package/dist/frontend/assets/lt-LT-XHIRWOB4-DvriKXBj.js +3 -0
  100. package/dist/frontend/assets/lv-LV-5QDEKY6T-DzQpwk87.js +7 -0
  101. package/dist/frontend/assets/mindmap-definition-ac74a2e8-DsRo8f2w.js +95 -0
  102. package/dist/frontend/assets/mindmap-definition-fc14e90a-dQ9reluI.js +95 -0
  103. package/dist/frontend/assets/mr-IN-CRQNXWMA-C7RzxxP5.js +13 -0
  104. package/dist/frontend/assets/my-MM-5M5IBNSE-B-RRuy29.js +1 -0
  105. package/dist/frontend/assets/nb-NO-T6EIAALU-B47x16Ik.js +10 -0
  106. package/dist/frontend/assets/nl-NL-IS3SIHDZ-BxAKoQne.js +8 -0
  107. package/dist/frontend/assets/nn-NO-6E72VCQL-dfpbEDSZ.js +8 -0
  108. package/dist/frontend/assets/oc-FR-POXYY2M6-gv6geBjV.js +8 -0
  109. package/dist/frontend/assets/ordinal-Cboi1Yqb.js +1 -0
  110. package/dist/frontend/assets/pa-IN-N4M65BXN-CY30-qH7.js +4 -0
  111. package/dist/frontend/assets/path-CbwjOpE9.js +1 -0
  112. package/dist/frontend/assets/pica-DWYGHLQV.js +7 -0
  113. package/dist/frontend/assets/pie-CDiWh1rj.js +1 -0
  114. package/dist/frontend/assets/pieDiagram-421022e6-Bgy-duyf.js +35 -0
  115. package/dist/frontend/assets/pieDiagram-8a3498a8-DH7FsbPK.js +35 -0
  116. package/dist/frontend/assets/pl-PL-T2D74RX3-TrHugsIA.js +9 -0
  117. package/dist/frontend/assets/pt-BR-5N22H2LF-CJxdFp9c.js +9 -0
  118. package/dist/frontend/assets/pt-PT-UZXXM6DQ-CB-1q6YJ.js +9 -0
  119. package/dist/frontend/assets/quadrantDiagram-0957ecba-DcwYI1oi.js +7 -0
  120. package/dist/frontend/assets/quadrantDiagram-120e2f19-CvHU5a9v.js +7 -0
  121. package/dist/frontend/assets/requirementDiagram-23d650b8-tdagN8HP.js +52 -0
  122. package/dist/frontend/assets/requirementDiagram-deff3bca-BMGM-fSI.js +52 -0
  123. package/dist/frontend/assets/ro-RO-JPDTUUEW-DQq9DBOd.js +11 -0
  124. package/dist/frontend/assets/roundRect-0PYZxl1G.js +1 -0
  125. package/dist/frontend/assets/ru-RU-B4JR7IUQ-CWX32rfh.js +9 -0
  126. package/dist/frontend/assets/sankeyDiagram-04a897e0-3i6zWpY2.js +8 -0
  127. package/dist/frontend/assets/sankeyDiagram-23345273-ncj1Ol7S.js +8 -0
  128. package/dist/frontend/assets/sankeyLinkHorizontal-DgqkLiUE.js +1 -0
  129. package/dist/frontend/assets/selectAll-DJwesbwT.js +1 -0
  130. package/dist/frontend/assets/sequenceDiagram-17ac3bff-ChyKKRZA.js +122 -0
  131. package/dist/frontend/assets/sequenceDiagram-704730f1-D57_wP9k.js +122 -0
  132. package/dist/frontend/assets/si-LK-N5RQ5JYF-Lkc5ZxyG.js +1 -0
  133. package/dist/frontend/assets/sk-SK-C5VTKIMK-DyvYXjqZ.js +6 -0
  134. package/dist/frontend/assets/sl-SI-NN7IZMDC-D_MvP9Rh.js +6 -0
  135. package/dist/frontend/assets/stateDiagram-587899a1-OjFTnFLS.js +1 -0
  136. package/dist/frontend/assets/stateDiagram-9c5f0230-BzU36S5C.js +1 -0
  137. package/dist/frontend/assets/stateDiagram-v2-51a3dcff-CfX1qo7U.js +1 -0
  138. package/dist/frontend/assets/stateDiagram-v2-d93cdb3a-BH7Ud4sU.js +1 -0
  139. package/dist/frontend/assets/styles-2ab5d517-CA8x9Nh5.js +116 -0
  140. package/dist/frontend/assets/styles-5f03d8d2-BnO2pLhV.js +160 -0
  141. package/dist/frontend/assets/styles-6aaf32cf-COnot1ea.js +207 -0
  142. package/dist/frontend/assets/styles-9a916d00-C3QkBgTF.js +160 -0
  143. package/dist/frontend/assets/styles-c10674c1-CPAG2_rr.js +116 -0
  144. package/dist/frontend/assets/styles-edf9a4b0-B8Q9fyu0.js +207 -0
  145. package/dist/frontend/assets/subset-shared.chunk.js +84 -0
  146. package/dist/frontend/assets/subset-worker.chunk.js +1 -0
  147. package/dist/frontend/assets/sv-SE-XGPEYMSR-t6voGQSI.js +10 -0
  148. package/dist/frontend/assets/svgDrawCommon-08f97a94-CdT21LWf.js +1 -0
  149. package/dist/frontend/assets/svgDrawCommon-3ba9043b-D1MU7jAE.js +1 -0
  150. package/dist/frontend/assets/ta-IN-2NMHFXQM-7VmfDDyV.js +9 -0
  151. package/dist/frontend/assets/th-TH-HPSO5L25-B5rLEY9P.js +2 -0
  152. package/dist/frontend/assets/timeline-definition-7e6b55e7-BIcL44O_.js +61 -0
  153. package/dist/frontend/assets/timeline-definition-85554ec2-TgrYYwpU.js +61 -0
  154. package/dist/frontend/assets/tr-TR-DEFEU3FU-0CgOHXTn.js +7 -0
  155. package/dist/frontend/assets/uk-UA-QMV73CPH-CzSFsIsx.js +6 -0
  156. package/dist/frontend/assets/union-CnQAJu0l.js +1 -0
  157. package/dist/frontend/assets/vi-VN-M7AON7JQ-Bhx3rYU9.js +5 -0
  158. package/dist/frontend/assets/xml-BOsq7VnW.js +1 -0
  159. package/dist/frontend/assets/xychartDiagram-b6496bcd-BMKDop6v.js +7 -0
  160. package/dist/frontend/assets/xychartDiagram-e933f94c-DAWithrN.js +7 -0
  161. package/dist/frontend/assets/zh-CN-LNUGB5OW-Br52_wH4.js +10 -0
  162. package/dist/frontend/assets/zh-HK-E62DVLB3-Cj6mnIQ9.js +1 -0
  163. package/dist/frontend/assets/zh-TW-RAJ6MFWO-yLEsVBbC.js +9 -0
  164. package/dist/frontend/assets/zipObject-BeXj5PVd.js +1 -0
  165. package/dist/frontend/index.html +339 -0
  166. package/dist/index.d.ts +4 -0
  167. package/dist/index.d.ts.map +1 -0
  168. package/dist/index.js +2305 -0
  169. package/dist/index.js.map +1 -0
  170. package/dist/remote.d.ts +4 -0
  171. package/dist/remote.d.ts.map +1 -0
  172. package/dist/remote.js +133 -0
  173. package/dist/remote.js.map +1 -0
  174. package/dist/server.d.ts +4 -0
  175. package/dist/server.d.ts.map +1 -0
  176. package/dist/server.js +1217 -0
  177. package/dist/server.js.map +1 -0
  178. package/dist/target.d.ts +41 -0
  179. package/dist/target.d.ts.map +1 -0
  180. package/dist/target.js +244 -0
  181. package/dist/target.js.map +1 -0
  182. package/dist/types.d.ts +228 -0
  183. package/dist/types.d.ts.map +1 -0
  184. package/dist/types.js +53 -0
  185. package/dist/types.js.map +1 -0
  186. package/dist/utils/auth.d.ts +15 -0
  187. package/dist/utils/auth.d.ts.map +1 -0
  188. package/dist/utils/auth.js +68 -0
  189. package/dist/utils/auth.js.map +1 -0
  190. package/dist/utils/github.d.ts +26 -0
  191. package/dist/utils/github.d.ts.map +1 -0
  192. package/dist/utils/github.js +111 -0
  193. package/dist/utils/github.js.map +1 -0
  194. package/dist/utils/logger.d.ts +4 -0
  195. package/dist/utils/logger.d.ts.map +1 -0
  196. package/dist/utils/logger.js +25 -0
  197. package/dist/utils/logger.js.map +1 -0
  198. package/dist/utils/r2store.d.ts +19 -0
  199. package/dist/utils/r2store.d.ts.map +1 -0
  200. package/dist/utils/r2store.js +75 -0
  201. package/dist/utils/r2store.js.map +1 -0
  202. package/frontend/index.html +338 -0
  203. package/frontend/src/App.tsx +1091 -0
  204. package/frontend/src/main.tsx +15 -0
  205. package/frontend/src/utils/ghSync.ts +171 -0
  206. package/frontend/src/utils/mermaidConverter.ts +49 -0
  207. package/frontend/src/utils/webmcp.ts +285 -0
  208. package/package.json +101 -0
  209. package/scripts/check-local-bind.mjs +164 -0
  210. package/scripts/postinstall.mjs +23 -0
  211. package/scripts/publish-pages.sh +39 -0
  212. package/scripts/seed-r2.mjs +9 -0
  213. package/skills/excalidraw-skill/SKILL.md +303 -0
  214. package/skills/excalidraw-skill/evals/evals.json +23 -0
  215. package/skills/excalidraw-skill/references/cheatsheet.md +142 -0
  216. package/skills/excalidraw-skill/scripts/clear-canvas.cjs +38 -0
  217. package/skills/excalidraw-skill/scripts/create-element.cjs +68 -0
  218. package/skills/excalidraw-skill/scripts/delete-element.cjs +48 -0
  219. package/skills/excalidraw-skill/scripts/export-elements.cjs +53 -0
  220. package/skills/excalidraw-skill/scripts/healthcheck.cjs +35 -0
  221. package/skills/excalidraw-skill/scripts/import-elements.cjs +81 -0
  222. package/skills/excalidraw-skill/scripts/update-element.cjs +70 -0
  223. package/src/cli.ts +559 -0
  224. package/src/index.ts +2557 -0
  225. package/src/remote.ts +96 -0
  226. package/src/server.ts +1349 -0
  227. package/src/target.ts +208 -0
  228. package/src/types.ts +338 -0
  229. package/src/utils/auth.ts +61 -0
  230. package/src/utils/github.ts +93 -0
  231. package/src/utils/logger.ts +35 -0
  232. package/src/utils/r2store.ts +76 -0
  233. package/tsconfig.json +50 -0
  234. package/vite.config.js +37 -0
@@ -0,0 +1,142 @@
1
+ # Excalidraw Skill Cheatsheet
2
+
3
+ ## Defaults
4
+
5
+ - Canvas base URL: `EXPRESS_SERVER_URL` (default `http://127.0.0.1:3000`)
6
+ - Canvas health: `GET /health`
7
+
8
+ ## MCP Tools (26 total)
9
+
10
+ ### Element CRUD
11
+
12
+ | Tool | Description | Required params |
13
+ |------|-------------|-----------------|
14
+ | `create_element` | Create shape/text/arrow/line | `type`, `x`, `y` |
15
+ | `get_element` | Get single element by ID | `id` |
16
+ | `update_element` | Update element properties | `id` |
17
+ | `delete_element` | Delete element | `id` |
18
+ | `query_elements` | Query by type/filters | (optional) `type`, `filter` |
19
+ | `batch_create_elements` | Create many at once | `elements[]` |
20
+ | `duplicate_elements` | Clone with offset | `elementIds[]`, (optional) `offsetX`, `offsetY` |
21
+
22
+ ### Layout & Organization
23
+
24
+ | Tool | Description | Required params |
25
+ |------|-------------|-----------------|
26
+ | `align_elements` | Align to left/center/right/top/middle/bottom | `elementIds[]`, `alignment` |
27
+ | `distribute_elements` | Even spacing horizontal/vertical | `elementIds[]`, `direction` |
28
+ | `group_elements` | Group elements | `elementIds[]` |
29
+ | `ungroup_elements` | Ungroup | `groupId` |
30
+ | `lock_elements` | Lock elements | `elementIds[]` |
31
+ | `unlock_elements` | Unlock elements | `elementIds[]` |
32
+
33
+ ### Scene Awareness (Iterative Refinement)
34
+
35
+ | Tool | Description | Required params |
36
+ |------|-------------|-----------------|
37
+ | `describe_scene` | AI-readable scene description (types, positions, labels, connections, bounding box) | (none) |
38
+ | `get_canvas_screenshot` | Returns PNG image of canvas for visual verification | (optional) `background` |
39
+ | `get_resource` | Get scene/library/theme/elements | `resource` |
40
+
41
+ ### File I/O & Export
42
+
43
+ | Tool | Description | Required params |
44
+ |------|-------------|-----------------|
45
+ | `export_scene` | Export to .excalidraw JSON | (optional) `filePath` |
46
+ | `import_scene` | Import from .excalidraw JSON | `mode` ("replace"\|"merge"), `filePath` or `data` |
47
+ | `export_to_image` | Export to PNG/SVG (needs browser) | `format` ("png"\|"svg"), (optional) `filePath`, `background` |
48
+ | `export_to_excalidraw_url` | Upload & get shareable excalidraw.com URL | (none) |
49
+
50
+ ### State Management
51
+
52
+ | Tool | Description | Required params |
53
+ |------|-------------|-----------------|
54
+ | `clear_canvas` | Remove all elements | (none) |
55
+ | `snapshot_scene` | Save named snapshot | `name` |
56
+ | `restore_snapshot` | Restore from snapshot | `name` |
57
+
58
+ ### Viewport & Camera
59
+
60
+ | Tool | Description | Required params |
61
+ |------|-------------|-----------------|
62
+ | `set_viewport` | Control camera: zoom-to-fit, center on element, manual zoom/scroll (needs browser) | (optional) `scrollToContent`, `scrollToElementId`, `zoom`, `offsetX`, `offsetY` |
63
+
64
+ ### Design Guide
65
+
66
+ | Tool | Description | Required params |
67
+ |------|-------------|-----------------|
68
+ | `read_diagram_guide` | Get design best practices (colors, sizing, layout, anti-patterns) | (none) |
69
+
70
+ ### Conversion
71
+
72
+ | Tool | Description | Required params |
73
+ |------|-------------|-----------------|
74
+ | `create_from_mermaid` | Mermaid diagram to Excalidraw | `mermaidDiagram` |
75
+
76
+ Notes:
77
+ - **MCP tools**: Set `text` field on shapes to label them (auto-converts to `label.text`). Use `startElementId`/`endElementId` on arrows.
78
+ - **REST API**: Use `"label": {"text": "..."}` for shape labels. Use `"start": {"id": "..."}` / `"end": {"id": "..."}` for arrow binding. (Different format from MCP!)
79
+ - `fontFamily` must be a string (e.g. `"1"`) or omit it entirely — do NOT pass a number.
80
+ - `points` accepts both `[[x,y]]` tuples and `[{x,y}]` objects.
81
+ - **Curved arrows**: Use `"roundness": {"type": 2}` with 3+ points for smooth curves. Use `"elbowed": true` for right-angle routing.
82
+ - Prefer creating shapes first, then arrows, then alignment/grouping.
83
+
84
+ ## Canvas REST API (HTTP)
85
+
86
+ ### Elements
87
+
88
+ | Method | Endpoint | Description |
89
+ |--------|----------|-------------|
90
+ | `GET` | `/api/elements` | List all elements |
91
+ | `GET` | `/api/elements/:id` | Get element by ID |
92
+ | `POST` | `/api/elements` | Create element |
93
+ | `PUT` | `/api/elements/:id` | Update element |
94
+ | `DELETE` | `/api/elements/:id` | Delete element |
95
+ | `DELETE` | `/api/elements/clear` | Clear all elements |
96
+ | `GET` | `/api/elements/search?type=...` | Search with filters |
97
+ | `POST` | `/api/elements/batch` | Batch create |
98
+ | `POST` | `/api/elements/sync` | Overwrite import (clear + write) |
99
+ | `POST` | `/api/elements/from-mermaid` | Mermaid conversion via frontend |
100
+
101
+ ### Export
102
+
103
+ | Method | Endpoint | Description |
104
+ |--------|----------|-------------|
105
+ | `POST` | `/api/export/image` | Request image export (needs frontend) |
106
+ | `POST` | `/api/export/image/result` | Frontend posts export result back |
107
+
108
+ ### Viewport
109
+
110
+ | Method | Endpoint | Description |
111
+ |--------|----------|-------------|
112
+ | `POST` | `/api/viewport` | Set viewport/camera (needs frontend) |
113
+ | `POST` | `/api/viewport/result` | Frontend posts viewport result back |
114
+
115
+ ### Snapshots
116
+
117
+ | Method | Endpoint | Description |
118
+ |--------|----------|-------------|
119
+ | `POST` | `/api/snapshots` | Save snapshot `{name}` |
120
+ | `GET` | `/api/snapshots` | List snapshots |
121
+ | `GET` | `/api/snapshots/:name` | Get snapshot by name |
122
+
123
+ ### System
124
+
125
+ | Method | Endpoint | Description |
126
+ |--------|----------|-------------|
127
+ | `GET` | `/health` | Health check |
128
+ | `GET` | `/api/sync/status` | Memory/WebSocket stats |
129
+
130
+ ## Skill Scripts
131
+
132
+ All scripts accept `--url <canvasUrl>` (defaults to `EXPRESS_SERVER_URL`).
133
+
134
+ ```bash
135
+ node scripts/healthcheck.cjs
136
+ node scripts/clear-canvas.cjs
137
+ node scripts/export-elements.cjs --out diagram.elements.json
138
+ node scripts/import-elements.cjs --in diagram.elements.json --mode batch|sync
139
+ node scripts/create-element.cjs --data '{...}'
140
+ node scripts/update-element.cjs --id <id> --data '{...}'
141
+ node scripts/delete-element.cjs --id <id>
142
+ ```
@@ -0,0 +1,38 @@
1
+ #!/usr/bin/env node
2
+ /* eslint-disable no-console */
3
+
4
+ const DEFAULT_URL = process.env.EXPRESS_SERVER_URL || "http://127.0.0.1:3000";
5
+
6
+ function parseArgs(argv) {
7
+ const out = { url: DEFAULT_URL };
8
+ for (let i = 0; i < argv.length; i++) {
9
+ const a = argv[i];
10
+ if (a === "--url") out.url = argv[++i];
11
+ }
12
+ return out;
13
+ }
14
+
15
+ async function main() {
16
+ if (typeof fetch !== "function") {
17
+ throw new Error("This script requires Node 18+ (global fetch).");
18
+ }
19
+
20
+ const { url } = parseArgs(process.argv.slice(2));
21
+ const baseUrl = url.replace(/\/$/, "");
22
+
23
+ const res = await fetch(`${baseUrl}/api/elements/clear`, {
24
+ method: "DELETE",
25
+ });
26
+
27
+ const json = await res.json().catch(() => null);
28
+ if (!res.ok || !json || json.success !== true) {
29
+ throw new Error(`Failed to clear canvas: ${res.status} ${res.statusText} ${json?.error ? `- ${json.error}` : ""}`);
30
+ }
31
+
32
+ console.log(`Cleared canvas (${json.count} elements removed)`);
33
+ }
34
+
35
+ main().catch((err) => {
36
+ console.error(err?.stack || String(err));
37
+ process.exit(1);
38
+ });
@@ -0,0 +1,68 @@
1
+ #!/usr/bin/env node
2
+ /* eslint-disable no-console */
3
+
4
+ const fs = require("node:fs");
5
+
6
+ const DEFAULT_URL = process.env.EXPRESS_SERVER_URL || "http://127.0.0.1:3000";
7
+
8
+ function usage() {
9
+ console.error(
10
+ [
11
+ "Usage:",
12
+ " node scripts/create-element.cjs (--data <json> | --file <path>) [--url <canvasUrl>]",
13
+ "",
14
+ "Examples:",
15
+ ' node scripts/create-element.cjs --data \'{"type":"rectangle","x":100,"y":100,"width":300,"height":200}\'',
16
+ " node scripts/create-element.cjs --file element.json",
17
+ ].join("\n"),
18
+ );
19
+ process.exit(2);
20
+ }
21
+
22
+ function parseArgs(argv) {
23
+ const out = { url: DEFAULT_URL, data: null, file: null };
24
+ for (let i = 0; i < argv.length; i++) {
25
+ const a = argv[i];
26
+ if (a === "--url") out.url = argv[++i];
27
+ else if (a === "--data") out.data = argv[++i];
28
+ else if (a === "--file") out.file = argv[++i];
29
+ }
30
+ return out;
31
+ }
32
+
33
+ function readJson({ data, file }) {
34
+ if (data) return JSON.parse(data);
35
+ if (file) return JSON.parse(fs.readFileSync(file, "utf8"));
36
+ usage();
37
+ }
38
+
39
+ async function main() {
40
+ if (typeof fetch !== "function") {
41
+ throw new Error("This script requires Node 18+ (global fetch).");
42
+ }
43
+
44
+ const args = parseArgs(process.argv.slice(2));
45
+ const payload = readJson(args);
46
+
47
+ const baseUrl = args.url.replace(/\/$/, "");
48
+ const res = await fetch(`${baseUrl}/api/elements`, {
49
+ method: "POST",
50
+ headers: { "Content-Type": "application/json" },
51
+ body: JSON.stringify(payload),
52
+ });
53
+
54
+ const json = await res.json().catch(() => null);
55
+ if (!res.ok || !json || json.success !== true) {
56
+ throw new Error(
57
+ `Failed to create element: ${res.status} ${res.statusText} ${json?.error ? `- ${json.error}` : ""}`,
58
+ );
59
+ }
60
+
61
+ process.stdout.write(JSON.stringify(json.element, null, 2) + "\n");
62
+ }
63
+
64
+ main().catch((err) => {
65
+ console.error(err?.stack || String(err));
66
+ process.exit(1);
67
+ });
68
+
@@ -0,0 +1,48 @@
1
+ #!/usr/bin/env node
2
+ /* eslint-disable no-console */
3
+
4
+ const DEFAULT_URL = process.env.EXPRESS_SERVER_URL || "http://127.0.0.1:3000";
5
+
6
+ function usage() {
7
+ console.error("Usage: node scripts/delete-element.cjs --id <id> [--url <canvasUrl>]");
8
+ process.exit(2);
9
+ }
10
+
11
+ function parseArgs(argv) {
12
+ const out = { url: DEFAULT_URL, id: null };
13
+ for (let i = 0; i < argv.length; i++) {
14
+ const a = argv[i];
15
+ if (a === "--url") out.url = argv[++i];
16
+ else if (a === "--id") out.id = argv[++i];
17
+ }
18
+ return out;
19
+ }
20
+
21
+ async function main() {
22
+ if (typeof fetch !== "function") {
23
+ throw new Error("This script requires Node 18+ (global fetch).");
24
+ }
25
+
26
+ const args = parseArgs(process.argv.slice(2));
27
+ if (!args.id) usage();
28
+
29
+ const baseUrl = args.url.replace(/\/$/, "");
30
+ const res = await fetch(`${baseUrl}/api/elements/${encodeURIComponent(args.id)}`, {
31
+ method: "DELETE",
32
+ });
33
+
34
+ const json = await res.json().catch(() => null);
35
+ if (!res.ok || !json || json.success !== true) {
36
+ throw new Error(
37
+ `Failed to delete element: ${res.status} ${res.statusText} ${json?.error ? `- ${json.error}` : ""}`,
38
+ );
39
+ }
40
+
41
+ console.log(`Deleted ${args.id}`);
42
+ }
43
+
44
+ main().catch((err) => {
45
+ console.error(err?.stack || String(err));
46
+ process.exit(1);
47
+ });
48
+
@@ -0,0 +1,53 @@
1
+ #!/usr/bin/env node
2
+ /* eslint-disable no-console */
3
+
4
+ const fs = require("node:fs");
5
+ const path = require("node:path");
6
+
7
+ const DEFAULT_URL = process.env.EXPRESS_SERVER_URL || "http://127.0.0.1:3000";
8
+
9
+ function parseArgs(argv) {
10
+ const out = { url: DEFAULT_URL, outFile: null };
11
+ for (let i = 0; i < argv.length; i++) {
12
+ const a = argv[i];
13
+ if (a === "--url") out.url = argv[++i];
14
+ else if (a === "--out") out.outFile = argv[++i];
15
+ else if (a === "-o") out.outFile = argv[++i];
16
+ }
17
+ return out;
18
+ }
19
+
20
+ async function main() {
21
+ if (typeof fetch !== "function") {
22
+ throw new Error("This script requires Node 18+ (global fetch).");
23
+ }
24
+
25
+ const { url, outFile } = parseArgs(process.argv.slice(2));
26
+ const res = await fetch(`${url.replace(/\/$/, "")}/api/elements`);
27
+ const json = await res.json();
28
+
29
+ if (!res.ok || !json || json.success !== true) {
30
+ throw new Error(`Failed to export elements: ${res.status} ${res.statusText}`);
31
+ }
32
+
33
+ const payload = {
34
+ exportedAt: new Date().toISOString(),
35
+ expressServerUrl: url,
36
+ elements: json.elements || [],
37
+ };
38
+
39
+ const text = JSON.stringify(payload, null, 2);
40
+ if (!outFile) {
41
+ process.stdout.write(text + "\n");
42
+ return;
43
+ }
44
+
45
+ fs.mkdirSync(path.dirname(outFile), { recursive: true });
46
+ fs.writeFileSync(outFile, text + "\n");
47
+ console.log(`Wrote ${payload.elements.length} elements to ${outFile}`);
48
+ }
49
+
50
+ main().catch((err) => {
51
+ console.error(err?.stack || String(err));
52
+ process.exit(1);
53
+ });
@@ -0,0 +1,35 @@
1
+ #!/usr/bin/env node
2
+ /* eslint-disable no-console */
3
+
4
+ const DEFAULT_URL = process.env.EXPRESS_SERVER_URL || "http://127.0.0.1:3000";
5
+
6
+ function parseArgs(argv) {
7
+ const out = { url: DEFAULT_URL };
8
+ for (let i = 0; i < argv.length; i++) {
9
+ const a = argv[i];
10
+ if (a === "--url") out.url = argv[++i];
11
+ }
12
+ return out;
13
+ }
14
+
15
+ async function main() {
16
+ if (typeof fetch !== "function") {
17
+ throw new Error("This script requires Node 18+ (global fetch).");
18
+ }
19
+
20
+ const { url } = parseArgs(process.argv.slice(2));
21
+ const res = await fetch(`${url.replace(/\/$/, "")}/health`);
22
+ const text = await res.text();
23
+
24
+ if (!res.ok) {
25
+ console.error(text);
26
+ process.exit(1);
27
+ }
28
+
29
+ console.log(text);
30
+ }
31
+
32
+ main().catch((err) => {
33
+ console.error(err?.stack || String(err));
34
+ process.exit(1);
35
+ });
@@ -0,0 +1,81 @@
1
+ #!/usr/bin/env node
2
+ /* eslint-disable no-console */
3
+
4
+ const fs = require("node:fs");
5
+
6
+ const DEFAULT_URL = process.env.EXPRESS_SERVER_URL || "http://127.0.0.1:3000";
7
+
8
+ function usage() {
9
+ console.error(
10
+ [
11
+ "Usage:",
12
+ " node scripts/import-elements.cjs --in <file> [--mode batch|sync] [--url <canvasUrl>]",
13
+ "",
14
+ "Modes:",
15
+ " batch POST /api/elements/batch (append; creates elements)",
16
+ " sync POST /api/elements/sync (overwrite; clears then writes)",
17
+ ].join("\n"),
18
+ );
19
+ process.exit(2);
20
+ }
21
+
22
+ function parseArgs(argv) {
23
+ const out = { url: DEFAULT_URL, inFile: null, mode: "batch" };
24
+ for (let i = 0; i < argv.length; i++) {
25
+ const a = argv[i];
26
+ if (a === "--url") out.url = argv[++i];
27
+ else if (a === "--in") out.inFile = argv[++i];
28
+ else if (a === "--mode") out.mode = argv[++i];
29
+ }
30
+ return out;
31
+ }
32
+
33
+ function readElementsFromFile(inFile) {
34
+ const raw = fs.readFileSync(inFile, "utf8");
35
+ const data = JSON.parse(raw);
36
+ if (Array.isArray(data)) return data;
37
+ if (data && Array.isArray(data.elements)) return data.elements;
38
+ throw new Error('Input file must be an array, or an object with an "elements" array');
39
+ }
40
+
41
+ async function main() {
42
+ if (typeof fetch !== "function") {
43
+ throw new Error("This script requires Node 18+ (global fetch).");
44
+ }
45
+
46
+ const { url, inFile, mode } = parseArgs(process.argv.slice(2));
47
+ if (!inFile) usage();
48
+ if (mode !== "batch" && mode !== "sync") usage();
49
+
50
+ const elements = readElementsFromFile(inFile);
51
+ const baseUrl = url.replace(/\/$/, "");
52
+
53
+ let endpoint;
54
+ let body;
55
+ if (mode === "batch") {
56
+ endpoint = `${baseUrl}/api/elements/batch`;
57
+ body = { elements };
58
+ } else {
59
+ endpoint = `${baseUrl}/api/elements/sync`;
60
+ body = { elements, timestamp: new Date().toISOString() };
61
+ }
62
+
63
+ const res = await fetch(endpoint, {
64
+ method: "POST",
65
+ headers: { "Content-Type": "application/json" },
66
+ body: JSON.stringify(body),
67
+ });
68
+
69
+ const json = await res.json().catch(() => null);
70
+ if (!res.ok || !json || json.success !== true) {
71
+ throw new Error(`Failed to import elements: ${res.status} ${res.statusText} ${json?.error ? `- ${json.error}` : ""}`);
72
+ }
73
+
74
+ const count = json.count ?? json.elements?.length ?? elements.length;
75
+ console.log(`Imported ${count} elements (${mode})`);
76
+ }
77
+
78
+ main().catch((err) => {
79
+ console.error(err?.stack || String(err));
80
+ process.exit(1);
81
+ });
@@ -0,0 +1,70 @@
1
+ #!/usr/bin/env node
2
+ /* eslint-disable no-console */
3
+
4
+ const fs = require("node:fs");
5
+
6
+ const DEFAULT_URL = process.env.EXPRESS_SERVER_URL || "http://127.0.0.1:3000";
7
+
8
+ function usage() {
9
+ console.error(
10
+ [
11
+ "Usage:",
12
+ " node scripts/update-element.cjs --id <id> (--data <json> | --file <path>) [--url <canvasUrl>]",
13
+ "",
14
+ "Examples:",
15
+ ' node scripts/update-element.cjs --id abc --data \'{"x":200,"y":250,"backgroundColor":"#ffeeee"}\'',
16
+ " node scripts/update-element.cjs --id abc --file updates.json",
17
+ ].join("\n"),
18
+ );
19
+ process.exit(2);
20
+ }
21
+
22
+ function parseArgs(argv) {
23
+ const out = { url: DEFAULT_URL, id: null, data: null, file: null };
24
+ for (let i = 0; i < argv.length; i++) {
25
+ const a = argv[i];
26
+ if (a === "--url") out.url = argv[++i];
27
+ else if (a === "--id") out.id = argv[++i];
28
+ else if (a === "--data") out.data = argv[++i];
29
+ else if (a === "--file") out.file = argv[++i];
30
+ }
31
+ return out;
32
+ }
33
+
34
+ function readJson({ data, file }) {
35
+ if (data) return JSON.parse(data);
36
+ if (file) return JSON.parse(fs.readFileSync(file, "utf8"));
37
+ usage();
38
+ }
39
+
40
+ async function main() {
41
+ if (typeof fetch !== "function") {
42
+ throw new Error("This script requires Node 18+ (global fetch).");
43
+ }
44
+
45
+ const args = parseArgs(process.argv.slice(2));
46
+ if (!args.id) usage();
47
+ const payload = readJson(args);
48
+
49
+ const baseUrl = args.url.replace(/\/$/, "");
50
+ const res = await fetch(`${baseUrl}/api/elements/${encodeURIComponent(args.id)}`, {
51
+ method: "PUT",
52
+ headers: { "Content-Type": "application/json" },
53
+ body: JSON.stringify(payload),
54
+ });
55
+
56
+ const json = await res.json().catch(() => null);
57
+ if (!res.ok || !json || json.success !== true) {
58
+ throw new Error(
59
+ `Failed to update element: ${res.status} ${res.statusText} ${json?.error ? `- ${json.error}` : ""}`,
60
+ );
61
+ }
62
+
63
+ process.stdout.write(JSON.stringify(json.element, null, 2) + "\n");
64
+ }
65
+
66
+ main().catch((err) => {
67
+ console.error(err?.stack || String(err));
68
+ process.exit(1);
69
+ });
70
+