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
@@ -10,11 +10,12 @@
10
10
  * @property {string | null} followedUserClientId
11
11
  * @property {string} followedCursorSignature
12
12
  * @property {{ status: string, unreachable: boolean }} connectionState
13
- * @property {{ displayNameDialog?: HTMLDialogElement | HTMLElement | null, tabLockOverlay?: HTMLElement | null, tabLockTitle?: HTMLElement | null, tabLockCopy?: HTMLElement | null }} elements
13
+ * @property {{ tabLockOverlay?: HTMLDialogElement | null, tabLockTitle?: HTMLElement | null, tabLockCopy?: HTMLElement | null }} elements
14
14
  * @property {{ connect(): void, disconnect(): void, provider?: unknown }} lobby
15
15
  * @property {{ connect(): void, disconnect(): void, provider?: unknown }} workspaceSync
16
16
  * @property {{ show(message: string): void }} toastController
17
17
  * @property {{ tryActivate(options?: { takeover?: boolean }): void }} tabActivityLock
18
+ * @property {{ refresh(): Promise<boolean> }} webMcpTools
18
19
  * @property {{ prepareFileDisconnect(filePath: string): Promise<void> }} excalidrawEmbed
19
20
  * @property {{ handleHashChange(): Promise<void> }} workspaceRouteController
20
21
  * @property {() => boolean} isExcalidrawFile
@@ -35,6 +36,7 @@ function handleTabActivated({ takeover = false } = {}) {
35
36
  const wasInactive = !this.isTabActive;
36
37
  this.isTabActive = true;
37
38
  this.hideTabLockOverlay();
39
+ void this.webMcpTools?.refresh();
38
40
 
39
41
  if (!this.lobby.provider) {
40
42
  this.lobby.connect();
@@ -65,9 +67,7 @@ async function handleTabBlocked({ reason } = {}) {
65
67
  );
66
68
 
67
69
  this.isTabActive = false;
68
- if (this.elements.displayNameDialog?.open) {
69
- this.elements.displayNameDialog.close();
70
- }
70
+ void this.webMcpTools?.refresh();
71
71
  this.lobby.disconnect();
72
72
  this.workspaceSync.disconnect();
73
73
  this.globalUsers = [];
@@ -100,6 +100,11 @@ function showTabLockOverlay({ reason } = {}) {
100
100
  const copy = this.elements.tabLockCopy;
101
101
  if (!overlay) return;
102
102
 
103
+ document.dispatchEvent(new Event('collabmd:close-custom-modals'));
104
+ document.querySelectorAll('dialog[open]').forEach((dialog) => {
105
+ if (dialog !== overlay) dialog.close();
106
+ });
107
+
103
108
  if (title) {
104
109
  title.textContent = reason === 'taken-over'
105
110
  ? 'This tab is no longer active'
@@ -112,12 +117,20 @@ function showTabLockOverlay({ reason } = {}) {
112
117
  : 'To avoid duplicate presence and chat, only one tab can stay connected at a time. Use the other tab, or take over the session here.';
113
118
  }
114
119
 
115
- overlay.classList.remove('hidden');
120
+ if (!overlay.open) {
121
+ this.tabLockPreviouslyFocusedElement = document.activeElement instanceof HTMLElement
122
+ ? document.activeElement
123
+ : null;
124
+ overlay.showModal();
125
+ }
126
+ this.elements.tabLockTakeoverButton?.focus();
116
127
  }
117
128
 
118
129
  /** @this {UiTabActivityContext} */
119
130
  function hideTabLockOverlay() {
120
- this.elements.tabLockOverlay?.classList.add('hidden');
131
+ if (this.elements.tabLockOverlay?.open) this.elements.tabLockOverlay.close();
132
+ this.tabLockPreviouslyFocusedElement?.focus?.();
133
+ this.tabLockPreviouslyFocusedElement = null;
121
134
  }
122
135
 
123
136
  export const uiFeatureTabActivityMethods = {
@@ -39,13 +39,17 @@ function renderBlockMenuMarkup(activeAction) {
39
39
  type="button"
40
40
  class="ui-button ui-button--ghost markdown-toolbar-block-trigger"
41
41
  data-markdown-block-menu-toggle
42
- aria-haspopup="menu"
43
- aria-expanded="false"
42
+ popovertarget="markdownBlockMenuPopover"
44
43
  title="Block formatting"
45
44
  >
46
45
  <span class="markdown-toolbar-block-trigger-label" data-markdown-block-trigger-label>${triggerLabel}</span>
47
46
  <span class="markdown-toolbar-block-trigger-icon" aria-hidden="true">${icons.chevronDown}</span>
48
47
  </button>
48
+ <div id="markdownBlockMenuPopover" class="markdown-toolbar-popover" popover="auto">
49
+ <div class="markdown-toolbar-menu" data-markdown-block-menu role="menu" aria-label="Block formatting">
50
+ ${renderBlockMenuItemsMarkup(activeAction)}
51
+ </div>
52
+ </div>
49
53
  </div>
50
54
  `;
51
55
  }
@@ -111,39 +115,12 @@ function renderMarkdownToolbar() {
111
115
 
112
116
  const activeAction = this.getActiveMarkdownBlockAction();
113
117
  root.innerHTML = renderMarkdownToolbarMarkup(activeAction);
114
- this.renderMarkdownBlockMenuPopover();
115
118
  this.syncMarkdownToolbarBlockUi();
116
119
  }
117
120
 
118
121
  /** @this {UiToolbarContext} */
119
122
  function getMarkdownBlockMenuPopover() {
120
- return this._markdownBlockMenuPopover ?? null;
121
- }
122
-
123
- /** @this {UiToolbarContext} */
124
- function renderMarkdownBlockMenuPopover() {
125
- const mountTarget = this.elements?.editorContainer ?? document.body;
126
- let popover = this.getMarkdownBlockMenuPopover();
127
- if (!popover) {
128
- popover = document.createElement('div');
129
- popover.className = 'markdown-toolbar-popover hidden';
130
- popover.innerHTML = '<div class="markdown-toolbar-menu" data-markdown-block-menu role="menu" aria-label="Block formatting"></div>';
131
- popover.addEventListener('click', (event) => {
132
- this.handleMarkdownToolbarClick?.(event);
133
- });
134
- popover.addEventListener('keydown', (event) => {
135
- this.handleMarkdownToolbarKeydown?.(event);
136
- });
137
- mountTarget?.appendChild(popover);
138
- this._markdownBlockMenuPopover = popover;
139
- } else if (popover.parentElement !== mountTarget) {
140
- mountTarget?.appendChild(popover);
141
- }
142
-
143
- const menu = popover.querySelector('[data-markdown-block-menu]');
144
- if (menu) {
145
- menu.innerHTML = renderBlockMenuItemsMarkup(this.getActiveMarkdownBlockAction());
146
- }
123
+ return document.getElementById('markdownBlockMenuPopover');
147
124
  }
148
125
 
149
126
  /** @this {UiToolbarContext} */
@@ -166,13 +143,7 @@ function syncMarkdownToolbarBlockUi() {
166
143
  toggle.setAttribute('title', `${actionMeta.label}. Block formatting`);
167
144
  }
168
145
 
169
- const popoverItems = Array.from(
170
- this.getMarkdownBlockMenuPopover()?.querySelectorAll('[data-markdown-block-action]') ?? [],
171
- );
172
- const blockActionItems = [
173
- ...root.querySelectorAll('[data-markdown-block-action]'),
174
- ...popoverItems,
175
- ];
146
+ const blockActionItems = root.querySelectorAll('[data-markdown-block-action]');
176
147
  blockActionItems.forEach((item) => {
177
148
  const itemAction = item.getAttribute('data-markdown-block-action');
178
149
  const isActive = itemAction === activeAction;
@@ -194,71 +165,23 @@ function setActiveMarkdownBlockAction(action) {
194
165
 
195
166
  /** @this {UiToolbarContext} */
196
167
  function isMarkdownBlockMenuOpen() {
197
- return Boolean(this.elements?.markdownToolbar?.classList.contains('is-menu-open'));
198
- }
199
-
200
- /** @this {UiToolbarContext} */
201
- function positionMarkdownBlockMenu() {
202
- const popover = this.getMarkdownBlockMenuPopover();
203
- const toggle = this.elements?.markdownToolbar?.querySelector('[data-markdown-block-menu-toggle]');
204
- const mountTarget = popover?.parentElement;
205
- if (!popover || !toggle || !(mountTarget instanceof HTMLElement)) {
206
- return;
207
- }
208
-
209
- const toggleRect = toggle.getBoundingClientRect();
210
- const mountRect = mountTarget.getBoundingClientRect();
211
- const menuRect = popover.getBoundingClientRect();
212
- const menuWidth = menuRect.width || 176;
213
- const menuHeight = menuRect.height || 240;
214
- const horizontalPadding = 8;
215
- const verticalGap = 6;
216
- const preferredLeft = toggleRect.left - mountRect.left;
217
- const maxLeft = Math.max(horizontalPadding, mountRect.width - menuWidth - horizontalPadding);
218
- const preferredTop = (toggleRect.bottom - mountRect.top) + verticalGap;
219
- const fitsBelow = preferredTop + menuHeight <= mountRect.height - horizontalPadding;
220
-
221
- popover.style.left = `${Math.max(horizontalPadding, Math.min(preferredLeft, maxLeft))}px`;
222
- popover.style.top = `${fitsBelow
223
- ? preferredTop
224
- : Math.max(horizontalPadding, (toggleRect.top - mountRect.top) - menuHeight - verticalGap)}px`;
168
+ return Boolean(this.getMarkdownBlockMenuPopover()?.matches(':popover-open'));
225
169
  }
226
170
 
227
171
  /** @this {UiToolbarContext} */
228
172
  function openMarkdownBlockMenu() {
229
- const root = this.elements?.markdownToolbar;
230
- if (!root) {
231
- return;
232
- }
233
-
234
- this.renderMarkdownBlockMenuPopover();
235
- root.classList.add('is-menu-open');
236
173
  const popover = this.getMarkdownBlockMenuPopover();
237
- popover?.classList.remove('hidden');
238
- root.querySelector('[data-markdown-block-menu-toggle]')?.setAttribute('aria-expanded', 'true');
239
- this.positionMarkdownBlockMenu();
240
- }
241
-
242
- /** @this {UiToolbarContext} */
243
- function closeMarkdownBlockMenu() {
244
- const root = this.elements?.markdownToolbar;
245
- if (!root) {
246
- return;
174
+ if (popover && !popover.matches(':popover-open')) {
175
+ popover.showPopover();
247
176
  }
248
-
249
- root.classList.remove('is-menu-open');
250
- this.getMarkdownBlockMenuPopover()?.classList.add('hidden');
251
- root.querySelector('[data-markdown-block-menu-toggle]')?.setAttribute('aria-expanded', 'false');
252
177
  }
253
178
 
254
179
  /** @this {UiToolbarContext} */
255
- function toggleMarkdownBlockMenu() {
256
- if (this.isMarkdownBlockMenuOpen()) {
257
- this.closeMarkdownBlockMenu();
258
- return;
180
+ function closeMarkdownBlockMenu() {
181
+ const popover = this.getMarkdownBlockMenuPopover();
182
+ if (popover?.matches(':popover-open')) {
183
+ popover.hidePopover();
259
184
  }
260
-
261
- this.openMarkdownBlockMenu();
262
185
  }
263
186
 
264
187
  /** @this {UiToolbarContext} */
@@ -276,12 +199,6 @@ function handleMarkdownToolbarClick(event) {
276
199
  return;
277
200
  }
278
201
 
279
- const blockMenuToggle = target.closest('[data-markdown-block-menu-toggle]');
280
- if (blockMenuToggle) {
281
- event.preventDefault();
282
- this.toggleMarkdownBlockMenu();
283
- return;
284
- }
285
202
 
286
203
  const blockActionButton = target.closest('[data-markdown-block-action]');
287
204
  if (blockActionButton) {
@@ -309,7 +226,7 @@ function handleMarkdownToolbarKeydown(event) {
309
226
  const toggle = event.target instanceof Element
310
227
  ? event.target.closest('[data-markdown-block-menu-toggle]')
311
228
  : null;
312
- if (toggle && ['ArrowDown', 'Enter', ' '].includes(event.key)) {
229
+ if (toggle && event.key === 'ArrowDown') {
313
230
  event.preventDefault();
314
231
  this.openMarkdownBlockMenu();
315
232
  this.getMarkdownBlockMenuPopover()?.querySelector('[data-markdown-block-action]')?.focus();
@@ -317,18 +234,7 @@ function handleMarkdownToolbarKeydown(event) {
317
234
  return;
318
235
  }
319
236
 
320
- if (event.key === 'Escape') {
321
- event.preventDefault();
322
- this.closeMarkdownBlockMenu();
323
- this.elements?.markdownToolbar?.querySelector('[data-markdown-block-menu-toggle]')?.focus();
324
- return;
325
- }
326
-
327
237
  const menuItems = Array.from(this.getMarkdownBlockMenuPopover()?.querySelectorAll('[data-markdown-block-action]') ?? []);
328
- if (menuItems.length === 0) {
329
- return;
330
- }
331
-
332
238
  const currentIndex = menuItems.findIndex((item) => item === event.target);
333
239
  if (currentIndex < 0) {
334
240
  return;
@@ -343,21 +249,6 @@ function handleMarkdownToolbarKeydown(event) {
343
249
  }
344
250
  }
345
251
 
346
- /** @this {UiToolbarContext} */
347
- function handleMarkdownToolbarDocumentPointerDown(event) {
348
- if (!this.isMarkdownBlockMenuOpen()) {
349
- return;
350
- }
351
-
352
- if (
353
- this.elements?.markdownToolbar?.contains(event.target)
354
- || this.getMarkdownBlockMenuPopover()?.contains(event.target)
355
- ) {
356
- return;
357
- }
358
-
359
- this.closeMarkdownBlockMenu();
360
- }
361
252
 
362
253
  /** @this {UiToolbarContext} */
363
254
  function applyMarkdownToolbarAction(action) {
@@ -470,16 +361,12 @@ export const uiFeatureToolbarMethods = {
470
361
  getMarkdownBlockMenuPopover,
471
362
  handleEditorImageInsert,
472
363
  handleMarkdownToolbarClick,
473
- handleMarkdownToolbarDocumentPointerDown,
474
364
  handleMarkdownToolbarKeydown,
475
365
  handleToolbarImageInsert,
476
366
  isMarkdownBlockMenuOpen,
477
367
  openMarkdownBlockMenu,
478
- positionMarkdownBlockMenu,
479
- renderMarkdownBlockMenuPopover,
480
368
  renderMarkdownToolbar,
481
369
  runEditorCommand,
482
370
  setActiveMarkdownBlockAction,
483
371
  syncMarkdownToolbarBlockUi,
484
- toggleMarkdownBlockMenu,
485
372
  };
@@ -1,5 +1,8 @@
1
1
  export function bindAppShellElements(doc = document) {
2
2
  return {
3
+ agentConnectionContent: doc.getElementById('agentConnectionContent'),
4
+ agentConnectionDialog: doc.getElementById('agentConnectionDialog'),
5
+ connectAgentButton: doc.getElementById('connectAgentBtn'),
3
6
  currentUserName: doc.getElementById('currentUserName'),
4
7
  chatContainer: doc.getElementById('chatContainer'),
5
8
  chatEmptyState: doc.getElementById('chatEmptyState'),
@@ -35,8 +38,10 @@ export function bindAppShellElements(doc = document) {
35
38
  displayNameInput: doc.getElementById('displayNameInput'),
36
39
  displayNameSubmit: doc.getElementById('displayNameSubmit'),
37
40
  displayNameTitle: doc.getElementById('displayNameTitle'),
41
+ fileActionDialog: doc.getElementById('fileActionDialog'),
38
42
  editNameButton: doc.getElementById('editNameBtn'),
39
43
  editorFindButton: doc.getElementById('editorFindBtn'),
44
+ editorFormatButton: doc.getElementById('editorFormatBtn'),
40
45
  editorContainer: doc.getElementById('editorContainer'),
41
46
  exportDocxButton: doc.getElementById('exportDocxBtn'),
42
47
  exportHtmlButton: doc.getElementById('exportHtmlBtn'),
@@ -55,12 +60,15 @@ export function bindAppShellElements(doc = document) {
55
60
  gitOperationStatus: doc.getElementById('gitOperationStatus'),
56
61
  lineInfo: doc.getElementById('lineInfo'),
57
62
  mobileViewToggle: doc.getElementById('mobileViewToggle'),
63
+ htmlPreviewMaximizeButton: doc.getElementById('htmlPreviewMaximize'),
58
64
  previewContent: doc.getElementById('previewContent'),
59
65
  previewContainer: doc.getElementById('previewContainer'),
66
+ reviewFileChangesButton: doc.getElementById('reviewFileChangesBtn'),
60
67
  presencePanel: doc.getElementById('presencePanel'),
61
68
  presencePanelList: doc.getElementById('presencePanelList'),
62
69
  presencePanelStatus: doc.getElementById('presencePanelStatus'),
63
70
  searchFilesButton: doc.getElementById('searchFilesBtn'),
71
+ skipToEditor: doc.getElementById('skipToEditor'),
64
72
  toolbarSearchButton: doc.getElementById('toolbarSearchBtn'),
65
73
  shareButton: doc.getElementById('shareBtn'),
66
74
  toastContainer: doc.getElementById('toastContainer'),
@@ -4,6 +4,7 @@ import hljs from 'highlight.js';
4
4
  import { isImageAttachmentFilePath } from '../../domain/file-kind.js';
5
5
  import { resolveVaultRelativePath } from '../../domain/vault-paths.js';
6
6
  import { resolveWikiTargetPath } from '../../domain/wiki-link-resolver.js';
7
+ import { classifyPublicVideoEmbed } from '../../domain/video-embed.js';
7
8
  import { escapeHtml } from '../domain/vault-utils.js';
8
9
  import { extractYamlFrontmatter } from '../../domain/yaml-frontmatter.js';
9
10
  import { renderFrontmatterBlock } from './markdown-frontmatter.js';
@@ -12,21 +13,6 @@ import { analyzeMarkdownComplexity } from './preview-render-profile.js';
12
13
  hljs.registerAliases(['cql', 'mariadb', 'mssql', 'mysql', 'plsql', 'sqlite'], { languageName: 'sql' });
13
14
  hljs.registerAliases(['ecmascript', 'node'], { languageName: 'javascript' });
14
15
 
15
- const DIRECT_VIDEO_MIME_TYPES = Object.freeze({
16
- '.mp4': 'video/mp4',
17
- '.ogg': 'video/ogg',
18
- '.webm': 'video/webm',
19
- });
20
-
21
- const YOUTUBE_HOSTS = new Set([
22
- 'youtube.com',
23
- 'www.youtube.com',
24
- 'm.youtube.com',
25
- 'youtu.be',
26
- 'www.youtu.be',
27
- 'youtube-nocookie.com',
28
- 'www.youtube-nocookie.com',
29
- ]);
30
16
 
31
17
  function renderToken(renderer, tokens, index, options, env, self) {
32
18
  return renderer?.(tokens, index, options, env, self) ?? self.renderToken(tokens, index, options);
@@ -192,78 +178,6 @@ function createBaseFileEmbedPlaceholder({ embedKey, label, target, viewName = ''
192
178
  return `<span class="bases-embed-placeholder diagram-preview-shell" data-base-key="${escapeHtml(embedKey)}" data-base-path="${escapeHtml(target)}" data-base-label="${escapeHtml(label)}"${viewAttribute}${sourceFileAttribute}><span class="diagram-preview-placeholder-card"><span class="diagram-preview-placeholder-copy"><strong>${escapeHtml(label)}</strong><span>Loads query results when preview renders</span></span></span></span>`;
193
179
  }
194
180
 
195
- function getDirectVideoMimeType(pathname = '') {
196
- const match = pathname.toLowerCase().match(/\.(mp4|ogg|webm)$/i);
197
- if (!match) {
198
- return null;
199
- }
200
-
201
- return DIRECT_VIDEO_MIME_TYPES[`.${match[1].toLowerCase()}`] || null;
202
- }
203
-
204
- function normalizeYouTubeVideoId(candidate = '') {
205
- const normalized = String(candidate || '').trim();
206
- return /^[A-Za-z0-9_-]{11}$/.test(normalized) ? normalized : null;
207
- }
208
-
209
- function getCanonicalYouTubeEmbedUrl(url) {
210
- const host = url.hostname.toLowerCase();
211
- let videoId = null;
212
-
213
- if (host === 'youtu.be' || host === 'www.youtu.be') {
214
- videoId = normalizeYouTubeVideoId(url.pathname.split('/').filter(Boolean)[0] || '');
215
- } else if (host.includes('youtube') || host.includes('youtube-nocookie')) {
216
- if (url.pathname === '/watch') {
217
- videoId = normalizeYouTubeVideoId(url.searchParams.get('v') || '');
218
- } else if (url.pathname.startsWith('/embed/')) {
219
- videoId = normalizeYouTubeVideoId(url.pathname.split('/').filter(Boolean)[1] || '');
220
- }
221
- }
222
-
223
- if (!videoId) {
224
- return null;
225
- }
226
-
227
- return `https://www.youtube-nocookie.com/embed/${videoId}`;
228
- }
229
-
230
- function classifyPublicVideoEmbed(source = '') {
231
- let url;
232
-
233
- try {
234
- url = new URL(String(source || '').trim());
235
- } catch {
236
- return null;
237
- }
238
-
239
- if (url.protocol !== 'https:') {
240
- return null;
241
- }
242
-
243
- const host = url.hostname.toLowerCase();
244
- if (YOUTUBE_HOSTS.has(host)) {
245
- const embedUrl = getCanonicalYouTubeEmbedUrl(url);
246
- if (!embedUrl) {
247
- return null;
248
- }
249
-
250
- return {
251
- embedUrl,
252
- type: 'youtube',
253
- };
254
- }
255
-
256
- const mimeType = getDirectVideoMimeType(url.pathname);
257
- if (!mimeType) {
258
- return null;
259
- }
260
-
261
- return {
262
- mimeType,
263
- sourceUrl: url.toString(),
264
- type: 'direct-video',
265
- };
266
- }
267
181
 
268
182
  function createVideoEmbedPlaceholder({
269
183
  embedKey,
@@ -6,24 +6,8 @@ import {
6
6
  import { getRenderProfile } from './preview-render-profile.js';
7
7
 
8
8
  export class PreviewRenderScheduler {
9
- constructor({
10
- cancelAnimationFrameFn = (frameId) => cancelAnimationFrame(frameId),
11
- cancelIdleRenderFn = cancelIdleRender,
12
- clearTimeoutFn = (timeoutId) => clearTimeout(timeoutId),
13
- getRenderProfileFn = getRenderProfile,
14
- idleTimeoutMs = IDLE_RENDER_TIMEOUT_MS,
15
- requestAnimationFrameFn = (callback) => requestAnimationFrame(callback),
16
- requestIdleRenderFn = requestIdleRender,
17
- setTimeoutFn = (callback, delay) => setTimeout(callback, delay),
18
- } = {}) {
19
- this.cancelAnimationFrameFn = cancelAnimationFrameFn;
20
- this.cancelIdleRenderFn = cancelIdleRenderFn;
21
- this.clearTimeoutFn = clearTimeoutFn;
9
+ constructor({ getRenderProfileFn = getRenderProfile } = {}) {
22
10
  this.getRenderProfileFn = getRenderProfileFn;
23
- this.idleTimeoutMs = idleTimeoutMs;
24
- this.requestAnimationFrameFn = requestAnimationFrameFn;
25
- this.requestIdleRenderFn = requestIdleRenderFn;
26
- this.setTimeoutFn = setTimeoutFn;
27
11
  this.frameId = null;
28
12
  this.idleId = null;
29
13
  this.timeoutId = null;
@@ -34,7 +18,7 @@ export class PreviewRenderScheduler {
34
18
  this.cancel();
35
19
 
36
20
  const scheduleFrame = () => {
37
- this.frameId = this.requestAnimationFrameFn(() => {
21
+ this.frameId = requestAnimationFrame(() => {
38
22
  this.frameId = null;
39
23
  this.timeoutId = null;
40
24
  onRenderRequested?.(markdownText, renderVersion);
@@ -43,25 +27,25 @@ export class PreviewRenderScheduler {
43
27
 
44
28
  const scheduleRender = () => {
45
29
  if (renderProfile.deferUntilIdle) {
46
- this.idleId = this.requestIdleRenderFn(() => {
30
+ this.idleId = requestIdleRender(() => {
47
31
  this.idleId = null;
48
32
  scheduleFrame();
49
- }, this.idleTimeoutMs);
33
+ }, IDLE_RENDER_TIMEOUT_MS);
50
34
  return;
51
35
  }
52
36
 
53
37
  scheduleFrame();
54
38
  };
55
39
 
56
- this.timeoutId = this.setTimeoutFn(scheduleRender, renderProfile.debounceMs);
40
+ this.timeoutId = setTimeout(scheduleRender, renderProfile.debounceMs);
57
41
  }
58
42
 
59
43
  cancel() {
60
- this.clearTimeoutFn(this.timeoutId);
44
+ clearTimeout(this.timeoutId);
61
45
  if (this.frameId) {
62
- this.cancelAnimationFrameFn(this.frameId);
46
+ cancelAnimationFrame(this.frameId);
63
47
  }
64
- this.cancelIdleRenderFn(this.idleId);
48
+ cancelIdleRender(this.idleId);
65
49
  this.frameId = null;
66
50
  this.idleId = null;
67
51
  this.timeoutId = null;
@@ -3,7 +3,7 @@ import { PlantUmlPreviewHydrator } from './plantuml-preview-hydrator.js';
3
3
  import { DiagramChrome } from './diagram-chrome.js';
4
4
  import { IDLE_RENDER_TIMEOUT_MS } from './preview-diagram-utils.js';
5
5
  import { PreviewRenderExecutor } from './preview-render-executor.js';
6
- import { getRenderProfile, isLargeDocumentStats } from './preview-render-profile.js';
6
+ import { isLargeDocumentStats } from './preview-render-profile.js';
7
7
  import { PreviewRenderScheduler } from './preview-render-scheduler.js';
8
8
  import { resolveApiUrl } from '../domain/runtime-paths.js';
9
9
 
@@ -105,7 +105,7 @@ export class PreviewRenderer {
105
105
  loadFileSource,
106
106
  renderClient: plantUmlRenderClient,
107
107
  });
108
- this.renderScheduler = new PreviewRenderScheduler({ getRenderProfileFn: getRenderProfile });
108
+ this.renderScheduler = new PreviewRenderScheduler();
109
109
  this.renderExecutor = new PreviewRenderExecutor({
110
110
  attachmentApiPath: resolveApiUrl('/attachment'),
111
111
  getFileList: () => this.getFileList?.() ?? [],
@@ -0,0 +1,47 @@
1
+ import { resolveRenderableDiagram } from '../../domain/diagram-source.js';
2
+ import {
3
+ rasterizeSvgMarkupToPngBlob,
4
+ renderMermaidExportSvgMarkup,
5
+ } from './diagram-preview-export.js';
6
+
7
+ export async function renderWebMcpDiagram(input = {}, {
8
+ callTool,
9
+ getMermaid,
10
+ signal,
11
+ } = {}) {
12
+ const requestedStartLine = Number.parseInt(input.startLine, 10);
13
+ const read = await callTool('read_document', {
14
+ lineCount: 500,
15
+ path: input.path,
16
+ startLine: Number.isInteger(requestedStartLine) ? requestedStartLine : 1,
17
+ }, { signal });
18
+ const diagram = resolveRenderableDiagram(read.content, input.path, {
19
+ contentStartLine: read.startLine,
20
+ startLine: input.startLine,
21
+ });
22
+ if (!diagram || diagram.kind !== 'mermaid') {
23
+ return callTool('render_diagram', input, { signal });
24
+ }
25
+ if (read.kind === 'mermaid' && read.truncated) {
26
+ throw new Error('Mermaid source exceeds the WebMCP read limit');
27
+ }
28
+
29
+ const svg = await renderMermaidExportSvgMarkup(await getMermaid(), diagram.source);
30
+ const format = input.format ?? 'png';
31
+ const mimeType = format === 'svg' ? 'image/svg+xml' : 'image/png';
32
+ const bytes = format === 'svg'
33
+ ? new TextEncoder().encode(svg)
34
+ : new Uint8Array(await (await rasterizeSvgMarkupToPngBlob(svg)).arrayBuffer());
35
+ return {
36
+ endLine: diagram.endLine,
37
+ format,
38
+ image: { data: bytes.toBase64(), encoding: 'base64', mimeType },
39
+ kind: diagram.kind,
40
+ mimeType,
41
+ path: read.path,
42
+ renderer: 'mermaid-browser',
43
+ revision: read.revision,
44
+ startLine: diagram.startLine,
45
+ warnings: [],
46
+ };
47
+ }