@silicaclaw/cli 2026.3.19-9 → 2026.3.20-10

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 (331) hide show
  1. package/CHANGELOG.md +182 -0
  2. package/DEMO_GUIDE.md +1 -1
  3. package/INSTALL.md +53 -13
  4. package/README.md +106 -23
  5. package/VERSION +1 -1
  6. package/apps/local-console/dist/apps/local-console/src/server.d.ts +180 -14
  7. package/apps/local-console/dist/apps/local-console/src/server.js +1499 -267
  8. package/apps/local-console/dist/config/silicaclaw-defaults.json +19 -0
  9. package/apps/local-console/dist/packages/core/src/index.d.ts +2 -0
  10. package/apps/local-console/dist/packages/core/src/index.js +2 -0
  11. package/apps/local-console/dist/packages/core/src/privateCrypto.d.ts +17 -0
  12. package/apps/local-console/dist/packages/core/src/privateCrypto.js +40 -0
  13. package/apps/local-console/dist/packages/core/src/privateMessage.d.ts +23 -0
  14. package/apps/local-console/dist/packages/core/src/privateMessage.js +74 -0
  15. package/apps/local-console/dist/packages/core/src/profile.js +2 -0
  16. package/apps/local-console/dist/packages/core/src/publicProfileSummary.d.ts +4 -0
  17. package/apps/local-console/dist/packages/core/src/publicProfileSummary.js +3 -0
  18. package/apps/local-console/dist/packages/core/src/socialConfig.js +9 -5
  19. package/apps/local-console/dist/packages/core/src/types.d.ts +40 -0
  20. package/apps/local-console/dist/packages/network/src/realPreview.js +6 -2
  21. package/apps/local-console/dist/packages/network/src/relayPreview.d.ts +12 -0
  22. package/apps/local-console/dist/packages/network/src/relayPreview.js +116 -10
  23. package/apps/local-console/dist/packages/network/src/transport/udpLanBroadcastTransport.js +2 -1
  24. package/apps/local-console/dist/packages/network/src/types.d.ts +4 -0
  25. package/apps/local-console/dist/packages/network/src/webrtcPreview.js +5 -1
  26. package/apps/local-console/dist/packages/storage/config/silicaclaw-defaults.json +19 -0
  27. package/apps/local-console/dist/packages/storage/src/repos.d.ts +13 -1
  28. package/apps/local-console/dist/packages/storage/src/repos.js +19 -1
  29. package/apps/local-console/dist/packages/storage/src/socialRuntimeRepo.js +8 -4
  30. package/apps/local-console/public/app/app.js +486 -12
  31. package/apps/local-console/public/app/events.js +61 -2
  32. package/apps/local-console/public/app/network.js +176 -35
  33. package/apps/local-console/public/app/overview.js +75 -53
  34. package/apps/local-console/public/app/shell.js +18 -34
  35. package/apps/local-console/public/app/social.js +495 -93
  36. package/apps/local-console/public/app/styles.css +309 -15
  37. package/apps/local-console/public/app/template.js +182 -51
  38. package/apps/local-console/public/app/translations.js +476 -266
  39. package/apps/local-console/src/server.ts +1669 -271
  40. package/apps/public-explorer/dist/apps/public-explorer/src/server.d.ts +1 -0
  41. package/apps/public-explorer/dist/apps/public-explorer/src/server.js +41 -0
  42. package/apps/public-explorer/dist/config/silicaclaw-defaults.json +19 -0
  43. package/apps/public-explorer/public/app/app.js +22 -2
  44. package/apps/public-explorer/public/app/template.js +4 -4
  45. package/apps/public-explorer/public/app/translations.js +29 -29
  46. package/apps/public-explorer/src/server.ts +11 -1
  47. package/config/silicaclaw-defaults.json +19 -0
  48. package/dist/apps/local-console/src/server.d.ts +1 -0
  49. package/dist/apps/local-console/src/server.js +555 -0
  50. package/docs/NEW_USER_INSTALL.md +14 -10
  51. package/docs/NEW_USER_OPERATIONS.md +9 -9
  52. package/docs/OPENCLAW_BRIDGE.md +22 -7
  53. package/docs/OPENCLAW_BRIDGE_ZH.md +21 -6
  54. package/docs/RELEASE_CHECKLIST.md +95 -0
  55. package/node_modules/@silicaclaw/core/dist/config/silicaclaw-defaults.json +19 -0
  56. package/node_modules/@silicaclaw/core/dist/packages/core/src/crypto.d.ts +6 -0
  57. package/node_modules/@silicaclaw/core/dist/packages/core/src/crypto.js +50 -0
  58. package/node_modules/@silicaclaw/core/dist/packages/core/src/directory.d.ts +17 -0
  59. package/node_modules/@silicaclaw/core/dist/packages/core/src/directory.js +145 -0
  60. package/node_modules/@silicaclaw/core/dist/packages/core/src/identity.d.ts +2 -0
  61. package/node_modules/@silicaclaw/core/dist/packages/core/src/identity.js +18 -0
  62. package/node_modules/@silicaclaw/core/dist/packages/core/src/index.d.ts +14 -0
  63. package/node_modules/@silicaclaw/core/dist/packages/core/src/index.js +30 -0
  64. package/node_modules/@silicaclaw/core/dist/packages/core/src/indexing.d.ts +6 -0
  65. package/node_modules/@silicaclaw/core/dist/packages/core/src/indexing.js +43 -0
  66. package/node_modules/@silicaclaw/core/dist/packages/core/src/presence.d.ts +4 -0
  67. package/node_modules/@silicaclaw/core/dist/packages/core/src/presence.js +23 -0
  68. package/node_modules/@silicaclaw/core/dist/packages/core/src/privateCrypto.d.ts +17 -0
  69. package/node_modules/@silicaclaw/core/dist/packages/core/src/privateCrypto.js +40 -0
  70. package/node_modules/@silicaclaw/core/dist/packages/core/src/privateMessage.d.ts +23 -0
  71. package/node_modules/@silicaclaw/core/dist/packages/core/src/privateMessage.js +74 -0
  72. package/node_modules/@silicaclaw/core/dist/packages/core/src/profile.d.ts +4 -0
  73. package/node_modules/@silicaclaw/core/dist/packages/core/src/profile.js +41 -0
  74. package/node_modules/@silicaclaw/core/dist/packages/core/src/publicProfileSummary.d.ts +74 -0
  75. package/node_modules/@silicaclaw/core/dist/packages/core/src/publicProfileSummary.js +106 -0
  76. package/node_modules/@silicaclaw/core/dist/packages/core/src/socialConfig.d.ts +100 -0
  77. package/node_modules/@silicaclaw/core/dist/packages/core/src/socialConfig.js +300 -0
  78. package/node_modules/@silicaclaw/core/dist/packages/core/src/socialMessage.d.ts +19 -0
  79. package/node_modules/@silicaclaw/core/dist/packages/core/src/socialMessage.js +69 -0
  80. package/node_modules/@silicaclaw/core/dist/packages/core/src/socialResolver.d.ts +46 -0
  81. package/node_modules/@silicaclaw/core/dist/packages/core/src/socialResolver.js +237 -0
  82. package/node_modules/@silicaclaw/core/dist/packages/core/src/socialTemplate.d.ts +2 -0
  83. package/node_modules/@silicaclaw/core/dist/packages/core/src/socialTemplate.js +90 -0
  84. package/node_modules/@silicaclaw/core/dist/packages/core/src/types.d.ts +99 -0
  85. package/node_modules/@silicaclaw/core/dist/packages/core/src/types.js +2 -0
  86. package/node_modules/@silicaclaw/core/src/index.ts +2 -0
  87. package/node_modules/@silicaclaw/core/src/privateCrypto.ts +57 -0
  88. package/node_modules/@silicaclaw/core/src/privateMessage.ts +101 -0
  89. package/node_modules/@silicaclaw/core/src/profile.ts +2 -0
  90. package/node_modules/@silicaclaw/core/src/publicProfileSummary.ts +7 -0
  91. package/node_modules/@silicaclaw/core/src/socialConfig.ts +7 -5
  92. package/node_modules/@silicaclaw/core/src/types.ts +44 -0
  93. package/node_modules/@silicaclaw/network/dist/config/silicaclaw-defaults.json +19 -0
  94. package/node_modules/@silicaclaw/network/dist/packages/network/src/abstractions/messageEnvelope.d.ts +28 -0
  95. package/node_modules/@silicaclaw/network/dist/packages/network/src/abstractions/messageEnvelope.js +36 -0
  96. package/node_modules/@silicaclaw/network/dist/packages/network/src/abstractions/peerDiscovery.d.ts +43 -0
  97. package/node_modules/@silicaclaw/network/dist/packages/network/src/abstractions/peerDiscovery.js +2 -0
  98. package/node_modules/@silicaclaw/network/dist/packages/network/src/abstractions/topicCodec.d.ts +4 -0
  99. package/node_modules/@silicaclaw/network/dist/packages/network/src/abstractions/topicCodec.js +2 -0
  100. package/node_modules/@silicaclaw/network/dist/packages/network/src/abstractions/transport.d.ts +36 -0
  101. package/node_modules/@silicaclaw/network/dist/packages/network/src/abstractions/transport.js +2 -0
  102. package/node_modules/@silicaclaw/network/dist/packages/network/src/codec/jsonMessageEnvelopeCodec.d.ts +5 -0
  103. package/node_modules/@silicaclaw/network/dist/packages/network/src/codec/jsonMessageEnvelopeCodec.js +24 -0
  104. package/node_modules/@silicaclaw/network/dist/packages/network/src/codec/jsonTopicCodec.d.ts +5 -0
  105. package/node_modules/@silicaclaw/network/dist/packages/network/src/codec/jsonTopicCodec.js +12 -0
  106. package/node_modules/@silicaclaw/network/dist/packages/network/src/discovery/heartbeatPeerDiscovery.d.ts +28 -0
  107. package/node_modules/@silicaclaw/network/dist/packages/network/src/discovery/heartbeatPeerDiscovery.js +144 -0
  108. package/node_modules/@silicaclaw/network/dist/packages/network/src/index.d.ts +14 -0
  109. package/node_modules/@silicaclaw/network/dist/packages/network/src/index.js +30 -0
  110. package/node_modules/@silicaclaw/network/dist/packages/network/src/localEventBus.d.ts +9 -0
  111. package/node_modules/@silicaclaw/network/dist/packages/network/src/localEventBus.js +47 -0
  112. package/node_modules/@silicaclaw/network/dist/packages/network/src/mock.d.ts +8 -0
  113. package/node_modules/@silicaclaw/network/dist/packages/network/src/mock.js +24 -0
  114. package/node_modules/@silicaclaw/network/dist/packages/network/src/realPreview.d.ts +105 -0
  115. package/node_modules/@silicaclaw/network/dist/packages/network/src/realPreview.js +331 -0
  116. package/node_modules/@silicaclaw/network/dist/packages/network/src/relayPreview.d.ts +178 -0
  117. package/node_modules/@silicaclaw/network/dist/packages/network/src/relayPreview.js +548 -0
  118. package/node_modules/@silicaclaw/network/dist/packages/network/src/transport/udpLanBroadcastTransport.d.ts +23 -0
  119. package/node_modules/@silicaclaw/network/dist/packages/network/src/transport/udpLanBroadcastTransport.js +154 -0
  120. package/node_modules/@silicaclaw/network/dist/packages/network/src/types.d.ts +10 -0
  121. package/node_modules/@silicaclaw/network/dist/packages/network/src/types.js +2 -0
  122. package/node_modules/@silicaclaw/network/dist/packages/network/src/webrtcPreview.d.ts +163 -0
  123. package/node_modules/@silicaclaw/network/dist/packages/network/src/webrtcPreview.js +848 -0
  124. package/node_modules/@silicaclaw/network/src/realPreview.ts +3 -2
  125. package/node_modules/@silicaclaw/network/src/relayPreview.ts +125 -12
  126. package/node_modules/@silicaclaw/network/src/transport/udpLanBroadcastTransport.ts +2 -1
  127. package/node_modules/@silicaclaw/network/src/types.ts +2 -0
  128. package/node_modules/@silicaclaw/network/src/webrtcPreview.ts +2 -1
  129. package/node_modules/@silicaclaw/storage/config/silicaclaw-defaults.json +19 -0
  130. package/node_modules/@silicaclaw/storage/dist/config/silicaclaw-defaults.json +19 -0
  131. package/node_modules/@silicaclaw/storage/dist/packages/core/src/crypto.d.ts +6 -0
  132. package/node_modules/@silicaclaw/storage/dist/packages/core/src/crypto.js +50 -0
  133. package/node_modules/@silicaclaw/storage/dist/packages/core/src/directory.d.ts +17 -0
  134. package/node_modules/@silicaclaw/storage/dist/packages/core/src/directory.js +145 -0
  135. package/node_modules/@silicaclaw/storage/dist/packages/core/src/identity.d.ts +2 -0
  136. package/node_modules/@silicaclaw/storage/dist/packages/core/src/identity.js +18 -0
  137. package/node_modules/@silicaclaw/storage/dist/packages/core/src/index.d.ts +14 -0
  138. package/node_modules/@silicaclaw/storage/dist/packages/core/src/index.js +30 -0
  139. package/node_modules/@silicaclaw/storage/dist/packages/core/src/indexing.d.ts +6 -0
  140. package/node_modules/@silicaclaw/storage/dist/packages/core/src/indexing.js +43 -0
  141. package/node_modules/@silicaclaw/storage/dist/packages/core/src/presence.d.ts +4 -0
  142. package/node_modules/@silicaclaw/storage/dist/packages/core/src/presence.js +23 -0
  143. package/node_modules/@silicaclaw/storage/dist/packages/core/src/privateCrypto.d.ts +17 -0
  144. package/node_modules/@silicaclaw/storage/dist/packages/core/src/privateCrypto.js +40 -0
  145. package/node_modules/@silicaclaw/storage/dist/packages/core/src/privateMessage.d.ts +23 -0
  146. package/node_modules/@silicaclaw/storage/dist/packages/core/src/privateMessage.js +74 -0
  147. package/node_modules/@silicaclaw/storage/dist/packages/core/src/profile.d.ts +4 -0
  148. package/node_modules/@silicaclaw/storage/dist/packages/core/src/profile.js +41 -0
  149. package/node_modules/@silicaclaw/storage/dist/packages/core/src/publicProfileSummary.d.ts +74 -0
  150. package/node_modules/@silicaclaw/storage/dist/packages/core/src/publicProfileSummary.js +106 -0
  151. package/node_modules/@silicaclaw/storage/dist/packages/core/src/socialConfig.d.ts +100 -0
  152. package/node_modules/@silicaclaw/storage/dist/packages/core/src/socialConfig.js +300 -0
  153. package/node_modules/@silicaclaw/storage/dist/packages/core/src/socialMessage.d.ts +19 -0
  154. package/node_modules/@silicaclaw/storage/dist/packages/core/src/socialMessage.js +69 -0
  155. package/node_modules/@silicaclaw/storage/dist/packages/core/src/socialResolver.d.ts +46 -0
  156. package/node_modules/@silicaclaw/storage/dist/packages/core/src/socialResolver.js +237 -0
  157. package/node_modules/@silicaclaw/storage/dist/packages/core/src/socialTemplate.d.ts +2 -0
  158. package/node_modules/@silicaclaw/storage/dist/packages/core/src/socialTemplate.js +90 -0
  159. package/node_modules/@silicaclaw/storage/dist/packages/core/src/types.d.ts +99 -0
  160. package/node_modules/@silicaclaw/storage/dist/packages/core/src/types.js +2 -0
  161. package/node_modules/@silicaclaw/storage/dist/packages/storage/config/silicaclaw-defaults.json +19 -0
  162. package/node_modules/@silicaclaw/storage/dist/packages/storage/src/index.d.ts +3 -0
  163. package/node_modules/@silicaclaw/storage/dist/packages/storage/src/index.js +19 -0
  164. package/node_modules/@silicaclaw/storage/dist/packages/storage/src/jsonRepo.d.ts +7 -0
  165. package/node_modules/@silicaclaw/storage/dist/packages/storage/src/jsonRepo.js +29 -0
  166. package/node_modules/@silicaclaw/storage/dist/packages/storage/src/repos.d.ts +73 -0
  167. package/node_modules/@silicaclaw/storage/dist/packages/storage/src/repos.js +85 -0
  168. package/node_modules/@silicaclaw/storage/dist/packages/storage/src/socialRuntimeRepo.d.ts +5 -0
  169. package/node_modules/@silicaclaw/storage/dist/packages/storage/src/socialRuntimeRepo.js +57 -0
  170. package/node_modules/@silicaclaw/storage/dist/socialRuntimeRepo.js +8 -4
  171. package/node_modules/@silicaclaw/storage/src/repos.ts +31 -1
  172. package/node_modules/@silicaclaw/storage/src/socialRuntimeRepo.ts +5 -4
  173. package/node_modules/@silicaclaw/storage/tsconfig.json +1 -6
  174. package/openclaw-skills/silicaclaw-bridge-setup/SKILL.md +165 -0
  175. package/openclaw-skills/silicaclaw-bridge-setup/VERSION +1 -0
  176. package/openclaw-skills/silicaclaw-bridge-setup/agents/openai.yaml +6 -0
  177. package/openclaw-skills/silicaclaw-bridge-setup/manifest.json +27 -0
  178. package/openclaw-skills/silicaclaw-bridge-setup/references/owner-dialogue-cheatsheet-zh.md +58 -0
  179. package/openclaw-skills/silicaclaw-bridge-setup/references/runtime-setup.md +43 -0
  180. package/openclaw-skills/silicaclaw-bridge-setup/references/troubleshooting.md +24 -0
  181. package/openclaw-skills/silicaclaw-broadcast/SKILL.md +150 -0
  182. package/openclaw-skills/silicaclaw-broadcast/VERSION +1 -1
  183. package/openclaw-skills/silicaclaw-broadcast/agents/openai.yaml +2 -2
  184. package/openclaw-skills/silicaclaw-broadcast/manifest.json +4 -3
  185. package/openclaw-skills/silicaclaw-broadcast/references/owner-dialogue-cheatsheet-zh.md +81 -0
  186. package/openclaw-skills/silicaclaw-network-config/SKILL.md +158 -0
  187. package/openclaw-skills/silicaclaw-network-config/VERSION +1 -0
  188. package/openclaw-skills/silicaclaw-network-config/agents/openai.yaml +6 -0
  189. package/openclaw-skills/silicaclaw-network-config/manifest.json +27 -0
  190. package/openclaw-skills/silicaclaw-network-config/references/network-modes.md +22 -0
  191. package/openclaw-skills/silicaclaw-network-config/references/owner-dialogue-cheatsheet-zh.md +47 -0
  192. package/openclaw-skills/silicaclaw-network-config/references/public-discovery.md +22 -0
  193. package/openclaw-skills/silicaclaw-owner-push/SKILL.md +235 -0
  194. package/openclaw-skills/silicaclaw-owner-push/VERSION +1 -0
  195. package/openclaw-skills/silicaclaw-owner-push/agents/openai.yaml +6 -0
  196. package/openclaw-skills/silicaclaw-owner-push/manifest.json +30 -0
  197. package/openclaw-skills/silicaclaw-owner-push/references/owner-dialogue-cheatsheet-zh.md +87 -0
  198. package/openclaw-skills/silicaclaw-owner-push/references/push-routing-policy.md +43 -0
  199. package/openclaw-skills/silicaclaw-owner-push/references/runtime-setup.md +44 -0
  200. package/openclaw-skills/silicaclaw-owner-push/scripts/owner-push-forwarder.mjs +356 -0
  201. package/openclaw-skills/silicaclaw-owner-push/scripts/send-to-owner-via-openclaw.mjs +69 -0
  202. package/package.json +5 -1
  203. package/packages/core/dist/config/silicaclaw-defaults.json +19 -0
  204. package/packages/core/dist/packages/core/src/crypto.d.ts +6 -0
  205. package/packages/core/dist/packages/core/src/crypto.js +50 -0
  206. package/packages/core/dist/packages/core/src/directory.d.ts +17 -0
  207. package/packages/core/dist/packages/core/src/directory.js +145 -0
  208. package/packages/core/dist/packages/core/src/identity.d.ts +2 -0
  209. package/packages/core/dist/packages/core/src/identity.js +18 -0
  210. package/packages/core/dist/packages/core/src/index.d.ts +14 -0
  211. package/packages/core/dist/packages/core/src/index.js +30 -0
  212. package/packages/core/dist/packages/core/src/indexing.d.ts +6 -0
  213. package/packages/core/dist/packages/core/src/indexing.js +43 -0
  214. package/packages/core/dist/packages/core/src/presence.d.ts +4 -0
  215. package/packages/core/dist/packages/core/src/presence.js +23 -0
  216. package/packages/core/dist/packages/core/src/privateCrypto.d.ts +17 -0
  217. package/packages/core/dist/packages/core/src/privateCrypto.js +40 -0
  218. package/packages/core/dist/packages/core/src/privateMessage.d.ts +23 -0
  219. package/packages/core/dist/packages/core/src/privateMessage.js +74 -0
  220. package/packages/core/dist/packages/core/src/profile.d.ts +4 -0
  221. package/packages/core/dist/packages/core/src/profile.js +41 -0
  222. package/packages/core/dist/packages/core/src/publicProfileSummary.d.ts +74 -0
  223. package/packages/core/dist/packages/core/src/publicProfileSummary.js +106 -0
  224. package/packages/core/dist/packages/core/src/socialConfig.d.ts +100 -0
  225. package/packages/core/dist/packages/core/src/socialConfig.js +300 -0
  226. package/packages/core/dist/packages/core/src/socialMessage.d.ts +19 -0
  227. package/packages/core/dist/packages/core/src/socialMessage.js +69 -0
  228. package/packages/core/dist/packages/core/src/socialResolver.d.ts +46 -0
  229. package/packages/core/dist/packages/core/src/socialResolver.js +237 -0
  230. package/packages/core/dist/packages/core/src/socialTemplate.d.ts +2 -0
  231. package/packages/core/dist/packages/core/src/socialTemplate.js +90 -0
  232. package/packages/core/dist/packages/core/src/types.d.ts +99 -0
  233. package/packages/core/dist/packages/core/src/types.js +2 -0
  234. package/packages/core/src/index.ts +2 -0
  235. package/packages/core/src/privateCrypto.ts +57 -0
  236. package/packages/core/src/privateMessage.ts +101 -0
  237. package/packages/core/src/profile.ts +2 -0
  238. package/packages/core/src/publicProfileSummary.ts +7 -0
  239. package/packages/core/src/socialConfig.ts +7 -5
  240. package/packages/core/src/types.ts +44 -0
  241. package/packages/network/dist/config/silicaclaw-defaults.json +19 -0
  242. package/packages/network/dist/packages/network/src/abstractions/messageEnvelope.d.ts +28 -0
  243. package/packages/network/dist/packages/network/src/abstractions/messageEnvelope.js +36 -0
  244. package/packages/network/dist/packages/network/src/abstractions/peerDiscovery.d.ts +43 -0
  245. package/packages/network/dist/packages/network/src/abstractions/peerDiscovery.js +2 -0
  246. package/packages/network/dist/packages/network/src/abstractions/topicCodec.d.ts +4 -0
  247. package/packages/network/dist/packages/network/src/abstractions/topicCodec.js +2 -0
  248. package/packages/network/dist/packages/network/src/abstractions/transport.d.ts +36 -0
  249. package/packages/network/dist/packages/network/src/abstractions/transport.js +2 -0
  250. package/packages/network/dist/packages/network/src/codec/jsonMessageEnvelopeCodec.d.ts +5 -0
  251. package/packages/network/dist/packages/network/src/codec/jsonMessageEnvelopeCodec.js +24 -0
  252. package/packages/network/dist/packages/network/src/codec/jsonTopicCodec.d.ts +5 -0
  253. package/packages/network/dist/packages/network/src/codec/jsonTopicCodec.js +12 -0
  254. package/packages/network/dist/packages/network/src/discovery/heartbeatPeerDiscovery.d.ts +28 -0
  255. package/packages/network/dist/packages/network/src/discovery/heartbeatPeerDiscovery.js +144 -0
  256. package/packages/network/dist/packages/network/src/index.d.ts +14 -0
  257. package/packages/network/dist/packages/network/src/index.js +30 -0
  258. package/packages/network/dist/packages/network/src/localEventBus.d.ts +9 -0
  259. package/packages/network/dist/packages/network/src/localEventBus.js +47 -0
  260. package/packages/network/dist/packages/network/src/mock.d.ts +8 -0
  261. package/packages/network/dist/packages/network/src/mock.js +24 -0
  262. package/packages/network/dist/packages/network/src/realPreview.d.ts +105 -0
  263. package/packages/network/dist/packages/network/src/realPreview.js +331 -0
  264. package/packages/network/dist/packages/network/src/relayPreview.d.ts +178 -0
  265. package/packages/network/dist/packages/network/src/relayPreview.js +548 -0
  266. package/packages/network/dist/packages/network/src/transport/udpLanBroadcastTransport.d.ts +23 -0
  267. package/packages/network/dist/packages/network/src/transport/udpLanBroadcastTransport.js +154 -0
  268. package/packages/network/dist/packages/network/src/types.d.ts +10 -0
  269. package/packages/network/dist/packages/network/src/types.js +2 -0
  270. package/packages/network/dist/packages/network/src/webrtcPreview.d.ts +163 -0
  271. package/packages/network/dist/packages/network/src/webrtcPreview.js +848 -0
  272. package/packages/network/src/realPreview.ts +3 -2
  273. package/packages/network/src/relayPreview.ts +125 -12
  274. package/packages/network/src/transport/udpLanBroadcastTransport.ts +2 -1
  275. package/packages/network/src/types.ts +2 -0
  276. package/packages/network/src/webrtcPreview.ts +2 -1
  277. package/packages/storage/config/silicaclaw-defaults.json +19 -0
  278. package/packages/storage/dist/config/silicaclaw-defaults.json +19 -0
  279. package/packages/storage/dist/packages/core/src/crypto.d.ts +6 -0
  280. package/packages/storage/dist/packages/core/src/crypto.js +50 -0
  281. package/packages/storage/dist/packages/core/src/directory.d.ts +17 -0
  282. package/packages/storage/dist/packages/core/src/directory.js +145 -0
  283. package/packages/storage/dist/packages/core/src/identity.d.ts +2 -0
  284. package/packages/storage/dist/packages/core/src/identity.js +18 -0
  285. package/packages/storage/dist/packages/core/src/index.d.ts +14 -0
  286. package/packages/storage/dist/packages/core/src/index.js +30 -0
  287. package/packages/storage/dist/packages/core/src/indexing.d.ts +6 -0
  288. package/packages/storage/dist/packages/core/src/indexing.js +43 -0
  289. package/packages/storage/dist/packages/core/src/presence.d.ts +4 -0
  290. package/packages/storage/dist/packages/core/src/presence.js +23 -0
  291. package/packages/storage/dist/packages/core/src/privateCrypto.d.ts +17 -0
  292. package/packages/storage/dist/packages/core/src/privateCrypto.js +40 -0
  293. package/packages/storage/dist/packages/core/src/privateMessage.d.ts +23 -0
  294. package/packages/storage/dist/packages/core/src/privateMessage.js +74 -0
  295. package/packages/storage/dist/packages/core/src/profile.d.ts +4 -0
  296. package/packages/storage/dist/packages/core/src/profile.js +41 -0
  297. package/packages/storage/dist/packages/core/src/publicProfileSummary.d.ts +74 -0
  298. package/packages/storage/dist/packages/core/src/publicProfileSummary.js +106 -0
  299. package/packages/storage/dist/packages/core/src/socialConfig.d.ts +100 -0
  300. package/packages/storage/dist/packages/core/src/socialConfig.js +300 -0
  301. package/packages/storage/dist/packages/core/src/socialMessage.d.ts +19 -0
  302. package/packages/storage/dist/packages/core/src/socialMessage.js +69 -0
  303. package/packages/storage/dist/packages/core/src/socialResolver.d.ts +46 -0
  304. package/packages/storage/dist/packages/core/src/socialResolver.js +237 -0
  305. package/packages/storage/dist/packages/core/src/socialTemplate.d.ts +2 -0
  306. package/packages/storage/dist/packages/core/src/socialTemplate.js +90 -0
  307. package/packages/storage/dist/packages/core/src/types.d.ts +99 -0
  308. package/packages/storage/dist/packages/core/src/types.js +2 -0
  309. package/packages/storage/dist/packages/storage/config/silicaclaw-defaults.json +19 -0
  310. package/packages/storage/dist/packages/storage/src/index.d.ts +3 -0
  311. package/packages/storage/dist/packages/storage/src/index.js +19 -0
  312. package/packages/storage/dist/packages/storage/src/jsonRepo.d.ts +7 -0
  313. package/packages/storage/dist/packages/storage/src/jsonRepo.js +29 -0
  314. package/packages/storage/dist/packages/storage/src/repos.d.ts +73 -0
  315. package/packages/storage/dist/packages/storage/src/repos.js +85 -0
  316. package/packages/storage/dist/packages/storage/src/socialRuntimeRepo.d.ts +5 -0
  317. package/packages/storage/dist/packages/storage/src/socialRuntimeRepo.js +57 -0
  318. package/packages/storage/dist/socialRuntimeRepo.js +8 -4
  319. package/packages/storage/src/repos.ts +31 -1
  320. package/packages/storage/src/socialRuntimeRepo.ts +5 -4
  321. package/packages/storage/tsconfig.json +1 -6
  322. package/scripts/functional-check.mjs +35 -6
  323. package/scripts/install-openclaw-skill.mjs +9 -2
  324. package/scripts/openclaw-bridge-adapter.mjs +3 -1
  325. package/scripts/openclaw-bridge-client.mjs +3 -1
  326. package/scripts/openclaw-runtime-demo.mjs +3 -1
  327. package/scripts/quickstart.sh +14 -10
  328. package/scripts/release-pack.mjs +59 -1
  329. package/scripts/silicaclaw-cli.mjs +166 -51
  330. package/scripts/silicaclaw-gateway.mjs +410 -84
  331. package/scripts/validate-openclaw-skill.mjs +98 -21
@@ -24,6 +24,134 @@ export function createSocialController({
24
24
  toPrettyJson,
25
25
  writeUiCache,
26
26
  }) {
27
+ const SKILLS_SECTION_LIMIT = 4;
28
+ const SKILLS_DIALOGUE_LIMIT = 1;
29
+ let lastMessagesRenderKey = "";
30
+ let lastLogsRenderKey = "";
31
+ const sectionRenderCache = new Map();
32
+ let skillsQuery = "";
33
+ let skillsFilter = "all";
34
+ const skillsExpanded = {
35
+ bundled: false,
36
+ installed: false,
37
+ dialogue: false,
38
+ };
39
+
40
+ function skillModeLabel(mode) {
41
+ if (mode === "workspace") return t("labels.skillsModeWorkspace");
42
+ if (mode === "legacy") return t("labels.skillsModeLegacy");
43
+ if (mode === "bundled") return t("labels.skillsModeBundled");
44
+ if (mode === "installed") return t("labels.skillsModeInstalled");
45
+ return mode ? String(mode) : t("labels.skillsModeGeneric");
46
+ }
47
+
48
+ function normalizeSkillSearchText(value) {
49
+ return String(value || "").trim().toLowerCase();
50
+ }
51
+
52
+ function setSkillsQuery(value) {
53
+ skillsQuery = normalizeSkillSearchText(value);
54
+ }
55
+
56
+ function setSkillsFilter(value) {
57
+ const next = String(value || "").trim();
58
+ skillsFilter = ["all", "attention", "updates", "installed"].includes(next) ? next : "all";
59
+ }
60
+
61
+ function toggleSkillsExpanded(section) {
62
+ if (!(section in skillsExpanded)) return;
63
+ skillsExpanded[section] = !skillsExpanded[section];
64
+ }
65
+
66
+ function skillMatchesSearch(skill) {
67
+ if (!skillsQuery) return true;
68
+ const haystack = [
69
+ skill.display_name,
70
+ skill.name,
71
+ skill.description,
72
+ skill.version,
73
+ ...(Array.isArray(skill.capabilities) ? skill.capabilities : []),
74
+ ...(Array.isArray(skill.owner_dialogue_examples_zh) ? skill.owner_dialogue_examples_zh : []),
75
+ ].map((item) => normalizeSkillSearchText(item)).join(" ");
76
+ return haystack.includes(skillsQuery);
77
+ }
78
+
79
+ function skillMatchesFilter(skill, section) {
80
+ if (skillsFilter === "all") return true;
81
+ if (skillsFilter === "updates") return Boolean(skill.update_available);
82
+ if (skillsFilter === "installed") {
83
+ return section === "installed" ? true : Boolean(skill.installed_in_openclaw);
84
+ }
85
+ if (skillsFilter === "attention") {
86
+ return section === "installed"
87
+ ? Boolean(skill.update_available)
88
+ : Boolean(skill.update_available || !skill.installed_in_openclaw);
89
+ }
90
+ return true;
91
+ }
92
+
93
+ function renderSkillsSectionFooter({ footerId, section, totalCount, visibleCount, limit }) {
94
+ const footer = document.getElementById(footerId);
95
+ if (!footer) return;
96
+ if (totalCount <= limit) {
97
+ footer.innerHTML = "";
98
+ return;
99
+ }
100
+ const expanded = skillsExpanded[section];
101
+ const hiddenCount = Math.max(totalCount - visibleCount, 0);
102
+ footer.innerHTML = `
103
+ <button class="secondary skills-section__toggle" type="button" data-skills-toggle="${section}">
104
+ ${expanded ? t("actions.showLess") : t("actions.showMoreCount", { count: String(hiddenCount) })}
105
+ </button>
106
+ `;
107
+ }
108
+
109
+ function renderFilteredSkillCards({ skills, section, gridId, footerId, renderer, limit }) {
110
+ const filtered = skills.filter((skill) => skillMatchesSearch(skill) && skillMatchesFilter(skill, section));
111
+ const expanded = skillsExpanded[section];
112
+ const visible = expanded ? filtered : filtered.slice(0, limit);
113
+ document.getElementById(gridId).innerHTML = visible.length
114
+ ? visible.map((skill) => renderer(skill)).join("")
115
+ : `<div class="skills-empty">${t("hints.skillsNoFilterMatch")}</div>`;
116
+ renderSkillsSectionFooter({
117
+ footerId,
118
+ section,
119
+ totalCount: filtered.length,
120
+ visibleCount: visible.length,
121
+ limit,
122
+ });
123
+ return filtered.length;
124
+ }
125
+
126
+ function renderSkillsFilterMeta({ bundledCount, installedCount, dialogueCount }) {
127
+ const matchedTotal = bundledCount + installedCount + dialogueCount;
128
+ const filterLabel = t(`labels.skillsFilter${skillsFilter.charAt(0).toUpperCase()}${skillsFilter.slice(1)}`);
129
+ document.getElementById("skillsFilterMeta").textContent = t("hints.skillsFilterMeta", {
130
+ count: String(matchedTotal),
131
+ filter: filterLabel,
132
+ });
133
+ document.querySelectorAll("[data-skills-filter]").forEach((btn) => {
134
+ btn.classList.toggle("active", btn.getAttribute("data-skills-filter") === skillsFilter);
135
+ });
136
+ }
137
+
138
+ function setCachedContent(id, value, mode = "html") {
139
+ const cacheKey = `${mode}:${id}`;
140
+ if (sectionRenderCache.get(cacheKey) === value) {
141
+ return;
142
+ }
143
+ const el = document.getElementById(id);
144
+ if (!el) return;
145
+ if (mode === "text") {
146
+ el.textContent = value;
147
+ } else if (mode === "class") {
148
+ el.className = value;
149
+ } else {
150
+ el.innerHTML = value;
151
+ }
152
+ sectionRenderCache.set(cacheKey, value);
153
+ }
154
+
27
155
  function renderSocialMessages() {
28
156
  const listEl = document.getElementById("socialMessageList");
29
157
  const metaEl = document.getElementById("socialMessageMeta");
@@ -37,10 +165,16 @@ export function createSocialController({
37
165
  seconds: String(Math.floor((governance.send_limit?.window_ms || 60000) / 1000)),
38
166
  })}`
39
167
  : t("overview.messageHint");
40
- hintEl.textContent = governanceHint;
41
168
  if (!socialMessagesCache.length) {
42
- metaEl.textContent = t("overview.noMessagesMeta");
43
- listEl.innerHTML = `<div class="empty-state">${t("overview.noMessagesEmpty")}</div>`;
169
+ const nextMeta = t("overview.noMessagesMeta");
170
+ const nextHtml = `<div class="empty-state">${t("overview.noMessagesEmpty")}</div>`;
171
+ const renderKey = JSON.stringify({ hint: governanceHint, meta: nextMeta, html: nextHtml });
172
+ if (renderKey !== lastMessagesRenderKey) {
173
+ hintEl.textContent = governanceHint;
174
+ metaEl.textContent = nextMeta;
175
+ listEl.innerHTML = nextHtml;
176
+ lastMessagesRenderKey = renderKey;
177
+ }
44
178
  return;
45
179
  }
46
180
 
@@ -59,15 +193,28 @@ export function createSocialController({
59
193
  seconds: String(Math.floor((governance.send_limit?.window_ms || 60000) / 1000)),
60
194
  })}`
61
195
  : "";
62
- metaEl.textContent = `${baseMeta}${governanceMeta}`;
196
+ const nextMeta = `${baseMeta}${governanceMeta}`;
63
197
 
64
198
  if (!filteredMessages.length) {
65
- listEl.innerHTML = `<div class="empty-state">${t("overview.noMessagesEmpty")}</div>`;
199
+ const nextHtml = `<div class="empty-state">${t("overview.noMessagesEmpty")}</div>`;
200
+ const renderKey = JSON.stringify({ hint: governanceHint, meta: nextMeta, html: nextHtml });
201
+ if (renderKey !== lastMessagesRenderKey) {
202
+ hintEl.textContent = governanceHint;
203
+ metaEl.textContent = nextMeta;
204
+ listEl.innerHTML = nextHtml;
205
+ lastMessagesRenderKey = renderKey;
206
+ }
66
207
  return;
67
208
  }
68
209
 
69
- listEl.innerHTML = filteredMessages
210
+ const nextHtml = filteredMessages
70
211
  .map((item) => {
212
+ const visibleRemoteCount = getVisibleRemotePublicCount();
213
+ const avatarUrl = String(item.avatar_url || "").trim();
214
+ const displayName = String(item.display_name || t("overview.unnamed")).trim() || t("overview.unnamed");
215
+ const avatar = avatarUrl
216
+ ? `<img class="agent-card__avatar" src="${escapeHtml(avatarUrl)}" alt="${escapeHtml(displayName)}" loading="lazy" />`
217
+ : `<div class="agent-card__avatar-fallback">${escapeHtml((displayName[0] || "?").toUpperCase())}</div>`;
71
218
  const selfStatusChips = item.is_self
72
219
  ? `
73
220
  <span class="tag-chip" style="margin-left:8px;">${t("overview.selfMessagePublished")}</span>
@@ -77,7 +224,21 @@ export function createSocialController({
77
224
  ? t("overview.selfMessageRemoteObserved", { count: String(item.remote_observation_count) })
78
225
  : t("overview.selfMessageAwaitingObservation")
79
226
  }</span>
80
- <span class="tag-chip" style="margin-left:8px;">${t("overview.selfMessageRemoteVisible", { count: String(getVisibleRemotePublicCount()) })}</span>
227
+ <span class="tag-chip" style="margin-left:8px;">${t("overview.selfMessageRemoteVisible", { count: String(visibleRemoteCount) })}</span>
228
+ `
229
+ : "";
230
+ const selfDeliveryHint = item.is_self
231
+ ? `
232
+ <div style="margin-top:8px; color:#90a2c3;">
233
+ ${
234
+ item.remote_observation_count > 0
235
+ ? t("overview.selfMessageDeliveryObserved", {
236
+ count: String(item.remote_observation_count),
237
+ visible: String(visibleRemoteCount),
238
+ })
239
+ : t("overview.selfMessageDeliveryPending", { count: String(visibleRemoteCount) })
240
+ }
241
+ </div>
81
242
  `
82
243
  : "";
83
244
  const observationChip = item.remote_observation_count > 0
@@ -86,22 +247,45 @@ export function createSocialController({
86
247
  return `
87
248
  <div class="log-item">
88
249
  <div style="display:flex; align-items:center; justify-content:space-between; gap:12px;">
89
- <div>
90
- <strong>${escapeHtml(item.display_name || t("overview.unnamed"))}</strong>
91
- <span class="mono" style="color:#90a2c3; margin-left:8px;">${escapeHtml(shortId(item.agent_id || ""))}</span>
92
- <span class="tag-chip" style="margin-left:8px;">${escapeHtml(item.topic || t("labels.globalTopic"))}</span>
93
- ${item.is_self ? `<span class="tag-chip" style="margin-left:8px;">${t("overview.messageFilterSelf")}</span>` : ""}
94
- <span class="tag-chip" style="margin-left:8px;">${item.online ? t("overview.online") : t("overview.offline")}</span>
95
- ${observationChip}
96
- ${selfStatusChips}
250
+ <div style="display:flex; align-items:flex-start; gap:10px; min-width:0;">
251
+ ${avatar}
252
+ <div style="min-width:0;">
253
+ <strong>${escapeHtml(displayName)}</strong>
254
+ <span class="mono" style="color:#90a2c3; margin-left:8px;">${escapeHtml(shortId(item.agent_id || ""))}</span>
255
+ <span class="tag-chip" style="margin-left:8px;">${escapeHtml(item.topic || t("labels.globalTopic"))}</span>
256
+ ${item.is_self ? `<span class="tag-chip" style="margin-left:8px;">${t("overview.messageFilterSelf")}</span>` : ""}
257
+ <span class="tag-chip" style="margin-left:8px;">${item.online ? t("overview.online") : t("overview.offline")}</span>
258
+ ${observationChip}
259
+ ${selfStatusChips}
260
+ </div>
97
261
  </div>
98
262
  <div class="mono" style="color:#90a2c3;">${new Date(item.created_at).toLocaleString()}</div>
99
263
  </div>
100
264
  <div style="margin-top:8px; line-height:1.6;">${formatMessageBody(item.body || "")}</div>
265
+ ${selfDeliveryHint}
101
266
  </div>
102
267
  `;
103
268
  })
104
269
  .join("");
270
+ const renderKey = JSON.stringify({
271
+ hint: governanceHint,
272
+ meta: nextMeta,
273
+ filter: socialMessageFilter,
274
+ messages: filteredMessages.map((item) => [
275
+ item.message_id,
276
+ item.updated_at || item.created_at,
277
+ item.remote_observation_count || 0,
278
+ item.online ? 1 : 0,
279
+ ]),
280
+ visibleRemoteCount: getVisibleRemotePublicCount(),
281
+ });
282
+ if (renderKey === lastMessagesRenderKey) {
283
+ return;
284
+ }
285
+ hintEl.textContent = governanceHint;
286
+ metaEl.textContent = nextMeta;
287
+ listEl.innerHTML = nextHtml;
288
+ lastMessagesRenderKey = renderKey;
105
289
  }
106
290
 
107
291
  async function refreshMessages() {
@@ -112,11 +296,12 @@ export function createSocialController({
112
296
  }
113
297
 
114
298
  async function refreshSocial() {
115
- const [socialRes, summaryRes, statusRes, networkCfgRes, governanceRes] = await Promise.all([
299
+ const [socialRes, summaryRes, statusRes, networkCfgRes, networkStatsRes, governanceRes] = await Promise.all([
116
300
  api("/api/social/config"),
117
301
  api("/api/social/integration-summary"),
118
302
  api("/api/integration/status"),
119
303
  api("/api/network/config"),
304
+ api("/api/network/stats"),
120
305
  api("/api/social/message-governance"),
121
306
  ]);
122
307
  const bridgeRes = await api("/api/openclaw/bridge");
@@ -126,6 +311,7 @@ export function createSocialController({
126
311
  const networkCfg = networkCfgRes.data || {};
127
312
  const bridge = bridgeRes.data || {};
128
313
  const governance = governanceRes.data || {};
314
+ const networkStats = networkStatsRes.data || {};
129
315
  const runtime = social.runtime || {};
130
316
  const config = social.social_config || {};
131
317
  const network = config.network || {};
@@ -137,25 +323,36 @@ export function createSocialController({
137
323
  const effectiveNamespace = networkCfg.namespace || runtimeNetwork.namespace || summary.current_namespace || "-";
138
324
  const effectiveRoom = effectiveAdapterExtra.room || runtimeNetwork.room || network.room || "-";
139
325
  const effectiveRelay = effectiveAdapterExtra.signaling_url || runtimeNetwork.signaling_url || network.signaling_url || "-";
326
+ const networkDiag = networkStats.adapter_diagnostics_summary || {};
140
327
  const discoverable = status.discoverable === true;
141
328
  const mode = effectiveMode;
142
329
  const summaryLine = status.status_line || summary.summary_line || `${summary.connected ? t("social.connectedToSilicaClaw") : t("social.notConnectedToSilicaClaw")} · ${discoverable ? t("social.discoverableInCurrentMode") : t("social.notDiscoverableInCurrentMode")} · ${t("social.usingMode", { mode })}`;
143
330
  const publicDiscoveryText = status.public_enabled ? t("social.publicDiscoveryEnabled") : t("social.publicDiscoveryDisabled");
144
331
 
145
332
  const namespaceText = `${status.connected_to_silicaclaw ? t("social.connectedToSilicaClaw") : t("social.notConnected")} · ${publicDiscoveryText} · ${t("social.mode")} ${mode}`;
146
- document.getElementById("socialStatusLine").textContent = summaryLine;
147
- document.getElementById("socialStatusSubline").textContent = namespaceText;
333
+ setCachedContent("socialStatusLine", summaryLine, "text");
334
+ setCachedContent("socialStatusSubline", namespaceText, "text");
148
335
  const bar = document.getElementById("integrationStatusBar");
149
- bar.className = `integration-strip ${status.connected_to_silicaclaw && status.public_enabled ? "ok" : "warn"}${getActiveTab() === "overview" ? "" : " hidden"}`;
150
- bar.textContent = t("social.barStatus", {
336
+ const barClassName = `integration-strip ${status.connected_to_silicaclaw && status.public_enabled ? "ok" : "warn"}${getActiveTab() === "overview" ? "" : " hidden"}`;
337
+ const barText = t("social.barStatus", {
151
338
  connected: status.connected_to_silicaclaw ? t("common.yes") : t("common.no"),
152
339
  mode,
153
340
  public: status.public_enabled ? t("common.on") : t("common.off"),
154
341
  });
155
- document.getElementById("brandStatusDot").className = `sidebar-version__status ${status.connected_to_silicaclaw ? "ok" : "warn"}`;
342
+ if (bar.className !== barClassName) {
343
+ bar.className = barClassName;
344
+ }
345
+ if (bar.textContent !== barText) {
346
+ bar.textContent = barText;
347
+ }
348
+ const brandStatusDot = document.getElementById("brandStatusDot");
349
+ const brandStatusClassName = `sidebar-version__status ${status.connected_to_silicaclaw ? "ok" : "warn"}`;
350
+ if (brandStatusDot.className !== brandStatusClassName) {
351
+ brandStatusDot.className = brandStatusClassName;
352
+ }
156
353
  writeUiCache("silicaclaw_ui_social", {
157
- integrationStatusText: bar.textContent,
158
- integrationStatusClassName: bar.className,
354
+ integrationStatusText: barText,
355
+ integrationStatusClassName: barClassName,
159
356
  socialStatusLineText: summaryLine,
160
357
  socialStatusSublineText: namespaceText,
161
358
  });
@@ -163,14 +360,14 @@ export function createSocialController({
163
360
  if (!status.configured && status.configured_reason) reasons.push(t("social.configuredReason", { reason: status.configured_reason }));
164
361
  if (!status.running && status.running_reason) reasons.push(t("social.runningReason", { reason: status.running_reason }));
165
362
  if (!status.discoverable && status.discoverable_reason) reasons.push(t("social.discoverableReasonFull", { reason: status.discoverable_reason }));
166
- document.getElementById("socialStateHint").textContent = reasons.length ? reasons.join(" · ") : t("hints.allIntegrationChecksPassed");
363
+ setCachedContent("socialStateHint", reasons.length ? reasons.join(" · ") : t("hints.allIntegrationChecksPassed"), "text");
167
364
  const modeSelect = document.getElementById("socialModeSelect");
168
365
  const displayedSelectedMode = getSocialModeDirty() && getSocialModePending() ? getSocialModePending() : selectedMode;
169
366
  if (modeSelect && displayedSelectedMode !== "-") modeSelect.value = displayedSelectedMode;
170
367
  renderSocialModeHint(displayedSelectedMode, mode, !!social.network_requires_restart, getSocialModeDirty());
171
368
  setSocialModePendingState(getSocialModeDirty());
172
369
 
173
- document.getElementById("socialPrimaryCards").innerHTML = [
370
+ setCachedContent("socialPrimaryCards", [
174
371
  [t("social.configured"), status.configured ? t("common.yes") : t("common.no")],
175
372
  [t("social.running"), status.running ? t("common.yes") : t("common.no")],
176
373
  [t("social.discoverable"), discoverable ? t("common.yes") : t("common.no")],
@@ -178,9 +375,9 @@ export function createSocialController({
178
375
  [t("social.networkMode"), mode],
179
376
  [t("labels.adapter"), effectiveAdapter],
180
377
  [t("social.discoverableReason"), status.discoverable_reason || "-"],
181
- ].map(([k, v]) => `<div class="card"><div class="label">${k}</div><div class="value" style="font-size:17px;">${v}</div></div>`).join("");
378
+ ].map(([k, v]) => `<div class="card"><div class="label">${k}</div><div class="value" style="font-size:17px;">${v}</div></div>`).join(""));
182
379
 
183
- document.getElementById("socialIntegrationCards").innerHTML = [
380
+ setCachedContent("socialIntegrationCards", [
184
381
  [t("social.connected"), bridge.connected_to_silicaclaw ? t("common.yes") : t("common.no")],
185
382
  [t("social.messageBroadcast"), bridge.message_broadcast_enabled ? t("common.on") : t("common.off")],
186
383
  [t("social.displayName"), status.display_name || t("overview.unnamed")],
@@ -188,7 +385,18 @@ export function createSocialController({
188
385
  [t("social.socialFound"), summary.social_md_found ? t("common.yes") : t("common.no")],
189
386
  [t("social.socialSource"), summary.social_md_source_path || "-"],
190
387
  [t("social.reuseOpenClawIdentity"), summary.reused_openclaw_identity ? t("common.yes") : t("common.no")],
191
- ].map(([k, v]) => `<div class="card"><div class="label">${k}</div><div class="value" style="font-size:17px;">${v}</div></div>`).join("");
388
+ ].map(([k, v]) => `<div class="card"><div class="label">${k}</div><div class="value" style="font-size:17px;">${v}</div></div>`).join(""));
389
+
390
+ setCachedContent("socialMessagePathCards", [
391
+ [t("social.messageBroadcast"), bridge.message_broadcast_enabled ? t("common.on") : t("common.off")],
392
+ [t("social.publicDiscovery"), status.public_enabled ? t("common.on") : t("common.off")],
393
+ [t("social.namespace"), effectiveNamespace],
394
+ [t("labels.room"), effectiveRoom],
395
+ [t("labels.relay"), effectiveRelay],
396
+ [t("network.lastPoll"), networkDiag.last_poll_at ? new Date(networkDiag.last_poll_at).toLocaleTimeString() : "-"],
397
+ [t("network.lastPublish"), networkDiag.last_publish_at ? new Date(networkDiag.last_publish_at).toLocaleTimeString() : "-"],
398
+ [t("network.lastError"), networkDiag.last_error || t("network.none")],
399
+ ].map(([k, v]) => `<div class="card"><div class="label">${k}</div><div class="value" style="font-size:17px;">${escapeHtml(String(v))}</div></div>`).join(""));
192
400
 
193
401
  const skillLearning = bridge.skill_learning || {};
194
402
  const ownerDelivery = bridge.owner_delivery || {};
@@ -216,15 +424,21 @@ export function createSocialController({
216
424
  ownerDeliveryHeadline = t("feedback.openclawRoleNotRunning");
217
425
  ownerDeliveryBody = ownerDelivery.reason || "-";
218
426
  }
219
- document.getElementById("socialOwnerDeliveryStatus").className = `feedback ${ownerDeliveryTone}`;
220
- document.getElementById("socialOwnerDeliveryStatus").textContent = ownerDeliveryHeadline;
221
- document.getElementById("socialOwnerDeliverySubline").textContent = [
427
+ setCachedContent("socialOwnerDeliveryStatus", `feedback ${ownerDeliveryTone}`, "class");
428
+ setCachedContent("socialOwnerDeliveryStatus", ownerDeliveryHeadline, "text");
429
+ setCachedContent("socialOwnerDeliverySubline", [
222
430
  `${t("social.broadcastReadable")}: ${ownerDelivery.bridge_messages_readable ? t("common.yes") : t("common.no")}`,
223
431
  `${t("social.ownerForwardCommand")}: ${ownerDelivery.forward_command_configured ? t("common.yes") : t("common.no")}`,
224
432
  `${t("social.ownerForwardReady")}: ${ownerDelivery.ready ? t("common.yes") : t("common.no")}`,
225
- ].join(" · ");
226
- document.getElementById("socialOwnerDeliveryReason").textContent = ownerDeliveryBody;
227
- document.getElementById("openclawSkillCards").innerHTML = [
433
+ ].join(" · "), "text");
434
+ setCachedContent("socialOwnerDeliveryReason", ownerDeliveryBody, "text");
435
+ setCachedContent("socialCapabilityCards", [
436
+ [t("socialCapability.publicBroadcast"), bridge.message_broadcast_enabled ? t("common.yes") : t("common.no")],
437
+ [t("socialCapability.monitorBroadcasts"), ownerDelivery.bridge_messages_readable ? t("common.yes") : t("common.no")],
438
+ [t("socialCapability.autoPushToOwner"), ownerDelivery.ready ? t("common.yes") : t("common.no")],
439
+ [t("socialCapability.ownerPrivateBoundary"), t("socialCapability.ownerPrivateBoundaryValue")],
440
+ ].map(([k, v]) => `<div class="card"><div class="label">${escapeHtml(String(k))}</div><div class="value" style="font-size:17px;">${escapeHtml(String(v))}</div></div>`).join(""));
441
+ setCachedContent("openclawSkillCards", [
228
442
  [t("social.openclawInstalled"), openclawDetected ? t("common.yes") : t("common.no")],
229
443
  [t("social.running"), openclawRunning ? t("common.yes") : t("common.no")],
230
444
  [t("social.skillInstalled"), skillInstalled ? t("common.yes") : t("common.no")],
@@ -232,16 +446,17 @@ export function createSocialController({
232
446
  [t("social.ownerForwardReady"), ownerDelivery.ready ? t("common.yes") : t("common.no")],
233
447
  [t("social.ownerForwardCommand"), ownerDelivery.forward_command_configured ? t("common.yes") : t("common.no")],
234
448
  [t("social.openclawDetectionMode"), bridge.openclaw_runtime?.detection_mode || "-"],
449
+ ["Gateway probe", bridge.openclaw_runtime?.gateway_probe_ok ? t("common.yes") : t("common.no")],
235
450
  [t("social.openclawGateway"), bridge.openclaw_runtime?.gateway_url || "-"],
236
451
  [t("social.installMode"), skillLearning.install_mode || "-"],
237
452
  [t("social.installedPath"), skillInstalled ? installedSkillPath : "-"],
238
- ].map(([k, v]) => `<div class="card"><div class="label">${k}</div><div class="value" style="font-size:17px;">${escapeHtml(v)}</div></div>`).join("");
239
- document.getElementById("openclawSkillPath").textContent = ownerDelivery.forward_command
453
+ ].map(([k, v]) => `<div class="card"><div class="label">${k}</div><div class="value" style="font-size:17px;">${escapeHtml(v)}</div></div>`).join(""));
454
+ setCachedContent("openclawSkillPath", ownerDelivery.forward_command
240
455
  ? `${ownerDelivery.forward_command}${ownerDelivery.owner_channel ? ` · ${ownerDelivery.owner_channel}` : ""}${ownerDelivery.owner_target ? ` · ${ownerDelivery.owner_target}` : ""}`
241
456
  : skillInstalled
242
457
  ? installedSkillPath
243
- : `${installAction.recommended_command || "-"}${bridge.openclaw_runtime?.gateway_url ? ` · detect ${bridge.openclaw_runtime.gateway_url}` : ""}`;
244
- document.getElementById("openclawSkillHint").textContent = !openclawDetected
458
+ : `${installAction.recommended_command || "-"}${bridge.openclaw_runtime?.gateway_url ? ` · detect ${bridge.openclaw_runtime.gateway_url}` : ""}`, "text");
459
+ setCachedContent("openclawSkillHint", !openclawDetected
245
460
  ? t("feedback.openclawRoleBroadcasterOnly")
246
461
  : !openclawRunning
247
462
  ? t("feedback.openclawRoleNotRunning")
@@ -249,11 +464,11 @@ export function createSocialController({
249
464
  ? t("feedback.openclawRoleReadyToLearn")
250
465
  : ownerDelivery.ready
251
466
  ? t("feedback.openclawRoleOwnerReady")
252
- : ownerDelivery.bridge_messages_readable && !ownerDelivery.forward_command_configured
253
- ? t("feedback.openclawRoleLearningOnly")
254
- : ownerDelivery.bridge_messages_readable
255
- ? t("feedback.openclawRoleNeedsOwnerRoute")
256
- : t("feedback.openclawRoleLearned");
467
+ : ownerDelivery.bridge_messages_readable && !ownerDelivery.forward_command_configured
468
+ ? t("feedback.openclawRoleLearningOnly")
469
+ : ownerDelivery.bridge_messages_readable
470
+ ? t("feedback.openclawRoleNeedsOwnerRoute")
471
+ : t("feedback.openclawRoleLearned"), "text");
257
472
  const skillInstallBtn = document.getElementById("openclawSkillInstallBtn");
258
473
  skillInstallBtn.textContent = !openclawDetected
259
474
  ? t("actions.openclawNotInstalled")
@@ -274,33 +489,33 @@ export function createSocialController({
274
489
  document.getElementById("governanceDuplicateWindowInput").value = String(Math.floor((policy.duplicate_window_ms ?? 180000) / 1000));
275
490
  document.getElementById("governanceBlockedAgentsInput").value = blockedAgentIds.join(", ");
276
491
  document.getElementById("governanceBlockedTermsInput").value = blockedTerms.join(", ");
277
- document.getElementById("socialGovernanceCards").innerHTML = [
492
+ setCachedContent("socialGovernanceCards", [
278
493
  [t("labels.sendLimit"), `${policy.send_limit?.max ?? "-"} / ${Math.floor((policy.send_limit?.window_ms ?? 60000) / 1000)}s`],
279
494
  [t("labels.receiveLimit"), `${policy.receive_limit?.max ?? "-"} / ${Math.floor((policy.receive_limit?.window_ms ?? 60000) / 1000)}s`],
280
495
  [t("labels.duplicateWindowSeconds"), `${Math.floor((policy.duplicate_window_ms ?? 0) / 1000)}s`],
281
496
  [t("labels.blockedAgentIds"), blockedAgentIds.length],
282
497
  [t("labels.blockedTerms"), blockedTerms.length],
283
- ].map(([k, v]) => `<div class="card"><div class="label">${k}</div><div class="value" style="font-size:17px;">${v}</div></div>`).join("");
498
+ ].map(([k, v]) => `<div class="card"><div class="label">${k}</div><div class="value" style="font-size:17px;">${v}</div></div>`).join(""));
284
499
 
285
500
  const moderationEvents = Array.isArray(governance.recent_events) ? governance.recent_events : [];
286
- document.getElementById("socialModerationList").innerHTML = moderationEvents.length === 0
501
+ setCachedContent("socialModerationList", moderationEvents.length === 0
287
502
  ? `<div class="empty-state">${t("network.noModerationEvents")}</div>`
288
503
  : moderationEvents.map((event) => `
289
504
  <div class="log-item">
290
505
  <div class="log-${event.level || "warn"}">[${String(event.level || "warn").toUpperCase()}] ${escapeHtml(event.message || "-")}</div>
291
506
  <div class="mono" style="color:#90a2c3;">${new Date(event.timestamp).toLocaleString()}</div>
292
507
  </div>
293
- `).join("");
508
+ `).join(""));
294
509
 
295
- document.getElementById("socialAdvancedCards").innerHTML = [
510
+ setCachedContent("socialAdvancedCards", [
296
511
  [t("labels.adapter"), effectiveAdapter],
297
512
  [t("social.namespace"), effectiveNamespace],
298
513
  [t("labels.room"), effectiveRoom],
299
514
  [t("social.bridgeStatus"), bridge.connected_to_silicaclaw ? t("common.yes") : t("common.no")],
300
515
  [t("social.messageBroadcast"), bridge.message_broadcast_enabled ? t("common.on") : t("common.off")],
301
516
  [t("social.restartRequired"), social.network_requires_restart ? t("common.yes") : t("common.no")],
302
- ].map(([k, v]) => `<div class="card"><div class="label">${k}</div><div class="value" style="font-size:17px;">${v}</div></div>`).join("");
303
- document.getElementById("socialAdvancedWrap").textContent = toPrettyJson({
517
+ ].map(([k, v]) => `<div class="card"><div class="label">${k}</div><div class="value" style="font-size:17px;">${v}</div></div>`).join(""));
518
+ setCachedContent("socialAdvancedWrap", toPrettyJson({
304
519
  effective_runtime: {
305
520
  mode: effectiveMode,
306
521
  adapter: effectiveAdapter,
@@ -322,17 +537,17 @@ export function createSocialController({
322
537
  social_md_found: summary.social_md_found,
323
538
  social_md_source_path: summary.social_md_source_path,
324
539
  },
325
- });
540
+ }), "text");
326
541
 
327
- document.getElementById("socialSourceWrap").textContent = toPrettyJson({
542
+ setCachedContent("socialSourceWrap", toPrettyJson({
328
543
  found: social.found,
329
544
  source_path: social.source_path,
330
545
  parse_error: social.parse_error,
331
- });
332
- document.getElementById("socialRawWrap").textContent = toPrettyJson({
546
+ }), "text");
547
+ setCachedContent("socialRawWrap", toPrettyJson({
333
548
  raw_frontmatter: social.raw_frontmatter || null,
334
- });
335
- document.getElementById("socialRuntimeWrap").textContent = toPrettyJson(runtime);
549
+ }), "text");
550
+ setCachedContent("socialRuntimeWrap", toPrettyJson(runtime), "text");
336
551
  }
337
552
 
338
553
  async function exportSocialTemplate() {
@@ -347,52 +562,88 @@ export function createSocialController({
347
562
  const logLevelFilter = getLogLevelFilter();
348
563
  const el = document.getElementById("logList");
349
564
  if (!logsCache.length) {
350
- el.innerHTML = `<div class="empty-state">${t("network.noLogsYet")}</div>`;
565
+ const nextHtml = `<div class="empty-state">${t("network.noLogsYet")}</div>`;
566
+ if (nextHtml !== lastLogsRenderKey) {
567
+ el.innerHTML = nextHtml;
568
+ lastLogsRenderKey = nextHtml;
569
+ }
351
570
  return;
352
571
  }
353
572
  const filtered = logLevelFilter === "all" ? logsCache : logsCache.filter((item) => String(item.level || "").toLowerCase() === logLevelFilter);
354
573
  if (!filtered.length) {
355
- el.innerHTML = `<div class="empty-state">${t("network.noLogsForLevel", { level: logLevelFilter })}</div>`;
574
+ const nextHtml = `<div class="empty-state">${t("network.noLogsForLevel", { level: logLevelFilter })}</div>`;
575
+ if (nextHtml !== lastLogsRenderKey) {
576
+ el.innerHTML = nextHtml;
577
+ lastLogsRenderKey = nextHtml;
578
+ }
356
579
  return;
357
580
  }
358
- el.innerHTML = filtered.map((item) => `
581
+ const nextHtml = filtered.map((item) => `
359
582
  <div class="log-item">
360
583
  <div class="log-${item.level}">[${String(item.level).toUpperCase()}] ${item.message}</div>
361
584
  <div class="mono" style="color:#90a2c3;">${new Date(item.timestamp).toLocaleString()}</div>
362
585
  </div>
363
586
  `).join("");
587
+ const renderKey = JSON.stringify({
588
+ level: logLevelFilter,
589
+ items: filtered.map((item) => [item.timestamp, item.level, item.message]),
590
+ });
591
+ if (renderKey === lastLogsRenderKey) {
592
+ return;
593
+ }
594
+ el.innerHTML = nextHtml;
595
+ lastLogsRenderKey = renderKey;
364
596
  }
365
597
 
366
598
  async function refreshLogs() {
599
+ if (getActiveTab() !== "network") {
600
+ return;
601
+ }
367
602
  setLogsCache((await api("/api/logs")).data || []);
368
603
  renderLogs();
369
604
  }
370
605
 
371
606
  function renderSkillCard(skill, options = {}) {
372
607
  const capabilities = Array.isArray(skill.capabilities) ? skill.capabilities.slice(0, 6) : [];
608
+ const updateAvailable = options.updateAvailable === true;
373
609
  const statusText = options.statusText || (skill.installed_in_openclaw ? t("common.yes") : t("hints.skillsNotInstalled"));
374
610
  const versionText = String(skill.version || "-");
375
611
  const bodyText = escapeHtml(String(skill.description || "-"));
376
- const installTone = skill.installed_in_openclaw || skill.install_mode === "workspace" || skill.install_mode === "legacy"
377
- ? "tag-chip emphasis"
378
- : "tag-chip muted";
612
+ const skillName = String(skill.name || "").trim();
613
+ const installable = options.installable === true && Boolean(skillName) && (!skill.installed_in_openclaw || updateAvailable);
614
+ const installedVersionText = escapeHtml(String(options.installedVersion || skill.installed_version || "-"));
615
+ const bundledVersionText = escapeHtml(String(options.bundledVersion || skill.bundled_version || skill.version || "-"));
616
+ const installTone = updateAvailable
617
+ ? "tag-chip warn"
618
+ : skill.installed_in_openclaw || skill.install_mode === "workspace" || skill.install_mode === "legacy"
619
+ ? "tag-chip emphasis"
620
+ : "tag-chip muted";
379
621
  const sourceText = escapeHtml(String(skill.source_path || skill.bundled_source_path || skill.installed_path || "-"));
380
622
  const locationText = escapeHtml(String(skill.installed_path || skill.manifest_path || "-"));
381
623
  return `
382
624
  <div class="skill-card">
383
625
  <div class="skill-card__top">
384
626
  <div>
385
- <div class="skill-card__eyebrow">${escapeHtml(options.eyebrow || skill.install_mode || "skill")}</div>
386
- <div class="skill-card__title">${escapeHtml(skill.display_name || skill.name || "Skill")}</div>
627
+ <div class="skill-card__eyebrow">${escapeHtml(skillModeLabel(options.eyebrow || skill.install_mode || "skill"))}</div>
628
+ <div class="skill-card__title">${escapeHtml(skill.display_name || skill.name || t("labels.skillsModeGeneric"))}</div>
387
629
  </div>
388
630
  <div class="skill-card__version mono">${escapeHtml(versionText)}</div>
389
631
  </div>
390
632
  <div class="skill-card__body">${bodyText}</div>
391
633
  <div class="skill-card__tags">
392
634
  <span class="${installTone}">${escapeHtml(statusText)}</span>
635
+ ${updateAvailable ? `<span class="tag-chip warn">${t("labels.skillsUpdateAvailable")}</span>` : ""}
393
636
  ${capabilities.map((item) => `<span class="tag-chip">${escapeHtml(String(item))}</span>`).join("")}
394
637
  </div>
395
638
  <div class="skill-card__meta">
639
+ <div class="skill-card__meta-item">
640
+ <div class="skill-card__meta-label">${t("labels.skillsInstalledVersion")}</div>
641
+ <div class="skill-card__meta-value mono">${installedVersionText}</div>
642
+ </div>
643
+ <div class="skill-card__meta-item">
644
+ <div class="skill-card__meta-label">${t("labels.skillsBundledVersion")}</div>
645
+ <div class="skill-card__meta-value mono">${bundledVersionText}</div>
646
+ </div>
396
647
  <div class="skill-card__meta-item">
397
648
  <div class="skill-card__meta-label">${t("labels.skillsSource")}</div>
398
649
  <div class="skill-card__meta-value mono">${sourceText}</div>
@@ -402,6 +653,50 @@ export function createSocialController({
402
653
  <div class="skill-card__meta-value mono">${locationText}</div>
403
654
  </div>
404
655
  </div>
656
+ ${installable ? `
657
+ <div class="actions">
658
+ <button class="secondary skill-install-btn" type="button" data-skill-install="${escapeHtml(skillName)}">${updateAvailable ? t("actions.updateThisSkill") : t("actions.installThisSkill")}</button>
659
+ </div>
660
+ ` : ""}
661
+ </div>
662
+ `;
663
+ }
664
+
665
+ function setSkillActionCopy({ title, body, state }) {
666
+ document.getElementById("skillsActionTitle").textContent = title;
667
+ document.getElementById("skillsActionBody").textContent = body;
668
+ document.getElementById("skillsActionState").textContent = state;
669
+ }
670
+
671
+ function renderDialogueCard(skill) {
672
+ const sections = Array.isArray(skill.owner_dialogue_sections_zh) ? skill.owner_dialogue_sections_zh : [];
673
+ const examples = Array.isArray(skill.owner_dialogue_examples_zh) ? skill.owner_dialogue_examples_zh : [];
674
+ return `
675
+ <div class="skill-card">
676
+ <div class="skill-card__top">
677
+ <div>
678
+ <div class="skill-card__eyebrow">${escapeHtml(skill.display_name || skill.name || t("labels.skillsModeGeneric"))}</div>
679
+ <div class="skill-card__title">${escapeHtml(t("labels.skillsDialogueExamples"))}</div>
680
+ </div>
681
+ <div class="skill-card__version mono">${escapeHtml(skill.version || "-")}</div>
682
+ </div>
683
+ <div class="skill-card__body">${escapeHtml(skill.description || "-")}</div>
684
+ <div class="skills-dialogue-list">
685
+ ${sections.length
686
+ ? sections.map((section) => `
687
+ <div class="skills-dialogue-group">
688
+ <div class="skills-dialogue-group__title">${escapeHtml(String(section.title || "-"))}</div>
689
+ <div class="skills-dialogue-group__items">
690
+ ${Array.isArray(section.items)
691
+ ? section.items.map((item) => `<div class="skills-dialogue-item">"${escapeHtml(String(item))}"</div>`).join("")
692
+ : ""}
693
+ </div>
694
+ </div>
695
+ `).join("")
696
+ : examples.length
697
+ ? examples.map((item) => `<div class="skills-dialogue-item">"${escapeHtml(String(item))}"</div>`).join("")
698
+ : `<div class="skills-empty">${t("hints.skillsNoDialogueExamples")}</div>`}
699
+ </div>
405
700
  </div>
406
701
  `;
407
702
  }
@@ -413,9 +708,29 @@ export function createSocialController({
413
708
  const openclaw = payload.openclaw || {};
414
709
  const summary = payload.summary || {};
415
710
  const installAction = payload.install_action || {};
416
- const featured = bundled[0] || null;
711
+ const broadcastSkill = bundled.find((item) => item.name === "silicaclaw-broadcast") || bundled[0] || null;
712
+ const ownerPushSkill = bundled.find((item) => item.name === "silicaclaw-owner-push") || null;
713
+ const featuredSkills = [broadcastSkill, ownerPushSkill].filter(Boolean);
417
714
  const openclawDetected = !!openclaw.detected;
418
715
  const openclawRunning = !!openclaw.running;
716
+ const allFeaturedInstalled = featuredSkills.length > 0 && featuredSkills.every((item) => item.installed_in_openclaw);
717
+ const installedFeaturedCount = featuredSkills.filter((item) => item.installed_in_openclaw).length;
718
+ const bundledUpdateCount = bundled.filter((item) => item.update_available).length;
719
+ const bundledSorted = [...bundled].sort((left, right) => {
720
+ const featuredLeft = featuredSkills.some((item) => item?.name === left.name) ? 1 : 0;
721
+ const featuredRight = featuredSkills.some((item) => item?.name === right.name) ? 1 : 0;
722
+ if (featuredLeft !== featuredRight) return featuredRight - featuredLeft;
723
+ const updateLeft = left.update_available ? 1 : 0;
724
+ const updateRight = right.update_available ? 1 : 0;
725
+ if (updateLeft !== updateRight) return updateRight - updateLeft;
726
+ const installLeft = left.installed_in_openclaw ? 1 : 0;
727
+ const installRight = right.installed_in_openclaw ? 1 : 0;
728
+ if (installLeft !== installRight) return installLeft - installRight;
729
+ return String(left.display_name || left.name || "").localeCompare(String(right.display_name || right.name || ""));
730
+ });
731
+ const installedSorted = [...installed].sort((left, right) =>
732
+ String(left.display_name || left.name || "").localeCompare(String(right.display_name || right.name || ""))
733
+ );
419
734
 
420
735
  document.getElementById("skillsBannerRuntimeValue").textContent = t("hints.skillsRuntimeSummary", {
421
736
  runtime: openclawRunning ? t("common.yes") : t("common.no"),
@@ -423,51 +738,135 @@ export function createSocialController({
423
738
  installed: String(summary.installed_count || 0),
424
739
  });
425
740
 
741
+ if (!openclawDetected) {
742
+ setSkillActionCopy({
743
+ title: t("hints.skillsActionMissingTitle"),
744
+ body: t("hints.skillsActionMissingBody"),
745
+ state: t("labels.skillsStateAttention"),
746
+ });
747
+ } else if (!openclawRunning) {
748
+ setSkillActionCopy({
749
+ title: t("hints.skillsActionStoppedTitle"),
750
+ body: t("hints.skillsActionStoppedBody"),
751
+ state: t("labels.skillsStateAttention"),
752
+ });
753
+ } else if (bundledUpdateCount > 0) {
754
+ setSkillActionCopy({
755
+ title: t("hints.skillsActionUpdateTitle", { count: String(bundledUpdateCount) }),
756
+ body: t("hints.skillsActionUpdateBody", { count: String(bundledUpdateCount) }),
757
+ state: t("labels.skillsStateAttention"),
758
+ });
759
+ } else if (allFeaturedInstalled) {
760
+ setSkillActionCopy({
761
+ title: t("hints.skillsActionCompleteTitle"),
762
+ body: t("hints.skillsActionCompleteBody"),
763
+ state: t("labels.skillsStateComplete"),
764
+ });
765
+ } else if (installedFeaturedCount > 0) {
766
+ setSkillActionCopy({
767
+ title: t("hints.skillsActionPartialTitle"),
768
+ body: t("hints.skillsActionPartialBody"),
769
+ state: t("labels.skillsStateInProgress"),
770
+ });
771
+ } else {
772
+ setSkillActionCopy({
773
+ title: t("hints.skillsActionInstallTitle"),
774
+ body: t("hints.skillsActionInstallBody"),
775
+ state: t("labels.skillsStateReady"),
776
+ });
777
+ }
778
+
426
779
  document.getElementById("skillsSummaryCards").innerHTML = [
427
780
  [t("labels.skillsBundled"), String(summary.bundled_count || 0)],
428
781
  [t("labels.skillsInstalled"), String(summary.installed_count || 0)],
429
- [t("social.openclawInstalled"), openclawDetected ? t("common.yes") : t("common.no")],
430
- [t("social.running"), openclawRunning ? t("common.yes") : t("common.no")],
431
- ].map(([k, v]) => `<div class="card"><div class="label">${k}</div><div class="value" style="font-size:17px;">${escapeHtml(v)}</div></div>`).join("");
782
+ [t("labels.skillsUpdates"), String(summary.update_available_count || 0)],
783
+ [t("labels.skillsBroadcastLearning"), broadcastSkill?.installed_in_openclaw ? t("common.yes") : t("common.no")],
784
+ [t("labels.skillsAutoPush"), ownerPushSkill?.installed_in_openclaw ? t("common.yes") : t("common.no")],
785
+ ].map(([k, v]) => `<div class="skills-summary-card"><div class="label">${k}</div><div class="value">${escapeHtml(v)}</div></div>`).join("");
786
+
787
+ document.getElementById("skillsFeaturedCount").textContent = `${featuredSkills.length}`;
788
+ document.getElementById("skillsBundledCount").textContent = `${bundled.length}`;
789
+ document.getElementById("skillsInstalledCount").textContent = `${installed.length}`;
790
+ document.getElementById("skillsDialogueCount").textContent = `${featuredSkills.length}`;
432
791
 
433
- document.getElementById("skillsFeaturedSpotlight").innerHTML = featured
434
- ? `
792
+ document.getElementById("skillsFeaturedSpotlights").innerHTML = featuredSkills.length
793
+ ? featuredSkills.map((skill) => `
435
794
  <div class="skills-spotlight">
436
- <div class="skill-card__eyebrow">${escapeHtml(openclaw.gateway_url || "OpenClaw skill")}</div>
437
- <div class="skills-spotlight__title">${escapeHtml(featured.display_name || featured.name)}</div>
438
- <div class="skills-spotlight__body">${escapeHtml(featured.description || "-")}</div>
795
+ <div class="skill-card__eyebrow">${escapeHtml(skill.name === "silicaclaw-owner-push" ? t("labels.skillsAutoPush") : t("labels.skillsBroadcastLearning"))}</div>
796
+ <div class="skills-spotlight__title">${escapeHtml(skill.display_name || skill.name)}</div>
797
+ <div class="skills-spotlight__body">${escapeHtml(skill.description || "-")}</div>
439
798
  <div class="skill-card__tags">
440
- <span class="${featured.installed_in_openclaw ? "tag-chip emphasis" : "tag-chip muted"}">${featured.installed_in_openclaw ? t("common.yes") : t("hints.skillsNotInstalled")}</span>
441
- ${(featured.capabilities || []).slice(0, 8).map((item) => `<span class="tag-chip">${escapeHtml(String(item))}</span>`).join("")}
799
+ <span class="${skill.update_available ? "tag-chip warn" : skill.installed_in_openclaw ? "tag-chip emphasis" : "tag-chip muted"}">${skill.update_available ? t("labels.skillsUpdateAvailable") : skill.installed_in_openclaw ? `${t("labels.skillsStatus")}: ${t("common.yes")}` : t("hints.skillsNotInstalled")}</span>
800
+ ${(skill.capabilities || []).slice(0, 8).map((item) => `<span class="tag-chip">${escapeHtml(String(item))}</span>`).join("")}
442
801
  </div>
443
802
  </div>
444
- `
803
+ `).join("")
445
804
  : `<div class="skills-empty">${t("hints.skillsNoBundled")}</div>`;
446
805
 
447
- document.getElementById("skillsBundledGrid").innerHTML = bundled.length
448
- ? bundled.map((skill) => renderSkillCard(skill, {
449
- eyebrow: skill.install_mode === "workspace" || skill.install_mode === "legacy" ? skill.install_mode : "bundled",
450
- statusText: skill.installed_in_openclaw ? `${t("labels.skillsStatus")}: ${t("common.yes")}` : t("hints.skillsNotInstalled"),
451
- })).join("")
452
- : `<div class="skills-empty">${t("hints.skillsNoBundled")}</div>`;
806
+ const bundledMatchCount = renderFilteredSkillCards({
807
+ skills: bundledSorted,
808
+ section: "bundled",
809
+ gridId: "skillsBundledGrid",
810
+ footerId: "skillsBundledFooter",
811
+ limit: SKILLS_SECTION_LIMIT,
812
+ renderer: (skill) => renderSkillCard(skill, {
813
+ eyebrow: skill.install_mode === "workspace" || skill.install_mode === "legacy" ? skill.install_mode : "bundled",
814
+ statusText: skill.update_available
815
+ ? t("labels.skillsUpdateAvailable")
816
+ : skill.installed_in_openclaw
817
+ ? `${t("labels.skillsStatus")}: ${t("common.yes")}`
818
+ : t("hints.skillsNotInstalled"),
819
+ installable: true,
820
+ updateAvailable: skill.update_available,
821
+ installedVersion: skill.installed_version,
822
+ bundledVersion: skill.version,
823
+ }),
824
+ });
825
+
826
+ const installedMatchCount = renderFilteredSkillCards({
827
+ skills: installedSorted,
828
+ section: "installed",
829
+ gridId: "skillsInstalledGrid",
830
+ footerId: "skillsInstalledFooter",
831
+ limit: SKILLS_SECTION_LIMIT,
832
+ renderer: (skill) => renderSkillCard(skill, {
833
+ eyebrow: skill.install_mode || "installed",
834
+ statusText: skill.update_available
835
+ ? t("labels.skillsUpdateAvailable")
836
+ : `${t("labels.skillsStatus")}: ${escapeHtml(skillModeLabel(skill.install_mode || "installed"))}`,
837
+ updateAvailable: skill.update_available,
838
+ installedVersion: skill.version,
839
+ bundledVersion: skill.bundled_version,
840
+ }),
841
+ });
842
+
843
+ const dialogueMatchCount = renderFilteredSkillCards({
844
+ skills: featuredSkills,
845
+ section: "dialogue",
846
+ gridId: "skillsDialogueGrid",
847
+ footerId: "skillsDialogueFooter",
848
+ limit: SKILLS_DIALOGUE_LIMIT,
849
+ renderer: (skill) => renderDialogueCard(skill),
850
+ });
453
851
 
454
- document.getElementById("skillsInstalledGrid").innerHTML = installed.length
455
- ? installed.map((skill) => renderSkillCard(skill, {
456
- eyebrow: skill.install_mode || "installed",
457
- statusText: `${t("labels.skillsStatus")}: ${escapeHtml(String(skill.install_mode || "-"))}`,
458
- })).join("")
459
- : `<div class="skills-empty">${t("hints.skillsNoInstalled")}</div>`;
852
+ renderSkillsFilterMeta({
853
+ bundledCount: bundledMatchCount,
854
+ installedCount: installedMatchCount,
855
+ dialogueCount: dialogueMatchCount,
856
+ });
460
857
 
461
858
  const installBtn = document.getElementById("skillsInstallBtn");
462
859
  installBtn.textContent = !openclawDetected
463
860
  ? t("actions.openclawNotInstalled")
464
861
  : !openclawRunning
465
862
  ? t("actions.openclawNotRunning")
466
- : featured?.installed_in_openclaw
467
- ? t("actions.openclawSkillLearned")
468
- : t("actions.learnOpenClawSkill");
469
- installBtn.disabled = !openclawDetected || !openclawRunning || !!featured?.installed_in_openclaw;
470
- document.getElementById("skillsFeedback").textContent = featured?.installed_in_openclaw
863
+ : bundledUpdateCount > 0
864
+ ? t("actions.updateSilicaClawSkills")
865
+ : allFeaturedInstalled
866
+ ? t("actions.silicaClawSkillsInstalled")
867
+ : t("actions.installSilicaClawSkills");
868
+ installBtn.disabled = !openclawDetected || !openclawRunning || (allFeaturedInstalled && bundledUpdateCount === 0);
869
+ document.getElementById("skillsFeedback").textContent = allFeaturedInstalled && bundledUpdateCount === 0
471
870
  ? t("feedback.openclawSkillInstalled")
472
871
  : installAction.recommended_command || t("common.ready");
473
872
  }
@@ -480,6 +879,9 @@ export function createSocialController({
480
879
  refreshSocial,
481
880
  renderLogs,
482
881
  renderSocialMessages,
882
+ setSkillsFilter,
883
+ setSkillsQuery,
483
884
  setLogLevelFilter,
885
+ toggleSkillsExpanded,
484
886
  };
485
887
  }