total-recall-brain 3.6.3 → 3.6.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.
@@ -530,6 +530,13 @@ export async function triggerDream(): Promise<{ success: boolean; status: string
530
530
  return res.json()
531
531
  }
532
532
 
533
+ export async function runAgentDiagnostics(): Promise<{ success: boolean; output: string }> {
534
+ const res = await apiFetch(`${API_BASE}/api/diagnostics/agents`, { method: 'POST' })
535
+ if (!res.ok) throw new Error(`Diagnostics API error: ${res.status}`)
536
+ return res.json()
537
+ }
538
+
539
+
533
540
  export async function fetchGraph(): Promise<{ nodes: MemoryNode[]; routes: unknown[] }> {
534
541
  const res = await apiFetch(`${API_BASE}/api/graph`)
535
542
  if (!res.ok) throw new Error(`Graph API error: ${res.status}`)
@@ -166,7 +166,7 @@ function CollabDashboard({ token, username, onLogout, onSelectSandbox }: { token
166
166
  <p style={{ fontSize: '12px', color: 'var(--text-secondary)' }}>Share annotations and real-time page chat rooms</p>
167
167
  </div>
168
168
  <div style={{ display: 'flex', gap: '10px' }}>
169
- <button className="btn btn-purple" onClick={onSelectSandbox}>🌐 Open Page Sandbox</button>
169
+ <button className="btn btn-purple" onClick={onSelectSandbox}>🌐 Open Browse Workspace</button>
170
170
  <button className="btn btn-ghost" onClick={onLogout} style={{ color: '#f87171' }}>Logout</button>
171
171
  </div>
172
172
  </div>
@@ -219,7 +219,7 @@ function CollabDashboard({ token, username, onLogout, onSelectSandbox }: { token
219
219
  function CollabSandbox({ token, username, onBack }: { token: string, username: string, onBack: () => void }) {
220
220
  const [groups, setGroups] = useState<CollabGroup[]>([]);
221
221
  const [selectedGroup, setSelectedGroup] = useState<CollabGroup | null>(null);
222
- const [simulatedUrl, setSimulatedUrl] = useState('https://news.ycombinator.com');
222
+ const [activeBrowseUrl, setActiveBrowseUrl] = useState('https://news.ycombinator.com');
223
223
  const [activeUrl, setActiveUrl] = useState('https://news.ycombinator.com');
224
224
  const [annotations, setAnnotations] = useState<Annotation[]>([]);
225
225
  const [noteText, setNoteText] = useState('');
@@ -313,9 +313,9 @@ function CollabSandbox({ token, username, onBack }: { token: string, username: s
313
313
 
314
314
  const handleUrlSubmit = (e: React.FormEvent) => {
315
315
  e.preventDefault();
316
- if (!simulatedUrl.trim()) return;
316
+ if (!activeBrowseUrl.trim()) return;
317
317
  setChatMessages([]); setSystemLogs([]); setActiveUsers([]);
318
- setActiveUrl(simulatedUrl);
318
+ setActiveUrl(activeBrowseUrl);
319
319
  };
320
320
 
321
321
  const handleAddAnnotation = async (e: React.FormEvent) => {
@@ -348,14 +348,14 @@ function CollabSandbox({ token, username, onBack }: { token: string, username: s
348
348
  <div style={{ display: 'flex', gap: '16px', alignItems: 'center', justifyContent: 'space-between', background: 'rgba(255,255,255,0.02)', padding: '12px 20px', borderRadius: '8px', border: '1px solid var(--border)', flexWrap: 'wrap' }}>
349
349
  <button className="btn btn-ghost" onClick={onBack}>← Back to Workspaces</button>
350
350
  <form onSubmit={handleUrlSubmit} style={{ display: 'flex', gap: '10px', flex: '1', minWidth: '250px' }}>
351
- <input type="text" value={simulatedUrl} onChange={e => setSimulatedUrl(e.target.value)} style={{ background: 'rgba(0,0,0,0.2)', border: '1px solid var(--border)', color: '#fff', padding: '6px 12px', borderRadius: '6px', flex: '1', fontFamily: 'monospace' }} />
352
- <button type="submit" className="btn btn-purple">Simulate Visit</button>
351
+ <input type="text" value={activeBrowseUrl} onChange={e => setActiveBrowseUrl(e.target.value)} style={{ background: 'rgba(0,0,0,0.2)', border: '1px solid var(--border)', color: '#fff', padding: '6px 12px', borderRadius: '6px', flex: '1', fontFamily: 'monospace' }} />
352
+ <button type="submit" className="btn btn-purple">Connect URL</button>
353
353
  </form>
354
354
  <div style={{ fontSize: '13px', color: wsConnected ? '#34d399' : '#f87171' }}>● {wsConnected ? 'Connected' : 'Disconnected'}</div>
355
355
  </div>
356
356
 
357
357
  <div style={{ fontSize: '13px', color: 'var(--text-secondary)' }}>
358
- Simulated browser context: <strong style={{ color: 'var(--purple-primary)', fontFamily: 'monospace' }}>{activeUrl}</strong>
358
+ Active browse context URL: <strong style={{ color: 'var(--purple-primary)', fontFamily: 'monospace' }}>{activeUrl}</strong>
359
359
  </div>
360
360
 
361
361
  <div style={{ display: 'grid', gridTemplateColumns: '1fr 340px', gap: '20px', height: '500px' }}>
@@ -1,5 +1,5 @@
1
1
  import { useState, useEffect, useRef } from 'react';
2
- import { fetchHealth, fetchLogs } from '../api';
2
+ import { fetchHealth, fetchLogs, runAgentDiagnostics } from '../api';
3
3
  import type { HealthData } from '../types';
4
4
 
5
5
  export default function DeploymentsPage() {
@@ -9,9 +9,9 @@ export default function DeploymentsPage() {
9
9
  const [error, setError] = useState<string | null>(null);
10
10
  const [success, setSuccess] = useState<string | null>(null);
11
11
 
12
- // Model Pull Form state
13
- const [modelToPull, setModelToPull] = useState('gemma4:26b');
14
- const [pulling, setPulling] = useState(false);
12
+ // CLI Agent Diagnostics state
13
+ const [runningDiagnostics, setRunningDiagnostics] = useState(false);
14
+ const [diagnosticLogs, setDiagnosticLogs] = useState<string | null>(null);
15
15
 
16
16
  const consoleEndRef = useRef<HTMLDivElement>(null);
17
17
 
@@ -44,29 +44,36 @@ export default function DeploymentsPage() {
44
44
  }
45
45
  }, [logs]);
46
46
 
47
- const handlePullModel = async (e: React.FormEvent) => {
47
+ const handleRunDiagnostics = async (e: React.FormEvent) => {
48
48
  e.preventDefault();
49
- setPulling(true);
49
+ setRunningDiagnostics(true);
50
50
  setError(null);
51
51
  setSuccess(null);
52
+ setDiagnosticLogs(null);
52
53
  try {
53
- // Simulate/trigger model pull trigger enqueued in task manager
54
- setSuccess(`Model pull job successfully enqueued for "${modelToPull}" in the background task runner.`);
55
- setTimeout(() => setSuccess(null), 5000);
54
+ const res = await runAgentDiagnostics();
55
+ setDiagnosticLogs(res.output);
56
+ if (res.success) {
57
+ setSuccess('CLI Agent diagnostics completed successfully.');
58
+ } else {
59
+ setError('CLI Agent diagnostics finished with warnings or missing binaries.');
60
+ }
61
+ void fetchSystemData();
56
62
  } catch (err: unknown) {
57
- setError((err as Error).message || 'Model pull request failed.');
63
+ setError((err as Error).message || 'Diagnostics execution failed.');
58
64
  } finally {
59
- setPulling(false);
65
+ setRunningDiagnostics(false);
60
66
  }
61
67
  };
62
68
 
63
- const MODELS_CATALOG = [
64
- { id: 'gemma4:26b', name: 'Gemma 4 (26B Parameter)', size: '15.6 GB', purpose: 'Standard Kernel LLM (Reasoning & Code Harness)', status: 'ready', type: 'ollama' },
65
- { id: 'gemma5:32b', name: 'Gemma 5 Pro (32B Parameter)', size: '19.2 GB', purpose: 'Advanced Reasoning & Deliberation Engine', status: 'available', type: 'ollama' },
66
- { id: 'text-embedding-004', name: 'Gemini Text Embeddings v4', size: 'Cloud-native', purpose: 'High-Dimensional Dense Vectorization', status: 'ready', type: 'gemini' },
67
- { id: 'claude-3-5-sonnet', name: 'Claude 3.5 Sonnet', size: 'Cloud-native', purpose: 'Frontier Advanced Programming', status: 'ready', type: 'claude' },
69
+ const AGENTS_LIST = [
70
+ { id: 'antigravity', name: 'Antigravity (Gemini SDK)', desc: 'Primary core developer agent' },
71
+ { id: 'gemini', name: 'Gemini CLI', desc: 'Direct Gemini assistant binary' },
72
+ { id: 'claude', name: 'Claude Code', desc: 'Anthropic developer CLI wrapper' },
73
+ { id: 'codex', name: 'Codex CLI', desc: 'OpenAI agent binary integration' }
68
74
  ];
69
75
 
76
+
70
77
  return (
71
78
  <div className="page" style={{ display: 'flex', flexDirection: 'column', height: '100%', overflowY: 'auto' }}>
72
79
  <div className="page-header" style={{ marginBottom: 24 }}>
@@ -146,7 +153,7 @@ export default function DeploymentsPage() {
146
153
 
147
154
  </div>
148
155
 
149
- {/* Model Catalog & Pull form */}
156
+ {/* CLI Agents Catalog & Diagnostics */}
150
157
  <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(360px, 1fr))', gap: 24 }}>
151
158
 
152
159
  {/* Catalog */}
@@ -154,31 +161,31 @@ export default function DeploymentsPage() {
154
161
  <div style={{ display: 'flex', alignItems: 'center', gap: 10, borderBottom: '1px solid var(--border)', paddingBottom: 12 }}>
155
162
  <span style={{ fontSize: 20 }}>🧠</span>
156
163
  <div>
157
- <h3 style={{ fontSize: 14, fontWeight: 600 }}>Kernel LLM Catalog</h3>
158
- <p style={{ fontSize: 11, color: 'var(--text-tertiary)' }}>Provisioned local intelligence engines</p>
164
+ <h3 style={{ fontSize: 14, fontWeight: 600 }}>CLI Reasoning Agents</h3>
165
+ <p style={{ fontSize: 11, color: 'var(--text-tertiary)' }}>Headless CLI reasoning agents configured on system</p>
159
166
  </div>
160
167
  </div>
161
168
 
162
169
  <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
163
- {MODELS_CATALOG.map((m) => {
164
- const activeModel = health?.ollama_models?.includes(m.id) || m.type !== 'ollama';
170
+ {AGENTS_LIST.map((a) => {
171
+ const activeAgent = health?.cli_agents?.includes(a.id);
165
172
  return (
166
- <div key={m.id} style={{ display: 'flex', alignItems: 'center', gap: 12, background: 'var(--bg-tertiary)', padding: 12, borderRadius: 8, border: '1px solid var(--border)' }}>
173
+ <div key={a.id} style={{ display: 'flex', alignItems: 'center', gap: 12, background: 'var(--bg-tertiary)', padding: 12, borderRadius: 8, border: '1px solid var(--border)' }}>
167
174
  <div style={{ flex: 1 }}>
168
175
  <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
169
- <span style={{ fontSize: 12, fontWeight: 600, color: 'var(--text-primary)' }}>{m.name}</span>
176
+ <span style={{ fontSize: 12, fontWeight: 600, color: 'var(--text-primary)' }}>{a.name}</span>
170
177
  <span className="badge" style={{
171
178
  fontSize: 9,
172
179
  padding: '2px 6px',
173
- background: activeModel ? 'rgba(0, 206, 201, 0.1)' : 'rgba(255, 255, 255, 0.04)',
174
- color: activeModel ? '#00cec9' : 'var(--text-tertiary)',
175
- border: activeModel ? '1px solid rgba(0, 206, 201, 0.2)' : '1px solid var(--border)'
180
+ background: activeAgent ? 'rgba(16, 185, 129, 0.1)' : 'rgba(239, 68, 68, 0.1)',
181
+ color: activeAgent ? '#10b981' : '#ef4444',
182
+ border: activeAgent ? '1px solid rgba(16, 185, 129, 0.2)' : '1px solid rgba(239, 68, 68, 0.2)'
176
183
  }}>
177
- {activeModel ? 'active' : 'available'}
184
+ {activeAgent ? 'available' : 'missing'}
178
185
  </span>
179
186
  </div>
180
- <div style={{ fontSize: 10, color: 'var(--text-secondary)', marginTop: 2 }}>{m.purpose}</div>
181
- <div style={{ fontSize: 9, color: 'var(--text-tertiary)', marginTop: 4 }}>ID: {m.id} • Size: {m.size}</div>
187
+ <div style={{ fontSize: 10, color: 'var(--text-secondary)', marginTop: 2 }}>{a.desc}</div>
188
+ <div style={{ fontSize: 9, color: 'var(--text-tertiary)', marginTop: 4 }}>Registry ID: {a.id}</div>
182
189
  </div>
183
190
  </div>
184
191
  );
@@ -186,42 +193,24 @@ export default function DeploymentsPage() {
186
193
  </div>
187
194
  </div>
188
195
 
189
- {/* Pull Model Form */}
196
+ {/* Diagnostics Form */}
190
197
  <div className="card" style={{ padding: 24, background: 'rgba(18, 18, 26, 0.6)', backdropFilter: 'blur(8px)', border: '1px solid var(--border)', display: 'flex', flexDirection: 'column', gap: 20 }}>
191
198
  <div style={{ display: 'flex', alignItems: 'center', gap: 10, borderBottom: '1px solid var(--border)', paddingBottom: 12 }}>
192
199
  <span style={{ fontSize: 20 }}>📡</span>
193
200
  <div>
194
- <h3 style={{ fontSize: 14, fontWeight: 600 }}>Pull Catalog Model</h3>
195
- <p style={{ fontSize: 11, color: 'var(--text-tertiary)' }}>Trigger high-performance model downloads in background</p>
201
+ <h3 style={{ fontSize: 14, fontWeight: 600 }}>CLI Agent Diagnostics</h3>
202
+ <p style={{ fontSize: 11, color: 'var(--text-tertiary)' }}>Trigger active paths check and verify registered agents</p>
196
203
  </div>
197
204
  </div>
198
205
 
199
- <form onSubmit={handlePullModel} style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
200
- <div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
201
- <label htmlFor="model_pull" style={{ fontSize: 12, fontWeight: 500 }}>Select Catalog Model</label>
202
- <select
203
- id="model_pull"
204
- value={modelToPull}
205
- onChange={(e) => setModelToPull(e.target.value)}
206
- style={{
207
- background: 'var(--bg-tertiary)',
208
- color: 'var(--text-primary)',
209
- border: '1px solid var(--border)',
210
- padding: '8px 12px',
211
- borderRadius: 6,
212
- outline: 'none',
213
- fontSize: 13
214
- }}
215
- >
216
- <option value="gemma4:26b">Gemma 4 (26B Parameter) — 15.6 GB</option>
217
- <option value="gemma5:32b">Gemma 5 Pro (32B Parameter) — 19.2 GB</option>
218
- <option value="llama3:70b">Llama 3 (70B Parameter) — 40 GB</option>
219
- </select>
220
- </div>
206
+ <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
207
+ <p style={{ fontSize: 12, lineHeight: 1.5, color: 'var(--text-secondary)' }}>
208
+ This executes a diagnostic check on registered reasoning agents (equivalent to running <code>npx total-recall upgrade --agents</code> in the background) to audit paths and verify binaries.
209
+ </p>
221
210
 
222
211
  <button
223
- type="submit"
224
- disabled={pulling}
212
+ onClick={handleRunDiagnostics}
213
+ disabled={runningDiagnostics}
225
214
  style={{
226
215
  background: 'linear-gradient(135deg, var(--accent), var(--accent-hover))',
227
216
  color: '#fff',
@@ -230,12 +219,32 @@ export default function DeploymentsPage() {
230
219
  fontWeight: 500,
231
220
  border: 'none',
232
221
  marginTop: 8,
233
- cursor: pulling ? 'not-allowed' : 'pointer'
222
+ cursor: runningDiagnostics ? 'not-allowed' : 'pointer'
234
223
  }}
235
224
  >
236
- {pulling ? '⏳ Initiating download...' : '🚀 Trigger Model Download'}
225
+ {runningDiagnostics ? '⏳ Running Audit...' : '🚀 Run Diagnostics Audit'}
237
226
  </button>
238
- </form>
227
+ </div>
228
+
229
+ {diagnosticLogs && (
230
+ <div style={{ display: 'flex', flexDirection: 'column', gap: 6, marginTop: 10 }}>
231
+ <span style={{ fontSize: 11, fontWeight: 500, color: 'var(--text-secondary)' }}>Diagnostics Console Output:</span>
232
+ <pre style={{
233
+ background: '#07070a',
234
+ border: '1px solid var(--border)',
235
+ padding: 10,
236
+ borderRadius: 6,
237
+ fontFamily: 'var(--font-mono)',
238
+ fontSize: 11,
239
+ color: '#e6edf3',
240
+ whiteSpace: 'pre-wrap',
241
+ maxHeight: 150,
242
+ overflowY: 'auto'
243
+ }}>
244
+ {diagnosticLogs}
245
+ </pre>
246
+ </div>
247
+ )}
239
248
  </div>
240
249
 
241
250
  </div>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "total-recall-brain",
3
- "version": "3.6.3",
3
+ "version": "3.6.4",
4
4
  "description": "Sovereign AI system — database-free, SSSS-powered personal intelligence engine deployable to any POSIX host.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -468,6 +468,25 @@ router.get('/api/vault/status', requireAuth, requireScope('memory:read'), async
468
468
  }
469
469
  });
470
470
 
471
+ /**
472
+ * POST /api/diagnostics/agents
473
+ * Run `upgrade --agents` diagnostics checks and return the console text output.
474
+ */
475
+ router.post('/api/diagnostics/agents', requireAuth, requireScope('health:read'), async (req, res) => {
476
+ try {
477
+ const result = spawnSync('node', [path.join(ROOT, 'bin', 'total-recall.mjs'), 'upgrade', '--agents'], {
478
+ encoding: 'utf8',
479
+ cwd: ROOT,
480
+ env: { ...process.env }
481
+ });
482
+ const output = (result.stdout || '') + (result.stderr || '');
483
+ res.json({ success: result.status === 0, output });
484
+ } catch (err) {
485
+ serverError(res, err);
486
+ }
487
+ });
488
+
489
+
471
490
  // ─── Keys ─────────── (moved to ./routes/keys.mjs)
472
491
  // ─── Sessions ─────── (moved to ./routes/sessions.mjs)
473
492
  // ─── Sandbox ──────────────────────────────────────────────────────────────────
@@ -67,6 +67,10 @@
67
67
  "method": "POST",
68
68
  "path": "/api/context/stream"
69
69
  },
70
+ {
71
+ "method": "POST",
72
+ "path": "/api/diagnostics/agents"
73
+ },
70
74
  {
71
75
  "method": "POST",
72
76
  "path": "/api/dream"