@cortexmemory/cli 0.27.3 → 0.28.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/dist/commands/db.d.ts.map +1 -1
  2. package/dist/commands/db.js +18 -6
  3. package/dist/commands/db.js.map +1 -1
  4. package/dist/commands/deploy.d.ts.map +1 -1
  5. package/dist/commands/deploy.js +191 -80
  6. package/dist/commands/deploy.js.map +1 -1
  7. package/dist/commands/dev.js +3 -2
  8. package/dist/commands/dev.js.map +1 -1
  9. package/dist/commands/init.d.ts.map +1 -1
  10. package/dist/commands/init.js +12 -0
  11. package/dist/commands/init.js.map +1 -1
  12. package/dist/types.d.ts +1 -1
  13. package/dist/types.d.ts.map +1 -1
  14. package/dist/utils/app-template-sync.d.ts.map +1 -1
  15. package/dist/utils/app-template-sync.js +35 -13
  16. package/dist/utils/app-template-sync.js.map +1 -1
  17. package/dist/utils/init/quickstart-setup.d.ts.map +1 -1
  18. package/dist/utils/init/quickstart-setup.js.map +1 -1
  19. package/package.json +4 -4
  20. package/templates/basic/.env.local.example +23 -0
  21. package/templates/basic/README.md +181 -56
  22. package/templates/basic/package-lock.json +2180 -406
  23. package/templates/basic/package.json +23 -5
  24. package/templates/basic/src/__tests__/chat.test.ts +340 -0
  25. package/templates/basic/src/__tests__/cortex.test.ts +260 -0
  26. package/templates/basic/src/__tests__/display.test.ts +455 -0
  27. package/templates/basic/src/__tests__/e2e/fact-extraction.test.ts +498 -0
  28. package/templates/basic/src/__tests__/e2e/memory-flow.test.ts +355 -0
  29. package/templates/basic/src/__tests__/e2e/server-e2e.test.ts +414 -0
  30. package/templates/basic/src/__tests__/helpers/test-utils.ts +345 -0
  31. package/templates/basic/src/__tests__/integration/chat-flow.test.ts +422 -0
  32. package/templates/basic/src/__tests__/integration/server.test.ts +441 -0
  33. package/templates/basic/src/__tests__/llm.test.ts +344 -0
  34. package/templates/basic/src/chat.ts +300 -0
  35. package/templates/basic/src/cortex.ts +203 -0
  36. package/templates/basic/src/display.ts +425 -0
  37. package/templates/basic/src/index.ts +194 -64
  38. package/templates/basic/src/llm.ts +214 -0
  39. package/templates/basic/src/server.ts +280 -0
  40. package/templates/basic/vitest.config.ts +33 -0
  41. package/templates/basic/vitest.e2e.config.ts +28 -0
  42. package/templates/basic/vitest.integration.config.ts +25 -0
  43. package/templates/vercel-ai-quickstart/app/api/auth/check/route.ts +1 -1
  44. package/templates/vercel-ai-quickstart/app/api/auth/login/route.ts +61 -19
  45. package/templates/vercel-ai-quickstart/app/api/auth/register/route.ts +14 -18
  46. package/templates/vercel-ai-quickstart/app/api/auth/setup/route.ts +4 -7
  47. package/templates/vercel-ai-quickstart/app/api/chat/route.ts +95 -23
  48. package/templates/vercel-ai-quickstart/app/api/chat-v6/route.ts +339 -0
  49. package/templates/vercel-ai-quickstart/app/api/conversations/route.ts +16 -16
  50. package/templates/vercel-ai-quickstart/app/globals.css +24 -9
  51. package/templates/vercel-ai-quickstart/app/page.tsx +41 -15
  52. package/templates/vercel-ai-quickstart/components/AdminSetup.tsx +3 -1
  53. package/templates/vercel-ai-quickstart/components/AuthProvider.tsx +6 -6
  54. package/templates/vercel-ai-quickstart/components/ChatHistorySidebar.tsx +19 -8
  55. package/templates/vercel-ai-quickstart/components/ChatInterface.tsx +46 -16
  56. package/templates/vercel-ai-quickstart/components/LoginScreen.tsx +10 -5
  57. package/templates/vercel-ai-quickstart/jest.config.js +8 -1
  58. package/templates/vercel-ai-quickstart/lib/agents/memory-agent.ts +165 -0
  59. package/templates/vercel-ai-quickstart/lib/password.ts +5 -5
  60. package/templates/vercel-ai-quickstart/lib/versions.ts +60 -0
  61. package/templates/vercel-ai-quickstart/next.config.js +10 -2
  62. package/templates/vercel-ai-quickstart/package.json +23 -12
  63. package/templates/vercel-ai-quickstart/test-api.mjs +303 -0
  64. package/templates/vercel-ai-quickstart/tests/e2e/chat-memory-flow.test.ts +483 -0
  65. package/templates/vercel-ai-quickstart/tests/helpers/mock-cortex.ts +40 -40
  66. package/templates/vercel-ai-quickstart/tests/integration/auth.test.ts +8 -8
  67. package/templates/vercel-ai-quickstart/tests/integration/conversations.test.ts +12 -8
  68. package/templates/vercel-ai-quickstart/tests/unit/password.test.ts +4 -1
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Version detection utilities for displaying SDK versions in the UI.
3
+ */
4
+
5
+ export interface VersionInfo {
6
+ cortexSdk: string;
7
+ aiSdk: string;
8
+ aiSdkMajor: number;
9
+ }
10
+
11
+ /**
12
+ * Detect installed SDK versions at runtime.
13
+ * Returns version strings for display in the UI.
14
+ */
15
+ export async function detectVersions(): Promise<VersionInfo> {
16
+ let cortexSdk = "unknown";
17
+ let aiSdk = "unknown";
18
+ let aiSdkMajor = 5;
19
+
20
+ // Detect Cortex SDK version
21
+ try {
22
+ const cortexModule = await import("@cortexmemory/sdk");
23
+ // Check for version export or use package version
24
+ if ("VERSION" in cortexModule) {
25
+ cortexSdk = cortexModule.VERSION as string;
26
+ } else {
27
+ // Fallback: try to detect from package
28
+ cortexSdk = "0.24.0";
29
+ }
30
+ } catch {
31
+ cortexSdk = "0.24.0";
32
+ }
33
+
34
+ // Detect AI SDK version by checking for v6-specific exports
35
+ try {
36
+ const aiModule = await import("ai");
37
+
38
+ // v6 has these specific exports
39
+ const hasV6Features =
40
+ "ToolLoopAgent" in aiModule ||
41
+ "createAgentUIStreamResponse" in aiModule ||
42
+ "Output" in aiModule;
43
+
44
+ if (hasV6Features) {
45
+ aiSdkMajor = 6;
46
+ aiSdk = "v6";
47
+ } else {
48
+ aiSdkMajor = 5;
49
+ aiSdk = "v5";
50
+ }
51
+ } catch {
52
+ aiSdk = "v5";
53
+ }
54
+
55
+ return {
56
+ cortexSdk,
57
+ aiSdk,
58
+ aiSdkMajor,
59
+ };
60
+ }
@@ -4,6 +4,11 @@ const path = require("path");
4
4
  const nextConfig = {
5
5
  transpilePackages: ["@cortexmemory/sdk", "@cortexmemory/vercel-ai-provider"],
6
6
  serverExternalPackages: ["convex"],
7
+ // Disable image optimization to avoid sharp dependency (LGPL licensed)
8
+ // This quickstart doesn't use image optimization features
9
+ images: {
10
+ unoptimized: true,
11
+ },
7
12
  experimental: {
8
13
  // Ensure linked packages resolve dependencies from this project's node_modules
9
14
  externalDir: true,
@@ -16,8 +21,11 @@ const nextConfig = {
16
21
  webpack: (config) => {
17
22
  config.resolve.alias = {
18
23
  ...config.resolve.alias,
19
- "@anthropic-ai/sdk": path.resolve(__dirname, "node_modules/@anthropic-ai/sdk"),
20
- "openai": path.resolve(__dirname, "node_modules/openai"),
24
+ "@anthropic-ai/sdk": path.resolve(
25
+ __dirname,
26
+ "node_modules/@anthropic-ai/sdk",
27
+ ),
28
+ openai: path.resolve(__dirname, "node_modules/openai"),
21
29
  "neo4j-driver": path.resolve(__dirname, "node_modules/neo4j-driver"),
22
30
  };
23
31
  return config;
@@ -5,42 +5,53 @@
5
5
  "license": "UNLICENSED",
6
6
  "description": "Cortex Memory + Vercel AI SDK Quickstart Demo",
7
7
  "scripts": {
8
- "dev": "next dev --webpack",
8
+ "dev": "next dev --webpack -H 0.0.0.0",
9
9
  "build": "next build --webpack",
10
- "start": "next start",
10
+ "start": "next start -H 0.0.0.0",
11
11
  "lint": "next lint",
12
- "test": "jest",
12
+ "test": "jest --selectProjects unit integration",
13
+ "test:unit": "jest --selectProjects unit",
14
+ "test:integration": "jest --selectProjects integration",
15
+ "test:e2e": "jest --selectProjects e2e",
16
+ "test:all": "jest",
13
17
  "test:watch": "jest --watch",
14
18
  "convex:dev": "convex dev",
15
19
  "convex:deploy": "convex deploy"
16
20
  },
17
21
  "dependencies": {
18
- "@ai-sdk/openai": "^3.0.1",
19
- "@ai-sdk/react": "^3.0.3",
22
+ "@ai-sdk/openai": "^3.0.4",
23
+ "@ai-sdk/react": "^3.0.11",
20
24
  "@anthropic-ai/sdk": "^0.71.2",
21
25
  "@cortexmemory/sdk": "file:../../..",
22
26
  "@cortexmemory/vercel-ai-provider": "file:..",
23
- "ai": "^6.0.3",
27
+ "ai": "^6.0.11",
24
28
  "convex": "^1.31.2",
25
- "framer-motion": "^12.23.26",
29
+ "framer-motion": "^12.24.0",
26
30
  "neo4j-driver": "^6.0.1",
27
31
  "next": "^16.1.1",
28
32
  "openai": "^6.15.0",
29
33
  "react": "^19.2.3",
30
34
  "react-dom": "^19.2.3",
31
- "zod": "^4.2.1"
35
+ "zod": "^4.3.5"
32
36
  },
33
37
  "devDependencies": {
34
38
  "@tailwindcss/postcss": "^4.1.18",
35
- "@types/jest": "^29.5.14",
39
+ "@types/jest": "^30.0.0",
36
40
  "@types/node": "^25.0.3",
37
41
  "@types/react": "^19.2.7",
38
42
  "@types/react-dom": "^19.2.3",
39
43
  "autoprefixer": "^10.4.23",
40
- "jest": "^29.7.0",
44
+ "jest": "^30.2.0",
41
45
  "postcss": "^8.5.6",
42
46
  "tailwindcss": "^4.1.18",
43
- "ts-jest": "^29.2.5",
47
+ "ts-jest": "^29.4.6",
44
48
  "typescript": "^5.9.3"
45
- }
49
+ },
50
+ "main": "jest.config.js",
51
+ "directories": {
52
+ "lib": "lib",
53
+ "test": "tests"
54
+ },
55
+ "keywords": [],
56
+ "author": ""
46
57
  }
@@ -0,0 +1,303 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Programmatic API Route Tests
4
+ * Tests both v5 and v6 routes for memory functionality
5
+ */
6
+
7
+ const BASE_URL = process.env.QUICKSTART_URL || "http://localhost:3000";
8
+
9
+ // Test configuration
10
+ const TEST_USER_ID = `test-user-${Date.now()}`;
11
+ const TEST_MEMORY_SPACE_ID = "quickstart-demo";
12
+
13
+ async function sleep(ms) {
14
+ return new Promise((resolve) => setTimeout(resolve, ms));
15
+ }
16
+
17
+ async function testRoute(routePath, routeName) {
18
+ console.log(`\n${"=".repeat(60)}`);
19
+ console.log(`Testing ${routeName} (${routePath})`);
20
+ console.log("=".repeat(60));
21
+
22
+ const conversationId = `conv-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
23
+
24
+ // Test 1: Send a message with a fact
25
+ console.log("\n📤 Test 1: Sending message with a fact...");
26
+ const message1 = {
27
+ id: `msg-${Date.now()}-1`,
28
+ role: "user",
29
+ content: `My favorite programming language is TypeScript and I work at a company called TechCorp.`,
30
+ createdAt: new Date().toISOString(),
31
+ };
32
+
33
+ try {
34
+ const response1 = await fetch(`${BASE_URL}${routePath}`, {
35
+ method: "POST",
36
+ headers: { "Content-Type": "application/json" },
37
+ body: JSON.stringify({
38
+ messages: [message1],
39
+ userId: TEST_USER_ID,
40
+ memorySpaceId: TEST_MEMORY_SPACE_ID,
41
+ conversationId,
42
+ }),
43
+ });
44
+
45
+ if (!response1.ok) {
46
+ const errorText = await response1.text();
47
+ console.log(`❌ Request failed with status ${response1.status}`);
48
+ console.log(` Error: ${errorText.slice(0, 500)}`);
49
+ return {
50
+ success: false,
51
+ route: routeName,
52
+ error: `HTTP ${response1.status}`,
53
+ };
54
+ }
55
+
56
+ // Read streaming response
57
+ const reader = response1.body.getReader();
58
+ const decoder = new TextDecoder();
59
+ let fullResponse = "";
60
+ let chunks = 0;
61
+
62
+ while (true) {
63
+ const { done, value } = await reader.read();
64
+ if (done) break;
65
+ const chunk = decoder.decode(value, { stream: true });
66
+ fullResponse += chunk;
67
+ chunks++;
68
+ }
69
+
70
+ console.log(
71
+ `✅ Response received (${chunks} chunks, ${fullResponse.length} bytes)`,
72
+ );
73
+
74
+ // Check for layer observer data
75
+ const hasLayerData =
76
+ fullResponse.includes("FACTS_LAYER") ||
77
+ fullResponse.includes("MEMORY_LAYER") ||
78
+ fullResponse.includes("layerId");
79
+ console.log(
80
+ ` Layer observer data: ${hasLayerData ? "✅ Present" : "❌ Missing"}`,
81
+ );
82
+
83
+ // Check for text content
84
+ const hasTextContent =
85
+ fullResponse.includes('"type":"text"') ||
86
+ fullResponse.includes("text-delta");
87
+ console.log(
88
+ ` Text content: ${hasTextContent ? "✅ Present" : "❌ Missing"}`,
89
+ );
90
+ } catch (error) {
91
+ console.log(`❌ Request error: ${error.message}`);
92
+ return { success: false, route: routeName, error: error.message };
93
+ }
94
+
95
+ // Wait for async processing (fact extraction, etc.)
96
+ console.log("\n⏳ Waiting for memory processing...");
97
+ await sleep(3000);
98
+
99
+ // Test 2: Check if facts were stored
100
+ console.log("\n🔍 Test 2: Checking stored facts...");
101
+ try {
102
+ const factsResponse = await fetch(
103
+ `${BASE_URL}/api/facts?userId=${TEST_USER_ID}&memorySpaceId=${TEST_MEMORY_SPACE_ID}`,
104
+ { method: "GET" },
105
+ );
106
+
107
+ if (factsResponse.ok) {
108
+ const factsData = await factsResponse.json();
109
+ const facts = factsData.facts || factsData || [];
110
+ console.log(
111
+ `✅ Facts API returned: ${Array.isArray(facts) ? facts.length : "unknown"} facts`,
112
+ );
113
+
114
+ if (Array.isArray(facts) && facts.length > 0) {
115
+ console.log(" Sample facts:");
116
+ facts.slice(0, 3).forEach((fact, i) => {
117
+ const content =
118
+ fact.content || fact.text || JSON.stringify(fact).slice(0, 100);
119
+ console.log(` ${i + 1}. ${content.slice(0, 80)}...`);
120
+ });
121
+ }
122
+ } else {
123
+ console.log(`⚠️ Facts API returned ${factsResponse.status}`);
124
+ }
125
+ } catch (error) {
126
+ console.log(`⚠️ Could not check facts: ${error.message}`);
127
+ }
128
+
129
+ // Test 3: Send follow-up message and verify recall
130
+ console.log("\n📤 Test 3: Sending follow-up to test recall...");
131
+ const message2 = {
132
+ id: `msg-${Date.now()}-2`,
133
+ role: "user",
134
+ content: "What programming language do I prefer?",
135
+ createdAt: new Date().toISOString(),
136
+ };
137
+
138
+ // Include previous assistant response for context
139
+ const message1Response = {
140
+ id: `msg-${Date.now()}-1r`,
141
+ role: "assistant",
142
+ content:
143
+ "Great! TypeScript is a fantastic choice for type-safe development.",
144
+ createdAt: new Date().toISOString(),
145
+ };
146
+
147
+ try {
148
+ const response2 = await fetch(`${BASE_URL}${routePath}`, {
149
+ method: "POST",
150
+ headers: { "Content-Type": "application/json" },
151
+ body: JSON.stringify({
152
+ messages: [message1, message1Response, message2],
153
+ userId: TEST_USER_ID,
154
+ memorySpaceId: TEST_MEMORY_SPACE_ID,
155
+ conversationId,
156
+ }),
157
+ });
158
+
159
+ if (!response2.ok) {
160
+ console.log(
161
+ `❌ Follow-up request failed with status ${response2.status}`,
162
+ );
163
+ return {
164
+ success: false,
165
+ route: routeName,
166
+ error: `Follow-up HTTP ${response2.status}`,
167
+ };
168
+ }
169
+
170
+ const reader = response2.body.getReader();
171
+ const decoder = new TextDecoder();
172
+ let fullResponse = "";
173
+
174
+ while (true) {
175
+ const { done, value } = await reader.read();
176
+ if (done) break;
177
+ fullResponse += decoder.decode(value, { stream: true });
178
+ }
179
+
180
+ // Check if TypeScript was mentioned in the response (recall working)
181
+ const mentionsTypeScript = fullResponse
182
+ .toLowerCase()
183
+ .includes("typescript");
184
+ console.log(`✅ Response received`);
185
+ console.log(
186
+ ` Recalls TypeScript preference: ${mentionsTypeScript ? "✅ Yes" : "❌ No"}`,
187
+ );
188
+
189
+ return {
190
+ success: true,
191
+ route: routeName,
192
+ recallWorks: mentionsTypeScript,
193
+ };
194
+ } catch (error) {
195
+ console.log(`❌ Follow-up request error: ${error.message}`);
196
+ return { success: false, route: routeName, error: error.message };
197
+ }
198
+ }
199
+
200
+ async function testConversationAPI() {
201
+ console.log(`\n${"=".repeat(60)}`);
202
+ console.log("Testing Conversation API");
203
+ console.log("=".repeat(60));
204
+
205
+ try {
206
+ const response = await fetch(
207
+ `${BASE_URL}/api/conversations?userId=${TEST_USER_ID}&memorySpaceId=${TEST_MEMORY_SPACE_ID}`,
208
+ { method: "GET" },
209
+ );
210
+
211
+ if (response.ok) {
212
+ const data = await response.json();
213
+ const conversations = data.conversations || data || [];
214
+ console.log(
215
+ `✅ Conversations API works: ${Array.isArray(conversations) ? conversations.length : "unknown"} conversations`,
216
+ );
217
+ return true;
218
+ } else {
219
+ console.log(`❌ Conversations API returned ${response.status}`);
220
+ return false;
221
+ }
222
+ } catch (error) {
223
+ console.log(`❌ Conversations API error: ${error.message}`);
224
+ return false;
225
+ }
226
+ }
227
+
228
+ async function checkServerHealth() {
229
+ console.log("🏥 Checking server health...");
230
+ try {
231
+ const response = await fetch(`${BASE_URL}/api/health`, {
232
+ method: "GET",
233
+ signal: AbortSignal.timeout(5000),
234
+ });
235
+ if (response.ok) {
236
+ console.log("✅ Server is healthy");
237
+ return true;
238
+ } else {
239
+ console.log(`❌ Health check failed: ${response.status}`);
240
+ return false;
241
+ }
242
+ } catch (error) {
243
+ console.log(`❌ Server not reachable: ${error.message}`);
244
+ return false;
245
+ }
246
+ }
247
+
248
+ async function main() {
249
+ console.log("🧪 Cortex Memory API Route Tests");
250
+ console.log(`📍 Testing server at: ${BASE_URL}`);
251
+ console.log(`👤 Test user: ${TEST_USER_ID}`);
252
+ console.log(`📦 Memory space: ${TEST_MEMORY_SPACE_ID}`);
253
+
254
+ // Check server health first
255
+ const healthy = await checkServerHealth();
256
+ if (!healthy) {
257
+ console.log(
258
+ "\n❌ Server is not running. Please start the quickstart first:",
259
+ );
260
+ console.log(" cd packages/vercel-ai-provider/quickstart && npm run dev");
261
+ process.exit(1);
262
+ }
263
+
264
+ const results = [];
265
+
266
+ // Test conversation API
267
+ await testConversationAPI();
268
+
269
+ // Test v5 route
270
+ const v5Result = await testRoute("/api/chat", "V5 Route");
271
+ results.push(v5Result);
272
+
273
+ // Test v6 route
274
+ const v6Result = await testRoute("/api/chat-v6", "V6 Route");
275
+ results.push(v6Result);
276
+
277
+ // Summary
278
+ console.log(`\n${"=".repeat(60)}`);
279
+ console.log("📊 Test Summary");
280
+ console.log("=".repeat(60));
281
+
282
+ let allPassed = true;
283
+ for (const result of results) {
284
+ const status = result.success ? "✅ PASS" : "❌ FAIL";
285
+ const recall =
286
+ result.recallWorks !== undefined
287
+ ? result.recallWorks
288
+ ? " (recall ✅)"
289
+ : " (recall ❌)"
290
+ : "";
291
+ const error = result.error ? ` - ${result.error}` : "";
292
+ console.log(`${status} ${result.route}${recall}${error}`);
293
+ if (!result.success) allPassed = false;
294
+ }
295
+
296
+ console.log("");
297
+ process.exit(allPassed ? 0 : 1);
298
+ }
299
+
300
+ main().catch((error) => {
301
+ console.error("Test runner error:", error);
302
+ process.exit(1);
303
+ });