Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 34 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ NetContextServer empowers AI coding assistants like Cursor AI to deeply understa
- 🛡️ **Built-in Security**: Safe file access with automatic protection of sensitive data
- 🚀 **Cursor AI Integration**: Seamless setup with Cursor AI for enhanced coding assistance
- 📦 **Package Analysis**: Understand your dependencies and get update recommendations
- 🔍 **Deep Dependency Visualization**: See transitive dependencies with interactive, color-coded graphs
- 🧩 **Smart Grouping**: Visually group related packages for easier navigation
- 📊 **Update Recommendations**: Identify outdated packages and security issues
- ⚡ **Fast & Efficient**: Quick indexing and response times for large codebases

## 🚀 Quick Start
Expand Down Expand Up @@ -148,9 +151,34 @@ dotnet run --project src/NetContextClient/NetContextClient.csproj -- list-source

5. **Analyze Packages**:
```bash
# Set your base directory first
dotnet run --project src/NetContextClient/NetContextClient.csproj -- set-base-dir --directory "path/to/your/project"

# Run the package analysis
dotnet run --project src/NetContextClient/NetContextClient.csproj -- analyze-packages
```

Example output:
```
Project: MyProject.csproj
Found 2 package(s):
- ✅ Newtonsoft.Json (13.0.1)
Used in 5 location(s)

Dependencies:
└─ Newtonsoft.Json
└─ System.*
└─ System.ComponentModel

- 🔄 Microsoft.Extensions.DependencyInjection (5.0.2 → 6.0.1)
Update available: 6.0.1

Dependencies:
└─ Microsoft.Extensions.DependencyInjection
└─ Microsoft.*
└─ Microsoft.Extensions.DependencyInjection.Abstractions
```

### Search Commands

1. **Text Search**:
Expand Down Expand Up @@ -235,7 +263,12 @@ dotnet run --project src/NetContextClient/NetContextClient.csproj -- add-ignore-
dotnet run --project src/NetContextClient/NetContextClient.csproj -- list-projects-in-dir --directory "D:\Projects\MyApp\src"
```

4. Search for authentication-related code:
4. Analyze your project's package dependencies:
```bash
dotnet run --project src/NetContextClient/NetContextClient.csproj -- analyze-packages
```

5. Search for authentication-related code:
```bash
dotnet run --project src/NetContextClient/NetContextClient.csproj -- semantic-search --query "user authentication and authorization logic"
```
Expand Down
16 changes: 16 additions & 0 deletions docs/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,22 @@ dotnet run --project src/NetContextClient/NetContextClient.csproj -- search-code
dotnet run --project src/NetContextClient/NetContextClient.csproj -- semantic-search --query "how is user data validated"
```

### Package Analysis
```bash
# First set your base directory
dotnet run --project src/NetContextClient/NetContextClient.csproj -- set-base-dir --directory "path/to/your/project"

# Analyze packages across all projects
dotnet run --project src/NetContextClient/NetContextClient.csproj -- analyze-packages
```

The package analysis provides:
- Visualization of transitive dependencies with color-coded graphs
- Detection of unused packages (⚠️) and available updates (🔄)
- Security vulnerability warnings (🔴)
- Smart grouping of related packages by namespace
- Recommendations for package maintenance

### Security Management
```bash
# Add files to ignore
Expand Down
42 changes: 41 additions & 1 deletion docs/tool-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -136,8 +136,48 @@ dotnet run --project src/NetContextClient/NetContextClient.csproj -- analyze-pac

**Output includes:**
- Package versions and available updates
- Usage analysis
- Usage analysis and detection of unused packages
- Security vulnerability warnings
- Recommendations for updates or removal
- Deep transitive dependency analysis
- Visual dependency graph representation with smart grouping

**Dependency Graph Features:**
- Hierarchical tree visualization in ASCII-art format
- Automatic grouping of related dependencies by namespace
- Color-coding of dependencies in the console:
- Cyan: Leaf dependencies (end nodes)
- Green: Intermediate dependencies
- Yellow: Grouped namespaces
- Clear visual separation between dependency groups
- Configurable depth of transitive dependency resolution

**Example Output:**
```
Project: MyProject.csproj
Found 3 package(s):
- ✅ Newtonsoft.Json (13.0.1)
Used in 5 location(s)

Dependencies:
└─ Newtonsoft.Json
├─ Microsoft.*
│ └─ Microsoft.CSharp
└─ System.*
└─ System.ComponentModel

- 🔄 Microsoft.Extensions.DependencyInjection (5.0.2 → 6.0.1)
Update available: 6.0.1
Used in 3 location(s)

Dependencies:
└─ Microsoft.Extensions.DependencyInjection
└─ Microsoft.*
└─ Microsoft.Extensions.DependencyInjection.Abstractions

- ⚠️ Unused.Package (1.0.0)
Consider removing this unused package
```

## Ignore Pattern Management

Expand Down
5 changes: 5 additions & 0 deletions src/NetContextClient/Models/PackageAnalysis.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,9 @@ public class PackageAnalysis
/// Gets or sets the list of packages that depend on this package.
/// </summary>
public List<string> TransitiveDependencies { get; set; } = [];

/// <summary>
/// Gets or sets a visual representation of the dependency graph as ASCII art.
/// </summary>
public string? DependencyGraph { get; set; }
}
34 changes: 34 additions & 0 deletions src/NetContextClient/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -651,6 +651,40 @@ static async Task<int> Main(string[] args)
{
await Console.Out.WriteLineAsync($" Used in {package.UsageLocations.Count} location(s)");
}

// Display dependency graph if available
if (!string.IsNullOrEmpty(package.DependencyGraph))
{
await Console.Out.WriteLineAsync("\n Dependencies:");
var lines = package.DependencyGraph.Split(Environment.NewLine);
foreach (var line in lines)
{
// Color code the dependency graph
string coloredLine = line;
if (line.Contains("└─"))
{
// Last items in their branch
coloredLine = $"\u001b[36m{line}\u001b[0m"; // Cyan
}
else if (line.Contains("├─"))
{
// Middle items
coloredLine = $"\u001b[32m{line}\u001b[0m"; // Green
}
else if (line.Contains(".*"))
{
// Group headers
coloredLine = $"\u001b[33m{line}\u001b[0m"; // Yellow
}

await Console.Out.WriteLineAsync($" {coloredLine}");
}
await Console.Out.WriteLineAsync();
}
else if (package.TransitiveDependencies.Count > 0)
{
await Console.Out.WriteLineAsync($" Has {package.TransitiveDependencies.Count} transitive dependencies");
}
}

await Console.Out.WriteLineAsync();
Expand Down
5 changes: 5 additions & 0 deletions src/NetContextServer/Models/PackageAnalysis.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,9 @@ public class PackageAnalysis
/// Gets or sets the recommended action to take regarding this package (e.g., update, remove, etc.).
/// </summary>
public string? RecommendedAction { get; set; }

/// <summary>
/// Gets or sets a visual representation of the dependency graph as ASCII art.
/// </summary>
public string? DependencyGraph { get; set; }
}
85 changes: 85 additions & 0 deletions src/NetContextServer/Services/PackageAnalyzerService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,49 @@ public async Task<PackageAnalysis> AnalyzePackageAsync(PackageReference package)
analysis.LatestVersion = latestVersion.ToString();
}
}

// Resolve transitive dependencies
try
{
var dependencyResource = await NuGetRepository.GetResourceAsync<DependencyInfoResource>();
var packageDependencyInfo = await dependencyResource.ResolvePackage(
new NuGet.Packaging.Core.PackageIdentity(package.Id, currentVersion),
NuGet.Frameworks.NuGetFramework.ParseFolder("net6.0"),
Cache,
NullLogger.Instance,
CancellationToken.None);

if (packageDependencyInfo != null)
{
var dependencies = new List<string>();
var visited = new HashSet<string>();

// Start with the direct dependencies
foreach (var dependency in packageDependencyInfo.Dependencies)
{
if (!visited.Contains(dependency.Id))
{
visited.Add(dependency.Id);
dependencies.Add(dependency.Id);

// Recursively gather deeper dependencies
await GatherDependenciesForPackageAsync(
dependency.Id,
dependency.VersionRange.MinVersion ?? NuGetVersion.Parse("0.0.1"),
dependencies,
visited,
1,
3);
}
}

analysis.TransitiveDependencies = dependencies;
}
}
catch (Exception ex)
{
Console.WriteLine($"Error resolving dependencies for {package.Id}: {ex.Message}");
}

// Check usage
try
Expand Down Expand Up @@ -156,4 +199,46 @@ public async Task<PackageAnalysis> AnalyzePackageAsync(PackageReference package)

return analysis;
}

private async Task GatherDependenciesForPackageAsync(string packageId, NuGetVersion packageVersion, List<string> dependencies, HashSet<string> visited, int currentDepth, int maxDepth)
{
if (currentDepth > maxDepth) return;
if (visited.Contains(packageId)) return;
visited.Add(packageId);

dependencies.Add(packageId);

try
{
var dependencyResource = await NuGetRepository.GetResourceAsync<DependencyInfoResource>();
var dependencyInfo = await dependencyResource.ResolvePackage(
new NuGet.Packaging.Core.PackageIdentity(packageId, packageVersion),
NuGet.Frameworks.NuGetFramework.ParseFolder("net6.0"),
Cache,
NullLogger.Instance,
CancellationToken.None);

if (dependencyInfo != null)
{
foreach (var childDependency in dependencyInfo.Dependencies)
{
if (!visited.Contains(childDependency.Id))
{
var minVersion = childDependency.VersionRange.MinVersion ?? NuGetVersion.Parse("0.0.1");
await GatherDependenciesForPackageAsync(
childDependency.Id,
minVersion,
dependencies,
visited,
currentDepth + 1,
maxDepth);
}
}
}
}
catch (Exception ex)
{
Console.WriteLine($"Error gathering dependencies for {packageId}: {ex.Message}");
}
}
}
Loading