collabmd 0.1.47 → 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 (305) hide show
  1. package/README.md +70 -11
  2. package/bin/collabmd.js +3 -0
  3. package/dist/client/assets/CodeMirrorEditor-UCMRAMCV-C-nmgL5g.js +1 -0
  4. package/dist/client/assets/JetBrainsMono-Regular-BQaDgvhP.woff2 +0 -0
  5. package/dist/client/assets/abnfDiagram-VCTEODGH-CdVZqicp.js +1 -0
  6. package/dist/client/assets/{architectureDiagram-5GKGNRK7-I39sYjHI.js → architectureDiagram-5GKGNRK7-wUo0bXif.js} +3 -3
  7. package/dist/client/assets/babel-CY5KOv-I.js +16 -0
  8. package/dist/client/assets/{blockDiagram-NRAW4CY4-C6DtJy5Y.js → blockDiagram-I7D4REHJ-BRSK3m49.js} +4 -4
  9. package/dist/client/assets/browser-utils-DbXSMI-6.js +1 -0
  10. package/dist/client/assets/{c4Diagram-UCG6FXSJ-CtWtxS9_.js → c4Diagram-7LVT6UL2-yD2poxqw.js} +1 -1
  11. package/dist/client/assets/channel-Fa4GS_-F.js +1 -0
  12. package/dist/client/assets/chunk-2E4U76K2-BPnTT-J3.js +2 -0
  13. package/dist/client/assets/{chunk-TEH6E4GO-DVayPj-q.js → chunk-4HAMMTFA-DStbIfJ1.js} +20 -20
  14. package/dist/client/assets/{chunk-75Z2AOVW-CdFSaPjz.js → chunk-75Z2AOVW-C5pGd3W9.js} +1 -1
  15. package/dist/client/assets/{chunk-CLGD4ZFX-DQLgbQrv.js → chunk-CLGD4ZFX-BMeArk03.js} +1 -1
  16. package/dist/client/assets/chunk-DU6HZSFF-Zkp69c6c.js +127 -0
  17. package/dist/client/assets/{chunk-F27PBJKO-CNHIFhjo.js → chunk-F27PBJKO-D4xNct1r.js} +1 -1
  18. package/dist/client/assets/{chunk-GMAD6QVW-CbcBqPM5.js → chunk-GMAD6QVW-NZ6WpDb8.js} +1 -1
  19. package/dist/client/assets/{chunk-OBVCFTLP-BJR7u1jh.js → chunk-GVQU2GXP-D8SDprfX.js} +1 -1
  20. package/dist/client/assets/{chunk-G27WJ6UU-D9-eg537.js → chunk-IMKFNOWR-D8jEuU3Q.js} +2 -2
  21. package/dist/client/assets/{chunk-JQ64N6SF-DSFNH4bh.js → chunk-L3NEJ4N5-aijKP-eh.js} +1 -1
  22. package/dist/client/assets/chunk-OSK3NFVY-CCbLQAMa.js +10 -0
  23. package/dist/client/assets/{chunk-P2QGCYS3-BRpqY32H.js → chunk-P2QGCYS3-Oag_FdCq.js} +1 -1
  24. package/dist/client/assets/{chunk-POPQ4Y6H-Cb4SlVZF.js → chunk-POPQ4Y6H-CYnpIgXT.js} +1 -1
  25. package/dist/client/assets/{chunk-PWAF6VOD-Cz8IwBB5.js → chunk-PWAF6VOD-JSNrcBmP.js} +1 -1
  26. package/dist/client/assets/{chunk-RM4UPSZO-CWRwxNWJ.js → chunk-RM4UPSZO-DOWllDY8.js} +4 -4
  27. package/dist/client/assets/{chunk-RHFEMEQ7-CWY8cf4H.js → chunk-SHT3W25Y-BiQGljao.js} +5 -5
  28. package/dist/client/assets/{chunk-SVP7TREG-CyHOmcac.js → chunk-SVP7TREG-DB485R5x.js} +1 -1
  29. package/dist/client/assets/{chunk-LCL6LL3I-DmDkVukh.js → chunk-TICWLB2K-8rAVvoS3.js} +4 -4
  30. package/dist/client/assets/{chunk-CKBBP62Z-DG26UiBv.js → chunk-TLUHSLCS-DTY5v0aj.js} +2 -2
  31. package/dist/client/assets/classDiagram-ZZMXUADV-BsQWoR3Q.js +1 -0
  32. package/dist/client/assets/classDiagram-v2-VYDZK3BY-BsQWoR3Q.js +1 -0
  33. package/dist/client/assets/{comment-thread-store-CdcwrObc.js → comment-thread-store-CX98zR6q.js} +1 -1
  34. package/dist/client/assets/comment-threads-BnRwo5B9.js +4 -0
  35. package/dist/client/assets/{cynefinDiagram-5FMLGOSQ-CdTPi2yO.js → cynefinDiagram-5FMLGOSQ-rTz9RhFH.js} +1 -1
  36. package/dist/client/assets/{dagre-3AP2YEHR-5gtJtd0O.js → dagre-GXQ25YYZ-Cr67wLpQ.js} +2 -2
  37. package/dist/client/assets/{diagram-S7CK7UJ4-BudWz9WU.js → diagram-S7CK7UJ4-DywERe__.js} +2 -2
  38. package/dist/client/assets/{diagram-UQ7AKVKN-3v4rbH-s.js → diagram-UQ7AKVKN-CNYlXtu4.js} +1 -1
  39. package/dist/client/assets/diagram-VSXAHHWV-0H1a61Bn.js +3 -0
  40. package/dist/client/assets/{diagram-VX7I27RA-C_-rj0sw.js → diagram-VX7I27RA-CsJbsx5F.js} +1 -1
  41. package/dist/client/assets/{diagram-Z3DM3KII-B4yxavgj.js → diagram-Z3DM3KII-D0mLxEgI.js} +1 -1
  42. package/dist/client/assets/dist--hk9I5HQ.js +1 -0
  43. package/dist/client/assets/{dist-DutPuFmC.js → dist-B1XEa-Zs.js} +1 -1
  44. package/dist/client/assets/dist-Bd1JucQF.js +1 -0
  45. package/dist/client/assets/{dist-DZAAWTG-.js → dist-C0G3AaXG.js} +1 -1
  46. package/dist/client/assets/dist-ChRoo3IB.js +9 -0
  47. package/dist/client/assets/dist-Dm4w5UId.js +1 -0
  48. package/dist/client/assets/{dist-B_yQaEv_.js → dist-DpYDHR9p.js} +1 -1
  49. package/dist/client/assets/{dist-CietwTVS.js → dist-DzNmC81X.js} +1 -1
  50. package/dist/client/assets/{dist-DDUn5zTz.js → dist-GvvCNBe4.js} +1 -1
  51. package/dist/client/assets/dist-JaU3aRlD.js +19 -0
  52. package/dist/client/assets/{dist-Bw3VIE_v.js → dist-TW8iFRyW.js} +1 -1
  53. package/dist/client/assets/{dist-Dir5dDKZ.js → dist-jVU5Be5P.js} +1 -1
  54. package/dist/client/assets/document-formatter-rDDjRfZ2.js +2 -0
  55. package/dist/client/assets/drawioEditor-JubEEha7.js +9 -0
  56. package/dist/client/assets/ebnfDiagram-PWID7BFC-HeTxHpCU.js +1 -0
  57. package/dist/client/assets/editor-session-Bk6oIvSr.js +54 -0
  58. package/dist/client/assets/embedded-editor-base-BlCgz6mw.css +1 -0
  59. package/dist/client/assets/{erDiagram-SSCWMZ5O-C-iy6VkX.js → erDiagram-RLTQ6QDP-CbrDdd5P.js} +2 -2
  60. package/dist/client/assets/{es-CAsWR6hG.js → es-Bfdp096f.js} +13 -13
  61. package/dist/client/assets/estree-CuT_pB8K.js +44 -0
  62. package/dist/client/assets/excalidraw-element-link-YLIaTnVF.js +7 -0
  63. package/dist/client/assets/{excalidraw-scene-BOben2gr.js → excalidraw-scene-6uROebca.js} +1 -1
  64. package/dist/client/assets/{excalidraw-editor-BlcN6umJ.css → excalidrawEditor-BbSbI80a.css} +1 -1
  65. package/dist/client/assets/excalidrawEditor-dBMbRX_S.js +9 -0
  66. package/dist/client/assets/export-page-CRRQ2NEl.js +57 -0
  67. package/dist/client/assets/exportDocument-BlQRd9_m.js +2 -0
  68. package/dist/client/assets/exportDocument-CNSbjZwu.css +1 -0
  69. package/dist/client/assets/{file-icon-svg-CQAjlWjK.js → file-icon-svg-Y_kpF957.js} +1 -1
  70. package/dist/client/assets/file-kind-BwMIcZbi.js +1 -0
  71. package/dist/client/assets/file-search-DDLyyLDU.js +1 -0
  72. package/dist/client/assets/flowDiagram-HODETNUW-D5Gy0wmg.js +1 -0
  73. package/dist/client/assets/{ganttDiagram-EL5Y4UJY-DtKHAbez.js → ganttDiagram-EL5Y4UJY-BHgOYiZz.js} +1 -1
  74. package/dist/client/assets/{gitGraphDiagram-WWUBYQGX-oue8fQ5o.js → gitGraphDiagram-WWUBYQGX-Dl__X3Sk.js} +1 -1
  75. package/dist/client/assets/html-Cdnr2qzU.js +25 -0
  76. package/dist/client/assets/image-ZVKINSPA-DgzW5zAy.js +1 -0
  77. package/dist/client/assets/index-D3RER1SZ.js +1023 -0
  78. package/dist/client/assets/index-DREVKl_K.css +1 -0
  79. package/dist/client/assets/{infoDiagram-RXCK75RN-BMzo6KIn.js → infoDiagram-27XIBGKW-DBpoANC9.js} +1 -1
  80. package/dist/client/assets/{ishikawaDiagram-5VMMS53U-BIM3h287.js → ishikawaDiagram-5VMMS53U-BMPC6hfp.js} +1 -1
  81. package/dist/client/assets/{journeyDiagram-EYS64GPL-mF6Lh8O-.js → journeyDiagram-3NMN7TZE-B1sApUmM.js} +2 -2
  82. package/dist/client/assets/{kanban-definition-3QL26DDD-DLN2NyoR.js → kanban-definition-UXKFOSKX-C9yP4td1.js} +4 -4
  83. package/dist/client/assets/{line-BfTWJmgf.js → line-BFl3ujec.js} +1 -1
  84. package/dist/client/assets/markdown-CByV-4CU.js +70 -0
  85. package/dist/client/assets/{mermaid.core-CLZBlpIW.js → mermaid.core-BrY09czX.js} +5 -5
  86. package/dist/client/assets/mermaid.core-DfcNfOTv.js +1 -0
  87. package/dist/client/assets/{mindmap-definition-FBJOCRG2-CRyHaHTk.js → mindmap-definition-YA3MSWOX-BUQHcYbK.js} +8 -8
  88. package/dist/client/assets/pegDiagram-XKGWAZYB-Bi2Iml7Z.js +1 -0
  89. package/dist/client/assets/{pieDiagram-E7YTZNPT-B5OZPb88.js → pieDiagram-E7YTZNPT-_gYXnMoi.js} +1 -1
  90. package/dist/client/assets/preview-render-compiler-CfxJYldJ.js +41 -0
  91. package/dist/client/assets/preview-render-compiler-Cu8_i9iS.js +1 -0
  92. package/dist/client/assets/{preview-render-worker-BmN79bVc.js → preview-render-worker-c4Yi93qW.js} +41 -35
  93. package/dist/client/assets/prod-BiJL30sl.js +1 -0
  94. package/dist/client/assets/prod-qAk7rHa4.js +177 -0
  95. package/dist/client/assets/{quadrantDiagram-AXDQQJYC-Drrw14YH.js → quadrantDiagram-AXDQQJYC-DwexhEhd.js} +1 -1
  96. package/dist/client/assets/quick-switcher-controller-BoIK_wuG.js +1 -0
  97. package/dist/client/assets/railroadDiagram-O6MQD6OU-BVA5UbMu.js +1 -0
  98. package/dist/client/assets/{requirementDiagram-EFPCY7ZU-CRZG6mRB.js → requirementDiagram-BXWQKSXE-C4cKwiIw.js} +2 -2
  99. package/dist/client/assets/runtime-config-DcmnGcXU.js +1 -0
  100. package/dist/client/assets/{sankeyDiagram-P5KCCOFB-DvarEJpo.js → sankeyDiagram-P5KCCOFB-B5HHkRT2.js} +1 -1
  101. package/dist/client/assets/{sequenceDiagram-WJ2MYXX4-B4oWlb-w.js → sequenceDiagram-WJ2MYXX4-BX6jqJFD.js} +6 -6
  102. package/dist/client/assets/standalone-6z5x8CWe.js +29 -0
  103. package/dist/client/assets/{stateDiagram-HBIQ2CUA-qbHIIqRZ.js → stateDiagram-D77RDMKH-CmqxyRGx.js} +1 -1
  104. package/dist/client/assets/stateDiagram-v2-MP3YSRHH-zoLLQVyh.js +1 -0
  105. package/dist/client/assets/{swimlanes-XN3QIQJK-xB6CtUGj.js → swimlanes-42K2YHIH-Bmgb9Zld.js} +1 -1
  106. package/dist/client/assets/swimlanesDiagram-VR7AAH4N-DS-KQN37.js +8 -0
  107. package/dist/client/assets/{timeline-definition-24CTP7MA-Lj_yTNlY.js → timeline-definition-24CTP7MA-BA-lVH6P.js} +1 -1
  108. package/dist/client/assets/vault-api-client-iZLhMJKe.js +6 -0
  109. package/dist/client/assets/{vennDiagram-4TSXK5OY-BekRp5Y0.js → vennDiagram-4TSXK5OY-DNdUC_Xj.js} +1 -1
  110. package/dist/client/assets/{wardleyDiagram-VM6X3IG4-kdnV_Hdm.js → wardleyDiagram-VM6X3IG4-C2oY-YbF.js} +1 -1
  111. package/dist/client/assets/wiki-link-resolver-DFIwErjc.js +1 -0
  112. package/dist/client/assets/{xychartDiagram-S5SC5T6Z-DufGwNSB.js → xychartDiagram-S5SC5T6Z-CoIR8CBX.js} +1 -1
  113. package/dist/client/assets/yaml-9ltHPDNO.js +154 -0
  114. package/dist/client/assets/{yjs-provider-reset-guard-DE0vINDP.js → yjs-provider-reset-guard-9ul1qF6k.js} +1 -1
  115. package/dist/client/drawio-editor.html +11 -3
  116. package/dist/client/excalidraw-editor.html +45 -2
  117. package/dist/client/export-document.html +3 -3
  118. package/dist/client/index.html +106 -52
  119. package/integrations/pi/index.ts +94 -0
  120. package/package.json +41 -29
  121. package/src/client/app/drawio-editor.html +2 -2
  122. package/src/client/app/excalidraw-editor.html +2 -2
  123. package/src/client/app/export-document.html +1 -1
  124. package/src/client/app/index.html +88 -50
  125. package/src/client/app/main-entry.js +15 -1
  126. package/src/client/application/app-shell/chat-feature.js +7 -22
  127. package/src/client/application/app-shell/export-feature.js +17 -1
  128. package/src/client/application/app-shell/git-feature.js +51 -14
  129. package/src/client/application/app-shell/presence-feature.js +8 -25
  130. package/src/client/application/app-shell/ui-feature-identity.js +13 -0
  131. package/src/client/application/app-shell/ui-feature-shell.js +199 -99
  132. package/src/client/application/app-shell/ui-feature-sidebar.js +43 -7
  133. package/src/client/application/app-shell/ui-feature-tab-activity.js +19 -6
  134. package/src/client/application/app-shell/ui-feature-toolbar.js +16 -129
  135. package/src/client/application/app-shell-elements.js +8 -0
  136. package/src/client/application/preview-render-compiler.js +1 -87
  137. package/src/client/application/preview-render-scheduler.js +8 -24
  138. package/src/client/application/preview-renderer.js +2 -2
  139. package/src/client/application/webmcp-diagram-renderer.js +47 -0
  140. package/src/client/application/workspace-coordinator.js +23 -4
  141. package/src/client/application/workspace-preview-controller.js +120 -2
  142. package/src/client/application/workspace-route-controller.js +11 -1
  143. package/src/client/assets/vendor/jetbrains-mono/JetBrainsMono-Regular.woff2 +0 -0
  144. package/src/client/assets/vendor/jetbrains-mono/OFL.txt +93 -0
  145. package/src/client/bootstrap/collabmd-app-shell.js +99 -6
  146. package/src/client/domain/document-formatter.js +193 -0
  147. package/src/client/domain/excalidraw-element-link.js +73 -0
  148. package/src/client/domain/excalidraw-scene.js +21 -0
  149. package/src/client/domain/file-search.js +73 -0
  150. package/src/client/domain/git-labels.js +5 -0
  151. package/src/client/domain/hash-routes.js +8 -0
  152. package/src/client/domain/room.js +1 -5
  153. package/src/client/domain/runtime-paths.js +5 -0
  154. package/src/client/domain/vault-paths.js +6 -4
  155. package/src/client/domain/wiki-link-completions.js +20 -20
  156. package/src/client/drawio-editor.js +8 -3
  157. package/src/client/excalidraw-editor.js +287 -16
  158. package/src/client/export/export-host.js +59 -36
  159. package/src/client/export/export-page.js +14 -4
  160. package/src/client/export/export-pipeline.js +270 -42
  161. package/src/client/infrastructure/agent-connection-api-client.js +23 -0
  162. package/src/client/infrastructure/auth-client.js +3 -13
  163. package/src/client/infrastructure/editor-session.js +15 -0
  164. package/src/client/infrastructure/editor-view-adapter.js +73 -14
  165. package/src/client/infrastructure/excalidraw-room-client.js +80 -1
  166. package/src/client/infrastructure/git-api-client.js +39 -33
  167. package/src/client/infrastructure/lobby-presence.js +2 -5
  168. package/src/client/infrastructure/runtime-config.js +11 -1
  169. package/src/client/infrastructure/tab-activity-lock.js +2 -5
  170. package/src/client/infrastructure/vault-api-client.js +33 -26
  171. package/src/client/infrastructure/webmcp-tool-registry.js +283 -0
  172. package/src/client/infrastructure/workspace-sync-client.js +6 -4
  173. package/src/client/presentation/agent-connection-controller.js +255 -0
  174. package/src/client/presentation/backlinks-panel.js +3 -0
  175. package/src/client/presentation/bases-preview-controller.js +59 -26
  176. package/src/client/presentation/comment-ui/comment-ui-card.js +4 -2
  177. package/src/client/presentation/create-menu-presenter.js +19 -16
  178. package/src/client/presentation/excalidraw-embed-controller.js +164 -4
  179. package/src/client/presentation/file-action-controller.js +15 -2
  180. package/src/client/presentation/file-explorer-controller.js +3 -0
  181. package/src/client/presentation/file-explorer-view.js +71 -12
  182. package/src/client/presentation/file-history-view-controller.js +19 -12
  183. package/src/client/presentation/file-tree-state.js +1 -11
  184. package/src/client/presentation/git-diff-view-controller.js +70 -53
  185. package/src/client/presentation/git-panel-controller.js +86 -32
  186. package/src/client/presentation/image-lightbox-controller.js +20 -16
  187. package/src/client/presentation/layout-controller.js +3 -1
  188. package/src/client/presentation/quick-switcher-controller.js +74 -232
  189. package/src/client/presentation/quick-switcher-text-search.js +10 -14
  190. package/src/client/styles/components/navigation.css +1 -2
  191. package/src/client/styles/components/scrollbars.css +10 -0
  192. package/src/client/styles/export-document.css +44 -29
  193. package/src/client/styles/features/agent-connection.css +202 -0
  194. package/src/client/styles/features/collaboration-chat.css +8 -1
  195. package/src/client/styles/features/collaboration-dialogs.css +16 -1
  196. package/src/client/styles/features/collaboration-presence.css +30 -5
  197. package/src/client/styles/features/diff-toolbar.css +1 -1
  198. package/src/client/styles/features/media-lightbox.css +12 -3
  199. package/src/client/styles/features/preview-markdown.css +54 -0
  200. package/src/client/styles/features/quick-switcher.css +20 -11
  201. package/src/client/styles/foundation/themes.css +2 -0
  202. package/src/client/styles/foundation/tokens.css +8 -0
  203. package/src/client/styles/layout/editor-page.css +25 -11
  204. package/src/client/styles/layout/responsive.css +2 -20
  205. package/src/client/styles/layout/shell.css +77 -24
  206. package/src/client/styles/layout/sidebar.css +7 -4
  207. package/src/client/styles/layout/view-modes.css +2 -0
  208. package/src/client/styles/overrides/codemirror.css +31 -19
  209. package/src/client/styles/primitives/controls.css +21 -54
  210. package/src/client/styles/style.css +1 -0
  211. package/src/client/styles/surfaces/excalidraw-editor.css +42 -0
  212. package/src/domain/agent-tool-definitions.js +796 -0
  213. package/src/domain/collabmd-content-capabilities.js +149 -0
  214. package/src/domain/collaboration-protocol.js +2 -0
  215. package/src/domain/comment-threads.js +3 -5
  216. package/src/domain/diagram-source.js +50 -0
  217. package/src/domain/editable-content-revision.js +10 -0
  218. package/src/domain/editable-text.js +3 -0
  219. package/src/domain/exact-text-edits.js +69 -0
  220. package/src/domain/excalidraw-agent-scene.js +522 -0
  221. package/src/domain/excalidraw-agent-verification.js +460 -0
  222. package/src/domain/excalidraw-room-codec.js +1 -5
  223. package/src/domain/file-kind.js +12 -1
  224. package/src/domain/video-embed.js +76 -0
  225. package/src/server/application/agent-connection-service.js +178 -0
  226. package/src/server/application/agent-content-service.js +773 -0
  227. package/src/server/application/workspace-reconciliation.js +5 -7
  228. package/src/server/config/env.js +51 -1
  229. package/src/server/create-app-server.js +36 -0
  230. package/src/server/domain/bases/base-query-service.js +1 -5
  231. package/src/server/domain/collaboration/collaboration-room.js +121 -25
  232. package/src/server/domain/collaboration/protocol.js +4 -0
  233. package/src/server/domain/hosted-workspace.js +21 -0
  234. package/src/server/domain/markdown-reference-extractor.js +15 -1
  235. package/src/server/domain/ripgrep-search-service.js +110 -37
  236. package/src/server/infrastructure/git/git-service.js +19 -1
  237. package/src/server/infrastructure/git/history-service.js +1 -1
  238. package/src/server/infrastructure/git/local-exclude.js +25 -0
  239. package/src/server/infrastructure/git/parsers.js +19 -17
  240. package/src/server/infrastructure/git/path-utils.js +0 -16
  241. package/src/server/infrastructure/git/status-service.js +1 -1
  242. package/src/server/infrastructure/git/untracked-files.js +12 -21
  243. package/src/server/infrastructure/http/create-agent-api-handler.js +171 -0
  244. package/src/server/infrastructure/http/create-git-api-command-handler.js +32 -0
  245. package/src/server/infrastructure/http/create-request-handler.js +28 -0
  246. package/src/server/infrastructure/http/create-static-handler.js +6 -0
  247. package/src/server/infrastructure/mcp/create-agent-mcp-handler.js +199 -0
  248. package/src/server/infrastructure/persistence/agent-connection-store.js +120 -0
  249. package/src/server/infrastructure/persistence/path-utils.js +10 -4
  250. package/src/server/infrastructure/persistence/pull-backup-store.js +2 -27
  251. package/src/server/infrastructure/persistence/vault-file-store.js +11 -2
  252. package/src/server/shared/agent-tool-image.js +22 -0
  253. package/src/server/shared/agent-tool-rate-limiter.js +20 -0
  254. package/src/server/startup/git-remote-bootstrap.js +5 -33
  255. package/dist/client/assets/CodeMirrorEditor-UCMRAMCV-BPH4FJkv.js +0 -1
  256. package/dist/client/assets/abnfDiagram-VCTEODGH-BNDLzJ7L.js +0 -1
  257. package/dist/client/assets/browser-utils--H_DkyEF.js +0 -1
  258. package/dist/client/assets/channel-CaoKA_We.js +0 -1
  259. package/dist/client/assets/chunk-DSNCTWBM-8xkug7fQ.js +0 -2
  260. package/dist/client/assets/chunk-DU6HZSFF-COXDzJK1.js +0 -127
  261. package/dist/client/assets/chunk-R7TYR2AO-CTd0Yj98.js +0 -10
  262. package/dist/client/assets/classDiagram-DTDB5LWJ-7fEmn0zV.js +0 -1
  263. package/dist/client/assets/classDiagram-v2-JRS7N3AN-7fEmn0zV.js +0 -1
  264. package/dist/client/assets/comment-threads-9J6Em-_y.js +0 -4
  265. package/dist/client/assets/comment-ui-shared-DWkk9Vh3.js +0 -7
  266. package/dist/client/assets/diagram-VSXAHHWV-CQRVEZR7.js +0 -3
  267. package/dist/client/assets/dist-73RPdcyU.js +0 -1
  268. package/dist/client/assets/dist-CH-sQu3r.js +0 -1
  269. package/dist/client/assets/drawio-editor-BjrxTe3l.js +0 -9
  270. package/dist/client/assets/drawioEditor-DUVZjSSr.js +0 -2
  271. package/dist/client/assets/ebnfDiagram-PWID7BFC-OXa8VEp1.js +0 -1
  272. package/dist/client/assets/editor-session-DfZuRgB_.js +0 -54
  273. package/dist/client/assets/embedded-editor-base-DvMynhKu.css +0 -1
  274. package/dist/client/assets/excalidraw-editor-D7pnUCLH.js +0 -9
  275. package/dist/client/assets/excalidraw-mermaid-stub-BNckbX2n.js +0 -1
  276. package/dist/client/assets/excalidraw-mermaid-stub-DE5FTiZB.js +0 -1
  277. package/dist/client/assets/excalidrawEditor-B0jOK3lv.js +0 -2
  278. package/dist/client/assets/export-page-Bs3xE1fg.js +0 -57
  279. package/dist/client/assets/exportDocument-Dg9MjkIk.js +0 -2
  280. package/dist/client/assets/exportDocument-PnYU3v1s.css +0 -1
  281. package/dist/client/assets/file-kind-BbqgGzpc.js +0 -1
  282. package/dist/client/assets/flowDiagram-A5DVABFB-CiW1eN8C.js +0 -1
  283. package/dist/client/assets/image-ZVKINSPA-0zXSnE7M.js +0 -1
  284. package/dist/client/assets/index-BIpgxyGZ.css +0 -1
  285. package/dist/client/assets/index-Z5sI0Bj-.js +0 -2
  286. package/dist/client/assets/main-Dwnj9Gaq.js +0 -903
  287. package/dist/client/assets/pegDiagram-XKGWAZYB-B31fKPR2.js +0 -1
  288. package/dist/client/assets/preview-render-compiler-BApvlLLo.js +0 -35
  289. package/dist/client/assets/preview-render-compiler-BQ_3h9vD.js +0 -1
  290. package/dist/client/assets/preview-render-profile-CE-5rVTC.js +0 -1
  291. package/dist/client/assets/prod-BiYPMR1i.js +0 -177
  292. package/dist/client/assets/prod-VxdGZ5Ly.js +0 -1
  293. package/dist/client/assets/quick-switcher-controller-ButWPmCI.js +0 -12
  294. package/dist/client/assets/railroadDiagram-O6MQD6OU-BPifP0MB.js +0 -1
  295. package/dist/client/assets/runtime-config-BLrEKVO1.js +0 -1
  296. package/dist/client/assets/stateDiagram-v2-4QOOHH4V-B--gjrit.js +0 -1
  297. package/dist/client/assets/swimlanesDiagram-VK2B7HYN-DO8XNXEg.js +0 -8
  298. package/dist/client/assets/vault-api-client-_LpV1aIn.js +0 -6
  299. package/dist/client/assets/vault-utils-wdQ0RNR9.js +0 -1
  300. package/src/client/app/drawio-editor-entry.js +0 -1
  301. package/src/client/app/excalidraw-editor-entry.js +0 -1
  302. package/src/client/excalidraw-mermaid-stub.js +0 -7
  303. package/src/client/main.js +0 -16
  304. /package/dist/client/assets/{drawio-editor-UQQ8XHou.css → drawioEditor-UQQ8XHou.css} +0 -0
  305. /package/dist/client/assets/{sizeCapture-X5ZJPWSS-B0uUizjq.js → sizeCapture-INFHLROL-B0uUizjq.js} +0 -0
@@ -2,14 +2,11 @@ import { vim } from '@replit/codemirror-vim';
2
2
  import { autocompletion, closeBrackets, closeBracketsKeymap } from '@codemirror/autocomplete';
3
3
  import {
4
4
  defaultKeymap,
5
- history,
6
- historyKeymap,
7
5
  indentLess,
8
6
  indentMore,
9
7
  indentWithTab,
10
- redo,
11
- undo,
12
8
  } from '@codemirror/commands';
9
+ import { html } from '@codemirror/lang-html';
13
10
  import { markdown, markdownLanguage } from '@codemirror/lang-markdown';
14
11
  import { yaml } from '@codemirror/lang-yaml';
15
12
  import {
@@ -44,15 +41,18 @@ import {
44
41
  lineNumbers,
45
42
  rectangularSelection,
46
43
  } from '@codemirror/view';
47
- import { yCollab } from 'y-codemirror.next';
44
+ import { yCollab, yUndoManagerKeymap } from 'y-codemirror.next';
48
45
 
49
46
  import {
50
47
  isBaseFilePath,
48
+ isHtmlFilePath,
51
49
  isMermaidFilePath,
52
50
  isPlantUmlFilePath,
53
51
  isStructurizrFilePath,
54
52
  } from '../../domain/file-kind.js';
53
+ import { resolveExactTextChanges } from '../../domain/exact-text-edits.js';
55
54
  import { normalizeCommentQuote } from '../../domain/comment-threads.js';
55
+ import { formatDocumentText } from '../domain/document-formatter.js';
56
56
  import { createMarkdownToolbarEdit } from '../domain/markdown-formatting.js';
57
57
  import { mermaidLanguage, mermaidLanguageDescription } from '../domain/mermaid-language.js';
58
58
  import { wikiLinkCompletions } from '../domain/wiki-link-completions.js';
@@ -149,8 +149,6 @@ const EDITOR_COMMANDS = Object.freeze({
149
149
  indentLess,
150
150
  indentMore,
151
151
  openSearch: openSearchPanelPreservingViewport,
152
- redo,
153
- undo,
154
152
  });
155
153
 
156
154
  class RemoteUpdateCaretWidget extends WidgetType {
@@ -391,6 +389,10 @@ function createEditorTheme(theme) {
391
389
  }
392
390
 
393
391
  export function createLanguageExtension(filePath) {
392
+ if (isHtmlFilePath(filePath)) {
393
+ return html();
394
+ }
395
+
394
396
  if (isMermaidFilePath(filePath)) {
395
397
  return mermaidLanguage;
396
398
  }
@@ -441,6 +443,7 @@ export class EditorViewAdapter {
441
443
  this.onSelectionChanged = onSelectionChanged;
442
444
  this.onViewportChanged = onViewportChanged;
443
445
  this.editorView = null;
446
+ this.undoManager = null;
444
447
  this.themeCompartment = new Compartment();
445
448
  this.syntaxThemeCompartment = new Compartment();
446
449
  this.lineWrappingCompartment = new Compartment();
@@ -477,11 +480,11 @@ export class EditorViewAdapter {
477
480
  }
478
481
 
479
482
  getBaseExtensions(filePath, { readOnly = false } = {}) {
483
+ const wikiLinkCompletionSource = wikiLinkCompletions(this.getFileList);
480
484
  const extensions = [
481
485
  lineNumbers(),
482
486
  highlightActiveLineGutter(),
483
487
  highlightSpecialChars(),
484
- history(),
485
488
  foldGutter(),
486
489
  drawSelection(),
487
490
  EditorState.allowMultipleSelections.of(true),
@@ -489,9 +492,10 @@ export class EditorViewAdapter {
489
492
  syntaxHighlighting(defaultHighlightStyle, { fallback: true }),
490
493
  bracketMatching({ renderMatch: renderBracketMatch }),
491
494
  closeBrackets(),
492
- autocompletion({
493
- override: [wikiLinkCompletions(this.getFileList)],
494
- }),
495
+ autocompletion(),
496
+ EditorState.languageData.of(() => [{
497
+ autocomplete: wikiLinkCompletionSource,
498
+ }]),
495
499
  rectangularSelection(),
496
500
  crosshairCursor(),
497
501
  highlightActiveLine(),
@@ -501,7 +505,6 @@ export class EditorViewAdapter {
501
505
  keymap.of([
502
506
  ...closeBracketsKeymap,
503
507
  ...defaultKeymap,
504
- ...historyKeymap,
505
508
  ...searchKeymap.map((binding) => (
506
509
  binding.run === openSearchPanel
507
510
  ? { ...binding, run: openSearchPanelPreservingViewport }
@@ -593,10 +596,12 @@ export class EditorViewAdapter {
593
596
 
594
597
  initialize({ awareness, filePath, undoManager, ytext }) {
595
598
  const preserveScrollTop = this.editorView?.scrollDOM?.scrollTop ?? 0;
599
+ this.undoManager = undoManager;
596
600
  const state = EditorState.create({
597
601
  doc: ytext.toString(),
598
602
  extensions: [
599
603
  ...this.getBaseExtensions(filePath),
604
+ keymap.of(yUndoManagerKeymap),
600
605
  yCollab(ytext, awareness, { undoManager }),
601
606
  ],
602
607
  });
@@ -609,6 +614,7 @@ export class EditorViewAdapter {
609
614
 
610
615
  initializeProvisional({ content = '', filePath }) {
611
616
  const preserveScrollTop = this.editorView?.scrollDOM?.scrollTop ?? 0;
617
+ this.undoManager = null;
612
618
  const state = EditorState.create({
613
619
  doc: String(content ?? ''),
614
620
  extensions: this.getBaseExtensions(filePath, { readOnly: true }),
@@ -629,6 +635,7 @@ export class EditorViewAdapter {
629
635
  clearTimeout(this.remoteUpdateFlashTimer);
630
636
  this.remoteUpdateFlashTimer = 0;
631
637
  }
638
+ this.undoManager = null;
632
639
  this.teardownEditorView({ clearContainer: true });
633
640
  }
634
641
 
@@ -709,18 +716,58 @@ export class EditorViewAdapter {
709
716
  this.editorView?.requestMeasure();
710
717
  }
711
718
 
719
+ async formatDocument(filePath) {
720
+ const view = this.editorView;
721
+ if (!view || view.state.readOnly) {
722
+ return 'unsupported';
723
+ }
724
+
725
+ const source = view.state.doc.toString();
726
+ const formatted = await formatDocumentText(filePath, source);
727
+ if (formatted == null) {
728
+ return 'unsupported';
729
+ }
730
+ if (this.editorView !== view || view.state.doc.toString() !== source) {
731
+ return 'changed';
732
+ }
733
+ if (formatted === source) {
734
+ return 'unchanged';
735
+ }
736
+
737
+ const selection = EditorSelection.create(view.state.selection.ranges.map(({ anchor, head }) => (
738
+ EditorSelection.range(Math.min(anchor, formatted.length), Math.min(head, formatted.length))
739
+ )));
740
+ view.dispatch({
741
+ changes: { from: 0, to: source.length, insert: formatted },
742
+ selection,
743
+ scrollIntoView: true,
744
+ userEvent: 'input.format',
745
+ });
746
+ view.focus();
747
+ return 'formatted';
748
+ }
749
+
712
750
  runEditorCommand(commandId) {
713
751
  if (!this.editorView) {
714
752
  return false;
715
753
  }
716
754
 
717
- const command = EDITOR_COMMANDS[String(commandId ?? '')];
755
+ const normalizedCommandId = String(commandId ?? '');
756
+ if ((normalizedCommandId === 'undo' || normalizedCommandId === 'redo') && this.undoManager) {
757
+ const applied = this.undoManager[normalizedCommandId]() != null;
758
+ if (applied) {
759
+ this.editorView.focus();
760
+ }
761
+ return applied;
762
+ }
763
+
764
+ const command = EDITOR_COMMANDS[normalizedCommandId];
718
765
  if (typeof command !== 'function') {
719
766
  return false;
720
767
  }
721
768
 
722
769
  const applied = command(this.editorView);
723
- if (applied && commandId !== 'openSearch') {
770
+ if (applied && normalizedCommandId !== 'openSearch') {
724
771
  this.editorView.focus();
725
772
  }
726
773
 
@@ -1097,6 +1144,18 @@ export class EditorViewAdapter {
1097
1144
  return true;
1098
1145
  }
1099
1146
 
1147
+ applyTextReplacements(replacements) {
1148
+ if (!this.editorView) {
1149
+ throw new Error('The editor is not available');
1150
+ }
1151
+
1152
+ const { state } = this.editorView;
1153
+ const changes = resolveExactTextChanges(state.doc.toString(), replacements);
1154
+
1155
+ this.editorView.dispatch({ changes, userEvent: 'input' });
1156
+ return changes.length;
1157
+ }
1158
+
1100
1159
  replaceText(text) {
1101
1160
  if (!this.editorView) {
1102
1161
  return false;
@@ -1,5 +1,7 @@
1
1
  import { Doc } from 'yjs';
2
2
  import { WebsocketProvider } from 'y-websocket';
3
+ import * as decoding from 'lib0/decoding';
4
+ import * as encoding from 'lib0/encoding';
3
5
  import {
4
6
  EXCALIDRAW_APP_STATE_KEY,
5
7
  EXCALIDRAW_ELEMENTS_KEY,
@@ -12,6 +14,10 @@ import {
12
14
  readLegacyExcalidrawRoomScene,
13
15
  replaceExcalidrawRoomScene,
14
16
  } from '../../domain/excalidraw-room-codec.js';
17
+ import {
18
+ MSG_AGENT_FLUSH,
19
+ MSG_AGENT_FLUSH_ACK,
20
+ } from '../../domain/collaboration-protocol.js';
15
21
 
16
22
  import {
17
23
  buildCollaboratorsMap,
@@ -33,6 +39,7 @@ import { stopReconnectOnControlledClose } from './yjs-provider-reset-guard.js';
33
39
  const DEFAULT_EMPTY_SCENE_GUARD_MS = 250;
34
40
  const DEFAULT_SAVE_THROTTLE_MS = 48;
35
41
  const DEFAULT_SYNC_TIMEOUT_MS = 4000;
42
+ const DEFAULT_AGENT_FLUSH_TIMEOUT_MS = 1000;
36
43
 
37
44
  export const EXCALIDRAW_ROOM_CONNECTION_STATE = Object.freeze({
38
45
  AUTHORITATIVE: 'authoritative',
@@ -178,6 +185,8 @@ export class ExcalidrawRoomClient {
178
185
  this.lastViewportSignature = '';
179
186
  this.lastSelectedIdsSignature = '';
180
187
  this.pendingEmptySceneCandidate = null;
188
+ this.agentFlushRequestCounter = 0;
189
+ this.pendingAgentFlushRequests = new Map();
181
190
  this.structuredObserversAttached = false;
182
191
  this.canWriteToRoom = false;
183
192
  this.waitingForAuthoritativeSync = false;
@@ -250,6 +259,74 @@ export class ExcalidrawRoomClient {
250
259
  return this.connectionState;
251
260
  }
252
261
 
262
+ installAgentFlushHandler() {
263
+ const messageHandlers = this.provider?.messageHandlers;
264
+ if (!messageHandlers || typeof messageHandlers !== 'object') {
265
+ return false;
266
+ }
267
+
268
+ messageHandlers[MSG_AGENT_FLUSH_ACK] = (_encoder, decoder) => {
269
+ let requestId;
270
+ try {
271
+ requestId = decoding.readVarString(decoder);
272
+ } catch {
273
+ return;
274
+ }
275
+
276
+ const request = this.pendingAgentFlushRequests.get(requestId);
277
+ if (!request) {
278
+ return;
279
+ }
280
+
281
+ request.resolve({ status: 'acknowledged' });
282
+ };
283
+ return true;
284
+ }
285
+
286
+ settleAgentFlushRequests(status) {
287
+ const requests = [...this.pendingAgentFlushRequests.values()];
288
+ requests.forEach((request) => request.resolve({ status }));
289
+ }
290
+
291
+ waitForServerFlush({ timeoutMs = DEFAULT_AGENT_FLUSH_TIMEOUT_MS } = {}) {
292
+ const ws = this.provider?.ws;
293
+ const openState = ws?.OPEN ?? globalThis.WebSocket?.OPEN ?? 1;
294
+ if (
295
+ !this.canWriteToRoom
296
+ || !ws
297
+ || ws.readyState !== openState
298
+ || !this.provider?.messageHandlers?.[MSG_AGENT_FLUSH_ACK]
299
+ ) {
300
+ return Promise.resolve({ status: 'unavailable' });
301
+ }
302
+
303
+ const requestId = `agent-flush-${this.ydoc?.clientID ?? 'client'}-${++this.agentFlushRequestCounter}`;
304
+ return new Promise((resolve) => {
305
+ const finish = (result) => {
306
+ const request = this.pendingAgentFlushRequests.get(requestId);
307
+ if (!request) {
308
+ return;
309
+ }
310
+ this.clearTimeoutFn(request.timeoutId);
311
+ this.pendingAgentFlushRequests.delete(requestId);
312
+ resolve(result);
313
+ };
314
+ this.pendingAgentFlushRequests.set(requestId, {
315
+ resolve: finish,
316
+ timeoutId: this.setTimeoutFn(() => finish({ status: 'timeout' }), timeoutMs),
317
+ });
318
+
319
+ try {
320
+ const encoder = encoding.createEncoder();
321
+ encoding.writeVarUint(encoder, MSG_AGENT_FLUSH);
322
+ encoding.writeVarString(encoder, requestId);
323
+ ws.send(encoding.toUint8Array(encoder));
324
+ } catch {
325
+ finish({ status: 'unavailable' });
326
+ }
327
+ });
328
+ }
329
+
253
330
  hasPendingWrites() {
254
331
  return Boolean(this.pendingSceneSyncPayload);
255
332
  }
@@ -368,6 +445,7 @@ export class ExcalidrawRoomClient {
368
445
  disableBc: true,
369
446
  maxBackoffTime: 5000,
370
447
  });
448
+ this.installAgentFlushHandler();
371
449
  stopReconnectOnControlledClose(this.provider);
372
450
 
373
451
  this.awareness = this.provider.awareness;
@@ -636,7 +714,7 @@ export class ExcalidrawRoomClient {
636
714
  }
637
715
 
638
716
  scheduleSceneSync(elements, appState, files) {
639
- if (!this.canWriteToRoom) {
717
+ if (!this.canWriteToRoom || this.isApplyingSharedSnapshot()) {
640
718
  return false;
641
719
  }
642
720
 
@@ -933,6 +1011,7 @@ export class ExcalidrawRoomClient {
933
1011
 
934
1012
  disconnect() {
935
1013
  this.flushSceneSync();
1014
+ this.settleAgentFlushRequests('disconnected');
936
1015
  this.setConnectionState(EXCALIDRAW_ROOM_CONNECTION_STATE.DISCONNECTING);
937
1016
  this.clearTimeoutFn(this.sceneSyncTimer);
938
1017
  this.sceneSyncTimer = null;
@@ -13,28 +13,37 @@ function createSearchParams(values = {}) {
13
13
  return params;
14
14
  }
15
15
 
16
- export class GitApiClient {
16
+ async function postJson(path, payload, { fallbackError, requestId = null } = {}) {
17
+ const response = await fetch(resolveApiUrl(path), {
18
+ body: JSON.stringify(payload),
19
+ headers: createRequestHeaders(requestId, { 'Content-Type': 'application/json' }),
20
+ method: 'POST',
21
+ });
22
+ return parseApiResponse(response, fallbackError);
23
+ }
24
+
25
+ export const gitApiClient = {
17
26
  async readStatus({ force = false } = {}) {
18
27
  const response = await fetch(resolveApiUrl(`/git/status${force ? '?force=true' : ''}`));
19
28
  return parseApiResponse(response, 'Failed to load git status');
20
- }
29
+ },
21
30
 
22
31
  async readPullBackups() {
23
32
  const response = await fetch(resolveApiUrl('/git/pull-backups'));
24
33
  return parseApiResponse(response, 'Failed to load pull backups');
25
- }
34
+ },
26
35
 
27
36
  async readHistory({ limit, offset } = {}) {
28
37
  const params = createSearchParams({ limit, offset });
29
38
  const response = await fetch(resolveApiUrl(`/git/history?${params.toString()}`));
30
39
  return parseApiResponse(response, 'Failed to load git history');
31
- }
40
+ },
32
41
 
33
42
  async readFileHistory({ path, limit, offset } = {}) {
34
43
  const params = createSearchParams({ limit, offset, path });
35
44
  const response = await fetch(resolveApiUrl(`/git/file-history?${params.toString()}`));
36
45
  return parseApiResponse(response, 'Failed to load file history');
37
- }
46
+ },
38
47
 
39
48
  async readDiff({
40
49
  allowLargePatch = false,
@@ -50,7 +59,7 @@ export class GitApiClient {
50
59
  });
51
60
  const response = await fetch(resolveApiUrl(`/git/diff?${params.toString()}`));
52
61
  return parseApiResponse(response, 'Failed to load git diff');
53
- }
62
+ },
54
63
 
55
64
  async readCommit({
56
65
  allowLargePatch = false,
@@ -66,51 +75,48 @@ export class GitApiClient {
66
75
  });
67
76
  const response = await fetch(resolveApiUrl(`/git/commit?${params.toString()}`));
68
77
  return parseApiResponse(response, 'Failed to load git commit');
69
- }
78
+ },
70
79
 
71
80
  async readFileSnapshot({ hash, path } = {}) {
72
81
  const params = createSearchParams({ hash, path });
73
82
  const response = await fetch(resolveApiUrl(`/git/file-snapshot?${params.toString()}`));
74
83
  return parseApiResponse(response, 'Failed to load historical file preview');
75
- }
84
+ },
76
85
 
77
86
  getFileAttachmentUrl({ hash, path } = {}) {
78
87
  const params = createSearchParams({ hash, path });
79
88
  return resolveApiUrl(`/git/file-attachment?${params.toString()}`);
80
- }
89
+ },
81
90
 
82
91
  async stageFile({ path, requestId = null } = {}) {
83
- return this.#postJson('/git/stage', { path }, { requestId, fallbackError: 'Failed to stage file' });
84
- }
92
+ return postJson('/git/stage', { path }, { requestId, fallbackError: 'Failed to stage file' });
93
+ },
85
94
 
86
95
  async unstageFile({ path, requestId = null } = {}) {
87
- return this.#postJson('/git/unstage', { path }, { requestId, fallbackError: 'Failed to unstage file' });
88
- }
96
+ return postJson('/git/unstage', { path }, { requestId, fallbackError: 'Failed to unstage file' });
97
+ },
98
+
99
+ async stageAll({ requestId = null } = {}) {
100
+ return postJson('/git/stage-all', {}, { requestId, fallbackError: 'Failed to stage all changes' });
101
+ },
102
+
103
+ async unstageAll({ requestId = null } = {}) {
104
+ return postJson('/git/unstage-all', {}, { requestId, fallbackError: 'Failed to unstage all changes' });
105
+ },
89
106
 
90
107
  async pushBranch({ requestId = null } = {}) {
91
- return this.#postJson('/git/push', {}, { requestId, fallbackError: 'Failed to push branch' });
92
- }
108
+ return postJson('/git/push', {}, { requestId, fallbackError: 'Failed to push branch' });
109
+ },
93
110
 
94
111
  async pullBranch({ requestId = null } = {}) {
95
- return this.#postJson('/git/pull', {}, { requestId, fallbackError: 'Failed to pull branch' });
96
- }
112
+ return postJson('/git/pull', {}, { requestId, fallbackError: 'Failed to pull branch' });
113
+ },
97
114
 
98
115
  async resetFile({ path, requestId = null } = {}) {
99
- return this.#postJson('/git/reset-file', { path }, { requestId, fallbackError: 'Failed to reset file' });
100
- }
116
+ return postJson('/git/reset-file', { path }, { requestId, fallbackError: 'Failed to reset file' });
117
+ },
101
118
 
102
119
  async commit({ message, requestId = null } = {}) {
103
- return this.#postJson('/git/commit', { message }, { requestId, fallbackError: 'Failed to commit staged changes' });
104
- }
105
-
106
- async #postJson(path, payload, { fallbackError, requestId = null } = {}) {
107
- const response = await fetch(resolveApiUrl(path), {
108
- body: JSON.stringify(payload),
109
- headers: createRequestHeaders(requestId, { 'Content-Type': 'application/json' }),
110
- method: 'POST',
111
- });
112
- return parseApiResponse(response, fallbackError);
113
- }
114
- }
115
-
116
- export const gitApiClient = new GitApiClient();
120
+ return postJson('/git/commit', { message }, { requestId, fallbackError: 'Failed to commit staged changes' });
121
+ },
122
+ };
@@ -19,11 +19,8 @@ function normalizeChatMessage(value) {
19
19
  }
20
20
 
21
21
  function createLobbyMessageId(peerId) {
22
- if (globalThis.crypto?.randomUUID) {
23
- return globalThis.crypto.randomUUID();
24
- }
25
-
26
- return `${peerId || 'user'}-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;
22
+ return globalThis.crypto?.randomUUID?.()
23
+ ?? `${peerId || 'user'}-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;
27
24
  }
28
25
 
29
26
  function normalizeWorkspaceEvent(event) {
@@ -74,7 +74,7 @@ export function getHashRoute() {
74
74
  }
75
75
 
76
76
  if (params.has(HASH_ROUTE_KEYS.file)) {
77
- return {
77
+ const route = {
78
78
  anchor: params.get('anchor') || null,
79
79
  column: params.has('column') ? Number(params.get('column')) || null : null,
80
80
  drawioMode: params.get('drawio') || null,
@@ -83,6 +83,12 @@ export function getHashRoute() {
83
83
  matchLength: params.has('matchLength') ? Number(params.get('matchLength')) || null : null,
84
84
  type: 'file',
85
85
  };
86
+ const elementId = params.get('element') || '';
87
+ if (elementId) {
88
+ route.elementId = elementId;
89
+ route.elementType = params.get('elementType') === 'group' ? 'group' : 'element';
90
+ }
91
+ return route;
86
92
  }
87
93
 
88
94
  return { type: 'empty' };
@@ -92,6 +98,8 @@ export function navigateToFile(filePath, {
92
98
  anchor = null,
93
99
  column = null,
94
100
  drawioMode = null,
101
+ elementId = null,
102
+ elementType = null,
95
103
  line = null,
96
104
  matchLength = null,
97
105
  } = {}) {
@@ -99,6 +107,8 @@ export function navigateToFile(filePath, {
99
107
  anchor,
100
108
  column,
101
109
  drawioMode,
110
+ elementId,
111
+ elementType,
102
112
  line,
103
113
  matchLength,
104
114
  });
@@ -8,11 +8,8 @@ function now() {
8
8
  }
9
9
 
10
10
  function createTabId() {
11
- if (globalThis.crypto?.randomUUID) {
12
- return globalThis.crypto.randomUUID();
13
- }
14
-
15
- return `tab-${now()}-${Math.random().toString(36).slice(2, 10)}`;
11
+ return globalThis.crypto?.randomUUID?.()
12
+ ?? `tab-${now()}-${Math.random().toString(36).slice(2, 10)}`;
16
13
  }
17
14
 
18
15
  function safeJsonParse(value) {