@silicaclaw/cli 1.0.0-beta.9 → 2026.3.18-3
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 +100 -0
- package/INSTALL.md +24 -13
- package/README.md +62 -18
- package/VERSION +1 -1
- package/apps/local-console/package.json +1 -0
- package/apps/local-console/public/index.html +2083 -473
- package/apps/local-console/src/server.ts +108 -31
- package/apps/public-explorer/public/index.html +283 -61
- package/docs/CLOUDFLARE_RELAY.md +61 -0
- package/docs/NEW_USER_INSTALL.md +166 -0
- package/docs/NEW_USER_OPERATIONS.md +265 -0
- package/package.json +2 -2
- package/packages/core/dist/socialConfig.d.ts +1 -1
- package/packages/core/dist/socialConfig.js +7 -6
- package/packages/core/dist/socialResolver.js +15 -5
- package/packages/core/src/socialConfig.ts +8 -7
- package/packages/core/src/socialResolver.ts +17 -5
- package/packages/network/dist/index.d.ts +1 -0
- package/packages/network/dist/index.js +1 -0
- package/packages/network/dist/relayPreview.d.ts +166 -0
- package/packages/network/dist/relayPreview.js +430 -0
- package/packages/network/src/index.ts +1 -0
- package/packages/network/src/relayPreview.ts +552 -0
- package/packages/storage/dist/socialRuntimeRepo.js +4 -4
- package/packages/storage/src/socialRuntimeRepo.ts +4 -4
- package/scripts/quickstart.sh +241 -38
- package/scripts/silicaclaw-cli.mjs +418 -56
- package/scripts/silicaclaw-gateway.mjs +231 -46
- package/scripts/webrtc-signaling-server.mjs +89 -5
|
@@ -4,65 +4,117 @@
|
|
|
4
4
|
<meta charset="UTF-8" />
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
6
|
<title>SilicaClaw Control UI</title>
|
|
7
|
-
<meta name="description" content="SilicaClaw local-first agent control console." />
|
|
7
|
+
<meta id="metaDescription" name="description" content="SilicaClaw local-first agent control console." />
|
|
8
8
|
<meta property="og:type" content="website" />
|
|
9
|
-
<meta property="og:title" content="SilicaClaw Local Console" />
|
|
10
|
-
<meta property="og:description" content="Local-first control surface for SilicaClaw agents." />
|
|
9
|
+
<meta id="ogTitle" property="og:title" content="SilicaClaw Local Console" />
|
|
10
|
+
<meta id="ogDescription" property="og:description" content="Local-first control surface for SilicaClaw agents." />
|
|
11
11
|
<meta property="og:image" content="/assets/silicaclaw-logo.png" />
|
|
12
12
|
<meta name="twitter:card" content="summary_large_image" />
|
|
13
|
-
<meta name="twitter:title" content="SilicaClaw Local Console" />
|
|
14
|
-
<meta name="twitter:description" content="Local-first control surface for SilicaClaw agents." />
|
|
13
|
+
<meta id="twitterTitle" name="twitter:title" content="SilicaClaw Local Console" />
|
|
14
|
+
<meta id="twitterDescription" name="twitter:description" content="Local-first control surface for SilicaClaw agents." />
|
|
15
15
|
<meta name="twitter:image" content="/assets/silicaclaw-logo.png" />
|
|
16
16
|
<link rel="icon" type="image/png" href="/assets/silicaclaw-logo.png" />
|
|
17
17
|
<link rel="apple-touch-icon" href="/assets/silicaclaw-logo.png" />
|
|
18
18
|
<style>
|
|
19
19
|
:root {
|
|
20
20
|
--bg: #0e1015;
|
|
21
|
+
--bg-accent: #13151b;
|
|
21
22
|
--bg-elevated: #191c24;
|
|
22
23
|
--bg-hover: #1f2330;
|
|
24
|
+
--bg-muted: #1f2330;
|
|
23
25
|
--panel: #0e1015;
|
|
26
|
+
--panel-strong: #191c24;
|
|
27
|
+
--panel-hover: #1f2330;
|
|
24
28
|
--card: #161920;
|
|
25
|
-
--
|
|
26
|
-
--
|
|
29
|
+
--card-foreground: #f0f0f2;
|
|
30
|
+
--card-highlight: rgba(255, 255, 255, 0.04);
|
|
31
|
+
--card-soft: rgba(22, 25, 32, 0.86);
|
|
32
|
+
--card-strong: rgba(25, 28, 36, 0.96);
|
|
33
|
+
--chrome: rgba(14, 16, 21, 0.96);
|
|
34
|
+
--chrome-strong: rgba(14, 16, 21, 0.98);
|
|
27
35
|
--text: #d4d4d8;
|
|
28
36
|
--text-strong: #f4f4f5;
|
|
29
|
-
--muted: #
|
|
30
|
-
--
|
|
31
|
-
--
|
|
32
|
-
--
|
|
37
|
+
--muted: #838387;
|
|
38
|
+
--muted-strong: #62626a;
|
|
39
|
+
--border: #1e2028;
|
|
40
|
+
--border-strong: #2e3040;
|
|
41
|
+
--border-hover: #3e4050;
|
|
42
|
+
--accent: #ff5c5c;
|
|
43
|
+
--accent-hover: #ff7070;
|
|
44
|
+
--accent-subtle: rgba(255, 92, 92, 0.1);
|
|
45
|
+
--accent-glow: rgba(255, 92, 92, 0.2);
|
|
33
46
|
--ok: #22c55e;
|
|
34
47
|
--warn: #f59e0b;
|
|
35
|
-
--
|
|
36
|
-
--
|
|
48
|
+
--danger: #ef4444;
|
|
49
|
+
--info: #3b82f6;
|
|
50
|
+
--focus-ring: 0 0 0 2px var(--bg), 0 0 0 3px color-mix(in srgb, var(--accent) 60%, transparent);
|
|
51
|
+
--shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.25);
|
|
52
|
+
--shadow-md: 0 4px 16px rgba(0, 0, 0, 0.3);
|
|
53
|
+
--shadow-lg: 0 12px 32px rgba(0, 0, 0, 0.4);
|
|
54
|
+
--radius-sm: 6px;
|
|
55
|
+
--radius-md: 10px;
|
|
56
|
+
--radius-lg: 14px;
|
|
57
|
+
--radius-xl: 20px;
|
|
58
|
+
--radius-full: 9999px;
|
|
59
|
+
--ease-out: cubic-bezier(0.16, 1, 0.3, 1);
|
|
60
|
+
--duration-fast: 100ms;
|
|
61
|
+
--font-body: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
|
62
|
+
--mono: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
|
|
63
|
+
|
|
37
64
|
}
|
|
38
65
|
:root[data-theme-mode="light"] {
|
|
39
66
|
--bg: #f8f9fa;
|
|
40
|
-
--bg-
|
|
67
|
+
--bg-accent: #f1f3f5;
|
|
68
|
+
--bg-elevated: #ffffff;
|
|
41
69
|
--bg-hover: #eceef0;
|
|
70
|
+
--bg-muted: #eceef0;
|
|
42
71
|
--panel: #f8f9fa;
|
|
72
|
+
--panel-strong: #f1f3f5;
|
|
73
|
+
--panel-hover: #e6e8eb;
|
|
43
74
|
--card: #ffffff;
|
|
44
|
-
--
|
|
45
|
-
--
|
|
75
|
+
--card-foreground: #1a1a1e;
|
|
76
|
+
--card-highlight: rgba(0, 0, 0, 0.02);
|
|
77
|
+
--card-soft: rgba(255, 255, 255, 0.9);
|
|
78
|
+
--card-strong: rgba(255, 255, 255, 0.98);
|
|
79
|
+
--chrome: rgba(248, 249, 250, 0.96);
|
|
80
|
+
--chrome-strong: rgba(248, 249, 250, 0.98);
|
|
46
81
|
--text: #3c3c43;
|
|
47
82
|
--text-strong: #1a1a1e;
|
|
48
|
-
--muted: #
|
|
49
|
-
--
|
|
50
|
-
--
|
|
51
|
-
--
|
|
52
|
-
--
|
|
53
|
-
--
|
|
54
|
-
--
|
|
55
|
-
--
|
|
83
|
+
--muted: #6e6e73;
|
|
84
|
+
--muted-strong: #545458;
|
|
85
|
+
--border: #e5e5ea;
|
|
86
|
+
--border-strong: #d1d1d6;
|
|
87
|
+
--border-hover: #aeaeb2;
|
|
88
|
+
--accent: #dc2626;
|
|
89
|
+
--accent-hover: #ef4444;
|
|
90
|
+
--accent-subtle: rgba(220, 38, 38, 0.08);
|
|
91
|
+
--accent-glow: rgba(220, 38, 38, 0.1);
|
|
92
|
+
--ok: #15803d;
|
|
93
|
+
--warn: #b45309;
|
|
94
|
+
--danger: #dc2626;
|
|
95
|
+
--info: #2563eb;
|
|
96
|
+
--focus-ring: 0 0 0 2px var(--bg), 0 0 0 3px color-mix(in srgb, var(--accent) 50%, transparent);
|
|
97
|
+
--shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.04);
|
|
98
|
+
--shadow-md: 0 4px 12px rgba(0, 0, 0, 0.06);
|
|
99
|
+
--shadow-lg: 0 12px 28px rgba(0, 0, 0, 0.08);
|
|
100
|
+
|
|
56
101
|
}
|
|
57
102
|
* { box-sizing: border-box; }
|
|
58
|
-
html, body {
|
|
103
|
+
html, body {
|
|
104
|
+
margin: 0;
|
|
105
|
+
height: 100%;
|
|
106
|
+
overflow: hidden;
|
|
107
|
+
}
|
|
59
108
|
body {
|
|
60
|
-
font
|
|
109
|
+
font: 400 13.5px/1.55 var(--font-body);
|
|
110
|
+
letter-spacing: -0.01em;
|
|
61
111
|
color: var(--text);
|
|
62
112
|
background:
|
|
63
113
|
radial-gradient(900px 420px at 8% -12%, rgba(255, 92, 92, 0.18), transparent 60%),
|
|
64
114
|
linear-gradient(180deg, #0e1015 0%, #0e1015 62%, #0f1219 100%);
|
|
65
115
|
transition: background .2s ease, color .2s ease;
|
|
116
|
+
-webkit-font-smoothing: antialiased;
|
|
117
|
+
-moz-osx-font-smoothing: grayscale;
|
|
66
118
|
}
|
|
67
119
|
:root[data-theme-mode="light"] body {
|
|
68
120
|
background:
|
|
@@ -72,35 +124,121 @@
|
|
|
72
124
|
|
|
73
125
|
.app {
|
|
74
126
|
display: grid;
|
|
75
|
-
grid-template-columns:
|
|
76
|
-
|
|
127
|
+
grid-template-columns: 258px 1fr;
|
|
128
|
+
height: 100vh;
|
|
129
|
+
overflow: hidden;
|
|
130
|
+
transition: grid-template-columns .2s ease;
|
|
131
|
+
}
|
|
132
|
+
.app.nav-collapsed {
|
|
133
|
+
grid-template-columns: 78px 1fr;
|
|
134
|
+
}
|
|
135
|
+
.app.focus-mode {
|
|
136
|
+
grid-template-columns: 1fr;
|
|
77
137
|
}
|
|
78
138
|
|
|
79
139
|
.sidebar {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
140
|
+
display: flex;
|
|
141
|
+
flex-direction: column;
|
|
142
|
+
min-height: 0;
|
|
143
|
+
border-right: 1px solid color-mix(in srgb, var(--border) 74%, transparent);
|
|
144
|
+
background: var(--bg);
|
|
145
|
+
padding: 14px 10px 12px;
|
|
146
|
+
position: relative;
|
|
147
|
+
overflow: hidden;
|
|
148
|
+
transition: padding .2s ease;
|
|
149
|
+
}
|
|
150
|
+
:root[data-theme-mode="light"] .sidebar {
|
|
151
|
+
background: var(--panel);
|
|
152
|
+
}
|
|
153
|
+
.app.nav-collapsed .sidebar {
|
|
154
|
+
padding: 12px 8px 10px;
|
|
155
|
+
}
|
|
156
|
+
.sidebar-shell {
|
|
157
|
+
display: flex;
|
|
158
|
+
flex: 1 1 auto;
|
|
159
|
+
min-height: 0;
|
|
160
|
+
flex-direction: column;
|
|
161
|
+
}
|
|
162
|
+
.sidebar-shell__header {
|
|
163
|
+
flex: 0 0 auto;
|
|
164
|
+
display: flex;
|
|
165
|
+
align-items: center;
|
|
166
|
+
justify-content: space-between;
|
|
167
|
+
gap: 12px;
|
|
168
|
+
min-height: 0;
|
|
169
|
+
padding: 0 8px 18px;
|
|
170
|
+
}
|
|
171
|
+
.nav-collapse-toggle {
|
|
172
|
+
width: 36px;
|
|
173
|
+
height: 36px;
|
|
174
|
+
display: flex;
|
|
175
|
+
align-items: center;
|
|
176
|
+
justify-content: center;
|
|
177
|
+
background: var(--bg-elevated);
|
|
178
|
+
border: 1px solid color-mix(in srgb, var(--border-strong) 68%, transparent);
|
|
179
|
+
border-radius: 999px;
|
|
180
|
+
cursor: pointer;
|
|
181
|
+
color: var(--muted);
|
|
182
|
+
flex: 0 0 auto;
|
|
183
|
+
transition:
|
|
184
|
+
background .16s ease,
|
|
185
|
+
border-color .16s ease,
|
|
186
|
+
color .16s ease,
|
|
187
|
+
transform .16s ease;
|
|
188
|
+
}
|
|
189
|
+
.nav-collapse-toggle:hover {
|
|
190
|
+
background: color-mix(in srgb, var(--bg-hover) 90%, transparent);
|
|
191
|
+
border-color: color-mix(in srgb, var(--border-strong) 88%, transparent);
|
|
192
|
+
color: var(--text);
|
|
193
|
+
transform: translateY(-1px);
|
|
194
|
+
}
|
|
195
|
+
.nav-collapse-toggle__icon {
|
|
196
|
+
display: flex;
|
|
197
|
+
align-items: center;
|
|
198
|
+
justify-content: center;
|
|
199
|
+
width: 16px;
|
|
200
|
+
height: 16px;
|
|
201
|
+
color: inherit;
|
|
202
|
+
}
|
|
203
|
+
.nav-collapse-toggle__icon svg {
|
|
204
|
+
width: 16px;
|
|
205
|
+
height: 16px;
|
|
206
|
+
stroke: currentColor;
|
|
207
|
+
fill: none;
|
|
208
|
+
stroke-width: 1.5px;
|
|
209
|
+
stroke-linecap: round;
|
|
210
|
+
stroke-linejoin: round;
|
|
211
|
+
}
|
|
212
|
+
.sidebar-shell__body {
|
|
213
|
+
flex: 1 1 auto;
|
|
214
|
+
min-height: 0;
|
|
215
|
+
display: flex;
|
|
216
|
+
flex-direction: column;
|
|
217
|
+
}
|
|
218
|
+
.sidebar-shell__footer {
|
|
219
|
+
flex: 0 0 auto;
|
|
220
|
+
padding: 12px 8px 0;
|
|
83
221
|
}
|
|
84
222
|
.brand {
|
|
85
223
|
display: flex;
|
|
86
224
|
align-items: center;
|
|
87
225
|
gap: 10px;
|
|
88
|
-
margin-bottom:
|
|
226
|
+
margin-bottom: 0;
|
|
89
227
|
}
|
|
90
228
|
.brand-logo {
|
|
91
|
-
width:
|
|
92
|
-
height:
|
|
229
|
+
width: 32px;
|
|
230
|
+
height: 32px;
|
|
93
231
|
border-radius: 10px;
|
|
94
232
|
object-fit: cover;
|
|
95
233
|
display: block;
|
|
96
|
-
box-shadow: 0
|
|
97
|
-
border: 1px solid color-mix(in srgb, var(--
|
|
234
|
+
box-shadow: 0 8px 18px rgba(0, 0, 0, 0.18);
|
|
235
|
+
border: 1px solid color-mix(in srgb, var(--border) 75%, transparent);
|
|
98
236
|
}
|
|
99
237
|
.brand-badge {
|
|
100
|
-
width:
|
|
101
|
-
height:
|
|
238
|
+
width: 32px;
|
|
239
|
+
height: 32px;
|
|
102
240
|
border-radius: 10px;
|
|
103
|
-
background: linear-gradient(135deg, var(--
|
|
241
|
+
background: linear-gradient(135deg, var(--accent), var(--accent-hover));
|
|
104
242
|
color: #fff;
|
|
105
243
|
font-weight: 900;
|
|
106
244
|
display: grid;
|
|
@@ -109,98 +247,425 @@
|
|
|
109
247
|
.brand-badge.hidden { display: none; }
|
|
110
248
|
.brand h1 {
|
|
111
249
|
margin: 0;
|
|
112
|
-
font-size:
|
|
250
|
+
font-size: 15px;
|
|
251
|
+
line-height: 1.1;
|
|
252
|
+
letter-spacing: -0.03em;
|
|
113
253
|
}
|
|
114
254
|
.brand p {
|
|
115
255
|
margin: 2px 0 0;
|
|
116
256
|
color: var(--muted);
|
|
117
|
-
font-size:
|
|
257
|
+
font-size: 10px;
|
|
258
|
+
line-height: 1.15;
|
|
259
|
+
font-weight: 600;
|
|
260
|
+
letter-spacing: 0.08em;
|
|
261
|
+
text-transform: uppercase;
|
|
262
|
+
}
|
|
263
|
+
.version-dot {
|
|
264
|
+
width: 5px;
|
|
265
|
+
height: 5px;
|
|
266
|
+
border-radius: 999px;
|
|
267
|
+
background: var(--accent);
|
|
268
|
+
opacity: .85;
|
|
269
|
+
}
|
|
270
|
+
.app.nav-collapsed .brand h1,
|
|
271
|
+
.app.nav-collapsed .brand p,
|
|
272
|
+
.app.nav-collapsed .sidebar-foot,
|
|
273
|
+
.app.nav-collapsed .sidebar-nav__label {
|
|
274
|
+
display: none;
|
|
275
|
+
}
|
|
276
|
+
.app.focus-mode .sidebar {
|
|
277
|
+
display: none;
|
|
278
|
+
}
|
|
279
|
+
.app.focus-mode .integration-strip,
|
|
280
|
+
.app.focus-mode .page-hero,
|
|
281
|
+
.app.focus-mode .notice,
|
|
282
|
+
.app.focus-mode #publicDiscoveryHint {
|
|
283
|
+
display: none !important;
|
|
284
|
+
}
|
|
285
|
+
.app.nav-collapsed .brand {
|
|
286
|
+
display: none;
|
|
287
|
+
}
|
|
288
|
+
.app.nav-collapsed .sidebar-shell__header {
|
|
289
|
+
justify-content: center;
|
|
290
|
+
align-items: center;
|
|
291
|
+
gap: 0;
|
|
292
|
+
padding: 0 2px 16px;
|
|
293
|
+
}
|
|
294
|
+
.app.nav-collapsed .nav button {
|
|
295
|
+
justify-content: center;
|
|
296
|
+
width: 44px;
|
|
297
|
+
min-height: 44px;
|
|
298
|
+
padding: 0;
|
|
299
|
+
margin: 0 auto;
|
|
300
|
+
border-radius: 16px;
|
|
301
|
+
border-color: transparent;
|
|
302
|
+
box-shadow: none;
|
|
303
|
+
background: transparent;
|
|
304
|
+
}
|
|
305
|
+
.app.nav-collapsed .nav button .tab-labels {
|
|
306
|
+
display: none;
|
|
307
|
+
}
|
|
308
|
+
.app.nav-collapsed .nav button .tab-icon {
|
|
309
|
+
width: 18px;
|
|
310
|
+
height: 18px;
|
|
311
|
+
}
|
|
312
|
+
.app.nav-collapsed .nav button .tab-icon svg {
|
|
313
|
+
width: 18px;
|
|
314
|
+
height: 18px;
|
|
315
|
+
}
|
|
316
|
+
.app.nav-collapsed .nav button.active::before {
|
|
317
|
+
left: 8px;
|
|
318
|
+
top: 10px;
|
|
319
|
+
bottom: 10px;
|
|
320
|
+
}
|
|
321
|
+
.app.nav-collapsed .sidebar-shell__footer {
|
|
322
|
+
padding: 8px 0 2px;
|
|
323
|
+
}
|
|
324
|
+
.app.nav-collapsed .sidebar-utility {
|
|
325
|
+
display: none;
|
|
326
|
+
}
|
|
327
|
+
.app.nav-collapsed .sidebar-version {
|
|
328
|
+
width: 44px;
|
|
329
|
+
min-height: 44px;
|
|
330
|
+
padding: 0;
|
|
331
|
+
justify-content: center;
|
|
332
|
+
border-radius: 16px;
|
|
118
333
|
}
|
|
119
334
|
|
|
120
335
|
.nav {
|
|
121
336
|
display: grid;
|
|
122
|
-
gap:
|
|
337
|
+
gap: 4px;
|
|
338
|
+
min-height: 0;
|
|
339
|
+
overflow: auto;
|
|
340
|
+
padding: 0;
|
|
341
|
+
scrollbar-width: none;
|
|
342
|
+
}
|
|
343
|
+
.nav::-webkit-scrollbar { display: none; }
|
|
344
|
+
.sidebar-nav__label {
|
|
345
|
+
padding: 0 10px 8px;
|
|
346
|
+
color: var(--muted);
|
|
347
|
+
font-size: 12px;
|
|
348
|
+
font-weight: 700;
|
|
349
|
+
letter-spacing: 0.06em;
|
|
350
|
+
text-transform: uppercase;
|
|
123
351
|
}
|
|
124
352
|
.nav button {
|
|
353
|
+
position: relative;
|
|
354
|
+
display: flex;
|
|
355
|
+
align-items: center;
|
|
356
|
+
justify-content: flex-start;
|
|
357
|
+
gap: 8px;
|
|
358
|
+
min-height: 40px;
|
|
125
359
|
text-align: left;
|
|
126
360
|
border: 1px solid transparent;
|
|
127
361
|
background: transparent;
|
|
128
362
|
color: var(--muted);
|
|
129
|
-
padding:
|
|
130
|
-
border-radius:
|
|
363
|
+
padding: 0 9px;
|
|
364
|
+
border-radius: 12px;
|
|
131
365
|
cursor: pointer;
|
|
132
366
|
font: inherit;
|
|
367
|
+
transition:
|
|
368
|
+
border-color .16s ease,
|
|
369
|
+
background .16s ease,
|
|
370
|
+
color .16s ease,
|
|
371
|
+
transform .16s ease;
|
|
372
|
+
}
|
|
373
|
+
.nav button .tab-icon {
|
|
374
|
+
width: 16px;
|
|
375
|
+
height: 16px;
|
|
376
|
+
display: inline-flex;
|
|
377
|
+
align-items: center;
|
|
378
|
+
justify-content: center;
|
|
379
|
+
flex-shrink: 0;
|
|
380
|
+
opacity: .72;
|
|
381
|
+
}
|
|
382
|
+
.nav button .tab-icon svg {
|
|
383
|
+
width: 16px;
|
|
384
|
+
height: 16px;
|
|
385
|
+
stroke: currentColor;
|
|
386
|
+
fill: none;
|
|
387
|
+
stroke-width: 1.5px;
|
|
388
|
+
stroke-linecap: round;
|
|
389
|
+
stroke-linejoin: round;
|
|
390
|
+
}
|
|
391
|
+
.nav button .tab-labels {
|
|
392
|
+
min-width: 0;
|
|
393
|
+
}
|
|
394
|
+
.nav button .tab-title {
|
|
395
|
+
display: block;
|
|
396
|
+
font-size: 14px;
|
|
397
|
+
font-weight: 600;
|
|
398
|
+
color: inherit;
|
|
399
|
+
white-space: nowrap;
|
|
400
|
+
}
|
|
401
|
+
.nav button .tab-copy {
|
|
402
|
+
display: none;
|
|
133
403
|
}
|
|
134
404
|
.nav button.active {
|
|
135
|
-
color:
|
|
136
|
-
border-color: color-mix(in srgb, var(--
|
|
137
|
-
background: var(--
|
|
405
|
+
color: var(--text-strong);
|
|
406
|
+
border-color: color-mix(in srgb, var(--accent) 18%, transparent);
|
|
407
|
+
background: color-mix(in srgb, var(--accent-subtle) 88%, var(--bg-elevated) 12%);
|
|
408
|
+
box-shadow: inset 0 1px 0 color-mix(in srgb, white 10%, transparent);
|
|
409
|
+
}
|
|
410
|
+
.nav button.active .tab-icon {
|
|
411
|
+
opacity: 1;
|
|
412
|
+
color: var(--accent);
|
|
413
|
+
}
|
|
414
|
+
.nav button:hover {
|
|
415
|
+
color: var(--text);
|
|
416
|
+
background: color-mix(in srgb, var(--bg-hover) 68%, transparent);
|
|
417
|
+
border-color: color-mix(in srgb, var(--border) 60%, transparent);
|
|
418
|
+
}
|
|
419
|
+
.nav button:hover .tab-icon {
|
|
420
|
+
opacity: 1;
|
|
138
421
|
}
|
|
139
|
-
.nav button:hover { color: #d2e7ff; }
|
|
140
422
|
|
|
141
423
|
.sidebar-foot {
|
|
142
|
-
margin-top:
|
|
143
|
-
|
|
144
|
-
|
|
424
|
+
margin-top: 12px;
|
|
425
|
+
flex: 0 0 auto;
|
|
426
|
+
border-top: 1px solid color-mix(in srgb, var(--border) 80%, transparent);
|
|
427
|
+
padding-top: 12px;
|
|
145
428
|
color: var(--muted);
|
|
146
429
|
font-size: 12px;
|
|
147
430
|
}
|
|
431
|
+
.sidebar-utility {
|
|
432
|
+
display: grid;
|
|
433
|
+
gap: 8px;
|
|
434
|
+
padding: 12px;
|
|
435
|
+
border-radius: 16px;
|
|
436
|
+
border: 1px solid color-mix(in srgb, var(--border) 72%, transparent);
|
|
437
|
+
background: var(--bg-elevated);
|
|
438
|
+
box-shadow: none;
|
|
439
|
+
}
|
|
440
|
+
.sidebar-utility-row {
|
|
441
|
+
display: flex;
|
|
442
|
+
align-items: center;
|
|
443
|
+
justify-content: space-between;
|
|
444
|
+
gap: 10px;
|
|
445
|
+
}
|
|
446
|
+
.sidebar-utility__label {
|
|
447
|
+
font-size: 11px;
|
|
448
|
+
font-weight: 700;
|
|
449
|
+
color: var(--muted);
|
|
450
|
+
text-transform: uppercase;
|
|
451
|
+
letter-spacing: 0.06em;
|
|
452
|
+
}
|
|
453
|
+
.sidebar-utility__value {
|
|
454
|
+
color: var(--text);
|
|
455
|
+
font-size: 12px;
|
|
456
|
+
font-weight: 600;
|
|
457
|
+
}
|
|
458
|
+
.sidebar-version {
|
|
459
|
+
margin-top: 10px;
|
|
460
|
+
display: flex;
|
|
461
|
+
align-items: center;
|
|
462
|
+
justify-content: center;
|
|
463
|
+
min-height: 40px;
|
|
464
|
+
padding: 0 12px;
|
|
465
|
+
border-radius: 14px;
|
|
466
|
+
background: var(--bg-elevated);
|
|
467
|
+
border: 1px solid color-mix(in srgb, var(--border) 72%, transparent);
|
|
468
|
+
box-shadow: none;
|
|
469
|
+
}
|
|
470
|
+
.sidebar-version__text {
|
|
471
|
+
font-size: 12px;
|
|
472
|
+
color: var(--text);
|
|
473
|
+
font-weight: 600;
|
|
474
|
+
line-height: 1.2;
|
|
475
|
+
white-space: nowrap;
|
|
476
|
+
overflow: hidden;
|
|
477
|
+
text-overflow: ellipsis;
|
|
478
|
+
text-align: center;
|
|
479
|
+
}
|
|
480
|
+
.app.nav-collapsed .sidebar-version {
|
|
481
|
+
justify-content: center;
|
|
482
|
+
padding: 0;
|
|
483
|
+
}
|
|
148
484
|
|
|
149
485
|
.main {
|
|
150
|
-
|
|
486
|
+
display: flex;
|
|
487
|
+
flex-direction: column;
|
|
488
|
+
min-width: 0;
|
|
489
|
+
min-height: 0;
|
|
490
|
+
height: 100vh;
|
|
491
|
+
overflow: hidden;
|
|
492
|
+
padding: 0;
|
|
151
493
|
}
|
|
152
494
|
.topbar {
|
|
495
|
+
flex: 0 0 auto;
|
|
153
496
|
display: flex;
|
|
154
497
|
justify-content: space-between;
|
|
155
|
-
gap:
|
|
498
|
+
gap: 12px;
|
|
156
499
|
align-items: center;
|
|
157
|
-
|
|
500
|
+
min-height: 52px;
|
|
501
|
+
padding: 0 24px;
|
|
502
|
+
border-bottom: 1px solid color-mix(in srgb, var(--border) 74%, transparent);
|
|
503
|
+
background: var(--chrome);
|
|
504
|
+
backdrop-filter: blur(12px) saturate(1.6);
|
|
505
|
+
-webkit-backdrop-filter: blur(12px) saturate(1.6);
|
|
158
506
|
}
|
|
159
507
|
.topbar h2 {
|
|
508
|
+
display: none;
|
|
160
509
|
margin: 0;
|
|
161
|
-
font-size: 22px;
|
|
162
510
|
}
|
|
163
511
|
.topbar p {
|
|
164
|
-
|
|
512
|
+
display: none;
|
|
513
|
+
margin: 0;
|
|
165
514
|
color: var(--muted);
|
|
166
|
-
font-size:
|
|
515
|
+
font-size: 12px;
|
|
516
|
+
white-space: nowrap;
|
|
517
|
+
overflow: hidden;
|
|
518
|
+
text-overflow: ellipsis;
|
|
519
|
+
}
|
|
520
|
+
.dashboard-header__breadcrumb {
|
|
521
|
+
display: flex;
|
|
522
|
+
align-items: center;
|
|
523
|
+
gap: 8px;
|
|
524
|
+
min-width: 0;
|
|
525
|
+
overflow: hidden;
|
|
526
|
+
font-size: 12px;
|
|
527
|
+
margin-bottom: 2px;
|
|
528
|
+
letter-spacing: 0.01em;
|
|
529
|
+
}
|
|
530
|
+
.dashboard-header__breadcrumb-link,
|
|
531
|
+
.dashboard-header__breadcrumb-sep {
|
|
532
|
+
color: var(--muted);
|
|
533
|
+
}
|
|
534
|
+
.dashboard-header__breadcrumb-current {
|
|
535
|
+
color: var(--text-strong);
|
|
536
|
+
font-weight: 650;
|
|
537
|
+
white-space: nowrap;
|
|
538
|
+
overflow: hidden;
|
|
539
|
+
text-overflow: ellipsis;
|
|
167
540
|
}
|
|
168
541
|
|
|
542
|
+
.topnav-shell__content {
|
|
543
|
+
min-width: 0;
|
|
544
|
+
flex: 1;
|
|
545
|
+
overflow: hidden;
|
|
546
|
+
}
|
|
547
|
+
.main-scroll {
|
|
548
|
+
flex: 1 1 auto;
|
|
549
|
+
min-height: 0;
|
|
550
|
+
overflow: auto;
|
|
551
|
+
padding: 12px 18px 18px;
|
|
552
|
+
}
|
|
169
553
|
.status-row {
|
|
170
554
|
display: flex;
|
|
171
555
|
gap: 8px;
|
|
172
|
-
flex-wrap:
|
|
556
|
+
flex-wrap: nowrap;
|
|
173
557
|
align-items: center;
|
|
558
|
+
flex-shrink: 0;
|
|
559
|
+
min-width: max-content;
|
|
174
560
|
}
|
|
175
|
-
.
|
|
561
|
+
.topbar-actions {
|
|
176
562
|
display: inline-flex;
|
|
177
|
-
|
|
178
|
-
|
|
563
|
+
align-items: center;
|
|
564
|
+
gap: 8px;
|
|
565
|
+
}
|
|
566
|
+
.icon-btn {
|
|
567
|
+
width: 30px;
|
|
568
|
+
height: 30px;
|
|
569
|
+
display: inline-flex;
|
|
570
|
+
align-items: center;
|
|
571
|
+
justify-content: center;
|
|
179
572
|
border-radius: 999px;
|
|
180
|
-
border: 1px solid var(--
|
|
573
|
+
border: 1px solid color-mix(in srgb, var(--border) 86%, transparent);
|
|
181
574
|
background: var(--bg-elevated);
|
|
575
|
+
color: var(--muted);
|
|
576
|
+
padding: 0;
|
|
577
|
+
}
|
|
578
|
+
.icon-btn:hover {
|
|
579
|
+
color: var(--text-strong);
|
|
580
|
+
border-color: color-mix(in srgb, var(--accent) 28%, transparent);
|
|
581
|
+
background: color-mix(in srgb, var(--accent-subtle) 65%, var(--bg-elevated));
|
|
582
|
+
}
|
|
583
|
+
.icon-btn.active {
|
|
584
|
+
color: var(--text-strong);
|
|
585
|
+
border-color: color-mix(in srgb, var(--accent) 34%, transparent);
|
|
586
|
+
background: var(--accent-subtle);
|
|
182
587
|
}
|
|
183
|
-
.
|
|
588
|
+
.icon-btn svg {
|
|
589
|
+
width: 15px;
|
|
590
|
+
height: 15px;
|
|
591
|
+
stroke: currentColor;
|
|
592
|
+
}
|
|
593
|
+
.topbar-theme-mode {
|
|
594
|
+
display: inline-flex;
|
|
595
|
+
align-items: center;
|
|
596
|
+
gap: 2px;
|
|
597
|
+
padding: 3px;
|
|
598
|
+
border: 1px solid color-mix(in srgb, var(--border) 84%, transparent);
|
|
599
|
+
border-radius: 999px;
|
|
600
|
+
background: color-mix(in srgb, var(--bg-elevated) 78%, transparent);
|
|
601
|
+
}
|
|
602
|
+
.topbar-theme-mode__btn {
|
|
603
|
+
width: 30px;
|
|
604
|
+
height: 30px;
|
|
605
|
+
display: inline-flex;
|
|
606
|
+
align-items: center;
|
|
607
|
+
justify-content: center;
|
|
608
|
+
padding: 0;
|
|
184
609
|
border: 1px solid transparent;
|
|
610
|
+
border-radius: 999px;
|
|
185
611
|
background: transparent;
|
|
186
612
|
color: var(--muted);
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
613
|
+
cursor: pointer;
|
|
614
|
+
transition:
|
|
615
|
+
color var(--duration-fast) ease,
|
|
616
|
+
background var(--duration-fast) ease,
|
|
617
|
+
border-color var(--duration-fast) ease;
|
|
191
618
|
}
|
|
192
|
-
.theme-
|
|
193
|
-
color: var(--text
|
|
194
|
-
background: var(--
|
|
195
|
-
|
|
619
|
+
.topbar-theme-mode__btn:hover {
|
|
620
|
+
color: var(--text);
|
|
621
|
+
background: var(--bg-hover);
|
|
622
|
+
}
|
|
623
|
+
.topbar-theme-mode__btn:focus-visible {
|
|
624
|
+
outline: none;
|
|
625
|
+
box-shadow: var(--focus-ring);
|
|
626
|
+
}
|
|
627
|
+
.topbar-theme-mode__btn--active {
|
|
628
|
+
color: var(--accent);
|
|
629
|
+
background: var(--accent-subtle);
|
|
630
|
+
border-color: color-mix(in srgb, var(--accent) 25%, transparent);
|
|
631
|
+
}
|
|
632
|
+
.topbar-theme-mode__btn svg {
|
|
633
|
+
width: 14px;
|
|
634
|
+
height: 14px;
|
|
635
|
+
stroke: currentColor;
|
|
636
|
+
fill: none;
|
|
637
|
+
stroke-width: 1.75px;
|
|
638
|
+
stroke-linecap: round;
|
|
639
|
+
stroke-linejoin: round;
|
|
640
|
+
}
|
|
641
|
+
.theme-icon {
|
|
642
|
+
width: 14px;
|
|
643
|
+
height: 14px;
|
|
644
|
+
display: inline-flex;
|
|
645
|
+
align-items: center;
|
|
646
|
+
justify-content: center;
|
|
647
|
+
}
|
|
648
|
+
.theme-icon svg {
|
|
649
|
+
width: 14px;
|
|
650
|
+
height: 14px;
|
|
651
|
+
stroke: currentColor;
|
|
652
|
+
fill: none;
|
|
653
|
+
stroke-width: 1.75px;
|
|
654
|
+
stroke-linecap: round;
|
|
655
|
+
stroke-linejoin: round;
|
|
196
656
|
}
|
|
197
657
|
.pill {
|
|
198
658
|
border-radius: 999px;
|
|
199
|
-
border: 1px solid var(--
|
|
200
|
-
background: var(--bg-elevated);
|
|
659
|
+
border: 1px solid color-mix(in srgb, var(--border) 86%, transparent);
|
|
660
|
+
background: color-mix(in srgb, var(--bg-elevated) 96%, transparent);
|
|
201
661
|
color: var(--muted);
|
|
202
|
-
padding:
|
|
662
|
+
padding: 6px 10px;
|
|
203
663
|
font-size: 12px;
|
|
664
|
+
font-weight: 500;
|
|
665
|
+
min-height: 32px;
|
|
666
|
+
display: inline-flex;
|
|
667
|
+
align-items: center;
|
|
668
|
+
box-shadow: inset 0 1px 0 color-mix(in srgb, white 4%, transparent);
|
|
204
669
|
}
|
|
205
670
|
.pill.ok { color: var(--ok); border-color: rgba(34, 197, 94, 0.45); background: rgba(34, 197, 94, 0.08); }
|
|
206
671
|
.pill.warn { color: var(--warn); border-color: rgba(245, 158, 11, 0.45); background: rgba(245, 158, 11, 0.08); }
|
|
@@ -208,8 +673,8 @@
|
|
|
208
673
|
.notice {
|
|
209
674
|
display: none;
|
|
210
675
|
margin-bottom: 12px;
|
|
211
|
-
border: 1px solid color-mix(in srgb, var(--
|
|
212
|
-
background: var(--
|
|
676
|
+
border: 1px solid color-mix(in srgb, var(--accent) 28%, transparent);
|
|
677
|
+
background: var(--accent-subtle);
|
|
213
678
|
border-radius: 10px;
|
|
214
679
|
padding: 10px 12px;
|
|
215
680
|
font-size: 13px;
|
|
@@ -219,13 +684,16 @@
|
|
|
219
684
|
position: sticky;
|
|
220
685
|
top: 0;
|
|
221
686
|
z-index: 9;
|
|
222
|
-
margin-bottom:
|
|
223
|
-
border: 1px solid var(--
|
|
224
|
-
border-radius:
|
|
225
|
-
background:
|
|
226
|
-
|
|
227
|
-
|
|
687
|
+
margin-bottom: 8px;
|
|
688
|
+
border: 1px solid color-mix(in srgb, var(--border) 82%, transparent);
|
|
689
|
+
border-radius: 14px;
|
|
690
|
+
background:
|
|
691
|
+
linear-gradient(180deg, color-mix(in srgb, var(--card-soft) 98%, transparent), color-mix(in srgb, var(--bg-elevated) 94%, transparent));
|
|
692
|
+
padding: 8px 12px;
|
|
693
|
+
font-size: 12px;
|
|
694
|
+
line-height: 1.45;
|
|
228
695
|
color: var(--text);
|
|
696
|
+
box-shadow: inset 0 1px 0 color-mix(in srgb, white 4%, transparent);
|
|
229
697
|
}
|
|
230
698
|
.integration-strip.ok {
|
|
231
699
|
border-color: rgba(34, 197, 94, 0.35);
|
|
@@ -233,40 +701,157 @@
|
|
|
233
701
|
.integration-strip.warn {
|
|
234
702
|
border-color: rgba(245, 158, 11, 0.35);
|
|
235
703
|
}
|
|
704
|
+
.page-hero {
|
|
705
|
+
display: grid;
|
|
706
|
+
grid-template-columns: 1.2fr .8fr;
|
|
707
|
+
gap: 10px;
|
|
708
|
+
margin-bottom: 8px;
|
|
709
|
+
}
|
|
710
|
+
.hero-copy {
|
|
711
|
+
border: 1px solid color-mix(in srgb, var(--border) 84%, transparent);
|
|
712
|
+
border-radius: 16px;
|
|
713
|
+
background:
|
|
714
|
+
linear-gradient(180deg, color-mix(in srgb, var(--card-strong) 98%, transparent), color-mix(in srgb, var(--card-soft) 96%, transparent));
|
|
715
|
+
padding: 11px 14px;
|
|
716
|
+
box-shadow:
|
|
717
|
+
inset 0 1px 0 color-mix(in srgb, white 4%, transparent),
|
|
718
|
+
0 10px 24px color-mix(in srgb, black 9%, transparent);
|
|
719
|
+
}
|
|
720
|
+
.hero-copy h3 {
|
|
721
|
+
margin: 0;
|
|
722
|
+
font-size: 17px;
|
|
723
|
+
color: var(--text-strong);
|
|
724
|
+
letter-spacing: -0.02em;
|
|
725
|
+
}
|
|
726
|
+
.hero-copy p {
|
|
727
|
+
margin: 5px 0 0;
|
|
728
|
+
color: var(--muted);
|
|
729
|
+
font-size: 12px;
|
|
730
|
+
line-height: 1.42;
|
|
731
|
+
}
|
|
732
|
+
.hero-meta {
|
|
733
|
+
border: 1px solid color-mix(in srgb, var(--border) 84%, transparent);
|
|
734
|
+
border-radius: 16px;
|
|
735
|
+
background:
|
|
736
|
+
linear-gradient(180deg, color-mix(in srgb, var(--bg-elevated) 97%, transparent), color-mix(in srgb, var(--panel) 98%, transparent));
|
|
737
|
+
padding: 11px;
|
|
738
|
+
box-shadow: inset 0 1px 0 color-mix(in srgb, white 4%, transparent);
|
|
739
|
+
}
|
|
740
|
+
.hero-meta-grid {
|
|
741
|
+
display: grid;
|
|
742
|
+
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
743
|
+
gap: 6px;
|
|
744
|
+
}
|
|
745
|
+
.hero-meta-item {
|
|
746
|
+
border: 1px solid color-mix(in srgb, var(--border) 76%, transparent);
|
|
747
|
+
border-radius: 12px;
|
|
748
|
+
background: color-mix(in srgb, var(--panel) 90%, transparent);
|
|
749
|
+
padding: 7px 9px;
|
|
750
|
+
}
|
|
236
751
|
|
|
237
752
|
.view { display: none; }
|
|
238
|
-
.view.active {
|
|
753
|
+
.view.active {
|
|
754
|
+
display: grid;
|
|
755
|
+
gap: 8px;
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
.section-header {
|
|
759
|
+
display: flex;
|
|
760
|
+
align-items: center;
|
|
761
|
+
justify-content: space-between;
|
|
762
|
+
gap: 12px;
|
|
763
|
+
min-width: 0;
|
|
764
|
+
}
|
|
765
|
+
.section-header__copy {
|
|
766
|
+
min-width: 0;
|
|
767
|
+
}
|
|
768
|
+
.section-header__eyebrow {
|
|
769
|
+
margin: 0 0 3px;
|
|
770
|
+
color: var(--muted);
|
|
771
|
+
font-size: 11px;
|
|
772
|
+
font-weight: 700;
|
|
773
|
+
letter-spacing: 0.08em;
|
|
774
|
+
text-transform: uppercase;
|
|
775
|
+
}
|
|
776
|
+
.section-header__title {
|
|
777
|
+
margin: 0;
|
|
778
|
+
color: var(--text-strong);
|
|
779
|
+
font-size: 16px;
|
|
780
|
+
letter-spacing: -0.02em;
|
|
781
|
+
}
|
|
782
|
+
.section-header__body {
|
|
783
|
+
margin: 4px 0 0;
|
|
784
|
+
color: var(--muted);
|
|
785
|
+
font-size: 12px;
|
|
786
|
+
line-height: 1.45;
|
|
787
|
+
}
|
|
788
|
+
.section-surface {
|
|
789
|
+
border: 1px solid color-mix(in srgb, var(--border) 84%, transparent);
|
|
790
|
+
border-radius: 16px;
|
|
791
|
+
background:
|
|
792
|
+
linear-gradient(180deg, color-mix(in srgb, var(--card-strong) 98%, transparent), color-mix(in srgb, var(--card-soft) 96%, transparent));
|
|
793
|
+
padding: 12px;
|
|
794
|
+
box-shadow:
|
|
795
|
+
inset 0 1px 0 color-mix(in srgb, white 4%, transparent),
|
|
796
|
+
0 14px 30px color-mix(in srgb, black 10%, transparent);
|
|
797
|
+
}
|
|
798
|
+
.section-surface.compact {
|
|
799
|
+
padding: 10px 12px;
|
|
800
|
+
}
|
|
239
801
|
|
|
240
802
|
.grid {
|
|
241
803
|
display: grid;
|
|
242
|
-
gap:
|
|
804
|
+
gap: 8px;
|
|
243
805
|
grid-template-columns: repeat(4, minmax(0, 1fr));
|
|
244
806
|
}
|
|
807
|
+
#networkCards,
|
|
808
|
+
#socialPrimaryCards,
|
|
809
|
+
#socialIntegrationCards,
|
|
810
|
+
#socialAdvancedCards {
|
|
811
|
+
grid-template-columns: repeat(3, minmax(0, 1fr));
|
|
812
|
+
}
|
|
245
813
|
.card {
|
|
246
|
-
border: 1px solid var(--
|
|
247
|
-
border-radius:
|
|
248
|
-
background:
|
|
814
|
+
border: 1px solid color-mix(in srgb, var(--border) 84%, transparent);
|
|
815
|
+
border-radius: 16px;
|
|
816
|
+
background:
|
|
817
|
+
linear-gradient(180deg, color-mix(in srgb, var(--card-strong) 98%, transparent), color-mix(in srgb, var(--card-soft) 96%, transparent));
|
|
249
818
|
padding: 12px;
|
|
250
|
-
box-shadow:
|
|
819
|
+
box-shadow:
|
|
820
|
+
inset 0 1px 0 color-mix(in srgb, white 4%, transparent),
|
|
821
|
+
0 14px 30px color-mix(in srgb, black 10%, transparent);
|
|
822
|
+
transition: border-color .16s ease, transform .16s ease, box-shadow .16s ease;
|
|
823
|
+
}
|
|
824
|
+
.card:hover {
|
|
825
|
+
border-color: color-mix(in srgb, var(--accent) 14%, var(--border));
|
|
826
|
+
box-shadow:
|
|
827
|
+
inset 0 1px 0 color-mix(in srgb, white 4%, transparent),
|
|
828
|
+
0 18px 36px color-mix(in srgb, black 14%, transparent);
|
|
251
829
|
}
|
|
252
830
|
.label { font-size: 12px; color: var(--muted); }
|
|
253
|
-
.value { margin-top: 4px; font-size:
|
|
831
|
+
.value { margin-top: 4px; font-size: 22px; font-weight: 800; letter-spacing: -0.03em; }
|
|
254
832
|
|
|
255
833
|
.split {
|
|
256
|
-
margin-top:
|
|
834
|
+
margin-top: 8px;
|
|
257
835
|
display: grid;
|
|
258
|
-
gap:
|
|
836
|
+
gap: 8px;
|
|
259
837
|
grid-template-columns: 1.2fr 1fr;
|
|
260
838
|
}
|
|
261
|
-
.title-sm { margin: 0 0 10px; font-size:
|
|
839
|
+
.title-sm { margin: 0 0 10px; font-size: 16px; letter-spacing: -0.02em; }
|
|
262
840
|
.mono { font-family: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 12px; }
|
|
263
841
|
|
|
264
842
|
.table {
|
|
265
843
|
width: 100%;
|
|
266
844
|
border-collapse: collapse;
|
|
267
845
|
}
|
|
846
|
+
.table thead th {
|
|
847
|
+
color: var(--muted);
|
|
848
|
+
font-size: 11px;
|
|
849
|
+
font-weight: 700;
|
|
850
|
+
text-transform: uppercase;
|
|
851
|
+
letter-spacing: 0.07em;
|
|
852
|
+
}
|
|
268
853
|
.table th, .table td {
|
|
269
|
-
border-bottom: 1px solid var(--
|
|
854
|
+
border-bottom: 1px solid var(--border);
|
|
270
855
|
text-align: left;
|
|
271
856
|
padding: 8px 6px;
|
|
272
857
|
font-size: 13px;
|
|
@@ -281,22 +866,33 @@
|
|
|
281
866
|
input, textarea {
|
|
282
867
|
margin-top: 5px;
|
|
283
868
|
width: 100%;
|
|
284
|
-
border-radius:
|
|
285
|
-
border: 1px solid var(--
|
|
286
|
-
background: var(--bg-elevated);
|
|
287
|
-
color:
|
|
869
|
+
border-radius: 12px;
|
|
870
|
+
border: 1px solid color-mix(in srgb, var(--border) 84%, transparent);
|
|
871
|
+
background: linear-gradient(180deg, color-mix(in srgb, var(--bg-elevated) 98%, transparent), color-mix(in srgb, var(--panel) 96%, transparent));
|
|
872
|
+
color: var(--text);
|
|
288
873
|
font: inherit;
|
|
289
874
|
padding: 10px;
|
|
875
|
+
box-shadow: inset 0 1px 0 color-mix(in srgb, white 3%, transparent);
|
|
290
876
|
}
|
|
291
877
|
select {
|
|
292
878
|
margin-top: 5px;
|
|
293
879
|
width: 100%;
|
|
294
|
-
border-radius:
|
|
295
|
-
border: 1px solid var(--
|
|
296
|
-
background: var(--bg-elevated);
|
|
880
|
+
border-radius: 12px;
|
|
881
|
+
border: 1px solid color-mix(in srgb, var(--border) 84%, transparent);
|
|
882
|
+
background: linear-gradient(180deg, color-mix(in srgb, var(--bg-elevated) 98%, transparent), color-mix(in srgb, var(--panel) 96%, transparent));
|
|
297
883
|
color: var(--text);
|
|
298
884
|
font: inherit;
|
|
299
885
|
padding: 10px;
|
|
886
|
+
box-shadow: inset 0 1px 0 color-mix(in srgb, white 3%, transparent);
|
|
887
|
+
}
|
|
888
|
+
input:focus,
|
|
889
|
+
textarea:focus,
|
|
890
|
+
select:focus {
|
|
891
|
+
outline: none;
|
|
892
|
+
border-color: color-mix(in srgb, var(--accent) 34%, transparent);
|
|
893
|
+
box-shadow:
|
|
894
|
+
inset 0 1px 0 color-mix(in srgb, white 3%, transparent),
|
|
895
|
+
0 0 0 3px color-mix(in srgb, var(--accent) 14%, transparent);
|
|
300
896
|
}
|
|
301
897
|
textarea { min-height: 90px; resize: vertical; }
|
|
302
898
|
|
|
@@ -305,28 +901,87 @@
|
|
|
305
901
|
gap: 8px;
|
|
306
902
|
flex-wrap: wrap;
|
|
307
903
|
}
|
|
904
|
+
.actions button,
|
|
905
|
+
.action-bar button,
|
|
906
|
+
.toolbar button {
|
|
907
|
+
min-height: 38px;
|
|
908
|
+
}
|
|
909
|
+
.action-bar {
|
|
910
|
+
display: flex;
|
|
911
|
+
gap: 8px;
|
|
912
|
+
flex-wrap: wrap;
|
|
913
|
+
margin-bottom: 8px;
|
|
914
|
+
padding: 2px 0 0;
|
|
915
|
+
}
|
|
916
|
+
.summary-list {
|
|
917
|
+
display: grid;
|
|
918
|
+
gap: 8px;
|
|
919
|
+
}
|
|
920
|
+
.summary-item {
|
|
921
|
+
display: grid;
|
|
922
|
+
gap: 3px;
|
|
923
|
+
padding: 10px;
|
|
924
|
+
border-radius: 12px;
|
|
925
|
+
border: 1px solid color-mix(in srgb, var(--border) 82%, transparent);
|
|
926
|
+
background: linear-gradient(180deg, color-mix(in srgb, var(--bg-elevated) 98%, transparent), color-mix(in srgb, var(--panel) 94%, transparent));
|
|
927
|
+
box-shadow: inset 0 1px 0 color-mix(in srgb, white 4%, transparent);
|
|
928
|
+
}
|
|
929
|
+
.empty-state {
|
|
930
|
+
border: 1px dashed color-mix(in srgb, var(--border-strong) 88%, transparent);
|
|
931
|
+
border-radius: 14px;
|
|
932
|
+
padding: 18px;
|
|
933
|
+
color: var(--muted);
|
|
934
|
+
background: linear-gradient(180deg, color-mix(in srgb, var(--panel) 94%, transparent), color-mix(in srgb, var(--bg-elevated) 88%, transparent));
|
|
935
|
+
line-height: 1.55;
|
|
936
|
+
}
|
|
308
937
|
button {
|
|
309
938
|
border: 1px solid transparent;
|
|
310
|
-
border-radius:
|
|
311
|
-
background: var(--
|
|
939
|
+
border-radius: 12px;
|
|
940
|
+
background: var(--accent);
|
|
312
941
|
color: #ffffff;
|
|
313
942
|
font-weight: 700;
|
|
314
943
|
padding: 9px 13px;
|
|
315
944
|
cursor: pointer;
|
|
945
|
+
box-shadow: 0 10px 20px color-mix(in srgb, var(--accent) 16%, transparent);
|
|
946
|
+
}
|
|
947
|
+
button:hover {
|
|
948
|
+
transform: translateY(-1px);
|
|
949
|
+
filter: saturate(1.04);
|
|
950
|
+
}
|
|
951
|
+
.nav button,
|
|
952
|
+
.nav-collapse-toggle,
|
|
953
|
+
.icon-btn,
|
|
954
|
+
.topbar-theme-mode__btn {
|
|
955
|
+
box-shadow: none;
|
|
956
|
+
filter: none;
|
|
957
|
+
}
|
|
958
|
+
.nav button,
|
|
959
|
+
.nav-collapse-toggle,
|
|
960
|
+
.icon-btn {
|
|
961
|
+
background: transparent;
|
|
962
|
+
color: var(--muted);
|
|
963
|
+
}
|
|
964
|
+
.nav button:hover,
|
|
965
|
+
.nav-collapse-toggle:hover,
|
|
966
|
+
.icon-btn:hover,
|
|
967
|
+
.topbar-theme-mode__btn:hover {
|
|
968
|
+
filter: none;
|
|
316
969
|
}
|
|
317
970
|
button.secondary {
|
|
318
|
-
border-color: var(--
|
|
319
|
-
background: var(--bg-elevated);
|
|
971
|
+
border-color: var(--border-strong);
|
|
972
|
+
background: color-mix(in srgb, var(--bg-elevated) 96%, transparent);
|
|
320
973
|
color: var(--text);
|
|
974
|
+
box-shadow: none;
|
|
321
975
|
}
|
|
322
976
|
|
|
323
977
|
.feedback {
|
|
324
|
-
border: 1px solid var(--
|
|
325
|
-
border-radius:
|
|
326
|
-
background: var(--bg-elevated);
|
|
327
|
-
padding:
|
|
978
|
+
border: 1px solid color-mix(in srgb, var(--border) 84%, transparent);
|
|
979
|
+
border-radius: 12px;
|
|
980
|
+
background: linear-gradient(180deg, color-mix(in srgb, var(--bg-elevated) 98%, transparent), color-mix(in srgb, var(--panel) 96%, transparent));
|
|
981
|
+
padding: 10px 11px;
|
|
328
982
|
font-size: 13px;
|
|
329
983
|
color: var(--muted);
|
|
984
|
+
box-shadow: inset 0 1px 0 color-mix(in srgb, white 4%, transparent);
|
|
330
985
|
}
|
|
331
986
|
.profile-layout {
|
|
332
987
|
display: grid;
|
|
@@ -334,10 +989,11 @@
|
|
|
334
989
|
grid-template-columns: 1.1fr .9fr;
|
|
335
990
|
}
|
|
336
991
|
.profile-meta {
|
|
337
|
-
border: 1px solid var(--
|
|
338
|
-
border-radius:
|
|
992
|
+
border: 1px solid color-mix(in srgb, var(--border) 82%, transparent);
|
|
993
|
+
border-radius: 12px;
|
|
339
994
|
padding: 10px;
|
|
340
|
-
background: color-mix(in srgb, var(--card)
|
|
995
|
+
background: linear-gradient(180deg, color-mix(in srgb, var(--card-soft) 98%, transparent), color-mix(in srgb, var(--bg-elevated) 90%, transparent));
|
|
996
|
+
box-shadow: inset 0 1px 0 color-mix(in srgb, white 4%, transparent);
|
|
341
997
|
}
|
|
342
998
|
.profile-meta h4 {
|
|
343
999
|
margin: 0 0 8px;
|
|
@@ -362,9 +1018,9 @@
|
|
|
362
1018
|
flex-wrap: wrap;
|
|
363
1019
|
}
|
|
364
1020
|
.tag-chip {
|
|
365
|
-
border: 1px solid var(--
|
|
1021
|
+
border: 1px solid var(--border-strong);
|
|
366
1022
|
border-radius: 999px;
|
|
367
|
-
background: var(--
|
|
1023
|
+
background: var(--bg-hover);
|
|
368
1024
|
color: var(--text);
|
|
369
1025
|
padding: 3px 9px;
|
|
370
1026
|
font-size: 12px;
|
|
@@ -377,14 +1033,15 @@
|
|
|
377
1033
|
margin-top: 4px;
|
|
378
1034
|
color: var(--muted);
|
|
379
1035
|
font-size: 12px;
|
|
1036
|
+
line-height: 1.45;
|
|
380
1037
|
}
|
|
381
1038
|
.field-error {
|
|
382
1039
|
margin-top: 4px;
|
|
383
|
-
color: var(--
|
|
1040
|
+
color: var(--danger);
|
|
384
1041
|
font-size: 12px;
|
|
385
1042
|
}
|
|
386
1043
|
.input-invalid {
|
|
387
|
-
border-color: color-mix(in srgb, var(--
|
|
1044
|
+
border-color: color-mix(in srgb, var(--danger) 55%, transparent);
|
|
388
1045
|
}
|
|
389
1046
|
.save-busy {
|
|
390
1047
|
opacity: 0.7;
|
|
@@ -394,46 +1051,71 @@
|
|
|
394
1051
|
.logs {
|
|
395
1052
|
max-height: 420px;
|
|
396
1053
|
overflow: auto;
|
|
397
|
-
border: 1px solid var(--
|
|
398
|
-
border-radius:
|
|
399
|
-
background: var(--panel);
|
|
1054
|
+
border: 1px solid color-mix(in srgb, var(--border) 82%, transparent);
|
|
1055
|
+
border-radius: 14px;
|
|
1056
|
+
background: linear-gradient(180deg, color-mix(in srgb, var(--panel) 96%, transparent), color-mix(in srgb, var(--bg-elevated) 90%, transparent));
|
|
400
1057
|
padding: 10px;
|
|
1058
|
+
box-shadow: inset 0 1px 0 color-mix(in srgb, white 3%, transparent);
|
|
401
1059
|
}
|
|
402
1060
|
.log-item {
|
|
403
|
-
border-bottom: 1px dashed var(--
|
|
1061
|
+
border-bottom: 1px dashed var(--border);
|
|
404
1062
|
padding: 7px 0;
|
|
405
1063
|
}
|
|
406
1064
|
.log-item:last-child { border-bottom: 0; }
|
|
407
1065
|
.log-info { color: #8dc6ff; }
|
|
408
1066
|
.log-warn { color: var(--warn); }
|
|
409
|
-
.log-error { color: var(--
|
|
1067
|
+
.log-error { color: var(--danger); }
|
|
410
1068
|
.toolbar {
|
|
411
1069
|
display: flex;
|
|
412
1070
|
gap: 10px;
|
|
413
1071
|
flex-wrap: wrap;
|
|
414
1072
|
align-items: end;
|
|
415
1073
|
margin-bottom: 10px;
|
|
1074
|
+
padding-bottom: 2px;
|
|
416
1075
|
}
|
|
417
1076
|
.toolbar .field {
|
|
418
1077
|
min-width: 180px;
|
|
419
1078
|
}
|
|
420
1079
|
.mono-block {
|
|
421
|
-
border: 1px solid var(--
|
|
422
|
-
border-radius:
|
|
423
|
-
background: color-mix(in srgb, var(--bg-elevated)
|
|
1080
|
+
border: 1px solid color-mix(in srgb, var(--border) 82%, transparent);
|
|
1081
|
+
border-radius: 12px;
|
|
1082
|
+
background: linear-gradient(180deg, color-mix(in srgb, var(--bg-elevated) 96%, transparent), color-mix(in srgb, var(--panel) 92%, transparent));
|
|
424
1083
|
padding: 10px;
|
|
425
1084
|
max-height: 240px;
|
|
426
1085
|
overflow: auto;
|
|
427
1086
|
white-space: pre-wrap;
|
|
428
1087
|
word-break: break-word;
|
|
1088
|
+
box-shadow: inset 0 1px 0 color-mix(in srgb, white 3%, transparent);
|
|
1089
|
+
}
|
|
1090
|
+
.advanced-panel {
|
|
1091
|
+
margin-top: 8px;
|
|
1092
|
+
}
|
|
1093
|
+
.advanced-panel.card > summary,
|
|
1094
|
+
details.card > summary {
|
|
1095
|
+
display: flex;
|
|
1096
|
+
align-items: center;
|
|
1097
|
+
justify-content: space-between;
|
|
429
1098
|
}
|
|
1099
|
+
.advanced-panel summary {
|
|
1100
|
+
cursor: pointer;
|
|
1101
|
+
list-style: none;
|
|
1102
|
+
user-select: none;
|
|
1103
|
+
}
|
|
1104
|
+
.advanced-panel summary::-webkit-details-marker { display: none; }
|
|
1105
|
+
.advanced-panel summary::after {
|
|
1106
|
+
content: attr(data-i18n-closed-label);
|
|
1107
|
+
float: right;
|
|
1108
|
+
color: var(--muted);
|
|
1109
|
+
font-size: 12px;
|
|
1110
|
+
}
|
|
1111
|
+
.advanced-panel[open] summary::after { content: attr(data-i18n-open-label); }
|
|
430
1112
|
|
|
431
1113
|
.toast {
|
|
432
1114
|
position: fixed;
|
|
433
1115
|
right: 16px;
|
|
434
1116
|
bottom: 16px;
|
|
435
1117
|
background: var(--bg-elevated);
|
|
436
|
-
border: 1px solid color-mix(in srgb, var(--
|
|
1118
|
+
border: 1px solid color-mix(in srgb, var(--accent) 32%, transparent);
|
|
437
1119
|
color: var(--text);
|
|
438
1120
|
border-radius: 10px;
|
|
439
1121
|
padding: 10px 12px;
|
|
@@ -449,69 +1131,220 @@
|
|
|
449
1131
|
transform: translateY(0);
|
|
450
1132
|
}
|
|
451
1133
|
|
|
1134
|
+
#view-overview .action-bar {
|
|
1135
|
+
margin-bottom: 0;
|
|
1136
|
+
}
|
|
1137
|
+
#view-overview .grid {
|
|
1138
|
+
grid-template-columns: repeat(4, minmax(0, 1fr));
|
|
1139
|
+
}
|
|
1140
|
+
#view-overview .card .field-hint {
|
|
1141
|
+
font-size: 12px;
|
|
1142
|
+
}
|
|
1143
|
+
#view-overview #snapshot {
|
|
1144
|
+
line-height: 1.55;
|
|
1145
|
+
}
|
|
1146
|
+
|
|
452
1147
|
@media (max-width: 980px) {
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
1148
|
+
html, body {
|
|
1149
|
+
height: auto;
|
|
1150
|
+
overflow: auto;
|
|
1151
|
+
}
|
|
1152
|
+
.app {
|
|
1153
|
+
grid-template-columns: 1fr;
|
|
1154
|
+
height: auto;
|
|
1155
|
+
overflow: visible;
|
|
1156
|
+
}
|
|
1157
|
+
.sidebar {
|
|
1158
|
+
border-right: 0;
|
|
1159
|
+
border-bottom: 1px solid var(--border);
|
|
1160
|
+
height: auto;
|
|
1161
|
+
overflow: visible;
|
|
1162
|
+
}
|
|
1163
|
+
.sidebar-shell {
|
|
1164
|
+
display: block;
|
|
1165
|
+
}
|
|
1166
|
+
.nav { grid-template-columns: repeat(2, minmax(0,1fr)); }
|
|
456
1167
|
.grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
|
|
457
|
-
.split, .row, .profile-layout { grid-template-columns: 1fr; }
|
|
1168
|
+
.split, .row, .profile-layout, .page-hero { grid-template-columns: 1fr; }
|
|
1169
|
+
.main {
|
|
1170
|
+
height: auto;
|
|
1171
|
+
overflow: visible;
|
|
1172
|
+
padding-bottom: 18px;
|
|
1173
|
+
}
|
|
1174
|
+
.main-scroll {
|
|
1175
|
+
overflow: visible;
|
|
1176
|
+
padding-right: 0;
|
|
1177
|
+
}
|
|
458
1178
|
}
|
|
459
1179
|
</style>
|
|
460
1180
|
</head>
|
|
461
1181
|
<body>
|
|
462
|
-
<div class="app">
|
|
1182
|
+
<div class="app" id="appShell">
|
|
463
1183
|
<aside class="sidebar">
|
|
464
|
-
<div class="
|
|
465
|
-
<
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
1184
|
+
<div class="sidebar-shell">
|
|
1185
|
+
<div class="sidebar-shell__header">
|
|
1186
|
+
<div class="brand">
|
|
1187
|
+
<img id="brandLogo" class="brand-logo" src="/assets/silicaclaw-logo.png" alt="SilicaClaw logo" />
|
|
1188
|
+
<div id="brandFallback" class="brand-badge hidden">SC</div>
|
|
1189
|
+
<div>
|
|
1190
|
+
<h1>SilicaClaw</h1>
|
|
1191
|
+
<p>Control UI</p>
|
|
1192
|
+
</div>
|
|
1193
|
+
</div>
|
|
1194
|
+
<button class="nav-collapse-toggle" id="sidebarToggleBtn" type="button" title="Collapse sidebar" aria-label="Collapse sidebar">
|
|
1195
|
+
<span class="nav-collapse-toggle__icon" aria-hidden="true">
|
|
1196
|
+
<svg viewBox="0 0 24 24">
|
|
1197
|
+
<rect x="3" y="3" width="18" height="18" rx="2"></rect>
|
|
1198
|
+
<path d="M9 3v18"></path>
|
|
1199
|
+
<path d="M16 10l-3 2 3 2"></path>
|
|
1200
|
+
</svg>
|
|
1201
|
+
</span>
|
|
1202
|
+
</button>
|
|
1203
|
+
</div>
|
|
1204
|
+
<div class="sidebar-shell__body">
|
|
1205
|
+
<div class="sidebar-nav__label">Control</div>
|
|
1206
|
+
<nav class="nav">
|
|
1207
|
+
<button class="tab active" data-tab="overview">
|
|
1208
|
+
<span class="tab-icon" aria-hidden="true">
|
|
1209
|
+
<svg viewBox="0 0 24 24">
|
|
1210
|
+
<line x1="12" x2="12" y1="20" y2="10"></line>
|
|
1211
|
+
<line x1="18" x2="18" y1="20" y2="4"></line>
|
|
1212
|
+
<line x1="6" x2="6" y1="20" y2="16"></line>
|
|
1213
|
+
</svg>
|
|
1214
|
+
</span>
|
|
1215
|
+
<span class="tab-labels"><span class="tab-title">Overview</span><span class="tab-copy">Agent summary and discovered peers</span></span>
|
|
1216
|
+
</button>
|
|
1217
|
+
<button class="tab" data-tab="profile">
|
|
1218
|
+
<span class="tab-icon" aria-hidden="true">
|
|
1219
|
+
<svg viewBox="0 0 24 24">
|
|
1220
|
+
<path d="M14.5 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7.5L14.5 2z"></path>
|
|
1221
|
+
<polyline points="14 2 14 8 20 8"></polyline>
|
|
1222
|
+
<line x1="16" x2="8" y1="13" y2="13"></line>
|
|
1223
|
+
<line x1="16" x2="8" y1="17" y2="17"></line>
|
|
1224
|
+
<line x1="10" x2="8" y1="9" y2="9"></line>
|
|
1225
|
+
</svg>
|
|
1226
|
+
</span>
|
|
1227
|
+
<span class="tab-labels"><span class="tab-title">Profile</span><span class="tab-copy">Public identity and saved profile</span></span>
|
|
1228
|
+
</button>
|
|
1229
|
+
<button class="tab" data-tab="network">
|
|
1230
|
+
<span class="tab-icon" aria-hidden="true">
|
|
1231
|
+
<svg viewBox="0 0 24 24">
|
|
1232
|
+
<circle cx="12" cy="12" r="2"></circle>
|
|
1233
|
+
<path d="M16.24 7.76a6 6 0 0 1 0 8.49m-8.48-.01a6 6 0 0 1 0-8.49m11.31-2.82a10 10 0 0 1 0 14.14m-14.14 0a10 10 0 0 1 0-14.14"></path>
|
|
1234
|
+
</svg>
|
|
1235
|
+
</span>
|
|
1236
|
+
<span class="tab-labels"><span class="tab-title">Network</span><span class="tab-copy">Relay health, broadcast, diagnostics</span></span>
|
|
1237
|
+
</button>
|
|
1238
|
+
<button class="tab" data-tab="social">
|
|
1239
|
+
<span class="tab-icon" aria-hidden="true">
|
|
1240
|
+
<svg viewBox="0 0 24 24">
|
|
1241
|
+
<path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"></path>
|
|
1242
|
+
</svg>
|
|
1243
|
+
</span>
|
|
1244
|
+
<span class="tab-labels"><span class="tab-title">Social</span><span class="tab-copy">social.md config and runtime state</span></span>
|
|
1245
|
+
</button>
|
|
1246
|
+
</nav>
|
|
1247
|
+
</div>
|
|
1248
|
+
<div class="sidebar-shell__footer">
|
|
1249
|
+
<div class="sidebar-version" title="Current version">
|
|
1250
|
+
<span class="sidebar-version__text" id="brandVersion">-</span>
|
|
1251
|
+
</div>
|
|
470
1252
|
</div>
|
|
471
1253
|
</div>
|
|
472
|
-
|
|
473
|
-
<nav class="nav">
|
|
474
|
-
<button class="tab active" data-tab="overview">Overview</button>
|
|
475
|
-
<button class="tab" data-tab="profile">Profile</button>
|
|
476
|
-
<button class="tab" data-tab="network">Network</button>
|
|
477
|
-
<button class="tab" data-tab="peers">Peers</button>
|
|
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>
|
|
481
|
-
</nav>
|
|
482
|
-
|
|
483
|
-
<div class="sidebar-foot" id="sideMeta">adapter: -<br/>namespace: -</div>
|
|
484
1254
|
</aside>
|
|
485
1255
|
|
|
486
1256
|
<main class="main">
|
|
487
1257
|
<div class="topbar">
|
|
488
|
-
<div>
|
|
489
|
-
<
|
|
490
|
-
|
|
1258
|
+
<div class="topnav-shell__content">
|
|
1259
|
+
<div class="dashboard-header__breadcrumb">
|
|
1260
|
+
<span class="dashboard-header__breadcrumb-link">SilicaClaw</span>
|
|
1261
|
+
<span class="dashboard-header__breadcrumb-sep">/</span>
|
|
1262
|
+
<span class="dashboard-header__breadcrumb-current" id="pageBreadcrumb">Overview</span>
|
|
1263
|
+
</div>
|
|
1264
|
+
<h2 id="topbarTitle">Local Console</h2>
|
|
1265
|
+
<p id="topbarSubtitle">OpenClaw-inspired local-first agent control surface</p>
|
|
491
1266
|
</div>
|
|
492
1267
|
<div class="status-row">
|
|
493
1268
|
<div class="pill" id="pillAdapter">adapter: -</div>
|
|
494
1269
|
<div class="pill" id="pillBroadcast">broadcast: -</div>
|
|
495
|
-
<div class="
|
|
496
|
-
<button id="
|
|
497
|
-
|
|
1270
|
+
<div class="topbar-actions">
|
|
1271
|
+
<button class="icon-btn" id="focusModeBtn" type="button" title="Toggle focus mode" aria-label="Toggle focus mode">
|
|
1272
|
+
<svg viewBox="0 0 24 24" fill="none" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
|
1273
|
+
<path d="M4 7V4h3"></path>
|
|
1274
|
+
<path d="M20 7V4h-3"></path>
|
|
1275
|
+
<path d="M4 17v3h3"></path>
|
|
1276
|
+
<path d="M20 17v3h-3"></path>
|
|
1277
|
+
<circle cx="12" cy="12" r="3"></circle>
|
|
1278
|
+
</svg>
|
|
1279
|
+
</button>
|
|
1280
|
+
<div class="topbar-theme-mode" id="themeModeGroup" role="group" aria-label="Color mode">
|
|
1281
|
+
<button class="topbar-theme-mode__btn" data-theme-choice="dark" type="button" title="Dark" aria-label="Color mode: Dark">
|
|
1282
|
+
<span class="theme-icon" aria-hidden="true">
|
|
1283
|
+
<svg viewBox="0 0 24 24">
|
|
1284
|
+
<path d="M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9z"></path>
|
|
1285
|
+
</svg>
|
|
1286
|
+
</span>
|
|
1287
|
+
</button>
|
|
1288
|
+
<button class="topbar-theme-mode__btn" data-theme-choice="light" type="button" title="Light" aria-label="Color mode: Light">
|
|
1289
|
+
<span class="theme-icon" aria-hidden="true">
|
|
1290
|
+
<svg viewBox="0 0 24 24">
|
|
1291
|
+
<circle cx="12" cy="12" r="4"></circle>
|
|
1292
|
+
<path d="M12 2v2"></path>
|
|
1293
|
+
<path d="M12 20v2"></path>
|
|
1294
|
+
<path d="M4.93 4.93l1.41 1.41"></path>
|
|
1295
|
+
<path d="M17.66 17.66l1.41 1.41"></path>
|
|
1296
|
+
<path d="M2 12h2"></path>
|
|
1297
|
+
<path d="M20 12h2"></path>
|
|
1298
|
+
<path d="M4.93 19.07l1.41-1.41"></path>
|
|
1299
|
+
<path d="M17.66 6.34l1.41-1.41"></path>
|
|
1300
|
+
</svg>
|
|
1301
|
+
</span>
|
|
1302
|
+
</button>
|
|
1303
|
+
<button class="topbar-theme-mode__btn" data-theme-choice="system" type="button" title="System" aria-label="Color mode: System">
|
|
1304
|
+
<span class="theme-icon" aria-hidden="true">
|
|
1305
|
+
<svg viewBox="0 0 24 24">
|
|
1306
|
+
<rect x="3" y="4" width="18" height="12" rx="2"></rect>
|
|
1307
|
+
<path d="M8 20h8"></path>
|
|
1308
|
+
<path d="M12 16v4"></path>
|
|
1309
|
+
</svg>
|
|
1310
|
+
</span>
|
|
1311
|
+
</button>
|
|
1312
|
+
</div>
|
|
498
1313
|
</div>
|
|
499
1314
|
</div>
|
|
500
1315
|
</div>
|
|
501
|
-
<div class="
|
|
502
|
-
|
|
503
|
-
|
|
1316
|
+
<div class="main-scroll">
|
|
1317
|
+
<div class="integration-strip warn" id="integrationStatusBar">
|
|
1318
|
+
Connected to SilicaClaw: - · Network mode: - · Public discovery: -
|
|
1319
|
+
</div>
|
|
1320
|
+
<section class="page-hero">
|
|
1321
|
+
<div class="hero-copy">
|
|
1322
|
+
<h3 id="pageHeroTitle">Overview</h3>
|
|
1323
|
+
<p id="pageHeroBody">See whether this node is online and who else is visible.</p>
|
|
1324
|
+
</div>
|
|
1325
|
+
<div class="hero-meta">
|
|
1326
|
+
<div class="hero-meta-grid">
|
|
1327
|
+
<div class="hero-meta-item"><div class="label">Mode</div><div class="mono" id="heroMode">-</div></div>
|
|
1328
|
+
<div class="hero-meta-item"><div class="label">Adapter</div><div class="mono" id="heroAdapter">-</div></div>
|
|
1329
|
+
<div class="hero-meta-item"><div class="label">Relay</div><div class="mono" id="heroRelay">-</div></div>
|
|
1330
|
+
<div class="hero-meta-item"><div class="label">Room</div><div class="mono" id="heroRoom">-</div></div>
|
|
1331
|
+
</div>
|
|
1332
|
+
</div>
|
|
1333
|
+
</section>
|
|
504
1334
|
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
</div>
|
|
510
|
-
<div class="field-hint" id="publicDiscoveryHint" style="margin-bottom:12px; display:none;">
|
|
511
|
-
Public discovery only shares signed profile/presence records. It does not share private files and does not enable chat or remote control.
|
|
512
|
-
</div>
|
|
1335
|
+
<div class="notice" id="initNotice"></div>
|
|
1336
|
+
<div class="field-hint" id="publicDiscoveryHint" style="margin-bottom:12px; display:none;">
|
|
1337
|
+
Use <strong>Profile → Public Enabled</strong> as the single public visibility switch.
|
|
1338
|
+
</div>
|
|
513
1339
|
|
|
514
|
-
|
|
1340
|
+
<section id="view-overview" class="view active">
|
|
1341
|
+
<div class="section-surface compact">
|
|
1342
|
+
<div class="action-bar">
|
|
1343
|
+
<button id="overviewBroadcastNowBtn" type="button">Broadcast Now</button>
|
|
1344
|
+
<button class="secondary" id="overviewGoProfileBtn" type="button">Edit Profile</button>
|
|
1345
|
+
<button class="secondary" id="overviewGoNetworkBtn" type="button">Open Network</button>
|
|
1346
|
+
</div>
|
|
1347
|
+
</div>
|
|
515
1348
|
<div class="grid" id="overviewCards"></div>
|
|
516
1349
|
<div class="split">
|
|
517
1350
|
<div class="card">
|
|
@@ -528,9 +1361,16 @@
|
|
|
528
1361
|
<div class="mono" id="snapshot"></div>
|
|
529
1362
|
</div>
|
|
530
1363
|
</div>
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
1364
|
+
</section>
|
|
1365
|
+
|
|
1366
|
+
<section id="view-profile" class="view">
|
|
1367
|
+
<div class="section-header">
|
|
1368
|
+
<div class="section-header__copy">
|
|
1369
|
+
<div class="section-header__eyebrow">Profile</div>
|
|
1370
|
+
<h3 class="section-header__title">Public profile</h3>
|
|
1371
|
+
<p class="section-header__body">Edit the public card other nodes can see.</p>
|
|
1372
|
+
</div>
|
|
1373
|
+
</div>
|
|
534
1374
|
<div class="profile-layout">
|
|
535
1375
|
<div class="card stack">
|
|
536
1376
|
<h3 class="title-sm">Public Profile Editor</h3>
|
|
@@ -561,6 +1401,7 @@
|
|
|
561
1401
|
<div class="field-error" id="errTags"></div>
|
|
562
1402
|
</div>
|
|
563
1403
|
<label><input type="checkbox" name="public_enabled" /> Public Enabled</label>
|
|
1404
|
+
<div class="field-hint">This is the main public visibility switch used for discovery and relay broadcast.</div>
|
|
564
1405
|
<div class="actions">
|
|
565
1406
|
<button type="submit" id="saveProfileBtn">Save Profile</button>
|
|
566
1407
|
<button type="button" class="secondary" id="refreshProfileBtn">Reload</button>
|
|
@@ -592,96 +1433,144 @@
|
|
|
592
1433
|
</div>
|
|
593
1434
|
</div>
|
|
594
1435
|
</div>
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
1436
|
+
</section>
|
|
1437
|
+
|
|
1438
|
+
<section id="view-network" class="view">
|
|
1439
|
+
<div class="section-header">
|
|
1440
|
+
<div class="section-header__copy">
|
|
1441
|
+
<div class="section-header__eyebrow">Network</div>
|
|
1442
|
+
<h3 class="section-header__title">Network</h3>
|
|
1443
|
+
<p class="section-header__body">Check relay status, peers, and broadcast health.</p>
|
|
1444
|
+
</div>
|
|
1445
|
+
</div>
|
|
598
1446
|
<div class="grid" id="networkCards"></div>
|
|
599
1447
|
<div class="split">
|
|
600
1448
|
<div class="card">
|
|
601
|
-
<h3 class="title-sm">
|
|
602
|
-
<div class="
|
|
1449
|
+
<h3 class="title-sm">Connection Summary</h3>
|
|
1450
|
+
<div class="summary-list" id="networkSummaryList"></div>
|
|
603
1451
|
</div>
|
|
604
1452
|
<div class="card">
|
|
605
|
-
<h3 class="title-sm">Actions</h3>
|
|
1453
|
+
<h3 class="title-sm">Quick Actions</h3>
|
|
1454
|
+
<div class="field-hint" style="margin-bottom:10px;">Use these first.</div>
|
|
606
1455
|
<div class="actions">
|
|
607
1456
|
<button id="startBroadcastBtn">Start Broadcast</button>
|
|
608
1457
|
<button class="secondary" id="stopBroadcastBtn">Stop Broadcast</button>
|
|
609
1458
|
<button class="secondary" id="broadcastNowBtn">Broadcast Now</button>
|
|
610
|
-
<button class="secondary" id="refreshCacheBtn">Refresh Cache</button>
|
|
611
|
-
<button class="secondary" id="clearCacheBtn">Clear Discovered Cache</button>
|
|
612
|
-
<button class="secondary" id="quickGlobalPreviewBtn">Enable Cross-network Preview</button>
|
|
613
1459
|
</div>
|
|
1460
|
+
<details class="advanced-panel">
|
|
1461
|
+
<summary class="title-sm">Advanced Actions</summary>
|
|
1462
|
+
<div class="actions" style="margin-top:10px;">
|
|
1463
|
+
<button class="secondary" id="quickGlobalPreviewBtn">Enable Cross-network Preview</button>
|
|
1464
|
+
</div>
|
|
1465
|
+
</details>
|
|
614
1466
|
<div id="networkFeedback" class="feedback" style="margin-top:10px;">Ready.</div>
|
|
615
1467
|
</div>
|
|
616
1468
|
</div>
|
|
617
|
-
<
|
|
1469
|
+
<details class="advanced-panel card">
|
|
1470
|
+
<summary class="title-sm">Diagnostics</summary>
|
|
618
1471
|
<div class="card" style="margin-top:10px;">
|
|
619
|
-
<h3 class="title-sm">
|
|
620
|
-
<div class="mono
|
|
1472
|
+
<h3 class="title-sm">Runtime Components</h3>
|
|
1473
|
+
<div class="mono" id="networkComponents"></div>
|
|
621
1474
|
</div>
|
|
1475
|
+
<div class="grid" id="peerCards" style="margin-top:10px;"></div>
|
|
622
1476
|
<div class="card" style="margin-top:10px;">
|
|
623
|
-
<h3 class="title-sm">
|
|
624
|
-
<div
|
|
1477
|
+
<h3 class="title-sm">Peer Inventory</h3>
|
|
1478
|
+
<div id="peerTableWrap"></div>
|
|
625
1479
|
</div>
|
|
626
|
-
</div>
|
|
627
|
-
</section>
|
|
628
|
-
|
|
629
|
-
<section id="view-peers" class="view">
|
|
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">
|
|
644
1480
|
<div class="card" style="margin-top:10px;">
|
|
645
|
-
<h3 class="title-sm">
|
|
646
|
-
<div class="
|
|
1481
|
+
<h3 class="title-sm">Peer Discovery Stats</h3>
|
|
1482
|
+
<div class="mono mono-block" id="peerStatsWrap">-</div>
|
|
1483
|
+
</div>
|
|
1484
|
+
<div class="grid" id="discoveryCards" style="margin-top:10px;"></div>
|
|
1485
|
+
<div class="split">
|
|
1486
|
+
<div class="card" style="margin-top:10px;">
|
|
1487
|
+
<h3 class="title-sm">Recent Discovery Events</h3>
|
|
1488
|
+
<div class="logs" id="discoveryEventList"></div>
|
|
1489
|
+
</div>
|
|
1490
|
+
<div class="card" style="margin-top:10px;">
|
|
1491
|
+
<h3 class="title-sm">Discovery Snapshot</h3>
|
|
1492
|
+
<div class="mono mono-block" id="discoverySnapshot">-</div>
|
|
1493
|
+
</div>
|
|
647
1494
|
</div>
|
|
648
1495
|
<div class="card" style="margin-top:10px;">
|
|
649
|
-
<h3 class="title-sm">
|
|
650
|
-
<div class="
|
|
1496
|
+
<h3 class="title-sm">Logs</h3>
|
|
1497
|
+
<div class="toolbar">
|
|
1498
|
+
<div class="field">
|
|
1499
|
+
<label for="logLevelFilter">Category</label>
|
|
1500
|
+
<select id="logLevelFilter">
|
|
1501
|
+
<option value="all">all</option>
|
|
1502
|
+
<option value="info">info</option>
|
|
1503
|
+
<option value="warn">warn</option>
|
|
1504
|
+
<option value="error">error</option>
|
|
1505
|
+
</select>
|
|
1506
|
+
</div>
|
|
1507
|
+
<div>
|
|
1508
|
+
<button type="button" class="secondary" id="refreshLogsBtn">Refresh Logs</button>
|
|
1509
|
+
</div>
|
|
1510
|
+
</div>
|
|
1511
|
+
<div class="logs" id="logList"></div>
|
|
1512
|
+
</div>
|
|
1513
|
+
<div class="split">
|
|
1514
|
+
<div class="card" style="margin-top:10px;">
|
|
1515
|
+
<h3 class="title-sm">Config Snapshot</h3>
|
|
1516
|
+
<div class="mono mono-block" id="networkConfigSnapshot">-</div>
|
|
1517
|
+
</div>
|
|
1518
|
+
<div class="card" style="margin-top:10px;">
|
|
1519
|
+
<h3 class="title-sm">Stats Snapshot</h3>
|
|
1520
|
+
<div class="mono mono-block" id="networkStatsSnapshot">-</div>
|
|
1521
|
+
</div>
|
|
1522
|
+
</div>
|
|
1523
|
+
</details>
|
|
1524
|
+
</section>
|
|
1525
|
+
|
|
1526
|
+
<section id="view-social" class="view">
|
|
1527
|
+
<div class="section-header">
|
|
1528
|
+
<div class="section-header__copy">
|
|
1529
|
+
<div class="section-header__eyebrow">Social</div>
|
|
1530
|
+
<h3 class="section-header__title">Social</h3>
|
|
1531
|
+
<p class="section-header__body">Switch mode and export a clean social.md template.</p>
|
|
651
1532
|
</div>
|
|
652
1533
|
</div>
|
|
653
|
-
</section>
|
|
654
|
-
|
|
655
|
-
<section id="view-social" class="view">
|
|
656
1534
|
<div class="card">
|
|
657
1535
|
<h3 class="title-sm">Integration Status</h3>
|
|
658
1536
|
<div class="feedback" id="socialStatusLine">Checking integration status...</div>
|
|
659
1537
|
<div class="field-hint" id="socialStatusSubline">-</div>
|
|
660
1538
|
<div class="field-hint" id="socialStateHint">-</div>
|
|
661
1539
|
</div>
|
|
662
|
-
<div class="
|
|
663
|
-
|
|
1540
|
+
<div class="split" style="margin-top:10px;">
|
|
1541
|
+
<div class="card">
|
|
1542
|
+
<h3 class="title-sm">What Is Active</h3>
|
|
1543
|
+
<div class="grid" id="socialPrimaryCards"></div>
|
|
1544
|
+
</div>
|
|
1545
|
+
<div class="card">
|
|
1546
|
+
<h3 class="title-sm">Identity Binding</h3>
|
|
1547
|
+
<div class="grid" id="socialIntegrationCards"></div>
|
|
1548
|
+
</div>
|
|
1549
|
+
</div>
|
|
664
1550
|
<details class="card" style="margin-top:10px;">
|
|
665
1551
|
<summary class="title-sm" style="cursor:pointer;">Advanced Network Details</summary>
|
|
666
1552
|
<div class="grid" id="socialAdvancedCards" style="margin-top:10px;"></div>
|
|
667
1553
|
<div class="mono mono-block" id="socialAdvancedWrap" style="margin-top:10px;">-</div>
|
|
668
1554
|
</details>
|
|
669
|
-
<
|
|
670
|
-
<
|
|
671
|
-
|
|
672
|
-
<div class="
|
|
673
|
-
|
|
674
|
-
|
|
1555
|
+
<details class="advanced-panel card">
|
|
1556
|
+
<summary class="title-sm">Source / Runtime / Template</summary>
|
|
1557
|
+
<div class="split">
|
|
1558
|
+
<div class="card" style="margin-top:10px;">
|
|
1559
|
+
<h3 class="title-sm">Source & Parsed Frontmatter</h3>
|
|
1560
|
+
<div class="mono mono-block" id="socialSourceWrap">-</div>
|
|
1561
|
+
<div style="height:10px;"></div>
|
|
1562
|
+
<div class="mono mono-block" id="socialRawWrap">-</div>
|
|
1563
|
+
</div>
|
|
1564
|
+
<div class="card" style="margin-top:10px;">
|
|
1565
|
+
<h3 class="title-sm">Runtime Summary</h3>
|
|
1566
|
+
<div class="mono mono-block" id="socialRuntimeWrap">-</div>
|
|
1567
|
+
</div>
|
|
675
1568
|
</div>
|
|
676
1569
|
<div class="card" style="margin-top:10px;">
|
|
677
|
-
<h3 class="title-sm">
|
|
678
|
-
<div class="mono mono-block" id="
|
|
1570
|
+
<h3 class="title-sm">Export Template Preview</h3>
|
|
1571
|
+
<div class="mono mono-block" id="socialTemplateWrap">-</div>
|
|
679
1572
|
</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>
|
|
1573
|
+
</details>
|
|
685
1574
|
<div class="card" style="margin-top:10px;">
|
|
686
1575
|
<h3 class="title-sm">Actions</h3>
|
|
687
1576
|
<div class="toolbar">
|
|
@@ -694,46 +1583,732 @@
|
|
|
694
1583
|
</select>
|
|
695
1584
|
</div>
|
|
696
1585
|
<div>
|
|
697
|
-
<button
|
|
1586
|
+
<button id="socialModeApplyBtn">Apply Runtime Mode</button>
|
|
698
1587
|
</div>
|
|
699
1588
|
</div>
|
|
1589
|
+
<div class="field-hint" style="margin-top:10px;">Profile visibility is managed in the Profile page.</div>
|
|
700
1590
|
<div class="actions">
|
|
701
|
-
<button id="socialReloadBtn">Reload Config</button>
|
|
702
|
-
<button class="secondary" id="socialGenerateBtn">Generate Default social.md</button>
|
|
703
1591
|
<button class="secondary" id="socialExportBtn">Export social.md template</button>
|
|
704
1592
|
<button class="secondary" id="socialCopyBtn">Copy Template</button>
|
|
705
1593
|
<button class="secondary" id="socialDownloadBtn">Download Template</button>
|
|
706
1594
|
</div>
|
|
707
1595
|
<div id="socialFeedback" class="feedback" style="margin-top:10px;">Ready.</div>
|
|
708
1596
|
</div>
|
|
709
|
-
|
|
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>
|
|
1597
|
+
</section>
|
|
1598
|
+
</div>
|
|
731
1599
|
</main>
|
|
732
1600
|
</div>
|
|
733
1601
|
|
|
734
1602
|
<div id="toast" class="toast"></div>
|
|
735
1603
|
|
|
736
1604
|
<script>
|
|
1605
|
+
const LOCALE_STORAGE_KEY = 'silicaclaw.i18n.locale';
|
|
1606
|
+
const DEFAULT_LOCALE = 'en';
|
|
1607
|
+
const SUPPORTED_LOCALES = ['en', 'zh-CN'];
|
|
1608
|
+
const TRANSLATIONS = {
|
|
1609
|
+
en: {
|
|
1610
|
+
meta: {
|
|
1611
|
+
title: 'SilicaClaw Control UI',
|
|
1612
|
+
description: 'SilicaClaw local-first agent control console.',
|
|
1613
|
+
socialTitle: 'SilicaClaw Local Console',
|
|
1614
|
+
socialDescription: 'Local-first control surface for SilicaClaw agents.',
|
|
1615
|
+
},
|
|
1616
|
+
common: {
|
|
1617
|
+
control: 'Control',
|
|
1618
|
+
version: 'Version',
|
|
1619
|
+
localConsole: 'Local Console',
|
|
1620
|
+
subtitle: 'OpenClaw-inspired local-first agent control surface',
|
|
1621
|
+
copied: 'Copied',
|
|
1622
|
+
done: 'Done',
|
|
1623
|
+
saving: 'Saving...',
|
|
1624
|
+
saved: 'Saved.',
|
|
1625
|
+
ready: 'Ready.',
|
|
1626
|
+
reload: 'Reload',
|
|
1627
|
+
yes: 'yes',
|
|
1628
|
+
no: 'no',
|
|
1629
|
+
on: 'enabled',
|
|
1630
|
+
off: 'disabled',
|
|
1631
|
+
unknownError: 'Unknown error',
|
|
1632
|
+
requestFailed: 'Request failed ({status})',
|
|
1633
|
+
},
|
|
1634
|
+
pageMeta: {
|
|
1635
|
+
overview: {
|
|
1636
|
+
title: 'Overview',
|
|
1637
|
+
body: 'See whether this node is online and who else is visible.',
|
|
1638
|
+
},
|
|
1639
|
+
profile: {
|
|
1640
|
+
title: 'Profile',
|
|
1641
|
+
body: 'Edit the public card other nodes can see.',
|
|
1642
|
+
},
|
|
1643
|
+
network: {
|
|
1644
|
+
title: 'Network',
|
|
1645
|
+
body: 'Check relay status, peers, and broadcast health.',
|
|
1646
|
+
},
|
|
1647
|
+
social: {
|
|
1648
|
+
title: 'Social',
|
|
1649
|
+
body: 'Switch mode and export a clean social.md template.',
|
|
1650
|
+
},
|
|
1651
|
+
},
|
|
1652
|
+
actions: {
|
|
1653
|
+
broadcastNow: 'Broadcast Now',
|
|
1654
|
+
editProfile: 'Edit Profile',
|
|
1655
|
+
openNetwork: 'Open Network',
|
|
1656
|
+
startBroadcast: 'Start Broadcast',
|
|
1657
|
+
stopBroadcast: 'Stop Broadcast',
|
|
1658
|
+
enablePreview: 'Enable Cross-network Preview',
|
|
1659
|
+
refreshLogs: 'Refresh Logs',
|
|
1660
|
+
exportTemplate: 'Export social.md template',
|
|
1661
|
+
copyTemplate: 'Copy Template',
|
|
1662
|
+
downloadTemplate: 'Download Template',
|
|
1663
|
+
applyRuntimeMode: 'Apply Runtime Mode',
|
|
1664
|
+
saveProfile: 'Save Profile',
|
|
1665
|
+
copyPublicProfilePreview: 'Copy public profile preview summary',
|
|
1666
|
+
},
|
|
1667
|
+
labels: {
|
|
1668
|
+
overviewTabCopy: 'Agent summary and discovered peers',
|
|
1669
|
+
profileTabCopy: 'Public identity and saved profile',
|
|
1670
|
+
networkTabCopy: 'Relay health, broadcast, diagnostics',
|
|
1671
|
+
socialTabCopy: 'social.md config and runtime state',
|
|
1672
|
+
collapseSidebar: 'Collapse sidebar',
|
|
1673
|
+
expandSidebar: 'Expand sidebar',
|
|
1674
|
+
toggleFocusMode: 'Toggle focus mode',
|
|
1675
|
+
exitFocusMode: 'Exit focus mode',
|
|
1676
|
+
colorMode: 'Color mode',
|
|
1677
|
+
dark: 'Dark',
|
|
1678
|
+
light: 'Light',
|
|
1679
|
+
system: 'System',
|
|
1680
|
+
mode: 'Mode',
|
|
1681
|
+
adapter: 'Adapter',
|
|
1682
|
+
relay: 'Relay',
|
|
1683
|
+
room: 'Room',
|
|
1684
|
+
namespace: 'Namespace',
|
|
1685
|
+
port: 'Port',
|
|
1686
|
+
show: 'Show',
|
|
1687
|
+
hide: 'Hide',
|
|
1688
|
+
discoveredAgents: 'Discovered Agents',
|
|
1689
|
+
onlyShowOnline: 'Only show online',
|
|
1690
|
+
nodeSnapshot: 'Node Snapshot',
|
|
1691
|
+
profileEyebrow: 'Profile',
|
|
1692
|
+
publicProfile: 'Public profile',
|
|
1693
|
+
publicProfileEditor: 'Public Profile Editor',
|
|
1694
|
+
displayName: 'Display Name',
|
|
1695
|
+
avatarUrl: 'Avatar URL',
|
|
1696
|
+
bio: 'Bio',
|
|
1697
|
+
tagsCommaSeparated: 'Tags (comma separated)',
|
|
1698
|
+
publicEnabled: 'Public Enabled',
|
|
1699
|
+
livePreview: 'Live Preview',
|
|
1700
|
+
publicCard: 'Public Card',
|
|
1701
|
+
publishStatus: 'Publish Status',
|
|
1702
|
+
publicProfilePreview: 'Public Profile Preview',
|
|
1703
|
+
networkEyebrow: 'Network',
|
|
1704
|
+
connectionSummary: 'Connection Summary',
|
|
1705
|
+
quickActions: 'Quick Actions',
|
|
1706
|
+
advancedActions: 'Advanced Actions',
|
|
1707
|
+
diagnostics: 'Diagnostics',
|
|
1708
|
+
runtimeComponents: 'Runtime Components',
|
|
1709
|
+
peerInventory: 'Peer Inventory',
|
|
1710
|
+
peerDiscoveryStats: 'Peer Discovery Stats',
|
|
1711
|
+
recentDiscoveryEvents: 'Recent Discovery Events',
|
|
1712
|
+
discoverySnapshot: 'Discovery Snapshot',
|
|
1713
|
+
logs: 'Logs',
|
|
1714
|
+
category: 'Category',
|
|
1715
|
+
configSnapshot: 'Config Snapshot',
|
|
1716
|
+
statsSnapshot: 'Stats Snapshot',
|
|
1717
|
+
socialEyebrow: 'Social',
|
|
1718
|
+
integrationStatus: 'Integration Status',
|
|
1719
|
+
whatIsActive: 'What Is Active',
|
|
1720
|
+
identityBinding: 'Identity Binding',
|
|
1721
|
+
advancedNetworkDetails: 'Advanced Network Details',
|
|
1722
|
+
sourceRuntimeTemplate: 'Source / Runtime / Template',
|
|
1723
|
+
sourceParsedFrontmatter: 'Source & Parsed Frontmatter',
|
|
1724
|
+
runtimeSummary: 'Runtime Summary',
|
|
1725
|
+
exportTemplatePreview: 'Export Template Preview',
|
|
1726
|
+
actionsTitle: 'Actions',
|
|
1727
|
+
networkModeRuntime: 'Network Mode (runtime)',
|
|
1728
|
+
},
|
|
1729
|
+
hints: {
|
|
1730
|
+
publicDiscoverySwitch: 'Use Profile -> Public Enabled as the single public visibility switch.',
|
|
1731
|
+
discoverabilityRecommendation: 'Recommended 2-32 chars for better discoverability.',
|
|
1732
|
+
avatarOptional: 'Optional. Must be http(s) URL if provided.',
|
|
1733
|
+
tagsLimit: 'Up to 8 tags, each <= 20 chars.',
|
|
1734
|
+
publicEnabledHint: 'This is the main public visibility switch used for discovery and relay broadcast.',
|
|
1735
|
+
signedPublicProfileHint: 'This is the signed public profile view other nodes/explorer can see.',
|
|
1736
|
+
useTheseFirst: 'Use these first.',
|
|
1737
|
+
profileVisibilityManaged: 'Profile visibility is managed in the Profile page.',
|
|
1738
|
+
checkingIntegration: 'Checking integration status...',
|
|
1739
|
+
allIntegrationChecksPassed: 'All integration checks passed.',
|
|
1740
|
+
},
|
|
1741
|
+
placeholders: {
|
|
1742
|
+
agentName: 'Agent name',
|
|
1743
|
+
bioSummary: 'Public summary',
|
|
1744
|
+
tags: 'ai,browser,local-first',
|
|
1745
|
+
},
|
|
1746
|
+
overview: {
|
|
1747
|
+
discovered: 'Discovered',
|
|
1748
|
+
online: 'Online',
|
|
1749
|
+
offline: 'Offline',
|
|
1750
|
+
presenceTtl: 'Presence TTL',
|
|
1751
|
+
agentsZero: '0 agents',
|
|
1752
|
+
noDiscoveredAgents: 'No discovered agents yet.',
|
|
1753
|
+
agentsOnlineFilter: '{shown}/{total} agents (online filter)',
|
|
1754
|
+
agentsDiscovered: '{count} agents discovered',
|
|
1755
|
+
tableName: 'Name',
|
|
1756
|
+
tableAgentId: 'Agent ID',
|
|
1757
|
+
tableStatus: 'Status',
|
|
1758
|
+
tableUpdated: 'Updated',
|
|
1759
|
+
unnamed: '(unnamed)',
|
|
1760
|
+
onboardingNotice: 'Connected · mode={mode} · discoverable={discoverable} · next: update your profile, turn on Public Enabled, and export social.md',
|
|
1761
|
+
pillRunning: 'broadcast: running',
|
|
1762
|
+
pillPaused: 'broadcast: paused',
|
|
1763
|
+
},
|
|
1764
|
+
preview: {
|
|
1765
|
+
unnamedAgent: '(unnamed agent)',
|
|
1766
|
+
noBioYet: 'No bio yet.',
|
|
1767
|
+
noTags: 'No tags',
|
|
1768
|
+
visibleFields: 'Visible fields: {visible} | Hidden fields: {hidden}',
|
|
1769
|
+
visible: '[visible] {field}',
|
|
1770
|
+
hidden: '[hidden] {field}',
|
|
1771
|
+
},
|
|
1772
|
+
network: {
|
|
1773
|
+
started: 'Started',
|
|
1774
|
+
transportState: 'Transport State',
|
|
1775
|
+
signalingUrl: 'Signaling URL',
|
|
1776
|
+
signalingEndpoints: 'Signaling Endpoints',
|
|
1777
|
+
webrtcRoom: 'WebRTC Room',
|
|
1778
|
+
bootstrapSources: 'Bootstrap Sources',
|
|
1779
|
+
seedPeers: 'Seed Peers',
|
|
1780
|
+
discoveryEvents: 'Discovery Events',
|
|
1781
|
+
recv: 'Recv',
|
|
1782
|
+
sent: 'Sent',
|
|
1783
|
+
peers: 'Peers',
|
|
1784
|
+
onlinePeers: 'Online Peers',
|
|
1785
|
+
activeWebrtcPeers: 'Active WebRTC Peers',
|
|
1786
|
+
reconnectAttempts: 'Reconnect Attempts',
|
|
1787
|
+
lastInbound: 'Last Inbound',
|
|
1788
|
+
lastOutbound: 'Last Outbound',
|
|
1789
|
+
relayHealth: 'Relay health',
|
|
1790
|
+
currentRelay: 'Current relay',
|
|
1791
|
+
currentRoom: 'Current room',
|
|
1792
|
+
lastJoin: 'Last join',
|
|
1793
|
+
lastPoll: 'Last poll',
|
|
1794
|
+
lastPublish: 'Last publish',
|
|
1795
|
+
lastError: 'Last error',
|
|
1796
|
+
degraded: 'degraded',
|
|
1797
|
+
connected: 'connected',
|
|
1798
|
+
none: 'none',
|
|
1799
|
+
total: 'Total',
|
|
1800
|
+
stale: 'Stale',
|
|
1801
|
+
observeCalls: 'Observe Calls',
|
|
1802
|
+
heartbeats: 'Heartbeats',
|
|
1803
|
+
peersAdded: 'Peers Added',
|
|
1804
|
+
peersRemoved: 'Peers Removed',
|
|
1805
|
+
noPeersDiscovered: 'No peers discovered yet. Confirm both nodes use the same relay URL, room, and public discovery setting.',
|
|
1806
|
+
peer: 'Peer',
|
|
1807
|
+
status: 'Status',
|
|
1808
|
+
lastSeen: 'Last Seen',
|
|
1809
|
+
staleSince: 'Stale Since',
|
|
1810
|
+
messages: 'Messages',
|
|
1811
|
+
firstSeen: 'First Seen',
|
|
1812
|
+
meta: 'Meta',
|
|
1813
|
+
eventsTotal: 'Events Total',
|
|
1814
|
+
lastEvent: 'Last Event',
|
|
1815
|
+
noDiscoveryEvents: 'No discovery events yet. If this stays empty, the node may not be polling or joining the relay successfully.',
|
|
1816
|
+
noLogsYet: 'No logs yet.',
|
|
1817
|
+
noLogsForLevel: 'No {level} logs.',
|
|
1818
|
+
},
|
|
1819
|
+
social: {
|
|
1820
|
+
connectedToSilicaClaw: 'Connected to SilicaClaw',
|
|
1821
|
+
notConnectedToSilicaClaw: 'Not connected to SilicaClaw',
|
|
1822
|
+
discoverableInCurrentMode: 'Discoverable in current mode',
|
|
1823
|
+
notDiscoverableInCurrentMode: 'Not discoverable in current mode',
|
|
1824
|
+
usingMode: 'Using {mode}',
|
|
1825
|
+
publicDiscoveryEnabled: 'Public discovery enabled',
|
|
1826
|
+
publicDiscoveryDisabled: 'Public discovery disabled',
|
|
1827
|
+
notConnected: 'Not connected',
|
|
1828
|
+
barStatus: 'Connected to SilicaClaw: {connected} · Network mode: {mode} · Public discovery: {public}',
|
|
1829
|
+
configured: 'Configured',
|
|
1830
|
+
running: 'Running',
|
|
1831
|
+
discoverable: 'Discoverable',
|
|
1832
|
+
publicDiscovery: 'Public discovery',
|
|
1833
|
+
networkMode: 'network mode',
|
|
1834
|
+
connected: 'connected',
|
|
1835
|
+
discoverableReason: 'discoverable reason',
|
|
1836
|
+
displayName: 'display name',
|
|
1837
|
+
agentId: 'agent id',
|
|
1838
|
+
socialFound: 'social.md found',
|
|
1839
|
+
socialSource: 'social.md source',
|
|
1840
|
+
runtimeGenerated: 'runtime generated',
|
|
1841
|
+
reuseOpenClawIdentity: 'reuse OpenClaw identity',
|
|
1842
|
+
mode: 'mode',
|
|
1843
|
+
broadcastStatus: 'broadcast status',
|
|
1844
|
+
namespace: 'namespace',
|
|
1845
|
+
bootstrapHints: 'bootstrap hints',
|
|
1846
|
+
restartRequired: 'restart required',
|
|
1847
|
+
configuredReason: 'Configured: {reason}',
|
|
1848
|
+
runningReason: 'Running: {reason}',
|
|
1849
|
+
discoverableReasonFull: 'Discoverable: {reason}',
|
|
1850
|
+
},
|
|
1851
|
+
feedback: {
|
|
1852
|
+
unsavedChanges: 'You have unsaved changes.',
|
|
1853
|
+
allChangesSaved: 'All changes saved.',
|
|
1854
|
+
fixValidation: 'Please fix validation errors before saving.',
|
|
1855
|
+
savingProfile: 'Saving profile...',
|
|
1856
|
+
profileSaved: 'Profile saved',
|
|
1857
|
+
profileReloaded: 'Profile form reloaded',
|
|
1858
|
+
exportingTemplate: 'Exporting template...',
|
|
1859
|
+
templateExported: 'Template exported from current runtime.',
|
|
1860
|
+
templateCopied: 'Template copied to clipboard.',
|
|
1861
|
+
preparingDownload: 'Preparing download...',
|
|
1862
|
+
runtimeUpdated: 'Runtime mode updated.',
|
|
1863
|
+
copyPreviewFailed: 'Copy preview failed',
|
|
1864
|
+
logsRefreshed: 'Logs refreshed',
|
|
1865
|
+
crossPreviewEnabled: 'Cross-network preview enabled',
|
|
1866
|
+
enableCrossPreviewFailed: 'Enable cross-network preview failed',
|
|
1867
|
+
downloadFailed: 'Download failed',
|
|
1868
|
+
exportFailed: 'Export failed',
|
|
1869
|
+
copyFailed: 'Copy failed',
|
|
1870
|
+
failed: 'Failed',
|
|
1871
|
+
runtimeMode: 'Runtime mode: {mode}',
|
|
1872
|
+
downloaded: 'Downloaded {filename}.',
|
|
1873
|
+
runtimeModeApplying: 'Applying runtime mode: {mode}...',
|
|
1874
|
+
copyingTemplate: 'Copying template...',
|
|
1875
|
+
crossPreviewEnabling: 'Enabling cross-network preview...',
|
|
1876
|
+
promptSignalingUrl: 'Signaling URL (publicly reachable):',
|
|
1877
|
+
promptRoom: 'Room:',
|
|
1878
|
+
},
|
|
1879
|
+
validation: {
|
|
1880
|
+
displayNameShort: 'Display name should be at least 2 chars.',
|
|
1881
|
+
displayNameLong: 'Display name too long.',
|
|
1882
|
+
avatarProtocol: 'Avatar URL must start with http:// or https://',
|
|
1883
|
+
tooManyTags: 'Too many tags (max 8).',
|
|
1884
|
+
tagTooLong: 'Each tag must be <= 20 chars.',
|
|
1885
|
+
leaveConfirm: 'You have unsaved profile changes. Leave anyway?',
|
|
1886
|
+
},
|
|
1887
|
+
},
|
|
1888
|
+
'zh-CN': {
|
|
1889
|
+
meta: {
|
|
1890
|
+
title: 'SilicaClaw 控制台',
|
|
1891
|
+
description: 'SilicaClaw 本地优先代理控制台。',
|
|
1892
|
+
socialTitle: 'SilicaClaw 本地控制台',
|
|
1893
|
+
socialDescription: '面向 SilicaClaw 代理的本地优先控制界面。',
|
|
1894
|
+
},
|
|
1895
|
+
common: {
|
|
1896
|
+
control: '控制',
|
|
1897
|
+
version: '版本',
|
|
1898
|
+
localConsole: '本地控制台',
|
|
1899
|
+
subtitle: '受 OpenClaw 启发的本地优先代理控制界面',
|
|
1900
|
+
copied: '已复制',
|
|
1901
|
+
done: '完成',
|
|
1902
|
+
saving: '保存中...',
|
|
1903
|
+
saved: '已保存。',
|
|
1904
|
+
ready: '就绪。',
|
|
1905
|
+
reload: '重新加载',
|
|
1906
|
+
yes: '是',
|
|
1907
|
+
no: '否',
|
|
1908
|
+
on: '已启用',
|
|
1909
|
+
off: '已禁用',
|
|
1910
|
+
unknownError: '未知错误',
|
|
1911
|
+
requestFailed: '请求失败 ({status})',
|
|
1912
|
+
},
|
|
1913
|
+
pageMeta: {
|
|
1914
|
+
overview: {
|
|
1915
|
+
title: '概览',
|
|
1916
|
+
body: '查看当前节点是否在线,以及还能看到哪些节点。',
|
|
1917
|
+
},
|
|
1918
|
+
profile: {
|
|
1919
|
+
title: 'Profile',
|
|
1920
|
+
body: '编辑其他节点可见的公开名片。',
|
|
1921
|
+
},
|
|
1922
|
+
network: {
|
|
1923
|
+
title: '网络',
|
|
1924
|
+
body: '检查 relay 状态、对等节点和广播健康度。',
|
|
1925
|
+
},
|
|
1926
|
+
social: {
|
|
1927
|
+
title: '社交',
|
|
1928
|
+
body: '切换模式并导出干净的 social.md 模板。',
|
|
1929
|
+
},
|
|
1930
|
+
},
|
|
1931
|
+
actions: {
|
|
1932
|
+
broadcastNow: '立即广播',
|
|
1933
|
+
editProfile: '编辑 Profile',
|
|
1934
|
+
openNetwork: '打开网络页',
|
|
1935
|
+
startBroadcast: '启动广播',
|
|
1936
|
+
stopBroadcast: '停止广播',
|
|
1937
|
+
enablePreview: '启用跨网络预览',
|
|
1938
|
+
refreshLogs: '刷新日志',
|
|
1939
|
+
exportTemplate: '导出 social.md 模板',
|
|
1940
|
+
copyTemplate: '复制模板',
|
|
1941
|
+
downloadTemplate: '下载模板',
|
|
1942
|
+
applyRuntimeMode: '应用运行时模式',
|
|
1943
|
+
saveProfile: '保存 Profile',
|
|
1944
|
+
copyPublicProfilePreview: '复制公开 Profile 预览摘要',
|
|
1945
|
+
},
|
|
1946
|
+
labels: {
|
|
1947
|
+
overviewTabCopy: '代理摘要与已发现节点',
|
|
1948
|
+
profileTabCopy: '公开身份与已保存的 Profile',
|
|
1949
|
+
networkTabCopy: 'Relay 健康度、广播与诊断',
|
|
1950
|
+
socialTabCopy: 'social.md 配置与运行时状态',
|
|
1951
|
+
collapseSidebar: '折叠侧边栏',
|
|
1952
|
+
expandSidebar: '展开侧边栏',
|
|
1953
|
+
toggleFocusMode: '切换专注模式',
|
|
1954
|
+
exitFocusMode: '退出专注模式',
|
|
1955
|
+
colorMode: '颜色模式',
|
|
1956
|
+
dark: '深色',
|
|
1957
|
+
light: '浅色',
|
|
1958
|
+
system: '跟随系统',
|
|
1959
|
+
mode: '模式',
|
|
1960
|
+
adapter: '适配器',
|
|
1961
|
+
relay: 'Relay',
|
|
1962
|
+
room: '房间',
|
|
1963
|
+
namespace: '命名空间',
|
|
1964
|
+
port: '端口',
|
|
1965
|
+
show: '显示',
|
|
1966
|
+
hide: '隐藏',
|
|
1967
|
+
discoveredAgents: '已发现代理',
|
|
1968
|
+
onlyShowOnline: '只显示在线',
|
|
1969
|
+
nodeSnapshot: '节点快照',
|
|
1970
|
+
profileEyebrow: 'Profile',
|
|
1971
|
+
publicProfile: '公开 Profile',
|
|
1972
|
+
publicProfileEditor: '公开 Profile 编辑器',
|
|
1973
|
+
displayName: '显示名称',
|
|
1974
|
+
avatarUrl: '头像 URL',
|
|
1975
|
+
bio: '简介',
|
|
1976
|
+
tagsCommaSeparated: '标签(逗号分隔)',
|
|
1977
|
+
publicEnabled: '公开启用',
|
|
1978
|
+
livePreview: '实时预览',
|
|
1979
|
+
publicCard: '公开卡片',
|
|
1980
|
+
publishStatus: '发布状态',
|
|
1981
|
+
publicProfilePreview: '公开 Profile 预览',
|
|
1982
|
+
networkEyebrow: '网络',
|
|
1983
|
+
connectionSummary: '连接摘要',
|
|
1984
|
+
quickActions: '快捷操作',
|
|
1985
|
+
advancedActions: '高级操作',
|
|
1986
|
+
diagnostics: '诊断',
|
|
1987
|
+
runtimeComponents: '运行时组件',
|
|
1988
|
+
peerInventory: '节点清单',
|
|
1989
|
+
peerDiscoveryStats: '节点发现统计',
|
|
1990
|
+
recentDiscoveryEvents: '最近发现事件',
|
|
1991
|
+
discoverySnapshot: '发现快照',
|
|
1992
|
+
logs: '日志',
|
|
1993
|
+
category: '类别',
|
|
1994
|
+
configSnapshot: '配置快照',
|
|
1995
|
+
statsSnapshot: '统计快照',
|
|
1996
|
+
socialEyebrow: '社交',
|
|
1997
|
+
integrationStatus: '集成状态',
|
|
1998
|
+
whatIsActive: '当前激活项',
|
|
1999
|
+
identityBinding: '身份绑定',
|
|
2000
|
+
advancedNetworkDetails: '高级网络详情',
|
|
2001
|
+
sourceRuntimeTemplate: '来源 / 运行时 / 模板',
|
|
2002
|
+
sourceParsedFrontmatter: '源文件与解析后的 Frontmatter',
|
|
2003
|
+
runtimeSummary: '运行时摘要',
|
|
2004
|
+
exportTemplatePreview: '导出模板预览',
|
|
2005
|
+
actionsTitle: '操作',
|
|
2006
|
+
networkModeRuntime: '网络模式(运行时)',
|
|
2007
|
+
},
|
|
2008
|
+
hints: {
|
|
2009
|
+
publicDiscoverySwitch: '使用 Profile -> Public Enabled 作为唯一的公开可见性开关。',
|
|
2010
|
+
discoverabilityRecommendation: '建议 2-32 个字符,以提升可发现性。',
|
|
2011
|
+
avatarOptional: '可选。如提供,必须是 http(s) URL。',
|
|
2012
|
+
tagsLimit: '最多 8 个标签,每个不超过 20 个字符。',
|
|
2013
|
+
publicEnabledHint: '这是发现与 relay 广播使用的主公开可见性开关。',
|
|
2014
|
+
signedPublicProfileHint: '这是其他节点或 explorer 可以看到的已签名公开 Profile 视图。',
|
|
2015
|
+
useTheseFirst: '优先使用这些操作。',
|
|
2016
|
+
profileVisibilityManaged: 'Profile 可见性在 Profile 页面管理。',
|
|
2017
|
+
checkingIntegration: '正在检查集成状态...',
|
|
2018
|
+
allIntegrationChecksPassed: '所有集成检查均已通过。',
|
|
2019
|
+
},
|
|
2020
|
+
placeholders: {
|
|
2021
|
+
agentName: '代理名称',
|
|
2022
|
+
bioSummary: '公开摘要',
|
|
2023
|
+
tags: 'ai,browser,local-first',
|
|
2024
|
+
},
|
|
2025
|
+
overview: {
|
|
2026
|
+
discovered: '已发现',
|
|
2027
|
+
online: '在线',
|
|
2028
|
+
offline: '离线',
|
|
2029
|
+
presenceTtl: 'Presence TTL',
|
|
2030
|
+
agentsZero: '0 个代理',
|
|
2031
|
+
noDiscoveredAgents: '还没有发现代理。',
|
|
2032
|
+
agentsOnlineFilter: '{shown}/{total} 个代理(在线筛选)',
|
|
2033
|
+
agentsDiscovered: '已发现 {count} 个代理',
|
|
2034
|
+
tableName: '名称',
|
|
2035
|
+
tableAgentId: '代理 ID',
|
|
2036
|
+
tableStatus: '状态',
|
|
2037
|
+
tableUpdated: '更新时间',
|
|
2038
|
+
unnamed: '(未命名)',
|
|
2039
|
+
onboardingNotice: '已连接 · mode={mode} · discoverable={discoverable} · 下一步:更新 Profile、开启 Public Enabled,并导出 social.md',
|
|
2040
|
+
pillRunning: 'broadcast: 运行中',
|
|
2041
|
+
pillPaused: 'broadcast: 已暂停',
|
|
2042
|
+
},
|
|
2043
|
+
preview: {
|
|
2044
|
+
unnamedAgent: '(未命名代理)',
|
|
2045
|
+
noBioYet: '还没有简介。',
|
|
2046
|
+
noTags: '没有标签',
|
|
2047
|
+
visibleFields: '显示字段: {visible} | 隐藏字段: {hidden}',
|
|
2048
|
+
visible: '[显示] {field}',
|
|
2049
|
+
hidden: '[隐藏] {field}',
|
|
2050
|
+
},
|
|
2051
|
+
network: {
|
|
2052
|
+
started: '已启动',
|
|
2053
|
+
transportState: '传输状态',
|
|
2054
|
+
signalingUrl: 'Signaling URL',
|
|
2055
|
+
signalingEndpoints: 'Signaling 端点',
|
|
2056
|
+
webrtcRoom: 'WebRTC 房间',
|
|
2057
|
+
bootstrapSources: 'Bootstrap 来源',
|
|
2058
|
+
seedPeers: '种子节点',
|
|
2059
|
+
discoveryEvents: '发现事件',
|
|
2060
|
+
recv: '接收',
|
|
2061
|
+
sent: '发送',
|
|
2062
|
+
peers: '节点',
|
|
2063
|
+
onlinePeers: '在线节点',
|
|
2064
|
+
activeWebrtcPeers: '活跃 WebRTC 节点',
|
|
2065
|
+
reconnectAttempts: '重连尝试次数',
|
|
2066
|
+
lastInbound: '最近入站',
|
|
2067
|
+
lastOutbound: '最近出站',
|
|
2068
|
+
relayHealth: 'Relay 健康度',
|
|
2069
|
+
currentRelay: '当前 Relay',
|
|
2070
|
+
currentRoom: '当前房间',
|
|
2071
|
+
lastJoin: '最近加入',
|
|
2072
|
+
lastPoll: '最近轮询',
|
|
2073
|
+
lastPublish: '最近发布',
|
|
2074
|
+
lastError: '最近错误',
|
|
2075
|
+
degraded: '降级',
|
|
2076
|
+
connected: '已连接',
|
|
2077
|
+
none: '无',
|
|
2078
|
+
total: '总数',
|
|
2079
|
+
stale: '陈旧',
|
|
2080
|
+
observeCalls: '观察调用',
|
|
2081
|
+
heartbeats: '心跳',
|
|
2082
|
+
peersAdded: '新增节点',
|
|
2083
|
+
peersRemoved: '移除节点',
|
|
2084
|
+
noPeersDiscovered: '尚未发现节点。请确认两端使用相同的 relay URL、room 与公开发现设置。',
|
|
2085
|
+
peer: '节点',
|
|
2086
|
+
status: '状态',
|
|
2087
|
+
lastSeen: '最近出现',
|
|
2088
|
+
staleSince: '陈旧开始于',
|
|
2089
|
+
messages: '消息数',
|
|
2090
|
+
firstSeen: '首次出现',
|
|
2091
|
+
meta: '元数据',
|
|
2092
|
+
eventsTotal: '事件总数',
|
|
2093
|
+
lastEvent: '最近事件',
|
|
2094
|
+
noDiscoveryEvents: '还没有发现事件。如果这里持续为空,节点可能没有成功轮询或加入 relay。',
|
|
2095
|
+
noLogsYet: '还没有日志。',
|
|
2096
|
+
noLogsForLevel: '没有 {level} 级别日志。',
|
|
2097
|
+
},
|
|
2098
|
+
social: {
|
|
2099
|
+
connectedToSilicaClaw: '已连接到 SilicaClaw',
|
|
2100
|
+
notConnectedToSilicaClaw: '未连接到 SilicaClaw',
|
|
2101
|
+
discoverableInCurrentMode: '当前模式下可发现',
|
|
2102
|
+
notDiscoverableInCurrentMode: '当前模式下不可发现',
|
|
2103
|
+
usingMode: '使用 {mode}',
|
|
2104
|
+
publicDiscoveryEnabled: '公开发现已启用',
|
|
2105
|
+
publicDiscoveryDisabled: '公开发现已禁用',
|
|
2106
|
+
notConnected: '未连接',
|
|
2107
|
+
barStatus: 'Connected to SilicaClaw: {connected} · Network mode: {mode} · Public discovery: {public}',
|
|
2108
|
+
configured: '已配置',
|
|
2109
|
+
running: '运行中',
|
|
2110
|
+
discoverable: '可发现',
|
|
2111
|
+
publicDiscovery: '公开发现',
|
|
2112
|
+
networkMode: '网络模式',
|
|
2113
|
+
connected: '已连接',
|
|
2114
|
+
discoverableReason: '可发现原因',
|
|
2115
|
+
displayName: '显示名称',
|
|
2116
|
+
agentId: '代理 ID',
|
|
2117
|
+
socialFound: '已找到 social.md',
|
|
2118
|
+
socialSource: 'social.md 来源',
|
|
2119
|
+
runtimeGenerated: '运行时生成',
|
|
2120
|
+
reuseOpenClawIdentity: '复用 OpenClaw 身份',
|
|
2121
|
+
mode: '模式',
|
|
2122
|
+
broadcastStatus: '广播状态',
|
|
2123
|
+
namespace: '命名空间',
|
|
2124
|
+
bootstrapHints: 'Bootstrap 提示',
|
|
2125
|
+
restartRequired: '需要重启',
|
|
2126
|
+
configuredReason: 'Configured: {reason}',
|
|
2127
|
+
runningReason: 'Running: {reason}',
|
|
2128
|
+
discoverableReasonFull: 'Discoverable: {reason}',
|
|
2129
|
+
},
|
|
2130
|
+
feedback: {
|
|
2131
|
+
unsavedChanges: '你有尚未保存的更改。',
|
|
2132
|
+
allChangesSaved: '所有更改都已保存。',
|
|
2133
|
+
fixValidation: '请先修复校验错误再保存。',
|
|
2134
|
+
savingProfile: '正在保存 Profile...',
|
|
2135
|
+
profileSaved: 'Profile 已保存',
|
|
2136
|
+
profileReloaded: 'Profile 表单已重新加载',
|
|
2137
|
+
exportingTemplate: '正在导出模板...',
|
|
2138
|
+
templateExported: '已按当前运行时导出模板。',
|
|
2139
|
+
templateCopied: '模板已复制到剪贴板。',
|
|
2140
|
+
preparingDownload: '正在准备下载...',
|
|
2141
|
+
runtimeUpdated: '运行时模式已更新。',
|
|
2142
|
+
copyPreviewFailed: '复制预览失败',
|
|
2143
|
+
logsRefreshed: '日志已刷新',
|
|
2144
|
+
crossPreviewEnabled: '跨网络预览已启用',
|
|
2145
|
+
enableCrossPreviewFailed: '启用跨网络预览失败',
|
|
2146
|
+
downloadFailed: '下载失败',
|
|
2147
|
+
exportFailed: '导出失败',
|
|
2148
|
+
copyFailed: '复制失败',
|
|
2149
|
+
failed: '失败',
|
|
2150
|
+
runtimeMode: '运行时模式: {mode}',
|
|
2151
|
+
downloaded: '已下载 {filename}。',
|
|
2152
|
+
runtimeModeApplying: '正在应用运行时模式: {mode}...',
|
|
2153
|
+
copyingTemplate: '正在复制模板...',
|
|
2154
|
+
crossPreviewEnabling: '正在启用跨网络预览...',
|
|
2155
|
+
promptSignalingUrl: 'Signaling URL(需公网可达):',
|
|
2156
|
+
promptRoom: '房间:',
|
|
2157
|
+
},
|
|
2158
|
+
validation: {
|
|
2159
|
+
displayNameShort: '显示名称至少需要 2 个字符。',
|
|
2160
|
+
displayNameLong: '显示名称过长。',
|
|
2161
|
+
avatarProtocol: '头像 URL 必须以 http:// 或 https:// 开头',
|
|
2162
|
+
tooManyTags: '标签过多(最多 8 个)。',
|
|
2163
|
+
tagTooLong: '每个标签必须不超过 20 个字符。',
|
|
2164
|
+
leaveConfirm: '你有未保存的 Profile 更改,仍要离开吗?',
|
|
2165
|
+
},
|
|
2166
|
+
},
|
|
2167
|
+
};
|
|
2168
|
+
function isSupportedLocale(value) {
|
|
2169
|
+
return SUPPORTED_LOCALES.includes(value);
|
|
2170
|
+
}
|
|
2171
|
+
function resolveNavigatorLocale(language) {
|
|
2172
|
+
return String(language || '').toLowerCase().startsWith('zh') ? 'zh-CN' : DEFAULT_LOCALE;
|
|
2173
|
+
}
|
|
2174
|
+
function resolveInitialLocale() {
|
|
2175
|
+
const saved = localStorage.getItem(LOCALE_STORAGE_KEY);
|
|
2176
|
+
if (isSupportedLocale(saved)) return saved;
|
|
2177
|
+
return resolveNavigatorLocale(globalThis.navigator?.language || '');
|
|
2178
|
+
}
|
|
2179
|
+
let currentLocale = resolveInitialLocale();
|
|
2180
|
+
function t(key, params = {}) {
|
|
2181
|
+
const parts = key.split('.');
|
|
2182
|
+
const resolve = (bundle) => parts.reduce((acc, part) => (acc && typeof acc === 'object' ? acc[part] : undefined), bundle);
|
|
2183
|
+
let value = resolve(TRANSLATIONS[currentLocale]);
|
|
2184
|
+
if (typeof value !== 'string') value = resolve(TRANSLATIONS[DEFAULT_LOCALE]);
|
|
2185
|
+
if (typeof value !== 'string') return key;
|
|
2186
|
+
return value.replace(/\{(\w+)\}/g, (_, name) => params[name] ?? `{${name}}`);
|
|
2187
|
+
}
|
|
2188
|
+
function setLocale(locale) {
|
|
2189
|
+
currentLocale = isSupportedLocale(locale) ? locale : DEFAULT_LOCALE;
|
|
2190
|
+
document.documentElement.lang = currentLocale;
|
|
2191
|
+
}
|
|
2192
|
+
function applyStaticTranslations() {
|
|
2193
|
+
const setText = (selector, text, index = 0) => {
|
|
2194
|
+
const nodes = document.querySelectorAll(selector);
|
|
2195
|
+
if (nodes[index]) nodes[index].textContent = text;
|
|
2196
|
+
};
|
|
2197
|
+
document.title = t('meta.title');
|
|
2198
|
+
document.getElementById('metaDescription').setAttribute('content', t('meta.description'));
|
|
2199
|
+
document.getElementById('ogTitle').setAttribute('content', t('meta.socialTitle'));
|
|
2200
|
+
document.getElementById('ogDescription').setAttribute('content', t('meta.socialDescription'));
|
|
2201
|
+
document.getElementById('twitterTitle').setAttribute('content', t('meta.socialTitle'));
|
|
2202
|
+
document.getElementById('twitterDescription').setAttribute('content', t('meta.socialDescription'));
|
|
2203
|
+
setText('.brand p', 'Control UI');
|
|
2204
|
+
document.querySelectorAll('.advanced-panel summary').forEach((summary) => {
|
|
2205
|
+
summary.setAttribute('data-i18n-closed-label', t('labels.show'));
|
|
2206
|
+
summary.setAttribute('data-i18n-open-label', t('labels.hide'));
|
|
2207
|
+
});
|
|
2208
|
+
setText('.sidebar-nav__label', t('common.control'));
|
|
2209
|
+
setText('[data-tab="overview"] .tab-title', t('pageMeta.overview.title'));
|
|
2210
|
+
setText('[data-tab="overview"] .tab-copy', t('labels.overviewTabCopy'));
|
|
2211
|
+
setText('[data-tab="profile"] .tab-title', t('pageMeta.profile.title'));
|
|
2212
|
+
setText('[data-tab="profile"] .tab-copy', t('labels.profileTabCopy'));
|
|
2213
|
+
setText('[data-tab="network"] .tab-title', t('pageMeta.network.title'));
|
|
2214
|
+
setText('[data-tab="network"] .tab-copy', t('labels.networkTabCopy'));
|
|
2215
|
+
setText('[data-tab="social"] .tab-title', t('pageMeta.social.title'));
|
|
2216
|
+
setText('[data-tab="social"] .tab-copy', t('labels.socialTabCopy'));
|
|
2217
|
+
document.getElementById('sidebarToggleBtn').title = t('labels.collapseSidebar');
|
|
2218
|
+
document.getElementById('sidebarToggleBtn').setAttribute('aria-label', t('labels.collapseSidebar'));
|
|
2219
|
+
document.querySelector('.sidebar-version').title = t('common.version');
|
|
2220
|
+
setText('.dashboard-header__breadcrumb-current', t('pageMeta.overview.title'));
|
|
2221
|
+
document.getElementById('topbarTitle').textContent = t('common.localConsole');
|
|
2222
|
+
document.getElementById('topbarSubtitle').textContent = t('common.subtitle');
|
|
2223
|
+
document.getElementById('focusModeBtn').title = t('labels.toggleFocusMode');
|
|
2224
|
+
document.getElementById('focusModeBtn').setAttribute('aria-label', t('labels.toggleFocusMode'));
|
|
2225
|
+
document.getElementById('themeModeGroup').setAttribute('aria-label', t('labels.colorMode'));
|
|
2226
|
+
document.querySelector('[data-theme-choice="dark"]').title = t('labels.dark');
|
|
2227
|
+
document.querySelector('[data-theme-choice="dark"]').setAttribute('aria-label', `${t('labels.colorMode')}: ${t('labels.dark')}`);
|
|
2228
|
+
document.querySelector('[data-theme-choice="light"]').title = t('labels.light');
|
|
2229
|
+
document.querySelector('[data-theme-choice="light"]').setAttribute('aria-label', `${t('labels.colorMode')}: ${t('labels.light')}`);
|
|
2230
|
+
document.querySelector('[data-theme-choice="system"]').title = t('labels.system');
|
|
2231
|
+
document.querySelector('[data-theme-choice="system"]').setAttribute('aria-label', `${t('labels.colorMode')}: ${t('labels.system')}`);
|
|
2232
|
+
setText('#view-overview .title-sm', t('labels.discoveredAgents'), 0);
|
|
2233
|
+
document.getElementById('agentsCountHint').textContent = t('overview.agentsZero');
|
|
2234
|
+
setText('#view-overview label.field-hint', t('labels.onlyShowOnline'));
|
|
2235
|
+
setText('#view-overview .title-sm', t('labels.nodeSnapshot'), 1);
|
|
2236
|
+
setText('#view-profile .section-header__eyebrow', t('labels.profileEyebrow'));
|
|
2237
|
+
setText('#view-profile .section-header__title', t('labels.publicProfile'));
|
|
2238
|
+
setText('#view-profile .title-sm', t('labels.publicProfileEditor'), 0);
|
|
2239
|
+
setText('#view-profile label', t('labels.displayName'), 0);
|
|
2240
|
+
setText('#view-profile .row > div:nth-child(2) label', t('labels.avatarUrl'));
|
|
2241
|
+
setText('#view-profile div > label + textarea', t('labels.bio'));
|
|
2242
|
+
setText('#view-profile div > label + input[name="tags"]', t('labels.tagsCommaSeparated'));
|
|
2243
|
+
document.querySelector('#view-profile input[name="display_name"]').setAttribute('placeholder', t('placeholders.agentName'));
|
|
2244
|
+
document.querySelector('#view-profile input[name="avatar_url"]').setAttribute('placeholder', 'https://...');
|
|
2245
|
+
document.querySelector('#view-profile textarea[name="bio"]').setAttribute('placeholder', t('placeholders.bioSummary'));
|
|
2246
|
+
document.querySelector('#view-profile input[name="tags"]').setAttribute('placeholder', t('placeholders.tags'));
|
|
2247
|
+
document.querySelector('#view-profile input[name="display_name"]').nextElementSibling.textContent = t('hints.discoverabilityRecommendation');
|
|
2248
|
+
document.querySelector('#view-profile input[name="avatar_url"]').nextElementSibling.textContent = t('hints.avatarOptional');
|
|
2249
|
+
document.querySelector('#view-profile input[name="tags"]').nextElementSibling.textContent = t('hints.tagsLimit');
|
|
2250
|
+
document.querySelector('#view-profile input[name="public_enabled"]').parentElement.childNodes[1].textContent = ` ${t('labels.publicEnabled')}`;
|
|
2251
|
+
setText('#view-profile .field-hint', t('hints.publicEnabledHint'), 3);
|
|
2252
|
+
setText('#view-profile .title-sm', t('labels.livePreview'), 1);
|
|
2253
|
+
setText('#view-profile .profile-meta h4', t('labels.publicCard'), 0);
|
|
2254
|
+
setText('#view-profile .profile-meta h4', t('labels.publishStatus'), 1);
|
|
2255
|
+
setText('#view-profile .profile-meta h4', t('labels.publicProfilePreview'), 2);
|
|
2256
|
+
setText('#view-profile .profile-meta .field-hint', t('hints.signedPublicProfileHint'));
|
|
2257
|
+
setText('#view-network .section-header__eyebrow', t('labels.networkEyebrow'));
|
|
2258
|
+
setText('#view-network .section-header__title', t('pageMeta.network.title'));
|
|
2259
|
+
setText('#view-network .split .card .title-sm', t('labels.connectionSummary'), 0);
|
|
2260
|
+
setText('#view-network .split .card .title-sm', t('labels.quickActions'), 1);
|
|
2261
|
+
setText('#view-network .split .card .field-hint', t('hints.useTheseFirst'));
|
|
2262
|
+
setText('#view-network details.advanced-panel summary', t('labels.advancedActions'), 0);
|
|
2263
|
+
setText('#view-network > details.advanced-panel.card > summary', t('labels.diagnostics'));
|
|
2264
|
+
setText('#view-network .card .title-sm', t('labels.runtimeComponents'), 3);
|
|
2265
|
+
setText('#view-network .card .title-sm', t('labels.peerInventory'), 4);
|
|
2266
|
+
setText('#view-network .card .title-sm', t('labels.peerDiscoveryStats'), 5);
|
|
2267
|
+
setText('#view-network .card .title-sm', t('labels.recentDiscoveryEvents'), 6);
|
|
2268
|
+
setText('#view-network .card .title-sm', t('labels.discoverySnapshot'), 7);
|
|
2269
|
+
setText('#view-network label[for="logLevelFilter"]', t('labels.category'));
|
|
2270
|
+
setText('#view-network .card .title-sm', t('labels.configSnapshot'), 9);
|
|
2271
|
+
setText('#view-network .card .title-sm', t('labels.statsSnapshot'), 10);
|
|
2272
|
+
setText('#view-social .section-header__eyebrow', t('labels.socialEyebrow'));
|
|
2273
|
+
setText('#view-social .section-header__title', t('pageMeta.social.title'));
|
|
2274
|
+
setText('#view-social .card .title-sm', t('labels.integrationStatus'), 0);
|
|
2275
|
+
document.querySelector('#socialStatusLine').textContent = t('hints.checkingIntegration');
|
|
2276
|
+
setText('#view-social .split .card .title-sm', t('labels.whatIsActive'), 0);
|
|
2277
|
+
setText('#view-social .split .card .title-sm', t('labels.identityBinding'), 1);
|
|
2278
|
+
setText('#view-social details.card summary', t('labels.advancedNetworkDetails'));
|
|
2279
|
+
setText('#view-social details.advanced-panel summary', t('labels.sourceRuntimeTemplate'));
|
|
2280
|
+
setText('#view-social .card .title-sm', t('labels.sourceParsedFrontmatter'), 3);
|
|
2281
|
+
setText('#view-social .card .title-sm', t('labels.runtimeSummary'), 4);
|
|
2282
|
+
setText('#view-social .card .title-sm', t('labels.exportTemplatePreview'), 5);
|
|
2283
|
+
setText('#view-social .card .title-sm', t('labels.actionsTitle'), 6);
|
|
2284
|
+
setText('label[for="socialModeSelect"]', t('labels.networkModeRuntime'));
|
|
2285
|
+
setText('#view-social > .card:last-of-type .field-hint', t('hints.profileVisibilityManaged'));
|
|
2286
|
+
setText('.hero-meta-item .label', t('labels.mode'), 0);
|
|
2287
|
+
setText('.hero-meta-item .label', t('labels.adapter'), 1);
|
|
2288
|
+
setText('.hero-meta-item .label', t('labels.relay'), 2);
|
|
2289
|
+
setText('.hero-meta-item .label', t('labels.room'), 3);
|
|
2290
|
+
document.getElementById('publicDiscoveryHint').innerHTML = t('hints.publicDiscoverySwitch');
|
|
2291
|
+
document.getElementById('overviewBroadcastNowBtn').textContent = t('actions.broadcastNow');
|
|
2292
|
+
document.getElementById('overviewGoProfileBtn').textContent = t('actions.editProfile');
|
|
2293
|
+
document.getElementById('overviewGoNetworkBtn').textContent = t('actions.openNetwork');
|
|
2294
|
+
document.getElementById('startBroadcastBtn').textContent = t('actions.startBroadcast');
|
|
2295
|
+
document.getElementById('stopBroadcastBtn').textContent = t('actions.stopBroadcast');
|
|
2296
|
+
document.getElementById('quickGlobalPreviewBtn').textContent = t('actions.enablePreview');
|
|
2297
|
+
document.getElementById('refreshLogsBtn').textContent = t('actions.refreshLogs');
|
|
2298
|
+
document.getElementById('socialExportBtn').textContent = t('actions.exportTemplate');
|
|
2299
|
+
document.getElementById('socialCopyBtn').textContent = t('actions.copyTemplate');
|
|
2300
|
+
document.getElementById('socialDownloadBtn').textContent = t('actions.downloadTemplate');
|
|
2301
|
+
document.getElementById('socialModeApplyBtn').textContent = t('actions.applyRuntimeMode');
|
|
2302
|
+
document.getElementById('copyPublicProfilePreviewBtn').textContent = t('actions.copyPublicProfilePreview');
|
|
2303
|
+
document.getElementById('saveProfileBtn').textContent = t('actions.saveProfile');
|
|
2304
|
+
document.getElementById('refreshProfileBtn').textContent = t('common.reload');
|
|
2305
|
+
document.getElementById('profileFeedback').textContent = t('common.ready');
|
|
2306
|
+
document.getElementById('networkFeedback').textContent = t('common.ready');
|
|
2307
|
+
document.getElementById('socialFeedback').textContent = t('common.ready');
|
|
2308
|
+
}
|
|
2309
|
+
setLocale(currentLocale);
|
|
2310
|
+
applyStaticTranslations();
|
|
2311
|
+
|
|
737
2312
|
let activeTab = 'overview';
|
|
738
2313
|
let profileBaseline = '';
|
|
739
2314
|
let profileDirty = false;
|
|
@@ -742,6 +2317,7 @@
|
|
|
742
2317
|
let logLevelFilter = 'all';
|
|
743
2318
|
let socialTemplate = '';
|
|
744
2319
|
let onlyShowOnline = false;
|
|
2320
|
+
const pageMeta = TRANSLATIONS[currentLocale].pageMeta || TRANSLATIONS[DEFAULT_LOCALE].pageMeta;
|
|
745
2321
|
|
|
746
2322
|
function ago(ts) {
|
|
747
2323
|
if (!ts) return '-';
|
|
@@ -767,6 +2343,12 @@
|
|
|
767
2343
|
t.classList.add('show');
|
|
768
2344
|
setTimeout(() => t.classList.remove('show'), 2000);
|
|
769
2345
|
}
|
|
2346
|
+
function resolveThemeMode(mode) {
|
|
2347
|
+
if (mode === 'system') {
|
|
2348
|
+
return window.matchMedia && window.matchMedia('(prefers-color-scheme: light)').matches ? 'light' : 'dark';
|
|
2349
|
+
}
|
|
2350
|
+
return mode === 'light' ? 'light' : 'dark';
|
|
2351
|
+
}
|
|
770
2352
|
function flashButton(btn, doneText = 'Done') {
|
|
771
2353
|
if (!btn) return;
|
|
772
2354
|
const oldText = btn.textContent || '';
|
|
@@ -783,11 +2365,16 @@
|
|
|
783
2365
|
el.style.color = level === 'error' ? '#ff6b81' : level === 'warn' ? '#ffb454' : '#9aa7c3';
|
|
784
2366
|
}
|
|
785
2367
|
function applyTheme(mode) {
|
|
786
|
-
const
|
|
2368
|
+
const raw = mode === 'system' ? 'system' : (mode === 'light' ? 'light' : 'dark');
|
|
2369
|
+
const next = resolveThemeMode(raw);
|
|
787
2370
|
document.documentElement.setAttribute('data-theme-mode', next);
|
|
788
|
-
localStorage.setItem('silicaclaw_theme_mode',
|
|
789
|
-
document.
|
|
790
|
-
|
|
2371
|
+
localStorage.setItem('silicaclaw_theme_mode', raw);
|
|
2372
|
+
document.querySelectorAll('[data-theme-choice]').forEach((btn) => {
|
|
2373
|
+
btn.classList.toggle('active', btn.dataset.themeChoice === raw);
|
|
2374
|
+
btn.classList.toggle('topbar-theme-mode__btn--active', btn.dataset.themeChoice === raw);
|
|
2375
|
+
btn.setAttribute('aria-checked', btn.dataset.themeChoice === raw ? 'true' : 'false');
|
|
2376
|
+
btn.setAttribute('aria-pressed', btn.dataset.themeChoice === raw ? 'true' : 'false');
|
|
2377
|
+
});
|
|
791
2378
|
}
|
|
792
2379
|
function parseTags(raw) {
|
|
793
2380
|
return String(raw || '')
|
|
@@ -822,7 +2409,7 @@
|
|
|
822
2409
|
if (fromUserInput && !profileSaving) {
|
|
823
2410
|
setFeedback(
|
|
824
2411
|
'profileFeedback',
|
|
825
|
-
profileDirty ? '
|
|
2412
|
+
profileDirty ? t('feedback.unsavedChanges') : t('feedback.allChangesSaved'),
|
|
826
2413
|
profileDirty ? 'warn' : 'info'
|
|
827
2414
|
);
|
|
828
2415
|
}
|
|
@@ -849,27 +2436,27 @@
|
|
|
849
2436
|
let ok = true;
|
|
850
2437
|
let err = '';
|
|
851
2438
|
if (displayName.length > 0 && displayName.length < 2) {
|
|
852
|
-
err = '
|
|
2439
|
+
err = t('validation.displayNameShort');
|
|
853
2440
|
ok = false;
|
|
854
2441
|
} else if (displayName.length > 48) {
|
|
855
|
-
err = '
|
|
2442
|
+
err = t('validation.displayNameLong');
|
|
856
2443
|
ok = false;
|
|
857
2444
|
}
|
|
858
2445
|
setInputError(displayNameEl, 'errDisplayName', err);
|
|
859
2446
|
|
|
860
2447
|
err = '';
|
|
861
2448
|
if (avatarUrl && !/^https?:\/\//i.test(avatarUrl)) {
|
|
862
|
-
err = '
|
|
2449
|
+
err = t('validation.avatarProtocol');
|
|
863
2450
|
ok = false;
|
|
864
2451
|
}
|
|
865
2452
|
setInputError(avatarEl, 'errAvatarUrl', err);
|
|
866
2453
|
|
|
867
2454
|
err = '';
|
|
868
2455
|
if (tags.length > 8) {
|
|
869
|
-
err = '
|
|
2456
|
+
err = t('validation.tooManyTags');
|
|
870
2457
|
ok = false;
|
|
871
2458
|
} else if (tags.some((t) => t.length > 20)) {
|
|
872
|
-
err = '
|
|
2459
|
+
err = t('validation.tagTooLong');
|
|
873
2460
|
ok = false;
|
|
874
2461
|
}
|
|
875
2462
|
setInputError(tagsEl, 'errTags', err);
|
|
@@ -881,14 +2468,14 @@
|
|
|
881
2468
|
const tags = parseTags(field(form, 'tags')?.value || '');
|
|
882
2469
|
const enabled = !!field(form, 'public_enabled')?.checked;
|
|
883
2470
|
|
|
884
|
-
document.getElementById('previewName').textContent = displayName || '
|
|
885
|
-
document.getElementById('previewBio').textContent = bio || '
|
|
2471
|
+
document.getElementById('previewName').textContent = displayName || t('preview.unnamedAgent');
|
|
2472
|
+
document.getElementById('previewBio').textContent = bio || t('preview.noBioYet');
|
|
886
2473
|
document.getElementById('previewPublish').textContent = `public_enabled: ${enabled}`;
|
|
887
2474
|
document.getElementById('bioCount').textContent = String(bio.length);
|
|
888
2475
|
|
|
889
2476
|
const tagBox = document.getElementById('previewTags');
|
|
890
2477
|
if (!tags.length) {
|
|
891
|
-
tagBox.innerHTML =
|
|
2478
|
+
tagBox.innerHTML = `<span class="tag-chip muted">${t('preview.noTags')}</span>`;
|
|
892
2479
|
return;
|
|
893
2480
|
}
|
|
894
2481
|
tagBox.innerHTML = tags.map((tag) => `<span class=\"tag-chip\">${tag}</span>`).join('');
|
|
@@ -898,30 +2485,34 @@
|
|
|
898
2485
|
const btn = document.getElementById('saveProfileBtn');
|
|
899
2486
|
btn.disabled = busy;
|
|
900
2487
|
btn.classList.toggle('save-busy', busy);
|
|
901
|
-
btn.textContent = busy ? '
|
|
2488
|
+
btn.textContent = busy ? t('common.saving') : t('actions.saveProfile');
|
|
902
2489
|
}
|
|
903
2490
|
|
|
904
2491
|
async function api(path, options = {}) {
|
|
905
2492
|
const res = await fetch(path, { headers: { 'Content-Type': 'application/json' }, ...options });
|
|
906
2493
|
const json = await res.json().catch(() => null);
|
|
907
2494
|
if (!res.ok || !json || !json.ok) {
|
|
908
|
-
throw new Error(json?.error?.message ||
|
|
2495
|
+
throw new Error(json?.error?.message || t('common.requestFailed', { status: String(res.status) }));
|
|
909
2496
|
}
|
|
910
2497
|
return json;
|
|
911
2498
|
}
|
|
912
2499
|
|
|
913
2500
|
function switchTab(tab) {
|
|
914
2501
|
if (activeTab === 'profile' && tab !== 'profile' && profileDirty && !profileSaving) {
|
|
915
|
-
const ok = window.confirm('
|
|
2502
|
+
const ok = window.confirm(t('validation.leaveConfirm'));
|
|
916
2503
|
if (!ok) {
|
|
917
2504
|
return;
|
|
918
2505
|
}
|
|
919
2506
|
}
|
|
920
2507
|
activeTab = tab;
|
|
921
2508
|
document.querySelectorAll('.tab').forEach((b) => b.classList.toggle('active', b.dataset.tab === tab));
|
|
922
|
-
['overview', 'profile', 'network', '
|
|
2509
|
+
['overview', 'profile', 'network', 'social'].forEach((k) => {
|
|
923
2510
|
document.getElementById(`view-${k}`).classList.toggle('active', k === tab);
|
|
924
2511
|
});
|
|
2512
|
+
const meta = pageMeta[tab] || pageMeta.overview;
|
|
2513
|
+
document.getElementById('pageBreadcrumb').textContent = meta.title;
|
|
2514
|
+
document.getElementById('pageHeroTitle').textContent = meta.title;
|
|
2515
|
+
document.getElementById('pageHeroBody').textContent = meta.body;
|
|
925
2516
|
if (tab === 'profile' && !profileDirty && !profileSaving) {
|
|
926
2517
|
refreshProfile().catch(() => {});
|
|
927
2518
|
}
|
|
@@ -934,67 +2525,62 @@
|
|
|
934
2525
|
const d = onlyShowOnline ? all.filter((agent) => agent.online) : all;
|
|
935
2526
|
|
|
936
2527
|
document.getElementById('overviewCards').innerHTML = [
|
|
937
|
-
['
|
|
938
|
-
['
|
|
939
|
-
['
|
|
940
|
-
['
|
|
2528
|
+
[t('overview.discovered'), o.discovered_count],
|
|
2529
|
+
[t('overview.online'), o.online_count],
|
|
2530
|
+
[t('overview.offline'), o.offline_count],
|
|
2531
|
+
[t('overview.presenceTtl'), `${Math.floor(o.presence_ttl_ms / 1000)}s`],
|
|
941
2532
|
].map(([k,v]) => `<div class="card"><div class="label">${k}</div><div class="value">${v}</div></div>`).join('');
|
|
942
2533
|
|
|
2534
|
+
document.getElementById('brandVersion').textContent = o.app_version ? `v${o.app_version}` : '-';
|
|
2535
|
+
|
|
943
2536
|
document.getElementById('snapshot').textContent = [
|
|
2537
|
+
`app_version: ${o.app_version || '-'}`,
|
|
944
2538
|
`agent_id: ${o.agent_id || '-'}`,
|
|
945
2539
|
`public_enabled: ${o.public_enabled}`,
|
|
946
2540
|
`broadcast_enabled: ${o.broadcast_enabled}`,
|
|
947
2541
|
`last_broadcast: ${ago(o.last_broadcast_at)}`,
|
|
948
2542
|
].join('\n');
|
|
2543
|
+
document.getElementById('heroMode').textContent = o.social?.network_mode || '-';
|
|
949
2544
|
|
|
950
|
-
document.getElementById('pillBroadcast').textContent = o.broadcast_enabled ? '
|
|
2545
|
+
document.getElementById('pillBroadcast').textContent = o.broadcast_enabled ? t('overview.pillRunning') : t('overview.pillPaused');
|
|
951
2546
|
document.getElementById('pillBroadcast').className = `pill ${o.broadcast_enabled ? 'ok' : 'warn'}`;
|
|
952
2547
|
|
|
953
2548
|
const init = o.init_state || {};
|
|
954
2549
|
const onboarding = o.onboarding || {};
|
|
955
2550
|
const notice = document.getElementById('initNotice');
|
|
956
|
-
const onboardingActions = document.getElementById('onboardingActions');
|
|
957
|
-
const enableBtn = document.getElementById('enablePublicDiscoveryBtn');
|
|
958
|
-
const disableBtn = document.getElementById('disablePublicDiscoveryBtn');
|
|
959
2551
|
const discoveryHint = document.getElementById('publicDiscoveryHint');
|
|
960
2552
|
const showOnboarding = onboarding.first_run || init.identity_auto_created || init.profile_auto_created || init.social_auto_created;
|
|
961
2553
|
if (onboarding.first_run || init.identity_auto_created || init.profile_auto_created || init.social_auto_created) {
|
|
962
2554
|
notice.classList.add('show');
|
|
963
|
-
notice.textContent =
|
|
2555
|
+
notice.textContent = t('overview.onboardingNotice', {
|
|
2556
|
+
mode: onboarding.mode || '-',
|
|
2557
|
+
discoverable: onboarding.discoverable ? t('common.yes') : t('common.no'),
|
|
2558
|
+
});
|
|
964
2559
|
} else {
|
|
965
2560
|
notice.classList.remove('show');
|
|
966
2561
|
}
|
|
967
2562
|
if (onboarding.can_enable_public_discovery || onboarding.public_enabled) {
|
|
968
|
-
onboardingActions.style.display = 'flex';
|
|
969
2563
|
discoveryHint.style.display = 'block';
|
|
970
|
-
if (onboarding.public_enabled) {
|
|
971
|
-
enableBtn.style.display = 'none';
|
|
972
|
-
disableBtn.style.display = 'inline-block';
|
|
973
|
-
} else {
|
|
974
|
-
enableBtn.style.display = 'inline-block';
|
|
975
|
-
disableBtn.style.display = 'none';
|
|
976
|
-
}
|
|
977
2564
|
} else {
|
|
978
|
-
onboardingActions.style.display = 'none';
|
|
979
2565
|
discoveryHint.style.display = 'none';
|
|
980
2566
|
}
|
|
981
2567
|
|
|
982
2568
|
if (!d.length) {
|
|
983
|
-
document.getElementById('agentsCountHint').textContent = '
|
|
984
|
-
document.getElementById('agentsWrap').innerHTML =
|
|
2569
|
+
document.getElementById('agentsCountHint').textContent = t('overview.agentsZero');
|
|
2570
|
+
document.getElementById('agentsWrap').innerHTML = `<div class="label">${t('overview.noDiscoveredAgents')}</div>`;
|
|
985
2571
|
} else {
|
|
986
2572
|
document.getElementById('agentsCountHint').textContent = onlyShowOnline
|
|
987
|
-
?
|
|
988
|
-
:
|
|
2573
|
+
? t('overview.agentsOnlineFilter', { shown: String(d.length), total: String(all.length) })
|
|
2574
|
+
: t('overview.agentsDiscovered', { count: String(d.length) });
|
|
989
2575
|
document.getElementById('agentsWrap').innerHTML = `
|
|
990
2576
|
<table class="table">
|
|
991
|
-
<thead><tr><th
|
|
2577
|
+
<thead><tr><th>${t('overview.tableName')}</th><th>${t('overview.tableAgentId')}</th><th>${t('overview.tableStatus')}</th><th>${t('overview.tableUpdated')}</th></tr></thead>
|
|
992
2578
|
<tbody>
|
|
993
2579
|
${d.map((a) => `
|
|
994
2580
|
<tr>
|
|
995
|
-
<td>${a.display_name || '
|
|
2581
|
+
<td>${a.display_name || t('overview.unnamed')}</td>
|
|
996
2582
|
<td class="mono">${shortId(a.agent_id)}</td>
|
|
997
|
-
<td class="${a.online ? 'online' : 'offline'}">${a.online ? 'online' : 'offline'}</td>
|
|
2583
|
+
<td class="${a.online ? 'online' : 'offline'}">${a.online ? t('overview.online') : t('overview.offline')}</td>
|
|
998
2584
|
<td>${ago(a.updated_at)}</td>
|
|
999
2585
|
</tr>
|
|
1000
2586
|
`).join('')}
|
|
@@ -1025,10 +2611,10 @@
|
|
|
1025
2611
|
const hiddenFields = summary?.public_visibility?.hidden_fields || [];
|
|
1026
2612
|
const visible = visibleFields.join(', ') || '-';
|
|
1027
2613
|
const hidden = hiddenFields.join(', ') || '-';
|
|
1028
|
-
document.getElementById('publicVisibilityHint').textContent =
|
|
2614
|
+
document.getElementById('publicVisibilityHint').textContent = t('preview.visibleFields', { visible, hidden });
|
|
1029
2615
|
const rows = [
|
|
1030
|
-
...visibleFields.map((field) =>
|
|
1031
|
-
...hiddenFields.map((field) =>
|
|
2616
|
+
...visibleFields.map((field) => t('preview.visible', { field })),
|
|
2617
|
+
...hiddenFields.map((field) => t('preview.hidden', { field })),
|
|
1032
2618
|
];
|
|
1033
2619
|
document.getElementById('publicVisibilityList').textContent = rows.length ? rows.join('\n') : '-';
|
|
1034
2620
|
}
|
|
@@ -1045,31 +2631,41 @@
|
|
|
1045
2631
|
const d = s.adapter_discovery_stats || {};
|
|
1046
2632
|
const dx = s.adapter_diagnostics_summary || {};
|
|
1047
2633
|
const ac = s.adapter_config || c.adapter_config || {};
|
|
2634
|
+
document.getElementById('heroAdapter').textContent = c.adapter || '-';
|
|
2635
|
+
document.getElementById('heroRelay').textContent = dx.signaling_url || '-';
|
|
2636
|
+
document.getElementById('heroRoom').textContent = dx.room || '-';
|
|
1048
2637
|
|
|
1049
2638
|
document.getElementById('pillAdapter').textContent = `adapter: ${c.adapter}`;
|
|
1050
|
-
document.getElementById('sideMeta').innerHTML = `adapter: ${c.adapter}<br/>namespace: ${c.namespace || '-'}<br/>port: ${c.port ?? '-'}`;
|
|
1051
|
-
|
|
1052
2639
|
document.getElementById('networkCards').innerHTML = [
|
|
1053
|
-
['
|
|
1054
|
-
['
|
|
1055
|
-
['
|
|
1056
|
-
['
|
|
1057
|
-
['
|
|
1058
|
-
['
|
|
1059
|
-
['
|
|
1060
|
-
['
|
|
1061
|
-
['
|
|
1062
|
-
['
|
|
1063
|
-
['
|
|
1064
|
-
['
|
|
1065
|
-
['
|
|
1066
|
-
['
|
|
1067
|
-
['
|
|
1068
|
-
['
|
|
1069
|
-
['
|
|
1070
|
-
['
|
|
1071
|
-
['
|
|
2640
|
+
[t('labels.adapter'), c.adapter],
|
|
2641
|
+
[t('labels.namespace'), c.namespace || '-'],
|
|
2642
|
+
[t('labels.port'), c.port ?? '-'],
|
|
2643
|
+
[t('network.started'), ac.started === true ? t('common.yes') : ac.started === false ? t('common.no') : '-'],
|
|
2644
|
+
[t('network.transportState'), ac.transport?.state || '-'],
|
|
2645
|
+
[t('network.signalingUrl'), dx.signaling_url || '-'],
|
|
2646
|
+
[t('network.signalingEndpoints'), (dx.signaling_endpoints || []).length || 0],
|
|
2647
|
+
[t('network.webrtcRoom'), dx.room || '-'],
|
|
2648
|
+
[t('network.bootstrapSources'), (dx.bootstrap_sources || []).length || 0],
|
|
2649
|
+
[t('network.seedPeers'), dx.seed_peers_count ?? 0],
|
|
2650
|
+
[t('network.discoveryEvents'), dx.discovery_events_total ?? 0],
|
|
2651
|
+
[t('network.recv'), msg.received_total ?? 0],
|
|
2652
|
+
[t('network.sent'), msg.broadcast_total ?? 0],
|
|
2653
|
+
[t('network.peers'), p.total ?? 0],
|
|
2654
|
+
[t('network.onlinePeers'), p.online ?? 0],
|
|
2655
|
+
[t('network.activeWebrtcPeers'), dx.active_webrtc_peers ?? '-'],
|
|
2656
|
+
[t('network.reconnectAttempts'), dx.reconnect_attempts_total ?? '-'],
|
|
2657
|
+
[t('network.lastInbound'), ago(msg.last_message_at)],
|
|
2658
|
+
[t('network.lastOutbound'), ago(msg.last_broadcast_at)],
|
|
1072
2659
|
].map(([k,v]) => `<div class="card"><div class="label">${k}</div><div class="value" style="font-size:17px;">${v}</div></div>`).join('');
|
|
2660
|
+
document.getElementById('networkSummaryList').innerHTML = [
|
|
2661
|
+
[t('network.relayHealth'), dx.last_error ? t('network.degraded') : t('network.connected')],
|
|
2662
|
+
[t('network.currentRelay'), dx.signaling_url || '-'],
|
|
2663
|
+
[t('network.currentRoom'), dx.room || '-'],
|
|
2664
|
+
[t('network.lastJoin'), ago(dx.last_join_at)],
|
|
2665
|
+
[t('network.lastPoll'), ago(dx.last_poll_at)],
|
|
2666
|
+
[t('network.lastPublish'), ago(dx.last_publish_at)],
|
|
2667
|
+
[t('network.lastError'), dx.last_error || t('network.none')],
|
|
2668
|
+
].map(([k, v]) => `<div class="summary-item"><div class="label">${k}</div><div class="mono">${v}</div></div>`).join('');
|
|
1073
2669
|
|
|
1074
2670
|
const comp = c.components || {};
|
|
1075
2671
|
const lim = c.limits || {};
|
|
@@ -1097,6 +2693,12 @@
|
|
|
1097
2693
|
`discovery_heartbeat_send_errors: ${d.heartbeat_send_errors ?? '-'}`,
|
|
1098
2694
|
`signaling_messages_sent_total: ${dx.signaling_messages_sent_total ?? '-'}`,
|
|
1099
2695
|
`signaling_messages_received_total: ${dx.signaling_messages_received_total ?? '-'}`,
|
|
2696
|
+
`last_join_at: ${dx.last_join_at ? new Date(dx.last_join_at).toISOString() : '-'}`,
|
|
2697
|
+
`last_poll_at: ${dx.last_poll_at ? new Date(dx.last_poll_at).toISOString() : '-'}`,
|
|
2698
|
+
`last_publish_at: ${dx.last_publish_at ? new Date(dx.last_publish_at).toISOString() : '-'}`,
|
|
2699
|
+
`last_peer_refresh_at: ${dx.last_peer_refresh_at ? new Date(dx.last_peer_refresh_at).toISOString() : '-'}`,
|
|
2700
|
+
`last_error_at: ${dx.last_error_at ? new Date(dx.last_error_at).toISOString() : '-'}`,
|
|
2701
|
+
`last_error: ${dx.last_error || '-'}`,
|
|
1100
2702
|
`signaling_endpoints: ${Array.isArray(dx.signaling_endpoints) ? dx.signaling_endpoints.join(', ') : '-'}`,
|
|
1101
2703
|
`bootstrap_sources: ${Array.isArray(dx.bootstrap_sources) ? dx.bootstrap_sources.join(', ') : '-'}`,
|
|
1102
2704
|
`seed_peers_count: ${dx.seed_peers_count ?? '-'}`,
|
|
@@ -1121,25 +2723,28 @@
|
|
|
1121
2723
|
const summary = peers.diagnostics_summary || {};
|
|
1122
2724
|
|
|
1123
2725
|
document.getElementById('peerCards').innerHTML = [
|
|
1124
|
-
['
|
|
1125
|
-
['
|
|
1126
|
-
['
|
|
1127
|
-
['
|
|
1128
|
-
['
|
|
1129
|
-
['
|
|
1130
|
-
['
|
|
1131
|
-
['
|
|
1132
|
-
['
|
|
1133
|
-
['
|
|
1134
|
-
['
|
|
1135
|
-
['
|
|
1136
|
-
['
|
|
1137
|
-
['
|
|
1138
|
-
['
|
|
2726
|
+
[t('network.total'), peers.total || 0],
|
|
2727
|
+
[t('overview.online'), peers.online || 0],
|
|
2728
|
+
[t('network.stale'), peers.stale || 0],
|
|
2729
|
+
[t('labels.namespace'), peers.namespace || '-'],
|
|
2730
|
+
[t('network.signalingUrl'), summary.signaling_url || '-'],
|
|
2731
|
+
[t('network.signalingEndpoints'), (summary.signaling_endpoints || []).length || 0],
|
|
2732
|
+
[t('labels.room'), summary.room || '-'],
|
|
2733
|
+
[t('network.lastJoin'), ago(summary.last_join_at)],
|
|
2734
|
+
[t('network.lastPoll'), ago(summary.last_poll_at)],
|
|
2735
|
+
[t('network.lastPublish'), ago(summary.last_publish_at)],
|
|
2736
|
+
[t('network.bootstrapSources'), (summary.bootstrap_sources || []).length || 0],
|
|
2737
|
+
[t('network.seedPeers'), summary.seed_peers_count ?? 0],
|
|
2738
|
+
[t('network.discoveryEvents'), summary.discovery_events_total ?? 0],
|
|
2739
|
+
[t('network.activeWebrtcPeers'), summary.active_webrtc_peers ?? '-'],
|
|
2740
|
+
[t('network.observeCalls'), ds.observe_calls || 0],
|
|
2741
|
+
[t('network.heartbeats'), ds.heartbeat_sent || 0],
|
|
2742
|
+
[t('network.peersAdded'), ds.peers_added || 0],
|
|
2743
|
+
[t('network.peersRemoved'), ds.peers_removed || 0],
|
|
1139
2744
|
].map(([k,v]) => `<div class="card"><div class="label">${k}</div><div class="value" style="font-size:17px;">${v}</div></div>`).join('');
|
|
1140
2745
|
|
|
1141
2746
|
if (!peers.items || !peers.items.length) {
|
|
1142
|
-
document.getElementById('peerTableWrap').innerHTML =
|
|
2747
|
+
document.getElementById('peerTableWrap').innerHTML = `<div class="empty-state">${t('network.noPeersDiscovered')}</div>`;
|
|
1143
2748
|
document.getElementById('peerStatsWrap').textContent = toPrettyJson({
|
|
1144
2749
|
discovery_stats: ds,
|
|
1145
2750
|
diagnostics_summary: summary,
|
|
@@ -1149,7 +2754,7 @@
|
|
|
1149
2754
|
|
|
1150
2755
|
document.getElementById('peerTableWrap').innerHTML = `
|
|
1151
2756
|
<table class="table">
|
|
1152
|
-
<thead><tr><th
|
|
2757
|
+
<thead><tr><th>${t('network.peer')}</th><th>${t('network.status')}</th><th>${t('network.lastSeen')}</th><th>${t('network.staleSince')}</th><th>${t('network.messages')}</th><th>${t('network.firstSeen')}</th><th>${t('network.meta')}</th></tr></thead>
|
|
1153
2758
|
<tbody>
|
|
1154
2759
|
${peers.items.map((peer) => `
|
|
1155
2760
|
<tr>
|
|
@@ -1178,16 +2783,16 @@
|
|
|
1178
2783
|
const items = Array.isArray(payload.items) ? payload.items : [];
|
|
1179
2784
|
|
|
1180
2785
|
document.getElementById('discoveryCards').innerHTML = [
|
|
1181
|
-
['
|
|
1182
|
-
['
|
|
1183
|
-
['
|
|
1184
|
-
['
|
|
1185
|
-
['
|
|
1186
|
-
['
|
|
2786
|
+
[t('labels.adapter'), payload.adapter || '-'],
|
|
2787
|
+
[t('labels.namespace'), payload.namespace || '-'],
|
|
2788
|
+
[t('network.eventsTotal'), payload.total ?? 0],
|
|
2789
|
+
[t('network.lastEvent'), ago(payload.last_event_at)],
|
|
2790
|
+
[t('network.signalingEndpoints'), (payload.signaling_endpoints || []).length || 0],
|
|
2791
|
+
[t('network.seedPeers'), payload.seed_peers_count ?? 0],
|
|
1187
2792
|
].map(([k,v]) => `<div class="card"><div class="label">${k}</div><div class="value" style="font-size:17px;">${v}</div></div>`).join('');
|
|
1188
2793
|
|
|
1189
2794
|
if (!items.length) {
|
|
1190
|
-
document.getElementById('discoveryEventList').innerHTML =
|
|
2795
|
+
document.getElementById('discoveryEventList').innerHTML = `<div class="empty-state">${t('network.noDiscoveryEvents')}</div>`;
|
|
1191
2796
|
} else {
|
|
1192
2797
|
document.getElementById('discoveryEventList').innerHTML = items
|
|
1193
2798
|
.slice()
|
|
@@ -1220,55 +2825,59 @@
|
|
|
1220
2825
|
const runtimeNetwork = runtime.resolved_network || {};
|
|
1221
2826
|
const discoverable = status.discoverable === true;
|
|
1222
2827
|
const mode = status.network_mode || summary.current_network_mode || network.mode || runtimeNetwork.mode || '-';
|
|
1223
|
-
const summaryLine = status.status_line || summary.summary_line || `${summary.connected ? '
|
|
1224
|
-
const publicDiscoveryText = status.public_enabled ? '
|
|
2828
|
+
const summaryLine = status.status_line || summary.summary_line || `${summary.connected ? t('social.connectedToSilicaClaw') : t('social.notConnectedToSilicaClaw')} · ${discoverable ? t('social.discoverableInCurrentMode') : t('social.notDiscoverableInCurrentMode')} · ${t('social.usingMode', { mode })}`;
|
|
2829
|
+
const publicDiscoveryText = status.public_enabled ? t('social.publicDiscoveryEnabled') : t('social.publicDiscoveryDisabled');
|
|
1225
2830
|
|
|
1226
|
-
const namespaceText = `${status.connected_to_silicaclaw ? '
|
|
2831
|
+
const namespaceText = `${status.connected_to_silicaclaw ? t('social.connectedToSilicaClaw') : t('social.notConnected')} · ${publicDiscoveryText} · ${t('social.mode')} ${mode}`;
|
|
1227
2832
|
document.getElementById('socialStatusLine').textContent = summaryLine;
|
|
1228
2833
|
document.getElementById('socialStatusSubline').textContent = namespaceText;
|
|
1229
2834
|
const bar = document.getElementById('integrationStatusBar');
|
|
1230
2835
|
bar.className = `integration-strip ${status.connected_to_silicaclaw && status.public_enabled ? 'ok' : 'warn'}`;
|
|
1231
|
-
bar.textContent =
|
|
2836
|
+
bar.textContent = t('social.barStatus', {
|
|
2837
|
+
connected: status.connected_to_silicaclaw ? t('common.yes') : t('common.no'),
|
|
2838
|
+
mode,
|
|
2839
|
+
public: status.public_enabled ? t('common.on') : t('common.off'),
|
|
2840
|
+
});
|
|
1232
2841
|
const reasons = [];
|
|
1233
|
-
if (!status.configured && status.configured_reason) reasons.push(
|
|
1234
|
-
if (!status.running && status.running_reason) reasons.push(
|
|
1235
|
-
if (!status.discoverable && status.discoverable_reason) reasons.push(
|
|
1236
|
-
document.getElementById('socialStateHint').textContent = reasons.length ? reasons.join(' · ') : '
|
|
2842
|
+
if (!status.configured && status.configured_reason) reasons.push(t('social.configuredReason', { reason: status.configured_reason }));
|
|
2843
|
+
if (!status.running && status.running_reason) reasons.push(t('social.runningReason', { reason: status.running_reason }));
|
|
2844
|
+
if (!status.discoverable && status.discoverable_reason) reasons.push(t('social.discoverableReasonFull', { reason: status.discoverable_reason }));
|
|
2845
|
+
document.getElementById('socialStateHint').textContent = reasons.length ? reasons.join(' · ') : t('hints.allIntegrationChecksPassed');
|
|
1237
2846
|
const modeSelect = document.getElementById('socialModeSelect');
|
|
1238
2847
|
if (modeSelect && mode !== '-') {
|
|
1239
2848
|
modeSelect.value = mode;
|
|
1240
2849
|
}
|
|
1241
2850
|
|
|
1242
2851
|
document.getElementById('socialPrimaryCards').innerHTML = [
|
|
1243
|
-
['
|
|
1244
|
-
['
|
|
1245
|
-
['
|
|
1246
|
-
['
|
|
1247
|
-
['
|
|
1248
|
-
['connected', status.connected_to_silicaclaw ? 'yes' : 'no'],
|
|
1249
|
-
['
|
|
2852
|
+
[t('social.configured'), status.configured ? t('common.yes') : t('common.no')],
|
|
2853
|
+
[t('social.running'), status.running ? t('common.yes') : t('common.no')],
|
|
2854
|
+
[t('social.discoverable'), discoverable ? t('common.yes') : t('common.no')],
|
|
2855
|
+
[t('social.publicDiscovery'), status.public_enabled ? t('common.on') : t('common.off')],
|
|
2856
|
+
[t('social.networkMode'), mode],
|
|
2857
|
+
[t('social.connected'), status.connected_to_silicaclaw ? t('common.yes') : t('common.no')],
|
|
2858
|
+
[t('social.discoverableReason'), status.discoverable_reason || '-'],
|
|
1250
2859
|
].map(([k,v]) => `<div class="card"><div class="label">${k}</div><div class="value" style="font-size:17px;">${v}</div></div>`).join('');
|
|
1251
2860
|
|
|
1252
2861
|
document.getElementById('socialIntegrationCards').innerHTML = [
|
|
1253
|
-
['
|
|
1254
|
-
['
|
|
1255
|
-
['social.
|
|
1256
|
-
['social.
|
|
1257
|
-
['
|
|
1258
|
-
['
|
|
1259
|
-
['mode', mode],
|
|
1260
|
-
['
|
|
2862
|
+
[t('social.displayName'), status.display_name || t('overview.unnamed')],
|
|
2863
|
+
[t('social.agentId'), shortId(status.agent_id || '')],
|
|
2864
|
+
[t('social.socialFound'), summary.social_md_found ? t('common.yes') : t('common.no')],
|
|
2865
|
+
[t('social.socialSource'), summary.social_md_source_path || '-'],
|
|
2866
|
+
[t('social.runtimeGenerated'), summary.runtime_generated ? t('common.yes') : t('common.no')],
|
|
2867
|
+
[t('social.reuseOpenClawIdentity'), summary.reused_openclaw_identity ? t('common.yes') : t('common.no')],
|
|
2868
|
+
[t('social.mode'), mode],
|
|
2869
|
+
[t('social.broadcastStatus'), summary.current_broadcast_status || '-'],
|
|
1261
2870
|
].map(([k,v]) => `<div class="card"><div class="label">${k}</div><div class="value" style="font-size:17px;">${v}</div></div>`).join('');
|
|
1262
2871
|
|
|
1263
2872
|
document.getElementById('socialAdvancedCards').innerHTML = [
|
|
1264
|
-
['adapter', runtimeNetwork.adapter || summary.current_adapter || '-'],
|
|
1265
|
-
['namespace', runtimeNetwork.namespace || summary.current_namespace || '-'],
|
|
1266
|
-
['room', runtimeNetwork.room || network.room || '-'],
|
|
1267
|
-
['
|
|
1268
|
-
['
|
|
1269
|
-
['
|
|
1270
|
-
['
|
|
1271
|
-
['
|
|
2873
|
+
[t('labels.adapter'), runtimeNetwork.adapter || summary.current_adapter || '-'],
|
|
2874
|
+
[t('social.namespace'), runtimeNetwork.namespace || summary.current_namespace || '-'],
|
|
2875
|
+
[t('labels.room'), runtimeNetwork.room || network.room || '-'],
|
|
2876
|
+
[t('network.signalingEndpoints'), (runtimeNetwork.signaling_urls || []).length || 0],
|
|
2877
|
+
[t('network.bootstrapSources'), (runtimeNetwork.bootstrap_sources || []).length || 0],
|
|
2878
|
+
[t('network.seedPeers'), (runtimeNetwork.seed_peers || []).length || 0],
|
|
2879
|
+
[t('social.bootstrapHints'), (runtimeNetwork.bootstrap_hints || []).length || 0],
|
|
2880
|
+
[t('social.restartRequired'), social.network_requires_restart ? t('common.yes') : t('common.no')],
|
|
1272
2881
|
].map(([k,v]) => `<div class="card"><div class="label">${k}</div><div class="value" style="font-size:17px;">${v}</div></div>`).join('');
|
|
1273
2882
|
document.getElementById('socialAdvancedWrap').textContent = toPrettyJson({
|
|
1274
2883
|
runtime_network: runtimeNetwork,
|
|
@@ -1295,14 +2904,14 @@
|
|
|
1295
2904
|
function renderLogs() {
|
|
1296
2905
|
const el = document.getElementById('logList');
|
|
1297
2906
|
if (!logsCache.length) {
|
|
1298
|
-
el.innerHTML =
|
|
2907
|
+
el.innerHTML = `<div class="empty-state">${t('network.noLogsYet')}</div>`;
|
|
1299
2908
|
return;
|
|
1300
2909
|
}
|
|
1301
2910
|
const filtered = logLevelFilter === 'all'
|
|
1302
2911
|
? logsCache
|
|
1303
2912
|
: logsCache.filter((l) => String(l.level || '').toLowerCase() === logLevelFilter);
|
|
1304
2913
|
if (!filtered.length) {
|
|
1305
|
-
el.innerHTML = `<div class="
|
|
2914
|
+
el.innerHTML = `<div class="empty-state">${t('network.noLogsForLevel', { level: logLevelFilter })}</div>`;
|
|
1306
2915
|
return;
|
|
1307
2916
|
}
|
|
1308
2917
|
el.innerHTML = filtered.map((l) => `
|
|
@@ -1320,34 +2929,81 @@
|
|
|
1320
2929
|
|
|
1321
2930
|
async function refreshAll() {
|
|
1322
2931
|
try {
|
|
1323
|
-
const tasks = [refreshOverview(), refreshNetwork(),
|
|
2932
|
+
const tasks = [refreshOverview(), refreshNetwork(), refreshSocial(), refreshPublicProfilePreview()];
|
|
2933
|
+
if (activeTab === 'network') {
|
|
2934
|
+
tasks.push(refreshPeers(), refreshDiscovery(), refreshLogs());
|
|
2935
|
+
}
|
|
1324
2936
|
const shouldRefreshProfile = !(activeTab === 'profile' && profileDirty);
|
|
1325
2937
|
if (shouldRefreshProfile) {
|
|
1326
2938
|
tasks.push(refreshProfile());
|
|
1327
2939
|
}
|
|
1328
2940
|
await Promise.all(tasks);
|
|
1329
2941
|
} catch (e) {
|
|
1330
|
-
setFeedback('networkFeedback', e instanceof Error ? e.message : '
|
|
2942
|
+
setFeedback('networkFeedback', e instanceof Error ? e.message : t('common.unknownError'), 'error');
|
|
1331
2943
|
}
|
|
1332
2944
|
}
|
|
1333
2945
|
|
|
1334
2946
|
document.querySelectorAll('.tab').forEach((btn) => {
|
|
1335
2947
|
btn.addEventListener('click', () => switchTab(btn.dataset.tab));
|
|
1336
2948
|
});
|
|
1337
|
-
document.getElementById('
|
|
1338
|
-
|
|
2949
|
+
document.getElementById('sidebarToggleBtn').addEventListener('click', () => {
|
|
2950
|
+
const shell = document.getElementById('appShell');
|
|
2951
|
+
const next = !shell.classList.contains('nav-collapsed');
|
|
2952
|
+
shell.classList.toggle('nav-collapsed', next);
|
|
2953
|
+
const btn = document.getElementById('sidebarToggleBtn');
|
|
2954
|
+
const icon = btn.querySelector('.nav-collapse-toggle__icon');
|
|
2955
|
+
btn.classList.toggle('active', next);
|
|
2956
|
+
btn.title = next ? t('labels.expandSidebar') : t('labels.collapseSidebar');
|
|
2957
|
+
btn.setAttribute('aria-label', btn.title);
|
|
2958
|
+
if (icon) {
|
|
2959
|
+
icon.innerHTML = next
|
|
2960
|
+
? `
|
|
2961
|
+
<svg viewBox="0 0 24 24">
|
|
2962
|
+
<rect x="3" y="3" width="18" height="18" rx="2"></rect>
|
|
2963
|
+
<path d="M9 3v18"></path>
|
|
2964
|
+
<path d="M14 10l3 2-3 2"></path>
|
|
2965
|
+
</svg>
|
|
2966
|
+
`
|
|
2967
|
+
: `
|
|
2968
|
+
<svg viewBox="0 0 24 24">
|
|
2969
|
+
<rect x="3" y="3" width="18" height="18" rx="2"></rect>
|
|
2970
|
+
<path d="M9 3v18"></path>
|
|
2971
|
+
<path d="M16 10l-3 2 3 2"></path>
|
|
2972
|
+
</svg>
|
|
2973
|
+
`;
|
|
2974
|
+
}
|
|
2975
|
+
});
|
|
2976
|
+
document.getElementById('focusModeBtn').addEventListener('click', () => {
|
|
2977
|
+
const shell = document.getElementById('appShell');
|
|
2978
|
+
const next = !shell.classList.contains('focus-mode');
|
|
2979
|
+
shell.classList.toggle('focus-mode', next);
|
|
2980
|
+
const btn = document.getElementById('focusModeBtn');
|
|
2981
|
+
btn.classList.toggle('active', next);
|
|
2982
|
+
btn.title = next ? t('labels.exitFocusMode') : t('labels.toggleFocusMode');
|
|
2983
|
+
btn.setAttribute('aria-label', btn.title);
|
|
2984
|
+
});
|
|
2985
|
+
document.querySelectorAll('[data-theme-choice]').forEach((btn) => {
|
|
2986
|
+
btn.addEventListener('click', () => {
|
|
2987
|
+
applyTheme(btn.dataset.themeChoice || 'dark');
|
|
2988
|
+
});
|
|
2989
|
+
});
|
|
2990
|
+
document.getElementById('overviewBroadcastNowBtn').addEventListener('click', () => {
|
|
2991
|
+
document.getElementById('broadcastNowBtn').click();
|
|
2992
|
+
});
|
|
2993
|
+
document.getElementById('overviewGoProfileBtn').addEventListener('click', () => switchTab('profile'));
|
|
2994
|
+
document.getElementById('overviewGoNetworkBtn').addEventListener('click', () => switchTab('network'));
|
|
1339
2995
|
|
|
1340
2996
|
document.getElementById('profileForm').addEventListener('submit', async (event) => {
|
|
1341
2997
|
event.preventDefault();
|
|
1342
2998
|
const f = event.currentTarget;
|
|
1343
2999
|
const result = validateProfileForm(f);
|
|
1344
3000
|
if (!result.ok) {
|
|
1345
|
-
setFeedback('profileFeedback', '
|
|
3001
|
+
setFeedback('profileFeedback', t('feedback.fixValidation'), 'warn');
|
|
1346
3002
|
return;
|
|
1347
3003
|
}
|
|
1348
3004
|
|
|
1349
3005
|
const tags = result.tags;
|
|
1350
|
-
setFeedback('profileFeedback', '
|
|
3006
|
+
setFeedback('profileFeedback', t('feedback.savingProfile'));
|
|
1351
3007
|
setSaveBusy(true);
|
|
1352
3008
|
try {
|
|
1353
3009
|
const r = await api('/api/profile', { method: 'PUT', body: JSON.stringify({
|
|
@@ -1357,12 +3013,12 @@
|
|
|
1357
3013
|
avatar_url: field(f, 'avatar_url').value,
|
|
1358
3014
|
public_enabled: !!field(f, 'public_enabled').checked,
|
|
1359
3015
|
})});
|
|
1360
|
-
setFeedback('profileFeedback', r.meta?.message || '
|
|
1361
|
-
toast('
|
|
3016
|
+
setFeedback('profileFeedback', r.meta?.message || t('common.saved'));
|
|
3017
|
+
toast(t('feedback.profileSaved'));
|
|
1362
3018
|
field(f, 'tags').value = normalizeTagsInput(field(f, 'tags').value);
|
|
1363
3019
|
await refreshAll();
|
|
1364
3020
|
} catch (e) {
|
|
1365
|
-
setFeedback('profileFeedback', e instanceof Error ? e.message : '
|
|
3021
|
+
setFeedback('profileFeedback', e instanceof Error ? e.message : t('feedback.failed'), 'error');
|
|
1366
3022
|
} finally {
|
|
1367
3023
|
setSaveBusy(false);
|
|
1368
3024
|
}
|
|
@@ -1370,7 +3026,7 @@
|
|
|
1370
3026
|
|
|
1371
3027
|
document.getElementById('refreshProfileBtn').addEventListener('click', async () => {
|
|
1372
3028
|
await refreshProfile();
|
|
1373
|
-
toast('
|
|
3029
|
+
toast(t('feedback.profileReloaded'));
|
|
1374
3030
|
});
|
|
1375
3031
|
const profileFormEl = document.getElementById('profileForm');
|
|
1376
3032
|
['input', 'change'].forEach((evt) => {
|
|
@@ -1405,27 +3061,21 @@
|
|
|
1405
3061
|
setFeedback('networkFeedback', text);
|
|
1406
3062
|
try {
|
|
1407
3063
|
const r = await api(path, { method: 'POST' });
|
|
1408
|
-
setFeedback('networkFeedback', r.meta?.message || '
|
|
1409
|
-
toast(r.meta?.message || '
|
|
3064
|
+
setFeedback('networkFeedback', r.meta?.message || t('common.done'), level);
|
|
3065
|
+
toast(r.meta?.message || t('common.done'));
|
|
1410
3066
|
await refreshAll();
|
|
1411
3067
|
} catch (e) {
|
|
1412
|
-
setFeedback('networkFeedback', e instanceof Error ? e.message : '
|
|
3068
|
+
setFeedback('networkFeedback', e instanceof Error ? e.message : t('feedback.failed'), 'error');
|
|
1413
3069
|
}
|
|
1414
3070
|
}
|
|
1415
|
-
document.getElementById('startBroadcastBtn').addEventListener('click', () => runAction('/api/broadcast/start', '
|
|
1416
|
-
document.getElementById('stopBroadcastBtn').addEventListener('click', () => runAction('/api/broadcast/stop', '
|
|
1417
|
-
document.getElementById('broadcastNowBtn').addEventListener('click', () => runAction('/api/broadcast/now', '
|
|
1418
|
-
document.getElementById('refreshCacheBtn').addEventListener('click', () => runAction('/api/cache/refresh', 'Refreshing cache...'));
|
|
1419
|
-
document.getElementById('clearCacheBtn').addEventListener('click', async () => {
|
|
1420
|
-
const ok = window.confirm('Clear discovered cache now?\n\nThis removes discovered peer profiles/presence/index references and keeps your self profile.');
|
|
1421
|
-
if (!ok) return;
|
|
1422
|
-
await runAction('/api/cache/clear', 'Clearing discovered cache...', 'warn');
|
|
1423
|
-
});
|
|
3071
|
+
document.getElementById('startBroadcastBtn').addEventListener('click', () => runAction('/api/broadcast/start', t('actions.startBroadcast')));
|
|
3072
|
+
document.getElementById('stopBroadcastBtn').addEventListener('click', () => runAction('/api/broadcast/stop', t('actions.stopBroadcast'), 'warn'));
|
|
3073
|
+
document.getElementById('broadcastNowBtn').addEventListener('click', () => runAction('/api/broadcast/now', t('actions.broadcastNow')));
|
|
1424
3074
|
document.getElementById('quickGlobalPreviewBtn').addEventListener('click', async () => {
|
|
1425
|
-
const currentSignaling = window.prompt('
|
|
3075
|
+
const currentSignaling = window.prompt(t('feedback.promptSignalingUrl'), 'http://localhost:4510');
|
|
1426
3076
|
if (!currentSignaling) return;
|
|
1427
|
-
const room = window.prompt('
|
|
1428
|
-
setFeedback('networkFeedback', '
|
|
3077
|
+
const room = window.prompt(t('feedback.promptRoom'), 'silicaclaw-global-preview') || 'silicaclaw-global-preview';
|
|
3078
|
+
setFeedback('networkFeedback', t('feedback.crossPreviewEnabling'));
|
|
1429
3079
|
try {
|
|
1430
3080
|
const result = await api('/api/network/quick-connect-global-preview', {
|
|
1431
3081
|
method: 'POST',
|
|
@@ -1434,11 +3084,11 @@
|
|
|
1434
3084
|
room: room.trim(),
|
|
1435
3085
|
}),
|
|
1436
3086
|
});
|
|
1437
|
-
setFeedback('networkFeedback', result.meta?.message || '
|
|
1438
|
-
toast('
|
|
3087
|
+
setFeedback('networkFeedback', result.meta?.message || t('feedback.crossPreviewEnabled'));
|
|
3088
|
+
toast(t('feedback.crossPreviewEnabled'));
|
|
1439
3089
|
await refreshAll();
|
|
1440
3090
|
} catch (e) {
|
|
1441
|
-
setFeedback('networkFeedback', e instanceof Error ? e.message : '
|
|
3091
|
+
setFeedback('networkFeedback', e instanceof Error ? e.message : t('feedback.enableCrossPreviewFailed'), 'error');
|
|
1442
3092
|
}
|
|
1443
3093
|
});
|
|
1444
3094
|
document.getElementById('onlyOnlineToggle').addEventListener('change', async (event) => {
|
|
@@ -1447,104 +3097,50 @@
|
|
|
1447
3097
|
});
|
|
1448
3098
|
document.getElementById('refreshLogsBtn').addEventListener('click', async () => {
|
|
1449
3099
|
await refreshLogs();
|
|
1450
|
-
toast('
|
|
1451
|
-
});
|
|
1452
|
-
document.getElementById('enablePublicDiscoveryBtn').addEventListener('click', async () => {
|
|
1453
|
-
const ok = window.confirm(
|
|
1454
|
-
'Enable public discovery now?\n\n' +
|
|
1455
|
-
'- Only profile/presence are shared.\n' +
|
|
1456
|
-
'- Private files are not shared.\n' +
|
|
1457
|
-
'- Chat and remote control are not enabled.\n\n' +
|
|
1458
|
-
'This updates runtime state and does not overwrite social.md.'
|
|
1459
|
-
);
|
|
1460
|
-
if (!ok) return;
|
|
1461
|
-
setFeedback('networkFeedback', 'Enabling public discovery...');
|
|
1462
|
-
try {
|
|
1463
|
-
const res = await api('/api/public-discovery/enable', { method: 'POST' });
|
|
1464
|
-
setFeedback('networkFeedback', res.meta?.message || 'Public discovery enabled.');
|
|
1465
|
-
toast('Public discovery enabled');
|
|
1466
|
-
await refreshAll();
|
|
1467
|
-
} catch (e) {
|
|
1468
|
-
setFeedback('networkFeedback', e instanceof Error ? e.message : 'Enable public discovery failed', 'error');
|
|
1469
|
-
}
|
|
1470
|
-
});
|
|
1471
|
-
document.getElementById('disablePublicDiscoveryBtn').addEventListener('click', async () => {
|
|
1472
|
-
const ok = window.confirm('Disable public discovery now? This updates runtime state and does not overwrite social.md.');
|
|
1473
|
-
if (!ok) return;
|
|
1474
|
-
setFeedback('networkFeedback', 'Disabling public discovery...');
|
|
1475
|
-
try {
|
|
1476
|
-
const res = await api('/api/public-discovery/disable', { method: 'POST' });
|
|
1477
|
-
setFeedback('networkFeedback', res.meta?.message || 'Public discovery disabled.');
|
|
1478
|
-
toast('Public discovery disabled');
|
|
1479
|
-
await refreshAll();
|
|
1480
|
-
} catch (e) {
|
|
1481
|
-
setFeedback('networkFeedback', e instanceof Error ? e.message : 'Disable public discovery failed', 'error');
|
|
1482
|
-
}
|
|
1483
|
-
});
|
|
1484
|
-
document.getElementById('socialReloadBtn').addEventListener('click', async () => {
|
|
1485
|
-
setFeedback('socialFeedback', 'Reloading social config...');
|
|
1486
|
-
try {
|
|
1487
|
-
const res = await api('/api/social/reload', { method: 'POST' });
|
|
1488
|
-
setFeedback('socialFeedback', res.meta?.message || 'Reloaded');
|
|
1489
|
-
toast('Social config reloaded');
|
|
1490
|
-
await refreshAll();
|
|
1491
|
-
} catch (e) {
|
|
1492
|
-
setFeedback('socialFeedback', e instanceof Error ? e.message : 'Reload failed', 'error');
|
|
1493
|
-
}
|
|
1494
|
-
});
|
|
1495
|
-
document.getElementById('socialGenerateBtn').addEventListener('click', async () => {
|
|
1496
|
-
setFeedback('socialFeedback', 'Generating default social.md...');
|
|
1497
|
-
try {
|
|
1498
|
-
const res = await api('/api/social/generate-default', { method: 'POST' });
|
|
1499
|
-
setFeedback('socialFeedback', res.meta?.message || 'Done');
|
|
1500
|
-
toast(res.meta?.message || 'Default social.md ready');
|
|
1501
|
-
await refreshAll();
|
|
1502
|
-
} catch (e) {
|
|
1503
|
-
setFeedback('socialFeedback', e instanceof Error ? e.message : 'Generate failed', 'error');
|
|
1504
|
-
}
|
|
3100
|
+
toast(t('feedback.logsRefreshed'));
|
|
1505
3101
|
});
|
|
1506
3102
|
document.getElementById('socialExportBtn').addEventListener('click', async () => {
|
|
1507
|
-
setFeedback('socialFeedback', '
|
|
3103
|
+
setFeedback('socialFeedback', t('feedback.exportingTemplate'));
|
|
1508
3104
|
try {
|
|
1509
3105
|
await exportSocialTemplate();
|
|
1510
|
-
setFeedback('socialFeedback', '
|
|
1511
|
-
toast('
|
|
3106
|
+
setFeedback('socialFeedback', t('feedback.templateExported'));
|
|
3107
|
+
toast(t('feedback.templateExported'));
|
|
1512
3108
|
} catch (e) {
|
|
1513
|
-
setFeedback('socialFeedback', e instanceof Error ? e.message : '
|
|
3109
|
+
setFeedback('socialFeedback', e instanceof Error ? e.message : t('feedback.exportFailed'), 'error');
|
|
1514
3110
|
}
|
|
1515
3111
|
});
|
|
1516
3112
|
document.getElementById('socialModeApplyBtn').addEventListener('click', async () => {
|
|
1517
3113
|
const mode = document.getElementById('socialModeSelect').value;
|
|
1518
|
-
setFeedback('socialFeedback',
|
|
3114
|
+
setFeedback('socialFeedback', t('feedback.runtimeModeApplying', { mode }));
|
|
1519
3115
|
try {
|
|
1520
3116
|
const res = await api('/api/social/runtime-mode', {
|
|
1521
3117
|
method: 'POST',
|
|
1522
3118
|
body: JSON.stringify({ mode }),
|
|
1523
3119
|
});
|
|
1524
|
-
setFeedback('socialFeedback', res.meta?.message || '
|
|
1525
|
-
toast(
|
|
3120
|
+
setFeedback('socialFeedback', res.meta?.message || t('feedback.runtimeUpdated'));
|
|
3121
|
+
toast(t('feedback.runtimeMode', { mode }));
|
|
1526
3122
|
await refreshAll();
|
|
1527
3123
|
} catch (e) {
|
|
1528
|
-
setFeedback('socialFeedback', e instanceof Error ? e.message : '
|
|
3124
|
+
setFeedback('socialFeedback', e instanceof Error ? e.message : t('feedback.failed'), 'error');
|
|
1529
3125
|
}
|
|
1530
3126
|
});
|
|
1531
3127
|
document.getElementById('socialCopyBtn').addEventListener('click', async () => {
|
|
1532
|
-
setFeedback('socialFeedback', '
|
|
3128
|
+
setFeedback('socialFeedback', t('feedback.copyingTemplate'));
|
|
1533
3129
|
const btn = document.getElementById('socialCopyBtn');
|
|
1534
3130
|
try {
|
|
1535
3131
|
if (!socialTemplate) {
|
|
1536
3132
|
await exportSocialTemplate();
|
|
1537
3133
|
}
|
|
1538
3134
|
await navigator.clipboard.writeText(socialTemplate);
|
|
1539
|
-
setFeedback('socialFeedback', '
|
|
1540
|
-
toast('
|
|
1541
|
-
flashButton(btn, '
|
|
3135
|
+
setFeedback('socialFeedback', t('feedback.templateCopied'));
|
|
3136
|
+
toast(t('common.copied'));
|
|
3137
|
+
flashButton(btn, t('common.copied'));
|
|
1542
3138
|
} catch (e) {
|
|
1543
|
-
setFeedback('socialFeedback', e instanceof Error ? e.message : '
|
|
3139
|
+
setFeedback('socialFeedback', e instanceof Error ? e.message : t('feedback.copyFailed'), 'error');
|
|
1544
3140
|
}
|
|
1545
3141
|
});
|
|
1546
3142
|
document.getElementById('socialDownloadBtn').addEventListener('click', async () => {
|
|
1547
|
-
setFeedback('socialFeedback', '
|
|
3143
|
+
setFeedback('socialFeedback', t('feedback.preparingDownload'));
|
|
1548
3144
|
try {
|
|
1549
3145
|
const payload = await exportSocialTemplate();
|
|
1550
3146
|
const filename = String(payload.filename || 'social.md');
|
|
@@ -1557,10 +3153,10 @@
|
|
|
1557
3153
|
anchor.click();
|
|
1558
3154
|
anchor.remove();
|
|
1559
3155
|
URL.revokeObjectURL(url);
|
|
1560
|
-
setFeedback('socialFeedback',
|
|
1561
|
-
toast('
|
|
3156
|
+
setFeedback('socialFeedback', t('feedback.downloaded', { filename }));
|
|
3157
|
+
toast(t('feedback.downloaded', { filename }));
|
|
1562
3158
|
} catch (e) {
|
|
1563
|
-
setFeedback('socialFeedback', e instanceof Error ? e.message : '
|
|
3159
|
+
setFeedback('socialFeedback', e instanceof Error ? e.message : t('feedback.downloadFailed'), 'error');
|
|
1564
3160
|
}
|
|
1565
3161
|
});
|
|
1566
3162
|
document.getElementById('copyPublicProfilePreviewBtn').addEventListener('click', async () => {
|
|
@@ -1568,10 +3164,10 @@
|
|
|
1568
3164
|
try {
|
|
1569
3165
|
const summary = (await api('/api/public-profile/preview')).data || null;
|
|
1570
3166
|
await navigator.clipboard.writeText(toPrettyJson(summary));
|
|
1571
|
-
toast('
|
|
1572
|
-
flashButton(btn, '
|
|
3167
|
+
toast(t('actions.copyPublicProfilePreview'));
|
|
3168
|
+
flashButton(btn, t('common.copied'));
|
|
1573
3169
|
} catch (e) {
|
|
1574
|
-
setFeedback('profileFeedback', e instanceof Error ? e.message : '
|
|
3170
|
+
setFeedback('profileFeedback', e instanceof Error ? e.message : t('feedback.copyPreviewFailed'), 'error');
|
|
1575
3171
|
}
|
|
1576
3172
|
});
|
|
1577
3173
|
document.getElementById('logLevelFilter').addEventListener('change', (event) => {
|
|
@@ -1593,6 +3189,20 @@
|
|
|
1593
3189
|
});
|
|
1594
3190
|
})();
|
|
1595
3191
|
|
|
3192
|
+
if (window.matchMedia) {
|
|
3193
|
+
const media = window.matchMedia('(prefers-color-scheme: light)');
|
|
3194
|
+
const handleThemeMedia = () => {
|
|
3195
|
+
if ((localStorage.getItem('silicaclaw_theme_mode') || 'dark') === 'system') {
|
|
3196
|
+
applyTheme('system');
|
|
3197
|
+
}
|
|
3198
|
+
};
|
|
3199
|
+
if (typeof media.addEventListener === 'function') {
|
|
3200
|
+
media.addEventListener('change', handleThemeMedia);
|
|
3201
|
+
} else if (typeof media.addListener === 'function') {
|
|
3202
|
+
media.addListener(handleThemeMedia);
|
|
3203
|
+
}
|
|
3204
|
+
}
|
|
3205
|
+
|
|
1596
3206
|
applyTheme(localStorage.getItem('silicaclaw_theme_mode') || 'dark');
|
|
1597
3207
|
refreshAll();
|
|
1598
3208
|
exportSocialTemplate().catch(() => {});
|