total-recall-brain 3.41.4 → 3.41.6

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 (147) hide show
  1. package/bin/total-recall.mjs +10 -6
  2. package/docs/reference/cli-reference.md +18 -0
  3. package/frontend/dist/assets/index-4tGQfTa2.js +5605 -0
  4. package/frontend/dist/assets/index-DtwsDyFM.css +1 -0
  5. package/frontend/dist/index.html +2 -2
  6. package/frontend/package.json +11 -0
  7. package/frontend/src/App.tsx +47 -122
  8. package/frontend/src/components/plugins/plugin-frame.ts +1 -0
  9. package/frontend/src/index.css +152 -86
  10. package/frontend/src/pages/HelpPage.tsx +13 -10
  11. package/frontend/src/pages/MemoryPage.tsx +28 -30
  12. package/frontend/src/pages/NetworkPage.tsx +3 -3
  13. package/frontend/src/pages/PluginsPage.tsx +6 -5
  14. package/frontend/src/pages/RulesPage.tsx +16 -12
  15. package/package.json +4 -3
  16. package/scaffold/.agent/skills/total-recall/plugins/code-quality/package-lock.json +3114 -36
  17. package/scaffold/.agent/skills/total-recall/plugins/code-quality/package.json +4 -1
  18. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/package-lock.json +3114 -36
  19. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/package.json +4 -1
  20. package/scaffold/.agent/skills/total-recall/plugins/embeddings/package-lock.json +3121 -33
  21. package/scaffold/.agent/skills/total-recall/plugins/embeddings/package.json +4 -1
  22. package/scaffold/.agent/skills/total-recall/plugins/git-sentinel/package-lock.json +3122 -34
  23. package/scaffold/.agent/skills/total-recall/plugins/git-sentinel/package.json +4 -1
  24. package/scaffold/.agent/skills/total-recall/plugins/mesh/package-lock.json +3127 -49
  25. package/scaffold/.agent/skills/total-recall/plugins/mesh/package.json +5 -2
  26. package/scaffold/.agent/skills/total-recall/plugins/mesh/src/core/mesh.mjs +1 -1
  27. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/capability/index.mjs +136 -7
  28. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/cli.mjs +135 -26
  29. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/package-lock.json +3121 -33
  30. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/package.json +5 -2
  31. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/plugin.json +228 -9
  32. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/skills/meta-harness/SKILL.md +24 -30
  33. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/alerts.mjs +29 -16
  34. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/cascade.mjs +73 -0
  35. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/coordinator.mjs +182 -365
  36. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/dispatch.mjs +33 -0
  37. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/documentation.mjs +40 -14
  38. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/executor.mjs +4 -4
  39. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/agy.mjs +187 -0
  40. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/claude.mjs +275 -0
  41. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/cline.mjs +132 -0
  42. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/codex.mjs +187 -0
  43. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/cursor.mjs +158 -0
  44. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/devin.mjs +157 -0
  45. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/dsh.mjs +183 -0
  46. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/grok.mjs +132 -0
  47. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/hermes.mjs +173 -0
  48. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/index.mjs +87 -0
  49. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/openclaw.mjs +173 -0
  50. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/pi.mjs +129 -0
  51. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate.mjs +12 -0
  52. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/json-reply.mjs +22 -0
  53. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/learner.mjs +72 -70
  54. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/model-catalog.mjs +195 -0
  55. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/paths.mjs +11 -0
  56. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/pool.mjs +36 -0
  57. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/review.mjs +169 -0
  58. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/router.mjs +136 -346
  59. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/runtime.mjs +1 -1
  60. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/ssss-store.mjs +20 -0
  61. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/telemetry.mjs +43 -0
  62. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/threads.mjs +156 -0
  63. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/worker.mjs +117 -35
  64. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/worktree.mjs +51 -0
  65. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/card.js +398 -57
  66. package/scaffold/.agent/skills/total-recall/plugins/openwiki/cli.mjs +304 -46
  67. package/scaffold/.agent/skills/total-recall/plugins/openwiki/package-lock.json +367 -41
  68. package/scaffold/.agent/skills/total-recall/plugins/openwiki/package.json +5 -2
  69. package/scaffold/.agent/skills/total-recall/plugins/openwiki/plugin.json +33 -0
  70. package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/config.mjs +2 -2
  71. package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/generate.mjs +159 -0
  72. package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/graph.mjs +197 -0
  73. package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/lint.mjs +153 -0
  74. package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/mesh-vaults.mjs +261 -0
  75. package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/refresh.mjs +151 -4
  76. package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/search.mjs +114 -0
  77. package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/token.mjs +96 -0
  78. package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/card.js +899 -662
  79. package/scaffold/.agent/skills/total-recall/plugins/openwiki/vendor/openwiki.mjs +8987 -0
  80. package/scaffold/.agent/skills/total-recall/plugins/openwiki/vendor/skills/mermaid-diagrams/SKILL.md +44 -0
  81. package/scaffold/.agent/skills/total-recall/plugins/openwiki/vendor/skills/write-connector/SKILL.md +56 -0
  82. package/scaffold/.agent/skills/total-recall/plugins/security/package-lock.json +3097 -81
  83. package/scaffold/.agent/skills/total-recall/plugins/security/package.json +4 -1
  84. package/src/cli/agent.mjs +12 -1
  85. package/src/cli/compact.mjs +108 -0
  86. package/src/cli/connect.mjs +56 -1
  87. package/src/cli/context.mjs +55 -23
  88. package/src/cli/doctor.mjs +5 -2
  89. package/src/cli/forget.mjs +2 -0
  90. package/src/cli/harness.mjs +62 -50
  91. package/src/cli/memory-entry.mjs +2 -2
  92. package/src/cli/preflight.mjs +152 -16
  93. package/src/cli/release.mjs +386 -0
  94. package/src/cli/remember.mjs +19 -1
  95. package/src/cli/rules.mjs +54 -12
  96. package/src/cli/startup.mjs +1 -1
  97. package/src/cli/status.mjs +12 -2
  98. package/src/core/claude-hooks.mjs +41 -3
  99. package/src/core/cli-commands.mjs +2 -0
  100. package/src/core/cli-semantic-index.mjs +3 -2
  101. package/src/core/conflict-detector.mjs +23 -12
  102. package/src/core/context-compactor.mjs +145 -0
  103. package/src/core/context-policy.mjs +20 -0
  104. package/src/core/duplicate-guard.mjs +350 -0
  105. package/src/core/meta-harness.mjs +31 -11
  106. package/src/core/preflight-gate.mjs +2 -2
  107. package/src/core/preflight-receipt.mjs +29 -1
  108. package/src/core/scaffold-plugins.mjs +7 -0
  109. package/src/core/stdio-flush.mjs +23 -0
  110. package/src/core/surface.mjs +33 -10
  111. package/src/server/invoke-durability.mjs +39 -0
  112. package/src/server/invoke-write-child.mjs +25 -0
  113. package/src/server/routes/invoke.mjs +7 -0
  114. package/src/server/routes/plugins.mjs +2 -2
  115. package/frontend/dist/assets/index-BIQmqDKP.css +0 -1
  116. package/frontend/dist/assets/index-CRzjQLu7.js +0 -5631
  117. package/frontend/src/components/DaemonLogsTab.tsx +0 -54
  118. package/frontend/src/components/ResearchAgendaTab.tsx +0 -712
  119. package/frontend/src/components/TaskQueueTab.tsx +0 -193
  120. package/frontend/src/components/VoiceInput.tsx +0 -112
  121. package/frontend/src/pages/ChatPage.tsx +0 -1059
  122. package/frontend/src/pages/CollabPage.tsx +0 -470
  123. package/frontend/src/pages/DesignDocsPage.tsx +0 -621
  124. package/frontend/src/pages/FilesPage.tsx +0 -393
  125. package/frontend/src/pages/HealthPage.tsx +0 -359
  126. package/frontend/src/pages/InboxPage.tsx +0 -83
  127. package/frontend/src/pages/InstructionsPage.tsx +0 -583
  128. package/frontend/src/pages/IntegrationsPage.tsx +0 -761
  129. package/frontend/src/pages/MeshPage.css +0 -58
  130. package/frontend/src/pages/MeshPage.tsx +0 -1219
  131. package/frontend/src/pages/OkfPage.tsx +0 -535
  132. package/frontend/src/pages/SandboxPage.tsx +0 -113
  133. package/frontend/src/pages/SkillsPage.tsx +0 -1994
  134. package/frontend/src/pages/TasksPage.tsx +0 -427
  135. package/frontend/src/pages/UsagePage.tsx +0 -702
  136. package/scaffold/.agent/skills/total-recall/plugins/cli-agents/README.md +0 -65
  137. package/scaffold/.agent/skills/total-recall/plugins/cli-agents/cli.mjs +0 -76
  138. package/scaffold/.agent/skills/total-recall/plugins/cli-agents/package.json +0 -19
  139. package/scaffold/.agent/skills/total-recall/plugins/cli-agents/plugin.json +0 -266
  140. package/scaffold/.agent/skills/total-recall/plugins/cli-agents/src/adapters/dsh.mjs +0 -446
  141. package/scaffold/.agent/skills/total-recall/plugins/cli-agents/src/documentation.mjs +0 -152
  142. package/scaffold/.agent/skills/total-recall/plugins/cli-agents/src/executor.mjs +0 -71
  143. package/scaffold/.agent/skills/total-recall/plugins/cli-agents/src/runtime.mjs +0 -36
  144. package/scaffold/.agent/skills/total-recall/plugins/cli-agents/src/setup.mjs +0 -35
  145. package/scaffold/.agent/skills/total-recall/plugins/cli-agents/src/worker.mjs +0 -175
  146. package/scaffold/.agent/skills/total-recall/plugins/cli-agents/ui/DESIGN.md +0 -32
  147. package/scaffold/.agent/skills/total-recall/plugins/cli-agents/ui/card.js +0 -575
@@ -1,621 +0,0 @@
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 KANBAN_COLUMNS: KanbanColumn[] = [
31
- {
32
- id: 'in-progress',
33
- title: 'In Progress',
34
- accent: '#3b82f6',
35
- cards: [
36
- { id: 'auto-update', name: 'Auto Update Feature', emoji: '🔄' },
37
- { id: 'compaction-cache', name: 'Compaction Cache Bypass', emoji: '⚡' },
38
- { id: 'memory-policy', name: 'Memory Policy Enforcement', emoji: '🛡️' },
39
- ],
40
- },
41
- {
42
- id: 'planned',
43
- title: 'Planned',
44
- accent: '#74b9ff',
45
- cards: [
46
- { id: 'system-resilience', name: 'System Resilience', emoji: '🧱' },
47
- { id: 'gpu-intelligence', name: 'GPU Intelligence Network', emoji: '🧠' },
48
- { id: 'living-memory', name: 'Living Memory Capsule (UltraChat)', emoji: '💊' },
49
- { id: 'expo-mobile', name: 'Expo Mobile (stub)', emoji: '📱' },
50
- ],
51
- },
52
- {
53
- id: 'completed',
54
- title: 'Completed',
55
- accent: '#00cec9',
56
- count: 35,
57
- collapsible: true,
58
- cards: [
59
- { id: 'okf-integration', name: 'OKF Integration', emoji: '✅' },
60
- { id: 'byom-architecture', name: 'BYOM Architecture', emoji: '✅' },
61
- { id: 'cli-performance', name: 'CLI Performance Optimization', emoji: '✅' },
62
- { id: 'ssss-portable-memory', name: 'SSSS Portable Memory', emoji: '✅' },
63
- { id: 'embedding-pipeline', name: 'Embedding Pipeline v2', emoji: '✅' },
64
- { id: 'surface-compiler', name: 'Surface Compiler', emoji: '✅' },
65
- ],
66
- },
67
- {
68
- id: 'archived',
69
- title: 'Archived',
70
- accent: '#636e72',
71
- count: 3,
72
- collapsible: true,
73
- cards: [
74
- { id: 'legacy-sync', name: 'Legacy Sync Protocol', emoji: '📦' },
75
- { id: 'deprecated-cli', name: 'Deprecated CLI v1', emoji: '📦' },
76
- { id: 'old-auth', name: 'Old Auth Flow', emoji: '📦' },
77
- ],
78
- },
79
- ];
80
-
81
- // ─── Simple Markdown Renderer ───────────────────────────────────────────────────
82
-
83
- function renderMarkdown(md: string): React.ReactNode {
84
- if (!md) return <></>;
85
-
86
- let html = md
87
- .replace(/&/g, '&amp;')
88
- .replace(/</g, '&lt;')
89
- .replace(/>/g, '&gt;');
90
-
91
- // Tables (basic pipe tables) — process before other inline transforms
92
- html = html.replace(
93
- /^(\|.+\|)\n(\|[\s:|-]+\|)\n((?:\|.+\|\n?)+)/gm,
94
- (_match, headerRow: string, _separator: string, bodyRows: string) => {
95
- const headers = headerRow.split('|').filter((c: string) => c.trim());
96
- const rows = bodyRows.trim().split('\n').map((r: string) =>
97
- r.split('|').filter((c: string) => c.trim())
98
- );
99
- const thCells = headers.map((h: string) =>
100
- `<th style="padding:8px 12px;text-align:left;border-bottom:2px solid var(--border-hover);font-weight:600;">${h.trim()}</th>`
101
- ).join('');
102
- const tbodyRows = rows.map((row: string[]) => {
103
- const cells = row.map((c: string) =>
104
- `<td style="padding:8px 12px;border-bottom:1px solid var(--border);">${c.trim()}</td>`
105
- ).join('');
106
- return `<tr>${cells}</tr>`;
107
- }).join('');
108
- return `<table style="width:100%;border-collapse:collapse;margin:16px 0;font-size:13px;"><thead><tr>${thCells}</tr></thead><tbody>${tbodyRows}</tbody></table>`;
109
- }
110
- );
111
-
112
- // Headings
113
- html = html.replace(/^#### (.*$)/gm, '<h4 style="margin:20px 0 8px;font-size:14px;color:var(--text-primary);">$1</h4>');
114
- html = html.replace(/^### (.*$)/gm, '<h3 style="margin:24px 0 10px;font-size:16px;color:var(--text-primary);">$1</h3>');
115
- 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>');
116
- html = html.replace(/^# (.*$)/gm, '<h1 style="margin:0 0 16px;font-size:24px;color:var(--text-primary);">$1</h1>');
117
-
118
- // Code blocks (fenced)
119
- html = html.replace(
120
- /```[\w]*\n([\s\S]*?)```/g,
121
- '<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>'
122
- );
123
-
124
- // Bold & Italic
125
- html = html.replace(/\*\*\*(.*?)\*\*\*/g, '<strong><em>$1</em></strong>');
126
- html = html.replace(/\*\*(.*?)\*\*/g, '<strong style="color:var(--text-primary);">$1</strong>');
127
- html = html.replace(/(?<!\*)\*(?!\*)(.+?)(?<!\*)\*(?!\*)/g, '<em>$1</em>');
128
-
129
- // Inline code
130
- html = html.replace(
131
- /`([^`]+)`/g,
132
- '<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>'
133
- );
134
-
135
- // Blockquotes
136
- html = html.replace(
137
- /^&gt; (.*$)/gm,
138
- '<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>'
139
- );
140
-
141
- // Unordered lists
142
- html = html.replace(
143
- /^- (.*$)/gm,
144
- '<li style="margin-left:20px;list-style-type:disc;margin-bottom:4px;">$1</li>'
145
- );
146
-
147
- // Ordered lists
148
- html = html.replace(
149
- /^\d+\. (.*$)/gm,
150
- '<li style="margin-left:20px;list-style-type:decimal;margin-bottom:4px;">$1</li>'
151
- );
152
-
153
- // Line breaks
154
- html = html.replace(/\n/g, '<br />');
155
-
156
- return <div dangerouslySetInnerHTML={{ __html: html }} className="markdown-preview-block" />;
157
- }
158
-
159
- // ─── Component ──────────────────────────────────────────────────────────────────
160
-
161
- export default function DesignDocsPage() {
162
- const [activeTab, setActiveTab] = useState<'architecture' | 'board'>('architecture');
163
-
164
- // Architecture docs state
165
- const [selectedDoc, setSelectedDoc] = useState<DocItem | null>(null);
166
- const [docContent, setDocContent] = useState<string>('');
167
- const [docLoading, setDocLoading] = useState(false);
168
- const [docError, setDocError] = useState<string | null>(null);
169
- const [docsFromApi, setDocsFromApi] = useState<DocItem[]>([]);
170
-
171
- // Kanban state
172
- const [expandedColumns, setExpandedColumns] = useState<Record<string, boolean>>({});
173
-
174
- // Load docs list on mount
175
- useEffect(() => {
176
- async function loadDocsList() {
177
- try {
178
- const data = await fetchDesignDocs();
179
- const docItems: DocItem[] = data.map(d => ({
180
- name: d.name,
181
- path: d.path,
182
- category: d.category || 'Other',
183
- icon: '📄',
184
- }));
185
- setDocsFromApi(docItems);
186
- if (docItems.length > 0) {
187
- setSelectedDoc(docItems[0]);
188
- }
189
- } catch {
190
- // Silently fall back
191
- }
192
- }
193
- loadDocsList();
194
- }, []);
195
-
196
- // Load selected doc content
197
- useEffect(() => {
198
- if (activeTab !== 'architecture' || !selectedDoc) return;
199
- let cancelled = false;
200
-
201
- async function loadContent() {
202
- setDocLoading(true);
203
- setDocError(null);
204
- try {
205
- const data = await fetchDesignDocContent(selectedDoc!.path);
206
- if (!cancelled) setDocContent(data.content);
207
- } catch {
208
- if (!cancelled) {
209
- setDocError(selectedDoc!.path);
210
- setDocContent('');
211
- }
212
- } finally {
213
- if (!cancelled) setDocLoading(false);
214
- }
215
- }
216
- loadContent();
217
- return () => { cancelled = true; };
218
- }, [selectedDoc, activeTab]);
219
-
220
- const toggleColumn = (colId: string) => {
221
- setExpandedColumns(prev => ({ ...prev, [colId]: !prev[colId] }));
222
- };
223
-
224
- // ─── Sidebar Section Renderer ───────────────────────────────────────────────
225
-
226
- const renderSidebarSection = (title: string, items: DocItem[]) => (
227
- <div style={{ marginBottom: 20 }}>
228
- <div
229
- style={{
230
- fontSize: 10,
231
- fontWeight: 700,
232
- textTransform: 'uppercase',
233
- letterSpacing: '0.08em',
234
- color: 'var(--text-tertiary)',
235
- padding: '0 12px',
236
- marginBottom: 8,
237
- }}
238
- >
239
- {title}
240
- </div>
241
- {items.map(item => {
242
- const isActive = selectedDoc?.path === item.path;
243
- return (
244
- <button
245
- id={`doc-nav-${item.name.replace(/\./g, '-').toLowerCase()}`}
246
- key={item.path}
247
- onClick={() => setSelectedDoc(item)}
248
- style={{
249
- display: 'flex',
250
- alignItems: 'center',
251
- gap: 10,
252
- width: '100%',
253
- textAlign: 'left',
254
- padding: '9px 12px',
255
- borderRadius: 'var(--radius-sm)',
256
- background: isActive ? 'var(--accent-muted)' : 'transparent',
257
- color: isActive ? 'var(--accent-hover)' : 'var(--text-secondary)',
258
- border: 'none',
259
- cursor: 'pointer',
260
- transition: 'var(--transition-normal)',
261
- fontSize: 13,
262
- fontWeight: isActive ? 600 : 400,
263
- }}
264
- >
265
- <span style={{ fontSize: 15, flexShrink: 0 }}>{item.icon}</span>
266
- <span style={{ overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
267
- {item.name}
268
- </span>
269
- </button>
270
- );
271
- })}
272
- </div>
273
- );
274
-
275
- // ─── Architecture Tab ───────────────────────────────────────────────────────
276
-
277
- const renderArchitectureTab = () => (
278
- <div
279
- id="architecture-panel"
280
- style={{ display: 'flex', gap: 24, minHeight: '65vh' }}
281
- >
282
- {/* Sidebar */}
283
- <div
284
- id="docs-sidebar"
285
- style={{
286
- width: 220,
287
- flexShrink: 0,
288
- background: 'var(--bg-secondary)',
289
- border: '1px solid var(--border)',
290
- borderRadius: 'var(--radius-md)',
291
- padding: '16px 8px',
292
- overflowY: 'auto',
293
- }}
294
- >
295
- {Object.entries(
296
- docsFromApi.reduce((acc, doc) => {
297
- acc[doc.category] = acc[doc.category] || [];
298
- acc[doc.category].push(doc);
299
- return acc;
300
- }, {} as Record<string, DocItem[]>)
301
- ).map(([category, items]) => (
302
- <React.Fragment key={category}>
303
- {renderSidebarSection(category, items)}
304
- </React.Fragment>
305
- ))}
306
- </div>
307
-
308
- {/* Main Viewer */}
309
- <div
310
- id="docs-viewer"
311
- style={{
312
- flex: 1,
313
- background: 'var(--bg-secondary)',
314
- border: '1px solid var(--border)',
315
- borderRadius: 'var(--radius-md)',
316
- padding: '24px 32px',
317
- overflowY: 'auto',
318
- maxHeight: '75vh',
319
- }}
320
- >
321
- {/* Breadcrumb */}
322
- <div
323
- id="docs-breadcrumb"
324
- style={{
325
- display: 'flex',
326
- alignItems: 'center',
327
- gap: 6,
328
- fontSize: 12,
329
- color: 'var(--text-tertiary)',
330
- marginBottom: 20,
331
- fontFamily: 'var(--font-mono)',
332
- }}
333
- >
334
- <span>Total Recall</span>
335
- <span style={{ color: 'var(--text-tertiary)' }}>›</span>
336
- <span>docs</span>
337
- <span style={{ color: 'var(--text-tertiary)' }}>›</span>
338
- <span style={{ color: 'var(--accent)' }}>{selectedDoc?.name}</span>
339
- </div>
340
-
341
- {/* Content */}
342
- {docLoading ? (
343
- <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
344
- {[200, 120, 280, 80, 160].map((w, i) => (
345
- <div
346
- key={i}
347
- className="skeleton"
348
- style={{ height: 16, width: `${w}px`, maxWidth: '100%', borderRadius: 4 }}
349
- />
350
- ))}
351
- </div>
352
- ) : docError ? (
353
- <div
354
- id="doc-fallback-message"
355
- style={{
356
- background: 'var(--warning-muted)',
357
- border: '1px solid rgba(253, 203, 110, 0.2)',
358
- borderRadius: 'var(--radius-sm)',
359
- padding: '20px 24px',
360
- color: 'var(--text-secondary)',
361
- lineHeight: 1.7,
362
- }}
363
- >
364
- <div style={{ marginBottom: 8, color: 'var(--warning)', fontWeight: 600 }}>
365
- 📄 Document not available via API
366
- </div>
367
- <div>
368
- This document is available in your project at{' '}
369
- <code
370
- style={{
371
- background: 'rgba(108,92,231,0.12)',
372
- color: '#b8b0f0',
373
- padding: '2px 6px',
374
- borderRadius: 4,
375
- fontFamily: 'var(--font-mono)',
376
- fontSize: 12,
377
- }}
378
- >
379
- {docError}
380
- </code>
381
- . Open it in your editor to view.
382
- </div>
383
- </div>
384
- ) : (
385
- <div style={{ color: 'var(--text-primary)', lineHeight: 1.75, fontSize: 14 }}>
386
- {renderMarkdown(docContent)}
387
- </div>
388
- )}
389
- </div>
390
- </div>
391
- );
392
-
393
- // ─── Kanban Board Tab ─────────────────────────────────────────────────────────
394
-
395
- const renderKanbanCard = (card: KanbanCard) => (
396
- <div
397
- id={`kanban-card-${card.id}`}
398
- key={card.id}
399
- style={{
400
- background: 'var(--bg-tertiary)',
401
- border: '1px solid var(--border)',
402
- borderRadius: 'var(--radius-sm)',
403
- padding: '12px 14px',
404
- cursor: 'default',
405
- transition: 'var(--transition-normal)',
406
- display: 'flex',
407
- alignItems: 'center',
408
- gap: 10,
409
- }}
410
- onMouseEnter={e => {
411
- (e.currentTarget as HTMLElement).style.transform = 'translateY(-2px)';
412
- (e.currentTarget as HTMLElement).style.boxShadow = '0 4px 12px rgba(0,0,0,0.3)';
413
- (e.currentTarget as HTMLElement).style.borderColor = 'var(--border-hover)';
414
- }}
415
- onMouseLeave={e => {
416
- (e.currentTarget as HTMLElement).style.transform = 'translateY(0)';
417
- (e.currentTarget as HTMLElement).style.boxShadow = 'none';
418
- (e.currentTarget as HTMLElement).style.borderColor = 'var(--border)';
419
- }}
420
- >
421
- <span style={{ fontSize: 16, flexShrink: 0 }}>{card.emoji}</span>
422
- <span style={{ fontSize: 13, fontWeight: 500, color: 'var(--text-primary)' }}>
423
- {card.name}
424
- </span>
425
- </div>
426
- );
427
-
428
- const renderKanbanColumn = (col: KanbanColumn) => {
429
- const isExpanded = expandedColumns[col.id] ?? !col.collapsible;
430
- const visibleCards = isExpanded ? col.cards : [];
431
-
432
- return (
433
- <div
434
- id={`kanban-col-${col.id}`}
435
- key={col.id}
436
- style={{
437
- minWidth: 260,
438
- flex: 1,
439
- maxWidth: 320,
440
- background: 'var(--bg-secondary)',
441
- border: '1px solid var(--border)',
442
- borderRadius: 'var(--radius-md)',
443
- borderTop: `4px solid ${col.accent}`,
444
- display: 'flex',
445
- flexDirection: 'column',
446
- overflow: 'hidden',
447
- }}
448
- >
449
- {/* Column Header */}
450
- <div
451
- style={{
452
- padding: '14px 16px 10px',
453
- display: 'flex',
454
- alignItems: 'center',
455
- justifyContent: 'space-between',
456
- }}
457
- >
458
- <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
459
- <span style={{ fontWeight: 600, fontSize: 14, color: 'var(--text-primary)' }}>
460
- {col.title}
461
- </span>
462
- <span
463
- className="badge"
464
- style={{
465
- background: `${col.accent}22`,
466
- color: col.accent,
467
- fontSize: 11,
468
- padding: '2px 8px',
469
- borderRadius: 10,
470
- fontWeight: 600,
471
- }}
472
- >
473
- {col.count ?? col.cards.length}
474
- </span>
475
- </div>
476
- {col.collapsible && (
477
- <button
478
- id={`kanban-toggle-${col.id}`}
479
- className="btn btn-ghost"
480
- onClick={() => toggleColumn(col.id)}
481
- style={{
482
- fontSize: 12,
483
- padding: '4px 10px',
484
- color: 'var(--text-secondary)',
485
- background: 'transparent',
486
- borderRadius: 'var(--radius-sm)',
487
- }}
488
- >
489
- {isExpanded ? 'Collapse' : 'Expand'}
490
- </button>
491
- )}
492
- </div>
493
-
494
- {/* Cards */}
495
- <div
496
- style={{
497
- padding: '0 12px 14px',
498
- display: 'flex',
499
- flexDirection: 'column',
500
- gap: 8,
501
- flex: 1,
502
- }}
503
- >
504
- {col.collapsible && !isExpanded ? (
505
- <div
506
- style={{
507
- color: 'var(--text-tertiary)',
508
- fontSize: 12,
509
- textAlign: 'center',
510
- padding: '12px 0',
511
- cursor: 'pointer',
512
- }}
513
- onClick={() => toggleColumn(col.id)}
514
- >
515
- {col.count ?? col.cards.length} projects — click to expand
516
- </div>
517
- ) : (
518
- visibleCards.map(card => renderKanbanCard(card))
519
- )}
520
- </div>
521
- </div>
522
- );
523
- };
524
-
525
- const renderBoardTab = () => (
526
- <div id="board-panel">
527
- <div
528
- id="kanban-board"
529
- style={{
530
- display: 'flex',
531
- gap: 16,
532
- overflowX: 'auto',
533
- paddingBottom: 16,
534
- }}
535
- >
536
- {KANBAN_COLUMNS.map(col => renderKanbanColumn(col))}
537
- </div>
538
- </div>
539
- );
540
-
541
- // ─── Main Render ──────────────────────────────────────────────────────────────
542
-
543
- const tabs: { key: typeof activeTab; label: string; icon: string }[] = [
544
- { key: 'architecture', label: 'Architecture', icon: '📐' },
545
- { key: 'board', label: 'Project Board', icon: '📋' },
546
- ];
547
-
548
- return (
549
- <div className="page" style={{ padding: '24px 28px', maxWidth: 1200, margin: '0 auto' }}>
550
- {/* Page Header */}
551
- <div className="page-header" style={{ marginBottom: 24 }}>
552
- <h1 style={{ fontSize: 22, fontWeight: 700 }}>Design Docs & Projects</h1>
553
- <p style={{ color: 'var(--text-secondary)', fontSize: 13, marginTop: 4 }}>
554
- Architecture documentation, specifications, and project tracking board.
555
- </p>
556
- </div>
557
-
558
- {/* Tab Navigation */}
559
- <div
560
- id="design-docs-tabs"
561
- style={{
562
- display: 'inline-flex',
563
- gap: 0,
564
- marginBottom: 24,
565
- borderBottom: '1px solid var(--border)',
566
- }}
567
- >
568
- {tabs.map(tab => {
569
- const isActive = activeTab === tab.key;
570
- return (
571
- <button
572
- id={`tab-${tab.key}`}
573
- key={tab.key}
574
- onClick={() => setActiveTab(tab.key)}
575
- style={{
576
- display: 'flex',
577
- alignItems: 'center',
578
- gap: 7,
579
- padding: '10px 20px',
580
- background: 'transparent',
581
- color: isActive ? 'var(--accent)' : 'var(--text-secondary)',
582
- fontSize: 14,
583
- fontWeight: isActive ? 600 : 400,
584
- borderBottom: isActive ? '2px solid var(--accent)' : '2px solid transparent',
585
- transition: 'var(--transition-normal)',
586
- cursor: 'pointer',
587
- marginBottom: -1,
588
- }}
589
- >
590
- <span>{tab.icon}</span>
591
- {tab.label}
592
- </button>
593
- );
594
- })}
595
- </div>
596
-
597
- {/* Tab Content */}
598
- {activeTab === 'architecture' ? renderArchitectureTab() : renderBoardTab()}
599
-
600
- {/* ─── Responsive Styles ─────────────────────────────────────────────────── */}
601
- <style>{`
602
- @media (max-width: 768px) {
603
- #architecture-panel {
604
- flex-direction: column !important;
605
- }
606
- #docs-sidebar {
607
- width: 100% !important;
608
- max-height: 200px;
609
- }
610
- #kanban-board {
611
- flex-direction: column !important;
612
- }
613
- #kanban-board > div {
614
- max-width: 100% !important;
615
- min-width: 100% !important;
616
- }
617
- }
618
- `}</style>
619
- </div>
620
- );
621
- }