total-recall-brain 3.41.2 → 3.41.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 (128) hide show
  1. package/bin/total-recall.mjs +19 -4
  2. package/frontend/dist/assets/{index-BG9NkVUy.css → index-BIQmqDKP.css} +1 -1
  3. package/frontend/dist/assets/{index-BtuiZqwP.js → index-CRzjQLu7.js} +7 -7
  4. package/frontend/dist/index.html +2 -2
  5. package/frontend/dist/sw.js +8 -5
  6. package/frontend/src/api/auth.ts +0 -3
  7. package/frontend/src/components/plugins/PluginPanel.tsx +7 -3
  8. package/frontend/src/components/plugins/card/CardEngine.tsx +1 -1
  9. package/frontend/src/pages/LoginPage.tsx +1 -41
  10. package/frontend/src/pages/PluginsPage.tsx +14 -7
  11. package/package.json +7 -5
  12. package/scaffold/.agent/skills/plugin/scripts/record.mjs +6 -3
  13. package/scaffold/.agent/skills/total-recall/plugins/auth/cli.mjs +197 -31
  14. package/scaffold/.agent/skills/total-recall/plugins/auth/package-lock.json +6 -6
  15. package/scaffold/.agent/skills/total-recall/plugins/auth/package.json +1 -1
  16. package/scaffold/.agent/skills/total-recall/plugins/auth/plugin.json +8 -1
  17. package/scaffold/.agent/skills/total-recall/plugins/auth/src/cli-secret.mjs +48 -0
  18. package/scaffold/.agent/skills/total-recall/plugins/auth/src/login-projections.mjs +42 -0
  19. package/scaffold/.agent/skills/total-recall/plugins/auth/src/mesh-secrets.mjs +18 -0
  20. package/scaffold/.agent/skills/total-recall/plugins/auth/src/routes/secrets.mjs +5 -2
  21. package/scaffold/.agent/skills/total-recall/plugins/auth/src/secrets-carriers.mjs +76 -0
  22. package/scaffold/.agent/skills/total-recall/plugins/auth/src/secrets-prune.mjs +37 -0
  23. package/scaffold/.agent/skills/total-recall/plugins/auth/src/secrets-sync.mjs +53 -17
  24. package/scaffold/.agent/skills/total-recall/plugins/auth/ui/DESIGN.md +56 -8
  25. package/scaffold/.agent/skills/total-recall/plugins/auth/ui/card.js +1068 -204
  26. package/scaffold/.agent/skills/total-recall/plugins/auth/ui/panel.js +4 -2
  27. package/scaffold/.agent/skills/total-recall/plugins/cli-agents/ui/DESIGN.md +32 -0
  28. package/scaffold/.agent/skills/total-recall/plugins/cli-agents/ui/card.js +436 -274
  29. package/scaffold/.agent/skills/total-recall/plugins/code-quality/package-lock.json +12 -12
  30. package/scaffold/.agent/skills/total-recall/plugins/code-quality/package.json +1 -1
  31. package/scaffold/.agent/skills/total-recall/plugins/code-quality/ui/DESIGN.md +16 -2
  32. package/scaffold/.agent/skills/total-recall/plugins/code-quality/ui/card.js +461 -242
  33. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/package-lock.json +12 -12
  34. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/package.json +1 -1
  35. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/plugin.json +1 -7
  36. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/DESIGN.md +17 -2
  37. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/card.js +426 -300
  38. package/scaffold/.agent/skills/total-recall/plugins/embeddings/package-lock.json +23 -8
  39. package/scaffold/.agent/skills/total-recall/plugins/embeddings/package.json +6 -2
  40. package/scaffold/.agent/skills/total-recall/plugins/embeddings/ui/DESIGN.md +32 -0
  41. package/scaffold/.agent/skills/total-recall/plugins/embeddings/ui/card.js +350 -283
  42. package/scaffold/.agent/skills/total-recall/plugins/git-sentinel/package-lock.json +23 -8
  43. package/scaffold/.agent/skills/total-recall/plugins/git-sentinel/package.json +5 -1
  44. package/scaffold/.agent/skills/total-recall/plugins/git-sentinel/ui/card.js +31 -19
  45. package/scaffold/.agent/skills/total-recall/plugins/mesh/package-lock.json +23 -10
  46. package/scaffold/.agent/skills/total-recall/plugins/mesh/package.json +5 -3
  47. package/scaffold/.agent/skills/total-recall/plugins/mesh/plugin.json +1 -1
  48. package/scaffold/.agent/skills/total-recall/plugins/mesh/src/cli/grants.mjs +7 -3
  49. package/scaffold/.agent/skills/total-recall/plugins/mesh/src/cli/mesh.mjs +61 -38
  50. package/scaffold/.agent/skills/total-recall/plugins/mesh/src/core/leader-election.mjs +57 -2
  51. package/scaffold/.agent/skills/total-recall/plugins/mesh/src/core/mesh.mjs +220 -36
  52. package/scaffold/.agent/skills/total-recall/plugins/mesh/src/server/routes/mesh.mjs +7 -2
  53. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/README.md +65 -0
  54. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/capability/BRICK.md +59 -0
  55. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/capability/index.mjs +534 -0
  56. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/cli.mjs +139 -0
  57. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/package-lock.json +2849 -0
  58. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/package.json +26 -0
  59. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/plugin.json +376 -0
  60. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/skills/meta-harness/SKILL.md +37 -0
  61. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/adapters/dsh.mjs +446 -0
  62. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/alerts.mjs +23 -0
  63. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/coordinator.mjs +398 -0
  64. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/documentation.mjs +152 -0
  65. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/executor.mjs +82 -0
  66. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/learner.mjs +90 -0
  67. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/router.mjs +415 -0
  68. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/runtime.mjs +36 -0
  69. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/setup.mjs +35 -0
  70. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/tracker.mjs +133 -0
  71. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/worker.mjs +233 -0
  72. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/DESIGN.md +32 -0
  73. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/card.js +845 -0
  74. package/scaffold/.agent/skills/total-recall/plugins/openwiki/capability/BRICK.md +64 -0
  75. package/scaffold/.agent/skills/total-recall/plugins/openwiki/capability/index.mjs +250 -0
  76. package/scaffold/.agent/skills/total-recall/plugins/openwiki/cli.mjs +344 -14
  77. package/scaffold/.agent/skills/total-recall/plugins/openwiki/package-lock.json +2917 -140
  78. package/scaffold/.agent/skills/total-recall/plugins/openwiki/package.json +9 -3
  79. package/scaffold/.agent/skills/total-recall/plugins/openwiki/plugin.json +223 -5
  80. package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/config.mjs +129 -0
  81. package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/refresh.mjs +355 -0
  82. package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/upstream-watcher.mjs +375 -0
  83. package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/DESIGN.md +37 -10
  84. package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/card.js +986 -280
  85. package/scaffold/.agent/skills/total-recall/plugins/security/cli.mjs +7 -1
  86. package/scaffold/.agent/skills/total-recall/plugins/security/package-lock.json +25 -10
  87. package/scaffold/.agent/skills/total-recall/plugins/security/package.json +6 -2
  88. package/scaffold/.agent/skills/total-recall/plugins/security/plugin.json +1 -1
  89. package/scaffold/.agent/skills/total-recall/plugins/security/src/scanner.mjs +17 -3
  90. package/scaffold/.agent/skills/total-recall/plugins/security/ui/DESIGN.md +38 -15
  91. package/scaffold/.agent/skills/total-recall/plugins/security/ui/card.js +60 -34
  92. package/src/cli/command.mjs +23 -18
  93. package/src/cli/config.mjs +3 -0
  94. package/src/cli/connect.mjs +12 -116
  95. package/src/cli/daemon.mjs +23 -1
  96. package/src/cli/harness.mjs +0 -1
  97. package/src/cli/plugin/copies.mjs +8 -5
  98. package/src/cli/plugin/create.mjs +56 -3
  99. package/src/cli/plugin/index.mjs +40 -5
  100. package/src/cli/plugin/monetization.mjs +232 -12
  101. package/src/cli/preflight.mjs +161 -0
  102. package/src/cli/rebuild.mjs +22 -0
  103. package/src/cli/reset-password.mjs +3 -2
  104. package/src/cli/skill.mjs +8 -2
  105. package/src/cli/status.mjs +25 -7
  106. package/src/core/automatic-brain-updates.mjs +9 -3
  107. package/src/core/brain-updates.mjs +63 -5
  108. package/src/core/cli-commands.mjs +2 -0
  109. package/src/core/context-compiler.mjs +8 -1
  110. package/src/core/default-plugins.mjs +1 -1
  111. package/src/core/global-brain-updates.mjs +21 -1
  112. package/src/core/mesh-brain-updates.mjs +5 -2
  113. package/src/core/meta-harness.mjs +32 -79
  114. package/src/core/plugin-dependencies.mjs +6 -1
  115. package/src/core/plugin-runner.mjs +6 -1
  116. package/src/core/plugin-store.mjs +67 -1
  117. package/src/core/plugin-updates.mjs +1 -1
  118. package/src/core/portable-skills-maintenance.mjs +19 -0
  119. package/src/core/preflight-gate.mjs +77 -0
  120. package/src/core/preflight-receipt.mjs +123 -0
  121. package/src/core/required-plugins.mjs +7 -0
  122. package/src/core/runtime.mjs +0 -3
  123. package/src/core/skills-registry.mjs +33 -3
  124. package/src/core/surface.mjs +38 -1
  125. package/src/server/auth.mjs +41 -1
  126. package/src/server/memory-app.mjs +2 -1
  127. package/src/server/routes/auth.mjs +25 -1
  128. package/src/server/routes/plugins.mjs +17 -4
@@ -1,411 +1,478 @@
1
1
  /**
2
- * Embeddings — Local Vector Space & Vault Semantic Coverage Engine
3
- * Purpose-built domain interface: queries vector engine and vault coverage on mount,
4
- * exposes benchmark runner, model weight downloads, and vector dimensions.
2
+ * Vector Space — On-Device Semantic Coverage & Vector Engine Console
5
3
  *
6
- * Adheres strictly to invariant: Never delete embeddings.db during rebuild.
7
- * Zero emojis, authentic commercial brand identity, touch-first ergonomics (>=44px).
4
+ * Bespoke operator interface for local vector embeddings and vault coverage.
5
+ * Displays real-time circular SVG coverage gauge, local model roster, vector
6
+ * dimensions, and benchmark latency meters with zero template wrappers or terminal dumps.
8
7
  */
9
8
 
9
+ const DASH = '\u2014';
10
+
11
+ function escapeHtml(str) {
12
+ if (str === null || str === undefined) return '';
13
+ return String(str).replace(/[&<>"']/g, c => ({
14
+ '&': '&amp;',
15
+ '<': '&lt;',
16
+ '>': '&gt;',
17
+ '"': '&quot;',
18
+ "'": '&#39;'
19
+ }[c]));
20
+ }
21
+
10
22
  export class EmbeddingsCard extends HTMLElement {
11
23
  constructor() {
12
24
  super();
25
+ this.coverage = null;
26
+ this.models = [];
27
+ this.benchmark = null;
28
+ this.selectedModel = 'nomic-embed-text';
13
29
  this.executing = false;
14
- this.telemetry = {
15
- model: 'nomic-embed-text',
16
- coverage: '98% Embedded',
17
- locality: 'Local (On-Device)'
18
- };
30
+ this.screens = [{ id: 'coverage', label: 'Vector Coverage' }];
31
+ this.screen = 'coverage';
19
32
  }
20
33
 
21
34
  connectedCallback() {
22
- if (!this.shadowRoot) this.attachShadow({ mode: 'open' });
35
+ if (!this.shadowRoot) {
36
+ this.attachShadow({ mode: 'open' });
37
+ }
23
38
  this.render();
24
39
  this.refreshTelemetry();
25
40
  }
26
41
 
27
42
  async refreshTelemetry() {
43
+ if (!this.host) return;
28
44
  try {
29
- const res = await this.host?.run('status', ['--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 {}
45
+ // 1. Fetch coverage
46
+ const covRes = await this.host.run('coverage', ['--json']);
47
+ if (covRes && typeof covRes === 'object') {
48
+ this.coverage = covRes;
49
+ } else if (typeof covRes === 'string' && covRes.trim().startsWith('{')) {
50
+ this.coverage = JSON.parse(covRes);
35
51
  }
36
52
 
37
- if (data) {
38
- const modelName = data.model?.name || data.model || 'nomic-embed-text';
39
- const dims = data.model?.dimensions ? ` (${data.model.dimensions}d)` : ' (768d)';
40
- const cov = data.coverage?.percent != null ? `${data.coverage.percent}% Embedded` : '98% Embedded';
41
- const loc = data.local ? 'Local (On-Device)' : 'Mesh Endpoint';
42
-
43
- this.telemetry = {
44
- model: `${modelName}${dims}`,
45
- coverage: cov,
46
- locality: loc
47
- };
48
- } else {
49
- this.telemetry = {
50
- model: 'nomic-embed-text (768d)',
51
- coverage: '98% Embedded',
52
- locality: 'Local (On-Device)'
53
- };
53
+ // 2. Fetch models
54
+ try {
55
+ const modRes = await this.host.run('models', ['--json']);
56
+ if (Array.isArray(modRes)) this.models = modRes;
57
+ else if (modRes && Array.isArray(modRes.models)) this.models = modRes.models;
58
+ } catch {
59
+ this.models = [];
54
60
  }
55
- this.updateView();
61
+
62
+ this.render();
56
63
  } catch {
57
- this.telemetry = {
58
- model: 'nomic-embed-text',
59
- coverage: 'Vector Index Active',
60
- locality: 'Local Endpoint'
61
- };
62
- this.updateView();
64
+ this.coverage = null;
65
+ this.render();
63
66
  }
64
67
  }
65
68
 
66
- updateView() {
67
- const root = this.shadowRoot;
68
- if (!root) return;
69
-
70
- const modEl = root.querySelector('#stat-model');
71
- const covEl = root.querySelector('#stat-coverage');
72
- const locEl = root.querySelector('#stat-locality');
73
- if (modEl) modEl.textContent = this.telemetry.model;
74
- if (covEl) covEl.textContent = this.telemetry.coverage;
75
- if (locEl) locEl.textContent = this.telemetry.locality;
76
- }
77
-
78
- async execute(action, args = []) {
79
- const out = this.shadowRoot?.querySelector('#card-out');
80
- const statusPill = this.shadowRoot?.querySelector('#status-pill');
81
- const actionLabel = action.toUpperCase();
82
-
83
- if (out) out.textContent = `[EMBEDDINGS ENGINE] Running ${actionLabel} ${args.join(' ')}...`;
84
- if (statusPill) statusPill.textContent = 'RUNNING';
69
+ async runBenchmark() {
70
+ if (!this.host || this.executing) return;
85
71
  this.executing = true;
86
-
72
+ this.render();
87
73
  try {
88
- const res = await this.host?.run(action, args);
89
- let text = '';
90
- if (typeof res === 'object') {
91
- text = res.output || JSON.stringify(res, null, 2);
92
- } else {
93
- text = String(res || 'Operation completed without output.');
74
+ const res = await this.host.run('benchmark', ['--json']);
75
+ if (res && typeof res === 'object') {
76
+ this.benchmark = res;
77
+ } else if (typeof res === 'string' && res.trim().startsWith('{')) {
78
+ this.benchmark = JSON.parse(res);
94
79
  }
95
- if (out) out.textContent = text.trim();
96
- if (statusPill) statusPill.textContent = 'READY';
97
-
98
- if (['status', 'pull', 'coverage'].includes(action)) {
99
- this.refreshTelemetry();
100
- }
101
- } catch (err) {
102
- if (out) out.textContent = `[VECTOR FAULT] ${err.message}`;
103
- if (statusPill) statusPill.textContent = 'ERROR';
80
+ } catch {
81
+ this.benchmark = null;
104
82
  } finally {
105
83
  this.executing = false;
84
+ this.render();
106
85
  }
107
86
  }
108
87
 
109
- copyOutput() {
110
- const out = this.shadowRoot?.querySelector('#card-out');
111
- const copyBtn = this.shadowRoot?.querySelector('#btn-copy');
112
- if (!out) return;
113
-
114
- navigator.clipboard?.writeText(out.textContent || '').then(() => {
115
- if (copyBtn) {
116
- const prev = copyBtn.textContent;
117
- copyBtn.textContent = 'COPIED';
118
- setTimeout(() => { copyBtn.textContent = prev; }, 1600);
119
- }
120
- }).catch(() => {});
121
- }
122
-
123
88
  render() {
124
89
  const root = this.shadowRoot;
125
90
  if (!root) return;
126
91
 
92
+ const cov = this.coverage;
93
+ const rawPct = cov?.percentage !== undefined ? Number(cov.percentage) : null;
94
+ const pct = rawPct !== null && !isNaN(rawPct) ? Math.min(100, Math.max(0, Math.round(rawPct))) : null;
95
+
96
+ // SVG arc stroke dash calculation
97
+ const radius = 38;
98
+ const circumference = 2 * Math.PI * radius;
99
+ const offset = pct !== null ? circumference - (pct / 100) * circumference : circumference;
100
+
101
+ const embeddedNodes = cov?.embeddedNodes !== undefined ? cov.embeddedNodes : (cov?.embedded || DASH);
102
+ const totalNodes = cov?.totalNodes !== undefined ? cov.totalNodes : (cov?.total || DASH);
103
+ const activeModel = cov?.model || this.selectedModel;
104
+ const dimensions = cov?.dimensions || 768;
105
+
127
106
  root.innerHTML = `
128
107
  <style>
129
108
  :host {
109
+ --face-bg: #07171d;
110
+ --face-surface: #0e2a35;
111
+ --face-line: #164e63;
112
+ --face-text: #ecfeff;
113
+ --face-muted: #67e8f9;
114
+ --face-brand: #06b6d4;
115
+ --face-brand-hover: #22d3ee;
116
+ --face-accent: #22d3ee;
117
+ --face-ok: #10b981;
118
+ --face-warn: #f59e0b;
119
+ --face-danger: #ef4444;
120
+ --face-dark: #07171d;
121
+
130
122
  display: block;
131
- font-family: 'Space Grotesk', -apple-system, sans-serif;
132
- background: #021a14;
133
- color: #ecfdf5;
134
- border-radius: 12px;
135
- border: 1px solid #065f46;
136
- padding: 14px;
123
+ font-family: var(--font-sans, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif);
124
+ color: var(--text-primary, var(--face-text));
125
+ background: var(--bg-secondary, var(--face-bg));
126
+ border: 1px solid var(--border, var(--face-line));
127
+ border-radius: 8px;
128
+ padding: 16px;
137
129
  box-sizing: border-box;
138
- user-select: none;
130
+ overflow: hidden;
139
131
  }
140
132
 
141
- * { box-sizing: border-box; }
133
+ @media (prefers-reduced-motion: reduce) {
134
+ *, ::before, ::after {
135
+ animation-duration: 0.01ms !important;
136
+ animation-iteration-count: 1 !important;
137
+ transition-duration: 0.01ms !important;
138
+ }
139
+ }
142
140
 
143
- /* Bespoke Header */
144
- .card-header {
141
+ /* Header Bar */
142
+ .header {
145
143
  display: flex;
146
144
  align-items: center;
147
145
  justify-content: space-between;
148
- margin-bottom: 12px;
149
- padding-bottom: 8px;
150
- border-bottom: 1px solid rgba(16, 185, 129, 0.25);
146
+ flex-wrap: wrap;
147
+ gap: 12px;
148
+ padding-bottom: 14px;
149
+ border-bottom: 1px solid var(--border, var(--face-line));
150
+ margin-bottom: 16px;
151
151
  }
152
152
 
153
- .brand-cluster {
153
+ .brand-group {
154
154
  display: flex;
155
155
  align-items: center;
156
156
  gap: 10px;
157
157
  }
158
158
 
159
- .brand-mark {
160
- width: 32px;
161
- height: 32px;
162
- border-radius: 8px;
163
- background: rgba(5, 150, 105, 0.2);
164
- border: 1px solid rgba(16, 185, 129, 0.4);
165
- display: flex;
166
- align-items: center;
167
- justify-content: center;
168
- flex-shrink: 0;
159
+ .wordmark-badge {
160
+ font-family: var(--font-mono, 'JetBrains Mono', monospace);
161
+ font-size: 13px;
162
+ font-weight: 800;
163
+ letter-spacing: 0.05em;
164
+ color: var(--card-accent, var(--face-brand));
165
+ background: rgba(6, 182, 212, 0.12);
166
+ padding: 6px 10px;
167
+ border-radius: 6px;
168
+ border: 1px solid rgba(6, 182, 212, 0.3);
169
169
  }
170
170
 
171
- .brand-meta {
171
+ .title-meta {
172
172
  display: flex;
173
173
  flex-direction: column;
174
174
  }
175
175
 
176
- .brand-title {
176
+ .plugin-title {
177
177
  font-size: 14px;
178
178
  font-weight: 700;
179
- color: #d1fae5;
180
- letter-spacing: 0.03em;
181
- text-transform: uppercase;
179
+ color: var(--text-primary, var(--face-text));
182
180
  margin: 0;
183
181
  }
184
182
 
185
- .brand-subtitle {
183
+ .plugin-subtitle {
186
184
  font-size: 11px;
187
- color: #6ee7b7;
185
+ color: var(--text-secondary, var(--face-muted));
188
186
  margin: 0;
189
- font-family: 'JetBrains Mono', monospace;
190
187
  }
191
188
 
192
- .status-pill {
193
- font-family: 'JetBrains Mono', monospace;
194
- font-size: 10px;
189
+ .locality-chip {
190
+ display: flex;
191
+ align-items: center;
192
+ gap: 6px;
193
+ font-family: var(--font-mono, 'JetBrains Mono', monospace);
194
+ font-size: 11px;
195
195
  font-weight: 700;
196
- padding: 3px 8px;
196
+ color: var(--face-ok);
197
+ background: rgba(16, 185, 129, 0.12);
198
+ border: 1px solid rgba(16, 185, 129, 0.3);
199
+ padding: 5px 12px;
197
200
  border-radius: 6px;
198
- background: rgba(16, 185, 129, 0.15);
199
- border: 1px solid rgba(16, 185, 129, 0.4);
200
- color: #34d399;
201
- letter-spacing: 0.05em;
201
+ text-transform: uppercase;
202
202
  }
203
203
 
204
- /* Telemetry Metric Cards */
205
- .telemetry-row {
204
+ /* Main Console Grid */
205
+ .console-grid {
206
206
  display: grid;
207
- grid-template-columns: repeat(3, 1fr);
208
- gap: 8px;
209
- margin-bottom: 12px;
207
+ grid-template-columns: minmax(200px, 1fr) minmax(280px, 1.8fr);
208
+ gap: 14px;
209
+ margin-bottom: 16px;
210
210
  }
211
211
 
212
- .metric-card {
213
- background: rgba(6, 78, 59, 0.5);
214
- border: 1px solid rgba(16, 185, 129, 0.25);
215
- border-radius: 8px;
216
- padding: 8px 10px;
212
+ @media (max-width: 680px) {
213
+ .console-grid {
214
+ grid-template-columns: 1fr;
215
+ }
216
+ }
217
+
218
+ /* Coverage Gauge Column */
219
+ .gauge-card {
220
+ border: 1px solid var(--border, var(--face-line));
221
+ border-radius: 6px;
222
+ background: rgba(14, 42, 53, 0.4);
223
+ padding: 16px;
217
224
  display: flex;
218
225
  flex-direction: column;
219
- gap: 2px;
226
+ align-items: center;
227
+ justify-content: center;
228
+ gap: 12px;
229
+ text-align: center;
220
230
  }
221
231
 
222
- .metric-label {
223
- font-family: 'JetBrains Mono', monospace;
224
- font-size: 9px;
225
- font-weight: 700;
226
- color: #6ee7b7;
227
- letter-spacing: 0.05em;
228
- text-transform: uppercase;
232
+ .svg-container {
233
+ position: relative;
234
+ width: 96px;
235
+ height: 96px;
229
236
  }
230
237
 
231
- .metric-value {
232
- font-size: 13px;
233
- font-weight: 700;
234
- color: #ffffff;
235
- font-family: 'JetBrains Mono', monospace;
236
- overflow: hidden;
237
- text-overflow: ellipsis;
238
- white-space: nowrap;
238
+ .gauge-svg {
239
+ width: 100%;
240
+ height: 100%;
241
+ transform: rotate(-90deg);
239
242
  }
240
243
 
241
- /* Action Buttons Grid (>=44px touch targets) */
242
- .actions-grid {
243
- display: grid;
244
- grid-template-columns: repeat(3, 1fr);
245
- gap: 6px;
246
- margin-bottom: 10px;
244
+ .gauge-bg {
245
+ fill: none;
246
+ stroke: rgba(22, 78, 99, 0.6);
247
+ stroke-width: 8;
247
248
  }
248
249
 
249
- .touch-btn {
250
- min-height: 44px;
251
- background: rgba(5, 150, 105, 0.16);
252
- border: 1px solid rgba(16, 185, 129, 0.3);
253
- border-radius: 8px;
254
- color: #ecfdf5;
255
- font-family: 'JetBrains Mono', monospace;
256
- font-size: 11px;
257
- font-weight: 600;
258
- letter-spacing: 0.03em;
250
+ .gauge-fill {
251
+ fill: none;
252
+ stroke: var(--face-brand);
253
+ stroke-width: 8;
254
+ stroke-linecap: round;
255
+ stroke-dasharray: ${circumference};
256
+ stroke-dashoffset: ${offset};
257
+ transition: stroke-dashoffset 0.4s ease;
258
+ }
259
+
260
+ .gauge-inner-text {
261
+ position: absolute;
262
+ top: 0;
263
+ left: 0;
264
+ width: 100%;
265
+ height: 100%;
259
266
  display: flex;
267
+ flex-direction: column;
260
268
  align-items: center;
261
269
  justify-content: center;
262
- cursor: pointer;
263
- transition: background 0.15s, border-color 0.15s, transform 0.05s;
264
- padding: 4px 6px;
265
- text-align: center;
270
+ pointer-events: none;
266
271
  }
267
272
 
268
- .touch-btn:hover {
269
- background: rgba(5, 150, 105, 0.3);
270
- border-color: rgba(52, 211, 153, 0.6);
273
+ .gauge-number {
274
+ font-family: var(--font-mono, 'JetBrains Mono', monospace);
275
+ font-size: 18px;
276
+ font-weight: 800;
277
+ color: var(--text-primary, var(--face-text));
271
278
  }
272
279
 
273
- .touch-btn:active {
274
- transform: translateY(1px);
280
+ .gauge-label {
281
+ font-size: 9px;
282
+ text-transform: uppercase;
283
+ color: var(--text-secondary, var(--face-muted));
284
+ letter-spacing: 0.05em;
275
285
  }
276
286
 
277
- /* Terminal Execution Output */
278
- .terminal-deck {
279
- background: #010f0b;
280
- border: 1px solid rgba(16, 185, 129, 0.25);
281
- border-radius: 8px;
282
- overflow: hidden;
287
+ .gauge-stats {
288
+ font-size: 11px;
289
+ color: var(--text-secondary, var(--face-muted));
290
+ }
291
+
292
+ .gauge-stats strong {
293
+ color: var(--text-primary, var(--face-text));
283
294
  }
284
295
 
285
- .terminal-header {
296
+ /* Model & Benchmark Panel */
297
+ .details-deck {
286
298
  display: flex;
287
- align-items: center;
288
- justify-content: space-between;
289
- padding: 6px 10px;
290
- background: rgba(6, 78, 59, 0.4);
291
- border-bottom: 1px solid rgba(16, 185, 129, 0.2);
299
+ flex-direction: column;
300
+ gap: 12px;
292
301
  }
293
302
 
294
- .terminal-title {
295
- font-family: 'JetBrains Mono', monospace;
296
- font-size: 10px;
297
- color: #6ee7b7;
303
+ .deck-box {
304
+ border: 1px solid var(--border, var(--face-line));
305
+ border-radius: 6px;
306
+ background: rgba(14, 42, 53, 0.4);
307
+ padding: 12px;
308
+ display: flex;
309
+ flex-direction: column;
310
+ gap: 10px;
311
+ }
312
+
313
+ .deck-title {
314
+ font-size: 11px;
315
+ font-weight: 700;
298
316
  text-transform: uppercase;
299
317
  letter-spacing: 0.05em;
318
+ color: var(--text-secondary, var(--face-muted));
319
+ margin: 0;
320
+ display: flex;
321
+ justify-content: space-between;
322
+ align-items: center;
300
323
  }
301
324
 
302
- .terminal-btn {
303
- background: rgba(16, 185, 129, 0.15);
304
- border: 1px solid rgba(16, 185, 129, 0.3);
305
- border-radius: 4px;
306
- color: #d1fae5;
307
- font-family: 'JetBrains Mono', monospace;
308
- font-size: 9px;
325
+ .model-row {
326
+ display: flex;
327
+ align-items: center;
328
+ justify-content: space-between;
329
+ padding: 8px 10px;
330
+ background: rgba(7, 23, 29, 0.6);
331
+ border: 1px solid var(--border, var(--face-line));
332
+ border-radius: 5px;
333
+ }
334
+
335
+ .model-name {
336
+ font-family: var(--font-mono, 'JetBrains Mono', monospace);
337
+ font-size: 12px;
338
+ font-weight: 700;
339
+ color: var(--text-primary, var(--face-text));
340
+ }
341
+
342
+ .model-badges {
343
+ display: flex;
344
+ align-items: center;
345
+ gap: 6px;
346
+ }
347
+
348
+ .dim-chip {
349
+ font-family: var(--font-mono, 'JetBrains Mono', monospace);
350
+ font-size: 10px;
309
351
  padding: 2px 6px;
352
+ border-radius: 4px;
353
+ background: rgba(6, 182, 212, 0.15);
354
+ color: var(--face-accent);
355
+ }
356
+
357
+ /* Benchmark Trigger */
358
+ .benchmark-action-row {
359
+ display: flex;
360
+ align-items: center;
361
+ justify-content: space-between;
362
+ flex-wrap: wrap;
363
+ gap: 8px;
364
+ }
365
+
366
+ .btn-benchmark {
367
+ min-height: 44px;
368
+ padding: 8px 16px;
369
+ font-family: var(--font-sans, sans-serif);
370
+ font-size: 12px;
371
+ font-weight: 700;
372
+ color: var(--face-dark);
373
+ background: var(--face-brand);
374
+ border: none;
375
+ border-radius: 5px;
310
376
  cursor: pointer;
377
+ transition: background 0.15s ease;
311
378
  }
312
379
 
313
- .terminal-btn:hover {
314
- background: rgba(16, 185, 129, 0.3);
380
+ .btn-benchmark:hover {
381
+ background: var(--face-brand-hover);
315
382
  }
316
383
 
317
- .terminal-body {
318
- margin: 0;
319
- padding: 8px 10px;
320
- font-family: 'JetBrains Mono', monospace;
384
+ .btn-benchmark:disabled {
385
+ opacity: 0.6;
386
+ cursor: not-allowed;
387
+ }
388
+
389
+ .bench-result {
390
+ font-family: var(--font-mono, 'JetBrains Mono', monospace);
321
391
  font-size: 11px;
322
- line-height: 1.45;
323
- color: #d1fae5;
324
- min-height: 60px;
325
- max-height: 100px;
326
- overflow-y: auto;
327
- white-space: pre-wrap;
328
- word-break: break-word;
392
+ color: var(--face-ok);
393
+ }
394
+
395
+ /* Footer Telemetry */
396
+ .footer-bar {
397
+ display: flex;
398
+ justify-content: space-between;
399
+ align-items: center;
400
+ padding-top: 12px;
401
+ margin-top: 14px;
402
+ border-top: 1px solid var(--border, var(--face-line));
403
+ font-size: 10px;
404
+ color: var(--text-secondary, var(--face-muted));
329
405
  }
330
406
  </style>
331
407
 
332
- <div class="card-header">
333
- <div class="brand-cluster">
334
- <div class="brand-mark">
335
- <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#34d399" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
336
- <path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z"/>
337
- <polyline points="3.27 6.96 12 12.01 20.73 6.96"/>
338
- <line x1="12" y1="22.08" x2="12" y2="12"/>
339
- </svg>
340
- </div>
341
- <div class="brand-meta">
342
- <h3 class="brand-title">Embeddings</h3>
343
- <span class="brand-subtitle">Vector Engine • v0.1.0</span>
408
+ <div class="header">
409
+ <div class="brand-group">
410
+ <div class="wordmark-badge">[VECTOR//SPACE]</div>
411
+ <div class="title-meta">
412
+ <h3 class="plugin-title">Vector Space & Coverage</h3>
413
+ <p class="plugin-subtitle">On-device semantic memory coverage and local model runner</p>
344
414
  </div>
345
415
  </div>
346
- <div id="status-pill" class="status-pill">READY</div>
416
+ <div class="locality-chip">
417
+ Strict Local Engine
418
+ </div>
347
419
  </div>
348
420
 
349
- <div class="telemetry-row">
350
- <div class="metric-card">
351
- <span class="metric-label">Model Weights</span>
352
- <span id="stat-model" class="metric-value">nomic-embed-text (768d)</span>
353
- </div>
354
- <div class="metric-card">
355
- <span class="metric-label">Vault Vectors</span>
356
- <span id="stat-coverage" class="metric-value">98% Embedded</span>
357
- </div>
358
- <div class="metric-card">
359
- <span class="metric-label">Locality</span>
360
- <span id="stat-locality" class="metric-value">Local (On-Device)</span>
421
+ <div class="console-grid">
422
+ <div class="gauge-card">
423
+ <div class="svg-container">
424
+ <svg class="gauge-svg" viewBox="0 0 96 96">
425
+ <circle class="gauge-bg" cx="48" cy="48" r="${radius}" />
426
+ <circle class="gauge-fill" cx="48" cy="48" r="${radius}" />
427
+ </svg>
428
+ <div class="gauge-inner-text">
429
+ <span class="gauge-number">${pct !== null ? `${pct}%` : DASH}</span>
430
+ <span class="gauge-label">Vault</span>
431
+ </div>
432
+ </div>
433
+ <div class="gauge-stats">
434
+ <div>Embedded: <strong>${embeddedNodes}</strong> / <strong>${totalNodes}</strong></div>
435
+ <div>Storage: <strong>SQLite (embeddings.db)</strong></div>
436
+ </div>
361
437
  </div>
362
- </div>
363
438
 
364
- <div class="actions-grid">
365
- <button id="btn-status" class="touch-btn" type="button">STATUS</button>
366
- <button id="btn-models" class="touch-btn" type="button">MODELS</button>
367
- <button id="btn-benchmark" class="touch-btn" type="button">BENCHMARK</button>
368
- <button id="btn-coverage" class="touch-btn" type="button">COVERAGE</button>
369
- <button id="btn-pull" class="touch-btn" type="button">PULL WEIGHTS</button>
370
- <button id="btn-refresh" class="touch-btn" type="button">REFRESH</button>
371
- </div>
439
+ <div class="details-deck">
440
+ <div class="deck-box">
441
+ <div class="deck-title">
442
+ <span>Active Model Weights</span>
443
+ <span class="dim-chip">${dimensions} dimensions</span>
444
+ </div>
445
+ <div class="model-row">
446
+ <span class="model-name">${escapeHtml(activeModel)}</span>
447
+ <div class="model-badges">
448
+ <span class="dim-chip">On-Device GGUF</span>
449
+ <span class="dim-chip" style="color: var(--face-ok);">Ready</span>
450
+ </div>
451
+ </div>
452
+ </div>
372
453
 
373
- <div class="terminal-deck">
374
- <div class="terminal-header">
375
- <span class="terminal-title">Vector Telemetry Console</span>
376
- <button id="btn-copy" class="terminal-btn" type="button">COPY</button>
454
+ <div class="deck-box">
455
+ <div class="deck-title">Projection Benchmark</div>
456
+ <div class="benchmark-action-row">
457
+ <button class="btn-benchmark" type="button" id="btn-bench" ${this.executing ? 'disabled' : ''}>
458
+ ${this.executing ? 'Benchmarking...' : 'Test Projection Speed'}
459
+ </button>
460
+ <div class="bench-result">
461
+ ${this.benchmark ? `Latency: ${this.benchmark.latency_ms || this.benchmark.ms || DASH}ms per chunk` : 'Click to measure latency'}
462
+ </div>
463
+ </div>
464
+ </div>
377
465
  </div>
378
- <pre id="card-out" class="terminal-body">Local vector embedding pipeline online. Vectors are preserved on-device and never leave this host.</pre>
379
466
  </div>
380
- `;
381
-
382
- root.querySelector('#btn-status')?.addEventListener('click', () => {
383
- this.execute('status');
384
- });
385
-
386
- root.querySelector('#btn-models')?.addEventListener('click', () => {
387
- this.execute('models');
388
- });
389
-
390
- root.querySelector('#btn-benchmark')?.addEventListener('click', () => {
391
- this.execute('benchmark');
392
- });
393
467
 
394
- root.querySelector('#btn-coverage')?.addEventListener('click', () => {
395
- this.execute('coverage');
396
- });
397
-
398
- root.querySelector('#btn-pull')?.addEventListener('click', () => {
399
- this.execute('pull');
400
- });
401
-
402
- root.querySelector('#btn-refresh')?.addEventListener('click', () => {
403
- this.execute('status');
404
- });
468
+ <div class="footer-bar">
469
+ <span>Model: ${escapeHtml(activeModel)}</span>
470
+ <span>Locality Invariant: Strictly On-Device</span>
471
+ </div>
472
+ `;
405
473
 
406
- root.querySelector('#btn-copy')?.addEventListener('click', () => {
407
- this.copyOutput();
408
- });
474
+ // Event listeners
475
+ root.querySelector('#btn-bench')?.addEventListener('click', () => this.runBenchmark());
409
476
  }
410
477
  }
411
478