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
@@ -1,4 +1,6 @@
1
1
  import { execFile as execFileCallback } from 'node:child_process';
2
+ import { glob, readFile, stat } from 'node:fs/promises';
3
+ import { join } from 'node:path';
2
4
  import { promisify } from 'node:util';
3
5
 
4
6
  import { getVaultFileKind } from '../../domain/file-kind.js';
@@ -17,6 +19,8 @@ const TEXT_SEARCH_GLOBS = Object.freeze([
17
19
  '*.md',
18
20
  '*.markdown',
19
21
  '*.mdx',
22
+ '*.html',
23
+ '*.htm',
20
24
  '*.base',
21
25
  '*.mmd',
22
26
  '*.mermaid',
@@ -24,9 +28,15 @@ const TEXT_SEARCH_GLOBS = Object.freeze([
24
28
  '*.plantuml',
25
29
  '*.dsl',
26
30
  '*.drawio',
27
- '*.excalidraw',
28
31
  ]);
29
32
 
33
+ function parseByteLimit(value) {
34
+ const match = String(value ?? '').trim().match(/^(\d+)([KMG])?$/iu);
35
+ if (!match) return 1024 * 1024;
36
+ const multipliers = { K: 1024, M: 1024 ** 2, G: 1024 ** 3 };
37
+ return Number(match[1]) * (multipliers[match[2]?.toUpperCase()] ?? 1);
38
+ }
39
+
30
40
  function normalizePositiveInt(value, fallback, { min = 1, max = Number.MAX_SAFE_INTEGER } = {}) {
31
41
  const parsed = Number.parseInt(value ?? '', 10);
32
42
  if (!Number.isInteger(parsed) || parsed < min) {
@@ -216,6 +226,72 @@ export function parseRipgrepJson(stdout, {
216
226
  };
217
227
  }
218
228
 
229
+ async function searchExcalidrawText({ maxFileSize, maxFiles, maxSnippetsPerFile, query, signal, vaultDir }) {
230
+ const files = [];
231
+ let matchCount = 0;
232
+ let truncated = false;
233
+ const normalizedQuery = query.toLocaleLowerCase();
234
+ const paths = glob('**/*.excalidraw', {
235
+ cwd: vaultDir,
236
+ exclude: ['**/.*', '**/node_modules/**'],
237
+ });
238
+
239
+ for await (const filePath of paths) {
240
+ signal?.throwIfAborted?.();
241
+ const absolutePath = join(vaultDir, filePath);
242
+ if ((await stat(absolutePath)).size > parseByteLimit(maxFileSize)) continue;
243
+
244
+ let scene;
245
+ try {
246
+ scene = JSON.parse(await readFile(absolutePath, 'utf8'));
247
+ } catch {
248
+ continue;
249
+ }
250
+
251
+ const snippets = [];
252
+ let fileMatchCount = 0;
253
+ for (const element of Array.isArray(scene?.elements) ? scene.elements : []) {
254
+ if (element?.isDeleted || element?.type !== 'text' || typeof element.text !== 'string') continue;
255
+ const text = element.text;
256
+ const normalizedText = text.toLocaleLowerCase();
257
+ let matchStart = normalizedText.indexOf(normalizedQuery);
258
+ while (matchStart >= 0) {
259
+ fileMatchCount += 1;
260
+ matchCount += 1;
261
+ if (snippets.length < maxSnippetsPerFile) {
262
+ const snippet = createSnippet(text, matchStart, matchStart + query.length);
263
+ snippets.push({
264
+ column: matchStart + 1,
265
+ line: 1,
266
+ matchEnd: snippet.matchEnd,
267
+ matchStart: snippet.matchStart,
268
+ text: snippet.text,
269
+ });
270
+ } else {
271
+ truncated = true;
272
+ }
273
+ matchStart = normalizedText.indexOf(normalizedQuery, matchStart + Math.max(query.length, 1));
274
+ }
275
+ }
276
+
277
+ if (fileMatchCount > 0) {
278
+ if (files.length >= maxFiles) {
279
+ truncated = true;
280
+ continue;
281
+ }
282
+ files.push({
283
+ file: filePath.replaceAll('\\', '/'),
284
+ kind: 'excalidraw',
285
+ matchCount: fileMatchCount,
286
+ snippets,
287
+ truncated: fileMatchCount > snippets.length,
288
+ });
289
+ }
290
+ }
291
+
292
+ return { files, matchCount, truncated };
293
+ }
294
+
219
295
  export class RipgrepSearchService {
220
296
  constructor({
221
297
  execFileImpl = execFile,
@@ -307,7 +383,7 @@ export class RipgrepSearchService {
307
383
  maxFileSize: this.maxFileSize,
308
384
  maxSnippetsPerFile: this.maxSnippetsPerFile,
309
385
  });
310
-
386
+ let parsed;
311
387
  try {
312
388
  const result = await this.execFileImpl('rg', args, {
313
389
  cwd: this.vaultDir,
@@ -316,56 +392,53 @@ export class RipgrepSearchService {
316
392
  ...(signal ? { signal } : {}),
317
393
  timeout: this.timeoutMs,
318
394
  });
319
- const parsed = parseRipgrepJson(result.stdout, {
395
+ parsed = parseRipgrepJson(result.stdout, {
320
396
  maxFiles,
321
397
  maxSnippetsPerFile: this.maxSnippetsPerFile,
322
398
  query: normalizedQuery,
323
399
  });
324
- parsed.search = this.getClientConfig();
325
-
326
- logPerfEvent(this.perfLoggingEnabled, 'search-query', {
327
- durationMs: Date.now() - startedAt,
328
- fileCount: parsed.files.length,
329
- matchCount: parsed.matchCount,
330
- truncated: parsed.truncated,
331
- });
332
- return parsed;
333
400
  } catch (error) {
334
401
  if (error?.code === 1) {
335
- const empty = createEmptySearchResult({
402
+ parsed = createEmptySearchResult({
336
403
  query: normalizedQuery,
337
404
  searchAvailable: this.available,
338
405
  });
339
- empty.search = this.getClientConfig();
340
- logPerfEvent(this.perfLoggingEnabled, 'search-query', {
341
- durationMs: Date.now() - startedAt,
342
- fileCount: 0,
343
- matchCount: 0,
344
- truncated: false,
406
+ } else {
407
+ const isMaxBuffer = error?.code === 'ERR_CHILD_PROCESS_STDIO_MAXBUFFER';
408
+ parsed = parseRipgrepJson(error?.stdout ?? '', {
409
+ maxFiles,
410
+ maxSnippetsPerFile: this.maxSnippetsPerFile,
411
+ query: normalizedQuery,
345
412
  });
346
- return empty;
413
+ if (isMaxBuffer && parsed.files.length > 0) {
414
+ parsed.truncated = true;
415
+ } else {
416
+ error.statusCode = error?.signal === 'SIGTERM' ? 504 : 500;
417
+ throw error;
418
+ }
347
419
  }
420
+ }
348
421
 
349
- const isMaxBuffer = error?.code === 'ERR_CHILD_PROCESS_STDIO_MAXBUFFER';
350
- const parsed = parseRipgrepJson(error?.stdout ?? '', {
351
- maxFiles,
422
+ if (parsed.files.length < maxFiles) {
423
+ const excalidraw = await searchExcalidrawText({
424
+ maxFileSize: this.maxFileSize,
425
+ maxFiles: maxFiles - parsed.files.length,
352
426
  maxSnippetsPerFile: this.maxSnippetsPerFile,
353
427
  query: normalizedQuery,
428
+ signal,
429
+ vaultDir: this.vaultDir,
354
430
  });
355
- if (isMaxBuffer && parsed.files.length > 0) {
356
- parsed.search = this.getClientConfig();
357
- parsed.truncated = true;
358
- logPerfEvent(this.perfLoggingEnabled, 'search-query', {
359
- durationMs: Date.now() - startedAt,
360
- fileCount: parsed.files.length,
361
- matchCount: parsed.matchCount,
362
- truncated: true,
363
- });
364
- return parsed;
365
- }
366
-
367
- error.statusCode = error?.signal === 'SIGTERM' ? 504 : 500;
368
- throw error;
431
+ parsed.files.push(...excalidraw.files);
432
+ parsed.matchCount += excalidraw.matchCount;
433
+ parsed.truncated ||= excalidraw.truncated;
369
434
  }
435
+ parsed.search = this.getClientConfig();
436
+ logPerfEvent(this.perfLoggingEnabled, 'search-query', {
437
+ durationMs: Date.now() - startedAt,
438
+ fileCount: parsed.files.length,
439
+ matchCount: parsed.matchCount,
440
+ truncated: parsed.truncated,
441
+ });
442
+ return parsed;
370
443
  }
371
444
  }
@@ -146,9 +146,18 @@ export class GitService {
146
146
  };
147
147
  }
148
148
 
149
+ async stageAll() {
150
+ await this.commandRunner.execGit(['add', '-A', '--']);
151
+ this.invalidateStatusCache();
152
+ return {
153
+ ok: true,
154
+ workspaceChange: createEmptyWorkspaceChange(),
155
+ };
156
+ }
157
+
149
158
  async unstageFile(path) {
150
159
  const normalizedPath = normalizeRelativeGitPath(path);
151
- await this.commandRunner.execGit(['reset', 'HEAD', '--', normalizedPath]);
160
+ await this.commandRunner.execGit(['reset', '--', normalizedPath]);
152
161
  this.invalidateStatusCache();
153
162
  return {
154
163
  ok: true,
@@ -157,6 +166,15 @@ export class GitService {
157
166
  };
158
167
  }
159
168
 
169
+ async unstageAll() {
170
+ await this.commandRunner.execGit(['reset', '--']);
171
+ this.invalidateStatusCache();
172
+ return {
173
+ ok: true,
174
+ workspaceChange: createEmptyWorkspaceChange(),
175
+ };
176
+ }
177
+
160
178
  async commitStaged({ author = null, message } = {}) {
161
179
  const normalizedMessage = String(message ?? '').trim();
162
180
  if (!normalizedMessage) {
@@ -233,7 +233,7 @@ export class GitHistoryService {
233
233
  '-n',
234
234
  String(normalizedLimit + 1),
235
235
  '--follow',
236
- '--find-renames=20%',
236
+ '--find-renames',
237
237
  '--date=iso-strict',
238
238
  '--format=%x1e%H%x1f%h%x1f%s%x1f%an%x1f%ae%x1f%aI%x1f%P',
239
239
  '--',
@@ -0,0 +1,25 @@
1
+ import { readFile, writeFile } from 'node:fs/promises';
2
+ import { resolve } from 'node:path';
3
+
4
+ export async function ensureCollabMetadataGitExclude(vaultDir) {
5
+ const excludePath = resolve(vaultDir, '.git/info/exclude');
6
+ let existingContent = '';
7
+
8
+ try {
9
+ existingContent = await readFile(excludePath, 'utf8');
10
+ } catch (error) {
11
+ if (error?.code !== 'ENOENT') {
12
+ throw error;
13
+ }
14
+ }
15
+
16
+ const lines = existingContent
17
+ .split(/\r?\n/u)
18
+ .map((line) => line.trim());
19
+ if (lines.includes('.collabmd') || lines.includes('.collabmd/')) {
20
+ return;
21
+ }
22
+
23
+ const prefix = existingContent && !existingContent.endsWith('\n') ? '\n' : '';
24
+ await writeFile(excludePath, `${existingContent}${prefix}.collabmd/\n`, 'utf8');
25
+ }
@@ -1,4 +1,4 @@
1
- import { decodeQuotedPath, parseRenamePath, stripDiffPrefix } from './path-utils.js';
1
+ import { decodeQuotedPath, stripDiffPrefix } from './path-utils.js';
2
2
  import { createEmptyBranchStatus, createStatusInfo } from './responses.js';
3
3
 
4
4
  function parseBranchLine(line) {
@@ -91,11 +91,8 @@ export function splitContentLines(content) {
91
91
  }
92
92
 
93
93
  export function parseStatusOutput(output) {
94
- const lines = String(output ?? '')
95
- .split(/\r?\n/u)
96
- .filter(Boolean);
97
- const [branchLine = '', ...statusLines] = lines;
98
- const branch = parseBranchLine(branchLine);
94
+ const records = String(output ?? '').split('\0');
95
+ const branch = parseBranchLine(records.shift() || '');
99
96
  const sections = {
100
97
  staged: [],
101
98
  'working-tree': [],
@@ -103,14 +100,15 @@ export function parseStatusOutput(output) {
103
100
  };
104
101
  const uniquePaths = new Set();
105
102
 
106
- for (const line of statusLines) {
107
- if (line.length < 3) {
103
+ for (let index = 0; index < records.length; index += 1) {
104
+ const record = records[index];
105
+ if (record.length < 3) {
108
106
  continue;
109
107
  }
110
108
 
111
- const indexStatus = line[0];
112
- const workTreeStatus = line[1];
113
- const rawPath = line.slice(3);
109
+ const indexStatus = record[0];
110
+ const workTreeStatus = record[1];
111
+ const path = record.slice(3);
114
112
 
115
113
  if (indexStatus === '!' && workTreeStatus === '!') {
116
114
  continue;
@@ -120,7 +118,7 @@ export function parseStatusOutput(output) {
120
118
  const file = {
121
119
  ...createStatusInfo('?'),
122
120
  oldPath: null,
123
- path: decodeQuotedPath(rawPath),
121
+ path,
124
122
  scope: 'untracked',
125
123
  };
126
124
  sections.untracked.push(file);
@@ -128,13 +126,17 @@ export function parseStatusOutput(output) {
128
126
  continue;
129
127
  }
130
128
 
131
- const parsedPath = parseRenamePath(rawPath);
129
+ const hasSourcePath = ['R', 'C'].includes(indexStatus) || ['R', 'C'].includes(workTreeStatus);
130
+ const oldPath = hasSourcePath ? records[index + 1] || null : null;
131
+ if (hasSourcePath) {
132
+ index += 1;
133
+ }
132
134
 
133
135
  if (indexStatus !== ' ') {
134
136
  const file = {
135
137
  ...createStatusInfo(indexStatus),
136
- oldPath: parsedPath.oldPath,
137
- path: parsedPath.path,
138
+ oldPath,
139
+ path,
138
140
  scope: 'staged',
139
141
  };
140
142
  sections.staged.push(file);
@@ -144,8 +146,8 @@ export function parseStatusOutput(output) {
144
146
  if (workTreeStatus !== ' ') {
145
147
  const file = {
146
148
  ...createStatusInfo(workTreeStatus),
147
- oldPath: parsedPath.oldPath,
148
- path: parsedPath.path,
149
+ oldPath,
150
+ path,
149
151
  scope: 'working-tree',
150
152
  };
151
153
  sections['working-tree'].push(file);
@@ -34,22 +34,6 @@ export function normalizeRelativeGitPath(pathValue) {
34
34
  return normalized.join('/');
35
35
  }
36
36
 
37
- export function parseRenamePath(rawPath) {
38
- const decodedPath = decodeQuotedPath(rawPath);
39
- const separator = ' -> ';
40
- const separatorIndex = decodedPath.indexOf(separator);
41
- if (separatorIndex === -1) {
42
- return {
43
- oldPath: null,
44
- path: decodedPath,
45
- };
46
- }
47
-
48
- return {
49
- oldPath: decodedPath.slice(0, separatorIndex),
50
- path: decodedPath.slice(separatorIndex + separator.length),
51
- };
52
- }
53
37
 
54
38
  export function stripDiffPrefix(pathValue) {
55
39
  const normalizedPath = String(pathValue ?? '').replace(/\s+$/u, '');
@@ -42,7 +42,7 @@ export class GitStatusService {
42
42
 
43
43
  const statusPromise = (async () => {
44
44
  const parsed = parseStatusOutput(
45
- await this.commandRunner.execGit(['status', '--porcelain=v1', '--branch', '--untracked-files=all']),
45
+ await this.commandRunner.execGit(['status', '--porcelain=v1', '-z', '--branch', '--untracked-files=all']),
46
46
  );
47
47
  const sections = [
48
48
  { files: parsed.sections.staged, key: 'staged', label: 'Staged Changes' },
@@ -1,6 +1,7 @@
1
1
  import { createReadStream } from 'node:fs';
2
2
  import { readFile } from 'node:fs/promises';
3
3
  import { join } from 'node:path';
4
+ import { createInterface } from 'node:readline';
4
5
 
5
6
  import { getVaultFileKind, isImageAttachmentFilePath } from '../../../domain/file-kind.js';
6
7
  import { mapWithConcurrency } from '../../shared/async-utils.js';
@@ -13,29 +14,19 @@ async function countFileLines(filePath) {
13
14
  return 0;
14
15
  }
15
16
 
16
- return new Promise((resolve, reject) => {
17
- const stream = createReadStream(filePath, { encoding: 'utf8' });
18
- let lineCount = 0;
19
- let sawData = false;
20
- let lastCharacter = '\n';
17
+ const lines = createInterface({
18
+ crlfDelay: Infinity,
19
+ input: createReadStream(filePath, { encoding: 'utf8' }),
20
+ });
21
+ let lineCount = 0;
21
22
 
22
- stream.on('data', (chunk) => {
23
- if (!chunk) {
24
- return;
25
- }
23
+ for await (const line of lines) {
24
+ if (typeof line === 'string') {
25
+ lineCount += 1;
26
+ }
27
+ }
26
28
 
27
- sawData = true;
28
- lastCharacter = chunk[chunk.length - 1];
29
- lineCount += chunk.match(/\n/gu)?.length ?? 0;
30
- });
31
- stream.on('error', reject);
32
- stream.on('end', () => {
33
- if (sawData && lastCharacter !== '\n') {
34
- lineCount += 1;
35
- }
36
- resolve(lineCount);
37
- });
38
- });
29
+ return lineCount;
39
30
  }
40
31
 
41
32
  function buildSyntheticAddedFileDiff(pathValue, content) {
@@ -0,0 +1,171 @@
1
+ import { fromJsonSchema } from '@modelcontextprotocol/server';
2
+
3
+ import { getAgentToolDefinition } from '../../../domain/agent-tool-definitions.js';
4
+ import { encodeAgentToolImage } from '../../shared/agent-tool-image.js';
5
+ import { readRequestId } from './http-request-helpers.js';
6
+ import { jsonResponse } from './http-response.js';
7
+ import { parseJsonBody } from './request-body.js';
8
+
9
+ const WEBMCP_TOOL_PATH = '/api/agent/tools/';
10
+ const WEBMCP_INPUT_SCHEMAS = new Map();
11
+
12
+ function createAgentError(code, message, statusCode) {
13
+ const error = new Error(message);
14
+ error.code = code;
15
+ error.statusCode = statusCode;
16
+ return error;
17
+ }
18
+
19
+ function sendAgentError(req, res, error) {
20
+ const statusCode = Number(error?.statusCode) || 500;
21
+ if (statusCode >= 500) console.error('[agent] Request failed:', error.message);
22
+ jsonResponse(req, res, statusCode, {
23
+ code: error?.code || 'AGENT_REQUEST_FAILED',
24
+ error: statusCode >= 500 ? 'Agent request failed' : error.message,
25
+ ...(Number.isFinite(error?.retryAfterMs) ? { retryAfterMs: error.retryAfterMs } : {}),
26
+ });
27
+ }
28
+
29
+ async function validateWebMcpInput(definition, input) {
30
+ let schema = WEBMCP_INPUT_SCHEMAS.get(definition.name);
31
+ if (!schema) {
32
+ schema = fromJsonSchema(definition.inputSchema);
33
+ WEBMCP_INPUT_SCHEMAS.set(definition.name, schema);
34
+ }
35
+ const validation = await schema['~standard'].validate(input);
36
+ if (validation.issues?.length) {
37
+ throw createAgentError('AGENT_INPUT_INVALID', 'WebMCP tool input does not match its schema', 400);
38
+ }
39
+ }
40
+
41
+ async function createWebMcpActor({ agentConnectionService, authService, config, req }) {
42
+ let subject;
43
+ if (config.auth.strategy === 'none') {
44
+ subject = {
45
+ collaborator: null,
46
+ subjectId: req.socket?.remoteAddress || 'unknown',
47
+ subjectType: 'anonymous',
48
+ };
49
+ } else {
50
+ const user = authService.getAuthenticatedUser?.(req) ?? null;
51
+ subject = await agentConnectionService.resolveManagementSubject(user);
52
+ }
53
+ const actorId = `webmcp:${subject.subjectType}:${subject.subjectId}`;
54
+ return {
55
+ collaborator: subject.collaborator,
56
+ connectionId: actorId,
57
+ origin: 'webmcp',
58
+ rateLimitKey: actorId,
59
+ requestId: readRequestId(req),
60
+ scopes: ['vault:edit', 'vault:read'],
61
+ sourceRef: 'webmcp',
62
+ };
63
+ }
64
+
65
+ async function mapWebMcpResult(definition, value) {
66
+ if (definition.resultKind === 'image' && value.svg) {
67
+ const { data, mimeType, structuredContent } = await encodeAgentToolImage(value);
68
+ return {
69
+ ...structuredContent,
70
+ image: { data, encoding: 'base64', mimeType },
71
+ scene: value.scene,
72
+ };
73
+ }
74
+ if (definition.resultKind === 'optional-image' && value.verification?.svg) {
75
+ const { verification, ...result } = value;
76
+ const { data, mimeType, structuredContent } = await encodeAgentToolImage(verification);
77
+ return {
78
+ ...result,
79
+ image: { data, encoding: 'base64', mimeType },
80
+ verification: {
81
+ ...structuredContent,
82
+ scene: verification.scene,
83
+ },
84
+ };
85
+ }
86
+ return value;
87
+ }
88
+
89
+ export function createAgentApiHandler({
90
+ agentConnectionService,
91
+ agentContentService,
92
+ authService,
93
+ config,
94
+ rateLimiter,
95
+ }) {
96
+ return async function handleAgentApi(req, res, requestUrl) {
97
+ if (!requestUrl.pathname.startsWith('/api/agent')) return false;
98
+
99
+ try {
100
+ if (requestUrl.pathname.startsWith(WEBMCP_TOOL_PATH)) {
101
+ if (req.method !== 'POST') {
102
+ throw createAgentError('AGENT_METHOD_NOT_ALLOWED', 'WebMCP tools require POST', 405);
103
+ }
104
+ const name = decodeURIComponent(requestUrl.pathname.slice(WEBMCP_TOOL_PATH.length));
105
+ const definition = getAgentToolDefinition(name);
106
+ if (!definition?.webMcp) {
107
+ throw createAgentError('AGENT_TOOL_NOT_FOUND', 'WebMCP tool not found', 404);
108
+ }
109
+ const input = await parseJsonBody(req);
110
+ await validateWebMcpInput(definition, input);
111
+ const actor = await createWebMcpActor({
112
+ agentConnectionService,
113
+ authService,
114
+ config,
115
+ req,
116
+ });
117
+ rateLimiter(actor.rateLimitKey);
118
+ const cancellation = new AbortController();
119
+ const abort = () => cancellation.abort();
120
+ req.once('aborted', abort);
121
+ try {
122
+ const value = await agentContentService[definition.method](actor, {
123
+ ...input,
124
+ signal: cancellation.signal,
125
+ });
126
+ jsonResponse(req, res, 200, await mapWebMcpResult(definition, value));
127
+ } finally {
128
+ req.off('aborted', abort);
129
+ }
130
+ return true;
131
+ }
132
+
133
+ if (!config.agentAccess?.enabled) {
134
+ jsonResponse(req, res, 404, { error: 'Agent Access is not enabled' });
135
+ return true;
136
+ }
137
+ const user = authService.getAuthenticatedUser?.(req) ?? null;
138
+ if (requestUrl.pathname === '/api/agent/connections' && req.method === 'GET') {
139
+ jsonResponse(req, res, 200, {
140
+ connections: await agentConnectionService.listConnections(user),
141
+ });
142
+ return true;
143
+ }
144
+ if (requestUrl.pathname === '/api/agent/connections' && req.method === 'POST') {
145
+ const body = await parseJsonBody(req);
146
+ jsonResponse(req, res, 201, await agentConnectionService.createConnection({
147
+ clientKind: body?.clientKind,
148
+ label: body?.label,
149
+ scopes: body?.scopes,
150
+ user,
151
+ }));
152
+ return true;
153
+ }
154
+ if (requestUrl.pathname.startsWith('/api/agent/connections/') && req.method === 'DELETE') {
155
+ const connectionId = decodeURIComponent(
156
+ requestUrl.pathname.slice('/api/agent/connections/'.length).split('/')[0] || '',
157
+ );
158
+ jsonResponse(req, res, 200, await agentConnectionService.revokeConnection({
159
+ connectionId,
160
+ user,
161
+ }));
162
+ return true;
163
+ }
164
+ jsonResponse(req, res, 404, { error: 'Agent endpoint not found' });
165
+ return true;
166
+ } catch (error) {
167
+ sendAgentError(req, res, error);
168
+ return true;
169
+ }
170
+ };
171
+ }
@@ -84,6 +84,38 @@ export function createGitApiCommandHandler({
84
84
  return true;
85
85
  }
86
86
 
87
+ if (requestUrl.pathname === '/api/git/stage-all' && req.method === 'POST') {
88
+ try {
89
+ jsonResponse(req, res, 200, await applyWorkspaceMutationEffects({
90
+ action: 'stage-all',
91
+ req,
92
+ responsePayload: await workspaceMutationCoordinator.runManagedWorkspaceMutation(
93
+ () => gitService.stageAll(),
94
+ ),
95
+ workspaceMutationCoordinator,
96
+ }));
97
+ } catch (error) {
98
+ handleApiError(req, res, error, '[api] Failed to stage all git changes:', 'Failed to stage all git changes');
99
+ }
100
+ return true;
101
+ }
102
+
103
+ if (requestUrl.pathname === '/api/git/unstage-all' && req.method === 'POST') {
104
+ try {
105
+ jsonResponse(req, res, 200, await applyWorkspaceMutationEffects({
106
+ action: 'unstage-all',
107
+ req,
108
+ responsePayload: await workspaceMutationCoordinator.runManagedWorkspaceMutation(
109
+ () => gitService.unstageAll(),
110
+ ),
111
+ workspaceMutationCoordinator,
112
+ }));
113
+ } catch (error) {
114
+ handleApiError(req, res, error, '[api] Failed to unstage all git changes:', 'Failed to unstage all git changes');
115
+ }
116
+ return true;
117
+ }
118
+
87
119
  if (requestUrl.pathname === '/api/git/commit' && req.method === 'POST') {
88
120
  try {
89
121
  const body = await parseRequiredBody(req, res, 'message');