@rainbow-robotics/muscat-plugin-kit 1.10.2-dev.5 → 1.10.2-dev.7

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 (36) hide show
  1. package/cli/bin/muscat-pk.mjs +3 -0
  2. package/cli/src/build.mjs +4 -9
  3. package/cli/src/cppIde.mjs +2 -1
  4. package/cli/src/dev.mjs +4 -1
  5. package/cli/src/devBack.mjs +10 -7
  6. package/cli/src/devId.mjs +54 -0
  7. package/cli/src/devUi.mjs +24 -14
  8. package/cli/src/mcpProxy.mjs +110 -0
  9. package/cli/src/muscatLocal.mjs +15 -2
  10. package/cli/src/storybook.mjs +2 -20
  11. package/cli/src/templates-embedded.mjs +2 -2
  12. package/cli/src/util.mjs +29 -1
  13. package/cli/src/zip.mjs +121 -0
  14. package/cli/storybook-dist/assets/{Color-YHDXOIA2-d4UialIW.js → Color-YHDXOIA2-BoqBLKNL.js} +1 -1
  15. package/cli/storybook-dist/assets/{Docs-DpuckkF2.js → Docs-BhJTZ0C_.js} +1 -1
  16. package/cli/storybook-dist/assets/{Docs-tWjVyRAS.js → Docs-BlIu-JrJ.js} +1 -1
  17. package/cli/storybook-dist/assets/{Docs-vU43epz3.js → Docs-C4ktkQce.js} +1 -1
  18. package/cli/storybook-dist/assets/{Docs-DOzwT3cw.js → Docs-Cg3A7xDz.js} +1 -1
  19. package/cli/storybook-dist/assets/{Docs-CppxziOu.js → Docs-VKVuhalv.js} +1 -1
  20. package/cli/storybook-dist/assets/{Docs-BySWRVQD.js → Docs-_i1XHVXU.js} +1 -1
  21. package/cli/storybook-dist/assets/{DocsRenderer-CFRXHY34-Boj7BBcx.js → DocsRenderer-CFRXHY34-BGHjhFiI.js} +1 -1
  22. package/cli/storybook-dist/assets/{entry-preview-BfxbSNyQ.js → entry-preview-C2IBQfq7.js} +1 -1
  23. package/cli/storybook-dist/assets/{iframe-D3ykNOcq.js → iframe-D-mTyH7q.js} +2 -2
  24. package/cli/storybook-dist/assets/{index-NJyPL3Uy.js → index-DKrg3vQJ.js} +3 -3
  25. package/cli/storybook-dist/assets/preview-CpePTsLG.js +5 -0
  26. package/cli/storybook-dist/assets/{preview-BoJV1ynr.js → preview-i5rYb1IR.js} +2 -2
  27. package/cli/storybook-dist/iframe.html +1 -1
  28. package/cli/storybook-dist/project.json +1 -1
  29. package/cli/templates/common/README.md +14 -1
  30. package/cli/templates/common/py/main.py +2 -2
  31. package/cli/templates/cpp/cpp/main.cpp +1 -1
  32. package/cli/templates/readme-cpp/README.md +16 -3
  33. package/cli/templates/ros2/ros2_ws/src/__PLUGIN_SLUG__/__PLUGIN_SLUG__/node.py +12 -1
  34. package/cli/templates/ros2-cpp/ros2_ws/src/__PLUGIN_SLUG__/src/node.cpp +18 -0
  35. package/package.json +3 -3
  36. package/cli/storybook-dist/assets/preview-3_yzT7Wt.js +0 -3
@@ -1,2 +1,2 @@
1
- const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./DocsRenderer-CFRXHY34-Boj7BBcx.js","./iframe-D3ykNOcq.js","./index-Dmy2JGbm.js","./index-ChsGqxH_.js","./index-NJyPL3Uy.js","./jsx-runtime-BTJTZTIL.js","./index-CT3U1fyk.js","./index-BRq5TIsn.js","./index-DgH-xKnr.js","./index-DrFu-skq.js","./client-DTf7SId2.js"])))=>i.map(i=>d[i]);
2
- import{_ as a}from"./iframe-D3ykNOcq.js";var i=Object.defineProperty,s=(e,r)=>{for(var t in r)i(e,t,{get:r[t],enumerable:!0})},_={};s(_,{parameters:()=>d});var p=Object.entries(globalThis.TAGS_OPTIONS??{}).reduce((e,r)=>{let[t,o]=r;return o.excludeFromDocsStories&&(e[t]=!0),e},{}),d={docs:{renderer:async()=>{let{DocsRenderer:e}=await a(()=>import("./DocsRenderer-CFRXHY34-Boj7BBcx.js"),__vite__mapDeps([0,1,2,3,4,5,6,7,8,9,10]),import.meta.url);return new e},stories:{filter:e=>{var r;return(e.tags||[]).filter(t=>p[t]).length===0&&!((r=e.parameters.docs)!=null&&r.disable)}}}};export{d as parameters};
1
+ const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./DocsRenderer-CFRXHY34-BGHjhFiI.js","./iframe-D-mTyH7q.js","./index-Dmy2JGbm.js","./index-ChsGqxH_.js","./index-DKrg3vQJ.js","./jsx-runtime-BTJTZTIL.js","./index-CT3U1fyk.js","./index-BRq5TIsn.js","./index-DgH-xKnr.js","./index-DrFu-skq.js","./client-DTf7SId2.js"])))=>i.map(i=>d[i]);
2
+ import{_ as a}from"./iframe-D-mTyH7q.js";var i=Object.defineProperty,s=(e,r)=>{for(var t in r)i(e,t,{get:r[t],enumerable:!0})},_={};s(_,{parameters:()=>d});var p=Object.entries(globalThis.TAGS_OPTIONS??{}).reduce((e,r)=>{let[t,o]=r;return o.excludeFromDocsStories&&(e[t]=!0),e},{}),d={docs:{renderer:async()=>{let{DocsRenderer:e}=await a(()=>import("./DocsRenderer-CFRXHY34-BGHjhFiI.js"),__vite__mapDeps([0,1,2,3,4,5,6,7,8,9,10]),import.meta.url);return new e},stories:{filter:e=>{var r;return(e.tags||[]).filter(t=>p[t]).length===0&&!((r=e.parameters.docs)!=null&&r.disable)}}}};export{d as parameters};
@@ -509,7 +509,7 @@
509
509
  }
510
510
  </script>
511
511
 
512
- <script type="module" crossorigin src="./assets/iframe-D3ykNOcq.js"></script>
512
+ <script type="module" crossorigin src="./assets/iframe-D-mTyH7q.js"></script>
513
513
  </head>
514
514
 
515
515
  <body>
@@ -1 +1 @@
1
- {"generatedAt":1792719902005,"userSince":1750932757926,"hasCustomBabel":false,"hasCustomWebpack":false,"hasStaticDirs":false,"hasStorybookEslint":true,"refCount":0,"testPackages":{"@vitest/browser":"3.2.4","@vitest/coverage-v8":"3.2.4","playwright":"1.59.1","vitest":"3.2.4"},"hasRouterPackage":false,"monorepo":"Turborepo","packageManager":{"type":"yarn","version":"berry","agent":"yarn@berry"},"preview":{"usesGlobals":false},"framework":{"name":"@storybook/react-vite","options":{}},"builder":"@storybook/builder-vite","renderer":"@storybook/react","portableStoriesFileCount":0,"applicationFileCount":0,"storybookVersion":"8.6.18","storybookVersionSpecifier":"^8.6.4","language":"typescript","storybookPackages":{"@chromatic-com/storybook":{"version":"3.2.7"},"@storybook/addon-essentials":{"version":"8.6.18"},"@storybook/addon-links":{"version":"8.6.18"},"@storybook/addon-onboarding":{"version":"8.6.18"},"@storybook/addon-themes":{"version":"8.6.18"},"@storybook/blocks":{"version":"8.6.18"},"@storybook/experimental-addon-test":{"version":"8.6.18"},"@storybook/react":{"version":"8.6.18"},"@storybook/react-vite":{"version":"8.6.18"},"@storybook/test":{"version":"8.6.18"},"@storybook/theming":{"version":"8.6.18"},"eslint-plugin-storybook":{"version":"0.11.6"},"storybook":{"version":"8.6.18"},"storybook-addon-react-docgen":{"version":"1.2.44"}},"addons":{"$SNIP/node_modules/@storybook/addon-links":{"version":null},"$SNIP/node_modules/@storybook/addon-essentials":{"version":null},"$SNIP/node_modules/@chromatic-com/storybook":{"version":null},"$SNIP/node_modules/@storybook/addon-themes":{"version":null},"$SNIP/node_modules/@storybook/experimental-addon-test":{"version":null}}}
1
+ {"generatedAt":1792728734236,"userSince":1750932757926,"hasCustomBabel":false,"hasCustomWebpack":false,"hasStaticDirs":false,"hasStorybookEslint":true,"refCount":0,"testPackages":{"@vitest/browser":"3.2.4","@vitest/coverage-v8":"3.2.4","playwright":"1.59.1","vitest":"3.2.4"},"hasRouterPackage":false,"monorepo":"Turborepo","packageManager":{"type":"yarn","version":"berry","agent":"yarn@berry"},"preview":{"usesGlobals":false},"framework":{"name":"@storybook/react-vite","options":{}},"builder":"@storybook/builder-vite","renderer":"@storybook/react","portableStoriesFileCount":0,"applicationFileCount":0,"storybookVersion":"8.6.18","storybookVersionSpecifier":"^8.6.4","language":"typescript","storybookPackages":{"@chromatic-com/storybook":{"version":"3.2.7"},"@storybook/addon-essentials":{"version":"8.6.18"},"@storybook/addon-links":{"version":"8.6.18"},"@storybook/addon-onboarding":{"version":"8.6.18"},"@storybook/addon-themes":{"version":"8.6.18"},"@storybook/blocks":{"version":"8.6.18"},"@storybook/experimental-addon-test":{"version":"8.6.18"},"@storybook/react":{"version":"8.6.18"},"@storybook/react-vite":{"version":"8.6.18"},"@storybook/test":{"version":"8.6.18"},"@storybook/theming":{"version":"8.6.18"},"eslint-plugin-storybook":{"version":"0.11.6"},"storybook":{"version":"8.6.18"},"storybook-addon-react-docgen":{"version":"1.2.44"}},"addons":{"$SNIP/node_modules/@storybook/addon-links":{"version":null},"$SNIP/node_modules/@storybook/addon-essentials":{"version":null},"$SNIP/node_modules/@chromatic-com/storybook":{"version":null},"$SNIP/node_modules/@storybook/addon-themes":{"version":null},"$SNIP/node_modules/@storybook/experimental-addon-test":{"version":null}}}
@@ -314,6 +314,19 @@ developing on the robot.
314
314
 
315
315
  ---
316
316
 
317
+ ## Several developers on one robot
318
+
319
+ Against a remote robot, `muscat-pk dev` / `dev:back` run your plugin under a dev id of its own,
320
+ `<manifest id>.dev-<user>-<random>` (printed at start; the random part is kept in `~/.muscat-pk/dev-id`).
321
+ Two machines developing the same plugin on one robot would otherwise register the same topics on its
322
+ gateway, and a button in one UI would silently run the other machine's backend. The UI, the backend,
323
+ the ROS namespace and external routes (`common/plugin/<dev id>/<path>`) all use the dev id.
324
+
325
+ Pass `--keep-id` to run under the manifest id instead, e.g. to test program `execute` or an external
326
+ client that uses the real id. Then only one machine may be connected to that robot.
327
+
328
+ ---
329
+
317
330
  ## Backend runtimes
318
331
 
319
332
  `manifest.json` chooses one backend runtime. `muscat-pk dev` runs backend code in
@@ -377,7 +390,7 @@ def move_j_example():
377
390
  manipulate = RBManipulateSDK()
378
391
  return manipulate.move.call_move_j(
379
392
  robot_model="C500920",
380
- target={"tar_values": [0, 0, 0, 0, 0, 0], "tar_frame": 0, "tar_unit": 0},
393
+ target={"tar_values": [0, 0, 0, 0, 0, 0, 0], "tar_frame": -1, "tar_unit": 0},
381
394
  )
382
395
 
383
396
 
@@ -81,8 +81,8 @@ def move_j_example():
81
81
  return manipulate.move.call_move_j(
82
82
  robot_model="C500920",
83
83
  target={
84
- "tar_values": [0, 0, 0, 0, 0, 0],
85
- "tar_frame": 0,
84
+ "tar_values": [0, 0, 0, 0, 0, 0, 0],
85
+ "tar_frame": -1,
86
86
  "tar_unit": 0,
87
87
  },
88
88
  )
@@ -59,7 +59,7 @@ int main() {
59
59
  });
60
60
 
61
61
  // Example: robot control (not called automatically — add safety checks first).
62
- // IPC::MoveInput_TargetT t; t.tar_values = {0, 0, 0, 0, 0, 0};
62
+ // IPC::MoveInput_TargetT t; t.tar_values = {0, 0, 0, 0, 0, 0, 0}; t.tar_frame = -1; t.tar_unit = 0;
63
63
  // manipulate.move.call_move_j("C500920", t);
64
64
 
65
65
  plugin->publish("state", {{"ready", true}, {"plugin", name}});
@@ -314,6 +314,19 @@ developing on the robot.
314
314
 
315
315
  ---
316
316
 
317
+ ## Several developers on one robot
318
+
319
+ Against a remote robot, `muscat-pk dev` / `dev:back` run your plugin under a dev id of its own,
320
+ `<manifest id>.dev-<user>-<random>` (printed at start; the random part is kept in `~/.muscat-pk/dev-id`).
321
+ Two machines developing the same plugin on one robot would otherwise register the same topics on its
322
+ gateway, and a button in one UI would silently run the other machine's backend. The UI, the backend,
323
+ the ROS namespace and external routes (`common/plugin/<dev id>/<path>`) all use the dev id.
324
+
325
+ Pass `--keep-id` to run under the manifest id instead, e.g. to test program `execute` or an external
326
+ client that uses the real id. Then only one machine may be connected to that robot.
327
+
328
+ ---
329
+
317
330
  ## Backend runtimes
318
331
 
319
332
  `manifest.json` chooses one backend runtime. `muscat-pk dev` runs backend code in
@@ -524,9 +537,9 @@ RBManipulateSDK manipulate; // on the robot: connects to t
524
537
  manipulate.state.call_servocontrol("C500920", 1);
525
538
 
526
539
  IPC::MoveInput_TargetT t;
527
- t.tar_values = {0, 0, 90, 0, 90, 0};
528
- t.tar_frame = 0;
529
- t.tar_unit = 1;
540
+ t.tar_values = {0, 0, 90, 0, 90, 0, 0}; // joint degrees, always 7 values (7th = 0 on 6-axis arms)
541
+ t.tar_frame = -1; // -1 = joint space
542
+ t.tar_unit = 0; // 0 = mm/deg
530
543
  manipulate.move.call_move_j("C500920", t, std::nullopt, MoveSpeedArg{1, 60.f, 120.f});
531
544
  manipulate.move.call_move_wait("C500920", -1);
532
545
  ```
@@ -1,14 +1,25 @@
1
1
  import rclpy
2
2
  from rclpy.node import Node
3
- from rainbow.rb_sdk import RBManipulateSDK # PyPI: rainbow-rb-sdk
3
+ from rainbow.rb_sdk import RBManipulateSDK, RBPluginCall # PyPI: rainbow-rb-sdk
4
4
 
5
5
 
6
6
  sdk = RBManipulateSDK()
7
+ plugin = RBPluginCall()
8
+
9
+
10
+ # External endpoint (REST / Socket.IO / TCP / MQTT / WebRTC), e.g.
11
+ # curl -X POST http://<robot>/common/plugin/<plugin_id>/hello -d '{"name": "kim"}'
12
+ @plugin.router.on("/hello")
13
+ def hello(payload=None, meta=None):
14
+ name = (payload or {}).get("name", "there")
15
+ return {"msg": f"hi {name}", "via": (meta or {}).get("transport")}
7
16
 
8
17
 
9
18
  class __PLUGIN_CLASS__Node(Node):
10
19
  def __init__(self):
11
20
  super().__init__("__PLUGIN_SLUG___node")
21
+ # Also connects the plugin to Muscat — router handlers register on the first call.
22
+ plugin.publish("state", {"ready": True, "plugin": "__PLUGIN_NAME__"}) # -> UI rb.sub("state")
12
23
  self.get_logger().info("__PLUGIN_NAME__ node started")
13
24
  # sdk is available here — use it alongside ROS2 topics as needed
14
25
 
@@ -6,6 +6,12 @@
6
6
  #include "rclcpp/rclcpp.hpp"
7
7
  // Rainbow Robotics C++ SDK (linked as rb_sdk::rb_sdk): RBManipulateSDK etc.
8
8
  #include <rainbow/rb_sdk/manipulate/rb_manipulate_sdk.hpp>
9
+ #include <rainbow/rb_sdk/plugin/rb_plugin.hpp>
10
+
11
+ #include <nlohmann/json.hpp>
12
+
13
+ using nlohmann::json;
14
+ using rb_plugin::RBPluginCall;
9
15
 
10
16
  class __PLUGIN_CLASS__Node : public rclcpp::Node {
11
17
  public:
@@ -17,6 +23,18 @@ public:
17
23
 
18
24
  int main(int argc, char** argv) {
19
25
  rclcpp::init(argc, argv);
26
+
27
+ // plugin id comes from RB_PLUGIN_ID.
28
+ auto plugin = RBPluginCall::get_instance(RBPluginCall::resolve_plugin_id(std::nullopt));
29
+ // External endpoint (REST / Socket.IO / TCP / MQTT / WebRTC), e.g.
30
+ // curl -X POST http://<robot>/common/plugin/<plugin_id>/hello -d '{"name":"kim"}'
31
+ plugin->router().on("/hello", [](const json& payload, const json& meta) {
32
+ const std::string who = payload.is_object() ? payload.value("name", std::string("there")) : "there";
33
+ return json{{"msg", "hi " + who}, {"via", meta.value("transport", std::string())}};
34
+ });
35
+ // Also connects the plugin to Muscat — router handlers register on the first call.
36
+ plugin->publish("state", {{"ready", true}, {"plugin", "__PLUGIN_NAME__"}}); // -> UI rb.sub("state")
37
+
20
38
  rclcpp::spin(std::make_shared<__PLUGIN_CLASS__Node>());
21
39
  rclcpp::shutdown();
22
40
  return 0;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rainbow-robotics/muscat-plugin-kit",
3
- "version": "1.10.2-dev.5",
3
+ "version": "1.10.2-dev.7",
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.2-dev.5",
56
- "@rainbow-robotics/preview-host": "1.10.2-dev.5",
55
+ "@rainbow-robotics/plugin-ui": "1.10.2-dev.7",
56
+ "@rainbow-robotics/preview-host": "1.10.2-dev.7",
57
57
  "@types/react": "^19.0.10",
58
58
  "postcss": "^8.5.8",
59
59
  "typescript": "^5.8.0",