@silicaclaw/cli 1.0.0-beta.2 → 1.0.0-beta.21
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.
- package/CHANGELOG.md +8 -0
- package/INSTALL.md +36 -0
- package/README.md +40 -0
- package/apps/local-console/public/index.html +81 -63
- package/apps/local-console/src/server.ts +41 -21
- package/docs/CLOUDFLARE_RELAY.md +61 -0
- package/package.json +6 -1
- package/packages/core/dist/crypto.d.ts +6 -0
- package/packages/core/dist/crypto.js +50 -0
- package/packages/core/dist/directory.d.ts +17 -0
- package/packages/core/dist/directory.js +145 -0
- package/packages/core/dist/identity.d.ts +2 -0
- package/packages/core/dist/identity.js +18 -0
- package/packages/core/dist/index.d.ts +11 -0
- package/packages/core/dist/index.js +27 -0
- package/packages/core/dist/indexing.d.ts +6 -0
- package/packages/core/dist/indexing.js +43 -0
- package/packages/core/dist/presence.d.ts +4 -0
- package/packages/core/dist/presence.js +23 -0
- package/packages/core/dist/profile.d.ts +4 -0
- package/packages/core/dist/profile.js +39 -0
- package/packages/core/dist/publicProfileSummary.d.ts +70 -0
- package/packages/core/dist/publicProfileSummary.js +103 -0
- package/packages/core/dist/socialConfig.d.ts +99 -0
- package/packages/core/dist/socialConfig.js +288 -0
- package/packages/core/dist/socialResolver.d.ts +46 -0
- package/packages/core/dist/socialResolver.js +237 -0
- package/packages/core/dist/socialTemplate.d.ts +2 -0
- package/packages/core/dist/socialTemplate.js +88 -0
- package/packages/core/dist/types.d.ts +37 -0
- package/packages/core/dist/types.js +2 -0
- package/packages/core/src/socialConfig.ts +7 -6
- package/packages/core/src/socialResolver.ts +17 -5
- package/packages/network/dist/abstractions/messageEnvelope.d.ts +28 -0
- package/packages/network/dist/abstractions/messageEnvelope.js +36 -0
- package/packages/network/dist/abstractions/peerDiscovery.d.ts +43 -0
- package/packages/network/dist/abstractions/peerDiscovery.js +2 -0
- package/packages/network/dist/abstractions/topicCodec.d.ts +4 -0
- package/packages/network/dist/abstractions/topicCodec.js +2 -0
- package/packages/network/dist/abstractions/transport.d.ts +36 -0
- package/packages/network/dist/abstractions/transport.js +2 -0
- package/packages/network/dist/codec/jsonMessageEnvelopeCodec.d.ts +5 -0
- package/packages/network/dist/codec/jsonMessageEnvelopeCodec.js +24 -0
- package/packages/network/dist/codec/jsonTopicCodec.d.ts +5 -0
- package/packages/network/dist/codec/jsonTopicCodec.js +12 -0
- package/packages/network/dist/discovery/heartbeatPeerDiscovery.d.ts +28 -0
- package/packages/network/dist/discovery/heartbeatPeerDiscovery.js +144 -0
- package/packages/network/dist/index.d.ts +14 -0
- package/packages/network/dist/index.js +30 -0
- package/packages/network/dist/localEventBus.d.ts +9 -0
- package/packages/network/dist/localEventBus.js +47 -0
- package/packages/network/dist/mock.d.ts +8 -0
- package/packages/network/dist/mock.js +24 -0
- package/packages/network/dist/realPreview.d.ts +105 -0
- package/packages/network/dist/realPreview.js +327 -0
- package/packages/network/dist/relayPreview.d.ts +133 -0
- package/packages/network/dist/relayPreview.js +320 -0
- package/packages/network/dist/transport/udpLanBroadcastTransport.d.ts +23 -0
- package/packages/network/dist/transport/udpLanBroadcastTransport.js +153 -0
- package/packages/network/dist/types.d.ts +6 -0
- package/packages/network/dist/types.js +2 -0
- package/packages/network/dist/webrtcPreview.d.ts +163 -0
- package/packages/network/dist/webrtcPreview.js +844 -0
- package/packages/network/src/index.ts +1 -0
- package/packages/network/src/relayPreview.ts +425 -0
- package/packages/storage/dist/index.d.ts +3 -0
- package/packages/storage/dist/index.js +19 -0
- package/packages/storage/dist/jsonRepo.d.ts +7 -0
- package/packages/storage/dist/jsonRepo.js +29 -0
- package/packages/storage/dist/repos.d.ts +21 -0
- package/packages/storage/dist/repos.js +41 -0
- package/packages/storage/dist/socialRuntimeRepo.d.ts +5 -0
- package/packages/storage/dist/socialRuntimeRepo.js +52 -0
- package/packages/storage/src/socialRuntimeRepo.ts +3 -3
- package/packages/storage/tsconfig.json +6 -1
- package/scripts/quickstart.sh +286 -20
- package/scripts/silicaclaw-cli.mjs +271 -1
- package/scripts/silicaclaw-gateway.mjs +411 -0
- package/scripts/webrtc-signaling-server.mjs +52 -1
package/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,14 @@
|
|
|
8
8
|
- `INSTALL.md`
|
|
9
9
|
- `DEMO_GUIDE.md`
|
|
10
10
|
- `RELEASE_NOTES_v1.0.md`
|
|
11
|
+
- CLI onboarding install UX polish:
|
|
12
|
+
- added shell alias fallback (`silicaclaw -> npx @silicaclaw/cli@beta`) when global install is unavailable
|
|
13
|
+
- reduced reliance on manual PATH/env edits for first-run success
|
|
14
|
+
- `silicaclaw update` guidance polish:
|
|
15
|
+
- prioritize zero-setup `npx` flow
|
|
16
|
+
- clarify global install is optional
|
|
17
|
+
- hide global-install recommendation during `npx` runtime to avoid repeated `EACCES` loops
|
|
18
|
+
- add explicit `command not found` alias guidance for first-run shells
|
|
11
19
|
- README first-screen and structure polish:
|
|
12
20
|
- fixed v1.0 beta project positioning
|
|
13
21
|
- added concise feature summary
|
package/INSTALL.md
CHANGED
|
@@ -22,11 +22,47 @@ CLI-style onboarding command (recommended, zero-config):
|
|
|
22
22
|
npx @silicaclaw/cli@beta onboard
|
|
23
23
|
```
|
|
24
24
|
|
|
25
|
+
Cross-network quick wizard (defaults to global-preview):
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
npx @silicaclaw/cli@beta connect
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Check/update CLI version:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
npx @silicaclaw/cli@beta update
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Gateway background service commands:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
npx @silicaclaw/cli@beta gateway start --mode=local
|
|
41
|
+
npx @silicaclaw/cli@beta gateway status
|
|
42
|
+
npx @silicaclaw/cli@beta gateway restart --mode=lan
|
|
43
|
+
npx @silicaclaw/cli@beta gateway stop
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
For most home users, just press Enter on defaults and use `local` mode first.
|
|
47
|
+
|
|
25
48
|
Optional global install (advanced users only):
|
|
26
49
|
|
|
27
50
|
```bash
|
|
28
51
|
npm i -g @silicaclaw/cli
|
|
29
52
|
silicaclaw onboard
|
|
53
|
+
silicaclaw connect
|
|
54
|
+
silicaclaw update
|
|
55
|
+
silicaclaw gateway start --mode=local
|
|
56
|
+
silicaclaw gateway status
|
|
57
|
+
silicaclaw gateway stop
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
If global install fails with `EACCES`, use alias mode (no PATH edits):
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
alias silicaclaw='npx -y @silicaclaw/cli@beta'
|
|
64
|
+
silicaclaw onboard
|
|
65
|
+
silicaclaw update
|
|
30
66
|
```
|
|
31
67
|
|
|
32
68
|
## 3. Run
|
package/README.md
CHANGED
|
@@ -28,6 +28,27 @@ Without servers, accounts, or central control.
|
|
|
28
28
|
npx @silicaclaw/cli@beta onboard
|
|
29
29
|
```
|
|
30
30
|
|
|
31
|
+
Cross-network preview quick wizard:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
npx @silicaclaw/cli@beta connect
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Check and update CLI version:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
npx @silicaclaw/cli@beta update
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Background gateway service:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
npx @silicaclaw/cli@beta gateway start --mode=local
|
|
47
|
+
npx @silicaclaw/cli@beta gateway status
|
|
48
|
+
npx @silicaclaw/cli@beta gateway restart --mode=lan
|
|
49
|
+
npx @silicaclaw/cli@beta gateway stop
|
|
50
|
+
```
|
|
51
|
+
|
|
31
52
|
Or manual:
|
|
32
53
|
|
|
33
54
|
```bash
|
|
@@ -53,11 +74,30 @@ Zero-config (recommended, no global install / no PATH setup):
|
|
|
53
74
|
npx @silicaclaw/cli@beta onboard
|
|
54
75
|
```
|
|
55
76
|
|
|
77
|
+
Cross-network preview (global-preview first):
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
npx @silicaclaw/cli@beta connect
|
|
81
|
+
```
|
|
82
|
+
|
|
56
83
|
Optional global install:
|
|
57
84
|
|
|
58
85
|
```bash
|
|
59
86
|
npm i -g @silicaclaw/cli
|
|
60
87
|
silicaclaw onboard
|
|
88
|
+
silicaclaw connect
|
|
89
|
+
silicaclaw update
|
|
90
|
+
silicaclaw gateway start --mode=local
|
|
91
|
+
silicaclaw gateway status
|
|
92
|
+
silicaclaw gateway stop
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
If global install is blocked by system permissions (`EACCES`), use alias mode:
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
alias silicaclaw='npx -y @silicaclaw/cli@beta'
|
|
99
|
+
silicaclaw onboard
|
|
100
|
+
silicaclaw update
|
|
61
101
|
```
|
|
62
102
|
|
|
63
103
|
## Quick Start (OpenClaw-style)
|
|
@@ -427,6 +427,22 @@
|
|
|
427
427
|
white-space: pre-wrap;
|
|
428
428
|
word-break: break-word;
|
|
429
429
|
}
|
|
430
|
+
.advanced-panel {
|
|
431
|
+
margin-top: 10px;
|
|
432
|
+
}
|
|
433
|
+
.advanced-panel summary {
|
|
434
|
+
cursor: pointer;
|
|
435
|
+
list-style: none;
|
|
436
|
+
user-select: none;
|
|
437
|
+
}
|
|
438
|
+
.advanced-panel summary::-webkit-details-marker { display: none; }
|
|
439
|
+
.advanced-panel summary::after {
|
|
440
|
+
content: "Show";
|
|
441
|
+
float: right;
|
|
442
|
+
color: var(--muted);
|
|
443
|
+
font-size: 12px;
|
|
444
|
+
}
|
|
445
|
+
.advanced-panel[open] summary::after { content: "Hide"; }
|
|
430
446
|
|
|
431
447
|
.toast {
|
|
432
448
|
position: fixed;
|
|
@@ -474,10 +490,7 @@
|
|
|
474
490
|
<button class="tab active" data-tab="overview">Overview</button>
|
|
475
491
|
<button class="tab" data-tab="profile">Profile</button>
|
|
476
492
|
<button class="tab" data-tab="network">Network</button>
|
|
477
|
-
<button class="tab" data-tab="
|
|
478
|
-
<button class="tab" data-tab="discovery">Discovery Events</button>
|
|
479
|
-
<button class="tab" data-tab="social">Social Config</button>
|
|
480
|
-
<button class="tab" data-tab="logs">Logs</button>
|
|
493
|
+
<button class="tab" data-tab="social">Social</button>
|
|
481
494
|
</nav>
|
|
482
495
|
|
|
483
496
|
<div class="sidebar-foot" id="sideMeta">adapter: -<br/>namespace: -</div>
|
|
@@ -602,15 +615,20 @@
|
|
|
602
615
|
<div class="mono" id="networkComponents"></div>
|
|
603
616
|
</div>
|
|
604
617
|
<div class="card">
|
|
605
|
-
<h3 class="title-sm">Actions</h3>
|
|
618
|
+
<h3 class="title-sm">Quick Actions</h3>
|
|
606
619
|
<div class="actions">
|
|
607
620
|
<button id="startBroadcastBtn">Start Broadcast</button>
|
|
608
621
|
<button class="secondary" id="stopBroadcastBtn">Stop Broadcast</button>
|
|
609
622
|
<button class="secondary" id="broadcastNowBtn">Broadcast Now</button>
|
|
623
|
+
</div>
|
|
624
|
+
<details class="advanced-panel">
|
|
625
|
+
<summary class="title-sm">Advanced Actions</summary>
|
|
626
|
+
<div class="actions" style="margin-top:10px;">
|
|
610
627
|
<button class="secondary" id="refreshCacheBtn">Refresh Cache</button>
|
|
611
628
|
<button class="secondary" id="clearCacheBtn">Clear Discovered Cache</button>
|
|
612
629
|
<button class="secondary" id="quickGlobalPreviewBtn">Enable Cross-network Preview</button>
|
|
613
630
|
</div>
|
|
631
|
+
</details>
|
|
614
632
|
<div id="networkFeedback" class="feedback" style="margin-top:10px;">Ready.</div>
|
|
615
633
|
</div>
|
|
616
634
|
</div>
|
|
@@ -624,32 +642,47 @@
|
|
|
624
642
|
<div class="mono mono-block" id="networkStatsSnapshot">-</div>
|
|
625
643
|
</div>
|
|
626
644
|
</div>
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
<div class="grid" id="peerCards"></div>
|
|
631
|
-
<div class="card" style="margin-top:10px;">
|
|
632
|
-
<h3 class="title-sm">Peer Inventory</h3>
|
|
633
|
-
<div id="peerTableWrap"></div>
|
|
634
|
-
</div>
|
|
635
|
-
<div class="card" style="margin-top:10px;">
|
|
636
|
-
<h3 class="title-sm">Peer Discovery Stats</h3>
|
|
637
|
-
<div class="mono mono-block" id="peerStatsWrap">-</div>
|
|
638
|
-
</div>
|
|
639
|
-
</section>
|
|
640
|
-
|
|
641
|
-
<section id="view-discovery" class="view">
|
|
642
|
-
<div class="grid" id="discoveryCards"></div>
|
|
643
|
-
<div class="split">
|
|
645
|
+
<details class="advanced-panel card">
|
|
646
|
+
<summary class="title-sm">Diagnostics</summary>
|
|
647
|
+
<div class="grid" id="peerCards" style="margin-top:10px;"></div>
|
|
644
648
|
<div class="card" style="margin-top:10px;">
|
|
645
|
-
<h3 class="title-sm">
|
|
646
|
-
<div
|
|
649
|
+
<h3 class="title-sm">Peer Inventory</h3>
|
|
650
|
+
<div id="peerTableWrap"></div>
|
|
647
651
|
</div>
|
|
648
652
|
<div class="card" style="margin-top:10px;">
|
|
649
|
-
<h3 class="title-sm">Discovery
|
|
650
|
-
<div class="mono mono-block" id="
|
|
653
|
+
<h3 class="title-sm">Peer Discovery Stats</h3>
|
|
654
|
+
<div class="mono mono-block" id="peerStatsWrap">-</div>
|
|
651
655
|
</div>
|
|
652
|
-
|
|
656
|
+
<div class="grid" id="discoveryCards" style="margin-top:10px;"></div>
|
|
657
|
+
<div class="split">
|
|
658
|
+
<div class="card" style="margin-top:10px;">
|
|
659
|
+
<h3 class="title-sm">Recent Discovery Events</h3>
|
|
660
|
+
<div class="logs" id="discoveryEventList"></div>
|
|
661
|
+
</div>
|
|
662
|
+
<div class="card" style="margin-top:10px;">
|
|
663
|
+
<h3 class="title-sm">Discovery Snapshot</h3>
|
|
664
|
+
<div class="mono mono-block" id="discoverySnapshot">-</div>
|
|
665
|
+
</div>
|
|
666
|
+
</div>
|
|
667
|
+
<div class="card" style="margin-top:10px;">
|
|
668
|
+
<h3 class="title-sm">Logs</h3>
|
|
669
|
+
<div class="toolbar">
|
|
670
|
+
<div class="field">
|
|
671
|
+
<label for="logLevelFilter">Category</label>
|
|
672
|
+
<select id="logLevelFilter">
|
|
673
|
+
<option value="all">all</option>
|
|
674
|
+
<option value="info">info</option>
|
|
675
|
+
<option value="warn">warn</option>
|
|
676
|
+
<option value="error">error</option>
|
|
677
|
+
</select>
|
|
678
|
+
</div>
|
|
679
|
+
<div>
|
|
680
|
+
<button type="button" class="secondary" id="refreshLogsBtn">Refresh Logs</button>
|
|
681
|
+
</div>
|
|
682
|
+
</div>
|
|
683
|
+
<div class="logs" id="logList"></div>
|
|
684
|
+
</div>
|
|
685
|
+
</details>
|
|
653
686
|
</section>
|
|
654
687
|
|
|
655
688
|
<section id="view-social" class="view">
|
|
@@ -666,22 +699,25 @@
|
|
|
666
699
|
<div class="grid" id="socialAdvancedCards" style="margin-top:10px;"></div>
|
|
667
700
|
<div class="mono mono-block" id="socialAdvancedWrap" style="margin-top:10px;">-</div>
|
|
668
701
|
</details>
|
|
669
|
-
<
|
|
670
|
-
<
|
|
671
|
-
|
|
672
|
-
<div class="
|
|
673
|
-
|
|
674
|
-
|
|
702
|
+
<details class="advanced-panel card">
|
|
703
|
+
<summary class="title-sm">Source / Runtime / Template</summary>
|
|
704
|
+
<div class="split">
|
|
705
|
+
<div class="card" style="margin-top:10px;">
|
|
706
|
+
<h3 class="title-sm">Source & Parsed Frontmatter</h3>
|
|
707
|
+
<div class="mono mono-block" id="socialSourceWrap">-</div>
|
|
708
|
+
<div style="height:10px;"></div>
|
|
709
|
+
<div class="mono mono-block" id="socialRawWrap">-</div>
|
|
710
|
+
</div>
|
|
711
|
+
<div class="card" style="margin-top:10px;">
|
|
712
|
+
<h3 class="title-sm">Runtime Summary</h3>
|
|
713
|
+
<div class="mono mono-block" id="socialRuntimeWrap">-</div>
|
|
714
|
+
</div>
|
|
675
715
|
</div>
|
|
676
716
|
<div class="card" style="margin-top:10px;">
|
|
677
|
-
<h3 class="title-sm">
|
|
678
|
-
<div class="mono mono-block" id="
|
|
717
|
+
<h3 class="title-sm">Export Template Preview</h3>
|
|
718
|
+
<div class="mono mono-block" id="socialTemplateWrap">-</div>
|
|
679
719
|
</div>
|
|
680
|
-
</
|
|
681
|
-
<div class="card" style="margin-top:10px;">
|
|
682
|
-
<h3 class="title-sm">Export Template Preview</h3>
|
|
683
|
-
<div class="mono mono-block" id="socialTemplateWrap">-</div>
|
|
684
|
-
</div>
|
|
720
|
+
</details>
|
|
685
721
|
<div class="card" style="margin-top:10px;">
|
|
686
722
|
<h3 class="title-sm">Actions</h3>
|
|
687
723
|
<div class="toolbar">
|
|
@@ -707,27 +743,6 @@
|
|
|
707
743
|
<div id="socialFeedback" class="feedback" style="margin-top:10px;">Ready.</div>
|
|
708
744
|
</div>
|
|
709
745
|
</section>
|
|
710
|
-
|
|
711
|
-
<section id="view-logs" class="view">
|
|
712
|
-
<div class="card">
|
|
713
|
-
<h3 class="title-sm">Recent Logs</h3>
|
|
714
|
-
<div class="toolbar">
|
|
715
|
-
<div class="field">
|
|
716
|
-
<label for="logLevelFilter">Category</label>
|
|
717
|
-
<select id="logLevelFilter">
|
|
718
|
-
<option value="all">all</option>
|
|
719
|
-
<option value="info">info</option>
|
|
720
|
-
<option value="warn">warn</option>
|
|
721
|
-
<option value="error">error</option>
|
|
722
|
-
</select>
|
|
723
|
-
</div>
|
|
724
|
-
<div>
|
|
725
|
-
<button type="button" class="secondary" id="refreshLogsBtn">Refresh Logs</button>
|
|
726
|
-
</div>
|
|
727
|
-
</div>
|
|
728
|
-
<div class="logs" id="logList"></div>
|
|
729
|
-
</div>
|
|
730
|
-
</section>
|
|
731
746
|
</main>
|
|
732
747
|
</div>
|
|
733
748
|
|
|
@@ -919,7 +934,7 @@
|
|
|
919
934
|
}
|
|
920
935
|
activeTab = tab;
|
|
921
936
|
document.querySelectorAll('.tab').forEach((b) => b.classList.toggle('active', b.dataset.tab === tab));
|
|
922
|
-
['overview', 'profile', 'network', '
|
|
937
|
+
['overview', 'profile', 'network', 'social'].forEach((k) => {
|
|
923
938
|
document.getElementById(`view-${k}`).classList.toggle('active', k === tab);
|
|
924
939
|
});
|
|
925
940
|
if (tab === 'profile' && !profileDirty && !profileSaving) {
|
|
@@ -1320,7 +1335,10 @@
|
|
|
1320
1335
|
|
|
1321
1336
|
async function refreshAll() {
|
|
1322
1337
|
try {
|
|
1323
|
-
const tasks = [refreshOverview(), refreshNetwork(),
|
|
1338
|
+
const tasks = [refreshOverview(), refreshNetwork(), refreshSocial(), refreshPublicProfilePreview()];
|
|
1339
|
+
if (activeTab === 'network') {
|
|
1340
|
+
tasks.push(refreshPeers(), refreshDiscovery(), refreshLogs());
|
|
1341
|
+
}
|
|
1324
1342
|
const shouldRefreshProfile = !(activeTab === 'profile' && profileDirty);
|
|
1325
1343
|
if (shouldRefreshProfile) {
|
|
1326
1344
|
tasks.push(refreshProfile());
|
|
@@ -44,6 +44,7 @@ import {
|
|
|
44
44
|
MockNetworkAdapter,
|
|
45
45
|
NetworkAdapter,
|
|
46
46
|
RealNetworkAdapterPreview,
|
|
47
|
+
RelayPreviewAdapter,
|
|
47
48
|
UdpLanBroadcastTransport,
|
|
48
49
|
WebRTCPreviewAdapter,
|
|
49
50
|
} from "@silicaclaw/network";
|
|
@@ -65,7 +66,7 @@ const NETWORK_UDP_BROADCAST_ADDRESS = process.env.NETWORK_UDP_BROADCAST_ADDRESS
|
|
|
65
66
|
const NETWORK_PEER_ID = process.env.NETWORK_PEER_ID;
|
|
66
67
|
const WEBRTC_SIGNALING_URL = process.env.WEBRTC_SIGNALING_URL || "http://localhost:4510";
|
|
67
68
|
const WEBRTC_SIGNALING_URLS = process.env.WEBRTC_SIGNALING_URLS || "";
|
|
68
|
-
const WEBRTC_ROOM = process.env.WEBRTC_ROOM || "silicaclaw-
|
|
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";
|
|
@@ -190,7 +191,7 @@ class LocalNodeService {
|
|
|
190
191
|
};
|
|
191
192
|
|
|
192
193
|
private network: NetworkAdapter;
|
|
193
|
-
private adapterMode: "mock" | "local-event-bus" | "real-preview" | "webrtc-preview";
|
|
194
|
+
private adapterMode: "mock" | "local-event-bus" | "real-preview" | "webrtc-preview" | "relay-preview";
|
|
194
195
|
private networkMode: "local" | "lan" | "global-preview" = "lan";
|
|
195
196
|
private networkNamespace: string;
|
|
196
197
|
private networkPort: number | null;
|
|
@@ -205,7 +206,7 @@ class LocalNodeService {
|
|
|
205
206
|
"silicaclaw-existing";
|
|
206
207
|
private resolvedOpenClawIdentityPath: string | null = null;
|
|
207
208
|
private webrtcSignalingUrls: string[] = [];
|
|
208
|
-
private webrtcRoom = "silicaclaw-
|
|
209
|
+
private webrtcRoom = "silicaclaw-global-preview";
|
|
209
210
|
private webrtcSeedPeers: string[] = [];
|
|
210
211
|
private webrtcBootstrapHints: string[] = [];
|
|
211
212
|
private webrtcBootstrapSources: string[] = [];
|
|
@@ -319,7 +320,7 @@ class LocalNodeService {
|
|
|
319
320
|
real_preview_stats: diagnostics?.stats ?? null,
|
|
320
321
|
real_preview_transport_stats: diagnostics?.transport_stats ?? null,
|
|
321
322
|
real_preview_discovery_stats: diagnostics?.discovery_stats ?? null,
|
|
322
|
-
webrtc_preview: diagnostics && diagnostics.adapter === "webrtc-preview"
|
|
323
|
+
webrtc_preview: diagnostics && (diagnostics.adapter === "webrtc-preview" || diagnostics.adapter === "relay-preview")
|
|
323
324
|
? {
|
|
324
325
|
signaling_url: diagnostics.signaling_url ?? null,
|
|
325
326
|
signaling_endpoints: diagnostics.signaling_endpoints ?? [],
|
|
@@ -350,7 +351,7 @@ class LocalNodeService {
|
|
|
350
351
|
},
|
|
351
352
|
limits: diagnostics?.limits ?? null,
|
|
352
353
|
adapter_config: diagnostics?.config ?? null,
|
|
353
|
-
adapter_extra: diagnostics && diagnostics.adapter === "webrtc-preview"
|
|
354
|
+
adapter_extra: diagnostics && (diagnostics.adapter === "webrtc-preview" || diagnostics.adapter === "relay-preview")
|
|
354
355
|
? {
|
|
355
356
|
signaling_url: diagnostics.signaling_url ?? null,
|
|
356
357
|
signaling_endpoints: diagnostics.signaling_endpoints ?? [],
|
|
@@ -387,8 +388,8 @@ class LocalNodeService {
|
|
|
387
388
|
demo_mode:
|
|
388
389
|
this.adapterMode === "real-preview"
|
|
389
390
|
? "lan-preview"
|
|
390
|
-
: this.adapterMode === "webrtc-preview"
|
|
391
|
-
? "
|
|
391
|
+
: this.adapterMode === "webrtc-preview" || this.adapterMode === "relay-preview"
|
|
392
|
+
? "internet-preview"
|
|
392
393
|
: "local-process",
|
|
393
394
|
};
|
|
394
395
|
}
|
|
@@ -644,7 +645,7 @@ class LocalNodeService {
|
|
|
644
645
|
}
|
|
645
646
|
|
|
646
647
|
this.socialConfig.network.mode = "global-preview";
|
|
647
|
-
this.socialConfig.network.adapter = "
|
|
648
|
+
this.socialConfig.network.adapter = "relay-preview";
|
|
648
649
|
this.socialConfig.network.signaling_url = signalingUrl;
|
|
649
650
|
this.socialConfig.network.signaling_urls = [signalingUrl];
|
|
650
651
|
this.socialConfig.network.room = room || "silicaclaw-demo";
|
|
@@ -652,7 +653,7 @@ class LocalNodeService {
|
|
|
652
653
|
await this.restartNetworkAdapter("quick_connect_global_preview");
|
|
653
654
|
this.socialNetworkRequiresRestart = false;
|
|
654
655
|
await this.writeSocialRuntime();
|
|
655
|
-
await this.log("info", `Quick connect enabled (
|
|
656
|
+
await this.log("info", `Quick connect enabled (relay-preview, room=${this.webrtcRoom})`);
|
|
656
657
|
|
|
657
658
|
return {
|
|
658
659
|
mode: this.networkMode,
|
|
@@ -1111,7 +1112,7 @@ class LocalNodeService {
|
|
|
1111
1112
|
|
|
1112
1113
|
private buildNetworkAdapter(): {
|
|
1113
1114
|
adapter: NetworkAdapter;
|
|
1114
|
-
mode: "mock" | "local-event-bus" | "real-preview" | "webrtc-preview";
|
|
1115
|
+
mode: "mock" | "local-event-bus" | "real-preview" | "webrtc-preview" | "relay-preview";
|
|
1115
1116
|
port: number | null;
|
|
1116
1117
|
} {
|
|
1117
1118
|
const mode = (process.env.NETWORK_ADAPTER as typeof this.adapterMode | undefined) || this.socialConfig.network.adapter;
|
|
@@ -1166,6 +1167,25 @@ class LocalNodeService {
|
|
|
1166
1167
|
port: this.networkPort,
|
|
1167
1168
|
};
|
|
1168
1169
|
}
|
|
1170
|
+
if (mode === "relay-preview") {
|
|
1171
|
+
return {
|
|
1172
|
+
adapter: new RelayPreviewAdapter({
|
|
1173
|
+
peerId: NETWORK_PEER_ID,
|
|
1174
|
+
namespace: this.networkNamespace,
|
|
1175
|
+
signalingUrl: this.webrtcSignalingUrls[0] ?? WEBRTC_SIGNALING_URL,
|
|
1176
|
+
signalingUrls: this.webrtcSignalingUrls,
|
|
1177
|
+
room: this.webrtcRoom,
|
|
1178
|
+
seedPeers: this.webrtcSeedPeers,
|
|
1179
|
+
bootstrapHints: this.webrtcBootstrapHints,
|
|
1180
|
+
bootstrapSources: this.webrtcBootstrapSources,
|
|
1181
|
+
maxMessageBytes: NETWORK_MAX_MESSAGE_BYTES,
|
|
1182
|
+
maxFutureDriftMs: NETWORK_MAX_FUTURE_DRIFT_MS,
|
|
1183
|
+
maxPastDriftMs: NETWORK_MAX_PAST_DRIFT_MS,
|
|
1184
|
+
}),
|
|
1185
|
+
mode: "relay-preview",
|
|
1186
|
+
port: this.networkPort,
|
|
1187
|
+
};
|
|
1188
|
+
}
|
|
1169
1189
|
return {
|
|
1170
1190
|
adapter: new LocalEventBusAdapter(),
|
|
1171
1191
|
mode: "local-event-bus",
|
|
@@ -1299,10 +1319,10 @@ class LocalNodeService {
|
|
|
1299
1319
|
return host ? `OpenClaw @ ${host}` : "OpenClaw Agent";
|
|
1300
1320
|
}
|
|
1301
1321
|
|
|
1302
|
-
private adapterForMode(mode: "local" | "lan" | "global-preview"): "local-event-bus" | "real-preview" | "webrtc-preview" {
|
|
1322
|
+
private adapterForMode(mode: "local" | "lan" | "global-preview"): "local-event-bus" | "real-preview" | "webrtc-preview" | "relay-preview" {
|
|
1303
1323
|
if (mode === "local") return "local-event-bus";
|
|
1304
1324
|
if (mode === "lan") return "real-preview";
|
|
1305
|
-
return "
|
|
1325
|
+
return "relay-preview";
|
|
1306
1326
|
}
|
|
1307
1327
|
|
|
1308
1328
|
private applyResolvedNetworkConfig(): void {
|
|
@@ -1326,15 +1346,15 @@ class LocalNodeService {
|
|
|
1326
1346
|
} else if (signalingUrlSocial) {
|
|
1327
1347
|
signalingUrls = [signalingUrlSocial];
|
|
1328
1348
|
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
1349
|
} else if (signalingUrlsEnv.length > 0) {
|
|
1333
1350
|
signalingUrls = signalingUrlsEnv;
|
|
1334
1351
|
signalingSource = "env:WEBRTC_SIGNALING_URLS";
|
|
1335
1352
|
} else if (signalingUrlEnvSingle) {
|
|
1336
1353
|
signalingUrls = [signalingUrlEnvSingle];
|
|
1337
1354
|
signalingSource = "env:WEBRTC_SIGNALING_URL";
|
|
1355
|
+
} else if (this.networkMode === "global-preview") {
|
|
1356
|
+
signalingUrls = builtInGlobalSignalingUrls;
|
|
1357
|
+
signalingSource = "built-in-defaults:global-preview.signaling_urls";
|
|
1338
1358
|
} else {
|
|
1339
1359
|
signalingUrls = ["http://localhost:4510"];
|
|
1340
1360
|
signalingSource = "default:http://localhost:4510";
|
|
@@ -1344,16 +1364,16 @@ class LocalNodeService {
|
|
|
1344
1364
|
const roomEnv = String(WEBRTC_ROOM || "").trim();
|
|
1345
1365
|
const room =
|
|
1346
1366
|
roomSocial ||
|
|
1347
|
-
(this.networkMode === "global-preview" ? builtInGlobalRoom : "") ||
|
|
1348
1367
|
roomEnv ||
|
|
1349
|
-
"
|
|
1368
|
+
(this.networkMode === "global-preview" ? builtInGlobalRoom : "") ||
|
|
1369
|
+
"silicaclaw-global-preview";
|
|
1350
1370
|
const roomSource = roomSocial
|
|
1351
1371
|
? "social.md:network.room"
|
|
1352
|
-
:
|
|
1353
|
-
? "built-in-defaults:global-preview.room"
|
|
1354
|
-
: roomEnv
|
|
1372
|
+
: roomEnv
|
|
1355
1373
|
? "env:WEBRTC_ROOM"
|
|
1356
|
-
: "
|
|
1374
|
+
: this.networkMode === "global-preview"
|
|
1375
|
+
? "built-in-defaults:global-preview.room"
|
|
1376
|
+
: "default:silicaclaw-global-preview";
|
|
1357
1377
|
|
|
1358
1378
|
const seedPeersSocial = dedupeStrings(this.socialConfig.network.seed_peers || []);
|
|
1359
1379
|
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://silicaclaw-relay.your-subdomain.workers.dev
|
|
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://silicaclaw-relay.your-subdomain.workers.dev --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://silicaclaw-relay.your-subdomain.workers.dev"
|
|
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.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@silicaclaw/cli",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
3
|
+
"version": "1.0.0-beta.21",
|
|
4
4
|
"private": false,
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -15,12 +15,15 @@
|
|
|
15
15
|
"apps/public-explorer/src/**",
|
|
16
16
|
"apps/public-explorer/tsconfig.json",
|
|
17
17
|
"packages/core/package.json",
|
|
18
|
+
"packages/core/dist/**",
|
|
18
19
|
"packages/core/src/**",
|
|
19
20
|
"packages/core/tsconfig.json",
|
|
20
21
|
"packages/network/package.json",
|
|
22
|
+
"packages/network/dist/**",
|
|
21
23
|
"packages/network/src/**",
|
|
22
24
|
"packages/network/tsconfig.json",
|
|
23
25
|
"packages/storage/package.json",
|
|
26
|
+
"packages/storage/dist/**",
|
|
24
27
|
"packages/storage/src/**",
|
|
25
28
|
"packages/storage/tsconfig.json",
|
|
26
29
|
"scripts/",
|
|
@@ -45,10 +48,12 @@
|
|
|
45
48
|
"packages/*"
|
|
46
49
|
],
|
|
47
50
|
"scripts": {
|
|
51
|
+
"prepack": "npm run build",
|
|
48
52
|
"build": "npm run -ws build",
|
|
49
53
|
"dev": "npm run --workspace @silicaclaw/local-console dev",
|
|
50
54
|
"onboard": "node scripts/silicaclaw-cli.mjs onboard",
|
|
51
55
|
"quickstart": "bash scripts/quickstart.sh",
|
|
56
|
+
"gateway": "node scripts/silicaclaw-gateway.mjs",
|
|
52
57
|
"local-console": "npm run --workspace @silicaclaw/local-console dev",
|
|
53
58
|
"public-explorer": "npm run --workspace @silicaclaw/public-explorer dev",
|
|
54
59
|
"logo": "bash scripts/install-logo.sh",
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export declare function toBase64(input: Uint8Array): string;
|
|
2
|
+
export declare function fromBase64(input: string): Uint8Array;
|
|
3
|
+
export declare function hashPublicKey(publicKey: Uint8Array): string;
|
|
4
|
+
export declare function stableStringify(input: unknown): string;
|
|
5
|
+
export declare function signPayload(payload: unknown, privateKeyBase64: string): string;
|
|
6
|
+
export declare function verifyPayload(payload: unknown, signatureBase64: string, publicKeyBase64: string): boolean;
|
|
@@ -0,0 +1,50 @@
|
|
|
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
|
+
exports.toBase64 = toBase64;
|
|
7
|
+
exports.fromBase64 = fromBase64;
|
|
8
|
+
exports.hashPublicKey = hashPublicKey;
|
|
9
|
+
exports.stableStringify = stableStringify;
|
|
10
|
+
exports.signPayload = signPayload;
|
|
11
|
+
exports.verifyPayload = verifyPayload;
|
|
12
|
+
const crypto_1 = require("crypto");
|
|
13
|
+
const tweetnacl_1 = __importDefault(require("tweetnacl"));
|
|
14
|
+
function toBase64(input) {
|
|
15
|
+
return Buffer.from(input).toString("base64");
|
|
16
|
+
}
|
|
17
|
+
function fromBase64(input) {
|
|
18
|
+
return new Uint8Array(Buffer.from(input, "base64"));
|
|
19
|
+
}
|
|
20
|
+
function hashPublicKey(publicKey) {
|
|
21
|
+
return (0, crypto_1.createHash)("sha256").update(publicKey).digest("hex");
|
|
22
|
+
}
|
|
23
|
+
function stableStringify(input) {
|
|
24
|
+
if (input === null || typeof input !== "object") {
|
|
25
|
+
return JSON.stringify(input);
|
|
26
|
+
}
|
|
27
|
+
if (Array.isArray(input)) {
|
|
28
|
+
return `[${input.map((item) => stableStringify(item)).join(",")}]`;
|
|
29
|
+
}
|
|
30
|
+
const entries = Object.entries(input)
|
|
31
|
+
.filter(([, value]) => value !== undefined)
|
|
32
|
+
.sort(([a], [b]) => a.localeCompare(b));
|
|
33
|
+
return `{${entries
|
|
34
|
+
.map(([key, value]) => `${JSON.stringify(key)}:${stableStringify(value)}`)
|
|
35
|
+
.join(",")}}`;
|
|
36
|
+
}
|
|
37
|
+
function signPayload(payload, privateKeyBase64) {
|
|
38
|
+
const payloadString = stableStringify(payload);
|
|
39
|
+
const signature = tweetnacl_1.default.sign.detached(Buffer.from(payloadString), fromBase64(privateKeyBase64));
|
|
40
|
+
return toBase64(signature);
|
|
41
|
+
}
|
|
42
|
+
function verifyPayload(payload, signatureBase64, publicKeyBase64) {
|
|
43
|
+
try {
|
|
44
|
+
const payloadString = stableStringify(payload);
|
|
45
|
+
return tweetnacl_1.default.sign.detached.verify(Buffer.from(payloadString), fromBase64(signatureBase64), fromBase64(publicKeyBase64));
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
}
|