@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
|
@@ -8,7 +8,7 @@ A Muscat plugin project. Build, develop, and ship with `muscat-pk` CLI.
|
|
|
8
8
|
muscat-pk dev # UI preview + backend together
|
|
9
9
|
muscat-pk dev:ui # UI preview only
|
|
10
10
|
muscat-pk dev:back # backend only (Python watchfiles / ROS2 Docker)
|
|
11
|
-
muscat-pk
|
|
11
|
+
muscat-pk build # build + distributable ZIP
|
|
12
12
|
```
|
|
13
13
|
|
|
14
14
|
---
|
|
@@ -17,20 +17,170 @@ muscat-pk pack # build a distributable ZIP
|
|
|
17
17
|
|
|
18
18
|
```
|
|
19
19
|
__PLUGIN_DIR__/
|
|
20
|
-
├─
|
|
21
|
-
│
|
|
20
|
+
├─ ui/
|
|
21
|
+
│ ├─ content.tsx # plugin UI entry point
|
|
22
|
+
│ └─ style.css # plugin styles auto-loaded by muscat()
|
|
23
|
+
├─ py/
|
|
24
|
+
│ └─ main.py # Python backend entry point
|
|
22
25
|
├─ assets/
|
|
23
26
|
│ └─ icon.svg # icon referenced from manifest
|
|
24
27
|
├─ manifest.json # metadata, contribution points, runtime config
|
|
25
|
-
├─
|
|
26
|
-
└─ requirements.txt # Python deps (auto-pinned to latest on
|
|
28
|
+
├─ README.md # this file (copied to dist/ on build)
|
|
29
|
+
└─ requirements.txt # Python deps (auto-pinned to latest on build)
|
|
27
30
|
```
|
|
28
31
|
|
|
29
32
|
> ROS2 plugins additionally include a `ros2_ws/` directory.
|
|
30
33
|
|
|
31
34
|
---
|
|
32
35
|
|
|
33
|
-
## Frontend (`
|
|
36
|
+
## Frontend (`ui/content.tsx`)
|
|
37
|
+
|
|
38
|
+
### JavaScript dependencies
|
|
39
|
+
|
|
40
|
+
`muscat-pk build` runs this plugin project's own Vite build. Vite resolves
|
|
41
|
+
imports from installed `node_modules`; it does not care whether a package is
|
|
42
|
+
listed under `dependencies` or `devDependencies`, but the package must be
|
|
43
|
+
installed.
|
|
44
|
+
|
|
45
|
+
Do not run a production-only install such as `npm install --omit=dev` before
|
|
46
|
+
building the plugin UI, because build tools like `vite`, `typescript`,
|
|
47
|
+
`tailwindcss`, `@tailwindcss/vite`, `sass`, or `less` are usually
|
|
48
|
+
`devDependencies`.
|
|
49
|
+
|
|
50
|
+
The scaffold keeps this split:
|
|
51
|
+
|
|
52
|
+
| package kind | examples | why |
|
|
53
|
+
|---|---|---|
|
|
54
|
+
| `dependencies` | `@rainbow-robotics/plugin-ui`, UI libraries imported by plugin source | Author-facing APIs used by `ui/*.tsx` |
|
|
55
|
+
| `devDependencies` | `vite`, `typescript`, `tailwindcss`, `@tailwindcss/vite`, `sass`, `less` | Build/dev tools needed before `dist/*.js` is produced |
|
|
56
|
+
|
|
57
|
+
The built plugin ZIP does not include `package.json` or `node_modules`. For
|
|
58
|
+
production, Muscat provides `@rainbow-robotics/plugin-ui`, React, and ReactDOM
|
|
59
|
+
through the host import map; plugin UI build output imports those as host
|
|
60
|
+
externals.
|
|
61
|
+
|
|
62
|
+
### Styles
|
|
63
|
+
|
|
64
|
+
`muscat()` automatically loads `ui/style.{css,scss,sass,less}` (or
|
|
65
|
+
`ui/styles.{css,scss,sass,less}`) for every UI entry, plus
|
|
66
|
+
`ui/{entry}.{css,scss,sass,less}` for a matching entry-specific stylesheet. You
|
|
67
|
+
do not need to import CSS from every `.tsx` file.
|
|
68
|
+
|
|
69
|
+
The scaffold uses Tailwind's theme/utilities layers only, so plugin utilities
|
|
70
|
+
are generated from files under `ui/` without applying Tailwind preflight resets
|
|
71
|
+
to the host page.
|
|
72
|
+
|
|
73
|
+
Built CSS selectors are scoped under the current plugin id
|
|
74
|
+
(`[data-muscat-plugin-id="..."]`). CSS-in-JS libraries such as Emotion work
|
|
75
|
+
normally, but global styles should be scoped by the author.
|
|
76
|
+
|
|
77
|
+
#### Tailwind
|
|
78
|
+
|
|
79
|
+
This template enables Tailwind in `vite.config.ts`:
|
|
80
|
+
|
|
81
|
+
```ts
|
|
82
|
+
import { defineConfig } from "vite";
|
|
83
|
+
import tailwindcss from "@tailwindcss/vite";
|
|
84
|
+
import { muscat } from "@rainbow-robotics/muscat-plugin-kit/vite";
|
|
85
|
+
|
|
86
|
+
export default defineConfig({
|
|
87
|
+
plugins: [tailwindcss(), muscat()],
|
|
88
|
+
});
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
The default `ui/style.css` uses Tailwind theme/utilities only, not preflight:
|
|
92
|
+
|
|
93
|
+
```css
|
|
94
|
+
@layer theme, utilities;
|
|
95
|
+
|
|
96
|
+
@import "tailwindcss/theme.css" layer(theme);
|
|
97
|
+
@import "tailwindcss/utilities.css" layer(utilities);
|
|
98
|
+
|
|
99
|
+
@source "./**/*.{ts,tsx}";
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
#### SCSS, Sass, and Less
|
|
103
|
+
|
|
104
|
+
Install the preprocessor package, then create one of the auto-loaded style files.
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
npm i -D sass
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
```scss
|
|
111
|
+
/* ui/style.scss */
|
|
112
|
+
$accent: #3b82f6;
|
|
113
|
+
|
|
114
|
+
.panel {
|
|
115
|
+
border: 1px solid color-mix(in srgb, $accent 40%, transparent);
|
|
116
|
+
|
|
117
|
+
&__title {
|
|
118
|
+
color: $accent;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
For Less, install `less` and use `ui/style.less`.
|
|
124
|
+
|
|
125
|
+
#### Emotion
|
|
126
|
+
|
|
127
|
+
Emotion dependencies may be in `dependencies` or `devDependencies`; Vite can
|
|
128
|
+
bundle them when they are installed and imported by the plugin.
|
|
129
|
+
|
|
130
|
+
For `styled`, no Vite config change is needed:
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
npm i @emotion/react @emotion/styled
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
```tsx
|
|
137
|
+
import styled from "@emotion/styled";
|
|
138
|
+
|
|
139
|
+
const Panel = styled.div({
|
|
140
|
+
display: "grid",
|
|
141
|
+
gap: 12,
|
|
142
|
+
});
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
For Emotion's `css` prop, pass React plugin options through `muscat()` and add
|
|
146
|
+
`jsxImportSource` to `tsconfig.json`:
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
npm i @emotion/react @emotion/styled
|
|
150
|
+
npm i -D @emotion/babel-plugin
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
```ts
|
|
154
|
+
// vite.config.ts
|
|
155
|
+
import { defineConfig } from "vite";
|
|
156
|
+
import tailwindcss from "@tailwindcss/vite";
|
|
157
|
+
import { muscat } from "@rainbow-robotics/muscat-plugin-kit/vite";
|
|
158
|
+
|
|
159
|
+
export default defineConfig({
|
|
160
|
+
plugins: [
|
|
161
|
+
tailwindcss(),
|
|
162
|
+
muscat({
|
|
163
|
+
react: {
|
|
164
|
+
jsxImportSource: "@emotion/react",
|
|
165
|
+
babel: {
|
|
166
|
+
plugins: ["@emotion/babel-plugin"],
|
|
167
|
+
},
|
|
168
|
+
},
|
|
169
|
+
}),
|
|
170
|
+
],
|
|
171
|
+
});
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
```json
|
|
175
|
+
{
|
|
176
|
+
"compilerOptions": {
|
|
177
|
+
"jsxImportSource": "@emotion/react"
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
Emotion `Global` writes global CSS at runtime, so scope it manually or avoid it
|
|
183
|
+
inside plugins.
|
|
34
184
|
|
|
35
185
|
### useRb() hook
|
|
36
186
|
|
|
@@ -46,13 +196,19 @@ function App() {
|
|
|
46
196
|
|
|
47
197
|
### rb API
|
|
48
198
|
|
|
49
|
-
| Method
|
|
50
|
-
|
|
51
|
-
| `rb.pub(topic, payload)`
|
|
52
|
-
| `rb.sub(topic, handler)`
|
|
53
|
-
| `rb.action(topic, payload?)`
|
|
54
|
-
| `rb.serve(topic, handler)`
|
|
55
|
-
| `rb.toast(message, type?)` |
|
|
199
|
+
| Method | Description |
|
|
200
|
+
| ------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
201
|
+
| `rb.pub(topic, payload)` | Publish a message to a topic |
|
|
202
|
+
| `rb.sub(topic, handler)` | Subscribe to a topic — returns `{ undeclare() }` |
|
|
203
|
+
| `rb.action(topic, payload?)` | Send a request and await a reply |
|
|
204
|
+
| `rb.serve(topic, handler)` | Handle incoming requests from the backend |
|
|
205
|
+
| `rb.toast({ title?, message, type?, actionLabel?, handleActionClick?, closeOnActionClick?, duration?, onClose? })` | Show a host toast notification. `message` accepts a string or `ReactElement`. `type` can be `"info"`, `"danger"`, `"warning"`, `"caution"`, or `"success"` |
|
|
206
|
+
| `rb.alert({ title?, message, buttonText? })` | Show a host alert dialog. Resolves when the dialog is closed |
|
|
207
|
+
| `rb.confirm({ title?, message, buttonText? })` | Show a host confirmation dialog. `buttonText` accepts `{ yes, no }`. Resolves to `true` or `false` |
|
|
208
|
+
| `rb.prompt({ title?, message, value?, placeholder?, buttonText? })` | Show a host prompt dialog. `buttonText` accepts `{ yes, no }`. Resolves to the entered string or `undefined` |
|
|
209
|
+
|
|
210
|
+
Topic names passed to `pub`, `sub`, `action`, and `serve` are isolated per plugin.
|
|
211
|
+
|
|
56
212
|
|
|
57
213
|
All methods support Generic Types:
|
|
58
214
|
|
|
@@ -66,91 +222,306 @@ const sub = await rb.sub<{ value: number }>("sensor/data", (data) => {
|
|
|
66
222
|
console.log(data.value);
|
|
67
223
|
});
|
|
68
224
|
sub.undeclare(); // cleanup
|
|
225
|
+
|
|
226
|
+
const ok = await rb.confirm({
|
|
227
|
+
title: "Run",
|
|
228
|
+
message: "Start the backend action?",
|
|
229
|
+
});
|
|
230
|
+
if (ok) {
|
|
231
|
+
await rb.action("run");
|
|
232
|
+
}
|
|
69
233
|
```
|
|
70
234
|
|
|
71
|
-
###
|
|
235
|
+
### Saving and restoring form data (`useRbFormData` / `useRbSave`)
|
|
72
236
|
|
|
73
|
-
|
|
237
|
+
If the host embeds your plugin in a form it owns (e.g. a program step editor
|
|
238
|
+
with its own Save button), it can hand your plugin previously-saved values and
|
|
239
|
+
pull the current values back out when the user saves. The host — not the
|
|
240
|
+
plugin — persists the data (IndexedDB, backend, etc.).
|
|
74
241
|
|
|
242
|
+
```tsx
|
|
243
|
+
import { useState } from "react";
|
|
244
|
+
import { useRbFormData, useRbSave } from "@rainbow-robotics/plugin-ui/react";
|
|
245
|
+
|
|
246
|
+
type GripArgs = { targetName: string; width: number };
|
|
247
|
+
const DEFAULTS: GripArgs = { targetName: "", width: 20 };
|
|
248
|
+
|
|
249
|
+
export default function App() {
|
|
250
|
+
// Previously-saved values, or undefined for a brand-new instance.
|
|
251
|
+
const saved = useRbFormData<GripArgs>();
|
|
252
|
+
const [args, setArgs] = useState<GripArgs>({ ...DEFAULTS, ...saved });
|
|
253
|
+
|
|
254
|
+
// Registers a getter the host calls when its Save button is clicked.
|
|
255
|
+
// Always returns the CURRENT values — re-registering on every render keeps
|
|
256
|
+
// the closure fresh, which useRbSave already handles for you.
|
|
257
|
+
useRbSave(() => ({
|
|
258
|
+
args,
|
|
259
|
+
summary: `${args.targetName || "target"} · ${args.width}mm`,
|
|
260
|
+
}));
|
|
261
|
+
|
|
262
|
+
return (/* ...form UI reading/writing `args`... */);
|
|
263
|
+
}
|
|
75
264
|
```
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
265
|
+
|
|
266
|
+
The value returned from `useRbSave` must be JSON-serialisable — the host
|
|
267
|
+
persists it as-is. Not every host embeds plugins in a save/restore form; if
|
|
268
|
+
yours doesn't, you can skip these hooks entirely.
|
|
79
269
|
|
|
80
270
|
### UI components
|
|
81
271
|
|
|
82
|
-
Import Muscat components from `@rainbow-robotics/plugin-ui/react
|
|
83
|
-
|
|
272
|
+
Import Muscat components from `@rainbow-robotics/plugin-ui/react` and export a
|
|
273
|
+
React component as the default export. The host mounts that component directly
|
|
274
|
+
and provides `useRb()` through context.
|
|
84
275
|
|
|
85
276
|
```tsx
|
|
86
|
-
import {
|
|
87
|
-
import {
|
|
277
|
+
import { useState } from "react";
|
|
278
|
+
import { RBLabelButton, RBSlider, RBSwitch } from "@rainbow-robotics/plugin-ui/react";
|
|
88
279
|
import { useRb } from "@rainbow-robotics/plugin-ui/sdk";
|
|
89
280
|
|
|
90
|
-
function App() {
|
|
281
|
+
export default function App() {
|
|
91
282
|
const rb = useRb();
|
|
92
|
-
|
|
283
|
+
const [width, setWidth] = useState(20);
|
|
284
|
+
const [enabled, setEnabled] = useState(true);
|
|
285
|
+
|
|
286
|
+
return (
|
|
287
|
+
<div className="flex flex-col gap-4">
|
|
288
|
+
<RBSlider
|
|
289
|
+
value={[width]}
|
|
290
|
+
min={0}
|
|
291
|
+
max={100}
|
|
292
|
+
onValueChange={(values: number[]) => setWidth(values[0] ?? 0)}
|
|
293
|
+
/>
|
|
294
|
+
<RBSwitch checked={enabled} onCheckedChange={setEnabled} />
|
|
295
|
+
<RBLabelButton
|
|
296
|
+
disabled={!enabled}
|
|
297
|
+
onClick={() => rb.action("grip", { width })}
|
|
298
|
+
>
|
|
299
|
+
Grip
|
|
300
|
+
</RBLabelButton>
|
|
301
|
+
</div>
|
|
302
|
+
);
|
|
93
303
|
}
|
|
304
|
+
```
|
|
94
305
|
|
|
95
|
-
|
|
306
|
+
---
|
|
307
|
+
|
|
308
|
+
## Developing directly on the robot PC
|
|
309
|
+
|
|
310
|
+
If you're running `muscat-pk dev` **on the robot PC itself**, Muscat is likely already
|
|
311
|
+
running its own Socket.IO bridge on port 10000. In that case the CLI detects the port
|
|
312
|
+
conflict and asks:
|
|
313
|
+
|
|
314
|
+
```
|
|
315
|
+
⚠ port 10000 is already in use — can't start Socket.IO bridge.
|
|
316
|
+
Proceed without Socket.IO bridge? [y/N]:
|
|
96
317
|
```
|
|
97
318
|
|
|
319
|
+
Answer **y**. Your plugin backend will connect to the Muscat bridge that's already
|
|
320
|
+
running instead of starting a new one — exactly what you want when developing on the
|
|
321
|
+
robot.
|
|
322
|
+
|
|
323
|
+
> If you answer **n** (or just press Enter), the CLI exits so you can free the port
|
|
324
|
+
> manually and retry.
|
|
325
|
+
|
|
98
326
|
---
|
|
99
327
|
|
|
100
|
-
## Backend
|
|
328
|
+
## Backend runtimes
|
|
329
|
+
|
|
330
|
+
`manifest.json` chooses one backend runtime. `muscat-pk dev` runs backend code in
|
|
331
|
+
a Docker container matching the robot environment. Backend code should contain
|
|
332
|
+
plugin logic only; it should not start the Muscat bridge or its own copy of the
|
|
333
|
+
plugin gateway.
|
|
334
|
+
|
|
335
|
+
### Which backend pattern? (depends on the contribution point)
|
|
336
|
+
|
|
337
|
+
**How you control the robot depends on what your plugin contributes** (see
|
|
338
|
+
`manifest.json` → `contributes[].point`). Don't mix these up:
|
|
339
|
+
|
|
340
|
+
| Contribution point | What it is | Backend pattern |
|
|
341
|
+
| --- | --- | --- |
|
|
342
|
+
| `program.panel` (with `commandInfo`) | Defines a **custom command** the plugin adds to the Program page's rule-based sequence builder. The operator places it into the program tree like any built-in command (Move J, Point, Wait, …); it runs when the program reaches that step. | **`PluginProgramContext`** — integrated with the program's stop/pause and variables. See _Program command backend_ below. |
|
|
343
|
+
| `toolbar` / `lnb` / `move.panel` | A live UI panel/popover the operator interacts with directly | Call the robot **SDK directly** (`RBManipulateSDK`, `RBAmrSDK`) from `py/main.py`, or `rb.action(...)` → your backend → SDK. **Not** a program step — there is no stop/pause/variable context. |
|
|
344
|
+
|
|
345
|
+
Rule of thumb: use `PluginProgramContext` **only** for a `program.panel` command
|
|
346
|
+
that runs as part of a program. To move the robot live from a toolbar/move panel,
|
|
347
|
+
use the SDK — a program-step context does not apply.
|
|
348
|
+
|
|
349
|
+
### Frontend-only (`none`)
|
|
350
|
+
|
|
351
|
+
Use this when the plugin only has UI and calls host services:
|
|
352
|
+
|
|
353
|
+
```json
|
|
354
|
+
{ "runtime": { "type": "none" } }
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
### Python
|
|
358
|
+
|
|
359
|
+
Python plugins use `py/main.py` and can communicate with the UI through
|
|
360
|
+
`rainbow.rb_sdk.RBPluginCall`.
|
|
361
|
+
|
|
362
|
+
```python
|
|
363
|
+
import time
|
|
364
|
+
from rainbow.rb_sdk import RBAmrSDK, RBManipulateSDK, RBPluginCall
|
|
365
|
+
|
|
366
|
+
plugin = RBPluginCall()
|
|
367
|
+
|
|
368
|
+
|
|
369
|
+
plugin.publish("state", {"ready": True})
|
|
101
370
|
|
|
102
|
-
The backend communicates with the frontend using `rainbow_rb_zenoh`.
|
|
103
|
-
Set the `prefix` to `plugin/{manifest.id}` to match the frontend's auto-namespace.
|
|
104
371
|
|
|
105
|
-
|
|
372
|
+
@plugin.subscribe("event")
|
|
373
|
+
def on_ui_event(payload=None):
|
|
374
|
+
print(payload)
|
|
375
|
+
|
|
376
|
+
|
|
377
|
+
@plugin.serve("tool/echo")
|
|
378
|
+
def echo(payload=None):
|
|
379
|
+
return {"echo": payload}
|
|
380
|
+
|
|
381
|
+
|
|
382
|
+
def call_frontend():
|
|
383
|
+
res = plugin.call("tool/ping", payload={"hello": "plugin"})
|
|
384
|
+
print(res)
|
|
385
|
+
|
|
386
|
+
|
|
387
|
+
def move_j_example():
|
|
388
|
+
amr = RBAmrSDK()
|
|
389
|
+
manipulate = RBManipulateSDK()
|
|
390
|
+
return manipulate.move.call_move_j(
|
|
391
|
+
robot_model="C500920",
|
|
392
|
+
target={"tar_values": [0, 0, 0, 0, 0, 0], "tar_frame": 0, "tar_unit": 0},
|
|
393
|
+
)
|
|
394
|
+
|
|
395
|
+
|
|
396
|
+
if __name__ == "__main__":
|
|
397
|
+
while True:
|
|
398
|
+
time.sleep(1)
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
#### Program command backend (`program.panel`)
|
|
402
|
+
|
|
403
|
+
A `program.panel` contribution defines a **custom command** your plugin adds to
|
|
404
|
+
the Muscat **Program page**, where the operator builds a robot program as a
|
|
405
|
+
rule-based sequence (a program tree). Your command appears alongside the
|
|
406
|
+
built-ins (Move J, Point, Wait, …); the operator places it into the tree, and
|
|
407
|
+
each time the program executes that step the host calls your backend through
|
|
408
|
+
`PluginProgramContext` — receiving the step args, checking for stop/pause,
|
|
409
|
+
reading/writing program variables, and signalling completion. This pattern is
|
|
410
|
+
**only** for `program.panel`; a toolbar/move-panel plugin uses the SDK directly
|
|
411
|
+
instead (see the table above).
|
|
106
412
|
|
|
107
413
|
```python
|
|
414
|
+
"""
|
|
415
|
+
Plugin backend main.py example (program.panel command).
|
|
416
|
+
|
|
417
|
+
manifest.json:
|
|
418
|
+
"runtime": {"type": "python", "entry": "main.py"},
|
|
419
|
+
"contributes": [{
|
|
420
|
+
"point": "program.panel",
|
|
421
|
+
"ui": "program",
|
|
422
|
+
"label": {"en": "My Plugin Step"},
|
|
423
|
+
"commandInfo": {
|
|
424
|
+
"name": "My Plugin Step",
|
|
425
|
+
"icon": "assets/icon.svg",
|
|
426
|
+
"funcName": "rb_program_sdk.plugin_execute",
|
|
427
|
+
"args": {"message": "hello"} # plugin-author-defined args
|
|
428
|
+
}
|
|
429
|
+
}]
|
|
430
|
+
|
|
431
|
+
The host invokes commandInfo.funcName (rb_program_sdk.plugin_execute) with
|
|
432
|
+
args.plugin_id + your args when the program reaches this step.
|
|
433
|
+
"""
|
|
108
434
|
import asyncio
|
|
109
|
-
from
|
|
435
|
+
from rainbow.rb_sdk import PluginProgramContext
|
|
110
436
|
|
|
111
|
-
|
|
112
|
-
client = ZenohClient()
|
|
437
|
+
ctx = PluginProgramContext(plugin_id="my-plugin")
|
|
113
438
|
|
|
114
439
|
|
|
115
|
-
@
|
|
116
|
-
async def
|
|
117
|
-
|
|
440
|
+
@ctx.on_execute
|
|
441
|
+
async def handle(args: dict) -> None:
|
|
442
|
+
message = args.get("message", "")
|
|
443
|
+
print(f"[my-plugin] execute called: message={message}", flush=True)
|
|
118
444
|
|
|
445
|
+
# check stop/pause during long-running work
|
|
446
|
+
for _ in range(10):
|
|
447
|
+
await ctx.check_stop()
|
|
448
|
+
await asyncio.sleep(0.1)
|
|
119
449
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
450
|
+
# read a program variable
|
|
451
|
+
counter = await ctx.get_variable("counter")
|
|
452
|
+
print(f"[my-plugin] counter={counter}", flush=True)
|
|
123
453
|
|
|
454
|
+
# update a variable
|
|
455
|
+
await ctx.set_variable("result", f"done: {message}")
|
|
124
456
|
|
|
125
|
-
|
|
126
|
-
await
|
|
127
|
-
await asyncio.Event().wait() # keep alive
|
|
457
|
+
# finish the step
|
|
458
|
+
await ctx.done()
|
|
128
459
|
|
|
129
460
|
|
|
130
461
|
if __name__ == "__main__":
|
|
131
|
-
asyncio.run(
|
|
462
|
+
asyncio.run(ctx.start())
|
|
132
463
|
```
|
|
133
464
|
|
|
134
|
-
###
|
|
465
|
+
### C++
|
|
466
|
+
|
|
467
|
+
C++ plugins use `cpp/` and are built with CMake inside Docker. The current C++
|
|
468
|
+
template is a build/run skeleton; wire it to the plugin gateway when the C++ SDK
|
|
469
|
+
is available.
|
|
470
|
+
|
|
471
|
+
```cpp
|
|
472
|
+
#include <chrono>
|
|
473
|
+
#include <cstdlib>
|
|
474
|
+
#include <iostream>
|
|
475
|
+
#include <string>
|
|
476
|
+
#include <thread>
|
|
477
|
+
|
|
478
|
+
int main() {
|
|
479
|
+
const char* plugin_id = std::getenv("RB_PLUGIN_ID");
|
|
480
|
+
std::cout << "[__PLUGIN_NAME__] backend ready"
|
|
481
|
+
<< (plugin_id ? std::string(" (id=") + plugin_id + ")" : "")
|
|
482
|
+
<< std::endl;
|
|
483
|
+
|
|
484
|
+
while (true) {
|
|
485
|
+
std::this_thread::sleep_for(std::chrono::seconds(1));
|
|
486
|
+
}
|
|
487
|
+
return 0;
|
|
488
|
+
}
|
|
489
|
+
```
|
|
135
490
|
|
|
136
|
-
|
|
137
|
-
|
|
491
|
+
### ROS2 (rclpy)
|
|
492
|
+
|
|
493
|
+
ROS2 Python plugins use `ros2_ws/` with `runtime.rosClient: "rclpy"`. The node
|
|
494
|
+
is launched with `--ros-args -r __ns:=/{slug}` automatically by `dev:back`.
|
|
138
495
|
|
|
139
496
|
```python
|
|
140
497
|
# ros2_ws/src/__PLUGIN_SLUG__/__PLUGIN_SLUG__/node.py
|
|
141
498
|
import rclpy
|
|
142
499
|
from rclpy.node import Node
|
|
143
|
-
from
|
|
500
|
+
from rainbow.rb_sdk import RBManipulateSDK
|
|
501
|
+
|
|
502
|
+
sdk = RBManipulateSDK()
|
|
503
|
+
|
|
144
504
|
|
|
145
505
|
class __PLUGIN_CLASS__Node(Node):
|
|
146
506
|
def __init__(self):
|
|
147
507
|
super().__init__("__PLUGIN_SLUG___node")
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
508
|
+
self.get_logger().info("__PLUGIN_NAME__ node started")
|
|
509
|
+
# use sdk alongside ROS2 publishers/subscribers/services as needed
|
|
510
|
+
```
|
|
151
511
|
|
|
152
|
-
|
|
153
|
-
|
|
512
|
+
### ROS2 (rclcpp)
|
|
513
|
+
|
|
514
|
+
ROS2 C++ plugins use `ros2_ws/` with `runtime.rosClient: "rclcpp"`.
|
|
515
|
+
|
|
516
|
+
```cpp
|
|
517
|
+
#include "rclcpp/rclcpp.hpp"
|
|
518
|
+
|
|
519
|
+
class __PLUGIN_CLASS__Node : public rclcpp::Node {
|
|
520
|
+
public:
|
|
521
|
+
__PLUGIN_CLASS__Node() : Node("__PLUGIN_SLUG___node") {
|
|
522
|
+
RCLCPP_INFO(this->get_logger(), "__PLUGIN_NAME__ node started");
|
|
523
|
+
}
|
|
524
|
+
};
|
|
154
525
|
```
|
|
155
526
|
|
|
156
527
|
---
|
|
@@ -159,30 +530,156 @@ class __PLUGIN_CLASS__Node(Node):
|
|
|
159
530
|
|
|
160
531
|
```jsonc
|
|
161
532
|
{
|
|
162
|
-
|
|
533
|
+
// unique plugin ID — reverse-domain format recommended
|
|
534
|
+
"id": "com.example.my-plugin",
|
|
163
535
|
"name": "My Plugin",
|
|
164
536
|
"version": "1.0.0",
|
|
165
|
-
|
|
166
|
-
|
|
537
|
+
|
|
538
|
+
// minimum Muscat version required to load this plugin
|
|
539
|
+
"minMuscatVersion": "1.0.0",
|
|
540
|
+
|
|
541
|
+
// plugin author (empty string is fine)
|
|
542
|
+
"author": "Your Name",
|
|
543
|
+
|
|
544
|
+
// displayed in the Muscat plugin store / info panel
|
|
545
|
+
// string or { en (required), ko, ja, zh, vi, th, es }
|
|
546
|
+
"description": { "en": "Plugin description", "ko": "플러그인 설명" },
|
|
547
|
+
|
|
548
|
+
// SVG string (single file) or PNG/JPG size map (all three sizes required)
|
|
549
|
+
"icons": "assets/icon.svg",
|
|
550
|
+
// "icons": { "16": "assets/icon-16.png", "48": "assets/icon-48.png", "128": "assets/icon-128.png" },
|
|
551
|
+
|
|
552
|
+
// targetModels and/or targetCategorys — at least one is required
|
|
553
|
+
// "all" = every target, or list specific values
|
|
554
|
+
"targetModels": "all",
|
|
555
|
+
// "targetModels": ["C500920", "C500930"],
|
|
556
|
+
"targetCategorys": "all",
|
|
557
|
+
// "targetCategorys": ["manipulate", "amr", "rby1", "vision"],
|
|
167
558
|
|
|
168
559
|
"contributes": [
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
{
|
|
560
|
+
// program.panel — defines a custom command for the Program page sequence
|
|
561
|
+
// builder; runs via PluginProgramContext when the program reaches it
|
|
562
|
+
{
|
|
563
|
+
"point": "program.panel",
|
|
564
|
+
"icon": "assets/icon.svg",
|
|
565
|
+
"label": { "ko": "내 플러그인", "en": "My Plugin" },
|
|
566
|
+
"ui": "program", // must be unique across all contributions
|
|
567
|
+
"commandInfo": {
|
|
568
|
+
"name": "My Plugin",
|
|
569
|
+
"icon": "assets/icon.svg",
|
|
570
|
+
"funcName": "rb_program_sdk.plugin_execute",
|
|
571
|
+
"args": {}
|
|
572
|
+
}
|
|
573
|
+
},
|
|
574
|
+
// toolbar — adds a button to the top toolbar (required)
|
|
575
|
+
{
|
|
576
|
+
"point": "toolbar",
|
|
577
|
+
"icon": "assets/icon.svg",
|
|
578
|
+
"label": { "ko": "내 플러그인", "en": "My Plugin" },
|
|
579
|
+
"ui": "content", // must be unique across all contributions
|
|
580
|
+
"opens": "popover" // popover | panel | page
|
|
581
|
+
},
|
|
582
|
+
// move.panel — adds a panel to the Move screen
|
|
583
|
+
{
|
|
584
|
+
"point": "move.panel",
|
|
585
|
+
"icon": "assets/icon.svg",
|
|
586
|
+
"label": { "ko": "내 플러그인", "en": "My Plugin" },
|
|
587
|
+
"ui": "move" // must be unique across all contributions
|
|
588
|
+
}
|
|
172
589
|
],
|
|
173
590
|
|
|
174
|
-
//
|
|
175
|
-
|
|
591
|
+
// runtime — one of:
|
|
592
|
+
// { "type": "none" }
|
|
593
|
+
// { "type": "python", "entry": "main.py" }
|
|
594
|
+
// { "type": "cpp", "entry": "<executable name>" }
|
|
595
|
+
// { "type": "ros2", "rosClient": "rclpy" | "rclcpp", "package": "...", "launch": "..._node" }
|
|
596
|
+
"runtime": { "type": "python", "entry": "main.py" },
|
|
597
|
+
|
|
598
|
+
// optional: TCP ports opened by this plugin backend
|
|
599
|
+
// only number[] is allowed; ranges/objects are not accepted
|
|
600
|
+
// external plugin ports must be within 28600-28999
|
|
601
|
+
"ports": [28600]
|
|
176
602
|
}
|
|
177
603
|
```
|
|
178
604
|
|
|
605
|
+
**Backend types:**
|
|
606
|
+
|
|
607
|
+
| type | source dir | build / run | entry |
|
|
608
|
+
|---|---|---|---|
|
|
609
|
+
| `python` | `py/` | pip + run in Docker | `main.py` |
|
|
610
|
+
| `cpp` | `cpp/` | CMake in Docker | built executable name |
|
|
611
|
+
| `ros2` (rclpy) | `ros2_ws/` | colcon (ament_python) in Docker | — |
|
|
612
|
+
| `ros2` (rclcpp) | `ros2_ws/` | colcon (ament_cmake) in Docker | — |
|
|
613
|
+
|
|
614
|
+
> Every back end runs in a Docker container matching the robot (Ubuntu 24.04 + Python 3.12), so dev behaves like production and compiled binaries are ABI-compatible. **Docker is required** for all backend types (only a frontend-only `none` plugin skips it). No local Python/toolchain setup is needed.
|
|
615
|
+
|
|
179
616
|
**Contribution points:**
|
|
180
617
|
|
|
181
|
-
| point | Where it appears |
|
|
182
|
-
|
|
183
|
-
| `
|
|
184
|
-
| `lnb` | Left navigation
|
|
185
|
-
| `
|
|
618
|
+
| point | Where it appears | Backend | `commandInfo` |
|
|
619
|
+
|---|---|---|:---:|
|
|
620
|
+
| `toolbar` | Top toolbar button (must have at least one) | SDK / `rb.action` | — |
|
|
621
|
+
| `lnb` | Left navigation entry | SDK / `rb.action` | — |
|
|
622
|
+
| `move.panel` | Move screen panel | SDK / `rb.action` | — |
|
|
623
|
+
| `program.panel` | Custom command in the Program page sequence builder | `PluginProgramContext` | ✓ |
|
|
624
|
+
|
|
625
|
+
**`commandInfo` fields** (for `program.panel`):
|
|
626
|
+
|
|
627
|
+
| field | type | description |
|
|
628
|
+
|---|---|---|
|
|
629
|
+
| `name` | `string` | Display name of the command in the program tree |
|
|
630
|
+
| `icon` | `string` | Icon path |
|
|
631
|
+
| `iconClassName` | `string?` | Optional CSS class for the icon |
|
|
632
|
+
| `funcName` | `string?` | Backend function name to call |
|
|
633
|
+
| `args` | `Record<string, any>?` | Default arguments |
|
|
634
|
+
| `disabled` | `boolean?` | Whether the node is disabled |
|
|
635
|
+
| `allowChildren` | `string[]?` | Allowed child commands |
|
|
636
|
+
| `allowParents` | `string[]?` | Allowed parent commands |
|
|
637
|
+
| `notAllowChildren` | `string[]?` | Disallowed child commands |
|
|
638
|
+
| `syncGroupId` | `boolean?` | Sync group ID across children |
|
|
639
|
+
| `disableCopy` | `boolean?` | Prevent copy |
|
|
640
|
+
| `disableDelete` | `boolean?` | Prevent delete |
|
|
641
|
+
| `requireChildren` | `boolean?` | Whether a child command is required |
|
|
642
|
+
| `requireParent` | `boolean?` | Whether a parent command is required |
|
|
643
|
+
| `childrenCommand` | `string?` | Default command type for children |
|
|
644
|
+
|
|
645
|
+
**Validation rules:**
|
|
646
|
+
- `id`, `name`, `version`, `minMuscatVersion` — required non-empty strings
|
|
647
|
+
- `author` — required non-empty string
|
|
648
|
+
- `description` — required (`string` or `{ en (required), ko?, ja?, zh?, vi?, th?, es? }`)
|
|
649
|
+
- `icons` — SVG: single string path ending in `.svg`; PNG/JPG: object with `"16"`, `"48"`, `"128"` all present
|
|
650
|
+
- `targetModels` — `"all"` or a non-empty array of robot model ID strings (at least one of `targetModels` / `targetCategorys` required)
|
|
651
|
+
- `targetCategorys` — `"all"` or a non-empty array of `"manipulate" | "amr" | "rby1" | "vision"` (at least one of `targetModels` / `targetCategorys` required)
|
|
652
|
+
- `contributes` — required array; must contain at least one `toolbar` entry
|
|
653
|
+
- `ui` — each contribution must have a unique value
|
|
654
|
+
- `commandInfo` — required when `point` is `"program.panel"`
|
|
655
|
+
- `ports` — optional `number[]`; every port must be within `28600-28999`
|
|
656
|
+
and must not be a reserved robot/industrial/internal port
|
|
657
|
+
|
|
658
|
+
`muscat-pk build` throws on any validation error. `muscat-pk dev` prints warnings.
|
|
659
|
+
|
|
660
|
+
**Backend port rules:**
|
|
661
|
+
- Declare a port only if your backend opens a TCP server/listener.
|
|
662
|
+
- `muscat-pk dev` and `muscat-pk dev:back` stop the backend if it opens an
|
|
663
|
+
undeclared managed port.
|
|
664
|
+
- Reserved ports include `502`, `2222`, `4840`, `5170-5179`, `8000-8999`,
|
|
665
|
+
`10000`, `30004`, `34964`, `44818`, `50000-50005`, and `50051`.
|
|
666
|
+
|
|
667
|
+
---
|
|
668
|
+
|
|
669
|
+
## Localized documentation
|
|
670
|
+
|
|
671
|
+
You can ship per-language README files alongside the main `README.md`. Place them in the project root:
|
|
672
|
+
|
|
673
|
+
```
|
|
674
|
+
README.md # default / English fallback
|
|
675
|
+
README.ko.md # Korean
|
|
676
|
+
README.en.md # explicit English (optional)
|
|
677
|
+
README.ja.md # Japanese
|
|
678
|
+
```
|
|
679
|
+
|
|
680
|
+
All `README*.md` files found at the project root are automatically copied to `dist/` on
|
|
681
|
+
`muscat-pk build`. Muscat displays the file matching the user's locale,
|
|
682
|
+
falling back to `README.md` if none matches.
|
|
186
683
|
|
|
187
684
|
---
|
|
188
685
|
|
|
@@ -197,37 +694,96 @@ numpy==1.26.4
|
|
|
197
694
|
opencv-python
|
|
198
695
|
```
|
|
199
696
|
|
|
200
|
-
|
|
697
|
+
Run `muscat-pk dev` or `muscat-pk dev:back` — dependencies are installed automatically
|
|
698
|
+
inside the dev container (`pip install -r requirements.txt`) on every startup. No
|
|
699
|
+
local Python is required for this.
|
|
201
700
|
|
|
202
|
-
-
|
|
203
|
-
|
|
701
|
+
`muscat-pk dev:back` also best-effort creates/refreshes a local `.venv` in the
|
|
702
|
+
background (via `uv` if available, else your system Python) with the same deps —
|
|
703
|
+
purely so your editor (pylint, pyright, mypy, ...) can resolve imports and lint
|
|
704
|
+
correctly. It's not used to run the backend; Docker is the actual execution
|
|
705
|
+
environment, so this step is silently skipped if no local Python toolchain is
|
|
706
|
+
available. Point your editor's Python interpreter at `.venv`.
|
|
204
707
|
|
|
205
|
-
|
|
708
|
+
`muscat-pk sdk update` also refreshes `.venv` in place if one already exists, so
|
|
709
|
+
your editor picks up the new `rainbow-rb-sdk` version immediately.
|
|
206
710
|
|
|
207
|
-
> `muscat-pk build`
|
|
711
|
+
> `muscat-pk build` only **pins** versions in `requirements.txt` — it does not run `pip install` (the robot installs them at load time).
|
|
208
712
|
|
|
209
713
|
---
|
|
210
714
|
|
|
211
715
|
## Switching backend type
|
|
212
716
|
|
|
213
717
|
```bash
|
|
214
|
-
muscat-pk type change
|
|
215
|
-
muscat-pk type change --to
|
|
216
|
-
muscat-pk type change --to
|
|
718
|
+
muscat-pk type change # interactive
|
|
719
|
+
muscat-pk type change --to cpp # → C++
|
|
720
|
+
muscat-pk type change --to ros2 # → ROS2 (rclpy / Python)
|
|
721
|
+
muscat-pk type change --to ros2-cpp # → ROS2 (rclcpp / C++)
|
|
722
|
+
muscat-pk type change --to python # → Python
|
|
723
|
+
```
|
|
724
|
+
|
|
725
|
+
> Existing backend dirs (`ros2_ws/`, `cpp/`) are not deleted when switching away. Remove them manually if no longer needed.
|
|
726
|
+
|
|
727
|
+
---
|
|
728
|
+
|
|
729
|
+
## AI coding assistants (MCP)
|
|
730
|
+
|
|
731
|
+
If you build your plugin with an AI assistant (Claude Code, Codex, …), give it
|
|
732
|
+
grounded knowledge of the Muscat UI components, design tokens, and SDK instead of
|
|
733
|
+
letting it guess. `muscat-pk mcp` is an MCP server exposing:
|
|
734
|
+
|
|
735
|
+
- `list_components` / `get_component_props` / `get_component_example` — every
|
|
736
|
+
`@rainbow-robotics/plugin-ui/react` component with its real props and a working
|
|
737
|
+
Storybook example.
|
|
738
|
+
- `list_design_tokens` / `search_design_tokens` — the Tailwind classes to use
|
|
739
|
+
(`bg-bg-*`, `text-fg-*`, `typo-*`, …) so your UI matches the host theme.
|
|
740
|
+
- `search_rb_sdk` — how to use `useRb()`, `rb.*`, `useRbFormData`/`useRbSave`, and
|
|
741
|
+
the backend runtimes.
|
|
742
|
+
- `list_rb_sdk` / `get_rb_sdk_api` — the installed `rainbow-rb-sdk` (Python
|
|
743
|
+
backend) classes and signatures.
|
|
744
|
+
|
|
745
|
+
**Browse the components live** with `muscat-pk storybook`.
|
|
746
|
+
|
|
747
|
+
### Register the server
|
|
748
|
+
|
|
749
|
+
**Claude Code** — a `.mcp.json` is already scaffolded at your plugin root, so
|
|
750
|
+
it works out of the box:
|
|
751
|
+
|
|
752
|
+
```json
|
|
753
|
+
{
|
|
754
|
+
"mcpServers": {
|
|
755
|
+
"muscat": {
|
|
756
|
+
"command": "muscat-pk",
|
|
757
|
+
"args": ["mcp"]
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
```
|
|
762
|
+
|
|
763
|
+
**Codex** — add to `~/.codex/config.toml`:
|
|
764
|
+
|
|
765
|
+
```toml
|
|
766
|
+
[mcp_servers.muscat]
|
|
767
|
+
command = "muscat-pk"
|
|
768
|
+
args = ["mcp"]
|
|
217
769
|
```
|
|
218
770
|
|
|
219
|
-
|
|
771
|
+
Any other MCP client works too — it's a standard stdio MCP server started with
|
|
772
|
+
`muscat-pk mcp`. If `muscat-pk` isn't on the client's PATH, use its absolute path
|
|
773
|
+
(`which muscat-pk`) as `command`.
|
|
220
774
|
|
|
221
775
|
---
|
|
222
776
|
|
|
223
777
|
## Shipping
|
|
224
778
|
|
|
225
779
|
```bash
|
|
226
|
-
muscat-pk
|
|
780
|
+
muscat-pk build # build + ZIP
|
|
781
|
+
muscat-pk build --no-zip # build only, no ZIP
|
|
227
782
|
```
|
|
228
783
|
|
|
229
|
-
- Builds `
|
|
784
|
+
- Builds `ui/content.tsx` → `dist/content.js` (minified)
|
|
230
785
|
- Pins `requirements.txt` to latest versions (stable-only on `main` branch)
|
|
786
|
+
- Copies `assets/`, `manifest.json`, `README*.md`, `py/`, and `requirements.txt` into `dist/`
|
|
231
787
|
- ROS2: runs `colcon build` inside the Jazzy container; includes `ros2_ws/install/`
|
|
232
788
|
- Output: `__PLUGIN_DIR__-{version}.zip`
|
|
233
789
|
|
|
@@ -235,10 +791,15 @@ ZIP layout:
|
|
|
235
791
|
|
|
236
792
|
```
|
|
237
793
|
__PLUGIN_DIR__-1.0.0.zip
|
|
238
|
-
├─ dist/
|
|
239
|
-
├─
|
|
240
|
-
├─
|
|
241
|
-
|
|
794
|
+
├─ dist/
|
|
795
|
+
│ ├─ content.js # built UI
|
|
796
|
+
│ ├─ manifest.json
|
|
797
|
+
│ ├─ assets/
|
|
798
|
+
│ ├─ README.md
|
|
799
|
+
│ ├─ README.ko.md # if present
|
|
800
|
+
│ ├─ main.py # from py/
|
|
801
|
+
│ └─ requirements.txt # pinned
|
|
802
|
+
└─ ros2_ws/install/ # ROS2 only
|
|
242
803
|
```
|
|
243
804
|
|
|
244
805
|
---
|
|
@@ -249,8 +810,9 @@ __PLUGIN_DIR__-1.0.0.zip
|
|
|
249
810
|
muscat-pk dev # UI + backend
|
|
250
811
|
muscat-pk dev:ui # UI preview only (preview-host)
|
|
251
812
|
muscat-pk dev:back # backend only (Python: watchfiles / ROS2: Docker)
|
|
252
|
-
muscat-pk build #
|
|
253
|
-
muscat-pk
|
|
813
|
+
muscat-pk build # build → dist/ + distributable ZIP (--no-zip to skip)
|
|
814
|
+
muscat-pk storybook # browse the rb-components UI library in a browser
|
|
815
|
+
muscat-pk mcp # MCP server for AI assistants (components/tokens/SDK docs)
|
|
254
816
|
```
|
|
255
817
|
|
|
256
818
|
```bash
|
|
@@ -258,4 +820,5 @@ muscat-pk type change # switch backend type
|
|
|
258
820
|
muscat-pk sdk list # show current Python SDK version
|
|
259
821
|
muscat-pk sdk update # update Python SDK to latest
|
|
260
822
|
muscat-pk update # update muscat-plugin-kit itself
|
|
823
|
+
muscat-pk uninstall # remove muscat-pk itself
|
|
261
824
|
```
|