code-graph-context 1.0.0 → 2.0.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 (47) hide show
  1. package/README.md +221 -101
  2. package/dist/core/config/fairsquare-framework-schema.js +47 -60
  3. package/dist/core/config/nestjs-framework-schema.js +11 -1
  4. package/dist/core/config/schema.js +1 -1
  5. package/dist/core/config/timeouts.js +27 -0
  6. package/dist/core/embeddings/embeddings.service.js +122 -2
  7. package/dist/core/embeddings/natural-language-to-cypher.service.js +428 -30
  8. package/dist/core/parsers/parser-factory.js +6 -6
  9. package/dist/core/parsers/typescript-parser.js +639 -44
  10. package/dist/core/parsers/workspace-parser.js +553 -0
  11. package/dist/core/utils/edge-factory.js +37 -0
  12. package/dist/core/utils/file-change-detection.js +105 -0
  13. package/dist/core/utils/file-utils.js +20 -0
  14. package/dist/core/utils/index.js +3 -0
  15. package/dist/core/utils/path-utils.js +75 -0
  16. package/dist/core/utils/progress-reporter.js +112 -0
  17. package/dist/core/utils/project-id.js +176 -0
  18. package/dist/core/utils/retry.js +41 -0
  19. package/dist/core/workspace/index.js +4 -0
  20. package/dist/core/workspace/workspace-detector.js +221 -0
  21. package/dist/mcp/constants.js +172 -7
  22. package/dist/mcp/handlers/cross-file-edge.helpers.js +19 -0
  23. package/dist/mcp/handlers/file-change-detection.js +105 -0
  24. package/dist/mcp/handlers/graph-generator.handler.js +97 -32
  25. package/dist/mcp/handlers/incremental-parse.handler.js +146 -0
  26. package/dist/mcp/handlers/streaming-import.handler.js +210 -0
  27. package/dist/mcp/handlers/traversal.handler.js +130 -71
  28. package/dist/mcp/mcp.server.js +46 -7
  29. package/dist/mcp/service-init.js +79 -0
  30. package/dist/mcp/services/job-manager.js +165 -0
  31. package/dist/mcp/services/watch-manager.js +376 -0
  32. package/dist/mcp/services.js +48 -127
  33. package/dist/mcp/tools/check-parse-status.tool.js +64 -0
  34. package/dist/mcp/tools/impact-analysis.tool.js +319 -0
  35. package/dist/mcp/tools/index.js +15 -1
  36. package/dist/mcp/tools/list-projects.tool.js +62 -0
  37. package/dist/mcp/tools/list-watchers.tool.js +51 -0
  38. package/dist/mcp/tools/natural-language-to-cypher.tool.js +34 -8
  39. package/dist/mcp/tools/parse-typescript-project.tool.js +325 -60
  40. package/dist/mcp/tools/search-codebase.tool.js +57 -23
  41. package/dist/mcp/tools/start-watch-project.tool.js +100 -0
  42. package/dist/mcp/tools/stop-watch-project.tool.js +49 -0
  43. package/dist/mcp/tools/traverse-from-node.tool.js +68 -9
  44. package/dist/mcp/utils.js +35 -12
  45. package/dist/mcp/workers/parse-worker.js +198 -0
  46. package/dist/storage/neo4j/neo4j.service.js +273 -34
  47. package/package.json +4 -2
package/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  [![npm version](https://badge.fury.io/js/code-graph-context.svg)](https://www.npmjs.com/package/code-graph-context)
4
4
  [![MIT License](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE)
5
5
  [![TypeScript](https://img.shields.io/badge/TypeScript-5.8-007ACC?logo=typescript&logoColor=white)](https://typescriptlang.org/)
6
- [![Neo4j](https://img.shields.io/badge/Neo4j-5.0+-018bff?logo=neo4j&logoColor=white)](https://neo4j.com/)
6
+ [![Neo4j](https://img.shields.io/badge/Neo4j-5.23+-018bff?logo=neo4j&logoColor=white)](https://neo4j.com/)
7
7
  [![NestJS](https://img.shields.io/badge/NestJS-Compatible-E0234E?logo=nestjs&logoColor=white)](https://nestjs.com/)
8
8
  [![OpenAI](https://img.shields.io/badge/OpenAI-Powered-412991?logo=openai&logoColor=white)](https://openai.com/)
9
9
  [![MCP](https://img.shields.io/badge/MCP-Server-blue)](https://modelcontextprotocol.io/)
@@ -14,11 +14,18 @@ A Model Context Protocol (MCP) server that builds rich code graphs to provide de
14
14
 
15
15
  ## Features
16
16
 
17
+ - **Multi-Project Support**: Parse and query multiple projects in a single database with complete isolation via `projectId`
17
18
  - **Rich Code Graph Generation**: Parses TypeScript projects and creates detailed graph representations with AST-level precision
18
19
  - **Semantic Search**: Vector-based semantic search using OpenAI embeddings to find relevant code patterns and implementations
19
20
  - **Natural Language Querying**: Convert natural language questions into Cypher queries using OpenAI assistants API
20
21
  - **Framework-Aware & Customizable**: Built-in NestJS schema with ability to define custom framework patterns via configuration
21
22
  - **Weighted Graph Traversal**: Intelligent traversal that scores paths based on relationship importance, query relevance, and depth
23
+ - **Workspace & Monorepo Support**: Auto-detects Turborepo, pnpm, Yarn, and npm workspaces
24
+ - **Async Parsing**: Background parsing with Worker threads for large codebases without blocking the MCP server
25
+ - **Streaming Import**: Chunked processing for projects with 100+ files to prevent memory issues
26
+ - **Incremental Parsing**: Only reparse changed files for faster updates
27
+ - **File Watching**: Real-time monitoring with automatic incremental graph updates on file changes
28
+ - **Impact Analysis**: Assess refactoring risk with dependency analysis (LOW/MEDIUM/HIGH/CRITICAL scoring)
22
29
  - **High Performance**: Optimized Neo4j storage with vector indexing for fast retrieval
23
30
  - **MCP Integration**: Seamless integration with Claude Code and other MCP-compatible tools
24
31
 
@@ -45,7 +52,7 @@ The system uses a dual-schema approach:
45
52
  ### Prerequisites
46
53
 
47
54
  - **Node.js** >= 18
48
- - **Neo4j** >= 5.0 with APOC plugin
55
+ - **Neo4j** >= 5.23 with APOC plugin
49
56
  - **OpenAI API Key** (for embeddings and natural language processing)
50
57
  - **Docker** (recommended for Neo4j setup)
51
58
 
@@ -112,7 +119,7 @@ docker run -d \
112
119
  -p 7474:7474 -p 7687:7687 \
113
120
  -e NEO4J_AUTH=neo4j/PASSWORD \
114
121
  -e NEO4J_PLUGINS='["apoc"]' \
115
- neo4j:5.15
122
+ neo4j:5.23
116
123
  ```
117
124
 
118
125
  **Option B: Neo4j Desktop**
@@ -226,9 +233,67 @@ node /path/to/code-graph-context/dist/mcp/mcp.server.js
226
233
  npm run build
227
234
  ```
228
235
 
229
- ## Tool Usage Guide & Sequential Workflows
236
+ ## Tool Usage Guide
230
237
 
231
- ### Sequential Tool Usage Patterns
238
+ ### Available Tools
239
+
240
+ | Tool | Description | Best For |
241
+ |------|-------------|----------|
242
+ | `list_projects` | List all parsed projects in database | **Discovery** - see available projects and their status |
243
+ | `search_codebase` | Semantic search using vector embeddings | **Starting point** - find code by describing what you need |
244
+ | `traverse_from_node` | Explore relationships from a specific node | **Deep dive** - understand dependencies and connections |
245
+ | `impact_analysis` | Analyze what depends on a node | **Pre-refactoring** - assess blast radius (LOW/MEDIUM/HIGH/CRITICAL) |
246
+ | `parse_typescript_project` | Parse project and build the graph | **Initial setup** - supports async mode for large projects |
247
+ | `check_parse_status` | Monitor async parsing job progress | **Monitoring** - track background parsing jobs |
248
+ | `start_watch_project` | Start file watching for a project | **Live updates** - auto-update graph on file changes |
249
+ | `stop_watch_project` | Stop file watching for a project | **Resource management** - stop monitoring |
250
+ | `list_watchers` | List all active file watchers | **Monitoring** - see what's being watched |
251
+ | `natural_language_to_cypher` | Convert natural language to Cypher | **Advanced queries** - complex graph queries |
252
+ | `test_neo4j_connection` | Verify database connectivity | **Health check** - troubleshooting |
253
+
254
+ > **Note**: All query tools (`search_codebase`, `traverse_from_node`, `impact_analysis`, `natural_language_to_cypher`) require a `projectId` parameter. Use `list_projects` to discover available projects.
255
+
256
+ ### Tool Selection Guide
257
+
258
+ - **`list_projects`**: First step - discover what projects are available
259
+ - **`search_codebase`**: Find code by describing what you're looking for
260
+ - **`traverse_from_node`**: Use node IDs from search results to explore relationships
261
+ - **`impact_analysis`**: Before refactoring - understand what depends on the code you're changing
262
+
263
+ ### Multi-Project Workflow
264
+
265
+ All query tools require a `projectId` parameter to ensure project isolation. You can provide:
266
+
267
+ 1. **Project ID**: `proj_a1b2c3d4e5f6` (auto-generated from path)
268
+ 2. **Project Name**: `my-backend` (extracted from package.json or directory name)
269
+ 3. **Project Path**: `/path/to/my-backend` (resolved to project ID)
270
+
271
+ **Typical Workflow:**
272
+
273
+ ```typescript
274
+ // Step 1: Discover available projects
275
+ list_projects()
276
+ // Returns: project names, IDs, status, node/edge counts
277
+
278
+ // Step 2: Parse a new project (if not already parsed)
279
+ parse_typescript_project({
280
+ projectPath: '/path/to/project',
281
+ tsconfigPath: '/path/to/project/tsconfig.json'
282
+ })
283
+ // Returns: projectId for use in queries
284
+
285
+ // Step 3: Query the project using any of these ID formats
286
+ search_codebase({ projectId: "my-backend", query: "authentication" })
287
+ search_codebase({ projectId: "proj_a1b2c3d4e5f6", query: "authentication" })
288
+ search_codebase({ projectId: "/path/to/my-backend", query: "authentication" })
289
+ ```
290
+
291
+ **Pro Tips:**
292
+ - Use project names instead of full IDs for convenience
293
+ - Run `list_projects` first to see what's available
294
+ - Each project is completely isolated - queries never cross project boundaries
295
+
296
+ ### Sequential Workflow Patterns
232
297
 
233
298
  The MCP tools are designed to work together in powerful workflows. Here are the most effective patterns:
234
299
 
@@ -419,24 +484,71 @@ traverse_from_node({
419
484
  ```
420
485
 
421
486
  #### 3. `parse_typescript_project` - Graph Generation
422
- **Purpose**: Parse a TypeScript/NestJS project and build the initial graph database.
487
+ **Purpose**: Parse a TypeScript/NestJS project and build the graph database.
488
+
489
+ **Parameters:**
490
+ | Parameter | Type | Default | Description |
491
+ |-----------|------|---------|-------------|
492
+ | `projectPath` | string | required | Path to project root directory |
493
+ | `tsconfigPath` | string | required | Path to tsconfig.json |
494
+ | `projectId` | string | auto | Override auto-generated project ID |
495
+ | `clearExisting` | boolean | true | Clear existing data (false = incremental) |
496
+ | `async` | boolean | false | Run in background Worker thread |
497
+ | `useStreaming` | enum | "auto" | "auto", "always", or "never" |
498
+ | `chunkSize` | number | 50 | Files per chunk for streaming |
499
+ | `projectType` | enum | "auto" | "auto", "nestjs", "vanilla" |
500
+ | `watch` | boolean | false | Start file watching after parse (requires `async: false`) |
501
+ | `watchDebounceMs` | number | 1000 | Debounce delay for watch mode in ms |
423
502
 
424
503
  ```typescript
425
- // Full project parsing
504
+ // Standard parsing (blocking)
505
+ await mcp.call('parse_typescript_project', {
506
+ projectPath: '/path/to/project',
507
+ tsconfigPath: '/path/to/project/tsconfig.json'
508
+ });
509
+ // Returns: projectId for use in queries
510
+
511
+ // Async parsing for large projects (non-blocking)
512
+ await mcp.call('parse_typescript_project', {
513
+ projectPath: '/path/to/large-project',
514
+ tsconfigPath: '/path/to/large-project/tsconfig.json',
515
+ async: true // Returns immediately with job ID
516
+ });
517
+ // Returns: "Job ID: job_abc123... Use check_parse_status to monitor."
518
+
519
+ // Check async job progress
520
+ await mcp.call('check_parse_status', { jobId: 'job_abc123' });
521
+ // Returns: progress %, phase, nodes/edges imported
522
+
523
+ // Incremental parsing (only changed files)
426
524
  await mcp.call('parse_typescript_project', {
427
- projectPath: '/path/to/your/nestjs/project',
428
- tsconfigPath: '/path/to/your/nestjs/project/tsconfig.json',
429
- clearExisting: true // Recommended: clear previous data
525
+ projectPath: '/path/to/project',
526
+ tsconfigPath: '/path/to/project/tsconfig.json',
527
+ clearExisting: false // Keep existing, only reparse changed files
430
528
  });
431
529
 
432
- // Response: Success confirmation with node/edge counts
433
- "✅ SUCCESS: Parsed 2,445 nodes and 4,892 edges. Graph imported to Neo4j."
530
+ // Parse and start file watching
531
+ await mcp.call('parse_typescript_project', {
532
+ projectPath: '/path/to/project',
533
+ tsconfigPath: '/path/to/project/tsconfig.json',
534
+ watch: true, // Start watching after parse completes
535
+ watchDebounceMs: 1000 // Wait 1s after last change before updating
536
+ });
537
+ // File changes now automatically trigger incremental graph updates
434
538
  ```
435
539
 
540
+ **Modes:**
541
+ - **Standard**: Blocks until complete, best for small-medium projects
542
+ - **Async**: Returns immediately, use `check_parse_status` to monitor
543
+ - **Streaming**: Auto-enabled for projects >100 files, prevents OOM
544
+ - **Incremental**: Set `clearExisting: false` to only reparse changed files
545
+ - **Watch**: Set `watch: true` to automatically update graph on file changes (requires sync mode)
546
+
436
547
  **Performance Notes**:
437
- - Large projects (>1000 files) may take several minutes
438
- - Embedding generation adds significant time but enables semantic search
439
- - Use `clearExisting: true` to avoid duplicate data
548
+ - Large projects (>1000 files) should use `async: true`
549
+ - Streaming is auto-enabled for projects >100 files
550
+ - Incremental mode detects changes via mtime, size, and content hash
551
+ - Worker threads have 30-minute timeout and 8GB heap limit
440
552
 
441
553
  #### 4. `test_neo4j_connection` - Health Check
442
554
  **Purpose**: Verify database connectivity and APOC plugin availability.
@@ -450,65 +562,104 @@ await mcp.call('test_neo4j_connection');
450
562
  APOC plugin available with 438 functions"
451
563
  ```
452
564
 
565
+ #### 5. File Watching Tools
566
+ **Purpose**: Monitor file changes and automatically update the graph.
567
+
568
+ ```typescript
569
+ // Option 1: Start watching during parse
570
+ await mcp.call('parse_typescript_project', {
571
+ projectPath: '/path/to/project',
572
+ tsconfigPath: '/path/to/project/tsconfig.json',
573
+ watch: true // Starts watching after parse completes
574
+ });
575
+
576
+ // Option 2: Start watching a previously parsed project
577
+ await mcp.call('start_watch_project', {
578
+ projectId: 'my-backend', // Project name, ID, or path
579
+ debounceMs: 2000 // Optional: wait 2s after last change (default: 1000)
580
+ });
581
+
582
+ // List all active watchers
583
+ await mcp.call('list_watchers');
584
+ // Returns: watcher status, pending changes, last update time
585
+
586
+ // Stop watching a project
587
+ await mcp.call('stop_watch_project', {
588
+ projectId: 'my-backend'
589
+ });
590
+ ```
591
+
592
+ **How It Works:**
593
+ 1. File watcher monitors `.ts` and `.tsx` files using native OS events
594
+ 2. Changes are debounced to batch rapid edits
595
+ 3. Only modified files are re-parsed (incremental)
596
+ 4. Cross-file edges are preserved during updates
597
+ 5. Graph updates happen automatically in the background
598
+
599
+ **Resource Limits:**
600
+ - Maximum 10 concurrent watchers
601
+ - 1000 pending events per watcher
602
+ - Graceful cleanup on server shutdown
603
+
453
604
  ### Workflow Examples
454
605
 
455
606
  #### Example 1: Understanding Authentication Flow
456
607
  ```typescript
457
608
  // Step 1: Find authentication-related code
458
609
  const searchResult = await mcp.call('search_codebase', {
459
- query: 'JWT token validation authentication',
460
- limit: 2
610
+ projectId: 'my-backend', // Required: project name, ID, or path
611
+ query: 'JWT token validation authentication'
461
612
  });
462
613
 
463
614
  // Step 2: Extract node ID from most relevant result
464
- const nodeId = "MethodDeclaration:697d2c96-1f91-4894-985d-1eece117b72b";
615
+ const nodeId = "proj_abc123:MethodDeclaration:697d2c96";
465
616
 
466
617
  // Step 3: Explore immediate relationships
467
618
  const immediateConnections = await mcp.call('traverse_from_node', {
619
+ projectId: 'my-backend',
468
620
  nodeId,
469
- maxDepth: 2,
470
- skip: 0
621
+ maxDepth: 2
471
622
  });
472
623
 
473
624
  // Step 4: Go deeper to understand full authentication chain
474
625
  const deepConnections = await mcp.call('traverse_from_node', {
626
+ projectId: 'my-backend',
475
627
  nodeId,
476
- maxDepth: 4,
477
- skip: 0
628
+ maxDepth: 4
478
629
  });
479
630
 
480
- // Step 5: Explore different connection branches
481
- const alternateConnections = await mcp.call('traverse_from_node', {
482
- nodeId,
483
- maxDepth: 3,
484
- skip: 10 // Skip first 10 to see different connections
631
+ // Step 5: Assess refactoring impact
632
+ const impact = await mcp.call('impact_analysis', {
633
+ projectId: 'my-backend',
634
+ nodeId
485
635
  });
636
+ // Returns: risk level (LOW/MEDIUM/HIGH/CRITICAL), dependents, affected files
486
637
  ```
487
638
 
488
639
  #### Example 2: API Endpoint Analysis
489
640
  ```typescript
490
641
  // Step 1: Search for controller endpoints
491
642
  const controllerSearch = await mcp.call('search_codebase', {
492
- query: 'HTTP controller endpoints routes POST GET',
493
- limit: 1
643
+ projectId: 'my-backend',
644
+ query: 'HTTP controller endpoints routes POST GET'
494
645
  });
495
646
 
496
647
  // Step 2: Find a controller node ID from results
497
- const controllerNodeId = "ClassDeclaration:controller-uuid";
648
+ const controllerNodeId = "proj_abc123:ClassDeclaration:controller-uuid";
498
649
 
499
650
  // Step 3: Explore what endpoints this controller exposes
500
651
  const endpoints = await mcp.call('traverse_from_node', {
652
+ projectId: 'my-backend',
501
653
  nodeId: controllerNodeId,
502
- maxDepth: 2,
503
- skip: 0
654
+ maxDepth: 2
504
655
  });
505
656
 
506
657
  // Step 4: For each endpoint found, explore its dependencies
507
- const endpointNodeId = "MethodDeclaration:endpoint-uuid";
658
+ const endpointNodeId = "proj_abc123:MethodDeclaration:endpoint-uuid";
508
659
  const endpointDeps = await mcp.call('traverse_from_node', {
660
+ projectId: 'my-backend',
509
661
  nodeId: endpointNodeId,
510
- maxDepth: 3,
511
- skip: 0
662
+ maxDepth: 3
512
663
  });
513
664
  ```
514
665
 
@@ -516,22 +667,24 @@ const endpointDeps = await mcp.call('traverse_from_node', {
516
667
  ```typescript
517
668
  // Step 1: Find a specific service
518
669
  const serviceSearch = await mcp.call('search_codebase', {
519
- query: 'UserService injectable dependency injection',
520
- limit: 1
670
+ projectId: 'my-backend',
671
+ query: 'UserService injectable dependency injection'
521
672
  });
522
673
 
523
674
  // Step 2: Map all its dependencies (what it injects)
524
675
  const serviceDeps = await mcp.call('traverse_from_node', {
525
- nodeId: "ClassDeclaration:user-service-uuid",
676
+ projectId: 'my-backend',
677
+ nodeId: "proj_abc123:ClassDeclaration:user-service-uuid",
526
678
  maxDepth: 2,
527
- skip: 0
679
+ direction: "OUTGOING" // What this service depends on
528
680
  });
529
681
 
530
- // Step 3: Find what depends on this service (reverse relationships)
531
- const serviceDependents = await mcp.call('search_codebase', {
532
- query: 'UserService injection constructor parameter',
533
- limit: 5
682
+ // Step 3: Impact analysis - what depends on this service
683
+ const impact = await mcp.call('impact_analysis', {
684
+ projectId: 'my-backend',
685
+ nodeId: "proj_abc123:ClassDeclaration:user-service-uuid"
534
686
  });
687
+ // Returns: risk level, all dependents, affected files
535
688
  ```
536
689
 
537
690
  ### Advanced Usage Tips
@@ -548,7 +701,10 @@ const serviceDependents = await mcp.call('search_codebase', {
548
701
 
549
702
  **Example Reading Pattern**:
550
703
  ```typescript
551
- const response = await search_codebase({ query: "authentication" });
704
+ const response = await search_codebase({
705
+ projectId: "my-backend",
706
+ query: "authentication"
707
+ });
552
708
 
553
709
  // 1. Get overview statistics
554
710
  console.log(`Found ${response.totalConnections} connections across ${response.uniqueFiles} files`);
@@ -571,7 +727,6 @@ firstDepth.chains.forEach(chain => {
571
727
  ```
572
728
 
573
729
  #### Managing Large Responses
574
- - **Start Small**: Use `limit: 1-3` for initial searches
575
730
  - **Relationship Filtering**: Use `relationshipTypes` to focus on specific connections
576
731
  - **Structure-Only View**: Set `includeCode: false` to exclude source code snippets
577
732
  - **Summary Mode**: Use `summaryOnly: true` for just file paths and statistics
@@ -607,6 +762,7 @@ Each potential path is scored using three factors multiplied together:
607
762
  ```typescript
608
763
  // Use standard traversal for exhaustive exploration
609
764
  search_codebase({
765
+ projectId: "my-backend",
610
766
  query: "...",
611
767
  useWeightedTraversal: false
612
768
  })
@@ -618,46 +774,6 @@ search_codebase({
618
774
  - **Memory**: Large traversals may hit Neo4j memory limits (increase heap size if needed)
619
775
  - **Caching**: Node IDs are persistent; save interesting ones for later exploration
620
776
 
621
- ## Available MCP Tools
622
-
623
- ### Core Tools
624
-
625
- | Tool | Description | Parameters | Use Case |
626
- |------|-------------|------------|----------|
627
- | `hello` | Test tool that says hello | None | Verify MCP connection |
628
- | `test_neo4j_connection` | Test Neo4j connection and APOC plugin | None | Health check before operations |
629
-
630
- ### Parsing Tools
631
-
632
- | Tool | Description | Parameters | Use Case |
633
- |------|-------------|------------|----------|
634
- | `parse_typescript_project` | Parse TypeScript/NestJS project into graph | `projectPath`, `tsconfigPath`, `clearExisting?` | Initial setup: build the graph database |
635
-
636
- ### Search & Exploration Tools
637
-
638
- | Tool | Description | Parameters | Best For |
639
- |------|-------------|------------|----------|
640
- | `search_codebase` | **Vector-based semantic search** - Find most relevant code using OpenAI embeddings | `query`, `limit?`, `useWeightedTraversal?` (default: true) | **Starting point** for code exploration. Uses weighted scoring for intelligent traversal |
641
- | `traverse_from_node` | **Focused graph traversal** - Explore specific relationships from a known node | `nodeId` (string), `maxDepth?` (1-10, default: 3), `skip?` (default: 0) | **Deep diving** into specific code relationships. Pagination for large graphs |
642
- | `natural_language_to_cypher` | **AI-powered query generation** - Convert natural language to Cypher queries using GPT-4 | `query` (string) | **Advanced queries** - currently requires OpenAI assistant setup |
643
-
644
- ### Tool Selection Guide
645
-
646
- **Start Here**: `search_codebase`
647
- - Use when you don't know specific node IDs
648
- - Best for exploring new codebases
649
- - Returns rich context with code snippets
650
-
651
- **Go Deeper**: `traverse_from_node`
652
- - Use when you have specific node IDs from search results
653
- - Perfect for understanding relationships and dependencies
654
- - Use `skip` parameter for pagination through large result sets
655
-
656
- **Advanced**: `natural_language_to_cypher`
657
- - Requires additional OpenAI assistant configuration
658
- - Best for complex queries beyond simple search/traversal
659
- - Currently in development - may require setup
660
-
661
777
  ## Claude Code Integration Tips
662
778
 
663
779
  ### Guiding Tool Usage with claude.md
@@ -687,12 +803,12 @@ You can add a `claude.md` file to your repository root to help Claude Code under
687
803
  ```markdown
688
804
  **Use `useWeightedTraversal: true` for:**
689
805
  - Service/Controller classes with many dependencies
690
- - Queries with depth > 3 or limit > 10
806
+ - Queries with depth > 3
691
807
  - Cleaner, more relevant results
692
808
 
693
809
  **Recommended settings:**
694
- - Default: `limit: 15, maxDepth: 5, snippetLength: 900`
695
- - Simple lookups: `limit: 5, maxDepth: 2`
810
+ - Default: `maxDepth: 5, snippetLength: 900`
811
+ - Simple lookups: `maxDepth: 2`
696
812
  ```
697
813
 
698
814
  #### Framework-Specific Patterns
@@ -713,13 +829,13 @@ Document your custom node types and relationships so Claude knows what to search
713
829
 
714
830
  ```markdown
715
831
  **Finding authentication:**
716
- search_codebase({ query: "JWT authentication middleware" })
832
+ search_codebase({ projectId: "my-project", query: "JWT authentication middleware" })
717
833
 
718
834
  **Tracing dependencies:**
719
- traverse_from_node({ nodeId: "...", direction: "OUTGOING", maxDepth: 5 })
835
+ traverse_from_node({ projectId: "my-project", nodeId: "...", direction: "OUTGOING", maxDepth: 5 })
720
836
 
721
837
  **Impact analysis:**
722
- traverse_from_node({ nodeId: "...", direction: "INCOMING", maxDepth: 4 })
838
+ impact_analysis({ projectId: "my-project", nodeId: "..." })
723
839
  ```
724
840
 
725
841
  ## Framework Support
@@ -778,6 +894,10 @@ The server provides deep understanding of NestJS patterns:
778
894
  | `NEO4J_URI` | Neo4j database URI | `bolt://localhost:7687` |
779
895
  | `NEO4J_USER` | Neo4j username | `neo4j` |
780
896
  | `NEO4J_PASSWORD` | Neo4j password | `PASSWORD` |
897
+ | `NEO4J_QUERY_TIMEOUT_MS` | Neo4j query timeout | `30000` (30s) |
898
+ | `NEO4J_CONNECTION_TIMEOUT_MS` | Neo4j connection timeout | `10000` (10s) |
899
+ | `OPENAI_EMBEDDING_TIMEOUT_MS` | Embedding API timeout | `60000` (60s) |
900
+ | `OPENAI_ASSISTANT_TIMEOUT_MS` | Assistant API timeout | `120000` (120s) |
781
901
 
782
902
  ### Parse Options
783
903
 
@@ -804,27 +924,27 @@ const parseOptions = {
804
924
  ### Current Limitations
805
925
 
806
926
  1. **Language Support**: Currently supports TypeScript/NestJS only
807
- 2. **Framework Support**: Primary focus on NestJS patterns
927
+ 2. **Framework Support**: Primary focus on NestJS patterns (React, Angular, Vue planned)
808
928
  3. **File Size**: Large files (>10MB) may cause parsing performance issues
809
- 4. **Memory Usage**: Graph generation is memory-intensive for very large projects
929
+ 4. **Memory Usage**: Mitigated by streaming import for large projects
810
930
  5. **Vector Search**: Requires OpenAI API for semantic search functionality
811
- 6. **Real-time Updates**: No file watching - requires manual re-parsing for code changes
812
- 7. **Response Size**: Large graph traversals can exceed token limits (25,000 tokens max)
813
- 8. **Neo4j Memory**: Database memory limits can cause query failures on large graphs
931
+ 6. **Response Size**: Large graph traversals can exceed token limits (25,000 tokens max)
932
+ 7. **Neo4j Memory**: Database memory limits can cause query failures on large graphs
814
933
 
815
934
  ### Performance Considerations
816
935
 
817
- - **Large Projects**: Projects with >10,000 files may require increased memory allocation
936
+ - **Large Projects**: Use `async: true` for projects with >1000 files
937
+ - **Streaming**: Auto-enabled for >100 files to prevent memory issues
818
938
  - **Graph Traversal**: Deep traversals (>5 levels) may be slow for highly connected graphs
819
939
  - **Embedding Generation**: Initial parsing with embeddings can take several minutes for large codebases
820
940
  - **Neo4j Memory**: Recommend at least 4GB RAM allocation for Neo4j with large graphs
941
+ - **Worker Timeout**: Async parsing has 30-minute timeout for safety
821
942
 
822
943
  ### Known Issues
823
944
 
824
945
  1. **Complex Type Inference**: Advanced TypeScript type gymnastics may not be fully captured
825
946
  2. **Dynamic Imports**: Runtime module loading not tracked in static analysis
826
947
  3. **Decorator Arguments**: Complex decorator argument patterns may not be fully parsed
827
- 4. **Monorepo Support**: Limited support for complex monorepo structures
828
948
 
829
949
  ## Troubleshooting
830
950
 
@@ -858,11 +978,11 @@ docker-compose restart neo4j
858
978
  ```
859
979
 
860
980
  #### Token Limit Exceeded
861
- If responses exceed 25,000 tokens:
981
+ If responses exceed token limits:
862
982
 
863
983
  ```typescript
864
- // Reduce limit parameter
865
- search_codebase({ query: "...", limit: 1 })
984
+ // Reduce depth or use structure-only view
985
+ traverse_from_node({ nodeId: "...", maxDepth: 2, includeCode: false })
866
986
 
867
987
  // Use pagination with skip
868
988
  traverse_from_node({ nodeId: "...", maxDepth: 2, skip: 0 })
@@ -76,6 +76,45 @@ const extractInjectableDependencies = (parsedNode, _allNodes, _sharedContext) =>
76
76
  }
77
77
  return {};
78
78
  };
79
+ /**
80
+ * Extract class property types for edge detection.
81
+ * This allows INTERNAL_API_CALL detection to work without AST access.
82
+ * Extracts both typed properties and instantiated properties.
83
+ */
84
+ const extractPropertyTypes = (parsedNode, _allNodes, _sharedContext) => {
85
+ const node = parsedNode.sourceNode;
86
+ if (!node || !Node.isClassDeclaration(node))
87
+ return {};
88
+ const propertyTypes = [];
89
+ const properties = node.getProperties();
90
+ for (const prop of properties) {
91
+ // Get type from type annotation (e.g., `private client: PaymentsClient`)
92
+ const typeNode = prop.getTypeNode();
93
+ if (typeNode) {
94
+ propertyTypes.push(typeNode.getText());
95
+ }
96
+ // Get type from initializer (e.g., `private client = new PaymentsClient()`)
97
+ const initializer = prop.getInitializer();
98
+ if (initializer && Node.isNewExpression(initializer)) {
99
+ const expression = initializer.getExpression();
100
+ propertyTypes.push(expression.getText());
101
+ }
102
+ }
103
+ // Also check constructor parameters for injected dependencies
104
+ const constructors = node.getConstructors();
105
+ for (const ctor of constructors) {
106
+ for (const param of ctor.getParameters()) {
107
+ const typeNode = param.getTypeNode();
108
+ if (typeNode) {
109
+ propertyTypes.push(typeNode.getText());
110
+ }
111
+ }
112
+ }
113
+ return {
114
+ propertyTypes,
115
+ hasVendorClient: propertyTypes.some((t) => t.endsWith('Client')),
116
+ };
117
+ };
79
118
  /**
80
119
  * Extract repository DAL dependencies
81
120
  * Uses the dependencies array from @Injectable([...]) decorator
@@ -332,6 +371,11 @@ export const FAIRSQUARE_FRAMEWORK_SCHEMA = {
332
371
  extractor: extractInjectableDependencies,
333
372
  priority: 10,
334
373
  },
374
+ {
375
+ nodeType: CoreNodeType.CLASS_DECLARATION,
376
+ extractor: extractPropertyTypes,
377
+ priority: 9, // Run after extractInjectableDependencies
378
+ },
335
379
  ],
336
380
  additionalRelationships: [FairSquareSemanticEdgeType.FS_INJECTS],
337
381
  neo4j: {
@@ -508,49 +552,6 @@ export const FAIRSQUARE_FRAMEWORK_SCHEMA = {
508
552
  primaryLabel: FairSquareSemanticNodeType.FS_ROUTE_DEFINITION,
509
553
  },
510
554
  },
511
- // HTTP Endpoint (Controller methods)
512
- // fairsquareHttpEndpoint: {
513
- // name: 'FairSquare HTTP Endpoint',
514
- // targetCoreType: CoreNodeType.METHOD_DECLARATION,
515
- // semanticType: FairSquareSemanticNodeType.FS_HTTP_ENDPOINT as any,
516
- // priority: 100,
517
- //
518
- // detectionPatterns: [
519
- // {
520
- // type: 'function',
521
- // pattern: (node: Node) => {
522
- // if (!Node.isMethodDeclaration(node)) return false;
523
- // const methodName = node.getName().toLowerCase();
524
- // const httpMethods = ['get', 'post', 'put', 'delete', 'patch'];
525
- //
526
- // // Check if method is HTTP verb AND parent is Controller
527
- // const parent = node.getParent();
528
- // const isController =
529
- // Node.isClassDeclaration(parent) &&
530
- // (parent.getName()?.endsWith('Controller') || parent.getExtends()?.getText() === 'Controller');
531
- //
532
- // return httpMethods.includes(methodName) && isController;
533
- // },
534
- // confidence: 1.0,
535
- // priority: 10,
536
- // },
537
- // ],
538
- //
539
- // contextExtractors: [
540
- // {
541
- // nodeType: CoreNodeType.METHOD_DECLARATION,
542
- // extractor: extractHttpEndpoint,
543
- // priority: 10,
544
- // },
545
- // ],
546
- //
547
- // additionalRelationships: [FairSquareSemanticEdgeType.FS_EXPOSES_HTTP as any],
548
- //
549
- // neo4j: {
550
- // additionalLabels: ['FairSquare', 'HttpEndpoint', 'API'],
551
- // primaryLabel: 'FairSquareHttpEndpoint',
552
- // },
553
- // },
554
555
  },
555
556
  // ============================================================================
556
557
  // EDGE ENHANCEMENTS (Relationship detection)
@@ -761,24 +762,10 @@ export const FAIRSQUARE_FRAMEWORK_SCHEMA = {
761
762
  if (!vendorName)
762
763
  return false;
763
764
  // Check if service uses the corresponding VendorClient
764
- const sourceNode = parsedSourceNode.sourceNode;
765
- if (!sourceNode || !Node.isClassDeclaration(sourceNode))
766
- return false;
765
+ // Use pre-extracted propertyTypes to avoid AST dependency (allows cross-chunk/cross-package detection)
766
+ const propertyTypes = parsedSourceNode.properties.context?.propertyTypes ?? [];
767
767
  const expectedClientName = `${vendorName.charAt(0).toUpperCase() + vendorName.slice(1)}Client`;
768
- const properties = sourceNode.getProperties();
769
- for (const prop of properties) {
770
- const typeNode = prop.getTypeNode();
771
- if (typeNode?.getText() === expectedClientName) {
772
- return true;
773
- }
774
- const initializer = prop.getInitializer();
775
- if (initializer && Node.isNewExpression(initializer)) {
776
- if (initializer.getExpression().getText() === expectedClientName) {
777
- return true;
778
- }
779
- }
780
- }
781
- return false;
768
+ return propertyTypes.includes(expectedClientName);
782
769
  },
783
770
  contextExtractor: (parsedSourceNode, parsedTargetNode, allParsedNodes, sharedContext) => {
784
771
  const vendorControllerMap = sharedContext?.get('vendorControllers');