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
@@ -1,6 +1,7 @@
1
1
  import { setDiagramActionButtonIcon } from '../domain/diagram-action-icons.js';
2
+ import { parseExcalidrawElementLink } from '../domain/excalidraw-element-link.js';
2
3
  import { reconcileEmbedEntries } from './excalidraw-embed-reconciler.js';
3
- import { resolveAppUrl, resolveWsServerOverride } from '../domain/runtime-paths.js';
4
+ import { resolveAppPath, resolveAppUrl, resolveWsServerOverride } from '../domain/runtime-paths.js';
4
5
  import {
5
6
  cancelIdleRender,
6
7
  isNearViewport,
@@ -26,6 +27,7 @@ export class ExcalidrawEmbedController {
26
27
  constructor({
27
28
  getTheme,
28
29
  getLocalUser,
30
+ onOpenElement = null,
29
31
  onOpenFile = null,
30
32
  onStopFollowing = null,
31
33
  onToggleQuickSwitcher = null,
@@ -35,6 +37,7 @@ export class ExcalidrawEmbedController {
35
37
  }) {
36
38
  this.getTheme = getTheme;
37
39
  this.getLocalUser = getLocalUser;
40
+ this.onOpenElement = onOpenElement;
38
41
  this.onOpenFile = onOpenFile;
39
42
  this.onStopFollowing = onStopFollowing;
40
43
  this.onToggleQuickSwitcher = onToggleQuickSwitcher;
@@ -56,6 +59,8 @@ export class ExcalidrawEmbedController {
56
59
  this.followedPeerIdsByFilePath = new Map();
57
60
  this.pendingDisconnectRequests = new Map();
58
61
  this.disconnectRequestCounter = 0;
62
+ this.pendingAgentBridgeRequests = new Map();
63
+ this.agentBridgeRequestCounter = 0;
59
64
 
60
65
  this._onMessage = this._onMessage.bind(this);
61
66
  this._onKeyDown = this._onKeyDown.bind(this);
@@ -96,6 +101,10 @@ export class ExcalidrawEmbedController {
96
101
  request.resolve(false);
97
102
  });
98
103
  this.pendingDisconnectRequests.clear();
104
+ this.pendingAgentBridgeRequests.forEach((request) => {
105
+ request.resolve({ status: 'destroyed' });
106
+ });
107
+ this.pendingAgentBridgeRequests.clear();
99
108
  this.followedPeerIdsByFilePath.clear();
100
109
  this.overlayRoot?.remove();
101
110
  this.overlayRoot = null;
@@ -251,6 +260,28 @@ export class ExcalidrawEmbedController {
251
260
  return true;
252
261
  }
253
262
 
263
+ openElement(filePath, elementId, elementType = 'element') {
264
+ if (!filePath || !elementId) {
265
+ return false;
266
+ }
267
+
268
+ const entry = this._findEntryByFilePath(filePath);
269
+ if (!entry) {
270
+ return false;
271
+ }
272
+
273
+ entry.pendingElementFocus = {
274
+ elementId: String(elementId),
275
+ elementType: elementType === 'group' ? 'group' : 'element',
276
+ };
277
+ if (entry.isReady) {
278
+ this._postPendingElement(entry);
279
+ } else if (!entry.wrapper) {
280
+ this._enqueueHydration(entry, { prioritize: true });
281
+ }
282
+ return true;
283
+ }
284
+
254
285
  prepareFileDisconnect(filePath, { timeoutMs = 10000 } = {}) {
255
286
  const entry = this._findEntryByFilePath(filePath);
256
287
  if (!entry?.iframe?.contentWindow) {
@@ -310,6 +341,73 @@ export class ExcalidrawEmbedController {
310
341
  });
311
342
  }
312
343
 
344
+ flushPendingAgentWrites(filePath, { signal = null, timeoutMs = 1500 } = {}) {
345
+ const entry = this._findEntryByFilePath(filePath);
346
+ if (
347
+ !entry?.isReady
348
+ || !entry.iframe?.contentWindow
349
+ || this._getEntryMode(entry) !== 'edit'
350
+ ) {
351
+ return Promise.resolve({ status: 'not-active' });
352
+ }
353
+ return this._requestAgentBridge(
354
+ entry,
355
+ 'flush-agent-writes',
356
+ {},
357
+ { signal, timeoutMs },
358
+ );
359
+ }
360
+
361
+ waitForAgentPaint(filePath, revision, {
362
+ afterRevision = '',
363
+ signal = null,
364
+ timeoutMs = 5000,
365
+ } = {}) {
366
+ const entry = this._findEntryByFilePath(filePath);
367
+ if (!entry?.isReady || !entry.iframe?.contentWindow || !revision) {
368
+ return Promise.resolve({ status: 'not-active' });
369
+ }
370
+ return this._requestAgentBridge(
371
+ entry,
372
+ 'wait-for-agent-revision',
373
+ { afterRevision, revision },
374
+ { signal, timeoutMs },
375
+ );
376
+ }
377
+
378
+ _requestAgentBridge(entry, type, payload, { signal, timeoutMs }) {
379
+ const requestId = `agent-bridge-${++this.agentBridgeRequestCounter}`;
380
+ return new Promise((resolve) => {
381
+ const finish = (value) => {
382
+ const request = this.pendingAgentBridgeRequests.get(requestId);
383
+ if (!request) return;
384
+ window.clearTimeout(request.timeoutId);
385
+ signal?.removeEventListener?.('abort', request.abort);
386
+ this.pendingAgentBridgeRequests.delete(requestId);
387
+ resolve(value);
388
+ };
389
+ const abort = () => finish({ status: 'cancelled' });
390
+ const timeoutId = window.setTimeout(() => finish({ status: 'timeout' }), timeoutMs);
391
+ this.pendingAgentBridgeRequests.set(requestId, {
392
+ abort,
393
+ entry,
394
+ resolve: finish,
395
+ timeoutId,
396
+ });
397
+ signal?.addEventListener?.('abort', abort, { once: true });
398
+ if (signal?.aborted) {
399
+ abort();
400
+ return;
401
+ }
402
+ this._postMessageToEntry(entry, {
403
+ ...payload,
404
+ requestId,
405
+ source: 'collabmd-host',
406
+ type,
407
+ });
408
+ });
409
+ }
410
+
313
411
  _ensurePlaceholderObserver() {
314
412
  if (!this.previewContainer) {
315
413
  return;
@@ -419,6 +517,9 @@ export class ExcalidrawEmbedController {
419
517
 
420
518
  if (!entry.wrapper) {
421
519
  const mount = this._createEmbedContainer(entry);
520
+ if (!mount) {
521
+ return;
522
+ }
422
523
  entry.header = mount.header;
423
524
  entry.wrapper = mount.wrapper;
424
525
  entry.iframe = mount.iframe;
@@ -491,6 +592,7 @@ export class ExcalidrawEmbedController {
491
592
  reusedEntry.key = nextEntry.key;
492
593
  reusedEntry.label = nextEntry.label;
493
594
  reusedEntry.placeholder = nextEntry.placeholder;
595
+ reusedEntry.pendingElementFocus = null;
494
596
  reusedEntry.queued = false;
495
597
  nextEntries.set(key, reusedEntry);
496
598
  });
@@ -644,7 +746,12 @@ export class ExcalidrawEmbedController {
644
746
  }
645
747
 
646
748
  _buildIframeUrl(entry) {
647
- const iframeUrl = new URL(resolveAppUrl(EDITOR_IFRAME_PATH));
749
+ let iframeUrl;
750
+ try {
751
+ iframeUrl = new URL(resolveAppUrl(EDITOR_IFRAME_PATH));
752
+ } catch {
753
+ return null;
754
+ }
648
755
  const theme = this.getTheme?.() || 'dark';
649
756
 
650
757
  iframeUrl.searchParams.set('file', entry.filePath);
@@ -687,6 +794,11 @@ export class ExcalidrawEmbedController {
687
794
  }
688
795
 
689
796
  _createEmbedContainer(entry) {
797
+ const iframeUrl = this._buildIframeUrl(entry);
798
+ if (!iframeUrl) {
799
+ return null;
800
+ }
801
+
690
802
  const wrapper = document.createElement('div');
691
803
  wrapper.className = 'excalidraw-embed diagram-preview-shell';
692
804
  wrapper.dataset.embedKey = entry.key;
@@ -727,7 +839,7 @@ export class ExcalidrawEmbedController {
727
839
  iframe.className = 'excalidraw-embed-iframe';
728
840
  iframe.dataset.instanceId = String(++this.instanceCounter);
729
841
  entry.instanceId = iframe.dataset.instanceId;
730
- iframe.src = this._buildIframeUrl(entry).toString();
842
+ iframe.src = iframeUrl.toString();
731
843
  // The controller already lazy-hydrates embeds near the viewport, so the
732
844
  // iframe should start loading immediately once it has been mounted.
733
845
  iframe.setAttribute('loading', 'eager');
@@ -1030,6 +1142,7 @@ export class ExcalidrawEmbedController {
1030
1142
  entry.bootMode = null;
1031
1143
  entry.loadedFilePath = null;
1032
1144
  entry.loadedMode = null;
1145
+ entry.pendingElementFocus = null;
1033
1146
  entry.placeholder = null;
1034
1147
  if (entry.wrapper.parentElement !== warmCacheRoot) {
1035
1148
  warmCacheRoot.appendChild(entry.wrapper);
@@ -1053,7 +1166,11 @@ export class ExcalidrawEmbedController {
1053
1166
  entry.bootMode = this._getEntryMode(entry);
1054
1167
  entry.loadedFilePath = null;
1055
1168
  entry.loadedMode = null;
1056
- entry.iframe.src = this._buildIframeUrl(entry).toString();
1169
+ const iframeUrl = this._buildIframeUrl(entry);
1170
+ if (!iframeUrl) {
1171
+ return;
1172
+ }
1173
+ entry.iframe.src = iframeUrl.toString();
1057
1174
  this._armEntryBootTimeout(entry);
1058
1175
  }
1059
1176
 
@@ -1218,6 +1335,7 @@ export class ExcalidrawEmbedController {
1218
1335
  });
1219
1336
  this._syncEntryFollowState(entry);
1220
1337
  this._postPendingCommentThread?.(entry);
1338
+ this._postPendingElement?.(entry);
1221
1339
  if (this._entryNeedsHardReload(entry)) {
1222
1340
  void this._hydrateEntry(entry);
1223
1341
  }
@@ -1234,6 +1352,17 @@ export class ExcalidrawEmbedController {
1234
1352
  return;
1235
1353
  }
1236
1354
 
1355
+ if (msg.type === 'open-element-link') {
1356
+ const target = parseExcalidrawElementLink(msg.href, {
1357
+ appPath: resolveAppPath('/'),
1358
+ origin: window.location.origin,
1359
+ });
1360
+ if (target) {
1361
+ this.onOpenElement?.(target);
1362
+ }
1363
+ return;
1364
+ }
1365
+
1237
1366
  if (msg.type === 'error') {
1238
1367
  if (entry.isParked) {
1239
1368
  return;
@@ -1252,6 +1381,23 @@ export class ExcalidrawEmbedController {
1252
1381
  return;
1253
1382
  }
1254
1383
 
1384
+ if (
1385
+ msg.type === 'agent-writes-flushed'
1386
+ || msg.type === 'agent-revision-painted'
1387
+ || msg.type === 'agent-revision-not-painted'
1388
+ ) {
1389
+ const request = this.pendingAgentBridgeRequests.get(msg.requestId);
1390
+ if (request?.entry === entry) {
1391
+ request.resolve({
1392
+ ...(msg.revision ? { revision: msg.revision } : {}),
1393
+ status: msg.status || (msg.type === 'agent-writes-flushed'
1394
+ ? 'flushed'
1395
+ : (msg.type === 'agent-revision-painted' ? 'painted' : 'not-painted')),
1396
+ });
1397
+ }
1398
+ return;
1399
+ }
1400
+
1255
1401
  if (msg.type === 'disconnect-blocked') {
1256
1402
  entry.authorityState = msg.state || 'reconnecting-readonly';
1257
1403
  this.toastController?.show?.('Waiting for the diagram to reconnect before leaving');
@@ -1300,6 +1446,20 @@ export class ExcalidrawEmbedController {
1300
1446
  entry.pendingCommentThreadId = null;
1301
1447
  }
1302
1448
 
1449
+ _postPendingElement(entry) {
1450
+ if (!entry?.isReady || !entry.pendingElementFocus) {
1451
+ return;
1452
+ }
1453
+
1454
+ this._postMessageToEntry(entry, {
1455
+ elementId: entry.pendingElementFocus.elementId,
1456
+ elementType: entry.pendingElementFocus.elementType,
1457
+ source: 'collabmd-host',
1458
+ type: 'focus-element',
1459
+ });
1460
+ entry.pendingElementFocus = null;
1461
+ }
1462
+
1303
1463
  _requestPreviewViewportFit(entry) {
1304
1464
  if (this._isFilePreviewEntry(entry)) {
1305
1465
  return;
@@ -58,7 +58,10 @@ export class FileExplorerView {
58
58
  this.longPressContext = null;
59
59
  this.suppressedActivationTarget = null;
60
60
  this.contextMenuCloseHandler = null;
61
+ this.contextMenuCloseTimer = null;
62
+ this.contextMenuAnchor = null;
61
63
  this.actionSheetCloseHandler = null;
64
+ this.blockingModalHandler = () => this.removeContextMenu();
62
65
  this.dragSource = null;
63
66
  this.currentSearchQuery = '';
64
67
  this.activeDropTarget = null;
@@ -336,6 +339,8 @@ export class FileExplorerView {
336
339
  button.setAttribute('aria-expanded', String(isExpanded));
337
340
  button.dataset.path = node.path;
338
341
  button.dataset.entryType = 'directory';
342
+ // Dynamic labels are escaped and icons are application-owned markup.
343
+ // pi-lens-ignore: no-inner-html-js
339
344
  button.innerHTML = `
340
345
  <svg class="file-tree-chevron${isExpanded ? ' expanded' : ''}" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="9 18 15 12 9 6"/></svg>
341
346
  <svg class="file-tree-icon" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"/></svg>
@@ -502,6 +507,8 @@ export class FileExplorerView {
502
507
  ${parentPath ? `<span class="file-tree-search-path">${escapeHtml(parentPath)}</span>` : ''}
503
508
  </span>`
504
509
  : `<span class="file-tree-name">${escapeHtml(displayName)}</span>`;
510
+ // Dynamic labels are escaped and icons are application-owned markup.
511
+ // pi-lens-ignore: no-inner-html-js
505
512
  button.innerHTML = `
506
513
  ${getVaultFileIconSvg(filePath)}
507
514
  ${nameMarkup}
@@ -965,18 +972,23 @@ export class FileExplorerView {
965
972
  return;
966
973
  }
967
974
 
975
+ const contextAnchor = event.currentTarget instanceof Element ? event.currentTarget : event.target;
976
+ this.contextMenuAnchor = contextAnchor instanceof HTMLElement ? contextAnchor : null;
968
977
  if (this.isMobileViewport()) {
969
978
  this.showActionSheet(items);
970
979
  return;
971
980
  }
972
981
 
973
- const contextAnchor = event.currentTarget instanceof Element ? event.currentTarget : event.target;
974
982
  const menu = document.createElement('div');
975
983
  menu.className = 'file-context-menu';
984
+ menu.setAttribute('role', 'menu');
985
+ menu.setAttribute('aria-label', 'File actions');
976
986
 
977
987
  for (const item of items) {
978
988
  const button = document.createElement('button');
989
+ button.type = 'button';
979
990
  button.className = `file-context-item${item.danger ? ' file-context-danger' : ''}`;
991
+ button.setAttribute('role', 'menuitem');
980
992
  button.textContent = item.label;
981
993
  button.addEventListener('click', () => {
982
994
  this.removeContextMenu();
@@ -999,17 +1011,47 @@ export class FileExplorerView {
999
1011
  }
1000
1012
  };
1001
1013
  this.contextMenuCloseHandler = close;
1002
- setTimeout(() => document.addEventListener('click', close), 0);
1014
+ const handleKeydown = (keyEvent) => {
1015
+ const buttons = Array.from(menu.querySelectorAll('[role="menuitem"]'));
1016
+ const index = Math.max(0, buttons.indexOf(document.activeElement));
1017
+ if (keyEvent.key === 'Escape') {
1018
+ keyEvent.preventDefault();
1019
+ this.removeContextMenu();
1020
+ return;
1021
+ }
1022
+ if (keyEvent.key === 'Tab') {
1023
+ this.removeContextMenu({ restoreFocus: false });
1024
+ return;
1025
+ }
1026
+ const nextIndex = keyEvent.key === 'Home'
1027
+ ? 0
1028
+ : keyEvent.key === 'End'
1029
+ ? buttons.length - 1
1030
+ : keyEvent.key === 'ArrowDown'
1031
+ ? (index + 1) % buttons.length
1032
+ : keyEvent.key === 'ArrowUp'
1033
+ ? (index - 1 + buttons.length) % buttons.length
1034
+ : -1;
1035
+ if (nextIndex >= 0) {
1036
+ keyEvent.preventDefault();
1037
+ buttons[nextIndex]?.focus();
1038
+ }
1039
+ };
1040
+ menu.addEventListener('keydown', handleKeydown);
1041
+ document.addEventListener('collabmd:close-custom-modals', this.blockingModalHandler);
1042
+ this.contextMenuCloseTimer = setTimeout(() => {
1043
+ this.contextMenuCloseTimer = null;
1044
+ if (menu.isConnected && this.contextMenuCloseHandler === close) {
1045
+ document.addEventListener('click', close);
1046
+ }
1047
+ }, 0);
1048
+ menu.querySelector('[role="menuitem"]')?.focus();
1003
1049
  }
1004
1050
 
1005
1051
  showActionSheet(items) {
1006
- const backdrop = document.createElement('button');
1007
- backdrop.type = 'button';
1008
- backdrop.className = 'file-action-sheet-backdrop';
1009
- backdrop.setAttribute('aria-label', 'Close file actions');
1010
-
1011
- const sheet = document.createElement('div');
1052
+ const sheet = document.createElement('dialog');
1012
1053
  sheet.className = 'file-action-sheet';
1054
+ sheet.setAttribute('aria-label', 'File actions');
1013
1055
 
1014
1056
  items.forEach((item) => {
1015
1057
  const button = document.createElement('button');
@@ -1038,26 +1080,42 @@ export class FileExplorerView {
1038
1080
  });
1039
1081
  sheet.appendChild(cancelButton);
1040
1082
 
1041
- backdrop.addEventListener('click', () => {
1083
+ sheet.addEventListener('cancel', (event) => {
1084
+ event.preventDefault();
1042
1085
  this.removeContextMenu();
1043
1086
  });
1087
+ sheet.addEventListener('click', (event) => {
1088
+ const bounds = sheet.getBoundingClientRect();
1089
+ if (event.clientX < bounds.left || event.clientX > bounds.right
1090
+ || event.clientY < bounds.top || event.clientY > bounds.bottom) this.removeContextMenu();
1091
+ });
1044
1092
 
1045
- document.body.append(backdrop, sheet);
1093
+ document.body.append(sheet);
1094
+ document.addEventListener('collabmd:close-custom-modals', this.blockingModalHandler);
1046
1095
  this.actionSheetCloseHandler = () => {
1047
- backdrop.remove();
1096
+ if (sheet.open) sheet.close();
1048
1097
  sheet.remove();
1049
1098
  this.actionSheetCloseHandler = null;
1050
1099
  };
1100
+ sheet.showModal();
1101
+ sheet.querySelector('button:not(:disabled)')?.focus();
1051
1102
  }
1052
1103
 
1053
- removeContextMenu() {
1104
+ removeContextMenu({ restoreFocus = true } = {}) {
1054
1105
  this.cancelLongPress();
1055
1106
  this.clearDragFeedback();
1056
1107
  document.querySelectorAll('.file-context-menu').forEach((menu) => menu.remove());
1108
+ if (this.contextMenuCloseTimer !== null) {
1109
+ clearTimeout(this.contextMenuCloseTimer);
1110
+ this.contextMenuCloseTimer = null;
1111
+ }
1057
1112
  if (this.contextMenuCloseHandler) {
1058
1113
  document.removeEventListener('click', this.contextMenuCloseHandler);
1059
1114
  this.contextMenuCloseHandler = null;
1060
1115
  }
1116
+ document.removeEventListener('collabmd:close-custom-modals', this.blockingModalHandler);
1061
1117
  this.actionSheetCloseHandler?.();
1118
+ if (restoreFocus) this.contextMenuAnchor?.focus?.();
1119
+ this.contextMenuAnchor = null;
1062
1120
  }
1063
1121
  }
@@ -544,12 +544,14 @@ export class FileHistoryViewController {
544
544
  this.actionsDivider?.classList.add('hidden');
545
545
  this.editorActionsGroup?.classList.remove('hidden');
546
546
  this.modeButtons.forEach((button) => {
547
+ const active = button.getAttribute('data-diff-mode') === this.diffMode;
547
548
  button.classList.toggle('hidden', !hasSelection);
548
- button.classList.toggle('active', button.getAttribute('data-diff-mode') === this.diffMode);
549
+ button.classList.toggle('active', active);
550
+ button.setAttribute?.('aria-pressed', String(active));
549
551
  });
550
552
  this.openEditorButton?.toggleAttribute('disabled', !this.currentFilePath);
551
553
  if (this.openEditorButton) {
552
- this.openEditorButton.textContent = 'Open File';
554
+ this.openEditorButton.textContent = 'Open file';
553
555
  }
554
556
  this.primaryActionButton?.toggleAttribute('disabled', true);
555
557
  this.commitButton?.toggleAttribute('disabled', true);
@@ -562,13 +564,13 @@ export class FileHistoryViewController {
562
564
  this.page?.classList.remove('hidden');
563
565
  if (this.content) {
564
566
  this.content.classList.add('diff-content--history');
565
- this.content.innerHTML = '<div class="git-panel-empty">Loading file history...</div>';
567
+ this.content.innerHTML = '<div class="git-panel-empty" role="status" aria-live="polite">Loading file history…</div>';
566
568
  }
567
569
  this.historyListElement = null;
568
570
  this.syncToolbar();
569
571
  }
570
572
 
571
- renderEmpty(message) {
573
+ renderEmpty(message, { alert = false } = {}) {
572
574
  if (!this.isActive) {
573
575
  return;
574
576
  }
@@ -576,7 +578,7 @@ export class FileHistoryViewController {
576
578
  if (this.content) {
577
579
  this.content.classList.add('diff-content--history');
578
580
  // pi-lens-ignore: no-inner-html-js
579
- this.content.innerHTML = `<div class="git-panel-empty">${escapeHtml(message)}</div>`;
581
+ this.content.innerHTML = `<div class="git-panel-empty"${alert ? ' role="alert"' : ''}>${escapeHtml(message)}</div>`;
580
582
  }
581
583
  this.historyListElement = null;
582
584
  this.syncToolbar();
@@ -691,7 +693,7 @@ export class FileHistoryViewController {
691
693
  type="button"
692
694
  data-file-history-open-selected-diff
693
695
  >
694
- Open Standalone Diff
696
+ Open standalone diff
695
697
  </button>
696
698
  ${entry.type === 'commit' ? `
697
699
  <button
@@ -699,7 +701,7 @@ export class FileHistoryViewController {
699
701
  type="button"
700
702
  data-file-history-open-selected-preview
701
703
  >
702
- Preview File
704
+ Preview file
703
705
  </button>
704
706
  ` : ''}
705
707
  </div>
@@ -719,7 +721,7 @@ export class FileHistoryViewController {
719
721
  <div class="diff-file-header">
720
722
  <span class="diff-file-path">${escapeHtml(entry.pathAtCommit || this.currentFilePath || '')}</span>
721
723
  </div>
722
- <div class="diff-empty-state">Loading diff...</div>
724
+ <div class="diff-empty-state" role="status" aria-live="polite">Loading diff…</div>
723
725
  </section>
724
726
  `;
725
727
  }
@@ -728,7 +730,7 @@ export class FileHistoryViewController {
728
730
  return `
729
731
  <section class="diff-file-block file-history-diff-block">
730
732
  ${this.renderDiffFileHeader({ path: entry.pathAtCommit || this.currentFilePath || '' })}
731
- <div class="diff-empty-state">${escapeHtml(selection.error)}</div>
733
+ <div class="diff-empty-state" role="alert">${escapeHtml(selection.error)}</div>
732
734
  </section>
733
735
  `;
734
736
  }
@@ -764,7 +766,7 @@ export class FileHistoryViewController {
764
766
 
765
767
  const hasRows = Boolean(this.localChanges) || (this.history.commits?.length ?? 0) > 0;
766
768
  if (!hasRows) {
767
- this.renderEmpty(this.history.error || 'No history found for this file.');
769
+ this.renderEmpty(this.history.error || 'No history found for this file.', { alert: Boolean(this.history.error) });
768
770
  return;
769
771
  }
770
772
 
@@ -794,7 +796,7 @@ export class FileHistoryViewController {
794
796
  data-file-history-load-more
795
797
  ${this.history.loadingMore ? 'disabled' : ''}
796
798
  >
797
- ${this.history.loadingMore ? 'Loading...' : 'Load More'}
799
+ ${this.history.loadingMore ? 'Loading' : 'Load more'}
798
800
  </button>
799
801
  </div>
800
802
  ` : ''}