shadow-claw 1.26.0 → 1.27.1

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 (230) hide show
  1. package/.agents/skills/main/skill-creator/SKILL.md +39 -0
  2. package/.agents/skills/main/skill-creator/references/declarative-pipelines.md +44 -0
  3. package/.agents/skills/main/skill-creator/references/declarative-tools.md +35 -0
  4. package/.agents/skills/main/skill-creator/references/frontmatter-spec.md +50 -0
  5. package/.well-known/agent-skills/index.json +14 -0
  6. package/README.md +5 -3
  7. package/bin/build/build.mjs +148 -15
  8. package/bin/build/build.test.mjs +128 -0
  9. package/bin/cli.mjs +35 -0
  10. package/bin/commands/mcp.mjs +277 -55
  11. package/bin/commands/mcp.test.mjs +275 -1
  12. package/bin/commands/skills-index.mjs +447 -0
  13. package/bin/commands/skills-index.test.mjs +243 -0
  14. package/bin/site-config/utils/custom-elements/get-approved-custom-element-scripts.test.mjs +2 -0
  15. package/bin/site-config/utils/custom-elements/sanitize-embedded-custom-element-scripts.test.mjs +10 -1
  16. package/dist/lib/components/index.js +25 -25
  17. package/dist/lib/components/settings/shadow-claw-accounts.js +1 -1
  18. package/dist/lib/components/settings/shadow-claw-channel-config.js +1 -1
  19. package/dist/lib/components/settings/shadow-claw-control-plane.js +1 -1
  20. package/dist/lib/components/settings/shadow-claw-git.js +1 -1
  21. package/dist/lib/components/settings/shadow-claw-integrations.js +1 -1
  22. package/dist/lib/components/settings/shadow-claw-llm.js +1 -1
  23. package/dist/lib/components/settings/shadow-claw-mcp-remote.js +1 -1
  24. package/dist/lib/components/settings/shadow-claw-networking.js +1 -1
  25. package/dist/lib/components/settings/shadow-claw-peerjs.js +1 -1
  26. package/dist/lib/components/settings/shadow-claw-storage.js +1 -1
  27. package/dist/lib/components/settings/shadow-claw-task-server.js +1 -1
  28. package/dist/lib/components/settings/shadow-claw-webvm.js +1 -1
  29. package/dist/lib/components/shadow-claw-a2ui.js +1 -1
  30. package/dist/lib/components/shadow-claw-accounts.js +1 -1
  31. package/dist/lib/components/shadow-claw-channel-config.js +1 -1
  32. package/dist/lib/components/shadow-claw-channels.js +1 -1
  33. package/dist/lib/components/shadow-claw-chat.js +1 -1
  34. package/dist/lib/components/shadow-claw-control-plane.js +1 -1
  35. package/dist/lib/components/shadow-claw-conversations.js +1 -1
  36. package/dist/lib/components/shadow-claw-file-viewer.js +1 -1
  37. package/dist/lib/components/shadow-claw-files.js +1 -1
  38. package/dist/lib/components/shadow-claw-git.js +1 -1
  39. package/dist/lib/components/shadow-claw-integrations.js +1 -1
  40. package/dist/lib/components/shadow-claw-llm.js +1 -1
  41. package/dist/lib/components/shadow-claw-mcp-remote.js +1 -1
  42. package/dist/lib/components/shadow-claw-networking.js +1 -1
  43. package/dist/lib/components/shadow-claw-page-header.js +1 -1
  44. package/dist/lib/components/shadow-claw-pages.js +1 -1
  45. package/dist/lib/components/shadow-claw-peerjs.js +1 -1
  46. package/dist/lib/components/shadow-claw-settings.js +1 -1
  47. package/dist/lib/components/shadow-claw-storage.js +1 -1
  48. package/dist/lib/components/shadow-claw-task-server.js +1 -1
  49. package/dist/lib/components/shadow-claw-tasks.js +1 -1
  50. package/dist/lib/components/shadow-claw-terminal.js +1 -1
  51. package/dist/lib/components/shadow-claw-tools.js +1 -1
  52. package/dist/lib/components/shadow-claw-webvm.js +1 -1
  53. package/dist/lib/components/shadow-claw.js +1 -1
  54. package/dist/lib/{configurePeerJs-CrlGan0m.js → configurePeerJs-oODzltaC.js} +2 -2
  55. package/dist/lib/{configurePeerJs-CrlGan0m.js.map → configurePeerJs-oODzltaC.js.map} +1 -1
  56. package/dist/lib/core/control-plane-client.d.ts +1 -0
  57. package/dist/lib/{downloadGroupFile-DboUjmp2.js → downloadGroupFile-DmcBQU1n.js} +2 -2
  58. package/dist/lib/{downloadGroupFile-DboUjmp2.js.map → downloadGroupFile-DmcBQU1n.js.map} +1 -1
  59. package/dist/lib/{file-viewer-BrK2Wxgh.js → file-viewer-C3YKnq_-.js} +4 -3
  60. package/dist/lib/{file-viewer-BrK2Wxgh.js.map → file-viewer-C3YKnq_-.js.map} +1 -1
  61. package/dist/lib/index.js +26 -26
  62. package/dist/lib/{initControlPlane-CsO4UR6_.js → initControlPlane-C2zURVIS.js} +86 -13
  63. package/dist/lib/initControlPlane-C2zURVIS.js.map +1 -0
  64. package/dist/lib/{markdown-eeSTFnMA.js → markdown-C6EHl9zs.js} +3 -3
  65. package/dist/lib/{markdown-eeSTFnMA.js.map → markdown-C6EHl9zs.js.map} +1 -1
  66. package/dist/lib/{orchestrator-CJvoC2Uu.js → orchestrator-CACLa_Ro.js} +7 -6
  67. package/dist/lib/{orchestrator-CJvoC2Uu.js.map → orchestrator-CACLa_Ro.js.map} +1 -1
  68. package/dist/lib/{orchestrator-DCfomsn9.js → orchestrator-KRjx0eba.js} +6 -534
  69. package/dist/lib/{orchestrator-DCfomsn9.js.map → orchestrator-KRjx0eba.js.map} +1 -1
  70. package/dist/lib/parsePath-DwC_YZjw.js +16 -0
  71. package/dist/lib/parsePath-DwC_YZjw.js.map +1 -0
  72. package/dist/lib/{peerjs-Dp02bXcG.js → peerjs-DFWOBcXf.js} +4 -4
  73. package/dist/lib/{peerjs-Dp02bXcG.js.map → peerjs-DFWOBcXf.js.map} +1 -1
  74. package/dist/lib/{readGroupFileBytes-Bve-e5e_.js → readGroupFileBytes-C8oOe8Iu.js} +3 -16
  75. package/dist/lib/readGroupFileBytes-C8oOe8Iu.js.map +1 -0
  76. package/dist/lib/security/custom-element-security.d.ts +8 -0
  77. package/dist/lib/server/control-plane-types.d.ts +1 -1
  78. package/dist/lib/{shadow-claw-D8xINM3c.js → shadow-claw-6UHdiy4a.js} +5 -5
  79. package/dist/lib/{shadow-claw-D8xINM3c.js.map → shadow-claw-6UHdiy4a.js.map} +1 -1
  80. package/dist/lib/{shadow-claw-a2ui-7rJqG4Ke.js → shadow-claw-a2ui-CpZUTzlh.js} +5 -4
  81. package/dist/lib/{shadow-claw-a2ui-7rJqG4Ke.js.map → shadow-claw-a2ui-CpZUTzlh.js.map} +1 -1
  82. package/dist/lib/{shadow-claw-accounts-CdruwN8A.js → shadow-claw-accounts-03oJ__XC.js} +2 -2
  83. package/dist/lib/{shadow-claw-accounts-CdruwN8A.js.map → shadow-claw-accounts-03oJ__XC.js.map} +1 -1
  84. package/dist/lib/{shadow-claw-channel-config-Bj0-Nk3t.js → shadow-claw-channel-config-DmfwJc6G.js} +3 -3
  85. package/dist/lib/{shadow-claw-channel-config-Bj0-Nk3t.js.map → shadow-claw-channel-config-DmfwJc6G.js.map} +1 -1
  86. package/dist/lib/{shadow-claw-channels-C_jI4KhP.js → shadow-claw-channels-1N6Jl-By.js} +3 -3
  87. package/dist/lib/{shadow-claw-channels-C_jI4KhP.js.map → shadow-claw-channels-1N6Jl-By.js.map} +1 -1
  88. package/dist/lib/{shadow-claw-chat-B16MspoP.js → shadow-claw-chat-BMoqQJRK.js} +10 -10
  89. package/dist/lib/{shadow-claw-chat-B16MspoP.js.map → shadow-claw-chat-BMoqQJRK.js.map} +1 -1
  90. package/dist/lib/{shadow-claw-control-plane-x8Ldid_h.js → shadow-claw-control-plane-UG0o7pCz.js} +6 -6
  91. package/dist/lib/{shadow-claw-control-plane-x8Ldid_h.js.map → shadow-claw-control-plane-UG0o7pCz.js.map} +1 -1
  92. package/dist/lib/{shadow-claw-conversations-Ct1kAYdB.js → shadow-claw-conversations-BwXep3iu.js} +4 -3
  93. package/dist/lib/{shadow-claw-conversations-Ct1kAYdB.js.map → shadow-claw-conversations-BwXep3iu.js.map} +1 -1
  94. package/dist/lib/{shadow-claw-file-viewer-BfDHHgpA.js → shadow-claw-file-viewer-DUxzVxDT.js} +14 -10
  95. package/dist/lib/shadow-claw-file-viewer-DUxzVxDT.js.map +1 -0
  96. package/dist/lib/{shadow-claw-files-EYhOPYIH.js → shadow-claw-files-DIREEnT2.js} +7 -7
  97. package/dist/lib/{shadow-claw-files-EYhOPYIH.js.map → shadow-claw-files-DIREEnT2.js.map} +1 -1
  98. package/dist/lib/{shadow-claw-git-tcSpT-P0.js → shadow-claw-git-Bg1SWgsF.js} +4 -4
  99. package/dist/lib/{shadow-claw-git-tcSpT-P0.js.map → shadow-claw-git-Bg1SWgsF.js.map} +1 -1
  100. package/dist/lib/{shadow-claw-integrations-NbcCx_ZI.js → shadow-claw-integrations-Ds-CLPhj.js} +2 -2
  101. package/dist/lib/{shadow-claw-integrations-NbcCx_ZI.js.map → shadow-claw-integrations-Ds-CLPhj.js.map} +1 -1
  102. package/dist/lib/{shadow-claw-llm-BazJdD5f.js → shadow-claw-llm-CazBrVpM.js} +3 -3
  103. package/dist/lib/{shadow-claw-llm-BazJdD5f.js.map → shadow-claw-llm-CazBrVpM.js.map} +1 -1
  104. package/dist/lib/{shadow-claw-mcp-remote-CYmhpg7a.js → shadow-claw-mcp-remote-CT5Q-54E.js} +2 -2
  105. package/dist/lib/{shadow-claw-mcp-remote-CYmhpg7a.js.map → shadow-claw-mcp-remote-CT5Q-54E.js.map} +1 -1
  106. package/dist/lib/{shadow-claw-networking-DImPxe0H.js → shadow-claw-networking-Df85tCbO.js} +2 -2
  107. package/dist/lib/{shadow-claw-networking-DImPxe0H.js.map → shadow-claw-networking-Df85tCbO.js.map} +1 -1
  108. package/dist/lib/{shadow-claw-page-header-CcHUfFUx.js → shadow-claw-page-header-Cti2fzf-.js} +2 -2
  109. package/dist/lib/{shadow-claw-page-header-CcHUfFUx.js.map → shadow-claw-page-header-Cti2fzf-.js.map} +1 -1
  110. package/dist/lib/{shadow-claw-pages-D54jF1Qq.js → shadow-claw-pages-BgPyIEZO.js} +15 -11
  111. package/dist/lib/shadow-claw-pages-BgPyIEZO.js.map +1 -0
  112. package/dist/lib/{shadow-claw-peerjs-B9-T8Nlx.js → shadow-claw-peerjs-xkBXILed.js} +3 -3
  113. package/dist/lib/{shadow-claw-peerjs-B9-T8Nlx.js.map → shadow-claw-peerjs-xkBXILed.js.map} +1 -1
  114. package/dist/lib/{shadow-claw-settings-Bt1VAe-1.js → shadow-claw-settings-CN89xRVU.js} +4 -4
  115. package/dist/lib/{shadow-claw-settings-Bt1VAe-1.js.map → shadow-claw-settings-CN89xRVU.js.map} +1 -1
  116. package/dist/lib/{shadow-claw-storage-CFOjGf1d.js → shadow-claw-storage-VnhcObCe.js} +3 -3
  117. package/dist/lib/{shadow-claw-storage-CFOjGf1d.js.map → shadow-claw-storage-VnhcObCe.js.map} +1 -1
  118. package/dist/lib/{shadow-claw-task-server-BiKa2GOm.js → shadow-claw-task-server-jgEC2hHB.js} +2 -2
  119. package/dist/lib/{shadow-claw-task-server-BiKa2GOm.js.map → shadow-claw-task-server-jgEC2hHB.js.map} +1 -1
  120. package/dist/lib/{shadow-claw-tasks-DDHd8W4d.js → shadow-claw-tasks-i_evIufy.js} +6 -6
  121. package/dist/lib/{shadow-claw-tasks-DDHd8W4d.js.map → shadow-claw-tasks-i_evIufy.js.map} +1 -1
  122. package/dist/lib/{shadow-claw-terminal-kB6_tWKz.js → shadow-claw-terminal-CwScROlu.js} +2 -2
  123. package/dist/lib/{shadow-claw-terminal-kB6_tWKz.js.map → shadow-claw-terminal-CwScROlu.js.map} +1 -1
  124. package/dist/lib/{shadow-claw-tools-DxXIm0ku.js → shadow-claw-tools-DD3fyXP4.js} +5 -4
  125. package/dist/lib/{shadow-claw-tools-DxXIm0ku.js.map → shadow-claw-tools-DD3fyXP4.js.map} +1 -1
  126. package/dist/lib/{shadow-claw-webvm-Dc8oo7ao.js → shadow-claw-webvm-DbJq4I3-.js} +2 -2
  127. package/dist/lib/{shadow-claw-webvm-Dc8oo7ao.js.map → shadow-claw-webvm-DbJq4I3-.js.map} +1 -1
  128. package/dist/lib/{syncWebMcpRegistration-jyRGbC9w.js → syncWebMcpRegistration-DNLnQ-jz.js} +3 -2
  129. package/dist/lib/{syncWebMcpRegistration-jyRGbC9w.js.map → syncWebMcpRegistration-DNLnQ-jz.js.map} +1 -1
  130. package/dist/lib/tools-DwwB9RBa.js +546 -0
  131. package/dist/lib/tools-DwwB9RBa.js.map +1 -0
  132. package/dist/lib/{trusted-types-CkLDpLiZ.js → trusted-types-Dx0RZlrd.js} +19 -8
  133. package/dist/lib/trusted-types-Dx0RZlrd.js.map +1 -0
  134. package/dist/lib/utils/index.js +1 -1
  135. package/dist/lib/utils/utils.js +1 -1
  136. package/dist/public/.well-known/agent-skills/index.json +14 -0
  137. package/dist/public/AGENTS.md +5 -3
  138. package/dist/public/README.md +5 -3
  139. package/dist/public/agent.worker.js +1 -1
  140. package/dist/public/{configurePeerJs-COcwE0E7.js → configurePeerJs-BqgeBjP7.js} +1 -1
  141. package/dist/public/custom-element-security-FU04Cq05.js +1 -0
  142. package/dist/public/dist-B9m1QM9v.js +58 -0
  143. package/dist/public/docs/README.md +31 -31
  144. package/dist/public/docs/example/article/index.html +1 -1
  145. package/dist/public/docs/publishing/index.html +1 -1
  146. package/dist/public/docs/skill-creator/index.html +1 -1
  147. package/dist/public/docs/subsystems/a2ui.md +11 -1
  148. package/dist/public/docs/subsystems/cli.md +32 -0
  149. package/dist/public/docs/subsystems/control-plane.md +8 -2
  150. package/dist/public/docs/subsystems/custom-element-security.md +19 -9
  151. package/dist/public/docs/subsystems/mcp-server.md +39 -15
  152. package/dist/public/docs/subsystems/skills.md +30 -0
  153. package/dist/public/docs/subsystems/webmcp.md +9 -0
  154. package/dist/public/downloadGroupFile-D8KRJGGL.js +1 -0
  155. package/dist/public/e2e/README.md +7 -4
  156. package/dist/public/{e2e-bridge-CHARpbpW.js → e2e-bridge-Ceqr5kGc.js} +1 -1
  157. package/dist/public/effect-BJCrpFdp.js +1 -0
  158. package/dist/public/file-viewer-C-6Jc_tb.js +1 -0
  159. package/dist/public/index.html +1 -1
  160. package/dist/public/index.js +1 -1
  161. package/dist/public/initControlPlane-BN9cWyO0.js +1 -0
  162. package/dist/public/main/index.html +1 -1
  163. package/dist/public/main/memory/index.html +1 -1
  164. package/dist/public/{markdown-1I3O6Mmd.js → markdown-C3M4OW_A.js} +1 -1
  165. package/dist/public/{orchestrator-Cl95w2vb.js → orchestrator-CMbCTjBf.js} +7 -7
  166. package/dist/public/{orchestrator-D-xlXG92.js → orchestrator-DHjdLtqa.js} +663 -663
  167. package/dist/public/peerjs-DUCKH-m9.js +1 -0
  168. package/dist/public/service-worker.js +1 -1
  169. package/dist/public/{shadow-claw-CaoKmIIB.js → shadow-claw-EAt2ml5Y.js} +3 -3
  170. package/dist/public/{shadow-claw-accounts-CJvYC4li.js → shadow-claw-accounts-xUOLBsQZ.js} +1 -1
  171. package/dist/public/{shadow-claw-channels-3K62sU5f.js → shadow-claw-channels-XsfuWFF8.js} +4 -4
  172. package/dist/public/{shadow-claw-chat-Cu2keU2I.js → shadow-claw-chat-CbSaOZ4q.js} +7 -7
  173. package/dist/public/{shadow-claw-control-plane-D1OwlQI_.js → shadow-claw-control-plane-DHvN3Ukg.js} +2 -2
  174. package/dist/public/{shadow-claw-conversations-DDtg3BEZ.js → shadow-claw-conversations-BWs5VVfs.js} +2 -2
  175. package/dist/public/{shadow-claw-file-viewer-BR__1z9S.js → shadow-claw-file-viewer-BWsoW5QS.js} +5 -4
  176. package/dist/public/{shadow-claw-files-BJSyZ-Bl.js → shadow-claw-files-CG7MqWiV.js} +8 -8
  177. package/dist/public/{shadow-claw-git-MAjhXRLc.js → shadow-claw-git-DBRPZNav.js} +6 -6
  178. package/dist/public/{shadow-claw-integrations-82UoFuDR.js → shadow-claw-integrations-BBVnO0Fc.js} +8 -8
  179. package/dist/public/{shadow-claw-llm-R8j0lwPP.js → shadow-claw-llm-DMvLgKXo.js} +2 -2
  180. package/dist/public/{shadow-claw-mcp-remote-BzZoz4LX.js → shadow-claw-mcp-remote-Bkx0gsmF.js} +2 -2
  181. package/dist/public/{shadow-claw-networking-DLEd9cNm.js → shadow-claw-networking-Dd8Rw31D.js} +2 -2
  182. package/dist/public/{shadow-claw-notifications-1vwR7TbT.js → shadow-claw-notifications-Dbevj-lq.js} +2 -2
  183. package/dist/public/{shadow-claw-page-header-DMKbkv3s.js → shadow-claw-page-header-BccSHItx.js} +1 -1
  184. package/dist/public/{shadow-claw-pages-CjyeIV__.js → shadow-claw-pages-3_lQAv0t.js} +4 -3
  185. package/dist/public/{shadow-claw-settings-BfbT4dBU.js → shadow-claw-settings-t8TIlgrM.js} +5 -5
  186. package/dist/public/{shadow-claw-storage-C-mWQQML.js → shadow-claw-storage-CfEXoSIE.js} +2 -2
  187. package/dist/public/{shadow-claw-task-server-D3lHp0Nc.js → shadow-claw-task-server-DxQSsgRZ.js} +2 -2
  188. package/dist/public/{shadow-claw-tasks-DVVWEm-c.js → shadow-claw-tasks-DNpicQwz.js} +14 -14
  189. package/dist/public/{shadow-claw-terminal-BwuTRp-O.js → shadow-claw-terminal-DpY6zU_r.js} +1 -1
  190. package/dist/public/{shadow-claw-toast-ClCwgzFG.js → shadow-claw-toast-BkrQIP-3.js} +1 -1
  191. package/dist/public/{shadow-claw-tools-zFLk2nbV.js → shadow-claw-tools-WSwWohnk.js} +2 -2
  192. package/dist/public/{shadow-claw-webvm-qR9X7fg7.js → shadow-claw-webvm-CP6oFjg5.js} +2 -2
  193. package/dist/public/syncWebMcpRegistration-DOn9gLnD.js +1 -0
  194. package/dist/public/toast-BXgUfbyh.js +1 -0
  195. package/dist/public/tools-DvckJZG2.js +1 -0
  196. package/dist/server.js +188 -188
  197. package/package.json +3 -1
  198. package/src/components/shadow-claw-a2ui/shadow-claw-a2ui.stories.ts +1380 -93
  199. package/src/components/shadow-claw-a2ui/shadow-claw-a2ui.ts +11 -6
  200. package/src/components/shadow-claw-file-viewer/shadow-claw-file-viewer.test.ts +8 -1
  201. package/src/components/shadow-claw-file-viewer/shadow-claw-file-viewer.ts +13 -5
  202. package/src/components/shadow-claw-pages/utils/buildHtmlPageSrcdoc.ts +13 -5
  203. package/src/core/control-plane-client.ts +15 -0
  204. package/src/core/utils/initControlPlane.test.ts +187 -0
  205. package/src/core/utils/initControlPlane.ts +194 -20
  206. package/src/security/custom-element-security.test.ts +51 -0
  207. package/src/security/custom-element-security.ts +33 -15
  208. package/src/server/control-plane-types.ts +1 -0
  209. package/src/server/control-plane.test.ts +69 -0
  210. package/src/server/control-plane.ts +45 -3
  211. package/src/server/mcp/tools/built-in-tools.ts +80 -5
  212. package/src/server/mcp/tools/client-tool-relay.ts +183 -26
  213. package/src/server/mcp/tools/mcp-tools.test.ts +140 -0
  214. package/src/server/middleware/static-files.test.ts +142 -0
  215. package/src/server/middleware/static-files.ts +66 -8
  216. package/src/testing/jest-setup.ts +14 -0
  217. package/src/worker/utils/handleMessage.ts +4 -1
  218. package/dist/lib/initControlPlane-CsO4UR6_.js.map +0 -1
  219. package/dist/lib/readGroupFileBytes-Bve-e5e_.js.map +0 -1
  220. package/dist/lib/shadow-claw-file-viewer-BfDHHgpA.js.map +0 -1
  221. package/dist/lib/shadow-claw-pages-D54jF1Qq.js.map +0 -1
  222. package/dist/lib/trusted-types-CkLDpLiZ.js.map +0 -1
  223. package/dist/public/custom-element-security-NCqQ5lmC.js +0 -1
  224. package/dist/public/downloadGroupFile-G0BZQgQg.js +0 -1
  225. package/dist/public/effect-rHYr4nfu.js +0 -1
  226. package/dist/public/file-viewer-8PdCURDD.js +0 -1
  227. package/dist/public/initControlPlane-CcGXax0A.js +0 -1
  228. package/dist/public/peerjs-BZdxWQFv.js +0 -1
  229. package/dist/public/syncWebMcpRegistration-DD42YsYV.js +0 -1
  230. package/dist/public/toast-HAq8XWFj.js +0 -58
package/bin/cli.mjs CHANGED
@@ -15,6 +15,7 @@ import { runTasksCommand } from "./commands/tasks.mjs";
15
15
  import { runPeerIdCommand } from "./commands/peer-id.mjs";
16
16
  import { runWebRtcListenCommand } from "./commands/webrtc-listen.mjs";
17
17
  import { runMcpCommand } from "./commands/mcp.mjs";
18
+ import { runSkillsIndexCommand } from "./commands/skills-index.mjs";
18
19
  import { resolveCacheDir } from "./utils/resolve-cache-dir.mjs";
19
20
 
20
21
  const __filename = fileURLToPath(import.meta.url);
@@ -962,4 +963,38 @@ program
962
963
  await runMcpCommand(options);
963
964
  });
964
965
 
966
+ // ---------------------------------------------------------------------------
967
+ // AGENT SKILLS INDEX COMMAND
968
+ // ---------------------------------------------------------------------------
969
+ program
970
+ .command("skills:index [dir]")
971
+ .alias("agent-skills")
972
+ .description(
973
+ "Generate or update .well-known/agent-skills/index.json per the Agent Skills Discovery RFC",
974
+ )
975
+ .option(
976
+ "--out-dir <dir>",
977
+ "Output directory relative to content root (default: .well-known/agent-skills)",
978
+ )
979
+ .option("--out-file <file>", "Explicit destination path for index.json")
980
+ .option(
981
+ "--metadata-root <dir>",
982
+ "Directory to read site metadata from (default: content root)",
983
+ )
984
+ .option(
985
+ "--config <file>",
986
+ "Explicit path to shadow-claw.config.json or site-config.json",
987
+ )
988
+ .option("--no-bundled", "Exclude bundled ShadowClaw skills from index")
989
+ .option("--stdout", "Print generated index.json to stdout", false)
990
+ .option("--no-write", "Skip writing file to disk")
991
+ .action(async (dir, options) => {
992
+ try {
993
+ await runSkillsIndexCommand(dir, options);
994
+ } catch (err) {
995
+ console.error("Failed to generate skills index:", err);
996
+ process.exit(1);
997
+ }
998
+ });
999
+
965
1000
  program.parse(process.argv);
@@ -71,6 +71,22 @@ export const CLI_BUILTIN_TOOLS = [
71
71
  },
72
72
  },
73
73
  },
74
+ {
75
+ name: "shadowclaw_set_active_client",
76
+ description:
77
+ "Set the active default connected client used when no clientId is explicitly provided in tool calls.",
78
+ inputSchema: {
79
+ type: "object",
80
+ properties: {
81
+ clientId: {
82
+ type: "string",
83
+ description:
84
+ "Target client ID (or index '0', '1', prefix, or device label) to make active.",
85
+ },
86
+ },
87
+ required: ["clientId"],
88
+ },
89
+ },
74
90
  {
75
91
  name: "shadowclaw_manage_backup",
76
92
  description:
@@ -95,6 +111,7 @@ export function createCliMcpEngine(options = {}) {
95
111
  const client = options.client || new CliControlClient(options);
96
112
  const relayClientTools = options.relayClientTools !== false;
97
113
  const targetClientId = options.targetClientId || options.clientTarget;
114
+ let activeClientId = targetClientId || "";
98
115
 
99
116
  const serverInfo = {
100
117
  name: "shadow-claw",
@@ -107,47 +124,138 @@ export function createCliMcpEngine(options = {}) {
107
124
  };
108
125
 
109
126
  async function resolveTargetId(requestedId) {
110
- if (requestedId && typeof requestedId === "string" && requestedId.trim()) {
111
- return requestedId.trim();
112
- }
113
- if (targetClientId) {
114
- return targetClientId;
115
- }
127
+ const candidate = requestedId || activeClientId || targetClientId;
116
128
  try {
117
129
  const clients = await client.listClients();
118
130
  if (Array.isArray(clients) && clients.length > 0) {
131
+ if (candidate && typeof candidate === "string" && candidate.trim()) {
132
+ const trimmed = candidate.trim();
133
+ const exact = clients.find((c) => (c.clientId || c.id) === trimmed);
134
+ if (exact) return exact.clientId || exact.id;
135
+
136
+ const idx = parseInt(trimmed, 10);
137
+ if (!isNaN(idx) && idx >= 0 && idx < clients.length) {
138
+ return clients[idx].clientId || clients[idx].id;
139
+ }
140
+
141
+ const prefix = clients.find(
142
+ (c) =>
143
+ (c.clientId || c.id || "").startsWith(trimmed) ||
144
+ (c.clientId || "").replace(/^client-/, "").startsWith(trimmed),
145
+ );
146
+ if (prefix) return prefix.clientId || prefix.id;
147
+
148
+ const byLabel = clients.find((c) =>
149
+ c.deviceLabel?.toLowerCase().includes(trimmed.toLowerCase()),
150
+ );
151
+ if (byLabel) return byLabel.clientId || byLabel.id;
152
+
153
+ return trimmed;
154
+ }
155
+
119
156
  return clients[0].clientId || clients[0].id || "";
120
157
  }
121
158
  } catch (_) {}
122
- return "";
159
+ return typeof candidate === "string" ? candidate.trim() : "";
123
160
  }
124
161
 
162
+ const toolSupportingClientsMap = new Map();
163
+ const toolDefMap = new Map();
164
+
125
165
  async function getRelayedTools() {
126
166
  if (!relayClientTools) {
127
167
  return [];
128
168
  }
129
- const clientId = await resolveTargetId();
130
- if (!clientId) {
131
- return [];
132
- }
169
+ let clients = [];
133
170
  try {
134
- const res = await client.sendCommand(clientId, "list-tools", {});
135
- if (
136
- res &&
137
- res.success &&
138
- res.data?.tools &&
139
- Array.isArray(res.data.tools)
140
- ) {
141
- return res.data.tools.map((t) => ({
142
- name: t.name,
143
- description:
144
- t.description || `Relayed tool '${t.name}' from connected client.`,
145
- inputSchema: t.inputSchema || { type: "object", properties: {} },
146
- annotations: t.annotations,
147
- }));
148
- }
171
+ clients = await client.listClients();
149
172
  } catch (_) {}
150
- return [];
173
+
174
+ if (!Array.isArray(clients) || clients.length === 0) {
175
+ toolSupportingClientsMap.clear();
176
+ toolDefMap.clear();
177
+ return [];
178
+ }
179
+
180
+ toolSupportingClientsMap.clear();
181
+ toolDefMap.clear();
182
+
183
+ for (const c of clients) {
184
+ const cid = c.clientId || c.id;
185
+ if (!cid) continue;
186
+
187
+ try {
188
+ const res = await client.sendCommand(cid, "list-tools", {});
189
+ if (
190
+ res &&
191
+ res.success &&
192
+ res.data?.tools &&
193
+ Array.isArray(res.data.tools)
194
+ ) {
195
+ for (const t of res.data.tools) {
196
+ if (!toolDefMap.has(t.name)) {
197
+ toolDefMap.set(t.name, t);
198
+ toolSupportingClientsMap.set(t.name, []);
199
+ }
200
+ toolSupportingClientsMap.get(t.name).push(c);
201
+ }
202
+ }
203
+ } catch (_) {}
204
+ }
205
+
206
+ const activeTargetId = await resolveTargetId();
207
+ const relayedTools = [];
208
+
209
+ for (const [toolName, t] of toolDefMap.entries()) {
210
+ const supportingClients = toolSupportingClientsMap.get(toolName) || [];
211
+ const supportingClientIds = supportingClients
212
+ .map((cl) => cl.clientId || cl.id)
213
+ .filter(Boolean);
214
+
215
+ const preferredClient =
216
+ supportingClients.find(
217
+ (cl) => (cl.clientId || cl.id) === activeTargetId,
218
+ ) || supportingClients[0];
219
+ const toolDefaultId =
220
+ preferredClient?.clientId || preferredClient?.id || "";
221
+ const toolDefaultLabel = preferredClient?.deviceLabel || "Client";
222
+
223
+ const existingSchema =
224
+ t.inputSchema && typeof t.inputSchema === "object"
225
+ ? t.inputSchema
226
+ : { type: "object", properties: {} };
227
+
228
+ const properties = {
229
+ ...(existingSchema.properties || {}),
230
+ clientId: {
231
+ type: "string",
232
+ description: `Target ShadowClaw client ID (optional; defaults to ${toolDefaultId} [${toolDefaultLabel}]). Available on: ${supportingClients.map((cl) => `${cl.clientId || cl.id} (${cl.deviceLabel || "Client"})`).join(", ")}`,
233
+ enum: supportingClientIds,
234
+ },
235
+ };
236
+
237
+ const clientNote =
238
+ clients.length > 1
239
+ ? supportingClients.length > 1
240
+ ? ` [Default: ${toolDefaultLabel} (${toolDefaultId.slice(0, 14)}...)]`
241
+ : ` [Client: ${toolDefaultLabel} (${toolDefaultId.slice(0, 14)}...)]`
242
+ : "";
243
+
244
+ relayedTools.push({
245
+ name: t.name,
246
+ description:
247
+ (t.description || `Relayed tool '${t.name}' from connected client.`) +
248
+ clientNote,
249
+ inputSchema: {
250
+ ...existingSchema,
251
+ type: "object",
252
+ properties,
253
+ },
254
+ annotations: t.annotations,
255
+ });
256
+ }
257
+
258
+ return relayedTools;
151
259
  }
152
260
 
153
261
  async function handleMessage(request, headers = {}) {
@@ -260,6 +368,48 @@ export function createCliMcpEngine(options = {}) {
260
368
  };
261
369
  }
262
370
 
371
+ if (toolName === "shadowclaw_set_active_client") {
372
+ const targetId = await resolveTargetId(args.clientId);
373
+ if (!targetId) {
374
+ return {
375
+ jsonrpc: "2.0",
376
+ id: reqId,
377
+ result: {
378
+ resultType: "complete",
379
+ isError: true,
380
+ content: [
381
+ {
382
+ type: "text",
383
+ text: `Error: Client '${args.clientId}' not found among connected clients.`,
384
+ },
385
+ ],
386
+ _meta: { "io.modelcontextprotocol/serverInfo": serverInfo },
387
+ },
388
+ };
389
+ }
390
+ activeClientId = targetId;
391
+ console.error(
392
+ `[ShadowClaw MCP] Active default client set to: ${activeClientId}`,
393
+ );
394
+ return {
395
+ jsonrpc: "2.0",
396
+ id: reqId,
397
+ result: {
398
+ resultType: "complete",
399
+ content: [
400
+ {
401
+ type: "text",
402
+ text: `Active default client set to: ${activeClientId}`,
403
+ },
404
+ ],
405
+ _meta: {
406
+ activeClientId,
407
+ "io.modelcontextprotocol/serverInfo": serverInfo,
408
+ },
409
+ },
410
+ };
411
+ }
412
+
263
413
  if (toolName === "shadowclaw_send_message") {
264
414
  const targetId = await resolveTargetId(args.clientId);
265
415
  if (!targetId) {
@@ -391,26 +541,12 @@ export function createCliMcpEngine(options = {}) {
391
541
  };
392
542
  }
393
543
 
394
- // Relayed interactive ask_user tool (MRTR)
395
- if (toolName === "ask_user") {
396
- if (!inputResponses || !inputResponses["response"]) {
397
- return {
398
- jsonrpc: "2.0",
399
- id: reqId,
400
- result: {
401
- resultType: "input_required",
402
- inputRequests: [
403
- {
404
- id: "response",
405
- type: "prompt",
406
- message:
407
- args.question || args.prompt || "User input requested",
408
- },
409
- ],
410
- _meta: { "io.modelcontextprotocol/serverInfo": serverInfo },
411
- },
412
- };
413
- }
544
+ // Relayed interactive ask_user tool with MRTR response fulfillment if provided
545
+ if (
546
+ toolName === "ask_user" &&
547
+ inputResponses &&
548
+ inputResponses["response"]
549
+ ) {
414
550
  return {
415
551
  jsonrpc: "2.0",
416
552
  id: reqId,
@@ -425,7 +561,29 @@ export function createCliMcpEngine(options = {}) {
425
561
  }
426
562
 
427
563
  // Relayed client tools (invoke-tool)
428
- const targetId = await resolveTargetId(args.clientId);
564
+ if (toolDefMap.size === 0) {
565
+ await getRelayedTools();
566
+ }
567
+
568
+ const supportingClients = toolSupportingClientsMap.get(toolName) || [];
569
+ const supportingClientIds = supportingClients
570
+ .map((cl) => cl.clientId || cl.id)
571
+ .filter(Boolean);
572
+
573
+ let targetId = "";
574
+ if (args.clientId) {
575
+ targetId = await resolveTargetId(args.clientId);
576
+ } else {
577
+ const activeSessionId = await resolveTargetId();
578
+ if (supportingClientIds.includes(activeSessionId)) {
579
+ targetId = activeSessionId;
580
+ } else if (supportingClientIds.length > 0) {
581
+ targetId = supportingClientIds[0];
582
+ } else {
583
+ targetId = activeSessionId;
584
+ }
585
+ }
586
+
429
587
  if (!targetId) {
430
588
  return {
431
589
  jsonrpc: "2.0",
@@ -441,11 +599,51 @@ export function createCliMcpEngine(options = {}) {
441
599
  };
442
600
  }
443
601
 
602
+ if (
603
+ supportingClientIds.length > 0 &&
604
+ !supportingClientIds.includes(targetId)
605
+ ) {
606
+ return {
607
+ jsonrpc: "2.0",
608
+ id: reqId,
609
+ result: {
610
+ resultType: "complete",
611
+ isError: true,
612
+ content: [
613
+ {
614
+ type: "text",
615
+ text: `Error: Tool '${toolName}' is not enabled or available on client '${targetId}'. (Available on: ${supportingClientIds.join(", ")})`,
616
+ },
617
+ ],
618
+ _meta: {
619
+ clientId: targetId,
620
+ "io.modelcontextprotocol/serverInfo": serverInfo,
621
+ },
622
+ },
623
+ };
624
+ }
625
+
444
626
  try {
445
- const res = await client.sendCommand(targetId, "invoke-tool", {
446
- toolName,
447
- input: args,
448
- });
627
+ console.error(
628
+ `[ShadowClaw MCP] Executing '${toolName}' on client: ${targetId}`,
629
+ );
630
+ const toolArgs = { ...args };
631
+ delete toolArgs.clientId;
632
+ const isInteractive = toolName === "ask_user";
633
+ const res = isInteractive
634
+ ? await client.sendCommand(
635
+ targetId,
636
+ "invoke-tool",
637
+ {
638
+ toolName,
639
+ input: toolArgs,
640
+ },
641
+ 300000,
642
+ )
643
+ : await client.sendCommand(targetId, "invoke-tool", {
644
+ toolName,
645
+ input: toolArgs,
646
+ });
449
647
 
450
648
  const rawResult =
451
649
  res.data?.result !== undefined ? res.data.result : res.data;
@@ -454,14 +652,31 @@ export function createCliMcpEngine(options = {}) {
454
652
  ? rawResult
455
653
  : JSON.stringify(rawResult, null, 2);
456
654
 
655
+ const errorMessage =
656
+ res.error ||
657
+ (res.data && res.data.error) ||
658
+ "Unknown tool execution error";
659
+
457
660
  return {
458
661
  jsonrpc: "2.0",
459
662
  id: reqId,
460
663
  result: {
461
664
  resultType: "complete",
462
665
  isError: !res.success,
463
- content: [{ type: "text", text: textOutput || "" }],
464
- _meta: { "io.modelcontextprotocol/serverInfo": serverInfo },
666
+ content: [
667
+ {
668
+ type: "text",
669
+ text: res.success
670
+ ? textOutput || ""
671
+ : textOutput && textOutput !== "null" && textOutput !== "{}"
672
+ ? `${textOutput}\n${errorMessage}`
673
+ : `Tool execution error: ${errorMessage}`,
674
+ },
675
+ ],
676
+ _meta: {
677
+ clientId: targetId,
678
+ "io.modelcontextprotocol/serverInfo": serverInfo,
679
+ },
465
680
  },
466
681
  };
467
682
  } catch (err) {
@@ -472,7 +687,10 @@ export function createCliMcpEngine(options = {}) {
472
687
  resultType: "complete",
473
688
  isError: true,
474
689
  content: [{ type: "text", text: `Tool error: ${err.message}` }],
475
- _meta: { "io.modelcontextprotocol/serverInfo": serverInfo },
690
+ _meta: {
691
+ clientId: targetId,
692
+ "io.modelcontextprotocol/serverInfo": serverInfo,
693
+ },
476
694
  },
477
695
  };
478
696
  }
@@ -511,6 +729,10 @@ export function createCliMcpEngine(options = {}) {
511
729
 
512
730
  return {
513
731
  handleMessage,
732
+ getActiveClientId: () => activeClientId,
733
+ setActiveClientId: (id) => {
734
+ activeClientId = id;
735
+ },
514
736
  };
515
737
  }
516
738