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,192 @@
1
+ /**
2
+ * Unit tests for the mem0 backend. We construct Mem0MemoryProvider directly
3
+ * with a hand-rolled fake mem0 Memory instance, so the real `mem0ai` package
4
+ * is never loaded. This keeps the test fast and dependency-free.
5
+ */
6
+ import { test } from "node:test";
7
+ import assert from "node:assert/strict";
8
+
9
+ import { Mem0MemoryProvider } from "../mem0/provider.js";
10
+
11
+ interface FakeMem0Call {
12
+ method: string;
13
+ args: unknown[];
14
+ }
15
+
16
+ function createFakeMemory() {
17
+ const calls: FakeMem0Call[] = [];
18
+ const records: Array<{ id: string; memory: string; userId: string; metadata: any; score?: number }> = [];
19
+ let nextId = 1;
20
+ return {
21
+ calls,
22
+ records,
23
+ async add(content: string, options: any) {
24
+ calls.push({ method: "add", args: [content, options] });
25
+ const id = `m${nextId++}`;
26
+ records.push({
27
+ id,
28
+ memory: content,
29
+ userId: options?.userId,
30
+ metadata: options?.metadata,
31
+ });
32
+ return [{ id, memory: content }];
33
+ },
34
+ async search(query: string, options: any) {
35
+ calls.push({ method: "search", args: [query, options] });
36
+ if (options?.userId) {
37
+ throw new Error(
38
+ "Top-level entity parameters [userId] are not supported in search(). Use filters: { user_id: \"...\" } instead.",
39
+ );
40
+ }
41
+ // Real mem0 v3 requires snake_case `user_id` inside filters.
42
+ const userId = options?.filters?.user_id;
43
+ if (!userId) {
44
+ throw new Error(
45
+ "filters must contain at least one of: user_id, agent_id, run_id.",
46
+ );
47
+ }
48
+ const matches = records
49
+ .filter((r) => r.userId === userId)
50
+ .filter((r) => r.memory.toLowerCase().includes(query.toLowerCase()))
51
+ .slice(0, options?.limit ?? 10)
52
+ .map((r) => ({ id: r.id, memory: r.memory, score: 0.9, metadata: r.metadata }));
53
+ return { results: matches };
54
+ },
55
+ async delete(id: string) {
56
+ calls.push({ method: "delete", args: [id] });
57
+ const i = records.findIndex((r) => r.id === id);
58
+ if (i >= 0) records.splice(i, 1);
59
+ return { success: true };
60
+ },
61
+ async getAll(options: any) {
62
+ calls.push({ method: "getAll", args: [options] });
63
+ const userId = options?.filters?.user_id ?? options?.userId;
64
+ return records
65
+ .filter((r) => r.userId === userId)
66
+ .slice(0, options?.limit ?? 1000)
67
+ .map((r) => ({ id: r.id, memory: r.memory, metadata: r.metadata }));
68
+ },
69
+ };
70
+ }
71
+
72
+ test("mem0: remember passes namespace as userId and infer:false by default", async () => {
73
+ const fake = createFakeMemory();
74
+ const provider = new Mem0MemoryProvider({ memory: fake, inferOnWrite: false });
75
+ await provider.remember({ namespace: "robotA", content: "remember this", tags: ["pref"] });
76
+ const addCall = fake.calls.find((c) => c.method === "add");
77
+ assert.ok(addCall, "add should have been called");
78
+ const [content, options] = addCall.args as [string, any];
79
+ assert.equal(content, "remember this");
80
+ assert.equal(options.userId, "robotA");
81
+ assert.equal(options.infer, false);
82
+ assert.deepEqual(options.metadata.tags, ["pref"]);
83
+ assert.ok(typeof options.metadata.createdAt === "number");
84
+ });
85
+
86
+ test("mem0: inferOnWrite:true forwards infer:true to add", async () => {
87
+ const fake = createFakeMemory();
88
+ const provider = new Mem0MemoryProvider({ memory: fake, inferOnWrite: true });
89
+ await provider.remember({ namespace: "ns", content: "hi" });
90
+ const addCall = fake.calls.find((c) => c.method === "add")!;
91
+ const [, options] = addCall.args as [string, any];
92
+ assert.equal(options.infer, true);
93
+ });
94
+
95
+ test("mem0: recall scopes by namespace via filters.userId and limits results", async () => {
96
+ const fake = createFakeMemory();
97
+ const provider = new Mem0MemoryProvider({ memory: fake, inferOnWrite: false });
98
+ await provider.remember({ namespace: "robotA", content: "kitchen rug" });
99
+ await provider.remember({ namespace: "robotB", content: "kitchen rug" });
100
+
101
+ const hits = await provider.recall({ namespace: "robotA", query: "kitchen", limit: 5 });
102
+ assert.equal(hits.length, 1, "should only see records for robotA");
103
+ assert.equal(hits[0].namespace, "robotA");
104
+
105
+ const searchCall = fake.calls.find((c) => c.method === "search")!;
106
+ const [, options] = searchCall.args as [string, any];
107
+ assert.equal(options.userId, undefined, "must NOT pass top-level userId (mem0 v3+ rejects it)");
108
+ assert.equal(options.filters.user_id, "robotA", "filters must use snake_case user_id");
109
+ assert.equal(options.limit, 5);
110
+ });
111
+
112
+ test("mem0: forget by id calls delete(id)", async () => {
113
+ const fake = createFakeMemory();
114
+ const provider = new Mem0MemoryProvider({ memory: fake, inferOnWrite: false });
115
+ const rec = await provider.remember({ namespace: "ns", content: "x" });
116
+ const result = await provider.forget({ id: rec.id });
117
+ assert.equal(result.removed, 1);
118
+ const delCall = fake.calls.find((c) => c.method === "delete")!;
119
+ assert.deepEqual(delCall.args, [rec.id]);
120
+ });
121
+
122
+ test("mem0: forget by query searches and deletes each match", async () => {
123
+ const fake = createFakeMemory();
124
+ const provider = new Mem0MemoryProvider({ memory: fake, inferOnWrite: false });
125
+ await provider.remember({ namespace: "ns", content: "kitchen rug fragile" });
126
+ await provider.remember({ namespace: "ns", content: "couch is comfortable" });
127
+
128
+ const result = await provider.forget({ namespace: "ns", query: "kitchen" });
129
+ assert.equal(result.removed, 1);
130
+ });
131
+
132
+ test("mem0: forget by namespace uses enumerate+delete (avoids version-fragile deleteAll)", async () => {
133
+ const fake = createFakeMemory();
134
+ // Add a deleteAll spy that should NOT be called.
135
+ (fake as any).deleteAll = async () => {
136
+ throw new Error("provider must NOT call deleteAll — mem0 v3 rejects some shapes");
137
+ };
138
+ const provider = new Mem0MemoryProvider({ memory: fake, inferOnWrite: false });
139
+ await provider.remember({ namespace: "ns", content: "a" });
140
+ await provider.remember({ namespace: "ns", content: "b" });
141
+ await provider.remember({ namespace: "other", content: "c" });
142
+
143
+ const result = await provider.forget({ namespace: "ns" });
144
+ assert.equal(result.removed, 2);
145
+ assert.equal(fake.records.length, 1);
146
+ assert.equal(fake.records[0].userId, "other");
147
+ });
148
+
149
+ test("mem0: status reports recordCount via getAll + embedder info", async () => {
150
+ const fake = createFakeMemory();
151
+ const provider = new Mem0MemoryProvider({
152
+ memory: fake,
153
+ inferOnWrite: false,
154
+ embedder: { provider: "ollama", config: { model: "nomic-embed-text" } },
155
+ });
156
+ await provider.remember({ namespace: "ns", content: "fact" });
157
+ const status = await provider.status("ns");
158
+ assert.equal(status.backend, "mem0");
159
+ assert.equal(status.namespace, "ns");
160
+ assert.equal(status.recordCount, 1);
161
+ assert.deepEqual(status.embedder, { provider: "ollama", model: "nomic-embed-text" });
162
+ });
163
+
164
+ test("mem0: recent() sorts by createdAt desc and respects limit and namespace", async () => {
165
+ const fake = createFakeMemory();
166
+ const provider = new Mem0MemoryProvider({ memory: fake, inferOnWrite: false });
167
+
168
+ // Stage records with explicit metadata.createdAt timestamps (newest -> oldest).
169
+ await provider.remember({ namespace: "ns", content: "oldest" });
170
+ await new Promise((r) => setTimeout(r, 2));
171
+ await provider.remember({ namespace: "ns", content: "middle" });
172
+ await new Promise((r) => setTimeout(r, 2));
173
+ await provider.remember({ namespace: "other", content: "other-ns" });
174
+ await new Promise((r) => setTimeout(r, 2));
175
+ await provider.remember({ namespace: "ns", content: "newest" });
176
+
177
+ const recent = await provider.recent("ns", 5);
178
+ assert.equal(recent.length, 3, "should only count records in 'ns'");
179
+ assert.equal(recent[0].content, "newest");
180
+ assert.equal(recent[1].content, "middle");
181
+ assert.equal(recent[2].content, "oldest");
182
+
183
+ const limited = await provider.recent("ns", 1);
184
+ assert.equal(limited.length, 1);
185
+ assert.equal(limited[0].content, "newest");
186
+
187
+ // recent() must use the documented v3 filter shape (snake_case user_id in filters).
188
+ const getAllCall = fake.calls.find(
189
+ (c) => c.method === "getAll" && (c.args[0] as any)?.filters?.user_id === "ns",
190
+ );
191
+ assert.ok(getAllCall, "recent() must filter by filters.user_id");
192
+ });
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Unit tests for the mem0 embedder auto-detection.
3
+ * Covers all three branches (Ollama / OpenAI / error) by injecting fetch and env.
4
+ */
5
+ import { test } from "node:test";
6
+ import assert from "node:assert/strict";
7
+
8
+ import { detectEmbedder } from "../mem0/provider.js";
9
+
10
+ test("smart-defaults: picks Ollama when 11434 responds OK", async () => {
11
+ const fetchImpl: any = async () => ({ ok: true });
12
+ const result = await detectEmbedder({
13
+ fetchImpl,
14
+ hasOpenAIKey: true, // even with OpenAI present, Ollama wins
15
+ });
16
+ assert.equal(result.provider, "ollama");
17
+ assert.equal((result.config as any).model, "nomic-embed-text");
18
+ });
19
+
20
+ test("smart-defaults: falls through to OpenAI when Ollama unreachable", async () => {
21
+ const fetchImpl: any = async () => {
22
+ throw new Error("ECONNREFUSED");
23
+ };
24
+ const result = await detectEmbedder({
25
+ fetchImpl,
26
+ hasOpenAIKey: true,
27
+ });
28
+ assert.equal(result.provider, "openai");
29
+ assert.equal((result.config as any).model, "text-embedding-3-small");
30
+ });
31
+
32
+ test("smart-defaults: throws actionable error when no embedder available", async () => {
33
+ const fetchImpl: any = async () => {
34
+ throw new Error("ECONNREFUSED");
35
+ };
36
+ await assert.rejects(
37
+ () => detectEmbedder({ fetchImpl, hasOpenAIKey: false }),
38
+ /needs an embedder/i,
39
+ );
40
+ });
41
+
42
+ test("smart-defaults: Ollama HTTP error (non-OK) falls through to OpenAI", async () => {
43
+ const fetchImpl: any = async () => ({ ok: false });
44
+ const result = await detectEmbedder({ fetchImpl, hasOpenAIKey: true });
45
+ assert.equal(result.provider, "openai");
46
+ });
@@ -0,0 +1,63 @@
1
+ import type { AgenticROSConfig } from "../config.js";
2
+ import type { MemoryProvider } from "./types.js";
3
+
4
+ /**
5
+ * Build a MemoryProvider from full config.
6
+ *
7
+ * Returns `null` when memory is disabled (`config.memory.enabled === false`),
8
+ * so adapters can short-circuit registering memory tools.
9
+ *
10
+ * The mem0 backend is loaded via dynamic import — `mem0ai` is an optional peer
11
+ * dependency. Users on `backend: "local"` never load it.
12
+ */
13
+ export async function createMemory(
14
+ config: AgenticROSConfig,
15
+ ): Promise<MemoryProvider | null> {
16
+ if (!config.memory?.enabled) return null;
17
+
18
+ const backend = config.memory.backend;
19
+ switch (backend) {
20
+ case "local": {
21
+ const { LocalMemoryProvider } = await import("./local/provider.js");
22
+ return new LocalMemoryProvider({
23
+ storePath: config.memory.local.storePath,
24
+ });
25
+ }
26
+
27
+ case "mem0": {
28
+ const { createMem0Provider } = await import("./mem0/provider.js");
29
+ return await createMem0Provider({
30
+ config: {
31
+ inferOnWrite: config.memory.mem0.inferOnWrite,
32
+ historyDbPath: config.memory.mem0.historyDbPath,
33
+ embedder: config.memory.mem0.embedder,
34
+ vectorStore: config.memory.mem0.vectorStore,
35
+ llm: config.memory.mem0.llm,
36
+ },
37
+ });
38
+ }
39
+
40
+ default: {
41
+ const _exhaustive: never = backend;
42
+ throw new Error(`Unknown memory backend: ${String(_exhaustive)}`);
43
+ }
44
+ }
45
+ }
46
+
47
+ /**
48
+ * Resolve the effective namespace used by memory tools.
49
+ * Argument > config.memory.namespace > config.robot.namespace.
50
+ */
51
+ export function resolveMemoryNamespace(
52
+ config: AgenticROSConfig,
53
+ argNamespace?: string,
54
+ ): string {
55
+ return (
56
+ (argNamespace && argNamespace.trim().length > 0 ? argNamespace : undefined) ??
57
+ (config.memory?.namespace && config.memory.namespace.trim().length > 0
58
+ ? config.memory.namespace
59
+ : undefined) ??
60
+ config.robot?.namespace ??
61
+ ""
62
+ );
63
+ }
@@ -0,0 +1,10 @@
1
+ export type {
2
+ ForgetInput,
3
+ MemoryProvider,
4
+ MemoryRecord,
5
+ MemoryStatus,
6
+ RecallInput,
7
+ RememberInput,
8
+ } from "./types.js";
9
+
10
+ export { createMemory, resolveMemoryNamespace } from "./factory.js";
@@ -0,0 +1,229 @@
1
+ import { promises as fs } from "node:fs";
2
+ import { homedir } from "node:os";
3
+ import path from "node:path";
4
+ import { randomUUID } from "node:crypto";
5
+
6
+ import type {
7
+ ForgetInput,
8
+ MemoryProvider,
9
+ MemoryRecord,
10
+ MemoryStatus,
11
+ RecallInput,
12
+ RememberInput,
13
+ } from "../types.js";
14
+
15
+ interface LocalConfig {
16
+ storePath: string;
17
+ }
18
+
19
+ interface FileShape {
20
+ version: 1;
21
+ records: MemoryRecord[];
22
+ }
23
+
24
+ /**
25
+ * Tiny JSON-on-disk memory backend. No new deps.
26
+ *
27
+ * Recall ranks by token-overlap score (tf-style) with a small recency bonus
28
+ * so two equally-relevant memories are returned newest-first. This is
29
+ * intentionally dumb — users who want true semantic search opt into mem0.
30
+ */
31
+ export class LocalMemoryProvider implements MemoryProvider {
32
+ readonly backend = "local" as const;
33
+ private readonly storePath: string;
34
+ private records: MemoryRecord[] | null = null;
35
+ private writeChain: Promise<void> = Promise.resolve();
36
+
37
+ constructor(config: LocalConfig) {
38
+ this.storePath = expandHome(config.storePath);
39
+ }
40
+
41
+ async remember(input: RememberInput): Promise<MemoryRecord> {
42
+ const namespace = requireNamespace(input.namespace);
43
+ const record: MemoryRecord = {
44
+ id: randomUUID(),
45
+ content: input.content,
46
+ namespace,
47
+ tags: input.tags && input.tags.length > 0 ? [...input.tags] : undefined,
48
+ path: input.path,
49
+ createdAt: Date.now(),
50
+ };
51
+ const records = await this.load();
52
+ records.push(record);
53
+ await this.persist();
54
+ return cloneRecord(record);
55
+ }
56
+
57
+ async recall(input: RecallInput): Promise<MemoryRecord[]> {
58
+ const namespace = requireNamespace(input.namespace);
59
+ const limit = input.limit ?? 10;
60
+ const records = await this.load();
61
+ const queryTokens = tokenize(input.query);
62
+ if (queryTokens.length === 0) return [];
63
+
64
+ const now = Date.now();
65
+ const scored = records
66
+ .filter((r) => r.namespace === namespace)
67
+ .map((r) => {
68
+ const recordTokens = tokenize(r.content);
69
+ const overlap = overlapScore(queryTokens, recordTokens);
70
+ const ageMs = Math.max(0, now - r.createdAt);
71
+ const recencyBonus = Math.exp(-ageMs / (1000 * 60 * 60 * 24 * 14)); // 14-day half-life
72
+ const score = overlap === 0 ? 0 : overlap + recencyBonus * 0.05;
73
+ return { record: r, score };
74
+ })
75
+ .filter((s) => s.score > 0)
76
+ .sort((a, b) => b.score - a.score)
77
+ .slice(0, limit);
78
+
79
+ return scored.map((s) => ({ ...cloneRecord(s.record), score: s.score }));
80
+ }
81
+
82
+ async forget(input: ForgetInput): Promise<{ removed: number }> {
83
+ const records = await this.load();
84
+ const before = records.length;
85
+ let next: MemoryRecord[];
86
+
87
+ if (input.id !== undefined) {
88
+ next = records.filter((r) => r.id !== input.id);
89
+ } else if (input.query !== undefined) {
90
+ const namespace = requireNamespace(input.namespace);
91
+ const tokens = tokenize(input.query);
92
+ next = records.filter((r) => {
93
+ if (r.namespace !== namespace) return true;
94
+ const overlap = overlapScore(tokens, tokenize(r.content));
95
+ return overlap === 0;
96
+ });
97
+ } else if (input.namespace !== undefined) {
98
+ next = records.filter((r) => r.namespace !== input.namespace);
99
+ } else {
100
+ throw new Error(
101
+ "forget() requires one of { id }, { query, namespace }, or { namespace }",
102
+ );
103
+ }
104
+
105
+ if (next.length === before) return { removed: 0 };
106
+ this.records = next;
107
+ await this.persist();
108
+ return { removed: before - next.length };
109
+ }
110
+
111
+ async status(namespace: string): Promise<MemoryStatus> {
112
+ const records = await this.load();
113
+ const inNs = records.filter((r) => r.namespace === namespace);
114
+ const lastWriteAt =
115
+ inNs.length === 0
116
+ ? null
117
+ : inNs.reduce((acc, r) => (r.createdAt > acc ? r.createdAt : acc), 0);
118
+ return {
119
+ enabled: true,
120
+ backend: "local",
121
+ namespace,
122
+ recordCount: inNs.length,
123
+ lastWriteAt,
124
+ };
125
+ }
126
+
127
+ async recent(namespace: string, limit = 5): Promise<MemoryRecord[]> {
128
+ const records = await this.load();
129
+ return records
130
+ .filter((r) => r.namespace === namespace)
131
+ .slice()
132
+ .sort((a, b) => b.createdAt - a.createdAt)
133
+ .slice(0, Math.max(0, limit))
134
+ .map(cloneRecord);
135
+ }
136
+
137
+ private async load(): Promise<MemoryRecord[]> {
138
+ if (this.records !== null) return this.records;
139
+ try {
140
+ const raw = await fs.readFile(this.storePath, "utf8");
141
+ const parsed = JSON.parse(raw) as FileShape;
142
+ if (
143
+ parsed &&
144
+ typeof parsed === "object" &&
145
+ parsed.version === 1 &&
146
+ Array.isArray(parsed.records)
147
+ ) {
148
+ this.records = parsed.records.map(normalizeRecord);
149
+ } else {
150
+ this.records = [];
151
+ }
152
+ } catch (err: any) {
153
+ if (err?.code === "ENOENT") {
154
+ this.records = [];
155
+ } else {
156
+ throw err;
157
+ }
158
+ }
159
+ return this.records;
160
+ }
161
+
162
+ private async persist(): Promise<void> {
163
+ if (this.records === null) return;
164
+ const snapshot: FileShape = { version: 1, records: this.records };
165
+ const text = JSON.stringify(snapshot, null, 2);
166
+ // Serialize writes so concurrent remember/forget calls don't race.
167
+ this.writeChain = this.writeChain.then(async () => {
168
+ await fs.mkdir(path.dirname(this.storePath), { recursive: true });
169
+ const tmp = `${this.storePath}.tmp`;
170
+ await fs.writeFile(tmp, text, "utf8");
171
+ await fs.rename(tmp, this.storePath);
172
+ });
173
+ await this.writeChain;
174
+ }
175
+ }
176
+
177
+ function expandHome(p: string): string {
178
+ if (p.startsWith("~/")) return path.join(homedir(), p.slice(2));
179
+ if (p === "~") return homedir();
180
+ return p;
181
+ }
182
+
183
+ function requireNamespace(ns: string | undefined): string {
184
+ if (!ns || ns.trim().length === 0) {
185
+ throw new Error(
186
+ "memory: namespace is required (config.memory.namespace or robot.namespace must be set)",
187
+ );
188
+ }
189
+ return ns;
190
+ }
191
+
192
+ function tokenize(s: string): string[] {
193
+ return s
194
+ .toLowerCase()
195
+ .replace(/[^a-z0-9_\s]/g, " ")
196
+ .split(/\s+/)
197
+ .filter((t) => t.length >= 2);
198
+ }
199
+
200
+ function overlapScore(query: string[], doc: string[]): number {
201
+ if (query.length === 0 || doc.length === 0) return 0;
202
+ const docSet = new Set(doc);
203
+ let hits = 0;
204
+ for (const t of query) if (docSet.has(t)) hits += 1;
205
+ return hits / Math.sqrt(query.length * doc.length);
206
+ }
207
+
208
+ function cloneRecord(r: MemoryRecord): MemoryRecord {
209
+ return {
210
+ id: r.id,
211
+ content: r.content,
212
+ namespace: r.namespace,
213
+ tags: r.tags ? [...r.tags] : undefined,
214
+ path: r.path,
215
+ createdAt: r.createdAt,
216
+ score: r.score,
217
+ };
218
+ }
219
+
220
+ function normalizeRecord(r: any): MemoryRecord {
221
+ return {
222
+ id: String(r.id ?? randomUUID()),
223
+ content: String(r.content ?? ""),
224
+ namespace: String(r.namespace ?? ""),
225
+ tags: Array.isArray(r.tags) ? r.tags.map(String) : undefined,
226
+ path: typeof r.path === "string" ? r.path : undefined,
227
+ createdAt: typeof r.createdAt === "number" ? r.createdAt : Date.now(),
228
+ };
229
+ }