@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
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
// Shared Python Docker helpers (Ubuntu 24.04 + Python 3.12 — matches the robot).
|
|
2
|
+
// Used by dev:back (hot-reload) and build (lock + wheel vendor).
|
|
3
|
+
import { spawnSync } from "node:child_process";
|
|
4
|
+
import { existsSync } from "node:fs";
|
|
5
|
+
import { dirname, resolve } from "node:path";
|
|
6
|
+
import { hasBin, log, pruneMuskatImages, resolveDockerfile } from "./util.mjs";
|
|
7
|
+
|
|
8
|
+
export const PYTHON_DEV_IMAGE = "muscat-pk-python-dev";
|
|
9
|
+
|
|
10
|
+
export function assertDockerReady() {
|
|
11
|
+
if (!hasBin("docker")) {
|
|
12
|
+
throw new Error("Docker not found. The Python backend runs in a container (Ubuntu 24.04 + Python 3.12).");
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/** Build the dev image from the kit's bundled Dockerfile (Docker layer-caches). */
|
|
17
|
+
export async function ensureImage(image = PYTHON_DEV_IMAGE, { platform = null } = {}) {
|
|
18
|
+
const dockerfile = await resolveDockerfile("Dockerfile.python");
|
|
19
|
+
log.step(`docker build -t ${image}${platform ? ` (${platform})` : ""} (first run is slow, then cached)…`);
|
|
20
|
+
const platformFlags = platform ? ["--platform", platform] : [];
|
|
21
|
+
const r = spawnSync(
|
|
22
|
+
"docker",
|
|
23
|
+
["build", ...platformFlags, "-t", image, "-f", dockerfile, dirname(dockerfile)],
|
|
24
|
+
{ stdio: "inherit" },
|
|
25
|
+
);
|
|
26
|
+
if (r.status !== 0) throw new Error("docker build failed.");
|
|
27
|
+
pruneMuskatImages();
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// pip --platform does NOT auto-expand manylinux tags (unlike sys_tags()) — exact match only.
|
|
31
|
+
// Specifying all common glibc milestones ensures packages built for any Ubuntu era are found.
|
|
32
|
+
const PIP_PLATFORM = {
|
|
33
|
+
amd64: [
|
|
34
|
+
"manylinux_2_5_x86_64",
|
|
35
|
+
"manylinux_2_17_x86_64",
|
|
36
|
+
"manylinux_2_27_x86_64",
|
|
37
|
+
"manylinux_2_28_x86_64",
|
|
38
|
+
"manylinux_2_34_x86_64",
|
|
39
|
+
"manylinux_2_39_x86_64",
|
|
40
|
+
"linux_x86_64",
|
|
41
|
+
],
|
|
42
|
+
arm64: [
|
|
43
|
+
"manylinux_2_17_aarch64",
|
|
44
|
+
"manylinux_2_27_aarch64",
|
|
45
|
+
"manylinux_2_28_aarch64",
|
|
46
|
+
"manylinux_2_34_aarch64",
|
|
47
|
+
"manylinux_2_39_aarch64",
|
|
48
|
+
"linux_aarch64",
|
|
49
|
+
],
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export async function lockAndVendor(pluginRoot, archs = ["amd64", "arm64"]) {
|
|
53
|
+
// ponytail: pip --platform used intentionally (not QEMU) — downloads wheels without running target arch code.
|
|
54
|
+
const reqTxt = resolve(pluginRoot, "requirements.txt");
|
|
55
|
+
if (!existsSync(reqTxt)) {
|
|
56
|
+
log.warn("requirements.txt not found — lock/vendor skipped");
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
await ensureImage();
|
|
61
|
+
|
|
62
|
+
log.step("generating lock (uv pip compile)…");
|
|
63
|
+
const lockResult = spawnSync(
|
|
64
|
+
"docker",
|
|
65
|
+
[
|
|
66
|
+
"run", "--rm",
|
|
67
|
+
"-v", `${pluginRoot}:/plugin`,
|
|
68
|
+
PYTHON_DEV_IMAGE,
|
|
69
|
+
"bash", "-c",
|
|
70
|
+
"set -e && cd /plugin && mkdir -p dist && uv pip compile requirements.txt --python-version 3.12 -o dist/requirements.lock",
|
|
71
|
+
],
|
|
72
|
+
{ stdio: "inherit" },
|
|
73
|
+
);
|
|
74
|
+
if (lockResult.status !== 0) throw new Error("lock generation failed (uv pip compile)");
|
|
75
|
+
log.ok("dist/requirements.lock ready");
|
|
76
|
+
|
|
77
|
+
const failed = [];
|
|
78
|
+
for (const arch of archs) {
|
|
79
|
+
const pipPlatforms = PIP_PLATFORM[arch];
|
|
80
|
+
if (!pipPlatforms) { log.warn(`unknown arch '${arch}' — skipped`); continue; }
|
|
81
|
+
log.step(`vendoring wheels for ${arch}…`);
|
|
82
|
+
const r = spawnSync(
|
|
83
|
+
"docker",
|
|
84
|
+
[
|
|
85
|
+
"run", "--rm",
|
|
86
|
+
"-e", "PIP_ROOT_USER_ACTION=ignore",
|
|
87
|
+
"-v", `${pluginRoot}:/plugin`,
|
|
88
|
+
"-w", "/plugin",
|
|
89
|
+
PYTHON_DEV_IMAGE,
|
|
90
|
+
"bash", "-c",
|
|
91
|
+
"mkdir -p dist/wheels && pip3 download -r dist/requirements.lock --no-deps --only-binary=:all: -d dist/wheels -q " +
|
|
92
|
+
"--python-version 312 --implementation cp --abi cp312 " +
|
|
93
|
+
pipPlatforms.map((p) => `--platform ${p}`).join(" "),
|
|
94
|
+
],
|
|
95
|
+
{ stdio: "inherit" },
|
|
96
|
+
);
|
|
97
|
+
if (r.status !== 0) {
|
|
98
|
+
log.warn(`wheel vendoring failed for ${arch}`);
|
|
99
|
+
failed.push(arch);
|
|
100
|
+
} else {
|
|
101
|
+
log.ok(`dist/wheels/ ready (${arch})`);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (failed.length === archs.length) {
|
|
106
|
+
throw new Error(`wheel vendoring failed for all archs: ${failed.join(", ")}`);
|
|
107
|
+
}
|
|
108
|
+
return failed;
|
|
109
|
+
}
|
package/cli/src/ros2.mjs
CHANGED
|
@@ -3,14 +3,10 @@
|
|
|
3
3
|
import { spawnSync } from "node:child_process";
|
|
4
4
|
import { existsSync, readdirSync } from "node:fs";
|
|
5
5
|
import { dirname, resolve } from "node:path";
|
|
6
|
-
import { hasBin,
|
|
6
|
+
import { hasBin, log, pruneMuskatImages, resolveDockerfile } from "./util.mjs";
|
|
7
7
|
|
|
8
8
|
export const ROS2_DEV_IMAGE = "muscat-pk-ros2-dev";
|
|
9
9
|
|
|
10
|
-
// Dockerfile lives inside the kit — plugin authors never see or edit it.
|
|
11
|
-
// It has no COPY/ADD, so the build context is irrelevant (its own dir is used).
|
|
12
|
-
const DOCKERFILE = resolve(kitRoot, "cli/docker/Dockerfile.dev");
|
|
13
|
-
|
|
14
10
|
/** First package directory under ros2_ws/src (the colcon package name). */
|
|
15
11
|
export function ros2PackageName(root) {
|
|
16
12
|
const srcDir = resolve(root, "ros2_ws/src");
|
|
@@ -25,20 +21,25 @@ export function assertDockerReady() {
|
|
|
25
21
|
if (!hasBin("docker")) {
|
|
26
22
|
throw new Error("Docker not found. ROS2 needs Docker (Jazzy + Python 3.12 container).");
|
|
27
23
|
}
|
|
28
|
-
if (!existsSync(DOCKERFILE)) {
|
|
29
|
-
throw new Error(`kit Dockerfile missing at ${DOCKERFILE} (reinstall muscat-plugin-kit).`);
|
|
30
|
-
}
|
|
31
24
|
}
|
|
32
25
|
|
|
26
|
+
export const ARCH_DOCKER_PLATFORM = {
|
|
27
|
+
amd64: "linux/amd64",
|
|
28
|
+
arm64: "linux/arm64",
|
|
29
|
+
};
|
|
30
|
+
|
|
33
31
|
/** Build the dev image from the kit's bundled Dockerfile (Docker layer-caches). */
|
|
34
|
-
export function ensureImage(image = ROS2_DEV_IMAGE) {
|
|
35
|
-
|
|
32
|
+
export async function ensureImage(image = ROS2_DEV_IMAGE, { platform = null } = {}) {
|
|
33
|
+
const dockerfile = await resolveDockerfile("Dockerfile.dev");
|
|
34
|
+
log.step(`docker build -t ${image}${platform ? ` (${platform})` : ""} (first run is slow, then cached)…`);
|
|
35
|
+
const platformFlags = platform ? ["--platform", platform] : [];
|
|
36
36
|
const r = spawnSync(
|
|
37
37
|
"docker",
|
|
38
|
-
["build", "-t", image, "-f",
|
|
38
|
+
["build", ...platformFlags, "-t", image, "-f", dockerfile, dirname(dockerfile)],
|
|
39
39
|
{ stdio: "inherit" },
|
|
40
40
|
);
|
|
41
41
|
if (r.status !== 0) throw new Error("docker build failed.");
|
|
42
|
+
pruneMuskatImages();
|
|
42
43
|
}
|
|
43
44
|
|
|
44
45
|
/**
|
|
@@ -46,20 +47,44 @@ export function ensureImage(image = ROS2_DEV_IMAGE) {
|
|
|
46
47
|
* (the workspace is mounted). symlink=true for dev (fast, edit-in-place);
|
|
47
48
|
* symlink=false for export builds that ship in the ZIP (real copies, relocatable).
|
|
48
49
|
*/
|
|
49
|
-
|
|
50
|
+
/**
|
|
51
|
+
* arch=null → dev mode, builds to ros2_ws/install/ (native)
|
|
52
|
+
* arch="amd64"|"arm64" → export mode, builds to ros2_ws/install-{arch}/ using arch-specific image
|
|
53
|
+
*/
|
|
54
|
+
/**
|
|
55
|
+
* symlink=true (dev): ros2_ws/install/ — local dev workspace, not for ZIP
|
|
56
|
+
* symlink=false, arch=null (rclpy export): dist/ros2_ws/install/
|
|
57
|
+
* symlink=false, arch="amd64"|"arm64" (rclcpp export): dist/ros2_ws/install-{arch}/
|
|
58
|
+
*/
|
|
59
|
+
export function colconBuild(root, { image = ROS2_DEV_IMAGE, symlink = false, arch = null } = {}) {
|
|
60
|
+
// paths are relative to ros2_ws/ inside the container
|
|
61
|
+
let installBase;
|
|
62
|
+
if (symlink) {
|
|
63
|
+
installBase = "install";
|
|
64
|
+
} else if (arch) {
|
|
65
|
+
installBase = `../dist/ros2_ws/install-${arch}`;
|
|
66
|
+
} else {
|
|
67
|
+
installBase = "../dist/ros2_ws/install";
|
|
68
|
+
}
|
|
50
69
|
const flag = symlink ? "--symlink-install" : "";
|
|
51
70
|
const script = [
|
|
52
|
-
// --ignore-installed: don't try to uninstall debian-managed packages
|
|
53
|
-
// (e.g. psutil), which fails with "RECORD file not found".
|
|
54
71
|
"pip install -r requirements.txt --break-system-packages --ignore-installed -q || true",
|
|
55
72
|
"cd ros2_ws",
|
|
56
|
-
|
|
73
|
+
// ponytail: rm only on cross-arch; same-arch dev rebuilds keep the cache
|
|
74
|
+
...(arch ? ["rm -rf build"] : []),
|
|
75
|
+
`colcon build ${flag} --install-base ${installBase}`.trim(),
|
|
57
76
|
].join(" && ");
|
|
58
|
-
|
|
77
|
+
const label = arch
|
|
78
|
+
? `colcon build (${arch}) → dist/ros2_ws/install-${arch}/…`
|
|
79
|
+
: `colcon build${symlink ? " --symlink-install" : ""} (in container)…`;
|
|
80
|
+
log.step(label);
|
|
81
|
+
const actualImage = arch ? `${ROS2_DEV_IMAGE}-${arch}` : image;
|
|
82
|
+
const dockerPlatform = arch ? ARCH_DOCKER_PLATFORM[arch] : null;
|
|
83
|
+
const platformFlags = dockerPlatform ? ["--platform", dockerPlatform] : [];
|
|
59
84
|
const r = spawnSync(
|
|
60
85
|
"docker",
|
|
61
|
-
["run", "--rm", "-v", `${root}:/plugin`, "-w", "/plugin",
|
|
86
|
+
["run", "--rm", ...platformFlags, "-e", "PIP_ROOT_USER_ACTION=ignore", "-v", `${root}:/plugin`, "-w", "/plugin", actualImage, "bash", "-lc", script],
|
|
62
87
|
{ cwd: root, stdio: "inherit" },
|
|
63
88
|
);
|
|
64
|
-
if (r.status !== 0) throw new Error(
|
|
89
|
+
if (r.status !== 0) throw new Error(`colcon build failed${arch ? ` (${arch})` : ""}.`);
|
|
65
90
|
}
|
package/cli/src/sdk.mjs
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
// muscat-pk sdk <list|update [version]> — manage the python rainbow-rb-sdk.
|
|
2
|
-
|
|
2
|
+
//
|
|
3
|
+
// Pins requirements.txt — the real install happens in the `dev`/`dev:back`
|
|
4
|
+
// Docker container. If a local .venv exists (see devBack.mjs's syncIdeVenv,
|
|
5
|
+
// for editor/linter support), also update it in place so pylint/pyright see
|
|
6
|
+
// the new version immediately; this is best-effort only.
|
|
3
7
|
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
4
8
|
import { resolve } from "node:path";
|
|
5
|
-
import {
|
|
9
|
+
import { spawnSync } from "node:child_process";
|
|
10
|
+
import { findPluginRoot, log, venvPython } from "./util.mjs";
|
|
6
11
|
|
|
7
12
|
const PKG = "rainbow-rb-sdk";
|
|
8
13
|
|
|
@@ -50,15 +55,12 @@ export async function runSdk(args = []) {
|
|
|
50
55
|
writeFileSync(reqs, content);
|
|
51
56
|
log.ok(`requirements.txt → ${line}`);
|
|
52
57
|
|
|
53
|
-
const py = resolve(root, ".venv"
|
|
58
|
+
const py = venvPython(resolve(root, ".venv"));
|
|
54
59
|
if (existsSync(py)) {
|
|
55
|
-
log.step("pip install -r requirements.txt…");
|
|
56
|
-
spawnSync(py, ["-m", "pip", "install", "-q", "-r", reqs], {
|
|
57
|
-
cwd: root,
|
|
58
|
-
stdio: "inherit",
|
|
59
|
-
});
|
|
60
|
+
log.step("pip install -r requirements.txt (.venv, for your editor)…");
|
|
61
|
+
spawnSync(py, ["-m", "pip", "install", "-q", "-r", reqs], { cwd: root, stdio: "inherit" });
|
|
60
62
|
} else {
|
|
61
|
-
log.
|
|
63
|
+
log.info("Installed automatically on the next `muscat-pk dev` / `dev:back` (Docker container).");
|
|
62
64
|
}
|
|
63
65
|
return;
|
|
64
66
|
}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { createServer } from "node:http";
|
|
2
|
+
import { randomUUID } from "node:crypto";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
import { Server } from "socket.io";
|
|
5
|
+
|
|
6
|
+
// Self-contained logger — this module also runs standalone inside the bridge
|
|
7
|
+
// Docker container, where ./util.mjs is not available.
|
|
8
|
+
const log = {
|
|
9
|
+
step: (...m) => console.log("›", ...m),
|
|
10
|
+
warn: (...m) => console.warn("⚠", ...m),
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const DEFAULT_ACTION_TIMEOUT_MS = 10_000;
|
|
14
|
+
|
|
15
|
+
export function startSocketBridge({ port = 10000, host = "0.0.0.0" } = {}) {
|
|
16
|
+
const httpServer = createServer();
|
|
17
|
+
const io = new Server(httpServer, { cors: { origin: "*" } });
|
|
18
|
+
|
|
19
|
+
// topic → socketId (serve_register로 등록된 queryable)
|
|
20
|
+
const queryables = new Map();
|
|
21
|
+
// call_id → { timer, resolve } (action → serve_call → serve_reply 대기)
|
|
22
|
+
const pending = new Map();
|
|
23
|
+
|
|
24
|
+
function cleanupSocket(socket) {
|
|
25
|
+
for (const [topic, sid] of queryables) {
|
|
26
|
+
if (sid === socket.id) queryables.delete(topic);
|
|
27
|
+
}
|
|
28
|
+
for (const [id, p] of pending) {
|
|
29
|
+
if (p.sid !== socket.id) continue;
|
|
30
|
+
clearTimeout(p.timer);
|
|
31
|
+
p.resolve(undefined);
|
|
32
|
+
pending.delete(id);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
io.on("connection", (socket) => {
|
|
37
|
+
socket.on("sub", async (data = {}) => {
|
|
38
|
+
if (!data.topic) return;
|
|
39
|
+
await socket.join(`t:${data.topic}`);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
socket.on("unsub", async (data = {}) => {
|
|
43
|
+
if (!data.topic) return;
|
|
44
|
+
await socket.leave(`t:${data.topic}`);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
socket.on("pub", (data = {}) => {
|
|
48
|
+
const { topic, payload } = data;
|
|
49
|
+
if (!topic) return;
|
|
50
|
+
io.to(`t:${topic}`).emit("msg", { topic, payload });
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
socket.on("serve_register", (data = {}) => {
|
|
54
|
+
if (!data.topic) return;
|
|
55
|
+
queryables.set(data.topic, socket.id);
|
|
56
|
+
log.step(`serve registered: ${data.topic}`);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
socket.on("serve_unregister", (data = {}) => {
|
|
60
|
+
if (queryables.get(data.topic) === socket.id) queryables.delete(data.topic);
|
|
61
|
+
if (data.topic) log.step(`serve unregistered: ${data.topic}`);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
socket.on("serve_reply", (data = {}) => {
|
|
65
|
+
const p = pending.get(data.id);
|
|
66
|
+
if (!p) return;
|
|
67
|
+
clearTimeout(p.timer);
|
|
68
|
+
p.resolve(data.payload);
|
|
69
|
+
pending.delete(data.id);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
socket.on("action", (data = {}, ack) => {
|
|
73
|
+
const { topic, payload } = data;
|
|
74
|
+
const targetSid = queryables.get(topic);
|
|
75
|
+
const target = targetSid && io.sockets.sockets.get(targetSid);
|
|
76
|
+
if (!target) {
|
|
77
|
+
log.warn(`action has no handler: ${topic}`);
|
|
78
|
+
if (typeof ack === "function") ack({ error: `No handler registered for ${topic}` });
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
log.step(`action: ${topic}`);
|
|
82
|
+
const id = randomUUID();
|
|
83
|
+
const timer = setTimeout(() => {
|
|
84
|
+
pending.delete(id);
|
|
85
|
+
if (typeof ack === "function") ack(undefined);
|
|
86
|
+
}, DEFAULT_ACTION_TIMEOUT_MS);
|
|
87
|
+
pending.set(id, {
|
|
88
|
+
sid: targetSid,
|
|
89
|
+
timer,
|
|
90
|
+
resolve: (v) => { if (typeof ack === "function") ack(v); },
|
|
91
|
+
});
|
|
92
|
+
target.emit("serve_call", { id, topic, payload });
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
socket.on("disconnect", () => cleanupSocket(socket));
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
return new Promise((resolve) => {
|
|
99
|
+
httpServer.once("error", (err) => {
|
|
100
|
+
if (err.code === "EADDRINUSE") {
|
|
101
|
+
log.warn(`Socket.IO bridge already running on :${port} — skipping`);
|
|
102
|
+
io.close();
|
|
103
|
+
httpServer.close();
|
|
104
|
+
resolve({ close: () => {} });
|
|
105
|
+
} else {
|
|
106
|
+
throw err;
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
httpServer.listen(port, host, () => {
|
|
111
|
+
log.step(`Socket.IO bridge listening on ws://127.0.0.1:${port}`);
|
|
112
|
+
|
|
113
|
+
const close = () => {
|
|
114
|
+
for (const p of pending.values()) {
|
|
115
|
+
clearTimeout(p.timer);
|
|
116
|
+
p.resolve(undefined);
|
|
117
|
+
}
|
|
118
|
+
pending.clear();
|
|
119
|
+
queryables.clear();
|
|
120
|
+
io.close();
|
|
121
|
+
httpServer.close();
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
resolve({ close });
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// When executed directly (inside the bridge Docker container), start the server.
|
|
130
|
+
if (process.argv[1] && process.argv[1] === fileURLToPath(import.meta.url)) {
|
|
131
|
+
const port = Number(process.env.PORT) || 10000;
|
|
132
|
+
startSocketBridge({ port });
|
|
133
|
+
}
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
// muscat-pk storybook — serve the bundled Storybook (foundations + muscat) so
|
|
2
|
+
// plugin authors can browse the real rb-components UI while developing.
|
|
3
|
+
//
|
|
4
|
+
// The static build is produced from apps/storybook (MUSCAT_STORYBOOK=true → only
|
|
5
|
+
// the 1.foundations + 4.muscat sections, ordering-number prefixes stripped) and
|
|
6
|
+
// staged into cli/storybook-dist so it ships inside the published muscat-pk.
|
|
7
|
+
// In the monorepo it's built on demand if missing (or with --rebuild).
|
|
8
|
+
import { createServer } from "node:http";
|
|
9
|
+
import {
|
|
10
|
+
cpSync,
|
|
11
|
+
createReadStream,
|
|
12
|
+
existsSync,
|
|
13
|
+
mkdirSync,
|
|
14
|
+
rmSync,
|
|
15
|
+
statSync,
|
|
16
|
+
} from "node:fs";
|
|
17
|
+
import { execSync, spawn } from "node:child_process";
|
|
18
|
+
import { copyFileSync } from "node:fs";
|
|
19
|
+
import { extname, join, resolve } from "node:path";
|
|
20
|
+
import { kitRoot, log, parseArgs } from "./util.mjs";
|
|
21
|
+
|
|
22
|
+
// Shipped location (under cli/ → included in the npm "files" list).
|
|
23
|
+
const SHIPPED_DIST = resolve(kitRoot, "cli/storybook-dist");
|
|
24
|
+
// Raw .stories.tsx sources, staged alongside the compiled build — the `mcp`
|
|
25
|
+
// command's get_component_example tool reads these directly (real usage
|
|
26
|
+
// code, not just prop types) without needing a Storybook runtime.
|
|
27
|
+
export const SHIPPED_STORIES_SRC = resolve(SHIPPED_DIST, "_stories-src");
|
|
28
|
+
// Monorepo source (absent in an external install).
|
|
29
|
+
const REPO_ROOT = resolve(kitRoot, "../..");
|
|
30
|
+
const REPO_STORYBOOK = resolve(REPO_ROOT, "apps/storybook");
|
|
31
|
+
const REPO_BUILD_OUT = resolve(REPO_STORYBOOK, "storybook-static-muscat");
|
|
32
|
+
const REPO_MUSCAT_STORIES = resolve(REPO_STORYBOOK, "stories/4.muscat");
|
|
33
|
+
const REPO_DESIGN_TOKENS = resolve(
|
|
34
|
+
REPO_ROOT,
|
|
35
|
+
"packages/rb-styles/css/output/rb-token.css",
|
|
36
|
+
);
|
|
37
|
+
// Generated Tailwind v4 token file (@theme colors + @utility typo-*), staged so
|
|
38
|
+
// the `mcp` command's *_design_tokens tools work in an external install too.
|
|
39
|
+
export const SHIPPED_DESIGN_TOKENS = resolve(SHIPPED_DIST, "_design-tokens.css");
|
|
40
|
+
|
|
41
|
+
const CONTENT_TYPE = {
|
|
42
|
+
".html": "text/html; charset=utf-8",
|
|
43
|
+
".js": "text/javascript; charset=utf-8",
|
|
44
|
+
".mjs": "text/javascript; charset=utf-8",
|
|
45
|
+
".css": "text/css; charset=utf-8",
|
|
46
|
+
".json": "application/json; charset=utf-8",
|
|
47
|
+
".map": "application/json; charset=utf-8",
|
|
48
|
+
".svg": "image/svg+xml",
|
|
49
|
+
".png": "image/png",
|
|
50
|
+
".jpg": "image/jpeg",
|
|
51
|
+
".jpeg": "image/jpeg",
|
|
52
|
+
".webp": "image/webp",
|
|
53
|
+
".gif": "image/gif",
|
|
54
|
+
".ico": "image/x-icon",
|
|
55
|
+
".woff": "font/woff",
|
|
56
|
+
".woff2": "font/woff2",
|
|
57
|
+
".ttf": "font/ttf",
|
|
58
|
+
".wasm": "application/wasm",
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
// Build apps/storybook (muscat subset) and stage it into cli/storybook-dist.
|
|
62
|
+
// Monorepo only. Outside the monorepo (e.g. re-packing an already-published
|
|
63
|
+
// copy) it's a no-op — the shipped cli/storybook-dist is already in place.
|
|
64
|
+
export function buildStorybook() {
|
|
65
|
+
if (!existsSync(REPO_STORYBOOK)) {
|
|
66
|
+
log.info("apps/storybook not found — using the pre-staged storybook-dist.");
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
log.step("building Storybook (foundations + muscat)…");
|
|
70
|
+
execSync("yarn workspace storybook storybook:build:muscat", {
|
|
71
|
+
cwd: REPO_ROOT,
|
|
72
|
+
stdio: "inherit",
|
|
73
|
+
env: { ...process.env, MUSCAT_STORYBOOK: "true" },
|
|
74
|
+
});
|
|
75
|
+
rmSync(SHIPPED_DIST, { recursive: true, force: true });
|
|
76
|
+
mkdirSync(SHIPPED_DIST, { recursive: true });
|
|
77
|
+
cpSync(REPO_BUILD_OUT, SHIPPED_DIST, { recursive: true });
|
|
78
|
+
|
|
79
|
+
// Stage raw .stories.tsx sources (not just the compiled JS bundle) for the
|
|
80
|
+
// `mcp` command's get_component_example tool.
|
|
81
|
+
if (existsSync(REPO_MUSCAT_STORIES)) {
|
|
82
|
+
cpSync(REPO_MUSCAT_STORIES, SHIPPED_STORIES_SRC, {
|
|
83
|
+
recursive: true,
|
|
84
|
+
filter: (src) => statSync(src).isDirectory() || src.endsWith(".stories.tsx"),
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Stage the design-token CSS for the `mcp` command's *_design_tokens tools.
|
|
89
|
+
if (existsSync(REPO_DESIGN_TOKENS)) {
|
|
90
|
+
copyFileSync(REPO_DESIGN_TOKENS, SHIPPED_DESIGN_TOKENS);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
log.ok(`storybook → ${SHIPPED_DIST}`);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function openBrowser(url) {
|
|
97
|
+
const cmd =
|
|
98
|
+
process.platform === "darwin"
|
|
99
|
+
? "open"
|
|
100
|
+
: process.platform === "win32"
|
|
101
|
+
? "start"
|
|
102
|
+
: "xdg-open";
|
|
103
|
+
try {
|
|
104
|
+
spawn(cmd, [url], {
|
|
105
|
+
stdio: "ignore",
|
|
106
|
+
detached: true,
|
|
107
|
+
shell: process.platform === "win32",
|
|
108
|
+
}).unref();
|
|
109
|
+
} catch {
|
|
110
|
+
/* headless / no browser — the URL is printed anyway */
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function serve(distDir, port) {
|
|
115
|
+
const server = createServer((req, res) => {
|
|
116
|
+
const url = decodeURIComponent((req.url || "/").split("?")[0]);
|
|
117
|
+
const rel = url === "/" ? "/index.html" : url;
|
|
118
|
+
const filePath = resolve(distDir, `.${rel}`);
|
|
119
|
+
|
|
120
|
+
// Serve the file if it's inside distDir and exists; otherwise fall back to
|
|
121
|
+
// index.html (Storybook is a single-page app).
|
|
122
|
+
if (
|
|
123
|
+
filePath.startsWith(distDir) &&
|
|
124
|
+
existsSync(filePath) &&
|
|
125
|
+
statSync(filePath).isFile()
|
|
126
|
+
) {
|
|
127
|
+
const type = CONTENT_TYPE[extname(filePath)];
|
|
128
|
+
if (type) res.setHeader("Content-Type", type);
|
|
129
|
+
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
130
|
+
createReadStream(filePath).pipe(res);
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
res.setHeader("Content-Type", "text/html; charset=utf-8");
|
|
134
|
+
createReadStream(join(distDir, "index.html")).pipe(res);
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
server.on("error", (err) => {
|
|
138
|
+
if (err.code === "EADDRINUSE") {
|
|
139
|
+
log.error(`port ${port} is in use — pass a free one with --port <n>.`);
|
|
140
|
+
process.exit(1);
|
|
141
|
+
}
|
|
142
|
+
throw err;
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
server.listen(port, () => {
|
|
146
|
+
const url = `http://localhost:${port}`;
|
|
147
|
+
log.ok(`Storybook → ${url}`);
|
|
148
|
+
openBrowser(url);
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
export async function runStorybook(args = []) {
|
|
153
|
+
const { port = "6007", rebuild } = parseArgs(args, { booleans: ["rebuild"] });
|
|
154
|
+
|
|
155
|
+
const staged = existsSync(join(SHIPPED_DIST, "index.html"));
|
|
156
|
+
if (rebuild || !staged) {
|
|
157
|
+
if (existsSync(REPO_STORYBOOK)) {
|
|
158
|
+
buildStorybook();
|
|
159
|
+
} else if (!staged) {
|
|
160
|
+
throw new Error(
|
|
161
|
+
`Storybook build not found at ${SHIPPED_DIST}.\n` +
|
|
162
|
+
" This build of muscat-pk was published without the bundled Storybook.",
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
serve(SHIPPED_DIST, Number(port));
|
|
168
|
+
}
|
package/cli/src/type.mjs
CHANGED
|
@@ -1,21 +1,20 @@
|
|
|
1
1
|
// muscat-pk type change — switch an existing plugin's backend type.
|
|
2
|
-
// python
|
|
3
|
-
// the
|
|
2
|
+
// python | cpp | ros2 (rclpy) | ros2-cpp (rclcpp).
|
|
3
|
+
// Adds the matching backend overlay; never deletes existing user code
|
|
4
|
+
// (e.g. ros2_ws/ or cpp/ are left in place when switching away).
|
|
4
5
|
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
5
|
-
import { createInterface } from "node:readline/promises";
|
|
6
6
|
import { basename, resolve } from "node:path";
|
|
7
|
-
import { findPluginRoot, log } from "./util.mjs";
|
|
8
|
-
import {
|
|
7
|
+
import { findPluginRoot, log, prompt } from "./util.mjs";
|
|
8
|
+
import {
|
|
9
|
+
TYPE_CHOICES,
|
|
10
|
+
applyTokens,
|
|
11
|
+
deriveNames,
|
|
12
|
+
overlayCpp,
|
|
13
|
+
overlayRos2,
|
|
14
|
+
runtimeForChoice,
|
|
15
|
+
} from "./new.mjs";
|
|
9
16
|
|
|
10
|
-
const TYPES =
|
|
11
|
-
|
|
12
|
-
async function prompt(question, fallback) {
|
|
13
|
-
if (!process.stdin.isTTY) return fallback;
|
|
14
|
-
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
15
|
-
const answer = (await rl.question(question)).trim();
|
|
16
|
-
rl.close();
|
|
17
|
-
return answer || fallback;
|
|
18
|
-
}
|
|
17
|
+
const TYPES = Object.keys(TYPE_CHOICES);
|
|
19
18
|
|
|
20
19
|
function readManifest(root) {
|
|
21
20
|
const path = resolve(root, "manifest.json");
|
|
@@ -23,44 +22,54 @@ function readManifest(root) {
|
|
|
23
22
|
return { path, json: JSON.parse(readFileSync(path, "utf8")) };
|
|
24
23
|
}
|
|
25
24
|
|
|
25
|
+
// Derive the current `--type`-style key from a manifest runtime block.
|
|
26
|
+
function currentTypeKey(runtime) {
|
|
27
|
+
if (runtime?.type === "ros2") return runtime.rosClient === "rclcpp" ? "ros2-cpp" : "ros2";
|
|
28
|
+
return runtime?.type ?? "python";
|
|
29
|
+
}
|
|
30
|
+
|
|
26
31
|
export async function runType(args) {
|
|
27
|
-
// accept `type change`, `type`, `type --to ros2`
|
|
32
|
+
// accept `type change`, `type`, `type --to ros2-cpp`
|
|
28
33
|
const sub = args[0];
|
|
29
34
|
const toFlagIdx = args.indexOf("--to");
|
|
30
35
|
let to = toFlagIdx >= 0 ? args[toFlagIdx + 1] : undefined;
|
|
31
36
|
|
|
32
37
|
const root = findPluginRoot();
|
|
33
38
|
const { path, json } = readManifest(root);
|
|
34
|
-
const current = json.runtime
|
|
39
|
+
const current = currentTypeKey(json.runtime);
|
|
35
40
|
|
|
36
41
|
if (sub && sub !== "change") {
|
|
37
|
-
log.warn(`unknown subcommand '${sub}'. Usage: muscat-pk type change [--to python|ros2]`);
|
|
42
|
+
log.warn(`unknown subcommand '${sub}'. Usage: muscat-pk type change [--to python|cpp|ros2|ros2-cpp]`);
|
|
38
43
|
}
|
|
39
44
|
|
|
40
45
|
if (!to) {
|
|
41
46
|
console.log(`\n현재 타입: ${current}`);
|
|
42
47
|
console.log("변경할 타입을 선택하세요:");
|
|
43
48
|
console.log(" 1) Python");
|
|
44
|
-
console.log(" 2)
|
|
45
|
-
|
|
46
|
-
|
|
49
|
+
console.log(" 2) C++");
|
|
50
|
+
console.log(" 3) ROS2 (rclpy / Python)");
|
|
51
|
+
console.log(" 4) ROS2 (rclcpp / C++)");
|
|
52
|
+
const choice = await prompt("\n선택 [1/2/3/4]: ", "");
|
|
53
|
+
to = { "1": "python", "2": "cpp", "3": "ros2", "4": "ros2-cpp" }[choice];
|
|
47
54
|
}
|
|
48
55
|
|
|
49
56
|
if (!TYPES.includes(to)) {
|
|
50
|
-
throw new Error(`invalid type. choose python
|
|
57
|
+
throw new Error(`invalid type. choose python | cpp | ros2 | ros2-cpp.`);
|
|
51
58
|
}
|
|
52
59
|
if (to === current) {
|
|
53
60
|
log.info(`already '${current}' — nothing to change.`);
|
|
54
61
|
return;
|
|
55
62
|
}
|
|
56
63
|
|
|
57
|
-
|
|
58
|
-
|
|
64
|
+
const runtimeChoice = TYPE_CHOICES[to];
|
|
65
|
+
const { slug, pluginName, pluginClass, pluginId } = deriveNames(root);
|
|
66
|
+
|
|
67
|
+
if (runtimeChoice.type === "ros2") {
|
|
59
68
|
if (existsSync(resolve(root, "ros2_ws"))) {
|
|
60
69
|
log.warn("ros2_ws/ already exists — keeping it, only flipping manifest type.");
|
|
61
70
|
} else {
|
|
62
|
-
log.step(
|
|
63
|
-
overlayRos2(root, slug);
|
|
71
|
+
log.step(`adding ros2_ws/ overlay (${runtimeChoice.rosClient})`);
|
|
72
|
+
await overlayRos2(root, slug, runtimeChoice.rosClient);
|
|
64
73
|
applyTokens(root, {
|
|
65
74
|
__PLUGIN_ID__: pluginId,
|
|
66
75
|
__PLUGIN_NAME__: pluginName,
|
|
@@ -69,14 +78,28 @@ export async function runType(args) {
|
|
|
69
78
|
__RUNTIME_TYPE__: "ros2",
|
|
70
79
|
});
|
|
71
80
|
}
|
|
81
|
+
} else if (runtimeChoice.type === "cpp") {
|
|
82
|
+
if (existsSync(resolve(root, "cpp"))) {
|
|
83
|
+
log.warn("cpp/ already exists — keeping it, only flipping manifest type.");
|
|
84
|
+
} else {
|
|
85
|
+
log.step("adding cpp/ overlay");
|
|
86
|
+
await overlayCpp(root);
|
|
87
|
+
applyTokens(root, {
|
|
88
|
+
__PLUGIN_ID__: pluginId,
|
|
89
|
+
__PLUGIN_NAME__: pluginName,
|
|
90
|
+
__PLUGIN_SLUG__: slug,
|
|
91
|
+
__PLUGIN_CLASS__: pluginClass,
|
|
92
|
+
__RUNTIME_TYPE__: "cpp",
|
|
93
|
+
});
|
|
94
|
+
}
|
|
72
95
|
} else {
|
|
73
|
-
//
|
|
74
|
-
if (existsSync(resolve(root, "ros2_ws"))) {
|
|
75
|
-
log.warn("
|
|
96
|
+
// → python. Leave any ros2_ws/ or cpp/ in place (never delete user code).
|
|
97
|
+
if (existsSync(resolve(root, "ros2_ws")) || existsSync(resolve(root, "cpp"))) {
|
|
98
|
+
log.warn("existing backend dir left in place (not deleted). Remove it manually if unused.");
|
|
76
99
|
}
|
|
77
100
|
}
|
|
78
101
|
|
|
79
|
-
json.runtime =
|
|
102
|
+
json.runtime = runtimeForChoice(runtimeChoice, slug);
|
|
80
103
|
writeFileSync(path, JSON.stringify(json, null, 2) + "\n");
|
|
81
104
|
log.ok(`${basename(root)} type: ${current} → ${to}`);
|
|
82
105
|
}
|