total-recall-brain 3.12.2 → 3.13.1

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 (154) hide show
  1. package/README.md +91 -108
  2. package/bin/antigravity.mjs +81 -52
  3. package/bin/total-recall.mjs +32 -57
  4. package/extension/background.js +1 -1
  5. package/extension/options/options.js +9 -3
  6. package/extension/sidepanel/sidepanel.js +0 -2
  7. package/frontend/index.html +4 -3
  8. package/frontend/package.json +3 -1
  9. package/frontend/src/App.tsx +112 -111
  10. package/frontend/src/api.ts +700 -18
  11. package/frontend/src/components/BrainSelector.tsx +211 -199
  12. package/frontend/src/components/DocumentEditorModal.tsx +57 -0
  13. package/frontend/src/components/DocumentTable.tsx +47 -0
  14. package/frontend/src/components/Graph3D.tsx +120 -71
  15. package/frontend/src/components/UsageChart.tsx +78 -0
  16. package/frontend/src/components/brand/BrandMark.tsx +95 -0
  17. package/frontend/src/index.css +286 -86
  18. package/frontend/src/pages/ApiKeysPage.tsx +1878 -215
  19. package/frontend/src/pages/ChatPage.tsx +103 -45
  20. package/frontend/src/pages/DesignDocsPage.tsx +614 -0
  21. package/frontend/src/pages/FilesPage.tsx +10 -6
  22. package/frontend/src/pages/GraphPage.tsx +5 -3
  23. package/frontend/src/pages/HelpPage.tsx +2 -2
  24. package/frontend/src/pages/InboxPage.tsx +82 -0
  25. package/frontend/src/pages/InstructionsPage.tsx +583 -0
  26. package/frontend/src/pages/IntegrationsPage.tsx +21 -10
  27. package/frontend/src/pages/LoginPage.tsx +95 -77
  28. package/frontend/src/pages/MemoryPage.tsx +31 -8
  29. package/frontend/src/pages/ModelsPage.tsx +280 -23
  30. package/frontend/src/pages/OkfPage.tsx +535 -0
  31. package/frontend/src/pages/OnboardingPage.tsx +690 -0
  32. package/frontend/src/pages/OpenWikiPage.tsx +561 -0
  33. package/frontend/src/pages/SettingsPage.tsx +826 -740
  34. package/frontend/src/pages/SkillsPage.tsx +1259 -117
  35. package/frontend/src/pages/UsagePage.tsx +256 -11
  36. package/frontend/src/pages/VaultPage.tsx +223 -0
  37. package/frontend/src/types.ts +173 -0
  38. package/package.json +4 -4
  39. package/scaffold/.agent/skills/total-recall/SKILL.md +43 -4
  40. package/scaffold/.agent/skills/total-recall/modules/README.md +10 -0
  41. package/scaffold/.agent/skills/total-recall/modules/agents/README.md +5 -0
  42. package/scaffold/.agent/skills/total-recall/{skills/tr-cli-agents → modules/agents}/agents.yml +8 -0
  43. package/scaffold/.agent/skills/total-recall/modules/skill-deploy/README.md +9 -0
  44. package/scaffold/.agent/skills/total-recall/openwiki/README.md +10 -0
  45. package/scaffold/.agent/skills/total-recall/openwiki/architecture.md +5 -0
  46. package/scaffold/.agent/skills/total-recall/openwiki/ide.md +10 -0
  47. package/scaffold/.agent/skills/total-recall/openwiki/memory.md +11 -0
  48. package/scaffold/.agent/skills/total-recall/openwiki/secrets.md +7 -0
  49. package/scaffold/.agent/skills/total-recall/openwiki/skills.md +7 -0
  50. package/src/cli/brain.mjs +63 -5
  51. package/src/cli/connect.mjs +11 -19
  52. package/src/cli/daemon.mjs +5 -4
  53. package/src/cli/deploy-ui.mjs +8 -3
  54. package/src/cli/deploy.mjs +84 -27
  55. package/src/cli/ingest/index.mjs +1 -1
  56. package/src/cli/init.mjs +63 -34
  57. package/src/cli/remember.mjs +3 -3
  58. package/src/cli/secret.mjs +812 -0
  59. package/src/cli/setup.mjs +34 -7
  60. package/src/cli/share.mjs +2 -2
  61. package/src/cli/skill.mjs +396 -35
  62. package/src/cli/sync.mjs +4 -4
  63. package/src/cli/task.mjs +287 -0
  64. package/src/core/clarity-rewriter.mjs +5 -5
  65. package/src/core/config.mjs +44 -2
  66. package/src/core/conflict-detector.mjs +5 -5
  67. package/src/core/crons.mjs +54 -0
  68. package/src/core/daemon-loop.mjs +87 -235
  69. package/src/core/dream.mjs +170 -10
  70. package/src/core/env-import.mjs +456 -0
  71. package/src/core/fact-seeker.mjs +14 -14
  72. package/src/core/import-rules.mjs +20 -7
  73. package/src/core/inference-engine.mjs +3 -3
  74. package/src/core/migrate.mjs +14 -8
  75. package/src/core/okf-adapter.mjs +2 -2
  76. package/src/core/operation-validator.mjs +39 -331
  77. package/src/core/optimizer.mjs +7 -0
  78. package/src/core/post-mortem.mjs +2 -2
  79. package/src/core/project-brain.mjs +349 -0
  80. package/src/core/provider-catalog.mjs +296 -0
  81. package/src/core/quick-capture.mjs +1 -1
  82. package/src/core/remote-vault-sync.mjs +194 -0
  83. package/src/core/research-queue.mjs +7 -11
  84. package/src/core/runtime.mjs +33 -9
  85. package/src/core/scheduler.mjs +59 -5
  86. package/src/core/schema.mjs +14 -0
  87. package/src/core/search.mjs +1 -1
  88. package/src/core/secrets-env-export.mjs +323 -0
  89. package/src/core/secrets-rotate.mjs +245 -0
  90. package/src/core/secrets-store.mjs +645 -0
  91. package/src/core/semantic-index.mjs +3 -3
  92. package/src/core/skills-registry.mjs +1062 -0
  93. package/src/core/source-adapters.mjs +4 -1
  94. package/src/core/ssss-host-extension.mjs +94 -0
  95. package/src/core/ssss-kernel-bridge.mjs +530 -0
  96. package/src/core/surface.mjs +14 -0
  97. package/src/core/task-envelope.mjs +298 -0
  98. package/src/core/task-executors.mjs +600 -0
  99. package/src/core/validated-write.mjs +124 -56
  100. package/src/core/vault.mjs +19 -34
  101. package/src/core/webauthn-store.mjs +272 -0
  102. package/src/server/api.mjs +28 -16
  103. package/src/server/auth.mjs +53 -2
  104. package/src/server/index.mjs +3 -3
  105. package/src/server/keys.mjs +30 -4
  106. package/src/server/rest.mjs +405 -68
  107. package/src/server/route-manifest.json +168 -0
  108. package/src/server/routes/_shared.mjs +40 -1
  109. package/src/server/routes/docs.mjs +260 -0
  110. package/src/server/routes/memory.mjs +145 -32
  111. package/src/server/routes/research.mjs +30 -0
  112. package/src/server/routes/secrets.mjs +470 -0
  113. package/src/server/routes/share.mjs +2 -2
  114. package/src/server/routes/skills.mjs +452 -54
  115. package/src/server/routes/sync.mjs +48 -0
  116. package/src/server/routes/webauthn.mjs +184 -0
  117. package/src/server/update-route-manifest.mjs +39 -0
  118. package/templates/onboarding-interview.md +32 -22
  119. package/templates/openwiki/README.md +10 -0
  120. package/templates/openwiki/architecture.md +5 -0
  121. package/templates/openwiki/ide.md +10 -0
  122. package/templates/openwiki/memory.md +11 -0
  123. package/templates/openwiki/secrets.md +7 -0
  124. package/templates/openwiki/skills.md +7 -0
  125. package/scaffold/.agent/skills/total-recall/skills/tr-cli-agents/SKILL.md +0 -121
  126. package/scaffold/.agent/skills/total-recall/skills/tr-cli-agents/references/antigravity.txt +0 -20
  127. package/scaffold/.agent/skills/total-recall/skills/tr-cli-agents/references/claude.txt +0 -58
  128. package/scaffold/.agent/skills/total-recall/skills/tr-cli-agents/references/codex.txt +0 -81
  129. package/scaffold/.agent/skills/total-recall/skills/tr-cli-agents/references/gemini.txt +0 -44
  130. package/scaffold/.agent/skills/total-recall/skills/tr-cli-agents/scripts/.gitkeep +0 -0
  131. package/scaffold/.agent/skills/total-recall/skills/tr-cli-agents/subagents/.gitkeep +0 -0
  132. package/scaffold/.agent/skills/total-recall/skills/tr-research/SKILL.md +0 -338
  133. package/scaffold/.agent/skills/total-recall/skills/tr-skill/SKILL.md +0 -282
  134. package/scaffold/.agent/skills/total-recall/skills/tr-skill/assets/skill-template/SKILL.md +0 -20
  135. package/scaffold/.agent/skills/total-recall/skills/tr-skill/evals/evals.json +0 -20
  136. package/scaffold/.agent/skills/total-recall/skills/tr-skill/hooks/on-skill-add.sh +0 -14
  137. package/scaffold/.agent/skills/total-recall/skills/tr-skill/hooks/on-skill-delete.sh +0 -14
  138. package/scaffold/.agent/skills/total-recall/skills/tr-skill/learnings/.gitkeep +0 -0
  139. package/scaffold/.agent/skills/total-recall/skills/tr-skill/references/.gitkeep +0 -0
  140. package/scaffold/.agent/skills/total-recall/skills/tr-skill/scripts/.gitkeep +0 -0
  141. package/scaffold/.agent/skills/total-recall/skills/tr-skill/scripts/create-skill.sh +0 -65
  142. package/scaffold/.agent/skills/total-recall/skills/tr-skill/scripts/enforce-skill-optimization.mjs +0 -135
  143. package/scaffold/.agent/skills/total-recall/skills/tr-skill/scripts/skill-watcher.mjs +0 -64
  144. package/scaffold/.agent/skills/total-recall/skills/tr-skill/subagents/audit-all-skills.md +0 -62
  145. package/scaffold/.agent/skills/total-recall/skills/tr-ssss/SKILL.md +0 -298
  146. package/scaffold/.agent/skills/total-recall/skills/tr-ssss/evals/evals.json +0 -17
  147. package/scaffold/.agent/skills/total-recall/skills/tr-ssss/references/CHANGELOG.md +0 -124
  148. package/scaffold/.agent/skills/total-recall/skills/tr-ssss/references/ssss-spec.md +0 -1325
  149. package/scaffold/.agent/skills/total-recall/skills/tr-ssss/scripts/validate-schema.mjs +0 -232
  150. package/scaffold/.agent/skills/total-recall/skills/tr-ssss/subagents/audit-ssss-node.md +0 -9
  151. /package/scaffold/.agent/skills/total-recall/{skills/tr-cli-agents/evals → modules/skill-deploy/scripts}/.gitkeep +0 -0
  152. /package/scaffold/.agent/skills/total-recall/{skills/tr-skill → modules/skill-deploy}/scripts/find-skills.mjs +0 -0
  153. /package/scaffold/.agent/skills/total-recall/{skills/tr-skill → modules/skill-deploy}/scripts/install-skill.mjs +0 -0
  154. /package/scaffold/.agent/skills/total-recall/{skills/tr-skill → modules/skill-deploy}/scripts/scan-skill.mjs +0 -0
@@ -0,0 +1,614 @@
1
+ import React, { useState, useEffect } from 'react';
2
+ import { fetchDesignDocs, fetchDesignDocContent } from '../api';
3
+
4
+ // ─── Types ──────────────────────────────────────────────────────────────────────
5
+
6
+ interface DocItem {
7
+ name: string;
8
+ path: string;
9
+ icon: string;
10
+ category: string;
11
+ }
12
+
13
+ interface KanbanCard {
14
+ id: string;
15
+ name: string;
16
+ emoji: string;
17
+ }
18
+
19
+ interface KanbanColumn {
20
+ id: string;
21
+ title: string;
22
+ accent: string;
23
+ cards: KanbanCard[];
24
+ count?: number;
25
+ collapsible?: boolean;
26
+ }
27
+
28
+ // ─── Static Data ────────────────────────────────────────────────────────────────
29
+
30
+ const CORE_DOCS: DocItem[] = [
31
+ { name: 'ARCHITECTURE.md', path: 'docs/ARCHITECTURE.md', icon: '🏗️', category: 'Core Docs' },
32
+ { name: 'SSSS.md', path: 'docs/SSSS.md', icon: '🔐', category: 'Core Docs' },
33
+ { name: 'IDE_INTEGRATION.md', path: 'docs/IDE_INTEGRATION.md', icon: '🔌', category: 'Core Docs' },
34
+ { name: 'CHANGELOG.md', path: 'docs/CHANGELOG.md', icon: '📋', category: 'Core Docs' },
35
+ ];
36
+
37
+ const DEV_GUIDES: DocItem[] = [
38
+ { name: 'README.md', path: 'README.md', icon: '📖', category: 'Developer Guides' },
39
+ ];
40
+
41
+ const KANBAN_COLUMNS: KanbanColumn[] = [
42
+ {
43
+ id: 'in-progress',
44
+ title: 'In Progress',
45
+ accent: '#3b82f6',
46
+ cards: [
47
+ { id: 'auto-update', name: 'Auto Update Feature', emoji: '🔄' },
48
+ { id: 'compaction-cache', name: 'Compaction Cache Bypass', emoji: '⚡' },
49
+ { id: 'memory-policy', name: 'Memory Policy Enforcement', emoji: '🛡️' },
50
+ ],
51
+ },
52
+ {
53
+ id: 'planned',
54
+ title: 'Planned',
55
+ accent: '#74b9ff',
56
+ cards: [
57
+ { id: 'system-resilience', name: 'System Resilience', emoji: '🧱' },
58
+ { id: 'gpu-intelligence', name: 'GPU Intelligence Network', emoji: '🧠' },
59
+ { id: 'living-memory', name: 'Living Memory Capsule (UltraChat)', emoji: '💊' },
60
+ { id: 'expo-mobile', name: 'Expo Mobile (stub)', emoji: '📱' },
61
+ ],
62
+ },
63
+ {
64
+ id: 'completed',
65
+ title: 'Completed',
66
+ accent: '#00cec9',
67
+ count: 35,
68
+ collapsible: true,
69
+ cards: [
70
+ { id: 'okf-integration', name: 'OKF Integration', emoji: '✅' },
71
+ { id: 'byom-architecture', name: 'BYOM Architecture', emoji: '✅' },
72
+ { id: 'cli-performance', name: 'CLI Performance Optimization', emoji: '✅' },
73
+ { id: 'ssss-portable-memory', name: 'SSSS Portable Memory', emoji: '✅' },
74
+ { id: 'embedding-pipeline', name: 'Embedding Pipeline v2', emoji: '✅' },
75
+ { id: 'surface-compiler', name: 'Surface Compiler', emoji: '✅' },
76
+ ],
77
+ },
78
+ {
79
+ id: 'archived',
80
+ title: 'Archived',
81
+ accent: '#636e72',
82
+ count: 3,
83
+ collapsible: true,
84
+ cards: [
85
+ { id: 'legacy-sync', name: 'Legacy Sync Protocol', emoji: '📦' },
86
+ { id: 'deprecated-cli', name: 'Deprecated CLI v1', emoji: '📦' },
87
+ { id: 'old-auth', name: 'Old Auth Flow', emoji: '📦' },
88
+ ],
89
+ },
90
+ ];
91
+
92
+ // ─── Simple Markdown Renderer ───────────────────────────────────────────────────
93
+
94
+ function renderMarkdown(md: string): React.ReactNode {
95
+ if (!md) return <></>;
96
+
97
+ let html = md
98
+ .replace(/&/g, '&amp;')
99
+ .replace(/</g, '&lt;')
100
+ .replace(/>/g, '&gt;');
101
+
102
+ // Tables (basic pipe tables) — process before other inline transforms
103
+ html = html.replace(
104
+ /^(\|.+\|)\n(\|[\s:|-]+\|)\n((?:\|.+\|\n?)+)/gm,
105
+ (_match, headerRow: string, _separator: string, bodyRows: string) => {
106
+ const headers = headerRow.split('|').filter((c: string) => c.trim());
107
+ const rows = bodyRows.trim().split('\n').map((r: string) =>
108
+ r.split('|').filter((c: string) => c.trim())
109
+ );
110
+ const thCells = headers.map((h: string) =>
111
+ `<th style="padding:8px 12px;text-align:left;border-bottom:2px solid var(--border-hover);font-weight:600;">${h.trim()}</th>`
112
+ ).join('');
113
+ const tbodyRows = rows.map((row: string[]) => {
114
+ const cells = row.map((c: string) =>
115
+ `<td style="padding:8px 12px;border-bottom:1px solid var(--border);">${c.trim()}</td>`
116
+ ).join('');
117
+ return `<tr>${cells}</tr>`;
118
+ }).join('');
119
+ return `<table style="width:100%;border-collapse:collapse;margin:16px 0;font-size:13px;"><thead><tr>${thCells}</tr></thead><tbody>${tbodyRows}</tbody></table>`;
120
+ }
121
+ );
122
+
123
+ // Headings
124
+ html = html.replace(/^#### (.*$)/gm, '<h4 style="margin:20px 0 8px;font-size:14px;color:var(--text-primary);">$1</h4>');
125
+ html = html.replace(/^### (.*$)/gm, '<h3 style="margin:24px 0 10px;font-size:16px;color:var(--text-primary);">$1</h3>');
126
+ html = html.replace(/^## (.*$)/gm, '<h2 style="margin:28px 0 12px;font-size:19px;color:var(--text-primary);border-bottom:1px solid var(--border);padding-bottom:8px;">$1</h2>');
127
+ html = html.replace(/^# (.*$)/gm, '<h1 style="margin:0 0 16px;font-size:24px;color:var(--text-primary);">$1</h1>');
128
+
129
+ // Code blocks (fenced)
130
+ html = html.replace(
131
+ /```[\w]*\n([\s\S]*?)```/g,
132
+ '<pre style="background:rgba(0,0,0,0.35);padding:14px 16px;border-radius:var(--radius-sm);border:1px solid var(--border);font-family:var(--font-mono);font-size:12.5px;overflow-x:auto;margin:12px 0;line-height:1.5;"><code>$1</code></pre>'
133
+ );
134
+
135
+ // Bold & Italic
136
+ html = html.replace(/\*\*\*(.*?)\*\*\*/g, '<strong><em>$1</em></strong>');
137
+ html = html.replace(/\*\*(.*?)\*\*/g, '<strong style="color:var(--text-primary);">$1</strong>');
138
+ html = html.replace(/(?<!\*)\*(?!\*)(.+?)(?<!\*)\*(?!\*)/g, '<em>$1</em>');
139
+
140
+ // Inline code
141
+ html = html.replace(
142
+ /`([^`]+)`/g,
143
+ '<code style="background:rgba(108,92,231,0.12);color:#b8b0f0;padding:2px 6px;border-radius:4px;font-family:var(--font-mono);font-size:12px;">$1</code>'
144
+ );
145
+
146
+ // Blockquotes
147
+ html = html.replace(
148
+ /^&gt; (.*$)/gm,
149
+ '<blockquote style="border-left:3px solid var(--accent);padding:8px 14px;color:var(--text-secondary);margin:12px 0;background:rgba(108,92,231,0.05);border-radius:0 var(--radius-sm) var(--radius-sm) 0;">$1</blockquote>'
150
+ );
151
+
152
+ // Unordered lists
153
+ html = html.replace(
154
+ /^- (.*$)/gm,
155
+ '<li style="margin-left:20px;list-style-type:disc;margin-bottom:4px;">$1</li>'
156
+ );
157
+
158
+ // Ordered lists
159
+ html = html.replace(
160
+ /^\d+\. (.*$)/gm,
161
+ '<li style="margin-left:20px;list-style-type:decimal;margin-bottom:4px;">$1</li>'
162
+ );
163
+
164
+ // Line breaks
165
+ html = html.replace(/\n/g, '<br />');
166
+
167
+ return <div dangerouslySetInnerHTML={{ __html: html }} className="markdown-preview-block" />;
168
+ }
169
+
170
+ // ─── Component ──────────────────────────────────────────────────────────────────
171
+
172
+ export default function DesignDocsPage() {
173
+ const [activeTab, setActiveTab] = useState<'architecture' | 'board'>('architecture');
174
+
175
+ // Architecture docs state
176
+ const [selectedDoc, setSelectedDoc] = useState<DocItem>(CORE_DOCS[0]);
177
+ const [docContent, setDocContent] = useState<string>('');
178
+ const [docLoading, setDocLoading] = useState(false);
179
+ const [docError, setDocError] = useState<string | null>(null);
180
+ const [, setDocsFromApi] = useState<Array<{ name: string; path: string; size: number; modified: string; category: string }>>([]);
181
+
182
+ // Kanban state
183
+ const [expandedColumns, setExpandedColumns] = useState<Record<string, boolean>>({});
184
+
185
+ // Load docs list on mount
186
+ useEffect(() => {
187
+ async function loadDocsList() {
188
+ try {
189
+ const data = await fetchDesignDocs();
190
+ setDocsFromApi(data);
191
+ } catch {
192
+ // Silently fall back to static doc list
193
+ }
194
+ }
195
+ loadDocsList();
196
+ }, []);
197
+
198
+ // Load selected doc content
199
+ useEffect(() => {
200
+ if (activeTab !== 'architecture' || !selectedDoc) return;
201
+ let cancelled = false;
202
+
203
+ async function loadContent() {
204
+ setDocLoading(true);
205
+ setDocError(null);
206
+ try {
207
+ const data = await fetchDesignDocContent(selectedDoc.path);
208
+ if (!cancelled) setDocContent(data.content);
209
+ } catch {
210
+ if (!cancelled) {
211
+ setDocError(selectedDoc.path);
212
+ setDocContent('');
213
+ }
214
+ } finally {
215
+ if (!cancelled) setDocLoading(false);
216
+ }
217
+ }
218
+ loadContent();
219
+ return () => { cancelled = true; };
220
+ }, [selectedDoc, activeTab]);
221
+
222
+ const toggleColumn = (colId: string) => {
223
+ setExpandedColumns(prev => ({ ...prev, [colId]: !prev[colId] }));
224
+ };
225
+
226
+ // ─── Sidebar Section Renderer ───────────────────────────────────────────────
227
+
228
+ const renderSidebarSection = (title: string, items: DocItem[]) => (
229
+ <div style={{ marginBottom: 20 }}>
230
+ <div
231
+ style={{
232
+ fontSize: 10,
233
+ fontWeight: 700,
234
+ textTransform: 'uppercase',
235
+ letterSpacing: '0.08em',
236
+ color: 'var(--text-tertiary)',
237
+ padding: '0 12px',
238
+ marginBottom: 8,
239
+ }}
240
+ >
241
+ {title}
242
+ </div>
243
+ {items.map(item => {
244
+ const isActive = selectedDoc.path === item.path;
245
+ return (
246
+ <button
247
+ id={`doc-nav-${item.name.replace(/\./g, '-').toLowerCase()}`}
248
+ key={item.path}
249
+ onClick={() => setSelectedDoc(item)}
250
+ style={{
251
+ display: 'flex',
252
+ alignItems: 'center',
253
+ gap: 10,
254
+ width: '100%',
255
+ textAlign: 'left',
256
+ padding: '9px 12px',
257
+ borderRadius: 'var(--radius-sm)',
258
+ background: isActive ? 'var(--accent-muted)' : 'transparent',
259
+ color: isActive ? 'var(--accent-hover)' : 'var(--text-secondary)',
260
+ border: 'none',
261
+ cursor: 'pointer',
262
+ transition: 'var(--transition-normal)',
263
+ fontSize: 13,
264
+ fontWeight: isActive ? 600 : 400,
265
+ }}
266
+ >
267
+ <span style={{ fontSize: 15, flexShrink: 0 }}>{item.icon}</span>
268
+ <span style={{ overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
269
+ {item.name}
270
+ </span>
271
+ </button>
272
+ );
273
+ })}
274
+ </div>
275
+ );
276
+
277
+ // ─── Architecture Tab ───────────────────────────────────────────────────────
278
+
279
+ const renderArchitectureTab = () => (
280
+ <div
281
+ id="architecture-panel"
282
+ style={{ display: 'flex', gap: 24, minHeight: '65vh' }}
283
+ >
284
+ {/* Sidebar */}
285
+ <div
286
+ id="docs-sidebar"
287
+ style={{
288
+ width: 220,
289
+ flexShrink: 0,
290
+ background: 'var(--bg-secondary)',
291
+ border: '1px solid var(--border)',
292
+ borderRadius: 'var(--radius-md)',
293
+ padding: '16px 8px',
294
+ overflowY: 'auto',
295
+ }}
296
+ >
297
+ {renderSidebarSection('Core Docs', CORE_DOCS)}
298
+ {renderSidebarSection('Developer Guides', DEV_GUIDES)}
299
+ </div>
300
+
301
+ {/* Main Viewer */}
302
+ <div
303
+ id="docs-viewer"
304
+ style={{
305
+ flex: 1,
306
+ background: 'var(--bg-secondary)',
307
+ border: '1px solid var(--border)',
308
+ borderRadius: 'var(--radius-md)',
309
+ padding: '24px 32px',
310
+ overflowY: 'auto',
311
+ maxHeight: '75vh',
312
+ }}
313
+ >
314
+ {/* Breadcrumb */}
315
+ <div
316
+ id="docs-breadcrumb"
317
+ style={{
318
+ display: 'flex',
319
+ alignItems: 'center',
320
+ gap: 6,
321
+ fontSize: 12,
322
+ color: 'var(--text-tertiary)',
323
+ marginBottom: 20,
324
+ fontFamily: 'var(--font-mono)',
325
+ }}
326
+ >
327
+ <span>Total Recall</span>
328
+ <span style={{ color: 'var(--text-tertiary)' }}>›</span>
329
+ <span>docs</span>
330
+ <span style={{ color: 'var(--text-tertiary)' }}>›</span>
331
+ <span style={{ color: 'var(--accent)' }}>{selectedDoc.name}</span>
332
+ </div>
333
+
334
+ {/* Content */}
335
+ {docLoading ? (
336
+ <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
337
+ {[200, 120, 280, 80, 160].map((w, i) => (
338
+ <div
339
+ key={i}
340
+ className="skeleton"
341
+ style={{ height: 16, width: `${w}px`, maxWidth: '100%', borderRadius: 4 }}
342
+ />
343
+ ))}
344
+ </div>
345
+ ) : docError ? (
346
+ <div
347
+ id="doc-fallback-message"
348
+ style={{
349
+ background: 'var(--warning-muted)',
350
+ border: '1px solid rgba(253, 203, 110, 0.2)',
351
+ borderRadius: 'var(--radius-sm)',
352
+ padding: '20px 24px',
353
+ color: 'var(--text-secondary)',
354
+ lineHeight: 1.7,
355
+ }}
356
+ >
357
+ <div style={{ marginBottom: 8, color: 'var(--warning)', fontWeight: 600 }}>
358
+ 📄 Document not available via API
359
+ </div>
360
+ <div>
361
+ This document is available in your project at{' '}
362
+ <code
363
+ style={{
364
+ background: 'rgba(108,92,231,0.12)',
365
+ color: '#b8b0f0',
366
+ padding: '2px 6px',
367
+ borderRadius: 4,
368
+ fontFamily: 'var(--font-mono)',
369
+ fontSize: 12,
370
+ }}
371
+ >
372
+ {docError}
373
+ </code>
374
+ . Open it in your editor to view.
375
+ </div>
376
+ </div>
377
+ ) : (
378
+ <div style={{ color: 'var(--text-primary)', lineHeight: 1.75, fontSize: 14 }}>
379
+ {renderMarkdown(docContent)}
380
+ </div>
381
+ )}
382
+ </div>
383
+ </div>
384
+ );
385
+
386
+ // ─── Kanban Board Tab ─────────────────────────────────────────────────────────
387
+
388
+ const renderKanbanCard = (card: KanbanCard) => (
389
+ <div
390
+ id={`kanban-card-${card.id}`}
391
+ key={card.id}
392
+ style={{
393
+ background: 'var(--bg-tertiary)',
394
+ border: '1px solid var(--border)',
395
+ borderRadius: 'var(--radius-sm)',
396
+ padding: '12px 14px',
397
+ cursor: 'default',
398
+ transition: 'var(--transition-normal)',
399
+ display: 'flex',
400
+ alignItems: 'center',
401
+ gap: 10,
402
+ }}
403
+ onMouseEnter={e => {
404
+ (e.currentTarget as HTMLElement).style.transform = 'translateY(-2px)';
405
+ (e.currentTarget as HTMLElement).style.boxShadow = '0 4px 12px rgba(0,0,0,0.3)';
406
+ (e.currentTarget as HTMLElement).style.borderColor = 'var(--border-hover)';
407
+ }}
408
+ onMouseLeave={e => {
409
+ (e.currentTarget as HTMLElement).style.transform = 'translateY(0)';
410
+ (e.currentTarget as HTMLElement).style.boxShadow = 'none';
411
+ (e.currentTarget as HTMLElement).style.borderColor = 'var(--border)';
412
+ }}
413
+ >
414
+ <span style={{ fontSize: 16, flexShrink: 0 }}>{card.emoji}</span>
415
+ <span style={{ fontSize: 13, fontWeight: 500, color: 'var(--text-primary)' }}>
416
+ {card.name}
417
+ </span>
418
+ </div>
419
+ );
420
+
421
+ const renderKanbanColumn = (col: KanbanColumn) => {
422
+ const isExpanded = expandedColumns[col.id] ?? !col.collapsible;
423
+ const visibleCards = isExpanded ? col.cards : [];
424
+
425
+ return (
426
+ <div
427
+ id={`kanban-col-${col.id}`}
428
+ key={col.id}
429
+ style={{
430
+ minWidth: 260,
431
+ flex: 1,
432
+ maxWidth: 320,
433
+ background: 'var(--bg-secondary)',
434
+ border: '1px solid var(--border)',
435
+ borderRadius: 'var(--radius-md)',
436
+ borderTop: `4px solid ${col.accent}`,
437
+ display: 'flex',
438
+ flexDirection: 'column',
439
+ overflow: 'hidden',
440
+ }}
441
+ >
442
+ {/* Column Header */}
443
+ <div
444
+ style={{
445
+ padding: '14px 16px 10px',
446
+ display: 'flex',
447
+ alignItems: 'center',
448
+ justifyContent: 'space-between',
449
+ }}
450
+ >
451
+ <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
452
+ <span style={{ fontWeight: 600, fontSize: 14, color: 'var(--text-primary)' }}>
453
+ {col.title}
454
+ </span>
455
+ <span
456
+ className="badge"
457
+ style={{
458
+ background: `${col.accent}22`,
459
+ color: col.accent,
460
+ fontSize: 11,
461
+ padding: '2px 8px',
462
+ borderRadius: 10,
463
+ fontWeight: 600,
464
+ }}
465
+ >
466
+ {col.count ?? col.cards.length}
467
+ </span>
468
+ </div>
469
+ {col.collapsible && (
470
+ <button
471
+ id={`kanban-toggle-${col.id}`}
472
+ className="btn btn-ghost"
473
+ onClick={() => toggleColumn(col.id)}
474
+ style={{
475
+ fontSize: 12,
476
+ padding: '4px 10px',
477
+ color: 'var(--text-secondary)',
478
+ background: 'transparent',
479
+ borderRadius: 'var(--radius-sm)',
480
+ }}
481
+ >
482
+ {isExpanded ? 'Collapse' : 'Expand'}
483
+ </button>
484
+ )}
485
+ </div>
486
+
487
+ {/* Cards */}
488
+ <div
489
+ style={{
490
+ padding: '0 12px 14px',
491
+ display: 'flex',
492
+ flexDirection: 'column',
493
+ gap: 8,
494
+ flex: 1,
495
+ }}
496
+ >
497
+ {col.collapsible && !isExpanded ? (
498
+ <div
499
+ style={{
500
+ color: 'var(--text-tertiary)',
501
+ fontSize: 12,
502
+ textAlign: 'center',
503
+ padding: '12px 0',
504
+ cursor: 'pointer',
505
+ }}
506
+ onClick={() => toggleColumn(col.id)}
507
+ >
508
+ {col.count ?? col.cards.length} projects — click to expand
509
+ </div>
510
+ ) : (
511
+ visibleCards.map(card => renderKanbanCard(card))
512
+ )}
513
+ </div>
514
+ </div>
515
+ );
516
+ };
517
+
518
+ const renderBoardTab = () => (
519
+ <div id="board-panel">
520
+ <div
521
+ id="kanban-board"
522
+ style={{
523
+ display: 'flex',
524
+ gap: 16,
525
+ overflowX: 'auto',
526
+ paddingBottom: 16,
527
+ }}
528
+ >
529
+ {KANBAN_COLUMNS.map(col => renderKanbanColumn(col))}
530
+ </div>
531
+ </div>
532
+ );
533
+
534
+ // ─── Main Render ──────────────────────────────────────────────────────────────
535
+
536
+ const tabs: { key: typeof activeTab; label: string; icon: string }[] = [
537
+ { key: 'architecture', label: 'Architecture', icon: '📐' },
538
+ { key: 'board', label: 'Project Board', icon: '📋' },
539
+ ];
540
+
541
+ return (
542
+ <div className="page" style={{ padding: '24px 28px', maxWidth: 1200, margin: '0 auto' }}>
543
+ {/* Page Header */}
544
+ <div className="page-header" style={{ marginBottom: 24 }}>
545
+ <h1 style={{ fontSize: 22, fontWeight: 700 }}>Design Docs & Projects</h1>
546
+ <p style={{ color: 'var(--text-secondary)', fontSize: 13, marginTop: 4 }}>
547
+ Architecture documentation, specifications, and project tracking board.
548
+ </p>
549
+ </div>
550
+
551
+ {/* Tab Navigation */}
552
+ <div
553
+ id="design-docs-tabs"
554
+ style={{
555
+ display: 'inline-flex',
556
+ gap: 0,
557
+ marginBottom: 24,
558
+ borderBottom: '1px solid var(--border)',
559
+ }}
560
+ >
561
+ {tabs.map(tab => {
562
+ const isActive = activeTab === tab.key;
563
+ return (
564
+ <button
565
+ id={`tab-${tab.key}`}
566
+ key={tab.key}
567
+ onClick={() => setActiveTab(tab.key)}
568
+ style={{
569
+ display: 'flex',
570
+ alignItems: 'center',
571
+ gap: 7,
572
+ padding: '10px 20px',
573
+ background: 'transparent',
574
+ color: isActive ? 'var(--accent)' : 'var(--text-secondary)',
575
+ fontSize: 14,
576
+ fontWeight: isActive ? 600 : 400,
577
+ borderBottom: isActive ? '2px solid var(--accent)' : '2px solid transparent',
578
+ transition: 'var(--transition-normal)',
579
+ cursor: 'pointer',
580
+ marginBottom: -1,
581
+ }}
582
+ >
583
+ <span>{tab.icon}</span>
584
+ {tab.label}
585
+ </button>
586
+ );
587
+ })}
588
+ </div>
589
+
590
+ {/* Tab Content */}
591
+ {activeTab === 'architecture' ? renderArchitectureTab() : renderBoardTab()}
592
+
593
+ {/* ─── Responsive Styles ─────────────────────────────────────────────────── */}
594
+ <style>{`
595
+ @media (max-width: 768px) {
596
+ #architecture-panel {
597
+ flex-direction: column !important;
598
+ }
599
+ #docs-sidebar {
600
+ width: 100% !important;
601
+ max-height: 200px;
602
+ }
603
+ #kanban-board {
604
+ flex-direction: column !important;
605
+ }
606
+ #kanban-board > div {
607
+ max-width: 100% !important;
608
+ min-width: 100% !important;
609
+ }
610
+ }
611
+ `}</style>
612
+ </div>
613
+ );
614
+ }
@@ -35,7 +35,11 @@ export default function FilesPage() {
35
35
  listSkills()
36
36
  ])
37
37
  setFiles(filesData)
38
- setSkills(skillsData)
38
+ // Skills API returns { skills, repos } catalog — flatten for this page
39
+ const flat = Array.isArray(skillsData)
40
+ ? skillsData
41
+ : (skillsData?.skills || [])
42
+ setSkills(flat as import('../types').FileNode[])
39
43
  setError("")
40
44
  } catch (e) {
41
45
  setError((e as Error).message)
@@ -121,10 +125,10 @@ export default function FilesPage() {
121
125
  setScriptLoading(true)
122
126
  try {
123
127
  const defaultCode = name.endsWith(".py")
124
- ? "#!/usr/bin/env python3\nprint('Hello from SSSS Sovereign Automation!')\n"
128
+ ? "#!/usr/bin/env python3\nprint('Hello from Total Recall automation!')\n"
125
129
  : name.endsWith(".sh")
126
- ? "#!/bin/bash\necho 'Hello from SSSS Sovereign Automation!'\n"
127
- : "/**\n * SSSS Skills Automation Script\n */\nconsole.log(\"Hello from SSSS Sovereign Automation!\");\n"
130
+ ? "#!/bin/bash\necho 'Hello from Total Recall automation!'\n"
131
+ : "/**\n * Total Recall skills automation script\n */\nconsole.log(\"Hello from Total Recall automation!\");\n"
128
132
 
129
133
  await saveScript(name, defaultCode)
130
134
  setNewScriptName("")
@@ -143,7 +147,7 @@ export default function FilesPage() {
143
147
  <div className="page-header" style={{ display: "flex", justifyContent: "space-between", alignItems: "flex-end", marginBottom: 20 }}>
144
148
  <div>
145
149
  <h1>Storage & Automations</h1>
146
- <p>Manage sovereign files, runtime skills, and automation scripts</p>
150
+ <p>Manage local files, runtime skills, and automation scripts</p>
147
151
  </div>
148
152
 
149
153
  {/* Navigation Tabs */}
@@ -176,7 +180,7 @@ export default function FilesPage() {
176
180
 
177
181
  {activeTab === "files" && (
178
182
  <div className="health-log" style={{ background: "rgba(15,23,42,0.45)", backdropFilter: "blur(12px)", border: "1px solid var(--border)", borderRadius: 12, padding: 24 }}>
179
- <h2 style={{ fontSize: 16, marginBottom: 12, borderBottom: "1px solid var(--border)", paddingBottom: 8, color: "#fff" }}>Sovereign Files (~/.agent/files/)</h2>
183
+ <h2 style={{ fontSize: 16, marginBottom: 12, borderBottom: "1px solid var(--border)", paddingBottom: 8, color: "#fff" }}>Local Files (~/.agent/files/)</h2>
180
184
  <table style={{ width: "100%", textAlign: "left", borderCollapse: "collapse" }}>
181
185
  <thead>
182
186
  <tr>
@@ -17,7 +17,7 @@ export default function GraphPage({ activeBrainId }: { activeBrainId?: string })
17
17
  try {
18
18
  const [nodes, researchRes, threadsRes] = await Promise.all([
19
19
  listMemory(activeBrainId),
20
- listResearch(activeBrainId).catch(() => ({ items: [] })),
20
+ listResearch().catch(() => ({ items: [] })),
21
21
  fetchChatThreads().catch(() => [])
22
22
  ])
23
23
  setMemoryNodes(nodes)
@@ -35,8 +35,10 @@ export default function GraphPage({ activeBrainId }: { activeBrainId?: string })
35
35
  return (
36
36
  <div className="page" style={{ padding: 0, height: 'calc(100vh - 1px)', display: 'flex', flexDirection: 'column', overflow: 'hidden' }}>
37
37
  <div style={{ padding: '16px 24px', background: 'rgba(18, 18, 26, 0.45)', backdropFilter: 'blur(16px)', borderBottom: '1px solid var(--border)', flexShrink: 0 }}>
38
- <h1 style={{ fontSize: '18px', fontWeight: 700 }}>Sovereign Memory Network</h1>
39
- <p style={{ fontSize: '12px', color: 'var(--text-secondary)', marginTop: '2px' }}>Interactive 3D constellation layout of your knowledge vault, sessions, and active thoughts.</p>
38
+ <h1 style={{ fontSize: '18px', fontWeight: 700, letterSpacing: '-0.02em' }}>Memory Graph</h1>
39
+ <p style={{ fontSize: '12px', color: 'var(--text-secondary)', marginTop: '2px' }}>
40
+ 3D vault map — facts (blue), rules (cyan/rose), research (amber), sessions (teal).
41
+ </p>
40
42
  </div>
41
43
 
42
44
  <div style={{ flex: 1, position: 'relative', overflow: 'hidden' }}>