collabmd 0.1.48 → 0.1.49

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 (268) hide show
  1. package/README.md +61 -5
  2. package/bin/collabmd.js +3 -0
  3. package/dist/client/assets/CodeMirrorEditor-UCMRAMCV-C-nmgL5g.js +1 -0
  4. package/dist/client/assets/abnfDiagram-VCTEODGH-CdVZqicp.js +1 -0
  5. package/dist/client/assets/{architectureDiagram-5GKGNRK7-I39sYjHI.js → architectureDiagram-5GKGNRK7-wUo0bXif.js} +3 -3
  6. package/dist/client/assets/{blockDiagram-NRAW4CY4-C6DtJy5Y.js → blockDiagram-I7D4REHJ-BRSK3m49.js} +4 -4
  7. package/dist/client/assets/browser-utils-DbXSMI-6.js +1 -0
  8. package/dist/client/assets/{c4Diagram-UCG6FXSJ-CtWtxS9_.js → c4Diagram-7LVT6UL2-yD2poxqw.js} +1 -1
  9. package/dist/client/assets/channel-Fa4GS_-F.js +1 -0
  10. package/dist/client/assets/chunk-2E4U76K2-BPnTT-J3.js +2 -0
  11. package/dist/client/assets/{chunk-TEH6E4GO-DVayPj-q.js → chunk-4HAMMTFA-DStbIfJ1.js} +20 -20
  12. package/dist/client/assets/{chunk-75Z2AOVW-CdFSaPjz.js → chunk-75Z2AOVW-C5pGd3W9.js} +1 -1
  13. package/dist/client/assets/{chunk-CLGD4ZFX-DQLgbQrv.js → chunk-CLGD4ZFX-BMeArk03.js} +1 -1
  14. package/dist/client/assets/chunk-DU6HZSFF-Zkp69c6c.js +127 -0
  15. package/dist/client/assets/{chunk-F27PBJKO-CNHIFhjo.js → chunk-F27PBJKO-D4xNct1r.js} +1 -1
  16. package/dist/client/assets/{chunk-GMAD6QVW-CbcBqPM5.js → chunk-GMAD6QVW-NZ6WpDb8.js} +1 -1
  17. package/dist/client/assets/{chunk-OBVCFTLP-BJR7u1jh.js → chunk-GVQU2GXP-D8SDprfX.js} +1 -1
  18. package/dist/client/assets/{chunk-G27WJ6UU-D9-eg537.js → chunk-IMKFNOWR-D8jEuU3Q.js} +2 -2
  19. package/dist/client/assets/{chunk-JQ64N6SF-DSFNH4bh.js → chunk-L3NEJ4N5-aijKP-eh.js} +1 -1
  20. package/dist/client/assets/chunk-OSK3NFVY-CCbLQAMa.js +10 -0
  21. package/dist/client/assets/{chunk-P2QGCYS3-BRpqY32H.js → chunk-P2QGCYS3-Oag_FdCq.js} +1 -1
  22. package/dist/client/assets/{chunk-POPQ4Y6H-Cb4SlVZF.js → chunk-POPQ4Y6H-CYnpIgXT.js} +1 -1
  23. package/dist/client/assets/{chunk-PWAF6VOD-Cz8IwBB5.js → chunk-PWAF6VOD-JSNrcBmP.js} +1 -1
  24. package/dist/client/assets/{chunk-RM4UPSZO-CWRwxNWJ.js → chunk-RM4UPSZO-DOWllDY8.js} +4 -4
  25. package/dist/client/assets/{chunk-RHFEMEQ7-CWY8cf4H.js → chunk-SHT3W25Y-BiQGljao.js} +5 -5
  26. package/dist/client/assets/{chunk-SVP7TREG-CyHOmcac.js → chunk-SVP7TREG-DB485R5x.js} +1 -1
  27. package/dist/client/assets/{chunk-LCL6LL3I-DmDkVukh.js → chunk-TICWLB2K-8rAVvoS3.js} +4 -4
  28. package/dist/client/assets/{chunk-CKBBP62Z-DG26UiBv.js → chunk-TLUHSLCS-DTY5v0aj.js} +2 -2
  29. package/dist/client/assets/classDiagram-ZZMXUADV-BsQWoR3Q.js +1 -0
  30. package/dist/client/assets/classDiagram-v2-VYDZK3BY-BsQWoR3Q.js +1 -0
  31. package/dist/client/assets/{comment-thread-store-CdcwrObc.js → comment-thread-store-CX98zR6q.js} +1 -1
  32. package/dist/client/assets/comment-threads-BnRwo5B9.js +4 -0
  33. package/dist/client/assets/{cynefinDiagram-5FMLGOSQ-CdTPi2yO.js → cynefinDiagram-5FMLGOSQ-rTz9RhFH.js} +1 -1
  34. package/dist/client/assets/{dagre-3AP2YEHR-5gtJtd0O.js → dagre-GXQ25YYZ-Cr67wLpQ.js} +2 -2
  35. package/dist/client/assets/{diagram-S7CK7UJ4-BudWz9WU.js → diagram-S7CK7UJ4-DywERe__.js} +2 -2
  36. package/dist/client/assets/{diagram-UQ7AKVKN-3v4rbH-s.js → diagram-UQ7AKVKN-CNYlXtu4.js} +1 -1
  37. package/dist/client/assets/diagram-VSXAHHWV-0H1a61Bn.js +3 -0
  38. package/dist/client/assets/{diagram-VX7I27RA-C_-rj0sw.js → diagram-VX7I27RA-CsJbsx5F.js} +1 -1
  39. package/dist/client/assets/{diagram-Z3DM3KII-B4yxavgj.js → diagram-Z3DM3KII-D0mLxEgI.js} +1 -1
  40. package/dist/client/assets/dist--hk9I5HQ.js +1 -0
  41. package/dist/client/assets/{dist-DutPuFmC.js → dist-B1XEa-Zs.js} +1 -1
  42. package/dist/client/assets/dist-Bd1JucQF.js +1 -0
  43. package/dist/client/assets/{dist-DZAAWTG-.js → dist-C0G3AaXG.js} +1 -1
  44. package/dist/client/assets/dist-Dm4w5UId.js +1 -0
  45. package/dist/client/assets/{dist-B_yQaEv_.js → dist-DpYDHR9p.js} +1 -1
  46. package/dist/client/assets/{dist-CietwTVS.js → dist-DzNmC81X.js} +1 -1
  47. package/dist/client/assets/{dist-DDUn5zTz.js → dist-GvvCNBe4.js} +1 -1
  48. package/dist/client/assets/dist-JaU3aRlD.js +19 -0
  49. package/dist/client/assets/{dist-Bw3VIE_v.js → dist-TW8iFRyW.js} +1 -1
  50. package/dist/client/assets/{dist-Dir5dDKZ.js → dist-jVU5Be5P.js} +1 -1
  51. package/dist/client/assets/document-formatter-rDDjRfZ2.js +2 -0
  52. package/dist/client/assets/drawioEditor-JubEEha7.js +9 -0
  53. package/dist/client/assets/ebnfDiagram-PWID7BFC-HeTxHpCU.js +1 -0
  54. package/dist/client/assets/editor-session-Bk6oIvSr.js +54 -0
  55. package/dist/client/assets/{embedded-editor-base-B3l6Xy65.css → embedded-editor-base-BlCgz6mw.css} +1 -1
  56. package/dist/client/assets/{erDiagram-SSCWMZ5O-C-iy6VkX.js → erDiagram-RLTQ6QDP-CbrDdd5P.js} +2 -2
  57. package/dist/client/assets/{vault-utils-DvoSftJT.js → es-Bfdp096f.js} +13 -13
  58. package/dist/client/assets/excalidraw-element-link-YLIaTnVF.js +7 -0
  59. package/dist/client/assets/{excalidraw-scene-BOben2gr.js → excalidraw-scene-6uROebca.js} +1 -1
  60. package/dist/client/assets/excalidrawEditor-dBMbRX_S.js +9 -0
  61. package/dist/client/assets/export-page-CRRQ2NEl.js +57 -0
  62. package/dist/client/assets/exportDocument-BlQRd9_m.js +2 -0
  63. package/dist/client/assets/exportDocument-CNSbjZwu.css +1 -0
  64. package/dist/client/assets/flowDiagram-HODETNUW-D5Gy0wmg.js +1 -0
  65. package/dist/client/assets/{ganttDiagram-EL5Y4UJY-DtKHAbez.js → ganttDiagram-EL5Y4UJY-BHgOYiZz.js} +1 -1
  66. package/dist/client/assets/{gitGraphDiagram-WWUBYQGX-oue8fQ5o.js → gitGraphDiagram-WWUBYQGX-Dl__X3Sk.js} +1 -1
  67. package/dist/client/assets/image-ZVKINSPA-DgzW5zAy.js +1 -0
  68. package/dist/client/assets/index-D3RER1SZ.js +1023 -0
  69. package/dist/client/assets/index-DREVKl_K.css +1 -0
  70. package/dist/client/assets/{infoDiagram-RXCK75RN-BMzo6KIn.js → infoDiagram-27XIBGKW-DBpoANC9.js} +1 -1
  71. package/dist/client/assets/{ishikawaDiagram-5VMMS53U-BIM3h287.js → ishikawaDiagram-5VMMS53U-BMPC6hfp.js} +1 -1
  72. package/dist/client/assets/{journeyDiagram-EYS64GPL-mF6Lh8O-.js → journeyDiagram-3NMN7TZE-B1sApUmM.js} +2 -2
  73. package/dist/client/assets/{kanban-definition-3QL26DDD-DLN2NyoR.js → kanban-definition-UXKFOSKX-C9yP4td1.js} +4 -4
  74. package/dist/client/assets/{line-BfTWJmgf.js → line-BFl3ujec.js} +1 -1
  75. package/dist/client/assets/mermaid.core-BrY09czX.js +11 -0
  76. package/dist/client/assets/mermaid.core-DfcNfOTv.js +1 -0
  77. package/dist/client/assets/{mindmap-definition-FBJOCRG2-CRyHaHTk.js → mindmap-definition-YA3MSWOX-BUQHcYbK.js} +8 -8
  78. package/dist/client/assets/pegDiagram-XKGWAZYB-Bi2Iml7Z.js +1 -0
  79. package/dist/client/assets/{pieDiagram-E7YTZNPT-B5OZPb88.js → pieDiagram-E7YTZNPT-_gYXnMoi.js} +1 -1
  80. package/dist/client/assets/preview-render-compiler-CfxJYldJ.js +41 -0
  81. package/dist/client/assets/preview-render-compiler-Cu8_i9iS.js +1 -0
  82. package/dist/client/assets/{preview-render-worker-_QTxqKvP.js → preview-render-worker-c4Yi93qW.js} +41 -35
  83. package/dist/client/assets/prod-BiJL30sl.js +1 -0
  84. package/dist/client/assets/prod-qAk7rHa4.js +177 -0
  85. package/dist/client/assets/{quadrantDiagram-AXDQQJYC-Drrw14YH.js → quadrantDiagram-AXDQQJYC-DwexhEhd.js} +1 -1
  86. package/dist/client/assets/quick-switcher-controller-BoIK_wuG.js +1 -0
  87. package/dist/client/assets/railroadDiagram-O6MQD6OU-BVA5UbMu.js +1 -0
  88. package/dist/client/assets/{requirementDiagram-EFPCY7ZU-CRZG6mRB.js → requirementDiagram-BXWQKSXE-C4cKwiIw.js} +2 -2
  89. package/dist/client/assets/runtime-config-DcmnGcXU.js +1 -0
  90. package/dist/client/assets/{sankeyDiagram-P5KCCOFB-DvarEJpo.js → sankeyDiagram-P5KCCOFB-B5HHkRT2.js} +1 -1
  91. package/dist/client/assets/{sequenceDiagram-WJ2MYXX4-B4oWlb-w.js → sequenceDiagram-WJ2MYXX4-BX6jqJFD.js} +6 -6
  92. package/dist/client/assets/{stateDiagram-HBIQ2CUA-qbHIIqRZ.js → stateDiagram-D77RDMKH-CmqxyRGx.js} +1 -1
  93. package/dist/client/assets/stateDiagram-v2-MP3YSRHH-zoLLQVyh.js +1 -0
  94. package/dist/client/assets/{swimlanes-XN3QIQJK-xB6CtUGj.js → swimlanes-42K2YHIH-Bmgb9Zld.js} +1 -1
  95. package/dist/client/assets/swimlanesDiagram-VR7AAH4N-DS-KQN37.js +8 -0
  96. package/dist/client/assets/{timeline-definition-24CTP7MA-Lj_yTNlY.js → timeline-definition-24CTP7MA-BA-lVH6P.js} +1 -1
  97. package/dist/client/assets/vault-api-client-iZLhMJKe.js +6 -0
  98. package/dist/client/assets/{vennDiagram-4TSXK5OY-BekRp5Y0.js → vennDiagram-4TSXK5OY-DNdUC_Xj.js} +1 -1
  99. package/dist/client/assets/{wardleyDiagram-VM6X3IG4-kdnV_Hdm.js → wardleyDiagram-VM6X3IG4-C2oY-YbF.js} +1 -1
  100. package/dist/client/assets/wiki-link-resolver-DFIwErjc.js +1 -0
  101. package/dist/client/assets/{xychartDiagram-S5SC5T6Z-DufGwNSB.js → xychartDiagram-S5SC5T6Z-CoIR8CBX.js} +1 -1
  102. package/dist/client/assets/{yjs-provider-reset-guard-DE0vINDP.js → yjs-provider-reset-guard-9ul1qF6k.js} +1 -1
  103. package/dist/client/drawio-editor.html +11 -3
  104. package/dist/client/excalidraw-editor.html +45 -2
  105. package/dist/client/export-document.html +3 -3
  106. package/dist/client/index.html +67 -35
  107. package/integrations/pi/index.ts +94 -0
  108. package/package.json +41 -32
  109. package/src/client/app/drawio-editor.html +2 -2
  110. package/src/client/app/excalidraw-editor.html +2 -2
  111. package/src/client/app/export-document.html +1 -1
  112. package/src/client/app/index.html +49 -33
  113. package/src/client/app/main-entry.js +15 -1
  114. package/src/client/application/app-shell/chat-feature.js +7 -22
  115. package/src/client/application/app-shell/git-feature.js +23 -5
  116. package/src/client/application/app-shell/presence-feature.js +8 -25
  117. package/src/client/application/app-shell/ui-feature-shell.js +36 -91
  118. package/src/client/application/app-shell/ui-feature-sidebar.js +43 -7
  119. package/src/client/application/app-shell/ui-feature-tab-activity.js +19 -6
  120. package/src/client/application/app-shell/ui-feature-toolbar.js +16 -129
  121. package/src/client/application/app-shell-elements.js +4 -0
  122. package/src/client/application/preview-render-compiler.js +1 -87
  123. package/src/client/application/preview-render-scheduler.js +8 -24
  124. package/src/client/application/preview-renderer.js +2 -2
  125. package/src/client/application/webmcp-diagram-renderer.js +47 -0
  126. package/src/client/application/workspace-coordinator.js +3 -1
  127. package/src/client/application/workspace-route-controller.js +7 -0
  128. package/src/client/bootstrap/collabmd-app-shell.js +78 -1
  129. package/src/client/domain/excalidraw-element-link.js +73 -0
  130. package/src/client/domain/excalidraw-scene.js +21 -0
  131. package/src/client/domain/hash-routes.js +8 -0
  132. package/src/client/domain/room.js +1 -5
  133. package/src/client/domain/runtime-paths.js +5 -0
  134. package/src/client/excalidraw-editor.js +135 -10
  135. package/src/client/export/export-host.js +3 -1
  136. package/src/client/export/export-pipeline.js +4 -17
  137. package/src/client/infrastructure/agent-connection-api-client.js +23 -0
  138. package/src/client/infrastructure/auth-client.js +3 -13
  139. package/src/client/infrastructure/editor-session.js +11 -0
  140. package/src/client/infrastructure/editor-view-adapter.js +13 -0
  141. package/src/client/infrastructure/excalidraw-room-client.js +80 -1
  142. package/src/client/infrastructure/git-api-client.js +39 -33
  143. package/src/client/infrastructure/lobby-presence.js +2 -5
  144. package/src/client/infrastructure/runtime-config.js +11 -1
  145. package/src/client/infrastructure/tab-activity-lock.js +2 -5
  146. package/src/client/infrastructure/vault-api-client.js +33 -26
  147. package/src/client/infrastructure/webmcp-tool-registry.js +283 -0
  148. package/src/client/infrastructure/workspace-sync-client.js +6 -4
  149. package/src/client/presentation/agent-connection-controller.js +255 -0
  150. package/src/client/presentation/backlinks-panel.js +3 -0
  151. package/src/client/presentation/bases-preview-controller.js +27 -18
  152. package/src/client/presentation/comment-ui/comment-ui-card.js +4 -2
  153. package/src/client/presentation/create-menu-presenter.js +19 -16
  154. package/src/client/presentation/excalidraw-embed-controller.js +164 -4
  155. package/src/client/presentation/file-explorer-view.js +70 -12
  156. package/src/client/presentation/file-history-view-controller.js +13 -11
  157. package/src/client/presentation/git-diff-view-controller.js +35 -43
  158. package/src/client/presentation/git-panel-controller.js +77 -27
  159. package/src/client/presentation/image-lightbox-controller.js +20 -16
  160. package/src/client/presentation/layout-controller.js +3 -1
  161. package/src/client/presentation/quick-switcher-controller.js +20 -78
  162. package/src/client/presentation/quick-switcher-text-search.js +10 -14
  163. package/src/client/styles/components/navigation.css +1 -2
  164. package/src/client/styles/features/agent-connection.css +202 -0
  165. package/src/client/styles/features/collaboration-chat.css +8 -1
  166. package/src/client/styles/features/collaboration-dialogs.css +16 -1
  167. package/src/client/styles/features/collaboration-presence.css +17 -4
  168. package/src/client/styles/features/diff-toolbar.css +1 -1
  169. package/src/client/styles/features/media-lightbox.css +12 -3
  170. package/src/client/styles/features/quick-switcher.css +20 -11
  171. package/src/client/styles/foundation/themes.css +2 -0
  172. package/src/client/styles/layout/editor-page.css +25 -11
  173. package/src/client/styles/layout/responsive.css +2 -20
  174. package/src/client/styles/layout/shell.css +1 -0
  175. package/src/client/styles/layout/sidebar.css +7 -4
  176. package/src/client/styles/primitives/controls.css +21 -54
  177. package/src/client/styles/style.css +1 -0
  178. package/src/domain/agent-tool-definitions.js +796 -0
  179. package/src/domain/collabmd-content-capabilities.js +149 -0
  180. package/src/domain/collaboration-protocol.js +2 -0
  181. package/src/domain/comment-threads.js +3 -5
  182. package/src/domain/diagram-source.js +50 -0
  183. package/src/domain/editable-content-revision.js +10 -0
  184. package/src/domain/editable-text.js +3 -0
  185. package/src/domain/exact-text-edits.js +69 -0
  186. package/src/domain/excalidraw-agent-scene.js +522 -0
  187. package/src/domain/excalidraw-agent-verification.js +460 -0
  188. package/src/domain/excalidraw-room-codec.js +1 -5
  189. package/src/domain/video-embed.js +76 -0
  190. package/src/server/application/agent-connection-service.js +178 -0
  191. package/src/server/application/agent-content-service.js +773 -0
  192. package/src/server/application/workspace-reconciliation.js +5 -7
  193. package/src/server/config/env.js +51 -1
  194. package/src/server/create-app-server.js +36 -0
  195. package/src/server/domain/bases/base-query-service.js +1 -5
  196. package/src/server/domain/collaboration/collaboration-room.js +121 -25
  197. package/src/server/domain/collaboration/protocol.js +4 -0
  198. package/src/server/domain/hosted-workspace.js +21 -0
  199. package/src/server/domain/markdown-reference-extractor.js +15 -1
  200. package/src/server/infrastructure/git/git-service.js +19 -1
  201. package/src/server/infrastructure/git/history-service.js +1 -1
  202. package/src/server/infrastructure/git/local-exclude.js +25 -0
  203. package/src/server/infrastructure/git/parsers.js +19 -17
  204. package/src/server/infrastructure/git/path-utils.js +0 -16
  205. package/src/server/infrastructure/git/status-service.js +1 -1
  206. package/src/server/infrastructure/git/untracked-files.js +12 -21
  207. package/src/server/infrastructure/http/create-agent-api-handler.js +171 -0
  208. package/src/server/infrastructure/http/create-git-api-command-handler.js +32 -0
  209. package/src/server/infrastructure/http/create-request-handler.js +28 -0
  210. package/src/server/infrastructure/http/create-static-handler.js +6 -0
  211. package/src/server/infrastructure/mcp/create-agent-mcp-handler.js +199 -0
  212. package/src/server/infrastructure/persistence/agent-connection-store.js +120 -0
  213. package/src/server/infrastructure/persistence/pull-backup-store.js +2 -27
  214. package/src/server/infrastructure/persistence/vault-file-store.js +9 -2
  215. package/src/server/shared/agent-tool-image.js +22 -0
  216. package/src/server/shared/agent-tool-rate-limiter.js +20 -0
  217. package/src/server/startup/git-remote-bootstrap.js +5 -33
  218. package/dist/client/assets/CodeMirrorEditor-UCMRAMCV-BPH4FJkv.js +0 -1
  219. package/dist/client/assets/abnfDiagram-VCTEODGH-BNDLzJ7L.js +0 -1
  220. package/dist/client/assets/browser-utils--H_DkyEF.js +0 -1
  221. package/dist/client/assets/channel-CaoKA_We.js +0 -1
  222. package/dist/client/assets/chunk-DSNCTWBM-8xkug7fQ.js +0 -2
  223. package/dist/client/assets/chunk-DU6HZSFF-COXDzJK1.js +0 -127
  224. package/dist/client/assets/chunk-R7TYR2AO-CTd0Yj98.js +0 -10
  225. package/dist/client/assets/classDiagram-DTDB5LWJ-7fEmn0zV.js +0 -1
  226. package/dist/client/assets/classDiagram-v2-JRS7N3AN-7fEmn0zV.js +0 -1
  227. package/dist/client/assets/comment-threads-9J6Em-_y.js +0 -4
  228. package/dist/client/assets/comment-ui-shared-DuoyznXW.js +0 -7
  229. package/dist/client/assets/diagram-VSXAHHWV-CQRVEZR7.js +0 -3
  230. package/dist/client/assets/dist-73RPdcyU.js +0 -1
  231. package/dist/client/assets/dist-CH-sQu3r.js +0 -1
  232. package/dist/client/assets/document-formatter-Dxl_a8XO.js +0 -2
  233. package/dist/client/assets/drawio-editor-BVaNNtYp.js +0 -9
  234. package/dist/client/assets/drawioEditor-BkIBlXx0.js +0 -2
  235. package/dist/client/assets/ebnfDiagram-PWID7BFC-OXa8VEp1.js +0 -1
  236. package/dist/client/assets/editor-session-DMyVdHLj.js +0 -54
  237. package/dist/client/assets/excalidraw-editor-BjYaNEMY.js +0 -9
  238. package/dist/client/assets/excalidraw-mermaid-stub-BNckbX2n.js +0 -1
  239. package/dist/client/assets/excalidraw-mermaid-stub-DE5FTiZB.js +0 -1
  240. package/dist/client/assets/excalidrawEditor-ChqF_d82.js +0 -2
  241. package/dist/client/assets/export-page-Dyu0XCbu.js +0 -57
  242. package/dist/client/assets/exportDocument-CJBx4Xjx.css +0 -1
  243. package/dist/client/assets/exportDocument-Dgvfa2Sd.js +0 -2
  244. package/dist/client/assets/flowDiagram-A5DVABFB-CiW1eN8C.js +0 -1
  245. package/dist/client/assets/image-ZVKINSPA-0zXSnE7M.js +0 -1
  246. package/dist/client/assets/index-CSNIMyOP.css +0 -1
  247. package/dist/client/assets/index-DG3N2Ps-.js +0 -2
  248. package/dist/client/assets/main-D0wCxpVn.js +0 -903
  249. package/dist/client/assets/mermaid.core-BJRLUQZE.js +0 -11
  250. package/dist/client/assets/pegDiagram-XKGWAZYB-B31fKPR2.js +0 -1
  251. package/dist/client/assets/preview-render-compiler-CrJIooVD.js +0 -35
  252. package/dist/client/assets/preview-render-compiler-O0JxBVNF.js +0 -1
  253. package/dist/client/assets/preview-render-profile-B4RWYWHt.js +0 -1
  254. package/dist/client/assets/prod-BiYPMR1i.js +0 -177
  255. package/dist/client/assets/prod-VxdGZ5Ly.js +0 -1
  256. package/dist/client/assets/quick-switcher-controller-CaEjEtq_.js +0 -1
  257. package/dist/client/assets/railroadDiagram-O6MQD6OU-BPifP0MB.js +0 -1
  258. package/dist/client/assets/runtime-config-BLrEKVO1.js +0 -1
  259. package/dist/client/assets/stateDiagram-v2-4QOOHH4V-B--gjrit.js +0 -1
  260. package/dist/client/assets/swimlanesDiagram-VK2B7HYN-DO8XNXEg.js +0 -8
  261. package/dist/client/assets/vault-api-client-BkwdFjx0.js +0 -6
  262. package/src/client/app/drawio-editor-entry.js +0 -1
  263. package/src/client/app/excalidraw-editor-entry.js +0 -1
  264. package/src/client/excalidraw-mermaid-stub.js +0 -7
  265. package/src/client/main.js +0 -16
  266. /package/dist/client/assets/{drawio-editor-UQQ8XHou.css → drawioEditor-UQQ8XHou.css} +0 -0
  267. /package/dist/client/assets/{excalidraw-editor-BbSbI80a.css → excalidrawEditor-BbSbI80a.css} +0 -0
  268. /package/dist/client/assets/{sizeCapture-X5ZJPWSS-B0uUizjq.js → sizeCapture-INFHLROL-B0uUizjq.js} +0 -0
@@ -0,0 +1,460 @@
1
+ const BASIC_SHAPE_TYPES = new Set(['diamond', 'ellipse', 'rectangle']);
2
+ const LINEAR_TYPES = new Set(['arrow', 'freedraw', 'line']);
3
+ const CONNECTOR_TYPES = new Set(['arrow', 'line']);
4
+ const RENDERED_TYPES = new Set([...BASIC_SHAPE_TYPES, ...LINEAR_TYPES, 'text']);
5
+ const MAX_SUMMARY_ELEMENTS = 500;
6
+ const MAX_WARNINGS = 200;
7
+ const MAX_RENDER_DIMENSION = 4096;
8
+
9
+ function finiteNumber(value, fallback = 0) {
10
+ const number = Number(value);
11
+ return Number.isFinite(number) ? number : fallback;
12
+ }
13
+
14
+ function elementBounds(element) {
15
+ const x = finiteNumber(element?.x);
16
+ const y = finiteNumber(element?.y);
17
+ if (LINEAR_TYPES.has(element?.type) && Array.isArray(element.points) && element.points.length > 0) {
18
+ const points = element.points
19
+ .filter((point) => Array.isArray(point) && point.length === 2)
20
+ .map(([pointX, pointY]) => [x + finiteNumber(pointX), y + finiteNumber(pointY)]);
21
+ if (points.length === 0) return null;
22
+ const xs = points.map(([pointX]) => pointX);
23
+ const ys = points.map(([, pointY]) => pointY);
24
+ const left = Math.min(...xs);
25
+ const top = Math.min(...ys);
26
+ return {
27
+ height: Math.max(...ys) - top,
28
+ width: Math.max(...xs) - left,
29
+ x: left,
30
+ y: top,
31
+ };
32
+ }
33
+ const width = finiteNumber(element?.width, Number.NaN);
34
+ const height = finiteNumber(element?.height, Number.NaN);
35
+ if (!Number.isFinite(width) || !Number.isFinite(height)) return null;
36
+ return {
37
+ height: Math.abs(height),
38
+ width: Math.abs(width),
39
+ x: width < 0 ? x + width : x,
40
+ y: height < 0 ? y + height : y,
41
+ };
42
+ }
43
+
44
+ function mergeBounds(boxes) {
45
+ if (boxes.length === 0) return { height: 0, width: 0, x: 0, y: 0 };
46
+ const left = Math.min(...boxes.map(({ x }) => x));
47
+ const top = Math.min(...boxes.map(({ y }) => y));
48
+ const right = Math.max(...boxes.map(({ width, x }) => x + width));
49
+ const bottom = Math.max(...boxes.map(({ height, y }) => y + height));
50
+ return { height: bottom - top, width: right - left, x: left, y: top };
51
+ }
52
+
53
+
54
+ function boxContains(outer, inner) {
55
+ return outer.x <= inner.x
56
+ && outer.y <= inner.y
57
+ && outer.x + outer.width >= inner.x + inner.width
58
+ && outer.y + outer.height >= inner.y + inner.height;
59
+ }
60
+
61
+ function boxesOverlap(left, right) {
62
+ return Math.min(left.x + left.width, right.x + right.width) - Math.max(left.x, right.x) > 1
63
+ && Math.min(left.y + left.height, right.y + right.height) - Math.max(left.y, right.y) > 1;
64
+ }
65
+
66
+ function sharesGroup(left, right) {
67
+ return Array.isArray(right?.groupIds) && left?.groupIds?.some?.((groupId) => right.groupIds.includes(groupId)) === true;
68
+ }
69
+
70
+ function segmentIntersectsBoxInterior(start, end, bounds) {
71
+ const inset = Math.min(1, bounds.width / 4, bounds.height / 4);
72
+ const ranges = [
73
+ [finiteNumber(start[0]), finiteNumber(end[0]) - finiteNumber(start[0]), bounds.x + inset, bounds.x + bounds.width - inset],
74
+ [finiteNumber(start[1]), finiteNumber(end[1]) - finiteNumber(start[1]), bounds.y + inset, bounds.y + bounds.height - inset],
75
+ ];
76
+ let entry = 0;
77
+ let exit = 1;
78
+ for (const [origin, delta, minimum, maximum] of ranges) {
79
+ if (delta === 0) {
80
+ if (origin <= minimum || origin >= maximum) return false;
81
+ continue;
82
+ }
83
+ const first = (minimum - origin) / delta;
84
+ const second = (maximum - origin) / delta;
85
+ entry = Math.max(entry, Math.min(first, second));
86
+ exit = Math.min(exit, Math.max(first, second));
87
+ if (entry > exit) return false;
88
+ }
89
+ return entry <= 1 && exit >= 0;
90
+ }
91
+
92
+ function connectorThroughComponentWarning(connector, component) {
93
+ if (
94
+ !CONNECTOR_TYPES.has(connector?.type)
95
+ || !BASIC_SHAPE_TYPES.has(component?.type)
96
+ || finiteNumber(component.angle) !== 0
97
+ || sharesGroup(connector, component)
98
+ ) {
99
+ return null;
100
+ }
101
+ const componentId = String(component.id ?? '');
102
+ if (
103
+ connector.startBinding?.elementId === componentId
104
+ || connector.endBinding?.elementId === componentId
105
+ ) {
106
+ return null;
107
+ }
108
+ const bounds = elementBounds(component);
109
+ const points = Array.isArray(connector.points)
110
+ ? connector.points
111
+ .filter((point) => Array.isArray(point) && point.length === 2)
112
+ .map(([x, y]) => [
113
+ finiteNumber(connector.x) + finiteNumber(x),
114
+ finiteNumber(connector.y) + finiteNumber(y),
115
+ ])
116
+ : [];
117
+ if (!bounds || points.length < 2) return null;
118
+ const isInside = ([x, y]) => (
119
+ x >= bounds.x
120
+ && x <= bounds.x + bounds.width
121
+ && y >= bounds.y
122
+ && y <= bounds.y + bounds.height
123
+ );
124
+ if (isInside(points[0]) || isInside(points.at(-1))) return null;
125
+ for (let index = 1; index < points.length; index += 1) {
126
+ if (segmentIntersectsBoxInterior(points[index - 1], points[index], bounds)) {
127
+ const connectorId = String(connector.id ?? '');
128
+ return warning(
129
+ 'connector-through-component',
130
+ `Connector ${connectorId} passes through component ${componentId}.`,
131
+ [connectorId, componentId],
132
+ );
133
+ }
134
+ }
135
+ return null;
136
+ }
137
+
138
+ function unintendedOverlapWarning(left, right) {
139
+ if (
140
+ !BASIC_SHAPE_TYPES.has(left?.type)
141
+ || !BASIC_SHAPE_TYPES.has(right?.type)
142
+ || finiteNumber(left.angle) !== 0
143
+ || finiteNumber(right.angle) !== 0
144
+ || sharesGroup(left, right)
145
+ ) {
146
+ return null;
147
+ }
148
+ const leftBounds = elementBounds(left);
149
+ const rightBounds = elementBounds(right);
150
+ if (
151
+ !leftBounds
152
+ || !rightBounds
153
+ || !boxesOverlap(leftBounds, rightBounds)
154
+ || boxContains(leftBounds, rightBounds)
155
+ || boxContains(rightBounds, leftBounds)
156
+ ) {
157
+ return null;
158
+ }
159
+ const leftId = String(left.id ?? '');
160
+ const rightId = String(right.id ?? '');
161
+ return warning(
162
+ 'unintended-overlap',
163
+ `Components ${leftId} and ${rightId} overlap without a shared group.`,
164
+ [leftId, rightId],
165
+ );
166
+ }
167
+
168
+ function summarizeElement(element, paintOrder, activeElements) {
169
+ const bounds = elementBounds(element) ?? { height: 0, width: 0, x: 0, y: 0 };
170
+ const summary = {
171
+ height: bounds.height,
172
+ id: String(element?.id ?? ''),
173
+ paintOrder,
174
+ type: String(element?.type ?? 'unknown'),
175
+ width: bounds.width,
176
+ x: bounds.x,
177
+ y: bounds.y,
178
+ };
179
+ const elementBehind = activeElements[paintOrder - 1];
180
+ const elementInFront = activeElements[paintOrder + 1];
181
+ if (elementInFront?.id) summary.behind = String(elementInFront.id);
182
+ if (elementBehind?.id) summary.inFrontOf = String(elementBehind.id);
183
+ if (element?.type === 'text') summary.text = String(element.text ?? '');
184
+ if (element?.type === 'text') {
185
+ summary.fontSize = finiteNumber(element.fontSize, 20);
186
+ summary.lineHeight = finiteNumber(element.lineHeight, 1.25);
187
+ if (element.containerId) summary.containerId = String(element.containerId);
188
+ if (element.textAlign) summary.textAlign = String(element.textAlign);
189
+ if (element.verticalAlign) summary.verticalAlign = String(element.verticalAlign);
190
+ }
191
+ if (element?.startBinding?.elementId) summary.startElementId = String(element.startBinding.elementId);
192
+ if (element?.endBinding?.elementId) summary.endElementId = String(element.endBinding.elementId);
193
+ return summary;
194
+ }
195
+
196
+ function warning(code, message, elementIds = []) {
197
+ return { code, elementIds, message };
198
+ }
199
+
200
+ function textOverflowWarning(element, bounds, id) {
201
+ if (element?.type !== 'text' || element.autoResize === true || !bounds) return null;
202
+ const text = String(element.text ?? '');
203
+ const fontSize = finiteNumber(element.fontSize, 20);
204
+ const lines = text.split('\n');
205
+ const expectedWidth = Math.max(1, ...lines.map((line) => line.length)) * fontSize * 0.6;
206
+ const expectedHeight = Math.max(1, lines.length) * fontSize * finiteNumber(element.lineHeight, 1.25);
207
+ return bounds.width + 1 < expectedWidth || bounds.height + 1 < expectedHeight
208
+ ? warning('text-overflow', `Text element ${id} may be clipped by its bounds.`, [id])
209
+ : null;
210
+ }
211
+
212
+ function boundEndpointWarning(element, binding, endpointName, activeById) {
213
+ if (!binding?.elementId || !LINEAR_TYPES.has(element?.type) || !Array.isArray(element.points)) {
214
+ return null;
215
+ }
216
+ const targetId = String(binding.elementId);
217
+ const target = activeById.get(targetId);
218
+ if (!target || finiteNumber(target.angle) !== 0) return null;
219
+ const point = endpointName === 'start' ? element.points[0] : element.points.at(-1);
220
+ const bounds = elementBounds(target);
221
+ if (!Array.isArray(point) || point.length !== 2 || !bounds) return null;
222
+ const pointX = finiteNumber(element.x) + finiteNumber(point[0]);
223
+ const pointY = finiteNumber(element.y) + finiteNumber(point[1]);
224
+ const dx = Math.max(bounds.x - pointX, 0, pointX - (bounds.x + bounds.width));
225
+ const dy = Math.max(bounds.y - pointY, 0, pointY - (bounds.y + bounds.height));
226
+ const distance = Math.hypot(dx, dy);
227
+ if (distance <= 32) return null;
228
+ const id = String(element.id ?? '');
229
+ return warning(
230
+ 'bound-endpoint-far',
231
+ `Element ${id} ${endpointName} endpoint is ${Math.round(distance)} diagram units from bound target ${targetId}.`,
232
+ [id, targetId],
233
+ );
234
+ }
235
+
236
+ function collectElementWarnings(element, activeById, seenIds) {
237
+ const warnings = [];
238
+ const id = String(element?.id ?? '');
239
+ if (!id) warnings.push(warning('missing-id', 'Element has no id.'));
240
+ else if (seenIds.has(id)) warnings.push(warning('duplicate-id', `Element id ${id} is duplicated.`, [id]));
241
+ seenIds.add(id);
242
+
243
+ const bounds = elementBounds(element);
244
+ const hasInvalidBounds = !bounds || (
245
+ LINEAR_TYPES.has(element?.type)
246
+ ? bounds.width <= 0 && bounds.height <= 0
247
+ : bounds.width <= 0 || bounds.height <= 0
248
+ );
249
+ if (hasInvalidBounds) {
250
+ warnings.push(warning('invalid-bounds', `Element ${id || '(missing id)'} has invalid or zero-size bounds.`, id ? [id] : []));
251
+ }
252
+ if (!RENDERED_TYPES.has(element?.type)) {
253
+ warnings.push(warning('unsupported-render-type', `Element ${id || '(missing id)'} uses unsupported render type ${element?.type}.`, id ? [id] : []));
254
+ }
255
+ for (const [endpointName, binding] of [
256
+ ['start', element?.startBinding],
257
+ ['end', element?.endBinding],
258
+ ]) {
259
+ if (binding?.elementId && !activeById.has(String(binding.elementId))) {
260
+ warnings.push(warning('missing-binding-target', `Element ${id} binds to missing element ${binding.elementId}.`, [id, String(binding.elementId)]));
261
+ continue;
262
+ }
263
+ const endpointWarning = boundEndpointWarning(element, binding, endpointName, activeById);
264
+ if (endpointWarning) warnings.push(endpointWarning);
265
+ }
266
+ const overflow = textOverflowWarning(element, bounds, id);
267
+ if (overflow) warnings.push(overflow);
268
+ if (finiteNumber(element?.strokeWidth, 2) > 32) {
269
+ warnings.push(warning('large-stroke', `Element ${id} has a stroke wider than 32 diagram units.`, [id]));
270
+ }
271
+ return warnings;
272
+ }
273
+
274
+ function isOpaqueSolidRectangle(element) {
275
+ return element?.type === 'rectangle'
276
+ && element.fillStyle === 'solid'
277
+ && finiteNumber(element.opacity, 100) === 100
278
+ && String(element.backgroundColor ?? 'transparent').toLowerCase() !== 'transparent';
279
+ }
280
+
281
+ function collectWarnings(elements, { inspectOcclusion = true } = {}) {
282
+ const warnings = [];
283
+ const push = (entry) => {
284
+ if (warnings.length < MAX_WARNINGS) warnings.push(entry);
285
+ };
286
+ const activeById = new Map(elements.map((element) => [String(element.id), element]));
287
+ const seenIds = new Set();
288
+ for (const element of elements) {
289
+ collectElementWarnings(element, activeById, seenIds).forEach(push);
290
+ }
291
+
292
+ for (const connector of elements) {
293
+ if (!CONNECTOR_TYPES.has(connector.type)) continue;
294
+ for (const component of elements) {
295
+ const intersection = connectorThroughComponentWarning(connector, component);
296
+ if (intersection) push(intersection);
297
+ }
298
+ }
299
+ for (let leftIndex = 0; leftIndex < elements.length; leftIndex += 1) {
300
+ for (let rightIndex = leftIndex + 1; rightIndex < elements.length; rightIndex += 1) {
301
+ const overlap = unintendedOverlapWarning(elements[leftIndex], elements[rightIndex]);
302
+ if (overlap) push(overlap);
303
+ }
304
+ }
305
+
306
+ if (inspectOcclusion) {
307
+ for (let hiddenIndex = 0; hiddenIndex < elements.length; hiddenIndex += 1) {
308
+ const hidden = elements[hiddenIndex];
309
+ const hiddenBounds = elementBounds(hidden);
310
+ if (!hiddenBounds) continue;
311
+ for (let foregroundIndex = hiddenIndex + 1; foregroundIndex < elements.length; foregroundIndex += 1) {
312
+ const foreground = elements[foregroundIndex];
313
+ const foregroundBounds = elementBounds(foreground);
314
+ if (
315
+ foregroundBounds
316
+ && isOpaqueSolidRectangle(foreground)
317
+ && boxContains(foregroundBounds, hiddenBounds)
318
+ ) {
319
+ push(warning(
320
+ 'fully-occluded',
321
+ `Element ${hidden.id} is fully occluded by ${foreground.id}.`,
322
+ [String(hidden.id), String(foreground.id)],
323
+ ));
324
+ break;
325
+ }
326
+ }
327
+ }
328
+ }
329
+ return warnings;
330
+ }
331
+
332
+ export function inspectAgentExcalidrawScene(scene = {}, {
333
+ includeElements = true,
334
+ inspectOcclusion = true,
335
+ } = {}) {
336
+ const activeElements = (Array.isArray(scene?.elements) ? scene.elements : [])
337
+ .filter((element) => element && !element.isDeleted);
338
+ const boxes = activeElements.map(elementBounds).filter(Boolean);
339
+ const warnings = collectWarnings(activeElements, { inspectOcclusion });
340
+ return {
341
+ bounds: mergeBounds(boxes),
342
+ elementCount: activeElements.length,
343
+ elements: includeElements
344
+ ? activeElements
345
+ .slice(0, MAX_SUMMARY_ELEMENTS)
346
+ .map((element, paintOrder) => summarizeElement(element, paintOrder, activeElements))
347
+ : [],
348
+ truncated: (!includeElements && activeElements.length > 0)
349
+ || activeElements.length > MAX_SUMMARY_ELEMENTS
350
+ || warnings.length >= MAX_WARNINGS,
351
+ warnings,
352
+ };
353
+ }
354
+
355
+ function escapeXml(value) {
356
+ return String(value)
357
+ .replaceAll('&', '&amp;')
358
+ .replaceAll('<', '&lt;')
359
+ .replaceAll('>', '&gt;')
360
+ .replaceAll('"', '&quot;')
361
+ .replaceAll("'", '&apos;');
362
+ }
363
+
364
+ function safeColor(value, fallback) {
365
+ const color = String(value ?? '').trim();
366
+ return /^(?:#[\da-f]{3,8}|transparent)$/iu.test(color) ? color : fallback;
367
+ }
368
+
369
+ function strokeAttributes(element) {
370
+ const dash = element?.strokeStyle === 'dashed'
371
+ ? ' stroke-dasharray="12 8"'
372
+ : element?.strokeStyle === 'dotted' ? ' stroke-dasharray="3 6"' : '';
373
+ return `stroke="${safeColor(element?.strokeColor, '#1e1e1e')}" stroke-width="${Math.max(0.5, finiteNumber(element?.strokeWidth, 2))}" stroke-linecap="round" stroke-linejoin="round"${dash} opacity="${Math.min(1, Math.max(0, finiteNumber(element?.opacity, 100) / 100))}"`;
374
+ }
375
+
376
+ function rotationAttribute(element, bounds) {
377
+ const angle = finiteNumber(element?.angle);
378
+ if (!angle) return '';
379
+ const degrees = angle * (180 / Math.PI);
380
+ return ` transform="rotate(${degrees} ${bounds.x + (bounds.width / 2)} ${bounds.y + (bounds.height / 2)})"`;
381
+ }
382
+
383
+ function renderText(element, bounds) {
384
+ const lines = String(element?.text ?? '').split('\n');
385
+ const fontSize = Math.max(1, finiteNumber(element?.fontSize, 20));
386
+ const lineHeight = fontSize * finiteNumber(element?.lineHeight, 1.25);
387
+ const startY = bounds.y + (bounds.height / 2) - ((lines.length - 1) * lineHeight / 2);
388
+ const spans = lines.map((line, index) => `<tspan x="${bounds.x + (bounds.width / 2)}" y="${startY + (index * lineHeight)}">${escapeXml(line)}</tspan>`).join('');
389
+ return `<text text-anchor="middle" dominant-baseline="middle" font-family="Arial, sans-serif" font-size="${fontSize}" fill="${safeColor(element?.strokeColor, '#1e1e1e')}"${rotationAttribute(element, bounds)}>${spans}</text>`;
390
+ }
391
+
392
+ function renderLinearElement(element) {
393
+ const originX = finiteNumber(element?.x);
394
+ const originY = finiteNumber(element?.y);
395
+ const points = Array.isArray(element?.points) ? element.points : [];
396
+ const coordinates = points
397
+ .filter((point) => Array.isArray(point) && point.length === 2)
398
+ .map(([x, y]) => [originX + finiteNumber(x), originY + finiteNumber(y)]);
399
+ if (coordinates.length < 2) return '';
400
+ const path = coordinates.map(([x, y], index) => `${index === 0 ? 'M' : 'L'} ${x} ${y}`).join(' ');
401
+ const markerStart = element?.startArrowhead ? ' marker-start="url(#arrow-start)"' : '';
402
+ const markerEnd = element?.type === 'arrow' && element?.endArrowhead !== null ? ' marker-end="url(#arrow-end)"' : '';
403
+ return `<path d="${path}" fill="none" ${strokeAttributes(element)}${markerStart}${markerEnd}/>`;
404
+ }
405
+
406
+ function renderElement(element) {
407
+ const bounds = elementBounds(element);
408
+ if (!bounds) return '';
409
+ if (element.type === 'text') return renderText(element, bounds);
410
+ if (LINEAR_TYPES.has(element.type)) return renderLinearElement(element);
411
+ const fill = safeColor(element.backgroundColor, 'transparent');
412
+ const rotation = rotationAttribute(element, bounds);
413
+ if (element.type === 'ellipse') {
414
+ return `<ellipse cx="${bounds.x + (bounds.width / 2)}" cy="${bounds.y + (bounds.height / 2)}" rx="${bounds.width / 2}" ry="${bounds.height / 2}" fill="${fill}" ${strokeAttributes(element)}${rotation}/>`;
415
+ }
416
+ if (element.type === 'diamond') {
417
+ const centerX = bounds.x + (bounds.width / 2);
418
+ const centerY = bounds.y + (bounds.height / 2);
419
+ const points = `${centerX},${bounds.y} ${bounds.x + bounds.width},${centerY} ${centerX},${bounds.y + bounds.height} ${bounds.x},${centerY}`;
420
+ return `<polygon points="${points}" fill="${fill}" ${strokeAttributes(element)}${rotation}/>`;
421
+ }
422
+ if (element.type === 'rectangle') {
423
+ return `<rect x="${bounds.x}" y="${bounds.y}" width="${bounds.width}" height="${bounds.height}" rx="8" fill="${fill}" ${strokeAttributes(element)}${rotation}/>`;
424
+ }
425
+ return '';
426
+ }
427
+
428
+ export function renderAgentExcalidrawSvg(scene, {
429
+ padding = 32,
430
+ scale = 1,
431
+ } = {}) {
432
+ const activeElements = (Array.isArray(scene?.elements) ? scene.elements : [])
433
+ .filter((element) => element && !element.isDeleted);
434
+ const bounds = mergeBounds(activeElements.map(elementBounds).filter(Boolean));
435
+ const inset = Math.min(100, Math.max(0, finiteNumber(padding, 32)));
436
+ const sceneWidth = Math.max(1, bounds.width + (inset * 2));
437
+ const sceneHeight = Math.max(1, bounds.height + (inset * 2));
438
+ const requestedScale = Math.min(4, Math.max(0.25, finiteNumber(scale, 1)));
439
+ const appliedScale = Math.min(
440
+ requestedScale,
441
+ MAX_RENDER_DIMENSION / sceneWidth,
442
+ MAX_RENDER_DIMENSION / sceneHeight,
443
+ );
444
+ const width = Math.max(1, Math.ceil(sceneWidth * appliedScale));
445
+ const height = Math.max(1, Math.ceil(sceneHeight * appliedScale));
446
+ const viewX = bounds.x - inset;
447
+ const viewY = bounds.y - inset;
448
+ const elements = activeElements.map(renderElement).join('');
449
+ const svg = `<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}" viewBox="${viewX} ${viewY} ${sceneWidth} ${sceneHeight}"><defs><marker id="arrow-end" markerWidth="10" markerHeight="10" refX="8" refY="3" orient="auto" markerUnits="strokeWidth"><path d="M0,0 L0,6 L9,3 z" fill="#1e1e1e"/></marker><marker id="arrow-start" markerWidth="10" markerHeight="10" refX="1" refY="3" orient="auto-start-reverse" markerUnits="strokeWidth"><path d="M9,0 L9,6 L0,3 z" fill="#1e1e1e"/></marker></defs><rect x="${viewX}" y="${viewY}" width="${sceneWidth}" height="${sceneHeight}" fill="#ffffff"/>${elements}</svg>`;
450
+ return {
451
+ elementCount: activeElements.length,
452
+ height,
453
+ scale: appliedScale,
454
+ svg,
455
+ width,
456
+ renderer: 'collabmd-basic-svg',
457
+ rendererVersion: '1',
458
+ warnings: ['preview-not-pixel-identical'],
459
+ };
460
+ }
@@ -61,11 +61,7 @@ function parseSceneJson(rawJson, { fallbackToEmpty = true } = {}) {
61
61
  }
62
62
 
63
63
  function cloneJsonValue(value) {
64
- if (value === undefined) {
65
- return undefined;
66
- }
67
-
68
- return JSON.parse(JSON.stringify(value));
64
+ return structuredClone(value);
69
65
  }
70
66
 
71
67
  function getRevisionKey(element) {
@@ -0,0 +1,76 @@
1
+ const DIRECT_VIDEO_MIME_TYPES = Object.freeze({
2
+ '.mp4': 'video/mp4',
3
+ '.ogg': 'video/ogg',
4
+ '.webm': 'video/webm',
5
+ });
6
+
7
+ const YOUTUBE_HOSTS = new Set([
8
+ 'youtube.com',
9
+ 'www.youtube.com',
10
+ 'm.youtube.com',
11
+ 'youtu.be',
12
+ 'www.youtu.be',
13
+ 'youtube-nocookie.com',
14
+ 'www.youtube-nocookie.com',
15
+ ]);
16
+
17
+ function getDirectVideoMimeType(pathname = '') {
18
+ const match = pathname.toLowerCase().match(/\.(mp4|ogg|webm)$/iu);
19
+ return match ? DIRECT_VIDEO_MIME_TYPES[`.${match[1].toLowerCase()}`] : null;
20
+ }
21
+
22
+ function normalizeYouTubeVideoId(candidate = '') {
23
+ const normalized = String(candidate || '').trim();
24
+ return /^[A-Za-z0-9_-]{11}$/u.test(normalized) ? normalized : null;
25
+ }
26
+
27
+ function getCanonicalYouTubeEmbedUrl(url) {
28
+ const host = url.hostname.toLowerCase();
29
+ let videoId = null;
30
+
31
+ if (host === 'youtu.be' || host === 'www.youtu.be') {
32
+ videoId = normalizeYouTubeVideoId(url.pathname.split('/').filter(Boolean)[0] || '');
33
+ } else if (host.includes('youtube') || host.includes('youtube-nocookie')) {
34
+ if (url.pathname === '/watch') {
35
+ videoId = normalizeYouTubeVideoId(url.searchParams.get('v') || '');
36
+ } else if (url.pathname.startsWith('/embed/')) {
37
+ videoId = normalizeYouTubeVideoId(url.pathname.split('/').filter(Boolean)[1] || '');
38
+ }
39
+ }
40
+
41
+ return videoId ? `https://www.youtube-nocookie.com/embed/${videoId}` : null;
42
+ }
43
+
44
+ function parseVideoUrl(source = '') {
45
+ try {
46
+ return new URL(String(source || '').trim());
47
+ } catch {
48
+ return null;
49
+ }
50
+ }
51
+
52
+ export function isPublicVideoEmbedCandidate(source = '') {
53
+ const url = parseVideoUrl(source);
54
+ return Boolean(url && (
55
+ YOUTUBE_HOSTS.has(url.hostname.toLowerCase())
56
+ || getDirectVideoMimeType(url.pathname)
57
+ ));
58
+ }
59
+
60
+ export function classifyPublicVideoEmbed(source = '') {
61
+ const url = parseVideoUrl(source);
62
+ if (!url || url.protocol !== 'https:') return null;
63
+
64
+ const host = url.hostname.toLowerCase();
65
+ if (YOUTUBE_HOSTS.has(host)) {
66
+ const embedUrl = getCanonicalYouTubeEmbedUrl(url);
67
+ return embedUrl ? { embedUrl, type: 'youtube' } : null;
68
+ }
69
+
70
+ const mimeType = getDirectVideoMimeType(url.pathname);
71
+ return mimeType ? {
72
+ mimeType,
73
+ sourceUrl: url.toString(),
74
+ type: 'direct-video',
75
+ } : null;
76
+ }