@rainbow-robotics/muscat-plugin-kit 1.3.8-dev.3 → 1.10.1-dev.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 (212) 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 -153
  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 -0
  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 -79
  16. package/cli/src/cppIde.mjs +75 -75
  17. package/cli/src/dev.mjs +165 -163
  18. package/cli/src/devBack.mjs +727 -670
  19. package/cli/src/devUi.mjs +243 -238
  20. package/cli/src/esbuild.mjs +56 -56
  21. package/cli/src/host_agent.py +223 -222
  22. package/cli/src/manifest.mjs +287 -287
  23. package/cli/src/mcp.mjs +1071 -1016
  24. package/cli/src/muscatLocal.mjs +209 -197
  25. package/cli/src/new.mjs +343 -338
  26. package/cli/src/pluginDevServer.mjs +111 -112
  27. package/cli/src/ports.mjs +193 -193
  28. package/cli/src/python.mjs +112 -113
  29. package/cli/src/ros2.mjs +109 -110
  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 -437
  36. package/cli/src/zenohDev.mjs +81 -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-CI89lJl-.js → Color-YHDXOIA2-D6JqZzDJ.js} +1 -1
  103. package/cli/storybook-dist/assets/{Docs-BFY0Ci6m.js → Docs-6gD2kUo1.js} +2 -2
  104. package/cli/storybook-dist/assets/{Docs-Csxm7Pfz.js → Docs-B9wd8Ok7.js} +3 -3
  105. package/cli/storybook-dist/assets/{Docs-CnEDa7je.js → Docs-CMjovnSY.js} +4 -4
  106. package/cli/storybook-dist/assets/{Docs-7jUVS93j.js → Docs-CgFbWWXM.js} +2 -2
  107. package/cli/storybook-dist/assets/{Docs-Bg_qFlWf.js → Docs-DBQup8Bu.js} +3 -3
  108. package/cli/storybook-dist/assets/{Docs-pBF5PbN5.js → Docs-ESb7JAHg.js} +3 -3
  109. package/cli/storybook-dist/assets/{DocsRenderer-CFRXHY34-DBBBNBbZ.js → DocsRenderer-CFRXHY34-BOUI1AHi.js} +1 -1
  110. package/cli/storybook-dist/assets/{NxAvatar.stories-CM98sSb1.js → NxAvatar.stories-DsYFMUh3.js} +1 -1
  111. package/cli/storybook-dist/assets/{NxButton.stories-BVmEmDTn.js → NxButton.stories-CHfNcqsc.js} +8 -8
  112. package/cli/storybook-dist/assets/{NxNumberInput.stories-DNvQbqEI.js → NxNumberInput.stories-BFw_4vFE.js} +1 -1
  113. package/cli/storybook-dist/assets/{NxPagination.stories-BHTyJLgq.js → NxPagination.stories-DVfxyw4M.js} +1 -1
  114. package/cli/storybook-dist/assets/{NxPointerHoldButton.stories-By8KWJWJ.js → NxPointerHoldButton.stories-BzyxUWoZ.js} +1 -1
  115. package/cli/storybook-dist/assets/{NxRangeInput.stories-CEN6h9wS.js → NxRangeInput.stories-DmRdzBc1.js} +6 -6
  116. package/cli/storybook-dist/assets/{NxSelectBox.stories-D8jfN20G.js → NxSelectBox.stories-B1KkNUOf.js} +1 -1
  117. package/cli/storybook-dist/assets/{NxSlideRange.stories-D3J7RLUl.js → NxSlideRange.stories-CyOdvfQ6.js} +1 -1
  118. package/cli/storybook-dist/assets/{NxSwitch.stories-DI9DCdqg.js → NxSwitch.stories-DrDBw0qp.js} +1 -1
  119. package/cli/storybook-dist/assets/{NxTextArea.stories-B-1Ou1vF.js → NxTextArea.stories-DTB2aqNS.js} +1 -1
  120. package/cli/storybook-dist/assets/{NxTextInput.stories-BKuOzpHo.js → NxTextInput.stories-DU0rucmM.js} +1 -1
  121. package/cli/storybook-dist/assets/{RBAccordion.stories-6IYUcdt3.js → RBAccordion.stories-DTfOtXtp.js} +3 -3
  122. package/cli/storybook-dist/assets/{RBAccordionGroup.stories-DP3JzHJm.js → RBAccordionGroup.stories-9y9BjrUe.js} +10 -10
  123. package/cli/storybook-dist/assets/{RBAlert.stories-DWuWyDhE.js → RBAlert.stories-DLTAv9fT.js} +3 -3
  124. package/cli/storybook-dist/assets/{RBBadge.stories-B-WWqdEZ.js → RBBadge.stories-BNMACewA.js} +1 -1
  125. package/cli/storybook-dist/assets/{RBBattery.stories-C_csZJf8.js → RBBattery.stories-B3kXMAt5.js} +1 -1
  126. package/cli/storybook-dist/assets/{RBCard.stories-DqJP2dj2.js → RBCard.stories-Y-s8R2n7.js} +39 -39
  127. package/cli/storybook-dist/assets/{RBCheckBox.stories-DJJtQVBP.js → RBCheckBox.stories-DBuT9tL4.js} +1 -1
  128. package/cli/storybook-dist/assets/{RBCheckIconButton.stories-DNi6YACF.js → RBCheckIconButton.stories-CWu1TL56.js} +1 -1
  129. package/cli/storybook-dist/assets/{RBCheckLabelButton.stories-Df2ZHCAH.js → RBCheckLabelButton.stories-sCu2MGCX.js} +17 -17
  130. package/cli/storybook-dist/assets/{RBChipTab.stories-DHIebYdr.js → RBChipTab.stories-BX9qLJkR.js} +5 -5
  131. package/cli/storybook-dist/assets/{RBChipsBoxTab.stories-BBng9GCS.js → RBChipsBoxTab.stories-35u1aJ-P.js} +1 -1
  132. package/cli/storybook-dist/assets/{RBColorIcons.stories-DJrurysg.js → RBColorIcons.stories-DAOZ5Ies.js} +1 -1
  133. package/cli/storybook-dist/assets/RBCommand.stories-BSqXDkKw.js +73 -0
  134. package/cli/storybook-dist/assets/{RBConfirm.stories-CSfY8YgA.js → RBConfirm.stories-iMXcUh7Z.js} +3 -3
  135. package/cli/storybook-dist/assets/{RBDateInput.stories-BxXvUfV6.js → RBDateInput.stories-hK5rXECf.js} +1 -1
  136. package/cli/storybook-dist/assets/RBDialog.stories-BAktz-ku.js +38 -0
  137. package/cli/storybook-dist/assets/{RBDivider.stories-C9oGl_IM.js → RBDivider.stories-BAK-iZ1Z.js} +1 -1
  138. package/cli/storybook-dist/assets/{RBDrawer.stories-D7DWSFAa.js → RBDrawer.stories-B2nqf2Nh.js} +12 -12
  139. package/cli/storybook-dist/assets/RBDropdownMenu.stories-DbW2fWAj.js +86 -0
  140. package/cli/storybook-dist/assets/{RBEmptyView.stories-D3yofNoP.js → RBEmptyView.stories-nCenrgBh.js} +1 -1
  141. package/cli/storybook-dist/assets/{RBIconButton.stories-l_YkDbHC.js → RBIconButton.stories-DRH7O3sp.js} +1 -1
  142. package/cli/storybook-dist/assets/{RBIcons.stories-BngzBBTw.js → RBIcons.stories-D3PyJXG8.js} +1 -1
  143. package/cli/storybook-dist/assets/{RBInlineLabelButton.stories-B6hyVALJ.js → RBInlineLabelButton.stories-modQbt10.js} +1 -1
  144. package/cli/storybook-dist/assets/{RBJoyStick.stories-D_Dq7D8E.js → RBJoyStick.stories-BY14qVgR.js} +1 -1
  145. package/cli/storybook-dist/assets/{RBLabelButton.stories-Bt6Nz4R8.js → RBLabelButton.stories-DzF7vGwm.js} +1 -1
  146. package/cli/storybook-dist/assets/{RBLight.stories-kRu2LDSP.js → RBLight.stories-lF4FRmVh.js} +1 -1
  147. package/cli/storybook-dist/assets/{RBMenubar.stories-CGuAr1W6.js → RBMenubar.stories-XhrI7bsV.js} +1 -1
  148. package/cli/storybook-dist/assets/{RBMultiRangeInput.stories-BX1UOmOj.js → RBMultiRangeInput.stories-DprllQDl.js} +1 -1
  149. package/cli/storybook-dist/assets/{RBPagination.stories-TrJdjSlQ.js → RBPagination.stories-2v2gBJfC.js} +1 -1
  150. package/cli/storybook-dist/assets/{RBPopover.stories-CbMwKmFe.js → RBPopover.stories-C8iLIZpv.js} +1 -1
  151. package/cli/storybook-dist/assets/{RBPrompt.stories-CFPXGQVF.js → RBPrompt.stories-Th_HrWHI.js} +1 -1
  152. package/cli/storybook-dist/assets/{RBRadioBox.stories-Cs2Rw1Rf.js → RBRadioBox.stories-CoHuLaN3.js} +1 -1
  153. package/cli/storybook-dist/assets/{RBRadioButton.stories-BVHC-XvU.js → RBRadioButton.stories-DULxE_ff.js} +1 -1
  154. package/cli/storybook-dist/assets/{RBRangeDateInput.stories-8LiCL1Vi.js → RBRangeDateInput.stories-D8A9KBSS.js} +1 -1
  155. package/cli/storybook-dist/assets/{RBResizable.stories-CXLXv-Cd.js → RBResizable.stories-C41QfrQ3.js} +14 -14
  156. package/cli/storybook-dist/assets/{RBSelectBox.stories-ccel3kbv.js → RBSelectBox.stories-C1gNmwzw.js} +1 -1
  157. package/cli/storybook-dist/assets/RBSheet.stories-_6VH-RUm.js +39 -0
  158. package/cli/storybook-dist/assets/{RBSideNumberInput.stories-CPOTUek4.js → RBSideNumberInput.stories-9LlgQ8nh.js} +3 -3
  159. package/cli/storybook-dist/assets/{RBSlider.stories-Cc_bwUwS.js → RBSlider.stories-oUgo5K9d.js} +3 -3
  160. package/cli/storybook-dist/assets/{RBSpinner.stories-m2I4_oTS.js → RBSpinner.stories-DDpohbY2.js} +1 -1
  161. package/cli/storybook-dist/assets/{RBSwitch.stories-DRQb4llM.js → RBSwitch.stories-gW-GN7QO.js} +7 -7
  162. package/cli/storybook-dist/assets/{RBTab.stories-DvnR5c0A.js → RBTab.stories-CN-PV3HH.js} +1 -1
  163. package/cli/storybook-dist/assets/{RBTable.stories-B0QWuQmW.js → RBTable.stories-BAZLpxtM.js} +29 -29
  164. package/cli/storybook-dist/assets/{RBTableRow.stories-B7V61cZI.js → RBTableRow.stories-CwjVrszB.js} +1 -1
  165. package/cli/storybook-dist/assets/{RBTabs.stories-CTcTt28t.js → RBTabs.stories-JuEo2sUL.js} +7 -7
  166. package/cli/storybook-dist/assets/{RBTextArea.stories-CxmXsiDS.js → RBTextArea.stories-D0_Pv4qZ.js} +3 -3
  167. package/cli/storybook-dist/assets/{RBTextField.stories-HuzSS1QR.js → RBTextField.stories-CCsOvZqV.js} +15 -15
  168. package/cli/storybook-dist/assets/{RBTextInput.stories-DzSR9mIU.js → RBTextInput.stories-Cccn3VNm.js} +3 -3
  169. package/cli/storybook-dist/assets/{RBToast.stories-CUyxR3hN.js → RBToast.stories-I5617t0K.js} +1 -1
  170. package/cli/storybook-dist/assets/{RBToggle.stories-9Z6J-KMM.js → RBToggle.stories-DsgKjGsJ.js} +4 -4
  171. package/cli/storybook-dist/assets/{RBToggleGroup.stories-Bq1QbXU3.js → RBToggleGroup.stories-BZEzSDuz.js} +5 -5
  172. package/cli/storybook-dist/assets/{RBTooltip.stories-CM1R_eeG.js → RBTooltip.stories-4oSyAWsA.js} +1 -1
  173. package/cli/storybook-dist/assets/{SideNumberInput-DJEqu6Ws.js → SideNumberInput-DSKbd0bG.js} +743 -743
  174. package/cli/storybook-dist/assets/{entry-preview-DP10QZSb.js → entry-preview-B35XREGs.js} +1 -1
  175. package/cli/storybook-dist/assets/{iframe-B8FjC8Y_.js → iframe-BB797lmL.js} +2 -2
  176. package/cli/storybook-dist/assets/{index-MqY7mw_o.js → index-BU2567EP.js} +3 -3
  177. package/cli/storybook-dist/assets/{preview-u1kopjLn.js → preview-C7DaSWyc.js} +2 -2
  178. package/cli/storybook-dist/assets/preview-CbuRHit4.js +3 -0
  179. package/cli/storybook-dist/assets/preview-CigNHo-I.css +1 -0
  180. package/cli/storybook-dist/assets/react-resizable-panels-Dp9zi-o3.css +1 -0
  181. package/cli/storybook-dist/assets/{react-resizable-panels.browser-D49JKwKo.js → react-resizable-panels.browser-ChIvlwo7.js} +8 -8
  182. package/cli/storybook-dist/iframe.html +2 -2
  183. package/cli/storybook-dist/index.html +1 -1
  184. package/cli/storybook-dist/project.json +1 -1
  185. package/cli/templates/common/.mcp.json +8 -8
  186. package/cli/templates/common/README.md +1231 -1226
  187. package/cli/templates/common/assets/icon.svg +45 -45
  188. package/cli/templates/common/manifest.json +26 -26
  189. package/cli/templates/common/package.json +22 -22
  190. package/cli/templates/common/py/main.py +125 -125
  191. package/cli/templates/common/tsconfig.json +13 -13
  192. package/cli/templates/common/ui/content.tsx +216 -216
  193. package/cli/templates/common/ui/style.css +6 -6
  194. package/cli/templates/common/vite.config.ts +10 -10
  195. package/cli/templates/cpp/cpp/main.cpp +73 -73
  196. package/cli/templates/readme-cpp/README.md +5 -0
  197. package/cli/templates/ros2/ros2_ws/src/__PLUGIN_SLUG__/__PLUGIN_SLUG__/node.py +25 -25
  198. package/cli/templates/ros2/ros2_ws/src/__PLUGIN_SLUG__/package.xml +10 -10
  199. package/cli/templates/ros2/ros2_ws/src/__PLUGIN_SLUG__/setup.py +18 -18
  200. package/cli/templates/ros2-cpp/ros2_ws/src/__PLUGIN_SLUG__/package.xml +11 -11
  201. package/cli/templates/ros2-cpp/ros2_ws/src/__PLUGIN_SLUG__/src/node.cpp +23 -23
  202. package/cli/vite.d.mts +25 -25
  203. package/cli/vite.mjs +292 -292
  204. package/package.json +4 -4
  205. package/cli/src/templates-embedded.mjs +0 -4
  206. package/cli/storybook-dist/assets/RBCommand.stories-DnXBHyas.js +0 -73
  207. package/cli/storybook-dist/assets/RBDialog.stories-D3yVVilm.js +0 -38
  208. package/cli/storybook-dist/assets/RBDropdownMenu.stories-BJN_1_jp.js +0 -86
  209. package/cli/storybook-dist/assets/RBSheet.stories-CGpXDNGJ.js +0 -39
  210. package/cli/storybook-dist/assets/preview-BYhMD55w.css +0 -1
  211. package/cli/storybook-dist/assets/preview-eUpuI_wJ.js +0 -3
  212. package/cli/storybook-dist/assets/react-resizable-panels-DJMuB2U0.css +0 -1
package/cli/src/devUi.mjs CHANGED
@@ -1,238 +1,243 @@
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 } 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
- log.step(`vite dev server (HMR) starting at :${port} — ui/*.tsx`);
117
-
118
- return spawn(node, [runner, pluginRoot, String(port), readyFile], {
119
- cwd: pluginRoot,
120
- stdio: "inherit",
121
- env: {
122
- ...process.env,
123
- VITE_PLUGIN_PREVIEW: "true",
124
- MUSCAT_PLUGIN_SHARED_RUNTIME_BASE: sharedRuntimeBase,
125
- },
126
- });
127
- }
128
-
129
- function waitForPluginDevPort(readyFile, proc, timeoutMs = 15_000) {
130
- const start = Date.now();
131
- return new Promise((res, rej) => {
132
- let exited = false;
133
- proc.once("exit", (code) => {
134
- exited = true;
135
- rej(new Error(`plugin dev server exited before ready (code ${code ?? 0})`));
136
- });
137
-
138
- const tick = () => {
139
- if (existsSync(readyFile)) {
140
- try {
141
- const { port } = JSON.parse(readFileSync(readyFile, "utf8"));
142
- if (Number.isInteger(port)) return res(port);
143
- } catch {
144
- console.log("Keep polling until the ready file contains valid JSON.")
145
- }
146
- }
147
- if (Date.now() - start > timeoutMs)
148
- return rej(new Error("plugin dev server did not become ready in time"));
149
- if (!exited) setTimeout(tick, 100);
150
- };
151
- tick();
152
- });
153
- }
154
-
155
- export async function runDevUi(args = []) {
156
- const parsed = parseArgs(args);
157
- const requestedPort = Number(parsed.port ?? "4180");
158
- const robotIp = parsed["robot-ip"] ?? process.env.MUSCAT_ROBOT_HOST ?? await prompt(" Robot IP (skip if no robot): ");
159
-
160
- await checkKitUpdate();
161
- const pluginRoot = findPluginRoot();
162
- const outDir = stageDevAssets(pluginRoot);
163
- const port = await getFreePort(requestedPort);
164
- if (port !== requestedPort)
165
- log.warn(`preview-host port ${requestedPort} is in use — using ${port} instead.`);
166
-
167
- if (robotIp) log.info(`MUSCAT_API_ORIGIN → http://${robotIp}:*`);
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
- log.step(`starting preview-host on :${port}`);
211
- const child = spawn(
212
- node ?? process.execPath,
213
- [
214
- serveEntry,
215
- "--plugin", outDir,
216
- "--port", String(port),
217
- "--dev-server-url", `http://localhost:${devPort}`,
218
- ...(robotIp ? ["--robot-host", robotIp] : []),
219
- ],
220
- { stdio: "inherit" },
221
- );
222
-
223
- let cleaned = false;
224
- const cleanup = () => {
225
- if (cleaned) return;
226
- cleaned = true;
227
- if (viteProc && !viteProc.killed && viteProc.exitCode === null) viteProc.kill();
228
- if (!child.killed && child.exitCode === null) child.kill();
229
- };
230
- process.once("SIGINT", cleanup);
231
- process.once("SIGTERM", cleanup);
232
- child.on("exit", (code) => {
233
- cleanup();
234
- process.exit(code ?? 0);
235
- });
236
- }
237
-
238
- 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
+ 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,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
+ }