agenticros 0.0.1 → 0.1.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 (330) hide show
  1. package/LICENSE +192 -0
  2. package/README.md +90 -4
  3. package/dist/commands/config.d.ts +20 -0
  4. package/dist/commands/config.d.ts.map +1 -0
  5. package/dist/commands/config.js +179 -0
  6. package/dist/commands/config.js.map +1 -0
  7. package/dist/commands/doctor.d.ts +33 -0
  8. package/dist/commands/doctor.d.ts.map +1 -0
  9. package/dist/commands/doctor.js +232 -0
  10. package/dist/commands/doctor.js.map +1 -0
  11. package/dist/commands/down.d.ts +15 -0
  12. package/dist/commands/down.d.ts.map +1 -0
  13. package/dist/commands/down.js +91 -0
  14. package/dist/commands/down.js.map +1 -0
  15. package/dist/commands/init.d.ts +21 -0
  16. package/dist/commands/init.d.ts.map +1 -0
  17. package/dist/commands/init.js +259 -0
  18. package/dist/commands/init.js.map +1 -0
  19. package/dist/commands/logs.d.ts +18 -0
  20. package/dist/commands/logs.d.ts.map +1 -0
  21. package/dist/commands/logs.js +67 -0
  22. package/dist/commands/logs.js.map +1 -0
  23. package/dist/commands/status.d.ts +12 -0
  24. package/dist/commands/status.d.ts.map +1 -0
  25. package/dist/commands/status.js +56 -0
  26. package/dist/commands/status.js.map +1 -0
  27. package/dist/commands/up.d.ts +20 -0
  28. package/dist/commands/up.d.ts.map +1 -0
  29. package/dist/commands/up.js +70 -0
  30. package/dist/commands/up.js.map +1 -0
  31. package/dist/index.d.ts +12 -0
  32. package/dist/index.d.ts.map +1 -0
  33. package/dist/index.js +107 -0
  34. package/dist/index.js.map +1 -0
  35. package/dist/menu.d.ts +9 -0
  36. package/dist/menu.d.ts.map +1 -0
  37. package/dist/menu.js +96 -0
  38. package/dist/menu.js.map +1 -0
  39. package/dist/runners/real-robot.d.ts +15 -0
  40. package/dist/runners/real-robot.d.ts.map +1 -0
  41. package/dist/runners/real-robot.js +46 -0
  42. package/dist/runners/real-robot.js.map +1 -0
  43. package/dist/runners/sim.d.ts +19 -0
  44. package/dist/runners/sim.d.ts.map +1 -0
  45. package/dist/runners/sim.js +53 -0
  46. package/dist/runners/sim.js.map +1 -0
  47. package/dist/util/env.d.ts +24 -0
  48. package/dist/util/env.d.ts.map +1 -0
  49. package/dist/util/env.js +53 -0
  50. package/dist/util/env.js.map +1 -0
  51. package/dist/util/logger.d.ts +24 -0
  52. package/dist/util/logger.d.ts.map +1 -0
  53. package/dist/util/logger.js +62 -0
  54. package/dist/util/logger.js.map +1 -0
  55. package/dist/util/paths.d.ts +57 -0
  56. package/dist/util/paths.d.ts.map +1 -0
  57. package/dist/util/paths.js +132 -0
  58. package/dist/util/paths.js.map +1 -0
  59. package/dist/util/pidfile.d.ts +16 -0
  60. package/dist/util/pidfile.d.ts.map +1 -0
  61. package/dist/util/pidfile.js +63 -0
  62. package/dist/util/pidfile.js.map +1 -0
  63. package/dist/util/state.d.ts +26 -0
  64. package/dist/util/state.d.ts.map +1 -0
  65. package/dist/util/state.js +55 -0
  66. package/dist/util/state.js.map +1 -0
  67. package/package.json +60 -1
  68. package/runtime/BUNDLE.json +11 -0
  69. package/runtime/LICENSE +192 -0
  70. package/runtime/README.md +273 -0
  71. package/runtime/docs/architecture.md +366 -0
  72. package/runtime/docs/cli.md +140 -0
  73. package/runtime/docs/memory.md +292 -0
  74. package/runtime/docs/robot-setup.md +347 -0
  75. package/runtime/package.json +28 -0
  76. package/runtime/packages/agenticros/agenticros-agenticros-0.0.1.tgz +0 -0
  77. package/runtime/packages/agenticros/openclaw.plugin.json +451 -0
  78. package/runtime/packages/agenticros/package.json +41 -0
  79. package/runtime/packages/agenticros/src/camera-snapshot-cache.ts +59 -0
  80. package/runtime/packages/agenticros/src/camera-snapshot-routes.ts +44 -0
  81. package/runtime/packages/agenticros/src/commands/estop.ts +41 -0
  82. package/runtime/packages/agenticros/src/commands/transport.ts +195 -0
  83. package/runtime/packages/agenticros/src/config-file.ts +136 -0
  84. package/runtime/packages/agenticros/src/config-page.ts +498 -0
  85. package/runtime/packages/agenticros/src/context/robot-context.ts +373 -0
  86. package/runtime/packages/agenticros/src/depth.ts +313 -0
  87. package/runtime/packages/agenticros/src/describer.ts +157 -0
  88. package/runtime/packages/agenticros/src/image-binary-trim.ts +16 -0
  89. package/runtime/packages/agenticros/src/index.ts +85 -0
  90. package/runtime/packages/agenticros/src/landing-page.ts +38 -0
  91. package/runtime/packages/agenticros/src/memory.ts +44 -0
  92. package/runtime/packages/agenticros/src/plugin-api.ts +173 -0
  93. package/runtime/packages/agenticros/src/plugin-image-base64.ts +69 -0
  94. package/runtime/packages/agenticros/src/preflight.ts +110 -0
  95. package/runtime/packages/agenticros/src/routes.ts +328 -0
  96. package/runtime/packages/agenticros/src/safety/validator.ts +43 -0
  97. package/runtime/packages/agenticros/src/service.ts +359 -0
  98. package/runtime/packages/agenticros/src/skill-api.ts +65 -0
  99. package/runtime/packages/agenticros/src/skill-loader.ts +146 -0
  100. package/runtime/packages/agenticros/src/teleop/page.ts +498 -0
  101. package/runtime/packages/agenticros/src/teleop/routes.ts +650 -0
  102. package/runtime/packages/agenticros/src/tools/index.ts +26 -0
  103. package/runtime/packages/agenticros/src/tools/ros2-action.ts +50 -0
  104. package/runtime/packages/agenticros/src/tools/ros2-camera.ts +221 -0
  105. package/runtime/packages/agenticros/src/tools/ros2-depth-distance.ts +58 -0
  106. package/runtime/packages/agenticros/src/tools/ros2-introspect.ts +62 -0
  107. package/runtime/packages/agenticros/src/tools/ros2-memory.ts +158 -0
  108. package/runtime/packages/agenticros/src/tools/ros2-param.ts +87 -0
  109. package/runtime/packages/agenticros/src/tools/ros2-publish.ts +52 -0
  110. package/runtime/packages/agenticros/src/tools/ros2-service.ts +46 -0
  111. package/runtime/packages/agenticros/src/tools/ros2-subscribe.ts +71 -0
  112. package/runtime/packages/agenticros/tsconfig.json +9 -0
  113. package/runtime/packages/agenticros-claude-code/README.md +260 -0
  114. package/runtime/packages/agenticros-claude-code/config.example.json +9 -0
  115. package/runtime/packages/agenticros-claude-code/dist/config.d.ts +8 -0
  116. package/runtime/packages/agenticros-claude-code/dist/config.d.ts.map +1 -0
  117. package/runtime/packages/agenticros-claude-code/dist/config.js +93 -0
  118. package/runtime/packages/agenticros-claude-code/dist/config.js.map +1 -0
  119. package/runtime/packages/agenticros-claude-code/dist/depth.d.ts +20 -0
  120. package/runtime/packages/agenticros-claude-code/dist/depth.d.ts.map +1 -0
  121. package/runtime/packages/agenticros-claude-code/dist/depth.js +126 -0
  122. package/runtime/packages/agenticros-claude-code/dist/depth.js.map +1 -0
  123. package/runtime/packages/agenticros-claude-code/dist/find-object/coco-classes.d.ts +6 -0
  124. package/runtime/packages/agenticros-claude-code/dist/find-object/coco-classes.d.ts.map +1 -0
  125. package/runtime/packages/agenticros-claude-code/dist/find-object/coco-classes.js +36 -0
  126. package/runtime/packages/agenticros-claude-code/dist/find-object/coco-classes.js.map +1 -0
  127. package/runtime/packages/agenticros-claude-code/dist/find-object/find-object.d.ts +33 -0
  128. package/runtime/packages/agenticros-claude-code/dist/find-object/find-object.d.ts.map +1 -0
  129. package/runtime/packages/agenticros-claude-code/dist/find-object/find-object.js +134 -0
  130. package/runtime/packages/agenticros-claude-code/dist/find-object/find-object.js.map +1 -0
  131. package/runtime/packages/agenticros-claude-code/dist/follow-me/controller.d.ts +43 -0
  132. package/runtime/packages/agenticros-claude-code/dist/follow-me/controller.d.ts.map +1 -0
  133. package/runtime/packages/agenticros-claude-code/dist/follow-me/controller.js +73 -0
  134. package/runtime/packages/agenticros-claude-code/dist/follow-me/controller.js.map +1 -0
  135. package/runtime/packages/agenticros-claude-code/dist/follow-me/detector.d.ts +58 -0
  136. package/runtime/packages/agenticros-claude-code/dist/follow-me/detector.d.ts.map +1 -0
  137. package/runtime/packages/agenticros-claude-code/dist/follow-me/detector.js +251 -0
  138. package/runtime/packages/agenticros-claude-code/dist/follow-me/detector.js.map +1 -0
  139. package/runtime/packages/agenticros-claude-code/dist/follow-me/loop.d.ts +61 -0
  140. package/runtime/packages/agenticros-claude-code/dist/follow-me/loop.d.ts.map +1 -0
  141. package/runtime/packages/agenticros-claude-code/dist/follow-me/loop.js +268 -0
  142. package/runtime/packages/agenticros-claude-code/dist/follow-me/loop.js.map +1 -0
  143. package/runtime/packages/agenticros-claude-code/dist/index.d.ts +3 -0
  144. package/runtime/packages/agenticros-claude-code/dist/index.d.ts.map +1 -0
  145. package/runtime/packages/agenticros-claude-code/dist/index.js +111 -0
  146. package/runtime/packages/agenticros-claude-code/dist/index.js.map +1 -0
  147. package/runtime/packages/agenticros-claude-code/dist/memory.d.ts +17 -0
  148. package/runtime/packages/agenticros-claude-code/dist/memory.d.ts.map +1 -0
  149. package/runtime/packages/agenticros-claude-code/dist/memory.js +44 -0
  150. package/runtime/packages/agenticros-claude-code/dist/memory.js.map +1 -0
  151. package/runtime/packages/agenticros-claude-code/dist/safety.d.ts +10 -0
  152. package/runtime/packages/agenticros-claude-code/dist/safety.d.ts.map +1 -0
  153. package/runtime/packages/agenticros-claude-code/dist/safety.js +34 -0
  154. package/runtime/packages/agenticros-claude-code/dist/safety.js.map +1 -0
  155. package/runtime/packages/agenticros-claude-code/dist/tools.d.ts +36 -0
  156. package/runtime/packages/agenticros-claude-code/dist/tools.d.ts.map +1 -0
  157. package/runtime/packages/agenticros-claude-code/dist/tools.js +777 -0
  158. package/runtime/packages/agenticros-claude-code/dist/tools.js.map +1 -0
  159. package/runtime/packages/agenticros-claude-code/dist/transport.d.ts +17 -0
  160. package/runtime/packages/agenticros-claude-code/dist/transport.d.ts.map +1 -0
  161. package/runtime/packages/agenticros-claude-code/dist/transport.js +46 -0
  162. package/runtime/packages/agenticros-claude-code/dist/transport.js.map +1 -0
  163. package/runtime/packages/agenticros-claude-code/dist/zero-shot/detector.d.ts +42 -0
  164. package/runtime/packages/agenticros-claude-code/dist/zero-shot/detector.d.ts.map +1 -0
  165. package/runtime/packages/agenticros-claude-code/dist/zero-shot/detector.js +114 -0
  166. package/runtime/packages/agenticros-claude-code/dist/zero-shot/detector.js.map +1 -0
  167. package/runtime/packages/agenticros-claude-code/package.json +29 -0
  168. package/runtime/packages/agenticros-claude-code/src/config.ts +96 -0
  169. package/runtime/packages/agenticros-claude-code/src/depth.ts +173 -0
  170. package/runtime/packages/agenticros-claude-code/src/find-object/coco-classes.ts +38 -0
  171. package/runtime/packages/agenticros-claude-code/src/find-object/find-object.ts +190 -0
  172. package/runtime/packages/agenticros-claude-code/src/follow-me/controller.ts +109 -0
  173. package/runtime/packages/agenticros-claude-code/src/follow-me/depth-loop.ts +420 -0
  174. package/runtime/packages/agenticros-claude-code/src/follow-me/detector.ts +303 -0
  175. package/runtime/packages/agenticros-claude-code/src/follow-me/loop.ts +330 -0
  176. package/runtime/packages/agenticros-claude-code/src/index.ts +125 -0
  177. package/runtime/packages/agenticros-claude-code/src/memory.ts +51 -0
  178. package/runtime/packages/agenticros-claude-code/src/safety.ts +44 -0
  179. package/runtime/packages/agenticros-claude-code/src/tools.ts +891 -0
  180. package/runtime/packages/agenticros-claude-code/src/transport.ts +58 -0
  181. package/runtime/packages/agenticros-claude-code/src/zero-shot/detector.ts +169 -0
  182. package/runtime/packages/agenticros-claude-code/tsconfig.json +9 -0
  183. package/runtime/packages/agenticros-claude-code/yolo-debug.mjs +106 -0
  184. package/runtime/packages/agenticros-gemini/README.md +139 -0
  185. package/runtime/packages/agenticros-gemini/package.json +28 -0
  186. package/runtime/packages/agenticros-gemini/scripts/smoke-api.mjs +42 -0
  187. package/runtime/packages/agenticros-gemini/src/chat.ts +139 -0
  188. package/runtime/packages/agenticros-gemini/src/config.ts +92 -0
  189. package/runtime/packages/agenticros-gemini/src/depth.ts +173 -0
  190. package/runtime/packages/agenticros-gemini/src/index.ts +58 -0
  191. package/runtime/packages/agenticros-gemini/src/memory.ts +32 -0
  192. package/runtime/packages/agenticros-gemini/src/safety.ts +44 -0
  193. package/runtime/packages/agenticros-gemini/src/tools.ts +516 -0
  194. package/runtime/packages/agenticros-gemini/src/transport.ts +58 -0
  195. package/runtime/packages/agenticros-gemini/tsconfig.json +8 -0
  196. package/runtime/packages/core/package.json +47 -0
  197. package/runtime/packages/core/src/banner.ts +32 -0
  198. package/runtime/packages/core/src/cmd-vel-twist.ts +31 -0
  199. package/runtime/packages/core/src/config.ts +279 -0
  200. package/runtime/packages/core/src/index.ts +54 -0
  201. package/runtime/packages/core/src/memory/__tests__/factory.test.ts +70 -0
  202. package/runtime/packages/core/src/memory/__tests__/local-provider.test.ts +195 -0
  203. package/runtime/packages/core/src/memory/__tests__/mem0-provider.test.ts +192 -0
  204. package/runtime/packages/core/src/memory/__tests__/smart-defaults.test.ts +46 -0
  205. package/runtime/packages/core/src/memory/factory.ts +63 -0
  206. package/runtime/packages/core/src/memory/index.ts +10 -0
  207. package/runtime/packages/core/src/memory/local/provider.ts +229 -0
  208. package/runtime/packages/core/src/memory/mem0/provider.ts +379 -0
  209. package/runtime/packages/core/src/memory/types.ts +96 -0
  210. package/runtime/packages/core/src/topic-utils.ts +95 -0
  211. package/runtime/packages/core/src/transport/factory.ts +47 -0
  212. package/runtime/packages/core/src/transport/local/conversion.ts +333 -0
  213. package/runtime/packages/core/src/transport/local/entities.ts +129 -0
  214. package/runtime/packages/core/src/transport/local/transport.ts +406 -0
  215. package/runtime/packages/core/src/transport/rosbridge/actions.ts +81 -0
  216. package/runtime/packages/core/src/transport/rosbridge/adapter.ts +157 -0
  217. package/runtime/packages/core/src/transport/rosbridge/client.ts +438 -0
  218. package/runtime/packages/core/src/transport/rosbridge/services.ts +41 -0
  219. package/runtime/packages/core/src/transport/rosbridge/topics.ts +60 -0
  220. package/runtime/packages/core/src/transport/rosbridge/types.ts +118 -0
  221. package/runtime/packages/core/src/transport/transport.ts +77 -0
  222. package/runtime/packages/core/src/transport/types.ts +137 -0
  223. package/runtime/packages/core/src/transport/webrtc/signaling-client.ts +196 -0
  224. package/runtime/packages/core/src/transport/webrtc/signaling-types.ts +130 -0
  225. package/runtime/packages/core/src/transport/webrtc/transport.ts +516 -0
  226. package/runtime/packages/core/src/transport/zenoh/adapter.ts +357 -0
  227. package/runtime/packages/core/src/transport/zenoh/cdr.ts +183 -0
  228. package/runtime/packages/core/src/transport/zenoh/keys.ts +51 -0
  229. package/runtime/packages/core/tsconfig.json +9 -0
  230. package/runtime/packages/ros-camera/package.json +30 -0
  231. package/runtime/packages/ros-camera/src/index.ts +13 -0
  232. package/runtime/packages/ros-camera/src/snapshot.ts +372 -0
  233. package/runtime/packages/ros-camera/tsconfig.json +9 -0
  234. package/runtime/pnpm-lock.yaml +5260 -0
  235. package/runtime/pnpm-workspace.yaml +2 -0
  236. package/runtime/ros2_ws/src/agenticros_agent/agenticros_agent/__init__.py +0 -0
  237. package/runtime/ros2_ws/src/agenticros_agent/agenticros_agent/agent_node.py +561 -0
  238. package/runtime/ros2_ws/src/agenticros_agent/package.xml +25 -0
  239. package/runtime/ros2_ws/src/agenticros_agent/resource/agenticros_agent +0 -0
  240. package/runtime/ros2_ws/src/agenticros_agent/setup.cfg +4 -0
  241. package/runtime/ros2_ws/src/agenticros_agent/setup.py +25 -0
  242. package/runtime/ros2_ws/src/agenticros_bringup/README.md +128 -0
  243. package/runtime/ros2_ws/src/agenticros_bringup/agenticros_bringup/__init__.py +1 -0
  244. package/runtime/ros2_ws/src/agenticros_bringup/agenticros_bringup/cmd_vel_relay.py +33 -0
  245. package/runtime/ros2_ws/src/agenticros_bringup/launch/cmd_vel_bridge.launch.py +58 -0
  246. package/runtime/ros2_ws/src/agenticros_bringup/launch/gazebo_turtlebot3.launch.py +69 -0
  247. package/runtime/ros2_ws/src/agenticros_bringup/launch/mode_a_gazebo.launch.py +55 -0
  248. package/runtime/ros2_ws/src/agenticros_bringup/launch/mode_a_gazebo_rviz.launch.py +48 -0
  249. package/runtime/ros2_ws/src/agenticros_bringup/launch/realsense_rosbridge.launch.py +154 -0
  250. package/runtime/ros2_ws/src/agenticros_bringup/launch/rosbridge_gazebo.launch.py +54 -0
  251. package/runtime/ros2_ws/src/agenticros_bringup/launch/rviz.launch.py +38 -0
  252. package/runtime/ros2_ws/src/agenticros_bringup/launch/turtlebot3_gazebo_rviz.launch.py +42 -0
  253. package/runtime/ros2_ws/src/agenticros_bringup/package.xml +24 -0
  254. package/runtime/ros2_ws/src/agenticros_bringup/resource/agenticros_bringup +0 -0
  255. package/runtime/ros2_ws/src/agenticros_bringup/rviz/turtlebot3_agenticros.rviz +174 -0
  256. package/runtime/ros2_ws/src/agenticros_bringup/setup.cfg +4 -0
  257. package/runtime/ros2_ws/src/agenticros_bringup/setup.py +28 -0
  258. package/runtime/ros2_ws/src/agenticros_discovery/agenticros_discovery/__init__.py +0 -0
  259. package/runtime/ros2_ws/src/agenticros_discovery/agenticros_discovery/discovery_node.py +172 -0
  260. package/runtime/ros2_ws/src/agenticros_discovery/package.xml +22 -0
  261. package/runtime/ros2_ws/src/agenticros_discovery/resource/agenticros_discovery +0 -0
  262. package/runtime/ros2_ws/src/agenticros_discovery/setup.cfg +5 -0
  263. package/runtime/ros2_ws/src/agenticros_discovery/setup.py +25 -0
  264. package/runtime/ros2_ws/src/agenticros_follow_me/README.md +66 -0
  265. package/runtime/ros2_ws/src/agenticros_follow_me/agenticros_follow_me/__init__.py +1 -0
  266. package/runtime/ros2_ws/src/agenticros_follow_me/agenticros_follow_me/__main__.py +5 -0
  267. package/runtime/ros2_ws/src/agenticros_follow_me/agenticros_follow_me/follow_me_node.py +278 -0
  268. package/runtime/ros2_ws/src/agenticros_follow_me/agenticros_follow_me/follower_controller.py +631 -0
  269. package/runtime/ros2_ws/src/agenticros_follow_me/agenticros_follow_me/person_tracker.py +635 -0
  270. package/runtime/ros2_ws/src/agenticros_follow_me/package.xml +22 -0
  271. package/runtime/ros2_ws/src/agenticros_follow_me/resource/agenticros_follow_me +0 -0
  272. package/runtime/ros2_ws/src/agenticros_follow_me/setup.py +25 -0
  273. package/runtime/ros2_ws/src/agenticros_msgs/CMakeLists.txt +26 -0
  274. package/runtime/ros2_ws/src/agenticros_msgs/msg/CapabilityManifest.msg +9 -0
  275. package/runtime/ros2_ws/src/agenticros_msgs/package.xml +22 -0
  276. package/runtime/ros2_ws/src/agenticros_msgs/srv/FollowMeGetStatus.srv +11 -0
  277. package/runtime/ros2_ws/src/agenticros_msgs/srv/FollowMeSetDistance.srv +4 -0
  278. package/runtime/ros2_ws/src/agenticros_msgs/srv/FollowMeSetTarget.srv +6 -0
  279. package/runtime/ros2_ws/src/agenticros_msgs/srv/FollowMeStart.srv +5 -0
  280. package/runtime/ros2_ws/src/agenticros_msgs/srv/FollowMeStop.srv +3 -0
  281. package/runtime/ros2_ws/src/agenticros_msgs/srv/GetCapabilities.srv +5 -0
  282. package/runtime/ros2_ws/src/agenticros_sim/CMakeLists.txt +24 -0
  283. package/runtime/ros2_ws/src/agenticros_sim/README.md +120 -0
  284. package/runtime/ros2_ws/src/agenticros_sim/config/agenticros-sim.config.json +28 -0
  285. package/runtime/ros2_ws/src/agenticros_sim/config/amr_bridge.yaml +111 -0
  286. package/runtime/ros2_ws/src/agenticros_sim/config/amr_view.rviz +172 -0
  287. package/runtime/ros2_ws/src/agenticros_sim/env-hooks/gz_resource_path.dsv.in +3 -0
  288. package/runtime/ros2_ws/src/agenticros_sim/env-hooks/gz_resource_path.sh.in +7 -0
  289. package/runtime/ros2_ws/src/agenticros_sim/launch/sim_amr.launch.py +159 -0
  290. package/runtime/ros2_ws/src/agenticros_sim/models/agenticros_amr/model.config +17 -0
  291. package/runtime/ros2_ws/src/agenticros_sim/models/agenticros_amr/model.sdf +244 -0
  292. package/runtime/ros2_ws/src/agenticros_sim/package.xml +27 -0
  293. package/runtime/ros2_ws/src/agenticros_sim/worlds/agenticros_indoor.sdf +183 -0
  294. package/runtime/scripts/activate_workspace.sh +285 -0
  295. package/runtime/scripts/agenticros-describer.policy.yaml +96 -0
  296. package/runtime/scripts/agenticros-proxy.cjs +99 -0
  297. package/runtime/scripts/agenticros-rosbridge.policy.yaml +62 -0
  298. package/runtime/scripts/check-cli-tarball-size.mjs +42 -0
  299. package/runtime/scripts/configure_agenticros.sh +200 -0
  300. package/runtime/scripts/configure_for_sim.sh +64 -0
  301. package/runtime/scripts/fix-openclaw-control-ui-path.sh +20 -0
  302. package/runtime/scripts/install_cli.sh +94 -0
  303. package/runtime/scripts/install_rosbridge_from_source.sh +67 -0
  304. package/runtime/scripts/lib/agenticros-banner.sh +28 -0
  305. package/runtime/scripts/onboard_robot.sh +75 -0
  306. package/runtime/scripts/openai.policy.yaml +77 -0
  307. package/runtime/scripts/openclaw-dashboard-url.cjs +49 -0
  308. package/runtime/scripts/pack-runtime.mjs +245 -0
  309. package/runtime/scripts/run_demo_native.sh +43 -0
  310. package/runtime/scripts/run_nemoclaw_host_stack.sh +91 -0
  311. package/runtime/scripts/run_robot_rosbridge.sh +36 -0
  312. package/runtime/scripts/sandbox_rosbridge_relay.py +137 -0
  313. package/runtime/scripts/setup-openclaw-local.cjs +75 -0
  314. package/runtime/scripts/setup_gateway_plugin.sh +329 -0
  315. package/runtime/scripts/setup_robot.sh +113 -0
  316. package/runtime/scripts/setup_workspace.sh +484 -0
  317. package/runtime/scripts/sim/run_sim.sh +146 -0
  318. package/runtime/scripts/smoke_test_nemoclaw.sh +123 -0
  319. package/runtime/scripts/start_demo.sh +55 -0
  320. package/runtime/scripts/sync-skill-tools.mjs +335 -0
  321. package/runtime/scripts/test-follow-me-sim.mjs +135 -0
  322. package/runtime/scripts/test-mcp-e2e.mjs +184 -0
  323. package/runtime/scripts/test-rclnodejs.mts +129 -0
  324. package/runtime/scripts/use-openclaw-2026.2.26.sh +19 -0
  325. package/runtime/scripts/use-openclaw-2026.3.11.sh +19 -0
  326. package/runtime/scripts/zenoh-bridge-ros2dds-robot.json5 +30 -0
  327. package/runtime/scripts/zenohd-agenticros.json5 +11 -0
  328. package/runtime/scripts/zenohd-rosclaw.json5 +11 -0
  329. package/runtime/tsconfig.base.json +19 -0
  330. package/index.js +0 -6
@@ -0,0 +1,139 @@
1
+ /**
2
+ * Gemini chat loop: generateContent with ROS2 tools, handle function calls, return final text.
3
+ */
4
+
5
+ import type { Content } from "@google/genai";
6
+ import {
7
+ createPartFromBase64,
8
+ createPartFromFunctionResponse,
9
+ createPartFromText,
10
+ createUserContent,
11
+ } from "@google/genai";
12
+ import { GoogleGenAI } from "@google/genai";
13
+ import type { AgenticROSConfig } from "@agenticros/core";
14
+ import { buildGeminiTools } from "./tools.js";
15
+ import { executeTool } from "./tools.js";
16
+
17
+ /** Override with env GEMINI_MODEL (e.g. gemini-2.5-flash, gemini-2.0-flash). */
18
+ const DEFAULT_MODEL = "gemini-2.5-flash";
19
+ const MAX_TURNS = 20;
20
+
21
+ function resolveModel(explicit?: string): string {
22
+ const fromEnv = process.env.GEMINI_MODEL?.trim();
23
+ return explicit ?? (fromEnv && fromEnv.length > 0 ? fromEnv : DEFAULT_MODEL);
24
+ }
25
+
26
+ export interface ChatOptions {
27
+ apiKey?: string;
28
+ model?: string;
29
+ systemInstruction?: string;
30
+ }
31
+
32
+ /**
33
+ * Run a single user message through Gemini with ROS2 tools. Repeats until the model
34
+ * returns a final text response (no more function calls) or MAX_TURNS is reached.
35
+ */
36
+ export async function chatWithRobot(
37
+ userMessage: string,
38
+ config: AgenticROSConfig,
39
+ options: ChatOptions = {},
40
+ ): Promise<string> {
41
+ const apiKey = options.apiKey ?? process.env.GEMINI_API_KEY ?? process.env.GOOGLE_API_KEY;
42
+ if (!apiKey || apiKey.trim().length === 0) {
43
+ throw new Error("Gemini API key required. Set GEMINI_API_KEY or GOOGLE_API_KEY.");
44
+ }
45
+
46
+ const ai = new GoogleGenAI({ apiKey });
47
+ const model = resolveModel(options.model);
48
+
49
+ const tools = await buildGeminiTools(config);
50
+ const generateConfig = {
51
+ tools,
52
+ systemInstruction: options.systemInstruction ?? "You are a helpful assistant controlling a ROS2 robot. Use the provided tools to list topics, publish commands, read sensor data, call services, send action goals, get/set parameters, capture camera images, and read depth distance. Be concise and safe with velocity commands.",
53
+ };
54
+
55
+ let contents: Content[] = [createUserContent(userMessage)];
56
+ let turns = 0;
57
+ let lastToolOutputs: string[] = [];
58
+
59
+ while (turns < MAX_TURNS) {
60
+ turns++;
61
+ let response;
62
+ try {
63
+ response = await ai.models.generateContent({
64
+ model,
65
+ contents,
66
+ config: generateConfig,
67
+ });
68
+ } catch (err) {
69
+ const message = err instanceof Error ? err.message : String(err);
70
+ if (
71
+ (message.includes("429") || message.includes("RESOURCE_EXHAUSTED") || message.toLowerCase().includes("quota")) &&
72
+ lastToolOutputs.length > 0
73
+ ) {
74
+ return (
75
+ `${lastToolOutputs.join("\n")}\n\n` +
76
+ "(Gemini quota hit while composing final response. Returning latest tool output directly.)"
77
+ );
78
+ }
79
+ throw err;
80
+ }
81
+
82
+ const functionCalls = response.functionCalls;
83
+ if (!functionCalls || functionCalls.length === 0) {
84
+ const text = response.text?.trim();
85
+ return text ?? "(No text response from model.)";
86
+ }
87
+
88
+ // Build model turn (so we can send it back in history). Use candidate content if available.
89
+ const modelContent: Content = response.candidates?.[0]?.content ?? {
90
+ role: "model",
91
+ parts: functionCalls.map((fc) => ({ functionCall: { name: fc.name, args: fc.args ?? {}, id: fc.id } })),
92
+ };
93
+
94
+ // Execute each function call and build function response parts.
95
+ const responseParts = [];
96
+ lastToolOutputs = [];
97
+ const additionalUserContents: Content[] = [];
98
+ for (const fc of functionCalls) {
99
+ const name = fc.name ?? "unknown";
100
+ const args = (fc.args ?? {}) as Record<string, unknown>;
101
+ const id = fc.id ?? `call_${turns}_${name}`;
102
+ if (process.stderr?.write) {
103
+ process.stderr.write(`[AgenticROS] Tool: ${name}(${JSON.stringify(args)})\n`);
104
+ }
105
+ let output: string;
106
+ let parts: import("@google/genai").FunctionResponsePart[] | undefined;
107
+ try {
108
+ const result = await executeTool(name, args, config);
109
+ output = result.output;
110
+ parts = result.parts;
111
+ if (result.inlineImage) {
112
+ // Models that reject multimodal function responses can still reason over
113
+ // image bytes when provided in a regular user multimodal turn.
114
+ additionalUserContents.push(
115
+ createUserContent([
116
+ createPartFromText(`Image returned by tool ${name}. Use it to answer the user request.`),
117
+ createPartFromBase64(result.inlineImage.data, result.inlineImage.mimeType),
118
+ ]),
119
+ );
120
+ }
121
+ } catch (err) {
122
+ output = err instanceof Error ? err.message : String(err);
123
+ }
124
+ const part = createPartFromFunctionResponse(id, name, { output }, parts);
125
+ responseParts.push(part);
126
+ lastToolOutputs.push(output);
127
+ }
128
+
129
+ // Next turn: previous conversation + model's function-call turn + our function responses as user content.
130
+ contents = [
131
+ ...contents,
132
+ modelContent,
133
+ createUserContent(responseParts),
134
+ ...additionalUserContents,
135
+ ];
136
+ }
137
+
138
+ return "(Max turns reached; model did not return a final text response.)";
139
+ }
@@ -0,0 +1,92 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import os from "node:os";
4
+ import type { AgenticROSConfig } from "@agenticros/core";
5
+ import { parseConfig } from "@agenticros/core";
6
+
7
+ /** Same as Claude Code MCP: optional `robot.namespace` override from the environment. */
8
+ function applyMcpEnvOverrides(config: AgenticROSConfig): AgenticROSConfig {
9
+ const ns = process.env.AGENTICROS_ROBOT_NAMESPACE?.trim();
10
+ if (!ns) return config;
11
+ return {
12
+ ...config,
13
+ robot: {
14
+ ...config.robot,
15
+ namespace: ns,
16
+ },
17
+ };
18
+ }
19
+
20
+ /**
21
+ * Resolve path to AgenticROS config file.
22
+ * Prefer AGENTICROS_CONFIG_PATH; else ~/.agenticros/config.json.
23
+ * Optional: fallback to OpenClaw config and read plugins.entries.agenticros.config.
24
+ */
25
+ function getConfigPath(): string {
26
+ const env = process.env.AGENTICROS_CONFIG_PATH;
27
+ if (env && env.trim().length > 0) {
28
+ return path.resolve(env);
29
+ }
30
+ return path.join(os.homedir(), ".agenticros", "config.json");
31
+ }
32
+
33
+ /**
34
+ * Try to read config from OpenClaw file (plugins.entries.agenticros.config).
35
+ */
36
+ function tryOpenClawConfig(): Record<string, unknown> | null {
37
+ const openclawEnv = process.env.OPENCLAW_CONFIG;
38
+ const openclawPath = openclawEnv && openclawEnv.trim().length > 0
39
+ ? path.resolve(openclawEnv)
40
+ : path.join(os.homedir(), ".openclaw", "openclaw.json");
41
+ try {
42
+ const raw = fs.readFileSync(openclawPath, "utf8");
43
+ const parsed = JSON.parse(raw) as Record<string, unknown>;
44
+ const entries = parsed?.plugins && typeof (parsed.plugins as Record<string, unknown>).entries === "object"
45
+ ? (parsed.plugins as Record<string, unknown>).entries as Record<string, unknown>
46
+ : null;
47
+ const agenticros = entries?.agenticros && typeof entries.agenticros === "object"
48
+ ? entries.agenticros as Record<string, unknown>
49
+ : null;
50
+ const config = agenticros?.config;
51
+ if (config !== null && typeof config === "object") {
52
+ return config as Record<string, unknown>;
53
+ }
54
+ } catch {
55
+ // ignore
56
+ }
57
+ return null;
58
+ }
59
+
60
+ /**
61
+ * Load and parse AgenticROS config.
62
+ * 1) AGENTICROS_CONFIG_PATH or ~/.agenticros/config.json (full JSON object = config).
63
+ * 2) If that file does not exist, try OpenClaw config and read plugins.entries.agenticros.config.
64
+ */
65
+ export function loadConfig(): AgenticROSConfig {
66
+ const primaryPath = getConfigPath();
67
+ try {
68
+ const raw = fs.readFileSync(primaryPath, "utf8");
69
+ const parsed = JSON.parse(raw) as unknown;
70
+ if (parsed !== null && typeof parsed === "object") {
71
+ const cfg = parseConfig(parsed as Record<string, unknown>);
72
+ if (process.stderr && typeof process.stderr.write === "function") {
73
+ process.stderr.write(`[AgenticROS] Config from ${primaryPath}\n`);
74
+ }
75
+ return applyMcpEnvOverrides(cfg);
76
+ }
77
+ } catch (err) {
78
+ const nodeErr = err as NodeJS.ErrnoException;
79
+ if (nodeErr.code === "ENOENT") {
80
+ const openclawConfig = tryOpenClawConfig();
81
+ if (openclawConfig) {
82
+ return applyMcpEnvOverrides(parseConfig(openclawConfig));
83
+ }
84
+ throw new Error(
85
+ `AgenticROS config not found at ${primaryPath}. Create it or set AGENTICROS_CONFIG_PATH. ` +
86
+ "See README for an example config.",
87
+ );
88
+ }
89
+ throw err;
90
+ }
91
+ return applyMcpEnvOverrides(parseConfig({}));
92
+ }
@@ -0,0 +1,173 @@
1
+ /**
2
+ * Sample distance (meters) from a ROS2 depth image topic.
3
+ * Same logic as OpenClaw and Claude Code adapters.
4
+ */
5
+
6
+ import type { RosTransport } from "@agenticros/core";
7
+ import {
8
+ ROS_MSG_IMAGE,
9
+ coerceRosImageDataToBuffer,
10
+ normalizeDepthImageEncoding,
11
+ rosBoolField,
12
+ rosNumericField,
13
+ rosStringField,
14
+ } from "@agenticros/ros-camera";
15
+
16
+ function depthImageDataBytes(data: unknown): Uint8Array {
17
+ try {
18
+ return new Uint8Array(coerceRosImageDataToBuffer(data));
19
+ } catch (e) {
20
+ const hint = e instanceof Error ? e.message : String(e);
21
+ const kind =
22
+ data == null
23
+ ? "null"
24
+ : `${typeof data}${typeof data === "object" && data !== null ? ` (${(data as object).constructor?.name ?? "Object"})` : ""}`;
25
+ throw new Error(`Depth image bytes: ${hint} (data field: ${kind})`);
26
+ }
27
+ }
28
+
29
+ function bytesPerPixelForDepthEncoding(encoding: string): number {
30
+ return normalizeDepthImageEncoding(encoding) === "32FC1" ? 4 : 2;
31
+ }
32
+
33
+ const DEPTH_SAMPLE_MAX_M = 40;
34
+ const DEPTH_REPORT_PERCENTILE = 12;
35
+
36
+ function sanitizeDepthSamplesMeters(values: number[]): number[] {
37
+ return values.filter((v) => Number.isFinite(v) && v > 0 && v <= DEPTH_SAMPLE_MAX_M);
38
+ }
39
+
40
+ function percentileLowerSorted(sortedAsc: number[], p: number): number {
41
+ const n = sortedAsc.length;
42
+ if (n === 0) return NaN;
43
+ if (n === 1) return sortedAsc[0]!;
44
+ const pp = Math.max(0, Math.min(100, p));
45
+ const idx = Math.min(n - 1, Math.floor((pp / 100) * n));
46
+ return sortedAsc[idx]!;
47
+ }
48
+
49
+ export function sampleDepthMeters(
50
+ width: number,
51
+ height: number,
52
+ step: number,
53
+ encoding: string,
54
+ data: Uint8Array,
55
+ centerFraction = 0.3,
56
+ isBigEndian = false,
57
+ ): number[] {
58
+ const enc = normalizeDepthImageEncoding(encoding);
59
+ const values: number[] = [];
60
+ const cx = width / 2;
61
+ const cy = height / 2;
62
+ const halfW = Math.max(1, Math.floor((width * centerFraction) / 2));
63
+ const halfH = Math.max(1, Math.floor((height * centerFraction) / 2));
64
+ const x0 = Math.max(0, Math.floor(cx - halfW));
65
+ const x1 = Math.min(width, Math.floor(cx + halfW));
66
+ const y0 = Math.max(0, Math.floor(cy - halfH));
67
+ const y1 = Math.min(height, Math.floor(cy + halfH));
68
+
69
+ if (enc === "16UC1") {
70
+ for (let y = y0; y < y1; y++) {
71
+ for (let x = x0; x < x1; x++) {
72
+ const off = y * step + x * 2;
73
+ if (off + 2 > data.length) continue;
74
+ const lo = data[off];
75
+ const hi = data[off + 1];
76
+ const v = isBigEndian ? (lo << 8) | hi : (hi << 8) | lo;
77
+ if (v > 0) values.push(v / 1000);
78
+ }
79
+ }
80
+ } else if (enc === "32FC1") {
81
+ for (let y = y0; y < y1; y++) {
82
+ for (let x = x0; x < x1; x++) {
83
+ const off = y * step + x * 4;
84
+ if (off + 4 > data.length) continue;
85
+ const v = new DataView(data.buffer, data.byteOffset + off, 4).getFloat32(0, !isBigEndian);
86
+ if (Number.isFinite(v) && v > 0) values.push(v);
87
+ }
88
+ }
89
+ } else {
90
+ throw new Error(
91
+ `Unsupported depth encoding: "${encoding}" (interpreted as "${enc}"). Use 16UC1/mono16 (mm) or 32FC1 (m).`,
92
+ );
93
+ }
94
+ return values;
95
+ }
96
+
97
+ function median(sorted: number[]): number {
98
+ if (sorted.length === 0) return NaN;
99
+ const m = sorted.length >> 1;
100
+ if (sorted.length % 2 === 1) return sorted[m];
101
+ return (sorted[m - 1] + sorted[m]) / 2;
102
+ }
103
+
104
+ export interface DepthSampleResult {
105
+ distance_m: number;
106
+ median_m: number;
107
+ valid: boolean;
108
+ topic: string;
109
+ encoding: string;
110
+ width: number;
111
+ height: number;
112
+ sample_count: number;
113
+ min_m: number;
114
+ max_m: number;
115
+ }
116
+
117
+ export async function getDepthDistance(
118
+ transport: RosTransport,
119
+ topic: string,
120
+ timeoutMs = 5000,
121
+ ): Promise<DepthSampleResult> {
122
+ const result = await new Promise<Record<string, unknown>>((resolve, reject) => {
123
+ const sub = transport.subscribe(
124
+ { topic, type: ROS_MSG_IMAGE },
125
+ (msg: Record<string, unknown>) => {
126
+ clearTimeout(timer);
127
+ sub.unsubscribe();
128
+ resolve(msg);
129
+ },
130
+ );
131
+ const timer = setTimeout(() => {
132
+ sub.unsubscribe();
133
+ reject(
134
+ new Error(
135
+ `Depth snapshot timeout on ${topic} (${timeoutMs}ms). No sensor_msgs/Image received—check topic and that it publishes raw depth (not CompressedImage only). With Zenoh, check the gateway log for CDR decode warnings.`,
136
+ ),
137
+ );
138
+ }, timeoutMs);
139
+ });
140
+
141
+ const encoding = normalizeDepthImageEncoding(rosStringField(result.encoding, "16UC1"));
142
+ const bpp = bytesPerPixelForDepthEncoding(encoding);
143
+ const width = rosNumericField(result.width, "width");
144
+ const height = rosNumericField(result.height, "height");
145
+ const step =
146
+ result.step != null && result.step !== ""
147
+ ? rosNumericField(result.step, "step")
148
+ : width * bpp;
149
+ const isBigEndian = rosBoolField(result.is_bigendian);
150
+ const data = depthImageDataBytes(result.data);
151
+
152
+ const values = sanitizeDepthSamplesMeters(
153
+ sampleDepthMeters(width, height, step, encoding, data, 0.3, isBigEndian),
154
+ );
155
+ const sorted = values.slice().sort((a, b) => a - b);
156
+ const distance_m = percentileLowerSorted(sorted, DEPTH_REPORT_PERCENTILE);
157
+ const median_m = median(sorted);
158
+ const min_m = sorted.length ? sorted[0] : NaN;
159
+ const max_m = sorted.length ? sorted[sorted.length - 1] : NaN;
160
+
161
+ return {
162
+ distance_m: Math.round(distance_m * 1000) / 1000,
163
+ median_m: Math.round(median_m * 1000) / 1000,
164
+ valid: sorted.length > 0 && Number.isFinite(distance_m),
165
+ topic,
166
+ encoding,
167
+ width,
168
+ height,
169
+ sample_count: sorted.length,
170
+ min_m: Math.round(min_m * 1000) / 1000,
171
+ max_m: Math.round(max_m * 1000) / 1000,
172
+ };
173
+ }
@@ -0,0 +1,58 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * AgenticROS Gemini CLI — chat with your ROS2 robot using Google Gemini.
4
+ *
5
+ * Usage:
6
+ * GEMINI_API_KEY=xxx agenticros-gemini "What do you see?"
7
+ * GEMINI_API_KEY=xxx agenticros-gemini # read message from stdin
8
+ *
9
+ * Config: AGENTICROS_CONFIG_PATH or ~/.agenticros/config.json (same as other adapters).
10
+ * Optional: GEMINI_MODEL (default gemini-2.5-flash) if you hit quota on a specific model.
11
+ */
12
+
13
+ import { loadConfig } from "./config.js";
14
+ import { connect, disconnect } from "./transport.js";
15
+ import { chatWithRobot } from "./chat.js";
16
+ import { renderAgenticROSBanner } from "@agenticros/core";
17
+
18
+ async function main(): Promise<void> {
19
+ process.stderr.write(renderAgenticROSBanner({ color: process.stderr.isTTY }) + "\n\n");
20
+
21
+ const args = process.argv.slice(2);
22
+ const normalizedArgs = args.length > 0 && args[0] === "--" ? args.slice(1) : args;
23
+ let userMessage: string;
24
+ if (normalizedArgs.length >= 1 && normalizedArgs[0].trim().length > 0) {
25
+ userMessage = normalizedArgs.join(" ").trim();
26
+ } else {
27
+ userMessage = await readStdin();
28
+ }
29
+ if (!userMessage) {
30
+ process.stderr.write("Usage: agenticros-gemini \"<message>\" or pipe message via stdin.\n");
31
+ process.stderr.write("Set GEMINI_API_KEY (or GOOGLE_API_KEY) in the environment.\n");
32
+ process.exit(1);
33
+ }
34
+
35
+ const config = loadConfig();
36
+ await connect(config);
37
+
38
+ try {
39
+ const response = await chatWithRobot(userMessage, config);
40
+ process.stdout.write(response + "\n");
41
+ } finally {
42
+ await disconnect();
43
+ }
44
+ }
45
+
46
+ function readStdin(): Promise<string> {
47
+ return new Promise((resolve) => {
48
+ const chunks: Buffer[] = [];
49
+ process.stdin.setEncoding("utf8");
50
+ process.stdin.on("data", (chunk: string | Buffer) => chunks.push(Buffer.from(chunk)));
51
+ process.stdin.on("end", () => resolve(Buffer.concat(chunks).toString("utf8").trim()));
52
+ });
53
+ }
54
+
55
+ main().catch((err) => {
56
+ process.stderr.write(String(err instanceof Error ? err.message : err) + "\n");
57
+ process.exit(1);
58
+ });
@@ -0,0 +1,32 @@
1
+ import type { AgenticROSConfig, MemoryProvider } from "@agenticros/core";
2
+ import { createMemory } from "@agenticros/core";
3
+
4
+ let provider: MemoryProvider | null = null;
5
+ let initialized = false;
6
+
7
+ /**
8
+ * Lazy-initialize the memory provider from config.
9
+ *
10
+ * Gemini CLI is one-shot (each `agenticros-gemini "..."` invocation is a fresh
11
+ * process), so this is effectively per-invocation. We still cache so the
12
+ * `buildGeminiTools` and `executeTool` paths don't double-load it.
13
+ */
14
+ export async function ensureMemory(
15
+ config: AgenticROSConfig,
16
+ ): Promise<MemoryProvider | null> {
17
+ if (initialized) return provider;
18
+ initialized = true;
19
+ try {
20
+ provider = await createMemory(config);
21
+ } catch (err) {
22
+ process.stderr?.write(
23
+ `[AgenticROS] memory: init failed — ${err instanceof Error ? err.message : String(err)}\n`,
24
+ );
25
+ provider = null;
26
+ }
27
+ return provider;
28
+ }
29
+
30
+ export function getMemory(): MemoryProvider | null {
31
+ return provider;
32
+ }
@@ -0,0 +1,44 @@
1
+ import type { AgenticROSConfig } from "@agenticros/core";
2
+
3
+ /**
4
+ * Minimal safety check for ros2_publish (Twist velocity limits).
5
+ * Same logic as OpenClaw and Claude Code adapters.
6
+ */
7
+ export function checkPublishSafety(
8
+ config: AgenticROSConfig,
9
+ params: Record<string, unknown>,
10
+ ): { block: boolean; blockReason?: string } {
11
+ const safety = config.safety ?? {};
12
+ const maxLinear = safety.maxLinearVelocity ?? 1.0;
13
+ const maxAngular = safety.maxAngularVelocity ?? 1.5;
14
+
15
+ const msg = params["message"] as Record<string, unknown> | undefined;
16
+ if (!msg) return { block: false };
17
+
18
+ const linear = msg["linear"] as Record<string, number> | undefined;
19
+ const angular = msg["angular"] as Record<string, number> | undefined;
20
+
21
+ if (linear) {
22
+ const speed = Math.sqrt(
23
+ (linear["x"] ?? 0) ** 2 + (linear["y"] ?? 0) ** 2 + (linear["z"] ?? 0) ** 2,
24
+ );
25
+ if (speed > maxLinear) {
26
+ return {
27
+ block: true,
28
+ blockReason: `Linear velocity ${speed.toFixed(2)} m/s exceeds safety limit of ${maxLinear} m/s`,
29
+ };
30
+ }
31
+ }
32
+
33
+ if (angular) {
34
+ const rate = Math.abs(angular["z"] ?? 0);
35
+ if (rate > maxAngular) {
36
+ return {
37
+ block: true,
38
+ blockReason: `Angular velocity ${rate.toFixed(2)} rad/s exceeds safety limit of ${maxAngular} rad/s`,
39
+ };
40
+ }
41
+ }
42
+
43
+ return { block: false };
44
+ }