total-recall-brain 3.41.5 → 3.42.0

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 (181) hide show
  1. package/bin/total-recall.mjs +7 -4
  2. package/frontend/dist/assets/index-4tGQfTa2.js +5605 -0
  3. package/frontend/dist/assets/index-DtwsDyFM.css +1 -0
  4. package/frontend/dist/index.html +2 -2
  5. package/frontend/package.json +11 -0
  6. package/frontend/src/App.tsx +47 -122
  7. package/frontend/src/components/plugins/plugin-frame.ts +1 -0
  8. package/frontend/src/index.css +152 -86
  9. package/frontend/src/pages/HelpPage.tsx +13 -10
  10. package/frontend/src/pages/MemoryPage.tsx +28 -30
  11. package/frontend/src/pages/NetworkPage.tsx +3 -3
  12. package/frontend/src/pages/PluginsPage.tsx +6 -5
  13. package/frontend/src/pages/RulesPage.tsx +16 -12
  14. package/package.json +3 -2
  15. package/scaffold/.agent/skills/total-recall/plugins/auth/package-lock.json +3118 -17
  16. package/scaffold/.agent/skills/total-recall/plugins/auth/package.json +7 -2
  17. package/scaffold/.agent/skills/total-recall/plugins/auth/src/cli-secret.mjs +84 -40
  18. package/scaffold/.agent/skills/total-recall/plugins/auth/src/exit-after-flush.mjs +22 -0
  19. package/scaffold/.agent/skills/total-recall/plugins/auth/src/provider-api-rotation.mjs +61 -6
  20. package/scaffold/.agent/skills/total-recall/plugins/auth/src/provider-catalog.mjs +1 -0
  21. package/scaffold/.agent/skills/total-recall/plugins/auth/src/secrets-remote-deploy.mjs +8 -0
  22. package/scaffold/.agent/skills/total-recall/plugins/auth/src/secrets-rotate.mjs +20 -1
  23. package/scaffold/.agent/skills/total-recall/plugins/auth/src/secrets-store.mjs +3 -0
  24. package/scaffold/.agent/skills/total-recall/plugins/code-quality/core/state.mjs +15 -7
  25. package/scaffold/.agent/skills/total-recall/plugins/code-quality/package-lock.json +8 -8
  26. package/scaffold/.agent/skills/total-recall/plugins/code-quality/package.json +3 -0
  27. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/package-lock.json +8 -8
  28. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/package.json +3 -0
  29. package/scaffold/.agent/skills/total-recall/plugins/embeddings/package-lock.json +8 -8
  30. package/scaffold/.agent/skills/total-recall/plugins/embeddings/package.json +3 -0
  31. package/scaffold/.agent/skills/total-recall/plugins/git-sentinel/package-lock.json +8 -8
  32. package/scaffold/.agent/skills/total-recall/plugins/git-sentinel/package.json +3 -0
  33. package/scaffold/.agent/skills/total-recall/plugins/mesh/package-lock.json +8 -8
  34. package/scaffold/.agent/skills/total-recall/plugins/mesh/package.json +4 -1
  35. package/scaffold/.agent/skills/total-recall/plugins/mesh/src/core/mesh.mjs +1 -1
  36. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/README.md +51 -7
  37. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/capability/index.mjs +136 -7
  38. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/cli.mjs +184 -33
  39. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/package-lock.json +8 -8
  40. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/package.json +4 -1
  41. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/plugin.json +275 -10
  42. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/skills/meta-harness/SKILL.md +24 -30
  43. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/alerts.mjs +29 -16
  44. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/cascade.mjs +86 -0
  45. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/compat-harness.mjs +110 -0
  46. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/coordinator.mjs +206 -363
  47. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/dispatch.mjs +38 -0
  48. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/documentation.mjs +28 -10
  49. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/executor.mjs +11 -7
  50. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/agy.mjs +187 -0
  51. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/claude.mjs +275 -0
  52. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/cline.mjs +132 -0
  53. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/codex.mjs +187 -0
  54. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/cursor.mjs +158 -0
  55. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/devin.mjs +157 -0
  56. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/dsh.mjs +183 -0
  57. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/grok.mjs +132 -0
  58. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/hermes.mjs +173 -0
  59. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/index.mjs +87 -0
  60. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/openclaw.mjs +173 -0
  61. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/pi.mjs +129 -0
  62. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate.mjs +18 -0
  63. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/json-reply.mjs +22 -0
  64. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/learner.mjs +98 -69
  65. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/model-catalog.mjs +195 -0
  66. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/paths.mjs +16 -0
  67. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/pool.mjs +52 -0
  68. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/process-manager.mjs +222 -0
  69. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/process-worker.mjs +18 -0
  70. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/reasoning.mjs +94 -0
  71. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/remote-operation.mjs +70 -0
  72. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/review.mjs +210 -0
  73. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/router.mjs +161 -346
  74. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/runtime.mjs +1 -1
  75. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/ssss-store.mjs +20 -0
  76. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/telemetry.mjs +43 -0
  77. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/termination.mjs +24 -0
  78. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/threads.mjs +119 -0
  79. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/worker.mjs +217 -54
  80. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/worktree.mjs +86 -0
  81. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/card.js +492 -61
  82. package/scaffold/.agent/skills/total-recall/plugins/openwiki/cli.mjs +23 -1
  83. package/scaffold/.agent/skills/total-recall/plugins/openwiki/package-lock.json +8 -8
  84. package/scaffold/.agent/skills/total-recall/plugins/openwiki/package.json +3 -0
  85. package/scaffold/.agent/skills/total-recall/plugins/openwiki/plugin.json +120 -190
  86. package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/context-provider.mjs +113 -0
  87. package/scaffold/.agent/skills/total-recall/plugins/openwiki/vendor/openwiki.mjs +1 -1
  88. package/scaffold/.agent/skills/total-recall/plugins/openwiki/vendor/skills/mermaid-diagrams/SKILL.md +44 -0
  89. package/scaffold/.agent/skills/total-recall/plugins/openwiki/vendor/skills/write-connector/SKILL.md +56 -0
  90. package/scaffold/.agent/skills/total-recall/plugins/security/package-lock.json +8 -8
  91. package/scaffold/.agent/skills/total-recall/plugins/security/package.json +3 -0
  92. package/src/cli/agent.mjs +23 -7
  93. package/src/cli/compact.mjs +3 -3
  94. package/src/cli/connect.mjs +56 -1
  95. package/src/cli/context.mjs +62 -26
  96. package/src/cli/doctor.mjs +5 -2
  97. package/src/cli/harness.mjs +73 -143
  98. package/src/cli/init.mjs +4 -2
  99. package/src/cli/memory-entry.mjs +2 -2
  100. package/src/cli/preflight.mjs +197 -18
  101. package/src/cli/remember.mjs +19 -1
  102. package/src/cli/rules.mjs +54 -12
  103. package/src/cli/startup.mjs +1 -1
  104. package/src/cli/status.mjs +12 -2
  105. package/src/core/agent-manager.mjs +23 -329
  106. package/src/core/claude-hooks.mjs +41 -3
  107. package/src/core/cli-semantic-index.mjs +3 -2
  108. package/src/core/conflict-detector.mjs +23 -12
  109. package/src/core/context-compactor.mjs +4 -1
  110. package/src/core/context-compiler.mjs +16 -25
  111. package/src/core/context-policy.mjs +20 -0
  112. package/src/core/context-providers.mjs +69 -0
  113. package/src/core/duplicate-guard.mjs +350 -0
  114. package/src/core/meta-harness.mjs +27 -729
  115. package/src/core/plugin-runner.mjs +12 -5
  116. package/src/core/plugin-runtime.mjs +4 -2
  117. package/src/core/preflight-gate.mjs +2 -2
  118. package/src/core/preflight-receipt.mjs +28 -0
  119. package/src/core/runtime.mjs +30 -604
  120. package/src/core/scaffold-plugins.mjs +7 -0
  121. package/src/core/stdio-flush.mjs +23 -0
  122. package/src/core/surface.mjs +33 -10
  123. package/src/core/task-context.mjs +122 -0
  124. package/src/server/routes/context.mjs +4 -1
  125. package/src/server/routes/plugins.mjs +2 -2
  126. package/frontend/dist/assets/index-BIQmqDKP.css +0 -1
  127. package/frontend/dist/assets/index-WT3gs-x6.js +0 -5631
  128. package/frontend/src/components/DaemonLogsTab.tsx +0 -54
  129. package/frontend/src/components/ResearchAgendaTab.tsx +0 -712
  130. package/frontend/src/components/TaskQueueTab.tsx +0 -193
  131. package/frontend/src/components/VoiceInput.tsx +0 -112
  132. package/frontend/src/pages/ChatPage.tsx +0 -1059
  133. package/frontend/src/pages/CollabPage.tsx +0 -470
  134. package/frontend/src/pages/DesignDocsPage.tsx +0 -621
  135. package/frontend/src/pages/FilesPage.tsx +0 -393
  136. package/frontend/src/pages/HealthPage.tsx +0 -359
  137. package/frontend/src/pages/InboxPage.tsx +0 -83
  138. package/frontend/src/pages/InstructionsPage.tsx +0 -583
  139. package/frontend/src/pages/IntegrationsPage.tsx +0 -761
  140. package/frontend/src/pages/MeshPage.css +0 -58
  141. package/frontend/src/pages/MeshPage.tsx +0 -1219
  142. package/frontend/src/pages/OkfPage.tsx +0 -535
  143. package/frontend/src/pages/SandboxPage.tsx +0 -113
  144. package/frontend/src/pages/SkillsPage.tsx +0 -1994
  145. package/frontend/src/pages/TasksPage.tsx +0 -427
  146. package/frontend/src/pages/UsagePage.tsx +0 -702
  147. package/scaffold/.agent/skills/decision/SKILL.md +0 -20
  148. package/scaffold/.agent/skills/decision/references/integration.md +0 -25
  149. package/scaffold/.agent/skills/decision/references/use-cases.md +0 -20
  150. package/scaffold/.agent/skills/meta-harness/SKILL.md +0 -15
  151. package/scaffold/.agent/skills/meta-harness/references/optimized/index.md +0 -20
  152. package/scaffold/.agent/skills/meta-harness/references/optimized/manifest.json +0 -79
  153. package/scaffold/.agent/skills/meta-harness/references/optimized/original.md +0 -135
  154. package/scaffold/.agent/skills/meta-harness/references/optimized/section-01.md +0 -5
  155. package/scaffold/.agent/skills/meta-harness/references/optimized/section-02.md +0 -17
  156. package/scaffold/.agent/skills/meta-harness/references/optimized/section-03.md +0 -8
  157. package/scaffold/.agent/skills/meta-harness/references/optimized/section-04.md +0 -2
  158. package/scaffold/.agent/skills/meta-harness/references/optimized/section-05.md +0 -6
  159. package/scaffold/.agent/skills/meta-harness/references/optimized/section-06.md +0 -14
  160. package/scaffold/.agent/skills/meta-harness/references/optimized/section-07.md +0 -8
  161. package/scaffold/.agent/skills/meta-harness/references/optimized/section-08.md +0 -4
  162. package/scaffold/.agent/skills/meta-harness/references/optimized/section-09.md +0 -20
  163. package/scaffold/.agent/skills/meta-harness/references/optimized/section-10.md +0 -6
  164. package/scaffold/.agent/skills/meta-harness/references/optimized/section-11.md +0 -5
  165. package/scaffold/.agent/skills/meta-harness/references/optimized/section-12.md +0 -7
  166. package/scaffold/.agent/skills/meta-harness/references/optimized/section-13.md +0 -4
  167. package/scaffold/.agent/skills/meta-harness/references/optimized/section-14.md +0 -7
  168. package/scaffold/.agent/skills/meta-harness/references/optimized/section-15.md +0 -9
  169. package/scaffold/.agent/skills/meta-harness/references/optimized/section-16.md +0 -5
  170. package/scaffold/.agent/skills/total-recall/plugins/cli-agents/README.md +0 -65
  171. package/scaffold/.agent/skills/total-recall/plugins/cli-agents/cli.mjs +0 -76
  172. package/scaffold/.agent/skills/total-recall/plugins/cli-agents/package.json +0 -19
  173. package/scaffold/.agent/skills/total-recall/plugins/cli-agents/plugin.json +0 -266
  174. package/scaffold/.agent/skills/total-recall/plugins/cli-agents/src/adapters/dsh.mjs +0 -446
  175. package/scaffold/.agent/skills/total-recall/plugins/cli-agents/src/documentation.mjs +0 -152
  176. package/scaffold/.agent/skills/total-recall/plugins/cli-agents/src/executor.mjs +0 -71
  177. package/scaffold/.agent/skills/total-recall/plugins/cli-agents/src/runtime.mjs +0 -36
  178. package/scaffold/.agent/skills/total-recall/plugins/cli-agents/src/setup.mjs +0 -35
  179. package/scaffold/.agent/skills/total-recall/plugins/cli-agents/src/worker.mjs +0 -175
  180. package/scaffold/.agent/skills/total-recall/plugins/cli-agents/ui/DESIGN.md +0 -32
  181. 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
- }