shieldcortex 2.1.0 → 2.1.2

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 (77) hide show
  1. package/README.md +1 -1
  2. package/hooks/clawdbot/cortex-memory/HOOK.md +2 -2
  3. package/package.json +32 -9
  4. package/dashboard/components.json +0 -22
  5. package/dashboard/eslint.config.mjs +0 -42
  6. package/dashboard/next.config.ts +0 -7
  7. package/dashboard/package-lock.json +0 -8053
  8. package/dashboard/package.json +0 -44
  9. package/dashboard/postcss.config.mjs +0 -7
  10. package/dashboard/public/file.svg +0 -1
  11. package/dashboard/public/globe.svg +0 -1
  12. package/dashboard/public/next.svg +0 -1
  13. package/dashboard/public/vercel.svg +0 -1
  14. package/dashboard/public/window.svg +0 -1
  15. package/dashboard/scripts/ensure-api.mjs +0 -76
  16. package/dashboard/src/app/error.tsx +0 -49
  17. package/dashboard/src/app/favicon.ico +0 -0
  18. package/dashboard/src/app/globals.css +0 -130
  19. package/dashboard/src/app/layout.tsx +0 -35
  20. package/dashboard/src/app/page.tsx +0 -364
  21. package/dashboard/src/components/Providers.tsx +0 -27
  22. package/dashboard/src/components/brain/ActivityPulseSystem.tsx +0 -229
  23. package/dashboard/src/components/brain/BrainMesh.tsx +0 -133
  24. package/dashboard/src/components/brain/BrainRegions.tsx +0 -254
  25. package/dashboard/src/components/brain/BrainScene.tsx +0 -255
  26. package/dashboard/src/components/brain/CategoryLabels.tsx +0 -103
  27. package/dashboard/src/components/brain/CoreSphere.tsx +0 -215
  28. package/dashboard/src/components/brain/DataFlowParticles.tsx +0 -123
  29. package/dashboard/src/components/brain/DataStreamRings.tsx +0 -161
  30. package/dashboard/src/components/brain/ElectronFlow.tsx +0 -323
  31. package/dashboard/src/components/brain/HolographicGrid.tsx +0 -235
  32. package/dashboard/src/components/brain/MemoryLinks.tsx +0 -271
  33. package/dashboard/src/components/brain/MemoryNode.tsx +0 -245
  34. package/dashboard/src/components/brain/NeuralPathways.tsx +0 -441
  35. package/dashboard/src/components/brain/SynapseNodes.tsx +0 -312
  36. package/dashboard/src/components/brain/TimelineControls.tsx +0 -205
  37. package/dashboard/src/components/chip/ChipScene.tsx +0 -497
  38. package/dashboard/src/components/chip/ChipSubstrate.tsx +0 -238
  39. package/dashboard/src/components/chip/CortexCore.tsx +0 -210
  40. package/dashboard/src/components/chip/DataBus.tsx +0 -416
  41. package/dashboard/src/components/chip/MemoryCell.tsx +0 -225
  42. package/dashboard/src/components/chip/MemoryGrid.tsx +0 -328
  43. package/dashboard/src/components/chip/QuantumCell.tsx +0 -316
  44. package/dashboard/src/components/chip/SectionLabel.tsx +0 -113
  45. package/dashboard/src/components/chip/index.ts +0 -14
  46. package/dashboard/src/components/controls/ControlPanel.tsx +0 -106
  47. package/dashboard/src/components/controls/VersionPanel.tsx +0 -185
  48. package/dashboard/src/components/dashboard/StatsPanel.tsx +0 -164
  49. package/dashboard/src/components/debug/ActivityLog.tsx +0 -250
  50. package/dashboard/src/components/debug/DebugPanel.tsx +0 -101
  51. package/dashboard/src/components/debug/QueryTester.tsx +0 -192
  52. package/dashboard/src/components/debug/RelationshipGraph.tsx +0 -403
  53. package/dashboard/src/components/debug/SqlConsole.tsx +0 -319
  54. package/dashboard/src/components/graph/KnowledgeGraph.tsx +0 -230
  55. package/dashboard/src/components/graph/OntologyGraph.tsx +0 -631
  56. package/dashboard/src/components/insights/ActivityHeatmap.tsx +0 -131
  57. package/dashboard/src/components/insights/InsightsView.tsx +0 -46
  58. package/dashboard/src/components/insights/KnowledgeMapPanel.tsx +0 -80
  59. package/dashboard/src/components/insights/QualityPanel.tsx +0 -116
  60. package/dashboard/src/components/memories/MemoriesView.tsx +0 -150
  61. package/dashboard/src/components/memories/MemoryCard.tsx +0 -103
  62. package/dashboard/src/components/memory/MemoryDetail.tsx +0 -325
  63. package/dashboard/src/components/nav/NavRail.tsx +0 -54
  64. package/dashboard/src/components/ui/button.tsx +0 -62
  65. package/dashboard/src/components/ui/card.tsx +0 -92
  66. package/dashboard/src/components/ui/input.tsx +0 -21
  67. package/dashboard/src/hooks/useDebouncedValue.ts +0 -24
  68. package/dashboard/src/hooks/useMemories.ts +0 -458
  69. package/dashboard/src/hooks/useSuggestions.ts +0 -46
  70. package/dashboard/src/lib/category-colors.ts +0 -84
  71. package/dashboard/src/lib/position-algorithm.ts +0 -177
  72. package/dashboard/src/lib/simplex-noise.ts +0 -217
  73. package/dashboard/src/lib/store.ts +0 -88
  74. package/dashboard/src/lib/utils.ts +0 -6
  75. package/dashboard/src/lib/websocket.ts +0 -249
  76. package/dashboard/src/types/memory.ts +0 -73
  77. package/dashboard/tsconfig.json +0 -34
@@ -1,250 +0,0 @@
1
- 'use client';
2
-
3
- /**
4
- * Activity Log Component
5
- *
6
- * Real-time event stream showing memory operations.
7
- * Uses WebSocket for live updates.
8
- */
9
-
10
- import { useState, useEffect, useRef } from 'react';
11
- import { useMemoryWebSocket, MemoryEventType } from '@/lib/websocket';
12
-
13
- interface LogEntry {
14
- id: number;
15
- timestamp: Date;
16
- type: MemoryEventType;
17
- message: string;
18
- details?: Record<string, unknown>;
19
- }
20
-
21
- const EVENT_COLORS: Record<MemoryEventType, string> = {
22
- memory_created: 'text-green-400',
23
- memory_accessed: 'text-blue-400',
24
- memory_updated: 'text-yellow-400',
25
- memory_deleted: 'text-red-400',
26
- consolidation_complete: 'text-purple-400',
27
- decay_tick: 'text-slate-500',
28
- initial_state: 'text-slate-400',
29
- worker_light_tick: 'text-slate-500',
30
- worker_medium_tick: 'text-slate-500',
31
- link_discovered: 'text-cyan-400',
32
- predictive_consolidation: 'text-purple-400',
33
- update_started: 'text-blue-400',
34
- update_complete: 'text-green-400',
35
- update_failed: 'text-red-400',
36
- server_restarting: 'text-orange-400',
37
- };
38
-
39
- const EVENT_ICONS: Record<MemoryEventType, string> = {
40
- memory_created: '+',
41
- memory_accessed: '👁',
42
- memory_updated: '✏',
43
- memory_deleted: '✕',
44
- consolidation_complete: '🔄',
45
- decay_tick: '⏱',
46
- initial_state: '📋',
47
- worker_light_tick: '⚡',
48
- worker_medium_tick: '🔋',
49
- link_discovered: '🔗',
50
- predictive_consolidation: '🔮',
51
- update_started: '⬆',
52
- update_complete: '✓',
53
- update_failed: '✗',
54
- server_restarting: '🔄',
55
- };
56
-
57
- export function ActivityLog() {
58
- const [logs, setLogs] = useState<LogEntry[]>([]);
59
- const [autoScroll, setAutoScroll] = useState(true);
60
- const [filters, setFilters] = useState<Record<MemoryEventType, boolean>>({
61
- memory_created: true,
62
- memory_accessed: true,
63
- memory_updated: true,
64
- memory_deleted: true,
65
- consolidation_complete: true,
66
- decay_tick: false, // Off by default (noisy)
67
- initial_state: false,
68
- worker_light_tick: false,
69
- worker_medium_tick: false,
70
- link_discovered: true,
71
- predictive_consolidation: true,
72
- update_started: true,
73
- update_complete: true,
74
- update_failed: true,
75
- server_restarting: true,
76
- });
77
-
78
- const logContainerRef = useRef<HTMLDivElement>(null);
79
- const nextIdRef = useRef(1);
80
-
81
- // Connect to WebSocket
82
- const { lastEvent, isConnected } = useMemoryWebSocket();
83
-
84
- // Process incoming events
85
- useEffect(() => {
86
- if (!lastEvent) return;
87
-
88
- const entry: LogEntry = {
89
- id: nextIdRef.current++,
90
- timestamp: new Date(lastEvent.timestamp),
91
- type: lastEvent.type,
92
- message: formatEventMessage(lastEvent),
93
- details: lastEvent.data as Record<string, unknown>,
94
- };
95
-
96
- setLogs((prev) => {
97
- const updated = [...prev, entry];
98
- // Keep only last 500 entries
99
- return updated.slice(-500);
100
- });
101
- }, [lastEvent]);
102
-
103
- // Auto-scroll to bottom
104
- useEffect(() => {
105
- if (autoScroll && logContainerRef.current) {
106
- logContainerRef.current.scrollTop = logContainerRef.current.scrollHeight;
107
- }
108
- }, [logs, autoScroll]);
109
-
110
- const filteredLogs = logs.filter((log) => filters[log.type]);
111
-
112
- const toggleFilter = (type: MemoryEventType) => {
113
- setFilters((prev) => ({ ...prev, [type]: !prev[type] }));
114
- };
115
-
116
- const clearLogs = () => {
117
- setLogs([]);
118
- };
119
-
120
- const exportLogs = () => {
121
- const json = JSON.stringify(filteredLogs, null, 2);
122
- const blob = new Blob([json], { type: 'application/json' });
123
- const url = URL.createObjectURL(blob);
124
- const a = document.createElement('a');
125
- a.href = url;
126
- a.download = `cortex-activity-${new Date().toISOString().split('T')[0]}.json`;
127
- a.click();
128
- URL.revokeObjectURL(url);
129
- };
130
-
131
- return (
132
- <div className="h-full flex flex-col">
133
- {/* Controls */}
134
- <div className="p-3 border-b border-slate-700 flex items-center gap-3 flex-wrap">
135
- {/* Connection Status */}
136
- <div className="flex items-center gap-2 text-xs">
137
- <span
138
- className={`w-2 h-2 rounded-full ${isConnected ? 'bg-green-500' : 'bg-red-500'}`}
139
- />
140
- <span className="text-slate-400">
141
- {isConnected ? 'Connected' : 'Disconnected'}
142
- </span>
143
- </div>
144
-
145
- <div className="w-px h-4 bg-slate-700" />
146
-
147
- {/* Filters */}
148
- <div className="flex items-center gap-1 flex-wrap">
149
- {(Object.keys(filters) as MemoryEventType[]).map((type) => (
150
- <button
151
- key={type}
152
- onClick={() => toggleFilter(type)}
153
- className={`px-2 py-0.5 text-xs rounded transition-colors ${
154
- filters[type]
155
- ? `${EVENT_COLORS[type]} bg-slate-700`
156
- : 'text-slate-600 bg-slate-800'
157
- }`}
158
- >
159
- {type.replace(/_/g, ' ').replace('memory ', '')}
160
- </button>
161
- ))}
162
- </div>
163
-
164
- <div className="flex-1" />
165
-
166
- {/* Actions */}
167
- <label className="flex items-center gap-1 text-xs text-slate-400 cursor-pointer">
168
- <input
169
- type="checkbox"
170
- checked={autoScroll}
171
- onChange={(e) => setAutoScroll(e.target.checked)}
172
- className="rounded border-slate-600 bg-slate-800"
173
- />
174
- Auto-scroll
175
- </label>
176
-
177
- <button
178
- onClick={exportLogs}
179
- className="text-xs text-slate-400 hover:text-white"
180
- >
181
- Export
182
- </button>
183
-
184
- <button
185
- onClick={clearLogs}
186
- className="text-xs text-red-400 hover:text-red-300"
187
- >
188
- Clear
189
- </button>
190
- </div>
191
-
192
- {/* Log Entries */}
193
- <div
194
- ref={logContainerRef}
195
- className="flex-1 overflow-auto p-3 font-mono text-xs"
196
- >
197
- {filteredLogs.length === 0 ? (
198
- <div className="text-slate-500 text-center py-8">
199
- {isConnected ? 'Waiting for events...' : 'Not connected to server'}
200
- </div>
201
- ) : (
202
- <div className="space-y-1">
203
- {filteredLogs.map((log) => (
204
- <div key={log.id} className="flex gap-2 hover:bg-slate-800/50 px-1 rounded">
205
- <span className="text-slate-500 shrink-0">
206
- {log.timestamp.toLocaleTimeString()}
207
- </span>
208
- <span className={`shrink-0 w-4 ${EVENT_COLORS[log.type]}`}>
209
- {EVENT_ICONS[log.type]}
210
- </span>
211
- <span className={EVENT_COLORS[log.type]}>{log.message}</span>
212
- </div>
213
- ))}
214
- </div>
215
- )}
216
- </div>
217
- </div>
218
- );
219
- }
220
-
221
- function formatEventMessage(event: { type: MemoryEventType; data?: unknown }): string {
222
- const data = event.data as Record<string, unknown> | undefined;
223
-
224
- switch (event.type) {
225
- case 'memory_created':
226
- return `Created: "${data?.title || 'Unknown'}" (${data?.type || 'unknown'})`;
227
- case 'memory_accessed':
228
- return `Accessed: "${data?.title || 'Unknown'}" → salience ${((data?.newSalience as number) * 100).toFixed(0)}%`;
229
- case 'memory_updated':
230
- return `Updated: "${data?.title || 'Unknown'}"`;
231
- case 'memory_deleted':
232
- return `Deleted: "${data?.title || 'Unknown'}" (ID: ${data?.memoryId})`;
233
- case 'consolidation_complete':
234
- return `Consolidation: ${data?.consolidated || 0} promoted, ${data?.decayed || 0} decayed, ${data?.deleted || 0} deleted`;
235
- case 'decay_tick':
236
- return `Decay tick: ${(data?.updates as unknown[])?.length || 0} memories updated`;
237
- case 'initial_state':
238
- return 'Connected - received initial state';
239
- case 'worker_light_tick':
240
- return 'Worker light tick completed';
241
- case 'worker_medium_tick':
242
- return 'Worker medium tick completed';
243
- case 'link_discovered':
244
- return `Link discovered: ${data?.sourceTitle || '?'} → ${data?.targetTitle || '?'}`;
245
- case 'predictive_consolidation':
246
- return `Predictive consolidation: ${data?.promoted || 0} promoted`;
247
- default:
248
- return `Event: ${event.type}`;
249
- }
250
- }
@@ -1,101 +0,0 @@
1
- 'use client';
2
-
3
- /**
4
- * Debug Panel Component
5
- *
6
- * Collapsible bottom panel with tabbed interface for debug tools:
7
- * - Memory Detail (enhanced)
8
- * - Query Tester
9
- * - Activity Log
10
- * - Relationship Graph
11
- * - SQL Console
12
- */
13
-
14
- import { useState } from 'react';
15
- import { QueryTester } from './QueryTester';
16
- import { ActivityLog } from './ActivityLog';
17
- import { RelationshipGraph } from './RelationshipGraph';
18
- import { SqlConsole } from './SqlConsole';
19
-
20
- type TabId = 'detail' | 'query' | 'activity' | 'graph' | 'sql';
21
-
22
- interface Tab {
23
- id: TabId;
24
- label: string;
25
- icon: string;
26
- }
27
-
28
- const TABS: Tab[] = [
29
- { id: 'query', label: 'Query', icon: '🔍' },
30
- { id: 'activity', label: 'Activity', icon: '📋' },
31
- { id: 'graph', label: 'Graph', icon: '🕸' },
32
- { id: 'sql', label: 'SQL', icon: '💾' },
33
- ];
34
-
35
- interface DebugPanelProps {
36
- onCollapse?: () => void;
37
- }
38
-
39
- export function DebugPanel({ onCollapse }: DebugPanelProps) {
40
- const [activeTab, setActiveTab] = useState<TabId>('query');
41
- const [isCollapsed, setIsCollapsed] = useState(false);
42
-
43
- const handleCollapse = () => {
44
- setIsCollapsed(!isCollapsed);
45
- onCollapse?.();
46
- };
47
-
48
- if (isCollapsed) {
49
- return (
50
- <div className="h-10 border-t border-slate-700 bg-slate-900/80 flex items-center px-4">
51
- <button
52
- onClick={handleCollapse}
53
- className="flex items-center gap-2 text-sm text-slate-400 hover:text-white"
54
- >
55
- <span>▲</span>
56
- <span>Debug Panel</span>
57
- </button>
58
- </div>
59
- );
60
- }
61
-
62
- return (
63
- <div className="h-96 border-t border-slate-700 bg-slate-900/80 flex flex-col">
64
- {/* Tab Bar */}
65
- <div className="flex items-center border-b border-slate-700 px-2">
66
- {TABS.map((tab) => (
67
- <button
68
- key={tab.id}
69
- onClick={() => setActiveTab(tab.id)}
70
- className={`px-4 py-2 text-sm flex items-center gap-1.5 border-b-2 transition-colors ${
71
- activeTab === tab.id
72
- ? 'text-white border-blue-500'
73
- : 'text-slate-400 border-transparent hover:text-white hover:border-slate-600'
74
- }`}
75
- >
76
- <span>{tab.icon}</span>
77
- <span>{tab.label}</span>
78
- </button>
79
- ))}
80
-
81
- <div className="flex-1" />
82
-
83
- <button
84
- onClick={handleCollapse}
85
- className="p-2 text-slate-400 hover:text-white"
86
- title="Collapse panel"
87
- >
88
-
89
- </button>
90
- </div>
91
-
92
- {/* Tab Content */}
93
- <div className="flex-1 overflow-hidden min-h-0">
94
- {activeTab === 'query' && <QueryTester />}
95
- {activeTab === 'activity' && <ActivityLog />}
96
- {activeTab === 'graph' && <RelationshipGraph />}
97
- {activeTab === 'sql' && <SqlConsole />}
98
- </div>
99
- </div>
100
- );
101
- }
@@ -1,192 +0,0 @@
1
- 'use client';
2
-
3
- /**
4
- * Query Tester Component
5
- *
6
- * Allows testing search queries against the memory system
7
- * with detailed score breakdowns and explanations.
8
- */
9
-
10
- import { useState } from 'react';
11
- import { Button } from '@/components/ui/button';
12
- import { Input } from '@/components/ui/input';
13
- import { Memory } from '@/types/memory';
14
-
15
- const API_BASE = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:3001';
16
-
17
- interface SearchResult {
18
- memory: Memory & { decayedScore: number };
19
- relevanceScore: number;
20
- }
21
-
22
- type SearchMode = 'hybrid' | 'fts' | 'vector';
23
-
24
- export function QueryTester() {
25
- const [query, setQuery] = useState('');
26
- const [mode, setMode] = useState<SearchMode>('hybrid');
27
- const [results, setResults] = useState<SearchResult[]>([]);
28
- const [isSearching, setIsSearching] = useState(false);
29
- const [error, setError] = useState<string | null>(null);
30
-
31
- const handleSearch = async () => {
32
- if (!query.trim()) return;
33
-
34
- setIsSearching(true);
35
- setError(null);
36
-
37
- try {
38
- const params = new URLSearchParams({
39
- query: query.trim(),
40
- mode: 'search',
41
- limit: '20',
42
- });
43
-
44
- const response = await fetch(`${API_BASE}/api/memories?${params}`);
45
- if (!response.ok) {
46
- throw new Error(`Search failed: ${response.statusText}`);
47
- }
48
-
49
- const data = await response.json();
50
- // Transform API response to include relevance score
51
- const resultsWithScore: SearchResult[] = data.memories.map((m: Memory & { decayedScore: number }) => ({
52
- memory: m,
53
- relevanceScore: m.decayedScore, // Using decayedScore as proxy for relevance
54
- }));
55
-
56
- setResults(resultsWithScore);
57
- } catch (err) {
58
- setError((err as Error).message);
59
- setResults([]);
60
- } finally {
61
- setIsSearching(false);
62
- }
63
- };
64
-
65
- const handleKeyDown = (e: React.KeyboardEvent) => {
66
- if (e.key === 'Enter') {
67
- handleSearch();
68
- }
69
- };
70
-
71
- return (
72
- <div className="h-full flex flex-col">
73
- {/* Search Controls */}
74
- <div className="p-3 border-b border-slate-700 flex gap-2 items-center">
75
- <Input
76
- type="text"
77
- placeholder="Enter search query..."
78
- value={query}
79
- onChange={(e) => setQuery(e.target.value)}
80
- onKeyDown={handleKeyDown}
81
- className="flex-1 bg-slate-800 border-slate-600 text-white"
82
- />
83
-
84
- {/* Mode Toggle */}
85
- <div className="flex gap-1 bg-slate-800 rounded-lg p-1">
86
- {(['hybrid', 'fts', 'vector'] as SearchMode[]).map((m) => (
87
- <button
88
- key={m}
89
- onClick={() => setMode(m)}
90
- className={`px-2 py-1 text-xs rounded transition-colors ${
91
- mode === m
92
- ? 'bg-blue-600 text-white'
93
- : 'text-slate-400 hover:text-white'
94
- }`}
95
- >
96
- {m.toUpperCase()}
97
- </button>
98
- ))}
99
- </div>
100
-
101
- <Button
102
- onClick={handleSearch}
103
- disabled={isSearching || !query.trim()}
104
- size="sm"
105
- className="bg-blue-600 hover:bg-blue-700"
106
- >
107
- {isSearching ? 'Searching...' : 'Search'}
108
- </Button>
109
- </div>
110
-
111
- {/* Results */}
112
- <div className="flex-1 overflow-auto p-3">
113
- {error && (
114
- <div className="p-3 rounded-lg bg-red-500/20 border border-red-500/50 text-red-300 text-sm mb-3">
115
- {error}
116
- </div>
117
- )}
118
-
119
- {results.length === 0 && !error && (
120
- <div className="text-slate-500 text-sm text-center py-8">
121
- {query ? 'No results found' : 'Enter a query to search memories'}
122
- </div>
123
- )}
124
-
125
- {results.length > 0 && (
126
- <div className="space-y-2">
127
- <div className="text-xs text-slate-400 mb-2">
128
- Found {results.length} results
129
- </div>
130
-
131
- <table className="w-full text-sm">
132
- <thead>
133
- <tr className="text-left text-slate-400 border-b border-slate-700">
134
- <th className="pb-2 pr-4">Title</th>
135
- <th className="pb-2 pr-4 w-20">Score</th>
136
- <th className="pb-2 pr-4 w-24">Type</th>
137
- <th className="pb-2 w-24">Category</th>
138
- </tr>
139
- </thead>
140
- <tbody>
141
- {results.map((result, index) => (
142
- <tr
143
- key={result.memory.id}
144
- className="border-b border-slate-800 hover:bg-slate-800/50"
145
- >
146
- <td className="py-2 pr-4">
147
- <div className="flex items-center gap-2">
148
- <span className="text-slate-500 text-xs w-5">
149
- {index + 1}.
150
- </span>
151
- <span className="text-white truncate max-w-[300px]">
152
- {result.memory.title}
153
- </span>
154
- </div>
155
- </td>
156
- <td className="py-2 pr-4">
157
- <div className="flex items-center gap-1">
158
- <div
159
- className="h-1.5 rounded-full bg-gradient-to-r from-blue-600 to-purple-600"
160
- style={{ width: `${result.relevanceScore * 100}%`, maxWidth: '60px' }}
161
- />
162
- <span className="text-xs text-slate-400">
163
- {(result.relevanceScore * 100).toFixed(0)}%
164
- </span>
165
- </div>
166
- </td>
167
- <td className="py-2 pr-4">
168
- <span className={`text-xs px-1.5 py-0.5 rounded ${
169
- result.memory.type === 'long_term'
170
- ? 'bg-purple-600/30 text-purple-300'
171
- : result.memory.type === 'short_term'
172
- ? 'bg-blue-600/30 text-blue-300'
173
- : 'bg-green-600/30 text-green-300'
174
- }`}>
175
- {result.memory.type.replace('_', '-')}
176
- </span>
177
- </td>
178
- <td className="py-2">
179
- <span className="text-xs text-slate-400">
180
- {result.memory.category}
181
- </span>
182
- </td>
183
- </tr>
184
- ))}
185
- </tbody>
186
- </table>
187
- </div>
188
- )}
189
- </div>
190
- </div>
191
- );
192
- }