@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.
Files changed (90) hide show
  1. package/dist/commands/convex.js +1 -1
  2. package/dist/commands/convex.js.map +1 -1
  3. package/dist/commands/deploy.d.ts +1 -1
  4. package/dist/commands/deploy.d.ts.map +1 -1
  5. package/dist/commands/deploy.js +771 -144
  6. package/dist/commands/deploy.js.map +1 -1
  7. package/dist/commands/dev.d.ts.map +1 -1
  8. package/dist/commands/dev.js +210 -36
  9. package/dist/commands/dev.js.map +1 -1
  10. package/dist/commands/init.d.ts.map +1 -1
  11. package/dist/commands/init.js +273 -43
  12. package/dist/commands/init.js.map +1 -1
  13. package/dist/commands/setup.d.ts.map +1 -1
  14. package/dist/commands/setup.js +102 -46
  15. package/dist/commands/setup.js.map +1 -1
  16. package/dist/commands/status.d.ts.map +1 -1
  17. package/dist/commands/status.js +94 -7
  18. package/dist/commands/status.js.map +1 -1
  19. package/dist/index.js +1 -1
  20. package/dist/types.d.ts +23 -0
  21. package/dist/types.d.ts.map +1 -1
  22. package/dist/utils/app-template-sync.d.ts +95 -0
  23. package/dist/utils/app-template-sync.d.ts.map +1 -0
  24. package/dist/utils/app-template-sync.js +425 -0
  25. package/dist/utils/app-template-sync.js.map +1 -0
  26. package/dist/utils/config.d.ts +11 -0
  27. package/dist/utils/config.d.ts.map +1 -1
  28. package/dist/utils/config.js +20 -0
  29. package/dist/utils/config.js.map +1 -1
  30. package/dist/utils/deployment-selector.d.ts +21 -0
  31. package/dist/utils/deployment-selector.d.ts.map +1 -1
  32. package/dist/utils/deployment-selector.js +32 -0
  33. package/dist/utils/deployment-selector.js.map +1 -1
  34. package/dist/utils/init/graph-setup.d.ts.map +1 -1
  35. package/dist/utils/init/graph-setup.js +25 -2
  36. package/dist/utils/init/graph-setup.js.map +1 -1
  37. package/dist/utils/init/quickstart-setup.d.ts +87 -0
  38. package/dist/utils/init/quickstart-setup.d.ts.map +1 -0
  39. package/dist/utils/init/quickstart-setup.js +462 -0
  40. package/dist/utils/init/quickstart-setup.js.map +1 -0
  41. package/dist/utils/schema-sync.d.ts.map +1 -1
  42. package/dist/utils/schema-sync.js +27 -21
  43. package/dist/utils/schema-sync.js.map +1 -1
  44. package/package.json +3 -2
  45. package/templates/vercel-ai-quickstart/.env.local.example +45 -0
  46. package/templates/vercel-ai-quickstart/README.md +280 -0
  47. package/templates/vercel-ai-quickstart/app/api/auth/check/route.ts +30 -0
  48. package/templates/vercel-ai-quickstart/app/api/auth/login/route.ts +83 -0
  49. package/templates/vercel-ai-quickstart/app/api/auth/register/route.ts +94 -0
  50. package/templates/vercel-ai-quickstart/app/api/auth/setup/route.ts +59 -0
  51. package/templates/vercel-ai-quickstart/app/api/chat/route.ts +277 -0
  52. package/templates/vercel-ai-quickstart/app/api/conversations/route.ts +179 -0
  53. package/templates/vercel-ai-quickstart/app/api/facts/route.ts +39 -0
  54. package/templates/vercel-ai-quickstart/app/api/health/route.ts +99 -0
  55. package/templates/vercel-ai-quickstart/app/api/memories/route.ts +37 -0
  56. package/templates/vercel-ai-quickstart/app/globals.css +275 -0
  57. package/templates/vercel-ai-quickstart/app/layout.tsx +19 -0
  58. package/templates/vercel-ai-quickstart/app/page.tsx +216 -0
  59. package/templates/vercel-ai-quickstart/components/AdminSetup.tsx +139 -0
  60. package/templates/vercel-ai-quickstart/components/AuthProvider.tsx +283 -0
  61. package/templates/vercel-ai-quickstart/components/ChatHistorySidebar.tsx +323 -0
  62. package/templates/vercel-ai-quickstart/components/ChatInterface.tsx +334 -0
  63. package/templates/vercel-ai-quickstart/components/ConvexClientProvider.tsx +21 -0
  64. package/templates/vercel-ai-quickstart/components/DataPreview.tsx +57 -0
  65. package/templates/vercel-ai-quickstart/components/HealthStatus.tsx +214 -0
  66. package/templates/vercel-ai-quickstart/components/LayerCard.tsx +263 -0
  67. package/templates/vercel-ai-quickstart/components/LayerFlowDiagram.tsx +195 -0
  68. package/templates/vercel-ai-quickstart/components/LoginScreen.tsx +202 -0
  69. package/templates/vercel-ai-quickstart/components/MemorySpaceSwitcher.tsx +93 -0
  70. package/templates/vercel-ai-quickstart/convex/conversations.ts +67 -0
  71. package/templates/vercel-ai-quickstart/convex/facts.ts +131 -0
  72. package/templates/vercel-ai-quickstart/convex/health.ts +15 -0
  73. package/templates/vercel-ai-quickstart/convex/memories.ts +104 -0
  74. package/templates/vercel-ai-quickstart/convex/schema.ts +20 -0
  75. package/templates/vercel-ai-quickstart/convex/users.ts +105 -0
  76. package/templates/vercel-ai-quickstart/jest.config.js +45 -0
  77. package/templates/vercel-ai-quickstart/lib/animations.ts +146 -0
  78. package/templates/vercel-ai-quickstart/lib/cortex.ts +27 -0
  79. package/templates/vercel-ai-quickstart/lib/layer-tracking.ts +214 -0
  80. package/templates/vercel-ai-quickstart/lib/password.ts +120 -0
  81. package/templates/vercel-ai-quickstart/next.config.js +27 -0
  82. package/templates/vercel-ai-quickstart/package.json +46 -0
  83. package/templates/vercel-ai-quickstart/postcss.config.js +5 -0
  84. package/templates/vercel-ai-quickstart/tailwind.config.js +37 -0
  85. package/templates/vercel-ai-quickstart/tests/helpers/mock-cortex.ts +263 -0
  86. package/templates/vercel-ai-quickstart/tests/helpers/setup.ts +48 -0
  87. package/templates/vercel-ai-quickstart/tests/integration/auth.test.ts +455 -0
  88. package/templates/vercel-ai-quickstart/tests/integration/conversations.test.ts +461 -0
  89. package/templates/vercel-ai-quickstart/tests/unit/password.test.ts +228 -0
  90. 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
+ }