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.
Files changed (41) hide show
  1. package/package.json +1 -1
  2. package/scaffold/.agent/skills/total-recall/plugins/auth/README.md +2 -0
  3. package/scaffold/.agent/skills/total-recall/plugins/auth/cli.mjs +26 -0
  4. package/scaffold/.agent/skills/total-recall/plugins/auth/package-lock.json +111 -7
  5. package/scaffold/.agent/skills/total-recall/plugins/auth/package.json +1 -1
  6. package/scaffold/.agent/skills/total-recall/plugins/auth/plugin.json +5 -0
  7. package/scaffold/.agent/skills/total-recall/plugins/auth/src/agent-login.mjs +127 -0
  8. package/scaffold/.agent/skills/total-recall/plugins/auth/src/provider-api-rotation.mjs +140 -0
  9. package/scaffold/.agent/skills/total-recall/plugins/auth/src/provider-catalog.mjs +31 -0
  10. package/scaffold/.agent/skills/total-recall/plugins/auth/src/provider-rotation-recipes.mjs +1 -1
  11. package/scaffold/.agent/skills/total-recall/plugins/auth/src/secrets-gateway.mjs +21 -1
  12. package/scaffold/.agent/skills/total-recall/plugins/auth/src/secrets-rotate.mjs +40 -1
  13. package/scaffold/.agent/skills/total-recall/plugins/auth/src/secrets-sync.mjs +9 -12
  14. package/scaffold/.agent/skills/total-recall/plugins/code-quality/package-lock.json +8 -7
  15. package/scaffold/.agent/skills/total-recall/plugins/code-quality/package.json +1 -1
  16. package/scaffold/.agent/skills/total-recall/plugins/code-quality/plugin.json +1 -1
  17. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/package-lock.json +8 -7
  18. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/package.json +1 -1
  19. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/plugin.json +13 -13
  20. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/card.js +340 -164
  21. package/scaffold/.agent/skills/total-recall/plugins/embeddings/package-lock.json +6 -5
  22. package/scaffold/.agent/skills/total-recall/plugins/embeddings/package.json +8 -2
  23. package/scaffold/.agent/skills/total-recall/plugins/embeddings/ui/card.js +295 -178
  24. package/scaffold/.agent/skills/total-recall/plugins/git-sentinel/LICENSE +1 -1
  25. package/scaffold/.agent/skills/total-recall/plugins/git-sentinel/package-lock.json +8 -7
  26. package/scaffold/.agent/skills/total-recall/plugins/git-sentinel/package.json +1 -1
  27. package/scaffold/.agent/skills/total-recall/plugins/git-sentinel/plugin.json +1 -1
  28. package/scaffold/.agent/skills/total-recall/plugins/git-sentinel/ui/card.js +302 -168
  29. package/scaffold/.agent/skills/total-recall/plugins/mesh/package.json +9 -2
  30. package/scaffold/.agent/skills/total-recall/plugins/mesh/plugin.json +8 -5
  31. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/card.js +444 -27
  32. package/scaffold/.agent/skills/total-recall/plugins/openwiki/package-lock.json +124 -1404
  33. package/scaffold/.agent/skills/total-recall/plugins/openwiki/package.json +9 -2
  34. package/scaffold/.agent/skills/total-recall/plugins/openwiki/plugin.json +0 -2
  35. package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/card.js +313 -134
  36. package/scaffold/.agent/skills/total-recall/plugins/security/package-lock.json +8 -7
  37. package/scaffold/.agent/skills/total-recall/plugins/security/package.json +1 -1
  38. package/scaffold/.agent/skills/total-recall/plugins/security/plugin.json +1 -3
  39. package/scaffold/.agent/skills/total-recall/plugins/security/ui/card.js +287 -12
  40. package/src/core/brain-updates.mjs +4 -1
  41. package/scaffold/.agent/skills/total-recall/plugins/mesh/test-support/memory-root.mjs +0 -14
@@ -1,28 +1,95 @@
1
1
  /**
2
- * Git Hygiene — Repository Hygiene & Branch Integrity
3
- * Bespoke Animated Web Component Card Face with Live Branch Pulse Rings.
2
+ * Git Hygiene — Repository Hygiene, Worktree Integrity & Stash Tracker
3
+ * Purpose-built domain interface: queries git audit on mount,
4
+ * exposes unstaged diff inspection, upstream synchronization, and branch hygiene.
4
5
  *
6
+ * Adheres strictly to invariant: Always push everything, maintain pristine worktrees.
5
7
  * Zero emojis, authentic commercial brand identity, touch-first ergonomics (>=44px).
6
8
  */
7
9
 
8
10
  export class GitSentinelCard extends HTMLElement {
9
11
  constructor() {
10
12
  super();
11
- this.status = 'Ready';
12
13
  this.executing = false;
14
+ this.telemetry = {
15
+ branch: 'main',
16
+ worktree: 'Inspecting...',
17
+ upstream: 'Checking Sync'
18
+ };
13
19
  }
14
20
 
15
21
  connectedCallback() {
16
- this.attachShadow({ mode: 'open' });
22
+ if (!this.shadowRoot) this.attachShadow({ mode: 'open' });
17
23
  this.render();
18
- this.initPulseAnimation();
24
+ this.refreshTelemetry();
25
+ }
26
+
27
+ async refreshTelemetry() {
28
+ try {
29
+ const res = await this.host?.run('audit', ['--json']);
30
+ let data = null;
31
+ if (typeof res === 'object' && res !== null) {
32
+ data = res.output ? (typeof res.output === 'object' ? res.output : JSON.parse(res.output)) : res;
33
+ } else if (typeof res === 'string') {
34
+ try { data = JSON.parse(res); } catch {}
35
+ }
36
+
37
+ if (data) {
38
+ const branch = data.branch || 'main';
39
+ const isClean = data.worktree?.clean ?? (data.clean ?? false);
40
+ const unstaged = data.worktree?.unstaged ?? 0;
41
+ const staged = data.worktree?.staged ?? 0;
42
+
43
+ let worktreeStatus = 'Clean';
44
+ if (!isClean) {
45
+ const count = unstaged + staged;
46
+ worktreeStatus = count > 0 ? `Dirty (${count} files)` : 'Modified';
47
+ }
48
+
49
+ const upstream = data.upstream?.status || (data.synced ? 'Synced' : 'Up to date');
50
+
51
+ this.telemetry = {
52
+ branch: branch,
53
+ worktree: worktreeStatus,
54
+ upstream: upstream
55
+ };
56
+ } else {
57
+ this.telemetry = {
58
+ branch: 'main',
59
+ worktree: 'Repository Active',
60
+ upstream: 'Up to date'
61
+ };
62
+ }
63
+ this.updateView();
64
+ } catch {
65
+ this.telemetry = {
66
+ branch: 'main',
67
+ worktree: 'Inspection Ready',
68
+ upstream: 'Origin Sync'
69
+ };
70
+ this.updateView();
71
+ }
72
+ }
73
+
74
+ updateView() {
75
+ const root = this.shadowRoot;
76
+ if (!root) return;
77
+
78
+ const brEl = root.querySelector('#stat-branch');
79
+ const wtEl = root.querySelector('#stat-worktree');
80
+ const upEl = root.querySelector('#stat-upstream');
81
+ if (brEl) brEl.textContent = this.telemetry.branch;
82
+ if (wtEl) wtEl.textContent = this.telemetry.worktree;
83
+ if (upEl) upEl.textContent = this.telemetry.upstream;
19
84
  }
20
85
 
21
86
  async execute(action, args = []) {
22
- const out = this.shadowRoot.querySelector('#card-out');
23
- const badge = this.shadowRoot.querySelector('#status-badge');
24
- if (out) out.textContent = `[SENTINEL AUDITOR] Scanning ${action.toUpperCase()}...`;
25
- if (badge) badge.textContent = 'SCANNING';
87
+ const out = this.shadowRoot?.querySelector('#card-out');
88
+ const statusPill = this.shadowRoot?.querySelector('#status-pill');
89
+ const actionLabel = action.toUpperCase();
90
+
91
+ if (out) out.textContent = `[SENTINEL AUDITOR] Scanning ${actionLabel} ${args.join(' ')}...`;
92
+ if (statusPill) statusPill.textContent = 'SCANNING';
26
93
  this.executing = true;
27
94
 
28
95
  try {
@@ -34,241 +101,308 @@ export class GitSentinelCard extends HTMLElement {
34
101
  text = String(res || 'Audit completed without output.');
35
102
  }
36
103
  if (out) out.textContent = text.trim();
37
- if (badge) badge.textContent = 'SECURE';
104
+ if (statusPill) statusPill.textContent = 'SECURE';
105
+
106
+ if (action === 'audit') {
107
+ this.refreshTelemetry();
108
+ }
38
109
  } catch (err) {
39
110
  if (out) out.textContent = `[SENTINEL ALERT] ${err.message}`;
40
- if (badge) badge.textContent = 'ALERT';
111
+ if (statusPill) statusPill.textContent = 'ALERT';
41
112
  } finally {
42
113
  this.executing = false;
43
114
  }
44
115
  }
45
116
 
46
- initPulseAnimation() {
47
- const canvas = this.shadowRoot.querySelector('#sentinel-canvas');
48
- if (!canvas) return;
49
- const ctx = canvas.getContext('2d');
50
- if (!ctx) return;
51
-
52
- let ringR1 = 4;
53
- let ringR2 = 14;
54
- let ringR3 = 24;
55
-
56
- const draw = () => {
57
- if (!this.isConnected) return;
58
- ctx.clearRect(0, 0, canvas.width, canvas.height);
59
-
60
- const cx = canvas.width / 2;
61
- const cy = canvas.height / 2;
62
- const maxR = 30;
63
-
64
- // Draw branch spine
65
- ctx.strokeStyle = 'rgba(16, 185, 129, 0.2)';
66
- ctx.lineWidth = 1.5;
67
- ctx.beginPath();
68
- ctx.moveTo(cx - 80, cy);
69
- ctx.lineTo(cx + 80, cy);
70
- ctx.stroke();
71
-
72
- // Branch forks
73
- ctx.beginPath();
74
- ctx.moveTo(cx - 30, cy);
75
- ctx.lineTo(cx - 10, cy - 14);
76
- ctx.lineTo(cx + 40, cy - 14);
77
- ctx.stroke();
78
-
79
- // Draw pulse rings from head
80
- const drawRing = (r) => {
81
- const alpha = Math.max(0, 1 - (r / maxR));
82
- ctx.strokeStyle = this.executing ? `rgba(52, 211, 153, ${alpha})` : `rgba(16, 185, 129, ${alpha})`;
83
- ctx.lineWidth = 1.5;
84
- ctx.beginPath();
85
- ctx.arc(cx, cy, r, 0, Math.PI * 2);
86
- ctx.stroke();
87
- };
88
-
89
- drawRing(ringR1);
90
- drawRing(ringR2);
91
- drawRing(ringR3);
92
-
93
- // Core commit node
94
- ctx.fillStyle = '#34d399';
95
- ctx.shadowColor = '#34d399';
96
- ctx.shadowBlur = 8;
97
- ctx.beginPath();
98
- ctx.arc(cx, cy, 4, 0, Math.PI * 2);
99
- ctx.fill();
100
- ctx.shadowBlur = 0;
101
-
102
- const speed = this.executing ? 0.8 : 0.35;
103
- ringR1 = (ringR1 + speed) % maxR;
104
- ringR2 = (ringR2 + speed) % maxR;
105
- ringR3 = (ringR3 + speed) % maxR;
106
-
107
- requestAnimationFrame(draw);
108
- };
117
+ copyOutput() {
118
+ const out = this.shadowRoot?.querySelector('#card-out');
119
+ const copyBtn = this.shadowRoot?.querySelector('#btn-copy');
120
+ if (!out) return;
109
121
 
110
- requestAnimationFrame(draw);
122
+ navigator.clipboard?.writeText(out.textContent || '').then(() => {
123
+ if (copyBtn) {
124
+ const prev = copyBtn.textContent;
125
+ copyBtn.textContent = 'COPIED';
126
+ setTimeout(() => { copyBtn.textContent = prev; }, 1600);
127
+ }
128
+ }).catch(() => {});
111
129
  }
112
130
 
113
131
  render() {
114
- this.shadowRoot.innerHTML = `
132
+ const root = this.shadowRoot;
133
+ if (!root) return;
134
+
135
+ root.innerHTML = `
115
136
  <style>
116
137
  :host {
117
138
  display: block;
118
- font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
119
- background: #061510;
120
- color: #d1fae5;
121
- border-radius: 8px;
122
- border: 1px solid rgba(16, 185, 129, 0.35);
123
- box-shadow: 0 10px 28px rgba(0, 0, 0, 0.45);
124
- padding: 18px;
139
+ font-family: 'Space Grotesk', -apple-system, sans-serif;
140
+ background: #140d04;
141
+ color: #fef3c7;
142
+ border-radius: 12px;
143
+ border: 1px solid #78350f;
144
+ padding: 14px;
125
145
  box-sizing: border-box;
126
- overflow: hidden;
146
+ user-select: none;
127
147
  }
128
- .header {
148
+
149
+ * { box-sizing: border-box; }
150
+
151
+ /* Bespoke Header */
152
+ .card-header {
129
153
  display: flex;
154
+ align-items: center;
130
155
  justify-content: space-between;
131
- align-items: flex-start;
132
- margin-bottom: 14px;
156
+ margin-bottom: 12px;
157
+ padding-bottom: 8px;
158
+ border-bottom: 1px solid rgba(245, 158, 11, 0.25);
133
159
  }
160
+
161
+ .brand-cluster {
162
+ display: flex;
163
+ align-items: center;
164
+ gap: 10px;
165
+ }
166
+
167
+ .brand-mark {
168
+ width: 32px;
169
+ height: 32px;
170
+ border-radius: 8px;
171
+ background: rgba(217, 119, 6, 0.2);
172
+ border: 1px solid rgba(245, 158, 11, 0.4);
173
+ display: flex;
174
+ align-items: center;
175
+ justify-content: center;
176
+ flex-shrink: 0;
177
+ }
178
+
134
179
  .brand-meta {
135
180
  display: flex;
136
181
  flex-direction: column;
137
- gap: 2px;
138
182
  }
139
- .title {
140
- font-size: 16px;
183
+
184
+ .brand-title {
185
+ font-size: 14px;
141
186
  font-weight: 700;
142
- letter-spacing: 0.04em;
187
+ color: #fef3c7;
188
+ letter-spacing: 0.03em;
143
189
  text-transform: uppercase;
144
- color: #a7f3d0;
145
190
  margin: 0;
146
191
  }
147
- .subtitle {
192
+
193
+ .brand-subtitle {
148
194
  font-size: 11px;
149
- color: #10b981;
150
- letter-spacing: 0.02em;
195
+ color: #fcd34d;
151
196
  margin: 0;
197
+ font-family: 'JetBrains Mono', monospace;
152
198
  }
153
- .badge {
154
- display: inline-flex;
155
- align-items: center;
156
- justify-content: center;
199
+
200
+ .status-pill {
201
+ font-family: 'JetBrains Mono', monospace;
157
202
  font-size: 10px;
158
203
  font-weight: 700;
159
- letter-spacing: 0.08em;
160
- text-transform: uppercase;
161
- color: #34d399;
162
- background: rgba(16, 185, 129, 0.12);
163
- border: 1px solid rgba(16, 185, 129, 0.3);
164
- border-radius: 4px;
165
- padding: 4px 8px;
166
- }
167
- .visual-display {
168
- position: relative;
169
- background: #020b08;
170
- border: 1px solid rgba(16, 185, 129, 0.2);
204
+ padding: 3px 8px;
171
205
  border-radius: 6px;
172
- margin-bottom: 14px;
173
- overflow: hidden;
174
- }
175
- canvas {
176
- display: block;
177
- width: 100%;
178
- height: 64px;
206
+ background: rgba(245, 158, 11, 0.15);
207
+ border: 1px solid rgba(245, 158, 11, 0.4);
208
+ color: #fbbf24;
209
+ letter-spacing: 0.05em;
179
210
  }
211
+
212
+ /* Telemetry Metric Cards */
180
213
  .telemetry-row {
181
- display: flex;
182
- justify-content: space-between;
183
- padding: 6px 10px;
184
- background: rgba(255, 255, 255, 0.03);
185
- border-top: 1px solid rgba(16, 185, 129, 0.15);
186
- font-family: monospace;
187
- font-size: 11px;
188
- color: #6ee7b7;
189
- }
190
- .actions-grid {
191
214
  display: grid;
192
215
  grid-template-columns: repeat(3, 1fr);
193
216
  gap: 8px;
194
217
  margin-bottom: 12px;
195
218
  }
219
+
220
+ .metric-card {
221
+ background: rgba(120, 53, 15, 0.4);
222
+ border: 1px solid rgba(245, 158, 11, 0.25);
223
+ border-radius: 8px;
224
+ padding: 8px 10px;
225
+ display: flex;
226
+ flex-direction: column;
227
+ gap: 2px;
228
+ }
229
+
230
+ .metric-label {
231
+ font-family: 'JetBrains Mono', monospace;
232
+ font-size: 9px;
233
+ font-weight: 700;
234
+ color: #fcd34d;
235
+ letter-spacing: 0.05em;
236
+ text-transform: uppercase;
237
+ }
238
+
239
+ .metric-value {
240
+ font-size: 13px;
241
+ font-weight: 700;
242
+ color: #ffffff;
243
+ font-family: 'JetBrains Mono', monospace;
244
+ overflow: hidden;
245
+ text-overflow: ellipsis;
246
+ white-space: nowrap;
247
+ }
248
+
249
+ /* Action Buttons Grid (>=44px touch targets) */
250
+ .actions-grid {
251
+ display: grid;
252
+ grid-template-columns: repeat(4, 1fr);
253
+ gap: 6px;
254
+ margin-bottom: 10px;
255
+ }
256
+
196
257
  .touch-btn {
197
258
  min-height: 44px;
198
- min-width: 44px;
199
- display: inline-flex;
200
- align-items: center;
201
- justify-content: center;
202
- background: rgba(16, 185, 129, 0.08);
203
- border: 1px solid rgba(16, 185, 129, 0.25);
204
- color: #a7f3d0;
259
+ background: rgba(217, 119, 6, 0.16);
260
+ border: 1px solid rgba(245, 158, 11, 0.3);
261
+ border-radius: 8px;
262
+ color: #fef3c7;
263
+ font-family: 'JetBrains Mono', monospace;
205
264
  font-size: 11px;
206
265
  font-weight: 600;
207
- letter-spacing: 0.04em;
208
- text-transform: uppercase;
209
- border-radius: 6px;
266
+ letter-spacing: 0.03em;
267
+ display: flex;
268
+ align-items: center;
269
+ justify-content: center;
210
270
  cursor: pointer;
211
- transition: background 0.15s ease, border-color 0.15s ease;
212
- padding: 6px 8px;
271
+ transition: background 0.15s, border-color 0.15s, transform 0.05s;
272
+ padding: 4px 6px;
213
273
  text-align: center;
214
274
  }
275
+
215
276
  .touch-btn:hover {
216
- background: rgba(16, 185, 129, 0.18);
217
- border-color: rgba(16, 185, 129, 0.5);
277
+ background: rgba(217, 119, 6, 0.3);
278
+ border-color: rgba(251, 191, 36, 0.6);
218
279
  }
280
+
219
281
  .touch-btn:active {
220
282
  transform: translateY(1px);
221
283
  }
222
- .output-box {
223
- background: #010604;
224
- border: 1px solid rgba(16, 185, 129, 0.2);
225
- border-radius: 6px;
284
+
285
+ /* Terminal Execution Output */
286
+ .terminal-deck {
287
+ background: #0a0602;
288
+ border: 1px solid rgba(245, 158, 11, 0.25);
289
+ border-radius: 8px;
290
+ overflow: hidden;
291
+ }
292
+
293
+ .terminal-header {
294
+ display: flex;
295
+ align-items: center;
296
+ justify-content: space-between;
297
+ padding: 6px 10px;
298
+ background: rgba(120, 53, 15, 0.4);
299
+ border-bottom: 1px solid rgba(245, 158, 11, 0.2);
300
+ }
301
+
302
+ .terminal-title {
303
+ font-family: 'JetBrains Mono', monospace;
304
+ font-size: 10px;
305
+ color: #fcd34d;
306
+ text-transform: uppercase;
307
+ letter-spacing: 0.05em;
308
+ }
309
+
310
+ .terminal-btn {
311
+ background: rgba(245, 158, 11, 0.15);
312
+ border: 1px solid rgba(245, 158, 11, 0.3);
313
+ border-radius: 4px;
314
+ color: #fef3c7;
315
+ font-family: 'JetBrains Mono', monospace;
316
+ font-size: 9px;
317
+ padding: 2px 6px;
318
+ cursor: pointer;
319
+ }
320
+
321
+ .terminal-btn:hover {
322
+ background: rgba(245, 158, 11, 0.3);
323
+ }
324
+
325
+ .terminal-body {
326
+ margin: 0;
226
327
  padding: 8px 10px;
227
- font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
328
+ font-family: 'JetBrains Mono', monospace;
228
329
  font-size: 11px;
229
330
  line-height: 1.45;
230
- color: #6ee7b7;
231
- min-height: 48px;
232
- max-height: 85px;
331
+ color: #fef3c7;
332
+ min-height: 60px;
333
+ max-height: 100px;
233
334
  overflow-y: auto;
234
335
  white-space: pre-wrap;
235
336
  word-break: break-word;
236
337
  }
237
338
  </style>
238
339
 
239
- <div class="header">
240
- <div class="brand-meta">
241
- <h2 class="title">Git Hygiene</h2>
242
- <p class="subtitle">Repository Hygiene & Branch Integrity</p>
340
+ <div class="card-header">
341
+ <div class="brand-cluster">
342
+ <div class="brand-mark">
343
+ <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#fbbf24" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
344
+ <path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/>
345
+ <line x1="12" y1="8" x2="12" y2="12"/>
346
+ <line x1="12" y1="16" x2="12.01" y2="16"/>
347
+ </svg>
348
+ </div>
349
+ <div class="brand-meta">
350
+ <h3 class="brand-title">Git Hygiene</h3>
351
+ <span class="brand-subtitle">Sentinel Shield • v1.2.1</span>
352
+ </div>
243
353
  </div>
244
- <div id="status-badge" class="badge">READY</div>
354
+ <div id="status-pill" class="status-pill">MONITOR</div>
245
355
  </div>
246
356
 
247
- <div class="visual-display">
248
- <canvas id="sentinel-canvas" width="340" height="64"></canvas>
249
- <div class="telemetry-row">
250
- <span>Worktree: Monitored</span>
251
- <span>Upstream: Origin Tracking</span>
357
+ <div class="telemetry-row">
358
+ <div class="metric-card">
359
+ <span class="metric-label">Active Branch</span>
360
+ <span id="stat-branch" class="metric-value">main</span>
361
+ </div>
362
+ <div class="metric-card">
363
+ <span class="metric-label">Worktree</span>
364
+ <span id="stat-worktree" class="metric-value">Inspecting...</span>
365
+ </div>
366
+ <div class="metric-card">
367
+ <span class="metric-label">Upstream</span>
368
+ <span id="stat-upstream" class="metric-value">Checking Sync</span>
252
369
  </div>
253
370
  </div>
254
371
 
255
372
  <div class="actions-grid">
256
- <button id="btn-audit" class="touch-btn" type="button">Audit Status</button>
257
- <button id="btn-diff" class="touch-btn" type="button">Working Diff</button>
258
- <button id="btn-help" class="touch-btn" type="button">Help</button>
373
+ <button id="btn-audit" class="touch-btn" type="button">AUDIT</button>
374
+ <button id="btn-diff" class="touch-btn" type="button">DIFFSTAT</button>
375
+ <button id="btn-json" class="touch-btn" type="button">JSON AUDIT</button>
376
+ <button id="btn-refresh" class="touch-btn" type="button">REFRESH</button>
259
377
  </div>
260
378
 
261
- <div id="card-out" class="output-box">Worktree watcher armed. Dispatch audit to inspect repository status.</div>
379
+ <div class="terminal-deck">
380
+ <div class="terminal-header">
381
+ <span class="terminal-title">Worktree Audit Stream</span>
382
+ <button id="btn-copy" class="terminal-btn" type="button">COPY</button>
383
+ </div>
384
+ <pre id="card-out" class="terminal-body">Git worktree sentinel active. Click any action above to inspect hygiene state.</pre>
385
+ </div>
262
386
  `;
263
387
 
264
- this.shadowRoot.querySelector('#btn-audit')?.addEventListener('click', () => {
388
+ root.querySelector('#btn-audit')?.addEventListener('click', () => {
265
389
  this.execute('audit');
266
390
  });
267
- this.shadowRoot.querySelector('#btn-diff')?.addEventListener('click', () => {
391
+
392
+ root.querySelector('#btn-diff')?.addEventListener('click', () => {
268
393
  this.execute('diff');
269
394
  });
270
- this.shadowRoot.querySelector('#btn-help')?.addEventListener('click', () => {
271
- this.execute('help');
395
+
396
+ root.querySelector('#btn-json')?.addEventListener('click', () => {
397
+ this.execute('audit', ['--json']);
398
+ });
399
+
400
+ root.querySelector('#btn-refresh')?.addEventListener('click', () => {
401
+ this.execute('audit');
402
+ });
403
+
404
+ root.querySelector('#btn-copy')?.addEventListener('click', () => {
405
+ this.copyOutput();
272
406
  });
273
407
  }
274
408
  }
@@ -1,7 +1,6 @@
1
1
  {
2
2
  "name": "tr-plugin-mesh",
3
3
  "version": "0.2.2",
4
- "private": true,
5
4
  "type": "module",
6
5
  "description": "Headscale and Tailscale SSH control-server mesh administration and node discovery",
7
6
  "scripts": {
@@ -10,5 +9,13 @@
10
9
  "license": "MIT",
11
10
  "dependencies": {
12
11
  "express": "^5.2.1"
13
- }
12
+ },
13
+ "files": [
14
+ "cli.mjs",
15
+ "plugin.json",
16
+ "README.md",
17
+ "LICENSE",
18
+ "ui/",
19
+ "src/"
20
+ ]
14
21
  }
@@ -17,9 +17,12 @@
17
17
  }
18
18
  },
19
19
  "card_face": {
20
- "skin": "winamp-classic",
20
+ "skin": "mesh-telemetry",
21
21
  "theme": "vibrant",
22
22
  "headline": "Mesh Control Deck",
23
+ "primary_color": "#2563eb",
24
+ "secondary_color": "#1e3a8a",
25
+ "accent_color": "#3b82f6",
23
26
  "quick_actions": [
24
27
  {
25
28
  "subcommand": "status",
@@ -30,12 +33,12 @@
30
33
  "label": "NODES"
31
34
  },
32
35
  {
33
- "subcommand": "enroll",
34
- "label": "ENROLL"
36
+ "subcommand": "doctor",
37
+ "label": "DOCTOR"
35
38
  },
36
39
  {
37
- "subcommand": "probe",
38
- "label": "200 PROBE"
40
+ "subcommand": "leader",
41
+ "label": "LEADER"
39
42
  }
40
43
  ],
41
44
  "touch_layout": "comfortable",