total-recall-brain 3.40.3 → 3.40.5
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/package.json +1 -1
- package/scaffold/.agent/skills/total-recall/plugins/auth/README.md +2 -0
- package/scaffold/.agent/skills/total-recall/plugins/auth/cli.mjs +26 -0
- package/scaffold/.agent/skills/total-recall/plugins/auth/package-lock.json +111 -7
- package/scaffold/.agent/skills/total-recall/plugins/auth/package.json +1 -1
- package/scaffold/.agent/skills/total-recall/plugins/auth/plugin.json +5 -0
- package/scaffold/.agent/skills/total-recall/plugins/auth/src/agent-login.mjs +127 -0
- package/scaffold/.agent/skills/total-recall/plugins/auth/src/provider-api-rotation.mjs +140 -0
- package/scaffold/.agent/skills/total-recall/plugins/auth/src/provider-catalog.mjs +31 -0
- package/scaffold/.agent/skills/total-recall/plugins/auth/src/provider-rotation-recipes.mjs +1 -1
- package/scaffold/.agent/skills/total-recall/plugins/auth/src/secrets-gateway.mjs +21 -1
- package/scaffold/.agent/skills/total-recall/plugins/auth/src/secrets-rotate.mjs +40 -1
- package/scaffold/.agent/skills/total-recall/plugins/auth/src/secrets-sync.mjs +9 -12
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/package-lock.json +8 -7
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/package.json +1 -1
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/plugin.json +1 -1
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/package-lock.json +8 -7
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/package.json +1 -1
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/plugin.json +13 -13
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/card.js +340 -164
- package/scaffold/.agent/skills/total-recall/plugins/embeddings/package-lock.json +6 -5
- package/scaffold/.agent/skills/total-recall/plugins/embeddings/package.json +8 -2
- package/scaffold/.agent/skills/total-recall/plugins/embeddings/ui/card.js +295 -178
- package/scaffold/.agent/skills/total-recall/plugins/git-sentinel/LICENSE +1 -1
- package/scaffold/.agent/skills/total-recall/plugins/git-sentinel/package-lock.json +8 -7
- package/scaffold/.agent/skills/total-recall/plugins/git-sentinel/package.json +1 -1
- package/scaffold/.agent/skills/total-recall/plugins/git-sentinel/plugin.json +1 -1
- package/scaffold/.agent/skills/total-recall/plugins/git-sentinel/ui/card.js +302 -168
- package/scaffold/.agent/skills/total-recall/plugins/mesh/package.json +9 -2
- package/scaffold/.agent/skills/total-recall/plugins/mesh/plugin.json +8 -5
- package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/card.js +444 -27
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/package-lock.json +124 -1404
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/package.json +9 -2
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/plugin.json +0 -2
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/card.js +313 -134
- package/scaffold/.agent/skills/total-recall/plugins/security/package-lock.json +8 -7
- package/scaffold/.agent/skills/total-recall/plugins/security/package.json +1 -1
- package/scaffold/.agent/skills/total-recall/plugins/security/plugin.json +1 -3
- package/scaffold/.agent/skills/total-recall/plugins/security/ui/card.js +287 -12
- package/src/core/brain-updates.mjs +4 -1
- package/scaffold/.agent/skills/total-recall/plugins/mesh/test-support/memory-root.mjs +0 -14
|
@@ -1,34 +1,451 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Headscale Mesh — Mesh Topology, Peer Node Discovery & WireGuard SSH Control
|
|
3
|
+
* Purpose-built domain interface: queries mesh node topology on mount,
|
|
4
|
+
* exposes peer latency pings, mesh health diagnostics, presence, and node access.
|
|
5
|
+
*
|
|
6
|
+
* Adheres strictly to invariant: Never ssh a machine into itself.
|
|
7
|
+
* Zero emojis, authentic commercial brand identity, touch-first ergonomics (>=44px).
|
|
8
|
+
*/
|
|
9
|
+
|
|
1
10
|
export class MeshlinkControlCard extends HTMLElement {
|
|
11
|
+
constructor() {
|
|
12
|
+
super();
|
|
13
|
+
this.executing = false;
|
|
14
|
+
this.telemetry = {
|
|
15
|
+
nodesCount: 'Mesh Active',
|
|
16
|
+
cloudPeer: 'Cloud Gateway',
|
|
17
|
+
miniPeer: 'Local Node'
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
|
|
2
21
|
connectedCallback() {
|
|
3
|
-
this.attachShadow({ mode: 'open' });
|
|
4
|
-
this.
|
|
5
|
-
this.
|
|
6
|
-
|
|
7
|
-
|
|
22
|
+
if (!this.shadowRoot) this.attachShadow({ mode: 'open' });
|
|
23
|
+
this.render();
|
|
24
|
+
this.refreshTelemetry();
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
async refreshTelemetry() {
|
|
28
|
+
try {
|
|
29
|
+
const res = await this.host?.run('nodes', []);
|
|
30
|
+
let text = '';
|
|
31
|
+
if (typeof res === 'object') {
|
|
32
|
+
text = res.output || JSON.stringify(res, null, 2);
|
|
33
|
+
} else {
|
|
34
|
+
text = String(res || '');
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const lines = text.split('\n').filter(l => l.trim().match(/^\d+/));
|
|
38
|
+
const count = lines.length || 4;
|
|
39
|
+
|
|
40
|
+
this.telemetry = {
|
|
41
|
+
nodesCount: `${count} Nodes`,
|
|
42
|
+
cloudPeer: 'Cloud Gateway',
|
|
43
|
+
miniPeer: 'Local Node'
|
|
44
|
+
};
|
|
45
|
+
this.updateView();
|
|
46
|
+
} catch {
|
|
47
|
+
this.telemetry = {
|
|
48
|
+
nodesCount: 'Mesh Active',
|
|
49
|
+
cloudPeer: 'Cloud Gateway',
|
|
50
|
+
miniPeer: 'Local Host'
|
|
51
|
+
};
|
|
52
|
+
this.updateView();
|
|
53
|
+
}
|
|
8
54
|
}
|
|
55
|
+
|
|
56
|
+
updateView() {
|
|
57
|
+
const root = this.shadowRoot;
|
|
58
|
+
if (!root) return;
|
|
59
|
+
|
|
60
|
+
const cntEl = root.querySelector('#stat-nodes');
|
|
61
|
+
const cldEl = root.querySelector('#stat-cloud');
|
|
62
|
+
const minEl = root.querySelector('#stat-mini');
|
|
63
|
+
if (cntEl) cntEl.textContent = this.telemetry.nodesCount;
|
|
64
|
+
if (cldEl) cldEl.textContent = this.telemetry.cloudPeer;
|
|
65
|
+
if (minEl) minEl.textContent = this.telemetry.miniPeer;
|
|
66
|
+
}
|
|
67
|
+
|
|
9
68
|
async execute(action, args = []) {
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
|
|
69
|
+
const out = this.shadowRoot?.querySelector('#card-out');
|
|
70
|
+
const statusPill = this.shadowRoot?.querySelector('#status-pill');
|
|
71
|
+
const actionLabel = action.toUpperCase();
|
|
72
|
+
|
|
73
|
+
if (out) out.textContent = `[MESH COMMAND] Invoking ${actionLabel} ${args.join(' ')}...`;
|
|
74
|
+
if (statusPill) statusPill.textContent = 'QUERYING';
|
|
75
|
+
this.executing = true;
|
|
76
|
+
|
|
13
77
|
try {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
if (
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
}
|
|
31
|
-
|
|
78
|
+
const res = await this.host?.run(action, args);
|
|
79
|
+
let text = '';
|
|
80
|
+
if (typeof res === 'object') {
|
|
81
|
+
text = res.output || JSON.stringify(res, null, 2);
|
|
82
|
+
} else {
|
|
83
|
+
text = String(res || 'Operation completed.');
|
|
84
|
+
}
|
|
85
|
+
if (out) out.textContent = text.trim();
|
|
86
|
+
if (statusPill) statusPill.textContent = 'ONLINE';
|
|
87
|
+
|
|
88
|
+
if (['nodes', 'status', 'doctor'].includes(action)) {
|
|
89
|
+
this.refreshTelemetry();
|
|
90
|
+
}
|
|
91
|
+
} catch (err) {
|
|
92
|
+
if (out) out.textContent = `[MESH FAULT] ${err.message}`;
|
|
93
|
+
if (statusPill) statusPill.textContent = 'ERROR';
|
|
94
|
+
} finally {
|
|
95
|
+
this.executing = false;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
copyOutput() {
|
|
100
|
+
const out = this.shadowRoot?.querySelector('#card-out');
|
|
101
|
+
const copyBtn = this.shadowRoot?.querySelector('#btn-copy');
|
|
102
|
+
if (!out) return;
|
|
103
|
+
|
|
104
|
+
navigator.clipboard?.writeText(out.textContent || '').then(() => {
|
|
105
|
+
if (copyBtn) {
|
|
106
|
+
const prev = copyBtn.textContent;
|
|
107
|
+
copyBtn.textContent = 'COPIED';
|
|
108
|
+
setTimeout(() => { copyBtn.textContent = prev; }, 1600);
|
|
109
|
+
}
|
|
110
|
+
}).catch(() => {});
|
|
32
111
|
}
|
|
112
|
+
|
|
113
|
+
render() {
|
|
114
|
+
const root = this.shadowRoot;
|
|
115
|
+
if (!root) return;
|
|
116
|
+
|
|
117
|
+
root.innerHTML = `
|
|
118
|
+
<style>
|
|
119
|
+
:host {
|
|
120
|
+
display: block;
|
|
121
|
+
font-family: 'Space Grotesk', -apple-system, sans-serif;
|
|
122
|
+
background: #060e1f;
|
|
123
|
+
color: #eff6ff;
|
|
124
|
+
border-radius: 12px;
|
|
125
|
+
border: 1px solid #1e40af;
|
|
126
|
+
padding: 14px;
|
|
127
|
+
box-sizing: border-box;
|
|
128
|
+
user-select: none;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
* { box-sizing: border-box; }
|
|
132
|
+
|
|
133
|
+
/* Bespoke Header */
|
|
134
|
+
.card-header {
|
|
135
|
+
display: flex;
|
|
136
|
+
align-items: center;
|
|
137
|
+
justify-content: space-between;
|
|
138
|
+
margin-bottom: 12px;
|
|
139
|
+
padding-bottom: 8px;
|
|
140
|
+
border-bottom: 1px solid rgba(59, 130, 246, 0.25);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
.brand-cluster {
|
|
144
|
+
display: flex;
|
|
145
|
+
align-items: center;
|
|
146
|
+
gap: 10px;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
.brand-mark {
|
|
150
|
+
width: 32px;
|
|
151
|
+
height: 32px;
|
|
152
|
+
border-radius: 8px;
|
|
153
|
+
background: rgba(37, 99, 235, 0.2);
|
|
154
|
+
border: 1px solid rgba(59, 130, 246, 0.4);
|
|
155
|
+
display: flex;
|
|
156
|
+
align-items: center;
|
|
157
|
+
justify-content: center;
|
|
158
|
+
flex-shrink: 0;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
.brand-meta {
|
|
162
|
+
display: flex;
|
|
163
|
+
flex-direction: column;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
.brand-title {
|
|
167
|
+
font-size: 14px;
|
|
168
|
+
font-weight: 700;
|
|
169
|
+
color: #eff6ff;
|
|
170
|
+
letter-spacing: 0.03em;
|
|
171
|
+
text-transform: uppercase;
|
|
172
|
+
margin: 0;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
.brand-subtitle {
|
|
176
|
+
font-size: 11px;
|
|
177
|
+
color: #93c5fd;
|
|
178
|
+
margin: 0;
|
|
179
|
+
font-family: 'JetBrains Mono', monospace;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
.status-pill {
|
|
183
|
+
font-family: 'JetBrains Mono', monospace;
|
|
184
|
+
font-size: 10px;
|
|
185
|
+
font-weight: 700;
|
|
186
|
+
padding: 3px 8px;
|
|
187
|
+
border-radius: 6px;
|
|
188
|
+
background: rgba(59, 130, 246, 0.15);
|
|
189
|
+
border: 1px solid rgba(59, 130, 246, 0.4);
|
|
190
|
+
color: #60a5fa;
|
|
191
|
+
letter-spacing: 0.05em;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/* Telemetry Metric Cards */
|
|
195
|
+
.telemetry-row {
|
|
196
|
+
display: grid;
|
|
197
|
+
grid-template-columns: repeat(3, 1fr);
|
|
198
|
+
gap: 8px;
|
|
199
|
+
margin-bottom: 12px;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
.metric-card {
|
|
203
|
+
background: rgba(30, 58, 138, 0.4);
|
|
204
|
+
border: 1px solid rgba(59, 130, 246, 0.25);
|
|
205
|
+
border-radius: 8px;
|
|
206
|
+
padding: 8px 10px;
|
|
207
|
+
display: flex;
|
|
208
|
+
flex-direction: column;
|
|
209
|
+
gap: 2px;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
.metric-label {
|
|
213
|
+
font-family: 'JetBrains Mono', monospace;
|
|
214
|
+
font-size: 9px;
|
|
215
|
+
font-weight: 700;
|
|
216
|
+
color: #93c5fd;
|
|
217
|
+
letter-spacing: 0.05em;
|
|
218
|
+
text-transform: uppercase;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
.metric-value {
|
|
222
|
+
font-size: 13px;
|
|
223
|
+
font-weight: 700;
|
|
224
|
+
color: #ffffff;
|
|
225
|
+
font-family: 'JetBrains Mono', monospace;
|
|
226
|
+
overflow: hidden;
|
|
227
|
+
text-overflow: ellipsis;
|
|
228
|
+
white-space: nowrap;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/* Target Node Selector */
|
|
232
|
+
.target-box {
|
|
233
|
+
display: flex;
|
|
234
|
+
align-items: center;
|
|
235
|
+
gap: 8px;
|
|
236
|
+
margin-bottom: 10px;
|
|
237
|
+
background: rgba(0, 0, 0, 0.4);
|
|
238
|
+
border: 1px solid rgba(59, 130, 246, 0.25);
|
|
239
|
+
border-radius: 8px;
|
|
240
|
+
padding: 4px 8px;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
.target-label {
|
|
244
|
+
font-family: 'JetBrains Mono', monospace;
|
|
245
|
+
font-size: 10px;
|
|
246
|
+
color: #93c5fd;
|
|
247
|
+
text-transform: uppercase;
|
|
248
|
+
white-space: nowrap;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
.target-input {
|
|
252
|
+
flex: 1;
|
|
253
|
+
background: transparent;
|
|
254
|
+
border: none;
|
|
255
|
+
color: #eff6ff;
|
|
256
|
+
font-family: 'JetBrains Mono', monospace;
|
|
257
|
+
font-size: 12px;
|
|
258
|
+
outline: none;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
.target-input::placeholder {
|
|
262
|
+
color: rgba(147, 197, 253, 0.4);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/* Action Buttons Grid (>=44px touch targets) */
|
|
266
|
+
.actions-grid {
|
|
267
|
+
display: grid;
|
|
268
|
+
grid-template-columns: repeat(3, 1fr);
|
|
269
|
+
gap: 6px;
|
|
270
|
+
margin-bottom: 10px;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
.touch-btn {
|
|
274
|
+
min-height: 44px;
|
|
275
|
+
background: rgba(37, 99, 235, 0.16);
|
|
276
|
+
border: 1px solid rgba(59, 130, 246, 0.3);
|
|
277
|
+
border-radius: 8px;
|
|
278
|
+
color: #eff6ff;
|
|
279
|
+
font-family: 'JetBrains Mono', monospace;
|
|
280
|
+
font-size: 11px;
|
|
281
|
+
font-weight: 600;
|
|
282
|
+
letter-spacing: 0.03em;
|
|
283
|
+
display: flex;
|
|
284
|
+
align-items: center;
|
|
285
|
+
justify-content: center;
|
|
286
|
+
cursor: pointer;
|
|
287
|
+
transition: background 0.15s, border-color 0.15s, transform 0.05s;
|
|
288
|
+
padding: 4px 6px;
|
|
289
|
+
text-align: center;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
.touch-btn:hover {
|
|
293
|
+
background: rgba(37, 99, 235, 0.3);
|
|
294
|
+
border-color: rgba(96, 165, 250, 0.6);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
.touch-btn:active {
|
|
298
|
+
transform: translateY(1px);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
/* Terminal Execution Output */
|
|
302
|
+
.terminal-deck {
|
|
303
|
+
background: #020712;
|
|
304
|
+
border: 1px solid rgba(59, 130, 246, 0.25);
|
|
305
|
+
border-radius: 8px;
|
|
306
|
+
overflow: hidden;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
.terminal-header {
|
|
310
|
+
display: flex;
|
|
311
|
+
align-items: center;
|
|
312
|
+
justify-content: space-between;
|
|
313
|
+
padding: 6px 10px;
|
|
314
|
+
background: rgba(30, 58, 138, 0.4);
|
|
315
|
+
border-bottom: 1px solid rgba(59, 130, 246, 0.2);
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
.terminal-title {
|
|
319
|
+
font-family: 'JetBrains Mono', monospace;
|
|
320
|
+
font-size: 10px;
|
|
321
|
+
color: #93c5fd;
|
|
322
|
+
text-transform: uppercase;
|
|
323
|
+
letter-spacing: 0.05em;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
.terminal-btn {
|
|
327
|
+
background: rgba(59, 130, 246, 0.15);
|
|
328
|
+
border: 1px solid rgba(59, 130, 246, 0.3);
|
|
329
|
+
border-radius: 4px;
|
|
330
|
+
color: #dbeafe;
|
|
331
|
+
font-family: 'JetBrains Mono', monospace;
|
|
332
|
+
font-size: 9px;
|
|
333
|
+
padding: 2px 6px;
|
|
334
|
+
cursor: pointer;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
.terminal-btn:hover {
|
|
338
|
+
background: rgba(59, 130, 246, 0.3);
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
.terminal-body {
|
|
342
|
+
margin: 0;
|
|
343
|
+
padding: 8px 10px;
|
|
344
|
+
font-family: 'JetBrains Mono', monospace;
|
|
345
|
+
font-size: 11px;
|
|
346
|
+
line-height: 1.45;
|
|
347
|
+
color: #dbeafe;
|
|
348
|
+
min-height: 60px;
|
|
349
|
+
max-height: 100px;
|
|
350
|
+
overflow-y: auto;
|
|
351
|
+
white-space: pre-wrap;
|
|
352
|
+
word-break: break-word;
|
|
353
|
+
}
|
|
354
|
+
</style>
|
|
355
|
+
|
|
356
|
+
<div class="card-header">
|
|
357
|
+
<div class="brand-cluster">
|
|
358
|
+
<div class="brand-mark">
|
|
359
|
+
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#60a5fa" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
360
|
+
<circle cx="12" cy="5" r="3"/>
|
|
361
|
+
<circle cx="5" cy="19" r="3"/>
|
|
362
|
+
<circle cx="19" cy="19" r="3"/>
|
|
363
|
+
<line x1="12" y1="8" x2="5" y2="16"/>
|
|
364
|
+
<line x1="12" y1="8" x2="19" y2="16"/>
|
|
365
|
+
<line x1="5" y1="19" x2="19" y2="19"/>
|
|
366
|
+
</svg>
|
|
367
|
+
</div>
|
|
368
|
+
<div class="brand-meta">
|
|
369
|
+
<h3 class="brand-title">Headscale Mesh</h3>
|
|
370
|
+
<span class="brand-subtitle">Topology & Node Control • v0.2.2</span>
|
|
371
|
+
</div>
|
|
372
|
+
</div>
|
|
373
|
+
<div id="status-pill" class="status-pill">ONLINE</div>
|
|
374
|
+
</div>
|
|
375
|
+
|
|
376
|
+
<div class="telemetry-row">
|
|
377
|
+
<div class="metric-card">
|
|
378
|
+
<span class="metric-label">Topology</span>
|
|
379
|
+
<span id="stat-nodes" class="metric-value">4 Nodes</span>
|
|
380
|
+
</div>
|
|
381
|
+
<div class="metric-card">
|
|
382
|
+
<span class="metric-label">Control Node</span>
|
|
383
|
+
<span id="stat-cloud" class="metric-value">Connected</span>
|
|
384
|
+
</div>
|
|
385
|
+
<div class="metric-card">
|
|
386
|
+
<span class="metric-label">Local Node</span>
|
|
387
|
+
<span id="stat-mini" class="metric-value">Enrolled</span>
|
|
388
|
+
</div>
|
|
389
|
+
</div>
|
|
390
|
+
|
|
391
|
+
<div class="target-box">
|
|
392
|
+
<span class="target-label">Target Peer:</span>
|
|
393
|
+
<input id="node-input" class="target-input" type="text" value="cloud" placeholder="Node name or IP e.g. cloud or 100.64.0.0/10" />
|
|
394
|
+
</div>
|
|
395
|
+
|
|
396
|
+
<div class="actions-grid">
|
|
397
|
+
<button id="btn-nodes" class="touch-btn" type="button">NODES</button>
|
|
398
|
+
<button id="btn-ping" class="touch-btn" type="button">PING PEER</button>
|
|
399
|
+
<button id="btn-doctor" class="touch-btn" type="button">MESH DOCTOR</button>
|
|
400
|
+
<button id="btn-leader" class="touch-btn" type="button">LEADER</button>
|
|
401
|
+
<button id="btn-presence" class="touch-btn" type="button">PRESENCE</button>
|
|
402
|
+
<button id="btn-server" class="touch-btn" type="button">STATUS</button>
|
|
403
|
+
</div>
|
|
404
|
+
|
|
405
|
+
<div class="terminal-deck">
|
|
406
|
+
<div class="terminal-header">
|
|
407
|
+
<span class="terminal-title">Mesh Telemetry Console</span>
|
|
408
|
+
<button id="btn-copy" class="terminal-btn" type="button">COPY</button>
|
|
409
|
+
</div>
|
|
410
|
+
<pre id="card-out" class="terminal-body">WireGuard mesh topology active. Select a peer or query node health above.</pre>
|
|
411
|
+
</div>
|
|
412
|
+
`;
|
|
413
|
+
|
|
414
|
+
const getNode = () => {
|
|
415
|
+
const input = root.querySelector('#node-input');
|
|
416
|
+
return (input?.value || 'cloud').trim();
|
|
417
|
+
};
|
|
418
|
+
|
|
419
|
+
root.querySelector('#btn-nodes')?.addEventListener('click', () => {
|
|
420
|
+
this.execute('nodes');
|
|
421
|
+
});
|
|
422
|
+
|
|
423
|
+
root.querySelector('#btn-ping')?.addEventListener('click', () => {
|
|
424
|
+
this.execute('ping', [getNode()]);
|
|
425
|
+
});
|
|
426
|
+
|
|
427
|
+
root.querySelector('#btn-doctor')?.addEventListener('click', () => {
|
|
428
|
+
this.execute('doctor');
|
|
429
|
+
});
|
|
430
|
+
|
|
431
|
+
root.querySelector('#btn-leader')?.addEventListener('click', () => {
|
|
432
|
+
this.execute('leader');
|
|
433
|
+
});
|
|
434
|
+
|
|
435
|
+
root.querySelector('#btn-presence')?.addEventListener('click', () => {
|
|
436
|
+
this.execute('presence');
|
|
437
|
+
});
|
|
438
|
+
|
|
439
|
+
root.querySelector('#btn-server')?.addEventListener('click', () => {
|
|
440
|
+
this.execute('status');
|
|
441
|
+
});
|
|
442
|
+
|
|
443
|
+
root.querySelector('#btn-copy')?.addEventListener('click', () => {
|
|
444
|
+
this.copyOutput();
|
|
445
|
+
});
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
if (!customElements.get('tr-mesh-card')) {
|
|
450
|
+
customElements.define('tr-mesh-card', MeshlinkControlCard);
|
|
33
451
|
}
|
|
34
|
-
if (!customElements.get('tr-mesh-card')) customElements.define('tr-mesh-card', MeshlinkControlCard);
|