@agent-canvas/cli 0.8.0 → 0.9.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 (199) hide show
  1. package/dist/commands/__tests__/add-arrow.test.d.ts +1 -0
  2. package/dist/commands/__tests__/add-arrow.test.js +186 -0
  3. package/dist/commands/__tests__/add-image.test.d.ts +1 -0
  4. package/dist/commands/__tests__/add-image.test.js +170 -0
  5. package/dist/commands/__tests__/add-line.test.d.ts +1 -0
  6. package/dist/commands/__tests__/add-line.test.js +138 -0
  7. package/dist/commands/__tests__/add-polygon.test.d.ts +1 -0
  8. package/dist/commands/__tests__/add-polygon.test.js +147 -0
  9. package/dist/commands/__tests__/add-shape.test.d.ts +1 -0
  10. package/dist/commands/__tests__/add-shape.test.js +193 -0
  11. package/dist/commands/__tests__/add-text.test.d.ts +1 -0
  12. package/dist/commands/__tests__/add-text.test.js +144 -0
  13. package/dist/commands/__tests__/clear.test.d.ts +1 -0
  14. package/dist/commands/__tests__/clear.test.js +65 -0
  15. package/dist/commands/__tests__/delete-elements.test.d.ts +1 -0
  16. package/dist/commands/__tests__/delete-elements.test.js +103 -0
  17. package/dist/commands/__tests__/export.test.d.ts +1 -0
  18. package/dist/commands/__tests__/export.test.js +187 -0
  19. package/dist/commands/__tests__/group-elements.test.d.ts +1 -0
  20. package/dist/commands/__tests__/group-elements.test.js +93 -0
  21. package/dist/commands/__tests__/list.test.d.ts +1 -0
  22. package/dist/commands/__tests__/list.test.js +134 -0
  23. package/dist/commands/__tests__/load.test.d.ts +1 -0
  24. package/dist/commands/__tests__/load.test.js +158 -0
  25. package/dist/commands/__tests__/move-elements.test.d.ts +1 -0
  26. package/dist/commands/__tests__/move-elements.test.js +117 -0
  27. package/dist/commands/__tests__/new-canvas.test.d.ts +1 -0
  28. package/dist/commands/__tests__/new-canvas.test.js +113 -0
  29. package/dist/commands/__tests__/read.test.d.ts +1 -0
  30. package/dist/commands/__tests__/read.test.js +247 -0
  31. package/dist/commands/__tests__/rename-canvas.test.d.ts +1 -0
  32. package/dist/commands/__tests__/rename-canvas.test.js +86 -0
  33. package/dist/commands/__tests__/resize-elements.test.d.ts +1 -0
  34. package/dist/commands/__tests__/resize-elements.test.js +150 -0
  35. package/dist/commands/__tests__/rotate-elements.test.d.ts +1 -0
  36. package/dist/commands/__tests__/rotate-elements.test.js +114 -0
  37. package/dist/commands/__tests__/save.test.d.ts +1 -0
  38. package/dist/commands/__tests__/save.test.js +105 -0
  39. package/dist/commands/__tests__/ungroup-element.test.d.ts +1 -0
  40. package/dist/commands/__tests__/ungroup-element.test.js +93 -0
  41. package/dist/commands/__tests__/use-canvas.test.d.ts +1 -0
  42. package/dist/commands/__tests__/use-canvas.test.js +86 -0
  43. package/dist/commands/add-arrow.d.ts +40 -0
  44. package/dist/commands/add-arrow.js +52 -0
  45. package/dist/commands/add-image.d.ts +26 -0
  46. package/dist/commands/add-image.js +66 -0
  47. package/dist/commands/add-line.d.ts +27 -0
  48. package/dist/commands/add-line.js +35 -0
  49. package/dist/commands/add-polygon.d.ts +26 -0
  50. package/dist/commands/add-polygon.js +44 -0
  51. package/dist/commands/add-shape.d.ts +32 -0
  52. package/dist/commands/add-shape.js +41 -0
  53. package/dist/commands/add-text.d.ts +28 -0
  54. package/dist/commands/add-text.js +35 -0
  55. package/dist/commands/clear.d.ts +17 -0
  56. package/dist/commands/clear.js +23 -0
  57. package/dist/commands/delete-elements.d.ts +20 -0
  58. package/dist/commands/delete-elements.js +26 -0
  59. package/dist/commands/export.d.ts +26 -0
  60. package/dist/commands/export.js +45 -0
  61. package/dist/commands/group-elements.d.ts +20 -0
  62. package/dist/commands/group-elements.js +28 -0
  63. package/dist/commands/list.d.ts +23 -0
  64. package/dist/commands/list.js +50 -0
  65. package/dist/commands/load.d.ts +20 -0
  66. package/dist/commands/load.js +67 -0
  67. package/dist/commands/move-elements.d.ts +22 -0
  68. package/dist/commands/move-elements.js +26 -0
  69. package/dist/commands/new-canvas.d.ts +21 -0
  70. package/dist/commands/new-canvas.js +29 -0
  71. package/dist/commands/read.d.ts +23 -0
  72. package/dist/commands/read.js +49 -0
  73. package/dist/commands/rename-canvas.d.ts +20 -0
  74. package/dist/commands/rename-canvas.js +27 -0
  75. package/dist/commands/resize-elements.d.ts +24 -0
  76. package/dist/commands/resize-elements.js +41 -0
  77. package/dist/commands/rotate-elements.d.ts +21 -0
  78. package/dist/commands/rotate-elements.js +26 -0
  79. package/dist/commands/save.d.ts +18 -0
  80. package/dist/commands/save.js +27 -0
  81. package/dist/commands/start.d.ts +0 -1
  82. package/dist/commands/start.js +0 -41
  83. package/dist/commands/ungroup-element.d.ts +20 -0
  84. package/dist/commands/ungroup-element.js +28 -0
  85. package/dist/commands/use-canvas.d.ts +20 -0
  86. package/dist/commands/use-canvas.js +27 -0
  87. package/dist/index.js +124 -518
  88. package/dist/lib/__tests__/image-utils.test.d.ts +1 -0
  89. package/dist/lib/__tests__/image-utils.test.js +123 -0
  90. package/dist/lib/__tests__/toon-converter.test.d.ts +1 -0
  91. package/dist/lib/__tests__/toon-converter.test.js +586 -0
  92. package/dist/lib/__tests__/ws-client.test.d.ts +1 -0
  93. package/dist/lib/__tests__/ws-client.test.js +22 -0
  94. package/dist/lib/image-utils.d.ts +3 -0
  95. package/dist/lib/image-utils.js +21 -0
  96. package/dist/lib/protocol.d.ts +24 -0
  97. package/dist/lib/toon-converter.d.ts +104 -0
  98. package/dist/lib/toon-converter.js +221 -0
  99. package/dist/static/assets/{ar-SA-G6X2FPQ2-DrFZc17I.js → ar-SA-G6X2FPQ2-DBOnFzSe.js} +1 -1
  100. package/dist/static/assets/{arc-BE4RRWho.js → arc-bbUtBUEI.js} +1 -1
  101. package/dist/static/assets/{az-AZ-76LH7QW2-DgHo0c8x.js → az-AZ-76LH7QW2-Cc10aZ9u.js} +1 -1
  102. package/dist/static/assets/{bg-BG-XCXSNQG7-D6Qfq7sN.js → bg-BG-XCXSNQG7-Ccf7m1dz.js} +1 -1
  103. package/dist/static/assets/{blockDiagram-38ab4fdb-j4QCKNBJ.js → blockDiagram-38ab4fdb-fpHXuuqC.js} +1 -1
  104. package/dist/static/assets/{bn-BD-2XOGV67Q-DtD_GeTA.js → bn-BD-2XOGV67Q-DUsn1OkS.js} +1 -1
  105. package/dist/static/assets/{c4Diagram-3d4e48cf-BmQ9mE4L.js → c4Diagram-3d4e48cf-R8YUsP4D.js} +1 -1
  106. package/dist/static/assets/{ca-ES-6MX7JW3Y-pqblEVH2.js → ca-ES-6MX7JW3Y-hu4EsJg6.js} +1 -1
  107. package/dist/static/assets/channel-DOejQ6Zr.js +1 -0
  108. package/dist/static/assets/{classDiagram-70f12bd4-CUF5vm_X.js → classDiagram-70f12bd4-Bd-nCoOe.js} +1 -1
  109. package/dist/static/assets/{classDiagram-v2-f2320105-Cpj_A_lB.js → classDiagram-v2-f2320105-BSqlF2Ya.js} +1 -1
  110. package/dist/static/assets/clone-BACvnIVb.js +1 -0
  111. package/dist/static/assets/{createText-2e5e7dd3-pnM7Sebc.js → createText-2e5e7dd3-DDxcRLmM.js} +1 -1
  112. package/dist/static/assets/{cs-CZ-2BRQDIVT-CybzkHZt.js → cs-CZ-2BRQDIVT-CvZtKTE7.js} +1 -1
  113. package/dist/static/assets/{da-DK-5WZEPLOC-pqELhXiQ.js → da-DK-5WZEPLOC-Bo6-ltfA.js} +1 -1
  114. package/dist/static/assets/{de-DE-XR44H4JA-ZL76WiIL.js → de-DE-XR44H4JA-Rki2qM_x.js} +1 -1
  115. package/dist/static/assets/{edges-e0da2a9e-B9extNmC.js → edges-e0da2a9e-DWJxCouB.js} +1 -1
  116. package/dist/static/assets/{el-GR-BZB4AONW-rKEdKItN.js → el-GR-BZB4AONW-BRy2rrt9.js} +1 -1
  117. package/dist/static/assets/{erDiagram-9861fffd-Bf-1lr9-.js → erDiagram-9861fffd-DXldiM4J.js} +1 -1
  118. package/dist/static/assets/{es-ES-U4NZUMDT-BB6riLIk.js → es-ES-U4NZUMDT-hCKbxwHs.js} +1 -1
  119. package/dist/static/assets/{eu-ES-A7QVB2H4-ChqJNrpA.js → eu-ES-A7QVB2H4-CmZGwoa5.js} +1 -1
  120. package/dist/static/assets/{fa-IR-HGAKTJCU--KEd62Xu.js → fa-IR-HGAKTJCU-C6DRPcaF.js} +1 -1
  121. package/dist/static/assets/{fi-FI-Z5N7JZ37-CdB0adCJ.js → fi-FI-Z5N7JZ37-DBaspnIB.js} +1 -1
  122. package/dist/static/assets/{flowDb-956e92f1-Dbca38tY.js → flowDb-956e92f1-C48Cmgvd.js} +1 -1
  123. package/dist/static/assets/{flowDiagram-66a62f08-DpQc0ZQB.js → flowDiagram-66a62f08-DV7f8TtG.js} +1 -1
  124. package/dist/static/assets/flowDiagram-v2-96b9c2cf-MnAxlKb6.js +1 -0
  125. package/dist/static/assets/{flowchart-elk-definition-4a651766-CAxl2EAj.js → flowchart-elk-definition-4a651766-C2muEpzy.js} +1 -1
  126. package/dist/static/assets/{fr-FR-RHASNOE6-LEJbMD3b.js → fr-FR-RHASNOE6-D1dEEEfS.js} +1 -1
  127. package/dist/static/assets/{ganttDiagram-c361ad54-BsKueDb1.js → ganttDiagram-c361ad54-CrooqCzc.js} +1 -1
  128. package/dist/static/assets/{gitGraphDiagram-72cf32ee-BySoTKcT.js → gitGraphDiagram-72cf32ee-x7BVIo_3.js} +1 -1
  129. package/dist/static/assets/{gl-ES-HMX3MZ6V-Bi3P3M7W.js → gl-ES-HMX3MZ6V-Czkw2ahx.js} +1 -1
  130. package/dist/static/assets/{graph-B_0qOa-k.js → graph-Bv0C_szp.js} +1 -1
  131. package/dist/static/assets/{he-IL-6SHJWFNN-DE7_aRwg.js → he-IL-6SHJWFNN-BLwbN3CV.js} +1 -1
  132. package/dist/static/assets/{hi-IN-IWLTKZ5I-CjARmJ8i.js → hi-IN-IWLTKZ5I-BJh3HrXc.js} +1 -1
  133. package/dist/static/assets/{hu-HU-A5ZG7DT2-d79urL5L.js → hu-HU-A5ZG7DT2-D00s-8EN.js} +1 -1
  134. package/dist/static/assets/{id-ID-SAP4L64H-bxo8Q0Jv.js → id-ID-SAP4L64H-BmyuzwXV.js} +1 -1
  135. package/dist/static/assets/{index-3862675e-BLm8h60G.js → index-3862675e-mZlepZqF.js} +1 -1
  136. package/dist/static/assets/{index-BkW4NM9R.js → index-Bnmyv9TE.js} +4 -4
  137. package/dist/static/assets/index-jjzEa4oB.js +316 -0
  138. package/dist/static/assets/{infoDiagram-f8f76790-CZ4J5sjk.js → infoDiagram-f8f76790-w7FUTsVV.js} +1 -1
  139. package/dist/static/assets/{it-IT-JPQ66NNP-D41R3uEK.js → it-IT-JPQ66NNP-CeVq0l8v.js} +1 -1
  140. package/dist/static/assets/{ja-JP-DBVTYXUO-zK8NUJnS.js → ja-JP-DBVTYXUO-BUNKxxGA.js} +1 -1
  141. package/dist/static/assets/{journeyDiagram-49397b02-DtFcZaIk.js → journeyDiagram-49397b02-DYjDqkQG.js} +1 -1
  142. package/dist/static/assets/{kaa-6HZHGXH3-CbGIc6V6.js → kaa-6HZHGXH3-BIKwULqb.js} +1 -1
  143. package/dist/static/assets/{kab-KAB-ZGHBKWFO-BweHPuX1.js → kab-KAB-ZGHBKWFO-BDpRo7IX.js} +1 -1
  144. package/dist/static/assets/{kk-KZ-P5N5QNE5-DSokMm7h.js → kk-KZ-P5N5QNE5-bI2LN3W0.js} +1 -1
  145. package/dist/static/assets/{km-KH-HSX4SM5Z-LYiEs3ge.js → km-KH-HSX4SM5Z-gtwrLJn5.js} +1 -1
  146. package/dist/static/assets/{ko-KR-MTYHY66A-BzgMEtcU.js → ko-KR-MTYHY66A-BVcwVELq.js} +1 -1
  147. package/dist/static/assets/{ku-TR-6OUDTVRD-D1FtjbSs.js → ku-TR-6OUDTVRD-COvDJH7d.js} +1 -1
  148. package/dist/static/assets/{layout-CQWIZrii.js → layout-HBWJ9_zM.js} +1 -1
  149. package/dist/static/assets/{line-BryEd-Ku.js → line-DxrK6d-_.js} +1 -1
  150. package/dist/static/assets/{linear-SXhM57Mz.js → linear-TwnxNDQ0.js} +1 -1
  151. package/dist/static/assets/{lt-LT-XHIRWOB4-BPrhIUrC.js → lt-LT-XHIRWOB4-BxYB7tM6.js} +1 -1
  152. package/dist/static/assets/{lv-LV-5QDEKY6T-CXJse_rs.js → lv-LV-5QDEKY6T-CGURbwyW.js} +1 -1
  153. package/dist/static/assets/{mindmap-definition-fc14e90a-C8giDsiX.js → mindmap-definition-fc14e90a-CWJfWF5a.js} +1 -1
  154. package/dist/static/assets/{mr-IN-CRQNXWMA-Clab-bAO.js → mr-IN-CRQNXWMA-65brZPyQ.js} +1 -1
  155. package/dist/static/assets/{my-MM-5M5IBNSE-Dp08JzEw.js → my-MM-5M5IBNSE-DaCAmQNv.js} +1 -1
  156. package/dist/static/assets/{nb-NO-T6EIAALU-CiaXJA-W.js → nb-NO-T6EIAALU-BiSJhu0W.js} +1 -1
  157. package/dist/static/assets/{nl-NL-IS3SIHDZ-D-9KUTnx.js → nl-NL-IS3SIHDZ-D3rj4Vme.js} +1 -1
  158. package/dist/static/assets/{nn-NO-6E72VCQL-Bg5gsQ4h.js → nn-NO-6E72VCQL-rxxP7Cwf.js} +1 -1
  159. package/dist/static/assets/{oc-FR-POXYY2M6-G4iqllhL.js → oc-FR-POXYY2M6-6emd2NQX.js} +1 -1
  160. package/dist/static/assets/{pa-IN-N4M65BXN-l6Lk41uX.js → pa-IN-N4M65BXN-CXwT_z_m.js} +1 -1
  161. package/dist/static/assets/{pica-CtkejCRD.js → pica-CtyIOuSv.js} +1 -1
  162. package/dist/static/assets/{pieDiagram-8a3498a8-CG6gQ14H.js → pieDiagram-8a3498a8-Ccff4vHz.js} +1 -1
  163. package/dist/static/assets/{pl-PL-T2D74RX3-BZPbB8S3.js → pl-PL-T2D74RX3-DMx_ZmIC.js} +1 -1
  164. package/dist/static/assets/{pt-BR-5N22H2LF-CIC4vRyd.js → pt-BR-5N22H2LF-D9nz7afr.js} +1 -1
  165. package/dist/static/assets/{pt-PT-UZXXM6DQ-rkGTBEI0.js → pt-PT-UZXXM6DQ-DeFH3geX.js} +1 -1
  166. package/dist/static/assets/{quadrantDiagram-120e2f19-BL9eFu4M.js → quadrantDiagram-120e2f19-RF2ZGF1U.js} +1 -1
  167. package/dist/static/assets/{requirementDiagram-deff3bca-crxdUpVK.js → requirementDiagram-deff3bca-CvnD9QLg.js} +1 -1
  168. package/dist/static/assets/{ro-RO-JPDTUUEW-GDhpTKBO.js → ro-RO-JPDTUUEW-Cy22QAjW.js} +1 -1
  169. package/dist/static/assets/{ru-RU-B4JR7IUQ-BzHvMwjC.js → ru-RU-B4JR7IUQ-Cw2rH2nW.js} +1 -1
  170. package/dist/static/assets/{sankeyDiagram-04a897e0-bM05WQw3.js → sankeyDiagram-04a897e0-CWfRjMv0.js} +1 -1
  171. package/dist/static/assets/{sequenceDiagram-704730f1-DjknV0Qp.js → sequenceDiagram-704730f1-pAE8N_Ym.js} +1 -1
  172. package/dist/static/assets/{si-LK-N5RQ5JYF-D3P3TNDH.js → si-LK-N5RQ5JYF-DmXIZ3i0.js} +1 -1
  173. package/dist/static/assets/{sk-SK-C5VTKIMK-CM8yTXlZ.js → sk-SK-C5VTKIMK-CboHDpHd.js} +1 -1
  174. package/dist/static/assets/{sl-SI-NN7IZMDC-CxoGm3aM.js → sl-SI-NN7IZMDC-8XnCHmN4.js} +1 -1
  175. package/dist/static/assets/{stateDiagram-587899a1-CmWqIdF5.js → stateDiagram-587899a1-B4nuLay6.js} +1 -1
  176. package/dist/static/assets/{stateDiagram-v2-d93cdb3a-CgzNTiHW.js → stateDiagram-v2-d93cdb3a-9cMNxr_8.js} +1 -1
  177. package/dist/static/assets/{styles-6aaf32cf-CI4s6NIA.js → styles-6aaf32cf-CynMMkPq.js} +1 -1
  178. package/dist/static/assets/{styles-9a916d00-ZcdN6rtW.js → styles-9a916d00-BTmAnC2j.js} +1 -1
  179. package/dist/static/assets/{styles-c10674c1-ZFkD6ta7.js → styles-c10674c1-DQ_pTuGr.js} +1 -1
  180. package/dist/static/assets/{subset-shared.chunk-B4F4dEPr.js → subset-shared.chunk-DPGuz0R6.js} +1 -1
  181. package/dist/static/assets/{subset-worker.chunk-CmgaOgn3.js → subset-worker.chunk-CMiOYLER.js} +1 -1
  182. package/dist/static/assets/{sv-SE-XGPEYMSR-CnVZlafq.js → sv-SE-XGPEYMSR-ATPKfqXs.js} +1 -1
  183. package/dist/static/assets/{svgDrawCommon-08f97a94-DbN3OiBf.js → svgDrawCommon-08f97a94-qY4BnSWc.js} +1 -1
  184. package/dist/static/assets/{ta-IN-2NMHFXQM-Bl-eCjzL.js → ta-IN-2NMHFXQM-Ct5-Fher.js} +1 -1
  185. package/dist/static/assets/{th-TH-HPSO5L25-CNIGPjSR.js → th-TH-HPSO5L25-5a6bUzcv.js} +1 -1
  186. package/dist/static/assets/{timeline-definition-85554ec2-Cmr82Iq1.js → timeline-definition-85554ec2-Bgexbl3C.js} +1 -1
  187. package/dist/static/assets/{tr-TR-DEFEU3FU-Cx7HbGIA.js → tr-TR-DEFEU3FU-WsK7dnwA.js} +1 -1
  188. package/dist/static/assets/{uk-UA-QMV73CPH-BxcA50Ze.js → uk-UA-QMV73CPH-B_P61mnc.js} +1 -1
  189. package/dist/static/assets/{vi-VN-M7AON7JQ-BvGuRh0c.js → vi-VN-M7AON7JQ-qdiQcney.js} +1 -1
  190. package/dist/static/assets/{xychartDiagram-e933f94c-BcWLDEHu.js → xychartDiagram-e933f94c-vkQjFADD.js} +1 -1
  191. package/dist/static/assets/{zh-CN-LNUGB5OW-SQH8i3l5.js → zh-CN-LNUGB5OW-DQ3BQjPe.js} +1 -1
  192. package/dist/static/assets/{zh-HK-E62DVLB3-COWoLNur.js → zh-HK-E62DVLB3-Ynj07W9J.js} +1 -1
  193. package/dist/static/assets/{zh-TW-RAJ6MFWO-Cm5B69ig.js → zh-TW-RAJ6MFWO-DNkcasuo.js} +1 -1
  194. package/dist/static/index.html +1 -1
  195. package/package.json +5 -2
  196. package/dist/static/assets/channel-DjiT9qJ0.js +0 -1
  197. package/dist/static/assets/clone-nkJpLn4s.js +0 -1
  198. package/dist/static/assets/flowDiagram-v2-96b9c2cf-Dlfh8z7R.js +0 -1
  199. package/dist/static/assets/index-B6CTdFKu.js +0 -311
@@ -0,0 +1,586 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { convertElementsToToon, processTextElement, processLineElement, processShapeElement, processImageElement, buildGroupsFromElements, } from '../toon-converter';
3
+ // Helper to create a minimal SceneElement
4
+ function createElement(overrides) {
5
+ return {
6
+ x: 0,
7
+ y: 0,
8
+ ...overrides,
9
+ };
10
+ }
11
+ describe('toon-converter', () => {
12
+ // ============================================================================
13
+ // convertElementsToToon
14
+ // ============================================================================
15
+ describe('convertElementsToToon', () => {
16
+ it('should return empty result for empty array', () => {
17
+ const result = convertElementsToToon([], false);
18
+ expect(result).toEqual({
19
+ shapes: [],
20
+ lines: [],
21
+ labels: [],
22
+ texts: [],
23
+ images: [],
24
+ groups: [],
25
+ });
26
+ });
27
+ it('should process rectangle element into shapes array', () => {
28
+ const elements = [
29
+ createElement({
30
+ id: 'rect-1',
31
+ type: 'rectangle',
32
+ x: 100,
33
+ y: 200,
34
+ width: 150,
35
+ height: 80,
36
+ }),
37
+ ];
38
+ const result = convertElementsToToon(elements, false);
39
+ expect(result.shapes).toHaveLength(1);
40
+ expect(result.shapes[0]).toEqual({
41
+ id: 'rect-1',
42
+ type: 'rectangle',
43
+ x: 100,
44
+ y: 200,
45
+ w: 150,
46
+ h: 80,
47
+ angle: 0,
48
+ labelId: null,
49
+ note: null,
50
+ });
51
+ });
52
+ it('should process ellipse element into shapes array', () => {
53
+ const elements = [
54
+ createElement({
55
+ id: 'ellipse-1',
56
+ type: 'ellipse',
57
+ x: 50,
58
+ y: 75,
59
+ width: 100,
60
+ height: 60,
61
+ }),
62
+ ];
63
+ const result = convertElementsToToon(elements, false);
64
+ expect(result.shapes).toHaveLength(1);
65
+ expect(result.shapes[0].type).toBe('ellipse');
66
+ });
67
+ it('should process diamond element into shapes array', () => {
68
+ const elements = [
69
+ createElement({
70
+ id: 'diamond-1',
71
+ type: 'diamond',
72
+ x: 0,
73
+ y: 0,
74
+ width: 80,
75
+ height: 80,
76
+ }),
77
+ ];
78
+ const result = convertElementsToToon(elements, false);
79
+ expect(result.shapes).toHaveLength(1);
80
+ expect(result.shapes[0].type).toBe('diamond');
81
+ });
82
+ it('should process standalone text into texts array', () => {
83
+ const elements = [
84
+ createElement({
85
+ id: 'text-1',
86
+ type: 'text',
87
+ x: 10,
88
+ y: 20,
89
+ text: 'Hello World',
90
+ width: 100,
91
+ height: 20,
92
+ }),
93
+ ];
94
+ const result = convertElementsToToon(elements, false);
95
+ expect(result.texts).toHaveLength(1);
96
+ expect(result.texts[0]).toEqual({
97
+ id: 'text-1',
98
+ content: 'Hello World',
99
+ x: 10,
100
+ y: 20,
101
+ w: 100,
102
+ h: 20,
103
+ angle: 0,
104
+ note: null,
105
+ });
106
+ });
107
+ it('should process bound text (with containerId) into labels array', () => {
108
+ const elements = [
109
+ createElement({
110
+ id: 'label-1',
111
+ type: 'text',
112
+ x: 50,
113
+ y: 60,
114
+ text: 'Label Text',
115
+ width: 80,
116
+ height: 16,
117
+ containerId: 'rect-1',
118
+ }),
119
+ ];
120
+ const result = convertElementsToToon(elements, false);
121
+ expect(result.labels).toHaveLength(1);
122
+ expect(result.labels[0]).toEqual({
123
+ id: 'label-1',
124
+ containerId: 'rect-1',
125
+ content: 'Label Text',
126
+ x: 50,
127
+ y: 60,
128
+ w: 80,
129
+ h: 16,
130
+ });
131
+ });
132
+ it('should process line element into lines array', () => {
133
+ const elements = [
134
+ createElement({
135
+ id: 'line-1',
136
+ type: 'line',
137
+ x: 0,
138
+ y: 0,
139
+ points: [[0, 0], [100, 50]],
140
+ }),
141
+ ];
142
+ const result = convertElementsToToon(elements, false);
143
+ expect(result.lines).toHaveLength(1);
144
+ expect(result.lines[0]).toEqual({
145
+ id: 'line-1',
146
+ type: 'line',
147
+ x: 0,
148
+ y: 0,
149
+ endX: 100,
150
+ endY: 50,
151
+ via: null,
152
+ angle: 0,
153
+ note: null,
154
+ });
155
+ });
156
+ it('should process arrow element into lines array with type arrow', () => {
157
+ const elements = [
158
+ createElement({
159
+ id: 'arrow-1',
160
+ type: 'arrow',
161
+ x: 10,
162
+ y: 20,
163
+ points: [[0, 0], [80, 40]],
164
+ }),
165
+ ];
166
+ const result = convertElementsToToon(elements, false);
167
+ expect(result.lines).toHaveLength(1);
168
+ expect(result.lines[0].type).toBe('arrow');
169
+ expect(result.lines[0].endX).toBe(90);
170
+ expect(result.lines[0].endY).toBe(60);
171
+ });
172
+ it('should process closed line (polygon) into shapes array', () => {
173
+ // A closed polygon: points form a triangle that closes back to origin (within 8px)
174
+ const elements = [
175
+ createElement({
176
+ id: 'polygon-1',
177
+ type: 'line',
178
+ x: 100,
179
+ y: 100,
180
+ points: [[0, 0], [50, 0], [25, 40], [0, 0]], // closed triangle
181
+ }),
182
+ ];
183
+ const result = convertElementsToToon(elements, false);
184
+ expect(result.shapes).toHaveLength(1);
185
+ expect(result.shapes[0].type).toBe('polygon');
186
+ expect(result.shapes[0].x).toBe(100);
187
+ expect(result.shapes[0].y).toBe(100);
188
+ expect(result.shapes[0].w).toBe(50);
189
+ expect(result.shapes[0].h).toBe(40);
190
+ });
191
+ it('should process image element into images array', () => {
192
+ const elements = [
193
+ createElement({
194
+ id: 'img-1',
195
+ type: 'image',
196
+ x: 200,
197
+ y: 300,
198
+ width: 400,
199
+ height: 300,
200
+ fileId: 'file-abc123',
201
+ }),
202
+ ];
203
+ const result = convertElementsToToon(elements, false);
204
+ expect(result.images).toHaveLength(1);
205
+ expect(result.images[0]).toEqual({
206
+ id: 'img-1',
207
+ x: 200,
208
+ y: 300,
209
+ w: 400,
210
+ h: 300,
211
+ angle: 0,
212
+ fileId: 'file-abc123',
213
+ note: null,
214
+ });
215
+ });
216
+ it('should collect groups from elements with groupIds', () => {
217
+ const elements = [
218
+ createElement({
219
+ id: 'el-1',
220
+ type: 'rectangle',
221
+ x: 0,
222
+ y: 0,
223
+ groupIds: ['group-A'],
224
+ }),
225
+ createElement({
226
+ id: 'el-2',
227
+ type: 'rectangle',
228
+ x: 100,
229
+ y: 0,
230
+ groupIds: ['group-A'],
231
+ }),
232
+ createElement({
233
+ id: 'el-3',
234
+ type: 'rectangle',
235
+ x: 200,
236
+ y: 0,
237
+ groupIds: ['group-B'],
238
+ }),
239
+ ];
240
+ const result = convertElementsToToon(elements, false);
241
+ expect(result.groups).toHaveLength(2);
242
+ expect(result.groups).toContainEqual({ id: 'group-A', elementIds: 'el-1,el-2' });
243
+ expect(result.groups).toContainEqual({ id: 'group-B', elementIds: 'el-3' });
244
+ });
245
+ it('should include stroke/bg when withStyle=true', () => {
246
+ const elements = [
247
+ createElement({
248
+ id: 'rect-1',
249
+ type: 'rectangle',
250
+ x: 0,
251
+ y: 0,
252
+ strokeColor: '#ff0000',
253
+ backgroundColor: '#00ff00',
254
+ }),
255
+ ];
256
+ const result = convertElementsToToon(elements, true);
257
+ expect(result.shapes[0].stroke).toBe('#ff0000');
258
+ expect(result.shapes[0].bg).toBe('#00ff00');
259
+ });
260
+ it('should not include stroke/bg when withStyle=false', () => {
261
+ const elements = [
262
+ createElement({
263
+ id: 'rect-1',
264
+ type: 'rectangle',
265
+ x: 0,
266
+ y: 0,
267
+ strokeColor: '#ff0000',
268
+ backgroundColor: '#00ff00',
269
+ }),
270
+ ];
271
+ const result = convertElementsToToon(elements, false);
272
+ expect(result.shapes[0]).not.toHaveProperty('stroke');
273
+ expect(result.shapes[0]).not.toHaveProperty('bg');
274
+ });
275
+ it('should convert angle from radians to degrees', () => {
276
+ const elements = [
277
+ createElement({
278
+ id: 'rect-1',
279
+ type: 'rectangle',
280
+ x: 0,
281
+ y: 0,
282
+ angle: Math.PI / 2, // 90 degrees
283
+ }),
284
+ ];
285
+ const result = convertElementsToToon(elements, false);
286
+ expect(result.shapes[0].angle).toBe(90);
287
+ });
288
+ it('should round coordinates to integers', () => {
289
+ const elements = [
290
+ createElement({
291
+ id: 'rect-1',
292
+ type: 'rectangle',
293
+ x: 100.7,
294
+ y: 200.3,
295
+ width: 150.9,
296
+ height: 80.1,
297
+ }),
298
+ ];
299
+ const result = convertElementsToToon(elements, false);
300
+ expect(result.shapes[0].x).toBe(101);
301
+ expect(result.shapes[0].y).toBe(200);
302
+ expect(result.shapes[0].w).toBe(151);
303
+ expect(result.shapes[0].h).toBe(80);
304
+ });
305
+ it('should extract note from customData', () => {
306
+ const elements = [
307
+ createElement({
308
+ id: 'rect-1',
309
+ type: 'rectangle',
310
+ x: 0,
311
+ y: 0,
312
+ customData: { note: 'This is a note' },
313
+ }),
314
+ ];
315
+ const result = convertElementsToToon(elements, false);
316
+ expect(result.shapes[0].note).toBe('This is a note');
317
+ });
318
+ });
319
+ // ============================================================================
320
+ // processTextElement
321
+ // ============================================================================
322
+ describe('processTextElement', () => {
323
+ it('should return label type when containerId is set', () => {
324
+ const el = createElement({
325
+ id: 'text-1',
326
+ type: 'text',
327
+ x: 10,
328
+ y: 20,
329
+ text: 'Label',
330
+ containerId: 'rect-1',
331
+ });
332
+ const result = processTextElement(el, false);
333
+ expect(result.type).toBe('label');
334
+ expect(result.data).toEqual({
335
+ id: 'text-1',
336
+ containerId: 'rect-1',
337
+ content: 'Label',
338
+ x: 10,
339
+ y: 20,
340
+ w: null,
341
+ h: null,
342
+ });
343
+ });
344
+ it('should return text type when containerId is not set', () => {
345
+ const el = createElement({
346
+ id: 'text-1',
347
+ type: 'text',
348
+ x: 10,
349
+ y: 20,
350
+ text: 'Standalone',
351
+ });
352
+ const result = processTextElement(el, false);
353
+ expect(result.type).toBe('text');
354
+ expect(result.data.content).toBe('Standalone');
355
+ });
356
+ it('should include stroke when withStyle=true for text', () => {
357
+ const el = createElement({
358
+ id: 'text-1',
359
+ type: 'text',
360
+ x: 0,
361
+ y: 0,
362
+ text: 'Test',
363
+ strokeColor: '#0000ff',
364
+ });
365
+ const result = processTextElement(el, true);
366
+ expect(result.type).toBe('text');
367
+ expect(result.data.stroke).toBe('#0000ff');
368
+ });
369
+ });
370
+ // ============================================================================
371
+ // processLineElement
372
+ // ============================================================================
373
+ describe('processLineElement', () => {
374
+ it('should return shape type for closed polygon', () => {
375
+ const el = createElement({
376
+ id: 'line-1',
377
+ type: 'line',
378
+ x: 0,
379
+ y: 0,
380
+ points: [[0, 0], [100, 0], [50, 80], [0, 0]],
381
+ });
382
+ const result = processLineElement(el, false);
383
+ expect(result.type).toBe('shape');
384
+ expect(result.data.type).toBe('polygon');
385
+ });
386
+ it('should return line type for open line', () => {
387
+ const el = createElement({
388
+ id: 'line-1',
389
+ type: 'line',
390
+ x: 0,
391
+ y: 0,
392
+ points: [[0, 0], [100, 50]],
393
+ });
394
+ const result = processLineElement(el, false);
395
+ expect(result.type).toBe('line');
396
+ });
397
+ it('should return line type for arrow', () => {
398
+ const el = createElement({
399
+ id: 'arrow-1',
400
+ type: 'arrow',
401
+ x: 0,
402
+ y: 0,
403
+ points: [[0, 0], [100, 50]],
404
+ });
405
+ const result = processLineElement(el, false);
406
+ expect(result.type).toBe('line');
407
+ expect(result.data.type).toBe('arrow');
408
+ });
409
+ it('should calculate via points for multi-point lines', () => {
410
+ const el = createElement({
411
+ id: 'line-1',
412
+ type: 'line',
413
+ x: 10,
414
+ y: 20,
415
+ points: [[0, 0], [50, 25], [100, 50]],
416
+ });
417
+ const result = processLineElement(el, false);
418
+ expect(result.type).toBe('line');
419
+ expect(result.data.via).toBe('60,45');
420
+ });
421
+ it('should return null via for two-point lines', () => {
422
+ const el = createElement({
423
+ id: 'line-1',
424
+ type: 'line',
425
+ x: 0,
426
+ y: 0,
427
+ points: [[0, 0], [100, 50]],
428
+ });
429
+ const result = processLineElement(el, false);
430
+ expect(result.data.via).toBeNull();
431
+ });
432
+ it('should handle line with near-closed points (within 8px) as polygon', () => {
433
+ const el = createElement({
434
+ id: 'line-1',
435
+ type: 'line',
436
+ x: 0,
437
+ y: 0,
438
+ points: [[0, 0], [100, 0], [50, 80], [5, 5]], // last point within 8px of first
439
+ });
440
+ const result = processLineElement(el, false);
441
+ expect(result.type).toBe('shape');
442
+ });
443
+ it('should handle line with points not close enough as line', () => {
444
+ const el = createElement({
445
+ id: 'line-1',
446
+ type: 'line',
447
+ x: 0,
448
+ y: 0,
449
+ points: [[0, 0], [100, 0], [50, 80], [10, 10]], // last point > 8px from first
450
+ });
451
+ const result = processLineElement(el, false);
452
+ expect(result.type).toBe('line');
453
+ });
454
+ });
455
+ // ============================================================================
456
+ // processShapeElement
457
+ // ============================================================================
458
+ describe('processShapeElement', () => {
459
+ it('should process basic shape', () => {
460
+ const el = createElement({
461
+ id: 'rect-1',
462
+ type: 'rectangle',
463
+ x: 100,
464
+ y: 200,
465
+ width: 150,
466
+ height: 80,
467
+ });
468
+ const result = processShapeElement(el, false);
469
+ expect(result).toEqual({
470
+ id: 'rect-1',
471
+ type: 'rectangle',
472
+ x: 100,
473
+ y: 200,
474
+ w: 150,
475
+ h: 80,
476
+ angle: 0,
477
+ labelId: null,
478
+ note: null,
479
+ });
480
+ });
481
+ it('should include labelId when shape has bound text', () => {
482
+ const el = createElement({
483
+ id: 'rect-1',
484
+ type: 'rectangle',
485
+ x: 0,
486
+ y: 0,
487
+ boundElements: [{ id: 'text-1', type: 'text' }],
488
+ });
489
+ const result = processShapeElement(el, false);
490
+ expect(result.labelId).toBe('text-1');
491
+ });
492
+ it('should not include labelId for bound arrows', () => {
493
+ const el = createElement({
494
+ id: 'rect-1',
495
+ type: 'rectangle',
496
+ x: 0,
497
+ y: 0,
498
+ boundElements: [{ id: 'arrow-1', type: 'arrow' }],
499
+ });
500
+ const result = processShapeElement(el, false);
501
+ expect(result.labelId).toBeNull();
502
+ });
503
+ it('should include stroke/bg when withStyle=true', () => {
504
+ const el = createElement({
505
+ id: 'rect-1',
506
+ type: 'rectangle',
507
+ x: 0,
508
+ y: 0,
509
+ strokeColor: '#123456',
510
+ backgroundColor: '#abcdef',
511
+ });
512
+ const result = processShapeElement(el, true);
513
+ expect(result.stroke).toBe('#123456');
514
+ expect(result.bg).toBe('#abcdef');
515
+ });
516
+ });
517
+ // ============================================================================
518
+ // processImageElement
519
+ // ============================================================================
520
+ describe('processImageElement', () => {
521
+ it('should process image element', () => {
522
+ const el = createElement({
523
+ id: 'img-1',
524
+ type: 'image',
525
+ x: 100,
526
+ y: 200,
527
+ width: 400,
528
+ height: 300,
529
+ fileId: 'file-123',
530
+ });
531
+ const result = processImageElement(el);
532
+ expect(result).toEqual({
533
+ id: 'img-1',
534
+ x: 100,
535
+ y: 200,
536
+ w: 400,
537
+ h: 300,
538
+ angle: 0,
539
+ fileId: 'file-123',
540
+ note: null,
541
+ });
542
+ });
543
+ it('should handle missing fileId', () => {
544
+ const el = createElement({
545
+ id: 'img-1',
546
+ type: 'image',
547
+ x: 0,
548
+ y: 0,
549
+ });
550
+ const result = processImageElement(el);
551
+ expect(result.fileId).toBeNull();
552
+ });
553
+ });
554
+ // ============================================================================
555
+ // buildGroupsFromElements
556
+ // ============================================================================
557
+ describe('buildGroupsFromElements', () => {
558
+ it('should return empty array when no groups', () => {
559
+ const elements = [
560
+ createElement({ id: 'el-1', type: 'rectangle', x: 0, y: 0 }),
561
+ ];
562
+ const result = buildGroupsFromElements(elements);
563
+ expect(result).toEqual([]);
564
+ });
565
+ it('should collect elements into groups', () => {
566
+ const elements = [
567
+ createElement({ id: 'el-1', type: 'rectangle', x: 0, y: 0, groupIds: ['g1'] }),
568
+ createElement({ id: 'el-2', type: 'rectangle', x: 0, y: 0, groupIds: ['g1'] }),
569
+ createElement({ id: 'el-3', type: 'rectangle', x: 0, y: 0, groupIds: ['g2'] }),
570
+ ];
571
+ const result = buildGroupsFromElements(elements);
572
+ expect(result).toHaveLength(2);
573
+ expect(result).toContainEqual({ id: 'g1', elementIds: 'el-1,el-2' });
574
+ expect(result).toContainEqual({ id: 'g2', elementIds: 'el-3' });
575
+ });
576
+ it('should handle elements in multiple groups', () => {
577
+ const elements = [
578
+ createElement({ id: 'el-1', type: 'rectangle', x: 0, y: 0, groupIds: ['g1', 'g2'] }),
579
+ ];
580
+ const result = buildGroupsFromElements(elements);
581
+ expect(result).toHaveLength(2);
582
+ expect(result).toContainEqual({ id: 'g1', elementIds: 'el-1' });
583
+ expect(result).toContainEqual({ id: 'g2', elementIds: 'el-1' });
584
+ });
585
+ });
586
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,22 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { generateId } from '../ws-client';
3
+ describe('generateId', () => {
4
+ it('should return a string with reasonable length', () => {
5
+ const id = generateId();
6
+ expect(typeof id).toBe('string');
7
+ // substring(2, 15) produces 11-13 characters depending on random value
8
+ expect(id.length).toBeGreaterThanOrEqual(10);
9
+ expect(id.length).toBeLessThanOrEqual(13);
10
+ });
11
+ it('should return unique IDs', () => {
12
+ const ids = new Set();
13
+ for (let i = 0; i < 100; i++) {
14
+ ids.add(generateId());
15
+ }
16
+ expect(ids.size).toBe(100);
17
+ });
18
+ it('should only contain alphanumeric characters', () => {
19
+ const id = generateId();
20
+ expect(id).toMatch(/^[a-z0-9]+$/);
21
+ });
22
+ });
@@ -0,0 +1,3 @@
1
+ export declare const MAX_IMAGE_SIZE: number;
2
+ export declare function getMimeType(filepath: string): string | null;
3
+ export declare function generateFileId(buffer: Buffer): string;
@@ -0,0 +1,21 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { extname } from 'node:path';
3
+ // Max image file size (2MB) - localStorage has ~5-10MB limit and Base64 adds ~33%
4
+ export const MAX_IMAGE_SIZE = 2 * 1024 * 1024;
5
+ // Helper: Get MIME type from file extension
6
+ export function getMimeType(filepath) {
7
+ const ext = extname(filepath).toLowerCase();
8
+ const mimeTypes = {
9
+ '.png': 'image/png',
10
+ '.jpg': 'image/jpeg',
11
+ '.jpeg': 'image/jpeg',
12
+ '.gif': 'image/gif',
13
+ '.svg': 'image/svg+xml',
14
+ '.webp': 'image/webp',
15
+ };
16
+ return mimeTypes[ext] || null;
17
+ }
18
+ // Helper: Generate FileId from file content (SHA-1 hash)
19
+ export function generateFileId(buffer) {
20
+ return createHash('sha1').update(buffer).digest('hex');
21
+ }
@@ -14,6 +14,7 @@ export interface ListCanvasesResponse {
14
14
  id: string;
15
15
  success: boolean;
16
16
  activeCanvasId?: string;
17
+ agentActiveCanvasId?: string;
17
18
  canvases?: CanvasMetadata[];
18
19
  error?: string;
19
20
  }
@@ -161,6 +162,28 @@ export interface AddPolygonResponse {
161
162
  elementId?: string;
162
163
  error?: string;
163
164
  }
165
+ export interface AddImageParams {
166
+ x: number;
167
+ y: number;
168
+ width?: number;
169
+ height?: number;
170
+ dataUrl: string;
171
+ mimeType: string;
172
+ fileId: string;
173
+ customData?: Record<string, unknown>;
174
+ }
175
+ export interface AddImageResponse {
176
+ type: 'addImageResult';
177
+ id: string;
178
+ success: boolean;
179
+ elementId?: string;
180
+ fileId?: string;
181
+ x?: number;
182
+ y?: number;
183
+ width?: number;
184
+ height?: number;
185
+ error?: string;
186
+ }
164
187
  export interface DeleteElementsParams {
165
188
  elementIds: string[];
166
189
  }
@@ -249,6 +272,7 @@ export interface SceneElement {
249
272
  points?: number[][];
250
273
  startArrowhead?: string | null;
251
274
  endArrowhead?: string | null;
275
+ fileId?: string | null;
252
276
  customData?: Record<string, unknown>;
253
277
  }
254
278
  export interface ReadSceneResponse {