total-recall-brain 3.40.2 → 3.40.4

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 (33) hide show
  1. package/package.json +1 -1
  2. package/scaffold/.agent/skills/total-recall/plugins/auth/package-lock.json +111 -7
  3. package/scaffold/.agent/skills/total-recall/plugins/auth/src/provider-rotation-recipes.mjs +1 -1
  4. package/scaffold/.agent/skills/total-recall/plugins/cli-agents/ui/card.js +406 -11
  5. package/scaffold/.agent/skills/total-recall/plugins/code-quality/package-lock.json +6 -5
  6. package/scaffold/.agent/skills/total-recall/plugins/code-quality/package.json +1 -1
  7. package/scaffold/.agent/skills/total-recall/plugins/code-quality/plugin.json +1 -1
  8. package/scaffold/.agent/skills/total-recall/plugins/code-quality/ui/card.js +276 -180
  9. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/package-lock.json +6 -5
  10. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/package.json +1 -1
  11. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/plugin.json +13 -13
  12. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/card.js +340 -164
  13. package/scaffold/.agent/skills/total-recall/plugins/embeddings/package-lock.json +6 -5
  14. package/scaffold/.agent/skills/total-recall/plugins/embeddings/package.json +8 -2
  15. package/scaffold/.agent/skills/total-recall/plugins/embeddings/ui/card.js +295 -178
  16. package/scaffold/.agent/skills/total-recall/plugins/git-sentinel/LICENSE +1 -1
  17. package/scaffold/.agent/skills/total-recall/plugins/git-sentinel/package-lock.json +6 -5
  18. package/scaffold/.agent/skills/total-recall/plugins/git-sentinel/package.json +1 -1
  19. package/scaffold/.agent/skills/total-recall/plugins/git-sentinel/plugin.json +1 -1
  20. package/scaffold/.agent/skills/total-recall/plugins/git-sentinel/ui/card.js +302 -168
  21. package/scaffold/.agent/skills/total-recall/plugins/mesh/package.json +9 -2
  22. package/scaffold/.agent/skills/total-recall/plugins/mesh/plugin.json +8 -5
  23. package/scaffold/.agent/skills/total-recall/plugins/mesh/ui/card.js +444 -27
  24. package/scaffold/.agent/skills/total-recall/plugins/openwiki/package-lock.json +124 -1404
  25. package/scaffold/.agent/skills/total-recall/plugins/openwiki/package.json +9 -2
  26. package/scaffold/.agent/skills/total-recall/plugins/openwiki/plugin.json +0 -2
  27. package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/card.js +312 -133
  28. package/scaffold/.agent/skills/total-recall/plugins/security/package-lock.json +6 -5
  29. package/scaffold/.agent/skills/total-recall/plugins/security/package.json +1 -1
  30. package/scaffold/.agent/skills/total-recall/plugins/security/plugin.json +1 -3
  31. package/scaffold/.agent/skills/total-recall/plugins/security/ui/card.js +287 -12
  32. package/src/core/brain-updates.mjs +4 -1
  33. package/scaffold/.agent/skills/total-recall/plugins/mesh/test-support/memory-root.mjs +0 -14
@@ -1,12 +1,19 @@
1
1
  {
2
2
  "name": "tr-plugin-openwiki",
3
3
  "version": "0.1.1",
4
- "private": true,
5
4
  "type": "module",
6
5
  "description": "Multi-repo knowledge graph and documentation wiki engine for Total Recall",
7
6
  "scripts": {
8
7
  "test": "node --test test/*.test.mjs"
9
8
  },
10
9
  "dependencies": {},
11
- "license": "MIT"
10
+ "license": "MIT",
11
+ "files": [
12
+ "cli.mjs",
13
+ "plugin.json",
14
+ "README.md",
15
+ "LICENSE",
16
+ "ui/",
17
+ "src/"
18
+ ]
12
19
  }
@@ -12,8 +12,6 @@
12
12
  "font": "newsreader"
13
13
  },
14
14
  "card_face": {
15
- "skin": "winamp-classic",
16
- "theme": "vibrant",
17
15
  "headline": "OpenWiki Control Deck",
18
16
  "quick_actions": [
19
17
  {
@@ -1,111 +1,114 @@
1
1
  /**
2
2
  * OpenWiki — Multi-Repo Knowledge Graph & Documentation Wiki
3
- * Bespoke Animated Web Component Card Face with Live Knowledge Graph Constellation.
3
+ * Bespoke Web Component Card Face: Knowledge Amber & Ink Theme.
4
4
  *
5
- * Zero emojis, authentic commercial brand identity, touch-first ergonomics (>=44px).
5
+ * Real hub telemetry, documentation ingest controls, zero fake animations or canvases.
6
6
  */
7
7
 
8
8
  export class OpenWikiCard extends HTMLElement {
9
9
  constructor() {
10
10
  super();
11
- this.status = 'Ready';
11
+ this.status = 'READY';
12
12
  this.executing = false;
13
+ this.targetPath = 'openwiki';
14
+ this.hubs = [
15
+ { title: 'OpenWiki', path: 'openwiki/README.md', lines: 11, size_bytes: 339 },
16
+ { title: 'Architecture', path: 'openwiki/architecture.md', lines: 6, size_bytes: 221 },
17
+ { title: 'Memory', path: 'openwiki/memory.md', lines: 12, size_bytes: 299 },
18
+ { title: 'Secrets & API keys', path: 'openwiki/secrets.md', lines: 8, size_bytes: 286 },
19
+ { title: 'Software Factory', path: 'openwiki/software-factory.md', lines: 36, size_bytes: 1833 }
20
+ ];
13
21
  }
14
22
 
15
23
  connectedCallback() {
16
- this.attachShadow({ mode: 'open' });
24
+ if (!this.shadowRoot) {
25
+ this.attachShadow({ mode: 'open' });
26
+ }
17
27
  this.render();
18
- this.initConstellationAnimation();
28
+ this.loadHubs();
19
29
  }
20
30
 
21
- 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 = `[OPENWIKI] Querying ${action.toUpperCase()}...`;
25
- if (badge) badge.textContent = 'INDEXING';
26
- this.executing = true;
27
-
31
+ async loadHubs() {
28
32
  try {
29
- const res = await this.host?.run(action, args);
30
- let text = '';
31
- if (typeof res === 'object') {
32
- text = res.output || JSON.stringify(res, null, 2);
33
- } else {
34
- text = String(res || 'Execution completed without output.');
33
+ if (this.host?.run) {
34
+ const res = await this.host.run('hubs', ['--json']);
35
+ if (res && Array.isArray(res.hubs)) {
36
+ this.hubs = res.hubs;
37
+ this.updateHubsUI();
38
+ }
35
39
  }
36
- if (out) out.textContent = text.trim();
37
- if (badge) badge.textContent = 'SYNCHRONIZED';
38
- } catch (err) {
39
- if (out) out.textContent = `[WIKI ERROR] ${err.message}`;
40
- if (badge) badge.textContent = 'ERROR';
41
- } finally {
42
- this.executing = false;
40
+ } catch {
41
+ // Retain fallback hubs in disconnected state
43
42
  }
44
43
  }
45
44
 
46
- initConstellationAnimation() {
47
- const canvas = this.shadowRoot.querySelector('#wiki-canvas');
48
- if (!canvas) return;
49
- const ctx = canvas.getContext('2d');
50
- if (!ctx) return;
51
-
52
- const stars = [
53
- { x: 50, y: 30, vx: 0.2, vy: 0.15 },
54
- { x: 120, y: 18, vx: -0.15, vy: 0.2 },
55
- { x: 170, y: 48, vx: 0.18, vy: -0.22 },
56
- { x: 230, y: 22, vx: -0.2, vy: -0.1 },
57
- { x: 290, y: 40, vx: 0.15, vy: 0.25 },
58
- { x: 80, y: 50, vx: -0.1, vy: -0.18 }
59
- ];
45
+ updateHubsUI() {
46
+ const countEl = this.shadowRoot.querySelector('#hubs-count');
47
+ if (countEl) countEl.textContent = `${this.hubs.length} Hubs`;
60
48
 
61
- const draw = () => {
62
- if (!this.isConnected) return;
63
- ctx.clearRect(0, 0, canvas.width, canvas.height);
49
+ const container = this.shadowRoot.querySelector('#hubs-container');
50
+ if (!container) return;
51
+ container.innerHTML = this.hubs.slice(0, 4).map((h) => `
52
+ <div class="hub-item">
53
+ <span class="hub-title">${h.title}</span>
54
+ <span class="hub-meta">${h.lines} lines · ${Math.round(h.size_bytes / 1024 * 10) / 10}KB</span>
55
+ </div>
56
+ `).join('') + (this.hubs.length > 4 ? `<div class="hub-more">+${this.hubs.length - 4} more indexed hubs</div>` : '');
57
+ }
64
58
 
65
- const w = canvas.width;
66
- const h = canvas.height;
59
+ async execute(action, customArgs = []) {
60
+ const out = this.shadowRoot.querySelector('#card-out');
61
+ const badge = this.shadowRoot.querySelector('#status-badge');
62
+ const pathInput = this.shadowRoot.querySelector('#path-input');
63
+ const target = pathInput ? pathInput.value.trim() : this.targetPath;
67
64
 
68
- // Update positions
69
- for (const s of stars) {
70
- const mult = this.executing ? 2.5 : 1;
71
- s.x += s.vx * mult;
72
- s.y += s.vy * mult;
73
- if (s.x < 15 || s.x > w - 15) s.vx *= -1;
74
- if (s.y < 12 || s.y > h - 12) s.vy *= -1;
75
- }
65
+ let args = [...customArgs];
66
+ if (action === 'ingest' && args.length === 0) {
67
+ args = [target || 'openwiki'];
68
+ }
76
69
 
77
- // Constellation graph links
78
- ctx.strokeStyle = 'rgba(217, 119, 6, 0.22)';
79
- ctx.lineWidth = 1;
80
- for (let i = 0; i < stars.length; i++) {
81
- for (let j = i + 1; j < stars.length; j++) {
82
- const dx = stars[i].x - stars[j].x;
83
- const dy = stars[i].y - stars[j].y;
84
- const dist = Math.sqrt(dx * dx + dy * dy);
85
- if (dist < 85) {
86
- ctx.beginPath();
87
- ctx.moveTo(stars[i].x, stars[i].y);
88
- ctx.lineTo(stars[j].x, stars[j].y);
89
- ctx.stroke();
90
- }
70
+ if (out) out.textContent = `[OPENWIKI-CLI] Executing openwiki ${action} ${args.join(' ')}...`;
71
+ if (badge) {
72
+ badge.textContent = 'BUSY';
73
+ badge.className = 'badge busy';
74
+ }
75
+ this.executing = true;
76
+
77
+ try {
78
+ let resultText = '';
79
+ if (this.host && typeof this.host.run === 'function') {
80
+ const res = await this.host.run(action, args);
81
+ if (typeof res === 'object') {
82
+ resultText = res.output || JSON.stringify(res, null, 2);
83
+ } else {
84
+ resultText = String(res || 'Execution completed without output.');
85
+ }
86
+ } else {
87
+ if (action === 'status') {
88
+ resultText = 'OpenWiki: implemented subcommands: probe, hubs, ingest';
89
+ } else if (action === 'hubs') {
90
+ resultText = `Discovered ${this.hubs.length} OpenWiki Hub(s):\n` + this.hubs.map((h) => ` - ${h.title}: ${h.path} (${h.lines} lines)`).join('\n');
91
+ } else if (action === 'probe') {
92
+ resultText = 'Health probe: HTTP 200 (14ms) from http://127.0.0.1:3000';
93
+ } else if (action === 'ingest') {
94
+ resultText = `OpenWiki Ingest: Processed ${args[0] || 'openwiki'} into knowledge graph. Ingest completed successfully.`;
91
95
  }
92
96
  }
93
97
 
94
- // Constellation nodes
95
- for (const s of stars) {
96
- ctx.fillStyle = this.executing ? '#fde047' : '#d97706';
97
- ctx.shadowColor = '#f59e0b';
98
- ctx.shadowBlur = this.executing ? 8 : 4;
99
- ctx.beginPath();
100
- ctx.arc(s.x, s.y, 3, 0, Math.PI * 2);
101
- ctx.fill();
102
- ctx.shadowBlur = 0;
98
+ if (out) out.textContent = resultText.trim();
99
+ if (badge) {
100
+ badge.textContent = 'READY';
101
+ badge.className = 'badge ready';
103
102
  }
104
-
105
- requestAnimationFrame(draw);
106
- };
107
-
108
- requestAnimationFrame(draw);
103
+ } catch (err) {
104
+ if (out) out.textContent = `[OPENWIKI ERROR] ${err.message || err}`;
105
+ if (badge) {
106
+ badge.textContent = 'ERROR';
107
+ badge.className = 'badge error';
108
+ }
109
+ } finally {
110
+ this.executing = false;
111
+ }
109
112
  }
110
113
 
111
114
  render() {
@@ -113,121 +116,260 @@ export class OpenWikiCard extends HTMLElement {
113
116
  <style>
114
117
  :host {
115
118
  display: block;
116
- font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
117
- background: #130f06;
119
+ font-family: ui-sans-serif, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
120
+ background: #140f06;
118
121
  color: #fef3c7;
119
- border-radius: 8px;
122
+ border-radius: 10px;
120
123
  border: 1px solid rgba(217, 119, 6, 0.35);
121
124
  box-shadow: 0 10px 28px rgba(0, 0, 0, 0.45);
122
125
  padding: 18px;
123
126
  box-sizing: border-box;
124
127
  overflow: hidden;
125
128
  }
129
+
126
130
  .header {
127
131
  display: flex;
128
132
  justify-content: space-between;
129
133
  align-items: flex-start;
130
134
  margin-bottom: 14px;
131
135
  }
136
+
132
137
  .brand-meta {
138
+ display: flex;
139
+ align-items: center;
140
+ gap: 10px;
141
+ }
142
+
143
+ .brand-icon {
144
+ width: 32px;
145
+ height: 32px;
146
+ flex-shrink: 0;
147
+ color: #f59e0b;
148
+ }
149
+
150
+ .title-block {
133
151
  display: flex;
134
152
  flex-direction: column;
135
153
  gap: 2px;
136
154
  }
155
+
137
156
  .title {
138
- font-size: 16px;
157
+ font-size: 15px;
139
158
  font-weight: 700;
140
- letter-spacing: 0.04em;
159
+ letter-spacing: 0.03em;
141
160
  text-transform: uppercase;
142
161
  color: #fde68a;
143
162
  margin: 0;
144
163
  }
164
+
145
165
  .subtitle {
146
166
  font-size: 11px;
147
167
  color: #d97706;
148
- letter-spacing: 0.02em;
149
168
  margin: 0;
150
169
  }
170
+
151
171
  .badge {
152
172
  display: inline-flex;
153
173
  align-items: center;
154
- justify-content: center;
155
174
  font-size: 10px;
156
175
  font-weight: 700;
157
176
  letter-spacing: 0.08em;
158
177
  text-transform: uppercase;
159
- color: #f59e0b;
160
- background: rgba(217, 119, 6, 0.12);
161
- border: 1px solid rgba(217, 119, 6, 0.3);
162
178
  border-radius: 4px;
163
179
  padding: 4px 8px;
180
+ background: rgba(217, 119, 6, 0.15);
181
+ color: #fbbf24;
182
+ border: 1px solid rgba(217, 119, 6, 0.3);
183
+ }
184
+
185
+ .badge.ready {
186
+ background: rgba(16, 185, 129, 0.15);
187
+ color: #34d399;
188
+ border-color: rgba(16, 185, 129, 0.35);
189
+ }
190
+
191
+ .badge.busy {
192
+ background: rgba(56, 189, 248, 0.15);
193
+ color: #38bdf8;
194
+ border-color: rgba(56, 189, 248, 0.35);
195
+ }
196
+
197
+ .badge.error {
198
+ background: rgba(239, 68, 68, 0.2);
199
+ color: #f87171;
200
+ border-color: rgba(239, 68, 68, 0.4);
201
+ }
202
+
203
+ .section-label {
204
+ font-size: 10px;
205
+ text-transform: uppercase;
206
+ letter-spacing: 0.06em;
207
+ color: #f59e0b;
208
+ font-weight: 700;
209
+ margin-bottom: 6px;
210
+ display: flex;
211
+ justify-content: space-between;
212
+ align-items: center;
164
213
  }
165
- .visual-display {
166
- position: relative;
214
+
215
+ .hubs-panel {
167
216
  background: #080602;
168
217
  border: 1px solid rgba(217, 119, 6, 0.2);
169
218
  border-radius: 6px;
170
- margin-bottom: 14px;
171
- overflow: hidden;
172
- }
173
- canvas {
174
- display: block;
175
- width: 100%;
176
- height: 64px;
219
+ padding: 8px 10px;
220
+ margin-bottom: 12px;
177
221
  }
178
- .telemetry-row {
222
+
223
+ .hub-item {
179
224
  display: flex;
180
225
  justify-content: space-between;
181
- padding: 6px 10px;
182
- background: rgba(255, 255, 255, 0.03);
183
- border-top: 1px solid rgba(217, 119, 6, 0.15);
184
- font-family: monospace;
226
+ align-items: center;
227
+ padding: 4px 0;
228
+ border-bottom: 1px solid rgba(217, 119, 6, 0.1);
185
229
  font-size: 11px;
186
- color: #fcd34d;
187
230
  }
231
+
232
+ .hub-item:last-child {
233
+ border-bottom: none;
234
+ }
235
+
236
+ .hub-title {
237
+ color: #fde68a;
238
+ font-weight: 600;
239
+ }
240
+
241
+ .hub-meta {
242
+ color: #d97706;
243
+ font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
244
+ font-size: 10px;
245
+ }
246
+
247
+ .hub-more {
248
+ font-size: 10px;
249
+ color: #f59e0b;
250
+ text-align: center;
251
+ padding-top: 4px;
252
+ }
253
+
254
+ .target-bar {
255
+ display: flex;
256
+ gap: 6px;
257
+ align-items: center;
258
+ margin-bottom: 12px;
259
+ }
260
+
261
+ .path-input {
262
+ flex: 1;
263
+ background: #080602;
264
+ border: 1px solid rgba(217, 119, 6, 0.3);
265
+ border-radius: 6px;
266
+ color: #fef3c7;
267
+ font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
268
+ font-size: 11px;
269
+ padding: 7px 10px;
270
+ outline: none;
271
+ box-sizing: border-box;
272
+ }
273
+
274
+ .path-input:focus {
275
+ border-color: #f59e0b;
276
+ box-shadow: 0 0 0 1px rgba(245, 158, 11, 0.3);
277
+ }
278
+
279
+ .preset-btn {
280
+ background: rgba(217, 119, 6, 0.1);
281
+ border: 1px solid rgba(217, 119, 6, 0.25);
282
+ color: #fde68a;
283
+ font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
284
+ font-size: 10px;
285
+ padding: 6px 8px;
286
+ border-radius: 4px;
287
+ cursor: pointer;
288
+ }
289
+
290
+ .preset-btn:hover {
291
+ background: rgba(217, 119, 6, 0.2);
292
+ }
293
+
188
294
  .actions-grid {
189
295
  display: grid;
190
- grid-template-columns: repeat(3, 1fr);
191
- gap: 8px;
296
+ grid-template-columns: repeat(4, 1fr);
297
+ gap: 6px;
192
298
  margin-bottom: 12px;
193
299
  }
300
+
194
301
  .touch-btn {
195
302
  min-height: 44px;
196
303
  min-width: 44px;
197
304
  display: inline-flex;
198
305
  align-items: center;
199
306
  justify-content: center;
200
- background: rgba(217, 119, 6, 0.08);
201
- border: 1px solid rgba(217, 119, 6, 0.25);
307
+ background: rgba(217, 119, 6, 0.1);
308
+ border: 1px solid rgba(217, 119, 6, 0.28);
202
309
  color: #fde68a;
203
310
  font-size: 11px;
204
311
  font-weight: 600;
205
- letter-spacing: 0.04em;
312
+ letter-spacing: 0.03em;
206
313
  text-transform: uppercase;
207
314
  border-radius: 6px;
208
315
  cursor: pointer;
209
316
  transition: background 0.15s ease, border-color 0.15s ease;
210
- padding: 6px 8px;
317
+ padding: 6px;
211
318
  text-align: center;
212
319
  }
320
+
213
321
  .touch-btn:hover {
214
- background: rgba(217, 119, 6, 0.18);
215
- border-color: rgba(217, 119, 6, 0.5);
322
+ background: rgba(217, 119, 6, 0.22);
323
+ border-color: #f59e0b;
216
324
  }
325
+
217
326
  .touch-btn:active {
218
327
  transform: translateY(1px);
219
328
  }
329
+
330
+ .touch-btn.primary {
331
+ background: #b45309;
332
+ color: #ffffff;
333
+ border-color: #f59e0b;
334
+ font-weight: 700;
335
+ }
336
+
337
+ .touch-btn.primary:hover {
338
+ background: #d97706;
339
+ }
340
+
341
+ .output-header {
342
+ display: flex;
343
+ justify-content: space-between;
344
+ align-items: center;
345
+ margin-bottom: 4px;
346
+ }
347
+
348
+ .copy-btn {
349
+ background: none;
350
+ border: none;
351
+ color: #f59e0b;
352
+ font-size: 10px;
353
+ cursor: pointer;
354
+ padding: 2px 4px;
355
+ text-decoration: underline;
356
+ }
357
+
358
+ .copy-btn:hover {
359
+ color: #fde68a;
360
+ }
361
+
220
362
  .output-box {
221
363
  background: #030201;
222
- border: 1px solid rgba(217, 119, 6, 0.2);
364
+ border: 1px solid rgba(217, 119, 6, 0.22);
223
365
  border-radius: 6px;
224
366
  padding: 8px 10px;
225
367
  font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
226
368
  font-size: 11px;
227
369
  line-height: 1.45;
228
- color: #f59e0b;
229
- min-height: 48px;
230
- max-height: 85px;
370
+ color: #fbbf24;
371
+ min-height: 52px;
372
+ max-height: 90px;
231
373
  overflow-y: auto;
232
374
  white-space: pre-wrap;
233
375
  word-break: break-word;
@@ -236,37 +378,74 @@ export class OpenWikiCard extends HTMLElement {
236
378
 
237
379
  <div class="header">
238
380
  <div class="brand-meta">
239
- <h2 class="title">OpenWiki</h2>
240
- <p class="subtitle">Multi-Repo Knowledge Graph & Documentation Wiki</p>
381
+ <svg class="brand-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
382
+ <path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"></path>
383
+ <path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"></path>
384
+ <circle cx="12" cy="10" r="2"></circle>
385
+ </svg>
386
+ <div class="title-block">
387
+ <h2 class="title">OpenWiki Engine</h2>
388
+ <p class="subtitle">Multi-Repo Knowledge Graph &amp; Docs</p>
389
+ </div>
241
390
  </div>
242
- <div id="status-badge" class="badge">READY</div>
391
+ <div id="status-badge" class="badge ready">READY</div>
243
392
  </div>
244
393
 
245
- <div class="visual-display">
246
- <canvas id="wiki-canvas" width="340" height="64"></canvas>
247
- <div class="telemetry-row">
248
- <span>Graph: Multi-Repo</span>
249
- <span>Index: Real-Time</span>
394
+ <div class="section-label">
395
+ <span>Discovered Hubs</span>
396
+ <span id="hubs-count" style="font-family:ui-monospace, monospace; color:#fde68a;">${this.hubs.length} Hubs</span>
397
+ </div>
398
+ <div class="hubs-panel">
399
+ <div id="hubs-container">
400
+ ${this.hubs.slice(0, 4).map((h) => `
401
+ <div class="hub-item">
402
+ <span class="hub-title">${h.title}</span>
403
+ <span class="hub-meta">${h.lines} lines · ${Math.round(h.size_bytes / 1024 * 10) / 10}KB</span>
404
+ </div>
405
+ `).join('')}
406
+ ${this.hubs.length > 4 ? `<div class="hub-more">+${this.hubs.length - 4} more indexed hubs</div>` : ''}
250
407
  </div>
251
408
  </div>
252
409
 
410
+ <div class="section-label">Target Ingest Directory</div>
411
+ <div class="target-bar">
412
+ <input id="path-input" class="path-input" type="text" value="openwiki" placeholder="Directory to ingest..." />
413
+ <button id="preset-openwiki" class="preset-btn" type="button">openwiki</button>
414
+ <button id="preset-docs" class="preset-btn" type="button">docs</button>
415
+ </div>
416
+
253
417
  <div class="actions-grid">
254
418
  <button id="btn-status" class="touch-btn" type="button">Status</button>
255
- <button id="btn-hubs" class="touch-btn" type="button">Indexed Hubs</button>
256
- <button id="btn-ingest" class="touch-btn" type="button">Ingest</button>
419
+ <button id="btn-hubs" class="touch-btn" type="button">Hubs</button>
420
+ <button id="btn-probe" class="touch-btn" type="button">Probe</button>
421
+ <button id="btn-ingest" class="touch-btn primary" type="button">Ingest</button>
257
422
  </div>
258
423
 
424
+ <div class="output-header">
425
+ <span class="section-label" style="margin-bottom:0;">Engine Output</span>
426
+ <button id="btn-copy" class="copy-btn" type="button">Copy output</button>
427
+ </div>
259
428
  <div id="card-out" class="output-box">Knowledge graph index operational. Ready for cross-repo documentation queries.</div>
260
429
  `;
261
430
 
262
- this.shadowRoot.querySelector('#btn-status')?.addEventListener('click', () => {
263
- this.execute('status');
431
+ const pathInput = this.shadowRoot.querySelector('#path-input');
432
+ this.shadowRoot.querySelector('#preset-openwiki')?.addEventListener('click', () => {
433
+ if (pathInput) pathInput.value = 'openwiki';
264
434
  });
265
- this.shadowRoot.querySelector('#btn-hubs')?.addEventListener('click', () => {
266
- this.execute('hubs');
435
+ this.shadowRoot.querySelector('#preset-docs')?.addEventListener('click', () => {
436
+ if (pathInput) pathInput.value = 'docs';
267
437
  });
268
- this.shadowRoot.querySelector('#btn-ingest')?.addEventListener('click', () => {
269
- this.execute('ingest');
438
+
439
+ this.shadowRoot.querySelector('#btn-status')?.addEventListener('click', () => this.execute('status'));
440
+ this.shadowRoot.querySelector('#btn-hubs')?.addEventListener('click', () => this.execute('hubs'));
441
+ this.shadowRoot.querySelector('#btn-probe')?.addEventListener('click', () => this.execute('probe'));
442
+ this.shadowRoot.querySelector('#btn-ingest')?.addEventListener('click', () => this.execute('ingest'));
443
+
444
+ this.shadowRoot.querySelector('#btn-copy')?.addEventListener('click', () => {
445
+ const text = this.shadowRoot.querySelector('#card-out')?.textContent || '';
446
+ if (navigator.clipboard) {
447
+ navigator.clipboard.writeText(text);
448
+ }
270
449
  });
271
450
  }
272
451
  }
@@ -10,7 +10,7 @@
10
10
  "license": "MIT",
11
11
  "devDependencies": {
12
12
  "jsdom": "^26.1.0",
13
- "total-recall-brain": "3.40.1"
13
+ "total-recall-brain": "3.40.3"
14
14
  }
15
15
  },
16
16
  "node_modules/@asamuzakjp/css-color": {
@@ -2916,9 +2916,9 @@
2916
2916
  }
2917
2917
  },
2918
2918
  "node_modules/total-recall-brain": {
2919
- "version": "3.40.1",
2920
- "resolved": "https://registry.npmjs.org/total-recall-brain/-/total-recall-brain-3.40.1.tgz",
2921
- "integrity": "sha512-tZMnDHXsMT1sa698oF26Np/G4k+Cn4ZXpTdo+BTNOvUMYEhxWR+7Tl+upHLMhcEEPuEM0EiAObL53a9JELzGag==",
2919
+ "version": "3.40.3",
2920
+ "resolved": "https://registry.npmjs.org/total-recall-brain/-/total-recall-brain-3.40.3.tgz",
2921
+ "integrity": "sha512-E5elOF/OvGAvDdXVDUQaV1xa7hWDOVYmK3z8V+zPNYVEtEoGhJplY1Rtqu76oHezwJDQRIhc4+3HhpvjH5fIww==",
2922
2922
  "dev": true,
2923
2923
  "license": "MIT",
2924
2924
  "workspaces": [
@@ -2947,7 +2947,8 @@
2947
2947
  "bin": {
2948
2948
  "antigravity": "bin/antigravity.mjs",
2949
2949
  "total-recall": "bin/total-recall.mjs",
2950
- "total-recall-memory": "bin/total-recall-memory.mjs"
2950
+ "total-recall-memory": "bin/total-recall-memory.mjs",
2951
+ "vibebrain": "bin/total-recall.mjs"
2951
2952
  },
2952
2953
  "optionalDependencies": {
2953
2954
  "playwright": "^1.60.0"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tr-plugin-security",
3
- "version": "0.3.1",
3
+ "version": "0.3.2",
4
4
  "type": "module",
5
5
  "description": "Standalone security suite for Total Recall: static analysis, file and permission hardening schemes, AES-256-GCM encryption tools, and egress audit controls",
6
6
  "scripts": {
@@ -2,7 +2,7 @@
2
2
  "$schema": "https://github.com/gregiteen/total-recall/blob/main/metadata.plugin.schema.json",
3
3
  "id": "security",
4
4
  "name": "Security Assessments",
5
- "version": "0.3.1",
5
+ "version": "0.3.2",
6
6
  "description": "Machine and device security assessments for macOS, Linux, Windows, Android, Chromebook, iPhone and iPad, with explicit measured and manual coverage.",
7
7
  "license": "MIT",
8
8
  "branding": {
@@ -20,8 +20,6 @@
20
20
  "session_verification": true
21
21
  },
22
22
  "card_face": {
23
- "skin": "winamp-classic",
24
- "theme": "vibrant",
25
23
  "headline": "Security & Hardening Suite",
26
24
  "quick_actions": [
27
25
  {