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,379 @@
1
+ import { homedir } from "node:os";
2
+ import path from "node:path";
3
+
4
+ import type {
5
+ ForgetInput,
6
+ MemoryProvider,
7
+ MemoryRecord,
8
+ MemoryStatus,
9
+ RecallInput,
10
+ RememberInput,
11
+ } from "../types.js";
12
+
13
+ /**
14
+ * Configuration shape for a single mem0 sub-component (embedder / vectorStore / llm).
15
+ * Passed through verbatim to `new Memory({ ... })`.
16
+ */
17
+ export interface Mem0ComponentConfig {
18
+ provider: string;
19
+ config: Record<string, unknown>;
20
+ }
21
+
22
+ export interface Mem0BackendConfig {
23
+ /** When true, mem0 runs its LLM-driven fact extraction on `add`. Default false (raw store). */
24
+ inferOnWrite: boolean;
25
+ /** SQLite history db path (passed to mem0 as `historyDbPath`). */
26
+ historyDbPath: string;
27
+ embedder?: Mem0ComponentConfig;
28
+ vectorStore?: Mem0ComponentConfig;
29
+ llm?: Mem0ComponentConfig;
30
+ }
31
+
32
+ /**
33
+ * Thin adapter over `mem0ai/oss`'s Memory class.
34
+ *
35
+ * The actual `mem0ai` module is loaded once via the factory's dynamic import
36
+ * and passed into the constructor here. That keeps the optional peer dep out
37
+ * of the load path for users on `backend: "local"`.
38
+ */
39
+ export class Mem0MemoryProvider implements MemoryProvider {
40
+ readonly backend = "mem0" as const;
41
+ private readonly memory: any;
42
+ private readonly inferOnWrite: boolean;
43
+ private readonly embedderInfo: { provider: string; model?: string } | undefined;
44
+ // mem0's search returns score + metadata.createdAt; we'll mirror those into MemoryRecord.
45
+
46
+ constructor(args: {
47
+ memory: any;
48
+ inferOnWrite: boolean;
49
+ embedder?: Mem0ComponentConfig;
50
+ }) {
51
+ this.memory = args.memory;
52
+ this.inferOnWrite = args.inferOnWrite;
53
+ this.embedderInfo = args.embedder
54
+ ? {
55
+ provider: args.embedder.provider,
56
+ model:
57
+ typeof args.embedder.config?.model === "string"
58
+ ? (args.embedder.config.model as string)
59
+ : undefined,
60
+ }
61
+ : undefined;
62
+ }
63
+
64
+ async remember(input: RememberInput): Promise<MemoryRecord> {
65
+ const namespace = requireNamespace(input.namespace);
66
+ const metadata: Record<string, unknown> = {};
67
+ if (input.tags && input.tags.length > 0) metadata.tags = input.tags;
68
+ if (input.path) metadata.path = input.path;
69
+ metadata.createdAt = Date.now();
70
+
71
+ const result = await this.memory.add(input.content, {
72
+ userId: namespace,
73
+ metadata,
74
+ infer: this.inferOnWrite,
75
+ });
76
+
77
+ const persistedId = extractFirstId(result);
78
+ return {
79
+ id: persistedId ?? `mem0:${metadata.createdAt}`,
80
+ content: input.content,
81
+ namespace,
82
+ tags: input.tags,
83
+ path: input.path,
84
+ createdAt: metadata.createdAt as number,
85
+ };
86
+ }
87
+
88
+ async recall(input: RecallInput): Promise<MemoryRecord[]> {
89
+ const namespace = requireNamespace(input.namespace);
90
+ const limit = input.limit ?? 10;
91
+ // mem0ai v3+ rejects top-level `userId` in search() — the user identifier
92
+ // must go through `filters.user_id` (snake_case).
93
+ const search = await this.memory.search(input.query, {
94
+ filters: { user_id: namespace },
95
+ limit,
96
+ });
97
+ const hits = normalizeHits(search);
98
+ return hits.map((h) => toRecord(h, namespace));
99
+ }
100
+
101
+ async forget(input: ForgetInput): Promise<{ removed: number }> {
102
+ if (input.id !== undefined) {
103
+ await this.memory.delete(input.id);
104
+ return { removed: 1 };
105
+ }
106
+ const namespace = requireNamespace(input.namespace);
107
+ if (input.query !== undefined) {
108
+ const hits = normalizeHits(
109
+ await this.memory.search(input.query, {
110
+ filters: { user_id: namespace },
111
+ limit: 100,
112
+ }),
113
+ );
114
+ let removed = 0;
115
+ for (const h of hits) {
116
+ if (h.id) {
117
+ await this.memory.delete(h.id);
118
+ removed += 1;
119
+ }
120
+ }
121
+ return { removed };
122
+ }
123
+ // We deliberately don't call `memory.deleteAll(...)` here: mem0's deleteAll
124
+ // signature has shifted across major versions (v2 wanted `{ userId }`, v3
125
+ // requires its own filter dialect and rejects some calls outright). The
126
+ // enumerate-and-delete fallback is slightly slower but works on every
127
+ // version and returns an accurate count.
128
+ const all = normalizeHits(
129
+ typeof this.memory.getAll === "function"
130
+ ? await this.memory.getAll({ filters: { user_id: namespace }, limit: 1000 })
131
+ : [],
132
+ );
133
+ let removed = 0;
134
+ for (const h of all) {
135
+ if (h.id) {
136
+ await this.memory.delete(h.id);
137
+ removed += 1;
138
+ }
139
+ }
140
+ return { removed };
141
+ }
142
+
143
+ async status(namespace: string): Promise<MemoryStatus> {
144
+ let records: any[] = [];
145
+ if (typeof this.memory.getAll === "function") {
146
+ try {
147
+ records = normalizeHits(
148
+ await this.memory.getAll({ filters: { user_id: namespace }, limit: 1000 }),
149
+ );
150
+ } catch {
151
+ records = [];
152
+ }
153
+ }
154
+ const lastWriteAt =
155
+ records.length === 0
156
+ ? null
157
+ : records.reduce<number>((acc, r) => {
158
+ const ts = readCreatedAt(r);
159
+ return ts > acc ? ts : acc;
160
+ }, 0) || null;
161
+ return {
162
+ enabled: true,
163
+ backend: "mem0",
164
+ namespace,
165
+ recordCount: records.length,
166
+ lastWriteAt,
167
+ embedder: this.embedderInfo,
168
+ };
169
+ }
170
+
171
+ async recent(namespace: string, limit = 5): Promise<MemoryRecord[]> {
172
+ if (typeof this.memory.getAll !== "function") return [];
173
+ let raw: any;
174
+ try {
175
+ raw = await this.memory.getAll({ filters: { user_id: namespace }, limit: 1000 });
176
+ } catch {
177
+ return [];
178
+ }
179
+ const hits = normalizeHits(raw);
180
+ return hits
181
+ .slice()
182
+ .sort((a, b) => readCreatedAt(b) - readCreatedAt(a))
183
+ .slice(0, Math.max(0, limit))
184
+ .map((h) => toRecord(h, namespace));
185
+ }
186
+ }
187
+
188
+ /**
189
+ * Build a Mem0MemoryProvider. Loads `mem0ai/oss` dynamically so users on the
190
+ * `local` backend never pay for it. Applies smart-defaults for the embedder
191
+ * when the user has not configured one explicitly.
192
+ */
193
+ export async function createMem0Provider(args: {
194
+ config: Mem0BackendConfig;
195
+ }): Promise<Mem0MemoryProvider> {
196
+ const { config } = args;
197
+ let MemoryCtor: any;
198
+ try {
199
+ // mem0ai is an optional peer dependency — resolved at runtime, never
200
+ // installed unless the user opts into backend: "mem0".
201
+ // @ts-ignore: optional peer dep not declared in this package's deps
202
+ const mod: any = await import("mem0ai/oss");
203
+ MemoryCtor = mod.Memory ?? mod.default?.Memory;
204
+ } catch {
205
+ throw new Error(
206
+ 'memory: backend "mem0" requires the "mem0ai" package. Install with: pnpm add mem0ai',
207
+ );
208
+ }
209
+ if (!MemoryCtor) {
210
+ throw new Error(
211
+ 'memory: failed to find Memory class in "mem0ai/oss" (incompatible version?)',
212
+ );
213
+ }
214
+
215
+ const embedder = config.embedder ?? (await detectEmbedder());
216
+ const memoryConfig: Record<string, unknown> = {
217
+ historyDbPath: expandHome(config.historyDbPath),
218
+ };
219
+ if (embedder) memoryConfig.embedder = embedder;
220
+ if (config.vectorStore) memoryConfig.vectorStore = config.vectorStore;
221
+ if (config.llm) memoryConfig.llm = config.llm;
222
+
223
+ const memory = new MemoryCtor(memoryConfig);
224
+ return new Mem0MemoryProvider({
225
+ memory,
226
+ inferOnWrite: config.inferOnWrite,
227
+ embedder: embedder ?? undefined,
228
+ });
229
+ }
230
+
231
+ /**
232
+ * Embedder auto-detection used when `config.memory.mem0.embedder` is not set.
233
+ *
234
+ * Order (matches plan):
235
+ * 1. Ollama if http://localhost:11434/api/tags responds within 200 ms.
236
+ * 2. OpenAI if OPENAI_API_KEY is set.
237
+ * 3. Throw a clear error pointing the user at docs/memory.md.
238
+ */
239
+ export async function detectEmbedder(opts?: {
240
+ ollamaUrl?: string;
241
+ fetchImpl?: typeof fetch;
242
+ timeoutMs?: number;
243
+ hasOpenAIKey?: boolean;
244
+ }): Promise<Mem0ComponentConfig> {
245
+ const url = opts?.ollamaUrl ?? "http://localhost:11434/api/tags";
246
+ const f = opts?.fetchImpl ?? globalThis.fetch;
247
+ const timeout = opts?.timeoutMs ?? 200;
248
+ const hasOpenAIKey = opts?.hasOpenAIKey ?? Boolean(process.env.OPENAI_API_KEY);
249
+
250
+ if (typeof f === "function") {
251
+ try {
252
+ const ctrl = new AbortController();
253
+ const timer = setTimeout(() => ctrl.abort(), timeout);
254
+ const res = await f(url, { signal: ctrl.signal });
255
+ clearTimeout(timer);
256
+ if (res && (res as any).ok) {
257
+ return {
258
+ provider: "ollama",
259
+ config: { model: "nomic-embed-text" },
260
+ };
261
+ }
262
+ } catch {
263
+ // fall through to OpenAI / error
264
+ }
265
+ }
266
+
267
+ if (hasOpenAIKey) {
268
+ return {
269
+ provider: "openai",
270
+ config: { model: "text-embedding-3-small" },
271
+ };
272
+ }
273
+
274
+ throw new Error(
275
+ 'memory: backend "mem0" needs an embedder. Either run Ollama locally ' +
276
+ "(http://localhost:11434), set OPENAI_API_KEY, or configure " +
277
+ "config.memory.mem0.embedder. See docs/memory.md.",
278
+ );
279
+ }
280
+
281
+ function expandHome(p: string): string {
282
+ if (p.startsWith("~/")) return path.join(homedir(), p.slice(2));
283
+ if (p === "~") return homedir();
284
+ return p;
285
+ }
286
+
287
+ function requireNamespace(ns: string | undefined): string {
288
+ if (!ns || ns.trim().length === 0) {
289
+ throw new Error(
290
+ "memory: namespace is required (config.memory.namespace or robot.namespace must be set)",
291
+ );
292
+ }
293
+ return ns;
294
+ }
295
+
296
+ /**
297
+ * mem0's `add` returns either an array of results, a `{ results: [...] }`
298
+ * wrapper, or a single object depending on version. Extract the first id.
299
+ */
300
+ function extractFirstId(result: any): string | null {
301
+ if (!result) return null;
302
+ if (Array.isArray(result)) {
303
+ return result[0]?.id ?? null;
304
+ }
305
+ if (Array.isArray(result.results)) {
306
+ return result.results[0]?.id ?? null;
307
+ }
308
+ if (typeof result.id === "string") return result.id;
309
+ return null;
310
+ }
311
+
312
+ interface NormalizedHit {
313
+ id: string | null;
314
+ content: string;
315
+ score?: number;
316
+ metadata?: Record<string, unknown>;
317
+ /** Top-level created_at / createdAt as returned by mem0 (string ISO or number ms). */
318
+ rawCreatedAt?: unknown;
319
+ }
320
+
321
+ function normalizeHits(raw: any): NormalizedHit[] {
322
+ if (!raw) return [];
323
+ const arr: any[] = Array.isArray(raw)
324
+ ? raw
325
+ : Array.isArray(raw.results)
326
+ ? raw.results
327
+ : Array.isArray(raw.data)
328
+ ? raw.data
329
+ : [];
330
+ return arr.map((h) => ({
331
+ id: typeof h?.id === "string" ? h.id : null,
332
+ content:
333
+ typeof h?.memory === "string"
334
+ ? h.memory
335
+ : typeof h?.content === "string"
336
+ ? h.content
337
+ : typeof h?.text === "string"
338
+ ? h.text
339
+ : "",
340
+ score: typeof h?.score === "number" ? h.score : undefined,
341
+ metadata:
342
+ h?.metadata && typeof h.metadata === "object" ? (h.metadata as Record<string, unknown>) : undefined,
343
+ rawCreatedAt: h?.created_at ?? h?.createdAt,
344
+ }));
345
+ }
346
+
347
+ /**
348
+ * Read a millisecond timestamp from a hit, trying (in order):
349
+ * 1. metadata.createdAt (what we set ourselves on `add`),
350
+ * 2. top-level `created_at` (mem0 v3 returns ISO string),
351
+ * 3. top-level `createdAt` (older mem0).
352
+ */
353
+ function readCreatedAt(h: NormalizedHit): number {
354
+ const meta = h.metadata?.createdAt;
355
+ if (typeof meta === "number") return meta;
356
+ const raw = h.rawCreatedAt;
357
+ if (typeof raw === "number") return raw;
358
+ if (typeof raw === "string") {
359
+ const parsed = Date.parse(raw);
360
+ if (!Number.isNaN(parsed)) return parsed;
361
+ }
362
+ return 0;
363
+ }
364
+
365
+ function toRecord(h: NormalizedHit, namespace: string): MemoryRecord {
366
+ const tags = Array.isArray(h.metadata?.tags)
367
+ ? (h.metadata!.tags as unknown[]).map(String)
368
+ : undefined;
369
+ const pathHint = typeof h.metadata?.path === "string" ? (h.metadata!.path as string) : undefined;
370
+ return {
371
+ id: h.id ?? `mem0:${Date.now()}`,
372
+ content: h.content,
373
+ namespace,
374
+ tags,
375
+ path: pathHint,
376
+ createdAt: readCreatedAt(h) || Date.now(),
377
+ score: h.score,
378
+ };
379
+ }
@@ -0,0 +1,96 @@
1
+ /**
2
+ * Cross-adapter semantic memory primitives.
3
+ *
4
+ * Memory is an optional, off-by-default subsystem that gives every adapter
5
+ * (OpenClaw, Claude Code MCP, Gemini CLI) a shared way to remember facts
6
+ * across sessions. Records are namespaced (default: robot namespace), so
7
+ * the three adapters talking to the same robot share the same store.
8
+ */
9
+
10
+ export interface MemoryRecord {
11
+ /** Provider-assigned id. Used for `forget({ id })`. */
12
+ id: string;
13
+ /** Raw text content the agent stored. */
14
+ content: string;
15
+ /** Namespace this record belongs to (defaults to robot namespace at call time). */
16
+ namespace: string;
17
+ /** Optional tags the agent supplied at write time. */
18
+ tags?: string[];
19
+ /** Optional hierarchical path hint (e.g. "profile.preferences.speed"). */
20
+ path?: string;
21
+ /** ms since epoch when the record was created. */
22
+ createdAt: number;
23
+ /** Similarity / relevance score, populated only by `recall`. Higher = more relevant. */
24
+ score?: number;
25
+ }
26
+
27
+ export interface MemoryStatus {
28
+ /** True when a non-null provider was created from config. */
29
+ enabled: boolean;
30
+ /** Active backend identifier. */
31
+ backend: "local" | "mem0";
32
+ /** Effective namespace the adapter is using. */
33
+ namespace: string;
34
+ /** Number of records stored under this namespace (may be approximate for mem0). */
35
+ recordCount: number;
36
+ /** ms since epoch of the most recent write under this namespace, or null. */
37
+ lastWriteAt: number | null;
38
+ /** Embedder description for the mem0 backend, when configured. */
39
+ embedder?: { provider: string; model?: string };
40
+ }
41
+
42
+ export interface RememberInput {
43
+ content: string;
44
+ namespace?: string;
45
+ tags?: string[];
46
+ path?: string;
47
+ }
48
+
49
+ export interface RecallInput {
50
+ query: string;
51
+ namespace?: string;
52
+ limit?: number;
53
+ }
54
+
55
+ export interface ForgetInput {
56
+ id?: string;
57
+ query?: string;
58
+ namespace?: string;
59
+ }
60
+
61
+ /**
62
+ * Backend-agnostic memory provider.
63
+ *
64
+ * Implementations are obtained via `createMemory(config)`. The provider is
65
+ * null when `config.memory.enabled === false`, so adapters skip registering
66
+ * memory tools entirely.
67
+ */
68
+ export interface MemoryProvider {
69
+ /** Backend identifier (matches `config.memory.backend`). */
70
+ readonly backend: "local" | "mem0";
71
+
72
+ /** Store a new memory. Returns the persisted record (with provider-assigned id). */
73
+ remember(input: RememberInput): Promise<MemoryRecord>;
74
+
75
+ /** Recall up to `limit` memories ranked by relevance to `query`. */
76
+ recall(input: RecallInput): Promise<MemoryRecord[]>;
77
+
78
+ /**
79
+ * Delete memories. Either:
80
+ * - `{ id }` — delete one record by id.
81
+ * - `{ query }` — delete all records in `namespace` matching the query.
82
+ * - `{ namespace }` only (no id, no query) — delete every record in the namespace.
83
+ */
84
+ forget(input: ForgetInput): Promise<{ removed: number }>;
85
+
86
+ /** Health check: counts records, reports last-write time and embedder info if any. */
87
+ status(namespace: string): Promise<MemoryStatus>;
88
+
89
+ /**
90
+ * Return up to `limit` most recently written records in the namespace.
91
+ * Used by adapters that want to surface "recently remembered" snippets in
92
+ * the system prompt so the LLM doesn't need a tool call for common
93
+ * personal-context questions. Order: newest first.
94
+ */
95
+ recent(namespace: string, limit?: number): Promise<MemoryRecord[]>;
96
+ }
@@ -0,0 +1,95 @@
1
+ import type { AgenticROSConfig } from "./config.js";
2
+
3
+ /**
4
+ * Normalize a ROS 2 topic name to a canonical form (leading slash, no trailing slash).
5
+ */
6
+ function normalizeTopic(topic: string): string {
7
+ const t = topic.trim().replace(/^\/+/, "").replace(/\/+$/, "");
8
+ return t ? `/${t}` : "/";
9
+ }
10
+
11
+ /**
12
+ * Return true if the topic is "root-level" (single segment, e.g. cmd_vel, battery_state).
13
+ */
14
+ function isRootLevelTopic(normalized: string): boolean {
15
+ const withoutLeading = normalized.replace(/^\/+/, "");
16
+ return withoutLeading.length > 0 && !withoutLeading.includes("/");
17
+ }
18
+
19
+ /**
20
+ * Apply robot namespace to a topic (or service/action name) when configured.
21
+ * If config.robot.namespace is set and the name is root-level (e.g. cmd_vel, battery_state),
22
+ * returns /<namespace>/<name>. Otherwise returns the normalized name as-is.
23
+ *
24
+ * Example: namespace "robot-uuid", topic "/cmd_vel" -> "/robot-uuid/cmd_vel"
25
+ * Example: namespace "", topic "/cmd_vel" -> "/cmd_vel"
26
+ * Example: namespace "robot-uuid", topic "/robot-uuid/odom" -> "/robot-uuid/odom" (unchanged)
27
+ */
28
+ export function toNamespacedTopic(config: AgenticROSConfig, topic: string): string {
29
+ const normalized = normalizeTopic(topic);
30
+ const ns = (config.robot?.namespace ?? "").trim();
31
+ if (!ns) return normalized;
32
+ if (!isRootLevelTopic(normalized)) return normalized;
33
+ const segment = normalized.replace(/^\/+/, "");
34
+ return `/${ns}/${segment}`;
35
+ }
36
+
37
+ /**
38
+ * Apply robot namespace to any topic when configured (for transport subscribe/publish).
39
+ * Use this when the robot publishes/subscribes all topics under a namespace (e.g. Zenoh with
40
+ * zenoh-bridge-ros2dds or rmw_zenoh). If config.robot.namespace is set, returns /<namespace>/<topic>
41
+ * unless the topic already starts with /<namespace>/.
42
+ *
43
+ * Example: namespace "robot-uuid", topic "/cmd_vel" -> "/robot-uuid/cmd_vel"
44
+ * Example: namespace "robot-uuid", topic "/camera/camera/color/image_raw/compressed" -> "/robot-uuid/camera/camera/color/image_raw/compressed"
45
+ * Example: namespace "robot-uuid", topic "/robot-uuid/odom" -> "/robot-uuid/odom" (unchanged)
46
+ */
47
+ export function toNamespacedTopicFull(config: AgenticROSConfig, topic: string): string {
48
+ const normalized = normalizeTopic(topic);
49
+ const ns = (config.robot?.namespace ?? "").trim();
50
+ if (!ns) return normalized;
51
+ const withoutLeading = normalized.replace(/^\/+/, "");
52
+ if (!withoutLeading) return normalized;
53
+ if (withoutLeading.startsWith(`${ns}/`) || withoutLeading === ns) return normalized;
54
+ return `/${ns}/${withoutLeading}`;
55
+ }
56
+
57
+ /**
58
+ * Canonical topic string for teleop UI and ?topic= query params: leading slash, no robot namespace prefix.
59
+ * Subscribe/publish still uses {@link toNamespacedTopicFull} on the server so Zenoh keys match the bridge.
60
+ */
61
+ export function toTeleopCameraTopicShort(config: AgenticROSConfig, topic: string): string {
62
+ const normalized = normalizeTopic(topic);
63
+ const ns = (config.robot?.namespace ?? "").trim();
64
+ if (!ns) return normalized;
65
+ const withoutLeading = normalized.replace(/^\/+/, "");
66
+ if (!withoutLeading) return normalized;
67
+ if (withoutLeading === ns) return "/";
68
+ if (withoutLeading.startsWith(`${ns}/`)) {
69
+ const rest = withoutLeading.slice(ns.length + 1);
70
+ return rest ? `/${rest}` : "/";
71
+ }
72
+ return normalized;
73
+ }
74
+
75
+ /**
76
+ * ROS topic to use when subscribing to camera streams (Zenoh / DDS).
77
+ * Unlike {@link toNamespacedTopicFull}, common sensor topics stay at the graph root (`/camera/...`, `/zed/...`)
78
+ * even when `robot.namespace` is set for cmd_vel. If the topic already starts with `/<namespace>/`, it is left as-is.
79
+ * Other multi-segment paths get the namespace prefix (same as Full) for odd layouts.
80
+ */
81
+ export function resolveCameraSubscribeTopic(config: AgenticROSConfig, topic: string): string {
82
+ const normalized = normalizeTopic(topic);
83
+ const ns = (config.robot?.namespace ?? "").trim();
84
+ if (!ns) return normalized;
85
+ const withoutLeading = normalized.replace(/^\/+/, "");
86
+ if (!withoutLeading) return normalized;
87
+ if (withoutLeading === ns || withoutLeading.startsWith(`${ns}/`)) return normalized;
88
+
89
+ const first = withoutLeading.split("/")[0] ?? "";
90
+ /** First path segment for topics that usually remain unprefixed while cmd_vel is namespaced. */
91
+ const globalRoots = new Set(["camera", "zed", "usb_cam", "image_raw", "depth"]);
92
+ if (first && globalRoots.has(first)) return normalized;
93
+
94
+ return `/${ns}/${withoutLeading}`;
95
+ }
@@ -0,0 +1,47 @@
1
+ import type { TransportConfig } from "./types.js";
2
+ import type { RosTransport } from "./transport.js";
3
+
4
+ /**
5
+ * Create a RosTransport instance for the given deployment mode.
6
+ *
7
+ * Uses dynamic import() to load the correct adapter so that
8
+ * unused adapters (and their dependencies) are never loaded.
9
+ */
10
+ export async function createTransport(config: TransportConfig): Promise<RosTransport> {
11
+ switch (config.mode) {
12
+ case "rosbridge": {
13
+ const { RosbridgeTransport } = await import("./rosbridge/adapter.js");
14
+ return new RosbridgeTransport(config.rosbridge);
15
+ }
16
+
17
+ case "local": {
18
+ try {
19
+ const { LocalTransport } = await import("./local/transport.js");
20
+ return new LocalTransport(config.local);
21
+ } catch (e: any) {
22
+ if (e?.code === "ERR_MODULE_NOT_FOUND" || e?.code === "MODULE_NOT_FOUND") {
23
+ throw new Error(
24
+ 'Mode A (local) requires the "rclnodejs" package. ' +
25
+ "Install it with: pnpm add rclnodejs (with ROS2 workspace sourced)",
26
+ );
27
+ }
28
+ throw e;
29
+ }
30
+ }
31
+
32
+ case "webrtc": {
33
+ const { WebRTCTransport } = await import("./webrtc/transport.js");
34
+ return new WebRTCTransport(config.webrtc);
35
+ }
36
+
37
+ case "zenoh": {
38
+ const { ZenohTransport } = await import("./zenoh/adapter.js");
39
+ return new ZenohTransport(config.zenoh);
40
+ }
41
+
42
+ default: {
43
+ const _exhaustive: never = config;
44
+ throw new Error(`Unknown transport mode: ${(_exhaustive as TransportConfig).mode}`);
45
+ }
46
+ }
47
+ }