@cortexmemory/cli 0.28.1 → 0.31.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.
@@ -19,20 +19,20 @@
19
19
  },
20
20
  "dependencies": {
21
21
  "@cortexmemory/sdk": "latest",
22
- "convex": "^1.31.2",
22
+ "convex": "^1.31.4",
23
23
  "dotenv": "^17.2.3",
24
- "hono": "^4.11.3",
25
- "@hono/node-server": "^1.19.7"
24
+ "hono": "^4.11.4",
25
+ "@hono/node-server": "^1.19.8"
26
26
  },
27
27
  "devDependencies": {
28
- "@types/node": "^25.0.3",
29
- "@vitest/coverage-v8": "^4.0.16",
28
+ "@types/node": "^25.0.7",
29
+ "@vitest/coverage-v8": "^4.0.17",
30
30
  "typescript": "^5.9.3",
31
31
  "tsx": "^4.21.0",
32
- "vitest": "^4.0.16"
32
+ "vitest": "^4.0.17"
33
33
  },
34
34
  "optionalDependencies": {
35
- "openai": "^6.15.0"
35
+ "openai": "^6.16.0"
36
36
  },
37
37
  "engines": {
38
38
  "node": ">=20"
@@ -45,6 +45,20 @@ export interface Fact {
45
45
  subject?: string;
46
46
  }
47
47
 
48
+ /**
49
+ * Transform SDK FactRecord to local Fact interface
50
+ * SDK uses 'fact' field, local interface uses 'content'
51
+ */
52
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
53
+ function transformFacts(sdkFacts: any[]): Fact[] {
54
+ return sdkFacts.map((f) => ({
55
+ content: f.fact || f.content || "", // SDK uses 'fact', fallback to 'content'
56
+ factType: f.factType,
57
+ confidence: f.confidence,
58
+ subject: f.subject,
59
+ }));
60
+ }
61
+
48
62
  // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
49
63
  // Conversation State
50
64
  // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
@@ -122,7 +136,9 @@ export async function chat(
122
136
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
123
137
  const result = recallResult as any;
124
138
  memories = (result.sources?.vector?.items || result.memories || []) as Memory[];
125
- facts = (result.sources?.facts?.items || result.facts || []) as Fact[];
139
+ // Transform facts: SDK FactRecord uses 'fact' field, local Fact uses 'content'
140
+ const rawFacts = result.sources?.facts?.items || result.facts || [];
141
+ facts = transformFacts(rawFacts);
126
142
 
127
143
  stopSpinner(true, `Found ${memories.length} memories, ${facts.length} facts`);
128
144
 
@@ -207,7 +223,9 @@ export async function recallMemories(query: string): Promise<void> {
207
223
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
208
224
  const result = recallResult as any;
209
225
  const memories = (result.sources?.vector?.items || result.memories || []) as Memory[];
210
- const facts = (result.sources?.facts?.items || result.facts || []) as Fact[];
226
+ // Transform facts: SDK FactRecord uses 'fact' field, local Fact uses 'content'
227
+ const rawFacts = result.sources?.facts?.items || result.facts || [];
228
+ const facts = transformFacts(rawFacts);
211
229
 
212
230
  stopSpinner(true, `Found ${memories.length} memories, ${facts.length} facts`);
213
231
  printRecallResults(memories, facts);
@@ -231,7 +249,10 @@ export async function listFacts(): Promise<void> {
231
249
  limit: 20,
232
250
  });
233
251
 
234
- const facts = (result.facts || result || []) as Fact[];
252
+ // Transform facts: SDK returns FactRecord[] directly with 'fact' field
253
+ // Local Fact interface uses 'content'
254
+ const rawFacts = Array.isArray(result) ? result : [];
255
+ const facts = transformFacts(rawFacts);
235
256
 
236
257
  stopSpinner(true, `Found ${facts.length} facts`);
237
258
  printRecallResults([], facts);
@@ -38,12 +38,28 @@ export const CONFIG = {
38
38
  // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
39
39
 
40
40
  let cortexClient: Cortex | null = null;
41
+ let initPromise: Promise<Cortex> | null = null;
41
42
 
42
43
  /**
43
- * Get or create a Cortex SDK client
44
+ * Initialize the Cortex SDK client (async)
45
+ *
46
+ * Uses Cortex.create() for automatic graph configuration from env vars.
47
+ * When CORTEX_GRAPH_SYNC=true and NEO4J_URI (or MEMGRAPH_URI) is set,
48
+ * the graph adapter is automatically created and connected.
49
+ *
50
+ * v0.29.0+: Graph sync is automatic when graphAdapter is configured.
51
+ * No need to pass syncToGraph option to remember() calls.
44
52
  */
45
- export function getCortex(): Cortex {
46
- if (!cortexClient) {
53
+ export async function initCortex(): Promise<Cortex> {
54
+ if (cortexClient) {
55
+ return cortexClient;
56
+ }
57
+
58
+ if (initPromise) {
59
+ return initPromise;
60
+ }
61
+
62
+ initPromise = (async () => {
47
63
  const convexUrl = process.env.CONVEX_URL;
48
64
  if (!convexUrl) {
49
65
  throw new Error(
@@ -65,9 +81,29 @@ export function getCortex(): Cortex {
65
81
  };
66
82
  }
67
83
 
68
- cortexClient = new Cortex(config);
69
- }
84
+ // Use Cortex.create() for async initialization with auto graph configuration
85
+ // This automatically:
86
+ // - Detects CORTEX_GRAPH_SYNC=true
87
+ // - Reads NEO4J_URI/MEMGRAPH_URI and credentials from env
88
+ // - Creates and connects the CypherGraphAdapter
89
+ cortexClient = await Cortex.create(config);
90
+ return cortexClient;
91
+ })();
92
+
93
+ return initPromise;
94
+ }
70
95
 
96
+ /**
97
+ * Get the Cortex SDK client (must call initCortex first)
98
+ *
99
+ * @throws Error if client hasn't been initialized
100
+ */
101
+ export function getCortex(): Cortex {
102
+ if (!cortexClient) {
103
+ throw new Error(
104
+ "Cortex client not initialized. Call initCortex() first.",
105
+ );
106
+ }
71
107
  return cortexClient;
72
108
  }
73
109
 
@@ -19,7 +19,7 @@
19
19
  */
20
20
 
21
21
  import * as readline from "readline";
22
- import { closeCortex } from "./cortex.js";
22
+ import { closeCortex, initCortex, CONFIG } from "./cortex.js";
23
23
  import {
24
24
  chat,
25
25
  recallMemories,
@@ -189,6 +189,22 @@ async function main(): Promise<void> {
189
189
  // Print welcome
190
190
  printWelcome("cli");
191
191
 
192
+ // Initialize Cortex client (async for graph support)
193
+ // v0.29.0+: Uses Cortex.create() for automatic graph configuration
194
+ try {
195
+ await initCortex();
196
+ // Check if graph is actually configured (flag + URI)
197
+ const hasGraphUri = !!(process.env.NEO4J_URI || process.env.MEMGRAPH_URI);
198
+ if (CONFIG.enableGraphMemory && hasGraphUri) {
199
+ printSuccess("Graph memory connected (auto-sync active)");
200
+ } else if (CONFIG.enableGraphMemory && !hasGraphUri) {
201
+ printInfo("Graph sync enabled but no database URI configured (NEO4J_URI or MEMGRAPH_URI)");
202
+ }
203
+ } catch (error) {
204
+ printError("Failed to initialize Cortex", error instanceof Error ? error : undefined);
205
+ process.exit(1);
206
+ }
207
+
192
208
  // Initialize conversation
193
209
  const convId = getConversationId();
194
210
  printSuccess(`Conversation: ${convId}`);
@@ -19,14 +19,14 @@ import { serve } from "@hono/node-server";
19
19
  import { Hono } from "hono";
20
20
  import { cors } from "hono/cors";
21
21
  import { logger } from "hono/logger";
22
- import { closeCortex, CONFIG } from "./cortex.js";
22
+ import { closeCortex, initCortex, CONFIG } from "./cortex.js";
23
23
  import {
24
24
  chat,
25
25
  recallMemories,
26
26
  listFacts,
27
27
  generateConversationId,
28
28
  } from "./chat.js";
29
- import { printWelcome, printInfo, printError } from "./display.js";
29
+ import { printWelcome, printInfo, printError, printSuccess } from "./display.js";
30
30
 
31
31
  // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
32
32
  // Server Setup
@@ -237,6 +237,22 @@ async function main(): Promise<void> {
237
237
  // Print welcome
238
238
  printWelcome("server");
239
239
 
240
+ // Initialize Cortex client (async for graph support)
241
+ // v0.29.0+: Uses Cortex.create() for automatic graph configuration
242
+ try {
243
+ await initCortex();
244
+ // Check if graph is actually configured (flag + URI)
245
+ const hasGraphUri = !!(process.env.NEO4J_URI || process.env.MEMGRAPH_URI);
246
+ if (CONFIG.enableGraphMemory && hasGraphUri) {
247
+ printSuccess("Graph memory connected (auto-sync active)");
248
+ } else if (CONFIG.enableGraphMemory && !hasGraphUri) {
249
+ printInfo("Graph sync enabled but no database URI configured (NEO4J_URI or MEMGRAPH_URI)");
250
+ }
251
+ } catch (error) {
252
+ printError("Failed to initialize Cortex", error instanceof Error ? error : undefined);
253
+ process.exit(1);
254
+ }
255
+
240
256
  // Start server
241
257
  console.log(`🚀 Server starting on http://localhost:${PORT}`);
242
258
  console.log("");
@@ -97,13 +97,14 @@ export const memoryAgent = new ToolLoopAgent({
97
97
  // │ - Facts (extracted knowledge) │
98
98
  // │ - Graph relationships (if configured) │
99
99
  // └─────────────────────────────────────────────────────────────────┘
100
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
100
101
  prepareCall: createMemoryPrepareCall({
101
102
  convexUrl: process.env.CONVEX_URL!,
102
103
  maxMemories: 20, // Max items to inject from recall
103
104
  includeFacts: true, // Include Layer 3 facts
104
105
  includeVector: true, // Include Layer 2 vector memories
105
106
  includeGraph: true, // Expand through graph relationships
106
- }),
107
+ }) as any, // Type assertion needed due to AI SDK v6 type evolution
107
108
 
108
109
  // Default to 5 steps (sufficient for most chat interactions)
109
110
  stopWhen: stepCountIs(5),
@@ -2,8 +2,8 @@ const path = require("path");
2
2
 
3
3
  /** @type {import('next').NextConfig} */
4
4
  const nextConfig = {
5
- transpilePackages: ["@cortexmemory/sdk", "@cortexmemory/vercel-ai-provider"],
6
- serverExternalPackages: ["convex"],
5
+ transpilePackages: ["@cortexmemory/vercel-ai-provider"],
6
+ serverExternalPackages: ["convex", "neo4j-driver", "@cortexmemory/sdk"],
7
7
  // Disable image optimization to avoid sharp dependency (LGPL licensed)
8
8
  // This quickstart doesn't use image optimization features
9
9
  images: {
@@ -18,7 +18,7 @@ const nextConfig = {
18
18
  // Webpack configuration for module resolution when SDK is file-linked
19
19
  // This is needed because the SDK uses dynamic imports that don't resolve
20
20
  // correctly from a linked package's location during local development
21
- webpack: (config) => {
21
+ webpack: (config, { isServer }) => {
22
22
  config.resolve.alias = {
23
23
  ...config.resolve.alias,
24
24
  "@anthropic-ai/sdk": path.resolve(
@@ -26,8 +26,17 @@ const nextConfig = {
26
26
  "node_modules/@anthropic-ai/sdk",
27
27
  ),
28
28
  openai: path.resolve(__dirname, "node_modules/openai"),
29
- "neo4j-driver": path.resolve(__dirname, "node_modules/neo4j-driver"),
30
29
  };
30
+
31
+ // Mark neo4j-driver and its rxjs dependency as external for server builds
32
+ // neo4j-driver uses rxjs for reactive sessions which doesn't bundle well
33
+ if (isServer) {
34
+ config.externals = config.externals || [];
35
+ if (Array.isArray(config.externals)) {
36
+ config.externals.push("neo4j-driver", /^rxjs/, /^rxjs\//);
37
+ }
38
+ }
39
+
31
40
  return config;
32
41
  },
33
42
  };
@@ -19,17 +19,17 @@
19
19
  "convex:deploy": "convex deploy"
20
20
  },
21
21
  "dependencies": {
22
- "@ai-sdk/openai": "^3.0.4",
23
- "@ai-sdk/react": "^3.0.11",
22
+ "@ai-sdk/openai": "^3.0.9",
23
+ "@ai-sdk/react": "^3.0.32",
24
24
  "@anthropic-ai/sdk": "^0.71.2",
25
25
  "@cortexmemory/sdk": "file:../../..",
26
26
  "@cortexmemory/vercel-ai-provider": "file:..",
27
- "ai": "^6.0.11",
28
- "convex": "^1.31.2",
29
- "framer-motion": "^12.24.0",
27
+ "ai": "^6.0.30",
28
+ "convex": "^1.31.4",
29
+ "framer-motion": "^12.26.1",
30
30
  "neo4j-driver": "^6.0.1",
31
31
  "next": "^16.1.1",
32
- "openai": "^6.15.0",
32
+ "openai": "^6.16.0",
33
33
  "react": "^19.2.3",
34
34
  "react-dom": "^19.2.3",
35
35
  "zod": "^4.3.5"
@@ -37,8 +37,8 @@
37
37
  "devDependencies": {
38
38
  "@tailwindcss/postcss": "^4.1.18",
39
39
  "@types/jest": "^30.0.0",
40
- "@types/node": "^25.0.3",
41
- "@types/react": "^19.2.7",
40
+ "@types/node": "^25.0.7",
41
+ "@types/react": "^19.2.8",
42
42
  "@types/react-dom": "^19.2.3",
43
43
  "autoprefixer": "^10.4.23",
44
44
  "jest": "^30.2.0",