@silicaclaw/cli 2026.3.19-15 → 2026.3.19-16

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 (195) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/INSTALL.md +44 -11
  3. package/README.md +53 -19
  4. package/VERSION +1 -1
  5. package/apps/local-console/dist/apps/local-console/src/server.d.ts +30 -12
  6. package/apps/local-console/dist/apps/local-console/src/server.js +265 -48
  7. package/apps/local-console/dist/config/silicaclaw-defaults.json +19 -0
  8. package/apps/local-console/dist/packages/core/src/socialConfig.js +9 -5
  9. package/apps/local-console/dist/packages/network/src/realPreview.js +6 -2
  10. package/apps/local-console/dist/packages/network/src/relayPreview.js +8 -2
  11. package/apps/local-console/dist/packages/network/src/transport/udpLanBroadcastTransport.js +2 -1
  12. package/apps/local-console/dist/packages/network/src/webrtcPreview.js +5 -1
  13. package/apps/local-console/dist/packages/storage/src/socialRuntimeRepo.js +8 -4
  14. package/apps/local-console/public/app/app.js +17 -1
  15. package/apps/local-console/public/app/events.js +38 -2
  16. package/apps/local-console/public/app/network.js +32 -3
  17. package/apps/local-console/public/app/overview.js +4 -2
  18. package/apps/local-console/public/app/social.js +175 -26
  19. package/apps/local-console/public/app/styles.css +182 -14
  20. package/apps/local-console/public/app/template.js +70 -30
  21. package/apps/local-console/public/app/translations.js +131 -43
  22. package/apps/local-console/src/server.ts +281 -50
  23. package/apps/public-explorer/dist/apps/public-explorer/src/server.d.ts +1 -0
  24. package/apps/public-explorer/dist/apps/public-explorer/src/server.js +41 -0
  25. package/apps/public-explorer/dist/config/silicaclaw-defaults.json +19 -0
  26. package/apps/public-explorer/public/app/app.js +22 -2
  27. package/apps/public-explorer/public/app/template.js +4 -4
  28. package/apps/public-explorer/public/app/translations.js +15 -15
  29. package/apps/public-explorer/src/server.ts +11 -1
  30. package/docs/NEW_USER_INSTALL.md +14 -10
  31. package/docs/NEW_USER_OPERATIONS.md +3 -3
  32. package/docs/OPENCLAW_BRIDGE.md +15 -0
  33. package/docs/OPENCLAW_BRIDGE_ZH.md +15 -0
  34. package/node_modules/@silicaclaw/core/dist/config/silicaclaw-defaults.json +19 -0
  35. package/node_modules/@silicaclaw/core/dist/packages/core/src/crypto.d.ts +6 -0
  36. package/node_modules/@silicaclaw/core/dist/packages/core/src/crypto.js +50 -0
  37. package/node_modules/@silicaclaw/core/dist/packages/core/src/directory.d.ts +17 -0
  38. package/node_modules/@silicaclaw/core/dist/packages/core/src/directory.js +145 -0
  39. package/node_modules/@silicaclaw/core/dist/packages/core/src/identity.d.ts +2 -0
  40. package/node_modules/@silicaclaw/core/dist/packages/core/src/identity.js +18 -0
  41. package/node_modules/@silicaclaw/core/dist/packages/core/src/index.d.ts +12 -0
  42. package/node_modules/@silicaclaw/core/dist/packages/core/src/index.js +28 -0
  43. package/node_modules/@silicaclaw/core/dist/packages/core/src/indexing.d.ts +6 -0
  44. package/node_modules/@silicaclaw/core/dist/packages/core/src/indexing.js +43 -0
  45. package/node_modules/@silicaclaw/core/dist/packages/core/src/presence.d.ts +4 -0
  46. package/node_modules/@silicaclaw/core/dist/packages/core/src/presence.js +23 -0
  47. package/node_modules/@silicaclaw/core/dist/packages/core/src/profile.d.ts +4 -0
  48. package/node_modules/@silicaclaw/core/dist/packages/core/src/profile.js +39 -0
  49. package/node_modules/@silicaclaw/core/dist/packages/core/src/publicProfileSummary.d.ts +70 -0
  50. package/node_modules/@silicaclaw/core/dist/packages/core/src/publicProfileSummary.js +103 -0
  51. package/node_modules/@silicaclaw/core/dist/packages/core/src/socialConfig.d.ts +100 -0
  52. package/node_modules/@silicaclaw/core/dist/packages/core/src/socialConfig.js +300 -0
  53. package/node_modules/@silicaclaw/core/dist/packages/core/src/socialMessage.d.ts +19 -0
  54. package/node_modules/@silicaclaw/core/dist/packages/core/src/socialMessage.js +69 -0
  55. package/node_modules/@silicaclaw/core/dist/packages/core/src/socialResolver.d.ts +46 -0
  56. package/node_modules/@silicaclaw/core/dist/packages/core/src/socialResolver.js +237 -0
  57. package/node_modules/@silicaclaw/core/dist/packages/core/src/socialTemplate.d.ts +2 -0
  58. package/node_modules/@silicaclaw/core/dist/packages/core/src/socialTemplate.js +90 -0
  59. package/node_modules/@silicaclaw/core/dist/packages/core/src/types.d.ts +59 -0
  60. package/node_modules/@silicaclaw/core/dist/packages/core/src/types.js +2 -0
  61. package/node_modules/@silicaclaw/core/src/socialConfig.ts +7 -5
  62. package/node_modules/@silicaclaw/network/dist/config/silicaclaw-defaults.json +19 -0
  63. package/node_modules/@silicaclaw/network/dist/packages/network/src/abstractions/messageEnvelope.d.ts +28 -0
  64. package/node_modules/@silicaclaw/network/dist/packages/network/src/abstractions/messageEnvelope.js +36 -0
  65. package/node_modules/@silicaclaw/network/dist/packages/network/src/abstractions/peerDiscovery.d.ts +43 -0
  66. package/node_modules/@silicaclaw/network/dist/packages/network/src/abstractions/peerDiscovery.js +2 -0
  67. package/node_modules/@silicaclaw/network/dist/packages/network/src/abstractions/topicCodec.d.ts +4 -0
  68. package/node_modules/@silicaclaw/network/dist/packages/network/src/abstractions/topicCodec.js +2 -0
  69. package/node_modules/@silicaclaw/network/dist/packages/network/src/abstractions/transport.d.ts +36 -0
  70. package/node_modules/@silicaclaw/network/dist/packages/network/src/abstractions/transport.js +2 -0
  71. package/node_modules/@silicaclaw/network/dist/packages/network/src/codec/jsonMessageEnvelopeCodec.d.ts +5 -0
  72. package/node_modules/@silicaclaw/network/dist/packages/network/src/codec/jsonMessageEnvelopeCodec.js +24 -0
  73. package/node_modules/@silicaclaw/network/dist/packages/network/src/codec/jsonTopicCodec.d.ts +5 -0
  74. package/node_modules/@silicaclaw/network/dist/packages/network/src/codec/jsonTopicCodec.js +12 -0
  75. package/node_modules/@silicaclaw/network/dist/packages/network/src/discovery/heartbeatPeerDiscovery.d.ts +28 -0
  76. package/node_modules/@silicaclaw/network/dist/packages/network/src/discovery/heartbeatPeerDiscovery.js +144 -0
  77. package/node_modules/@silicaclaw/network/dist/packages/network/src/index.d.ts +14 -0
  78. package/node_modules/@silicaclaw/network/dist/packages/network/src/index.js +30 -0
  79. package/node_modules/@silicaclaw/network/dist/packages/network/src/localEventBus.d.ts +9 -0
  80. package/node_modules/@silicaclaw/network/dist/packages/network/src/localEventBus.js +47 -0
  81. package/node_modules/@silicaclaw/network/dist/packages/network/src/mock.d.ts +8 -0
  82. package/node_modules/@silicaclaw/network/dist/packages/network/src/mock.js +24 -0
  83. package/node_modules/@silicaclaw/network/dist/packages/network/src/realPreview.d.ts +105 -0
  84. package/node_modules/@silicaclaw/network/dist/packages/network/src/realPreview.js +331 -0
  85. package/node_modules/@silicaclaw/network/dist/packages/network/src/relayPreview.d.ts +166 -0
  86. package/node_modules/@silicaclaw/network/dist/packages/network/src/relayPreview.js +448 -0
  87. package/node_modules/@silicaclaw/network/dist/packages/network/src/transport/udpLanBroadcastTransport.d.ts +23 -0
  88. package/node_modules/@silicaclaw/network/dist/packages/network/src/transport/udpLanBroadcastTransport.js +154 -0
  89. package/node_modules/@silicaclaw/network/dist/packages/network/src/types.d.ts +6 -0
  90. package/node_modules/@silicaclaw/network/dist/packages/network/src/types.js +2 -0
  91. package/node_modules/@silicaclaw/network/dist/packages/network/src/webrtcPreview.d.ts +163 -0
  92. package/node_modules/@silicaclaw/network/dist/packages/network/src/webrtcPreview.js +848 -0
  93. package/node_modules/@silicaclaw/network/src/realPreview.ts +3 -2
  94. package/node_modules/@silicaclaw/network/src/relayPreview.ts +5 -2
  95. package/node_modules/@silicaclaw/network/src/transport/udpLanBroadcastTransport.ts +2 -1
  96. package/node_modules/@silicaclaw/network/src/webrtcPreview.ts +2 -1
  97. package/node_modules/@silicaclaw/storage/dist/socialRuntimeRepo.js +8 -4
  98. package/node_modules/@silicaclaw/storage/src/socialRuntimeRepo.ts +5 -4
  99. package/openclaw-skills/silicaclaw-bridge-setup/SKILL.md +147 -0
  100. package/openclaw-skills/silicaclaw-bridge-setup/VERSION +1 -0
  101. package/openclaw-skills/silicaclaw-bridge-setup/agents/openai.yaml +6 -0
  102. package/openclaw-skills/silicaclaw-bridge-setup/manifest.json +27 -0
  103. package/openclaw-skills/silicaclaw-bridge-setup/references/owner-dialogue-cheatsheet-zh.md +58 -0
  104. package/openclaw-skills/silicaclaw-bridge-setup/references/runtime-setup.md +43 -0
  105. package/openclaw-skills/silicaclaw-bridge-setup/references/troubleshooting.md +24 -0
  106. package/openclaw-skills/silicaclaw-broadcast/SKILL.md +132 -0
  107. package/openclaw-skills/silicaclaw-broadcast/VERSION +1 -1
  108. package/openclaw-skills/silicaclaw-broadcast/agents/openai.yaml +2 -2
  109. package/openclaw-skills/silicaclaw-broadcast/manifest.json +3 -2
  110. package/openclaw-skills/silicaclaw-broadcast/references/owner-dialogue-cheatsheet-zh.md +81 -0
  111. package/openclaw-skills/silicaclaw-owner-push/SKILL.md +217 -0
  112. package/openclaw-skills/silicaclaw-owner-push/VERSION +1 -0
  113. package/openclaw-skills/silicaclaw-owner-push/agents/openai.yaml +6 -0
  114. package/openclaw-skills/silicaclaw-owner-push/manifest.json +30 -0
  115. package/openclaw-skills/silicaclaw-owner-push/references/owner-dialogue-cheatsheet-zh.md +87 -0
  116. package/openclaw-skills/silicaclaw-owner-push/references/push-routing-policy.md +43 -0
  117. package/openclaw-skills/silicaclaw-owner-push/references/runtime-setup.md +41 -0
  118. package/openclaw-skills/silicaclaw-owner-push/scripts/owner-push-forwarder.mjs +214 -0
  119. package/openclaw-skills/silicaclaw-owner-push/scripts/send-to-owner-via-openclaw.mjs +69 -0
  120. package/package.json +1 -1
  121. package/packages/core/dist/config/silicaclaw-defaults.json +19 -0
  122. package/packages/core/dist/packages/core/src/crypto.d.ts +6 -0
  123. package/packages/core/dist/packages/core/src/crypto.js +50 -0
  124. package/packages/core/dist/packages/core/src/directory.d.ts +17 -0
  125. package/packages/core/dist/packages/core/src/directory.js +145 -0
  126. package/packages/core/dist/packages/core/src/identity.d.ts +2 -0
  127. package/packages/core/dist/packages/core/src/identity.js +18 -0
  128. package/packages/core/dist/packages/core/src/index.d.ts +12 -0
  129. package/packages/core/dist/packages/core/src/index.js +28 -0
  130. package/packages/core/dist/packages/core/src/indexing.d.ts +6 -0
  131. package/packages/core/dist/packages/core/src/indexing.js +43 -0
  132. package/packages/core/dist/packages/core/src/presence.d.ts +4 -0
  133. package/packages/core/dist/packages/core/src/presence.js +23 -0
  134. package/packages/core/dist/packages/core/src/profile.d.ts +4 -0
  135. package/packages/core/dist/packages/core/src/profile.js +39 -0
  136. package/packages/core/dist/packages/core/src/publicProfileSummary.d.ts +70 -0
  137. package/packages/core/dist/packages/core/src/publicProfileSummary.js +103 -0
  138. package/packages/core/dist/packages/core/src/socialConfig.d.ts +100 -0
  139. package/packages/core/dist/packages/core/src/socialConfig.js +300 -0
  140. package/packages/core/dist/packages/core/src/socialMessage.d.ts +19 -0
  141. package/packages/core/dist/packages/core/src/socialMessage.js +69 -0
  142. package/packages/core/dist/packages/core/src/socialResolver.d.ts +46 -0
  143. package/packages/core/dist/packages/core/src/socialResolver.js +237 -0
  144. package/packages/core/dist/packages/core/src/socialTemplate.d.ts +2 -0
  145. package/packages/core/dist/packages/core/src/socialTemplate.js +90 -0
  146. package/packages/core/dist/packages/core/src/types.d.ts +59 -0
  147. package/packages/core/dist/packages/core/src/types.js +2 -0
  148. package/packages/core/src/socialConfig.ts +7 -5
  149. package/packages/network/dist/config/silicaclaw-defaults.json +19 -0
  150. package/packages/network/dist/packages/network/src/abstractions/messageEnvelope.d.ts +28 -0
  151. package/packages/network/dist/packages/network/src/abstractions/messageEnvelope.js +36 -0
  152. package/packages/network/dist/packages/network/src/abstractions/peerDiscovery.d.ts +43 -0
  153. package/packages/network/dist/packages/network/src/abstractions/peerDiscovery.js +2 -0
  154. package/packages/network/dist/packages/network/src/abstractions/topicCodec.d.ts +4 -0
  155. package/packages/network/dist/packages/network/src/abstractions/topicCodec.js +2 -0
  156. package/packages/network/dist/packages/network/src/abstractions/transport.d.ts +36 -0
  157. package/packages/network/dist/packages/network/src/abstractions/transport.js +2 -0
  158. package/packages/network/dist/packages/network/src/codec/jsonMessageEnvelopeCodec.d.ts +5 -0
  159. package/packages/network/dist/packages/network/src/codec/jsonMessageEnvelopeCodec.js +24 -0
  160. package/packages/network/dist/packages/network/src/codec/jsonTopicCodec.d.ts +5 -0
  161. package/packages/network/dist/packages/network/src/codec/jsonTopicCodec.js +12 -0
  162. package/packages/network/dist/packages/network/src/discovery/heartbeatPeerDiscovery.d.ts +28 -0
  163. package/packages/network/dist/packages/network/src/discovery/heartbeatPeerDiscovery.js +144 -0
  164. package/packages/network/dist/packages/network/src/index.d.ts +14 -0
  165. package/packages/network/dist/packages/network/src/index.js +30 -0
  166. package/packages/network/dist/packages/network/src/localEventBus.d.ts +9 -0
  167. package/packages/network/dist/packages/network/src/localEventBus.js +47 -0
  168. package/packages/network/dist/packages/network/src/mock.d.ts +8 -0
  169. package/packages/network/dist/packages/network/src/mock.js +24 -0
  170. package/packages/network/dist/packages/network/src/realPreview.d.ts +105 -0
  171. package/packages/network/dist/packages/network/src/realPreview.js +331 -0
  172. package/packages/network/dist/packages/network/src/relayPreview.d.ts +166 -0
  173. package/packages/network/dist/packages/network/src/relayPreview.js +448 -0
  174. package/packages/network/dist/packages/network/src/transport/udpLanBroadcastTransport.d.ts +23 -0
  175. package/packages/network/dist/packages/network/src/transport/udpLanBroadcastTransport.js +154 -0
  176. package/packages/network/dist/packages/network/src/types.d.ts +6 -0
  177. package/packages/network/dist/packages/network/src/types.js +2 -0
  178. package/packages/network/dist/packages/network/src/webrtcPreview.d.ts +163 -0
  179. package/packages/network/dist/packages/network/src/webrtcPreview.js +848 -0
  180. package/packages/network/src/realPreview.ts +3 -2
  181. package/packages/network/src/relayPreview.ts +5 -2
  182. package/packages/network/src/transport/udpLanBroadcastTransport.ts +2 -1
  183. package/packages/network/src/webrtcPreview.ts +2 -1
  184. package/packages/storage/dist/socialRuntimeRepo.js +8 -4
  185. package/packages/storage/src/socialRuntimeRepo.ts +5 -4
  186. package/scripts/functional-check.mjs +35 -6
  187. package/scripts/install-openclaw-skill.mjs +9 -2
  188. package/scripts/openclaw-bridge-adapter.mjs +3 -1
  189. package/scripts/openclaw-bridge-client.mjs +3 -1
  190. package/scripts/openclaw-runtime-demo.mjs +3 -1
  191. package/scripts/quickstart.sh +13 -9
  192. package/scripts/release-pack.mjs +13 -1
  193. package/scripts/silicaclaw-cli.mjs +23 -18
  194. package/scripts/silicaclaw-gateway.mjs +33 -27
  195. package/scripts/validate-openclaw-skill.mjs +79 -21
@@ -6,6 +6,7 @@ import { accessSync, constants, copyFileSync, existsSync, mkdirSync, readFileSyn
6
6
  import { createHash } from "crypto";
7
7
  import { homedir, hostname } from "os";
8
8
  import { promisify } from "util";
9
+ import defaults from "../../../config/silicaclaw-defaults.json";
9
10
  import {
10
11
  AgentIdentity,
11
12
  DirectoryState,
@@ -80,16 +81,22 @@ const NETWORK_MAX_PAST_DRIFT_MS = Number(process.env.NETWORK_MAX_PAST_DRIFT_MS |
80
81
  const NETWORK_HEARTBEAT_INTERVAL_MS = Number(process.env.NETWORK_HEARTBEAT_INTERVAL_MS || 12_000);
81
82
  const NETWORK_PEER_STALE_AFTER_MS = Number(process.env.NETWORK_PEER_STALE_AFTER_MS || 45_000);
82
83
  const OPENCLAW_GATEWAY_HOST = "127.0.0.1";
83
- const OPENCLAW_GATEWAY_PORT = 18_789;
84
+ const DEFAULT_NETWORK_MODE = defaults.network.default_mode as "global-preview";
85
+ const DEFAULT_NETWORK_NAMESPACE = defaults.network.default_namespace;
86
+ const DEFAULT_NETWORK_PORT = defaults.ports.network_default;
87
+ const DEFAULT_GLOBAL_SIGNALING_URL = defaults.network.global_preview.relay_url;
88
+ const DEFAULT_GLOBAL_ROOM = defaults.network.global_preview.room;
89
+ const DEFAULT_BRIDGE_API_BASE = defaults.bridge.api_base;
90
+ const OPENCLAW_GATEWAY_PORT = defaults.ports.openclaw_gateway;
84
91
  const OPENCLAW_GATEWAY_URL = `http://${OPENCLAW_GATEWAY_HOST}:${OPENCLAW_GATEWAY_PORT}/`;
85
92
  const NETWORK_PEER_REMOVE_AFTER_MS = Number(process.env.NETWORK_PEER_REMOVE_AFTER_MS || 180_000);
86
93
  const NETWORK_UDP_BIND_ADDRESS = process.env.NETWORK_UDP_BIND_ADDRESS || "0.0.0.0";
87
94
  const NETWORK_UDP_BROADCAST_ADDRESS = process.env.NETWORK_UDP_BROADCAST_ADDRESS || "255.255.255.255";
88
95
  const NETWORK_PEER_ID = process.env.NETWORK_PEER_ID;
89
96
  const NETWORK_MODE = process.env.NETWORK_MODE || "";
90
- const WEBRTC_SIGNALING_URL = process.env.WEBRTC_SIGNALING_URL || "https://relay.silicaclaw.com";
97
+ const WEBRTC_SIGNALING_URL = process.env.WEBRTC_SIGNALING_URL || DEFAULT_GLOBAL_SIGNALING_URL;
91
98
  const WEBRTC_SIGNALING_URLS = process.env.WEBRTC_SIGNALING_URLS || "";
92
- const WEBRTC_ROOM = process.env.WEBRTC_ROOM || "silicaclaw-global-preview";
99
+ const WEBRTC_ROOM = process.env.WEBRTC_ROOM || DEFAULT_GLOBAL_ROOM;
93
100
  const WEBRTC_SEED_PEERS = process.env.WEBRTC_SEED_PEERS || "";
94
101
  const WEBRTC_BOOTSTRAP_HINTS = process.env.WEBRTC_BOOTSTRAP_HINTS || "";
95
102
  const PROFILE_VERSION = "v0.9";
@@ -133,6 +140,40 @@ function readWorkspaceVersion(workspaceRoot: string): string {
133
140
  return "unknown";
134
141
  }
135
142
 
143
+ function normalizeVersionText(value: unknown): string {
144
+ const text = String(value || "").trim();
145
+ return text.startsWith("v") ? text.slice(1) : text;
146
+ }
147
+
148
+ function tokenizeVersion(value: unknown): Array<number | string> {
149
+ return normalizeVersionText(value)
150
+ .split(/[^0-9A-Za-z]+/)
151
+ .map((token) => token.trim())
152
+ .filter(Boolean)
153
+ .map((token) => (/^\d+$/.test(token) ? Number(token) : token.toLowerCase()));
154
+ }
155
+
156
+ function compareVersionTokens(left: unknown, right: unknown): number {
157
+ const leftTokens = tokenizeVersion(left);
158
+ const rightTokens = tokenizeVersion(right);
159
+ const maxLength = Math.max(leftTokens.length, rightTokens.length);
160
+ for (let index = 0; index < maxLength; index += 1) {
161
+ const leftToken = leftTokens[index];
162
+ const rightToken = rightTokens[index];
163
+ if (leftToken === undefined && rightToken === undefined) return 0;
164
+ if (leftToken === undefined) return -1;
165
+ if (rightToken === undefined) return 1;
166
+ if (typeof leftToken === "number" && typeof rightToken === "number") {
167
+ if (leftToken !== rightToken) return leftToken > rightToken ? 1 : -1;
168
+ continue;
169
+ }
170
+ const leftText = String(leftToken);
171
+ const rightText = String(rightToken);
172
+ if (leftText !== rightText) return leftText.localeCompare(rightText);
173
+ }
174
+ return 0;
175
+ }
176
+
136
177
  function resolveWorkspaceRoot(cwd = process.cwd()): string {
137
178
  if (existsSync(resolve(cwd, "apps", "local-console", "package.json"))) {
138
179
  return cwd;
@@ -149,6 +190,12 @@ function resolveProjectRoot(appRoot: string, cwd = process.cwd()): string {
149
190
  if (envRoot) {
150
191
  return resolve(envRoot);
151
192
  }
193
+ if (
194
+ existsSync(resolve(appRoot, "apps", "local-console", "package.json")) &&
195
+ existsSync(resolve(appRoot, "package.json"))
196
+ ) {
197
+ return appRoot;
198
+ }
152
199
  if (!existsSync(resolve(cwd, "apps", "local-console", "package.json"))) {
153
200
  return resolve(cwd);
154
201
  }
@@ -236,6 +283,50 @@ function summarizeSkillReadme(filePath: string) {
236
283
  }
237
284
  }
238
285
 
286
+ function readDialogueCheatsheetPreview(filePath: string, limit = 6) {
287
+ if (!filePath || !existsSync(filePath)) return [];
288
+ try {
289
+ return readFileSync(filePath, "utf8")
290
+ .split(/\r?\n/)
291
+ .map((line) => line.trim())
292
+ .filter((line) => line.startsWith("- "))
293
+ .map((line) => line.slice(2).trim())
294
+ .filter(Boolean)
295
+ .slice(0, limit);
296
+ } catch {
297
+ return [];
298
+ }
299
+ }
300
+
301
+ function readDialogueCheatsheetSections(filePath: string, maxSections = 3, maxItemsPerSection = 5) {
302
+ if (!filePath || !existsSync(filePath)) return [];
303
+ try {
304
+ const lines = readFileSync(filePath, "utf8").split(/\r?\n/);
305
+ const sections: Array<{ title: string; items: string[] }> = [];
306
+ let current: { title: string; items: string[] } | null = null;
307
+ for (const rawLine of lines) {
308
+ const line = rawLine.trim();
309
+ if (line.startsWith("## ")) {
310
+ if (current && current.items.length) sections.push(current);
311
+ current = { title: line.slice(3).trim(), items: [] };
312
+ continue;
313
+ }
314
+ if (line.startsWith("- ")) {
315
+ if (!current) {
316
+ current = { title: "Examples", items: [] };
317
+ }
318
+ if (current.items.length < maxItemsPerSection) {
319
+ current.items.push(line.slice(2).trim());
320
+ }
321
+ }
322
+ }
323
+ if (current && current.items.length) sections.push(current);
324
+ return sections.slice(0, maxSections);
325
+ } catch {
326
+ return [];
327
+ }
328
+ }
329
+
239
330
  function detectOpenClawInstallation(workspaceRoot: string) {
240
331
  const workspaceDir = resolve(workspaceRoot, ".openclaw");
241
332
  const homeDir = resolve(process.env.HOME || "", ".openclaw");
@@ -795,7 +886,7 @@ export class LocalNodeService {
795
886
 
796
887
  private network: NetworkAdapter;
797
888
  private adapterMode: "mock" | "local-event-bus" | "real-preview" | "webrtc-preview" | "relay-preview";
798
- private networkMode: "local" | "lan" | "global-preview" = "global-preview";
889
+ private networkMode: "local" | "lan" | "global-preview" = DEFAULT_NETWORK_MODE;
799
890
  private networkNamespace: string;
800
891
  private networkPort: number | null;
801
892
  private socialConfig: SocialConfig;
@@ -809,7 +900,7 @@ export class LocalNodeService {
809
900
  "silicaclaw-existing";
810
901
  private resolvedOpenClawIdentityPath: string | null = null;
811
902
  private webrtcSignalingUrls: string[] = [];
812
- private webrtcRoom = "silicaclaw-global-preview";
903
+ private webrtcRoom = DEFAULT_GLOBAL_ROOM;
813
904
  private webrtcSeedPeers: string[] = [];
814
905
  private webrtcBootstrapHints: string[] = [];
815
906
  private webrtcBootstrapSources: string[] = [];
@@ -838,7 +929,7 @@ export class LocalNodeService {
838
929
  display_name: this.getDefaultDisplayName(),
839
930
  bio: "Local AI agent connected to SilicaClaw",
840
931
  tags: ["openclaw", "local-first"],
841
- mode: "global-preview",
932
+ mode: DEFAULT_NETWORK_MODE,
842
933
  public_enabled: false,
843
934
  });
844
935
  loadedSocial = loadSocialConfig(this.projectRoot);
@@ -850,8 +941,8 @@ export class LocalNodeService {
850
941
  this.socialParseError = loadedSocial.meta.parse_error;
851
942
  this.socialRawFrontmatter = loadedSocial.raw_frontmatter;
852
943
 
853
- this.networkNamespace = this.socialConfig.network.namespace || process.env.NETWORK_NAMESPACE || "silicaclaw.preview";
854
- this.networkPort = Number(this.socialConfig.network.port || process.env.NETWORK_PORT || 44123);
944
+ this.networkNamespace = this.socialConfig.network.namespace || process.env.NETWORK_NAMESPACE || DEFAULT_NETWORK_NAMESPACE;
945
+ this.networkPort = Number(this.socialConfig.network.port || process.env.NETWORK_PORT || DEFAULT_NETWORK_PORT);
855
946
  this.applyResolvedNetworkConfig();
856
947
  const resolved = this.buildNetworkAdapter();
857
948
  this.network = resolved.adapter;
@@ -903,12 +994,8 @@ export class LocalNodeService {
903
994
  }
904
995
 
905
996
  getOverview() {
906
- this.ensureLocalDirectoryBaseline();
907
- this.compactCacheInMemory();
908
- const profiles = Object.values(this.directory.profiles);
909
- const onlineCount = profiles.filter((profile) =>
910
- isAgentOnline(this.directory.presence[profile.agent_id], Date.now(), PRESENCE_TTL_MS)
911
- ).length;
997
+ const discovered = this.search("");
998
+ const onlineCount = discovered.filter((profile) => profile.online).length;
912
999
 
913
1000
  return {
914
1001
  app_version: this.appVersion,
@@ -919,9 +1006,9 @@ export class LocalNodeService {
919
1006
  last_broadcast_error_at: this.lastBroadcastErrorAt,
920
1007
  last_broadcast_error: this.lastBroadcastError,
921
1008
  broadcast_failure_count: this.broadcastFailureCount,
922
- discovered_count: profiles.length,
1009
+ discovered_count: discovered.length,
923
1010
  online_count: onlineCount,
924
- offline_count: Math.max(0, profiles.length - onlineCount),
1011
+ offline_count: Math.max(0, discovered.length - onlineCount),
925
1012
  init_state: this.initState,
926
1013
  presence_ttl_ms: PRESENCE_TTL_MS,
927
1014
  onboarding: this.getOnboardingSummary(),
@@ -1307,20 +1394,36 @@ export class LocalNodeService {
1307
1394
  }
1308
1395
 
1309
1396
  async setNetworkModeRuntime(mode: "local" | "lan" | "global-preview") {
1310
- const currentMode = this.networkMode;
1397
+ const before = {
1398
+ mode: this.networkMode,
1399
+ adapter: this.adapterMode,
1400
+ namespace: this.networkNamespace,
1401
+ port: this.networkPort,
1402
+ };
1311
1403
  if (mode !== "local" && mode !== "lan" && mode !== "global-preview") {
1312
1404
  throw new Error("invalid_network_mode");
1313
1405
  }
1314
1406
  this.socialConfig.network.mode = mode;
1315
1407
  this.socialConfig.network.adapter = this.adapterForMode(mode);
1316
1408
  this.applyResolvedNetworkConfig();
1317
- this.socialNetworkRequiresRestart = currentMode !== mode || this.adapterMode !== this.socialConfig.network.adapter;
1409
+
1410
+ const needsRestart =
1411
+ before.mode !== this.networkMode ||
1412
+ before.adapter !== this.socialConfig.network.adapter ||
1413
+ before.namespace !== this.networkNamespace ||
1414
+ (before.port ?? null) !== (this.networkPort ?? null);
1415
+
1416
+ if (needsRestart) {
1417
+ await this.restartNetworkAdapter("set_network_mode_runtime");
1418
+ }
1419
+
1420
+ this.socialNetworkRequiresRestart = false;
1318
1421
  await this.writeSocialRuntime();
1319
1422
  return {
1320
1423
  mode: this.networkMode,
1321
- adapter: this.socialConfig.network.adapter,
1322
- network_requires_restart: this.socialNetworkRequiresRestart,
1323
- note: "Runtime mode updated. Existing social.md is unchanged.",
1424
+ adapter: this.adapterMode,
1425
+ network_requires_restart: false,
1426
+ note: "Runtime mode updated and adapter restarted. Existing social.md is unchanged.",
1324
1427
  };
1325
1428
  }
1326
1429
 
@@ -1335,7 +1438,7 @@ export class LocalNodeService {
1335
1438
  this.socialConfig.network.adapter = "relay-preview";
1336
1439
  this.socialConfig.network.signaling_url = signalingUrl;
1337
1440
  this.socialConfig.network.signaling_urls = [signalingUrl];
1338
- this.socialConfig.network.room = room || "silicaclaw-global-preview";
1441
+ this.socialConfig.network.room = room || DEFAULT_GLOBAL_ROOM;
1339
1442
  this.applyResolvedNetworkConfig();
1340
1443
  await this.restartNetworkAdapter("quick_connect_global_preview");
1341
1444
  this.socialNetworkRequiresRestart = false;
@@ -1382,6 +1485,11 @@ export class LocalNodeService {
1382
1485
  before.namespace !== after.namespace ||
1383
1486
  (before.port ?? null) !== (after.port ?? null);
1384
1487
 
1488
+ if (this.socialNetworkRequiresRestart) {
1489
+ await this.restartNetworkAdapter("reload_social_config");
1490
+ this.socialNetworkRequiresRestart = false;
1491
+ }
1492
+
1385
1493
  await this.writeSocialRuntime();
1386
1494
 
1387
1495
  return this.getSocialConfigView();
@@ -1415,10 +1523,11 @@ export class LocalNodeService {
1415
1523
  search(keyword: string): PublicProfileSummary[] {
1416
1524
  this.ensureLocalDirectoryBaseline();
1417
1525
  this.compactCacheInMemory();
1418
- return searchDirectory(this.directory, keyword, { presenceTTLms: PRESENCE_TTL_MS }).map((profile) => {
1526
+ const directMatches = searchDirectory(this.directory, keyword, { presenceTTLms: PRESENCE_TTL_MS }).map((profile) => {
1419
1527
  const lastSeenAt = this.directory.presence[profile.agent_id] ?? 0;
1420
1528
  return this.toPublicProfileSummary(profile, { last_seen_at: lastSeenAt });
1421
1529
  });
1530
+ return this.mergeMessageOnlyAgentSummaries(directMatches, keyword);
1422
1531
  }
1423
1532
 
1424
1533
  getPublicProfilePreview(): PublicProfileSummary | null {
@@ -1563,9 +1672,13 @@ export class LocalNodeService {
1563
1672
  };
1564
1673
  }
1565
1674
 
1566
- async installOpenClawSkill() {
1675
+ async installOpenClawSkill(skillName?: string) {
1567
1676
  const scriptPath = resolve(this.workspaceRoot, "scripts", "install-openclaw-skill.mjs");
1568
- const { stdout } = await execFileAsync(process.execPath, [scriptPath], {
1677
+ const args = [scriptPath];
1678
+ if (skillName) {
1679
+ args.push(`--skill=${skillName}`);
1680
+ }
1681
+ const { stdout } = await execFileAsync(process.execPath, args, {
1569
1682
  cwd: this.workspaceRoot,
1570
1683
  env: { ...process.env, SILICACLAW_WORKSPACE_DIR: this.projectRoot },
1571
1684
  maxBuffer: 1024 * 1024,
@@ -1595,7 +1708,7 @@ export class LocalNodeService {
1595
1708
  const openclawRuntime = detectOpenClawRuntime(this.projectRoot);
1596
1709
 
1597
1710
  return {
1598
- bridge_api_base: "http://localhost:4310",
1711
+ bridge_api_base: DEFAULT_BRIDGE_API_BASE,
1599
1712
  openclaw_detected: detectOpenClawInstallation(this.projectRoot).detected,
1600
1713
  openclaw_running: openclawRuntime.running,
1601
1714
  openclaw_gateway_host: OPENCLAW_GATEWAY_HOST,
@@ -1605,7 +1718,7 @@ export class LocalNodeService {
1605
1718
  openclaw_workspace_skill_dir: workspaceSkillDir,
1606
1719
  openclaw_legacy_skill_dir: legacySkillDir,
1607
1720
  silicaclaw_env_template_path: resolve(this.workspaceRoot, "openclaw-owner-forward.env.example"),
1608
- recommended_skill_name: "silicaclaw-broadcast",
1721
+ recommended_skill_name: "silicaclaw-bridge-setup",
1609
1722
  recommended_install_command: "silicaclaw openclaw-skill-install",
1610
1723
  recommended_owner_forward_env: {
1611
1724
  OPENCLAW_SOURCE_DIR: openclawSourceDir,
@@ -1623,6 +1736,7 @@ export class LocalNodeService {
1623
1736
  ].join(" "),
1624
1737
  notes: [
1625
1738
  "Install and maintain the skill from SilicaClaw; do not edit OpenClaw core source for this integration.",
1739
+ "Use silicaclaw-bridge-setup first when OpenClaw still needs local install, readiness checks, or troubleshooting guidance.",
1626
1740
  "OpenClaw learns broadcasts via the installed skill under ~/.openclaw/workspace/skills/.",
1627
1741
  "Runtime detection prefers the actual OpenClaw gateway listener port, then falls back to OpenClaw's own openclaw.json gateway.port.",
1628
1742
  "Owner delivery runs through OpenClaw's own message channel stack after the skill forwards a summary.",
@@ -1642,6 +1756,12 @@ export class LocalNodeService {
1642
1756
  const skillPath = resolve(dir.path, "SKILL.md");
1643
1757
  const versionPath = resolve(dir.path, "VERSION");
1644
1758
  const manifest = readJsonFileSafe(manifestPath);
1759
+ const references = (manifest?.references && typeof manifest.references === "object")
1760
+ ? manifest.references as Record<string, unknown>
1761
+ : null;
1762
+ const ownerDialogueCheatsheetPath = references?.owner_dialogue_cheatsheet_zh
1763
+ ? resolve(dir.path, String(references.owner_dialogue_cheatsheet_zh))
1764
+ : null;
1645
1765
  const name = String(manifest?.name || dir.name);
1646
1766
  const capabilities = Array.isArray(manifest?.capabilities)
1647
1767
  ? manifest.capabilities.map((item) => String(item))
@@ -1661,6 +1781,9 @@ export class LocalNodeService {
1661
1781
  skill_path: existsSync(skillPath) ? skillPath : null,
1662
1782
  capabilities,
1663
1783
  transport: manifest?.transport || null,
1784
+ owner_dialogue_cheatsheet_path: ownerDialogueCheatsheetPath && existsSync(ownerDialogueCheatsheetPath) ? ownerDialogueCheatsheetPath : null,
1785
+ owner_dialogue_examples_zh: ownerDialogueCheatsheetPath ? readDialogueCheatsheetPreview(ownerDialogueCheatsheetPath) : [],
1786
+ owner_dialogue_sections_zh: ownerDialogueCheatsheetPath ? readDialogueCheatsheetSections(ownerDialogueCheatsheetPath) : [],
1664
1787
  installed_in_openclaw: installedInWorkspace || installedInLegacy,
1665
1788
  install_mode: installedInWorkspace ? "workspace" : installedInLegacy ? "legacy" : "not_installed",
1666
1789
  installed_path: installedInWorkspace ? installedWorkspacePath : installedInLegacy ? installedLegacyPath : null,
@@ -1675,6 +1798,12 @@ export class LocalNodeService {
1675
1798
  const skillPath = resolve(dir.path, "SKILL.md");
1676
1799
  const versionPath = resolve(dir.path, "VERSION");
1677
1800
  const manifest = readJsonFileSafe(manifestPath);
1801
+ const references = (manifest?.references && typeof manifest.references === "object")
1802
+ ? manifest.references as Record<string, unknown>
1803
+ : null;
1804
+ const ownerDialogueCheatsheetPath = references?.owner_dialogue_cheatsheet_zh
1805
+ ? resolve(dir.path, String(references.owner_dialogue_cheatsheet_zh))
1806
+ : null;
1678
1807
  return {
1679
1808
  key: `${dir.install_mode}:${dir.name}`,
1680
1809
  name: String(manifest?.name || dir.name),
@@ -1686,10 +1815,43 @@ export class LocalNodeService {
1686
1815
  manifest_path: existsSync(manifestPath) ? manifestPath : null,
1687
1816
  skill_path: existsSync(skillPath) ? skillPath : null,
1688
1817
  capabilities: Array.isArray(manifest?.capabilities) ? manifest.capabilities.map((item) => String(item)) : [],
1818
+ owner_dialogue_cheatsheet_path: ownerDialogueCheatsheetPath && existsSync(ownerDialogueCheatsheetPath) ? ownerDialogueCheatsheetPath : null,
1819
+ owner_dialogue_examples_zh: ownerDialogueCheatsheetPath ? readDialogueCheatsheetPreview(ownerDialogueCheatsheetPath) : [],
1820
+ owner_dialogue_sections_zh: ownerDialogueCheatsheetPath ? readDialogueCheatsheetSections(ownerDialogueCheatsheetPath) : [],
1689
1821
  bundled_source_path: bundledSkills.find((item) => item.name === String(manifest?.name || dir.name))?.source_path || null,
1690
1822
  };
1691
1823
  });
1692
1824
 
1825
+ const installedSkillVersions = new Map(installedSkills.map((item) => [item.name, item.version]));
1826
+ const bundledSkillsWithUpdateState = bundledSkills.map((skill) => {
1827
+ const installedVersion = installedSkillVersions.get(skill.name) || "";
1828
+ const updateAvailable = Boolean(
1829
+ skill.installed_in_openclaw &&
1830
+ installedVersion &&
1831
+ skill.version &&
1832
+ compareVersionTokens(installedVersion, skill.version) < 0
1833
+ );
1834
+ return {
1835
+ ...skill,
1836
+ installed_version: installedVersion || null,
1837
+ update_available: updateAvailable,
1838
+ };
1839
+ });
1840
+ const bundledSkillVersions = new Map(bundledSkillsWithUpdateState.map((item) => [item.name, item.version]));
1841
+ const installedSkillsWithUpdateState = installedSkills.map((skill) => {
1842
+ const bundledVersion = bundledSkillVersions.get(skill.name) || "";
1843
+ const updateAvailable = Boolean(
1844
+ bundledVersion &&
1845
+ skill.version &&
1846
+ compareVersionTokens(skill.version, bundledVersion) < 0
1847
+ );
1848
+ return {
1849
+ ...skill,
1850
+ bundled_version: bundledVersion || null,
1851
+ update_available: updateAvailable,
1852
+ };
1853
+ });
1854
+
1693
1855
  return {
1694
1856
  openclaw: {
1695
1857
  detected: bridge.openclaw_installation.detected,
@@ -1700,13 +1862,14 @@ export class LocalNodeService {
1700
1862
  legacy_install_root: legacyInstallRoot,
1701
1863
  },
1702
1864
  summary: {
1703
- bundled_count: bundledSkills.length,
1704
- installed_count: installedSkills.length,
1705
- installed_bundled_count: bundledSkills.filter((item) => item.installed_in_openclaw).length,
1865
+ bundled_count: bundledSkillsWithUpdateState.length,
1866
+ installed_count: installedSkillsWithUpdateState.length,
1867
+ installed_bundled_count: bundledSkillsWithUpdateState.filter((item) => item.installed_in_openclaw).length,
1868
+ update_available_count: bundledSkillsWithUpdateState.filter((item) => item.update_available).length,
1706
1869
  },
1707
1870
  install_action: bridge.skill_learning.install_action,
1708
- bundled_skills: bundledSkills,
1709
- installed_skills: installedSkills,
1871
+ bundled_skills: bundledSkillsWithUpdateState,
1872
+ installed_skills: installedSkillsWithUpdateState,
1710
1873
  };
1711
1874
  }
1712
1875
 
@@ -2345,6 +2508,7 @@ export class LocalNodeService {
2345
2508
  this.network = next.adapter;
2346
2509
  this.adapterMode = next.mode;
2347
2510
  this.networkPort = next.port;
2511
+ this.subscriptionsBound = false;
2348
2512
 
2349
2513
  await this.network.start();
2350
2514
  this.bindNetworkSubscriptions();
@@ -2464,6 +2628,72 @@ export class LocalNodeService {
2464
2628
  });
2465
2629
  }
2466
2630
 
2631
+ private mergeMessageOnlyAgentSummaries(
2632
+ summaries: PublicProfileSummary[],
2633
+ keyword: string
2634
+ ): PublicProfileSummary[] {
2635
+ const normalizedKeyword = String(keyword || "").trim().toLowerCase();
2636
+ const knownAgentIds = new Set(summaries.map((item) => item.agent_id));
2637
+ const messageOnly: PublicProfileSummary[] = [];
2638
+
2639
+ for (const message of this.socialMessages) {
2640
+ if (!message?.agent_id || knownAgentIds.has(message.agent_id)) {
2641
+ continue;
2642
+ }
2643
+
2644
+ const displayName = String(message.display_name || "Unnamed").trim() || "Unnamed";
2645
+ if (normalizedKeyword) {
2646
+ const haystacks = [
2647
+ displayName.toLowerCase(),
2648
+ message.agent_id.toLowerCase(),
2649
+ String(message.topic || "").toLowerCase(),
2650
+ ];
2651
+ if (!haystacks.some((value) => value.includes(normalizedKeyword))) {
2652
+ continue;
2653
+ }
2654
+ }
2655
+
2656
+ knownAgentIds.add(message.agent_id);
2657
+ messageOnly.push(
2658
+ buildPublicProfileSummary({
2659
+ profile: {
2660
+ agent_id: message.agent_id,
2661
+ display_name: displayName,
2662
+ bio: "Seen from signed public message. Profile/presence not synced yet.",
2663
+ tags: ["message-only"],
2664
+ avatar_url: "",
2665
+ public_enabled: true,
2666
+ updated_at: message.created_at,
2667
+ signature: "",
2668
+ },
2669
+ online: false,
2670
+ last_seen_at: null,
2671
+ network_mode: "unknown",
2672
+ openclaw_bound: false,
2673
+ profile_version: PROFILE_VERSION,
2674
+ public_key_fingerprint: null,
2675
+ verified_profile: false,
2676
+ now: Date.now(),
2677
+ presence_ttl_ms: PRESENCE_TTL_MS,
2678
+ })
2679
+ );
2680
+ }
2681
+
2682
+ return [...summaries, ...messageOnly].sort((a, b) => {
2683
+ if (a.online !== b.online) {
2684
+ return a.online ? -1 : 1;
2685
+ }
2686
+ if (a.updated_at !== b.updated_at) {
2687
+ return b.updated_at - a.updated_at;
2688
+ }
2689
+ const byName = a.display_name.localeCompare(b.display_name);
2690
+ if (byName !== 0) {
2691
+ return byName;
2692
+ }
2693
+ return a.agent_id.localeCompare(b.agent_id);
2694
+ });
2695
+ }
2696
+
2467
2697
  private fingerprintPublicKey(publicKey: string): string {
2468
2698
  const digest = createHash("sha256").update(publicKey, "utf8").digest("hex");
2469
2699
  return `${digest.slice(0, 12)}:${digest.slice(-8)}`;
@@ -2524,7 +2754,7 @@ export class LocalNodeService {
2524
2754
  };
2525
2755
  }
2526
2756
  return {
2527
- mode: "global-preview",
2757
+ mode: DEFAULT_NETWORK_MODE,
2528
2758
  short_label: "Relay preview",
2529
2759
  summary: "Uses the public relay preview room so public nodes can find each other across the internet.",
2530
2760
  };
@@ -2554,14 +2784,14 @@ export class LocalNodeService {
2554
2784
  this.socialConfig.network.mode ||
2555
2785
  (modeEnv === "local" || modeEnv === "lan" || modeEnv === "global-preview"
2556
2786
  ? modeEnv
2557
- : "global-preview");
2787
+ : DEFAULT_NETWORK_MODE);
2558
2788
 
2559
2789
  this.networkMode = resolvedMode;
2560
- this.networkNamespace = this.socialConfig.network.namespace || process.env.NETWORK_NAMESPACE || "silicaclaw.preview";
2561
- this.networkPort = Number(this.socialConfig.network.port || process.env.NETWORK_PORT || 44123);
2790
+ this.networkNamespace = this.socialConfig.network.namespace || process.env.NETWORK_NAMESPACE || DEFAULT_NETWORK_NAMESPACE;
2791
+ this.networkPort = Number(this.socialConfig.network.port || process.env.NETWORK_PORT || DEFAULT_NETWORK_PORT);
2562
2792
 
2563
- const builtInGlobalSignalingUrls = ["https://relay.silicaclaw.com"];
2564
- const builtInGlobalRoom = "silicaclaw-global-preview";
2793
+ const builtInGlobalSignalingUrls = [DEFAULT_GLOBAL_SIGNALING_URL];
2794
+ const builtInGlobalRoom = DEFAULT_GLOBAL_ROOM;
2565
2795
 
2566
2796
  const signalingUrlsSocial = dedupeStrings(this.socialConfig.network.signaling_urls || []);
2567
2797
  const signalingUrlSocial = String(this.socialConfig.network.signaling_url || "").trim();
@@ -2586,8 +2816,8 @@ export class LocalNodeService {
2586
2816
  signalingUrls = builtInGlobalSignalingUrls;
2587
2817
  signalingSource = "built-in-defaults:global-preview.signaling_urls";
2588
2818
  } else {
2589
- signalingUrls = ["https://relay.silicaclaw.com"];
2590
- signalingSource = "default:https://relay.silicaclaw.com";
2819
+ signalingUrls = [DEFAULT_GLOBAL_SIGNALING_URL];
2820
+ signalingSource = `default:${DEFAULT_GLOBAL_SIGNALING_URL}`;
2591
2821
  }
2592
2822
 
2593
2823
  const roomSocial = String(this.socialConfig.network.room || "").trim();
@@ -2596,14 +2826,14 @@ export class LocalNodeService {
2596
2826
  roomSocial ||
2597
2827
  roomEnv ||
2598
2828
  (this.networkMode === "global-preview" ? builtInGlobalRoom : "") ||
2599
- "silicaclaw-global-preview";
2829
+ DEFAULT_GLOBAL_ROOM;
2600
2830
  const roomSource = roomSocial
2601
2831
  ? "social.md:network.room"
2602
2832
  : roomEnv
2603
2833
  ? "env:WEBRTC_ROOM"
2604
2834
  : this.networkMode === "global-preview"
2605
2835
  ? "built-in-defaults:global-preview.room"
2606
- : "default:silicaclaw-global-preview";
2836
+ : `default:${DEFAULT_GLOBAL_ROOM}`;
2607
2837
 
2608
2838
  const seedPeersSocial = dedupeStrings(this.socialConfig.network.seed_peers || []);
2609
2839
  const seedPeersEnv = dedupeStrings(parseListEnv(WEBRTC_SEED_PEERS));
@@ -2971,15 +3201,15 @@ function renderBootstrapScript(payload: unknown): string {
2971
3201
  if (data.pillBroadcastClassName) pillBroadcast.className = data.pillBroadcastClassName;
2972
3202
  }
2973
3203
  setHtml('overviewCards', data.overviewCardsHtml || '');
2974
- setText('agentsCountHint', data.agentsCountHintText || '0 agents');
2975
- setHtml('agentsWrap', data.agentsWrapHtml || '<div class="label">No discovered agents yet.</div>');
3204
+ setText('agentsCountHint', data.agentsCountHintText || '0 nodes');
3205
+ setHtml('agentsWrap', data.agentsWrapHtml || '<div class="label">No discovered nodes yet.</div>');
2976
3206
  })();
2977
3207
  </script>`;
2978
3208
  }
2979
3209
 
2980
3210
  export async function main() {
2981
3211
  const app = express();
2982
- const port = Number(process.env.PORT || 4310);
3212
+ const port = Number(process.env.PORT || defaults.ports.local_console);
2983
3213
  const staticDir = resolveLocalConsoleStaticDir();
2984
3214
  const staticIndexFile = resolve(staticDir, "index.html");
2985
3215
 
@@ -3187,9 +3417,10 @@ export async function main() {
3187
3417
 
3188
3418
  app.post(
3189
3419
  "/api/openclaw/bridge/skill-install",
3190
- asyncRoute(async (_req, res) => {
3420
+ asyncRoute(async (req, res) => {
3191
3421
  try {
3192
- const result = await node.installOpenClawSkill();
3422
+ const skillName = String(req.body?.skill_name || "").trim();
3423
+ const result = await node.installOpenClawSkill(skillName || undefined);
3193
3424
  sendOk(res, result, {
3194
3425
  message: "OpenClaw skill installed",
3195
3426
  });
@@ -3237,7 +3468,7 @@ export async function main() {
3237
3468
  const agentId = req.params.agentId;
3238
3469
  const profile = state.profiles[agentId];
3239
3470
  if (!profile) {
3240
- sendError(res, 404, "AGENT_NOT_FOUND", "Agent not found", { agent_id: agentId });
3471
+ sendError(res, 404, "AGENT_NOT_FOUND", "Node not found", { agent_id: agentId });
3241
3472
  return;
3242
3473
  }
3243
3474
 
@@ -3273,7 +3504,7 @@ export async function main() {
3273
3504
  .join("");
3274
3505
  const agentsWrapHtml =
3275
3506
  discovered.length === 0
3276
- ? `<div class="label">No discovered agents yet.</div>`
3507
+ ? `<div class="label">No discovered nodes yet.</div>`
3277
3508
  : `
3278
3509
  <table class="table">
3279
3510
  <thead><tr><th>Name</th><th>Agent ID</th><th>Status</th><th>Updated</th></tr></thead>
@@ -3309,7 +3540,7 @@ export async function main() {
3309
3540
  pillBroadcastText: overview.broadcast_enabled ? "broadcast: running" : "broadcast: paused",
3310
3541
  pillBroadcastClassName: `pill ${overview.broadcast_enabled ? "ok" : "warn"}`,
3311
3542
  overviewCardsHtml,
3312
- agentsCountHintText: `${discovered.length} agents discovered`,
3543
+ agentsCountHintText: `${discovered.length} nodes discovered`,
3313
3544
  agentsWrapHtml,
3314
3545
  integrationStatusText: `Connected to SilicaClaw: ${integration.connected_to_silicaclaw ? "yes" : "no"} · Network mode: ${integration.network_mode || "-"} · Public discovery: ${integration.public_enabled ? "enabled" : "disabled"}`,
3315
3546
  integrationStatusClassName: `integration-strip ${integration.connected_to_silicaclaw && integration.public_enabled ? "ok" : "warn"}`,
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const express_1 = __importDefault(require("express"));
7
+ const cors_1 = __importDefault(require("cors"));
8
+ const path_1 = require("path");
9
+ const fs_1 = require("fs");
10
+ const silicaclaw_defaults_json_1 = __importDefault(require("../../../config/silicaclaw-defaults.json"));
11
+ const app = (0, express_1.default)();
12
+ const port = Number(process.env.PORT || silicaclaw_defaults_json_1.default.ports.public_explorer);
13
+ function resolvePublicExplorerStaticDir() {
14
+ const candidates = [
15
+ (0, path_1.resolve)(process.cwd(), "public"),
16
+ (0, path_1.resolve)(process.cwd(), "apps", "public-explorer", "public"),
17
+ (0, path_1.resolve)(__dirname, "..", "public"),
18
+ (0, path_1.resolve)(__dirname, "..", "..", "apps", "public-explorer", "public"),
19
+ ];
20
+ for (const dir of candidates) {
21
+ if ((0, fs_1.existsSync)((0, path_1.resolve)(dir, "index.html"))) {
22
+ return dir;
23
+ }
24
+ }
25
+ return candidates[0];
26
+ }
27
+ app.use((0, cors_1.default)({ origin: true }));
28
+ app.get("/api/config", (_req, res) => {
29
+ res.json({
30
+ ok: true,
31
+ data: {
32
+ local_console_api_base: silicaclaw_defaults_json_1.default.bridge.api_base,
33
+ local_console_port: silicaclaw_defaults_json_1.default.ports.local_console,
34
+ },
35
+ });
36
+ });
37
+ app.use(express_1.default.static(resolvePublicExplorerStaticDir()));
38
+ app.listen(port, () => {
39
+ // eslint-disable-next-line no-console
40
+ console.log(`SilicaClaw public-explorer running: http://localhost:${port}`);
41
+ });
@@ -0,0 +1,19 @@
1
+ {
2
+ "ports": {
3
+ "local_console": 4310,
4
+ "public_explorer": 4311,
5
+ "openclaw_gateway": 18789,
6
+ "network_default": 44123
7
+ },
8
+ "network": {
9
+ "default_mode": "global-preview",
10
+ "default_namespace": "silicaclaw.preview",
11
+ "global_preview": {
12
+ "relay_url": "https://relay.silicaclaw.com",
13
+ "room": "silicaclaw-global-preview"
14
+ }
15
+ },
16
+ "bridge": {
17
+ "api_base": "http://localhost:4310"
18
+ }
19
+ }