@rainbow-robotics/muscat-plugin-kit 1.10.1-dev.1 → 1.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +282 -282
- package/cli/README.md +274 -274
- package/cli/bin/create-muscat-plugin.mjs +8 -8
- package/cli/bin/muscat-pk.mjs +155 -155
- package/cli/bundle-templates.mjs +31 -31
- package/cli/docker/Dockerfile.cpp +28 -28
- package/cli/docker/Dockerfile.dev +30 -30
- package/cli/docker/Dockerfile.python +21 -21
- package/cli/m5-e2e.mjs +69 -69
- package/cli/prepack.mjs +10 -10
- package/cli/src/ai-rules.mjs +70 -70
- package/cli/src/build.mjs +447 -447
- package/cli/src/check-package.mjs +13 -13
- package/cli/src/completion.mjs +166 -166
- package/cli/src/cpp.mjs +78 -78
- package/cli/src/cppIde.mjs +75 -75
- package/cli/src/dev.mjs +165 -165
- package/cli/src/devBack.mjs +734 -727
- package/cli/src/devUi.mjs +247 -243
- package/cli/src/esbuild.mjs +56 -56
- package/cli/src/host_agent.py +223 -223
- package/cli/src/manifest.mjs +287 -287
- package/cli/src/mcp.mjs +1071 -1071
- package/cli/src/muscatLocal.mjs +209 -209
- package/cli/src/new.mjs +343 -343
- package/cli/src/pluginDevServer.mjs +111 -111
- package/cli/src/ports.mjs +193 -193
- package/cli/src/python.mjs +112 -112
- package/cli/src/ros2.mjs +109 -109
- package/cli/src/sdk.mjs +117 -117
- package/cli/src/storybook.mjs +168 -168
- package/cli/src/type.mjs +141 -141
- package/cli/src/uninstall.mjs +81 -81
- package/cli/src/update.mjs +295 -295
- package/cli/src/util.mjs +441 -441
- package/cli/src/zenohDev.mjs +83 -81
- package/cli/storybook-dist/_design-tokens.css +4957 -4957
- package/cli/storybook-dist/_stories-src/NxAvatar.stories.tsx +27 -27
- package/cli/storybook-dist/_stories-src/NxPagination.stories.tsx +28 -28
- package/cli/storybook-dist/_stories-src/RBAccordion/RBAccordion.stories.tsx +46 -46
- package/cli/storybook-dist/_stories-src/RBAccordion/RBAccordionGroup.stories.tsx +73 -73
- package/cli/storybook-dist/_stories-src/RBBadge/RBBadge.stories.tsx +93 -93
- package/cli/storybook-dist/_stories-src/RBBattery/RBBattery.stories.tsx +74 -74
- package/cli/storybook-dist/_stories-src/RBButton/RBCheckIconButton.stories.tsx +28 -28
- package/cli/storybook-dist/_stories-src/RBButton/RBCheckLabelButton.stories.tsx +84 -84
- package/cli/storybook-dist/_stories-src/RBButton/RBIconButton.stories.tsx +57 -57
- package/cli/storybook-dist/_stories-src/RBButton/RBInlineLabelButton.stories.tsx +41 -41
- package/cli/storybook-dist/_stories-src/RBButton/RBLabelButton.stories.tsx +60 -60
- package/cli/storybook-dist/_stories-src/RBDatePicker/RBDateInput.stories.tsx +44 -44
- package/cli/storybook-dist/_stories-src/RBDatePicker/RBRangeDateInput.stories.tsx +56 -56
- package/cli/storybook-dist/_stories-src/RBDialog/RBAlert.stories.tsx +51 -51
- package/cli/storybook-dist/_stories-src/RBDialog/RBConfirm.stories.tsx +55 -55
- package/cli/storybook-dist/_stories-src/RBDialog/RBPrompt.stories.tsx +52 -52
- package/cli/storybook-dist/_stories-src/RBDivider/RBDivider.stories.tsx +93 -93
- package/cli/storybook-dist/_stories-src/RBEmptyView/RBEmptyView.stories.tsx +49 -49
- package/cli/storybook-dist/_stories-src/RBIcons/RBColorIcons.stories.tsx +108 -108
- package/cli/storybook-dist/_stories-src/RBIcons/RBIcons.stories.tsx +106 -106
- package/cli/storybook-dist/_stories-src/RBInput/RBCheckBox.stories.tsx +89 -89
- package/cli/storybook-dist/_stories-src/RBInput/RBMultiRangeInput.stories.tsx +64 -64
- package/cli/storybook-dist/_stories-src/RBInput/RBRadioBox.stories.tsx +65 -65
- package/cli/storybook-dist/_stories-src/RBInput/RBRadioButton.stories.tsx +68 -68
- package/cli/storybook-dist/_stories-src/RBInput/RBSelectBox.stories.tsx +216 -216
- package/cli/storybook-dist/_stories-src/RBInput/RBSideNumberInput.stories.tsx +90 -90
- package/cli/storybook-dist/_stories-src/RBInput/RBText/RBTextArea.stories.tsx +45 -45
- package/cli/storybook-dist/_stories-src/RBInput/RBText/RBTextInput.stories.tsx +50 -50
- package/cli/storybook-dist/_stories-src/RBInput/RBTextField.stories.tsx +102 -102
- package/cli/storybook-dist/_stories-src/RBJoyStick/RBJoyStick.stories.tsx +31 -31
- package/cli/storybook-dist/_stories-src/RBLight/RBLight.stories.tsx +36 -36
- package/cli/storybook-dist/_stories-src/RBPagination/RBPagination.stories.tsx +49 -49
- package/cli/storybook-dist/_stories-src/RBShadcn/RBCard/RBCard.stories.tsx +89 -89
- package/cli/storybook-dist/_stories-src/RBShadcn/RBCommand/RBCommand.stories.tsx +116 -116
- package/cli/storybook-dist/_stories-src/RBShadcn/RBDialog/RBDialog.stories.tsx +74 -74
- package/cli/storybook-dist/_stories-src/RBShadcn/RBDrawer/RBDrawer.stories.tsx +99 -99
- package/cli/storybook-dist/_stories-src/RBShadcn/RBDropdownMenu/RBDropdownMenu.stories.tsx +123 -123
- package/cli/storybook-dist/_stories-src/RBShadcn/RBMenubar/RBMenubar.stories.tsx +135 -135
- package/cli/storybook-dist/_stories-src/RBShadcn/RBPopover/RBPopover.stories.tsx +69 -69
- package/cli/storybook-dist/_stories-src/RBShadcn/RBResizable/RBResizable.stories.tsx +49 -49
- package/cli/storybook-dist/_stories-src/RBShadcn/RBSheet/RBSheet.stories.tsx +91 -91
- package/cli/storybook-dist/_stories-src/RBShadcn/RBSlider/RBSlider.stories.tsx +38 -38
- package/cli/storybook-dist/_stories-src/RBShadcn/RBSwitch/RBSwitch.stories.tsx +112 -112
- package/cli/storybook-dist/_stories-src/RBShadcn/RBTabs/RBTabs.stories.tsx +75 -75
- package/cli/storybook-dist/_stories-src/RBShadcn/RBToggle/RBToggle.stories.tsx +51 -51
- package/cli/storybook-dist/_stories-src/RBShadcn/RBToggleGroup/RBToggleGroup.stories.tsx +84 -84
- package/cli/storybook-dist/_stories-src/RBTab/RBChipTab.stories.tsx +102 -102
- package/cli/storybook-dist/_stories-src/RBTab/RBChipsBoxTab.stories.tsx +78 -78
- package/cli/storybook-dist/_stories-src/RBTab/RBTab.stories.tsx +57 -57
- package/cli/storybook-dist/_stories-src/RBTable/RBTable.stories.tsx +177 -177
- package/cli/storybook-dist/_stories-src/RBTable/RBTableRow.stories.tsx +64 -64
- package/cli/storybook-dist/_stories-src/RBToast/RBToast.stories.tsx +117 -117
- package/cli/storybook-dist/_stories-src/RBTooltip/RBTooltip.stories.tsx +50 -50
- package/cli/storybook-dist/_stories-src/loading/RBSpinner.stories.tsx +30 -30
- package/cli/storybook-dist/_stories-src/nx-button/NxButton.stories.tsx +54 -54
- package/cli/storybook-dist/_stories-src/nx-button/NxPointerHoldButton.stories.tsx +57 -57
- package/cli/storybook-dist/_stories-src/nx-icons/NxIcons.stories.tsx +48 -48
- package/cli/storybook-dist/_stories-src/nx-inputs/NxNumberInput.stories.tsx +103 -103
- package/cli/storybook-dist/_stories-src/nx-inputs/NxRangeInput.stories.tsx +27 -27
- package/cli/storybook-dist/_stories-src/nx-inputs/NxSelectBox.stories.tsx +67 -67
- package/cli/storybook-dist/_stories-src/nx-inputs/NxSlideRange.stories.tsx +45 -45
- package/cli/storybook-dist/_stories-src/nx-inputs/NxSwitch.stories.tsx +27 -27
- package/cli/storybook-dist/_stories-src/nx-inputs/NxTextArea.stories.tsx +48 -48
- package/cli/storybook-dist/_stories-src/nx-inputs/NxTextInput.stories.tsx +46 -46
- package/cli/storybook-dist/assets/{Color-YHDXOIA2-D6JqZzDJ.js → Color-YHDXOIA2-B4IER17l.js} +1 -1
- package/cli/storybook-dist/assets/{Docs-ESb7JAHg.js → Docs-C8GCHFtK.js} +3 -3
- package/cli/storybook-dist/assets/{Docs-6gD2kUo1.js → Docs-CgdEMPQP.js} +2 -2
- package/cli/storybook-dist/assets/{Docs-B9wd8Ok7.js → Docs-Ck3WHvk6.js} +3 -3
- package/cli/storybook-dist/assets/{Docs-CgFbWWXM.js → Docs-D9NHsoeZ.js} +2 -2
- package/cli/storybook-dist/assets/{Docs-DBQup8Bu.js → Docs-DNYQC7nl.js} +3 -3
- package/cli/storybook-dist/assets/{Docs-CMjovnSY.js → Docs-DUfeiM4I.js} +4 -4
- package/cli/storybook-dist/assets/{DocsRenderer-CFRXHY34-BOUI1AHi.js → DocsRenderer-CFRXHY34-C0WhyDoR.js} +1 -1
- package/cli/storybook-dist/assets/{NxAvatar.stories-DsYFMUh3.js → NxAvatar.stories-CwnK8AUF.js} +1 -1
- package/cli/storybook-dist/assets/{NxButton.stories-CHfNcqsc.js → NxButton.stories-ueYdosfQ.js} +8 -8
- package/cli/storybook-dist/assets/{NxNumberInput.stories-BFw_4vFE.js → NxNumberInput.stories-M5ZCLbrK.js} +1 -1
- package/cli/storybook-dist/assets/{NxPagination.stories-DVfxyw4M.js → NxPagination.stories-bxxUnHEL.js} +1 -1
- package/cli/storybook-dist/assets/{NxPointerHoldButton.stories-BzyxUWoZ.js → NxPointerHoldButton.stories-BHxB2kr5.js} +1 -1
- package/cli/storybook-dist/assets/{NxRangeInput.stories-DmRdzBc1.js → NxRangeInput.stories-BKfr-fp4.js} +6 -6
- package/cli/storybook-dist/assets/{NxSelectBox.stories-B1KkNUOf.js → NxSelectBox.stories-CG8FuTBq.js} +1 -1
- package/cli/storybook-dist/assets/{NxSlideRange.stories-CyOdvfQ6.js → NxSlideRange.stories-BRTFtMTL.js} +1 -1
- package/cli/storybook-dist/assets/{NxSwitch.stories-DrDBw0qp.js → NxSwitch.stories-Bwuyzn-R.js} +1 -1
- package/cli/storybook-dist/assets/{NxTextArea.stories-DTB2aqNS.js → NxTextArea.stories-COq2sGqu.js} +1 -1
- package/cli/storybook-dist/assets/{NxTextInput.stories-DU0rucmM.js → NxTextInput.stories-CjsBLz05.js} +1 -1
- package/cli/storybook-dist/assets/{RBAccordion.stories-DTfOtXtp.js → RBAccordion.stories-BARwuZ0Q.js} +3 -3
- package/cli/storybook-dist/assets/{RBAccordionGroup.stories-9y9BjrUe.js → RBAccordionGroup.stories-COrPxETW.js} +10 -10
- package/cli/storybook-dist/assets/{RBAlert.stories-DLTAv9fT.js → RBAlert.stories-BQrkjZPt.js} +3 -3
- package/cli/storybook-dist/assets/{RBBadge.stories-BNMACewA.js → RBBadge.stories-BTsLL-lK.js} +1 -1
- package/cli/storybook-dist/assets/{RBBattery.stories-B3kXMAt5.js → RBBattery.stories-DAeQdJbc.js} +1 -1
- package/cli/storybook-dist/assets/{RBCard.stories-Y-s8R2n7.js → RBCard.stories-HyhOE80R.js} +39 -39
- package/cli/storybook-dist/assets/{RBCheckBox.stories-DBuT9tL4.js → RBCheckBox.stories-KFk0WqX_.js} +1 -1
- package/cli/storybook-dist/assets/{RBCheckIconButton.stories-CWu1TL56.js → RBCheckIconButton.stories-CXbbktF5.js} +1 -1
- package/cli/storybook-dist/assets/{RBCheckLabelButton.stories-sCu2MGCX.js → RBCheckLabelButton.stories-DWfYz_9Z.js} +17 -17
- package/cli/storybook-dist/assets/{RBChipTab.stories-BX9qLJkR.js → RBChipTab.stories-JPEgVFAS.js} +5 -5
- package/cli/storybook-dist/assets/{RBChipsBoxTab.stories-35u1aJ-P.js → RBChipsBoxTab.stories-CTPuWXrQ.js} +1 -1
- package/cli/storybook-dist/assets/{RBColorIcons.stories-DAOZ5Ies.js → RBColorIcons.stories-DiFRZ5jk.js} +1 -1
- package/cli/storybook-dist/assets/RBCommand.stories-Pf1HAVIR.js +73 -0
- package/cli/storybook-dist/assets/{RBConfirm.stories-iMXcUh7Z.js → RBConfirm.stories-D1cEPUXk.js} +3 -3
- package/cli/storybook-dist/assets/{RBDateInput.stories-hK5rXECf.js → RBDateInput.stories-RPYpCjig.js} +1 -1
- package/cli/storybook-dist/assets/RBDialog.stories-DJH-0XSR.js +38 -0
- package/cli/storybook-dist/assets/{RBDivider.stories-BAK-iZ1Z.js → RBDivider.stories-uEj1vOgK.js} +1 -1
- package/cli/storybook-dist/assets/{RBDrawer.stories-B2nqf2Nh.js → RBDrawer.stories-BiMzElb2.js} +12 -12
- package/cli/storybook-dist/assets/RBDropdownMenu.stories-Da_TBkla.js +86 -0
- package/cli/storybook-dist/assets/{RBEmptyView.stories-nCenrgBh.js → RBEmptyView.stories-BHeKGfPS.js} +1 -1
- package/cli/storybook-dist/assets/{RBIconButton.stories-DRH7O3sp.js → RBIconButton.stories-NEsRFoYp.js} +1 -1
- package/cli/storybook-dist/assets/{RBIcons.stories-D3PyJXG8.js → RBIcons.stories-CcZ-TTLS.js} +1 -1
- package/cli/storybook-dist/assets/{RBInlineLabelButton.stories-modQbt10.js → RBInlineLabelButton.stories-B0wpdQyR.js} +1 -1
- package/cli/storybook-dist/assets/{RBJoyStick.stories-BY14qVgR.js → RBJoyStick.stories-DEgBou3K.js} +1 -1
- package/cli/storybook-dist/assets/{RBLabelButton.stories-DzF7vGwm.js → RBLabelButton.stories-DT8drIsF.js} +1 -1
- package/cli/storybook-dist/assets/{RBLight.stories-lF4FRmVh.js → RBLight.stories-Dh-aoeyG.js} +1 -1
- package/cli/storybook-dist/assets/{RBMenubar.stories-XhrI7bsV.js → RBMenubar.stories-D-H7UqVh.js} +1 -1
- package/cli/storybook-dist/assets/{RBMultiRangeInput.stories-DprllQDl.js → RBMultiRangeInput.stories-hlclv6jI.js} +1 -1
- package/cli/storybook-dist/assets/{RBPagination.stories-2v2gBJfC.js → RBPagination.stories-DWCeoZ_S.js} +1 -1
- package/cli/storybook-dist/assets/{RBPopover.stories-C8iLIZpv.js → RBPopover.stories-C514M09_.js} +1 -1
- package/cli/storybook-dist/assets/{RBPrompt.stories-Th_HrWHI.js → RBPrompt.stories-BSItvfiT.js} +1 -1
- package/cli/storybook-dist/assets/{RBRadioBox.stories-CoHuLaN3.js → RBRadioBox.stories-BBb4YbFU.js} +1 -1
- package/cli/storybook-dist/assets/{RBRadioButton.stories-DULxE_ff.js → RBRadioButton.stories-CXyOGJCv.js} +1 -1
- package/cli/storybook-dist/assets/{RBRangeDateInput.stories-D8A9KBSS.js → RBRangeDateInput.stories-qvhubu0e.js} +1 -1
- package/cli/storybook-dist/assets/{RBResizable.stories-C41QfrQ3.js → RBResizable.stories-CZKeyGjH.js} +14 -14
- package/cli/storybook-dist/assets/{RBSelectBox.stories-C1gNmwzw.js → RBSelectBox.stories-CRKP3ybf.js} +1 -1
- package/cli/storybook-dist/assets/RBSheet.stories-sCM3ZJUa.js +39 -0
- package/cli/storybook-dist/assets/{RBSideNumberInput.stories-9LlgQ8nh.js → RBSideNumberInput.stories-Bb7gw8RF.js} +3 -3
- package/cli/storybook-dist/assets/{RBSlider.stories-oUgo5K9d.js → RBSlider.stories-23OAQU5z.js} +3 -3
- package/cli/storybook-dist/assets/{RBSpinner.stories-DDpohbY2.js → RBSpinner.stories-2xcQdcmt.js} +1 -1
- package/cli/storybook-dist/assets/{RBSwitch.stories-gW-GN7QO.js → RBSwitch.stories-BACUaJm_.js} +7 -7
- package/cli/storybook-dist/assets/{RBTab.stories-CN-PV3HH.js → RBTab.stories-CDHE3sVs.js} +1 -1
- package/cli/storybook-dist/assets/{RBTable.stories-BAZLpxtM.js → RBTable.stories-C0Cfhfl7.js} +29 -29
- package/cli/storybook-dist/assets/{RBTableRow.stories-CwjVrszB.js → RBTableRow.stories-BF8kIkpp.js} +1 -1
- package/cli/storybook-dist/assets/{RBTabs.stories-JuEo2sUL.js → RBTabs.stories-BdJWRq1o.js} +7 -7
- package/cli/storybook-dist/assets/{RBTextArea.stories-D0_Pv4qZ.js → RBTextArea.stories-CGy2xeYH.js} +3 -3
- package/cli/storybook-dist/assets/{RBTextField.stories-CCsOvZqV.js → RBTextField.stories-IfUOzxCM.js} +15 -15
- package/cli/storybook-dist/assets/{RBTextInput.stories-Cccn3VNm.js → RBTextInput.stories-VjXNFo4R.js} +3 -3
- package/cli/storybook-dist/assets/{RBToast.stories-I5617t0K.js → RBToast.stories-BzcobblV.js} +1 -1
- package/cli/storybook-dist/assets/{RBToggle.stories-DsgKjGsJ.js → RBToggle.stories-DuLE5mKv.js} +4 -4
- package/cli/storybook-dist/assets/{RBToggleGroup.stories-BZEzSDuz.js → RBToggleGroup.stories-CuR0N0GJ.js} +5 -5
- package/cli/storybook-dist/assets/{RBTooltip.stories-4oSyAWsA.js → RBTooltip.stories--aAgNC8_.js} +1 -1
- package/cli/storybook-dist/assets/{SideNumberInput-DSKbd0bG.js → SideNumberInput-DyWQxYUj.js} +743 -743
- package/cli/storybook-dist/assets/{entry-preview-B35XREGs.js → entry-preview-D7IHsza_.js} +1 -1
- package/cli/storybook-dist/assets/{iframe-BB797lmL.js → iframe-CbaIp5I-.js} +2 -2
- package/cli/storybook-dist/assets/{index-BU2567EP.js → index-C6CBgMuG.js} +3 -3
- package/cli/storybook-dist/assets/{preview-C7DaSWyc.js → preview-B-iYLDuW.js} +2 -2
- package/cli/storybook-dist/assets/{preview-CbuRHit4.js → preview-CRWqc9DH.js} +1 -1
- package/cli/storybook-dist/assets/{react-resizable-panels.browser-ChIvlwo7.js → react-resizable-panels.browser-8hC8dr-6.js} +8 -8
- package/cli/storybook-dist/iframe.html +2 -2
- package/cli/storybook-dist/index.html +1 -1
- package/cli/storybook-dist/project.json +1 -1
- package/cli/templates/common/.mcp.json +8 -8
- package/cli/templates/common/README.md +1231 -1231
- package/cli/templates/common/assets/icon.svg +45 -45
- package/cli/templates/common/manifest.json +26 -26
- package/cli/templates/common/package.json +22 -22
- package/cli/templates/common/py/main.py +125 -125
- package/cli/templates/common/tsconfig.json +13 -13
- package/cli/templates/common/ui/content.tsx +216 -216
- package/cli/templates/common/ui/style.css +6 -6
- package/cli/templates/common/vite.config.ts +10 -10
- package/cli/templates/cpp/cpp/main.cpp +73 -73
- package/cli/templates/ros2/ros2_ws/src/__PLUGIN_SLUG__/__PLUGIN_SLUG__/node.py +25 -25
- package/cli/templates/ros2/ros2_ws/src/__PLUGIN_SLUG__/package.xml +10 -10
- package/cli/templates/ros2/ros2_ws/src/__PLUGIN_SLUG__/setup.py +18 -18
- package/cli/templates/ros2-cpp/ros2_ws/src/__PLUGIN_SLUG__/package.xml +11 -11
- package/cli/templates/ros2-cpp/ros2_ws/src/__PLUGIN_SLUG__/src/node.cpp +23 -23
- package/cli/vite.d.mts +25 -25
- package/cli/vite.mjs +292 -292
- package/package.json +3 -3
- package/cli/storybook-dist/assets/RBCommand.stories-BSqXDkKw.js +0 -73
- package/cli/storybook-dist/assets/RBDialog.stories-BAktz-ku.js +0 -38
- package/cli/storybook-dist/assets/RBDropdownMenu.stories-DbW2fWAj.js +0 -86
- package/cli/storybook-dist/assets/RBSheet.stories-_6VH-RUm.js +0 -39
package/cli/vite.mjs
CHANGED
|
@@ -1,292 +1,292 @@
|
|
|
1
|
-
import react from "@vitejs/plugin-react";
|
|
2
|
-
import cssInjectedByJsPlugin from "vite-plugin-css-injected-by-js";
|
|
3
|
-
import postcss from "postcss";
|
|
4
|
-
import { createRequire } from "node:module";
|
|
5
|
-
import { existsSync, readFileSync, readdirSync } from "node:fs";
|
|
6
|
-
import { basename, extname, resolve } from "node:path";
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
const HOST_PROVIDED_EXTERNALS = [
|
|
10
|
-
/^react(\/.*)?$/,
|
|
11
|
-
/^react-dom(\/.*)?$/,
|
|
12
|
-
/^@rainbow-robotics\/plugin-ui(\/.*)?$/,
|
|
13
|
-
/^@repo\/rb-components(\/.*)?$/,
|
|
14
|
-
];
|
|
15
|
-
|
|
16
|
-
const UI_ENTRY_PREFIX = "muscat-ui-entry:";
|
|
17
|
-
const RESOLVED_UI_ENTRY_PREFIX = "\0" + UI_ENTRY_PREFIX;
|
|
18
|
-
const SHARED_RUNTIME_PREFIX = "muscat-shared-runtime:";
|
|
19
|
-
const RESOLVED_SHARED_RUNTIME_PREFIX = "\0" + SHARED_RUNTIME_PREFIX;
|
|
20
|
-
const STYLE_EXTENSIONS = [".css", ".scss", ".sass", ".less"];
|
|
21
|
-
// `@rainbow-robotics/plugin-ui/react` ships transpiled-only (see
|
|
22
|
-
// build-dist.mjs: `bundle: false, // consumers resolve deps themselves") — its
|
|
23
|
-
// `export * from "@repo/rb-components/new_components"` is a monorepo-private
|
|
24
|
-
// package no external plugin can npm-install. So a "dev" plugin can't use its
|
|
25
|
-
// own local copy of plugin-ui/react (or /sdk, whose RbContext must stay one
|
|
26
|
-
// singleton with host.tsx's Provider) — these, plus react/react-dom itself
|
|
27
|
-
// (so elements created by rb-components match the instance rendering them)
|
|
28
|
-
// and host-ui (the plain-function toast/alert/confirm/prompt channel), all
|
|
29
|
-
// redirect to the host's already-loaded instances instead.
|
|
30
|
-
const SHARED_RUNTIME_FILES = {
|
|
31
|
-
react: "react",
|
|
32
|
-
"react/jsx-runtime": "react_jsx-runtime",
|
|
33
|
-
"react/jsx-dev-runtime": "react_jsx-dev-runtime",
|
|
34
|
-
"react-dom": "react-dom",
|
|
35
|
-
"react-dom/client": "react-dom_client",
|
|
36
|
-
"@rainbow-robotics/plugin-ui/react": "plugin-ui_react",
|
|
37
|
-
"@rainbow-robotics/plugin-ui/sdk": "plugin-ui_sdk",
|
|
38
|
-
"@rainbow-robotics/plugin-ui/host-ui": "plugin-ui_host-ui",
|
|
39
|
-
"@rainbow-robotics/plugin-ui/ws": "plugin-ui_ws",
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
function cssString(value) {
|
|
43
|
-
return String(value).replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\n/g, "\\a ");
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
function readPluginId(root) {
|
|
47
|
-
try {
|
|
48
|
-
const manifest = JSON.parse(readFileSync(resolve(root, "manifest.json"), "utf8"));
|
|
49
|
-
return typeof manifest.id === "string" && manifest.id ? manifest.id : null;
|
|
50
|
-
} catch {
|
|
51
|
-
return null;
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
function pluginScopeSelector(pluginId) {
|
|
56
|
-
if (!pluginId) return ":where([data-muscat-plugin-root])";
|
|
57
|
-
return `:where([data-muscat-plugin-id="${cssString(pluginId)}"])`;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
function discoverUiEntries(uiDir) {
|
|
61
|
-
return Object.fromEntries(
|
|
62
|
-
readdirSync(uiDir)
|
|
63
|
-
.filter((f) => /\.(tsx?|jsx?)$/.test(f))
|
|
64
|
-
.map((f) => [basename(f, extname(f)), resolve(uiDir, f)]),
|
|
65
|
-
);
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
function discoverUiStyles(uiDir, entryName) {
|
|
69
|
-
return STYLE_EXTENSIONS.flatMap((ext) => [
|
|
70
|
-
resolve(uiDir, `style${ext}`),
|
|
71
|
-
resolve(uiDir, `styles${ext}`),
|
|
72
|
-
resolve(uiDir, `${entryName}${ext}`),
|
|
73
|
-
]).filter((file, index, files) => existsSync(file) && files.indexOf(file) === index);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
function isKeyframesRule(rule) {
|
|
77
|
-
for (let node = rule.parent; node; node = node.parent) {
|
|
78
|
-
if (node.type === "atrule" && /keyframes$/i.test(node.name)) return true;
|
|
79
|
-
}
|
|
80
|
-
return false;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
function scopeSelector(selector, rootSelector) {
|
|
84
|
-
const trimmed = selector.trim();
|
|
85
|
-
if (
|
|
86
|
-
!trimmed ||
|
|
87
|
-
trimmed.includes("[data-muscat-plugin-root]") ||
|
|
88
|
-
trimmed.includes("[data-muscat-plugin-id")
|
|
89
|
-
) {
|
|
90
|
-
return selector;
|
|
91
|
-
}
|
|
92
|
-
if (/^(:root|:host)\b/.test(trimmed)) {
|
|
93
|
-
return trimmed.replace(/^(:root|:host)\b/, rootSelector);
|
|
94
|
-
}
|
|
95
|
-
if (/^(html|body)\b/.test(trimmed)) {
|
|
96
|
-
return trimmed.replace(/^(html|body)\b/, rootSelector);
|
|
97
|
-
}
|
|
98
|
-
return `${rootSelector} ${trimmed}`;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
function scopePluginCss(css, rootSelector) {
|
|
102
|
-
if (!css.trim()) return css;
|
|
103
|
-
const root = postcss.parse(css);
|
|
104
|
-
root.walkRules((rule) => {
|
|
105
|
-
if (isKeyframesRule(rule)) return;
|
|
106
|
-
rule.selectors = rule.selectors.map((selector) => scopeSelector(selector, rootSelector));
|
|
107
|
-
});
|
|
108
|
-
return root.toString();
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
function createUiEntryPlugin(uiDir, entries) {
|
|
112
|
-
return {
|
|
113
|
-
name: "muscat-ui-entry",
|
|
114
|
-
enforce: "pre",
|
|
115
|
-
resolveId(id) {
|
|
116
|
-
if (id.startsWith(UI_ENTRY_PREFIX)) return "\0" + id;
|
|
117
|
-
},
|
|
118
|
-
load(id) {
|
|
119
|
-
if (!id.startsWith(RESOLVED_UI_ENTRY_PREFIX)) return;
|
|
120
|
-
const entryName = id.slice(RESOLVED_UI_ENTRY_PREFIX.length);
|
|
121
|
-
const entry = entries[entryName];
|
|
122
|
-
if (!entry) throw new Error(`Unknown Muscat UI entry: ${entryName}`);
|
|
123
|
-
|
|
124
|
-
const styleImports = discoverUiStyles(uiDir, entryName)
|
|
125
|
-
.map((file) => {
|
|
126
|
-
this.addWatchFile(file);
|
|
127
|
-
return `import ${JSON.stringify(file)};`;
|
|
128
|
-
})
|
|
129
|
-
.join("\n");
|
|
130
|
-
|
|
131
|
-
return `${styleImports}\nexport { default } from ${JSON.stringify(entry)};\n`;
|
|
132
|
-
},
|
|
133
|
-
};
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
function resolveFromPlugin(root, specifier) {
|
|
137
|
-
try {
|
|
138
|
-
return createRequire(resolve(root, "package.json")).resolve(specifier);
|
|
139
|
-
} catch {
|
|
140
|
-
return null;
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
function exactSpecifier(specifier) {
|
|
145
|
-
return new RegExp(`^${specifier.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}$`);
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
function reactAliases(root) {
|
|
149
|
-
return [
|
|
150
|
-
"react",
|
|
151
|
-
"react/jsx-runtime",
|
|
152
|
-
"react/jsx-dev-runtime",
|
|
153
|
-
"react-dom",
|
|
154
|
-
"react-dom/client",
|
|
155
|
-
].flatMap((specifier) => {
|
|
156
|
-
const resolved = resolveFromPlugin(root, specifier);
|
|
157
|
-
return resolved ? [{ find: exactSpecifier(specifier), replacement: resolved }] : [];
|
|
158
|
-
});
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
function createSharedRuntimePlugin(baseUrl) {
|
|
162
|
-
const base = baseUrl.replace(/\/$/, "");
|
|
163
|
-
|
|
164
|
-
return {
|
|
165
|
-
name: "muscat-shared-runtime",
|
|
166
|
-
enforce: "pre",
|
|
167
|
-
resolveId(id) {
|
|
168
|
-
if (id in SHARED_RUNTIME_FILES) return "\0" + SHARED_RUNTIME_PREFIX + id;
|
|
169
|
-
},
|
|
170
|
-
load(id) {
|
|
171
|
-
if (!id.startsWith(RESOLVED_SHARED_RUNTIME_PREFIX)) return;
|
|
172
|
-
const specifier = id.slice(RESOLVED_SHARED_RUNTIME_PREFIX.length);
|
|
173
|
-
const file = SHARED_RUNTIME_FILES[specifier];
|
|
174
|
-
if (!file) throw new Error(`Unknown Muscat shared runtime module: ${specifier}`);
|
|
175
|
-
|
|
176
|
-
const url = JSON.stringify(`${base}/${file}.js`);
|
|
177
|
-
if (specifier === "react" || specifier === "react-dom") {
|
|
178
|
-
return `export * from ${url};\nimport sharedDefault from ${url};\nexport default sharedDefault;\n`;
|
|
179
|
-
}
|
|
180
|
-
return `export * from ${url};\n`;
|
|
181
|
-
},
|
|
182
|
-
};
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
const REACT_REFRESH_ACCEPT_MARKER =
|
|
186
|
-
"\nif (import.meta.hot && !inWebWorker) {\n RefreshRuntime.__hmr_import(import.meta.url).then((currentExports) => {";
|
|
187
|
-
|
|
188
|
-
function createManualHmrBoundaryPlugin(uiDir) {
|
|
189
|
-
const normalizedUiDir = uiDir.replace(/\/$/, "");
|
|
190
|
-
|
|
191
|
-
return {
|
|
192
|
-
name: "muscat-manual-hmr-boundary",
|
|
193
|
-
apply: "serve",
|
|
194
|
-
enforce: "post",
|
|
195
|
-
transform(code, id) {
|
|
196
|
-
const [file] = id.split("?");
|
|
197
|
-
if (!file.startsWith(`${normalizedUiDir}/`) || !/\.[jt]sx?$/.test(file)) return null;
|
|
198
|
-
|
|
199
|
-
const markerIndex = code.lastIndexOf(REACT_REFRESH_ACCEPT_MARKER);
|
|
200
|
-
if (markerIndex === -1) return null;
|
|
201
|
-
|
|
202
|
-
// preview-host provides the same production ReactDOM as Nexus. Vite's
|
|
203
|
-
// React Fast Refresh receives updates but cannot drive that renderer, so
|
|
204
|
-
// let the bootstrap module handle HMR by re-rendering the updated entry.
|
|
205
|
-
return { code: code.slice(0, markerIndex), map: null };
|
|
206
|
-
},
|
|
207
|
-
};
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
export function muscat(options = {}) {
|
|
211
|
-
const pluginRoot = process.cwd();
|
|
212
|
-
const uiDir = resolve(pluginRoot, "ui");
|
|
213
|
-
const entries = discoverUiEntries(uiDir);
|
|
214
|
-
const rootSelector = pluginScopeSelector(readPluginId(pluginRoot));
|
|
215
|
-
const sharedRuntimeBase = process.env.MUSCAT_PLUGIN_SHARED_RUNTIME_BASE;
|
|
216
|
-
const wrappedEntries = Object.fromEntries(
|
|
217
|
-
Object.keys(entries).map((name) => [name, `${UI_ENTRY_PREFIX}${name}`]),
|
|
218
|
-
);
|
|
219
|
-
const reactPlugins = options.react === false ? [] : [react(options.react)];
|
|
220
|
-
|
|
221
|
-
return [
|
|
222
|
-
...reactPlugins,
|
|
223
|
-
createUiEntryPlugin(uiDir, entries),
|
|
224
|
-
...(sharedRuntimeBase ? [createSharedRuntimePlugin(sharedRuntimeBase)] : []),
|
|
225
|
-
...(sharedRuntimeBase ? [createManualHmrBoundaryPlugin(uiDir)] : []),
|
|
226
|
-
cssInjectedByJsPlugin({
|
|
227
|
-
relativeCSSInjection: true,
|
|
228
|
-
preRenderCSSCode: (css) => scopePluginCss(css, rootSelector),
|
|
229
|
-
}),
|
|
230
|
-
{
|
|
231
|
-
name: "muscat-plugin-build",
|
|
232
|
-
apply: "build",
|
|
233
|
-
config: () => ({
|
|
234
|
-
build: {
|
|
235
|
-
target: "esnext",
|
|
236
|
-
outDir: "dist",
|
|
237
|
-
emptyOutDir: false,
|
|
238
|
-
rollupOptions: {
|
|
239
|
-
input: wrappedEntries,
|
|
240
|
-
external: HOST_PROVIDED_EXTERNALS,
|
|
241
|
-
// Entries only `export default App` (the host mounts it). Without
|
|
242
|
-
// this, Vite treats entries as self-executing apps and tree-shakes
|
|
243
|
-
// the unused default export away.
|
|
244
|
-
preserveEntrySignatures: "strict",
|
|
245
|
-
output: {
|
|
246
|
-
format: "es",
|
|
247
|
-
entryFileNames: "[name].js",
|
|
248
|
-
chunkFileNames: "chunks/[name]-[hash].js",
|
|
249
|
-
assetFileNames: "assets/[name]-[hash][extname]",
|
|
250
|
-
},
|
|
251
|
-
},
|
|
252
|
-
},
|
|
253
|
-
}),
|
|
254
|
-
},
|
|
255
|
-
{
|
|
256
|
-
name: "muscat-plugin-dev",
|
|
257
|
-
apply: "serve",
|
|
258
|
-
config: () => {
|
|
259
|
-
return {
|
|
260
|
-
// NOTE: even with sharedRuntimeBase set (so `alias` is empty and our
|
|
261
|
-
// resolveId below wins for every actual import), @vitejs/plugin-react
|
|
262
|
-
// still unconditionally adds react/react-dom/jsx-(dev-)runtime to
|
|
263
|
-
// optimizeDeps.include for Fast Refresh — Vite merges every plugin's
|
|
264
|
-
// optimizeDeps (arrays are concatenated, not overridden), so esbuild's
|
|
265
|
-
// pre-bundle scanner still tries to statically resolve those on disk.
|
|
266
|
-
// That's why the scaffold template keeps react/react-dom as local
|
|
267
|
-
// devDependencies even in shared-runtime mode: purely so this static
|
|
268
|
-
// scan has something real to resolve. The actual dev-server imports
|
|
269
|
-
// never reach that local copy — resolveId (enforce: "pre") below
|
|
270
|
-
// always wins first and redirects to the host's instance.
|
|
271
|
-
resolve: {
|
|
272
|
-
alias: sharedRuntimeBase ? [] : reactAliases(pluginRoot),
|
|
273
|
-
dedupe: ["react", "react-dom"],
|
|
274
|
-
},
|
|
275
|
-
optimizeDeps: sharedRuntimeBase
|
|
276
|
-
? { noDiscovery: true, include: [] }
|
|
277
|
-
: {
|
|
278
|
-
include: [
|
|
279
|
-
"react",
|
|
280
|
-
"react-dom",
|
|
281
|
-
"react-dom/client",
|
|
282
|
-
"@rainbow-robotics/plugin-ui/react",
|
|
283
|
-
"@rainbow-robotics/plugin-ui/sdk",
|
|
284
|
-
"@rainbow-robotics/plugin-ui/host-ui",
|
|
285
|
-
"@rainbow-robotics/plugin-ui/ws",
|
|
286
|
-
],
|
|
287
|
-
},
|
|
288
|
-
};
|
|
289
|
-
},
|
|
290
|
-
},
|
|
291
|
-
];
|
|
292
|
-
}
|
|
1
|
+
import react from "@vitejs/plugin-react";
|
|
2
|
+
import cssInjectedByJsPlugin from "vite-plugin-css-injected-by-js";
|
|
3
|
+
import postcss from "postcss";
|
|
4
|
+
import { createRequire } from "node:module";
|
|
5
|
+
import { existsSync, readFileSync, readdirSync } from "node:fs";
|
|
6
|
+
import { basename, extname, resolve } from "node:path";
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
const HOST_PROVIDED_EXTERNALS = [
|
|
10
|
+
/^react(\/.*)?$/,
|
|
11
|
+
/^react-dom(\/.*)?$/,
|
|
12
|
+
/^@rainbow-robotics\/plugin-ui(\/.*)?$/,
|
|
13
|
+
/^@repo\/rb-components(\/.*)?$/,
|
|
14
|
+
];
|
|
15
|
+
|
|
16
|
+
const UI_ENTRY_PREFIX = "muscat-ui-entry:";
|
|
17
|
+
const RESOLVED_UI_ENTRY_PREFIX = "\0" + UI_ENTRY_PREFIX;
|
|
18
|
+
const SHARED_RUNTIME_PREFIX = "muscat-shared-runtime:";
|
|
19
|
+
const RESOLVED_SHARED_RUNTIME_PREFIX = "\0" + SHARED_RUNTIME_PREFIX;
|
|
20
|
+
const STYLE_EXTENSIONS = [".css", ".scss", ".sass", ".less"];
|
|
21
|
+
// `@rainbow-robotics/plugin-ui/react` ships transpiled-only (see
|
|
22
|
+
// build-dist.mjs: `bundle: false, // consumers resolve deps themselves") — its
|
|
23
|
+
// `export * from "@repo/rb-components/new_components"` is a monorepo-private
|
|
24
|
+
// package no external plugin can npm-install. So a "dev" plugin can't use its
|
|
25
|
+
// own local copy of plugin-ui/react (or /sdk, whose RbContext must stay one
|
|
26
|
+
// singleton with host.tsx's Provider) — these, plus react/react-dom itself
|
|
27
|
+
// (so elements created by rb-components match the instance rendering them)
|
|
28
|
+
// and host-ui (the plain-function toast/alert/confirm/prompt channel), all
|
|
29
|
+
// redirect to the host's already-loaded instances instead.
|
|
30
|
+
const SHARED_RUNTIME_FILES = {
|
|
31
|
+
react: "react",
|
|
32
|
+
"react/jsx-runtime": "react_jsx-runtime",
|
|
33
|
+
"react/jsx-dev-runtime": "react_jsx-dev-runtime",
|
|
34
|
+
"react-dom": "react-dom",
|
|
35
|
+
"react-dom/client": "react-dom_client",
|
|
36
|
+
"@rainbow-robotics/plugin-ui/react": "plugin-ui_react",
|
|
37
|
+
"@rainbow-robotics/plugin-ui/sdk": "plugin-ui_sdk",
|
|
38
|
+
"@rainbow-robotics/plugin-ui/host-ui": "plugin-ui_host-ui",
|
|
39
|
+
"@rainbow-robotics/plugin-ui/ws": "plugin-ui_ws",
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
function cssString(value) {
|
|
43
|
+
return String(value).replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\n/g, "\\a ");
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function readPluginId(root) {
|
|
47
|
+
try {
|
|
48
|
+
const manifest = JSON.parse(readFileSync(resolve(root, "manifest.json"), "utf8"));
|
|
49
|
+
return typeof manifest.id === "string" && manifest.id ? manifest.id : null;
|
|
50
|
+
} catch {
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function pluginScopeSelector(pluginId) {
|
|
56
|
+
if (!pluginId) return ":where([data-muscat-plugin-root])";
|
|
57
|
+
return `:where([data-muscat-plugin-id="${cssString(pluginId)}"])`;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function discoverUiEntries(uiDir) {
|
|
61
|
+
return Object.fromEntries(
|
|
62
|
+
readdirSync(uiDir)
|
|
63
|
+
.filter((f) => /\.(tsx?|jsx?)$/.test(f))
|
|
64
|
+
.map((f) => [basename(f, extname(f)), resolve(uiDir, f)]),
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function discoverUiStyles(uiDir, entryName) {
|
|
69
|
+
return STYLE_EXTENSIONS.flatMap((ext) => [
|
|
70
|
+
resolve(uiDir, `style${ext}`),
|
|
71
|
+
resolve(uiDir, `styles${ext}`),
|
|
72
|
+
resolve(uiDir, `${entryName}${ext}`),
|
|
73
|
+
]).filter((file, index, files) => existsSync(file) && files.indexOf(file) === index);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function isKeyframesRule(rule) {
|
|
77
|
+
for (let node = rule.parent; node; node = node.parent) {
|
|
78
|
+
if (node.type === "atrule" && /keyframes$/i.test(node.name)) return true;
|
|
79
|
+
}
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function scopeSelector(selector, rootSelector) {
|
|
84
|
+
const trimmed = selector.trim();
|
|
85
|
+
if (
|
|
86
|
+
!trimmed ||
|
|
87
|
+
trimmed.includes("[data-muscat-plugin-root]") ||
|
|
88
|
+
trimmed.includes("[data-muscat-plugin-id")
|
|
89
|
+
) {
|
|
90
|
+
return selector;
|
|
91
|
+
}
|
|
92
|
+
if (/^(:root|:host)\b/.test(trimmed)) {
|
|
93
|
+
return trimmed.replace(/^(:root|:host)\b/, rootSelector);
|
|
94
|
+
}
|
|
95
|
+
if (/^(html|body)\b/.test(trimmed)) {
|
|
96
|
+
return trimmed.replace(/^(html|body)\b/, rootSelector);
|
|
97
|
+
}
|
|
98
|
+
return `${rootSelector} ${trimmed}`;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function scopePluginCss(css, rootSelector) {
|
|
102
|
+
if (!css.trim()) return css;
|
|
103
|
+
const root = postcss.parse(css);
|
|
104
|
+
root.walkRules((rule) => {
|
|
105
|
+
if (isKeyframesRule(rule)) return;
|
|
106
|
+
rule.selectors = rule.selectors.map((selector) => scopeSelector(selector, rootSelector));
|
|
107
|
+
});
|
|
108
|
+
return root.toString();
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function createUiEntryPlugin(uiDir, entries) {
|
|
112
|
+
return {
|
|
113
|
+
name: "muscat-ui-entry",
|
|
114
|
+
enforce: "pre",
|
|
115
|
+
resolveId(id) {
|
|
116
|
+
if (id.startsWith(UI_ENTRY_PREFIX)) return "\0" + id;
|
|
117
|
+
},
|
|
118
|
+
load(id) {
|
|
119
|
+
if (!id.startsWith(RESOLVED_UI_ENTRY_PREFIX)) return;
|
|
120
|
+
const entryName = id.slice(RESOLVED_UI_ENTRY_PREFIX.length);
|
|
121
|
+
const entry = entries[entryName];
|
|
122
|
+
if (!entry) throw new Error(`Unknown Muscat UI entry: ${entryName}`);
|
|
123
|
+
|
|
124
|
+
const styleImports = discoverUiStyles(uiDir, entryName)
|
|
125
|
+
.map((file) => {
|
|
126
|
+
this.addWatchFile(file);
|
|
127
|
+
return `import ${JSON.stringify(file)};`;
|
|
128
|
+
})
|
|
129
|
+
.join("\n");
|
|
130
|
+
|
|
131
|
+
return `${styleImports}\nexport { default } from ${JSON.stringify(entry)};\n`;
|
|
132
|
+
},
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function resolveFromPlugin(root, specifier) {
|
|
137
|
+
try {
|
|
138
|
+
return createRequire(resolve(root, "package.json")).resolve(specifier);
|
|
139
|
+
} catch {
|
|
140
|
+
return null;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function exactSpecifier(specifier) {
|
|
145
|
+
return new RegExp(`^${specifier.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}$`);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function reactAliases(root) {
|
|
149
|
+
return [
|
|
150
|
+
"react",
|
|
151
|
+
"react/jsx-runtime",
|
|
152
|
+
"react/jsx-dev-runtime",
|
|
153
|
+
"react-dom",
|
|
154
|
+
"react-dom/client",
|
|
155
|
+
].flatMap((specifier) => {
|
|
156
|
+
const resolved = resolveFromPlugin(root, specifier);
|
|
157
|
+
return resolved ? [{ find: exactSpecifier(specifier), replacement: resolved }] : [];
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function createSharedRuntimePlugin(baseUrl) {
|
|
162
|
+
const base = baseUrl.replace(/\/$/, "");
|
|
163
|
+
|
|
164
|
+
return {
|
|
165
|
+
name: "muscat-shared-runtime",
|
|
166
|
+
enforce: "pre",
|
|
167
|
+
resolveId(id) {
|
|
168
|
+
if (id in SHARED_RUNTIME_FILES) return "\0" + SHARED_RUNTIME_PREFIX + id;
|
|
169
|
+
},
|
|
170
|
+
load(id) {
|
|
171
|
+
if (!id.startsWith(RESOLVED_SHARED_RUNTIME_PREFIX)) return;
|
|
172
|
+
const specifier = id.slice(RESOLVED_SHARED_RUNTIME_PREFIX.length);
|
|
173
|
+
const file = SHARED_RUNTIME_FILES[specifier];
|
|
174
|
+
if (!file) throw new Error(`Unknown Muscat shared runtime module: ${specifier}`);
|
|
175
|
+
|
|
176
|
+
const url = JSON.stringify(`${base}/${file}.js`);
|
|
177
|
+
if (specifier === "react" || specifier === "react-dom") {
|
|
178
|
+
return `export * from ${url};\nimport sharedDefault from ${url};\nexport default sharedDefault;\n`;
|
|
179
|
+
}
|
|
180
|
+
return `export * from ${url};\n`;
|
|
181
|
+
},
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
const REACT_REFRESH_ACCEPT_MARKER =
|
|
186
|
+
"\nif (import.meta.hot && !inWebWorker) {\n RefreshRuntime.__hmr_import(import.meta.url).then((currentExports) => {";
|
|
187
|
+
|
|
188
|
+
function createManualHmrBoundaryPlugin(uiDir) {
|
|
189
|
+
const normalizedUiDir = uiDir.replace(/\/$/, "");
|
|
190
|
+
|
|
191
|
+
return {
|
|
192
|
+
name: "muscat-manual-hmr-boundary",
|
|
193
|
+
apply: "serve",
|
|
194
|
+
enforce: "post",
|
|
195
|
+
transform(code, id) {
|
|
196
|
+
const [file] = id.split("?");
|
|
197
|
+
if (!file.startsWith(`${normalizedUiDir}/`) || !/\.[jt]sx?$/.test(file)) return null;
|
|
198
|
+
|
|
199
|
+
const markerIndex = code.lastIndexOf(REACT_REFRESH_ACCEPT_MARKER);
|
|
200
|
+
if (markerIndex === -1) return null;
|
|
201
|
+
|
|
202
|
+
// preview-host provides the same production ReactDOM as Nexus. Vite's
|
|
203
|
+
// React Fast Refresh receives updates but cannot drive that renderer, so
|
|
204
|
+
// let the bootstrap module handle HMR by re-rendering the updated entry.
|
|
205
|
+
return { code: code.slice(0, markerIndex), map: null };
|
|
206
|
+
},
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
export function muscat(options = {}) {
|
|
211
|
+
const pluginRoot = process.cwd();
|
|
212
|
+
const uiDir = resolve(pluginRoot, "ui");
|
|
213
|
+
const entries = discoverUiEntries(uiDir);
|
|
214
|
+
const rootSelector = pluginScopeSelector(readPluginId(pluginRoot));
|
|
215
|
+
const sharedRuntimeBase = process.env.MUSCAT_PLUGIN_SHARED_RUNTIME_BASE;
|
|
216
|
+
const wrappedEntries = Object.fromEntries(
|
|
217
|
+
Object.keys(entries).map((name) => [name, `${UI_ENTRY_PREFIX}${name}`]),
|
|
218
|
+
);
|
|
219
|
+
const reactPlugins = options.react === false ? [] : [react(options.react)];
|
|
220
|
+
|
|
221
|
+
return [
|
|
222
|
+
...reactPlugins,
|
|
223
|
+
createUiEntryPlugin(uiDir, entries),
|
|
224
|
+
...(sharedRuntimeBase ? [createSharedRuntimePlugin(sharedRuntimeBase)] : []),
|
|
225
|
+
...(sharedRuntimeBase ? [createManualHmrBoundaryPlugin(uiDir)] : []),
|
|
226
|
+
cssInjectedByJsPlugin({
|
|
227
|
+
relativeCSSInjection: true,
|
|
228
|
+
preRenderCSSCode: (css) => scopePluginCss(css, rootSelector),
|
|
229
|
+
}),
|
|
230
|
+
{
|
|
231
|
+
name: "muscat-plugin-build",
|
|
232
|
+
apply: "build",
|
|
233
|
+
config: () => ({
|
|
234
|
+
build: {
|
|
235
|
+
target: "esnext",
|
|
236
|
+
outDir: "dist",
|
|
237
|
+
emptyOutDir: false,
|
|
238
|
+
rollupOptions: {
|
|
239
|
+
input: wrappedEntries,
|
|
240
|
+
external: HOST_PROVIDED_EXTERNALS,
|
|
241
|
+
// Entries only `export default App` (the host mounts it). Without
|
|
242
|
+
// this, Vite treats entries as self-executing apps and tree-shakes
|
|
243
|
+
// the unused default export away.
|
|
244
|
+
preserveEntrySignatures: "strict",
|
|
245
|
+
output: {
|
|
246
|
+
format: "es",
|
|
247
|
+
entryFileNames: "[name].js",
|
|
248
|
+
chunkFileNames: "chunks/[name]-[hash].js",
|
|
249
|
+
assetFileNames: "assets/[name]-[hash][extname]",
|
|
250
|
+
},
|
|
251
|
+
},
|
|
252
|
+
},
|
|
253
|
+
}),
|
|
254
|
+
},
|
|
255
|
+
{
|
|
256
|
+
name: "muscat-plugin-dev",
|
|
257
|
+
apply: "serve",
|
|
258
|
+
config: () => {
|
|
259
|
+
return {
|
|
260
|
+
// NOTE: even with sharedRuntimeBase set (so `alias` is empty and our
|
|
261
|
+
// resolveId below wins for every actual import), @vitejs/plugin-react
|
|
262
|
+
// still unconditionally adds react/react-dom/jsx-(dev-)runtime to
|
|
263
|
+
// optimizeDeps.include for Fast Refresh — Vite merges every plugin's
|
|
264
|
+
// optimizeDeps (arrays are concatenated, not overridden), so esbuild's
|
|
265
|
+
// pre-bundle scanner still tries to statically resolve those on disk.
|
|
266
|
+
// That's why the scaffold template keeps react/react-dom as local
|
|
267
|
+
// devDependencies even in shared-runtime mode: purely so this static
|
|
268
|
+
// scan has something real to resolve. The actual dev-server imports
|
|
269
|
+
// never reach that local copy — resolveId (enforce: "pre") below
|
|
270
|
+
// always wins first and redirects to the host's instance.
|
|
271
|
+
resolve: {
|
|
272
|
+
alias: sharedRuntimeBase ? [] : reactAliases(pluginRoot),
|
|
273
|
+
dedupe: ["react", "react-dom"],
|
|
274
|
+
},
|
|
275
|
+
optimizeDeps: sharedRuntimeBase
|
|
276
|
+
? { noDiscovery: true, include: [] }
|
|
277
|
+
: {
|
|
278
|
+
include: [
|
|
279
|
+
"react",
|
|
280
|
+
"react-dom",
|
|
281
|
+
"react-dom/client",
|
|
282
|
+
"@rainbow-robotics/plugin-ui/react",
|
|
283
|
+
"@rainbow-robotics/plugin-ui/sdk",
|
|
284
|
+
"@rainbow-robotics/plugin-ui/host-ui",
|
|
285
|
+
"@rainbow-robotics/plugin-ui/ws",
|
|
286
|
+
],
|
|
287
|
+
},
|
|
288
|
+
};
|
|
289
|
+
},
|
|
290
|
+
},
|
|
291
|
+
];
|
|
292
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rainbow-robotics/muscat-plugin-kit",
|
|
3
|
-
"version": "1.10.1
|
|
3
|
+
"version": "1.10.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=20"
|
|
@@ -52,8 +52,8 @@
|
|
|
52
52
|
},
|
|
53
53
|
"dependencies": {
|
|
54
54
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
55
|
-
"@rainbow-robotics/plugin-ui": "1.10.1
|
|
56
|
-
"@rainbow-robotics/preview-host": "1.10.1
|
|
55
|
+
"@rainbow-robotics/plugin-ui": "1.10.1",
|
|
56
|
+
"@rainbow-robotics/preview-host": "1.10.1",
|
|
57
57
|
"@types/react": "^19.0.10",
|
|
58
58
|
"postcss": "^8.5.8",
|
|
59
59
|
"typescript": "^5.8.0",
|