shadow-claw 1.40.0 → 1.41.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 (373) hide show
  1. package/.well-known/mcp/server-card.json +2 -2
  2. package/.well-known/mcp/servers.json +1 -1
  3. package/.well-known/mcp.json +2 -2
  4. package/README.md +1 -0
  5. package/dist/cli/build/build.js +1 -1
  6. package/dist/cli/{chunk-Bfz2NYgD.js → chunk-0IeC97mU.js} +7 -7
  7. package/dist/cli/chunk-3oLxlxPn.js +1 -0
  8. package/dist/cli/{chunk-BXg4-9Rq2.js → chunk-8CrZyP1b2.js} +1 -1
  9. package/dist/cli/{chunk-BP5Hg6CM.js → chunk-B--ueArB.js} +1 -1
  10. package/dist/cli/chunk-BIh7rXlJ2.js +1 -0
  11. package/dist/cli/{chunk-Drr0VSGA2.js → chunk-BKnTOLLS2.js} +1 -1
  12. package/dist/cli/{chunk-C5PuRV08.js → chunk-BLMC1Bxv.js} +1 -1
  13. package/dist/cli/{chunk-B2tNSlFy2.js → chunk-BOigzz2U2.js} +1 -1
  14. package/dist/cli/{chunk-DOf3DZdR.js → chunk-BOzn335y.js} +1 -1
  15. package/dist/cli/chunk-BjOeVLb42.js +1 -0
  16. package/dist/cli/{chunk-DqTx0rRp2.js → chunk-Bjqh5_SU2.js} +1 -1
  17. package/dist/cli/chunk-BqWBd_jF2.js +1 -0
  18. package/dist/cli/{chunk-Bc9nRNyN.js → chunk-BvVUnHTq.js} +12 -9
  19. package/dist/cli/{chunk-DIbSoQmd2.js → chunk-C6FFByBU2.js} +2 -2
  20. package/dist/cli/{chunk-Drq18VZe.js → chunk-C9-aL3rF.js} +1 -1
  21. package/dist/cli/{chunk-BUhqHeEA2.js → chunk-C9czddEh2.js} +2 -2
  22. package/dist/cli/chunk-CCx8WOwz2.js +1 -0
  23. package/dist/cli/{chunk-BkMSjVJb.js → chunk-CK6ejMig.js} +1 -1
  24. package/dist/cli/chunk-CUUERioR2.js +1 -0
  25. package/dist/cli/chunk-CXAobnJd.js +1 -0
  26. package/dist/cli/chunk-CY1X0pOF2.js +1 -0
  27. package/dist/cli/chunk-CZvvgLVv.js +1 -0
  28. package/dist/cli/chunk-CbcwbfJB.js +1 -0
  29. package/dist/cli/{chunk-quilB3TV2.js → chunk-Ci9OJGcd2.js} +1 -1
  30. package/dist/cli/chunk-Cj9wl0qx.js +1 -0
  31. package/dist/cli/{chunk-3gRhOmGo2.js → chunk-CjJsVrKI2.js} +1 -1
  32. package/dist/cli/{chunk-CmEfzm-_.js → chunk-ClPZ4Rea.js} +1 -1
  33. package/dist/cli/{chunk-WMPAfIvV2.js → chunk-DHJCGRuG2.js} +1 -1
  34. package/dist/cli/{chunk-C7Y2xIk4.js → chunk-DKVkYTV9.js} +1 -1
  35. package/dist/cli/chunk-DR2XtWRo.js +1 -0
  36. package/dist/cli/{chunk-DID5VvOG.js → chunk-DTES-dE6.js} +3 -3
  37. package/dist/cli/{chunk-BiVJVh_S.js → chunk-DUlIqkaX.js} +7 -7
  38. package/dist/cli/{chunk-CkpueGaZ2.js → chunk-DjWle8FF2.js} +1 -1
  39. package/dist/cli/{chunk-CSvHmNOk.js → chunk-DmRXVLfy.js} +1 -1
  40. package/dist/cli/{chunk-BT1xXZn72.js → chunk-HlSiTC-u2.js} +1 -1
  41. package/dist/cli/{chunk-da0bsiOn.js → chunk-P4JSeFBI.js} +1 -1
  42. package/dist/cli/chunk-UcNbHaRQ.js +1 -0
  43. package/dist/cli/{chunk-BXFHFbEd.js → chunk-UweLmfQS.js} +1 -1
  44. package/dist/cli/chunk-bQQkVCw-.js +94 -0
  45. package/dist/cli/{chunk-CGiXWHTi2.js → chunk-gwpxl-0W2.js} +1 -1
  46. package/dist/cli/{chunk-NH8koEis2.js → chunk-nmDhxXH_2.js} +1 -1
  47. package/dist/cli/chunk-p0n_c-I2.js +1 -0
  48. package/dist/cli/{chunk-D7xP72La.js → chunk-q7r4FosZ.js} +1 -1
  49. package/dist/cli/cli.js +3 -3
  50. package/dist/cli/prerender/dsd-shell/prerender-dsd-shell.js +1 -1
  51. package/dist/electron/main.cjs +1 -1
  52. package/dist/headless-agent.js +1 -1
  53. package/dist/lib/{app-routes-BAEMLu9g.js → app-routes-CKkiX12g.js} +7 -2
  54. package/dist/lib/app-routes-CKkiX12g.js.map +1 -0
  55. package/dist/lib/components/index.js +26 -26
  56. package/dist/lib/components/settings/shadow-claw-accounts.js +1 -1
  57. package/dist/lib/components/settings/shadow-claw-channel-config.js +1 -1
  58. package/dist/lib/components/settings/shadow-claw-control-plane.js +1 -1
  59. package/dist/lib/components/settings/shadow-claw-git.js +1 -1
  60. package/dist/lib/components/settings/shadow-claw-integrations.js +1 -1
  61. package/dist/lib/components/settings/shadow-claw-llm.js +1 -1
  62. package/dist/lib/components/settings/shadow-claw-mcp-remote.js +1 -1
  63. package/dist/lib/components/settings/shadow-claw-networking.js +1 -1
  64. package/dist/lib/components/settings/shadow-claw-notifications.js +1 -1
  65. package/dist/lib/components/settings/shadow-claw-peerjs.js +1 -1
  66. package/dist/lib/components/settings/shadow-claw-storage.js +1 -1
  67. package/dist/lib/components/settings/shadow-claw-task-server.js +1 -1
  68. package/dist/lib/components/settings/shadow-claw-webvm.js +1 -1
  69. package/dist/lib/components/shadow-claw/utils/syncSlottedSidebarActiveLinks.d.ts +10 -0
  70. package/dist/lib/components/shadow-claw-a2ui.js +1 -1
  71. package/dist/lib/components/shadow-claw-accounts.js +1 -1
  72. package/dist/lib/components/shadow-claw-channel-config.js +1 -1
  73. package/dist/lib/components/shadow-claw-channels.js +1 -1
  74. package/dist/lib/components/shadow-claw-chat.js +1 -1
  75. package/dist/lib/components/shadow-claw-control-plane.js +1 -1
  76. package/dist/lib/components/shadow-claw-conversations.js +1 -1
  77. package/dist/lib/components/shadow-claw-file-viewer/shadow-claw-file-viewer.d.ts +1 -1
  78. package/dist/lib/components/shadow-claw-file-viewer.js +1 -1
  79. package/dist/lib/components/shadow-claw-files.js +1 -1
  80. package/dist/lib/components/shadow-claw-git.js +1 -1
  81. package/dist/lib/components/shadow-claw-integrations.js +1 -1
  82. package/dist/lib/components/shadow-claw-llm.js +1 -1
  83. package/dist/lib/components/shadow-claw-mcp-remote.js +1 -1
  84. package/dist/lib/components/shadow-claw-networking.js +1 -1
  85. package/dist/lib/components/shadow-claw-notifications.js +1 -1
  86. package/dist/lib/components/shadow-claw-page-header.js +1 -1
  87. package/dist/lib/components/shadow-claw-pages.js +1 -1
  88. package/dist/lib/components/shadow-claw-peerjs.js +1 -1
  89. package/dist/lib/components/shadow-claw-settings.js +1 -1
  90. package/dist/lib/components/shadow-claw-storage.js +1 -1
  91. package/dist/lib/components/shadow-claw-task-server.js +1 -1
  92. package/dist/lib/components/shadow-claw-tasks.js +1 -1
  93. package/dist/lib/components/shadow-claw-terminal.js +1 -1
  94. package/dist/lib/components/shadow-claw-tools.js +1 -1
  95. package/dist/lib/components/shadow-claw-webvm.js +1 -1
  96. package/dist/lib/components/shadow-claw.js +1 -1
  97. package/dist/lib/{config-CPHDmyTx.js → config-DZkF9LiO.js} +2 -2
  98. package/dist/lib/{config-CPHDmyTx.js.map → config-DZkF9LiO.js.map} +1 -1
  99. package/dist/lib/{configurePeerJs-BsJoycQd.js → configurePeerJs-B3IE9BY2.js} +3 -3
  100. package/dist/lib/{configurePeerJs-BsJoycQd.js.map → configurePeerJs-B3IE9BY2.js.map} +1 -1
  101. package/dist/lib/{connections-BdIru7bF.js → connections-CalJGWvZ.js} +2 -2
  102. package/dist/lib/{connections-BdIru7bF.js.map → connections-CalJGWvZ.js.map} +1 -1
  103. package/dist/lib/core/orchestrator/orchestrator-state.d.ts +2 -1
  104. package/dist/lib/core/orchestrator/orchestrator.d.ts +2 -1
  105. package/dist/lib/core/orchestrator/utils/operations/task.d.ts +1 -0
  106. package/dist/lib/{downloadGroupFile-Dn0KsMlV.js → downloadGroupFile-DDE1fIhJ.js} +2 -2
  107. package/dist/lib/{downloadGroupFile-Dn0KsMlV.js.map → downloadGroupFile-DDE1fIhJ.js.map} +1 -1
  108. package/dist/lib/{file-viewer-BYrXXu-X.js → file-viewer-Bll2EoGc.js} +5 -5
  109. package/dist/lib/{file-viewer-BYrXXu-X.js.map → file-viewer-Bll2EoGc.js.map} +1 -1
  110. package/dist/lib/{getGroupDir-DF-RZO8X.js → getGroupDir-MHv7Lvmp.js} +4 -4
  111. package/dist/lib/{getGroupDir-DF-RZO8X.js.map → getGroupDir-MHv7Lvmp.js.map} +1 -1
  112. package/dist/lib/{git-s_0cgKm1.js → git-Bv_M3dgw.js} +3 -3
  113. package/dist/lib/{git-s_0cgKm1.js.map → git-Bv_M3dgw.js.map} +1 -1
  114. package/dist/lib/{iframe-sanitizer-DFdda1jJ.js → iframe-sanitizer-C7ZGDjEI.js} +2 -2
  115. package/dist/lib/{iframe-sanitizer-DFdda1jJ.js.map → iframe-sanitizer-C7ZGDjEI.js.map} +1 -1
  116. package/dist/lib/{iframe-storage-proxy-qrhZmQyO.js → iframe-storage-proxy-CR8ZYHPd.js} +2 -2
  117. package/dist/lib/{iframe-storage-proxy-qrhZmQyO.js.map → iframe-storage-proxy-CR8ZYHPd.js.map} +1 -1
  118. package/dist/lib/index.js +27 -27
  119. package/dist/lib/{initChatSplitResize-DuNlwCuI.js → initChatSplitResize-DiKTI-wk.js} +2 -2
  120. package/dist/lib/{initChatSplitResize-DuNlwCuI.js.map → initChatSplitResize-DiKTI-wk.js.map} +1 -1
  121. package/dist/lib/{initControlPlane-D4UZ4EhV.js → initControlPlane-CzjtQ4aM.js} +15 -15
  122. package/dist/lib/{initControlPlane-D4UZ4EhV.js.map → initControlPlane-CzjtQ4aM.js.map} +1 -1
  123. package/dist/lib/{markdown-CRRwbN9h.js → markdown-k8wA9LKy.js} +4 -4
  124. package/dist/lib/{markdown-CRRwbN9h.js.map → markdown-k8wA9LKy.js.map} +1 -1
  125. package/dist/lib/{mcp-reconnect-COdZ-cea.js → mcp-reconnect-CGIdfZnS.js} +2 -2
  126. package/dist/lib/{mcp-reconnect-COdZ-cea.js.map → mcp-reconnect-CGIdfZnS.js.map} +1 -1
  127. package/dist/lib/{memoryStorage-BsMe2FOQ.js → memoryStorage-DL-Bo3dh.js} +2 -2
  128. package/dist/lib/{memoryStorage-BsMe2FOQ.js.map → memoryStorage-DL-Bo3dh.js.map} +1 -1
  129. package/dist/lib/{orchestrator-D9f5fDCb.js → orchestrator-DKHCoikY.js} +11 -11
  130. package/dist/lib/{orchestrator-D9f5fDCb.js.map → orchestrator-DKHCoikY.js.map} +1 -1
  131. package/dist/lib/{orchestrator-Bq9ft3uG.js → orchestrator-Dn1ZOz9B.js} +20 -24
  132. package/dist/lib/orchestrator-Dn1ZOz9B.js.map +1 -0
  133. package/dist/lib/{peerjs-6u8KtenE.js → peerjs-BK41iBvP.js} +7 -7
  134. package/dist/lib/{peerjs-6u8KtenE.js.map → peerjs-BK41iBvP.js.map} +1 -1
  135. package/dist/lib/{push-client-DCnB2-OU.js → push-client-DKgVFD2Z.js} +3 -3
  136. package/dist/lib/{push-client-DCnB2-OU.js.map → push-client-DKgVFD2Z.js.map} +1 -1
  137. package/dist/lib/{readGroupFileBytes-nKNJ6sbl.js → readGroupFileBytes-CgU_UfGv.js} +2 -2
  138. package/dist/lib/{readGroupFileBytes-nKNJ6sbl.js.map → readGroupFileBytes-CgU_UfGv.js.map} +1 -1
  139. package/dist/lib/{shadow-claw-MumteAJy.js → shadow-claw-CtCj5Rn_.js} +121 -16
  140. package/dist/lib/shadow-claw-CtCj5Rn_.js.map +1 -0
  141. package/dist/lib/{shadow-claw-a2ui-Dipe8nY2.js → shadow-claw-a2ui-CvK5w940.js} +2 -2
  142. package/dist/lib/{shadow-claw-a2ui-Dipe8nY2.js.map → shadow-claw-a2ui-CvK5w940.js.map} +1 -1
  143. package/dist/lib/{shadow-claw-accounts-BgCkz3Zv.js → shadow-claw-accounts-Br3XdHro.js} +3 -3
  144. package/dist/lib/{shadow-claw-accounts-BgCkz3Zv.js.map → shadow-claw-accounts-Br3XdHro.js.map} +1 -1
  145. package/dist/lib/{shadow-claw-channel-config-CIm_Bxd2.js → shadow-claw-channel-config-Da2dN19M.js} +3 -3
  146. package/dist/lib/{shadow-claw-channel-config-CIm_Bxd2.js.map → shadow-claw-channel-config-Da2dN19M.js.map} +1 -1
  147. package/dist/lib/{shadow-claw-channels-CaceK52s.js → shadow-claw-channels-BofYHgz8.js} +3 -3
  148. package/dist/lib/{shadow-claw-channels-CaceK52s.js.map → shadow-claw-channels-BofYHgz8.js.map} +1 -1
  149. package/dist/lib/{shadow-claw-chat-BD18-mAR.js → shadow-claw-chat-Dw32DPV2.js} +12 -12
  150. package/dist/lib/{shadow-claw-chat-BD18-mAR.js.map → shadow-claw-chat-Dw32DPV2.js.map} +1 -1
  151. package/dist/lib/{shadow-claw-control-plane-U6LsfRPm.js → shadow-claw-control-plane-CwFotFDh.js} +7 -7
  152. package/dist/lib/{shadow-claw-control-plane-U6LsfRPm.js.map → shadow-claw-control-plane-CwFotFDh.js.map} +1 -1
  153. package/dist/lib/{shadow-claw-conversations-CDsza_oB.js → shadow-claw-conversations-0UXge23k.js} +5 -5
  154. package/dist/lib/{shadow-claw-conversations-CDsza_oB.js.map → shadow-claw-conversations-0UXge23k.js.map} +1 -1
  155. package/dist/lib/{shadow-claw-file-viewer-CMOnFmcP.js → shadow-claw-file-viewer-CAsn9NxH.js} +30 -30
  156. package/dist/lib/{shadow-claw-file-viewer-CMOnFmcP.js.map → shadow-claw-file-viewer-CAsn9NxH.js.map} +1 -1
  157. package/dist/lib/{shadow-claw-files-BI0P3m8a.js → shadow-claw-files-xGGhsHNH.js} +9 -9
  158. package/dist/lib/{shadow-claw-files-BI0P3m8a.js.map → shadow-claw-files-xGGhsHNH.js.map} +1 -1
  159. package/dist/lib/{shadow-claw-git-xRApLEMN.js → shadow-claw-git-B606hcMU.js} +6 -6
  160. package/dist/lib/{shadow-claw-git-xRApLEMN.js.map → shadow-claw-git-B606hcMU.js.map} +1 -1
  161. package/dist/lib/{shadow-claw-integrations-B2e1Nfg1.js → shadow-claw-integrations-Bwq5cba1.js} +4 -4
  162. package/dist/lib/{shadow-claw-integrations-B2e1Nfg1.js.map → shadow-claw-integrations-Bwq5cba1.js.map} +1 -1
  163. package/dist/lib/{shadow-claw-llm-Bc2mWuGb.js → shadow-claw-llm-BgpcMBIy.js} +6 -6
  164. package/dist/lib/{shadow-claw-llm-Bc2mWuGb.js.map → shadow-claw-llm-BgpcMBIy.js.map} +1 -1
  165. package/dist/lib/{shadow-claw-mcp-remote-D_Bh3aeC.js → shadow-claw-mcp-remote-DvQCA-Bk.js} +4 -4
  166. package/dist/lib/{shadow-claw-mcp-remote-D_Bh3aeC.js.map → shadow-claw-mcp-remote-DvQCA-Bk.js.map} +1 -1
  167. package/dist/lib/{shadow-claw-networking-F5W3n5ci.js → shadow-claw-networking-Cxvf9c7E.js} +2 -2
  168. package/dist/lib/{shadow-claw-networking-F5W3n5ci.js.map → shadow-claw-networking-Cxvf9c7E.js.map} +1 -1
  169. package/dist/lib/{shadow-claw-notifications-lvMt9WJ1.js → shadow-claw-notifications-CGVcFYBy.js} +3 -3
  170. package/dist/lib/{shadow-claw-notifications-lvMt9WJ1.js.map → shadow-claw-notifications-CGVcFYBy.js.map} +1 -1
  171. package/dist/lib/{shadow-claw-page-header-6gq6EMqX.js → shadow-claw-page-header-DAYz3I_o.js} +2 -2
  172. package/dist/lib/{shadow-claw-page-header-6gq6EMqX.js.map → shadow-claw-page-header-DAYz3I_o.js.map} +1 -1
  173. package/dist/lib/{shadow-claw-pages-Bo8_z2S-.js → shadow-claw-pages-BLeEZb9k.js} +24 -12
  174. package/dist/lib/shadow-claw-pages-BLeEZb9k.js.map +1 -0
  175. package/dist/lib/{shadow-claw-peerjs-DRTLCVDQ.js → shadow-claw-peerjs-BcFnbK74.js} +3 -3
  176. package/dist/lib/{shadow-claw-peerjs-DRTLCVDQ.js.map → shadow-claw-peerjs-BcFnbK74.js.map} +1 -1
  177. package/dist/lib/{shadow-claw-settings-D00B4p4L.js → shadow-claw-settings-B7o0Z4hu.js} +9 -9
  178. package/dist/lib/{shadow-claw-settings-D00B4p4L.js.map → shadow-claw-settings-B7o0Z4hu.js.map} +1 -1
  179. package/dist/lib/{shadow-claw-storage-DgMe7-Zo.js → shadow-claw-storage-afMVqB7E.js} +5 -5
  180. package/dist/lib/{shadow-claw-storage-DgMe7-Zo.js.map → shadow-claw-storage-afMVqB7E.js.map} +1 -1
  181. package/dist/lib/{shadow-claw-task-server-D103YOuI.js → shadow-claw-task-server-B9-MQjl6.js} +2 -2
  182. package/dist/lib/{shadow-claw-task-server-D103YOuI.js.map → shadow-claw-task-server-B9-MQjl6.js.map} +1 -1
  183. package/dist/lib/{shadow-claw-tasks-6OhALkq1.js → shadow-claw-tasks-Dc4BC-t-.js} +8 -8
  184. package/dist/lib/{shadow-claw-tasks-6OhALkq1.js.map → shadow-claw-tasks-Dc4BC-t-.js.map} +1 -1
  185. package/dist/lib/{shadow-claw-terminal-BGtxA1qD.js → shadow-claw-terminal-BINcTdsk.js} +2 -2
  186. package/dist/lib/{shadow-claw-terminal-BGtxA1qD.js.map → shadow-claw-terminal-BINcTdsk.js.map} +1 -1
  187. package/dist/lib/{shadow-claw-tools-OeIwAnnd.js → shadow-claw-tools-BjFgXNLR.js} +7 -7
  188. package/dist/lib/{shadow-claw-tools-OeIwAnnd.js.map → shadow-claw-tools-BjFgXNLR.js.map} +1 -1
  189. package/dist/lib/{shadow-claw-webvm-gVFZ197u.js → shadow-claw-webvm-Xe3ByMDw.js} +3 -3
  190. package/dist/lib/{shadow-claw-webvm-gVFZ197u.js.map → shadow-claw-webvm-Xe3ByMDw.js.map} +1 -1
  191. package/dist/lib/subsystems/mcp/webmcp.d.ts +64 -0
  192. package/dist/lib/{syncWebMcpRegistration-Bbph0XZl.js → syncWebMcpRegistration-D7alChz0.js} +21 -6
  193. package/dist/lib/syncWebMcpRegistration-D7alChz0.js.map +1 -0
  194. package/dist/lib/{tools-D0OlSzMD.js → tools-Cmhpk3X8.js} +4 -4
  195. package/dist/lib/{tools-D0OlSzMD.js.map → tools-Cmhpk3X8.js.map} +1 -1
  196. package/dist/lib/utils/index.js +1 -1
  197. package/dist/lib/utils/namespacedStorage.js +1 -1
  198. package/dist/lib/utils/utils.js +1 -1
  199. package/dist/lib/{utils-DYdrO2KI.js → utils-CzgKe_XZ.js} +4 -4
  200. package/dist/lib/{utils-DYdrO2KI.js.map → utils-CzgKe_XZ.js.map} +1 -1
  201. package/dist/lib/{webmcp-D2bocsgh.js → webmcp-oEP9YpR2.js} +119 -3
  202. package/dist/lib/{webmcp-D2bocsgh.js.map → webmcp-oEP9YpR2.js.map} +1 -1
  203. package/dist/public/.well-known/mcp/server-card.json +2 -2
  204. package/dist/public/.well-known/mcp/servers.json +1 -1
  205. package/dist/public/.well-known/mcp.json +2 -2
  206. package/dist/public/AGENTS.md +2 -1
  207. package/dist/public/README.md +1 -0
  208. package/dist/public/agent.worker.js +1 -1
  209. package/dist/public/app-routes-C6-H2zPH.js +1 -0
  210. package/dist/public/components/shadow-claw/shadow-claw.css +1 -1
  211. package/dist/public/components/shadow-claw/shadow-claw.html +1 -1
  212. package/dist/public/components/shadow-claw-pages/shadow-claw-pages.css +1 -1
  213. package/dist/public/{config-D4lVqMs8.js → config-Dewnqegf.js} +1 -1
  214. package/dist/public/{configurePeerJs-DDOAVSaH.js → configurePeerJs-CaPU2sN5.js} +1 -1
  215. package/dist/public/{connections-CiukjGiH.js → connections-CwE7jE9l.js} +1 -1
  216. package/dist/public/{custom-element-security-piU2U-Ec.js → custom-element-security-DLgHMf5R.js} +1 -1
  217. package/dist/public/docs/decisions/native-web-components-and-signals.md +1 -1
  218. package/dist/public/docs/example/article/index.html +5 -5
  219. package/dist/public/docs/guides/publishing-to-github-pages.md +49 -6
  220. package/dist/public/docs/publishing/index.html +5 -5
  221. package/dist/public/docs/skill-creator/index.html +5 -5
  222. package/dist/public/docs/subsystems/pages.md +10 -3
  223. package/dist/public/docs/subsystems/webmcp.md +89 -1
  224. package/dist/public/{downloadGroupFile-BiZQYY-O.js → downloadGroupFile-ChWHuap_.js} +1 -1
  225. package/dist/public/e2e/README.md +2 -2
  226. package/dist/public/{e2e-bridge-CybB810Q.js → e2e-bridge-BkaldjV2.js} +1 -1
  227. package/dist/public/{file-viewer-DLUBvOVD.js → file-viewer-Df4qUJCn.js} +1 -1
  228. package/dist/public/{getGroupDir-CLz5c8cg.js → getGroupDir-CeSr4fzS.js} +1 -1
  229. package/dist/public/{git-Ba8AeviI.js → git-Bscc1tK-.js} +2 -2
  230. package/dist/public/{iframe-sanitizer-CKOO7cxp.js → iframe-sanitizer-BVdkQsor.js} +1 -1
  231. package/dist/public/{iframe-storage-proxy-BvRiccH0.js → iframe-storage-proxy-Cg8aFw7o.js} +1 -1
  232. package/dist/public/index.css +1 -1
  233. package/dist/public/index.html +5 -5
  234. package/dist/public/index.js +1 -1
  235. package/dist/public/{initChatSplitResize-osJXM2gu.js → initChatSplitResize-C3Rp1LeZ.js} +1 -1
  236. package/dist/public/{initControlPlane-CNggzsRw.js → initControlPlane-C1pnzG16.js} +1 -1
  237. package/dist/public/llms.txt +1 -1
  238. package/dist/public/main/index.html +5 -5
  239. package/dist/public/main/memory/index.html +5 -5
  240. package/dist/public/{markdown-CZA-Ye2Q.js → markdown-D3A902nT.js} +1 -1
  241. package/dist/public/{mcp-reconnect-BK1bYBdC.js → mcp-reconnect-BJWxQBm_.js} +1 -1
  242. package/dist/public/{memoryStorage-Bew1X8Uy.js → memoryStorage-ykv-Ri-y.js} +1 -1
  243. package/dist/public/{orchestrator-D6tel2Zp.js → orchestrator-BVnC4Vtt.js} +2 -2
  244. package/dist/public/{orchestrator-BLkS_jpm.js → orchestrator-CQcc7OFA.js} +2 -2
  245. package/dist/public/{peerjs-CYs1F7sq.js → peerjs-CYC2cI1Y.js} +1 -1
  246. package/dist/public/{push-client-_HUyJlFJ.js → push-client-BJrnOULM.js} +1 -1
  247. package/dist/public/service-worker/fetch-proxy.js +1 -1
  248. package/dist/public/service-worker.js +1 -1
  249. package/dist/public/{shadow-claw-DmrxnX3Q.js → shadow-claw-WwfOu-tu.js} +33 -3
  250. package/dist/public/{shadow-claw-accounts-BqGrm47Z.js → shadow-claw-accounts-BFZxrPsH.js} +1 -1
  251. package/dist/public/{shadow-claw-channels-Ci2UPaaA.js → shadow-claw-channels-C0w0c1EF.js} +1 -1
  252. package/dist/public/{shadow-claw-chat-BxR6cBYQ.js → shadow-claw-chat-DIJ0A-QN.js} +1 -1
  253. package/dist/public/{shadow-claw-control-plane-C1A-CZ9H.js → shadow-claw-control-plane-DZoxUd-1.js} +2 -2
  254. package/dist/public/{shadow-claw-conversations-DcwG05-H.js → shadow-claw-conversations-DMyG_5zj.js} +1 -1
  255. package/dist/public/{shadow-claw-file-viewer-a_uRA30F.js → shadow-claw-file-viewer-DYgZjZb9.js} +2 -2
  256. package/dist/public/{shadow-claw-files-B774Xz1d.js → shadow-claw-files-DIOUdKJr.js} +1 -1
  257. package/dist/public/{shadow-claw-git-CTIPP0vs.js → shadow-claw-git-if5S0QJr.js} +2 -2
  258. package/dist/public/{shadow-claw-integrations-CjtkA6l0.js → shadow-claw-integrations-BQt4hcWe.js} +1 -1
  259. package/dist/public/{shadow-claw-llm-DfmITHde.js → shadow-claw-llm-9uf1KFA0.js} +2 -2
  260. package/dist/public/{shadow-claw-mcp-remote-BPuV22So.js → shadow-claw-mcp-remote-COpNIzJd.js} +1 -1
  261. package/dist/public/{shadow-claw-networking-DEMMygy0.js → shadow-claw-networking-AOVRUn6B.js} +1 -1
  262. package/dist/public/{shadow-claw-notifications-B9Xhcj1P.js → shadow-claw-notifications-CKB-W1TA.js} +1 -1
  263. package/dist/public/{shadow-claw-page-header-CAXokjQy.js → shadow-claw-page-header-D4LmUigA.js} +1 -1
  264. package/dist/public/{shadow-claw-pages-BRQw8bTm.js → shadow-claw-pages-BpHRY4vH.js} +12 -3
  265. package/dist/public/{shadow-claw-settings-BGrDNyqh.js → shadow-claw-settings-CE-aUo_J.js} +3 -3
  266. package/dist/public/{shadow-claw-storage-DK3pf11w.js → shadow-claw-storage-CFKC-Y3V.js} +1 -1
  267. package/dist/public/{shadow-claw-task-server-CMp5Vjza.js → shadow-claw-task-server-B_ZjqK4B.js} +1 -1
  268. package/dist/public/{shadow-claw-tasks-BO8aXM2B.js → shadow-claw-tasks-CGsEv48K.js} +1 -1
  269. package/dist/public/{shadow-claw-terminal-BSeTuyDa.js → shadow-claw-terminal-DcaS7cPH.js} +1 -1
  270. package/dist/public/{shadow-claw-tools-Bj6DLZ-2.js → shadow-claw-tools-Cnu9hKy0.js} +1 -1
  271. package/dist/public/{shadow-claw-webvm-M7d5RH8H.js → shadow-claw-webvm-BB8SFvJ8.js} +1 -1
  272. package/dist/public/syncWebMcpRegistration-D2Zx4oA1.js +1 -0
  273. package/dist/public/theme-init.js +1 -1
  274. package/dist/public/{tools-nysPKnGT.js → tools-sOLCHTj8.js} +1 -1
  275. package/dist/public/{webmcp-Bo3KTgRb.js → webmcp-YFt6vM1_.js} +1 -1
  276. package/dist/server.js +189 -189
  277. package/package.json +1 -1
  278. package/src/cli/cli.ts +2 -2
  279. package/src/cli/prerender/dsd-shell/prerender-dsd-shell.test.ts +4 -1
  280. package/src/cli/prerender/dsd-shell/prerender-dsd-shell.ts +7 -1
  281. package/src/cli/prerender/utils/insert-before-closing-head.test.ts +12 -0
  282. package/src/cli/prerender/utils/insert-before-closing-head.ts +4 -6
  283. package/src/cli/site-config/apply.test.ts +90 -0
  284. package/src/cli/site-config/apply.ts +181 -13
  285. package/src/components/shadow-claw/shadow-claw.css +26 -0
  286. package/src/components/shadow-claw/shadow-claw.html +4 -0
  287. package/src/components/shadow-claw/utils/applyRoute.ts +3 -0
  288. package/src/components/shadow-claw/utils/bindEventListeners.test.ts +6 -0
  289. package/src/components/shadow-claw/utils/bindEventListeners.ts +30 -1
  290. package/src/components/shadow-claw/utils/getRoute.test.ts +52 -0
  291. package/src/components/shadow-claw/utils/getRoute.ts +18 -0
  292. package/src/components/shadow-claw/utils/navigateToRoute.test.ts +21 -0
  293. package/src/components/shadow-claw/utils/navigateToRoute.ts +10 -0
  294. package/src/components/shadow-claw/utils/sidebarVisibility.ts +12 -4
  295. package/src/components/shadow-claw/utils/syncSlottedSidebarActiveLinks.test.ts +93 -0
  296. package/src/components/shadow-claw/utils/syncSlottedSidebarActiveLinks.ts +100 -0
  297. package/src/components/shadow-claw-file-viewer/shadow-claw-file-viewer.ts +31 -31
  298. package/src/components/shadow-claw-pages/shadow-claw-pages.css +10 -1
  299. package/src/components/shadow-claw-pages/utils/removePreviewIframe.ts +3 -0
  300. package/src/core/effect.test.ts +19 -0
  301. package/src/core/orchestrator/orchestrator-state.ts +2 -1
  302. package/src/core/orchestrator/orchestrator.test.ts +686 -5
  303. package/src/core/orchestrator/orchestrator.ts +3 -10
  304. package/src/core/orchestrator/utils/compactContext.test.ts +423 -121
  305. package/src/core/orchestrator/utils/configurePeerJs.test.ts +27 -0
  306. package/src/core/orchestrator/utils/deliverResponse.test.ts +127 -0
  307. package/src/core/orchestrator/utils/dispatchSubagentInvoke.test.ts +23 -0
  308. package/src/core/orchestrator/utils/enqueue.test.ts +520 -86
  309. package/src/core/orchestrator/utils/handleWorkerMessage.test.ts +664 -144
  310. package/src/core/orchestrator/utils/initTasks.node.test.ts +147 -0
  311. package/src/core/orchestrator/utils/initTasks.test.ts +926 -191
  312. package/src/core/orchestrator/utils/initTasks.ts +5 -4
  313. package/src/core/orchestrator/utils/invokeAgent.test.ts +563 -110
  314. package/src/core/orchestrator/utils/invokeAgent.ts +8 -10
  315. package/src/core/orchestrator/utils/loadChannelConfigurations.test.ts +50 -0
  316. package/src/core/orchestrator/utils/operations/channel.test.ts +377 -170
  317. package/src/core/orchestrator/utils/operations/provider.test.ts +663 -85
  318. package/src/core/orchestrator/utils/operations/room.test.ts +74 -11
  319. package/src/core/orchestrator/utils/operations/task.test.ts +452 -56
  320. package/src/core/orchestrator/utils/operations/task.ts +1 -1
  321. package/src/core/orchestrator/utils/operations/vm.test.ts +66 -7
  322. package/src/core/orchestrator/utils/parseDirectToolCommand.test.ts +6 -0
  323. package/src/core/orchestrator/utils/settings.test.ts +248 -81
  324. package/src/core/orchestrator/utils/setupPushTaskListener.test.ts +58 -0
  325. package/src/core/orchestrator/utils/syncWebMcpRegistration.test.ts +392 -64
  326. package/src/core/orchestrator/utils/syncWebMcpRegistration.ts +32 -3
  327. package/src/server/middleware/static-files.test.ts +36 -0
  328. package/src/server/middleware/static-files.ts +14 -6
  329. package/src/server/routes/mcp.ts +2 -2
  330. package/src/storage/staticRouting.test.ts +36 -0
  331. package/src/storage/staticRouting.ts +31 -3
  332. package/src/stores/file-viewer.test.ts +11 -0
  333. package/src/stores/theme.test.ts +41 -2
  334. package/src/stores/toast.test.ts +25 -0
  335. package/src/subsystems/mcp/webmcp.test.ts +255 -0
  336. package/src/subsystems/mcp/webmcp.ts +253 -0
  337. package/src/worker/tools/bash/native-bash-executor.test.ts +31 -1
  338. package/src/worker/tools/git/utils/extractConflictPaths.test.ts +24 -0
  339. package/src/worker/tools/git/utils/parseConflictRegions.test.ts +46 -0
  340. package/src/worker/tools/git/utils/resolveCorsProxy.test.ts +26 -5
  341. package/src/worker/tools/git/utils/truncateSnippet.test.ts +16 -0
  342. package/src/worker/tools/node-transformers-executor.test.ts +105 -6
  343. package/src/worker/tools/remote-mcp/remote-mcp.test.ts +172 -47
  344. package/src/worker/tools/remote-mcp/utils/formatListToolsOutput.test.ts +19 -0
  345. package/src/worker/tools/remote-mcp/utils/isMcpReauthError.test.ts +45 -0
  346. package/src/worker/tools/remote-mcp/utils/resolveMcpReauth.test.ts +48 -0
  347. package/src/worker/tools/rooms/list-room-members.test.ts +24 -10
  348. package/src/worker/tools/tasks/list-tasks.test.ts +39 -8
  349. package/src/worker/tools/tasks/update-task.test.ts +78 -14
  350. package/src/worker/tools/ui/javascript.test.ts +70 -17
  351. package/src/worker/tools/ui/list-tool-profiles.test.ts +31 -9
  352. package/dist/cli/chunk-00GAzVPl2.js +0 -1
  353. package/dist/cli/chunk-2hnFoNNC.js +0 -1
  354. package/dist/cli/chunk-BKQL4nzF2.js +0 -1
  355. package/dist/cli/chunk-BQ4K3fqj2.js +0 -1
  356. package/dist/cli/chunk-BVCGo6uf2.js +0 -1
  357. package/dist/cli/chunk-BcTH_-FL.js +0 -1
  358. package/dist/cli/chunk-BmD_sPRt.js +0 -1
  359. package/dist/cli/chunk-BsxNqqer.js +0 -1
  360. package/dist/cli/chunk-CCcF5T-c.js +0 -1
  361. package/dist/cli/chunk-CFhvwUeL.js +0 -91
  362. package/dist/cli/chunk-CwWtvULn.js +0 -1
  363. package/dist/cli/chunk-Drf-hXIR2.js +0 -1
  364. package/dist/cli/chunk-Dt5HNYVi.js +0 -1
  365. package/dist/cli/chunk-DwZQi9Ax.js +0 -1
  366. package/dist/cli/chunk-m9ZX7TyF2.js +0 -1
  367. package/dist/lib/app-routes-BAEMLu9g.js.map +0 -1
  368. package/dist/lib/orchestrator-Bq9ft3uG.js.map +0 -1
  369. package/dist/lib/shadow-claw-MumteAJy.js.map +0 -1
  370. package/dist/lib/shadow-claw-pages-Bo8_z2S-.js.map +0 -1
  371. package/dist/lib/syncWebMcpRegistration-Bbph0XZl.js.map +0 -1
  372. package/dist/public/app-routes-BMQ4HFaM.js +0 -1
  373. package/dist/public/syncWebMcpRegistration-4bT0YUyZ.js +0 -1
@@ -1,33 +1,71 @@
1
1
  import { beforeEach, describe, expect, it, jest } from "@jest/globals";
2
-
3
- const mockClearPeerJsTypingState = jest.fn();
2
+ import type { ProviderConfig } from "../../../config/config.js";
3
+ import type { MessageAttachment } from "../../../content/types.js";
4
+ import type { ShadowClawDatabase } from "../../../db/db.js";
5
+ import type { GroupMeta, StoredMessage } from "../../../db/types.js";
6
+ import type {
7
+ ChannelType,
8
+ InboundMessage,
9
+ } from "../../../subsystems/channels/types.js";
10
+ import type {
11
+ SkillDiagnostic,
12
+ SkillRecord,
13
+ } from "../../../subsystems/skills/types.js";
14
+ import type { Orchestrator } from "../orchestrator.js";
15
+ import type { ParsedDirectToolCommand } from "./types.js";
16
+
17
+ const mockClearPeerJsTypingState = jest.fn<(groupId: string) => void>();
4
18
  jest.unstable_mockModule("./operations/channel.js", () => ({
5
19
  clearPeerJsTypingState: mockClearPeerJsTypingState,
6
20
  }));
7
21
 
8
- const { clearPeerJsTypingState } = await import("./operations/channel.js");
9
-
10
- const mockParseDirectToolCommand = jest.fn() as any;
22
+ const mockParseDirectToolCommand =
23
+ jest.fn<
24
+ (
25
+ policy: unknown,
26
+ assistantName: string,
27
+ msg: InboundMessage,
28
+ ) => ParsedDirectToolCommand | null
29
+ >();
11
30
  jest.unstable_mockModule("./parseDirectToolCommand.js", () => ({
12
31
  parseDirectToolCommand: mockParseDirectToolCommand,
13
32
  }));
14
33
 
15
- const mockDiscoverSkills = jest.fn() as any;
34
+ const mockDiscoverSkills =
35
+ jest.fn<
36
+ (
37
+ db: ShadowClawDatabase,
38
+ groupId: string,
39
+ ) => Promise<{ skills: SkillRecord[]; diagnostics: SkillDiagnostic[] }>
40
+ >();
16
41
  jest.unstable_mockModule(
17
42
  "../../../subsystems/skills/discoverSkills.js",
18
43
  () => ({ discoverSkills: mockDiscoverSkills }),
19
44
  );
20
45
 
21
- const mockGetApiKeyForRequest = jest.fn() as any;
46
+ const mockGetApiKeyForRequest =
47
+ jest.fn<(o: Orchestrator) => Promise<string | null>>();
22
48
  jest.unstable_mockModule("./operations/provider.js", () => ({
23
49
  getApiKeyForRequest: mockGetApiKeyForRequest,
24
50
  }));
25
51
 
26
- const mockDetectProviderHelpType = jest.fn() as any;
27
- const mockGetProvider = jest.fn() as any;
28
- const mockPersistMessageAttachments = jest.fn() as any;
29
- const mockListGroups = jest.fn() as any;
30
- const mockSaveMessage = jest.fn() as any;
52
+ const mockDetectProviderHelpType =
53
+ jest.fn<
54
+ (providerId: string, reason: string, requiresApiKey: boolean) => string
55
+ >();
56
+ const mockGetProvider = jest.fn<(id: string) => ProviderConfig | null>();
57
+ const mockPersistMessageAttachments =
58
+ jest.fn<
59
+ (
60
+ db: ShadowClawDatabase,
61
+ groupId: string,
62
+ attachments: MessageAttachment[],
63
+ ) => Promise<MessageAttachment[]>
64
+ >();
65
+ const mockListGroups =
66
+ jest.fn<(db: ShadowClawDatabase) => Promise<GroupMeta[]>>();
67
+ const mockSaveMessage =
68
+ jest.fn<(db: ShadowClawDatabase, msg: StoredMessage) => Promise<void>>();
31
69
 
32
70
  jest.unstable_mockModule(
33
71
  "../../../components/common/help/providers.js",
@@ -59,39 +97,130 @@ jest.unstable_mockModule("../../../db/saveMessage.js", () => ({
59
97
  saveMessage: mockSaveMessage,
60
98
  }));
61
99
 
62
- const mockInvokeAgent = jest.fn() as any;
100
+ const mockInvokeAgent =
101
+ jest.fn<
102
+ (
103
+ o: unknown,
104
+ db: unknown,
105
+ groupId: string,
106
+ content: string,
107
+ freshContext?: boolean,
108
+ subagent?: boolean,
109
+ ) => Promise<void>
110
+ >();
63
111
  jest.unstable_mockModule("./invokeAgent.js", () => ({
64
112
  invokeAgent: mockInvokeAgent,
65
113
  }));
66
114
 
115
+ const { clearPeerJsTypingState } = await import("./operations/channel.js");
67
116
  const { enqueue, processQueue } = await import("./enqueue.js");
68
117
 
118
+ interface MockOrchestrator {
119
+ events: {
120
+ emit: jest.Mock<(_event: string, _payload: unknown) => void>;
121
+ };
122
+ channelRegistry: {
123
+ shouldAutoTrigger: jest.Mock<(_channel: ChannelType) => boolean>;
124
+ };
125
+ triggerPattern: RegExp;
126
+ peerCompletedContexts: Set<string>;
127
+ peerjsMyPeerId: string;
128
+ peerjsMyAlias: string;
129
+ peerjsPeerAliases: Record<string, string>;
130
+ messageQueue: Array<{
131
+ groupId: string;
132
+ content: string;
133
+ freshContext?: boolean;
134
+ subagent?: boolean;
135
+ }>;
136
+ clearPeerJsTypingState: jest.Mock<() => void>;
137
+ router: {
138
+ send: jest.Mock<
139
+ (
140
+ _groupId: string,
141
+ _content: string,
142
+ _attachments: MessageAttachment[],
143
+ ) => Promise<void>
144
+ >;
145
+ };
146
+ agentWorker: {
147
+ postMessage: jest.Mock<(_msg: unknown) => void>;
148
+ };
149
+ processQueue: jest.Mock<() => void>;
150
+ providerConfig: {
151
+ requiresApiKey: boolean;
152
+ };
153
+ provider: string;
154
+ getApiKey: jest.Mock<() => Promise<string | null>>;
155
+ getApiKeyForSpecificProvider: jest.Mock<
156
+ (_db: ShadowClawDatabase, _prov: string) => Promise<string | null>
157
+ >;
158
+ directToolCommandPolicy: {
159
+ enabledChannelTypes: ChannelType[];
160
+ };
161
+ assistantName: string;
162
+ processing: boolean;
163
+ }
164
+
165
+ function makeInboundMessage(
166
+ overrides: Partial<InboundMessage> = {},
167
+ ): InboundMessage {
168
+ return {
169
+ id: "msg-1",
170
+ groupId: "g1",
171
+ sender: "user",
172
+ content: "test message",
173
+ timestamp: Date.now(),
174
+ channel: "browser",
175
+ ...overrides,
176
+ };
177
+ }
178
+
69
179
  describe("enqueue & processQueue", () => {
70
- let mockOrchestrator: any;
71
- let mockDb: any;
180
+ let mockOrchestrator: MockOrchestrator;
181
+ const mockDb = {} as ShadowClawDatabase;
72
182
 
73
183
  beforeEach(() => {
74
184
  jest.clearAllMocks();
75
- mockDb = {};
76
185
  mockOrchestrator = {
77
186
  events: { emit: jest.fn() },
78
- channelRegistry: { shouldAutoTrigger: jest.fn().mockReturnValue(false) },
187
+ channelRegistry: {
188
+ shouldAutoTrigger: jest
189
+ .fn<(_channel: ChannelType) => boolean>()
190
+ .mockReturnValue(false),
191
+ },
79
192
  triggerPattern: /trigger/i,
80
- peerCompletedContexts: new Set(),
193
+ peerCompletedContexts: new Set<string>(),
81
194
  peerjsMyPeerId: "my-id",
82
195
  peerjsMyAlias: "my-alias",
83
196
  peerjsPeerAliases: { "peer2-alias": "peer2-id" },
84
197
  messageQueue: [],
85
198
  clearPeerJsTypingState: jest.fn(),
86
- router: { send: (jest.fn() as any).mockResolvedValue(undefined) },
199
+ router: {
200
+ send: jest
201
+ .fn<
202
+ (
203
+ _groupId: string,
204
+ _content: string,
205
+ _attachments: MessageAttachment[],
206
+ ) => Promise<void>
207
+ >()
208
+ .mockResolvedValue(undefined),
209
+ },
87
210
  agentWorker: { postMessage: jest.fn() },
88
211
  processQueue: jest.fn(),
89
212
  providerConfig: { requiresApiKey: true },
90
213
  provider: "test-provider",
91
- getApiKey: (jest.fn() as any).mockResolvedValue("key"),
92
- getApiKeyForSpecificProvider: (jest.fn() as any).mockResolvedValue("key"),
214
+ getApiKey: jest
215
+ .fn<() => Promise<string | null>>()
216
+ .mockResolvedValue("key"),
217
+ getApiKeyForSpecificProvider: jest
218
+ .fn<
219
+ (_db: ShadowClawDatabase, _prov: string) => Promise<string | null>
220
+ >()
221
+ .mockResolvedValue("key"),
93
222
  directToolCommandPolicy: {
94
- enabledChannelTypes: ["browser", "peerjs", "web"],
223
+ enabledChannelTypes: ["browser", "peerjs"],
95
224
  },
96
225
  assistantName: "Assistant",
97
226
  processing: false,
@@ -111,34 +240,64 @@ describe("enqueue & processQueue", () => {
111
240
  });
112
241
 
113
242
  it("should emit A2UI envelopes and actions and exit if no text/attachments", async () => {
114
- const msg: any = {
243
+ const msg = makeInboundMessage({
115
244
  groupId: "g1",
116
- a2uiEnvelopes: [{ type: "test" }],
117
- a2uiAction: { action: "test" },
118
- };
245
+ content: "",
246
+ a2uiEnvelopes: [
247
+ {
248
+ surfaceId: "s1",
249
+ data: {},
250
+ } as unknown as InboundMessage["a2uiEnvelopes"] extends Array<infer U>
251
+ ? U
252
+ : never,
253
+ ],
254
+ a2uiAction: {
255
+ actionId: "test",
256
+ } as unknown as InboundMessage["a2uiAction"],
257
+ });
119
258
 
120
- await enqueue(mockOrchestrator, mockDb, msg);
259
+ await enqueue(mockOrchestrator as unknown as Orchestrator, mockDb, msg);
121
260
 
122
261
  expect(mockOrchestrator.events.emit).toHaveBeenCalledWith(
123
262
  "a2ui-surface",
124
- { groupId: "g1", envelope: { type: "test" } },
263
+ { groupId: "g1", envelope: { surfaceId: "s1", data: {} } },
125
264
  );
126
265
  expect(mockOrchestrator.events.emit).toHaveBeenCalledWith("a2ui-action", {
127
266
  groupId: "g1",
128
- action: { action: "test" },
267
+ action: { actionId: "test" },
129
268
  });
130
269
  expect(mockSaveMessage).not.toHaveBeenCalled();
131
270
  });
132
271
 
272
+ it("should proceed to normal handling if message has a2uiAction but no envelopes", async () => {
273
+ const msg = makeInboundMessage({
274
+ groupId: "g1",
275
+ content: "",
276
+ a2uiAction: {
277
+ actionId: "test-action",
278
+ } as unknown as InboundMessage["a2uiAction"],
279
+ });
280
+
281
+ await enqueue(mockOrchestrator as unknown as Orchestrator, mockDb, msg);
282
+
283
+ expect(mockSaveMessage).toHaveBeenCalled();
284
+ });
285
+
133
286
  it("should process normal message, detect trigger, persist and enqueue", async () => {
134
- const msg: any = {
287
+ const msg = makeInboundMessage({
135
288
  groupId: "g1",
136
289
  content: "hello trigger",
137
290
  channel: "browser",
291
+ });
292
+ const persistedAttachment: MessageAttachment = {
293
+ fileName: "test.png",
294
+ mimeType: "image/png",
295
+ path: "/path/test.png",
296
+ size: 100,
138
297
  };
139
- mockPersistMessageAttachments.mockResolvedValue([{ name: "test.png" }]);
298
+ mockPersistMessageAttachments.mockResolvedValue([persistedAttachment]);
140
299
 
141
- await enqueue(mockOrchestrator, mockDb, msg);
300
+ await enqueue(mockOrchestrator as unknown as Orchestrator, mockDb, msg);
142
301
 
143
302
  expect(mockSaveMessage).toHaveBeenCalledWith(
144
303
  mockDb,
@@ -151,24 +310,143 @@ describe("enqueue & processQueue", () => {
151
310
  );
152
311
  });
153
312
 
313
+ it("should auto-trigger from browser channel for regular conversations", async () => {
314
+ const msg = makeInboundMessage({
315
+ groupId: "normal-group",
316
+ content: "regular message without keywords",
317
+ channel: "browser",
318
+ });
319
+
320
+ await enqueue(mockOrchestrator as unknown as Orchestrator, mockDb, msg);
321
+
322
+ expect(mockSaveMessage).toHaveBeenCalledWith(
323
+ mockDb,
324
+ expect.objectContaining({ isTrigger: true }),
325
+ );
326
+ expect(mockOrchestrator.messageQueue).toHaveLength(1);
327
+ });
328
+
329
+ it("should not auto-trigger from browser channel in peer and room channels", async () => {
330
+ const peerMsg = makeInboundMessage({
331
+ groupId: "peer:peer-1",
332
+ content: "direct peer message",
333
+ channel: "browser",
334
+ });
335
+ await enqueue(
336
+ mockOrchestrator as unknown as Orchestrator,
337
+ mockDb,
338
+ peerMsg,
339
+ );
340
+ expect(mockSaveMessage).toHaveBeenCalledWith(
341
+ mockDb,
342
+ expect.objectContaining({ isTrigger: false }),
343
+ );
344
+ expect(mockOrchestrator.messageQueue).toHaveLength(0);
345
+
346
+ const roomMsg = makeInboundMessage({
347
+ groupId: "room:room-1",
348
+ content: "direct room message",
349
+ channel: "browser",
350
+ });
351
+ await enqueue(
352
+ mockOrchestrator as unknown as Orchestrator,
353
+ mockDb,
354
+ roomMsg,
355
+ );
356
+ expect(mockSaveMessage).toHaveBeenCalledWith(
357
+ mockDb,
358
+ expect.objectContaining({ isTrigger: false }),
359
+ );
360
+ expect(mockOrchestrator.messageQueue).toHaveLength(0);
361
+ });
362
+
363
+ it("should reopen completed peer context when local user sends message from browser", async () => {
364
+ mockOrchestrator.peerCompletedContexts.add("peer:finished-task");
365
+ const msg = makeInboundMessage({
366
+ groupId: "peer:finished-task",
367
+ content: "reopen message",
368
+ channel: "browser",
369
+ });
370
+
371
+ await enqueue(mockOrchestrator as unknown as Orchestrator, mockDb, msg);
372
+
373
+ expect(
374
+ mockOrchestrator.peerCompletedContexts.has("peer:finished-task"),
375
+ ).toBe(false);
376
+ });
377
+
378
+ it("should suppress auto-trigger for peer conversations in peerCompletedContexts", async () => {
379
+ mockOrchestrator.peerCompletedContexts.add("peer:finished-task");
380
+ const msg = makeInboundMessage({
381
+ groupId: "peer:finished-task",
382
+ content: "hey @my-alias more work",
383
+ channel: "peerjs",
384
+ });
385
+
386
+ await enqueue(mockOrchestrator as unknown as Orchestrator, mockDb, msg);
387
+
388
+ expect(mockSaveMessage).toHaveBeenCalledWith(
389
+ mockDb,
390
+ expect.objectContaining({ isTrigger: false }),
391
+ );
392
+ expect(mockOrchestrator.messageQueue).toHaveLength(0);
393
+ });
394
+
395
+ it("should trigger if message mentions my exact peer ID", async () => {
396
+ const msg = makeInboundMessage({
397
+ groupId: "peer:group",
398
+ content: "hey @my-id can you help?",
399
+ channel: "peerjs",
400
+ });
401
+
402
+ await enqueue(mockOrchestrator as unknown as Orchestrator, mockDb, msg);
403
+
404
+ expect(mockSaveMessage).toHaveBeenCalledWith(
405
+ mockDb,
406
+ expect.objectContaining({ isTrigger: true }),
407
+ );
408
+ expect(mockOrchestrator.messageQueue).toHaveLength(1);
409
+ });
410
+
411
+ it("should trigger if message mentions an alias mapping to peerjsMyPeerId", async () => {
412
+ mockOrchestrator.peerjsPeerAliases = {
413
+ "friendly-peer": "my-id",
414
+ "other-peer": "different-id",
415
+ };
416
+ const msg = makeInboundMessage({
417
+ groupId: "peer:group",
418
+ content: "hey @friendly-peer check this out",
419
+ channel: "peerjs",
420
+ });
421
+
422
+ await enqueue(mockOrchestrator as unknown as Orchestrator, mockDb, msg);
423
+
424
+ expect(mockSaveMessage).toHaveBeenCalledWith(
425
+ mockDb,
426
+ expect.objectContaining({ isTrigger: true }),
427
+ );
428
+ expect(mockOrchestrator.messageQueue).toHaveLength(1);
429
+ });
430
+
154
431
  it("should route a user-invocable skill slash command to the agent", async () => {
432
+ const skill: SkillRecord = {
433
+ name: "toast-random-number",
434
+ description: "Show a random number",
435
+ userInvocable: true,
436
+ path: "/path/skill",
437
+ basePath: "/path",
438
+ };
155
439
  mockDiscoverSkills.mockResolvedValue({
156
- skills: [
157
- {
158
- name: "toast-random-number",
159
- description: "Show a random number",
160
- userInvocable: true,
161
- },
162
- ],
440
+ skills: [skill],
163
441
  diagnostics: [],
164
442
  });
165
- const msg: any = {
443
+ const msg = makeInboundMessage({
166
444
  groupId: "g1",
167
445
  content: "/toast-random-number",
168
446
  channel: "peerjs",
169
- };
447
+ });
170
448
 
171
- await enqueue(mockOrchestrator, mockDb, msg);
449
+ await enqueue(mockOrchestrator as unknown as Orchestrator, mockDb, msg);
172
450
 
173
451
  expect(mockOrchestrator.messageQueue[0]).toEqual(
174
452
  expect.objectContaining({
@@ -183,30 +461,31 @@ describe("enqueue & processQueue", () => {
183
461
  });
184
462
 
185
463
  it("should execute a declarative skill chain without queueing an agent turn", async () => {
464
+ const skill: SkillRecord = {
465
+ name: "toast-random-number",
466
+ description: "Show a random number",
467
+ userInvocable: true,
468
+ path: "/path/skill",
469
+ basePath: "/path",
470
+ execution: {
471
+ type: "tools",
472
+ tools: [
473
+ { name: "javascript", input: { code: "1" } },
474
+ { name: "show_toast", input: { message: { $pipe: "prev" } } },
475
+ ],
476
+ },
477
+ };
186
478
  mockDiscoverSkills.mockResolvedValue({
187
- skills: [
188
- {
189
- name: "toast-random-number",
190
- description: "Show a random number",
191
- userInvocable: true,
192
- execution: {
193
- type: "tools",
194
- tools: [
195
- { name: "javascript", input: { code: "1" } },
196
- { name: "show_toast", input: { message: { $pipe: "prev" } } },
197
- ],
198
- },
199
- },
200
- ],
479
+ skills: [skill],
201
480
  diagnostics: [],
202
481
  });
203
- const msg: any = {
482
+ const msg = makeInboundMessage({
204
483
  groupId: "g1",
205
484
  content: "/toast-random-number",
206
485
  channel: "browser",
207
- };
486
+ });
208
487
 
209
- await enqueue(mockOrchestrator, mockDb, msg);
488
+ await enqueue(mockOrchestrator as unknown as Orchestrator, mockDb, msg);
210
489
 
211
490
  expect(mockOrchestrator.messageQueue).toHaveLength(0);
212
491
  expect(mockOrchestrator.agentWorker.postMessage).toHaveBeenCalledWith({
@@ -218,14 +497,65 @@ describe("enqueue & processQueue", () => {
218
497
  });
219
498
  });
220
499
 
500
+ it("should populate rawInput on declarative tools with arguments when input is empty or non-object", async () => {
501
+ const skill: SkillRecord = {
502
+ name: "echo-skill",
503
+ description: "Echo skill with arguments",
504
+ userInvocable: true,
505
+ path: "/path/skill",
506
+ basePath: "/path",
507
+ execution: {
508
+ type: "tools",
509
+ tools: [
510
+ { name: "tool-with-empty-input", input: {} },
511
+ {
512
+ name: "tool-with-non-object-input",
513
+ input: null as unknown as Record<string, unknown>,
514
+ },
515
+ { name: "tool-with-existing-input", input: { existing: "val" } },
516
+ ],
517
+ },
518
+ };
519
+ mockDiscoverSkills.mockResolvedValue({
520
+ skills: [skill],
521
+ diagnostics: [],
522
+ });
523
+ const msg = makeInboundMessage({
524
+ groupId: "g1",
525
+ content: "/echo-skill hello world arguments",
526
+ channel: "browser",
527
+ });
528
+
529
+ await enqueue(mockOrchestrator as unknown as Orchestrator, mockDb, msg);
530
+
531
+ expect(mockOrchestrator.agentWorker.postMessage).toHaveBeenCalledWith({
532
+ type: "execute-skill-tools",
533
+ payload: {
534
+ groupId: "g1",
535
+ skillName: "echo-skill",
536
+ tools: [
537
+ {
538
+ name: "tool-with-empty-input",
539
+ input: { rawInput: "hello world arguments" },
540
+ },
541
+ {
542
+ name: "tool-with-non-object-input",
543
+ input: { rawInput: "hello world arguments" },
544
+ },
545
+ { name: "tool-with-existing-input", input: { existing: "val" } },
546
+ ],
547
+ },
548
+ });
549
+ });
550
+
221
551
  it("should handle direct tool commands without enqueuing for invokeAgent", async () => {
222
552
  mockParseDirectToolCommand.mockReturnValue({
223
553
  toolName: "tool1",
224
- input: "input",
554
+ input: { text: "input" },
225
555
  });
226
- const msg: any = { groupId: "g1", content: "cmd" };
556
+ const msg = makeInboundMessage({ groupId: "g1", content: "cmd" });
227
557
 
228
- await enqueue(mockOrchestrator, mockDb, msg);
558
+ await enqueue(mockOrchestrator as unknown as Orchestrator, mockDb, msg);
229
559
 
230
560
  expect(mockSaveMessage).toHaveBeenCalledWith(
231
561
  mockDb,
@@ -234,17 +564,17 @@ describe("enqueue & processQueue", () => {
234
564
  expect(mockOrchestrator.messageQueue).toHaveLength(0);
235
565
  expect(mockOrchestrator.agentWorker.postMessage).toHaveBeenCalledWith({
236
566
  type: "execute-direct-tool",
237
- payload: { groupId: "g1", name: "tool1", input: "input" },
567
+ payload: { groupId: "g1", name: "tool1", input: { text: "input" } },
238
568
  });
239
569
  });
240
570
 
241
571
  it("should trigger if mentioned by peerjs alias", async () => {
242
- const msg: any = {
572
+ const msg = makeInboundMessage({
243
573
  groupId: "peer:g1",
244
574
  content: "hey @my-alias",
245
575
  channel: "peerjs",
246
- };
247
- await enqueue(mockOrchestrator, mockDb, msg);
576
+ });
577
+ await enqueue(mockOrchestrator as unknown as Orchestrator, mockDb, msg);
248
578
 
249
579
  expect(mockSaveMessage).toHaveBeenCalledWith(
250
580
  mockDb,
@@ -254,8 +584,11 @@ describe("enqueue & processQueue", () => {
254
584
  });
255
585
 
256
586
  it("should trigger if scheduled task", async () => {
257
- const msg: any = { groupId: "g1", content: "[SCHEDULED TASK] go" };
258
- await enqueue(mockOrchestrator, mockDb, msg);
587
+ const msg = makeInboundMessage({
588
+ groupId: "g1",
589
+ content: "[SCHEDULED TASK] go",
590
+ });
591
+ await enqueue(mockOrchestrator as unknown as Orchestrator, mockDb, msg);
259
592
  expect(mockSaveMessage).toHaveBeenCalledWith(
260
593
  mockDb,
261
594
  expect.objectContaining({ isTrigger: true }),
@@ -263,35 +596,52 @@ describe("enqueue & processQueue", () => {
263
596
  });
264
597
 
265
598
  it("should trigger if A2UI action message", async () => {
266
- const msg: any = { groupId: "g1", content: "[A2UI ACTION] click" };
267
- await enqueue(mockOrchestrator, mockDb, msg);
599
+ const msg = makeInboundMessage({
600
+ groupId: "g1",
601
+ content: "[A2UI ACTION] click",
602
+ });
603
+ await enqueue(mockOrchestrator as unknown as Orchestrator, mockDb, msg);
268
604
  expect(mockSaveMessage).toHaveBeenCalledWith(
269
605
  mockDb,
270
606
  expect.objectContaining({ isTrigger: true }),
271
607
  );
272
608
  });
273
609
 
274
- it("should route browser message to peer channel", async () => {
275
- const msg: any = {
610
+ it("should route browser message to peer channel and handle send errors", async () => {
611
+ const msg = makeInboundMessage({
276
612
  groupId: "peer:g1",
277
613
  content: "hello",
278
614
  channel: "browser",
279
- };
280
- await enqueue(mockOrchestrator, mockDb, msg);
615
+ });
616
+ mockOrchestrator.router.send.mockRejectedValueOnce(
617
+ new Error("Network drop"),
618
+ );
619
+ const consoleErrorSpy = jest
620
+ .spyOn(console, "error")
621
+ .mockImplementation(() => {});
622
+
623
+ await enqueue(mockOrchestrator as unknown as Orchestrator, mockDb, msg);
624
+
281
625
  expect(mockOrchestrator.router.send).toHaveBeenCalledWith(
282
626
  "peer:g1",
283
627
  "hello",
284
628
  [],
285
629
  );
630
+ await Promise.resolve();
631
+ expect(consoleErrorSpy).toHaveBeenCalledWith(
632
+ "Failed to route browser message to peer:",
633
+ expect.any(Error),
634
+ );
635
+ consoleErrorSpy.mockRestore();
286
636
  });
287
637
 
288
638
  it("should clear peerJs typing state for peerjs channel", async () => {
289
- const msg: any = {
639
+ const msg = makeInboundMessage({
290
640
  groupId: "peer:g1",
291
641
  content: "hello",
292
642
  channel: "peerjs",
293
- };
294
- await enqueue(mockOrchestrator, mockDb, msg);
643
+ });
644
+ await enqueue(mockOrchestrator as unknown as Orchestrator, mockDb, msg);
295
645
  expect(clearPeerJsTypingState).toHaveBeenCalledWith("peer:g1");
296
646
  });
297
647
  });
@@ -299,18 +649,18 @@ describe("enqueue & processQueue", () => {
299
649
  describe("processQueue", () => {
300
650
  it("should do nothing if processing or queue is empty", async () => {
301
651
  mockOrchestrator.processing = true;
302
- await processQueue(mockOrchestrator, mockDb);
652
+ await processQueue(mockOrchestrator as unknown as Orchestrator, mockDb);
303
653
  expect(mockInvokeAgent).not.toHaveBeenCalled();
304
654
 
305
655
  mockOrchestrator.processing = false;
306
656
  mockOrchestrator.messageQueue = [];
307
- await processQueue(mockOrchestrator, mockDb);
657
+ await processQueue(mockOrchestrator as unknown as Orchestrator, mockDb);
308
658
  expect(mockInvokeAgent).not.toHaveBeenCalled();
309
659
  });
310
660
 
311
661
  it("should process next message if API key present", async () => {
312
662
  mockOrchestrator.messageQueue = [{ groupId: "g1", content: "hello" }];
313
- await processQueue(mockOrchestrator, mockDb);
663
+ await processQueue(mockOrchestrator as unknown as Orchestrator, mockDb);
314
664
  expect(mockInvokeAgent).toHaveBeenCalledWith(
315
665
  mockOrchestrator,
316
666
  mockDb,
@@ -323,12 +673,87 @@ describe("enqueue & processQueue", () => {
323
673
  expect(mockOrchestrator.messageQueue).toHaveLength(0);
324
674
  });
325
675
 
676
+ it("should process message without checking API key if provider does not require one", async () => {
677
+ mockOrchestrator.messageQueue = [
678
+ { groupId: "g1", content: "local message" },
679
+ ];
680
+ mockOrchestrator.providerConfig = { requiresApiKey: false };
681
+
682
+ await processQueue(mockOrchestrator as unknown as Orchestrator, mockDb);
683
+
684
+ expect(mockGetApiKeyForRequest).not.toHaveBeenCalled();
685
+ expect(mockInvokeAgent).toHaveBeenCalledWith(
686
+ mockOrchestrator,
687
+ mockDb,
688
+ "g1",
689
+ "local message",
690
+ undefined,
691
+ undefined,
692
+ );
693
+ });
694
+
695
+ it("should process message without groupId lookup when nextMsg groupId is empty", async () => {
696
+ mockOrchestrator.messageQueue = [{ groupId: "", content: "no group" }];
697
+
698
+ await processQueue(mockOrchestrator as unknown as Orchestrator, mockDb);
699
+
700
+ expect(mockListGroups).not.toHaveBeenCalled();
701
+ expect(mockInvokeAgent).toHaveBeenCalledWith(
702
+ mockOrchestrator,
703
+ mockDb,
704
+ "",
705
+ "no group",
706
+ undefined,
707
+ undefined,
708
+ );
709
+ });
710
+
711
+ it("should fallback to default provider if pinned provider is not found", async () => {
712
+ mockOrchestrator.messageQueue = [{ groupId: "g1", content: "hello" }];
713
+ mockListGroups.mockResolvedValue([
714
+ {
715
+ groupId: "g1",
716
+ name: "Group 1",
717
+ createdAt: Date.now(),
718
+ pinnedProvider: "unknown-prov",
719
+ } as GroupMeta,
720
+ ]);
721
+ mockGetProvider.mockReturnValue(null);
722
+
723
+ await processQueue(mockOrchestrator as unknown as Orchestrator, mockDb);
724
+
725
+ expect(mockInvokeAgent).toHaveBeenCalledWith(
726
+ mockOrchestrator,
727
+ mockDb,
728
+ "g1",
729
+ "hello",
730
+ undefined,
731
+ undefined,
732
+ );
733
+ });
734
+
735
+ it("should handle listGroups error gracefully in processQueue", async () => {
736
+ mockOrchestrator.messageQueue = [{ groupId: "g1", content: "hello" }];
737
+ mockListGroups.mockRejectedValueOnce(new Error("Storage unavailable"));
738
+
739
+ await processQueue(mockOrchestrator as unknown as Orchestrator, mockDb);
740
+
741
+ expect(mockInvokeAgent).toHaveBeenCalledWith(
742
+ mockOrchestrator,
743
+ mockDb,
744
+ "g1",
745
+ "hello",
746
+ undefined,
747
+ undefined,
748
+ );
749
+ });
750
+
326
751
  it("should emit provider-help if API key missing", async () => {
327
752
  mockOrchestrator.messageQueue = [{ groupId: "g1", content: "hello" }];
328
753
  mockGetApiKeyForRequest.mockResolvedValue(null);
329
754
  mockDetectProviderHelpType.mockReturnValue("help");
330
755
 
331
- await processQueue(mockOrchestrator, mockDb);
756
+ await processQueue(mockOrchestrator as unknown as Orchestrator, mockDb);
332
757
 
333
758
  expect(mockOrchestrator.events.emit).toHaveBeenCalledWith(
334
759
  "provider-help",
@@ -348,7 +773,7 @@ describe("enqueue & processQueue", () => {
348
773
  .spyOn(console, "error")
349
774
  .mockImplementation(() => {});
350
775
 
351
- await processQueue(mockOrchestrator, mockDb);
776
+ await processQueue(mockOrchestrator as unknown as Orchestrator, mockDb);
352
777
 
353
778
  expect(consoleError).toHaveBeenCalled();
354
779
  expect(mockOrchestrator.processing).toBe(false);
@@ -364,7 +789,7 @@ describe("enqueue & processQueue", () => {
364
789
 
365
790
  mockInvokeAgent.mockImplementation(() => Promise.resolve());
366
791
 
367
- await processQueue(mockOrchestrator, mockDb);
792
+ await processQueue(mockOrchestrator as unknown as Orchestrator, mockDb);
368
793
 
369
794
  await new Promise((resolve) => setTimeout(resolve, 10));
370
795
 
@@ -391,14 +816,23 @@ describe("enqueue & processQueue", () => {
391
816
  it("should lookup pinned provider for API key check", async () => {
392
817
  mockOrchestrator.messageQueue = [{ groupId: "g1", content: "hello" }];
393
818
  mockListGroups.mockResolvedValue([
394
- { groupId: "g1", pinnedProvider: "pinned-prov" },
819
+ {
820
+ groupId: "g1",
821
+ name: "Group 1",
822
+ createdAt: Date.now(),
823
+ pinnedProvider: "pinned-prov",
824
+ } as GroupMeta,
395
825
  ]);
396
- mockGetProvider.mockReturnValue({ requiresApiKey: true });
826
+ mockGetProvider.mockReturnValue({
827
+ id: "pinned-prov",
828
+ name: "Pinned Provider",
829
+ requiresApiKey: true,
830
+ } as unknown as ProviderConfig);
397
831
  mockOrchestrator.getApiKeyForSpecificProvider.mockResolvedValue(
398
832
  "pinned-key",
399
833
  );
400
834
 
401
- await processQueue(mockOrchestrator, mockDb);
835
+ await processQueue(mockOrchestrator as unknown as Orchestrator, mockDb);
402
836
 
403
837
  expect(
404
838
  mockOrchestrator.getApiKeyForSpecificProvider,