shadow-claw 1.31.0 → 1.33.0

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 (231) hide show
  1. package/.well-known/mcp/server-card.json +1 -1
  2. package/.well-known/mcp.json +1 -1
  3. package/dist/electron/main.cjs +1 -1
  4. package/dist/lib/components/index.js +26 -26
  5. package/dist/lib/components/settings/shadow-claw-accounts.js +1 -1
  6. package/dist/lib/components/settings/shadow-claw-channel-config.js +1 -1
  7. package/dist/lib/components/settings/shadow-claw-control-plane.js +1 -1
  8. package/dist/lib/components/settings/shadow-claw-git.js +1 -1
  9. package/dist/lib/components/settings/shadow-claw-integrations.js +1 -1
  10. package/dist/lib/components/settings/shadow-claw-llm.js +1 -1
  11. package/dist/lib/components/settings/shadow-claw-mcp-remote.js +1 -1
  12. package/dist/lib/components/settings/shadow-claw-networking.js +1 -1
  13. package/dist/lib/components/settings/shadow-claw-notifications.js +1 -1
  14. package/dist/lib/components/settings/shadow-claw-peerjs.js +1 -1
  15. package/dist/lib/components/settings/shadow-claw-storage.js +1 -1
  16. package/dist/lib/components/settings/shadow-claw-task-server.js +1 -1
  17. package/dist/lib/components/settings/shadow-claw-webvm.js +1 -1
  18. package/dist/lib/components/shadow-claw-a2ui.js +1 -1
  19. package/dist/lib/components/shadow-claw-accounts.js +1 -1
  20. package/dist/lib/components/shadow-claw-channel-config.js +1 -1
  21. package/dist/lib/components/shadow-claw-channels.js +1 -1
  22. package/dist/lib/components/shadow-claw-chat.js +1 -1
  23. package/dist/lib/components/shadow-claw-control-plane.js +1 -1
  24. package/dist/lib/components/shadow-claw-conversations.js +1 -1
  25. package/dist/lib/components/shadow-claw-file-viewer.js +1 -1
  26. package/dist/lib/components/shadow-claw-files.js +1 -1
  27. package/dist/lib/components/shadow-claw-git.js +1 -1
  28. package/dist/lib/components/shadow-claw-integrations.js +1 -1
  29. package/dist/lib/components/shadow-claw-llm.js +1 -1
  30. package/dist/lib/components/shadow-claw-mcp-remote.js +1 -1
  31. package/dist/lib/components/shadow-claw-networking.js +1 -1
  32. package/dist/lib/components/shadow-claw-notifications.js +1 -1
  33. package/dist/lib/components/shadow-claw-page-header.js +1 -1
  34. package/dist/lib/components/shadow-claw-pages.js +1 -1
  35. package/dist/lib/components/shadow-claw-peerjs.js +1 -1
  36. package/dist/lib/components/shadow-claw-settings.js +1 -1
  37. package/dist/lib/components/shadow-claw-storage.js +1 -1
  38. package/dist/lib/components/shadow-claw-task-server.js +1 -1
  39. package/dist/lib/components/shadow-claw-tasks.js +1 -1
  40. package/dist/lib/components/shadow-claw-terminal.js +1 -1
  41. package/dist/lib/components/shadow-claw-tools.js +1 -1
  42. package/dist/lib/components/shadow-claw-webvm.js +1 -1
  43. package/dist/lib/components/shadow-claw.js +1 -1
  44. package/dist/lib/{config-DjZ9QWc4.js → config-BcFbkaQv.js} +21 -4
  45. package/dist/lib/config-BcFbkaQv.js.map +1 -0
  46. package/dist/lib/{configurePeerJs-u7CYSquX.js → configurePeerJs-CBMPHbwa.js} +3 -3
  47. package/dist/lib/{configurePeerJs-u7CYSquX.js.map → configurePeerJs-CBMPHbwa.js.map} +1 -1
  48. package/dist/lib/{connections-BURqMIUv.js → connections-PZrUDf49.js} +2 -2
  49. package/dist/lib/{connections-BURqMIUv.js.map → connections-PZrUDf49.js.map} +1 -1
  50. package/dist/lib/{downloadGroupFile-B8J4up2a.js → downloadGroupFile-DSRUa9Au.js} +2 -2
  51. package/dist/lib/{downloadGroupFile-B8J4up2a.js.map → downloadGroupFile-DSRUa9Au.js.map} +1 -1
  52. package/dist/lib/{file-viewer-DoHM75Jz.js → file-viewer-11VVOpJv.js} +5 -5
  53. package/dist/lib/{file-viewer-DoHM75Jz.js.map → file-viewer-11VVOpJv.js.map} +1 -1
  54. package/dist/lib/{getGroupDir-QrN2aTo8.js → getGroupDir-BxKMYPPm.js} +3 -3
  55. package/dist/lib/{getGroupDir-QrN2aTo8.js.map → getGroupDir-BxKMYPPm.js.map} +1 -1
  56. package/dist/lib/{git-DAP_EV6R.js → git-BppibnJW.js} +27 -10
  57. package/dist/lib/{git-DAP_EV6R.js.map → git-BppibnJW.js.map} +1 -1
  58. package/dist/lib/{iframe-sanitizer-Bujgq14T.js → iframe-sanitizer-Dp8EYffI.js} +2 -2
  59. package/dist/lib/{iframe-sanitizer-Bujgq14T.js.map → iframe-sanitizer-Dp8EYffI.js.map} +1 -1
  60. package/dist/lib/index.js +27 -27
  61. package/dist/lib/{initChatSplitResize-BjiWoqC_.js → initChatSplitResize-CE_kWaLf.js} +2 -2
  62. package/dist/lib/{initChatSplitResize-BjiWoqC_.js.map → initChatSplitResize-CE_kWaLf.js.map} +1 -1
  63. package/dist/lib/{initControlPlane-DCK_SHeR.js → initControlPlane-BRIIOzoH.js} +18 -17
  64. package/dist/lib/{initControlPlane-DCK_SHeR.js.map → initControlPlane-BRIIOzoH.js.map} +1 -1
  65. package/dist/lib/{markdown-BFUTPQoO.js → markdown-Cq4sVwUT.js} +4 -4
  66. package/dist/lib/{markdown-BFUTPQoO.js.map → markdown-Cq4sVwUT.js.map} +1 -1
  67. package/dist/lib/{mcp-reconnect-BxJ77WSb.js → mcp-reconnect-CoHDMjmY.js} +2 -2
  68. package/dist/lib/{mcp-reconnect-BxJ77WSb.js.map → mcp-reconnect-CoHDMjmY.js.map} +1 -1
  69. package/dist/lib/{memoryStorage-D3FBwO9T.js → memoryStorage-DcFWrn_y.js} +2 -2
  70. package/dist/lib/{memoryStorage-D3FBwO9T.js.map → memoryStorage-DcFWrn_y.js.map} +1 -1
  71. package/dist/lib/{orchestrator-DNamnY-k.js → orchestrator-C3TgDZvq.js} +100 -19
  72. package/dist/lib/{orchestrator-DNamnY-k.js.map → orchestrator-C3TgDZvq.js.map} +1 -1
  73. package/dist/lib/{orchestrator-XygttQw2.js → orchestrator-Ce9_lmL2.js} +12 -12
  74. package/dist/lib/{orchestrator-XygttQw2.js.map → orchestrator-Ce9_lmL2.js.map} +1 -1
  75. package/dist/lib/{peerjs-BgkPSHKa.js → peerjs-PTYQ7yEG.js} +6 -6
  76. package/dist/lib/{peerjs-BgkPSHKa.js.map → peerjs-PTYQ7yEG.js.map} +1 -1
  77. package/dist/lib/{push-client-C09NQEk5.js → push-client-DDV5Rcg6.js} +3 -3
  78. package/dist/lib/{push-client-C09NQEk5.js.map → push-client-DDV5Rcg6.js.map} +1 -1
  79. package/dist/lib/{readGroupFileBytes-CSA7u-nJ.js → readGroupFileBytes-7C8G-yps.js} +2 -2
  80. package/dist/lib/{readGroupFileBytes-CSA7u-nJ.js.map → readGroupFileBytes-7C8G-yps.js.map} +1 -1
  81. package/dist/lib/{shadow-claw-vzcggiax.js → shadow-claw-WrWoPqFx.js} +10 -10
  82. package/dist/lib/{shadow-claw-vzcggiax.js.map → shadow-claw-WrWoPqFx.js.map} +1 -1
  83. package/dist/lib/{shadow-claw-a2ui-2I5nffIn.js → shadow-claw-a2ui-CcmJNXQP.js} +2 -2
  84. package/dist/lib/{shadow-claw-a2ui-2I5nffIn.js.map → shadow-claw-a2ui-CcmJNXQP.js.map} +1 -1
  85. package/dist/lib/{shadow-claw-accounts-DMb0y4ca.js → shadow-claw-accounts-CcB2429E.js} +3 -3
  86. package/dist/lib/{shadow-claw-accounts-DMb0y4ca.js.map → shadow-claw-accounts-CcB2429E.js.map} +1 -1
  87. package/dist/lib/{shadow-claw-channel-config-Cl3JvxIJ.js → shadow-claw-channel-config-C4v0h8oa.js} +3 -3
  88. package/dist/lib/{shadow-claw-channel-config-Cl3JvxIJ.js.map → shadow-claw-channel-config-C4v0h8oa.js.map} +1 -1
  89. package/dist/lib/{shadow-claw-channels-kv21lr_O.js → shadow-claw-channels-CyV88k9T.js} +3 -3
  90. package/dist/lib/{shadow-claw-channels-kv21lr_O.js.map → shadow-claw-channels-CyV88k9T.js.map} +1 -1
  91. package/dist/lib/{shadow-claw-chat-Cj1fHQIl.js → shadow-claw-chat-DSYtuZod.js} +11 -11
  92. package/dist/lib/{shadow-claw-chat-Cj1fHQIl.js.map → shadow-claw-chat-DSYtuZod.js.map} +1 -1
  93. package/dist/lib/{shadow-claw-control-plane-DySeKB36.js → shadow-claw-control-plane-DBSGuDT1.js} +7 -7
  94. package/dist/lib/{shadow-claw-control-plane-DySeKB36.js.map → shadow-claw-control-plane-DBSGuDT1.js.map} +1 -1
  95. package/dist/lib/{shadow-claw-conversations-DghueOOD.js → shadow-claw-conversations-Cp8pK4PM.js} +5 -5
  96. package/dist/lib/{shadow-claw-conversations-DghueOOD.js.map → shadow-claw-conversations-Cp8pK4PM.js.map} +1 -1
  97. package/dist/lib/{shadow-claw-file-viewer-C_ITv8T6.js → shadow-claw-file-viewer-B8G8yo48.js} +8 -8
  98. package/dist/lib/{shadow-claw-file-viewer-C_ITv8T6.js.map → shadow-claw-file-viewer-B8G8yo48.js.map} +1 -1
  99. package/dist/lib/{shadow-claw-files-CWBaYt9p.js → shadow-claw-files-D1COKzuC.js} +9 -9
  100. package/dist/lib/{shadow-claw-files-CWBaYt9p.js.map → shadow-claw-files-D1COKzuC.js.map} +1 -1
  101. package/dist/lib/{shadow-claw-git-XfPBpfXd.js → shadow-claw-git-60tWU4Ee.js} +6 -6
  102. package/dist/lib/{shadow-claw-git-XfPBpfXd.js.map → shadow-claw-git-60tWU4Ee.js.map} +1 -1
  103. package/dist/lib/{shadow-claw-integrations-yT7j07TM.js → shadow-claw-integrations-Bw1cG1ze.js} +4 -4
  104. package/dist/lib/{shadow-claw-integrations-yT7j07TM.js.map → shadow-claw-integrations-Bw1cG1ze.js.map} +1 -1
  105. package/dist/lib/{shadow-claw-llm-Gzx4ufL_.js → shadow-claw-llm-By5CvsFJ.js} +6 -6
  106. package/dist/lib/{shadow-claw-llm-Gzx4ufL_.js.map → shadow-claw-llm-By5CvsFJ.js.map} +1 -1
  107. package/dist/lib/{shadow-claw-mcp-remote-DGDWjByQ.js → shadow-claw-mcp-remote-BaNODd1v.js} +4 -4
  108. package/dist/lib/{shadow-claw-mcp-remote-DGDWjByQ.js.map → shadow-claw-mcp-remote-BaNODd1v.js.map} +1 -1
  109. package/dist/lib/{shadow-claw-networking-CYEbc5TR.js → shadow-claw-networking-DtZ5bsTz.js} +2 -2
  110. package/dist/lib/{shadow-claw-networking-CYEbc5TR.js.map → shadow-claw-networking-DtZ5bsTz.js.map} +1 -1
  111. package/dist/lib/{shadow-claw-notifications-DHvkTrgv.js → shadow-claw-notifications-C3VEba_A.js} +3 -3
  112. package/dist/lib/{shadow-claw-notifications-DHvkTrgv.js.map → shadow-claw-notifications-C3VEba_A.js.map} +1 -1
  113. package/dist/lib/{shadow-claw-page-header-DrAcWCZ9.js → shadow-claw-page-header-BLowJopA.js} +2 -2
  114. package/dist/lib/{shadow-claw-page-header-DrAcWCZ9.js.map → shadow-claw-page-header-BLowJopA.js.map} +1 -1
  115. package/dist/lib/{shadow-claw-pages-Bj3w3V6Y.js → shadow-claw-pages-CpeUV-hw.js} +9 -9
  116. package/dist/lib/{shadow-claw-pages-Bj3w3V6Y.js.map → shadow-claw-pages-CpeUV-hw.js.map} +1 -1
  117. package/dist/lib/{shadow-claw-peerjs-B3sx2xLA.js → shadow-claw-peerjs-DYAzJbTy.js} +3 -3
  118. package/dist/lib/{shadow-claw-peerjs-B3sx2xLA.js.map → shadow-claw-peerjs-DYAzJbTy.js.map} +1 -1
  119. package/dist/lib/{shadow-claw-settings-DK-0kp3A.js → shadow-claw-settings-ByxwW3WK.js} +9 -9
  120. package/dist/lib/{shadow-claw-settings-DK-0kp3A.js.map → shadow-claw-settings-ByxwW3WK.js.map} +1 -1
  121. package/dist/lib/{shadow-claw-storage-p9nVMQPF.js → shadow-claw-storage-CsSPYVDJ.js} +5 -5
  122. package/dist/lib/{shadow-claw-storage-p9nVMQPF.js.map → shadow-claw-storage-CsSPYVDJ.js.map} +1 -1
  123. package/dist/lib/{shadow-claw-task-server-BNKCWG2M.js → shadow-claw-task-server-De2WCEw4.js} +2 -2
  124. package/dist/lib/{shadow-claw-task-server-BNKCWG2M.js.map → shadow-claw-task-server-De2WCEw4.js.map} +1 -1
  125. package/dist/lib/{shadow-claw-tasks-Dbq9rUku.js → shadow-claw-tasks-zHWT4GaE.js} +7 -7
  126. package/dist/lib/{shadow-claw-tasks-Dbq9rUku.js.map → shadow-claw-tasks-zHWT4GaE.js.map} +1 -1
  127. package/dist/lib/{shadow-claw-terminal-Wk2qRWJ9.js → shadow-claw-terminal-Bpawfv4N.js} +2 -2
  128. package/dist/lib/{shadow-claw-terminal-Wk2qRWJ9.js.map → shadow-claw-terminal-Bpawfv4N.js.map} +1 -1
  129. package/dist/lib/{shadow-claw-tools-C9TEf2k7.js → shadow-claw-tools-BbKdWcps.js} +7 -7
  130. package/dist/lib/{shadow-claw-tools-C9TEf2k7.js.map → shadow-claw-tools-BbKdWcps.js.map} +1 -1
  131. package/dist/lib/{shadow-claw-webvm-VoKerWW8.js → shadow-claw-webvm-DLqK0AxW.js} +3 -3
  132. package/dist/lib/{shadow-claw-webvm-VoKerWW8.js.map → shadow-claw-webvm-DLqK0AxW.js.map} +1 -1
  133. package/dist/lib/subsystems/git/git.d.ts +8 -1
  134. package/dist/lib/subsystems/git/types.d.ts +7 -1
  135. package/dist/lib/subsystems/mcp/webmcp.d.ts +37 -0
  136. package/dist/lib/subsystems/providers/model-registry.d.ts +4 -1
  137. package/dist/lib/subsystems/providers/providers.d.ts +10 -0
  138. package/dist/lib/{syncWebMcpRegistration-DEs4JjI_.js → syncWebMcpRegistration-mlbbvcdm.js} +5 -5
  139. package/dist/lib/{syncWebMcpRegistration-DEs4JjI_.js.map → syncWebMcpRegistration-mlbbvcdm.js.map} +1 -1
  140. package/dist/lib/{tools-f1WPNDSS.js → tools-Bb2ujM2E.js} +4 -4
  141. package/dist/lib/{tools-f1WPNDSS.js.map → tools-Bb2ujM2E.js.map} +1 -1
  142. package/dist/lib/utils/index.js +1 -1
  143. package/dist/lib/utils/utils.js +1 -1
  144. package/dist/lib/{utils-B99XP70b.js → utils-mpsYPfS7.js} +3 -3
  145. package/dist/lib/{utils-B99XP70b.js.map → utils-mpsYPfS7.js.map} +1 -1
  146. package/dist/lib/webmcp-BVR2lBVo.js +1544 -0
  147. package/dist/lib/webmcp-BVR2lBVo.js.map +1 -0
  148. package/dist/public/.well-known/mcp/server-card.json +1 -1
  149. package/dist/public/.well-known/mcp.json +1 -1
  150. package/dist/public/agent.worker.js +44 -44
  151. package/dist/public/config-BqecTktB.js +1 -0
  152. package/dist/public/{configurePeerJs-B68egTBd.js → configurePeerJs-BPKfWuEt.js} +1 -1
  153. package/dist/public/{connections-6575KDGE.js → connections-C_3tYsmX.js} +1 -1
  154. package/dist/public/{custom-element-security-Da_6HQ6X.js → custom-element-security-DXwU3Lae.js} +1 -1
  155. package/dist/public/docs/example/article/index.html +2 -2
  156. package/dist/public/docs/publishing/index.html +2 -2
  157. package/dist/public/docs/skill-creator/index.html +2 -2
  158. package/dist/public/docs/subsystems/tools.md +4 -3
  159. package/dist/public/docs/subsystems/webmcp.md +58 -13
  160. package/dist/public/{downloadGroupFile-Dj-AMNsd.js → downloadGroupFile-DTyf5DIC.js} +1 -1
  161. package/dist/public/{e2e-bridge-DQ4Mb_eC.js → e2e-bridge-DXwWCQKw.js} +1 -1
  162. package/dist/public/{file-viewer-BqNHyqzy.js → file-viewer-ConEyDDG.js} +1 -1
  163. package/dist/public/{getGroupDir-BwprrdrQ.js → getGroupDir-ZfZsiq6d.js} +1 -1
  164. package/dist/public/git-BtBaLC1-.js +100 -0
  165. package/dist/public/git-DgFF7xTW.js +100 -0
  166. package/dist/public/{iframe-sanitizer-viROQkRn.js → iframe-sanitizer-Corkvo_d.js} +1 -1
  167. package/dist/public/index.html +2 -2
  168. package/dist/public/index.js +1 -1
  169. package/dist/public/{initChatSplitResize-BA18wLQQ.js → initChatSplitResize-CUc-TEmT.js} +1 -1
  170. package/dist/public/{initControlPlane-DG_LcLDy.js → initControlPlane-B_uYS8a4.js} +1 -1
  171. package/dist/public/main/index.html +2 -2
  172. package/dist/public/main/memory/index.html +2 -2
  173. package/dist/public/{markdown-eFKxxpVP.js → markdown-Cfa6GuJs.js} +1 -1
  174. package/dist/public/{mcp-reconnect-CBHuaYdF.js → mcp-reconnect-CUOkdPEz.js} +1 -1
  175. package/dist/public/{memoryStorage-C1llaYus.js → memoryStorage-Bh8fjmip.js} +1 -1
  176. package/dist/public/{orchestrator-BXwxW4N2.js → orchestrator-BcSzrg6E.js} +2 -2
  177. package/dist/public/{orchestrator-DAJkyJmV.js → orchestrator-Bi5OdVZD.js} +11 -11
  178. package/dist/public/{peerjs-BaDbzfgl.js → peerjs-CzCXG-NW.js} +1 -1
  179. package/dist/public/{push-client-B1CCaldJ.js → push-client-Cr3Ruahp.js} +1 -1
  180. package/dist/public/service-worker.js +1 -1
  181. package/dist/public/{shadow-claw-CpBmveOh.js → shadow-claw-CzUYuuOa.js} +2 -2
  182. package/dist/public/{shadow-claw-accounts-D1y-zbMs.js → shadow-claw-accounts-BgIHB_aP.js} +1 -1
  183. package/dist/public/{shadow-claw-channels-7Oew09u0.js → shadow-claw-channels-Ce_trJ5D.js} +1 -1
  184. package/dist/public/{shadow-claw-chat-CskwjDzZ.js → shadow-claw-chat-CdECLLwL.js} +1 -1
  185. package/dist/public/{shadow-claw-control-plane-BqjEyhx7.js → shadow-claw-control-plane-DM62UmOz.js} +2 -2
  186. package/dist/public/{shadow-claw-conversations-ClGgBPVY.js → shadow-claw-conversations-AM5g3C00.js} +1 -1
  187. package/dist/public/{shadow-claw-file-viewer-rDepUwFJ.js → shadow-claw-file-viewer-BP7gWS5g.js} +1 -1
  188. package/dist/public/{shadow-claw-files-C0r05PYf.js → shadow-claw-files-RPPGszcK.js} +1 -1
  189. package/dist/public/{shadow-claw-git-CXrECHKy.js → shadow-claw-git-BsHEvLrb.js} +2 -2
  190. package/dist/public/{shadow-claw-integrations-CRGL78Fy.js → shadow-claw-integrations-B0vbcOqg.js} +1 -1
  191. package/dist/public/{shadow-claw-llm-jeGVNciG.js → shadow-claw-llm-FNNamrc_.js} +2 -2
  192. package/dist/public/{shadow-claw-mcp-remote-DyGnK4S_.js → shadow-claw-mcp-remote-7mDgniQu.js} +1 -1
  193. package/dist/public/{shadow-claw-networking--q6MgEAT.js → shadow-claw-networking-CGsetaLp.js} +1 -1
  194. package/dist/public/{shadow-claw-notifications-CrFUF0fl.js → shadow-claw-notifications-pnwRcR-4.js} +1 -1
  195. package/dist/public/{shadow-claw-page-header-DA-FG08G.js → shadow-claw-page-header-BUy15Poz.js} +1 -1
  196. package/dist/public/{shadow-claw-pages-_n1wVXAV.js → shadow-claw-pages-ILAjGWNk.js} +1 -1
  197. package/dist/public/{shadow-claw-settings-5yIfa3ie.js → shadow-claw-settings-Bx5IgVqN.js} +3 -3
  198. package/dist/public/{shadow-claw-storage-PLX9EFGn.js → shadow-claw-storage-PAtNykaF.js} +1 -1
  199. package/dist/public/{shadow-claw-task-server-BMps7aSr.js → shadow-claw-task-server-Cbbi_2OO.js} +1 -1
  200. package/dist/public/{shadow-claw-tasks-CHO1xvsu.js → shadow-claw-tasks-B-jKYWZJ.js} +1 -1
  201. package/dist/public/{shadow-claw-terminal-BJnSXRsb.js → shadow-claw-terminal-BRejND-Z.js} +1 -1
  202. package/dist/public/{shadow-claw-tools-BHfxRckC.js → shadow-claw-tools-DNQe3oa-.js} +1 -1
  203. package/dist/public/{shadow-claw-webvm-CyI23mQT.js → shadow-claw-webvm-BFuwRifU.js} +1 -1
  204. package/dist/public/{syncWebMcpRegistration-R0tha3kP.js → syncWebMcpRegistration-FxKAPwaz.js} +1 -1
  205. package/dist/public/theme-init.js +1 -1
  206. package/dist/public/{tools-Cp1gequ8.js → tools-BwQKGsro.js} +1 -1
  207. package/dist/public/transformers-js.worker.js +1 -1
  208. package/dist/public/webmcp-C28PAlfy.js +1 -0
  209. package/dist/server.js +1 -1
  210. package/package.json +3 -3
  211. package/src/core/utils/initControlPlane.test.ts +122 -1
  212. package/src/core/utils/initControlPlane.ts +12 -8
  213. package/src/storage/staticMainSite.ts +16 -2
  214. package/src/stores/orchestrator.test.ts +33 -0
  215. package/src/stores/orchestrator.ts +36 -0
  216. package/src/subsystems/git/git.test.ts +99 -0
  217. package/src/subsystems/git/git.ts +92 -12
  218. package/src/subsystems/git/types.ts +7 -0
  219. package/src/subsystems/mcp/webmcp.test.ts +253 -1
  220. package/src/subsystems/mcp/webmcp.ts +147 -4
  221. package/src/subsystems/providers/model-registry.test.ts +139 -0
  222. package/src/subsystems/providers/model-registry.ts +54 -2
  223. package/src/subsystems/providers/providers.test.ts +329 -0
  224. package/src/subsystems/providers/providers.ts +135 -11
  225. package/dist/lib/config-DjZ9QWc4.js.map +0 -1
  226. package/dist/lib/webmcp-BC8_WafM.js +0 -1710
  227. package/dist/lib/webmcp-BC8_WafM.js.map +0 -1
  228. package/dist/public/config-Bnwx4EfS.js +0 -1
  229. package/dist/public/git-BDaM5VT5.js +0 -100
  230. package/dist/public/git-D4n46G9B.js +0 -100
  231. package/dist/public/webmcp-DBONjQWd.js +0 -2
package/dist/server.js CHANGED
@@ -1,4 +1,4 @@
1
- import e,{createRequire as t}from"node:module";import n from"process";import{env as r,exit as i}from"node:process";import a from"node:http";import o from"node:https";import s,{basename as c}from"node:path";import l,{constants as u,createReadStream as d,promises as f,statSync as p}from"node:fs";import m,{tmpdir as h}from"node:os";import g,{URL as _,fileURLToPath as v,format as y}from"node:url";import b from"tcp-port-used";import x from"compression";import S from"express";import C from"web-push";import{DatabaseSync as w}from"node:sqlite";import{createHash as T,randomBytes as E,randomUUID as D}from"node:crypto";import O from"cors";import{Buffer as k}from"buffer";import A from"express-urlrewrite";import{BedrockClient as j,ListFoundationModelsCommand as M,ListInferenceProfilesCommand as N}from"@aws-sdk/client-bedrock";import{BedrockRuntimeClient as P,ConverseCommand as F,ConverseStreamCommand as I}from"@aws-sdk/client-bedrock-runtime";import{fromNodeProviderChain as L,fromSSO as ee}from"@aws-sdk/credential-providers";import*as te from"fs";import{createWriteStream as ne}from"fs";import*as R from"stream";import re from"node:zlib";import ie,{PassThrough as ae,Readable as oe,pipeline as se}from"node:stream";import{Buffer as z}from"node:buffer";import{deprecate as ce,promisify as le,types as ue}from"node:util";import{isIP as de}from"node:net";import*as fe from"path";import*as pe from"fs/promises";import{writeFile as me}from"fs/promises";import{finished as he}from"node:stream/promises";import{access as ge,mkdir as _e,readFile as ve,readdir as ye,stat as be,unlink as xe,writeFile as Se}from"node:fs/promises";import{execFileSync as Ce,spawn as we}from"node:child_process";import{EventEmitter as Te}from"node:events";var Ee=Object.create,De=Object.defineProperty,Oe=Object.getOwnPropertyDescriptor,ke=Object.getOwnPropertyNames,Ae=Object.getPrototypeOf,je=Object.prototype.hasOwnProperty,B=(e,t,n)=>()=>{if(n)throw n[0];try{return e&&(t=e(e=0)),t}catch(e){throw n=[e],e}},V=(e,t)=>()=>(t||(e((t={exports:{}}).exports,t),e=null),t.exports),Me=(e,t)=>{let n={};for(var r in e)De(n,r,{get:e[r],enumerable:!0});return t||De(n,Symbol.toStringTag,{value:`Module`}),n},Ne=(e,t,n,r)=>{if(t&&typeof t==`object`||typeof t==`function`)for(var i=ke(t),a=0,o=i.length,s;a<o;a++)s=i[a],!je.call(e,s)&&s!==n&&De(e,s,{get:(e=>t[e]).bind(null,s),enumerable:!(r=Oe(t,s))||r.enumerable});return e},Pe=(e,t,n)=>(n=e==null?{}:Ee(Ae(e)),Ne(t||!e||!e.__esModule?De(n,`default`,{value:e,enumerable:!0}):n,e)),H=t(import.meta.url);const Fe=new class{loading=!1;models=new Map;getModelInfo(e){return this.models.get(e.toLowerCase())??null}registerModelInfo(e,t){this.models.set(e.toLowerCase(),t)}clear(){this.models.clear()}async fetchModelInfo(e,t,n){if(e.modelsUrl){this.loading=!0;try{let r=new Headers;if(r.set(`Content-Type`,`application/json`),e.headers)for(let[t,n]of Object.entries(e.headers))r.set(t,n);if(n)for(let[e,t]of Object.entries(n))r.set(e,t);if(t&&e.apiKeyHeader){let n=e.apiKeyHeaderFormat;r.set(e.apiKeyHeader,n?n.replace(`{key}`,t):t)}let i=await fetch(e.modelsUrl,{headers:r});if(!i.ok)throw Error(`HTTP ${i.status} ${i.statusText}`);let a=await i.json(),o=Array.isArray(a.data)?a.data:Array.isArray(a.models)?a.models:[];for(let e of o){if(!e.id)continue;let t=e.context_length??e.context_window??0,n=e.max_completion_tokens||e.per_request_limits?.completion_tokens||e.top_provider?.max_completion_tokens||null,r=typeof e.supports_tools==`boolean`?e.supports_tools:typeof e.supportsTools==`boolean`?e.supportsTools:void 0,i=this.extractModalities(e,`input`),a=this.extractModalities(e,`output`),o=this.modalitiesInclude(i,`image`,`vision`),s=this.modalitiesInclude(i,`audio`,`voice`,`hearing`),c=this.modalitiesInclude(i,`video`),l=e.id===`openrouter/free`||this.supportedParametersInclude(e,`image`,`vision`,`audio`,`tool`,`structured`),u=this.extractReasoning(e);!t&&Array.isArray(e.providers)&&e.providers.length>0&&(t=e.providers[0]?.context_length||0),this.registerModelInfo(e.id,{contextWindow:t,maxOutput:n,...r!==void 0&&{supportsTools:r},...i.length>0&&{inputModalities:i},...a.length>0&&{outputModalities:a},...o!==void 0&&{supportsImageInput:o},...s!==void 0&&{supportsAudioInput:s},...c!==void 0&&{supportsVideoInput:c},...u&&{reasoning:u},...l&&{routesByRequestFeatures:l}})}o.length>0&&console.log(`[ModelRegistry] Registered ${o.length} models for provider "${e.id}"`)}catch(t){console.error(`[ModelRegistry] Error fetching models for ${e.id}:`,t)}finally{this.loading=!1}}}extractModalities(e,t){let n=t===`input`?e.input_modalities||e.inputModalities:e.output_modalities||e.outputModalities,r=e.architecture||{},i=t===`input`?r.input_modalities||r.inputModalities:r.output_modalities||r.outputModalities,a=typeof r.modality==`string`?r.modality:``,o=this.parseArchitectureModality(a,t),s=[...this.normalizeStringArray(n),...this.normalizeStringArray(i),...o];return Array.from(new Set(s))}extractReasoning(e){let t=e?.reasoning;if(!t||typeof t!=`object`)return;let n=this.normalizeStringArray(t.supported_efforts),r=typeof t.default_effort==`string`?t.default_effort.toLowerCase():void 0,i=typeof t.default_enabled==`boolean`?t.default_enabled:void 0,a=typeof t.supports_max_tokens==`boolean`?t.supports_max_tokens:void 0,o=typeof t.mandatory==`boolean`?t.mandatory:void 0;if(!(n.length===0&&r===void 0&&i===void 0&&a===void 0&&o===void 0))return{...n.length>0&&{supportedEfforts:n},...r!==void 0&&{defaultEffort:r},...i!==void 0&&{defaultEnabled:i},...a!==void 0&&{supportsMaxTokens:a},...o!==void 0&&{mandatory:o}}}modalitiesInclude(e,...t){if(e.length!==0)return t.some(t=>e.some(e=>e.includes(t)))}normalizeStringArray(e){return Array.isArray(e)?e.filter(e=>typeof e==`string`).map(e=>e.toLowerCase()):[]}parseArchitectureModality(e,t){if(!e)return[];let[n=``,r=``]=e.toLowerCase().split(`->`).map(e=>e.trim());return(t===`input`?n:r).split(/[+,/\s]+/).map(e=>e.trim()).filter(Boolean)}supportedParametersInclude(e,...t){let n=this.normalizeStringArray(e.supported_parameters||e.supportedParameters);return t.some(e=>n.some(t=>t.includes(e)))}};function Ie(e){return e.replace(/^\/+|\/+$/g,``)}function Le(e){let t=Ie(e);return t.endsWith(`/index.html`)?t=t.slice(0,-11):t.endsWith(`index.html`)&&(t=t.slice(0,-10)),Ie(t)}function Re(e){let t=Ie(e),n=t.split(`/`).filter(Boolean);if(n.length===0)return null;let r=n[0].toLowerCase();if(r===`pages`){if(n.length>=3){let e=n[1];return{page:`pages`,groupId:e===`main`?`br:main`:e.startsWith(`br-`)?`br:${e.slice(3)}`:e,path:n.slice(2).join(`/`)}}return{page:`pages`,groupId:`br:main`,path:n.slice(1).join(`/`)}}if(r===`files`){let e=n[1]||`main`;return{page:`files`,groupId:e===`main`?`br:main`:e.startsWith(`br-`)?`br:${e.slice(3)}`:e,path:n.slice(2).join(`/`)||void 0}}if(r===`chat`){let e=n[1]||`main`;return{page:`chat`,groupId:e===`main`?`br:main`:e.startsWith(`br-`)?`br:${e.slice(3)}`:e}}if(r===`tasks`){let e=n[1]||`main`;return{page:`tasks`,groupId:e===`main`?`br:main`:e.startsWith(`br-`)?`br:${e.slice(3)}`:e}}return r===`main`?{page:`pages`,groupId:`br:main`,path:n.slice(1).join(`/`)}:{page:`pages`,groupId:`br:main`,path:t}}function ze(){if(typeof document<`u`){let e=document.getElementById(`shadow-claw-static-routing`);if(e&&e.textContent)try{let t=JSON.parse(e.textContent);if(t&&typeof t==`object`&&t.routes)return t}catch(e){console.warn(`Failed to parse embedded static routing manifest:`,e)}}return null}function Be(e,t){let n=t||ze();if(!n||!n.routes)return null;let r=Le(e);if(!r)return null;for(let[e,t]of Object.entries(n.routes))if(!(!t||!t.prettyPath)&&Le(t.prettyPath)===r)return Re(e);return null}let Ve=null;const He=new Set([`chat`,`files`,`tasks`,`pages`,`settings`,`tools`,`channels`]);function Ue(){Ve=null}typeof globalThis<`u`&&(globalThis.__applyBasePathCacheReset=Ue);function We(){let e=typeof window<`u`?window:typeof self<`u`?self:globalThis;if(e&&e.__SHADOWCLAW_DEPLOY_ID__){let t=String(e.__SHADOWCLAW_DEPLOY_ID__).trim();if(t)return t.replace(/[^a-zA-Z0-9_-]/g,`-`)}let t=globalThis.process;if(t&&t.env&&t.env.SHADOWCLAW_DEPLOY_ID){let e=String(t.env.SHADOWCLAW_DEPLOY_ID).trim();if(e)return e.replace(/[^a-zA-Z0-9_-]/g,`-`)}let n=Ge();return!n||n===`/`?``:n.replace(/^\/+|\/+$/g,``).replace(/[^a-zA-Z0-9_-]/g,`-`)}function Ge(){if(Ve!==null)return Ve;if((typeof window>`u`||globalThis.WorkerGlobalScope!==void 0&&typeof self<`u`&&self instanceof globalThis.WorkerGlobalScope)&&typeof self<`u`&&self.location){let e=(self.location.pathname||`/`).split(`/`).filter(Boolean);if(e.length<=1)return Ve=`/`,Ve;let t=e[0].toLowerCase(),n=t===`service-worker.js`||t===`sw.js`||t===`manifest.json`||t===`sitemap.xml`||t===`favicon.ico`||t===`index.html`||t===`service-worker`||t===`assets`||t===`dist`||t===`public`;if(n&&e.length===2)return Ve=`/`,Ve;if(!n)return Ve=`/`+e[0]+`/`,Ve}let e=typeof window<`u`&&window.location?window.location:typeof self<`u`&&self.location?self.location:null;if(!e)return`/`;if(typeof document<`u`&&typeof document.querySelector==`function`){let t=document.querySelector(`base[href]`);if(t){let n=t.getAttribute(`href`);if(n)try{let t=new URL(n,e.origin).pathname;return t.endsWith(`/`)||(t+=`/`),Ve=t,Ve}catch{}}}let t=e.pathname||`/`;if(t===`/`)return Ve=`/`,Ve;let n=t.split(`/`).filter(Boolean),r=n.findIndex(e=>He.has(e.toLowerCase()));return r>=0?r===0?(Ve=`/`,Ve):(Ve=`/`+n.slice(0,r).join(`/`)+`/`,Ve):Be(t)?(Ve=`/`,Ve):n.length===1&&!t.includes(`.`)?(Ve=`/`+n[0]+`/`,Ve):(Ve=`/`,Ve)}function Ke(e){let t=e.replace(/[.*+?^${}()|[\]\\]/g,`\\$&`);return RegExp(`(^|\\s)@${t}\\b`,`i`)}Ke(`ShadowClaw`);function qe(){let e=We();return e?`shadowclaw-${e}`:`shadowclaw`}qe();const Je={github:{providerId:`github`,name:`GitHub`,aliases:[`github`,`api.github.com`],modes:[`oauth`,`token`],defaultMode:`oauth`,serviceTypes:[`http_api`,`git_remote`],authTypes:[`token`,`oauth`],tokenAuth:{token:{headerName:`Authorization`,headerPrefix:`token `},oauth:{headerName:`Authorization`,headerPrefix:`Bearer `}},oauth:{authorizeUrl:`https://github.com/login/oauth/authorize`,tokenUrl:`https://github.com/login/oauth/access_token`,defaultScopes:[`repo`,`read:user`],usePkce:!0,clientAuthMethod:`request_body`,scopeSeparator:`space`}},gitlab:{providerId:`gitlab`,name:`GitLab`,aliases:[`gitlab`,`gitlab.com`],modes:[`oauth`,`token`],defaultMode:`oauth`,serviceTypes:[`http_api`,`git_remote`],authTypes:[`token`,`oauth`],tokenAuth:{token:{headerName:`PRIVATE-TOKEN`,headerPrefix:``},oauth:{headerName:`Authorization`,headerPrefix:`Bearer `}},tokenAuthByServiceType:{git_remote:{token:{headerName:`Authorization`,headerPrefix:`Bearer `},oauth:{headerName:`Authorization`,headerPrefix:`Bearer `}}},oauth:{authorizeUrl:`https://gitlab.com/oauth/authorize`,tokenUrl:`https://gitlab.com/oauth/token`,defaultScopes:[`read_api`,`read_user`],usePkce:!0,clientAuthMethod:`request_body`,scopeSeparator:`space`}},figma:{providerId:`figma`,name:`Figma`,aliases:[`figma`,`api.figma.com`],modes:[`oauth`,`token`],defaultMode:`oauth`,serviceTypes:[`http_api`],authTypes:[`token`,`oauth`],tokenAuth:{token:{headerName:`X-Figma-Token`,headerPrefix:``},oauth:{headerName:`Authorization`,headerPrefix:`Bearer `}},oauth:{authorizeUrl:`https://www.figma.com/oauth`,tokenUrl:`https://api.figma.com/v1/oauth/token`,refreshUrl:`https://api.figma.com/v1/oauth/refresh`,defaultScopes:[],usePkce:!0,clientAuthMethod:`basic_header`,scopeSeparator:`space`}},notion:{providerId:`notion`,name:`Notion`,aliases:[`notion`,`api.notion.com`,`notion.so`],modes:[`oauth`,`token`],defaultMode:`oauth`,serviceTypes:[`http_api`],authTypes:[`token`,`oauth`],tokenAuth:{token:{headerName:`Authorization`,headerPrefix:`Bearer `},oauth:{headerName:`Authorization`,headerPrefix:`Bearer `}},oauth:{authorizeUrl:`https://api.notion.com/v1/oauth/authorize`,tokenUrl:`https://api.notion.com/v1/oauth/token`,defaultScopes:[],usePkce:!0,clientAuthMethod:`basic_header`,scopeSeparator:`space`}},microsoft_graph:{providerId:`microsoft_graph`,name:`Microsoft Graph`,aliases:[`microsoft`,`graph.microsoft.com`,`microsoft_graph`],modes:[`oauth`,`token`],defaultMode:`oauth`,serviceTypes:[`http_api`],authTypes:[`token`,`oauth`],tokenAuth:{token:{headerName:`Authorization`,headerPrefix:`Bearer `},oauth:{headerName:`Authorization`,headerPrefix:`Bearer `}},oauth:{authorizeUrl:`https://login.microsoftonline.com/common/oauth2/v2.0/authorize`,tokenUrl:`https://login.microsoftonline.com/common/oauth2/v2.0/token`,defaultScopes:[`openid`,`profile`,`offline_access`,`User.Read`],usePkce:!0,clientAuthMethod:`request_body`,scopeSeparator:`space`}},yahoo_mail:{providerId:`yahoo_mail`,name:`Yahoo Mail`,aliases:[`yahoo`,`yahoo_mail`,`mail.yahoo.com`],modes:[`oauth`,`token`],defaultMode:`oauth`,serviceTypes:[`http_api`],authTypes:[`token`,`oauth`],tokenAuth:{token:{headerName:`Authorization`,headerPrefix:`Bearer `},oauth:{headerName:`Authorization`,headerPrefix:`Bearer `}},oauth:{authorizeUrl:`https://api.login.yahoo.com/oauth2/request_auth`,tokenUrl:`https://api.login.yahoo.com/oauth2/get_token`,defaultScopes:[`mail-r`,`mail-w`],usePkce:!0,clientAuthMethod:`request_body`,scopeSeparator:`space`}},google:{providerId:`google`,name:`Google`,aliases:[`google`,`googleapis.com`],modes:[`oauth`,`token`],defaultMode:`oauth`,serviceTypes:[`http_api`],authTypes:[`token`,`oauth`],tokenAuth:{token:{headerName:`Authorization`,headerPrefix:`Bearer `},oauth:{headerName:`Authorization`,headerPrefix:`Bearer `}},oauth:{authorizeUrl:`https://accounts.google.com/o/oauth2/v2/auth`,tokenUrl:`https://oauth2.googleapis.com/token`,defaultScopes:[`openid`,`profile`,`email`],usePkce:!0,clientAuthMethod:`request_body`,scopeSeparator:`space`}},atlassian:{providerId:`atlassian`,name:`Atlassian`,aliases:[`atlassian`,`api.atlassian.com`],modes:[`oauth`,`token`,`basic`],defaultMode:`basic`,serviceTypes:[`http_api`,`git_remote`],authTypes:[`token`,`oauth`,`basic_userpass`],tokenAuth:{token:{headerName:`Authorization`,headerPrefix:`Bearer `},oauth:{headerName:`Authorization`,headerPrefix:`Bearer `},basic:{headerName:`Authorization`,headerPrefix:`Basic `}},oauth:{authorizeUrl:`https://auth.atlassian.com/authorize`,tokenUrl:`https://auth.atlassian.com/oauth/token`,defaultScopes:[],usePkce:!0,clientAuthMethod:`request_body`,scopeSeparator:`space`}},slack:{providerId:`slack`,name:`Slack`,aliases:[`slack`,`slack.com`],modes:[`oauth`,`token`],defaultMode:`oauth`,serviceTypes:[`http_api`],authTypes:[`token`,`oauth`],tokenAuth:{token:{headerName:`Authorization`,headerPrefix:`Bearer `},oauth:{headerName:`Authorization`,headerPrefix:`Bearer `}},oauth:{authorizeUrl:`https://slack.com/oauth/v2/authorize`,tokenUrl:`https://slack.com/api/oauth.v2.access`,defaultScopes:[],usePkce:!1,clientAuthMethod:`request_body`,scopeSeparator:`comma`}},linear:{providerId:`linear`,name:`Linear`,aliases:[`linear`,`api.linear.app`,`linear.app`],modes:[`oauth`,`token`],defaultMode:`oauth`,serviceTypes:[`http_api`],authTypes:[`token`,`oauth`],tokenAuth:{token:{headerName:`Authorization`,headerPrefix:`Bearer `},oauth:{headerName:`Authorization`,headerPrefix:`Bearer `}},oauth:{authorizeUrl:`https://linear.app/oauth/authorize`,tokenUrl:`https://api.linear.app/oauth/token`,defaultScopes:[],usePkce:!0,clientAuthMethod:`request_body`,scopeSeparator:`space`}},azure_devops:{providerId:`azure_devops`,name:`Azure DevOps`,aliases:[`azure_devops`,`dev.azure.com`],modes:[`oauth`,`token`],defaultMode:`oauth`,serviceTypes:[`http_api`,`git_remote`],authTypes:[`token`,`oauth`,`basic_userpass`,`ssh_key`],tokenAuth:{token:{headerName:`Authorization`,headerPrefix:`Bearer `},oauth:{headerName:`Authorization`,headerPrefix:`Bearer `}},tokenAuthByServiceType:{git_remote:{token:{headerName:`Authorization`,headerPrefix:`Basic `},oauth:{headerName:`Authorization`,headerPrefix:`Basic `}}},oauth:{authorizeUrl:`https://app.vssps.visualstudio.com/oauth2/authorize`,tokenUrl:`https://app.vssps.visualstudio.com/oauth2/token`,defaultScopes:[`vso.code`,`vso.profile`,`offline_access`],usePkce:!1,clientAuthMethod:`request_body`,scopeSeparator:`space`}},custom_mcp:{providerId:`custom_mcp`,name:`Custom MCP`,aliases:[`custom_mcp`],modes:[`oauth`,`token`],defaultMode:`oauth`,serviceTypes:[`mcp_remote`,`webmcp_local`],authTypes:[`none`,`token`,`oauth`,`custom_header`,`ssh_key`],tokenAuth:{token:{headerName:`Authorization`,headerPrefix:`Bearer `},oauth:{headerName:`Authorization`,headerPrefix:`Bearer `}},oauth:{authorizeUrl:`https://example.com/oauth/authorize`,tokenUrl:`https://example.com/oauth/token`,defaultScopes:[],usePkce:!0,clientAuthMethod:`request_body`,scopeSeparator:`space`}}},Ye=Object.fromEntries(Object.values(Je).filter(e=>!!e.oauth).map(e=>{let t=e.oauth;return[e.providerId,{id:e.providerId,name:e.name,authorizeUrl:t.authorizeUrl,tokenUrl:t.tokenUrl,redirectUri:t.redirectUri,defaultScopes:t.defaultScopes,usePkce:t.usePkce,clientAuthMethod:t.clientAuthMethod,scopeSeparator:t.scopeSeparator}]}));Object.fromEntries(Object.values(Je).map(e=>[e.providerId,{providerId:e.providerId,modes:e.modes,defaultMode:e.defaultMode}]));function Xe(e){return Ye[e]||null}let Ze=null;function Qe(e=`database/push-subscriptions.db`){if(Ze)return Ze;Ze=new w(e),Ze.exec(`
1
+ import e,{createRequire as t}from"node:module";import n from"process";import{env as r,exit as i}from"node:process";import a from"node:http";import o from"node:https";import s,{basename as c}from"node:path";import l,{constants as u,createReadStream as d,promises as f,statSync as p}from"node:fs";import m,{tmpdir as h}from"node:os";import g,{URL as _,fileURLToPath as v,format as y}from"node:url";import b from"tcp-port-used";import x from"compression";import S from"express";import C from"web-push";import{DatabaseSync as w}from"node:sqlite";import{createHash as T,randomBytes as E,randomUUID as D}from"node:crypto";import O from"cors";import{Buffer as k}from"buffer";import A from"express-urlrewrite";import{BedrockClient as j,ListFoundationModelsCommand as M,ListInferenceProfilesCommand as N}from"@aws-sdk/client-bedrock";import{BedrockRuntimeClient as P,ConverseCommand as F,ConverseStreamCommand as I}from"@aws-sdk/client-bedrock-runtime";import{fromNodeProviderChain as L,fromSSO as ee}from"@aws-sdk/credential-providers";import*as te from"fs";import{createWriteStream as ne}from"fs";import*as R from"stream";import re from"node:zlib";import ie,{PassThrough as ae,Readable as oe,pipeline as se}from"node:stream";import{Buffer as z}from"node:buffer";import{deprecate as ce,promisify as le,types as ue}from"node:util";import{isIP as de}from"node:net";import*as fe from"path";import*as pe from"fs/promises";import{writeFile as me}from"fs/promises";import{finished as he}from"node:stream/promises";import{access as ge,mkdir as _e,readFile as ve,readdir as ye,stat as be,unlink as xe,writeFile as Se}from"node:fs/promises";import{execFileSync as Ce,spawn as we}from"node:child_process";import{EventEmitter as Te}from"node:events";var Ee=Object.create,De=Object.defineProperty,Oe=Object.getOwnPropertyDescriptor,ke=Object.getOwnPropertyNames,Ae=Object.getPrototypeOf,je=Object.prototype.hasOwnProperty,B=(e,t,n)=>()=>{if(n)throw n[0];try{return e&&(t=e(e=0)),t}catch(e){throw n=[e],e}},V=(e,t)=>()=>(t||(e((t={exports:{}}).exports,t),e=null),t.exports),Me=(e,t)=>{let n={};for(var r in e)De(n,r,{get:e[r],enumerable:!0});return t||De(n,Symbol.toStringTag,{value:`Module`}),n},Ne=(e,t,n,r)=>{if(t&&typeof t==`object`||typeof t==`function`)for(var i=ke(t),a=0,o=i.length,s;a<o;a++)s=i[a],!je.call(e,s)&&s!==n&&De(e,s,{get:(e=>t[e]).bind(null,s),enumerable:!(r=Oe(t,s))||r.enumerable});return e},Pe=(e,t,n)=>(n=e==null?{}:Ee(Ae(e)),Ne(t||!e||!e.__esModule?De(n,`default`,{value:e,enumerable:!0}):n,e)),H=t(import.meta.url);const Fe=new class{loading=!1;models=new Map;getModelInfo(e){if(!e||typeof e!=`string`)return null;let t=e.toLowerCase().trim(),n=this.models.get(t);if(n)return n;if(t.includes(`/`)){let e=t.split(`/`).pop();if(e&&this.models.has(e))return this.models.get(e)}else for(let[e,n]of this.models.entries())if(e.endsWith(`/${t}`))return n;if(t.includes(`:`)){let e=t.split(`:`)[0],n=this.getModelInfo(e);if(n)return n}return null}registerModelInfo(e,t){this.models.set(e.toLowerCase(),t)}clear(){this.models.clear()}async fetchModelInfo(e,t,n){if(e.modelsUrl){this.loading=!0;try{let r=new Headers;if(r.set(`Content-Type`,`application/json`),e.headers)for(let[t,n]of Object.entries(e.headers))r.set(t,n);if(n)for(let[e,t]of Object.entries(n))r.set(e,t);if(t&&e.apiKeyHeader){let n=e.apiKeyHeaderFormat;r.set(e.apiKeyHeader,n?n.replace(`{key}`,t):t)}let i=await fetch(e.modelsUrl,{headers:r});if(!i.ok)throw Error(`HTTP ${i.status} ${i.statusText}`);let a=await i.json(),o=Array.isArray(a.data)?a.data:Array.isArray(a.models)?a.models:[];for(let e of o){if(!e.id)continue;let t=e.context_length??e.context_window??0,n=e.max_completion_tokens||e.per_request_limits?.completion_tokens||e.top_provider?.max_completion_tokens||null,r=typeof e.supports_tools==`boolean`?e.supports_tools:typeof e.supportsTools==`boolean`?e.supportsTools:void 0,i=this.extractModalities(e,`input`),a=this.extractModalities(e,`output`),o=this.modalitiesInclude(i,`image`,`vision`),s=this.modalitiesInclude(i,`audio`,`voice`,`hearing`),c=this.modalitiesInclude(i,`video`),l=e.id===`openrouter/free`||this.supportedParametersInclude(e,`image`,`vision`,`audio`,`tool`,`structured`),u=this.extractReasoning(e),d=typeof e.supports_prompt_caching==`boolean`?e.supports_prompt_caching:typeof e.supportsPromptCaching==`boolean`?e.supportsPromptCaching:this.supportedParametersInclude(e,`cache_control`,`prompt_caching`)?!0:void 0;!t&&Array.isArray(e.providers)&&e.providers.length>0&&(t=e.providers[0]?.context_length||0),this.registerModelInfo(e.id,{contextWindow:t,maxOutput:n,...r!==void 0&&{supportsTools:r},...i.length>0&&{inputModalities:i},...a.length>0&&{outputModalities:a},...o!==void 0&&{supportsImageInput:o},...s!==void 0&&{supportsAudioInput:s},...c!==void 0&&{supportsVideoInput:c},...u&&{reasoning:u},...l&&{routesByRequestFeatures:l},...d!==void 0&&{supportsPromptCaching:d}})}o.length>0&&console.log(`[ModelRegistry] Registered ${o.length} models for provider "${e.id}"`)}catch(t){console.error(`[ModelRegistry] Error fetching models for ${e.id}:`,t)}finally{this.loading=!1}}}extractModalities(e,t){let n=t===`input`?e.input_modalities||e.inputModalities:e.output_modalities||e.outputModalities,r=e.architecture||{},i=t===`input`?r.input_modalities||r.inputModalities:r.output_modalities||r.outputModalities,a=typeof r.modality==`string`?r.modality:``,o=this.parseArchitectureModality(a,t),s=[...this.normalizeStringArray(n),...this.normalizeStringArray(i),...o];return Array.from(new Set(s))}extractReasoning(e){let t=e?.reasoning;if(!t||typeof t!=`object`)return;let n=this.normalizeStringArray(t.supported_efforts),r=typeof t.default_effort==`string`?t.default_effort.toLowerCase():void 0,i=typeof t.default_enabled==`boolean`?t.default_enabled:void 0,a=typeof t.supports_max_tokens==`boolean`?t.supports_max_tokens:void 0,o=typeof t.mandatory==`boolean`?t.mandatory:void 0;if(!(n.length===0&&r===void 0&&i===void 0&&a===void 0&&o===void 0))return{...n.length>0&&{supportedEfforts:n},...r!==void 0&&{defaultEffort:r},...i!==void 0&&{defaultEnabled:i},...a!==void 0&&{supportsMaxTokens:a},...o!==void 0&&{mandatory:o}}}modalitiesInclude(e,...t){if(e.length!==0)return t.some(t=>e.some(e=>e.includes(t)))}normalizeStringArray(e){return Array.isArray(e)?e.filter(e=>typeof e==`string`).map(e=>e.toLowerCase()):[]}parseArchitectureModality(e,t){if(!e)return[];let[n=``,r=``]=e.toLowerCase().split(`->`).map(e=>e.trim());return(t===`input`?n:r).split(/[+,/\s]+/).map(e=>e.trim()).filter(Boolean)}supportedParametersInclude(e,...t){let n=this.normalizeStringArray(e.supported_parameters||e.supportedParameters);return t.some(e=>n.some(t=>t.includes(e)))}};function Ie(e){return e.replace(/^\/+|\/+$/g,``)}function Le(e){let t=Ie(e);return t.endsWith(`/index.html`)?t=t.slice(0,-11):t.endsWith(`index.html`)&&(t=t.slice(0,-10)),Ie(t)}function Re(e){let t=Ie(e),n=t.split(`/`).filter(Boolean);if(n.length===0)return null;let r=n[0].toLowerCase();if(r===`pages`){if(n.length>=3){let e=n[1];return{page:`pages`,groupId:e===`main`?`br:main`:e.startsWith(`br-`)?`br:${e.slice(3)}`:e,path:n.slice(2).join(`/`)}}return{page:`pages`,groupId:`br:main`,path:n.slice(1).join(`/`)}}if(r===`files`){let e=n[1]||`main`;return{page:`files`,groupId:e===`main`?`br:main`:e.startsWith(`br-`)?`br:${e.slice(3)}`:e,path:n.slice(2).join(`/`)||void 0}}if(r===`chat`){let e=n[1]||`main`;return{page:`chat`,groupId:e===`main`?`br:main`:e.startsWith(`br-`)?`br:${e.slice(3)}`:e}}if(r===`tasks`){let e=n[1]||`main`;return{page:`tasks`,groupId:e===`main`?`br:main`:e.startsWith(`br-`)?`br:${e.slice(3)}`:e}}return r===`main`?{page:`pages`,groupId:`br:main`,path:n.slice(1).join(`/`)}:{page:`pages`,groupId:`br:main`,path:t}}function ze(){if(typeof document<`u`){let e=document.getElementById(`shadow-claw-static-routing`);if(e&&e.textContent)try{let t=JSON.parse(e.textContent);if(t&&typeof t==`object`&&t.routes)return t}catch(e){console.warn(`Failed to parse embedded static routing manifest:`,e)}}return null}function Be(e,t){let n=t||ze();if(!n||!n.routes)return null;let r=Le(e);if(!r)return null;for(let[e,t]of Object.entries(n.routes))if(!(!t||!t.prettyPath)&&Le(t.prettyPath)===r)return Re(e);return null}let Ve=null;const He=new Set([`chat`,`files`,`tasks`,`pages`,`settings`,`tools`,`channels`]);function Ue(){Ve=null}typeof globalThis<`u`&&(globalThis.__applyBasePathCacheReset=Ue);function We(){let e=typeof window<`u`?window:typeof self<`u`?self:globalThis;if(e&&e.__SHADOWCLAW_DEPLOY_ID__){let t=String(e.__SHADOWCLAW_DEPLOY_ID__).trim();if(t)return t.replace(/[^a-zA-Z0-9_-]/g,`-`)}let t=globalThis.process;if(t&&t.env&&t.env.SHADOWCLAW_DEPLOY_ID){let e=String(t.env.SHADOWCLAW_DEPLOY_ID).trim();if(e)return e.replace(/[^a-zA-Z0-9_-]/g,`-`)}let n=Ge();return!n||n===`/`?``:n.replace(/^\/+|\/+$/g,``).replace(/[^a-zA-Z0-9_-]/g,`-`)}function Ge(){if(Ve!==null)return Ve;if((typeof window>`u`||globalThis.WorkerGlobalScope!==void 0&&typeof self<`u`&&self instanceof globalThis.WorkerGlobalScope)&&typeof self<`u`&&self.location){let e=(self.location.pathname||`/`).split(`/`).filter(Boolean);if(e.length<=1)return Ve=`/`,Ve;let t=e[0].toLowerCase(),n=t===`service-worker.js`||t===`sw.js`||t===`manifest.json`||t===`sitemap.xml`||t===`favicon.ico`||t===`index.html`||t===`service-worker`||t===`assets`||t===`dist`||t===`public`;if(n&&e.length===2)return Ve=`/`,Ve;if(!n)return Ve=`/`+e[0]+`/`,Ve}let e=typeof window<`u`&&window.location?window.location:typeof self<`u`&&self.location?self.location:null;if(!e)return`/`;if(typeof document<`u`&&typeof document.querySelector==`function`){let t=document.querySelector(`base[href]`);if(t){let n=t.getAttribute(`href`);if(n)try{let t=new URL(n,e.origin).pathname;return t.endsWith(`/`)||(t+=`/`),Ve=t,Ve}catch{}}}let t=e.pathname||`/`;if(t===`/`)return Ve=`/`,Ve;let n=t.split(`/`).filter(Boolean),r=n.findIndex(e=>He.has(e.toLowerCase()));return r>=0?r===0?(Ve=`/`,Ve):(Ve=`/`+n.slice(0,r).join(`/`)+`/`,Ve):Be(t)?(Ve=`/`,Ve):n.length===1&&!t.includes(`.`)?(Ve=`/`+n[0]+`/`,Ve):(Ve=`/`,Ve)}function Ke(e){let t=e.replace(/[.*+?^${}()|[\]\\]/g,`\\$&`);return RegExp(`(^|\\s)@${t}\\b`,`i`)}Ke(`ShadowClaw`);function qe(){let e=We();return e?`shadowclaw-${e}`:`shadowclaw`}qe();const Je={github:{providerId:`github`,name:`GitHub`,aliases:[`github`,`api.github.com`],modes:[`oauth`,`token`],defaultMode:`oauth`,serviceTypes:[`http_api`,`git_remote`],authTypes:[`token`,`oauth`],tokenAuth:{token:{headerName:`Authorization`,headerPrefix:`token `},oauth:{headerName:`Authorization`,headerPrefix:`Bearer `}},oauth:{authorizeUrl:`https://github.com/login/oauth/authorize`,tokenUrl:`https://github.com/login/oauth/access_token`,defaultScopes:[`repo`,`read:user`],usePkce:!0,clientAuthMethod:`request_body`,scopeSeparator:`space`}},gitlab:{providerId:`gitlab`,name:`GitLab`,aliases:[`gitlab`,`gitlab.com`],modes:[`oauth`,`token`],defaultMode:`oauth`,serviceTypes:[`http_api`,`git_remote`],authTypes:[`token`,`oauth`],tokenAuth:{token:{headerName:`PRIVATE-TOKEN`,headerPrefix:``},oauth:{headerName:`Authorization`,headerPrefix:`Bearer `}},tokenAuthByServiceType:{git_remote:{token:{headerName:`Authorization`,headerPrefix:`Bearer `},oauth:{headerName:`Authorization`,headerPrefix:`Bearer `}}},oauth:{authorizeUrl:`https://gitlab.com/oauth/authorize`,tokenUrl:`https://gitlab.com/oauth/token`,defaultScopes:[`read_api`,`read_user`],usePkce:!0,clientAuthMethod:`request_body`,scopeSeparator:`space`}},figma:{providerId:`figma`,name:`Figma`,aliases:[`figma`,`api.figma.com`],modes:[`oauth`,`token`],defaultMode:`oauth`,serviceTypes:[`http_api`],authTypes:[`token`,`oauth`],tokenAuth:{token:{headerName:`X-Figma-Token`,headerPrefix:``},oauth:{headerName:`Authorization`,headerPrefix:`Bearer `}},oauth:{authorizeUrl:`https://www.figma.com/oauth`,tokenUrl:`https://api.figma.com/v1/oauth/token`,refreshUrl:`https://api.figma.com/v1/oauth/refresh`,defaultScopes:[],usePkce:!0,clientAuthMethod:`basic_header`,scopeSeparator:`space`}},notion:{providerId:`notion`,name:`Notion`,aliases:[`notion`,`api.notion.com`,`notion.so`],modes:[`oauth`,`token`],defaultMode:`oauth`,serviceTypes:[`http_api`],authTypes:[`token`,`oauth`],tokenAuth:{token:{headerName:`Authorization`,headerPrefix:`Bearer `},oauth:{headerName:`Authorization`,headerPrefix:`Bearer `}},oauth:{authorizeUrl:`https://api.notion.com/v1/oauth/authorize`,tokenUrl:`https://api.notion.com/v1/oauth/token`,defaultScopes:[],usePkce:!0,clientAuthMethod:`basic_header`,scopeSeparator:`space`}},microsoft_graph:{providerId:`microsoft_graph`,name:`Microsoft Graph`,aliases:[`microsoft`,`graph.microsoft.com`,`microsoft_graph`],modes:[`oauth`,`token`],defaultMode:`oauth`,serviceTypes:[`http_api`],authTypes:[`token`,`oauth`],tokenAuth:{token:{headerName:`Authorization`,headerPrefix:`Bearer `},oauth:{headerName:`Authorization`,headerPrefix:`Bearer `}},oauth:{authorizeUrl:`https://login.microsoftonline.com/common/oauth2/v2.0/authorize`,tokenUrl:`https://login.microsoftonline.com/common/oauth2/v2.0/token`,defaultScopes:[`openid`,`profile`,`offline_access`,`User.Read`],usePkce:!0,clientAuthMethod:`request_body`,scopeSeparator:`space`}},yahoo_mail:{providerId:`yahoo_mail`,name:`Yahoo Mail`,aliases:[`yahoo`,`yahoo_mail`,`mail.yahoo.com`],modes:[`oauth`,`token`],defaultMode:`oauth`,serviceTypes:[`http_api`],authTypes:[`token`,`oauth`],tokenAuth:{token:{headerName:`Authorization`,headerPrefix:`Bearer `},oauth:{headerName:`Authorization`,headerPrefix:`Bearer `}},oauth:{authorizeUrl:`https://api.login.yahoo.com/oauth2/request_auth`,tokenUrl:`https://api.login.yahoo.com/oauth2/get_token`,defaultScopes:[`mail-r`,`mail-w`],usePkce:!0,clientAuthMethod:`request_body`,scopeSeparator:`space`}},google:{providerId:`google`,name:`Google`,aliases:[`google`,`googleapis.com`],modes:[`oauth`,`token`],defaultMode:`oauth`,serviceTypes:[`http_api`],authTypes:[`token`,`oauth`],tokenAuth:{token:{headerName:`Authorization`,headerPrefix:`Bearer `},oauth:{headerName:`Authorization`,headerPrefix:`Bearer `}},oauth:{authorizeUrl:`https://accounts.google.com/o/oauth2/v2/auth`,tokenUrl:`https://oauth2.googleapis.com/token`,defaultScopes:[`openid`,`profile`,`email`],usePkce:!0,clientAuthMethod:`request_body`,scopeSeparator:`space`}},atlassian:{providerId:`atlassian`,name:`Atlassian`,aliases:[`atlassian`,`api.atlassian.com`],modes:[`oauth`,`token`,`basic`],defaultMode:`basic`,serviceTypes:[`http_api`,`git_remote`],authTypes:[`token`,`oauth`,`basic_userpass`],tokenAuth:{token:{headerName:`Authorization`,headerPrefix:`Bearer `},oauth:{headerName:`Authorization`,headerPrefix:`Bearer `},basic:{headerName:`Authorization`,headerPrefix:`Basic `}},oauth:{authorizeUrl:`https://auth.atlassian.com/authorize`,tokenUrl:`https://auth.atlassian.com/oauth/token`,defaultScopes:[],usePkce:!0,clientAuthMethod:`request_body`,scopeSeparator:`space`}},slack:{providerId:`slack`,name:`Slack`,aliases:[`slack`,`slack.com`],modes:[`oauth`,`token`],defaultMode:`oauth`,serviceTypes:[`http_api`],authTypes:[`token`,`oauth`],tokenAuth:{token:{headerName:`Authorization`,headerPrefix:`Bearer `},oauth:{headerName:`Authorization`,headerPrefix:`Bearer `}},oauth:{authorizeUrl:`https://slack.com/oauth/v2/authorize`,tokenUrl:`https://slack.com/api/oauth.v2.access`,defaultScopes:[],usePkce:!1,clientAuthMethod:`request_body`,scopeSeparator:`comma`}},linear:{providerId:`linear`,name:`Linear`,aliases:[`linear`,`api.linear.app`,`linear.app`],modes:[`oauth`,`token`],defaultMode:`oauth`,serviceTypes:[`http_api`],authTypes:[`token`,`oauth`],tokenAuth:{token:{headerName:`Authorization`,headerPrefix:`Bearer `},oauth:{headerName:`Authorization`,headerPrefix:`Bearer `}},oauth:{authorizeUrl:`https://linear.app/oauth/authorize`,tokenUrl:`https://api.linear.app/oauth/token`,defaultScopes:[],usePkce:!0,clientAuthMethod:`request_body`,scopeSeparator:`space`}},azure_devops:{providerId:`azure_devops`,name:`Azure DevOps`,aliases:[`azure_devops`,`dev.azure.com`],modes:[`oauth`,`token`],defaultMode:`oauth`,serviceTypes:[`http_api`,`git_remote`],authTypes:[`token`,`oauth`,`basic_userpass`,`ssh_key`],tokenAuth:{token:{headerName:`Authorization`,headerPrefix:`Bearer `},oauth:{headerName:`Authorization`,headerPrefix:`Bearer `}},tokenAuthByServiceType:{git_remote:{token:{headerName:`Authorization`,headerPrefix:`Basic `},oauth:{headerName:`Authorization`,headerPrefix:`Basic `}}},oauth:{authorizeUrl:`https://app.vssps.visualstudio.com/oauth2/authorize`,tokenUrl:`https://app.vssps.visualstudio.com/oauth2/token`,defaultScopes:[`vso.code`,`vso.profile`,`offline_access`],usePkce:!1,clientAuthMethod:`request_body`,scopeSeparator:`space`}},custom_mcp:{providerId:`custom_mcp`,name:`Custom MCP`,aliases:[`custom_mcp`],modes:[`oauth`,`token`],defaultMode:`oauth`,serviceTypes:[`mcp_remote`,`webmcp_local`],authTypes:[`none`,`token`,`oauth`,`custom_header`,`ssh_key`],tokenAuth:{token:{headerName:`Authorization`,headerPrefix:`Bearer `},oauth:{headerName:`Authorization`,headerPrefix:`Bearer `}},oauth:{authorizeUrl:`https://example.com/oauth/authorize`,tokenUrl:`https://example.com/oauth/token`,defaultScopes:[],usePkce:!0,clientAuthMethod:`request_body`,scopeSeparator:`space`}}},Ye=Object.fromEntries(Object.values(Je).filter(e=>!!e.oauth).map(e=>{let t=e.oauth;return[e.providerId,{id:e.providerId,name:e.name,authorizeUrl:t.authorizeUrl,tokenUrl:t.tokenUrl,redirectUri:t.redirectUri,defaultScopes:t.defaultScopes,usePkce:t.usePkce,clientAuthMethod:t.clientAuthMethod,scopeSeparator:t.scopeSeparator}]}));Object.fromEntries(Object.values(Je).map(e=>[e.providerId,{providerId:e.providerId,modes:e.modes,defaultMode:e.defaultMode}]));function Xe(e){return Ye[e]||null}let Ze=null;function Qe(e=`database/push-subscriptions.db`){if(Ze)return Ze;Ze=new w(e),Ze.exec(`
2
2
  CREATE TABLE IF NOT EXISTS vapid_keys (
3
3
  id INTEGER PRIMARY KEY CHECK (id = 1),
4
4
  public_key TEXT NOT NULL,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shadow-claw",
3
- "version": "1.31.0",
3
+ "version": "1.33.0",
4
4
  "type": "module",
5
5
  "license": "AGPL-3.0",
6
6
  "description": "Browser-native personal AI assistant.",
@@ -132,8 +132,8 @@
132
132
  "web-push": "^3.6.7"
133
133
  },
134
134
  "devDependencies": {
135
- "@mcp-b/webmcp-polyfill": "^3.0.0",
136
- "@mcp-b/webmcp-types": "^3.0.0",
135
+ "@mcp-b/webmcp-polyfill": "^5.1.0",
136
+ "@mcp-b/webmcp-types": "^5.1.0",
137
137
  "@playwright/test": "^1.59.2",
138
138
  "@storybook/addon-docs": "^10.6.0",
139
139
  "@storybook/web-components-vite": "^10.6.0",
@@ -703,7 +703,8 @@ describe("initControlPlane", () => {
703
703
  });
704
704
  expect(mockExecuteTool).toHaveBeenCalledWith(
705
705
  nativeModelContextTool,
706
- "{}",
706
+ {},
707
+ undefined,
707
708
  );
708
709
  } finally {
709
710
  if (origDocMC)
@@ -713,6 +714,126 @@ describe("initControlPlane", () => {
713
714
  }
714
715
  });
715
716
 
717
+ it("handles Chrome 155+ WebMCP invoke-tool passing JavaScript object directly to executeTool", async () => {
718
+ const origDocMC = Object.getOwnPropertyDescriptor(
719
+ document,
720
+ "modelContext",
721
+ );
722
+ const origNavMC = Object.getOwnPropertyDescriptor(
723
+ navigator,
724
+ "modelContext",
725
+ );
726
+ delete (navigator as any).modelContext;
727
+
728
+ const nativeModelContextTool = {
729
+ name: "list_files",
730
+ description: "List files and directories",
731
+ inputSchema: { type: "object" },
732
+ title: "list_files",
733
+ origin: "http://localhost:8888",
734
+ window: globalThis.window,
735
+ };
736
+
737
+ const mockExecuteTool = jest.fn(async (tool: any, input: any) => {
738
+ if (tool !== nativeModelContextTool) {
739
+ throw new TypeError("parameter 1 is not of type 'ModelContextTool'");
740
+ }
741
+ if (typeof input !== "object" || input === null) {
742
+ throw new TypeError("parameter 2 is not of type 'Object'");
743
+ }
744
+ return "chrome-155-object-result";
745
+ });
746
+
747
+ Object.defineProperty(document, "modelContext", {
748
+ value: {
749
+ getTools: jest.fn(async () => [nativeModelContextTool]),
750
+ executeTool: mockExecuteTool,
751
+ },
752
+ configurable: true,
753
+ });
754
+
755
+ try {
756
+ const res = await executeClientControlCommand(
757
+ "invoke-tool",
758
+ { toolName: "list_files", input: { recursive: true } },
759
+ {},
760
+ );
761
+
762
+ expect(res).toEqual({ result: "chrome-155-object-result" });
763
+ expect(mockExecuteTool).toHaveBeenCalledTimes(1);
764
+ expect(mockExecuteTool).toHaveBeenCalledWith(
765
+ nativeModelContextTool,
766
+ {
767
+ recursive: true,
768
+ },
769
+ undefined,
770
+ );
771
+ } finally {
772
+ if (origDocMC)
773
+ Object.defineProperty(document, "modelContext", origDocMC);
774
+ if (origNavMC)
775
+ Object.defineProperty(navigator, "modelContext", origNavMC);
776
+ }
777
+ });
778
+
779
+ it("gracefully falls back to stringified input in invoke-tool when executeTool throws 'Failed to parse input'", async () => {
780
+ const origDocMC = Object.getOwnPropertyDescriptor(
781
+ document,
782
+ "modelContext",
783
+ );
784
+ const origNavMC = Object.getOwnPropertyDescriptor(
785
+ navigator,
786
+ "modelContext",
787
+ );
788
+ delete (navigator as any).modelContext;
789
+
790
+ const nativeModelContextTool = {
791
+ name: "list_files",
792
+ description: "List files and directories",
793
+ inputSchema: '{"type":"object"}',
794
+ title: "list_files",
795
+ origin: "http://localhost:8888",
796
+ window: globalThis.window,
797
+ };
798
+
799
+ const calls: any[] = [];
800
+ const mockExecuteTool = jest.fn(async (_tool: any, input: any) => {
801
+ calls.push(input);
802
+ if (typeof input !== "string") {
803
+ throw new Error(
804
+ "Failed to parse input arguments: expected DOMString",
805
+ );
806
+ }
807
+ return "legacy-chrome-string-result";
808
+ });
809
+
810
+ Object.defineProperty(document, "modelContext", {
811
+ value: {
812
+ getTools: jest.fn(async () => [nativeModelContextTool]),
813
+ executeTool: mockExecuteTool,
814
+ },
815
+ configurable: true,
816
+ });
817
+
818
+ try {
819
+ const res = await executeClientControlCommand(
820
+ "invoke-tool",
821
+ { toolName: "list_files", input: { path: "src" } },
822
+ {},
823
+ );
824
+
825
+ expect(res).toEqual({ result: "legacy-chrome-string-result" });
826
+ expect(calls).toHaveLength(2);
827
+ expect(calls[0]).toEqual({ path: "src" });
828
+ expect(calls[1]).toBe(JSON.stringify({ path: "src" }));
829
+ } finally {
830
+ if (origDocMC)
831
+ Object.defineProperty(document, "modelContext", origDocMC);
832
+ if (origNavMC)
833
+ Object.defineProperty(navigator, "modelContext", origNavMC);
834
+ }
835
+ });
836
+
716
837
  it("refuses to execute tool when tool is not registered on client or not enabled in active conversation", async () => {
717
838
  const origDocMC = Object.getOwnPropertyDescriptor(
718
839
  document,
@@ -466,36 +466,40 @@ export async function executeClientControlCommand(
466
466
  }
467
467
  }
468
468
 
469
- const inputStr =
470
- typeof args.input === "string"
471
- ? args.input
472
- : JSON.stringify(args.input || {});
469
+ const { executeWebMcpTool } =
470
+ await import("../../subsystems/mcp/webmcp.js");
473
471
 
474
472
  if (typeof ctx.executeTool === "function") {
475
473
  // 1. Pass the actual ModelContextTool object from getTools() if available (required by native Chromium)
476
474
  if (matchedTool) {
477
475
  try {
478
- const res = await ctx.executeTool(matchedTool, inputStr);
476
+ const res = await executeWebMcpTool(ctx, matchedTool, args.input);
479
477
  return { result: res };
480
478
  } catch (_) {}
481
479
  }
482
480
 
483
481
  // 2. Pass { name: toolName } object (accepted by polyfill / mocks)
484
482
  try {
485
- const res = await ctx.executeTool(
483
+ const res = await executeWebMcpTool(
484
+ ctx,
486
485
  { name: args.toolName },
487
- inputStr,
486
+ args.input,
488
487
  );
489
488
  return { result: res };
490
489
  } catch (_) {}
491
490
 
492
491
  // 3. Pass toolName string directly (accepted by some preview shims)
493
492
  try {
494
- const res = await ctx.executeTool(args.toolName, inputStr);
493
+ const res = await executeWebMcpTool(ctx, args.toolName, args.input);
495
494
  return { result: res };
496
495
  } catch (_) {}
497
496
  }
498
497
 
498
+ const inputStr =
499
+ typeof args.input === "string"
500
+ ? args.input
501
+ : JSON.stringify(args.input || {});
502
+
499
503
  // 4. Check navigator.modelContextTesting if present
500
504
  if (
501
505
  typeof navigator !== "undefined" &&
@@ -425,7 +425,21 @@ export async function seedStaticMainSite(
425
425
  try {
426
426
  await deleteGroupDirectory(db, groupId, ".agents/skills/main");
427
427
  } catch (error) {
428
- // A fresh workspace has no bundled-skill directory to remove yet.
428
+ if (
429
+ !(
430
+ error &&
431
+ typeof error === "object" &&
432
+ "name" in error &&
433
+ error.name === "NotFoundError"
434
+ )
435
+ ) {
436
+ throw error;
437
+ }
438
+ }
439
+ try {
440
+ await deleteGroupDirectory(db, groupId, ".agents/tools/main");
441
+ } catch (error) {
442
+ // A fresh workspace has no bundled-tool directory to remove yet.
429
443
  if (
430
444
  !(
431
445
  error &&
@@ -543,7 +557,7 @@ export async function seedStaticMainSite(
543
557
  for (const tool of manifest.tools || []) {
544
558
  const toolPath = `.agents/tools/main/${tool.displayPath}`;
545
559
  try {
546
- if (!(await groupFileExists(db, groupId, toolPath))) {
560
+ if (didPurgeSkills || !(await groupFileExists(db, groupId, toolPath))) {
547
561
  await writeGroupFile(db, groupId, toolPath, tool.content);
548
562
  }
549
563
  } catch (error) {
@@ -2853,6 +2853,39 @@ describe("OrchestratorStore", () => {
2853
2853
  }
2854
2854
  });
2855
2855
 
2856
+ it("applies internetAccess from site-config to vmBashFullInternetAccess", async () => {
2857
+ const store = new OrchestratorStore();
2858
+ const events = createEvents();
2859
+ const orch: any = {
2860
+ events,
2861
+ getUseProxy: () => false,
2862
+ getProxyUrl: () => "",
2863
+ getGitProxyUrl: () => "",
2864
+ getVMBashFullInternetAccess: () => false,
2865
+ getTaskServerUrl: () => "/schedule",
2866
+ taskServerEnabled: true,
2867
+ vmBashFullInternetAccess: false,
2868
+ };
2869
+
2870
+ const configElement = document.createElement("script");
2871
+ configElement.id = "shadow-claw-site-config";
2872
+ configElement.type = "application/json";
2873
+ configElement.textContent = JSON.stringify({
2874
+ settings: {
2875
+ internetAccess: true,
2876
+ },
2877
+ });
2878
+ document.head.appendChild(configElement);
2879
+
2880
+ try {
2881
+ await store.init({} as any, orch);
2882
+ expect(orch.vmBashFullInternetAccess).toBe(true);
2883
+ expect(store._vmBashFullInternetAccess.get()).toBe(true);
2884
+ } finally {
2885
+ configElement.remove();
2886
+ }
2887
+ });
2888
+
2856
2889
  it("clears legacy group-level toolTags on DEFAULT_GROUP_ID if present", async () => {
2857
2890
  const store = new OrchestratorStore();
2858
2891
  const events = createEvents();
@@ -2558,6 +2558,26 @@ export class OrchestratorStore {
2558
2558
  await updateGroupToolTags(db, DEFAULT_GROUP_ID, undefined);
2559
2559
  }
2560
2560
 
2561
+ // If site configuration declares internet access, ensure it is honored
2562
+ const declaredInternetAccess =
2563
+ config.settings?.internetAccess ??
2564
+ config.settings?.vm_bash_full_internet_access ??
2565
+ config.settings?.fullInternetAccess ??
2566
+ config.internetAccess;
2567
+ if (declaredInternetAccess === true) {
2568
+ const currentInternet = await getConfig(
2569
+ db,
2570
+ CONFIG_KEYS.VM_BASH_FULL_INTERNET_ACCESS,
2571
+ );
2572
+ if (currentInternet !== "true") {
2573
+ await setConfig(db, CONFIG_KEYS.VM_BASH_FULL_INTERNET_ACCESS, "true");
2574
+ if (this.orchestrator) {
2575
+ this.orchestrator.vmBashFullInternetAccess = true;
2576
+ }
2577
+ this._vmBashFullInternetAccess.set(true);
2578
+ }
2579
+ }
2580
+
2561
2581
  const isSeeded = await getConfig(db, CONFIG_KEYS.SITE_CONFIG_SEEDED);
2562
2582
  if (isSeeded) {
2563
2583
  return;
@@ -2635,6 +2655,22 @@ export class OrchestratorStore {
2635
2655
  if (assistantName && typeof assistantName === "string") {
2636
2656
  await setConfig(db, CONFIG_KEYS.ASSISTANT_NAME, assistantName);
2637
2657
  }
2658
+ const allowInternet =
2659
+ config.settings.internetAccess ??
2660
+ config.settings.vm_bash_full_internet_access ??
2661
+ config.settings.fullInternetAccess ??
2662
+ config.internetAccess;
2663
+ if (typeof allowInternet === "boolean") {
2664
+ await setConfig(
2665
+ db,
2666
+ CONFIG_KEYS.VM_BASH_FULL_INTERNET_ACCESS,
2667
+ String(allowInternet),
2668
+ );
2669
+ if (this.orchestrator) {
2670
+ this.orchestrator.vmBashFullInternetAccess = allowInternet;
2671
+ }
2672
+ this._vmBashFullInternetAccess.set(allowInternet);
2673
+ }
2638
2674
  }
2639
2675
 
2640
2676
  const defaultToolsProfile =
@@ -83,6 +83,7 @@ jest.unstable_mockModule("@zip.js/zip.js", () => ({}) as any);
83
83
  describe("git", () => {
84
84
  let buildAuthCallbacks: Function;
85
85
  let ensureDir: Function;
86
+ let getGitTargetAddressSpace: Function;
86
87
  let getProxyUrl: Function;
87
88
  let gitAdd: Function;
88
89
  let gitBranch: Function;
@@ -124,6 +125,7 @@ describe("git", () => {
124
125
 
125
126
  buildAuthCallbacks = mod.buildAuthCallbacks;
126
127
  ensureDir = mod.ensureDir;
128
+ getGitTargetAddressSpace = mod.getGitTargetAddressSpace;
127
129
  getProxyUrl = mod.getProxyUrl;
128
130
  gitAdd = mod.gitAdd;
129
131
  gitBranch = mod.gitBranch;
@@ -744,6 +746,103 @@ describe("git", () => {
744
746
 
745
747
  expect(url).toContain("git-proxy");
746
748
  });
749
+
750
+ it("uses https when running under https on localhost:8888", () => {
751
+ expect(
752
+ getProxyUrl("local", undefined, {
753
+ protocol: "https:",
754
+ host: "localhost:8888",
755
+ hostname: "localhost",
756
+ }),
757
+ ).toBe("https://localhost:8888/git-proxy");
758
+ });
759
+
760
+ it("uses https when running under https on a remote host", () => {
761
+ expect(
762
+ getProxyUrl("local", undefined, {
763
+ protocol: "https:",
764
+ host: "xt-ml.github.io",
765
+ hostname: "xt-ml.github.io",
766
+ }),
767
+ ).toBe("https://localhost:8888/git-proxy");
768
+ });
769
+
770
+ it("uses https when running under https with empty or loopback hostname", () => {
771
+ expect(
772
+ getProxyUrl("local", undefined, {
773
+ protocol: "https:",
774
+ host: "localhost:8888",
775
+ hostname: "",
776
+ }),
777
+ ).toBe("https://localhost:8888/git-proxy");
778
+
779
+ expect(
780
+ getProxyUrl("local", undefined, {
781
+ protocol: "https:",
782
+ host: "[::1]:8888",
783
+ hostname: "[::1]",
784
+ }),
785
+ ).toBe("https://[::1]:8888/git-proxy");
786
+ });
787
+
788
+ it("preserves http when running under http", () => {
789
+ expect(
790
+ getProxyUrl("local", undefined, {
791
+ protocol: "http:",
792
+ host: "localhost:8888",
793
+ hostname: "localhost",
794
+ }),
795
+ ).toBe("http://localhost:8888/git-proxy");
796
+
797
+ expect(
798
+ getProxyUrl("local", undefined, {
799
+ protocol: "http:",
800
+ host: "xt-ml.github.io",
801
+ hostname: "xt-ml.github.io",
802
+ }),
803
+ ).toBe("http://localhost:8888/git-proxy");
804
+ });
805
+
806
+ it("uses custom URL when provided", () => {
807
+ expect(getProxyUrl("custom", "https://proxy.example.com/git")).toBe(
808
+ "https://proxy.example.com/git",
809
+ );
810
+ });
811
+ });
812
+
813
+ describe("getGitTargetAddressSpace", () => {
814
+ it("returns loopback for localhost and 127.0.0.1 and [::1]", () => {
815
+ expect(
816
+ getGitTargetAddressSpace("http://localhost:8888/git-proxy/test"),
817
+ ).toBe("loopback");
818
+ expect(
819
+ getGitTargetAddressSpace("https://127.0.0.1:8888/git-proxy/test"),
820
+ ).toBe("loopback");
821
+ expect(
822
+ getGitTargetAddressSpace("https://[::1]:8888/git-proxy/test"),
823
+ ).toBe("loopback");
824
+ });
825
+
826
+ it("returns private for private networks and local domains", () => {
827
+ expect(
828
+ getGitTargetAddressSpace("https://192.168.1.10:8888/git-proxy/test"),
829
+ ).toBe("private");
830
+ expect(
831
+ getGitTargetAddressSpace("https://10.0.0.5:8888/git-proxy/test"),
832
+ ).toBe("private");
833
+ expect(getGitTargetAddressSpace("https://tv:8888/git-proxy/test")).toBe(
834
+ "private",
835
+ );
836
+ expect(
837
+ getGitTargetAddressSpace("https://my-nas.local:8888/git-proxy/test"),
838
+ ).toBe("private");
839
+ });
840
+
841
+ it("returns undefined for public domains", () => {
842
+ expect(
843
+ getGitTargetAddressSpace("https://github.com/user/repo.git"),
844
+ ).toBeUndefined();
845
+ });
747
846
  });
748
847
 
749
848
  describe("repoDir", () => {
@@ -17,6 +17,39 @@ if (!globalThis.Buffer) {
17
17
  globalThis.Buffer = Buffer;
18
18
  }
19
19
 
20
+ export function getGitTargetAddressSpace(
21
+ url: string,
22
+ ): "loopback" | "private" | undefined {
23
+ try {
24
+ const locOrigin =
25
+ typeof location !== "undefined" && location.origin
26
+ ? location.origin
27
+ : typeof globalThis !== "undefined" && globalThis.location?.origin
28
+ ? globalThis.location.origin
29
+ : "http://127.0.0.1:8888";
30
+ const u = new URL(url, locOrigin);
31
+ const host = u.hostname.toLowerCase();
32
+ if (
33
+ host === "localhost" ||
34
+ host === "127.0.0.1" ||
35
+ host === "::1" ||
36
+ host === "[::1]"
37
+ ) {
38
+ return "loopback";
39
+ } else if (
40
+ /^(10\.|172\.(1[6-9]|2\d|3[01])\.|192\.168\.)/.test(host) ||
41
+ !host.includes(".") ||
42
+ host.endsWith(".local") ||
43
+ host.endsWith(".lan") ||
44
+ host.endsWith(".home") ||
45
+ host.endsWith(".internal")
46
+ ) {
47
+ return "private";
48
+ }
49
+ } catch (_) {}
50
+ return undefined;
51
+ }
52
+
20
53
  const httpClient = {
21
54
  async request({
22
55
  url,
@@ -34,12 +67,18 @@ const httpClient = {
34
67
  body = await collectBody(body);
35
68
  }
36
69
 
37
- const res = await fetch(url, {
70
+ const targetAddressSpace = getGitTargetAddressSpace(url);
71
+ const fetchOptions: RequestInit & { targetAddressSpace?: string } = {
38
72
  method,
39
73
  headers,
40
74
  body,
41
75
  credentials: "omit",
42
- });
76
+ };
77
+ if (targetAddressSpace) {
78
+ fetchOptions.targetAddressSpace = targetAddressSpace;
79
+ }
80
+
81
+ const res = await fetch(url, fetchOptions);
43
82
 
44
83
  const iter =
45
84
  res.body && typeof res.body.getReader === "function"
@@ -572,6 +611,13 @@ const DEFAULT_DEPTH = 20;
572
611
  export function getProxyUrl(
573
612
  preference: "local" | "public" | "custom",
574
613
  customUrl?: string,
614
+ loc?: {
615
+ protocol?: string;
616
+ host?: string;
617
+ hostname?: string;
618
+ origin?: string;
619
+ href?: string;
620
+ },
575
621
  ): string {
576
622
  if (preference === "custom" && customUrl) {
577
623
  return customUrl;
@@ -582,16 +628,50 @@ export function getProxyUrl(
582
628
  }
583
629
 
584
630
  // Default to local proxy
585
- const { protocol, host, hostname } = globalThis.location;
586
-
587
- // If running on localhost/127.0.0.1, use the current host (works for dev)
588
- if (hostname === "localhost" || hostname === "127.0.0.1") {
589
- return `${protocol}//${host}/git-proxy`;
590
- }
591
-
592
- // If on a remote host, default to local dev server port
593
-
594
- return `http://${DEFAULT_DEV_HOST}:${DEFAULT_DEV_PORT}/git-proxy`;
631
+ const currentLoc =
632
+ loc ||
633
+ (typeof globalThis !== "undefined" && globalThis.location
634
+ ? globalThis.location
635
+ : typeof self !== "undefined" && (self as any).location
636
+ ? (self as any).location
637
+ : typeof window !== "undefined" && window.location
638
+ ? window.location
639
+ : null);
640
+
641
+ const rawProtocol = currentLoc?.protocol || "";
642
+ const isHttps =
643
+ rawProtocol === "https:" ||
644
+ rawProtocol === "https" ||
645
+ (typeof currentLoc?.origin === "string" &&
646
+ currentLoc.origin.startsWith("https:")) ||
647
+ (typeof currentLoc?.href === "string" &&
648
+ currentLoc.href.startsWith("https://"));
649
+ const scheme = isHttps ? "https:" : "http:";
650
+
651
+ const host = currentLoc?.host || "";
652
+ const hostname = currentLoc?.hostname || "";
653
+
654
+ const isLoopback =
655
+ hostname === "localhost" ||
656
+ hostname === "127.0.0.1" ||
657
+ hostname === "::1" ||
658
+ hostname === "[::1]" ||
659
+ hostname === "0.0.0.0" ||
660
+ host.startsWith("localhost:") ||
661
+ host.startsWith("127.0.0.1:") ||
662
+ host.startsWith("[::1]:");
663
+
664
+ const isStaticHost =
665
+ currentLoc &&
666
+ (currentLoc.protocol === "file:" ||
667
+ (hostname &&
668
+ (hostname.endsWith(".github.io") || hostname.endsWith(".pages.dev"))));
669
+
670
+ if (host && (isLoopback || !isStaticHost)) {
671
+ return `${scheme}//${host}/git-proxy`;
672
+ }
673
+
674
+ return `${scheme}//${DEFAULT_DEV_HOST}:${DEFAULT_DEV_PORT}/git-proxy`;
595
675
  }
596
676
 
597
677
  /**