@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.
Files changed (205) hide show
  1. package/README.md +282 -282
  2. package/cli/README.md +274 -274
  3. package/cli/bin/create-muscat-plugin.mjs +8 -8
  4. package/cli/bin/muscat-pk.mjs +155 -155
  5. package/cli/bundle-templates.mjs +31 -31
  6. package/cli/docker/Dockerfile.cpp +28 -28
  7. package/cli/docker/Dockerfile.dev +30 -30
  8. package/cli/docker/Dockerfile.python +21 -21
  9. package/cli/m5-e2e.mjs +69 -69
  10. package/cli/prepack.mjs +10 -10
  11. package/cli/src/ai-rules.mjs +70 -70
  12. package/cli/src/build.mjs +447 -447
  13. package/cli/src/check-package.mjs +13 -13
  14. package/cli/src/completion.mjs +166 -166
  15. package/cli/src/cpp.mjs +78 -78
  16. package/cli/src/cppIde.mjs +75 -75
  17. package/cli/src/dev.mjs +165 -165
  18. package/cli/src/devBack.mjs +734 -727
  19. package/cli/src/devUi.mjs +247 -243
  20. package/cli/src/esbuild.mjs +56 -56
  21. package/cli/src/host_agent.py +223 -223
  22. package/cli/src/manifest.mjs +287 -287
  23. package/cli/src/mcp.mjs +1071 -1071
  24. package/cli/src/muscatLocal.mjs +209 -209
  25. package/cli/src/new.mjs +343 -343
  26. package/cli/src/pluginDevServer.mjs +111 -111
  27. package/cli/src/ports.mjs +193 -193
  28. package/cli/src/python.mjs +112 -112
  29. package/cli/src/ros2.mjs +109 -109
  30. package/cli/src/sdk.mjs +117 -117
  31. package/cli/src/storybook.mjs +168 -168
  32. package/cli/src/type.mjs +141 -141
  33. package/cli/src/uninstall.mjs +81 -81
  34. package/cli/src/update.mjs +295 -295
  35. package/cli/src/util.mjs +441 -441
  36. package/cli/src/zenohDev.mjs +83 -81
  37. package/cli/storybook-dist/_design-tokens.css +4957 -4957
  38. package/cli/storybook-dist/_stories-src/NxAvatar.stories.tsx +27 -27
  39. package/cli/storybook-dist/_stories-src/NxPagination.stories.tsx +28 -28
  40. package/cli/storybook-dist/_stories-src/RBAccordion/RBAccordion.stories.tsx +46 -46
  41. package/cli/storybook-dist/_stories-src/RBAccordion/RBAccordionGroup.stories.tsx +73 -73
  42. package/cli/storybook-dist/_stories-src/RBBadge/RBBadge.stories.tsx +93 -93
  43. package/cli/storybook-dist/_stories-src/RBBattery/RBBattery.stories.tsx +74 -74
  44. package/cli/storybook-dist/_stories-src/RBButton/RBCheckIconButton.stories.tsx +28 -28
  45. package/cli/storybook-dist/_stories-src/RBButton/RBCheckLabelButton.stories.tsx +84 -84
  46. package/cli/storybook-dist/_stories-src/RBButton/RBIconButton.stories.tsx +57 -57
  47. package/cli/storybook-dist/_stories-src/RBButton/RBInlineLabelButton.stories.tsx +41 -41
  48. package/cli/storybook-dist/_stories-src/RBButton/RBLabelButton.stories.tsx +60 -60
  49. package/cli/storybook-dist/_stories-src/RBDatePicker/RBDateInput.stories.tsx +44 -44
  50. package/cli/storybook-dist/_stories-src/RBDatePicker/RBRangeDateInput.stories.tsx +56 -56
  51. package/cli/storybook-dist/_stories-src/RBDialog/RBAlert.stories.tsx +51 -51
  52. package/cli/storybook-dist/_stories-src/RBDialog/RBConfirm.stories.tsx +55 -55
  53. package/cli/storybook-dist/_stories-src/RBDialog/RBPrompt.stories.tsx +52 -52
  54. package/cli/storybook-dist/_stories-src/RBDivider/RBDivider.stories.tsx +93 -93
  55. package/cli/storybook-dist/_stories-src/RBEmptyView/RBEmptyView.stories.tsx +49 -49
  56. package/cli/storybook-dist/_stories-src/RBIcons/RBColorIcons.stories.tsx +108 -108
  57. package/cli/storybook-dist/_stories-src/RBIcons/RBIcons.stories.tsx +106 -106
  58. package/cli/storybook-dist/_stories-src/RBInput/RBCheckBox.stories.tsx +89 -89
  59. package/cli/storybook-dist/_stories-src/RBInput/RBMultiRangeInput.stories.tsx +64 -64
  60. package/cli/storybook-dist/_stories-src/RBInput/RBRadioBox.stories.tsx +65 -65
  61. package/cli/storybook-dist/_stories-src/RBInput/RBRadioButton.stories.tsx +68 -68
  62. package/cli/storybook-dist/_stories-src/RBInput/RBSelectBox.stories.tsx +216 -216
  63. package/cli/storybook-dist/_stories-src/RBInput/RBSideNumberInput.stories.tsx +90 -90
  64. package/cli/storybook-dist/_stories-src/RBInput/RBText/RBTextArea.stories.tsx +45 -45
  65. package/cli/storybook-dist/_stories-src/RBInput/RBText/RBTextInput.stories.tsx +50 -50
  66. package/cli/storybook-dist/_stories-src/RBInput/RBTextField.stories.tsx +102 -102
  67. package/cli/storybook-dist/_stories-src/RBJoyStick/RBJoyStick.stories.tsx +31 -31
  68. package/cli/storybook-dist/_stories-src/RBLight/RBLight.stories.tsx +36 -36
  69. package/cli/storybook-dist/_stories-src/RBPagination/RBPagination.stories.tsx +49 -49
  70. package/cli/storybook-dist/_stories-src/RBShadcn/RBCard/RBCard.stories.tsx +89 -89
  71. package/cli/storybook-dist/_stories-src/RBShadcn/RBCommand/RBCommand.stories.tsx +116 -116
  72. package/cli/storybook-dist/_stories-src/RBShadcn/RBDialog/RBDialog.stories.tsx +74 -74
  73. package/cli/storybook-dist/_stories-src/RBShadcn/RBDrawer/RBDrawer.stories.tsx +99 -99
  74. package/cli/storybook-dist/_stories-src/RBShadcn/RBDropdownMenu/RBDropdownMenu.stories.tsx +123 -123
  75. package/cli/storybook-dist/_stories-src/RBShadcn/RBMenubar/RBMenubar.stories.tsx +135 -135
  76. package/cli/storybook-dist/_stories-src/RBShadcn/RBPopover/RBPopover.stories.tsx +69 -69
  77. package/cli/storybook-dist/_stories-src/RBShadcn/RBResizable/RBResizable.stories.tsx +49 -49
  78. package/cli/storybook-dist/_stories-src/RBShadcn/RBSheet/RBSheet.stories.tsx +91 -91
  79. package/cli/storybook-dist/_stories-src/RBShadcn/RBSlider/RBSlider.stories.tsx +38 -38
  80. package/cli/storybook-dist/_stories-src/RBShadcn/RBSwitch/RBSwitch.stories.tsx +112 -112
  81. package/cli/storybook-dist/_stories-src/RBShadcn/RBTabs/RBTabs.stories.tsx +75 -75
  82. package/cli/storybook-dist/_stories-src/RBShadcn/RBToggle/RBToggle.stories.tsx +51 -51
  83. package/cli/storybook-dist/_stories-src/RBShadcn/RBToggleGroup/RBToggleGroup.stories.tsx +84 -84
  84. package/cli/storybook-dist/_stories-src/RBTab/RBChipTab.stories.tsx +102 -102
  85. package/cli/storybook-dist/_stories-src/RBTab/RBChipsBoxTab.stories.tsx +78 -78
  86. package/cli/storybook-dist/_stories-src/RBTab/RBTab.stories.tsx +57 -57
  87. package/cli/storybook-dist/_stories-src/RBTable/RBTable.stories.tsx +177 -177
  88. package/cli/storybook-dist/_stories-src/RBTable/RBTableRow.stories.tsx +64 -64
  89. package/cli/storybook-dist/_stories-src/RBToast/RBToast.stories.tsx +117 -117
  90. package/cli/storybook-dist/_stories-src/RBTooltip/RBTooltip.stories.tsx +50 -50
  91. package/cli/storybook-dist/_stories-src/loading/RBSpinner.stories.tsx +30 -30
  92. package/cli/storybook-dist/_stories-src/nx-button/NxButton.stories.tsx +54 -54
  93. package/cli/storybook-dist/_stories-src/nx-button/NxPointerHoldButton.stories.tsx +57 -57
  94. package/cli/storybook-dist/_stories-src/nx-icons/NxIcons.stories.tsx +48 -48
  95. package/cli/storybook-dist/_stories-src/nx-inputs/NxNumberInput.stories.tsx +103 -103
  96. package/cli/storybook-dist/_stories-src/nx-inputs/NxRangeInput.stories.tsx +27 -27
  97. package/cli/storybook-dist/_stories-src/nx-inputs/NxSelectBox.stories.tsx +67 -67
  98. package/cli/storybook-dist/_stories-src/nx-inputs/NxSlideRange.stories.tsx +45 -45
  99. package/cli/storybook-dist/_stories-src/nx-inputs/NxSwitch.stories.tsx +27 -27
  100. package/cli/storybook-dist/_stories-src/nx-inputs/NxTextArea.stories.tsx +48 -48
  101. package/cli/storybook-dist/_stories-src/nx-inputs/NxTextInput.stories.tsx +46 -46
  102. package/cli/storybook-dist/assets/{Color-YHDXOIA2-D6JqZzDJ.js → Color-YHDXOIA2-B4IER17l.js} +1 -1
  103. package/cli/storybook-dist/assets/{Docs-ESb7JAHg.js → Docs-C8GCHFtK.js} +3 -3
  104. package/cli/storybook-dist/assets/{Docs-6gD2kUo1.js → Docs-CgdEMPQP.js} +2 -2
  105. package/cli/storybook-dist/assets/{Docs-B9wd8Ok7.js → Docs-Ck3WHvk6.js} +3 -3
  106. package/cli/storybook-dist/assets/{Docs-CgFbWWXM.js → Docs-D9NHsoeZ.js} +2 -2
  107. package/cli/storybook-dist/assets/{Docs-DBQup8Bu.js → Docs-DNYQC7nl.js} +3 -3
  108. package/cli/storybook-dist/assets/{Docs-CMjovnSY.js → Docs-DUfeiM4I.js} +4 -4
  109. package/cli/storybook-dist/assets/{DocsRenderer-CFRXHY34-BOUI1AHi.js → DocsRenderer-CFRXHY34-C0WhyDoR.js} +1 -1
  110. package/cli/storybook-dist/assets/{NxAvatar.stories-DsYFMUh3.js → NxAvatar.stories-CwnK8AUF.js} +1 -1
  111. package/cli/storybook-dist/assets/{NxButton.stories-CHfNcqsc.js → NxButton.stories-ueYdosfQ.js} +8 -8
  112. package/cli/storybook-dist/assets/{NxNumberInput.stories-BFw_4vFE.js → NxNumberInput.stories-M5ZCLbrK.js} +1 -1
  113. package/cli/storybook-dist/assets/{NxPagination.stories-DVfxyw4M.js → NxPagination.stories-bxxUnHEL.js} +1 -1
  114. package/cli/storybook-dist/assets/{NxPointerHoldButton.stories-BzyxUWoZ.js → NxPointerHoldButton.stories-BHxB2kr5.js} +1 -1
  115. package/cli/storybook-dist/assets/{NxRangeInput.stories-DmRdzBc1.js → NxRangeInput.stories-BKfr-fp4.js} +6 -6
  116. package/cli/storybook-dist/assets/{NxSelectBox.stories-B1KkNUOf.js → NxSelectBox.stories-CG8FuTBq.js} +1 -1
  117. package/cli/storybook-dist/assets/{NxSlideRange.stories-CyOdvfQ6.js → NxSlideRange.stories-BRTFtMTL.js} +1 -1
  118. package/cli/storybook-dist/assets/{NxSwitch.stories-DrDBw0qp.js → NxSwitch.stories-Bwuyzn-R.js} +1 -1
  119. package/cli/storybook-dist/assets/{NxTextArea.stories-DTB2aqNS.js → NxTextArea.stories-COq2sGqu.js} +1 -1
  120. package/cli/storybook-dist/assets/{NxTextInput.stories-DU0rucmM.js → NxTextInput.stories-CjsBLz05.js} +1 -1
  121. package/cli/storybook-dist/assets/{RBAccordion.stories-DTfOtXtp.js → RBAccordion.stories-BARwuZ0Q.js} +3 -3
  122. package/cli/storybook-dist/assets/{RBAccordionGroup.stories-9y9BjrUe.js → RBAccordionGroup.stories-COrPxETW.js} +10 -10
  123. package/cli/storybook-dist/assets/{RBAlert.stories-DLTAv9fT.js → RBAlert.stories-BQrkjZPt.js} +3 -3
  124. package/cli/storybook-dist/assets/{RBBadge.stories-BNMACewA.js → RBBadge.stories-BTsLL-lK.js} +1 -1
  125. package/cli/storybook-dist/assets/{RBBattery.stories-B3kXMAt5.js → RBBattery.stories-DAeQdJbc.js} +1 -1
  126. package/cli/storybook-dist/assets/{RBCard.stories-Y-s8R2n7.js → RBCard.stories-HyhOE80R.js} +39 -39
  127. package/cli/storybook-dist/assets/{RBCheckBox.stories-DBuT9tL4.js → RBCheckBox.stories-KFk0WqX_.js} +1 -1
  128. package/cli/storybook-dist/assets/{RBCheckIconButton.stories-CWu1TL56.js → RBCheckIconButton.stories-CXbbktF5.js} +1 -1
  129. package/cli/storybook-dist/assets/{RBCheckLabelButton.stories-sCu2MGCX.js → RBCheckLabelButton.stories-DWfYz_9Z.js} +17 -17
  130. package/cli/storybook-dist/assets/{RBChipTab.stories-BX9qLJkR.js → RBChipTab.stories-JPEgVFAS.js} +5 -5
  131. package/cli/storybook-dist/assets/{RBChipsBoxTab.stories-35u1aJ-P.js → RBChipsBoxTab.stories-CTPuWXrQ.js} +1 -1
  132. package/cli/storybook-dist/assets/{RBColorIcons.stories-DAOZ5Ies.js → RBColorIcons.stories-DiFRZ5jk.js} +1 -1
  133. package/cli/storybook-dist/assets/RBCommand.stories-Pf1HAVIR.js +73 -0
  134. package/cli/storybook-dist/assets/{RBConfirm.stories-iMXcUh7Z.js → RBConfirm.stories-D1cEPUXk.js} +3 -3
  135. package/cli/storybook-dist/assets/{RBDateInput.stories-hK5rXECf.js → RBDateInput.stories-RPYpCjig.js} +1 -1
  136. package/cli/storybook-dist/assets/RBDialog.stories-DJH-0XSR.js +38 -0
  137. package/cli/storybook-dist/assets/{RBDivider.stories-BAK-iZ1Z.js → RBDivider.stories-uEj1vOgK.js} +1 -1
  138. package/cli/storybook-dist/assets/{RBDrawer.stories-B2nqf2Nh.js → RBDrawer.stories-BiMzElb2.js} +12 -12
  139. package/cli/storybook-dist/assets/RBDropdownMenu.stories-Da_TBkla.js +86 -0
  140. package/cli/storybook-dist/assets/{RBEmptyView.stories-nCenrgBh.js → RBEmptyView.stories-BHeKGfPS.js} +1 -1
  141. package/cli/storybook-dist/assets/{RBIconButton.stories-DRH7O3sp.js → RBIconButton.stories-NEsRFoYp.js} +1 -1
  142. package/cli/storybook-dist/assets/{RBIcons.stories-D3PyJXG8.js → RBIcons.stories-CcZ-TTLS.js} +1 -1
  143. package/cli/storybook-dist/assets/{RBInlineLabelButton.stories-modQbt10.js → RBInlineLabelButton.stories-B0wpdQyR.js} +1 -1
  144. package/cli/storybook-dist/assets/{RBJoyStick.stories-BY14qVgR.js → RBJoyStick.stories-DEgBou3K.js} +1 -1
  145. package/cli/storybook-dist/assets/{RBLabelButton.stories-DzF7vGwm.js → RBLabelButton.stories-DT8drIsF.js} +1 -1
  146. package/cli/storybook-dist/assets/{RBLight.stories-lF4FRmVh.js → RBLight.stories-Dh-aoeyG.js} +1 -1
  147. package/cli/storybook-dist/assets/{RBMenubar.stories-XhrI7bsV.js → RBMenubar.stories-D-H7UqVh.js} +1 -1
  148. package/cli/storybook-dist/assets/{RBMultiRangeInput.stories-DprllQDl.js → RBMultiRangeInput.stories-hlclv6jI.js} +1 -1
  149. package/cli/storybook-dist/assets/{RBPagination.stories-2v2gBJfC.js → RBPagination.stories-DWCeoZ_S.js} +1 -1
  150. package/cli/storybook-dist/assets/{RBPopover.stories-C8iLIZpv.js → RBPopover.stories-C514M09_.js} +1 -1
  151. package/cli/storybook-dist/assets/{RBPrompt.stories-Th_HrWHI.js → RBPrompt.stories-BSItvfiT.js} +1 -1
  152. package/cli/storybook-dist/assets/{RBRadioBox.stories-CoHuLaN3.js → RBRadioBox.stories-BBb4YbFU.js} +1 -1
  153. package/cli/storybook-dist/assets/{RBRadioButton.stories-DULxE_ff.js → RBRadioButton.stories-CXyOGJCv.js} +1 -1
  154. package/cli/storybook-dist/assets/{RBRangeDateInput.stories-D8A9KBSS.js → RBRangeDateInput.stories-qvhubu0e.js} +1 -1
  155. package/cli/storybook-dist/assets/{RBResizable.stories-C41QfrQ3.js → RBResizable.stories-CZKeyGjH.js} +14 -14
  156. package/cli/storybook-dist/assets/{RBSelectBox.stories-C1gNmwzw.js → RBSelectBox.stories-CRKP3ybf.js} +1 -1
  157. package/cli/storybook-dist/assets/RBSheet.stories-sCM3ZJUa.js +39 -0
  158. package/cli/storybook-dist/assets/{RBSideNumberInput.stories-9LlgQ8nh.js → RBSideNumberInput.stories-Bb7gw8RF.js} +3 -3
  159. package/cli/storybook-dist/assets/{RBSlider.stories-oUgo5K9d.js → RBSlider.stories-23OAQU5z.js} +3 -3
  160. package/cli/storybook-dist/assets/{RBSpinner.stories-DDpohbY2.js → RBSpinner.stories-2xcQdcmt.js} +1 -1
  161. package/cli/storybook-dist/assets/{RBSwitch.stories-gW-GN7QO.js → RBSwitch.stories-BACUaJm_.js} +7 -7
  162. package/cli/storybook-dist/assets/{RBTab.stories-CN-PV3HH.js → RBTab.stories-CDHE3sVs.js} +1 -1
  163. package/cli/storybook-dist/assets/{RBTable.stories-BAZLpxtM.js → RBTable.stories-C0Cfhfl7.js} +29 -29
  164. package/cli/storybook-dist/assets/{RBTableRow.stories-CwjVrszB.js → RBTableRow.stories-BF8kIkpp.js} +1 -1
  165. package/cli/storybook-dist/assets/{RBTabs.stories-JuEo2sUL.js → RBTabs.stories-BdJWRq1o.js} +7 -7
  166. package/cli/storybook-dist/assets/{RBTextArea.stories-D0_Pv4qZ.js → RBTextArea.stories-CGy2xeYH.js} +3 -3
  167. package/cli/storybook-dist/assets/{RBTextField.stories-CCsOvZqV.js → RBTextField.stories-IfUOzxCM.js} +15 -15
  168. package/cli/storybook-dist/assets/{RBTextInput.stories-Cccn3VNm.js → RBTextInput.stories-VjXNFo4R.js} +3 -3
  169. package/cli/storybook-dist/assets/{RBToast.stories-I5617t0K.js → RBToast.stories-BzcobblV.js} +1 -1
  170. package/cli/storybook-dist/assets/{RBToggle.stories-DsgKjGsJ.js → RBToggle.stories-DuLE5mKv.js} +4 -4
  171. package/cli/storybook-dist/assets/{RBToggleGroup.stories-BZEzSDuz.js → RBToggleGroup.stories-CuR0N0GJ.js} +5 -5
  172. package/cli/storybook-dist/assets/{RBTooltip.stories-4oSyAWsA.js → RBTooltip.stories--aAgNC8_.js} +1 -1
  173. package/cli/storybook-dist/assets/{SideNumberInput-DSKbd0bG.js → SideNumberInput-DyWQxYUj.js} +743 -743
  174. package/cli/storybook-dist/assets/{entry-preview-B35XREGs.js → entry-preview-D7IHsza_.js} +1 -1
  175. package/cli/storybook-dist/assets/{iframe-BB797lmL.js → iframe-CbaIp5I-.js} +2 -2
  176. package/cli/storybook-dist/assets/{index-BU2567EP.js → index-C6CBgMuG.js} +3 -3
  177. package/cli/storybook-dist/assets/{preview-C7DaSWyc.js → preview-B-iYLDuW.js} +2 -2
  178. package/cli/storybook-dist/assets/{preview-CbuRHit4.js → preview-CRWqc9DH.js} +1 -1
  179. package/cli/storybook-dist/assets/{react-resizable-panels.browser-ChIvlwo7.js → react-resizable-panels.browser-8hC8dr-6.js} +8 -8
  180. package/cli/storybook-dist/iframe.html +2 -2
  181. package/cli/storybook-dist/index.html +1 -1
  182. package/cli/storybook-dist/project.json +1 -1
  183. package/cli/templates/common/.mcp.json +8 -8
  184. package/cli/templates/common/README.md +1231 -1231
  185. package/cli/templates/common/assets/icon.svg +45 -45
  186. package/cli/templates/common/manifest.json +26 -26
  187. package/cli/templates/common/package.json +22 -22
  188. package/cli/templates/common/py/main.py +125 -125
  189. package/cli/templates/common/tsconfig.json +13 -13
  190. package/cli/templates/common/ui/content.tsx +216 -216
  191. package/cli/templates/common/ui/style.css +6 -6
  192. package/cli/templates/common/vite.config.ts +10 -10
  193. package/cli/templates/cpp/cpp/main.cpp +73 -73
  194. package/cli/templates/ros2/ros2_ws/src/__PLUGIN_SLUG__/__PLUGIN_SLUG__/node.py +25 -25
  195. package/cli/templates/ros2/ros2_ws/src/__PLUGIN_SLUG__/package.xml +10 -10
  196. package/cli/templates/ros2/ros2_ws/src/__PLUGIN_SLUG__/setup.py +18 -18
  197. package/cli/templates/ros2-cpp/ros2_ws/src/__PLUGIN_SLUG__/package.xml +11 -11
  198. package/cli/templates/ros2-cpp/ros2_ws/src/__PLUGIN_SLUG__/src/node.cpp +23 -23
  199. package/cli/vite.d.mts +25 -25
  200. package/cli/vite.mjs +292 -292
  201. package/package.json +3 -3
  202. package/cli/storybook-dist/assets/RBCommand.stories-BSqXDkKw.js +0 -73
  203. package/cli/storybook-dist/assets/RBDialog.stories-BAktz-ku.js +0 -38
  204. package/cli/storybook-dist/assets/RBDropdownMenu.stories-DbW2fWAj.js +0 -86
  205. package/cli/storybook-dist/assets/RBSheet.stories-_6VH-RUm.js +0 -39
package/cli/src/devUi.mjs CHANGED
@@ -1,243 +1,247 @@
1
-
2
- import { spawn, spawnSync } from "node:child_process";
3
- import { createServer as createNetServer } from "node:net";
4
- import { createRequire } from "node:module";
5
- import { copyFileSync, cpSync, existsSync, mkdirSync, readFileSync, rmSync, watch } from "node:fs";
6
- import { homedir } from "node:os";
7
- import { dirname, resolve } from "node:path";
8
- import { fileURLToPath } from "node:url";
9
- import { checkKitUpdate, findPluginRoot, hasBin, kitRoot, log, parseArgs, prompt } from "./util.mjs";
10
- import { ensureLocalMuscat, GATEWAY_PORT, robotHasMuscat } from "./muscatLocal.mjs";
11
- import { isRemoteRobot } from "./zenohDev.mjs";
12
-
13
-
14
- const DEV_PLUGIN_PORT = 4181;
15
-
16
- function getFreePort(preferred) {
17
- return new Promise((res) => {
18
- const srv = createNetServer();
19
- srv.once("error", () => {
20
- const s2 = createNetServer();
21
- s2.listen(0, () => {
22
- const { port } = s2.address();
23
- s2.close(() => res(port));
24
- });
25
- });
26
- srv.listen(preferred, () => srv.close(() => res(preferred)));
27
- });
28
- }
29
-
30
- const PREVIEW_PKG = "@rainbow-robotics/preview-host";
31
- const CACHE_DIR = resolve(homedir(), ".muscat-pk");
32
- const CACHE_ROOT = resolve(CACHE_DIR, "node_modules", "@rainbow-robotics", "preview-host");
33
-
34
-
35
- const DEV_OUT = ".muscat-dev";
36
-
37
- function findNodeBin() {
38
- if (typeof Bun === "undefined") return process.execPath;
39
- for (const c of ["node", "node20", "node18"]) {
40
- if (hasBin(c)) return c;
41
- }
42
- return null;
43
- }
44
-
45
- function findPreviewHostRoot() {
46
- try {
47
- const req = createRequire(import.meta.url);
48
- return dirname(req.resolve(`${PREVIEW_PKG}/package.json`));
49
- } catch {
50
- console.log("Try the sibling and cached package locations below.")
51
- }
52
-
53
- const sibling = resolve(kitRoot, "../preview-host");
54
- if (existsSync(resolve(sibling, "package.json"))) return sibling;
55
-
56
- if (existsSync(resolve(CACHE_ROOT, "package.json"))) return CACHE_ROOT;
57
-
58
- if (!hasBin("npm")) {
59
- throw new Error(
60
- `preview-host를 찾을 수 없습니다.\n` +
61
- `Node.js 20+ 를 설치하면 자동으로 준비됩니다: https://nodejs.org`,
62
- );
63
- }
64
- log.step(`preview-host 설치 중 (~/.muscat-pk) — 첫 실행 시 한 번만 수행됩니다…`);
65
- mkdirSync(CACHE_DIR, { recursive: true });
66
- const r = spawnSync(
67
- "npm",
68
- ["install", "--prefix", CACHE_DIR, "--save", PREVIEW_PKG],
69
- { stdio: "inherit" },
70
- );
71
- if (r.status !== 0) throw new Error("preview-host 설치 실패.");
72
- if (!existsSync(resolve(CACHE_ROOT, "package.json"))) {
73
- throw new Error("preview-host 설치 후에도 패키지를 찾을 수 없습니다.");
74
- }
75
- return CACHE_ROOT;
76
- }
77
-
78
- function syncAssets(pluginRoot, outDir) {
79
- const assetsSrc = resolve(pluginRoot, "assets");
80
- if (existsSync(assetsSrc)) cpSync(assetsSrc, resolve(outDir, "assets"), { recursive: true });
81
- }
82
-
83
-
84
- function stageDevAssets(pluginRoot) {
85
- const outDir = resolve(pluginRoot, DEV_OUT);
86
- mkdirSync(outDir, { recursive: true });
87
- const manifestSrc = resolve(pluginRoot, "manifest.json");
88
- if (existsSync(manifestSrc)) copyFileSync(manifestSrc, resolve(outDir, "manifest.json"));
89
- syncAssets(pluginRoot, outDir);
90
- return outDir;
91
- }
92
-
93
- function watchAssets(pluginRoot, outDir) {
94
- const assetsSrc = resolve(pluginRoot, "assets");
95
- if (!existsSync(assetsSrc)) return;
96
- watch(assetsSrc, { recursive: true }, () => syncAssets(pluginRoot, outDir));
97
- }
98
-
99
-
100
- function findViteBin(pluginRoot) {
101
- try {
102
- const req = createRequire(resolve(pluginRoot, "package.json"));
103
- const vitePkg = req.resolve("vite/package.json");
104
- return resolve(dirname(vitePkg), "bin", "vite.js");
105
- } catch {
106
- return null;
107
- }
108
- }
109
-
110
-
111
- function spawnPluginDevServer(pluginRoot, node, port, readyFile, sharedRuntimeBase) {
112
- if (!node || !findViteBin(pluginRoot)) return null;
113
- const runner = fileURLToPath(new URL("./pluginDevServer.mjs", import.meta.url));
114
-
115
- rmSync(resolve(pluginRoot, "node_modules", ".vite"), { recursive: true, force: true });
116
-
117
- return spawn(node, [runner, pluginRoot, String(port), readyFile], {
118
- cwd: pluginRoot,
119
- stdio: "inherit",
120
- env: {
121
- ...process.env,
122
- VITE_PLUGIN_PREVIEW: "true",
123
- MUSCAT_PLUGIN_SHARED_RUNTIME_BASE: sharedRuntimeBase,
124
- },
125
- });
126
- }
127
-
128
- function waitForPluginDevPort(readyFile, proc, timeoutMs = 15_000) {
129
- const start = Date.now();
130
- return new Promise((res, rej) => {
131
- let exited = false;
132
- proc.once("exit", (code) => {
133
- exited = true;
134
- rej(new Error(`plugin dev server exited before ready (code ${code ?? 0})`));
135
- });
136
-
137
- const tick = () => {
138
- if (existsSync(readyFile)) {
139
- try {
140
- const { port } = JSON.parse(readFileSync(readyFile, "utf8"));
141
- if (Number.isInteger(port)) return res(port);
142
- } catch {
143
- console.log("Keep polling until the ready file contains valid JSON.")
144
- }
145
- }
146
- if (Date.now() - start > timeoutMs)
147
- return rej(new Error("plugin dev server did not become ready in time"));
148
- if (!exited) setTimeout(tick, 100);
149
- };
150
- tick();
151
- });
152
- }
153
-
154
- export async function runDevUi(args = []) {
155
- const parsed = parseArgs(args);
156
- const requestedPort = Number(parsed.port ?? "4180");
157
- const robotIp = parsed["robot-ip"] ?? process.env.MUSCAT_ROBOT_HOST ?? await prompt(" Robot IP (skip if no robot): ");
158
-
159
- await checkKitUpdate();
160
- const pluginRoot = findPluginRoot();
161
- const outDir = stageDevAssets(pluginRoot);
162
- const port = await getFreePort(requestedPort);
163
-
164
- // No robot: the bundle talks to localhost:3000, so put a Muscat there (`dev` already did).
165
- if (!isRemoteRobot(robotIp) && process.env.MUSCAT_PK_MANAGED_DEV !== "1") {
166
- await ensureLocalMuscat().catch((e) => log.warn(`local Muscat: ${e.message}`));
167
- }
168
-
169
- watchAssets(pluginRoot, outDir);
170
-
171
- const node = findNodeBin();
172
- const readyFile = resolve(outDir, "plugin-dev-port.json");
173
- rmSync(readyFile, { force: true });
174
- const sharedRuntimeBase = `http://localhost:${port}/plugin-shared`;
175
- const viteProc = spawnPluginDevServer(
176
- pluginRoot,
177
- node,
178
- DEV_PLUGIN_PORT,
179
- readyFile,
180
- sharedRuntimeBase,
181
- );
182
- let devPort = DEV_PLUGIN_PORT;
183
-
184
- if (!viteProc) {
185
- log.warn("vite not found — UI will not load. Run `npm install` in the plugin project.");
186
- } else {
187
- devPort = await waitForPluginDevPort(readyFile, viteProc);
188
- viteProc.on("exit", (code) => {
189
- if (code) log.warn(`plugin dev server exited (code ${code}) — UI won't load (is :${devPort} free?).`);
190
- });
191
- }
192
-
193
- const previewRoot = findPreviewHostRoot();
194
- const serveEntry = resolve(previewRoot, "serve.mjs");
195
- if (!existsSync(resolve(previewRoot, "dist", "index.html"))) {
196
- log.step("building preview-host bundle (first run)…");
197
- await new Promise((res, rej) => {
198
- const p = spawn(node ?? process.execPath, [resolve(previewRoot, "build.mjs")], {
199
- stdio: "inherit",
200
- env: { ...process.env, VITE_PLUGIN_PREVIEW: "true" },
201
- });
202
- p.on("exit", (c) => (c === 0 ? res() : rej(new Error("preview-host build failed"))));
203
- });
204
- }
205
-
206
- const child = spawn(
207
- node ?? process.execPath,
208
- [
209
- serveEntry,
210
- "--plugin", outDir,
211
- "--port", String(port),
212
- "--dev-server-url", `http://localhost:${devPort}`,
213
- // A remote robot turns the bundle into that robot's Muscat UI; localhost stays the mock preview.
214
- ...(isRemoteRobot(robotIp) ? ["--robot-host", robotIp] : []),
215
- // The dev plugin's socket goes to the robot's gateway when the robot runs Muscat (the UI is
216
- // that robot's Muscat then); otherwise to the local runtime.
217
- ...((await robotHasMuscat(robotIp)) ? ["--socket-url", `ws://${robotIp}:${GATEWAY_PORT}`] : []),
218
- ],
219
- // preview-host only prints its address and paths; the "UI →" line below says what matters.
220
- { stdio: ["inherit", "ignore", "inherit"] },
221
- );
222
-
223
- for (let i = 0; i < 50 && !(await fetch(`http://localhost:${port}/`).then(() => true, () => false)); i++)
224
- await new Promise((r) => setTimeout(r, 200));
225
- log.ok(`UI → http://localhost:${port}`);
226
-
227
- let cleaned = false;
228
- const cleanup = () => {
229
- if (cleaned) return;
230
- cleaned = true;
231
- if (viteProc && !viteProc.killed && viteProc.exitCode === null) viteProc.kill();
232
- if (!child.killed && child.exitCode === null) child.kill();
233
- };
234
- process.once("SIGINT", cleanup);
235
- process.once("SIGTERM", cleanup);
236
- process.once("SIGHUP", cleanup);
237
- child.on("exit", (code) => {
238
- cleanup();
239
- process.exit(code ?? 0);
240
- });
241
- }
242
-
243
- export { findPluginRoot, findPreviewHostRoot };
1
+
2
+ import { spawn, spawnSync } from "node:child_process";
3
+ import { createServer as createNetServer } from "node:net";
4
+ import { createRequire } from "node:module";
5
+ import { copyFileSync, cpSync, existsSync, mkdirSync, readFileSync, rmSync, watch } from "node:fs";
6
+ import { homedir } from "node:os";
7
+ import { dirname, resolve } from "node:path";
8
+ import { fileURLToPath } from "node:url";
9
+ import { checkKitUpdate, findPluginRoot, hasBin, kitRoot, log, parseArgs, prompt } from "./util.mjs";
10
+ import { ensureLocalMuscat, GATEWAY_PORT, robotHasMuscat } from "./muscatLocal.mjs";
11
+ import { isRemoteRobot } from "./zenohDev.mjs";
12
+
13
+
14
+ const DEV_PLUGIN_PORT = 4181;
15
+
16
+ function getFreePort(preferred) {
17
+ return new Promise((res) => {
18
+ const srv = createNetServer();
19
+ srv.once("error", () => {
20
+ const s2 = createNetServer();
21
+ s2.listen(0, () => {
22
+ const { port } = s2.address();
23
+ s2.close(() => res(port));
24
+ });
25
+ });
26
+ srv.listen(preferred, () => srv.close(() => res(preferred)));
27
+ });
28
+ }
29
+
30
+ const PREVIEW_PKG = "@rainbow-robotics/preview-host";
31
+ const CACHE_DIR = resolve(homedir(), ".muscat-pk");
32
+ const CACHE_ROOT = resolve(CACHE_DIR, "node_modules", "@rainbow-robotics", "preview-host");
33
+
34
+
35
+ const DEV_OUT = ".muscat-dev";
36
+
37
+ function findNodeBin() {
38
+ if (typeof Bun === "undefined") return process.execPath;
39
+ for (const c of ["node", "node20", "node18"]) {
40
+ if (hasBin(c)) return c;
41
+ }
42
+ return null;
43
+ }
44
+
45
+ function findPreviewHostRoot() {
46
+ try {
47
+ const req = createRequire(import.meta.url);
48
+ return dirname(req.resolve(`${PREVIEW_PKG}/package.json`));
49
+ } catch {
50
+ console.log("Try the sibling and cached package locations below.")
51
+ }
52
+
53
+ const sibling = resolve(kitRoot, "../preview-host");
54
+ if (existsSync(resolve(sibling, "package.json"))) return sibling;
55
+
56
+ if (existsSync(resolve(CACHE_ROOT, "package.json"))) return CACHE_ROOT;
57
+
58
+ if (!hasBin("npm")) {
59
+ throw new Error(
60
+ `preview-host를 찾을 수 없습니다.\n` +
61
+ `Node.js 20+ 를 설치하면 자동으로 준비됩니다: https://nodejs.org`,
62
+ );
63
+ }
64
+ log.step(`preview-host 설치 중 (~/.muscat-pk) — 첫 실행 시 한 번만 수행됩니다…`);
65
+ mkdirSync(CACHE_DIR, { recursive: true });
66
+ const r = spawnSync(
67
+ "npm",
68
+ ["install", "--prefix", CACHE_DIR, "--save", PREVIEW_PKG],
69
+ { stdio: "inherit" },
70
+ );
71
+ if (r.status !== 0) throw new Error("preview-host 설치 실패.");
72
+ if (!existsSync(resolve(CACHE_ROOT, "package.json"))) {
73
+ throw new Error("preview-host 설치 후에도 패키지를 찾을 수 없습니다.");
74
+ }
75
+ return CACHE_ROOT;
76
+ }
77
+
78
+ function syncAssets(pluginRoot, outDir) {
79
+ const assetsSrc = resolve(pluginRoot, "assets");
80
+ if (existsSync(assetsSrc)) cpSync(assetsSrc, resolve(outDir, "assets"), { recursive: true });
81
+ }
82
+
83
+
84
+ function stageDevAssets(pluginRoot) {
85
+ const outDir = resolve(pluginRoot, DEV_OUT);
86
+ mkdirSync(outDir, { recursive: true });
87
+ const manifestSrc = resolve(pluginRoot, "manifest.json");
88
+ if (existsSync(manifestSrc)) copyFileSync(manifestSrc, resolve(outDir, "manifest.json"));
89
+ syncAssets(pluginRoot, outDir);
90
+ return outDir;
91
+ }
92
+
93
+ function watchAssets(pluginRoot, outDir) {
94
+ const assetsSrc = resolve(pluginRoot, "assets");
95
+ if (!existsSync(assetsSrc)) return;
96
+ watch(assetsSrc, { recursive: true }, () => syncAssets(pluginRoot, outDir));
97
+ }
98
+
99
+
100
+ function findViteBin(pluginRoot) {
101
+ try {
102
+ const req = createRequire(resolve(pluginRoot, "package.json"));
103
+ const vitePkg = req.resolve("vite/package.json");
104
+ return resolve(dirname(vitePkg), "bin", "vite.js");
105
+ } catch {
106
+ return null;
107
+ }
108
+ }
109
+
110
+
111
+ function spawnPluginDevServer(pluginRoot, node, port, readyFile, sharedRuntimeBase) {
112
+ if (!node || !findViteBin(pluginRoot)) return null;
113
+ const runner = fileURLToPath(new URL("./pluginDevServer.mjs", import.meta.url));
114
+
115
+ rmSync(resolve(pluginRoot, "node_modules", ".vite"), { recursive: true, force: true });
116
+
117
+ return spawn(node, [runner, pluginRoot, String(port), readyFile], {
118
+ cwd: pluginRoot,
119
+ stdio: "inherit",
120
+ env: {
121
+ ...process.env,
122
+ VITE_PLUGIN_PREVIEW: "true",
123
+ MUSCAT_PLUGIN_SHARED_RUNTIME_BASE: sharedRuntimeBase,
124
+ },
125
+ });
126
+ }
127
+
128
+ // The ready file is the signal and an exit the failure; the timeout only guards a hang. A cold vite start
129
+ // takes ~11s on Windows and more while `dev`'s first docker build loads the machine, so a tight limit
130
+ // stopped a healthy `dev`.
131
+ function waitForPluginDevPort(readyFile, proc, timeoutMs = 120_000) {
132
+ const start = Date.now();
133
+ const slow = setTimeout(() => log.info("plugin dev server (vite) is still starting…"), 15_000);
134
+ return new Promise((res, rej) => {
135
+ let exited = false;
136
+ proc.once("exit", (code) => {
137
+ exited = true;
138
+ rej(new Error(`plugin dev server exited before ready (code ${code ?? 0})`));
139
+ });
140
+
141
+ const tick = () => {
142
+ if (existsSync(readyFile)) {
143
+ try {
144
+ const { port } = JSON.parse(readFileSync(readyFile, "utf8"));
145
+ if (Number.isInteger(port)) return res(port);
146
+ } catch {
147
+ console.log("Keep polling until the ready file contains valid JSON.")
148
+ }
149
+ }
150
+ if (Date.now() - start > timeoutMs)
151
+ return rej(new Error("plugin dev server did not become ready in time"));
152
+ if (!exited) setTimeout(tick, 100);
153
+ };
154
+ tick();
155
+ }).finally(() => clearTimeout(slow));
156
+ }
157
+
158
+ export async function runDevUi(args = []) {
159
+ const parsed = parseArgs(args);
160
+ const requestedPort = Number(parsed.port ?? "4180");
161
+ const robotIp = parsed["robot-ip"] ?? process.env.MUSCAT_ROBOT_HOST ?? await prompt(" Robot IP (skip if no robot): ");
162
+
163
+ await checkKitUpdate();
164
+ const pluginRoot = findPluginRoot();
165
+ const outDir = stageDevAssets(pluginRoot);
166
+ const port = await getFreePort(requestedPort);
167
+
168
+ // No robot: the bundle talks to localhost:3000, so put a Muscat there (`dev` already did).
169
+ if (!isRemoteRobot(robotIp) && process.env.MUSCAT_PK_MANAGED_DEV !== "1") {
170
+ await ensureLocalMuscat().catch((e) => log.warn(`local Muscat: ${e.message}`));
171
+ }
172
+
173
+ watchAssets(pluginRoot, outDir);
174
+
175
+ const node = findNodeBin();
176
+ const readyFile = resolve(outDir, "plugin-dev-port.json");
177
+ rmSync(readyFile, { force: true });
178
+ const sharedRuntimeBase = `http://localhost:${port}/plugin-shared`;
179
+ const viteProc = spawnPluginDevServer(
180
+ pluginRoot,
181
+ node,
182
+ DEV_PLUGIN_PORT,
183
+ readyFile,
184
+ sharedRuntimeBase,
185
+ );
186
+ let devPort = DEV_PLUGIN_PORT;
187
+
188
+ if (!viteProc) {
189
+ log.warn("vite not found — UI will not load. Run `npm install` in the plugin project.");
190
+ } else {
191
+ devPort = await waitForPluginDevPort(readyFile, viteProc);
192
+ viteProc.on("exit", (code) => {
193
+ if (code) log.warn(`plugin dev server exited (code ${code}) — UI won't load (is :${devPort} free?).`);
194
+ });
195
+ }
196
+
197
+ const previewRoot = findPreviewHostRoot();
198
+ const serveEntry = resolve(previewRoot, "serve.mjs");
199
+ if (!existsSync(resolve(previewRoot, "dist", "index.html"))) {
200
+ log.step("building preview-host bundle (first run)…");
201
+ await new Promise((res, rej) => {
202
+ const p = spawn(node ?? process.execPath, [resolve(previewRoot, "build.mjs")], {
203
+ stdio: "inherit",
204
+ env: { ...process.env, VITE_PLUGIN_PREVIEW: "true" },
205
+ });
206
+ p.on("exit", (c) => (c === 0 ? res() : rej(new Error("preview-host build failed"))));
207
+ });
208
+ }
209
+
210
+ const child = spawn(
211
+ node ?? process.execPath,
212
+ [
213
+ serveEntry,
214
+ "--plugin", outDir,
215
+ "--port", String(port),
216
+ "--dev-server-url", `http://localhost:${devPort}`,
217
+ // A remote robot turns the bundle into that robot's Muscat UI; localhost stays the mock preview.
218
+ ...(isRemoteRobot(robotIp) ? ["--robot-host", robotIp] : []),
219
+ // The dev plugin's socket goes to the robot's gateway when the robot runs Muscat (the UI is
220
+ // that robot's Muscat then); otherwise to the local runtime.
221
+ ...((await robotHasMuscat(robotIp)) ? ["--socket-url", `ws://${robotIp}:${GATEWAY_PORT}`] : []),
222
+ ],
223
+ // preview-host only prints its address and paths; the "UI →" line below says what matters.
224
+ { stdio: ["inherit", "ignore", "inherit"] },
225
+ );
226
+
227
+ for (let i = 0; i < 50 && !(await fetch(`http://localhost:${port}/`).then(() => true, () => false)); i++)
228
+ await new Promise((r) => setTimeout(r, 200));
229
+ log.ok(`UI → http://localhost:${port}`);
230
+
231
+ let cleaned = false;
232
+ const cleanup = () => {
233
+ if (cleaned) return;
234
+ cleaned = true;
235
+ if (viteProc && !viteProc.killed && viteProc.exitCode === null) viteProc.kill();
236
+ if (!child.killed && child.exitCode === null) child.kill();
237
+ };
238
+ process.once("SIGINT", cleanup);
239
+ process.once("SIGTERM", cleanup);
240
+ process.once("SIGHUP", cleanup);
241
+ child.on("exit", (code) => {
242
+ cleanup();
243
+ process.exit(code ?? 0);
244
+ });
245
+ }
246
+
247
+ export { findPluginRoot, findPreviewHostRoot };
@@ -1,56 +1,56 @@
1
- // When compiled with `bun --compile`, esbuild's native subprocess binary is
2
- // not bundled. Use Bun's built-in bundler instead.
3
- async function buildWithBun(options) {
4
- const { entryPoints, outfile, format, minify, loader, define, external } = options;
5
- const { dirname } = await import("node:path");
6
- const result = await Bun.build({
7
- entrypoints: entryPoints,
8
- outdir: dirname(outfile),
9
- format: format ?? "esm",
10
- minify: minify ?? false,
11
- loader,
12
- define,
13
- external,
14
- target: "node",
15
- throw: false,
16
- });
17
- if (!result.success) {
18
- for (const log of result.logs) console.error(log.message);
19
- throw new Error("Bun.build() failed");
20
- }
21
- }
22
-
23
- async function buildWithWasm(options) {
24
- const wasm = await import("esbuild-wasm");
25
- return wasm.build(options);
26
- }
27
-
28
- function isNativeMissing(err) {
29
- const msg = String(err?.message || err?.code || err || "");
30
- return (
31
- msg.includes("another platform") ||
32
- msg.includes("Cannot find module") ||
33
- msg.includes("Cannot find package") ||
34
- msg.includes("not found") ||
35
- msg.includes("No such file") ||
36
- msg.includes("ENOENT") ||
37
- msg.includes("MODULE_NOT_FOUND")
38
- );
39
- }
40
-
41
- export async function buildWithFallback(options) {
42
- if (typeof Bun !== "undefined") return buildWithBun(options);
43
-
44
- // Try native esbuild (faster, no extra setup). Falls back to wasm when:
45
- // - esbuild was not installed (removed from hard dependencies to avoid
46
- // postinstall script blocking npm i -g on Windows)
47
- // - binary was built for a different platform
48
- try {
49
- const native = await import("esbuild");
50
- return await native.build(options);
51
- } catch (err) {
52
- if (!isNativeMissing(err)) throw err;
53
- }
54
-
55
- return buildWithWasm(options);
56
- }
1
+ // When compiled with `bun --compile`, esbuild's native subprocess binary is
2
+ // not bundled. Use Bun's built-in bundler instead.
3
+ async function buildWithBun(options) {
4
+ const { entryPoints, outfile, format, minify, loader, define, external } = options;
5
+ const { dirname } = await import("node:path");
6
+ const result = await Bun.build({
7
+ entrypoints: entryPoints,
8
+ outdir: dirname(outfile),
9
+ format: format ?? "esm",
10
+ minify: minify ?? false,
11
+ loader,
12
+ define,
13
+ external,
14
+ target: "node",
15
+ throw: false,
16
+ });
17
+ if (!result.success) {
18
+ for (const log of result.logs) console.error(log.message);
19
+ throw new Error("Bun.build() failed");
20
+ }
21
+ }
22
+
23
+ async function buildWithWasm(options) {
24
+ const wasm = await import("esbuild-wasm");
25
+ return wasm.build(options);
26
+ }
27
+
28
+ function isNativeMissing(err) {
29
+ const msg = String(err?.message || err?.code || err || "");
30
+ return (
31
+ msg.includes("another platform") ||
32
+ msg.includes("Cannot find module") ||
33
+ msg.includes("Cannot find package") ||
34
+ msg.includes("not found") ||
35
+ msg.includes("No such file") ||
36
+ msg.includes("ENOENT") ||
37
+ msg.includes("MODULE_NOT_FOUND")
38
+ );
39
+ }
40
+
41
+ export async function buildWithFallback(options) {
42
+ if (typeof Bun !== "undefined") return buildWithBun(options);
43
+
44
+ // Try native esbuild (faster, no extra setup). Falls back to wasm when:
45
+ // - esbuild was not installed (removed from hard dependencies to avoid
46
+ // postinstall script blocking npm i -g on Windows)
47
+ // - binary was built for a different platform
48
+ try {
49
+ const native = await import("esbuild");
50
+ return await native.build(options);
51
+ } catch (err) {
52
+ if (!isNativeMissing(err)) throw err;
53
+ }
54
+
55
+ return buildWithWasm(options);
56
+ }