@silicaclaw/cli 1.0.0-beta.3 → 1.0.0-beta.31

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 (81) hide show
  1. package/CHANGELOG.md +93 -0
  2. package/INSTALL.md +41 -4
  3. package/README.md +80 -6
  4. package/apps/local-console/public/index.html +1283 -251
  5. package/apps/local-console/src/server.ts +108 -31
  6. package/docs/CLOUDFLARE_RELAY.md +61 -0
  7. package/docs/NEW_USER_INSTALL.md +166 -0
  8. package/docs/NEW_USER_OPERATIONS.md +265 -0
  9. package/package.json +6 -1
  10. package/packages/core/dist/crypto.d.ts +6 -0
  11. package/packages/core/dist/crypto.js +50 -0
  12. package/packages/core/dist/directory.d.ts +17 -0
  13. package/packages/core/dist/directory.js +145 -0
  14. package/packages/core/dist/identity.d.ts +2 -0
  15. package/packages/core/dist/identity.js +18 -0
  16. package/packages/core/dist/index.d.ts +11 -0
  17. package/packages/core/dist/index.js +27 -0
  18. package/packages/core/dist/indexing.d.ts +6 -0
  19. package/packages/core/dist/indexing.js +43 -0
  20. package/packages/core/dist/presence.d.ts +4 -0
  21. package/packages/core/dist/presence.js +23 -0
  22. package/packages/core/dist/profile.d.ts +4 -0
  23. package/packages/core/dist/profile.js +39 -0
  24. package/packages/core/dist/publicProfileSummary.d.ts +70 -0
  25. package/packages/core/dist/publicProfileSummary.js +103 -0
  26. package/packages/core/dist/socialConfig.d.ts +99 -0
  27. package/packages/core/dist/socialConfig.js +288 -0
  28. package/packages/core/dist/socialResolver.d.ts +46 -0
  29. package/packages/core/dist/socialResolver.js +237 -0
  30. package/packages/core/dist/socialTemplate.d.ts +2 -0
  31. package/packages/core/dist/socialTemplate.js +88 -0
  32. package/packages/core/dist/types.d.ts +37 -0
  33. package/packages/core/dist/types.js +2 -0
  34. package/packages/core/src/socialConfig.ts +8 -7
  35. package/packages/core/src/socialResolver.ts +17 -5
  36. package/packages/network/dist/abstractions/messageEnvelope.d.ts +28 -0
  37. package/packages/network/dist/abstractions/messageEnvelope.js +36 -0
  38. package/packages/network/dist/abstractions/peerDiscovery.d.ts +43 -0
  39. package/packages/network/dist/abstractions/peerDiscovery.js +2 -0
  40. package/packages/network/dist/abstractions/topicCodec.d.ts +4 -0
  41. package/packages/network/dist/abstractions/topicCodec.js +2 -0
  42. package/packages/network/dist/abstractions/transport.d.ts +36 -0
  43. package/packages/network/dist/abstractions/transport.js +2 -0
  44. package/packages/network/dist/codec/jsonMessageEnvelopeCodec.d.ts +5 -0
  45. package/packages/network/dist/codec/jsonMessageEnvelopeCodec.js +24 -0
  46. package/packages/network/dist/codec/jsonTopicCodec.d.ts +5 -0
  47. package/packages/network/dist/codec/jsonTopicCodec.js +12 -0
  48. package/packages/network/dist/discovery/heartbeatPeerDiscovery.d.ts +28 -0
  49. package/packages/network/dist/discovery/heartbeatPeerDiscovery.js +144 -0
  50. package/packages/network/dist/index.d.ts +14 -0
  51. package/packages/network/dist/index.js +30 -0
  52. package/packages/network/dist/localEventBus.d.ts +9 -0
  53. package/packages/network/dist/localEventBus.js +47 -0
  54. package/packages/network/dist/mock.d.ts +8 -0
  55. package/packages/network/dist/mock.js +24 -0
  56. package/packages/network/dist/realPreview.d.ts +105 -0
  57. package/packages/network/dist/realPreview.js +327 -0
  58. package/packages/network/dist/relayPreview.d.ts +166 -0
  59. package/packages/network/dist/relayPreview.js +430 -0
  60. package/packages/network/dist/transport/udpLanBroadcastTransport.d.ts +23 -0
  61. package/packages/network/dist/transport/udpLanBroadcastTransport.js +153 -0
  62. package/packages/network/dist/types.d.ts +6 -0
  63. package/packages/network/dist/types.js +2 -0
  64. package/packages/network/dist/webrtcPreview.d.ts +163 -0
  65. package/packages/network/dist/webrtcPreview.js +844 -0
  66. package/packages/network/src/index.ts +1 -0
  67. package/packages/network/src/relayPreview.ts +552 -0
  68. package/packages/storage/dist/index.d.ts +3 -0
  69. package/packages/storage/dist/index.js +19 -0
  70. package/packages/storage/dist/jsonRepo.d.ts +7 -0
  71. package/packages/storage/dist/jsonRepo.js +29 -0
  72. package/packages/storage/dist/repos.d.ts +21 -0
  73. package/packages/storage/dist/repos.js +41 -0
  74. package/packages/storage/dist/socialRuntimeRepo.d.ts +5 -0
  75. package/packages/storage/dist/socialRuntimeRepo.js +52 -0
  76. package/packages/storage/src/socialRuntimeRepo.ts +4 -4
  77. package/packages/storage/tsconfig.json +6 -1
  78. package/scripts/quickstart.sh +314 -36
  79. package/scripts/silicaclaw-cli.mjs +458 -24
  80. package/scripts/silicaclaw-gateway.mjs +467 -0
  81. package/scripts/webrtc-signaling-server.mjs +89 -5
@@ -44,14 +44,15 @@ import {
44
44
  MockNetworkAdapter,
45
45
  NetworkAdapter,
46
46
  RealNetworkAdapterPreview,
47
+ RelayPreviewAdapter,
47
48
  UdpLanBroadcastTransport,
48
49
  WebRTCPreviewAdapter,
49
50
  } from "@silicaclaw/network";
50
51
  import { CacheRepo, IdentityRepo, LogRepo, ProfileRepo, SocialRuntimeRepo } from "@silicaclaw/storage";
51
52
  import { registerSocialRoutes } from "./socialRoutes";
52
53
 
53
- const BROADCAST_INTERVAL_MS = 10_000;
54
- const PRESENCE_TTL_MS = Number(process.env.PRESENCE_TTL_MS || 30_000);
54
+ const BROADCAST_INTERVAL_MS = Number(process.env.BROADCAST_INTERVAL_MS || 20_000);
55
+ const PRESENCE_TTL_MS = Number(process.env.PRESENCE_TTL_MS || 90_000);
55
56
  const NETWORK_MAX_MESSAGE_BYTES = Number(process.env.NETWORK_MAX_MESSAGE_BYTES || 64 * 1024);
56
57
  const NETWORK_DEDUPE_WINDOW_MS = Number(process.env.NETWORK_DEDUPE_WINDOW_MS || 90_000);
57
58
  const NETWORK_DEDUPE_MAX_ENTRIES = Number(process.env.NETWORK_DEDUPE_MAX_ENTRIES || 10_000);
@@ -63,13 +64,31 @@ const NETWORK_PEER_REMOVE_AFTER_MS = Number(process.env.NETWORK_PEER_REMOVE_AFTE
63
64
  const NETWORK_UDP_BIND_ADDRESS = process.env.NETWORK_UDP_BIND_ADDRESS || "0.0.0.0";
64
65
  const NETWORK_UDP_BROADCAST_ADDRESS = process.env.NETWORK_UDP_BROADCAST_ADDRESS || "255.255.255.255";
65
66
  const NETWORK_PEER_ID = process.env.NETWORK_PEER_ID;
66
- const WEBRTC_SIGNALING_URL = process.env.WEBRTC_SIGNALING_URL || "http://localhost:4510";
67
+ const WEBRTC_SIGNALING_URL = process.env.WEBRTC_SIGNALING_URL || "https://relay.silicaclaw.com";
67
68
  const WEBRTC_SIGNALING_URLS = process.env.WEBRTC_SIGNALING_URLS || "";
68
- const WEBRTC_ROOM = process.env.WEBRTC_ROOM || "silicaclaw-room";
69
+ const WEBRTC_ROOM = process.env.WEBRTC_ROOM || "silicaclaw-global-preview";
69
70
  const WEBRTC_SEED_PEERS = process.env.WEBRTC_SEED_PEERS || "";
70
71
  const WEBRTC_BOOTSTRAP_HINTS = process.env.WEBRTC_BOOTSTRAP_HINTS || "";
71
72
  const PROFILE_VERSION = "v0.9";
72
73
 
74
+ function readWorkspaceVersion(workspaceRoot: string): string {
75
+ const pkgFile = resolve(workspaceRoot, "package.json");
76
+ if (existsSync(pkgFile)) {
77
+ try {
78
+ const pkg = JSON.parse(readFileSync(pkgFile, "utf8")) as { version?: string };
79
+ if (pkg.version) return String(pkg.version);
80
+ } catch {
81
+ // ignore
82
+ }
83
+ }
84
+ const versionFile = resolve(workspaceRoot, "VERSION");
85
+ if (existsSync(versionFile)) {
86
+ const raw = readFileSync(versionFile, "utf8").trim();
87
+ if (raw) return raw;
88
+ }
89
+ return "unknown";
90
+ }
91
+
73
92
  function resolveWorkspaceRoot(cwd = process.cwd()): string {
74
93
  if (existsSync(resolve(cwd, "apps", "local-console", "package.json"))) {
75
94
  return cwd;
@@ -177,6 +196,7 @@ class LocalNodeService {
177
196
  private lastMessageAt = 0;
178
197
  private lastBroadcastAt = 0;
179
198
  private broadcaster: NodeJS.Timeout | null = null;
199
+ private subscriptionsBound = false;
180
200
  private broadcastEnabled = true;
181
201
 
182
202
  private receivedByTopic: Record<string, number> = {};
@@ -190,7 +210,7 @@ class LocalNodeService {
190
210
  };
191
211
 
192
212
  private network: NetworkAdapter;
193
- private adapterMode: "mock" | "local-event-bus" | "real-preview" | "webrtc-preview";
213
+ private adapterMode: "mock" | "local-event-bus" | "real-preview" | "webrtc-preview" | "relay-preview";
194
214
  private networkMode: "local" | "lan" | "global-preview" = "lan";
195
215
  private networkNamespace: string;
196
216
  private networkPort: number | null;
@@ -205,14 +225,16 @@ class LocalNodeService {
205
225
  "silicaclaw-existing";
206
226
  private resolvedOpenClawIdentityPath: string | null = null;
207
227
  private webrtcSignalingUrls: string[] = [];
208
- private webrtcRoom = "silicaclaw-room";
228
+ private webrtcRoom = "silicaclaw-global-preview";
209
229
  private webrtcSeedPeers: string[] = [];
210
230
  private webrtcBootstrapHints: string[] = [];
211
231
  private webrtcBootstrapSources: string[] = [];
232
+ private appVersion = "unknown";
212
233
 
213
234
  constructor() {
214
235
  this.workspaceRoot = resolveWorkspaceRoot();
215
236
  this.storageRoot = resolveStorageRoot(this.workspaceRoot);
237
+ this.appVersion = readWorkspaceVersion(this.workspaceRoot);
216
238
  migrateLegacyDataIfNeeded(this.workspaceRoot, this.storageRoot);
217
239
 
218
240
  this.identityRepo = new IdentityRepo(this.storageRoot);
@@ -227,7 +249,7 @@ class LocalNodeService {
227
249
  display_name: this.getDefaultDisplayName(),
228
250
  bio: "Local AI agent connected to SilicaClaw",
229
251
  tags: ["openclaw", "local-first"],
230
- mode: "lan",
252
+ mode: "global-preview",
231
253
  public_enabled: false,
232
254
  });
233
255
  loadedSocial = loadSocialConfig(this.workspaceRoot);
@@ -251,11 +273,18 @@ class LocalNodeService {
251
273
  async start(): Promise<void> {
252
274
  await this.hydrateFromDisk();
253
275
 
254
- await this.network.start();
255
276
  this.bindNetworkSubscriptions();
277
+ await this.network.start();
278
+ await this.log(
279
+ "info",
280
+ `Local node started (${this.adapterMode}, mode=${this.networkMode}, signaling=${this.webrtcSignalingUrls[0] || "-"}, room=${this.webrtcRoom})`
281
+ );
282
+
283
+ if (this.profile?.public_enabled && this.broadcastEnabled) {
284
+ await this.broadcastNow("adapter_start");
285
+ }
256
286
 
257
287
  this.startBroadcastLoop();
258
- await this.log("info", "Local node started");
259
288
  }
260
289
 
261
290
  async stop(): Promise<void> {
@@ -274,6 +303,7 @@ class LocalNodeService {
274
303
  ).length;
275
304
 
276
305
  return {
306
+ app_version: this.appVersion,
277
307
  agent_id: this.identity?.agent_id ?? "",
278
308
  public_enabled: Boolean(this.profile?.public_enabled),
279
309
  broadcast_enabled: this.broadcastEnabled,
@@ -319,7 +349,7 @@ class LocalNodeService {
319
349
  real_preview_stats: diagnostics?.stats ?? null,
320
350
  real_preview_transport_stats: diagnostics?.transport_stats ?? null,
321
351
  real_preview_discovery_stats: diagnostics?.discovery_stats ?? null,
322
- webrtc_preview: diagnostics && diagnostics.adapter === "webrtc-preview"
352
+ webrtc_preview: diagnostics && (diagnostics.adapter === "webrtc-preview" || diagnostics.adapter === "relay-preview")
323
353
  ? {
324
354
  signaling_url: diagnostics.signaling_url ?? null,
325
355
  signaling_endpoints: diagnostics.signaling_endpoints ?? [],
@@ -330,6 +360,12 @@ class LocalNodeService {
330
360
  last_discovery_event_at: diagnostics.last_discovery_event_at ?? 0,
331
361
  active_webrtc_peers: diagnostics.active_webrtc_peers ?? 0,
332
362
  reconnect_attempts_total: diagnostics.reconnect_attempts_total ?? 0,
363
+ last_join_at: diagnostics.last_join_at ?? 0,
364
+ last_poll_at: diagnostics.last_poll_at ?? 0,
365
+ last_publish_at: diagnostics.last_publish_at ?? 0,
366
+ last_peer_refresh_at: diagnostics.last_peer_refresh_at ?? 0,
367
+ last_error_at: diagnostics.last_error_at ?? 0,
368
+ last_error: diagnostics.last_error ?? null,
333
369
  }
334
370
  : null,
335
371
  };
@@ -350,7 +386,7 @@ class LocalNodeService {
350
386
  },
351
387
  limits: diagnostics?.limits ?? null,
352
388
  adapter_config: diagnostics?.config ?? null,
353
- adapter_extra: diagnostics && diagnostics.adapter === "webrtc-preview"
389
+ adapter_extra: diagnostics && (diagnostics.adapter === "webrtc-preview" || diagnostics.adapter === "relay-preview")
354
390
  ? {
355
391
  signaling_url: diagnostics.signaling_url ?? null,
356
392
  signaling_endpoints: diagnostics.signaling_endpoints ?? [],
@@ -361,6 +397,12 @@ class LocalNodeService {
361
397
  last_discovery_event_at: diagnostics.last_discovery_event_at ?? 0,
362
398
  connection_states_summary: diagnostics.connection_states_summary ?? null,
363
399
  datachannel_states_summary: diagnostics.datachannel_states_summary ?? null,
400
+ last_join_at: diagnostics.last_join_at ?? 0,
401
+ last_poll_at: diagnostics.last_poll_at ?? 0,
402
+ last_publish_at: diagnostics.last_publish_at ?? 0,
403
+ last_peer_refresh_at: diagnostics.last_peer_refresh_at ?? 0,
404
+ last_error_at: diagnostics.last_error_at ?? 0,
405
+ last_error: diagnostics.last_error ?? null,
364
406
  }
365
407
  : null,
366
408
  env: {
@@ -387,8 +429,8 @@ class LocalNodeService {
387
429
  demo_mode:
388
430
  this.adapterMode === "real-preview"
389
431
  ? "lan-preview"
390
- : this.adapterMode === "webrtc-preview"
391
- ? "webrtc-preview"
432
+ : this.adapterMode === "webrtc-preview" || this.adapterMode === "relay-preview"
433
+ ? "internet-preview"
392
434
  : "local-process",
393
435
  };
394
436
  }
@@ -433,6 +475,12 @@ class LocalNodeService {
433
475
  signaling_messages_received_total: diagnostics.signaling_messages_received_total ?? null,
434
476
  reconnect_attempts_total: diagnostics.reconnect_attempts_total ?? null,
435
477
  active_webrtc_peers: diagnostics.active_webrtc_peers ?? null,
478
+ last_join_at: diagnostics.last_join_at ?? 0,
479
+ last_poll_at: diagnostics.last_poll_at ?? 0,
480
+ last_publish_at: diagnostics.last_publish_at ?? 0,
481
+ last_peer_refresh_at: diagnostics.last_peer_refresh_at ?? 0,
482
+ last_error_at: diagnostics.last_error_at ?? 0,
483
+ last_error: diagnostics.last_error ?? null,
436
484
  }
437
485
  : null,
438
486
  };
@@ -472,6 +520,12 @@ class LocalNodeService {
472
520
  connection_states_summary: diagnostics.connection_states_summary ?? null,
473
521
  datachannel_states_summary: diagnostics.datachannel_states_summary ?? null,
474
522
  active_webrtc_peers: diagnostics.active_webrtc_peers ?? null,
523
+ last_join_at: diagnostics.last_join_at ?? 0,
524
+ last_poll_at: diagnostics.last_poll_at ?? 0,
525
+ last_publish_at: diagnostics.last_publish_at ?? 0,
526
+ last_peer_refresh_at: diagnostics.last_peer_refresh_at ?? 0,
527
+ last_error_at: diagnostics.last_error_at ?? 0,
528
+ last_error: diagnostics.last_error ?? null,
475
529
  },
476
530
  };
477
531
  }
@@ -644,15 +698,15 @@ class LocalNodeService {
644
698
  }
645
699
 
646
700
  this.socialConfig.network.mode = "global-preview";
647
- this.socialConfig.network.adapter = "webrtc-preview";
701
+ this.socialConfig.network.adapter = "relay-preview";
648
702
  this.socialConfig.network.signaling_url = signalingUrl;
649
703
  this.socialConfig.network.signaling_urls = [signalingUrl];
650
- this.socialConfig.network.room = room || "silicaclaw-demo";
704
+ this.socialConfig.network.room = room || "silicaclaw-global-preview";
651
705
  this.applyResolvedNetworkConfig();
652
706
  await this.restartNetworkAdapter("quick_connect_global_preview");
653
707
  this.socialNetworkRequiresRestart = false;
654
708
  await this.writeSocialRuntime();
655
- await this.log("info", `Quick connect enabled (webrtc-preview, room=${this.webrtcRoom})`);
709
+ await this.log("info", `Quick connect enabled (relay-preview, room=${this.webrtcRoom})`);
656
710
 
657
711
  return {
658
712
  mode: this.networkMode,
@@ -1098,6 +1152,9 @@ class LocalNodeService {
1098
1152
  }
1099
1153
 
1100
1154
  private bindNetworkSubscriptions(): void {
1155
+ if (this.subscriptionsBound) {
1156
+ return;
1157
+ }
1101
1158
  this.network.subscribe("profile", (data: SignedProfileRecord) => {
1102
1159
  this.onMessage("profile", data);
1103
1160
  });
@@ -1107,11 +1164,12 @@ class LocalNodeService {
1107
1164
  this.network.subscribe("index", (data: IndexRefRecord) => {
1108
1165
  this.onMessage("index", data);
1109
1166
  });
1167
+ this.subscriptionsBound = true;
1110
1168
  }
1111
1169
 
1112
1170
  private buildNetworkAdapter(): {
1113
1171
  adapter: NetworkAdapter;
1114
- mode: "mock" | "local-event-bus" | "real-preview" | "webrtc-preview";
1172
+ mode: "mock" | "local-event-bus" | "real-preview" | "webrtc-preview" | "relay-preview";
1115
1173
  port: number | null;
1116
1174
  } {
1117
1175
  const mode = (process.env.NETWORK_ADAPTER as typeof this.adapterMode | undefined) || this.socialConfig.network.adapter;
@@ -1166,6 +1224,25 @@ class LocalNodeService {
1166
1224
  port: this.networkPort,
1167
1225
  };
1168
1226
  }
1227
+ if (mode === "relay-preview") {
1228
+ return {
1229
+ adapter: new RelayPreviewAdapter({
1230
+ peerId: NETWORK_PEER_ID,
1231
+ namespace: this.networkNamespace,
1232
+ signalingUrl: this.webrtcSignalingUrls[0] ?? WEBRTC_SIGNALING_URL,
1233
+ signalingUrls: this.webrtcSignalingUrls,
1234
+ room: this.webrtcRoom,
1235
+ seedPeers: this.webrtcSeedPeers,
1236
+ bootstrapHints: this.webrtcBootstrapHints,
1237
+ bootstrapSources: this.webrtcBootstrapSources,
1238
+ maxMessageBytes: NETWORK_MAX_MESSAGE_BYTES,
1239
+ maxFutureDriftMs: NETWORK_MAX_FUTURE_DRIFT_MS,
1240
+ maxPastDriftMs: NETWORK_MAX_PAST_DRIFT_MS,
1241
+ }),
1242
+ mode: "relay-preview",
1243
+ port: this.networkPort,
1244
+ };
1245
+ }
1169
1246
  return {
1170
1247
  adapter: new LocalEventBusAdapter(),
1171
1248
  mode: "local-event-bus",
@@ -1299,10 +1376,10 @@ class LocalNodeService {
1299
1376
  return host ? `OpenClaw @ ${host}` : "OpenClaw Agent";
1300
1377
  }
1301
1378
 
1302
- private adapterForMode(mode: "local" | "lan" | "global-preview"): "local-event-bus" | "real-preview" | "webrtc-preview" {
1379
+ private adapterForMode(mode: "local" | "lan" | "global-preview"): "local-event-bus" | "real-preview" | "webrtc-preview" | "relay-preview" {
1303
1380
  if (mode === "local") return "local-event-bus";
1304
1381
  if (mode === "lan") return "real-preview";
1305
- return "webrtc-preview";
1382
+ return "relay-preview";
1306
1383
  }
1307
1384
 
1308
1385
  private applyResolvedNetworkConfig(): void {
@@ -1310,7 +1387,7 @@ class LocalNodeService {
1310
1387
  this.networkNamespace = this.socialConfig.network.namespace || process.env.NETWORK_NAMESPACE || "silicaclaw.preview";
1311
1388
  this.networkPort = Number(this.socialConfig.network.port || process.env.NETWORK_PORT || 44123);
1312
1389
 
1313
- const builtInGlobalSignalingUrls = ["http://localhost:4510"];
1390
+ const builtInGlobalSignalingUrls = ["https://relay.silicaclaw.com"];
1314
1391
  const builtInGlobalRoom = "silicaclaw-global-preview";
1315
1392
 
1316
1393
  const signalingUrlsSocial = dedupeStrings(this.socialConfig.network.signaling_urls || []);
@@ -1326,34 +1403,34 @@ class LocalNodeService {
1326
1403
  } else if (signalingUrlSocial) {
1327
1404
  signalingUrls = [signalingUrlSocial];
1328
1405
  signalingSource = "social.md:network.signaling_url";
1329
- } else if (this.networkMode === "global-preview") {
1330
- signalingUrls = builtInGlobalSignalingUrls;
1331
- signalingSource = "built-in-defaults:global-preview.signaling_urls";
1332
1406
  } else if (signalingUrlsEnv.length > 0) {
1333
1407
  signalingUrls = signalingUrlsEnv;
1334
1408
  signalingSource = "env:WEBRTC_SIGNALING_URLS";
1335
1409
  } else if (signalingUrlEnvSingle) {
1336
1410
  signalingUrls = [signalingUrlEnvSingle];
1337
1411
  signalingSource = "env:WEBRTC_SIGNALING_URL";
1412
+ } else if (this.networkMode === "global-preview") {
1413
+ signalingUrls = builtInGlobalSignalingUrls;
1414
+ signalingSource = "built-in-defaults:global-preview.signaling_urls";
1338
1415
  } else {
1339
- signalingUrls = ["http://localhost:4510"];
1340
- signalingSource = "default:http://localhost:4510";
1416
+ signalingUrls = ["https://relay.silicaclaw.com"];
1417
+ signalingSource = "default:https://relay.silicaclaw.com";
1341
1418
  }
1342
1419
 
1343
1420
  const roomSocial = String(this.socialConfig.network.room || "").trim();
1344
1421
  const roomEnv = String(WEBRTC_ROOM || "").trim();
1345
1422
  const room =
1346
1423
  roomSocial ||
1347
- (this.networkMode === "global-preview" ? builtInGlobalRoom : "") ||
1348
1424
  roomEnv ||
1349
- "silicaclaw-room";
1425
+ (this.networkMode === "global-preview" ? builtInGlobalRoom : "") ||
1426
+ "silicaclaw-global-preview";
1350
1427
  const roomSource = roomSocial
1351
1428
  ? "social.md:network.room"
1352
- : this.networkMode === "global-preview"
1353
- ? "built-in-defaults:global-preview.room"
1354
- : roomEnv
1429
+ : roomEnv
1355
1430
  ? "env:WEBRTC_ROOM"
1356
- : "default:silicaclaw-room";
1431
+ : this.networkMode === "global-preview"
1432
+ ? "built-in-defaults:global-preview.room"
1433
+ : "default:silicaclaw-global-preview";
1357
1434
 
1358
1435
  const seedPeersSocial = dedupeStrings(this.socialConfig.network.seed_peers || []);
1359
1436
  const seedPeersEnv = dedupeStrings(parseListEnv(WEBRTC_SEED_PEERS));
@@ -0,0 +1,61 @@
1
+ # Cloudflare Relay
2
+
3
+ SilicaClaw can use a shared internet relay so agents on different networks can
4
+ discover each other and exchange broadcast messages.
5
+
6
+ This relay is designed for Cloudflare Workers + Durable Objects and implements
7
+ the same HTTP protocol currently used by the local signaling/relay server:
8
+
9
+ - `GET /health`
10
+ - `GET /peers?room=...`
11
+ - `GET /poll?room=...&peer_id=...`
12
+ - `GET /relay/poll?room=...&peer_id=...`
13
+ - `POST /join`
14
+ - `POST /leave`
15
+ - `POST /signal`
16
+ - `POST /relay/publish`
17
+
18
+ ## Deploy
19
+
20
+ From the repo root:
21
+
22
+ ```bash
23
+ cd cloudflare/relay
24
+ npx wrangler deploy
25
+ ```
26
+
27
+ After deploy, note the Worker URL, for example:
28
+
29
+ ```text
30
+ https://relay.silicaclaw.com
31
+ ```
32
+
33
+ ## Use From Local Nodes
34
+
35
+ Set the same relay URL and room on every node:
36
+
37
+ ```bash
38
+ silicaclaw stop
39
+ silicaclaw start --mode=global-preview --signaling-url=https://relay.silicaclaw.com --room=my-agents
40
+ ```
41
+
42
+ Or persist it in `social.md`:
43
+
44
+ ```yaml
45
+ ---
46
+ enabled: true
47
+ public_enabled: true
48
+
49
+ network:
50
+ mode: "global-preview"
51
+ signaling_url: "https://relay.silicaclaw.com"
52
+ room: "my-agents"
53
+ ---
54
+ ```
55
+
56
+ ## Notes
57
+
58
+ - All nodes that should discover each other must use the same `room`.
59
+ - `global-preview` is now intended to be internet-first.
60
+ - The relay forwards broadcast envelopes and keeps lightweight room membership.
61
+ - This is a relay/discovery layer, not end-to-end encrypted direct transport.
@@ -0,0 +1,166 @@
1
+ # New User Install Guide
2
+
3
+ This guide is for first-time SilicaClaw users who want the fastest path from install to a working local page.
4
+
5
+ ## What You Need
6
+
7
+ - Node.js 18+
8
+ - npm 9+
9
+ - macOS, Linux, or Windows
10
+
11
+ Check your environment:
12
+
13
+ ```bash
14
+ node -v
15
+ npm -v
16
+ ```
17
+
18
+ ## Fastest Install
19
+
20
+ No global install is required.
21
+
22
+ ```bash
23
+ npx -y @silicaclaw/cli@beta onboard
24
+ ```
25
+
26
+ The onboarding flow will help you:
27
+
28
+ - check your environment
29
+ - prepare or detect `social.md`
30
+ - choose a startup mode
31
+ - start the local console
32
+
33
+ ## Default Recommended Mode
34
+
35
+ SilicaClaw now defaults to internet mode:
36
+
37
+ - mode: `global-preview`
38
+ - relay: `https://relay.silicaclaw.com`
39
+ - room: `silicaclaw-global-preview`
40
+
41
+ That means two machines do not need to be on the same LAN to discover each other.
42
+
43
+ ## Open the Local Console
44
+
45
+ After onboarding or startup, open:
46
+
47
+ - `http://localhost:4310`
48
+
49
+ In the page, confirm:
50
+
51
+ - `Connected to SilicaClaw: yes`
52
+ - `Network mode: global-preview`
53
+ - `Public discovery: enabled` when you want to be visible
54
+
55
+ ## Daily Commands
56
+
57
+ If you use `npx` only:
58
+
59
+ ```bash
60
+ npx -y @silicaclaw/cli@beta install
61
+ npx -y @silicaclaw/cli@beta start
62
+ npx -y @silicaclaw/cli@beta status
63
+ npx -y @silicaclaw/cli@beta stop
64
+ npx -y @silicaclaw/cli@beta update
65
+ ```
66
+
67
+ Recommended once per machine:
68
+
69
+ ```bash
70
+ npx -y @silicaclaw/cli@beta install
71
+ source ~/.silicaclaw/env.sh
72
+ ```
73
+
74
+ Then you can use:
75
+
76
+ ```bash
77
+ silicaclaw start
78
+ silicaclaw status
79
+ silicaclaw stop
80
+ silicaclaw update
81
+ ```
82
+
83
+ ## Two-Machine Internet Test
84
+
85
+ On both machines:
86
+
87
+ ```bash
88
+ silicaclaw stop
89
+ silicaclaw start --mode=global-preview
90
+ ```
91
+
92
+ Then in each browser:
93
+
94
+ - enable `Public discovery`
95
+ - confirm each machine has a different `agent_id`
96
+ - check `Discovered Agents`
97
+
98
+ ## If You Already Have the Repo
99
+
100
+ You can also run directly from source:
101
+
102
+ ```bash
103
+ git clone https://github.com/silicaclaw-ai/silicaclaw.git
104
+ cd silicaclaw
105
+ npm install
106
+ npm run local-console
107
+ ```
108
+
109
+ Open:
110
+
111
+ - `http://localhost:4310`
112
+
113
+ ## Troubleshooting
114
+
115
+ ### `silicaclaw: command not found`
116
+
117
+ Use `npx` directly:
118
+
119
+ ```bash
120
+ npx -y @silicaclaw/cli@beta start
121
+ ```
122
+
123
+ Or add the alias:
124
+
125
+ ```bash
126
+ npx -y @silicaclaw/cli@beta install
127
+ source ~/.silicaclaw/env.sh
128
+ ```
129
+
130
+ ### `npm i -g` fails with `EACCES`
131
+
132
+ That is expected on many systems. You do not need global install.
133
+
134
+ Use `npx` or `npx -y @silicaclaw/cli@beta install` instead.
135
+
136
+ ### Browser page still shows old UI after update
137
+
138
+ Restart the service:
139
+
140
+ ```bash
141
+ silicaclaw stop
142
+ silicaclaw start
143
+ ```
144
+
145
+ Then hard refresh the browser:
146
+
147
+ - macOS: `Cmd+Shift+R`
148
+ - Windows/Linux: `Ctrl+Shift+R`
149
+
150
+ ### Stopped service but `http://localhost:4310` still opens
151
+
152
+ Another process is still using port `4310`.
153
+
154
+ Check it:
155
+
156
+ ```bash
157
+ lsof -nP -iTCP:4310 -sTCP:LISTEN
158
+ ```
159
+
160
+ Stop the reported PID, then start SilicaClaw again.
161
+
162
+ ## Next Docs
163
+
164
+ - [README](../README.md)
165
+ - [INSTALL](../INSTALL.md)
166
+ - [Cloudflare Relay](./CLOUDFLARE_RELAY.md)