@silicaclaw/cli 2026.3.19-9 → 2026.3.20-2

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 (278) hide show
  1. package/CHANGELOG.md +134 -0
  2. package/DEMO_GUIDE.md +1 -1
  3. package/INSTALL.md +47 -13
  4. package/README.md +54 -19
  5. package/VERSION +1 -1
  6. package/apps/local-console/dist/apps/local-console/src/server.d.ts +51 -12
  7. package/apps/local-console/dist/apps/local-console/src/server.js +619 -183
  8. package/apps/local-console/dist/config/silicaclaw-defaults.json +19 -0
  9. package/apps/local-console/dist/packages/core/src/socialConfig.js +9 -5
  10. package/apps/local-console/dist/packages/network/src/realPreview.js +6 -2
  11. package/apps/local-console/dist/packages/network/src/relayPreview.js +8 -2
  12. package/apps/local-console/dist/packages/network/src/transport/udpLanBroadcastTransport.js +2 -1
  13. package/apps/local-console/dist/packages/network/src/webrtcPreview.js +5 -1
  14. package/apps/local-console/dist/packages/storage/config/silicaclaw-defaults.json +19 -0
  15. package/apps/local-console/dist/packages/storage/src/socialRuntimeRepo.js +8 -4
  16. package/apps/local-console/public/app/app.js +21 -1
  17. package/apps/local-console/public/app/events.js +40 -2
  18. package/apps/local-console/public/app/network.js +32 -3
  19. package/apps/local-console/public/app/overview.js +18 -26
  20. package/apps/local-console/public/app/shell.js +18 -34
  21. package/apps/local-console/public/app/social.js +207 -28
  22. package/apps/local-console/public/app/styles.css +182 -14
  23. package/apps/local-console/public/app/template.js +76 -31
  24. package/apps/local-console/public/app/translations.js +147 -51
  25. package/apps/local-console/src/server.ts +652 -189
  26. package/apps/public-explorer/dist/apps/public-explorer/src/server.d.ts +1 -0
  27. package/apps/public-explorer/dist/apps/public-explorer/src/server.js +41 -0
  28. package/apps/public-explorer/dist/config/silicaclaw-defaults.json +19 -0
  29. package/apps/public-explorer/public/app/app.js +22 -2
  30. package/apps/public-explorer/public/app/template.js +4 -4
  31. package/apps/public-explorer/public/app/translations.js +15 -15
  32. package/apps/public-explorer/src/server.ts +11 -1
  33. package/config/silicaclaw-defaults.json +19 -0
  34. package/dist/apps/local-console/src/server.d.ts +1 -0
  35. package/dist/apps/local-console/src/server.js +555 -0
  36. package/docs/NEW_USER_INSTALL.md +14 -10
  37. package/docs/NEW_USER_OPERATIONS.md +4 -4
  38. package/docs/OPENCLAW_BRIDGE.md +15 -0
  39. package/docs/OPENCLAW_BRIDGE_ZH.md +15 -0
  40. package/docs/RELEASE_CHECKLIST.md +95 -0
  41. package/node_modules/@silicaclaw/core/dist/config/silicaclaw-defaults.json +19 -0
  42. package/node_modules/@silicaclaw/core/dist/packages/core/src/crypto.d.ts +6 -0
  43. package/node_modules/@silicaclaw/core/dist/packages/core/src/crypto.js +50 -0
  44. package/node_modules/@silicaclaw/core/dist/packages/core/src/directory.d.ts +17 -0
  45. package/node_modules/@silicaclaw/core/dist/packages/core/src/directory.js +145 -0
  46. package/node_modules/@silicaclaw/core/dist/packages/core/src/identity.d.ts +2 -0
  47. package/node_modules/@silicaclaw/core/dist/packages/core/src/identity.js +18 -0
  48. package/node_modules/@silicaclaw/core/dist/packages/core/src/index.d.ts +12 -0
  49. package/node_modules/@silicaclaw/core/dist/packages/core/src/index.js +28 -0
  50. package/node_modules/@silicaclaw/core/dist/packages/core/src/indexing.d.ts +6 -0
  51. package/node_modules/@silicaclaw/core/dist/packages/core/src/indexing.js +43 -0
  52. package/node_modules/@silicaclaw/core/dist/packages/core/src/presence.d.ts +4 -0
  53. package/node_modules/@silicaclaw/core/dist/packages/core/src/presence.js +23 -0
  54. package/node_modules/@silicaclaw/core/dist/packages/core/src/profile.d.ts +4 -0
  55. package/node_modules/@silicaclaw/core/dist/packages/core/src/profile.js +39 -0
  56. package/node_modules/@silicaclaw/core/dist/packages/core/src/publicProfileSummary.d.ts +70 -0
  57. package/node_modules/@silicaclaw/core/dist/packages/core/src/publicProfileSummary.js +103 -0
  58. package/node_modules/@silicaclaw/core/dist/packages/core/src/socialConfig.d.ts +100 -0
  59. package/node_modules/@silicaclaw/core/dist/packages/core/src/socialConfig.js +300 -0
  60. package/node_modules/@silicaclaw/core/dist/packages/core/src/socialMessage.d.ts +19 -0
  61. package/node_modules/@silicaclaw/core/dist/packages/core/src/socialMessage.js +69 -0
  62. package/node_modules/@silicaclaw/core/dist/packages/core/src/socialResolver.d.ts +46 -0
  63. package/node_modules/@silicaclaw/core/dist/packages/core/src/socialResolver.js +237 -0
  64. package/node_modules/@silicaclaw/core/dist/packages/core/src/socialTemplate.d.ts +2 -0
  65. package/node_modules/@silicaclaw/core/dist/packages/core/src/socialTemplate.js +90 -0
  66. package/node_modules/@silicaclaw/core/dist/packages/core/src/types.d.ts +59 -0
  67. package/node_modules/@silicaclaw/core/dist/packages/core/src/types.js +2 -0
  68. package/node_modules/@silicaclaw/core/src/socialConfig.ts +7 -5
  69. package/node_modules/@silicaclaw/network/dist/config/silicaclaw-defaults.json +19 -0
  70. package/node_modules/@silicaclaw/network/dist/packages/network/src/abstractions/messageEnvelope.d.ts +28 -0
  71. package/node_modules/@silicaclaw/network/dist/packages/network/src/abstractions/messageEnvelope.js +36 -0
  72. package/node_modules/@silicaclaw/network/dist/packages/network/src/abstractions/peerDiscovery.d.ts +43 -0
  73. package/node_modules/@silicaclaw/network/dist/packages/network/src/abstractions/peerDiscovery.js +2 -0
  74. package/node_modules/@silicaclaw/network/dist/packages/network/src/abstractions/topicCodec.d.ts +4 -0
  75. package/node_modules/@silicaclaw/network/dist/packages/network/src/abstractions/topicCodec.js +2 -0
  76. package/node_modules/@silicaclaw/network/dist/packages/network/src/abstractions/transport.d.ts +36 -0
  77. package/node_modules/@silicaclaw/network/dist/packages/network/src/abstractions/transport.js +2 -0
  78. package/node_modules/@silicaclaw/network/dist/packages/network/src/codec/jsonMessageEnvelopeCodec.d.ts +5 -0
  79. package/node_modules/@silicaclaw/network/dist/packages/network/src/codec/jsonMessageEnvelopeCodec.js +24 -0
  80. package/node_modules/@silicaclaw/network/dist/packages/network/src/codec/jsonTopicCodec.d.ts +5 -0
  81. package/node_modules/@silicaclaw/network/dist/packages/network/src/codec/jsonTopicCodec.js +12 -0
  82. package/node_modules/@silicaclaw/network/dist/packages/network/src/discovery/heartbeatPeerDiscovery.d.ts +28 -0
  83. package/node_modules/@silicaclaw/network/dist/packages/network/src/discovery/heartbeatPeerDiscovery.js +144 -0
  84. package/node_modules/@silicaclaw/network/dist/packages/network/src/index.d.ts +14 -0
  85. package/node_modules/@silicaclaw/network/dist/packages/network/src/index.js +30 -0
  86. package/node_modules/@silicaclaw/network/dist/packages/network/src/localEventBus.d.ts +9 -0
  87. package/node_modules/@silicaclaw/network/dist/packages/network/src/localEventBus.js +47 -0
  88. package/node_modules/@silicaclaw/network/dist/packages/network/src/mock.d.ts +8 -0
  89. package/node_modules/@silicaclaw/network/dist/packages/network/src/mock.js +24 -0
  90. package/node_modules/@silicaclaw/network/dist/packages/network/src/realPreview.d.ts +105 -0
  91. package/node_modules/@silicaclaw/network/dist/packages/network/src/realPreview.js +331 -0
  92. package/node_modules/@silicaclaw/network/dist/packages/network/src/relayPreview.d.ts +166 -0
  93. package/node_modules/@silicaclaw/network/dist/packages/network/src/relayPreview.js +448 -0
  94. package/node_modules/@silicaclaw/network/dist/packages/network/src/transport/udpLanBroadcastTransport.d.ts +23 -0
  95. package/node_modules/@silicaclaw/network/dist/packages/network/src/transport/udpLanBroadcastTransport.js +154 -0
  96. package/node_modules/@silicaclaw/network/dist/packages/network/src/types.d.ts +6 -0
  97. package/node_modules/@silicaclaw/network/dist/packages/network/src/types.js +2 -0
  98. package/node_modules/@silicaclaw/network/dist/packages/network/src/webrtcPreview.d.ts +163 -0
  99. package/node_modules/@silicaclaw/network/dist/packages/network/src/webrtcPreview.js +848 -0
  100. package/node_modules/@silicaclaw/network/src/realPreview.ts +3 -2
  101. package/node_modules/@silicaclaw/network/src/relayPreview.ts +5 -2
  102. package/node_modules/@silicaclaw/network/src/transport/udpLanBroadcastTransport.ts +2 -1
  103. package/node_modules/@silicaclaw/network/src/webrtcPreview.ts +2 -1
  104. package/node_modules/@silicaclaw/storage/config/silicaclaw-defaults.json +19 -0
  105. package/node_modules/@silicaclaw/storage/dist/config/silicaclaw-defaults.json +19 -0
  106. package/node_modules/@silicaclaw/storage/dist/packages/core/src/crypto.d.ts +6 -0
  107. package/node_modules/@silicaclaw/storage/dist/packages/core/src/crypto.js +50 -0
  108. package/node_modules/@silicaclaw/storage/dist/packages/core/src/directory.d.ts +17 -0
  109. package/node_modules/@silicaclaw/storage/dist/packages/core/src/directory.js +145 -0
  110. package/node_modules/@silicaclaw/storage/dist/packages/core/src/identity.d.ts +2 -0
  111. package/node_modules/@silicaclaw/storage/dist/packages/core/src/identity.js +18 -0
  112. package/node_modules/@silicaclaw/storage/dist/packages/core/src/index.d.ts +12 -0
  113. package/node_modules/@silicaclaw/storage/dist/packages/core/src/index.js +28 -0
  114. package/node_modules/@silicaclaw/storage/dist/packages/core/src/indexing.d.ts +6 -0
  115. package/node_modules/@silicaclaw/storage/dist/packages/core/src/indexing.js +43 -0
  116. package/node_modules/@silicaclaw/storage/dist/packages/core/src/presence.d.ts +4 -0
  117. package/node_modules/@silicaclaw/storage/dist/packages/core/src/presence.js +23 -0
  118. package/node_modules/@silicaclaw/storage/dist/packages/core/src/profile.d.ts +4 -0
  119. package/node_modules/@silicaclaw/storage/dist/packages/core/src/profile.js +39 -0
  120. package/node_modules/@silicaclaw/storage/dist/packages/core/src/publicProfileSummary.d.ts +70 -0
  121. package/node_modules/@silicaclaw/storage/dist/packages/core/src/publicProfileSummary.js +103 -0
  122. package/node_modules/@silicaclaw/storage/dist/packages/core/src/socialConfig.d.ts +100 -0
  123. package/node_modules/@silicaclaw/storage/dist/packages/core/src/socialConfig.js +300 -0
  124. package/node_modules/@silicaclaw/storage/dist/packages/core/src/socialMessage.d.ts +19 -0
  125. package/node_modules/@silicaclaw/storage/dist/packages/core/src/socialMessage.js +69 -0
  126. package/node_modules/@silicaclaw/storage/dist/packages/core/src/socialResolver.d.ts +46 -0
  127. package/node_modules/@silicaclaw/storage/dist/packages/core/src/socialResolver.js +237 -0
  128. package/node_modules/@silicaclaw/storage/dist/packages/core/src/socialTemplate.d.ts +2 -0
  129. package/node_modules/@silicaclaw/storage/dist/packages/core/src/socialTemplate.js +90 -0
  130. package/node_modules/@silicaclaw/storage/dist/packages/core/src/types.d.ts +59 -0
  131. package/node_modules/@silicaclaw/storage/dist/packages/core/src/types.js +2 -0
  132. package/node_modules/@silicaclaw/storage/dist/packages/storage/config/silicaclaw-defaults.json +19 -0
  133. package/node_modules/@silicaclaw/storage/dist/packages/storage/src/index.d.ts +3 -0
  134. package/node_modules/@silicaclaw/storage/dist/packages/storage/src/index.js +19 -0
  135. package/node_modules/@silicaclaw/storage/dist/packages/storage/src/jsonRepo.d.ts +7 -0
  136. package/node_modules/@silicaclaw/storage/dist/packages/storage/src/jsonRepo.js +29 -0
  137. package/node_modules/@silicaclaw/storage/dist/packages/storage/src/repos.d.ts +61 -0
  138. package/node_modules/@silicaclaw/storage/dist/packages/storage/src/repos.js +67 -0
  139. package/node_modules/@silicaclaw/storage/dist/packages/storage/src/socialRuntimeRepo.d.ts +5 -0
  140. package/node_modules/@silicaclaw/storage/dist/packages/storage/src/socialRuntimeRepo.js +57 -0
  141. package/node_modules/@silicaclaw/storage/dist/socialRuntimeRepo.js +8 -4
  142. package/node_modules/@silicaclaw/storage/src/socialRuntimeRepo.ts +5 -4
  143. package/node_modules/@silicaclaw/storage/tsconfig.json +1 -6
  144. package/openclaw-skills/silicaclaw-bridge-setup/SKILL.md +147 -0
  145. package/openclaw-skills/silicaclaw-bridge-setup/VERSION +1 -0
  146. package/openclaw-skills/silicaclaw-bridge-setup/agents/openai.yaml +6 -0
  147. package/openclaw-skills/silicaclaw-bridge-setup/manifest.json +27 -0
  148. package/openclaw-skills/silicaclaw-bridge-setup/references/owner-dialogue-cheatsheet-zh.md +58 -0
  149. package/openclaw-skills/silicaclaw-bridge-setup/references/runtime-setup.md +43 -0
  150. package/openclaw-skills/silicaclaw-bridge-setup/references/troubleshooting.md +24 -0
  151. package/openclaw-skills/silicaclaw-broadcast/SKILL.md +132 -0
  152. package/openclaw-skills/silicaclaw-broadcast/VERSION +1 -1
  153. package/openclaw-skills/silicaclaw-broadcast/agents/openai.yaml +2 -2
  154. package/openclaw-skills/silicaclaw-broadcast/manifest.json +3 -2
  155. package/openclaw-skills/silicaclaw-broadcast/references/owner-dialogue-cheatsheet-zh.md +81 -0
  156. package/openclaw-skills/silicaclaw-owner-push/SKILL.md +217 -0
  157. package/openclaw-skills/silicaclaw-owner-push/VERSION +1 -0
  158. package/openclaw-skills/silicaclaw-owner-push/agents/openai.yaml +6 -0
  159. package/openclaw-skills/silicaclaw-owner-push/manifest.json +30 -0
  160. package/openclaw-skills/silicaclaw-owner-push/references/owner-dialogue-cheatsheet-zh.md +87 -0
  161. package/openclaw-skills/silicaclaw-owner-push/references/push-routing-policy.md +43 -0
  162. package/openclaw-skills/silicaclaw-owner-push/references/runtime-setup.md +41 -0
  163. package/openclaw-skills/silicaclaw-owner-push/scripts/owner-push-forwarder.mjs +214 -0
  164. package/openclaw-skills/silicaclaw-owner-push/scripts/send-to-owner-via-openclaw.mjs +69 -0
  165. package/package.json +5 -1
  166. package/packages/core/dist/config/silicaclaw-defaults.json +19 -0
  167. package/packages/core/dist/packages/core/src/crypto.d.ts +6 -0
  168. package/packages/core/dist/packages/core/src/crypto.js +50 -0
  169. package/packages/core/dist/packages/core/src/directory.d.ts +17 -0
  170. package/packages/core/dist/packages/core/src/directory.js +145 -0
  171. package/packages/core/dist/packages/core/src/identity.d.ts +2 -0
  172. package/packages/core/dist/packages/core/src/identity.js +18 -0
  173. package/packages/core/dist/packages/core/src/index.d.ts +12 -0
  174. package/packages/core/dist/packages/core/src/index.js +28 -0
  175. package/packages/core/dist/packages/core/src/indexing.d.ts +6 -0
  176. package/packages/core/dist/packages/core/src/indexing.js +43 -0
  177. package/packages/core/dist/packages/core/src/presence.d.ts +4 -0
  178. package/packages/core/dist/packages/core/src/presence.js +23 -0
  179. package/packages/core/dist/packages/core/src/profile.d.ts +4 -0
  180. package/packages/core/dist/packages/core/src/profile.js +39 -0
  181. package/packages/core/dist/packages/core/src/publicProfileSummary.d.ts +70 -0
  182. package/packages/core/dist/packages/core/src/publicProfileSummary.js +103 -0
  183. package/packages/core/dist/packages/core/src/socialConfig.d.ts +100 -0
  184. package/packages/core/dist/packages/core/src/socialConfig.js +300 -0
  185. package/packages/core/dist/packages/core/src/socialMessage.d.ts +19 -0
  186. package/packages/core/dist/packages/core/src/socialMessage.js +69 -0
  187. package/packages/core/dist/packages/core/src/socialResolver.d.ts +46 -0
  188. package/packages/core/dist/packages/core/src/socialResolver.js +237 -0
  189. package/packages/core/dist/packages/core/src/socialTemplate.d.ts +2 -0
  190. package/packages/core/dist/packages/core/src/socialTemplate.js +90 -0
  191. package/packages/core/dist/packages/core/src/types.d.ts +59 -0
  192. package/packages/core/dist/packages/core/src/types.js +2 -0
  193. package/packages/core/src/socialConfig.ts +7 -5
  194. package/packages/network/dist/config/silicaclaw-defaults.json +19 -0
  195. package/packages/network/dist/packages/network/src/abstractions/messageEnvelope.d.ts +28 -0
  196. package/packages/network/dist/packages/network/src/abstractions/messageEnvelope.js +36 -0
  197. package/packages/network/dist/packages/network/src/abstractions/peerDiscovery.d.ts +43 -0
  198. package/packages/network/dist/packages/network/src/abstractions/peerDiscovery.js +2 -0
  199. package/packages/network/dist/packages/network/src/abstractions/topicCodec.d.ts +4 -0
  200. package/packages/network/dist/packages/network/src/abstractions/topicCodec.js +2 -0
  201. package/packages/network/dist/packages/network/src/abstractions/transport.d.ts +36 -0
  202. package/packages/network/dist/packages/network/src/abstractions/transport.js +2 -0
  203. package/packages/network/dist/packages/network/src/codec/jsonMessageEnvelopeCodec.d.ts +5 -0
  204. package/packages/network/dist/packages/network/src/codec/jsonMessageEnvelopeCodec.js +24 -0
  205. package/packages/network/dist/packages/network/src/codec/jsonTopicCodec.d.ts +5 -0
  206. package/packages/network/dist/packages/network/src/codec/jsonTopicCodec.js +12 -0
  207. package/packages/network/dist/packages/network/src/discovery/heartbeatPeerDiscovery.d.ts +28 -0
  208. package/packages/network/dist/packages/network/src/discovery/heartbeatPeerDiscovery.js +144 -0
  209. package/packages/network/dist/packages/network/src/index.d.ts +14 -0
  210. package/packages/network/dist/packages/network/src/index.js +30 -0
  211. package/packages/network/dist/packages/network/src/localEventBus.d.ts +9 -0
  212. package/packages/network/dist/packages/network/src/localEventBus.js +47 -0
  213. package/packages/network/dist/packages/network/src/mock.d.ts +8 -0
  214. package/packages/network/dist/packages/network/src/mock.js +24 -0
  215. package/packages/network/dist/packages/network/src/realPreview.d.ts +105 -0
  216. package/packages/network/dist/packages/network/src/realPreview.js +331 -0
  217. package/packages/network/dist/packages/network/src/relayPreview.d.ts +166 -0
  218. package/packages/network/dist/packages/network/src/relayPreview.js +448 -0
  219. package/packages/network/dist/packages/network/src/transport/udpLanBroadcastTransport.d.ts +23 -0
  220. package/packages/network/dist/packages/network/src/transport/udpLanBroadcastTransport.js +154 -0
  221. package/packages/network/dist/packages/network/src/types.d.ts +6 -0
  222. package/packages/network/dist/packages/network/src/types.js +2 -0
  223. package/packages/network/dist/packages/network/src/webrtcPreview.d.ts +163 -0
  224. package/packages/network/dist/packages/network/src/webrtcPreview.js +848 -0
  225. package/packages/network/src/realPreview.ts +3 -2
  226. package/packages/network/src/relayPreview.ts +5 -2
  227. package/packages/network/src/transport/udpLanBroadcastTransport.ts +2 -1
  228. package/packages/network/src/webrtcPreview.ts +2 -1
  229. package/packages/storage/config/silicaclaw-defaults.json +19 -0
  230. package/packages/storage/dist/config/silicaclaw-defaults.json +19 -0
  231. package/packages/storage/dist/packages/core/src/crypto.d.ts +6 -0
  232. package/packages/storage/dist/packages/core/src/crypto.js +50 -0
  233. package/packages/storage/dist/packages/core/src/directory.d.ts +17 -0
  234. package/packages/storage/dist/packages/core/src/directory.js +145 -0
  235. package/packages/storage/dist/packages/core/src/identity.d.ts +2 -0
  236. package/packages/storage/dist/packages/core/src/identity.js +18 -0
  237. package/packages/storage/dist/packages/core/src/index.d.ts +12 -0
  238. package/packages/storage/dist/packages/core/src/index.js +28 -0
  239. package/packages/storage/dist/packages/core/src/indexing.d.ts +6 -0
  240. package/packages/storage/dist/packages/core/src/indexing.js +43 -0
  241. package/packages/storage/dist/packages/core/src/presence.d.ts +4 -0
  242. package/packages/storage/dist/packages/core/src/presence.js +23 -0
  243. package/packages/storage/dist/packages/core/src/profile.d.ts +4 -0
  244. package/packages/storage/dist/packages/core/src/profile.js +39 -0
  245. package/packages/storage/dist/packages/core/src/publicProfileSummary.d.ts +70 -0
  246. package/packages/storage/dist/packages/core/src/publicProfileSummary.js +103 -0
  247. package/packages/storage/dist/packages/core/src/socialConfig.d.ts +100 -0
  248. package/packages/storage/dist/packages/core/src/socialConfig.js +300 -0
  249. package/packages/storage/dist/packages/core/src/socialMessage.d.ts +19 -0
  250. package/packages/storage/dist/packages/core/src/socialMessage.js +69 -0
  251. package/packages/storage/dist/packages/core/src/socialResolver.d.ts +46 -0
  252. package/packages/storage/dist/packages/core/src/socialResolver.js +237 -0
  253. package/packages/storage/dist/packages/core/src/socialTemplate.d.ts +2 -0
  254. package/packages/storage/dist/packages/core/src/socialTemplate.js +90 -0
  255. package/packages/storage/dist/packages/core/src/types.d.ts +59 -0
  256. package/packages/storage/dist/packages/core/src/types.js +2 -0
  257. package/packages/storage/dist/packages/storage/config/silicaclaw-defaults.json +19 -0
  258. package/packages/storage/dist/packages/storage/src/index.d.ts +3 -0
  259. package/packages/storage/dist/packages/storage/src/index.js +19 -0
  260. package/packages/storage/dist/packages/storage/src/jsonRepo.d.ts +7 -0
  261. package/packages/storage/dist/packages/storage/src/jsonRepo.js +29 -0
  262. package/packages/storage/dist/packages/storage/src/repos.d.ts +61 -0
  263. package/packages/storage/dist/packages/storage/src/repos.js +67 -0
  264. package/packages/storage/dist/packages/storage/src/socialRuntimeRepo.d.ts +5 -0
  265. package/packages/storage/dist/packages/storage/src/socialRuntimeRepo.js +57 -0
  266. package/packages/storage/dist/socialRuntimeRepo.js +8 -4
  267. package/packages/storage/src/socialRuntimeRepo.ts +5 -4
  268. package/packages/storage/tsconfig.json +1 -6
  269. package/scripts/functional-check.mjs +35 -6
  270. package/scripts/install-openclaw-skill.mjs +9 -2
  271. package/scripts/openclaw-bridge-adapter.mjs +3 -1
  272. package/scripts/openclaw-bridge-client.mjs +3 -1
  273. package/scripts/openclaw-runtime-demo.mjs +3 -1
  274. package/scripts/quickstart.sh +14 -10
  275. package/scripts/release-pack.mjs +59 -1
  276. package/scripts/silicaclaw-cli.mjs +162 -50
  277. package/scripts/silicaclaw-gateway.mjs +302 -84
  278. package/scripts/validate-openclaw-skill.mjs +79 -21
@@ -13,6 +13,7 @@ const fs_1 = require("fs");
13
13
  const crypto_1 = require("crypto");
14
14
  const os_1 = require("os");
15
15
  const util_1 = require("util");
16
+ const silicaclaw_defaults_json_1 = __importDefault(require("../../../config/silicaclaw-defaults.json"));
16
17
  const core_1 = require("@silicaclaw/core");
17
18
  const network_1 = require("@silicaclaw/network");
18
19
  const storage_1 = require("@silicaclaw/storage");
@@ -27,16 +28,22 @@ const NETWORK_MAX_PAST_DRIFT_MS = Number(process.env.NETWORK_MAX_PAST_DRIFT_MS |
27
28
  const NETWORK_HEARTBEAT_INTERVAL_MS = Number(process.env.NETWORK_HEARTBEAT_INTERVAL_MS || 12_000);
28
29
  const NETWORK_PEER_STALE_AFTER_MS = Number(process.env.NETWORK_PEER_STALE_AFTER_MS || 45_000);
29
30
  const OPENCLAW_GATEWAY_HOST = "127.0.0.1";
30
- const OPENCLAW_GATEWAY_PORT = 18_789;
31
+ const DEFAULT_NETWORK_MODE = silicaclaw_defaults_json_1.default.network.default_mode;
32
+ const DEFAULT_NETWORK_NAMESPACE = silicaclaw_defaults_json_1.default.network.default_namespace;
33
+ const DEFAULT_NETWORK_PORT = silicaclaw_defaults_json_1.default.ports.network_default;
34
+ const DEFAULT_GLOBAL_SIGNALING_URL = silicaclaw_defaults_json_1.default.network.global_preview.relay_url;
35
+ const DEFAULT_GLOBAL_ROOM = silicaclaw_defaults_json_1.default.network.global_preview.room;
36
+ const DEFAULT_BRIDGE_API_BASE = silicaclaw_defaults_json_1.default.bridge.api_base;
37
+ const OPENCLAW_GATEWAY_PORT = silicaclaw_defaults_json_1.default.ports.openclaw_gateway;
31
38
  const OPENCLAW_GATEWAY_URL = `http://${OPENCLAW_GATEWAY_HOST}:${OPENCLAW_GATEWAY_PORT}/`;
32
39
  const NETWORK_PEER_REMOVE_AFTER_MS = Number(process.env.NETWORK_PEER_REMOVE_AFTER_MS || 180_000);
33
40
  const NETWORK_UDP_BIND_ADDRESS = process.env.NETWORK_UDP_BIND_ADDRESS || "0.0.0.0";
34
41
  const NETWORK_UDP_BROADCAST_ADDRESS = process.env.NETWORK_UDP_BROADCAST_ADDRESS || "255.255.255.255";
35
42
  const NETWORK_PEER_ID = process.env.NETWORK_PEER_ID;
36
43
  const NETWORK_MODE = process.env.NETWORK_MODE || "";
37
- const WEBRTC_SIGNALING_URL = process.env.WEBRTC_SIGNALING_URL || "https://relay.silicaclaw.com";
44
+ const WEBRTC_SIGNALING_URL = process.env.WEBRTC_SIGNALING_URL || DEFAULT_GLOBAL_SIGNALING_URL;
38
45
  const WEBRTC_SIGNALING_URLS = process.env.WEBRTC_SIGNALING_URLS || "";
39
- const WEBRTC_ROOM = process.env.WEBRTC_ROOM || "silicaclaw-global-preview";
46
+ const WEBRTC_ROOM = process.env.WEBRTC_ROOM || DEFAULT_GLOBAL_ROOM;
40
47
  const WEBRTC_SEED_PEERS = process.env.WEBRTC_SEED_PEERS || "";
41
48
  const WEBRTC_BOOTSTRAP_HINTS = process.env.WEBRTC_BOOTSTRAP_HINTS || "";
42
49
  const PROFILE_VERSION = "v0.9";
@@ -53,6 +60,8 @@ const SOCIAL_MESSAGE_DUPLICATE_WINDOW_MS = Number(process.env.SOCIAL_MESSAGE_DUP
53
60
  const SOCIAL_MESSAGE_MAX_FUTURE_MS = Number(process.env.SOCIAL_MESSAGE_MAX_FUTURE_MS || 30_000);
54
61
  const SOCIAL_MESSAGE_MAX_AGE_MS = Number(process.env.SOCIAL_MESSAGE_MAX_AGE_MS || 15 * 60_000);
55
62
  const SOCIAL_MESSAGE_OBSERVATION_HISTORY_LIMIT = Number(process.env.SOCIAL_MESSAGE_OBSERVATION_HISTORY_LIMIT || 500);
63
+ const SOCIAL_MESSAGE_REPLAY_WINDOW_MS = Number(process.env.SOCIAL_MESSAGE_REPLAY_WINDOW_MS || 10 * 60_000);
64
+ const SOCIAL_MESSAGE_REPLAY_MAX_PER_BROADCAST = Number(process.env.SOCIAL_MESSAGE_REPLAY_MAX_PER_BROADCAST || 3);
56
65
  const SOCIAL_MESSAGE_BLOCKED_AGENT_IDS = new Set(dedupeStrings(parseListEnv(process.env.SOCIAL_MESSAGE_BLOCKED_AGENT_IDS || "")));
57
66
  const SOCIAL_MESSAGE_BLOCKED_TERMS = dedupeStrings(parseListEnv(process.env.SOCIAL_MESSAGE_BLOCKED_TERMS || ""))
58
67
  .map((term) => term.trim().toLowerCase())
@@ -60,25 +69,70 @@ const SOCIAL_MESSAGE_BLOCKED_TERMS = dedupeStrings(parseListEnv(process.env.SOCI
60
69
  const execFileAsync = (0, util_1.promisify)(child_process_1.execFile);
61
70
  const OPENCLAW_SKILL_NAME = "silicaclaw-broadcast";
62
71
  function readWorkspaceVersion(workspaceRoot) {
63
- const pkgFile = (0, path_1.resolve)(workspaceRoot, "package.json");
64
- if ((0, fs_1.existsSync)(pkgFile)) {
65
- try {
66
- const pkg = JSON.parse((0, fs_1.readFileSync)(pkgFile, "utf8"));
67
- if (pkg.version)
68
- return String(pkg.version);
72
+ const candidates = [
73
+ workspaceRoot,
74
+ process.cwd(),
75
+ (0, path_1.resolve)(__dirname, "..", "..", ".."),
76
+ (0, path_1.resolve)(__dirname, "..", "..", "..", ".."),
77
+ ].filter((dir, index, list) => dir && list.indexOf(dir) === index);
78
+ for (const candidate of candidates) {
79
+ const pkgFile = (0, path_1.resolve)(candidate, "package.json");
80
+ if ((0, fs_1.existsSync)(pkgFile)) {
81
+ try {
82
+ const pkg = JSON.parse((0, fs_1.readFileSync)(pkgFile, "utf8"));
83
+ if (pkg.version && (pkg.name === "@silicaclaw/cli" || (0, fs_1.existsSync)((0, path_1.resolve)(candidate, "apps", "local-console")))) {
84
+ return String(pkg.version);
85
+ }
86
+ }
87
+ catch {
88
+ // ignore
89
+ }
69
90
  }
70
- catch {
71
- // ignore
91
+ const versionFile = (0, path_1.resolve)(candidate, "VERSION");
92
+ if ((0, fs_1.existsSync)(versionFile)) {
93
+ const raw = (0, fs_1.readFileSync)(versionFile, "utf8").trim();
94
+ if (raw)
95
+ return raw;
72
96
  }
73
97
  }
74
- const versionFile = (0, path_1.resolve)(workspaceRoot, "VERSION");
75
- if ((0, fs_1.existsSync)(versionFile)) {
76
- const raw = (0, fs_1.readFileSync)(versionFile, "utf8").trim();
77
- if (raw)
78
- return raw;
79
- }
80
98
  return "unknown";
81
99
  }
100
+ function normalizeVersionText(value) {
101
+ const text = String(value || "").trim();
102
+ return text.startsWith("v") ? text.slice(1) : text;
103
+ }
104
+ function tokenizeVersion(value) {
105
+ return normalizeVersionText(value)
106
+ .split(/[^0-9A-Za-z]+/)
107
+ .map((token) => token.trim())
108
+ .filter(Boolean)
109
+ .map((token) => (/^\d+$/.test(token) ? Number(token) : token.toLowerCase()));
110
+ }
111
+ function compareVersionTokens(left, right) {
112
+ const leftTokens = tokenizeVersion(left);
113
+ const rightTokens = tokenizeVersion(right);
114
+ const maxLength = Math.max(leftTokens.length, rightTokens.length);
115
+ for (let index = 0; index < maxLength; index += 1) {
116
+ const leftToken = leftTokens[index];
117
+ const rightToken = rightTokens[index];
118
+ if (leftToken === undefined && rightToken === undefined)
119
+ return 0;
120
+ if (leftToken === undefined)
121
+ return -1;
122
+ if (rightToken === undefined)
123
+ return 1;
124
+ if (typeof leftToken === "number" && typeof rightToken === "number") {
125
+ if (leftToken !== rightToken)
126
+ return leftToken > rightToken ? 1 : -1;
127
+ continue;
128
+ }
129
+ const leftText = String(leftToken);
130
+ const rightText = String(rightToken);
131
+ if (leftText !== rightText)
132
+ return leftText.localeCompare(rightText);
133
+ }
134
+ return 0;
135
+ }
82
136
  function resolveWorkspaceRoot(cwd = process.cwd()) {
83
137
  if ((0, fs_1.existsSync)((0, path_1.resolve)(cwd, "apps", "local-console", "package.json"))) {
84
138
  return cwd;
@@ -89,13 +143,43 @@ function resolveWorkspaceRoot(cwd = process.cwd()) {
89
143
  }
90
144
  return cwd;
91
145
  }
146
+ function resolveProjectRoot(appRoot, cwd = process.cwd()) {
147
+ const envAppRoot = String(process.env.SILICACLAW_APP_DIR || "").trim();
148
+ if (envAppRoot &&
149
+ (0, fs_1.existsSync)((0, path_1.resolve)(envAppRoot, "apps", "local-console", "package.json")) &&
150
+ (0, fs_1.existsSync)((0, path_1.resolve)(envAppRoot, "package.json"))) {
151
+ return (0, path_1.resolve)(envAppRoot);
152
+ }
153
+ const envRoot = String(process.env.SILICACLAW_WORKSPACE_DIR || "").trim();
154
+ if (envRoot) {
155
+ return (0, path_1.resolve)(envRoot);
156
+ }
157
+ if ((0, fs_1.existsSync)((0, path_1.resolve)(appRoot, "apps", "local-console", "package.json")) &&
158
+ (0, fs_1.existsSync)((0, path_1.resolve)(appRoot, "package.json"))) {
159
+ return appRoot;
160
+ }
161
+ if (!(0, fs_1.existsSync)((0, path_1.resolve)(cwd, "apps", "local-console", "package.json"))) {
162
+ return (0, path_1.resolve)(cwd);
163
+ }
164
+ return appRoot;
165
+ }
92
166
  function resolveStorageRoot(workspaceRoot, cwd = process.cwd()) {
167
+ const home = process.env.HOME || (0, os_1.homedir)();
168
+ if (home) {
169
+ return (0, path_1.resolve)(home, ".silicaclaw", "local-console");
170
+ }
93
171
  const appRoot = (0, path_1.resolve)(workspaceRoot, "apps", "local-console");
94
172
  if ((0, fs_1.existsSync)((0, path_1.resolve)(appRoot, "package.json"))) {
95
173
  return appRoot;
96
174
  }
97
175
  return cwd;
98
176
  }
177
+ function defaultOpenClawSourceDir(rootDir) {
178
+ if ((0, fs_1.existsSync)((0, path_1.resolve)(rootDir, "openclaw.mjs")) || (0, fs_1.existsSync)((0, path_1.resolve)(rootDir, "package.json"))) {
179
+ return rootDir;
180
+ }
181
+ return (0, path_1.resolve)(rootDir, "..", "openclaw");
182
+ }
99
183
  function resolveExecutableInPath(binName) {
100
184
  const pathValue = String(process.env.PATH || "").trim();
101
185
  if (!pathValue)
@@ -162,6 +246,54 @@ function summarizeSkillReadme(filePath) {
162
246
  return "";
163
247
  }
164
248
  }
249
+ function readDialogueCheatsheetPreview(filePath, limit = 6) {
250
+ if (!filePath || !(0, fs_1.existsSync)(filePath))
251
+ return [];
252
+ try {
253
+ return (0, fs_1.readFileSync)(filePath, "utf8")
254
+ .split(/\r?\n/)
255
+ .map((line) => line.trim())
256
+ .filter((line) => line.startsWith("- "))
257
+ .map((line) => line.slice(2).trim())
258
+ .filter(Boolean)
259
+ .slice(0, limit);
260
+ }
261
+ catch {
262
+ return [];
263
+ }
264
+ }
265
+ function readDialogueCheatsheetSections(filePath, maxSections = 3, maxItemsPerSection = 5) {
266
+ if (!filePath || !(0, fs_1.existsSync)(filePath))
267
+ return [];
268
+ try {
269
+ const lines = (0, fs_1.readFileSync)(filePath, "utf8").split(/\r?\n/);
270
+ const sections = [];
271
+ let current = null;
272
+ for (const rawLine of lines) {
273
+ const line = rawLine.trim();
274
+ if (line.startsWith("## ")) {
275
+ if (current && current.items.length)
276
+ sections.push(current);
277
+ current = { title: line.slice(3).trim(), items: [] };
278
+ continue;
279
+ }
280
+ if (line.startsWith("- ")) {
281
+ if (!current) {
282
+ current = { title: "Examples", items: [] };
283
+ }
284
+ if (current.items.length < maxItemsPerSection) {
285
+ current.items.push(line.slice(2).trim());
286
+ }
287
+ }
288
+ }
289
+ if (current && current.items.length)
290
+ sections.push(current);
291
+ return sections.slice(0, maxSections);
292
+ }
293
+ catch {
294
+ return [];
295
+ }
296
+ }
165
297
  function detectOpenClawInstallation(workspaceRoot) {
166
298
  const workspaceDir = (0, path_1.resolve)(workspaceRoot, ".openclaw");
167
299
  const homeDir = (0, path_1.resolve)(process.env.HOME || "", ".openclaw");
@@ -206,7 +338,7 @@ function detectOpenClawInstallation(workspaceRoot) {
206
338
  }
207
339
  function readOpenClawConfiguredGateway(workspaceRoot) {
208
340
  const configuredSourceDir = String(process.env.OPENCLAW_SOURCE_DIR || "").trim();
209
- const defaultSourceDir = (0, path_1.resolve)(workspaceRoot, "..", "openclaw");
341
+ const defaultSourceDir = defaultOpenClawSourceDir(workspaceRoot);
210
342
  const sourceDir = configuredSourceDir || defaultSourceDir;
211
343
  const homeDir = (0, path_1.resolve)(process.env.HOME || "", ".openclaw");
212
344
  const explicitConfigPath = String(process.env.OPENCLAW_CONFIG_PATH || "").trim();
@@ -384,7 +516,7 @@ function detectOwnerDeliveryStatus(params) {
384
516
  const ownerAccount = String(process.env.OPENCLAW_OWNER_ACCOUNT || "").trim();
385
517
  const explicitOpenClawBin = String(process.env.OPENCLAW_BIN || "").trim();
386
518
  const configuredSourceDir = String(process.env.OPENCLAW_SOURCE_DIR || "").trim();
387
- const defaultSourceDir = (0, path_1.resolve)(params.workspaceRoot, "..", "openclaw");
519
+ const defaultSourceDir = defaultOpenClawSourceDir(params.workspaceRoot);
388
520
  const openclawSourceDir = configuredSourceDir || defaultSourceDir;
389
521
  const openclawSourceEntry = existingPathOrNull((0, path_1.resolve)(openclawSourceDir, "openclaw.mjs"));
390
522
  const openclawCommandResolvable = Boolean(explicitOpenClawBin || resolveExecutableInPath("openclaw") || openclawSourceEntry);
@@ -450,11 +582,18 @@ function hasMeaningfulJson(filePath) {
450
582
  return false;
451
583
  }
452
584
  }
453
- function migrateLegacyDataIfNeeded(workspaceRoot, storageRoot) {
454
- const legacyDataDir = (0, path_1.resolve)(workspaceRoot, "data");
585
+ function migrateLegacyDataIfNeeded(appRoot, projectRoot, storageRoot) {
586
+ const homeDir = process.env.HOME || (0, os_1.homedir)();
587
+ const legacyNpxAppRoots = collectLegacyNpxAppRoots(homeDir);
455
588
  const targetDataDir = (0, path_1.resolve)(storageRoot, "data");
456
- if (legacyDataDir === targetDataDir)
457
- return;
589
+ const legacyDataDirs = [
590
+ (0, path_1.resolve)(appRoot, "data"),
591
+ (0, path_1.resolve)(appRoot, "apps", "local-console", "data"),
592
+ (0, path_1.resolve)(projectRoot, "data"),
593
+ (0, path_1.resolve)(projectRoot, "apps", "local-console", "data"),
594
+ (0, path_1.resolve)(process.cwd(), "data"),
595
+ ...legacyNpxAppRoots.map((root) => (0, path_1.resolve)(root, "apps", "local-console", "data")),
596
+ ].filter((dir, index, list) => list.indexOf(dir) === index && dir !== targetDataDir);
458
597
  const files = [
459
598
  "identity.json",
460
599
  "profile.json",
@@ -464,17 +603,70 @@ function migrateLegacyDataIfNeeded(workspaceRoot, storageRoot) {
464
603
  "social-message-observations.json",
465
604
  ];
466
605
  for (const file of files) {
467
- const src = (0, path_1.resolve)(legacyDataDir, file);
468
606
  const dst = (0, path_1.resolve)(targetDataDir, file);
469
- if (!(0, fs_1.existsSync)(src))
607
+ if (hasMeaningfulJson(dst))
470
608
  continue;
609
+ for (const legacyDataDir of legacyDataDirs) {
610
+ const src = (0, path_1.resolve)(legacyDataDir, file);
611
+ if (!(0, fs_1.existsSync)(src))
612
+ continue;
613
+ if (!hasMeaningfulJson(src))
614
+ continue;
615
+ (0, fs_1.mkdirSync)(targetDataDir, { recursive: true });
616
+ (0, fs_1.copyFileSync)(src, dst);
617
+ break;
618
+ }
619
+ }
620
+ const targetDotDir = (0, path_1.resolve)(storageRoot, ".silicaclaw");
621
+ const legacyDotDirs = [
622
+ (0, path_1.resolve)(appRoot, ".silicaclaw"),
623
+ (0, path_1.resolve)(appRoot, "apps", "local-console", ".silicaclaw"),
624
+ (0, path_1.resolve)(projectRoot, ".silicaclaw"),
625
+ (0, path_1.resolve)(projectRoot, "apps", "local-console", ".silicaclaw"),
626
+ (0, path_1.resolve)(process.cwd(), ".silicaclaw"),
627
+ ...legacyNpxAppRoots.map((root) => (0, path_1.resolve)(root, "apps", "local-console", ".silicaclaw")),
628
+ ].filter((dir, index, list) => list.indexOf(dir) === index && dir !== targetDotDir);
629
+ const dotFiles = ["social.runtime.json", "social.message-governance.json"];
630
+ for (const file of dotFiles) {
631
+ const dst = (0, path_1.resolve)(targetDotDir, file);
471
632
  if (hasMeaningfulJson(dst))
472
633
  continue;
473
- if (!hasMeaningfulJson(src))
634
+ for (const legacyDotDir of legacyDotDirs) {
635
+ const src = (0, path_1.resolve)(legacyDotDir, file);
636
+ if (!(0, fs_1.existsSync)(src))
637
+ continue;
638
+ if (!hasMeaningfulJson(src))
639
+ continue;
640
+ (0, fs_1.mkdirSync)(targetDotDir, { recursive: true });
641
+ (0, fs_1.copyFileSync)(src, dst);
642
+ break;
643
+ }
644
+ }
645
+ }
646
+ function collectLegacyNpxAppRoots(homeDir) {
647
+ const cacheRoots = [
648
+ (0, path_1.resolve)(homeDir, ".silicaclaw", "npm-cache", "_npx"),
649
+ (0, path_1.resolve)(homeDir, ".npm", "_npx"),
650
+ ];
651
+ const roots = [];
652
+ for (const cacheRoot of cacheRoots) {
653
+ if (!(0, fs_1.existsSync)(cacheRoot))
654
+ continue;
655
+ let entries = [];
656
+ try {
657
+ entries = (0, fs_1.readdirSync)(cacheRoot);
658
+ }
659
+ catch {
474
660
  continue;
475
- (0, fs_1.mkdirSync)(targetDataDir, { recursive: true });
476
- (0, fs_1.copyFileSync)(src, dst);
661
+ }
662
+ for (const entry of entries) {
663
+ const candidate = (0, path_1.resolve)(cacheRoot, entry, "node_modules", "@silicaclaw", "cli");
664
+ if (!(0, fs_1.existsSync)((0, path_1.resolve)(candidate, "apps", "local-console")))
665
+ continue;
666
+ roots.push(candidate);
667
+ }
477
668
  }
669
+ return Array.from(new Set(roots));
478
670
  }
479
671
  function parseListEnv(raw) {
480
672
  return raw
@@ -487,6 +679,7 @@ function dedupeStrings(values) {
487
679
  }
488
680
  class LocalNodeService {
489
681
  workspaceRoot;
682
+ projectRoot;
490
683
  storageRoot;
491
684
  identityRepo;
492
685
  profileRepo;
@@ -524,7 +717,7 @@ class LocalNodeService {
524
717
  };
525
718
  network;
526
719
  adapterMode;
527
- networkMode = "global-preview";
720
+ networkMode = DEFAULT_NETWORK_MODE;
528
721
  networkNamespace;
529
722
  networkPort;
530
723
  socialConfig;
@@ -537,16 +730,21 @@ class LocalNodeService {
537
730
  resolvedIdentitySource = "silicaclaw-existing";
538
731
  resolvedOpenClawIdentityPath = null;
539
732
  webrtcSignalingUrls = [];
540
- webrtcRoom = "silicaclaw-global-preview";
733
+ webrtcRoom = DEFAULT_GLOBAL_ROOM;
541
734
  webrtcSeedPeers = [];
542
735
  webrtcBootstrapHints = [];
543
736
  webrtcBootstrapSources = [];
737
+ networkStarted = false;
738
+ networkStartupError = null;
739
+ networkReconnectTimer = null;
740
+ networkReconnectDelayMs = 5_000;
544
741
  appVersion = "unknown";
545
742
  constructor(options) {
546
743
  this.workspaceRoot = options?.workspaceRoot || resolveWorkspaceRoot();
744
+ this.projectRoot = options?.projectRoot || resolveProjectRoot(this.workspaceRoot);
547
745
  this.storageRoot = options?.storageRoot || resolveStorageRoot(this.workspaceRoot);
548
746
  this.appVersion = readWorkspaceVersion(this.workspaceRoot);
549
- migrateLegacyDataIfNeeded(this.workspaceRoot, this.storageRoot);
747
+ migrateLegacyDataIfNeeded(this.workspaceRoot, this.projectRoot, this.storageRoot);
550
748
  this.identityRepo = new storage_1.IdentityRepo(this.storageRoot);
551
749
  this.profileRepo = new storage_1.ProfileRepo(this.storageRoot);
552
750
  this.cacheRepo = new storage_1.CacheRepo(this.storageRoot);
@@ -556,16 +754,16 @@ class LocalNodeService {
556
754
  this.socialMessageObservationRepo = new storage_1.SocialMessageObservationRepo(this.storageRoot);
557
755
  this.socialRuntimeRepo = new storage_1.SocialRuntimeRepo(this.storageRoot);
558
756
  this.messageGovernance = this.defaultMessageGovernance();
559
- let loadedSocial = (0, core_1.loadSocialConfig)(this.workspaceRoot);
757
+ let loadedSocial = (0, core_1.loadSocialConfig)(this.projectRoot);
560
758
  if (!loadedSocial.meta.found) {
561
- (0, core_1.ensureDefaultSocialMd)(this.workspaceRoot, {
759
+ (0, core_1.ensureDefaultSocialMd)(this.projectRoot, {
562
760
  display_name: this.getDefaultDisplayName(),
563
761
  bio: "Local AI agent connected to SilicaClaw",
564
762
  tags: ["openclaw", "local-first"],
565
- mode: "global-preview",
763
+ mode: DEFAULT_NETWORK_MODE,
566
764
  public_enabled: false,
567
765
  });
568
- loadedSocial = (0, core_1.loadSocialConfig)(this.workspaceRoot);
766
+ loadedSocial = (0, core_1.loadSocialConfig)(this.projectRoot);
569
767
  this.initState.social_auto_created = true;
570
768
  }
571
769
  this.socialConfig = loadedSocial.config;
@@ -573,8 +771,8 @@ class LocalNodeService {
573
771
  this.socialFound = loadedSocial.meta.found;
574
772
  this.socialParseError = loadedSocial.meta.parse_error;
575
773
  this.socialRawFrontmatter = loadedSocial.raw_frontmatter;
576
- this.networkNamespace = this.socialConfig.network.namespace || process.env.NETWORK_NAMESPACE || "silicaclaw.preview";
577
- this.networkPort = Number(this.socialConfig.network.port || process.env.NETWORK_PORT || 44123);
774
+ this.networkNamespace = this.socialConfig.network.namespace || process.env.NETWORK_NAMESPACE || DEFAULT_NETWORK_NAMESPACE;
775
+ this.networkPort = Number(this.socialConfig.network.port || process.env.NETWORK_PORT || DEFAULT_NETWORK_PORT);
578
776
  this.applyResolvedNetworkConfig();
579
777
  const resolved = this.buildNetworkAdapter();
580
778
  this.network = resolved.adapter;
@@ -584,24 +782,18 @@ class LocalNodeService {
584
782
  async start() {
585
783
  await this.hydrateFromDisk();
586
784
  this.bindNetworkSubscriptions();
587
- await this.network.start();
588
- await this.log("info", `Local node started (${this.adapterMode}, mode=${this.networkMode}, signaling=${this.webrtcSignalingUrls[0] || "-"}, room=${this.webrtcRoom})`);
589
- if (this.profile?.public_enabled && this.broadcastEnabled) {
590
- try {
591
- await this.broadcastNow("adapter_start");
592
- }
593
- catch (error) {
594
- await this.log("warn", `Initial broadcast failed: ${error instanceof Error ? error.message : String(error)}`);
595
- }
596
- }
597
- this.startBroadcastLoop();
785
+ await this.startNetworkAdapterWithRetry("adapter_start");
598
786
  }
599
787
  async stop() {
788
+ this.clearNetworkReconnectTimer();
600
789
  if (this.broadcaster) {
601
790
  clearInterval(this.broadcaster);
602
791
  this.broadcaster = null;
603
792
  }
604
- await this.network.stop();
793
+ if (this.networkStarted) {
794
+ await this.network.stop();
795
+ }
796
+ this.networkStarted = false;
605
797
  }
606
798
  ensureLocalDirectoryBaseline() {
607
799
  if (this.profile) {
@@ -614,10 +806,8 @@ class LocalNodeService {
614
806
  }
615
807
  }
616
808
  getOverview() {
617
- this.ensureLocalDirectoryBaseline();
618
- this.compactCacheInMemory();
619
- const profiles = Object.values(this.directory.profiles);
620
- const onlineCount = profiles.filter((profile) => (0, core_1.isAgentOnline)(this.directory.presence[profile.agent_id], Date.now(), PRESENCE_TTL_MS)).length;
809
+ const discovered = this.search("");
810
+ const onlineCount = discovered.filter((profile) => profile.online).length;
621
811
  return {
622
812
  app_version: this.appVersion,
623
813
  agent_id: this.identity?.agent_id ?? "",
@@ -627,9 +817,9 @@ class LocalNodeService {
627
817
  last_broadcast_error_at: this.lastBroadcastErrorAt,
628
818
  last_broadcast_error: this.lastBroadcastError,
629
819
  broadcast_failure_count: this.broadcastFailureCount,
630
- discovered_count: profiles.length,
820
+ discovered_count: discovered.length,
631
821
  online_count: onlineCount,
632
- offline_count: Math.max(0, profiles.length - onlineCount),
822
+ offline_count: Math.max(0, discovered.length - onlineCount),
633
823
  init_state: this.initState,
634
824
  presence_ttl_ms: PRESENCE_TTL_MS,
635
825
  onboarding: this.getOnboardingSummary(),
@@ -650,7 +840,9 @@ class LocalNodeService {
650
840
  };
651
841
  }
652
842
  getNetworkSummary() {
653
- const diagnostics = this.getAdapterDiagnostics();
843
+ const network = this.getResolvedRealtimeNetworkSummary();
844
+ const diagnostics = network.diagnostics;
845
+ const relayCapable = this.adapterMode === "webrtc-preview" || this.adapterMode === "relay-preview";
654
846
  const peerCount = diagnostics?.peers.total ?? 0;
655
847
  return {
656
848
  status: "running",
@@ -677,29 +869,33 @@ class LocalNodeService {
677
869
  real_preview_stats: diagnostics?.stats ?? null,
678
870
  real_preview_transport_stats: diagnostics?.transport_stats ?? null,
679
871
  real_preview_discovery_stats: diagnostics?.discovery_stats ?? null,
680
- webrtc_preview: diagnostics && (diagnostics.adapter === "webrtc-preview" || diagnostics.adapter === "relay-preview")
872
+ webrtc_preview: relayCapable
681
873
  ? {
682
- signaling_url: diagnostics.signaling_url ?? null,
683
- signaling_endpoints: diagnostics.signaling_endpoints ?? [],
684
- room: diagnostics.room ?? null,
685
- bootstrap_sources: diagnostics.bootstrap_sources ?? [],
686
- seed_peers_count: diagnostics.seed_peers_count ?? 0,
687
- discovery_events_total: diagnostics.discovery_events_total ?? 0,
688
- last_discovery_event_at: diagnostics.last_discovery_event_at ?? 0,
689
- active_webrtc_peers: diagnostics.active_webrtc_peers ?? 0,
690
- reconnect_attempts_total: diagnostics.reconnect_attempts_total ?? 0,
691
- last_join_at: diagnostics.last_join_at ?? 0,
692
- last_poll_at: diagnostics.last_poll_at ?? 0,
693
- last_publish_at: diagnostics.last_publish_at ?? 0,
694
- last_peer_refresh_at: diagnostics.last_peer_refresh_at ?? 0,
695
- last_error_at: diagnostics.last_error_at ?? 0,
696
- last_error: diagnostics.last_error ?? null,
874
+ started: this.networkStarted,
875
+ startup_error: this.networkStartupError,
876
+ signaling_url: network.signaling_url,
877
+ signaling_endpoints: network.signaling_endpoints,
878
+ room: network.room,
879
+ bootstrap_sources: network.bootstrap_sources,
880
+ seed_peers_count: network.seed_peers_count,
881
+ discovery_events_total: diagnostics?.discovery_events_total ?? 0,
882
+ last_discovery_event_at: diagnostics?.last_discovery_event_at ?? 0,
883
+ active_webrtc_peers: diagnostics?.active_webrtc_peers ?? 0,
884
+ reconnect_attempts_total: diagnostics?.reconnect_attempts_total ?? 0,
885
+ last_join_at: diagnostics?.last_join_at ?? 0,
886
+ last_poll_at: diagnostics?.last_poll_at ?? 0,
887
+ last_publish_at: diagnostics?.last_publish_at ?? 0,
888
+ last_peer_refresh_at: diagnostics?.last_peer_refresh_at ?? 0,
889
+ last_error_at: diagnostics?.last_error_at ?? 0,
890
+ last_error: diagnostics?.last_error ?? null,
697
891
  }
698
892
  : null,
699
893
  };
700
894
  }
701
895
  getNetworkConfig() {
702
- const diagnostics = this.getAdapterDiagnostics();
896
+ const network = this.getResolvedRealtimeNetworkSummary();
897
+ const diagnostics = network.diagnostics;
898
+ const relayCapable = this.adapterMode === "webrtc-preview" || this.adapterMode === "relay-preview";
703
899
  return {
704
900
  adapter: this.adapterMode,
705
901
  mode: this.networkMode,
@@ -713,23 +909,25 @@ class LocalNodeService {
713
909
  },
714
910
  limits: diagnostics?.limits ?? null,
715
911
  adapter_config: diagnostics?.config ?? null,
716
- adapter_extra: diagnostics && (diagnostics.adapter === "webrtc-preview" || diagnostics.adapter === "relay-preview")
912
+ adapter_extra: relayCapable
717
913
  ? {
718
- signaling_url: diagnostics.signaling_url ?? null,
719
- signaling_endpoints: diagnostics.signaling_endpoints ?? [],
720
- room: diagnostics.room ?? null,
721
- bootstrap_sources: diagnostics.bootstrap_sources ?? [],
722
- seed_peers_count: diagnostics.seed_peers_count ?? 0,
723
- discovery_events_total: diagnostics.discovery_events_total ?? 0,
724
- last_discovery_event_at: diagnostics.last_discovery_event_at ?? 0,
725
- connection_states_summary: diagnostics.connection_states_summary ?? null,
726
- datachannel_states_summary: diagnostics.datachannel_states_summary ?? null,
727
- last_join_at: diagnostics.last_join_at ?? 0,
728
- last_poll_at: diagnostics.last_poll_at ?? 0,
729
- last_publish_at: diagnostics.last_publish_at ?? 0,
730
- last_peer_refresh_at: diagnostics.last_peer_refresh_at ?? 0,
731
- last_error_at: diagnostics.last_error_at ?? 0,
732
- last_error: diagnostics.last_error ?? null,
914
+ started: this.networkStarted,
915
+ startup_error: this.networkStartupError,
916
+ signaling_url: network.signaling_url,
917
+ signaling_endpoints: network.signaling_endpoints,
918
+ room: network.room,
919
+ bootstrap_sources: network.bootstrap_sources,
920
+ seed_peers_count: network.seed_peers_count,
921
+ discovery_events_total: diagnostics?.discovery_events_total ?? 0,
922
+ last_discovery_event_at: diagnostics?.last_discovery_event_at ?? 0,
923
+ connection_states_summary: diagnostics?.connection_states_summary ?? null,
924
+ datachannel_states_summary: diagnostics?.datachannel_states_summary ?? null,
925
+ last_join_at: diagnostics?.last_join_at ?? 0,
926
+ last_poll_at: diagnostics?.last_poll_at ?? 0,
927
+ last_publish_at: diagnostics?.last_publish_at ?? 0,
928
+ last_peer_refresh_at: diagnostics?.last_peer_refresh_at ?? 0,
929
+ last_error_at: diagnostics?.last_error_at ?? 0,
930
+ last_error: diagnostics?.last_error ?? null,
733
931
  }
734
932
  : null,
735
933
  env: {
@@ -756,13 +954,15 @@ class LocalNodeService {
756
954
  demo_mode: this.adapterMode === "real-preview"
757
955
  ? "lan-preview"
758
956
  : this.adapterMode === "webrtc-preview" || this.adapterMode === "relay-preview"
759
- ? "internet-preview"
957
+ ? "global-preview"
760
958
  : "local-process",
761
959
  mode_explainer: this.getModeExplainer(),
762
960
  };
763
961
  }
764
962
  getNetworkStats() {
765
- const diagnostics = this.getAdapterDiagnostics();
963
+ const network = this.getResolvedRealtimeNetworkSummary();
964
+ const diagnostics = network.diagnostics;
965
+ const relayCapable = this.adapterMode === "webrtc-preview" || this.adapterMode === "relay-preview";
766
966
  const peers = diagnostics?.peers?.items ?? [];
767
967
  const online = peers.filter((peer) => peer.status === "online").length;
768
968
  return {
@@ -788,33 +988,36 @@ class LocalNodeService {
788
988
  adapter_stats: diagnostics?.stats ?? null,
789
989
  adapter_transport_stats: diagnostics?.transport_stats ?? null,
790
990
  adapter_discovery_stats: diagnostics?.discovery_stats ?? null,
791
- adapter_diagnostics_summary: diagnostics
991
+ adapter_diagnostics_summary: relayCapable || diagnostics
792
992
  ? {
793
- signaling_url: diagnostics.signaling_url ?? null,
794
- signaling_endpoints: diagnostics.signaling_endpoints ?? [],
795
- room: diagnostics.room ?? null,
796
- bootstrap_sources: diagnostics.bootstrap_sources ?? [],
797
- seed_peers_count: diagnostics.seed_peers_count ?? 0,
798
- discovery_events_total: diagnostics.discovery_events_total ?? 0,
799
- last_discovery_event_at: diagnostics.last_discovery_event_at ?? 0,
800
- connection_states_summary: diagnostics.connection_states_summary ?? null,
801
- datachannel_states_summary: diagnostics.datachannel_states_summary ?? null,
802
- signaling_messages_sent_total: diagnostics.signaling_messages_sent_total ?? null,
803
- signaling_messages_received_total: diagnostics.signaling_messages_received_total ?? null,
804
- reconnect_attempts_total: diagnostics.reconnect_attempts_total ?? null,
805
- active_webrtc_peers: diagnostics.active_webrtc_peers ?? null,
806
- last_join_at: diagnostics.last_join_at ?? 0,
807
- last_poll_at: diagnostics.last_poll_at ?? 0,
808
- last_publish_at: diagnostics.last_publish_at ?? 0,
809
- last_peer_refresh_at: diagnostics.last_peer_refresh_at ?? 0,
810
- last_error_at: diagnostics.last_error_at ?? 0,
811
- last_error: diagnostics.last_error ?? null,
993
+ started: this.networkStarted,
994
+ startup_error: this.networkStartupError,
995
+ signaling_url: network.signaling_url,
996
+ signaling_endpoints: network.signaling_endpoints,
997
+ room: network.room,
998
+ bootstrap_sources: network.bootstrap_sources,
999
+ seed_peers_count: network.seed_peers_count,
1000
+ discovery_events_total: diagnostics?.discovery_events_total ?? 0,
1001
+ last_discovery_event_at: diagnostics?.last_discovery_event_at ?? 0,
1002
+ connection_states_summary: diagnostics?.connection_states_summary ?? null,
1003
+ datachannel_states_summary: diagnostics?.datachannel_states_summary ?? null,
1004
+ signaling_messages_sent_total: diagnostics?.signaling_messages_sent_total ?? null,
1005
+ signaling_messages_received_total: diagnostics?.signaling_messages_received_total ?? null,
1006
+ reconnect_attempts_total: diagnostics?.reconnect_attempts_total ?? null,
1007
+ active_webrtc_peers: diagnostics?.active_webrtc_peers ?? null,
1008
+ last_join_at: diagnostics?.last_join_at ?? 0,
1009
+ last_poll_at: diagnostics?.last_poll_at ?? 0,
1010
+ last_publish_at: diagnostics?.last_publish_at ?? 0,
1011
+ last_peer_refresh_at: diagnostics?.last_peer_refresh_at ?? 0,
1012
+ last_error_at: diagnostics?.last_error_at ?? 0,
1013
+ last_error: diagnostics?.last_error ?? null,
812
1014
  }
813
1015
  : null,
814
1016
  };
815
1017
  }
816
1018
  getPeersSummary() {
817
- const diagnostics = this.getAdapterDiagnostics();
1019
+ const network = this.getResolvedRealtimeNetworkSummary();
1020
+ const diagnostics = network.diagnostics;
818
1021
  if (!diagnostics) {
819
1022
  return {
820
1023
  adapter: this.adapterMode,
@@ -837,11 +1040,13 @@ class LocalNodeService {
837
1040
  components: diagnostics.components,
838
1041
  limits: diagnostics.limits,
839
1042
  diagnostics_summary: {
840
- signaling_url: diagnostics.signaling_url ?? null,
841
- signaling_endpoints: diagnostics.signaling_endpoints ?? [],
842
- room: diagnostics.room ?? null,
843
- bootstrap_sources: diagnostics.bootstrap_sources ?? [],
844
- seed_peers_count: diagnostics.seed_peers_count ?? 0,
1043
+ started: this.networkStarted,
1044
+ startup_error: this.networkStartupError,
1045
+ signaling_url: network.signaling_url,
1046
+ signaling_endpoints: network.signaling_endpoints,
1047
+ room: network.room,
1048
+ bootstrap_sources: network.bootstrap_sources,
1049
+ seed_peers_count: network.seed_peers_count,
845
1050
  discovery_events_total: diagnostics.discovery_events_total ?? 0,
846
1051
  last_discovery_event_at: diagnostics.last_discovery_event_at ?? 0,
847
1052
  connection_states_summary: diagnostics.connection_states_summary ?? null,
@@ -885,11 +1090,12 @@ class LocalNodeService {
885
1090
  getRuntimePaths() {
886
1091
  return {
887
1092
  workspace_root: this.workspaceRoot,
1093
+ project_root: this.projectRoot,
888
1094
  storage_root: this.storageRoot,
889
1095
  data_dir: (0, path_1.resolve)(this.storageRoot, "data"),
890
1096
  social_runtime_path: (0, path_1.resolve)(this.storageRoot, ".silicaclaw", "social.runtime.json"),
891
1097
  local_console_public_dir: (0, path_1.resolve)(this.workspaceRoot, "apps", "local-console", "public"),
892
- social_lookup_paths: (0, core_1.getSocialConfigSearchPaths)(this.workspaceRoot),
1098
+ social_lookup_paths: (0, core_1.getSocialConfigSearchPaths)(this.projectRoot),
893
1099
  social_source_path: this.socialSourcePath,
894
1100
  };
895
1101
  }
@@ -925,9 +1131,10 @@ class LocalNodeService {
925
1131
  }
926
1132
  getIntegrationStatus() {
927
1133
  const runtimeGenerated = Boolean(this.socialRuntime && this.socialRuntime.last_loaded_at > 0);
928
- const connected = this.socialFound && runtimeGenerated && !this.socialParseError;
929
- const configured = connected && this.socialConfig.enabled;
930
- const running = configured && this.broadcastEnabled;
1134
+ const runtimeReady = this.socialFound && runtimeGenerated && !this.socialParseError;
1135
+ const connected = runtimeReady && this.networkStarted;
1136
+ const configured = runtimeReady && this.socialConfig.enabled;
1137
+ const running = configured && this.broadcastEnabled && this.networkStarted;
931
1138
  const publicEnabled = Boolean(this.profile?.public_enabled);
932
1139
  const discoveryEnabled = this.socialConfig.discovery.discoverable &&
933
1140
  this.socialConfig.discovery.allow_profile_broadcast &&
@@ -946,9 +1153,13 @@ class LocalNodeService {
946
1153
  ? "running"
947
1154
  : !configured
948
1155
  ? "not configured"
949
- : !this.broadcastEnabled
950
- ? "broadcast paused"
951
- : "not running";
1156
+ : this.networkReconnectTimer
1157
+ ? "reconnecting to relay"
1158
+ : this.networkStartupError
1159
+ ? this.networkStartupError
1160
+ : !this.broadcastEnabled
1161
+ ? "broadcast paused"
1162
+ : "not running";
952
1163
  const discoverableReason = discoverable
953
1164
  ? "discoverable"
954
1165
  : !running
@@ -987,20 +1198,32 @@ class LocalNodeService {
987
1198
  };
988
1199
  }
989
1200
  async setNetworkModeRuntime(mode) {
990
- const currentMode = this.networkMode;
1201
+ const before = {
1202
+ mode: this.networkMode,
1203
+ adapter: this.adapterMode,
1204
+ namespace: this.networkNamespace,
1205
+ port: this.networkPort,
1206
+ };
991
1207
  if (mode !== "local" && mode !== "lan" && mode !== "global-preview") {
992
1208
  throw new Error("invalid_network_mode");
993
1209
  }
994
1210
  this.socialConfig.network.mode = mode;
995
1211
  this.socialConfig.network.adapter = this.adapterForMode(mode);
996
1212
  this.applyResolvedNetworkConfig();
997
- this.socialNetworkRequiresRestart = currentMode !== mode || this.adapterMode !== this.socialConfig.network.adapter;
1213
+ const needsRestart = before.mode !== this.networkMode ||
1214
+ before.adapter !== this.socialConfig.network.adapter ||
1215
+ before.namespace !== this.networkNamespace ||
1216
+ (before.port ?? null) !== (this.networkPort ?? null);
1217
+ if (needsRestart) {
1218
+ await this.restartNetworkAdapter("set_network_mode_runtime");
1219
+ }
1220
+ this.socialNetworkRequiresRestart = false;
998
1221
  await this.writeSocialRuntime();
999
1222
  return {
1000
1223
  mode: this.networkMode,
1001
- adapter: this.socialConfig.network.adapter,
1002
- network_requires_restart: this.socialNetworkRequiresRestart,
1003
- note: "Runtime mode updated. Existing social.md is unchanged.",
1224
+ adapter: this.adapterMode,
1225
+ network_requires_restart: false,
1226
+ note: "Runtime mode updated and adapter restarted. Existing social.md is unchanged.",
1004
1227
  };
1005
1228
  }
1006
1229
  async quickConnectGlobalPreview(options) {
@@ -1013,7 +1236,7 @@ class LocalNodeService {
1013
1236
  this.socialConfig.network.adapter = "relay-preview";
1014
1237
  this.socialConfig.network.signaling_url = signalingUrl;
1015
1238
  this.socialConfig.network.signaling_urls = [signalingUrl];
1016
- this.socialConfig.network.room = room || "silicaclaw-global-preview";
1239
+ this.socialConfig.network.room = room || DEFAULT_GLOBAL_ROOM;
1017
1240
  this.applyResolvedNetworkConfig();
1018
1241
  await this.restartNetworkAdapter("quick_connect_global_preview");
1019
1242
  this.socialNetworkRequiresRestart = false;
@@ -1035,7 +1258,7 @@ class LocalNodeService {
1035
1258
  namespace: this.networkNamespace,
1036
1259
  port: this.networkPort,
1037
1260
  };
1038
- const loaded = (0, core_1.loadSocialConfig)(this.workspaceRoot);
1261
+ const loaded = (0, core_1.loadSocialConfig)(this.projectRoot);
1039
1262
  this.socialConfig = loaded.config;
1040
1263
  this.socialSourcePath = loaded.meta.source_path;
1041
1264
  this.socialFound = loaded.meta.found;
@@ -1054,11 +1277,15 @@ class LocalNodeService {
1054
1277
  before.adapter !== after.adapter ||
1055
1278
  before.namespace !== after.namespace ||
1056
1279
  (before.port ?? null) !== (after.port ?? null);
1280
+ if (this.socialNetworkRequiresRestart) {
1281
+ await this.restartNetworkAdapter("reload_social_config");
1282
+ this.socialNetworkRequiresRestart = false;
1283
+ }
1057
1284
  await this.writeSocialRuntime();
1058
1285
  return this.getSocialConfigView();
1059
1286
  }
1060
1287
  async generateDefaultSocialMd() {
1061
- const result = (0, core_1.ensureDefaultSocialMd)(this.workspaceRoot, {
1288
+ const result = (0, core_1.ensureDefaultSocialMd)(this.projectRoot, {
1062
1289
  display_name: this.getDefaultDisplayName(),
1063
1290
  bio: "Local AI agent connected to SilicaClaw",
1064
1291
  tags: ["openclaw", "local-first"],
@@ -1082,10 +1309,11 @@ class LocalNodeService {
1082
1309
  search(keyword) {
1083
1310
  this.ensureLocalDirectoryBaseline();
1084
1311
  this.compactCacheInMemory();
1085
- return (0, core_1.searchDirectory)(this.directory, keyword, { presenceTTLms: PRESENCE_TTL_MS }).map((profile) => {
1312
+ const directMatches = (0, core_1.searchDirectory)(this.directory, keyword, { presenceTTLms: PRESENCE_TTL_MS }).map((profile) => {
1086
1313
  const lastSeenAt = this.directory.presence[profile.agent_id] ?? 0;
1087
1314
  return this.toPublicProfileSummary(profile, { last_seen_at: lastSeenAt });
1088
1315
  });
1316
+ return this.mergeMessageOnlyAgentSummaries(directMatches, keyword);
1089
1317
  }
1090
1318
  getPublicProfilePreview() {
1091
1319
  if (!this.profile) {
@@ -1147,11 +1375,11 @@ class LocalNodeService {
1147
1375
  }
1148
1376
  getOpenClawBridgeStatus() {
1149
1377
  const integration = this.getIntegrationStatus();
1150
- const openclawInstallation = detectOpenClawInstallation(this.workspaceRoot);
1151
- const openclawRuntime = detectOpenClawRuntime(this.workspaceRoot);
1378
+ const openclawInstallation = detectOpenClawInstallation(this.projectRoot);
1379
+ const openclawRuntime = detectOpenClawRuntime(this.projectRoot);
1152
1380
  const skillInstallation = detectOpenClawSkillInstallation();
1153
1381
  const ownerDelivery = detectOwnerDeliveryStatus({
1154
- workspaceRoot: this.workspaceRoot,
1382
+ workspaceRoot: this.projectRoot,
1155
1383
  connectedToSilicaclaw: integration.connected_to_silicaclaw,
1156
1384
  openclawRunning: openclawRuntime.running,
1157
1385
  skillInstalled: skillInstallation.installed,
@@ -1213,11 +1441,15 @@ class LocalNodeService {
1213
1441
  },
1214
1442
  };
1215
1443
  }
1216
- async installOpenClawSkill() {
1444
+ async installOpenClawSkill(skillName) {
1217
1445
  const scriptPath = (0, path_1.resolve)(this.workspaceRoot, "scripts", "install-openclaw-skill.mjs");
1218
- const { stdout } = await execFileAsync(process.execPath, [scriptPath], {
1446
+ const args = [scriptPath];
1447
+ if (skillName) {
1448
+ args.push(`--skill=${skillName}`);
1449
+ }
1450
+ const { stdout } = await execFileAsync(process.execPath, args, {
1219
1451
  cwd: this.workspaceRoot,
1220
- env: process.env,
1452
+ env: { ...process.env, SILICACLAW_WORKSPACE_DIR: this.projectRoot },
1221
1453
  maxBuffer: 1024 * 1024,
1222
1454
  });
1223
1455
  const parsed = JSON.parse(String(stdout || "{}"));
@@ -1239,11 +1471,11 @@ class LocalNodeService {
1239
1471
  const homeDir = (0, path_1.resolve)(process.env.HOME || "", ".openclaw");
1240
1472
  const workspaceSkillDir = (0, path_1.resolve)(homeDir, "workspace", "skills");
1241
1473
  const legacySkillDir = (0, path_1.resolve)(homeDir, "skills");
1242
- const openclawSourceDir = (0, path_1.resolve)(this.workspaceRoot, "..", "openclaw");
1243
- const openclawRuntime = detectOpenClawRuntime(this.workspaceRoot);
1474
+ const openclawSourceDir = defaultOpenClawSourceDir(this.projectRoot);
1475
+ const openclawRuntime = detectOpenClawRuntime(this.projectRoot);
1244
1476
  return {
1245
- bridge_api_base: "http://localhost:4310",
1246
- openclaw_detected: detectOpenClawInstallation(this.workspaceRoot).detected,
1477
+ bridge_api_base: DEFAULT_BRIDGE_API_BASE,
1478
+ openclaw_detected: detectOpenClawInstallation(this.projectRoot).detected,
1247
1479
  openclaw_running: openclawRuntime.running,
1248
1480
  openclaw_gateway_host: OPENCLAW_GATEWAY_HOST,
1249
1481
  openclaw_gateway_port: openclawRuntime.configured_gateway_port,
@@ -1252,7 +1484,7 @@ class LocalNodeService {
1252
1484
  openclaw_workspace_skill_dir: workspaceSkillDir,
1253
1485
  openclaw_legacy_skill_dir: legacySkillDir,
1254
1486
  silicaclaw_env_template_path: (0, path_1.resolve)(this.workspaceRoot, "openclaw-owner-forward.env.example"),
1255
- recommended_skill_name: "silicaclaw-broadcast",
1487
+ recommended_skill_name: "silicaclaw-bridge-setup",
1256
1488
  recommended_install_command: "silicaclaw openclaw-skill-install",
1257
1489
  recommended_owner_forward_env: {
1258
1490
  OPENCLAW_SOURCE_DIR: openclawSourceDir,
@@ -1270,6 +1502,7 @@ class LocalNodeService {
1270
1502
  ].join(" "),
1271
1503
  notes: [
1272
1504
  "Install and maintain the skill from SilicaClaw; do not edit OpenClaw core source for this integration.",
1505
+ "Use silicaclaw-bridge-setup first when OpenClaw still needs local install, readiness checks, or troubleshooting guidance.",
1273
1506
  "OpenClaw learns broadcasts via the installed skill under ~/.openclaw/workspace/skills/.",
1274
1507
  "Runtime detection prefers the actual OpenClaw gateway listener port, then falls back to OpenClaw's own openclaw.json gateway.port.",
1275
1508
  "Owner delivery runs through OpenClaw's own message channel stack after the skill forwards a summary.",
@@ -1288,6 +1521,12 @@ class LocalNodeService {
1288
1521
  const skillPath = (0, path_1.resolve)(dir.path, "SKILL.md");
1289
1522
  const versionPath = (0, path_1.resolve)(dir.path, "VERSION");
1290
1523
  const manifest = readJsonFileSafe(manifestPath);
1524
+ const references = (manifest?.references && typeof manifest.references === "object")
1525
+ ? manifest.references
1526
+ : null;
1527
+ const ownerDialogueCheatsheetPath = references?.owner_dialogue_cheatsheet_zh
1528
+ ? (0, path_1.resolve)(dir.path, String(references.owner_dialogue_cheatsheet_zh))
1529
+ : null;
1291
1530
  const name = String(manifest?.name || dir.name);
1292
1531
  const capabilities = Array.isArray(manifest?.capabilities)
1293
1532
  ? manifest.capabilities.map((item) => String(item))
@@ -1307,6 +1546,9 @@ class LocalNodeService {
1307
1546
  skill_path: (0, fs_1.existsSync)(skillPath) ? skillPath : null,
1308
1547
  capabilities,
1309
1548
  transport: manifest?.transport || null,
1549
+ owner_dialogue_cheatsheet_path: ownerDialogueCheatsheetPath && (0, fs_1.existsSync)(ownerDialogueCheatsheetPath) ? ownerDialogueCheatsheetPath : null,
1550
+ owner_dialogue_examples_zh: ownerDialogueCheatsheetPath ? readDialogueCheatsheetPreview(ownerDialogueCheatsheetPath) : [],
1551
+ owner_dialogue_sections_zh: ownerDialogueCheatsheetPath ? readDialogueCheatsheetSections(ownerDialogueCheatsheetPath) : [],
1310
1552
  installed_in_openclaw: installedInWorkspace || installedInLegacy,
1311
1553
  install_mode: installedInWorkspace ? "workspace" : installedInLegacy ? "legacy" : "not_installed",
1312
1554
  installed_path: installedInWorkspace ? installedWorkspacePath : installedInLegacy ? installedLegacyPath : null,
@@ -1320,6 +1562,12 @@ class LocalNodeService {
1320
1562
  const skillPath = (0, path_1.resolve)(dir.path, "SKILL.md");
1321
1563
  const versionPath = (0, path_1.resolve)(dir.path, "VERSION");
1322
1564
  const manifest = readJsonFileSafe(manifestPath);
1565
+ const references = (manifest?.references && typeof manifest.references === "object")
1566
+ ? manifest.references
1567
+ : null;
1568
+ const ownerDialogueCheatsheetPath = references?.owner_dialogue_cheatsheet_zh
1569
+ ? (0, path_1.resolve)(dir.path, String(references.owner_dialogue_cheatsheet_zh))
1570
+ : null;
1323
1571
  return {
1324
1572
  key: `${dir.install_mode}:${dir.name}`,
1325
1573
  name: String(manifest?.name || dir.name),
@@ -1331,9 +1579,37 @@ class LocalNodeService {
1331
1579
  manifest_path: (0, fs_1.existsSync)(manifestPath) ? manifestPath : null,
1332
1580
  skill_path: (0, fs_1.existsSync)(skillPath) ? skillPath : null,
1333
1581
  capabilities: Array.isArray(manifest?.capabilities) ? manifest.capabilities.map((item) => String(item)) : [],
1582
+ owner_dialogue_cheatsheet_path: ownerDialogueCheatsheetPath && (0, fs_1.existsSync)(ownerDialogueCheatsheetPath) ? ownerDialogueCheatsheetPath : null,
1583
+ owner_dialogue_examples_zh: ownerDialogueCheatsheetPath ? readDialogueCheatsheetPreview(ownerDialogueCheatsheetPath) : [],
1584
+ owner_dialogue_sections_zh: ownerDialogueCheatsheetPath ? readDialogueCheatsheetSections(ownerDialogueCheatsheetPath) : [],
1334
1585
  bundled_source_path: bundledSkills.find((item) => item.name === String(manifest?.name || dir.name))?.source_path || null,
1335
1586
  };
1336
1587
  });
1588
+ const installedSkillVersions = new Map(installedSkills.map((item) => [item.name, item.version]));
1589
+ const bundledSkillsWithUpdateState = bundledSkills.map((skill) => {
1590
+ const installedVersion = installedSkillVersions.get(skill.name) || "";
1591
+ const updateAvailable = Boolean(skill.installed_in_openclaw &&
1592
+ installedVersion &&
1593
+ skill.version &&
1594
+ compareVersionTokens(installedVersion, skill.version) < 0);
1595
+ return {
1596
+ ...skill,
1597
+ installed_version: installedVersion || null,
1598
+ update_available: updateAvailable,
1599
+ };
1600
+ });
1601
+ const bundledSkillVersions = new Map(bundledSkillsWithUpdateState.map((item) => [item.name, item.version]));
1602
+ const installedSkillsWithUpdateState = installedSkills.map((skill) => {
1603
+ const bundledVersion = bundledSkillVersions.get(skill.name) || "";
1604
+ const updateAvailable = Boolean(bundledVersion &&
1605
+ skill.version &&
1606
+ compareVersionTokens(skill.version, bundledVersion) < 0);
1607
+ return {
1608
+ ...skill,
1609
+ bundled_version: bundledVersion || null,
1610
+ update_available: updateAvailable,
1611
+ };
1612
+ });
1337
1613
  return {
1338
1614
  openclaw: {
1339
1615
  detected: bridge.openclaw_installation.detected,
@@ -1344,13 +1620,14 @@ class LocalNodeService {
1344
1620
  legacy_install_root: legacyInstallRoot,
1345
1621
  },
1346
1622
  summary: {
1347
- bundled_count: bundledSkills.length,
1348
- installed_count: installedSkills.length,
1349
- installed_bundled_count: bundledSkills.filter((item) => item.installed_in_openclaw).length,
1623
+ bundled_count: bundledSkillsWithUpdateState.length,
1624
+ installed_count: installedSkillsWithUpdateState.length,
1625
+ installed_bundled_count: bundledSkillsWithUpdateState.filter((item) => item.installed_in_openclaw).length,
1626
+ update_available_count: bundledSkillsWithUpdateState.filter((item) => item.update_available).length,
1350
1627
  },
1351
1628
  install_action: bridge.skill_learning.install_action,
1352
- bundled_skills: bundledSkills,
1353
- installed_skills: installedSkills,
1629
+ bundled_skills: bundledSkillsWithUpdateState,
1630
+ installed_skills: installedSkillsWithUpdateState,
1354
1631
  };
1355
1632
  }
1356
1633
  getRuntimeMessageGovernance() {
@@ -1569,12 +1846,16 @@ class LocalNodeService {
1569
1846
  };
1570
1847
  const presenceRecord = (0, core_1.signPresence)(this.identity, Date.now());
1571
1848
  const indexRecords = (0, core_1.buildIndexRecords)(this.profile);
1849
+ const replayMessages = this.getReplayableSelfSocialMessages();
1572
1850
  try {
1573
1851
  await this.publish("profile", profileRecord);
1574
1852
  await this.publish("presence", presenceRecord);
1575
1853
  for (const record of indexRecords) {
1576
1854
  await this.publish("index", record);
1577
1855
  }
1856
+ for (const message of replayMessages) {
1857
+ await this.publish(SOCIAL_MESSAGE_TOPIC, message);
1858
+ }
1578
1859
  }
1579
1860
  catch (error) {
1580
1861
  const message = error instanceof Error ? error.message : String(error);
@@ -1595,7 +1876,7 @@ class LocalNodeService {
1595
1876
  }
1596
1877
  this.compactCacheInMemory();
1597
1878
  await this.persistCache();
1598
- await this.log("info", `Broadcast sent (${indexRecords.length} index refs, reason=${reason})`);
1879
+ await this.log("info", `Broadcast sent (${indexRecords.length} index refs, replayed_messages=${replayMessages.length}, reason=${reason})`);
1599
1880
  return { sent: true, reason };
1600
1881
  }
1601
1882
  async hydrateFromDisk() {
@@ -1613,7 +1894,7 @@ class LocalNodeService {
1613
1894
  socialConfig: this.socialConfig,
1614
1895
  existingIdentity,
1615
1896
  generatedIdentity: (0, core_1.createIdentity)(),
1616
- rootDir: this.workspaceRoot,
1897
+ rootDir: this.projectRoot,
1617
1898
  });
1618
1899
  this.identity = resolvedIdentity.identity;
1619
1900
  this.resolvedIdentitySource = resolvedIdentity.source;
@@ -1631,7 +1912,7 @@ class LocalNodeService {
1631
1912
  socialConfig: this.socialConfig,
1632
1913
  agentId: this.identity.agent_id,
1633
1914
  existingProfile: existingProfile && existingProfile.agent_id === this.identity.agent_id ? existingProfile : null,
1634
- rootDir: this.workspaceRoot,
1915
+ rootDir: this.projectRoot,
1635
1916
  });
1636
1917
  this.profile = (0, core_1.signProfile)(profileInput, this.identity);
1637
1918
  if (!existingProfile || existingProfile.agent_id !== this.identity.agent_id) {
@@ -1639,7 +1920,7 @@ class LocalNodeService {
1639
1920
  await this.log("info", "profile.json missing/invalid, initialized from social/default profile");
1640
1921
  }
1641
1922
  await this.profileRepo.set(this.profile);
1642
- this.directory = (0, core_1.dedupeIndex)(await this.cacheRepo.get());
1923
+ this.directory = (0, core_1.createEmptyDirectoryState)();
1643
1924
  this.messageGovernance = {
1644
1925
  ...this.defaultMessageGovernance(),
1645
1926
  ...(await this.socialMessageGovernanceRepo.get()),
@@ -1660,7 +1941,7 @@ class LocalNodeService {
1660
1941
  socialConfig: this.socialConfig,
1661
1942
  agentId: this.identity.agent_id,
1662
1943
  existingProfile: this.profile,
1663
- rootDir: this.workspaceRoot,
1944
+ rootDir: this.projectRoot,
1664
1945
  });
1665
1946
  const nextProfile = (0, core_1.signProfile)(nextProfileInput, this.identity);
1666
1947
  this.profile = nextProfile;
@@ -1765,6 +2046,10 @@ class LocalNodeService {
1765
2046
  await this.log("warn", `Rejected social message with invalid signature (${record.message_id.slice(0, 10)})`);
1766
2047
  return;
1767
2048
  }
2049
+ if (this.hasSocialMessage(record.message_id)) {
2050
+ await this.publishObservationForMessage(record);
2051
+ return;
2052
+ }
1768
2053
  const governanceReason = this.getIncomingSocialMessageRejectionReason(record);
1769
2054
  if (governanceReason) {
1770
2055
  await this.log("warn", `Rejected social message (${record.message_id.slice(0, 10)}): ${governanceReason}`);
@@ -1800,7 +2085,7 @@ class LocalNodeService {
1800
2085
  if (this.broadcaster) {
1801
2086
  clearInterval(this.broadcaster);
1802
2087
  }
1803
- if (!this.broadcastEnabled) {
2088
+ if (!this.broadcastEnabled || !this.networkStarted) {
1804
2089
  return;
1805
2090
  }
1806
2091
  this.broadcaster = setInterval(async () => {
@@ -1912,6 +2197,7 @@ class LocalNodeService {
1912
2197
  };
1913
2198
  }
1914
2199
  async restartNetworkAdapter(reason) {
2200
+ this.clearNetworkReconnectTimer();
1915
2201
  const previous = this.network;
1916
2202
  try {
1917
2203
  await previous.stop();
@@ -1923,13 +2209,52 @@ class LocalNodeService {
1923
2209
  this.network = next.adapter;
1924
2210
  this.adapterMode = next.mode;
1925
2211
  this.networkPort = next.port;
1926
- await this.network.start();
2212
+ this.subscriptionsBound = false;
1927
2213
  this.bindNetworkSubscriptions();
1928
- this.startBroadcastLoop();
1929
- if (this.broadcastEnabled && this.profile?.public_enabled) {
1930
- await this.broadcastNow("adapter_restart");
2214
+ await this.startNetworkAdapterWithRetry(reason);
2215
+ }
2216
+ clearNetworkReconnectTimer() {
2217
+ if (this.networkReconnectTimer) {
2218
+ clearTimeout(this.networkReconnectTimer);
2219
+ this.networkReconnectTimer = null;
2220
+ }
2221
+ }
2222
+ async startNetworkAdapterWithRetry(reason) {
2223
+ this.clearNetworkReconnectTimer();
2224
+ try {
2225
+ await this.network.start();
2226
+ this.networkStarted = true;
2227
+ this.networkStartupError = null;
2228
+ this.networkReconnectDelayMs = 5_000;
2229
+ await this.log("info", `Local node started (${this.adapterMode}, mode=${this.networkMode}, signaling=${this.webrtcSignalingUrls[0] || "-"}, room=${this.webrtcRoom})`);
2230
+ this.startBroadcastLoop();
2231
+ if (this.broadcastEnabled && this.profile?.public_enabled) {
2232
+ try {
2233
+ await this.broadcastNow(reason);
2234
+ }
2235
+ catch (error) {
2236
+ await this.log("warn", `Initial broadcast failed: ${error instanceof Error ? error.message : String(error)}`);
2237
+ }
2238
+ }
2239
+ }
2240
+ catch (error) {
2241
+ this.networkStarted = false;
2242
+ this.networkStartupError = error instanceof Error ? error.message : String(error);
2243
+ await this.log("warn", `Network start failed (${this.adapterMode}, mode=${this.networkMode}): ${this.networkStartupError}`);
2244
+ this.scheduleNetworkReconnect();
1931
2245
  }
1932
2246
  }
2247
+ scheduleNetworkReconnect() {
2248
+ if (this.networkReconnectTimer) {
2249
+ return;
2250
+ }
2251
+ const delayMs = this.networkReconnectDelayMs;
2252
+ this.networkReconnectTimer = setTimeout(() => {
2253
+ this.networkReconnectTimer = null;
2254
+ void this.startNetworkAdapterWithRetry("adapter_reconnect");
2255
+ }, delayMs);
2256
+ this.networkReconnectDelayMs = Math.min(30_000, Math.max(5_000, Math.floor(delayMs * 1.5)));
2257
+ }
1933
2258
  compactCacheInMemory() {
1934
2259
  const cleaned = (0, core_1.cleanupExpiredPresence)(this.directory, Date.now(), PRESENCE_TTL_MS);
1935
2260
  this.directory = (0, core_1.dedupeIndex)(cleaned.state);
@@ -1940,7 +2265,22 @@ class LocalNodeService {
1940
2265
  this.publishedByTopic[topic] = (this.publishedByTopic[topic] ?? 0) + 1;
1941
2266
  }
1942
2267
  async persistCache() {
1943
- await this.cacheRepo.set(this.directory);
2268
+ const persisted = (0, core_1.createEmptyDirectoryState)();
2269
+ if (this.profile) {
2270
+ const selfProfileRecord = {
2271
+ type: "profile",
2272
+ profile: this.profile,
2273
+ };
2274
+ this.directory = (0, core_1.ingestProfileRecord)(this.directory, selfProfileRecord);
2275
+ persisted.profiles[this.profile.agent_id] = this.profile;
2276
+ const selfLastSeenAt = this.directory.presence[this.profile.agent_id];
2277
+ if (typeof selfLastSeenAt === "number" && Number.isFinite(selfLastSeenAt)) {
2278
+ persisted.presence[this.profile.agent_id] = selfLastSeenAt;
2279
+ }
2280
+ const indexed = (0, core_1.rebuildIndexForProfile)(persisted, this.profile);
2281
+ persisted.index = indexed.index;
2282
+ }
2283
+ await this.cacheRepo.set(persisted);
1944
2284
  }
1945
2285
  async persistSocialMessages() {
1946
2286
  await this.socialMessageRepo.set(this.socialMessages);
@@ -1961,6 +2301,18 @@ class LocalNodeService {
1961
2301
  }
1962
2302
  return this.network.getDiagnostics();
1963
2303
  }
2304
+ getResolvedRealtimeNetworkSummary() {
2305
+ const diagnostics = this.getAdapterDiagnostics();
2306
+ const relayCapable = this.adapterMode === "webrtc-preview" || this.adapterMode === "relay-preview";
2307
+ return {
2308
+ diagnostics,
2309
+ signaling_url: diagnostics?.signaling_url ?? (relayCapable ? this.webrtcSignalingUrls[0] ?? null : null),
2310
+ signaling_endpoints: diagnostics?.signaling_endpoints ?? (relayCapable ? this.webrtcSignalingUrls : []),
2311
+ room: diagnostics?.room ?? (relayCapable ? this.webrtcRoom : null),
2312
+ bootstrap_sources: diagnostics?.bootstrap_sources ?? (relayCapable ? this.webrtcBootstrapSources : []),
2313
+ seed_peers_count: diagnostics?.seed_peers_count ?? this.webrtcSeedPeers.length,
2314
+ };
2315
+ }
1964
2316
  toPublicProfileSummary(profile, options) {
1965
2317
  const lastSeenAt = options?.last_seen_at ?? this.directory.presence[profile.agent_id] ?? 0;
1966
2318
  const online = (0, core_1.isAgentOnline)(lastSeenAt, Date.now(), PRESENCE_TTL_MS);
@@ -1996,6 +2348,62 @@ class LocalNodeService {
1996
2348
  presence_ttl_ms: PRESENCE_TTL_MS,
1997
2349
  });
1998
2350
  }
2351
+ mergeMessageOnlyAgentSummaries(summaries, keyword) {
2352
+ const normalizedKeyword = String(keyword || "").trim().toLowerCase();
2353
+ const knownAgentIds = new Set(summaries.map((item) => item.agent_id));
2354
+ const messageOnly = [];
2355
+ for (const message of this.socialMessages) {
2356
+ if (!message?.agent_id || knownAgentIds.has(message.agent_id)) {
2357
+ continue;
2358
+ }
2359
+ const displayName = String(message.display_name || "Unnamed").trim() || "Unnamed";
2360
+ if (normalizedKeyword) {
2361
+ const haystacks = [
2362
+ displayName.toLowerCase(),
2363
+ message.agent_id.toLowerCase(),
2364
+ String(message.topic || "").toLowerCase(),
2365
+ ];
2366
+ if (!haystacks.some((value) => value.includes(normalizedKeyword))) {
2367
+ continue;
2368
+ }
2369
+ }
2370
+ knownAgentIds.add(message.agent_id);
2371
+ messageOnly.push((0, core_1.buildPublicProfileSummary)({
2372
+ profile: {
2373
+ agent_id: message.agent_id,
2374
+ display_name: displayName,
2375
+ bio: "Seen from signed public message. Profile/presence not synced yet.",
2376
+ tags: ["message-only"],
2377
+ avatar_url: "",
2378
+ public_enabled: true,
2379
+ updated_at: message.created_at,
2380
+ signature: "",
2381
+ },
2382
+ online: false,
2383
+ last_seen_at: null,
2384
+ network_mode: "unknown",
2385
+ openclaw_bound: false,
2386
+ profile_version: PROFILE_VERSION,
2387
+ public_key_fingerprint: null,
2388
+ verified_profile: false,
2389
+ now: Date.now(),
2390
+ presence_ttl_ms: PRESENCE_TTL_MS,
2391
+ }));
2392
+ }
2393
+ return [...summaries, ...messageOnly].sort((a, b) => {
2394
+ if (a.online !== b.online) {
2395
+ return a.online ? -1 : 1;
2396
+ }
2397
+ if (a.updated_at !== b.updated_at) {
2398
+ return b.updated_at - a.updated_at;
2399
+ }
2400
+ const byName = a.display_name.localeCompare(b.display_name);
2401
+ if (byName !== 0) {
2402
+ return byName;
2403
+ }
2404
+ return a.agent_id.localeCompare(b.agent_id);
2405
+ });
2406
+ }
1999
2407
  fingerprintPublicKey(publicKey) {
2000
2408
  const digest = (0, crypto_1.createHash)("sha256").update(publicKey, "utf8").digest("hex");
2001
2409
  return `${digest.slice(0, 12)}:${digest.slice(-8)}`;
@@ -2003,6 +2411,22 @@ class LocalNodeService {
2003
2411
  getOnboardingSummary() {
2004
2412
  const summary = this.getIntegrationSummary();
2005
2413
  const publicEnabled = Boolean(this.profile?.public_enabled);
2414
+ const nextSteps = [];
2415
+ if (!String(this.profile?.display_name || "").trim()) {
2416
+ nextSteps.push("Update display name in Profile page");
2417
+ }
2418
+ if (!publicEnabled) {
2419
+ nextSteps.push("Enable Public Enabled in Profile");
2420
+ }
2421
+ if (!summary.running) {
2422
+ nextSteps.push("Start broadcast in Network");
2423
+ }
2424
+ if (!summary.discoverable) {
2425
+ nextSteps.push("Announce node once after the network is running");
2426
+ }
2427
+ if (nextSteps.length === 0) {
2428
+ nextSteps.push("Node is public and discoverable");
2429
+ }
2006
2430
  return {
2007
2431
  first_run: Boolean(this.initState.social_auto_created ||
2008
2432
  this.initState.identity_auto_created ||
@@ -2012,10 +2436,7 @@ class LocalNodeService {
2012
2436
  mode: this.networkMode,
2013
2437
  public_enabled: publicEnabled,
2014
2438
  can_enable_public_discovery: !publicEnabled,
2015
- next_steps: [
2016
- "Update display name in Profile page",
2017
- "Export social.md from Social Config",
2018
- ],
2439
+ next_steps: nextSteps,
2019
2440
  };
2020
2441
  }
2021
2442
  getDefaultDisplayName() {
@@ -2038,7 +2459,7 @@ class LocalNodeService {
2038
2459
  };
2039
2460
  }
2040
2461
  return {
2041
- mode: "global-preview",
2462
+ mode: DEFAULT_NETWORK_MODE,
2042
2463
  short_label: "Relay preview",
2043
2464
  summary: "Uses the public relay preview room so public nodes can find each other across the internet.",
2044
2465
  };
@@ -2066,12 +2487,12 @@ class LocalNodeService {
2066
2487
  const resolvedMode = this.socialConfig.network.mode ||
2067
2488
  (modeEnv === "local" || modeEnv === "lan" || modeEnv === "global-preview"
2068
2489
  ? modeEnv
2069
- : "global-preview");
2490
+ : DEFAULT_NETWORK_MODE);
2070
2491
  this.networkMode = resolvedMode;
2071
- this.networkNamespace = this.socialConfig.network.namespace || process.env.NETWORK_NAMESPACE || "silicaclaw.preview";
2072
- this.networkPort = Number(this.socialConfig.network.port || process.env.NETWORK_PORT || 44123);
2073
- const builtInGlobalSignalingUrls = ["https://relay.silicaclaw.com"];
2074
- const builtInGlobalRoom = "silicaclaw-global-preview";
2492
+ this.networkNamespace = this.socialConfig.network.namespace || process.env.NETWORK_NAMESPACE || DEFAULT_NETWORK_NAMESPACE;
2493
+ this.networkPort = Number(this.socialConfig.network.port || process.env.NETWORK_PORT || DEFAULT_NETWORK_PORT);
2494
+ const builtInGlobalSignalingUrls = [DEFAULT_GLOBAL_SIGNALING_URL];
2495
+ const builtInGlobalRoom = DEFAULT_GLOBAL_ROOM;
2075
2496
  const signalingUrlsSocial = dedupeStrings(this.socialConfig.network.signaling_urls || []);
2076
2497
  const signalingUrlSocial = String(this.socialConfig.network.signaling_url || "").trim();
2077
2498
  const signalingUrlsEnv = dedupeStrings(parseListEnv(WEBRTC_SIGNALING_URLS));
@@ -2099,22 +2520,22 @@ class LocalNodeService {
2099
2520
  signalingSource = "built-in-defaults:global-preview.signaling_urls";
2100
2521
  }
2101
2522
  else {
2102
- signalingUrls = ["https://relay.silicaclaw.com"];
2103
- signalingSource = "default:https://relay.silicaclaw.com";
2523
+ signalingUrls = [DEFAULT_GLOBAL_SIGNALING_URL];
2524
+ signalingSource = `default:${DEFAULT_GLOBAL_SIGNALING_URL}`;
2104
2525
  }
2105
2526
  const roomSocial = String(this.socialConfig.network.room || "").trim();
2106
2527
  const roomEnv = String(WEBRTC_ROOM || "").trim();
2107
2528
  const room = roomSocial ||
2108
2529
  roomEnv ||
2109
2530
  (this.networkMode === "global-preview" ? builtInGlobalRoom : "") ||
2110
- "silicaclaw-global-preview";
2531
+ DEFAULT_GLOBAL_ROOM;
2111
2532
  const roomSource = roomSocial
2112
2533
  ? "social.md:network.room"
2113
2534
  : roomEnv
2114
2535
  ? "env:WEBRTC_ROOM"
2115
2536
  : this.networkMode === "global-preview"
2116
2537
  ? "built-in-defaults:global-preview.room"
2117
- : "default:silicaclaw-global-preview";
2538
+ : `default:${DEFAULT_GLOBAL_ROOM}`;
2118
2539
  const seedPeersSocial = dedupeStrings(this.socialConfig.network.seed_peers || []);
2119
2540
  const seedPeersEnv = dedupeStrings(parseListEnv(WEBRTC_SEED_PEERS));
2120
2541
  const seedPeers = seedPeersSocial.length > 0 ? seedPeersSocial : seedPeersEnv;
@@ -2162,6 +2583,20 @@ class LocalNodeService {
2162
2583
  const normalized = String(body || "").toLowerCase();
2163
2584
  return this.messageGovernance.blocked_terms.some((term) => normalized.includes(term));
2164
2585
  }
2586
+ hasSocialMessage(messageId) {
2587
+ return this.socialMessages.some((item) => item.message_id === messageId);
2588
+ }
2589
+ getReplayableSelfSocialMessages(now = Date.now()) {
2590
+ const maxCount = Math.max(0, SOCIAL_MESSAGE_REPLAY_MAX_PER_BROADCAST);
2591
+ if (!this.identity || maxCount === 0) {
2592
+ return [];
2593
+ }
2594
+ return this.socialMessages
2595
+ .filter((item) => (item.agent_id === this.identity?.agent_id &&
2596
+ now - item.created_at <= SOCIAL_MESSAGE_REPLAY_WINDOW_MS))
2597
+ .sort((a, b) => a.created_at - b.created_at)
2598
+ .slice(-maxCount);
2599
+ }
2165
2600
  hasRecentDuplicateMessage(agentId, body, topic, now = Date.now()) {
2166
2601
  return this.socialMessages.some((item) => (item.agent_id === agentId &&
2167
2602
  item.topic === topic &&
@@ -2441,18 +2876,17 @@ function renderBootstrapScript(payload) {
2441
2876
  if (data.pillBroadcastClassName) pillBroadcast.className = data.pillBroadcastClassName;
2442
2877
  }
2443
2878
  setHtml('overviewCards', data.overviewCardsHtml || '');
2444
- setText('agentsCountHint', data.agentsCountHintText || '0 agents');
2445
- setHtml('agentsWrap', data.agentsWrapHtml || '<div class="label">No discovered agents yet.</div>');
2879
+ setText('agentsCountHint', data.agentsCountHintText || '0 nodes');
2880
+ setHtml('agentsWrap', data.agentsWrapHtml || '<div class="label">No discovered nodes yet.</div>');
2446
2881
  })();
2447
2882
  </script>`;
2448
2883
  }
2449
2884
  async function main() {
2450
2885
  const app = (0, express_1.default)();
2451
- const port = Number(process.env.PORT || 4310);
2886
+ const port = Number(process.env.PORT || silicaclaw_defaults_json_1.default.ports.local_console);
2452
2887
  const staticDir = resolveLocalConsoleStaticDir();
2453
2888
  const staticIndexFile = (0, path_1.resolve)(staticDir, "index.html");
2454
2889
  const node = new LocalNodeService();
2455
- await node.start();
2456
2890
  app.use((0, cors_1.default)({ origin: true }));
2457
2891
  app.use(express_1.default.json());
2458
2892
  app.get("/api/identity", (_req, res) => {
@@ -2591,9 +3025,10 @@ async function main() {
2591
3025
  message: result.sent ? "OpenClaw bridge message published" : `OpenClaw bridge message skipped: ${result.reason}`,
2592
3026
  });
2593
3027
  }));
2594
- app.post("/api/openclaw/bridge/skill-install", asyncRoute(async (_req, res) => {
3028
+ app.post("/api/openclaw/bridge/skill-install", asyncRoute(async (req, res) => {
2595
3029
  try {
2596
- const result = await node.installOpenClawSkill();
3030
+ const skillName = String(req.body?.skill_name || "").trim();
3031
+ const result = await node.installOpenClawSkill(skillName || undefined);
2597
3032
  sendOk(res, result, {
2598
3033
  message: "OpenClaw skill installed",
2599
3034
  });
@@ -2622,7 +3057,7 @@ async function main() {
2622
3057
  const agentId = req.params.agentId;
2623
3058
  const profile = state.profiles[agentId];
2624
3059
  if (!profile) {
2625
- sendError(res, 404, "AGENT_NOT_FOUND", "Agent not found", { agent_id: agentId });
3060
+ sendError(res, 404, "AGENT_NOT_FOUND", "Node not found", { agent_id: agentId });
2626
3061
  return;
2627
3062
  }
2628
3063
  const lastSeenAt = state.presence[agentId] ?? 0;
@@ -2652,7 +3087,7 @@ async function main() {
2652
3087
  .map(([k, v]) => `<div class="card"><div class="label">${escapeHtml(String(k))}</div><div class="value">${escapeHtml(String(v))}</div></div>`)
2653
3088
  .join("");
2654
3089
  const agentsWrapHtml = discovered.length === 0
2655
- ? `<div class="label">No discovered agents yet.</div>`
3090
+ ? `<div class="label">No discovered nodes yet.</div>`
2656
3091
  : `
2657
3092
  <table class="table">
2658
3093
  <thead><tr><th>Name</th><th>Agent ID</th><th>Status</th><th>Updated</th></tr></thead>
@@ -2686,7 +3121,7 @@ async function main() {
2686
3121
  pillBroadcastText: overview.broadcast_enabled ? "broadcast: running" : "broadcast: paused",
2687
3122
  pillBroadcastClassName: `pill ${overview.broadcast_enabled ? "ok" : "warn"}`,
2688
3123
  overviewCardsHtml,
2689
- agentsCountHintText: `${discovered.length} agents discovered`,
3124
+ agentsCountHintText: `${discovered.length} nodes discovered`,
2690
3125
  agentsWrapHtml,
2691
3126
  integrationStatusText: `Connected to SilicaClaw: ${integration.connected_to_silicaclaw ? "yes" : "no"} · Network mode: ${integration.network_mode || "-"} · Public discovery: ${integration.public_enabled ? "enabled" : "disabled"}`,
2692
3127
  integrationStatusClassName: `integration-strip ${integration.connected_to_silicaclaw && integration.public_enabled ? "ok" : "warn"}`,
@@ -2707,6 +3142,7 @@ async function main() {
2707
3142
  // eslint-disable-next-line no-console
2708
3143
  console.log(`SilicaClaw local-console running: http://localhost:${port}`);
2709
3144
  });
3145
+ await node.start();
2710
3146
  process.on("SIGINT", async () => {
2711
3147
  await node.stop();
2712
3148
  process.exit(0);