@silicaclaw/cli 1.0.0-beta.21 → 1.0.0-beta.23
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 +33 -0
- package/INSTALL.md +1 -1
- package/README.md +54 -22
- package/apps/local-console/public/index.html +246 -26
- package/apps/local-console/src/server.ts +44 -8
- package/docs/CLOUDFLARE_RELAY.md +3 -3
- package/docs/NEW_USER_INSTALL.md +164 -0
- package/package.json +1 -1
- package/packages/core/dist/socialConfig.js +1 -1
- package/packages/core/src/socialConfig.ts +1 -1
- package/packages/network/dist/relayPreview.d.ts +24 -0
- package/packages/network/dist/relayPreview.js +82 -18
- package/packages/network/src/relayPreview.ts +97 -18
- package/packages/storage/dist/socialRuntimeRepo.js +1 -1
- package/packages/storage/src/socialRuntimeRepo.ts +1 -1
- package/scripts/quickstart.sh +3 -3
- package/scripts/silicaclaw-cli.mjs +76 -5
- package/scripts/silicaclaw-gateway.mjs +5 -5
- package/scripts/webrtc-signaling-server.mjs +29 -1
|
@@ -74,13 +74,20 @@
|
|
|
74
74
|
display: grid;
|
|
75
75
|
grid-template-columns: 240px 1fr;
|
|
76
76
|
min-height: 100vh;
|
|
77
|
+
transition: grid-template-columns .2s ease;
|
|
78
|
+
}
|
|
79
|
+
.app.nav-collapsed {
|
|
80
|
+
grid-template-columns: 84px 1fr;
|
|
77
81
|
}
|
|
78
82
|
|
|
79
83
|
.sidebar {
|
|
80
84
|
border-right: 1px solid color-mix(in srgb, var(--line) 74%, transparent);
|
|
81
85
|
background: color-mix(in srgb, var(--panel) 96%, transparent);
|
|
82
86
|
padding: 18px 14px;
|
|
87
|
+
position: relative;
|
|
88
|
+
transition: padding .2s ease;
|
|
83
89
|
}
|
|
90
|
+
.app.nav-collapsed .sidebar { padding-inline: 10px; }
|
|
84
91
|
.brand {
|
|
85
92
|
display: flex;
|
|
86
93
|
align-items: center;
|
|
@@ -116,6 +123,24 @@
|
|
|
116
123
|
color: var(--muted);
|
|
117
124
|
font-size: 12px;
|
|
118
125
|
}
|
|
126
|
+
.sidebar-toggle {
|
|
127
|
+
width: 100%;
|
|
128
|
+
margin: 0 0 12px;
|
|
129
|
+
border: 1px solid var(--line);
|
|
130
|
+
background: var(--bg-elevated);
|
|
131
|
+
color: var(--muted);
|
|
132
|
+
font-size: 12px;
|
|
133
|
+
text-align: left;
|
|
134
|
+
}
|
|
135
|
+
.app.nav-collapsed .brand h1,
|
|
136
|
+
.app.nav-collapsed .brand p,
|
|
137
|
+
.app.nav-collapsed .tab-copy,
|
|
138
|
+
.app.nav-collapsed .sidebar-foot {
|
|
139
|
+
display: none;
|
|
140
|
+
}
|
|
141
|
+
.app.nav-collapsed .brand {
|
|
142
|
+
justify-content: center;
|
|
143
|
+
}
|
|
119
144
|
|
|
120
145
|
.nav {
|
|
121
146
|
display: grid;
|
|
@@ -131,6 +156,18 @@
|
|
|
131
156
|
cursor: pointer;
|
|
132
157
|
font: inherit;
|
|
133
158
|
}
|
|
159
|
+
.nav button .tab-title {
|
|
160
|
+
display: block;
|
|
161
|
+
font-weight: 700;
|
|
162
|
+
color: var(--text);
|
|
163
|
+
}
|
|
164
|
+
.nav button .tab-copy {
|
|
165
|
+
display: block;
|
|
166
|
+
margin-top: 3px;
|
|
167
|
+
font-size: 11px;
|
|
168
|
+
color: var(--muted);
|
|
169
|
+
line-height: 1.35;
|
|
170
|
+
}
|
|
134
171
|
.nav button.active {
|
|
135
172
|
color: #e9f7ff;
|
|
136
173
|
border-color: color-mix(in srgb, var(--brand) 28%, transparent);
|
|
@@ -149,6 +186,13 @@
|
|
|
149
186
|
.main {
|
|
150
187
|
padding: 18px;
|
|
151
188
|
}
|
|
189
|
+
.app.focus-mode .sidebar,
|
|
190
|
+
.app.focus-mode .topbar {
|
|
191
|
+
display: none;
|
|
192
|
+
}
|
|
193
|
+
.app.focus-mode {
|
|
194
|
+
grid-template-columns: 1fr;
|
|
195
|
+
}
|
|
152
196
|
.topbar {
|
|
153
197
|
display: flex;
|
|
154
198
|
justify-content: space-between;
|
|
@@ -172,6 +216,11 @@
|
|
|
172
216
|
flex-wrap: wrap;
|
|
173
217
|
align-items: center;
|
|
174
218
|
}
|
|
219
|
+
.utility-row {
|
|
220
|
+
display: flex;
|
|
221
|
+
gap: 8px;
|
|
222
|
+
margin-left: 6px;
|
|
223
|
+
}
|
|
175
224
|
.theme-switch {
|
|
176
225
|
display: inline-flex;
|
|
177
226
|
gap: 4px;
|
|
@@ -233,6 +282,46 @@
|
|
|
233
282
|
.integration-strip.warn {
|
|
234
283
|
border-color: rgba(245, 158, 11, 0.35);
|
|
235
284
|
}
|
|
285
|
+
.page-hero {
|
|
286
|
+
display: grid;
|
|
287
|
+
grid-template-columns: 1.2fr .8fr;
|
|
288
|
+
gap: 10px;
|
|
289
|
+
margin-bottom: 12px;
|
|
290
|
+
}
|
|
291
|
+
.hero-copy {
|
|
292
|
+
border: 1px solid var(--line);
|
|
293
|
+
border-radius: 14px;
|
|
294
|
+
background: color-mix(in srgb, var(--card) 92%, transparent);
|
|
295
|
+
padding: 14px;
|
|
296
|
+
}
|
|
297
|
+
.hero-copy h3 {
|
|
298
|
+
margin: 0;
|
|
299
|
+
font-size: 20px;
|
|
300
|
+
color: var(--text-strong);
|
|
301
|
+
}
|
|
302
|
+
.hero-copy p {
|
|
303
|
+
margin: 8px 0 0;
|
|
304
|
+
color: var(--muted);
|
|
305
|
+
font-size: 13px;
|
|
306
|
+
line-height: 1.5;
|
|
307
|
+
}
|
|
308
|
+
.hero-meta {
|
|
309
|
+
border: 1px solid var(--line);
|
|
310
|
+
border-radius: 14px;
|
|
311
|
+
background: color-mix(in srgb, var(--bg-elevated) 90%, transparent);
|
|
312
|
+
padding: 14px;
|
|
313
|
+
}
|
|
314
|
+
.hero-meta-grid {
|
|
315
|
+
display: grid;
|
|
316
|
+
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
317
|
+
gap: 8px;
|
|
318
|
+
}
|
|
319
|
+
.hero-meta-item {
|
|
320
|
+
border: 1px solid var(--line);
|
|
321
|
+
border-radius: 10px;
|
|
322
|
+
background: color-mix(in srgb, var(--panel) 88%, transparent);
|
|
323
|
+
padding: 10px;
|
|
324
|
+
}
|
|
236
325
|
|
|
237
326
|
.view { display: none; }
|
|
238
327
|
.view.active { display: block; }
|
|
@@ -248,6 +337,11 @@
|
|
|
248
337
|
background: var(--card);
|
|
249
338
|
padding: 12px;
|
|
250
339
|
box-shadow: 0 1px 2px rgba(0,0,0,0.25);
|
|
340
|
+
transition: border-color .16s ease, transform .16s ease, box-shadow .16s ease;
|
|
341
|
+
}
|
|
342
|
+
.card:hover {
|
|
343
|
+
border-color: color-mix(in srgb, var(--brand) 14%, var(--line));
|
|
344
|
+
box-shadow: 0 6px 22px rgba(0, 0, 0, 0.18);
|
|
251
345
|
}
|
|
252
346
|
.label { font-size: 12px; color: var(--muted); }
|
|
253
347
|
.value { margin-top: 4px; font-size: 24px; font-weight: 800; }
|
|
@@ -305,6 +399,31 @@
|
|
|
305
399
|
gap: 8px;
|
|
306
400
|
flex-wrap: wrap;
|
|
307
401
|
}
|
|
402
|
+
.action-bar {
|
|
403
|
+
display: flex;
|
|
404
|
+
gap: 8px;
|
|
405
|
+
flex-wrap: wrap;
|
|
406
|
+
margin-bottom: 10px;
|
|
407
|
+
}
|
|
408
|
+
.summary-list {
|
|
409
|
+
display: grid;
|
|
410
|
+
gap: 8px;
|
|
411
|
+
}
|
|
412
|
+
.summary-item {
|
|
413
|
+
display: grid;
|
|
414
|
+
gap: 3px;
|
|
415
|
+
padding: 10px;
|
|
416
|
+
border-radius: 10px;
|
|
417
|
+
border: 1px solid var(--line);
|
|
418
|
+
background: color-mix(in srgb, var(--bg-elevated) 88%, transparent);
|
|
419
|
+
}
|
|
420
|
+
.empty-state {
|
|
421
|
+
border: 1px dashed var(--line-strong);
|
|
422
|
+
border-radius: 12px;
|
|
423
|
+
padding: 16px;
|
|
424
|
+
color: var(--muted);
|
|
425
|
+
background: color-mix(in srgb, var(--panel) 88%, transparent);
|
|
426
|
+
}
|
|
308
427
|
button {
|
|
309
428
|
border: 1px solid transparent;
|
|
310
429
|
border-radius: 10px;
|
|
@@ -468,15 +587,16 @@
|
|
|
468
587
|
@media (max-width: 980px) {
|
|
469
588
|
.app { grid-template-columns: 1fr; }
|
|
470
589
|
.sidebar { border-right: 0; border-bottom: 1px solid var(--line); }
|
|
471
|
-
.nav { grid-template-columns: repeat(
|
|
590
|
+
.nav { grid-template-columns: repeat(2, minmax(0,1fr)); }
|
|
472
591
|
.grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
|
|
473
|
-
.split, .row, .profile-layout { grid-template-columns: 1fr; }
|
|
592
|
+
.split, .row, .profile-layout, .page-hero { grid-template-columns: 1fr; }
|
|
474
593
|
}
|
|
475
594
|
</style>
|
|
476
595
|
</head>
|
|
477
596
|
<body>
|
|
478
|
-
<div class="app">
|
|
597
|
+
<div class="app" id="appShell">
|
|
479
598
|
<aside class="sidebar">
|
|
599
|
+
<button class="secondary sidebar-toggle" id="sidebarToggleBtn" type="button">Collapse sidebar</button>
|
|
480
600
|
<div class="brand">
|
|
481
601
|
<img id="brandLogo" class="brand-logo" src="/assets/silicaclaw-logo.png" alt="SilicaClaw logo" />
|
|
482
602
|
<div id="brandFallback" class="brand-badge hidden">SC</div>
|
|
@@ -487,10 +607,10 @@
|
|
|
487
607
|
</div>
|
|
488
608
|
|
|
489
609
|
<nav class="nav">
|
|
490
|
-
<button class="tab active" data-tab="overview">Overview</button>
|
|
491
|
-
<button class="tab" data-tab="profile">Profile</button>
|
|
492
|
-
<button class="tab" data-tab="network">Network</button>
|
|
493
|
-
<button class="tab" data-tab="social">Social</button>
|
|
610
|
+
<button class="tab active" data-tab="overview"><span class="tab-title">Overview</span><span class="tab-copy">Agent summary and discovered peers</span></button>
|
|
611
|
+
<button class="tab" data-tab="profile"><span class="tab-title">Profile</span><span class="tab-copy">Public identity and saved profile</span></button>
|
|
612
|
+
<button class="tab" data-tab="network"><span class="tab-title">Network</span><span class="tab-copy">Relay health, broadcast, diagnostics</span></button>
|
|
613
|
+
<button class="tab" data-tab="social"><span class="tab-title">Social</span><span class="tab-copy">social.md config and runtime state</span></button>
|
|
494
614
|
</nav>
|
|
495
615
|
|
|
496
616
|
<div class="sidebar-foot" id="sideMeta">adapter: -<br/>namespace: -</div>
|
|
@@ -509,11 +629,29 @@
|
|
|
509
629
|
<button id="themeDarkBtn" type="button">Dark</button>
|
|
510
630
|
<button id="themeLightBtn" type="button">Light</button>
|
|
511
631
|
</div>
|
|
632
|
+
<div class="utility-row">
|
|
633
|
+
<button class="secondary" id="refreshAllBtn" type="button">Refresh</button>
|
|
634
|
+
<button class="secondary" id="focusModeBtn" type="button">Focus mode</button>
|
|
635
|
+
</div>
|
|
512
636
|
</div>
|
|
513
637
|
</div>
|
|
514
638
|
<div class="integration-strip warn" id="integrationStatusBar">
|
|
515
639
|
Connected to SilicaClaw: - · Network mode: - · Public discovery: -
|
|
516
640
|
</div>
|
|
641
|
+
<section class="page-hero">
|
|
642
|
+
<div class="hero-copy">
|
|
643
|
+
<h3 id="pageHeroTitle">Overview</h3>
|
|
644
|
+
<p id="pageHeroBody">See the live state of this node, whether discovery is working, and whether other public agents are visible.</p>
|
|
645
|
+
</div>
|
|
646
|
+
<div class="hero-meta">
|
|
647
|
+
<div class="hero-meta-grid">
|
|
648
|
+
<div class="hero-meta-item"><div class="label">Mode</div><div class="mono" id="heroMode">-</div></div>
|
|
649
|
+
<div class="hero-meta-item"><div class="label">Adapter</div><div class="mono" id="heroAdapter">-</div></div>
|
|
650
|
+
<div class="hero-meta-item"><div class="label">Relay</div><div class="mono" id="heroRelay">-</div></div>
|
|
651
|
+
<div class="hero-meta-item"><div class="label">Room</div><div class="mono" id="heroRoom">-</div></div>
|
|
652
|
+
</div>
|
|
653
|
+
</div>
|
|
654
|
+
</section>
|
|
517
655
|
|
|
518
656
|
<div class="notice" id="initNotice"></div>
|
|
519
657
|
<div class="actions" id="onboardingActions" style="display:none; margin:8px 0 12px;">
|
|
@@ -525,6 +663,11 @@
|
|
|
525
663
|
</div>
|
|
526
664
|
|
|
527
665
|
<section id="view-overview" class="view active">
|
|
666
|
+
<div class="action-bar">
|
|
667
|
+
<button id="overviewBroadcastNowBtn" type="button">Broadcast Now</button>
|
|
668
|
+
<button class="secondary" id="overviewGoProfileBtn" type="button">Edit Profile</button>
|
|
669
|
+
<button class="secondary" id="overviewGoNetworkBtn" type="button">Open Network Diagnostics</button>
|
|
670
|
+
</div>
|
|
528
671
|
<div class="grid" id="overviewCards"></div>
|
|
529
672
|
<div class="split">
|
|
530
673
|
<div class="card">
|
|
@@ -611,11 +754,12 @@
|
|
|
611
754
|
<div class="grid" id="networkCards"></div>
|
|
612
755
|
<div class="split">
|
|
613
756
|
<div class="card">
|
|
614
|
-
<h3 class="title-sm">
|
|
615
|
-
<div class="
|
|
757
|
+
<h3 class="title-sm">Connection Summary</h3>
|
|
758
|
+
<div class="summary-list" id="networkSummaryList"></div>
|
|
616
759
|
</div>
|
|
617
760
|
<div class="card">
|
|
618
761
|
<h3 class="title-sm">Quick Actions</h3>
|
|
762
|
+
<div class="field-hint" style="margin-bottom:10px;">Use these first. Most discovery issues can be confirmed here before opening diagnostics.</div>
|
|
619
763
|
<div class="actions">
|
|
620
764
|
<button id="startBroadcastBtn">Start Broadcast</button>
|
|
621
765
|
<button class="secondary" id="stopBroadcastBtn">Stop Broadcast</button>
|
|
@@ -632,18 +776,12 @@
|
|
|
632
776
|
<div id="networkFeedback" class="feedback" style="margin-top:10px;">Ready.</div>
|
|
633
777
|
</div>
|
|
634
778
|
</div>
|
|
635
|
-
<div class="split">
|
|
636
|
-
<div class="card" style="margin-top:10px;">
|
|
637
|
-
<h3 class="title-sm">Config Snapshot</h3>
|
|
638
|
-
<div class="mono mono-block" id="networkConfigSnapshot">-</div>
|
|
639
|
-
</div>
|
|
640
|
-
<div class="card" style="margin-top:10px;">
|
|
641
|
-
<h3 class="title-sm">Stats Snapshot</h3>
|
|
642
|
-
<div class="mono mono-block" id="networkStatsSnapshot">-</div>
|
|
643
|
-
</div>
|
|
644
|
-
</div>
|
|
645
779
|
<details class="advanced-panel card">
|
|
646
780
|
<summary class="title-sm">Diagnostics</summary>
|
|
781
|
+
<div class="card" style="margin-top:10px;">
|
|
782
|
+
<h3 class="title-sm">Runtime Components</h3>
|
|
783
|
+
<div class="mono" id="networkComponents"></div>
|
|
784
|
+
</div>
|
|
647
785
|
<div class="grid" id="peerCards" style="margin-top:10px;"></div>
|
|
648
786
|
<div class="card" style="margin-top:10px;">
|
|
649
787
|
<h3 class="title-sm">Peer Inventory</h3>
|
|
@@ -682,6 +820,16 @@
|
|
|
682
820
|
</div>
|
|
683
821
|
<div class="logs" id="logList"></div>
|
|
684
822
|
</div>
|
|
823
|
+
<div class="split">
|
|
824
|
+
<div class="card" style="margin-top:10px;">
|
|
825
|
+
<h3 class="title-sm">Config Snapshot</h3>
|
|
826
|
+
<div class="mono mono-block" id="networkConfigSnapshot">-</div>
|
|
827
|
+
</div>
|
|
828
|
+
<div class="card" style="margin-top:10px;">
|
|
829
|
+
<h3 class="title-sm">Stats Snapshot</h3>
|
|
830
|
+
<div class="mono mono-block" id="networkStatsSnapshot">-</div>
|
|
831
|
+
</div>
|
|
832
|
+
</div>
|
|
685
833
|
</details>
|
|
686
834
|
</section>
|
|
687
835
|
|
|
@@ -692,8 +840,16 @@
|
|
|
692
840
|
<div class="field-hint" id="socialStatusSubline">-</div>
|
|
693
841
|
<div class="field-hint" id="socialStateHint">-</div>
|
|
694
842
|
</div>
|
|
695
|
-
<div class="
|
|
696
|
-
|
|
843
|
+
<div class="split" style="margin-top:10px;">
|
|
844
|
+
<div class="card">
|
|
845
|
+
<h3 class="title-sm">What Is Active</h3>
|
|
846
|
+
<div class="grid" id="socialPrimaryCards"></div>
|
|
847
|
+
</div>
|
|
848
|
+
<div class="card">
|
|
849
|
+
<h3 class="title-sm">Identity Binding</h3>
|
|
850
|
+
<div class="grid" id="socialIntegrationCards"></div>
|
|
851
|
+
</div>
|
|
852
|
+
</div>
|
|
697
853
|
<details class="card" style="margin-top:10px;">
|
|
698
854
|
<summary class="title-sm" style="cursor:pointer;">Advanced Network Details</summary>
|
|
699
855
|
<div class="grid" id="socialAdvancedCards" style="margin-top:10px;"></div>
|
|
@@ -757,6 +913,24 @@
|
|
|
757
913
|
let logLevelFilter = 'all';
|
|
758
914
|
let socialTemplate = '';
|
|
759
915
|
let onlyShowOnline = false;
|
|
916
|
+
const pageMeta = {
|
|
917
|
+
overview: {
|
|
918
|
+
title: 'Overview',
|
|
919
|
+
body: 'See the live state of this node, whether discovery is healthy, and whether other public agents are visible through the relay.',
|
|
920
|
+
},
|
|
921
|
+
profile: {
|
|
922
|
+
title: 'Profile',
|
|
923
|
+
body: 'Edit the signed public identity card that other agents can discover. Saved profile data should survive restart and update.',
|
|
924
|
+
},
|
|
925
|
+
network: {
|
|
926
|
+
title: 'Network',
|
|
927
|
+
body: 'Inspect relay connectivity, peer inventory, broadcast timing, and diagnostics when cross-device discovery is not working.',
|
|
928
|
+
},
|
|
929
|
+
social: {
|
|
930
|
+
title: 'Social',
|
|
931
|
+
body: 'Review social.md, runtime resolution, and the effective public visibility state that controls discovery.',
|
|
932
|
+
},
|
|
933
|
+
};
|
|
760
934
|
|
|
761
935
|
function ago(ts) {
|
|
762
936
|
if (!ts) return '-';
|
|
@@ -937,6 +1111,9 @@
|
|
|
937
1111
|
['overview', 'profile', 'network', 'social'].forEach((k) => {
|
|
938
1112
|
document.getElementById(`view-${k}`).classList.toggle('active', k === tab);
|
|
939
1113
|
});
|
|
1114
|
+
const meta = pageMeta[tab] || pageMeta.overview;
|
|
1115
|
+
document.getElementById('pageHeroTitle').textContent = meta.title;
|
|
1116
|
+
document.getElementById('pageHeroBody').textContent = meta.body;
|
|
940
1117
|
if (tab === 'profile' && !profileDirty && !profileSaving) {
|
|
941
1118
|
refreshProfile().catch(() => {});
|
|
942
1119
|
}
|
|
@@ -961,6 +1138,7 @@
|
|
|
961
1138
|
`broadcast_enabled: ${o.broadcast_enabled}`,
|
|
962
1139
|
`last_broadcast: ${ago(o.last_broadcast_at)}`,
|
|
963
1140
|
].join('\n');
|
|
1141
|
+
document.getElementById('heroMode').textContent = o.social?.network_mode || '-';
|
|
964
1142
|
|
|
965
1143
|
document.getElementById('pillBroadcast').textContent = o.broadcast_enabled ? 'broadcast: running' : 'broadcast: paused';
|
|
966
1144
|
document.getElementById('pillBroadcast').className = `pill ${o.broadcast_enabled ? 'ok' : 'warn'}`;
|
|
@@ -1060,6 +1238,9 @@
|
|
|
1060
1238
|
const d = s.adapter_discovery_stats || {};
|
|
1061
1239
|
const dx = s.adapter_diagnostics_summary || {};
|
|
1062
1240
|
const ac = s.adapter_config || c.adapter_config || {};
|
|
1241
|
+
document.getElementById('heroAdapter').textContent = c.adapter || '-';
|
|
1242
|
+
document.getElementById('heroRelay').textContent = dx.signaling_url || '-';
|
|
1243
|
+
document.getElementById('heroRoom').textContent = dx.room || '-';
|
|
1063
1244
|
|
|
1064
1245
|
document.getElementById('pillAdapter').textContent = `adapter: ${c.adapter}`;
|
|
1065
1246
|
document.getElementById('sideMeta').innerHTML = `adapter: ${c.adapter}<br/>namespace: ${c.namespace || '-'}<br/>port: ${c.port ?? '-'}`;
|
|
@@ -1085,6 +1266,15 @@
|
|
|
1085
1266
|
['Last Inbound', ago(msg.last_message_at)],
|
|
1086
1267
|
['Last Outbound', ago(msg.last_broadcast_at)],
|
|
1087
1268
|
].map(([k,v]) => `<div class="card"><div class="label">${k}</div><div class="value" style="font-size:17px;">${v}</div></div>`).join('');
|
|
1269
|
+
document.getElementById('networkSummaryList').innerHTML = [
|
|
1270
|
+
['Relay health', dx.last_error ? 'degraded' : 'connected'],
|
|
1271
|
+
['Current relay', dx.signaling_url || '-'],
|
|
1272
|
+
['Current room', dx.room || '-'],
|
|
1273
|
+
['Last join', ago(dx.last_join_at)],
|
|
1274
|
+
['Last poll', ago(dx.last_poll_at)],
|
|
1275
|
+
['Last publish', ago(dx.last_publish_at)],
|
|
1276
|
+
['Last error', dx.last_error || 'none'],
|
|
1277
|
+
].map(([k, v]) => `<div class="summary-item"><div class="label">${k}</div><div class="mono">${v}</div></div>`).join('');
|
|
1088
1278
|
|
|
1089
1279
|
const comp = c.components || {};
|
|
1090
1280
|
const lim = c.limits || {};
|
|
@@ -1112,6 +1302,12 @@
|
|
|
1112
1302
|
`discovery_heartbeat_send_errors: ${d.heartbeat_send_errors ?? '-'}`,
|
|
1113
1303
|
`signaling_messages_sent_total: ${dx.signaling_messages_sent_total ?? '-'}`,
|
|
1114
1304
|
`signaling_messages_received_total: ${dx.signaling_messages_received_total ?? '-'}`,
|
|
1305
|
+
`last_join_at: ${dx.last_join_at ? new Date(dx.last_join_at).toISOString() : '-'}`,
|
|
1306
|
+
`last_poll_at: ${dx.last_poll_at ? new Date(dx.last_poll_at).toISOString() : '-'}`,
|
|
1307
|
+
`last_publish_at: ${dx.last_publish_at ? new Date(dx.last_publish_at).toISOString() : '-'}`,
|
|
1308
|
+
`last_peer_refresh_at: ${dx.last_peer_refresh_at ? new Date(dx.last_peer_refresh_at).toISOString() : '-'}`,
|
|
1309
|
+
`last_error_at: ${dx.last_error_at ? new Date(dx.last_error_at).toISOString() : '-'}`,
|
|
1310
|
+
`last_error: ${dx.last_error || '-'}`,
|
|
1115
1311
|
`signaling_endpoints: ${Array.isArray(dx.signaling_endpoints) ? dx.signaling_endpoints.join(', ') : '-'}`,
|
|
1116
1312
|
`bootstrap_sources: ${Array.isArray(dx.bootstrap_sources) ? dx.bootstrap_sources.join(', ') : '-'}`,
|
|
1117
1313
|
`seed_peers_count: ${dx.seed_peers_count ?? '-'}`,
|
|
@@ -1143,6 +1339,9 @@
|
|
|
1143
1339
|
['Signaling URL', summary.signaling_url || '-'],
|
|
1144
1340
|
['Signaling Endpoints', (summary.signaling_endpoints || []).length || 0],
|
|
1145
1341
|
['Room', summary.room || '-'],
|
|
1342
|
+
['Last Join', ago(summary.last_join_at)],
|
|
1343
|
+
['Last Poll', ago(summary.last_poll_at)],
|
|
1344
|
+
['Last Publish', ago(summary.last_publish_at)],
|
|
1146
1345
|
['Bootstrap Sources', (summary.bootstrap_sources || []).length || 0],
|
|
1147
1346
|
['Seed Peers', summary.seed_peers_count ?? 0],
|
|
1148
1347
|
['Discovery Events', summary.discovery_events_total ?? 0],
|
|
@@ -1154,7 +1353,7 @@
|
|
|
1154
1353
|
].map(([k,v]) => `<div class="card"><div class="label">${k}</div><div class="value" style="font-size:17px;">${v}</div></div>`).join('');
|
|
1155
1354
|
|
|
1156
1355
|
if (!peers.items || !peers.items.length) {
|
|
1157
|
-
document.getElementById('peerTableWrap').innerHTML = '<div class="
|
|
1356
|
+
document.getElementById('peerTableWrap').innerHTML = '<div class="empty-state">No peers discovered yet. Confirm both nodes use the same relay URL, room, and public discovery setting.</div>';
|
|
1158
1357
|
document.getElementById('peerStatsWrap').textContent = toPrettyJson({
|
|
1159
1358
|
discovery_stats: ds,
|
|
1160
1359
|
diagnostics_summary: summary,
|
|
@@ -1202,7 +1401,7 @@
|
|
|
1202
1401
|
].map(([k,v]) => `<div class="card"><div class="label">${k}</div><div class="value" style="font-size:17px;">${v}</div></div>`).join('');
|
|
1203
1402
|
|
|
1204
1403
|
if (!items.length) {
|
|
1205
|
-
document.getElementById('discoveryEventList').innerHTML = '<div class="
|
|
1404
|
+
document.getElementById('discoveryEventList').innerHTML = '<div class="empty-state">No discovery events yet. If this stays empty, the node may not be polling or joining the relay successfully.</div>';
|
|
1206
1405
|
} else {
|
|
1207
1406
|
document.getElementById('discoveryEventList').innerHTML = items
|
|
1208
1407
|
.slice()
|
|
@@ -1310,14 +1509,14 @@
|
|
|
1310
1509
|
function renderLogs() {
|
|
1311
1510
|
const el = document.getElementById('logList');
|
|
1312
1511
|
if (!logsCache.length) {
|
|
1313
|
-
el.innerHTML = '<div class="
|
|
1512
|
+
el.innerHTML = '<div class="empty-state">No logs yet.</div>';
|
|
1314
1513
|
return;
|
|
1315
1514
|
}
|
|
1316
1515
|
const filtered = logLevelFilter === 'all'
|
|
1317
1516
|
? logsCache
|
|
1318
1517
|
: logsCache.filter((l) => String(l.level || '').toLowerCase() === logLevelFilter);
|
|
1319
1518
|
if (!filtered.length) {
|
|
1320
|
-
el.innerHTML = `<div class="
|
|
1519
|
+
el.innerHTML = `<div class="empty-state">No ${logLevelFilter} logs.</div>`;
|
|
1321
1520
|
return;
|
|
1322
1521
|
}
|
|
1323
1522
|
el.innerHTML = filtered.map((l) => `
|
|
@@ -1354,6 +1553,27 @@
|
|
|
1354
1553
|
});
|
|
1355
1554
|
document.getElementById('themeDarkBtn').addEventListener('click', () => applyTheme('dark'));
|
|
1356
1555
|
document.getElementById('themeLightBtn').addEventListener('click', () => applyTheme('light'));
|
|
1556
|
+
document.getElementById('refreshAllBtn').addEventListener('click', async () => {
|
|
1557
|
+
await refreshAll();
|
|
1558
|
+
toast('Refreshed');
|
|
1559
|
+
});
|
|
1560
|
+
document.getElementById('focusModeBtn').addEventListener('click', () => {
|
|
1561
|
+
const shell = document.getElementById('appShell');
|
|
1562
|
+
const next = !shell.classList.contains('focus-mode');
|
|
1563
|
+
shell.classList.toggle('focus-mode', next);
|
|
1564
|
+
document.getElementById('focusModeBtn').textContent = next ? 'Exit focus' : 'Focus mode';
|
|
1565
|
+
});
|
|
1566
|
+
document.getElementById('sidebarToggleBtn').addEventListener('click', () => {
|
|
1567
|
+
const shell = document.getElementById('appShell');
|
|
1568
|
+
const next = !shell.classList.contains('nav-collapsed');
|
|
1569
|
+
shell.classList.toggle('nav-collapsed', next);
|
|
1570
|
+
document.getElementById('sidebarToggleBtn').textContent = next ? 'Expand sidebar' : 'Collapse sidebar';
|
|
1571
|
+
});
|
|
1572
|
+
document.getElementById('overviewBroadcastNowBtn').addEventListener('click', () => {
|
|
1573
|
+
document.getElementById('broadcastNowBtn').click();
|
|
1574
|
+
});
|
|
1575
|
+
document.getElementById('overviewGoProfileBtn').addEventListener('click', () => switchTab('profile'));
|
|
1576
|
+
document.getElementById('overviewGoNetworkBtn').addEventListener('click', () => switchTab('network'));
|
|
1357
1577
|
|
|
1358
1578
|
document.getElementById('profileForm').addEventListener('submit', async (event) => {
|
|
1359
1579
|
event.preventDefault();
|
|
@@ -1442,7 +1662,7 @@
|
|
|
1442
1662
|
document.getElementById('quickGlobalPreviewBtn').addEventListener('click', async () => {
|
|
1443
1663
|
const currentSignaling = window.prompt('Signaling URL (publicly reachable):', 'http://localhost:4510');
|
|
1444
1664
|
if (!currentSignaling) return;
|
|
1445
|
-
const room = window.prompt('Room:', 'silicaclaw-
|
|
1665
|
+
const room = window.prompt('Room:', 'silicaclaw-global-preview') || 'silicaclaw-global-preview';
|
|
1446
1666
|
setFeedback('networkFeedback', 'Enabling cross-network preview...');
|
|
1447
1667
|
try {
|
|
1448
1668
|
const result = await api('/api/network/quick-connect-global-preview', {
|
|
@@ -64,7 +64,7 @@ const NETWORK_PEER_REMOVE_AFTER_MS = Number(process.env.NETWORK_PEER_REMOVE_AFTE
|
|
|
64
64
|
const NETWORK_UDP_BIND_ADDRESS = process.env.NETWORK_UDP_BIND_ADDRESS || "0.0.0.0";
|
|
65
65
|
const NETWORK_UDP_BROADCAST_ADDRESS = process.env.NETWORK_UDP_BROADCAST_ADDRESS || "255.255.255.255";
|
|
66
66
|
const NETWORK_PEER_ID = process.env.NETWORK_PEER_ID;
|
|
67
|
-
const WEBRTC_SIGNALING_URL = process.env.WEBRTC_SIGNALING_URL || "
|
|
67
|
+
const WEBRTC_SIGNALING_URL = process.env.WEBRTC_SIGNALING_URL || "https://relay.silicaclaw.com";
|
|
68
68
|
const WEBRTC_SIGNALING_URLS = process.env.WEBRTC_SIGNALING_URLS || "";
|
|
69
69
|
const WEBRTC_ROOM = process.env.WEBRTC_ROOM || "silicaclaw-global-preview";
|
|
70
70
|
const WEBRTC_SEED_PEERS = process.env.WEBRTC_SEED_PEERS || "";
|
|
@@ -178,6 +178,7 @@ class LocalNodeService {
|
|
|
178
178
|
private lastMessageAt = 0;
|
|
179
179
|
private lastBroadcastAt = 0;
|
|
180
180
|
private broadcaster: NodeJS.Timeout | null = null;
|
|
181
|
+
private subscriptionsBound = false;
|
|
181
182
|
private broadcastEnabled = true;
|
|
182
183
|
|
|
183
184
|
private receivedByTopic: Record<string, number> = {};
|
|
@@ -228,7 +229,7 @@ class LocalNodeService {
|
|
|
228
229
|
display_name: this.getDefaultDisplayName(),
|
|
229
230
|
bio: "Local AI agent connected to SilicaClaw",
|
|
230
231
|
tags: ["openclaw", "local-first"],
|
|
231
|
-
mode: "
|
|
232
|
+
mode: "global-preview",
|
|
232
233
|
public_enabled: false,
|
|
233
234
|
});
|
|
234
235
|
loadedSocial = loadSocialConfig(this.workspaceRoot);
|
|
@@ -252,11 +253,18 @@ class LocalNodeService {
|
|
|
252
253
|
async start(): Promise<void> {
|
|
253
254
|
await this.hydrateFromDisk();
|
|
254
255
|
|
|
255
|
-
await this.network.start();
|
|
256
256
|
this.bindNetworkSubscriptions();
|
|
257
|
+
await this.network.start();
|
|
258
|
+
await this.log(
|
|
259
|
+
"info",
|
|
260
|
+
`Local node started (${this.adapterMode}, mode=${this.networkMode}, signaling=${this.webrtcSignalingUrls[0] || "-"}, room=${this.webrtcRoom})`
|
|
261
|
+
);
|
|
262
|
+
|
|
263
|
+
if (this.profile?.public_enabled && this.broadcastEnabled) {
|
|
264
|
+
await this.broadcastNow("adapter_start");
|
|
265
|
+
}
|
|
257
266
|
|
|
258
267
|
this.startBroadcastLoop();
|
|
259
|
-
await this.log("info", "Local node started");
|
|
260
268
|
}
|
|
261
269
|
|
|
262
270
|
async stop(): Promise<void> {
|
|
@@ -331,6 +339,12 @@ class LocalNodeService {
|
|
|
331
339
|
last_discovery_event_at: diagnostics.last_discovery_event_at ?? 0,
|
|
332
340
|
active_webrtc_peers: diagnostics.active_webrtc_peers ?? 0,
|
|
333
341
|
reconnect_attempts_total: diagnostics.reconnect_attempts_total ?? 0,
|
|
342
|
+
last_join_at: diagnostics.last_join_at ?? 0,
|
|
343
|
+
last_poll_at: diagnostics.last_poll_at ?? 0,
|
|
344
|
+
last_publish_at: diagnostics.last_publish_at ?? 0,
|
|
345
|
+
last_peer_refresh_at: diagnostics.last_peer_refresh_at ?? 0,
|
|
346
|
+
last_error_at: diagnostics.last_error_at ?? 0,
|
|
347
|
+
last_error: diagnostics.last_error ?? null,
|
|
334
348
|
}
|
|
335
349
|
: null,
|
|
336
350
|
};
|
|
@@ -362,6 +376,12 @@ class LocalNodeService {
|
|
|
362
376
|
last_discovery_event_at: diagnostics.last_discovery_event_at ?? 0,
|
|
363
377
|
connection_states_summary: diagnostics.connection_states_summary ?? null,
|
|
364
378
|
datachannel_states_summary: diagnostics.datachannel_states_summary ?? null,
|
|
379
|
+
last_join_at: diagnostics.last_join_at ?? 0,
|
|
380
|
+
last_poll_at: diagnostics.last_poll_at ?? 0,
|
|
381
|
+
last_publish_at: diagnostics.last_publish_at ?? 0,
|
|
382
|
+
last_peer_refresh_at: diagnostics.last_peer_refresh_at ?? 0,
|
|
383
|
+
last_error_at: diagnostics.last_error_at ?? 0,
|
|
384
|
+
last_error: diagnostics.last_error ?? null,
|
|
365
385
|
}
|
|
366
386
|
: null,
|
|
367
387
|
env: {
|
|
@@ -434,6 +454,12 @@ class LocalNodeService {
|
|
|
434
454
|
signaling_messages_received_total: diagnostics.signaling_messages_received_total ?? null,
|
|
435
455
|
reconnect_attempts_total: diagnostics.reconnect_attempts_total ?? null,
|
|
436
456
|
active_webrtc_peers: diagnostics.active_webrtc_peers ?? null,
|
|
457
|
+
last_join_at: diagnostics.last_join_at ?? 0,
|
|
458
|
+
last_poll_at: diagnostics.last_poll_at ?? 0,
|
|
459
|
+
last_publish_at: diagnostics.last_publish_at ?? 0,
|
|
460
|
+
last_peer_refresh_at: diagnostics.last_peer_refresh_at ?? 0,
|
|
461
|
+
last_error_at: diagnostics.last_error_at ?? 0,
|
|
462
|
+
last_error: diagnostics.last_error ?? null,
|
|
437
463
|
}
|
|
438
464
|
: null,
|
|
439
465
|
};
|
|
@@ -473,6 +499,12 @@ class LocalNodeService {
|
|
|
473
499
|
connection_states_summary: diagnostics.connection_states_summary ?? null,
|
|
474
500
|
datachannel_states_summary: diagnostics.datachannel_states_summary ?? null,
|
|
475
501
|
active_webrtc_peers: diagnostics.active_webrtc_peers ?? null,
|
|
502
|
+
last_join_at: diagnostics.last_join_at ?? 0,
|
|
503
|
+
last_poll_at: diagnostics.last_poll_at ?? 0,
|
|
504
|
+
last_publish_at: diagnostics.last_publish_at ?? 0,
|
|
505
|
+
last_peer_refresh_at: diagnostics.last_peer_refresh_at ?? 0,
|
|
506
|
+
last_error_at: diagnostics.last_error_at ?? 0,
|
|
507
|
+
last_error: diagnostics.last_error ?? null,
|
|
476
508
|
},
|
|
477
509
|
};
|
|
478
510
|
}
|
|
@@ -648,7 +680,7 @@ class LocalNodeService {
|
|
|
648
680
|
this.socialConfig.network.adapter = "relay-preview";
|
|
649
681
|
this.socialConfig.network.signaling_url = signalingUrl;
|
|
650
682
|
this.socialConfig.network.signaling_urls = [signalingUrl];
|
|
651
|
-
this.socialConfig.network.room = room || "silicaclaw-
|
|
683
|
+
this.socialConfig.network.room = room || "silicaclaw-global-preview";
|
|
652
684
|
this.applyResolvedNetworkConfig();
|
|
653
685
|
await this.restartNetworkAdapter("quick_connect_global_preview");
|
|
654
686
|
this.socialNetworkRequiresRestart = false;
|
|
@@ -1099,6 +1131,9 @@ class LocalNodeService {
|
|
|
1099
1131
|
}
|
|
1100
1132
|
|
|
1101
1133
|
private bindNetworkSubscriptions(): void {
|
|
1134
|
+
if (this.subscriptionsBound) {
|
|
1135
|
+
return;
|
|
1136
|
+
}
|
|
1102
1137
|
this.network.subscribe("profile", (data: SignedProfileRecord) => {
|
|
1103
1138
|
this.onMessage("profile", data);
|
|
1104
1139
|
});
|
|
@@ -1108,6 +1143,7 @@ class LocalNodeService {
|
|
|
1108
1143
|
this.network.subscribe("index", (data: IndexRefRecord) => {
|
|
1109
1144
|
this.onMessage("index", data);
|
|
1110
1145
|
});
|
|
1146
|
+
this.subscriptionsBound = true;
|
|
1111
1147
|
}
|
|
1112
1148
|
|
|
1113
1149
|
private buildNetworkAdapter(): {
|
|
@@ -1330,7 +1366,7 @@ class LocalNodeService {
|
|
|
1330
1366
|
this.networkNamespace = this.socialConfig.network.namespace || process.env.NETWORK_NAMESPACE || "silicaclaw.preview";
|
|
1331
1367
|
this.networkPort = Number(this.socialConfig.network.port || process.env.NETWORK_PORT || 44123);
|
|
1332
1368
|
|
|
1333
|
-
const builtInGlobalSignalingUrls = ["
|
|
1369
|
+
const builtInGlobalSignalingUrls = ["https://relay.silicaclaw.com"];
|
|
1334
1370
|
const builtInGlobalRoom = "silicaclaw-global-preview";
|
|
1335
1371
|
|
|
1336
1372
|
const signalingUrlsSocial = dedupeStrings(this.socialConfig.network.signaling_urls || []);
|
|
@@ -1356,8 +1392,8 @@ class LocalNodeService {
|
|
|
1356
1392
|
signalingUrls = builtInGlobalSignalingUrls;
|
|
1357
1393
|
signalingSource = "built-in-defaults:global-preview.signaling_urls";
|
|
1358
1394
|
} else {
|
|
1359
|
-
signalingUrls = ["
|
|
1360
|
-
signalingSource = "default:
|
|
1395
|
+
signalingUrls = ["https://relay.silicaclaw.com"];
|
|
1396
|
+
signalingSource = "default:https://relay.silicaclaw.com";
|
|
1361
1397
|
}
|
|
1362
1398
|
|
|
1363
1399
|
const roomSocial = String(this.socialConfig.network.room || "").trim();
|
package/docs/CLOUDFLARE_RELAY.md
CHANGED
|
@@ -27,7 +27,7 @@ npx wrangler deploy
|
|
|
27
27
|
After deploy, note the Worker URL, for example:
|
|
28
28
|
|
|
29
29
|
```text
|
|
30
|
-
https://
|
|
30
|
+
https://relay.silicaclaw.com
|
|
31
31
|
```
|
|
32
32
|
|
|
33
33
|
## Use From Local Nodes
|
|
@@ -36,7 +36,7 @@ Set the same relay URL and room on every node:
|
|
|
36
36
|
|
|
37
37
|
```bash
|
|
38
38
|
silicaclaw stop
|
|
39
|
-
silicaclaw start --mode=global-preview --signaling-url=https://
|
|
39
|
+
silicaclaw start --mode=global-preview --signaling-url=https://relay.silicaclaw.com --room=my-agents
|
|
40
40
|
```
|
|
41
41
|
|
|
42
42
|
Or persist it in `social.md`:
|
|
@@ -48,7 +48,7 @@ public_enabled: true
|
|
|
48
48
|
|
|
49
49
|
network:
|
|
50
50
|
mode: "global-preview"
|
|
51
|
-
signaling_url: "https://
|
|
51
|
+
signaling_url: "https://relay.silicaclaw.com"
|
|
52
52
|
room: "my-agents"
|
|
53
53
|
---
|
|
54
54
|
```
|