@rainbow-robotics/muscat-plugin-kit 0.1.2-dev.9 → 1.0.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 (272) hide show
  1. package/README.md +113 -49
  2. package/cli/README.md +191 -5
  3. package/cli/bin/create-muscat-plugin.mjs +1 -1
  4. package/cli/bin/muscat-pk.mjs +44 -26
  5. package/cli/bundle-templates.mjs +28 -0
  6. package/cli/docker/Dockerfile.bridge +17 -0
  7. package/cli/docker/Dockerfile.cpp +22 -0
  8. package/cli/docker/Dockerfile.dev +1 -0
  9. package/cli/docker/Dockerfile.python +20 -0
  10. package/cli/docker/bridge-package.json +8 -0
  11. package/cli/prepack.mjs +10 -0
  12. package/cli/src/__pycache__/host_agent.cpython-37.pyc +0 -0
  13. package/cli/src/bridge.mjs +95 -0
  14. package/cli/src/build.mjs +345 -85
  15. package/cli/src/check-package.mjs +8 -23
  16. package/cli/src/cpp.mjs +61 -0
  17. package/cli/src/dev.mjs +156 -4
  18. package/cli/src/devBack.mjs +505 -57
  19. package/cli/src/devUi.mjs +167 -22
  20. package/cli/src/esbuild.mjs +27 -10
  21. package/cli/src/host_agent.py +162 -0
  22. package/cli/src/manifest.mjs +208 -0
  23. package/cli/src/mcp.mjs +617 -0
  24. package/cli/src/new.mjs +170 -67
  25. package/cli/src/pluginDevServer.mjs +112 -0
  26. package/cli/src/ports.mjs +160 -0
  27. package/cli/src/python.mjs +109 -0
  28. package/cli/src/ros2.mjs +43 -18
  29. package/cli/src/sdk.mjs +11 -9
  30. package/cli/src/socketBridge.mjs +133 -0
  31. package/cli/src/storybook.mjs +168 -0
  32. package/cli/src/type.mjs +52 -29
  33. package/cli/src/uninstall.mjs +98 -0
  34. package/cli/src/update.mjs +259 -30
  35. package/cli/src/util.mjs +123 -9
  36. package/cli/src/zenohDev.mjs +75 -0
  37. package/cli/storybook-dist/_design-tokens.css +4957 -0
  38. package/cli/storybook-dist/_stories-src/NxAvatar.stories.tsx +27 -0
  39. package/cli/storybook-dist/_stories-src/NxPagination.stories.tsx +28 -0
  40. package/cli/storybook-dist/_stories-src/RBAccordion/RBAccordion.stories.tsx +46 -0
  41. package/cli/storybook-dist/_stories-src/RBAccordion/RBAccordionGroup.stories.tsx +73 -0
  42. package/cli/storybook-dist/_stories-src/RBBadge/RBBadge.stories.tsx +93 -0
  43. package/cli/storybook-dist/_stories-src/RBBattery/RBBattery.stories.tsx +74 -0
  44. package/cli/storybook-dist/_stories-src/RBButton/RBCheckIconButton.stories.tsx +28 -0
  45. package/cli/storybook-dist/_stories-src/RBButton/RBCheckLabelButton.stories.tsx +84 -0
  46. package/cli/storybook-dist/_stories-src/RBButton/RBIconButton.stories.tsx +57 -0
  47. package/cli/storybook-dist/_stories-src/RBButton/RBInlineLabelButton.stories.tsx +41 -0
  48. package/cli/storybook-dist/_stories-src/RBButton/RBLabelButton.stories.tsx +60 -0
  49. package/cli/storybook-dist/_stories-src/RBDatePicker/RBDateInput.stories.tsx +44 -0
  50. package/cli/storybook-dist/_stories-src/RBDatePicker/RBRangeDateInput.stories.tsx +44 -0
  51. package/cli/storybook-dist/_stories-src/RBDialog/RBAlert.stories.tsx +51 -0
  52. package/cli/storybook-dist/_stories-src/RBDialog/RBConfirm.stories.tsx +55 -0
  53. package/cli/storybook-dist/_stories-src/RBDialog/RBPrompt.stories.tsx +52 -0
  54. package/cli/storybook-dist/_stories-src/RBDivider/RBDivider.stories.tsx +93 -0
  55. package/cli/storybook-dist/_stories-src/RBEmptyView/RBEmptyView.stories.tsx +49 -0
  56. package/cli/storybook-dist/_stories-src/RBIcons/RBColorIcons.stories.tsx +108 -0
  57. package/cli/storybook-dist/_stories-src/RBIcons/RBIcons.stories.tsx +106 -0
  58. package/cli/storybook-dist/_stories-src/RBIcons/RBMenuTreeIcons.stories.tsx +108 -0
  59. package/cli/storybook-dist/_stories-src/RBIcons/RBProgramIcons.stories.tsx +116 -0
  60. package/cli/storybook-dist/_stories-src/RBInput/RBCheckBox.stories.tsx +89 -0
  61. package/cli/storybook-dist/_stories-src/RBInput/RBMultiRangeInput.stories.tsx +64 -0
  62. package/cli/storybook-dist/_stories-src/RBInput/RBRadioBox.stories.tsx +65 -0
  63. package/cli/storybook-dist/_stories-src/RBInput/RBRadioButton.stories.tsx +68 -0
  64. package/cli/storybook-dist/_stories-src/RBInput/RBSelectBox.stories.tsx +119 -0
  65. package/cli/storybook-dist/_stories-src/RBInput/RBSideNumberInput.stories.tsx +90 -0
  66. package/cli/storybook-dist/_stories-src/RBInput/RBText/RBTextArea.stories.tsx +45 -0
  67. package/cli/storybook-dist/_stories-src/RBInput/RBText/RBTextInput.stories.tsx +50 -0
  68. package/cli/storybook-dist/_stories-src/RBInput/RBTextField.stories.tsx +102 -0
  69. package/cli/storybook-dist/_stories-src/RBJoyStick/RBJoyStick.stories.tsx +31 -0
  70. package/cli/storybook-dist/_stories-src/RBLight/RBLight.stories.tsx +36 -0
  71. package/cli/storybook-dist/_stories-src/RBPagination/RBPagination.stories.tsx +49 -0
  72. package/cli/storybook-dist/_stories-src/RBShadcn/RBCard/RBCard.stories.tsx +89 -0
  73. package/cli/storybook-dist/_stories-src/RBShadcn/RBCommand/RBCommand.stories.tsx +116 -0
  74. package/cli/storybook-dist/_stories-src/RBShadcn/RBDialog/RBDialog.stories.tsx +74 -0
  75. package/cli/storybook-dist/_stories-src/RBShadcn/RBDrawer/RBDrawer.stories.tsx +99 -0
  76. package/cli/storybook-dist/_stories-src/RBShadcn/RBDropdownMenu/RBDropdownMenu.stories.tsx +123 -0
  77. package/cli/storybook-dist/_stories-src/RBShadcn/RBMenubar/RBMenubar.stories.tsx +135 -0
  78. package/cli/storybook-dist/_stories-src/RBShadcn/RBPopover/RBPopover.stories.tsx +69 -0
  79. package/cli/storybook-dist/_stories-src/RBShadcn/RBResizable/RBResizable.stories.tsx +49 -0
  80. package/cli/storybook-dist/_stories-src/RBShadcn/RBSheet/RBSheet.stories.tsx +91 -0
  81. package/cli/storybook-dist/_stories-src/RBShadcn/RBSlider/RBSlider.stories.tsx +38 -0
  82. package/cli/storybook-dist/_stories-src/RBShadcn/RBSwitch/RBSwitch.stories.tsx +112 -0
  83. package/cli/storybook-dist/_stories-src/RBShadcn/RBTabs/RBTabs.stories.tsx +75 -0
  84. package/cli/storybook-dist/_stories-src/RBShadcn/RBToggle/RBToggle.stories.tsx +51 -0
  85. package/cli/storybook-dist/_stories-src/RBShadcn/RBToggleGroup/RBToggleGroup.stories.tsx +84 -0
  86. package/cli/storybook-dist/_stories-src/RBTab/RBChipTab.stories.tsx +102 -0
  87. package/cli/storybook-dist/_stories-src/RBTab/RBChipsBoxTab.stories.tsx +78 -0
  88. package/cli/storybook-dist/_stories-src/RBTab/RBTab.stories.tsx +57 -0
  89. package/cli/storybook-dist/_stories-src/RBTable/RBTable.stories.tsx +177 -0
  90. package/cli/storybook-dist/_stories-src/RBTable/RBTableRow.stories.tsx +64 -0
  91. package/cli/storybook-dist/_stories-src/RBToast/RBToast.stories.tsx +117 -0
  92. package/cli/storybook-dist/_stories-src/RBTooltip/RBTooltip.stories.tsx +50 -0
  93. package/cli/storybook-dist/_stories-src/loading/RBSpinner.stories.tsx +30 -0
  94. package/cli/storybook-dist/_stories-src/nx-button/NxButton.stories.tsx +54 -0
  95. package/cli/storybook-dist/_stories-src/nx-button/NxPointerHoldButton.stories.tsx +57 -0
  96. package/cli/storybook-dist/_stories-src/nx-icons/NxIcons.stories.tsx +48 -0
  97. package/cli/storybook-dist/_stories-src/nx-inputs/NxNumberInput.stories.tsx +103 -0
  98. package/cli/storybook-dist/_stories-src/nx-inputs/NxRangeInput.stories.tsx +27 -0
  99. package/cli/storybook-dist/_stories-src/nx-inputs/NxSelectBox.stories.tsx +67 -0
  100. package/cli/storybook-dist/_stories-src/nx-inputs/NxSlideRange.stories.tsx +45 -0
  101. package/cli/storybook-dist/_stories-src/nx-inputs/NxSwitch.stories.tsx +27 -0
  102. package/cli/storybook-dist/_stories-src/nx-inputs/NxTextArea.stories.tsx +48 -0
  103. package/cli/storybook-dist/_stories-src/nx-inputs/NxTextInput.stories.tsx +46 -0
  104. package/cli/storybook-dist/assets/Color-YHDXOIA2-ttZJDaKn.js +1 -0
  105. package/cli/storybook-dist/assets/Docs-B1jnlXHd.js +12 -0
  106. package/cli/storybook-dist/assets/Docs-B7dRsHh7.js +8 -0
  107. package/cli/storybook-dist/assets/Docs-C68t3mnn.js +20 -0
  108. package/cli/storybook-dist/assets/Docs-D7rPMMhK.js +7 -0
  109. package/cli/storybook-dist/assets/Docs-DM98U-ZG.js +7 -0
  110. package/cli/storybook-dist/assets/Docs-guWsANnn.js +8 -0
  111. package/cli/storybook-dist/assets/DocsRenderer-CFRXHY34-t12O9QfY.js +2 -0
  112. package/cli/storybook-dist/assets/NxAvatar.stories-ikdLTtys.js +13 -0
  113. package/cli/storybook-dist/assets/NxButton.stories-DL3S2KEV.js +20 -0
  114. package/cli/storybook-dist/assets/NxIcons.stories-Ca7qpAaO.js +3 -0
  115. package/cli/storybook-dist/assets/NxNumberInput.stories-D6NVMTos.js +26 -0
  116. package/cli/storybook-dist/assets/NxPagination.stories-BDKSlHiQ.js +11 -0
  117. package/cli/storybook-dist/assets/NxPointerHoldButton.stories-BI544zqB.js +14 -0
  118. package/cli/storybook-dist/assets/NxRangeInput.stories-BigBBkE7.js +17 -0
  119. package/cli/storybook-dist/assets/NxSelectBox.stories-Ci0IyUWd.js +17 -0
  120. package/cli/storybook-dist/assets/NxSlideRange.stories-sjnPAjFy.js +14 -0
  121. package/cli/storybook-dist/assets/NxSwitch.stories-CRxPDlJm.js +11 -0
  122. package/cli/storybook-dist/assets/NxTextArea.stories-Jh09n24O.js +11 -0
  123. package/cli/storybook-dist/assets/NxTextInput.stories-BeGCjxES.js +11 -0
  124. package/cli/storybook-dist/assets/PretendardVariable-CJuje-Rk.woff2 +0 -0
  125. package/cli/storybook-dist/assets/RBAccordion.stories-CnC95OwM.js +17 -0
  126. package/cli/storybook-dist/assets/RBAccordionGroup.stories-og-6ePox.js +33 -0
  127. package/cli/storybook-dist/assets/RBAlert.stories-BcE9-UOT.js +17 -0
  128. package/cli/storybook-dist/assets/RBBadge.stories-DYZMXb-e.js +1 -0
  129. package/cli/storybook-dist/assets/RBBattery.stories-B7YAUvlM.js +10 -0
  130. package/cli/storybook-dist/assets/RBCard.stories-DTL_7n6I.js +45 -0
  131. package/cli/storybook-dist/assets/RBCheckBox.stories-D9KC6hTg.js +1 -0
  132. package/cli/storybook-dist/assets/RBCheckIconButton.stories-BR8aIkOC.js +1 -0
  133. package/cli/storybook-dist/assets/RBCheckLabelButton.stories-C1ABYhEr.js +24 -0
  134. package/cli/storybook-dist/assets/RBChipTab.stories-Ceo_vnNi.js +21 -0
  135. package/cli/storybook-dist/assets/RBChipsBoxTab.stories-CB_bfK8M.js +1 -0
  136. package/cli/storybook-dist/assets/RBColorIcons.stories-DHZKezld.js +3 -0
  137. package/cli/storybook-dist/assets/RBCommand.stories-DjuCDn5h.js +73 -0
  138. package/cli/storybook-dist/assets/RBConfirm.stories-HMmUPkB1.js +20 -0
  139. package/cli/storybook-dist/assets/RBDateInput.stories-BRfpYtJ4.js +15 -0
  140. package/cli/storybook-dist/assets/RBDialog.stories-Ln23Gyhk.js +38 -0
  141. package/cli/storybook-dist/assets/RBDivider.stories-Bhc_D5Cm.js +1 -0
  142. package/cli/storybook-dist/assets/RBDrawer.stories-CEEhamr_.js +14 -0
  143. package/cli/storybook-dist/assets/RBDropdownMenu.stories-DBvwDCnf.js +86 -0
  144. package/cli/storybook-dist/assets/RBEmptyView.stories-BY5QtXVc.js +12 -0
  145. package/cli/storybook-dist/assets/RBIconButton.stories-DyMFWpIV.js +1 -0
  146. package/cli/storybook-dist/assets/RBIcons.stories-DisU8G0d.js +3 -0
  147. package/cli/storybook-dist/assets/RBInlineLabelButton.stories-Cx0KJqxD.js +1 -0
  148. package/cli/storybook-dist/assets/RBJoyStick.stories-D1THM1Du.js +11 -0
  149. package/cli/storybook-dist/assets/RBLabelButton.stories-BDktlyzc.js +1 -0
  150. package/cli/storybook-dist/assets/RBLight.stories-C5qpnM6J.js +1 -0
  151. package/cli/storybook-dist/assets/RBMenuTreeIcons.stories-DUCeQPKJ.js +3 -0
  152. package/cli/storybook-dist/assets/RBMenubar.stories-ClyM9v37.js +3 -0
  153. package/cli/storybook-dist/assets/RBMultiRangeInput.stories--xSn64ww.js +14 -0
  154. package/cli/storybook-dist/assets/RBPagination.stories-C_uTj83z.js +17 -0
  155. package/cli/storybook-dist/assets/RBPopover.stories-DWmb9Por.js +11 -0
  156. package/cli/storybook-dist/assets/RBProgramIcons.stories-B8ZjEtvw.js +3 -0
  157. package/cli/storybook-dist/assets/RBPrompt.stories-BFKfyYtl.js +20 -0
  158. package/cli/storybook-dist/assets/RBRadioBox.stories-DUz8a27t.js +1 -0
  159. package/cli/storybook-dist/assets/RBRadioButton.stories-DKF61xvC.js +11 -0
  160. package/cli/storybook-dist/assets/RBRangeDateInput.stories-GhMVDyMr.js +15 -0
  161. package/cli/storybook-dist/assets/RBResizable.stories-V0iisR-x.js +20 -0
  162. package/cli/storybook-dist/assets/RBSelectBox.stories-DhvooAcg.js +6 -0
  163. package/cli/storybook-dist/assets/RBSheet.stories-C93Hpmvn.js +39 -0
  164. package/cli/storybook-dist/assets/RBSideNumberInput.stories-Y547mUsB.js +5 -0
  165. package/cli/storybook-dist/assets/RBSlider.stories-BJZyHiLO.js +5 -0
  166. package/cli/storybook-dist/assets/RBSpinner.stories-6wkbu-bU.js +14 -0
  167. package/cli/storybook-dist/assets/RBSwitch.stories-T9InolEP.js +65 -0
  168. package/cli/storybook-dist/assets/RBTab.stories-CjGzZODx.js +1 -0
  169. package/cli/storybook-dist/assets/RBTable.stories-CaolKsVG.js +62 -0
  170. package/cli/storybook-dist/assets/RBTableRow.stories-D13urGfs.js +11 -0
  171. package/cli/storybook-dist/assets/RBTabs.stories-Cv2iIxvP.js +21 -0
  172. package/cli/storybook-dist/assets/RBTextArea.stories-CmrPeit2.js +5 -0
  173. package/cli/storybook-dist/assets/RBTextField.stories-ByW-EKCD.js +45 -0
  174. package/cli/storybook-dist/assets/RBTextInput.stories-DSPlr3uh.js +5 -0
  175. package/cli/storybook-dist/assets/RBToast.stories-DJNZ9tku.js +11 -0
  176. package/cli/storybook-dist/assets/RBToggle.stories-BDQW2WO1.js +12 -0
  177. package/cli/storybook-dist/assets/RBToggleGroup.stories-CjwH6YbI.js +17 -0
  178. package/cli/storybook-dist/assets/RBTooltip.stories-Cp1oL68L.js +9 -0
  179. package/cli/storybook-dist/assets/RainbowUiProvider-BYlbsa69.css +1 -0
  180. package/cli/storybook-dist/assets/RainbowUiProvider-B_piZBLb.js +31 -0
  181. package/cli/storybook-dist/assets/browserUtils-DeopUpDy.js +1 -0
  182. package/cli/storybook-dist/assets/chunk-XP5HYGXS-BHXC9YeQ.js +1 -0
  183. package/cli/storybook-dist/assets/client-DTf7SId2.js +1 -0
  184. package/cli/storybook-dist/assets/createConveyorBeltLayer-769P8deX.js +6257 -0
  185. package/cli/storybook-dist/assets/createConveyorBeltLayer-Ds5AOper.css +21 -0
  186. package/cli/storybook-dist/assets/entry-preview-CNdFC92L.js +2 -0
  187. package/cli/storybook-dist/assets/entry-preview-docs-b8bpVBXy.js +46 -0
  188. package/cli/storybook-dist/assets/iframe-CLUgOMp4.js +211 -0
  189. package/cli/storybook-dist/assets/index-B4FGfHer.js +1 -0
  190. package/cli/storybook-dist/assets/index-BRq5TIsn.js +24 -0
  191. package/cli/storybook-dist/assets/index-C1OzuK6-.js +240 -0
  192. package/cli/storybook-dist/assets/index-CT3U1fyk.js +1 -0
  193. package/cli/storybook-dist/assets/index-ChsGqxH_.js +9 -0
  194. package/cli/storybook-dist/assets/index-DKFBREX_.js +1 -0
  195. package/cli/storybook-dist/assets/index-DgH-xKnr.js +11 -0
  196. package/cli/storybook-dist/assets/index-Dmy2JGbm.js +1 -0
  197. package/cli/storybook-dist/assets/index-DrFu-skq.js +6 -0
  198. package/cli/storybook-dist/assets/index-mT46TdHs.js +575 -0
  199. package/cli/storybook-dist/assets/jsx-runtime-BTJTZTIL.js +9 -0
  200. package/cli/storybook-dist/assets/keymapTileIndex.worker-BsNYNbqs.js +1 -0
  201. package/cli/storybook-dist/assets/preview-B8lJiyuQ.js +34 -0
  202. package/cli/storybook-dist/assets/preview-BBWR9nbA.js +1 -0
  203. package/cli/storybook-dist/assets/preview-BWzBA1C2.js +396 -0
  204. package/cli/storybook-dist/assets/preview-CILRoSnB.js +1 -0
  205. package/cli/storybook-dist/assets/preview-CVgpLj3b.js +1 -0
  206. package/cli/storybook-dist/assets/preview-Com4scch.css +1 -0
  207. package/cli/storybook-dist/assets/preview-CvbIS5ZJ.js +1 -0
  208. package/cli/storybook-dist/assets/preview-CvycU0Br.js +2 -0
  209. package/cli/storybook-dist/assets/preview-CzhIqee1.js +3 -0
  210. package/cli/storybook-dist/assets/preview-DD_OYowb.js +1 -0
  211. package/cli/storybook-dist/assets/preview-DGUiP6tS.js +7 -0
  212. package/cli/storybook-dist/assets/preview-DHQbi4pV.js +1 -0
  213. package/cli/storybook-dist/assets/react-18-hB3smqWJ.js +1 -0
  214. package/cli/storybook-dist/assets/react-resizable-panels.browser-CvAJUcrm.js +72 -0
  215. package/cli/storybook-dist/assets/test-utils-BQudk2xt.js +9 -0
  216. package/cli/storybook-dist/favicon.svg +1 -0
  217. package/cli/storybook-dist/iframe.html +666 -0
  218. package/cli/storybook-dist/index.html +190 -0
  219. package/cli/storybook-dist/index.json +1 -0
  220. package/cli/storybook-dist/nunito-sans-bold-italic.woff2 +0 -0
  221. package/cli/storybook-dist/nunito-sans-bold.woff2 +0 -0
  222. package/cli/storybook-dist/nunito-sans-italic.woff2 +0 -0
  223. package/cli/storybook-dist/nunito-sans-regular.woff2 +0 -0
  224. package/cli/storybook-dist/project.json +1 -0
  225. package/cli/storybook-dist/sb-addons/chromatic-com-storybook-10/manager-bundle.js +331 -0
  226. package/cli/storybook-dist/sb-addons/chromatic-com-storybook-10/manager-bundle.js.LEGAL.txt +51 -0
  227. package/cli/storybook-dist/sb-addons/essentials-actions-3/manager-bundle.js +3 -0
  228. package/cli/storybook-dist/sb-addons/essentials-backgrounds-5/manager-bundle.js +12 -0
  229. package/cli/storybook-dist/sb-addons/essentials-controls-2/manager-bundle.js +405 -0
  230. package/cli/storybook-dist/sb-addons/essentials-docs-4/manager-bundle.js +245 -0
  231. package/cli/storybook-dist/sb-addons/essentials-measure-8/manager-bundle.js +3 -0
  232. package/cli/storybook-dist/sb-addons/essentials-outline-9/manager-bundle.js +3 -0
  233. package/cli/storybook-dist/sb-addons/essentials-toolbars-7/manager-bundle.js +3 -0
  234. package/cli/storybook-dist/sb-addons/essentials-viewport-6/manager-bundle.js +3 -0
  235. package/cli/storybook-dist/sb-addons/links-1/manager-bundle.js +3 -0
  236. package/cli/storybook-dist/sb-addons/storybook-13/manager-bundle.js +3 -0
  237. package/cli/storybook-dist/sb-addons/storybook-core-core-server-presets-0/common-manager-bundle.js +3 -0
  238. package/cli/storybook-dist/sb-addons/storybook-experimental-addon-test-12/manager-bundle.js +223 -0
  239. package/cli/storybook-dist/sb-addons/themes-11/manager-bundle.js +3 -0
  240. package/cli/storybook-dist/sb-common-assets/favicon.svg +1 -0
  241. package/cli/storybook-dist/sb-common-assets/nunito-sans-bold-italic.woff2 +0 -0
  242. package/cli/storybook-dist/sb-common-assets/nunito-sans-bold.woff2 +0 -0
  243. package/cli/storybook-dist/sb-common-assets/nunito-sans-italic.woff2 +0 -0
  244. package/cli/storybook-dist/sb-common-assets/nunito-sans-regular.woff2 +0 -0
  245. package/cli/storybook-dist/sb-manager/globals-module-info.js +1052 -0
  246. package/cli/storybook-dist/sb-manager/globals-runtime.js +41775 -0
  247. package/cli/storybook-dist/sb-manager/globals.js +48 -0
  248. package/cli/storybook-dist/sb-manager/runtime.js +12048 -0
  249. package/cli/templates/common/.mcp.json +8 -0
  250. package/cli/templates/common/README.md +644 -81
  251. package/cli/templates/common/assets/icon.svg +44 -2
  252. package/cli/templates/common/manifest.json +13 -13
  253. package/cli/templates/common/package.json +11 -4
  254. package/cli/templates/common/py/main.py +98 -0
  255. package/cli/templates/common/requirements.txt +4 -3
  256. package/cli/templates/common/tsconfig.json +1 -1
  257. package/cli/templates/common/ui/content.tsx +216 -0
  258. package/cli/templates/common/ui/style.css +6 -0
  259. package/cli/templates/common/vite.config.ts +6 -25
  260. package/cli/templates/cpp/cpp/CMakeLists.txt +14 -0
  261. package/cli/templates/cpp/cpp/main.cpp +26 -0
  262. package/cli/templates/ros2/ros2_ws/src/__PLUGIN_SLUG__/__PLUGIN_SLUG__/node.py +1 -1
  263. package/cli/templates/ros2-cpp/ros2_ws/src/__PLUGIN_SLUG__/CMakeLists.txt +17 -0
  264. package/cli/templates/ros2-cpp/ros2_ws/src/__PLUGIN_SLUG__/package.xml +11 -0
  265. package/cli/templates/ros2-cpp/ros2_ws/src/__PLUGIN_SLUG__/src/node.cpp +22 -0
  266. package/cli/vite.d.mts +25 -0
  267. package/cli/vite.mjs +292 -0
  268. package/package.json +32 -5
  269. package/cli/src/pack.mjs +0 -61
  270. package/cli/src/preview.mjs +0 -91
  271. package/cli/templates/common/main.py +0 -114
  272. package/cli/templates/common/src/content.tsx +0 -33
@@ -0,0 +1,617 @@
1
+ // muscat-pk mcp — an MCP (Model Context Protocol) server exposing the Muscat
2
+ // plugin UI/SDK surface to an AI coding agent (Claude Code, Codex, ...) so it
3
+ // looks things up instead of guessing. Tools:
4
+ //
5
+ // Frontend UI (@rainbow-robotics/plugin-ui/react, via dist/react.d.ts):
6
+ // - list_components every exported component/hook/type.
7
+ // - get_component_props the real TypeScript type for one export.
8
+ // - get_component_example a real Storybook story (working code, not a guess).
9
+ //
10
+ // Design system (rb-styles rb-token.css):
11
+ // - list_design_tokens Tailwind classes to use (bg-bg-*, text-fg-*, typo-*, ...).
12
+ // - search_design_tokens find a token by name or hex value.
13
+ //
14
+ // Plugin SDK docs + Python backend:
15
+ // - search_rb_sdk search the plugin-author README (useRb(), rb.*, manifest, runtimes).
16
+ // - list_rb_sdk classes/functions of the installed rainbow.rb_sdk.
17
+ // - get_rb_sdk_api signature + docstring for an rb_sdk class/function.
18
+ //
19
+ // Add to an MCP client config, e.g. Claude Code's .mcp.json:
20
+ // { "mcpServers": { "muscat": { "command": "muscat-pk", "args": ["mcp"] } } }
21
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
22
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
23
+ import { z } from "zod";
24
+ import ts from "typescript";
25
+ import { existsSync, readdirSync, readFileSync, statSync } from "node:fs";
26
+ import { spawnSync } from "node:child_process";
27
+ import { join, resolve } from "node:path";
28
+ import { fileURLToPath } from "node:url";
29
+ import { kitRoot, kitVersion, findPluginRoot, venvPython } from "./util.mjs";
30
+ import { SHIPPED_STORIES_SRC, SHIPPED_DESIGN_TOKENS } from "./storybook.mjs";
31
+
32
+ const TEMPLATE_README = join(kitRoot, "cli/templates/common/README.md");
33
+ // Design tokens: prefer the shipped copy, fall back to the monorepo source.
34
+ const DESIGN_TOKENS_CSS = existsSync(SHIPPED_DESIGN_TOKENS)
35
+ ? SHIPPED_DESIGN_TOKENS
36
+ : resolve(kitRoot, "../..", "packages/rb-styles/css/output/rb-token.css");
37
+
38
+ /* -------------------------------------------------------------------------- */
39
+ /* react.d.ts introspection — component/hook list + prop types */
40
+ /* -------------------------------------------------------------------------- */
41
+
42
+ let typesCache = null;
43
+
44
+ // Parse plugin-ui/react's dist/react.d.ts. It's self-contained (rb-components
45
+ // types are inlined at build — see plugin-ui/build-dist.mjs), so this one file
46
+ // is enough even in an external install.
47
+ async function loadReactTypes() {
48
+ if (typesCache) return typesCache;
49
+
50
+ const entryUrl = await import.meta.resolve("@rainbow-robotics/plugin-ui/react");
51
+ const dtsPath = fileURLToPath(entryUrl).replace(/\.js$/, ".d.ts");
52
+ if (!existsSync(dtsPath)) {
53
+ throw new Error(
54
+ `plugin-ui type declarations not found at ${dtsPath} — reinstall or rebuild @rainbow-robotics/plugin-ui.`,
55
+ );
56
+ }
57
+
58
+ const program = ts.createProgram([dtsPath], {
59
+ target: ts.ScriptTarget.ES2022,
60
+ module: ts.ModuleKind.ESNext,
61
+ skipLibCheck: true,
62
+ });
63
+ const sourceFile = program.getSourceFile(dtsPath);
64
+ const checker = program.getTypeChecker();
65
+ const moduleSymbol = sourceFile && checker.getSymbolAtLocation(sourceFile);
66
+ const exports = moduleSymbol ? checker.getExportsOfModule(moduleSymbol) : [];
67
+
68
+ typesCache = { checker, sourceFile, exports };
69
+ return typesCache;
70
+ }
71
+
72
+ // The barrel's trailing `export { A, B, ... }` produces Alias symbols whose
73
+ // OWN flags don't reflect value-vs-type — resolve to the real declaration first.
74
+ function resolveExport(checker, symbol) {
75
+ return symbol.flags & ts.SymbolFlags.Alias
76
+ ? checker.getAliasedSymbol(symbol)
77
+ : symbol;
78
+ }
79
+
80
+ function exportKind(checker, symbol) {
81
+ const resolved = resolveExport(checker, symbol);
82
+ return resolved.flags & ts.SymbolFlags.Value ? "value" : "type";
83
+ }
84
+
85
+ /* -------------------------------------------------------------------------- */
86
+ /* Storybook story source lookup */
87
+ /* -------------------------------------------------------------------------- */
88
+
89
+ // Case-insensitive recursive search for `${name}.stories.tsx` under the
90
+ // staged story sources (see storybook.mjs's buildStorybook()).
91
+ function findStorySource(name) {
92
+ if (!existsSync(SHIPPED_STORIES_SRC)) return null;
93
+ const target = `${name.toLowerCase()}.stories.tsx`;
94
+ const stack = [SHIPPED_STORIES_SRC];
95
+ while (stack.length) {
96
+ const dir = stack.pop();
97
+ for (const entry of readdirSync(dir)) {
98
+ const full = join(dir, entry);
99
+ if (statSync(full).isDirectory()) {
100
+ stack.push(full);
101
+ continue;
102
+ }
103
+ if (entry.toLowerCase() === target) return readFileSync(full, "utf8");
104
+ }
105
+ }
106
+ return null;
107
+ }
108
+
109
+ /* -------------------------------------------------------------------------- */
110
+ /* README search */
111
+ /* -------------------------------------------------------------------------- */
112
+
113
+ // Split the README on headings and keyword-score each section.
114
+ function searchReadme(query) {
115
+ if (!existsSync(TEMPLATE_README)) return [];
116
+ const text = readFileSync(TEMPLATE_README, "utf8");
117
+ const sections = text.split(/\n(?=#{1,4} )/);
118
+ const terms = query.toLowerCase().split(/\s+/).filter(Boolean);
119
+
120
+ return sections
121
+ .map((section) => {
122
+ const lower = section.toLowerCase();
123
+ const score = terms.reduce((n, term) => n + (lower.includes(term) ? 1 : 0), 0);
124
+ return { section: section.trim(), score };
125
+ })
126
+ .filter((x) => x.score > 0)
127
+ .sort((a, b) => b.score - a.score)
128
+ .slice(0, 5)
129
+ .map((x) => x.section);
130
+ }
131
+
132
+ /* -------------------------------------------------------------------------- */
133
+ /* Design tokens — parsed from rb-styles' generated rb-token.css */
134
+ /* -------------------------------------------------------------------------- */
135
+
136
+ // A color var `--color-<name>` becomes Tailwind utilities `bg-<name>`,
137
+ // `text-<name>`, `border-<name>`, `fill-<name>`. The design system's naming
138
+ // already encodes intent (bg-/fg-/border-/fill-), so we surface the idiomatic
139
+ // class per group.
140
+ const COLOR_CLASS_HINT = {
141
+ bg: (n) => `bg-${n}`, // --color-bg-default → bg-bg-default
142
+ fg: (n) => `text-${n}`, // --color-fg-subtle → text-fg-subtle
143
+ border: (n) => `border-${n}`,
144
+ fill: (n) => `fill-${n}`,
145
+ };
146
+
147
+ let tokensCache = null;
148
+
149
+ function loadDesignTokens() {
150
+ if (tokensCache) return tokensCache;
151
+ if (!existsSync(DESIGN_TOKENS_CSS)) {
152
+ throw new Error(
153
+ `design token CSS not found at ${DESIGN_TOKENS_CSS} — rebuild via "muscat-pk storybook --rebuild" (monorepo) or reinstall.`,
154
+ );
155
+ }
156
+ const css = readFileSync(DESIGN_TOKENS_CSS, "utf8");
157
+
158
+ // @theme { --name: value; ... } → { group, name, value, class? }
159
+ const vars = [];
160
+ for (const [, rawName, value] of css.matchAll(
161
+ /^\s*(--[a-z0-9-]+)\s*:\s*([^;]+);/gim,
162
+ )) {
163
+ const name = rawName.replace(/^--/, "");
164
+ const m = name.match(/^color-(bg|fg|border|fill)-(.+)$/);
165
+ const token = { name, value: value.trim() };
166
+ if (m) {
167
+ token.group = `color-${m[1]}`;
168
+ token.class = COLOR_CLASS_HINT[m[1]](`${m[1]}-${m[2]}`);
169
+ } else {
170
+ token.group = name.split("-").slice(0, 2).join("-");
171
+ }
172
+ vars.push(token);
173
+ }
174
+
175
+ // @utility typo-… → composite typography classes used directly in className.
176
+ const typo = [
177
+ ...new Set(
178
+ [...css.matchAll(/@utility\s+(typo-[a-z0-9-]+)\s*\{/g)].map((m) => m[1]),
179
+ ),
180
+ ].sort();
181
+
182
+ tokensCache = { vars, typo };
183
+ return tokensCache;
184
+ }
185
+
186
+ /* -------------------------------------------------------------------------- */
187
+ /* rainbow-rb-sdk (Python) introspection */
188
+ /* -------------------------------------------------------------------------- */
189
+
190
+ function pythonCmd() {
191
+ // Prefer the current plugin's own .venv — that's where `muscat-pk new` /
192
+ // ensureIdeVenv() installs rainbow-rb-sdk from requirements.txt. The AI
193
+ // agent's cwd is usually the plugin dir mcp was launched from.
194
+ try {
195
+ const py = venvPython(resolve(findPluginRoot(), ".venv"));
196
+ if (existsSync(py)) return py;
197
+ } catch {
198
+ /* not inside a plugin project — fall through to PATH lookup */
199
+ }
200
+ for (const c of ["python3", "python"]) {
201
+ const r = spawnSync(c, ["--version"], { encoding: "utf8" });
202
+ if (r.status === 0) return c;
203
+ }
204
+ return null;
205
+ }
206
+
207
+ // Run an introspection script against the installed rainbow.rb_sdk (a plugin's
208
+ // backend dependency). Returns a clear hint if it isn't importable.
209
+ function introspectRbSdk(script) {
210
+ const py = pythonCmd();
211
+ if (!py) {
212
+ return { error: "Python not found on PATH. Install Python 3 to use rb-sdk introspection." };
213
+ }
214
+ const probe = `
215
+ import json, importlib
216
+ try:
217
+ importlib.import_module("rainbow.rb_sdk")
218
+ except Exception as e:
219
+ print(json.dumps({"__notinstalled__": str(e)})); raise SystemExit(0)
220
+ ${script}
221
+ `;
222
+ const r = spawnSync(py, ["-c", probe], { encoding: "utf8", maxBuffer: 8 << 20 });
223
+ if (r.status !== 0) {
224
+ return { error: `python introspection failed: ${(r.stderr || "").trim().slice(0, 500)}` };
225
+ }
226
+ // Importing rainbow.rb_sdk has side effects that print to stdout (e.g. the
227
+ // Zenoh client logs its connection endpoints), ahead of our own final
228
+ // print(json.dumps(...)) — so parse the last line, not the whole output.
229
+ const lines = r.stdout.trim().split("\n");
230
+ let data;
231
+ try {
232
+ data = JSON.parse(lines[lines.length - 1]);
233
+ } catch {
234
+ return { error: `unexpected introspection output: ${r.stdout.slice(0, 300)}` };
235
+ }
236
+ if (data && data.__notinstalled__) {
237
+ return {
238
+ error:
239
+ "rainbow-rb-sdk is not installed in this environment. Install it with `pip install rainbow-rb-sdk` " +
240
+ "(it's already in a plugin's requirements.txt), then retry.",
241
+ };
242
+ }
243
+ return { data };
244
+ }
245
+
246
+ /* -------------------------------------------------------------------------- */
247
+ /* server */
248
+ /* -------------------------------------------------------------------------- */
249
+
250
+ export async function runMcp() {
251
+ const server = new McpServer({ name: "muscat-plugin-kit", version: kitVersion() });
252
+
253
+ server.registerTool(
254
+ "list_components",
255
+ {
256
+ title: "List Muscat plugin UI components",
257
+ description:
258
+ "List every component, hook, and type exported from @rainbow-robotics/plugin-ui/react — " +
259
+ "the full UI surface available to Muscat plugin authors. Call this first before guessing a " +
260
+ "component name.",
261
+ inputSchema: {},
262
+ },
263
+ async () => {
264
+ const { checker, exports } = await loadReactTypes();
265
+ const lines = exports
266
+ .map((sym) => `${sym.getName()} (${exportKind(checker, sym)})`)
267
+ .sort();
268
+ return { content: [{ type: "text", text: lines.join("\n") }] };
269
+ },
270
+ );
271
+
272
+ server.registerTool(
273
+ "get_component_props",
274
+ {
275
+ title: "Get a component or hook's real type signature",
276
+ description:
277
+ "Get the full TypeScript type for a named export of @rainbow-robotics/plugin-ui/react " +
278
+ "(e.g. RBSlider, RBLabelButton, useRb, useRbFormData). Use list_components to find valid names.",
279
+ inputSchema: { name: z.string().describe('Exported name, e.g. "RBSlider"') },
280
+ },
281
+ async ({ name }) => {
282
+ const { checker, sourceFile, exports } = await loadReactTypes();
283
+ const symbol = exports.find((sym) => sym.getName() === name);
284
+ if (!symbol) {
285
+ return {
286
+ isError: true,
287
+ content: [
288
+ {
289
+ type: "text",
290
+ text: `No export named "${name}" in @rainbow-robotics/plugin-ui/react. Call list_components for valid names.`,
291
+ },
292
+ ],
293
+ };
294
+ }
295
+ const resolved = resolveExport(checker, symbol);
296
+ const declaration = resolved.valueDeclaration ?? resolved.declarations?.[0] ?? sourceFile;
297
+ const type = checker.getTypeOfSymbolAtLocation(resolved, declaration);
298
+ const text = checker.typeToString(
299
+ type,
300
+ undefined,
301
+ ts.TypeFormatFlags.NoTruncation | ts.TypeFormatFlags.MultilineObjectLiterals,
302
+ );
303
+ return { content: [{ type: "text", text }] };
304
+ },
305
+ );
306
+
307
+ server.registerTool(
308
+ "get_component_example",
309
+ {
310
+ title: "Get a real Storybook usage example",
311
+ description:
312
+ "Get the real Storybook story source for a component (e.g. RBSlider) — actual working " +
313
+ "props, imports, and layout, not a guessed shape. Prefer this over get_component_props when " +
314
+ "you just need to know how to use a component, not its full type.",
315
+ // `component` accepted as an alias — agents often guess it over `name`.
316
+ inputSchema: {
317
+ name: z.string().optional().describe('Component name, e.g. "RBSlider"'),
318
+ component: z.string().optional().describe("Alias for `name`."),
319
+ },
320
+ },
321
+ async ({ name, component }) => {
322
+ const target = name ?? component;
323
+ if (!target) {
324
+ return {
325
+ isError: true,
326
+ content: [{ type: "text", text: 'Missing required argument: "name" (component name, e.g. "RBSlider").' }],
327
+ };
328
+ }
329
+ const source = findStorySource(target);
330
+ if (!source) {
331
+ return {
332
+ content: [
333
+ {
334
+ type: "text",
335
+ text: `No Storybook example found for "${target}". Run "muscat-pk storybook" to browse all components live, or use get_component_props for its type.`,
336
+ },
337
+ ],
338
+ };
339
+ }
340
+ return { content: [{ type: "text", text: source }] };
341
+ },
342
+ );
343
+
344
+ server.registerTool(
345
+ "search_rb_sdk",
346
+ {
347
+ title: "Search the Muscat plugin-author docs",
348
+ description:
349
+ "Search the Muscat plugin-author README for how to use useRb(), rb.pub/sub/action/serve, " +
350
+ "rb.toast/alert/confirm/prompt, useRbFormData/useRbSave (save/restore form data through the " +
351
+ "host), manifest.json, contribution points, and backend runtimes (Python/C++/ROS2). IMPORTANT: " +
352
+ "the backend pattern depends on the contribution point — search 'which backend pattern' before " +
353
+ "writing py/main.py. Only a program.panel command uses PluginProgramContext; a toolbar/move.panel " +
354
+ "plugin controls the robot with the SDK (RBManipulateSDK/RBAmrSDK) directly.",
355
+ inputSchema: {
356
+ query: z.string().describe('Keywords, e.g. "save form data" or "rb.action"'),
357
+ },
358
+ },
359
+ async ({ query }) => {
360
+ const sections = searchReadme(query);
361
+ if (sections.length === 0) {
362
+ return { content: [{ type: "text", text: `No matching section found for "${query}".` }] };
363
+ }
364
+ return { content: [{ type: "text", text: sections.join("\n\n---\n\n") }] };
365
+ },
366
+ );
367
+
368
+ /* --- design tokens --- */
369
+
370
+ server.registerTool(
371
+ "list_design_tokens",
372
+ {
373
+ title: "List Muscat design tokens (Tailwind classes)",
374
+ description:
375
+ "List the design system's tokens as the Tailwind classes to use in a plugin's className: " +
376
+ "semantic colors (bg-bg-*, text-fg-*, border-border-*, fill-fill-*), typography (typo-*), " +
377
+ "shadows, radius, spacing. Use these instead of raw hex/px so the plugin matches the host theme " +
378
+ "(and light/dark). Optionally filter by category.",
379
+ inputSchema: {
380
+ category: z
381
+ .enum(["bg", "fg", "border", "fill", "typography", "shadow", "radius", "spacing", "all"])
382
+ .optional()
383
+ .describe('Filter, e.g. "bg", "fg", "typography". Omit for a grouped overview.'),
384
+ },
385
+ },
386
+ async ({ category }) => {
387
+ const { vars, typo } = loadDesignTokens();
388
+ const out = [];
389
+
390
+ const colorGroups = { bg: [], fg: [], border: [], fill: [] };
391
+ const other = { shadow: [], radius: [], spacing: [] };
392
+ for (const t of vars) {
393
+ const m = t.group?.match(/^color-(bg|fg|border|fill)$/);
394
+ if (m && t.class) colorGroups[m[1]].push(`${t.class} (${t.value})`);
395
+ else if (t.name.startsWith("shadow-")) other.shadow.push(`shadow-${t.name.slice(7)}`);
396
+ else if (t.name.startsWith("radius-")) other.radius.push(`rounded-${t.name.slice(7)}`);
397
+ else if (t.name.startsWith("spacing-")) other.spacing.push(t.name);
398
+ }
399
+
400
+ const want = (c) => !category || category === "all" || category === c;
401
+ const push = (title, items) => {
402
+ if (items.length) out.push(`## ${title}\n${[...new Set(items)].sort().join("\n")}`);
403
+ };
404
+ if (want("bg")) push("Background — bg-bg-*", colorGroups.bg);
405
+ if (want("fg")) push("Text/foreground — text-fg-*", colorGroups.fg);
406
+ if (want("border")) push("Border — border-border-*", colorGroups.border);
407
+ if (want("fill")) push("SVG fill — fill-fill-*", colorGroups.fill);
408
+ if (want("typography")) push("Typography — typo-* (use directly)", typo);
409
+ if (want("shadow")) push("Shadow", other.shadow);
410
+ if (want("radius")) push("Radius", other.radius);
411
+ if (want("spacing")) push("Spacing scale (p-/m-/gap-/w-/h-)", other.spacing);
412
+
413
+ return {
414
+ content: [
415
+ {
416
+ type: "text",
417
+ text: out.join("\n\n") || `No tokens for category "${category}".`,
418
+ },
419
+ ],
420
+ };
421
+ },
422
+ );
423
+
424
+ server.registerTool(
425
+ "search_design_tokens",
426
+ {
427
+ title: "Search design tokens by name or value",
428
+ description:
429
+ "Find a design token by keyword — e.g. 'danger' (error colors), 'elevated', 'brand', or a hex " +
430
+ "like '#fb2c36'. Returns the matching Tailwind class + value.",
431
+ inputSchema: { query: z.string().describe('e.g. "danger", "elevated", "#fb2c36"') },
432
+ },
433
+ async ({ query }) => {
434
+ const { vars, typo } = loadDesignTokens();
435
+ const q = query.toLowerCase();
436
+ const hits = vars
437
+ .filter((t) => t.name.toLowerCase().includes(q) || t.value.toLowerCase().includes(q))
438
+ .map((t) => `${t.class ?? t.name} (${t.value})`);
439
+ const typoHits = typo.filter((c) => c.toLowerCase().includes(q));
440
+ const all = [...typoHits, ...hits];
441
+ return {
442
+ content: [
443
+ {
444
+ type: "text",
445
+ text: all.length ? [...new Set(all)].slice(0, 60).join("\n") : `No token matches "${query}".`,
446
+ },
447
+ ],
448
+ };
449
+ },
450
+ );
451
+
452
+ /* --- rainbow-rb-sdk (Python backend) --- */
453
+
454
+ server.registerTool(
455
+ "list_rb_sdk",
456
+ {
457
+ title: "List rainbow-rb-sdk (Python) classes and functions",
458
+ description:
459
+ "List the public classes and functions of the installed rainbow.rb_sdk Python package — the " +
460
+ "plugin BACKEND SDK (RBPluginCall, RBManipulateSDK, RBAmrSDK, PluginProgramContext, ...). Call " +
461
+ "before writing py/main.py. Requires rainbow-rb-sdk to be pip-installed.",
462
+ inputSchema: {},
463
+ },
464
+ async () => {
465
+ const { data, error } = introspectRbSdk(`
466
+ import inspect, json
467
+ mod = importlib.import_module("rainbow.rb_sdk")
468
+ out = []
469
+ for name in sorted(getattr(mod, "__all__", None) or dir(mod)):
470
+ if name.startswith("_"): continue
471
+ obj = getattr(mod, name)
472
+ if inspect.isclass(obj): out.append(name + " (class)")
473
+ elif inspect.isfunction(obj) or inspect.isbuiltin(obj): out.append(name + " (function)")
474
+ print(json.dumps(out))
475
+ `);
476
+ if (error) return { isError: true, content: [{ type: "text", text: error }] };
477
+ return { content: [{ type: "text", text: data.join("\n") }] };
478
+ },
479
+ );
480
+
481
+ server.registerTool(
482
+ "get_rb_sdk_api",
483
+ {
484
+ title: "Get a rainbow-rb-sdk class/function signature + docs",
485
+ description:
486
+ "Get the signature(s) and docstring for a rainbow.rb_sdk class or function (e.g. " +
487
+ "'PluginProgramContext', 'RBManipulateSDK'). For a class, lists its public methods with " +
488
+ "signatures. To drill into ONE method of a class (e.g. RBManipulateSDK.call_move_j), pass " +
489
+ "`method` alongside `name` — do not put both in `name`. Requires rainbow-rb-sdk to be " +
490
+ "pip-installed.",
491
+ inputSchema: {
492
+ name: z.string().describe('Class or function name, e.g. "RBManipulateSDK"'),
493
+ method: z.string().optional().describe('Optional: a specific method on that class, e.g. "call_move_j"'),
494
+ },
495
+ },
496
+ async ({ name, method }) => {
497
+ // Tolerate a combined "ClassName method_name" in `name` (a common agent
498
+ // mistake) by splitting it ourselves instead of failing validation.
499
+ let className = name;
500
+ let methodName = method;
501
+ if (!methodName && /\s/.test(name.trim())) {
502
+ const parts = name.trim().split(/\s+/);
503
+ if (parts.length === 2) [className, methodName] = parts;
504
+ }
505
+
506
+ const { data, error } = introspectRbSdk(`
507
+ import inspect, json
508
+ mod = importlib.import_module("rainbow.rb_sdk")
509
+ name = ${JSON.stringify(className)}
510
+ method = ${methodName ? JSON.stringify(methodName) : "None"}
511
+ obj = getattr(mod, name, None)
512
+ if obj is None:
513
+ print(json.dumps({"__missing__": True})); raise SystemExit(0)
514
+ def sig(o):
515
+ try: return str(inspect.signature(o))
516
+ except Exception: return "(...)"
517
+
518
+ if method:
519
+ # Direct method on the class itself.
520
+ fn = getattr(obj, method, None) if inspect.isclass(obj) else None
521
+ # rb_sdk classes often group calls under a nested namespace set in
522
+ # __init__ (e.g. RBManipulateSDK().move.call_move_j) — that only exists on
523
+ # an INSTANCE, which we won't construct (side effects, needs a robot
524
+ # connection). Best-effort: search the class's own __init__ source text
525
+ # for self.<attr> = <NestedClass>(...) and check each nested class too.
526
+ owner = name
527
+ if fn is None and inspect.isclass(obj):
528
+ try:
529
+ src = inspect.getsource(obj.__init__)
530
+ except Exception:
531
+ src = ""
532
+ import re, sys as _sys
533
+ # The nested sub-SDK classes (e.g. RBManipulateMoveSDK) are imported in
534
+ # the module that DEFINES obj (rainbow.rb_sdk.manipulate), not in the
535
+ # rainbow.rb_sdk top-level namespace — resolve names against both.
536
+ _defmod = _sys.modules.get(getattr(obj, "__module__", ""))
537
+ for attr, nested_name in re.findall(r"self\\.(\\w+)\\s*=\\s*(\\w+)\\(", src):
538
+ nested = (
539
+ (getattr(_defmod, nested_name, None) if _defmod else None)
540
+ or mod.__dict__.get(nested_name)
541
+ or globals().get(nested_name)
542
+ )
543
+ cand = getattr(nested, method, None) if nested else None
544
+ if cand:
545
+ fn = cand
546
+ owner = f"{name}.{attr} ({nested_name})"
547
+ break
548
+ if fn is None:
549
+ print(json.dumps({"__missing__": True, "__method__": True})); raise SystemExit(0)
550
+ print(json.dumps({
551
+ "name": name, "kind": "method", "owner": owner,
552
+ "signature": method + sig(fn), "doc": inspect.getdoc(fn) or "",
553
+ }))
554
+ raise SystemExit(0)
555
+
556
+ res = {"name": name, "doc": inspect.getdoc(obj) or ""}
557
+ if inspect.isclass(obj):
558
+ res["kind"] = "class"
559
+ res["init"] = name + sig(obj.__init__ if "__init__" in dir(obj) else obj)
560
+ def _methods_of(cls, prefix=""):
561
+ out = []
562
+ for m, fn in inspect.getmembers(cls, predicate=inspect.isfunction):
563
+ if m.startswith("_"): continue
564
+ out.append({"name": prefix + m, "sig": prefix + m + sig(fn),
565
+ "doc": (inspect.getdoc(fn) or "").split("\\n")[0]})
566
+ return out
567
+ methods = _methods_of(obj)
568
+ # Most rb_sdk calls live on nested sub-SDKs assigned in __init__
569
+ # (e.g. self.move = RBManipulateMoveSDK() -> obj.move.call_move_j). List
570
+ # those too, name-prefixed, so the API is discoverable without an instance.
571
+ import re as _re, sys as _sys
572
+ _defmod = _sys.modules.get(getattr(obj, "__module__", ""))
573
+ try:
574
+ _src = inspect.getsource(obj.__init__)
575
+ except Exception:
576
+ _src = ""
577
+ for _attr, _nested_name in _re.findall(r"self\\.(\\w+)\\s*=\\s*(\\w+)\\(", _src):
578
+ _nested = (getattr(_defmod, _nested_name, None) if _defmod else None) or mod.__dict__.get(_nested_name)
579
+ if inspect.isclass(_nested):
580
+ methods.extend(_methods_of(_nested, prefix=_attr + "."))
581
+ res["methods"] = methods
582
+ else:
583
+ res["kind"] = "function"
584
+ res["signature"] = name + sig(obj)
585
+ print(json.dumps(res))
586
+ `);
587
+ if (error) return { isError: true, content: [{ type: "text", text: error }] };
588
+ if (data.__missing__) {
589
+ const text = data.__method__
590
+ ? `No method "${methodName}" found directly on "${className}" (nor in an obvious nested ` +
591
+ `namespace set in __init__). Call get_rb_sdk_api with just \`name: "${className}"\` to see ` +
592
+ `its full method list and constructor first.`
593
+ : `No "${className}" in rainbow.rb_sdk. Call list_rb_sdk for valid names.`;
594
+ return { isError: true, content: [{ type: "text", text }] };
595
+ }
596
+ if (data.kind === "method") {
597
+ const lines = [`# ${data.owner}.${data.signature.split("(")[0]}`, data.signature];
598
+ if (data.doc) lines.push("", data.doc);
599
+ return { content: [{ type: "text", text: lines.join("\n") }] };
600
+ }
601
+ const lines = [`# ${data.name} (${data.kind})`];
602
+ if (data.doc) lines.push(data.doc, "");
603
+ if (data.kind === "class") {
604
+ lines.push(`constructor: ${data.init}`, "", "methods:");
605
+ for (const m of data.methods) {
606
+ lines.push(` ${m.sig}${m.doc ? ` — ${m.doc}` : ""}`);
607
+ }
608
+ } else {
609
+ lines.push(data.signature);
610
+ }
611
+ return { content: [{ type: "text", text: lines.join("\n") }] };
612
+ },
613
+ );
614
+
615
+ const transport = new StdioServerTransport();
616
+ await server.connect(transport);
617
+ }