@rainbow-robotics/muscat-plugin-kit 0.1.2-dev.8 → 1.0.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.
- package/README.md +113 -49
- package/cli/README.md +191 -5
- package/cli/bin/create-muscat-plugin.mjs +1 -1
- package/cli/bin/muscat-pk.mjs +25 -14
- package/cli/bundle-templates.mjs +28 -0
- package/cli/docker/Dockerfile.bridge +17 -0
- package/cli/docker/Dockerfile.cpp +22 -0
- package/cli/docker/Dockerfile.dev +1 -0
- package/cli/docker/Dockerfile.python +20 -0
- package/cli/docker/bridge-package.json +8 -0
- package/cli/prepack.mjs +10 -0
- package/cli/src/__pycache__/host_agent.cpython-37.pyc +0 -0
- package/cli/src/bridge.mjs +95 -0
- package/cli/src/build.mjs +345 -85
- package/cli/src/check-package.mjs +8 -23
- package/cli/src/cpp.mjs +61 -0
- package/cli/src/dev.mjs +156 -4
- package/cli/src/devBack.mjs +505 -57
- package/cli/src/devUi.mjs +167 -22
- package/cli/src/esbuild.mjs +27 -10
- package/cli/src/host_agent.py +162 -0
- package/cli/src/manifest.mjs +208 -0
- package/cli/src/mcp.mjs +617 -0
- package/cli/src/new.mjs +170 -67
- package/cli/src/pluginDevServer.mjs +112 -0
- package/cli/src/ports.mjs +160 -0
- package/cli/src/python.mjs +109 -0
- package/cli/src/ros2.mjs +43 -18
- package/cli/src/sdk.mjs +11 -9
- package/cli/src/socketBridge.mjs +133 -0
- package/cli/src/storybook.mjs +168 -0
- package/cli/src/type.mjs +52 -29
- package/cli/src/uninstall.mjs +98 -0
- package/cli/src/update.mjs +259 -30
- package/cli/src/util.mjs +123 -9
- package/cli/src/zenohDev.mjs +75 -0
- package/cli/storybook-dist/_design-tokens.css +4957 -0
- package/cli/storybook-dist/_stories-src/NxAvatar.stories.tsx +27 -0
- package/cli/storybook-dist/_stories-src/NxPagination.stories.tsx +28 -0
- package/cli/storybook-dist/_stories-src/RBAccordion/RBAccordion.stories.tsx +46 -0
- package/cli/storybook-dist/_stories-src/RBAccordion/RBAccordionGroup.stories.tsx +73 -0
- package/cli/storybook-dist/_stories-src/RBBadge/RBBadge.stories.tsx +93 -0
- package/cli/storybook-dist/_stories-src/RBBattery/RBBattery.stories.tsx +74 -0
- package/cli/storybook-dist/_stories-src/RBButton/RBCheckIconButton.stories.tsx +28 -0
- package/cli/storybook-dist/_stories-src/RBButton/RBCheckLabelButton.stories.tsx +84 -0
- package/cli/storybook-dist/_stories-src/RBButton/RBIconButton.stories.tsx +57 -0
- package/cli/storybook-dist/_stories-src/RBButton/RBInlineLabelButton.stories.tsx +41 -0
- package/cli/storybook-dist/_stories-src/RBButton/RBLabelButton.stories.tsx +60 -0
- package/cli/storybook-dist/_stories-src/RBDatePicker/RBDateInput.stories.tsx +44 -0
- package/cli/storybook-dist/_stories-src/RBDatePicker/RBRangeDateInput.stories.tsx +44 -0
- package/cli/storybook-dist/_stories-src/RBDialog/RBAlert.stories.tsx +51 -0
- package/cli/storybook-dist/_stories-src/RBDialog/RBConfirm.stories.tsx +55 -0
- package/cli/storybook-dist/_stories-src/RBDialog/RBPrompt.stories.tsx +52 -0
- package/cli/storybook-dist/_stories-src/RBDivider/RBDivider.stories.tsx +93 -0
- package/cli/storybook-dist/_stories-src/RBEmptyView/RBEmptyView.stories.tsx +49 -0
- package/cli/storybook-dist/_stories-src/RBIcons/RBColorIcons.stories.tsx +108 -0
- package/cli/storybook-dist/_stories-src/RBIcons/RBIcons.stories.tsx +106 -0
- package/cli/storybook-dist/_stories-src/RBIcons/RBMenuTreeIcons.stories.tsx +108 -0
- package/cli/storybook-dist/_stories-src/RBIcons/RBProgramIcons.stories.tsx +116 -0
- package/cli/storybook-dist/_stories-src/RBInput/RBCheckBox.stories.tsx +89 -0
- package/cli/storybook-dist/_stories-src/RBInput/RBMultiRangeInput.stories.tsx +64 -0
- package/cli/storybook-dist/_stories-src/RBInput/RBRadioBox.stories.tsx +65 -0
- package/cli/storybook-dist/_stories-src/RBInput/RBRadioButton.stories.tsx +68 -0
- package/cli/storybook-dist/_stories-src/RBInput/RBSelectBox.stories.tsx +119 -0
- package/cli/storybook-dist/_stories-src/RBInput/RBSideNumberInput.stories.tsx +90 -0
- package/cli/storybook-dist/_stories-src/RBInput/RBText/RBTextArea.stories.tsx +45 -0
- package/cli/storybook-dist/_stories-src/RBInput/RBText/RBTextInput.stories.tsx +50 -0
- package/cli/storybook-dist/_stories-src/RBInput/RBTextField.stories.tsx +102 -0
- package/cli/storybook-dist/_stories-src/RBJoyStick/RBJoyStick.stories.tsx +31 -0
- package/cli/storybook-dist/_stories-src/RBLight/RBLight.stories.tsx +36 -0
- package/cli/storybook-dist/_stories-src/RBPagination/RBPagination.stories.tsx +49 -0
- package/cli/storybook-dist/_stories-src/RBShadcn/RBCard/RBCard.stories.tsx +89 -0
- package/cli/storybook-dist/_stories-src/RBShadcn/RBCommand/RBCommand.stories.tsx +116 -0
- package/cli/storybook-dist/_stories-src/RBShadcn/RBDialog/RBDialog.stories.tsx +74 -0
- package/cli/storybook-dist/_stories-src/RBShadcn/RBDrawer/RBDrawer.stories.tsx +99 -0
- package/cli/storybook-dist/_stories-src/RBShadcn/RBDropdownMenu/RBDropdownMenu.stories.tsx +123 -0
- package/cli/storybook-dist/_stories-src/RBShadcn/RBMenubar/RBMenubar.stories.tsx +135 -0
- package/cli/storybook-dist/_stories-src/RBShadcn/RBPopover/RBPopover.stories.tsx +69 -0
- package/cli/storybook-dist/_stories-src/RBShadcn/RBResizable/RBResizable.stories.tsx +49 -0
- package/cli/storybook-dist/_stories-src/RBShadcn/RBSheet/RBSheet.stories.tsx +91 -0
- package/cli/storybook-dist/_stories-src/RBShadcn/RBSlider/RBSlider.stories.tsx +38 -0
- package/cli/storybook-dist/_stories-src/RBShadcn/RBSwitch/RBSwitch.stories.tsx +112 -0
- package/cli/storybook-dist/_stories-src/RBShadcn/RBTabs/RBTabs.stories.tsx +75 -0
- package/cli/storybook-dist/_stories-src/RBShadcn/RBToggle/RBToggle.stories.tsx +51 -0
- package/cli/storybook-dist/_stories-src/RBShadcn/RBToggleGroup/RBToggleGroup.stories.tsx +84 -0
- package/cli/storybook-dist/_stories-src/RBTab/RBChipTab.stories.tsx +102 -0
- package/cli/storybook-dist/_stories-src/RBTab/RBChipsBoxTab.stories.tsx +78 -0
- package/cli/storybook-dist/_stories-src/RBTab/RBTab.stories.tsx +57 -0
- package/cli/storybook-dist/_stories-src/RBTable/RBTable.stories.tsx +177 -0
- package/cli/storybook-dist/_stories-src/RBTable/RBTableRow.stories.tsx +64 -0
- package/cli/storybook-dist/_stories-src/RBToast/RBToast.stories.tsx +117 -0
- package/cli/storybook-dist/_stories-src/RBTooltip/RBTooltip.stories.tsx +50 -0
- package/cli/storybook-dist/_stories-src/loading/RBSpinner.stories.tsx +30 -0
- package/cli/storybook-dist/_stories-src/nx-button/NxButton.stories.tsx +54 -0
- package/cli/storybook-dist/_stories-src/nx-button/NxPointerHoldButton.stories.tsx +57 -0
- package/cli/storybook-dist/_stories-src/nx-icons/NxIcons.stories.tsx +48 -0
- package/cli/storybook-dist/_stories-src/nx-inputs/NxNumberInput.stories.tsx +103 -0
- package/cli/storybook-dist/_stories-src/nx-inputs/NxRangeInput.stories.tsx +27 -0
- package/cli/storybook-dist/_stories-src/nx-inputs/NxSelectBox.stories.tsx +67 -0
- package/cli/storybook-dist/_stories-src/nx-inputs/NxSlideRange.stories.tsx +45 -0
- package/cli/storybook-dist/_stories-src/nx-inputs/NxSwitch.stories.tsx +27 -0
- package/cli/storybook-dist/_stories-src/nx-inputs/NxTextArea.stories.tsx +48 -0
- package/cli/storybook-dist/_stories-src/nx-inputs/NxTextInput.stories.tsx +46 -0
- package/cli/storybook-dist/assets/Color-YHDXOIA2-ttZJDaKn.js +1 -0
- package/cli/storybook-dist/assets/Docs-B1jnlXHd.js +12 -0
- package/cli/storybook-dist/assets/Docs-B7dRsHh7.js +8 -0
- package/cli/storybook-dist/assets/Docs-C68t3mnn.js +20 -0
- package/cli/storybook-dist/assets/Docs-D7rPMMhK.js +7 -0
- package/cli/storybook-dist/assets/Docs-DM98U-ZG.js +7 -0
- package/cli/storybook-dist/assets/Docs-guWsANnn.js +8 -0
- package/cli/storybook-dist/assets/DocsRenderer-CFRXHY34-t12O9QfY.js +2 -0
- package/cli/storybook-dist/assets/NxAvatar.stories-ikdLTtys.js +13 -0
- package/cli/storybook-dist/assets/NxButton.stories-DL3S2KEV.js +20 -0
- package/cli/storybook-dist/assets/NxIcons.stories-Ca7qpAaO.js +3 -0
- package/cli/storybook-dist/assets/NxNumberInput.stories-D6NVMTos.js +26 -0
- package/cli/storybook-dist/assets/NxPagination.stories-BDKSlHiQ.js +11 -0
- package/cli/storybook-dist/assets/NxPointerHoldButton.stories-BI544zqB.js +14 -0
- package/cli/storybook-dist/assets/NxRangeInput.stories-BigBBkE7.js +17 -0
- package/cli/storybook-dist/assets/NxSelectBox.stories-Ci0IyUWd.js +17 -0
- package/cli/storybook-dist/assets/NxSlideRange.stories-sjnPAjFy.js +14 -0
- package/cli/storybook-dist/assets/NxSwitch.stories-CRxPDlJm.js +11 -0
- package/cli/storybook-dist/assets/NxTextArea.stories-Jh09n24O.js +11 -0
- package/cli/storybook-dist/assets/NxTextInput.stories-BeGCjxES.js +11 -0
- package/cli/storybook-dist/assets/PretendardVariable-CJuje-Rk.woff2 +0 -0
- package/cli/storybook-dist/assets/RBAccordion.stories-CnC95OwM.js +17 -0
- package/cli/storybook-dist/assets/RBAccordionGroup.stories-og-6ePox.js +33 -0
- package/cli/storybook-dist/assets/RBAlert.stories-BcE9-UOT.js +17 -0
- package/cli/storybook-dist/assets/RBBadge.stories-DYZMXb-e.js +1 -0
- package/cli/storybook-dist/assets/RBBattery.stories-B7YAUvlM.js +10 -0
- package/cli/storybook-dist/assets/RBCard.stories-DTL_7n6I.js +45 -0
- package/cli/storybook-dist/assets/RBCheckBox.stories-D9KC6hTg.js +1 -0
- package/cli/storybook-dist/assets/RBCheckIconButton.stories-BR8aIkOC.js +1 -0
- package/cli/storybook-dist/assets/RBCheckLabelButton.stories-C1ABYhEr.js +24 -0
- package/cli/storybook-dist/assets/RBChipTab.stories-Ceo_vnNi.js +21 -0
- package/cli/storybook-dist/assets/RBChipsBoxTab.stories-CB_bfK8M.js +1 -0
- package/cli/storybook-dist/assets/RBColorIcons.stories-DHZKezld.js +3 -0
- package/cli/storybook-dist/assets/RBCommand.stories-DjuCDn5h.js +73 -0
- package/cli/storybook-dist/assets/RBConfirm.stories-HMmUPkB1.js +20 -0
- package/cli/storybook-dist/assets/RBDateInput.stories-BRfpYtJ4.js +15 -0
- package/cli/storybook-dist/assets/RBDialog.stories-Ln23Gyhk.js +38 -0
- package/cli/storybook-dist/assets/RBDivider.stories-Bhc_D5Cm.js +1 -0
- package/cli/storybook-dist/assets/RBDrawer.stories-CEEhamr_.js +14 -0
- package/cli/storybook-dist/assets/RBDropdownMenu.stories-DBvwDCnf.js +86 -0
- package/cli/storybook-dist/assets/RBEmptyView.stories-BY5QtXVc.js +12 -0
- package/cli/storybook-dist/assets/RBIconButton.stories-DyMFWpIV.js +1 -0
- package/cli/storybook-dist/assets/RBIcons.stories-DisU8G0d.js +3 -0
- package/cli/storybook-dist/assets/RBInlineLabelButton.stories-Cx0KJqxD.js +1 -0
- package/cli/storybook-dist/assets/RBJoyStick.stories-D1THM1Du.js +11 -0
- package/cli/storybook-dist/assets/RBLabelButton.stories-BDktlyzc.js +1 -0
- package/cli/storybook-dist/assets/RBLight.stories-C5qpnM6J.js +1 -0
- package/cli/storybook-dist/assets/RBMenuTreeIcons.stories-DUCeQPKJ.js +3 -0
- package/cli/storybook-dist/assets/RBMenubar.stories-ClyM9v37.js +3 -0
- package/cli/storybook-dist/assets/RBMultiRangeInput.stories--xSn64ww.js +14 -0
- package/cli/storybook-dist/assets/RBPagination.stories-C_uTj83z.js +17 -0
- package/cli/storybook-dist/assets/RBPopover.stories-DWmb9Por.js +11 -0
- package/cli/storybook-dist/assets/RBProgramIcons.stories-B8ZjEtvw.js +3 -0
- package/cli/storybook-dist/assets/RBPrompt.stories-BFKfyYtl.js +20 -0
- package/cli/storybook-dist/assets/RBRadioBox.stories-DUz8a27t.js +1 -0
- package/cli/storybook-dist/assets/RBRadioButton.stories-DKF61xvC.js +11 -0
- package/cli/storybook-dist/assets/RBRangeDateInput.stories-GhMVDyMr.js +15 -0
- package/cli/storybook-dist/assets/RBResizable.stories-V0iisR-x.js +20 -0
- package/cli/storybook-dist/assets/RBSelectBox.stories-DhvooAcg.js +6 -0
- package/cli/storybook-dist/assets/RBSheet.stories-C93Hpmvn.js +39 -0
- package/cli/storybook-dist/assets/RBSideNumberInput.stories-Y547mUsB.js +5 -0
- package/cli/storybook-dist/assets/RBSlider.stories-BJZyHiLO.js +5 -0
- package/cli/storybook-dist/assets/RBSpinner.stories-6wkbu-bU.js +14 -0
- package/cli/storybook-dist/assets/RBSwitch.stories-T9InolEP.js +65 -0
- package/cli/storybook-dist/assets/RBTab.stories-CjGzZODx.js +1 -0
- package/cli/storybook-dist/assets/RBTable.stories-CaolKsVG.js +62 -0
- package/cli/storybook-dist/assets/RBTableRow.stories-D13urGfs.js +11 -0
- package/cli/storybook-dist/assets/RBTabs.stories-Cv2iIxvP.js +21 -0
- package/cli/storybook-dist/assets/RBTextArea.stories-CmrPeit2.js +5 -0
- package/cli/storybook-dist/assets/RBTextField.stories-ByW-EKCD.js +45 -0
- package/cli/storybook-dist/assets/RBTextInput.stories-DSPlr3uh.js +5 -0
- package/cli/storybook-dist/assets/RBToast.stories-DJNZ9tku.js +11 -0
- package/cli/storybook-dist/assets/RBToggle.stories-BDQW2WO1.js +12 -0
- package/cli/storybook-dist/assets/RBToggleGroup.stories-CjwH6YbI.js +17 -0
- package/cli/storybook-dist/assets/RBTooltip.stories-Cp1oL68L.js +9 -0
- package/cli/storybook-dist/assets/RainbowUiProvider-BYlbsa69.css +1 -0
- package/cli/storybook-dist/assets/RainbowUiProvider-B_piZBLb.js +31 -0
- package/cli/storybook-dist/assets/browserUtils-DeopUpDy.js +1 -0
- package/cli/storybook-dist/assets/chunk-XP5HYGXS-BHXC9YeQ.js +1 -0
- package/cli/storybook-dist/assets/client-DTf7SId2.js +1 -0
- package/cli/storybook-dist/assets/createConveyorBeltLayer-769P8deX.js +6257 -0
- package/cli/storybook-dist/assets/createConveyorBeltLayer-Ds5AOper.css +21 -0
- package/cli/storybook-dist/assets/entry-preview-CNdFC92L.js +2 -0
- package/cli/storybook-dist/assets/entry-preview-docs-b8bpVBXy.js +46 -0
- package/cli/storybook-dist/assets/iframe-CLUgOMp4.js +211 -0
- package/cli/storybook-dist/assets/index-B4FGfHer.js +1 -0
- package/cli/storybook-dist/assets/index-BRq5TIsn.js +24 -0
- package/cli/storybook-dist/assets/index-C1OzuK6-.js +240 -0
- package/cli/storybook-dist/assets/index-CT3U1fyk.js +1 -0
- package/cli/storybook-dist/assets/index-ChsGqxH_.js +9 -0
- package/cli/storybook-dist/assets/index-DKFBREX_.js +1 -0
- package/cli/storybook-dist/assets/index-DgH-xKnr.js +11 -0
- package/cli/storybook-dist/assets/index-Dmy2JGbm.js +1 -0
- package/cli/storybook-dist/assets/index-DrFu-skq.js +6 -0
- package/cli/storybook-dist/assets/index-mT46TdHs.js +575 -0
- package/cli/storybook-dist/assets/jsx-runtime-BTJTZTIL.js +9 -0
- package/cli/storybook-dist/assets/keymapTileIndex.worker-BsNYNbqs.js +1 -0
- package/cli/storybook-dist/assets/preview-B8lJiyuQ.js +34 -0
- package/cli/storybook-dist/assets/preview-BBWR9nbA.js +1 -0
- package/cli/storybook-dist/assets/preview-BWzBA1C2.js +396 -0
- package/cli/storybook-dist/assets/preview-CILRoSnB.js +1 -0
- package/cli/storybook-dist/assets/preview-CVgpLj3b.js +1 -0
- package/cli/storybook-dist/assets/preview-Com4scch.css +1 -0
- package/cli/storybook-dist/assets/preview-CvbIS5ZJ.js +1 -0
- package/cli/storybook-dist/assets/preview-CvycU0Br.js +2 -0
- package/cli/storybook-dist/assets/preview-CzhIqee1.js +3 -0
- package/cli/storybook-dist/assets/preview-DD_OYowb.js +1 -0
- package/cli/storybook-dist/assets/preview-DGUiP6tS.js +7 -0
- package/cli/storybook-dist/assets/preview-DHQbi4pV.js +1 -0
- package/cli/storybook-dist/assets/react-18-hB3smqWJ.js +1 -0
- package/cli/storybook-dist/assets/react-resizable-panels.browser-CvAJUcrm.js +72 -0
- package/cli/storybook-dist/assets/test-utils-BQudk2xt.js +9 -0
- package/cli/storybook-dist/favicon.svg +1 -0
- package/cli/storybook-dist/iframe.html +666 -0
- package/cli/storybook-dist/index.html +190 -0
- package/cli/storybook-dist/index.json +1 -0
- package/cli/storybook-dist/nunito-sans-bold-italic.woff2 +0 -0
- package/cli/storybook-dist/nunito-sans-bold.woff2 +0 -0
- package/cli/storybook-dist/nunito-sans-italic.woff2 +0 -0
- package/cli/storybook-dist/nunito-sans-regular.woff2 +0 -0
- package/cli/storybook-dist/project.json +1 -0
- package/cli/storybook-dist/sb-addons/chromatic-com-storybook-10/manager-bundle.js +331 -0
- package/cli/storybook-dist/sb-addons/chromatic-com-storybook-10/manager-bundle.js.LEGAL.txt +51 -0
- package/cli/storybook-dist/sb-addons/essentials-actions-3/manager-bundle.js +3 -0
- package/cli/storybook-dist/sb-addons/essentials-backgrounds-5/manager-bundle.js +12 -0
- package/cli/storybook-dist/sb-addons/essentials-controls-2/manager-bundle.js +405 -0
- package/cli/storybook-dist/sb-addons/essentials-docs-4/manager-bundle.js +245 -0
- package/cli/storybook-dist/sb-addons/essentials-measure-8/manager-bundle.js +3 -0
- package/cli/storybook-dist/sb-addons/essentials-outline-9/manager-bundle.js +3 -0
- package/cli/storybook-dist/sb-addons/essentials-toolbars-7/manager-bundle.js +3 -0
- package/cli/storybook-dist/sb-addons/essentials-viewport-6/manager-bundle.js +3 -0
- package/cli/storybook-dist/sb-addons/links-1/manager-bundle.js +3 -0
- package/cli/storybook-dist/sb-addons/storybook-13/manager-bundle.js +3 -0
- package/cli/storybook-dist/sb-addons/storybook-core-core-server-presets-0/common-manager-bundle.js +3 -0
- package/cli/storybook-dist/sb-addons/storybook-experimental-addon-test-12/manager-bundle.js +223 -0
- package/cli/storybook-dist/sb-addons/themes-11/manager-bundle.js +3 -0
- package/cli/storybook-dist/sb-common-assets/favicon.svg +1 -0
- package/cli/storybook-dist/sb-common-assets/nunito-sans-bold-italic.woff2 +0 -0
- package/cli/storybook-dist/sb-common-assets/nunito-sans-bold.woff2 +0 -0
- package/cli/storybook-dist/sb-common-assets/nunito-sans-italic.woff2 +0 -0
- package/cli/storybook-dist/sb-common-assets/nunito-sans-regular.woff2 +0 -0
- package/cli/storybook-dist/sb-manager/globals-module-info.js +1052 -0
- package/cli/storybook-dist/sb-manager/globals-runtime.js +41775 -0
- package/cli/storybook-dist/sb-manager/globals.js +48 -0
- package/cli/storybook-dist/sb-manager/runtime.js +12048 -0
- package/cli/templates/common/.mcp.json +8 -0
- package/cli/templates/common/README.md +644 -81
- package/cli/templates/common/assets/icon.svg +44 -2
- package/cli/templates/common/manifest.json +13 -13
- package/cli/templates/common/package.json +11 -4
- package/cli/templates/common/py/main.py +98 -0
- package/cli/templates/common/requirements.txt +4 -3
- package/cli/templates/common/tsconfig.json +1 -1
- package/cli/templates/common/ui/content.tsx +216 -0
- package/cli/templates/common/ui/style.css +6 -0
- package/cli/templates/common/vite.config.ts +6 -25
- package/cli/templates/cpp/cpp/CMakeLists.txt +14 -0
- package/cli/templates/cpp/cpp/main.cpp +26 -0
- package/cli/templates/ros2/ros2_ws/src/__PLUGIN_SLUG__/__PLUGIN_SLUG__/node.py +1 -1
- package/cli/templates/ros2-cpp/ros2_ws/src/__PLUGIN_SLUG__/CMakeLists.txt +17 -0
- package/cli/templates/ros2-cpp/ros2_ws/src/__PLUGIN_SLUG__/package.xml +11 -0
- package/cli/templates/ros2-cpp/ros2_ws/src/__PLUGIN_SLUG__/src/node.cpp +22 -0
- package/cli/vite.d.mts +25 -0
- package/cli/vite.mjs +292 -0
- package/package.json +32 -5
- package/cli/src/pack.mjs +0 -61
- package/cli/src/preview.mjs +0 -91
- package/cli/templates/common/main.py +0 -114
- package/cli/templates/common/src/content.tsx +0 -33
package/cli/src/mcp.mjs
ADDED
|
@@ -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
|
+
}
|