@cortexmemory/cli 0.26.2 → 0.27.3
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/dist/commands/convex.js +1 -1
- package/dist/commands/convex.js.map +1 -1
- package/dist/commands/deploy.d.ts +1 -1
- package/dist/commands/deploy.d.ts.map +1 -1
- package/dist/commands/deploy.js +771 -144
- package/dist/commands/deploy.js.map +1 -1
- package/dist/commands/dev.d.ts.map +1 -1
- package/dist/commands/dev.js +210 -36
- package/dist/commands/dev.js.map +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +273 -43
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/setup.d.ts.map +1 -1
- package/dist/commands/setup.js +102 -46
- package/dist/commands/setup.js.map +1 -1
- package/dist/commands/status.d.ts.map +1 -1
- package/dist/commands/status.js +94 -7
- package/dist/commands/status.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/types.d.ts +23 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/app-template-sync.d.ts +95 -0
- package/dist/utils/app-template-sync.d.ts.map +1 -0
- package/dist/utils/app-template-sync.js +425 -0
- package/dist/utils/app-template-sync.js.map +1 -0
- package/dist/utils/config.d.ts +11 -0
- package/dist/utils/config.d.ts.map +1 -1
- package/dist/utils/config.js +20 -0
- package/dist/utils/config.js.map +1 -1
- package/dist/utils/deployment-selector.d.ts +21 -0
- package/dist/utils/deployment-selector.d.ts.map +1 -1
- package/dist/utils/deployment-selector.js +32 -0
- package/dist/utils/deployment-selector.js.map +1 -1
- package/dist/utils/init/graph-setup.d.ts.map +1 -1
- package/dist/utils/init/graph-setup.js +25 -2
- package/dist/utils/init/graph-setup.js.map +1 -1
- package/dist/utils/init/quickstart-setup.d.ts +87 -0
- package/dist/utils/init/quickstart-setup.d.ts.map +1 -0
- package/dist/utils/init/quickstart-setup.js +462 -0
- package/dist/utils/init/quickstart-setup.js.map +1 -0
- package/dist/utils/schema-sync.d.ts.map +1 -1
- package/dist/utils/schema-sync.js +27 -21
- package/dist/utils/schema-sync.js.map +1 -1
- package/package.json +3 -2
- package/templates/vercel-ai-quickstart/.env.local.example +45 -0
- package/templates/vercel-ai-quickstart/README.md +280 -0
- package/templates/vercel-ai-quickstart/app/api/auth/check/route.ts +30 -0
- package/templates/vercel-ai-quickstart/app/api/auth/login/route.ts +83 -0
- package/templates/vercel-ai-quickstart/app/api/auth/register/route.ts +94 -0
- package/templates/vercel-ai-quickstart/app/api/auth/setup/route.ts +59 -0
- package/templates/vercel-ai-quickstart/app/api/chat/route.ts +277 -0
- package/templates/vercel-ai-quickstart/app/api/conversations/route.ts +179 -0
- package/templates/vercel-ai-quickstart/app/api/facts/route.ts +39 -0
- package/templates/vercel-ai-quickstart/app/api/health/route.ts +99 -0
- package/templates/vercel-ai-quickstart/app/api/memories/route.ts +37 -0
- package/templates/vercel-ai-quickstart/app/globals.css +275 -0
- package/templates/vercel-ai-quickstart/app/layout.tsx +19 -0
- package/templates/vercel-ai-quickstart/app/page.tsx +216 -0
- package/templates/vercel-ai-quickstart/components/AdminSetup.tsx +139 -0
- package/templates/vercel-ai-quickstart/components/AuthProvider.tsx +283 -0
- package/templates/vercel-ai-quickstart/components/ChatHistorySidebar.tsx +323 -0
- package/templates/vercel-ai-quickstart/components/ChatInterface.tsx +334 -0
- package/templates/vercel-ai-quickstart/components/ConvexClientProvider.tsx +21 -0
- package/templates/vercel-ai-quickstart/components/DataPreview.tsx +57 -0
- package/templates/vercel-ai-quickstart/components/HealthStatus.tsx +214 -0
- package/templates/vercel-ai-quickstart/components/LayerCard.tsx +263 -0
- package/templates/vercel-ai-quickstart/components/LayerFlowDiagram.tsx +195 -0
- package/templates/vercel-ai-quickstart/components/LoginScreen.tsx +202 -0
- package/templates/vercel-ai-quickstart/components/MemorySpaceSwitcher.tsx +93 -0
- package/templates/vercel-ai-quickstart/convex/conversations.ts +67 -0
- package/templates/vercel-ai-quickstart/convex/facts.ts +131 -0
- package/templates/vercel-ai-quickstart/convex/health.ts +15 -0
- package/templates/vercel-ai-quickstart/convex/memories.ts +104 -0
- package/templates/vercel-ai-quickstart/convex/schema.ts +20 -0
- package/templates/vercel-ai-quickstart/convex/users.ts +105 -0
- package/templates/vercel-ai-quickstart/jest.config.js +45 -0
- package/templates/vercel-ai-quickstart/lib/animations.ts +146 -0
- package/templates/vercel-ai-quickstart/lib/cortex.ts +27 -0
- package/templates/vercel-ai-quickstart/lib/layer-tracking.ts +214 -0
- package/templates/vercel-ai-quickstart/lib/password.ts +120 -0
- package/templates/vercel-ai-quickstart/next.config.js +27 -0
- package/templates/vercel-ai-quickstart/package.json +46 -0
- package/templates/vercel-ai-quickstart/postcss.config.js +5 -0
- package/templates/vercel-ai-quickstart/tailwind.config.js +37 -0
- package/templates/vercel-ai-quickstart/tests/helpers/mock-cortex.ts +263 -0
- package/templates/vercel-ai-quickstart/tests/helpers/setup.ts +48 -0
- package/templates/vercel-ai-quickstart/tests/integration/auth.test.ts +455 -0
- package/templates/vercel-ai-quickstart/tests/integration/conversations.test.ts +461 -0
- package/templates/vercel-ai-quickstart/tests/unit/password.test.ts +228 -0
- package/templates/vercel-ai-quickstart/tsconfig.json +33 -0
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { Cortex } from "@cortexmemory/sdk";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Health check endpoint to verify all backend services
|
|
5
|
+
*/
|
|
6
|
+
export async function GET() {
|
|
7
|
+
const checks: Record<
|
|
8
|
+
string,
|
|
9
|
+
{ status: string; latencyMs?: number; error?: string }
|
|
10
|
+
> = {};
|
|
11
|
+
|
|
12
|
+
// Check 1: Environment variables
|
|
13
|
+
const hasConvexUrl = !!process.env.CONVEX_URL;
|
|
14
|
+
const hasPublicConvexUrl = !!process.env.NEXT_PUBLIC_CONVEX_URL;
|
|
15
|
+
const hasOpenAIKey = !!process.env.OPENAI_API_KEY;
|
|
16
|
+
const hasNeo4jUri = !!process.env.NEO4J_URI;
|
|
17
|
+
const hasMemgraphUri = !!process.env.MEMGRAPH_URI;
|
|
18
|
+
|
|
19
|
+
checks.environment = {
|
|
20
|
+
status: hasConvexUrl && hasOpenAIKey ? "ok" : "warning",
|
|
21
|
+
error: !hasConvexUrl
|
|
22
|
+
? "CONVEX_URL not set"
|
|
23
|
+
: !hasOpenAIKey
|
|
24
|
+
? "OPENAI_API_KEY not set"
|
|
25
|
+
: undefined,
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
// Check 2: Cortex SDK initialization
|
|
29
|
+
try {
|
|
30
|
+
const startTime = Date.now();
|
|
31
|
+
const cortex = new Cortex({
|
|
32
|
+
convexUrl: process.env.CONVEX_URL!,
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
// Quick test - just initialize, don't actually query
|
|
36
|
+
checks.cortexSdk = {
|
|
37
|
+
status: "ok",
|
|
38
|
+
latencyMs: Date.now() - startTime,
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
cortex.close();
|
|
42
|
+
} catch (error) {
|
|
43
|
+
checks.cortexSdk = {
|
|
44
|
+
status: "error",
|
|
45
|
+
error: error instanceof Error ? error.message : "Unknown error",
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Check 3: Convex backend connectivity (via HTTP)
|
|
50
|
+
if (process.env.CONVEX_URL) {
|
|
51
|
+
try {
|
|
52
|
+
const startTime = Date.now();
|
|
53
|
+
// Convex URLs are like "https://xxx.convex.cloud"
|
|
54
|
+
// We can ping the HTTP endpoint
|
|
55
|
+
const convexUrl = new URL(process.env.CONVEX_URL);
|
|
56
|
+
const response = await fetch(`${convexUrl.origin}/version`, {
|
|
57
|
+
method: "GET",
|
|
58
|
+
signal: AbortSignal.timeout(5000),
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
checks.convexBackend = {
|
|
62
|
+
status: response.ok ? "ok" : "error",
|
|
63
|
+
latencyMs: Date.now() - startTime,
|
|
64
|
+
error: response.ok ? undefined : `HTTP ${response.status}`,
|
|
65
|
+
};
|
|
66
|
+
} catch (error) {
|
|
67
|
+
checks.convexBackend = {
|
|
68
|
+
status: "error",
|
|
69
|
+
error: error instanceof Error ? error.message : "Connection failed",
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
} else {
|
|
73
|
+
checks.convexBackend = {
|
|
74
|
+
status: "error",
|
|
75
|
+
error: "CONVEX_URL not configured",
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Overall status
|
|
80
|
+
const hasErrors = Object.values(checks).some((c) => c.status === "error");
|
|
81
|
+
const hasWarnings = Object.values(checks).some((c) => c.status === "warning");
|
|
82
|
+
|
|
83
|
+
return Response.json({
|
|
84
|
+
status: hasErrors ? "unhealthy" : hasWarnings ? "degraded" : "healthy",
|
|
85
|
+
timestamp: new Date().toISOString(),
|
|
86
|
+
checks,
|
|
87
|
+
config: {
|
|
88
|
+
convexUrl: hasConvexUrl ? "configured" : "missing",
|
|
89
|
+
publicConvexUrl: hasPublicConvexUrl ? "configured" : "missing",
|
|
90
|
+
openaiKey: hasOpenAIKey ? "configured" : "missing",
|
|
91
|
+
graphSync: hasNeo4jUri || hasMemgraphUri ? "enabled" : "disabled",
|
|
92
|
+
graphBackend: hasNeo4jUri
|
|
93
|
+
? "neo4j"
|
|
94
|
+
: hasMemgraphUri
|
|
95
|
+
? "memgraph"
|
|
96
|
+
: "none",
|
|
97
|
+
},
|
|
98
|
+
});
|
|
99
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { Cortex } from "@cortexmemory/sdk";
|
|
2
|
+
|
|
3
|
+
export const dynamic = "force-dynamic";
|
|
4
|
+
|
|
5
|
+
function getCortex() {
|
|
6
|
+
return new Cortex({ convexUrl: process.env.CONVEX_URL! });
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export async function GET(req: Request) {
|
|
10
|
+
try {
|
|
11
|
+
const { searchParams } = new URL(req.url);
|
|
12
|
+
const memorySpaceId =
|
|
13
|
+
searchParams.get("memorySpaceId") || "quickstart-demo";
|
|
14
|
+
const limit = parseInt(searchParams.get("limit") || "20");
|
|
15
|
+
|
|
16
|
+
const cortex = getCortex();
|
|
17
|
+
|
|
18
|
+
// Fetch recent memories
|
|
19
|
+
const memories = await cortex.memory.list({
|
|
20
|
+
memorySpaceId,
|
|
21
|
+
limit,
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
return Response.json({
|
|
25
|
+
memories,
|
|
26
|
+
count: memories.length,
|
|
27
|
+
memorySpaceId,
|
|
28
|
+
});
|
|
29
|
+
} catch (error) {
|
|
30
|
+
console.error("[Memories API Error]", error);
|
|
31
|
+
|
|
32
|
+
return Response.json(
|
|
33
|
+
{ error: error instanceof Error ? error.message : "Unknown error" },
|
|
34
|
+
{ status: 500 },
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
@import "tailwindcss";
|
|
2
|
+
|
|
3
|
+
/* Source paths for v4 */
|
|
4
|
+
@source "../components/**/*.{js,ts,jsx,tsx}";
|
|
5
|
+
@source "./**/*.{js,ts,jsx,tsx}";
|
|
6
|
+
|
|
7
|
+
/* Custom theme for v4 */
|
|
8
|
+
@theme {
|
|
9
|
+
--color-cortex-50: #f0f7ff;
|
|
10
|
+
--color-cortex-100: #e0effe;
|
|
11
|
+
--color-cortex-200: #b9dffc;
|
|
12
|
+
--color-cortex-300: #7cc5fa;
|
|
13
|
+
--color-cortex-400: #36a8f5;
|
|
14
|
+
--color-cortex-500: #0c8ce6;
|
|
15
|
+
--color-cortex-600: #006fc4;
|
|
16
|
+
--color-cortex-700: #0159a0;
|
|
17
|
+
--color-cortex-800: #064b84;
|
|
18
|
+
--color-cortex-900: #0b3f6d;
|
|
19
|
+
--color-cortex-950: #072848;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/* Custom scrollbar */
|
|
23
|
+
::-webkit-scrollbar {
|
|
24
|
+
width: 8px;
|
|
25
|
+
height: 8px;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
::-webkit-scrollbar-track {
|
|
29
|
+
background: rgba(255, 255, 255, 0.05);
|
|
30
|
+
border-radius: 4px;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
::-webkit-scrollbar-thumb {
|
|
34
|
+
background: rgba(255, 255, 255, 0.2);
|
|
35
|
+
border-radius: 4px;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
::-webkit-scrollbar-thumb:hover {
|
|
39
|
+
background: rgba(255, 255, 255, 0.3);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/* Layer flow animations */
|
|
43
|
+
@keyframes pulse-glow {
|
|
44
|
+
0%,
|
|
45
|
+
100% {
|
|
46
|
+
box-shadow: 0 0 0 0 rgba(34, 197, 94, 0.4);
|
|
47
|
+
}
|
|
48
|
+
50% {
|
|
49
|
+
box-shadow: 0 0 0 10px rgba(34, 197, 94, 0);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
@keyframes flow-down {
|
|
54
|
+
0% {
|
|
55
|
+
transform: translateY(-100%);
|
|
56
|
+
opacity: 0;
|
|
57
|
+
}
|
|
58
|
+
50% {
|
|
59
|
+
opacity: 1;
|
|
60
|
+
}
|
|
61
|
+
100% {
|
|
62
|
+
transform: translateY(100%);
|
|
63
|
+
opacity: 0;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.layer-complete {
|
|
68
|
+
animation: pulse-glow 1.5s ease-in-out;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.flow-indicator {
|
|
72
|
+
animation: flow-down 1.5s ease-in-out infinite;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/* Chat message animations */
|
|
76
|
+
@keyframes message-in {
|
|
77
|
+
from {
|
|
78
|
+
opacity: 0;
|
|
79
|
+
transform: translateY(10px);
|
|
80
|
+
}
|
|
81
|
+
to {
|
|
82
|
+
opacity: 1;
|
|
83
|
+
transform: translateY(0);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
.message-animate {
|
|
88
|
+
animation: message-in 0.3s ease-out;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/* Gradient backgrounds */
|
|
92
|
+
.gradient-radial {
|
|
93
|
+
background: radial-gradient(
|
|
94
|
+
ellipse at center,
|
|
95
|
+
var(--tw-gradient-from) 0%,
|
|
96
|
+
var(--tw-gradient-to) 70%
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/* Glass effect */
|
|
101
|
+
.glass {
|
|
102
|
+
background: rgba(255, 255, 255, 0.05);
|
|
103
|
+
backdrop-filter: blur(10px);
|
|
104
|
+
border: 1px solid rgba(255, 255, 255, 0.1);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/* Code block styling */
|
|
108
|
+
.code-block {
|
|
109
|
+
background: rgba(0, 0, 0, 0.3);
|
|
110
|
+
border: 1px solid rgba(255, 255, 255, 0.1);
|
|
111
|
+
font-family: "Monaco", "Menlo", "Ubuntu Mono", monospace;
|
|
112
|
+
font-size: 0.875rem;
|
|
113
|
+
line-height: 1.5;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/* ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
117
|
+
Auth Screen Animations
|
|
118
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ */
|
|
119
|
+
|
|
120
|
+
@keyframes fade-in-up {
|
|
121
|
+
from {
|
|
122
|
+
opacity: 0;
|
|
123
|
+
transform: translateY(20px);
|
|
124
|
+
}
|
|
125
|
+
to {
|
|
126
|
+
opacity: 1;
|
|
127
|
+
transform: translateY(0);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
@keyframes logo-pulse {
|
|
132
|
+
0%, 100% {
|
|
133
|
+
transform: scale(1);
|
|
134
|
+
box-shadow: 0 0 0 0 rgba(12, 140, 230, 0.4);
|
|
135
|
+
}
|
|
136
|
+
50% {
|
|
137
|
+
transform: scale(1.02);
|
|
138
|
+
box-shadow: 0 0 40px 10px rgba(12, 140, 230, 0.2);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
.auth-screen {
|
|
143
|
+
animation: fade-in-up 0.5s ease-out;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
.auth-logo {
|
|
147
|
+
animation: logo-pulse 3s ease-in-out infinite;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/* ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
151
|
+
Sidebar Animations
|
|
152
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ */
|
|
153
|
+
|
|
154
|
+
@keyframes sidebar-slide-in {
|
|
155
|
+
from {
|
|
156
|
+
opacity: 0;
|
|
157
|
+
transform: translateX(-20px);
|
|
158
|
+
}
|
|
159
|
+
to {
|
|
160
|
+
opacity: 1;
|
|
161
|
+
transform: translateX(0);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
@keyframes conversation-item-in {
|
|
166
|
+
from {
|
|
167
|
+
opacity: 0;
|
|
168
|
+
transform: translateX(-10px);
|
|
169
|
+
}
|
|
170
|
+
to {
|
|
171
|
+
opacity: 1;
|
|
172
|
+
transform: translateX(0);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
.sidebar-animate {
|
|
177
|
+
animation: sidebar-slide-in 0.3s ease-out;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
.conversation-item {
|
|
181
|
+
animation: conversation-item-in 0.2s ease-out;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/* Staggered animation for conversation list */
|
|
185
|
+
.conversation-item:nth-child(1) { animation-delay: 0ms; }
|
|
186
|
+
.conversation-item:nth-child(2) { animation-delay: 30ms; }
|
|
187
|
+
.conversation-item:nth-child(3) { animation-delay: 60ms; }
|
|
188
|
+
.conversation-item:nth-child(4) { animation-delay: 90ms; }
|
|
189
|
+
.conversation-item:nth-child(5) { animation-delay: 120ms; }
|
|
190
|
+
.conversation-item:nth-child(n+6) { animation-delay: 150ms; }
|
|
191
|
+
|
|
192
|
+
/* ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
193
|
+
Input Focus Animations
|
|
194
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ */
|
|
195
|
+
|
|
196
|
+
input:focus {
|
|
197
|
+
box-shadow: 0 0 0 2px rgba(12, 140, 230, 0.2);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/* ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
201
|
+
Button Hover Effects
|
|
202
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ */
|
|
203
|
+
|
|
204
|
+
.btn-primary {
|
|
205
|
+
position: relative;
|
|
206
|
+
overflow: hidden;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
.btn-primary::after {
|
|
210
|
+
content: "";
|
|
211
|
+
position: absolute;
|
|
212
|
+
top: 50%;
|
|
213
|
+
left: 50%;
|
|
214
|
+
width: 0;
|
|
215
|
+
height: 0;
|
|
216
|
+
background: rgba(255, 255, 255, 0.1);
|
|
217
|
+
border-radius: 50%;
|
|
218
|
+
transform: translate(-50%, -50%);
|
|
219
|
+
transition: width 0.4s ease, height 0.4s ease;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
.btn-primary:hover::after {
|
|
223
|
+
width: 300px;
|
|
224
|
+
height: 300px;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/* ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
228
|
+
Loading States
|
|
229
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ */
|
|
230
|
+
|
|
231
|
+
@keyframes shimmer {
|
|
232
|
+
0% {
|
|
233
|
+
background-position: -200% 0;
|
|
234
|
+
}
|
|
235
|
+
100% {
|
|
236
|
+
background-position: 200% 0;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
.skeleton {
|
|
241
|
+
background: linear-gradient(
|
|
242
|
+
90deg,
|
|
243
|
+
rgba(255, 255, 255, 0.05) 25%,
|
|
244
|
+
rgba(255, 255, 255, 0.1) 50%,
|
|
245
|
+
rgba(255, 255, 255, 0.05) 75%
|
|
246
|
+
);
|
|
247
|
+
background-size: 200% 100%;
|
|
248
|
+
animation: shimmer 1.5s infinite;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/* ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
252
|
+
Responsive Sidebar
|
|
253
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ */
|
|
254
|
+
|
|
255
|
+
@media (max-width: 1024px) {
|
|
256
|
+
/* On smaller screens, the layer flow visualization is hidden */
|
|
257
|
+
.layer-flow-panel {
|
|
258
|
+
display: none;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
@media (max-width: 768px) {
|
|
263
|
+
/* On mobile, sidebar becomes collapsible */
|
|
264
|
+
.sidebar-mobile-hidden {
|
|
265
|
+
transform: translateX(-100%);
|
|
266
|
+
transition: transform 0.3s ease;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
.sidebar-mobile-visible {
|
|
270
|
+
transform: translateX(0);
|
|
271
|
+
position: fixed;
|
|
272
|
+
z-index: 50;
|
|
273
|
+
height: 100vh;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { Metadata } from "next";
|
|
2
|
+
import "./globals.css";
|
|
3
|
+
|
|
4
|
+
export const metadata: Metadata = {
|
|
5
|
+
title: "Cortex Memory Quickstart",
|
|
6
|
+
description: "Interactive demo of Cortex Memory with Vercel AI SDK",
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export default function RootLayout({
|
|
10
|
+
children,
|
|
11
|
+
}: {
|
|
12
|
+
children: React.ReactNode;
|
|
13
|
+
}) {
|
|
14
|
+
return (
|
|
15
|
+
<html lang="en">
|
|
16
|
+
<body className="bg-gray-900 text-white min-h-screen">{children}</body>
|
|
17
|
+
</html>
|
|
18
|
+
);
|
|
19
|
+
}
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import dynamic from "next/dynamic";
|
|
4
|
+
import { useState, useCallback } from "react";
|
|
5
|
+
import { useLayerTracking } from "@/lib/layer-tracking";
|
|
6
|
+
import { AuthProvider, useAuth } from "@/components/AuthProvider";
|
|
7
|
+
import { AdminSetup } from "@/components/AdminSetup";
|
|
8
|
+
import { LoginScreen } from "@/components/LoginScreen";
|
|
9
|
+
|
|
10
|
+
// Dynamic imports to avoid SSR issues with framer-motion
|
|
11
|
+
const ChatInterface = dynamic(
|
|
12
|
+
() =>
|
|
13
|
+
import("@/components/ChatInterface").then((m) => ({
|
|
14
|
+
default: m.ChatInterface,
|
|
15
|
+
})),
|
|
16
|
+
{ ssr: false },
|
|
17
|
+
);
|
|
18
|
+
const LayerFlowDiagram = dynamic(
|
|
19
|
+
() =>
|
|
20
|
+
import("@/components/LayerFlowDiagram").then((m) => ({
|
|
21
|
+
default: m.LayerFlowDiagram,
|
|
22
|
+
})),
|
|
23
|
+
{ ssr: false },
|
|
24
|
+
);
|
|
25
|
+
const MemorySpaceSwitcher = dynamic(
|
|
26
|
+
() =>
|
|
27
|
+
import("@/components/MemorySpaceSwitcher").then((m) => ({
|
|
28
|
+
default: m.MemorySpaceSwitcher,
|
|
29
|
+
})),
|
|
30
|
+
{ ssr: false },
|
|
31
|
+
);
|
|
32
|
+
const HealthStatus = dynamic(
|
|
33
|
+
() =>
|
|
34
|
+
import("@/components/HealthStatus").then((m) => ({
|
|
35
|
+
default: m.HealthStatus,
|
|
36
|
+
})),
|
|
37
|
+
{ ssr: false },
|
|
38
|
+
);
|
|
39
|
+
const ChatHistorySidebar = dynamic(
|
|
40
|
+
() =>
|
|
41
|
+
import("@/components/ChatHistorySidebar").then((m) => ({
|
|
42
|
+
default: m.ChatHistorySidebar,
|
|
43
|
+
})),
|
|
44
|
+
{ ssr: false },
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
48
|
+
// Main App Content (with auth)
|
|
49
|
+
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
50
|
+
|
|
51
|
+
function MainContent() {
|
|
52
|
+
const { isLoading, isAdminSetup, isAuthenticated, user } = useAuth();
|
|
53
|
+
const [memorySpaceId, setMemorySpaceId] = useState("quickstart-demo");
|
|
54
|
+
const [currentConversationId, setCurrentConversationId] = useState<string | null>(null);
|
|
55
|
+
const {
|
|
56
|
+
layers,
|
|
57
|
+
isOrchestrating,
|
|
58
|
+
startOrchestration,
|
|
59
|
+
updateLayer,
|
|
60
|
+
resetLayers,
|
|
61
|
+
} = useLayerTracking();
|
|
62
|
+
|
|
63
|
+
// Handle new chat
|
|
64
|
+
const handleNewChat = useCallback(() => {
|
|
65
|
+
setCurrentConversationId(null);
|
|
66
|
+
resetLayers();
|
|
67
|
+
}, [resetLayers]);
|
|
68
|
+
|
|
69
|
+
// Handle conversation selection
|
|
70
|
+
const handleSelectConversation = useCallback((conversationId: string) => {
|
|
71
|
+
setCurrentConversationId(conversationId);
|
|
72
|
+
resetLayers();
|
|
73
|
+
}, [resetLayers]);
|
|
74
|
+
|
|
75
|
+
// Handle conversation update (e.g., title change after first message)
|
|
76
|
+
const handleConversationUpdate = useCallback((conversationId: string) => {
|
|
77
|
+
// Update current conversation ID if it was null (new chat created)
|
|
78
|
+
if (!currentConversationId) {
|
|
79
|
+
setCurrentConversationId(conversationId);
|
|
80
|
+
}
|
|
81
|
+
}, [currentConversationId]);
|
|
82
|
+
|
|
83
|
+
// Loading state
|
|
84
|
+
if (isLoading) {
|
|
85
|
+
return (
|
|
86
|
+
<div className="min-h-screen flex items-center justify-center">
|
|
87
|
+
<div className="text-center">
|
|
88
|
+
<div className="w-16 h-16 mx-auto mb-4 rounded-2xl bg-gradient-to-br from-cortex-500 to-cortex-700 flex items-center justify-center animate-pulse">
|
|
89
|
+
<span className="text-3xl">🧠</span>
|
|
90
|
+
</div>
|
|
91
|
+
<p className="text-gray-400">Loading Cortex...</p>
|
|
92
|
+
</div>
|
|
93
|
+
</div>
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// First-run: Admin setup
|
|
98
|
+
if (isAdminSetup === false) {
|
|
99
|
+
return <AdminSetup />;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Not authenticated: Login/Register
|
|
103
|
+
if (!isAuthenticated) {
|
|
104
|
+
return <LoginScreen />;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Get userId from authenticated user
|
|
108
|
+
const userId = user?.id || "demo-user";
|
|
109
|
+
|
|
110
|
+
// Main authenticated interface
|
|
111
|
+
return (
|
|
112
|
+
<main className="min-h-screen flex flex-col">
|
|
113
|
+
{/* Header */}
|
|
114
|
+
<header className="border-b border-white/10 px-6 py-4">
|
|
115
|
+
<div className="flex items-center justify-between">
|
|
116
|
+
<div className="flex items-center gap-3">
|
|
117
|
+
<div className="w-10 h-10 rounded-lg bg-gradient-to-br from-cortex-500 to-cortex-700 flex items-center justify-center">
|
|
118
|
+
<span className="text-xl">🧠</span>
|
|
119
|
+
</div>
|
|
120
|
+
<div>
|
|
121
|
+
<h1 className="text-xl font-bold">Cortex Memory Quickstart</h1>
|
|
122
|
+
<p className="text-sm text-gray-400">
|
|
123
|
+
Real-time memory orchestration demo
|
|
124
|
+
</p>
|
|
125
|
+
</div>
|
|
126
|
+
</div>
|
|
127
|
+
|
|
128
|
+
<div className="flex items-center gap-4">
|
|
129
|
+
<HealthStatus />
|
|
130
|
+
<MemorySpaceSwitcher
|
|
131
|
+
value={memorySpaceId}
|
|
132
|
+
onChange={setMemorySpaceId}
|
|
133
|
+
/>
|
|
134
|
+
</div>
|
|
135
|
+
</div>
|
|
136
|
+
</header>
|
|
137
|
+
|
|
138
|
+
{/* Main Content - Three Column Layout */}
|
|
139
|
+
<div className="flex-1 flex overflow-hidden">
|
|
140
|
+
{/* Left: Chat History Sidebar */}
|
|
141
|
+
<ChatHistorySidebar
|
|
142
|
+
memorySpaceId={memorySpaceId}
|
|
143
|
+
currentConversationId={currentConversationId}
|
|
144
|
+
onSelectConversation={handleSelectConversation}
|
|
145
|
+
onNewChat={handleNewChat}
|
|
146
|
+
/>
|
|
147
|
+
|
|
148
|
+
{/* Center: Chat Section */}
|
|
149
|
+
<div className="flex-1 flex flex-col border-r border-white/10">
|
|
150
|
+
<ChatInterface
|
|
151
|
+
memorySpaceId={memorySpaceId}
|
|
152
|
+
userId={userId}
|
|
153
|
+
conversationId={currentConversationId}
|
|
154
|
+
onOrchestrationStart={startOrchestration}
|
|
155
|
+
onLayerUpdate={updateLayer}
|
|
156
|
+
onReset={resetLayers}
|
|
157
|
+
onConversationUpdate={handleConversationUpdate}
|
|
158
|
+
/>
|
|
159
|
+
</div>
|
|
160
|
+
|
|
161
|
+
{/* Right: Layer Flow Visualization */}
|
|
162
|
+
<div className="w-[480px] flex flex-col bg-black/20">
|
|
163
|
+
<div className="p-4 border-b border-white/10">
|
|
164
|
+
<h2 className="font-semibold flex items-center gap-2">
|
|
165
|
+
<span className="text-lg">📊</span>
|
|
166
|
+
Memory Orchestration Flow
|
|
167
|
+
</h2>
|
|
168
|
+
<p className="text-sm text-gray-400 mt-1">
|
|
169
|
+
Watch data flow through Cortex layers in real-time
|
|
170
|
+
</p>
|
|
171
|
+
</div>
|
|
172
|
+
|
|
173
|
+
<div className="flex-1 overflow-y-auto p-4">
|
|
174
|
+
<LayerFlowDiagram
|
|
175
|
+
layers={layers}
|
|
176
|
+
isOrchestrating={isOrchestrating}
|
|
177
|
+
memorySpaceId={memorySpaceId}
|
|
178
|
+
userId={userId}
|
|
179
|
+
/>
|
|
180
|
+
</div>
|
|
181
|
+
</div>
|
|
182
|
+
</div>
|
|
183
|
+
|
|
184
|
+
{/* Footer */}
|
|
185
|
+
<footer className="border-t border-white/10 px-6 py-3">
|
|
186
|
+
<div className="flex items-center justify-between text-sm text-gray-500">
|
|
187
|
+
<div className="flex items-center gap-4">
|
|
188
|
+
<span>Cortex SDK v0.24.0</span>
|
|
189
|
+
<span>•</span>
|
|
190
|
+
<span>Vercel AI SDK v5</span>
|
|
191
|
+
</div>
|
|
192
|
+
<a
|
|
193
|
+
href="https://cortexmemory.dev/docs"
|
|
194
|
+
target="_blank"
|
|
195
|
+
rel="noopener noreferrer"
|
|
196
|
+
className="hover:text-white transition-colors"
|
|
197
|
+
>
|
|
198
|
+
Documentation →
|
|
199
|
+
</a>
|
|
200
|
+
</div>
|
|
201
|
+
</footer>
|
|
202
|
+
</main>
|
|
203
|
+
);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
207
|
+
// Page Component (wraps with AuthProvider)
|
|
208
|
+
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
209
|
+
|
|
210
|
+
export default function Home() {
|
|
211
|
+
return (
|
|
212
|
+
<AuthProvider>
|
|
213
|
+
<MainContent />
|
|
214
|
+
</AuthProvider>
|
|
215
|
+
);
|
|
216
|
+
}
|