cf-memory-mcp 3.8.5 โ†’ 3.8.7

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.
@@ -25,20 +25,51 @@ const { URL } = require('url');
25
25
  const os = require('os');
26
26
  const process = require('process');
27
27
 
28
- const API_URL = process.env.CF_MEMORY_API_URL || 'https://cf-memory-mcp-simplified.johnlam90.workers.dev';
28
+ // Resolve API URL, overriding the dead workers.dev URL if it's still in the
29
+ // shell environment from before the memcp.ai migration.
30
+ function _resolveApiUrl() {
31
+ const raw = process.env.CF_MEMORY_API_URL || process.env.CF_MEMORY_BASE_URL;
32
+ if (!raw || raw.includes('workers.dev')) {
33
+ return 'https://memcp.ai';
34
+ }
35
+ return raw;
36
+ }
37
+ const API_URL = _resolveApiUrl();
29
38
  const API_KEY = process.env.CF_MEMORY_API_KEY;
30
39
  const CACHE_DIR = path.join(os.homedir(), '.cache', 'cf-memory-indexer');
31
40
 
32
41
  // File patterns to include/exclude
42
+ // Mirrors src-simplified/utils/index.ts DEFAULT_INCLUDE_EXTENSIONS (110+ languages)
33
43
  const DEFAULT_INCLUDE = [
34
- '**/*.ts', '**/*.tsx', '**/*.js', '**/*.jsx',
35
- '**/*.py', '**/*.go', '**/*.rs', '**/*.java',
36
- '**/*.md', '**/*.json'
44
+ // Mainstream
45
+ '**/*.ts', '**/*.tsx', '**/*.js', '**/*.jsx', '**/*.mjs', '**/*.cjs',
46
+ '**/*.py', '**/*.rb', '**/*.go', '**/*.rs', '**/*.java', '**/*.kt', '**/*.scala',
47
+ '**/*.cs', '**/*.cpp', '**/*.c', '**/*.h', '**/*.hpp', '**/*.swift', '**/*.php',
48
+ // Functional & systems
49
+ '**/*.lua', '**/*.ex', '**/*.exs', '**/*.hs', '**/*.lhs',
50
+ '**/*.clj', '**/*.cljs', '**/*.cljc', '**/*.jl', '**/*.elm', '**/*.purs',
51
+ '**/*.dart', '**/*.zig', '**/*.nim', '**/*.cr', '**/*.erl', '**/*.hrl',
52
+ '**/*.ml', '**/*.fs', '**/*.fsi',
53
+ // Web & data
54
+ '**/*.html', '**/*.css', '**/*.scss', '**/*.vue', '**/*.svelte', '**/*.astro',
55
+ '**/*.json', '**/*.yaml', '**/*.yml', '**/*.toml',
56
+ '**/*.md', '**/*.mdx',
57
+ // Infra & build
58
+ '**/*.tf', '**/*.hcl', '**/*.sql', '**/*.sh', '**/*.bash',
59
+ '**/*.proto', '**/*.graphql', '**/*.gql',
60
+ // Shaders & GPU
61
+ '**/*.glsl', '**/*.hlsl', '**/*.wgsl', '**/*.metal', '**/*.cu', '**/*.cuh',
37
62
  ];
63
+
38
64
  const DEFAULT_EXCLUDE = [
39
65
  '**/node_modules/**', '**/.git/**', '**/dist/**',
40
- '**/build/**', '**/.next/**', '**/coverage/**',
41
- '**/*.min.js', '**/*.d.ts'
66
+ '**/build/**', '**/out/**', '**/.next/**', '**/.nuxt/**',
67
+ '**/coverage/**', '**/__pycache__/**', '**/venv/**', '**/.venv/**',
68
+ '**/.wrangler/**', '**/.turbo/**', '**/.cache/**',
69
+ '**/.history/**', '**/.vscode/**', '**/.idea/**', '**/.vs/**',
70
+ '**/.augment/**', '**/.kiro/**', '**/.intent/**', '**/.husky/**', '**/.claude/**',
71
+ '**/*.min.js', '**/*.min.css', '**/*.map', '**/*.d.ts',
72
+ '**/package-lock.json', '**/yarn.lock', '**/pnpm-lock.yaml',
42
73
  ];
43
74
 
44
75
  class IncrementalIndexer {
@@ -205,6 +236,16 @@ class IncrementalIndexer {
205
236
  console.log(`๐Ÿ“ค Uploading ${changedFiles.length} files...`);
206
237
  await this.uploadFiles(changedFiles);
207
238
  }
239
+
240
+ if (this.cache.projectId && deletedFiles.length > 0) {
241
+ console.log(`๐Ÿงน Cleaning up ${deletedFiles.length} deleted files...`);
242
+ await this.cleanupDeletedFiles(deletedFiles);
243
+ }
244
+
245
+ if (this.cache.projectId && (changedFiles.length > 0 || deletedFiles.length > 0)) {
246
+ console.log('๐Ÿ“Œ Finalizing project stats...');
247
+ await this.finalizeProject();
248
+ }
208
249
 
209
250
  // Update cache
210
251
  for (const file of changedFiles) {
@@ -238,59 +279,101 @@ class IncrementalIndexer {
238
279
  }
239
280
 
240
281
  async uploadBatch(files) {
241
- return new Promise((resolve, reject) => {
242
- const payload = JSON.stringify({
282
+ if (!this.cache.projectId) {
283
+ const initResult = await this.callMcpTool('index_project', {
243
284
  project_path: this.projectPath,
244
- project_name: this.projectName,
245
- files: files.map(f => ({
246
- path: f.path,
247
- content: f.content
248
- }))
285
+ project_name: this.projectName
249
286
  });
250
-
251
- const url = new URL(`${API_URL}/mcp/tools/index_project`);
287
+ const initContent = this.parseToolTextResult(initResult);
288
+
289
+ if (!initContent.project_id) {
290
+ throw new Error('Project initialization did not return project_id');
291
+ }
292
+
293
+ this.cache.projectId = initContent.project_id;
294
+ this.saveCache();
295
+ }
296
+
297
+ return this.postJson(`/api/projects/${encodeURIComponent(this.cache.projectId)}/files/batch`, {
298
+ files: files.map(f => ({
299
+ file_path: f.path,
300
+ content: f.content
301
+ }))
302
+ });
303
+ }
304
+
305
+ async callMcpTool(name, args) {
306
+ return this.postJson('/mcp', {
307
+ jsonrpc: '2.0',
308
+ id: `idx-${Date.now()}`,
309
+ method: 'tools/call',
310
+ params: {
311
+ name,
312
+ arguments: args
313
+ }
314
+ });
315
+ }
316
+
317
+ async cleanupDeletedFiles(filePaths) {
318
+ return this.postJson(`/api/projects/${encodeURIComponent(this.cache.projectId)}/files/cleanup`, {
319
+ file_paths: filePaths
320
+ });
321
+ }
322
+
323
+ async finalizeProject() {
324
+ return this.postJson(`/api/projects/${encodeURIComponent(this.cache.projectId)}/finalize`, {});
325
+ }
326
+
327
+ parseToolTextResult(result) {
328
+ const text = result?.result?.content?.[0]?.text;
329
+ if (!text) {
330
+ throw new Error('Tool response did not contain text content');
331
+ }
332
+ return JSON.parse(text);
333
+ }
334
+
335
+ async postJson(route, payload) {
336
+ return new Promise((resolve, reject) => {
337
+ const body = JSON.stringify(payload);
338
+ const url = new URL(`${API_URL}${route}`);
252
339
  const options = {
253
340
  hostname: url.hostname,
254
- path: url.pathname,
341
+ port: url.port || 443,
342
+ path: url.pathname + url.search,
255
343
  method: 'POST',
256
344
  headers: {
257
345
  'Content-Type': 'application/json',
258
346
  'Authorization': `Bearer ${API_KEY}`,
259
- 'Content-Length': Buffer.byteLength(payload)
347
+ 'X-API-Key': API_KEY,
348
+ 'Content-Length': Buffer.byteLength(body)
260
349
  },
261
350
  timeout: 120000
262
351
  };
263
-
352
+
264
353
  const req = https.request(options, (res) => {
265
354
  let data = '';
266
355
  res.on('data', chunk => data += chunk);
267
356
  res.on('end', () => {
268
- if (res.statusCode >= 200 && res.statusCode < 300) {
269
- try {
270
- const result = JSON.parse(data);
271
- if (result.content && result.content[0]) {
272
- const content = JSON.parse(result.content[0].text);
273
- if (content.project_id) {
274
- this.cache.projectId = content.project_id;
275
- }
276
- }
277
- resolve(result);
278
- } catch (err) {
279
- reject(new Error(`Invalid response: ${err.message}`));
357
+ try {
358
+ const parsed = JSON.parse(data || '{}');
359
+ if (res.statusCode >= 200 && res.statusCode < 300) {
360
+ resolve(parsed);
361
+ return;
280
362
  }
281
- } else {
282
363
  reject(new Error(`HTTP ${res.statusCode}: ${data}`));
364
+ } catch (err) {
365
+ reject(new Error(`Invalid response: ${err.message}`));
283
366
  }
284
367
  });
285
368
  });
286
-
369
+
287
370
  req.on('error', reject);
288
371
  req.on('timeout', () => {
289
372
  req.destroy();
290
373
  reject(new Error('Request timeout'));
291
374
  });
292
-
293
- req.write(payload);
375
+
376
+ req.write(body);
294
377
  req.end();
295
378
  });
296
379
  }
@@ -350,15 +433,20 @@ async function main() {
350
433
 
351
434
  // Detect command from how the script was called (cf-memory-index vs cf-memory-watch)
352
435
  const scriptName = path.basename(process.argv[1]);
353
- let command = args[0];
354
- let projectPath = args[1] || '.';
436
+ let command = 'index';
437
+ let projectPath = '.';
355
438
 
356
- if (scriptName.includes('watch')) {
439
+ if (args[0] === 'watch' || args[0] === 'index') {
440
+ command = args[0];
441
+ projectPath = args[1] || '.';
442
+ } else if (scriptName.includes('watch')) {
357
443
  command = 'watch';
358
444
  projectPath = args[0] || '.';
359
445
  } else if (scriptName.includes('index')) {
360
446
  command = 'index';
361
447
  projectPath = args[0] || '.';
448
+ } else {
449
+ projectPath = args[0] || '.';
362
450
  }
363
451
 
364
452
  const options = {