claude-cortex 1.0.0 → 1.1.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.
- package/dashboard/README.md +36 -0
- package/dashboard/components.json +22 -0
- package/dashboard/eslint.config.mjs +18 -0
- package/dashboard/next.config.ts +7 -0
- package/dashboard/package-lock.json +7784 -0
- package/dashboard/package.json +42 -0
- package/dashboard/postcss.config.mjs +7 -0
- package/dashboard/public/file.svg +1 -0
- package/dashboard/public/globe.svg +1 -0
- package/dashboard/public/next.svg +1 -0
- package/dashboard/public/vercel.svg +1 -0
- package/dashboard/public/window.svg +1 -0
- package/dashboard/src/app/favicon.ico +0 -0
- package/dashboard/src/app/globals.css +125 -0
- package/dashboard/src/app/layout.tsx +35 -0
- package/dashboard/src/app/page.tsx +338 -0
- package/dashboard/src/components/Providers.tsx +27 -0
- package/dashboard/src/components/brain/ActivityPulseSystem.tsx +229 -0
- package/dashboard/src/components/brain/BrainMesh.tsx +118 -0
- package/dashboard/src/components/brain/BrainRegions.tsx +254 -0
- package/dashboard/src/components/brain/BrainScene.tsx +255 -0
- package/dashboard/src/components/brain/CategoryLabels.tsx +103 -0
- package/dashboard/src/components/brain/CoreSphere.tsx +215 -0
- package/dashboard/src/components/brain/DataFlowParticles.tsx +123 -0
- package/dashboard/src/components/brain/DataStreamRings.tsx +161 -0
- package/dashboard/src/components/brain/ElectronFlow.tsx +323 -0
- package/dashboard/src/components/brain/HolographicGrid.tsx +235 -0
- package/dashboard/src/components/brain/MemoryLinks.tsx +271 -0
- package/dashboard/src/components/brain/MemoryNode.tsx +245 -0
- package/dashboard/src/components/brain/NeuralPathways.tsx +441 -0
- package/dashboard/src/components/brain/SynapseNodes.tsx +306 -0
- package/dashboard/src/components/brain/TimelineControls.tsx +205 -0
- package/dashboard/src/components/chip/ChipScene.tsx +497 -0
- package/dashboard/src/components/chip/ChipSubstrate.tsx +238 -0
- package/dashboard/src/components/chip/CortexCore.tsx +210 -0
- package/dashboard/src/components/chip/DataBus.tsx +416 -0
- package/dashboard/src/components/chip/MemoryCell.tsx +225 -0
- package/dashboard/src/components/chip/MemoryGrid.tsx +328 -0
- package/dashboard/src/components/chip/QuantumCell.tsx +316 -0
- package/dashboard/src/components/chip/SectionLabel.tsx +113 -0
- package/dashboard/src/components/chip/index.ts +14 -0
- package/dashboard/src/components/controls/ControlPanel.tsx +100 -0
- package/dashboard/src/components/dashboard/StatsPanel.tsx +164 -0
- package/dashboard/src/components/debug/ActivityLog.tsx +238 -0
- package/dashboard/src/components/debug/DebugPanel.tsx +101 -0
- package/dashboard/src/components/debug/QueryTester.tsx +192 -0
- package/dashboard/src/components/debug/RelationshipGraph.tsx +403 -0
- package/dashboard/src/components/debug/SqlConsole.tsx +313 -0
- package/dashboard/src/components/memory/MemoryDetail.tsx +325 -0
- package/dashboard/src/components/ui/button.tsx +62 -0
- package/dashboard/src/components/ui/card.tsx +92 -0
- package/dashboard/src/components/ui/input.tsx +21 -0
- package/dashboard/src/hooks/useDebouncedValue.ts +24 -0
- package/dashboard/src/hooks/useMemories.ts +276 -0
- package/dashboard/src/hooks/useSuggestions.ts +46 -0
- package/dashboard/src/lib/category-colors.ts +84 -0
- package/dashboard/src/lib/position-algorithm.ts +177 -0
- package/dashboard/src/lib/simplex-noise.ts +217 -0
- package/dashboard/src/lib/store.ts +88 -0
- package/dashboard/src/lib/utils.ts +6 -0
- package/dashboard/src/lib/websocket.ts +216 -0
- package/dashboard/src/types/memory.ts +73 -0
- package/dashboard/tsconfig.json +34 -0
- package/dist/api/control.d.ts +27 -0
- package/dist/api/control.d.ts.map +1 -0
- package/dist/api/control.js +60 -0
- package/dist/api/control.js.map +1 -0
- package/dist/api/visualization-server.d.ts.map +1 -1
- package/dist/api/visualization-server.js +109 -2
- package/dist/api/visualization-server.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +80 -4
- package/dist/index.js.map +1 -1
- package/dist/memory/store.d.ts +6 -0
- package/dist/memory/store.d.ts.map +1 -1
- package/dist/memory/store.js +14 -0
- package/dist/memory/store.js.map +1 -1
- package/package.json +7 -3
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import * as React from "react"
|
|
2
|
+
|
|
3
|
+
import { cn } from "@/lib/utils"
|
|
4
|
+
|
|
5
|
+
function Card({ className, ...props }: React.ComponentProps<"div">) {
|
|
6
|
+
return (
|
|
7
|
+
<div
|
|
8
|
+
data-slot="card"
|
|
9
|
+
className={cn(
|
|
10
|
+
"bg-card text-card-foreground flex flex-col gap-6 rounded-xl border py-6 shadow-sm",
|
|
11
|
+
className
|
|
12
|
+
)}
|
|
13
|
+
{...props}
|
|
14
|
+
/>
|
|
15
|
+
)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function CardHeader({ className, ...props }: React.ComponentProps<"div">) {
|
|
19
|
+
return (
|
|
20
|
+
<div
|
|
21
|
+
data-slot="card-header"
|
|
22
|
+
className={cn(
|
|
23
|
+
"@container/card-header grid auto-rows-min grid-rows-[auto_auto] items-start gap-2 px-6 has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6",
|
|
24
|
+
className
|
|
25
|
+
)}
|
|
26
|
+
{...props}
|
|
27
|
+
/>
|
|
28
|
+
)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function CardTitle({ className, ...props }: React.ComponentProps<"div">) {
|
|
32
|
+
return (
|
|
33
|
+
<div
|
|
34
|
+
data-slot="card-title"
|
|
35
|
+
className={cn("leading-none font-semibold", className)}
|
|
36
|
+
{...props}
|
|
37
|
+
/>
|
|
38
|
+
)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function CardDescription({ className, ...props }: React.ComponentProps<"div">) {
|
|
42
|
+
return (
|
|
43
|
+
<div
|
|
44
|
+
data-slot="card-description"
|
|
45
|
+
className={cn("text-muted-foreground text-sm", className)}
|
|
46
|
+
{...props}
|
|
47
|
+
/>
|
|
48
|
+
)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function CardAction({ className, ...props }: React.ComponentProps<"div">) {
|
|
52
|
+
return (
|
|
53
|
+
<div
|
|
54
|
+
data-slot="card-action"
|
|
55
|
+
className={cn(
|
|
56
|
+
"col-start-2 row-span-2 row-start-1 self-start justify-self-end",
|
|
57
|
+
className
|
|
58
|
+
)}
|
|
59
|
+
{...props}
|
|
60
|
+
/>
|
|
61
|
+
)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function CardContent({ className, ...props }: React.ComponentProps<"div">) {
|
|
65
|
+
return (
|
|
66
|
+
<div
|
|
67
|
+
data-slot="card-content"
|
|
68
|
+
className={cn("px-6", className)}
|
|
69
|
+
{...props}
|
|
70
|
+
/>
|
|
71
|
+
)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function CardFooter({ className, ...props }: React.ComponentProps<"div">) {
|
|
75
|
+
return (
|
|
76
|
+
<div
|
|
77
|
+
data-slot="card-footer"
|
|
78
|
+
className={cn("flex items-center px-6 [.border-t]:pt-6", className)}
|
|
79
|
+
{...props}
|
|
80
|
+
/>
|
|
81
|
+
)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export {
|
|
85
|
+
Card,
|
|
86
|
+
CardHeader,
|
|
87
|
+
CardFooter,
|
|
88
|
+
CardTitle,
|
|
89
|
+
CardAction,
|
|
90
|
+
CardDescription,
|
|
91
|
+
CardContent,
|
|
92
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import * as React from "react"
|
|
2
|
+
|
|
3
|
+
import { cn } from "@/lib/utils"
|
|
4
|
+
|
|
5
|
+
function Input({ className, type, ...props }: React.ComponentProps<"input">) {
|
|
6
|
+
return (
|
|
7
|
+
<input
|
|
8
|
+
type={type}
|
|
9
|
+
data-slot="input"
|
|
10
|
+
className={cn(
|
|
11
|
+
"file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground dark:bg-input/30 border-input h-9 w-full min-w-0 rounded-md border bg-transparent px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
|
|
12
|
+
"focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]",
|
|
13
|
+
"aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
|
|
14
|
+
className
|
|
15
|
+
)}
|
|
16
|
+
{...props}
|
|
17
|
+
/>
|
|
18
|
+
)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export { Input }
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Debounce Hook
|
|
3
|
+
*
|
|
4
|
+
* Delays updating a value until after a specified delay has passed
|
|
5
|
+
* since the last time the value changed.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { useState, useEffect } from 'react';
|
|
9
|
+
|
|
10
|
+
export function useDebouncedValue<T>(value: T, delay: number = 300): T {
|
|
11
|
+
const [debouncedValue, setDebouncedValue] = useState<T>(value);
|
|
12
|
+
|
|
13
|
+
useEffect(() => {
|
|
14
|
+
const timer = setTimeout(() => {
|
|
15
|
+
setDebouncedValue(value);
|
|
16
|
+
}, delay);
|
|
17
|
+
|
|
18
|
+
return () => {
|
|
19
|
+
clearTimeout(timer);
|
|
20
|
+
};
|
|
21
|
+
}, [value, delay]);
|
|
22
|
+
|
|
23
|
+
return debouncedValue;
|
|
24
|
+
}
|
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Memory Data Hooks
|
|
5
|
+
* TanStack Query hooks for fetching memory data
|
|
6
|
+
*
|
|
7
|
+
* Uses WebSocket for real-time updates with polling as fallback.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
|
|
11
|
+
import { Memory, MemoryStats, MemoryLink } from '@/types/memory';
|
|
12
|
+
import { useMemoryWebSocket } from '@/lib/websocket';
|
|
13
|
+
|
|
14
|
+
const API_BASE = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:3001';
|
|
15
|
+
|
|
16
|
+
// Pagination metadata from API
|
|
17
|
+
export interface PaginationInfo {
|
|
18
|
+
offset: number;
|
|
19
|
+
limit: number;
|
|
20
|
+
total: number;
|
|
21
|
+
hasMore: boolean;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Paginated response from API
|
|
25
|
+
interface PaginatedMemoriesResponse {
|
|
26
|
+
memories: Memory[];
|
|
27
|
+
pagination: PaginationInfo;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Fetch memories with pagination support
|
|
31
|
+
async function fetchMemories(options?: {
|
|
32
|
+
project?: string;
|
|
33
|
+
type?: string;
|
|
34
|
+
category?: string;
|
|
35
|
+
limit?: number;
|
|
36
|
+
offset?: number;
|
|
37
|
+
mode?: 'recent' | 'important' | 'search';
|
|
38
|
+
query?: string;
|
|
39
|
+
}): Promise<PaginatedMemoriesResponse> {
|
|
40
|
+
const params = new URLSearchParams();
|
|
41
|
+
if (options?.project) params.set('project', options.project);
|
|
42
|
+
if (options?.type) params.set('type', options.type);
|
|
43
|
+
if (options?.category) params.set('category', options.category);
|
|
44
|
+
if (options?.limit) params.set('limit', options.limit.toString());
|
|
45
|
+
if (options?.offset) params.set('offset', options.offset.toString());
|
|
46
|
+
if (options?.mode) params.set('mode', options.mode);
|
|
47
|
+
if (options?.query) params.set('query', options.query);
|
|
48
|
+
|
|
49
|
+
const response = await fetch(`${API_BASE}/api/memories?${params}`);
|
|
50
|
+
if (!response.ok) throw new Error('Failed to fetch memories');
|
|
51
|
+
return response.json();
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Fetch memory stats
|
|
55
|
+
async function fetchStats(project?: string): Promise<MemoryStats> {
|
|
56
|
+
const params = project ? `?project=${project}` : '';
|
|
57
|
+
const response = await fetch(`${API_BASE}/api/stats${params}`);
|
|
58
|
+
if (!response.ok) throw new Error('Failed to fetch stats');
|
|
59
|
+
return response.json();
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Fetch memory links
|
|
63
|
+
async function fetchLinks(project?: string): Promise<MemoryLink[]> {
|
|
64
|
+
const params = project ? `?project=${project}` : '';
|
|
65
|
+
const response = await fetch(`${API_BASE}/api/links${params}`);
|
|
66
|
+
if (!response.ok) throw new Error('Failed to fetch links');
|
|
67
|
+
return response.json();
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Project info from API
|
|
71
|
+
export interface ProjectInfo {
|
|
72
|
+
project: string | null;
|
|
73
|
+
memory_count: number;
|
|
74
|
+
label: string;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Fetch list of projects
|
|
78
|
+
async function fetchProjects(): Promise<{ projects: ProjectInfo[] }> {
|
|
79
|
+
const response = await fetch(`${API_BASE}/api/projects`);
|
|
80
|
+
if (!response.ok) throw new Error('Failed to fetch projects');
|
|
81
|
+
return response.json();
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Access a memory (reinforce)
|
|
85
|
+
async function accessMemory(id: number): Promise<Memory> {
|
|
86
|
+
const response = await fetch(`${API_BASE}/api/memories/${id}/access`, {
|
|
87
|
+
method: 'POST',
|
|
88
|
+
});
|
|
89
|
+
if (!response.ok) throw new Error('Failed to access memory');
|
|
90
|
+
return response.json();
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Trigger consolidation
|
|
94
|
+
async function triggerConsolidation(): Promise<{
|
|
95
|
+
success: boolean;
|
|
96
|
+
consolidated: number;
|
|
97
|
+
decayed: number;
|
|
98
|
+
deleted: number;
|
|
99
|
+
}> {
|
|
100
|
+
const response = await fetch(`${API_BASE}/api/consolidate`, {
|
|
101
|
+
method: 'POST',
|
|
102
|
+
});
|
|
103
|
+
if (!response.ok) throw new Error('Failed to consolidate');
|
|
104
|
+
return response.json();
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Hook: Get all memories with pagination
|
|
108
|
+
// Polling is reduced because WebSocket handles real-time updates
|
|
109
|
+
export function useMemories(options?: {
|
|
110
|
+
project?: string;
|
|
111
|
+
type?: string;
|
|
112
|
+
category?: string;
|
|
113
|
+
limit?: number;
|
|
114
|
+
offset?: number;
|
|
115
|
+
mode?: 'recent' | 'important' | 'search';
|
|
116
|
+
query?: string;
|
|
117
|
+
}) {
|
|
118
|
+
const query = useQuery({
|
|
119
|
+
queryKey: ['memories', options],
|
|
120
|
+
queryFn: () => fetchMemories(options),
|
|
121
|
+
refetchInterval: 30000, // Fallback poll every 30 seconds (WebSocket handles real-time)
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
// Extract memories array and pagination from response
|
|
125
|
+
return {
|
|
126
|
+
...query,
|
|
127
|
+
data: query.data?.memories,
|
|
128
|
+
pagination: query.data?.pagination,
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Hook: Get memory stats
|
|
133
|
+
export function useStats(project?: string) {
|
|
134
|
+
return useQuery({
|
|
135
|
+
queryKey: ['stats', project],
|
|
136
|
+
queryFn: () => fetchStats(project),
|
|
137
|
+
refetchInterval: 30000, // Fallback poll every 30 seconds
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Hook: Get memory links
|
|
142
|
+
export function useMemoryLinks(project?: string) {
|
|
143
|
+
return useQuery({
|
|
144
|
+
queryKey: ['links', project],
|
|
145
|
+
queryFn: () => fetchLinks(project),
|
|
146
|
+
refetchInterval: 60000, // Fallback poll every 60 seconds
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// Hook: Get list of projects
|
|
151
|
+
export function useProjects() {
|
|
152
|
+
return useQuery({
|
|
153
|
+
queryKey: ['projects'],
|
|
154
|
+
queryFn: fetchProjects,
|
|
155
|
+
refetchInterval: 60000, // Refresh project list every minute
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Hook: Combined memories with WebSocket real-time updates
|
|
160
|
+
export function useMemoriesWithRealtime(options?: {
|
|
161
|
+
project?: string;
|
|
162
|
+
type?: string;
|
|
163
|
+
category?: string;
|
|
164
|
+
limit?: number;
|
|
165
|
+
offset?: number;
|
|
166
|
+
mode?: 'recent' | 'important' | 'search';
|
|
167
|
+
query?: string;
|
|
168
|
+
}) {
|
|
169
|
+
// Connect to WebSocket for real-time updates
|
|
170
|
+
const ws = useMemoryWebSocket();
|
|
171
|
+
|
|
172
|
+
// Fetch memories with reduced polling (WebSocket handles most updates)
|
|
173
|
+
const memories = useMemories(options);
|
|
174
|
+
|
|
175
|
+
return {
|
|
176
|
+
...memories,
|
|
177
|
+
isConnected: ws.isConnected,
|
|
178
|
+
lastEvent: ws.lastEvent,
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// Hook: Access/reinforce a memory
|
|
183
|
+
export function useAccessMemory() {
|
|
184
|
+
const queryClient = useQueryClient();
|
|
185
|
+
|
|
186
|
+
return useMutation({
|
|
187
|
+
mutationFn: accessMemory,
|
|
188
|
+
onSuccess: () => {
|
|
189
|
+
// Invalidate memories to trigger refetch
|
|
190
|
+
queryClient.invalidateQueries({ queryKey: ['memories'] });
|
|
191
|
+
queryClient.invalidateQueries({ queryKey: ['stats'] });
|
|
192
|
+
},
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// Hook: Trigger consolidation
|
|
197
|
+
export function useConsolidate() {
|
|
198
|
+
const queryClient = useQueryClient();
|
|
199
|
+
|
|
200
|
+
return useMutation({
|
|
201
|
+
mutationFn: triggerConsolidation,
|
|
202
|
+
onSuccess: () => {
|
|
203
|
+
queryClient.invalidateQueries({ queryKey: ['memories'] });
|
|
204
|
+
queryClient.invalidateQueries({ queryKey: ['stats'] });
|
|
205
|
+
},
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// ============================================
|
|
210
|
+
// CONTROL API
|
|
211
|
+
// ============================================
|
|
212
|
+
|
|
213
|
+
// Control status response
|
|
214
|
+
export interface ControlStatus {
|
|
215
|
+
paused: boolean;
|
|
216
|
+
uptime: number;
|
|
217
|
+
uptimeFormatted: string;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// Fetch control status
|
|
221
|
+
async function fetchControlStatus(): Promise<ControlStatus> {
|
|
222
|
+
const response = await fetch(`${API_BASE}/api/control/status`);
|
|
223
|
+
if (!response.ok) throw new Error('Failed to fetch control status');
|
|
224
|
+
return response.json();
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// Pause memory creation
|
|
228
|
+
async function pauseMemoryCreation(): Promise<{ paused: boolean }> {
|
|
229
|
+
const response = await fetch(`${API_BASE}/api/control/pause`, {
|
|
230
|
+
method: 'POST',
|
|
231
|
+
});
|
|
232
|
+
if (!response.ok) throw new Error('Failed to pause');
|
|
233
|
+
return response.json();
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// Resume memory creation
|
|
237
|
+
async function resumeMemoryCreation(): Promise<{ paused: boolean }> {
|
|
238
|
+
const response = await fetch(`${API_BASE}/api/control/resume`, {
|
|
239
|
+
method: 'POST',
|
|
240
|
+
});
|
|
241
|
+
if (!response.ok) throw new Error('Failed to resume');
|
|
242
|
+
return response.json();
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// Hook: Get control status
|
|
246
|
+
export function useControlStatus() {
|
|
247
|
+
return useQuery({
|
|
248
|
+
queryKey: ['control-status'],
|
|
249
|
+
queryFn: fetchControlStatus,
|
|
250
|
+
refetchInterval: 10000, // Poll every 10 seconds for uptime updates
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// Hook: Pause memory creation
|
|
255
|
+
export function usePauseMemory() {
|
|
256
|
+
const queryClient = useQueryClient();
|
|
257
|
+
|
|
258
|
+
return useMutation({
|
|
259
|
+
mutationFn: pauseMemoryCreation,
|
|
260
|
+
onSuccess: () => {
|
|
261
|
+
queryClient.invalidateQueries({ queryKey: ['control-status'] });
|
|
262
|
+
},
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// Hook: Resume memory creation
|
|
267
|
+
export function useResumeMemory() {
|
|
268
|
+
const queryClient = useQueryClient();
|
|
269
|
+
|
|
270
|
+
return useMutation({
|
|
271
|
+
mutationFn: resumeMemoryCreation,
|
|
272
|
+
onSuccess: () => {
|
|
273
|
+
queryClient.invalidateQueries({ queryKey: ['control-status'] });
|
|
274
|
+
},
|
|
275
|
+
});
|
|
276
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Search Suggestions Hook
|
|
3
|
+
*
|
|
4
|
+
* Fetches autocomplete suggestions for the search input.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { useQuery } from '@tanstack/react-query';
|
|
8
|
+
import { useDebouncedValue } from './useDebouncedValue';
|
|
9
|
+
|
|
10
|
+
const API_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:3001';
|
|
11
|
+
|
|
12
|
+
interface Suggestion {
|
|
13
|
+
text: string;
|
|
14
|
+
type: 'title' | 'category' | 'project';
|
|
15
|
+
count: number;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
async function fetchSuggestions(query: string): Promise<Suggestion[]> {
|
|
19
|
+
if (!query || query.length < 2) {
|
|
20
|
+
return [];
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const response = await fetch(
|
|
24
|
+
`${API_URL}/api/suggestions?q=${encodeURIComponent(query)}&limit=8`
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
if (!response.ok) {
|
|
28
|
+
throw new Error('Failed to fetch suggestions');
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const data = await response.json();
|
|
32
|
+
return data.suggestions;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function useSuggestions(query: string) {
|
|
36
|
+
// Debounce the query to avoid too many requests
|
|
37
|
+
const debouncedQuery = useDebouncedValue(query, 200);
|
|
38
|
+
|
|
39
|
+
return useQuery({
|
|
40
|
+
queryKey: ['suggestions', debouncedQuery],
|
|
41
|
+
queryFn: () => fetchSuggestions(debouncedQuery),
|
|
42
|
+
enabled: debouncedQuery.length >= 2,
|
|
43
|
+
staleTime: 30000, // Cache for 30 seconds
|
|
44
|
+
refetchOnWindowFocus: false,
|
|
45
|
+
});
|
|
46
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Category Colors
|
|
3
|
+
* Visual color mappings for memory categories
|
|
4
|
+
*
|
|
5
|
+
* Includes both classic (cool blue/purple) and Jarvis (warm gold/orange) palettes
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { MemoryCategory, MemoryType } from '@/types/memory';
|
|
9
|
+
|
|
10
|
+
// Classic color palette (cool blues and purples)
|
|
11
|
+
export const CATEGORY_COLORS: Record<MemoryCategory, string> = {
|
|
12
|
+
architecture: '#3B82F6', // Blue
|
|
13
|
+
pattern: '#8B5CF6', // Purple
|
|
14
|
+
preference: '#EC4899', // Pink
|
|
15
|
+
error: '#EF4444', // Red
|
|
16
|
+
context: '#10B981', // Green
|
|
17
|
+
learning: '#F59E0B', // Amber
|
|
18
|
+
todo: '#F97316', // Orange
|
|
19
|
+
note: '#6B7280', // Gray
|
|
20
|
+
relationship: '#06B6D4', // Cyan
|
|
21
|
+
custom: '#A855F7', // Violet
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export const TYPE_COLORS: Record<MemoryType, string> = {
|
|
25
|
+
short_term: '#F97316', // Orange
|
|
26
|
+
long_term: '#3B82F6', // Blue
|
|
27
|
+
episodic: '#8B5CF6', // Purple
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
// Jarvis color palette (warm gold/orange holographic style)
|
|
31
|
+
export const JARVIS_CATEGORY_COLORS: Record<MemoryCategory, string> = {
|
|
32
|
+
architecture: '#FFD700', // Bright gold
|
|
33
|
+
pattern: '#FFB347', // Warm gold
|
|
34
|
+
preference: '#FFA500', // Pure orange
|
|
35
|
+
error: '#FF6B6B', // Keep red-ish for errors
|
|
36
|
+
context: '#FFC080', // Soft peach
|
|
37
|
+
learning: '#FFE4B5', // Moccasin
|
|
38
|
+
todo: '#FF8C00', // Deep orange
|
|
39
|
+
note: '#FFCC66', // Light amber
|
|
40
|
+
relationship: '#00D4FF', // Cyan accent
|
|
41
|
+
custom: '#FFB347', // Warm gold
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export const JARVIS_TYPE_COLORS: Record<MemoryType, string> = {
|
|
45
|
+
short_term: '#FFD700', // Bright gold (front)
|
|
46
|
+
episodic: '#FFB347', // Warm gold (middle)
|
|
47
|
+
long_term: '#FF8C00', // Deep orange (back)
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
// Color mode toggle - defaults to Jarvis mode
|
|
51
|
+
let useJarvisColors = true;
|
|
52
|
+
|
|
53
|
+
export function setUseJarvisColors(value: boolean): void {
|
|
54
|
+
useJarvisColors = value;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function getUseJarvisColors(): boolean {
|
|
58
|
+
return useJarvisColors;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function getCategoryColor(category: MemoryCategory): string {
|
|
62
|
+
if (useJarvisColors) {
|
|
63
|
+
return JARVIS_CATEGORY_COLORS[category] || JARVIS_CATEGORY_COLORS.custom;
|
|
64
|
+
}
|
|
65
|
+
return CATEGORY_COLORS[category] || CATEGORY_COLORS.custom;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export function getTypeColor(type: MemoryType): string {
|
|
69
|
+
if (useJarvisColors) {
|
|
70
|
+
return JARVIS_TYPE_COLORS[type] || JARVIS_TYPE_COLORS.short_term;
|
|
71
|
+
}
|
|
72
|
+
return TYPE_COLORS[type] || TYPE_COLORS.short_term;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export function hexToRgb(hex: string): { r: number; g: number; b: number } {
|
|
76
|
+
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
|
|
77
|
+
return result
|
|
78
|
+
? {
|
|
79
|
+
r: parseInt(result[1], 16) / 255,
|
|
80
|
+
g: parseInt(result[2], 16) / 255,
|
|
81
|
+
b: parseInt(result[3], 16) / 255,
|
|
82
|
+
}
|
|
83
|
+
: { r: 1, g: 1, b: 1 };
|
|
84
|
+
}
|