Skip to content

Commit 328125b

Browse files
Krystian Mikrutclaude
andcommitted
fix: Windows compatibility for setup-claude and MSBuild detection
- Change slash command files from cg:*.md to cg/*.md subdirectory (Windows doesn't allow colons in filenames) - Fix Microsoft.Build.Locator packaging with ExcludeAssets to include runtime assembly while excluding problematic build targets - Add PATH-based MSBuild detection fallback when standard locator fails - Update README and CLAUDE.md snippet with new /cg/ command format - Bump version to 0.2.0 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent bd3cf7d commit 328125b

6 files changed

Lines changed: 99 additions & 44 deletions

File tree

AiCodeGraph.Cli/AiCodeGraph.Cli.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
</ItemGroup>
66

77
<ItemGroup>
8-
<PackageReference Include="Microsoft.Build.Locator" Version="1.11.2" />
8+
<PackageReference Include="Microsoft.Build.Locator" Version="1.11.2" ExcludeAssets="build;buildTransitive" />
99
<PackageReference Include="System.CommandLine" Version="2.0.2" />
1010
</ItemGroup>
1111

@@ -17,7 +17,7 @@
1717
<PackAsTool>true</PackAsTool>
1818
<ToolCommandName>ai-code-graph</ToolCommandName>
1919
<PackageOutputPath>./nupkg</PackageOutputPath>
20-
<Version>0.1.1</Version>
20+
<Version>0.2.0</Version>
2121
<PackageId>AiCodeGraph.Cli</PackageId>
2222
<Description>Roslyn-based static analysis tool that builds semantic code graphs, detects duplicates, computes complexity, and exposes an MCP server for AI-assisted development.</Description>
2323
<Authors>AiCodeGraph Contributors</Authors>

AiCodeGraph.Cli/Program.cs

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1760,12 +1760,12 @@
17601760
var dbPath = parseResult.GetValue(setupDbOption) ?? "./ai-code-graph/graph.db";
17611761
var created = new List<string>();
17621762

1763-
// 1. Create .claude/commands/ directory
1764-
var commandsDir = Path.Combine(Directory.GetCurrentDirectory(), ".claude", "commands");
1763+
// 1. Create .claude/commands/cg/ directory
1764+
var commandsDir = Path.Combine(Directory.GetCurrentDirectory(), ".claude", "commands", "cg");
17651765
Directory.CreateDirectory(commandsDir);
17661766

17671767
// 2. Write slash command files
1768-
var contextCmd = Path.Combine(commandsDir, "cg:context.md");
1768+
var contextCmd = Path.Combine(commandsDir, "context.md");
17691769
if (!File.Exists(contextCmd))
17701770
{
17711771
File.WriteAllText(contextCmd, $@"Get method context before editing: $ARGUMENTS
@@ -1782,7 +1782,7 @@ 4. If complexity (CC) is high (>10), warn about the method's complexity before m
17821782
created.Add(contextCmd);
17831783
}
17841784

1785-
var hotspotsCmd = Path.Combine(commandsDir, "cg:hotspots.md");
1785+
var hotspotsCmd = Path.Combine(commandsDir, "hotspots.md");
17861786
if (!File.Exists(hotspotsCmd))
17871787
{
17881788
File.WriteAllText(hotspotsCmd, $@"Show complexity hotspots in the codebase.
@@ -1796,7 +1796,7 @@ 1. Run `ai-code-graph hotspots --top 15 --db {dbPath}`
17961796
created.Add(hotspotsCmd);
17971797
}
17981798

1799-
var duplicatesCmd = Path.Combine(commandsDir, "cg:duplicates.md");
1799+
var duplicatesCmd = Path.Combine(commandsDir, "duplicates.md");
18001800
if (!File.Exists(duplicatesCmd))
18011801
{
18021802
File.WriteAllText(duplicatesCmd, $@"Show detected code duplicates in the codebase.
@@ -1811,7 +1811,7 @@ 3. Group the results by clone type (Type1 = exact, Type2 = renamed, Semantic = s
18111811
created.Add(duplicatesCmd);
18121812
}
18131813

1814-
var driftCmd = Path.Combine(commandsDir, "cg:drift.md");
1814+
var driftCmd = Path.Combine(commandsDir, "drift.md");
18151815
if (!File.Exists(driftCmd))
18161816
{
18171817
File.WriteAllText(driftCmd, $@"Run drift detection against the baseline.
@@ -1830,7 +1830,7 @@ 3. Group the results by clone type (Type1 = exact, Type2 = renamed, Semantic = s
18301830
created.Add(driftCmd);
18311831
}
18321832

1833-
var callgraphCmd = Path.Combine(commandsDir, "cg:callgraph.md");
1833+
var callgraphCmd = Path.Combine(commandsDir, "callgraph.md");
18341834
if (!File.Exists(callgraphCmd))
18351835
{
18361836
File.WriteAllText(callgraphCmd, $@"Explore method call graph: $ARGUMENTS
@@ -1845,7 +1845,7 @@ 4. Highlight any deep call chains or circular dependencies
18451845
created.Add(callgraphCmd);
18461846
}
18471847

1848-
var treeCmd = Path.Combine(commandsDir, "cg:tree.md");
1848+
var treeCmd = Path.Combine(commandsDir, "tree.md");
18491849
if (!File.Exists(treeCmd))
18501850
{
18511851
File.WriteAllText(treeCmd, $@"Display code structure tree.
@@ -1859,7 +1859,7 @@ 4. Use the structure to understand codebase organization
18591859
created.Add(treeCmd);
18601860
}
18611861

1862-
var similarCmd = Path.Combine(commandsDir, "cg:similar.md");
1862+
var similarCmd = Path.Combine(commandsDir, "similar.md");
18631863
if (!File.Exists(similarCmd))
18641864
{
18651865
File.WriteAllText(similarCmd, $@"Find methods similar to: $ARGUMENTS
@@ -1873,7 +1873,7 @@ 3. Present ranked list of similar methods with similarity scores
18731873
created.Add(similarCmd);
18741874
}
18751875

1876-
var clustersCmd = Path.Combine(commandsDir, "cg:clusters.md");
1876+
var clustersCmd = Path.Combine(commandsDir, "clusters.md");
18771877
if (!File.Exists(clustersCmd))
18781878
{
18791879
File.WriteAllText(clustersCmd, $@"Show intent clusters in the codebase.
@@ -1887,7 +1887,7 @@ 4. Highlight clusters with low cohesion (<0.5) as refactoring candidates
18871887
created.Add(clustersCmd);
18881888
}
18891889

1890-
var searchCmd = Path.Combine(commandsDir, "cg:token-search.md");
1890+
var searchCmd = Path.Combine(commandsDir, "token-search.md");
18911891
if (!File.Exists(searchCmd))
18921892
{
18931893
File.WriteAllText(searchCmd, $@"Search code by token overlap: $ARGUMENTS
@@ -1901,7 +1901,7 @@ 4. Suggest which methods are most relevant to the query
19011901
created.Add(searchCmd);
19021902
}
19031903

1904-
var exportCmd = Path.Combine(commandsDir, "cg:export.md");
1904+
var exportCmd = Path.Combine(commandsDir, "export.md");
19051905
if (!File.Exists(exportCmd))
19061906
{
19071907
File.WriteAllText(exportCmd, $@"Export code graph data.
@@ -1914,7 +1914,7 @@ 3. Present a summary of the exported data
19141914
created.Add(exportCmd);
19151915
}
19161916

1917-
var analyzeCmd = Path.Combine(commandsDir, "cg:analyze.md");
1917+
var analyzeCmd = Path.Combine(commandsDir, "analyze.md");
19181918
if (!File.Exists(analyzeCmd))
19191919
{
19201920
File.WriteAllText(analyzeCmd, @"Analyze solution and build code graph.
@@ -1928,7 +1928,7 @@ 4. Inform the user that all slash commands are now available
19281928
created.Add(analyzeCmd);
19291929
}
19301930

1931-
var churnCmd = Path.Combine(commandsDir, "cg:churn.md");
1931+
var churnCmd = Path.Combine(commandsDir, "churn.md");
19321932
if (!File.Exists(churnCmd))
19331933
{
19341934
File.WriteAllText(churnCmd, $@"Show methods with high change-frequency x complexity (churn hotspots): $ARGUMENTS
@@ -1978,7 +1978,7 @@ 5. Suggest which methods would benefit most from refactoring to reduce complexit
19781978
- Apply the same fix to duplicates when fixing bugs
19791979
- Understand which intent cluster a method belongs to before refactoring
19801980
1981-
Available slash commands (all prefixed with `cg:`):
1981+
Available slash commands:
19821982
- `/cg:analyze [solution]` - Analyze solution and build the graph
19831983
- `/cg:context <method>` - Full method context before editing
19841984
- `/cg:hotspots` - Top complexity hotspots

AiCodeGraph.Core/AiCodeGraph.Core.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
</ItemGroup>
1212

1313
<ItemGroup>
14-
<PackageReference Include="Microsoft.Build.Locator" Version="1.11.2" />
14+
<PackageReference Include="Microsoft.Build.Locator" Version="1.11.2" ExcludeAssets="build;buildTransitive" />
1515
<PackageReference Include="Microsoft.Build.Framework" Version="17.11.31" ExcludeAssets="runtime" PrivateAssets="all" />
1616
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="5.0.0" />
1717
<PackageReference Include="Microsoft.CodeAnalysis.Workspaces.MSBuild" Version="5.0.0" />

AiCodeGraph.Core/WorkspaceLoader.cs

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,59 @@ private static void EnsureMSBuildRegistered()
1717
lock (_registrationLock)
1818
{
1919
if (_msBuildRegistered) return;
20-
MSBuildLocator.RegisterDefaults();
20+
21+
// Query all discovery types
22+
var instances = MSBuildLocator.QueryVisualStudioInstances(
23+
new VisualStudioInstanceQueryOptions
24+
{
25+
DiscoveryTypes = DiscoveryType.DeveloperConsole
26+
| DiscoveryType.DotNetSdk
27+
| DiscoveryType.VisualStudioSetup
28+
}).ToList();
29+
30+
if (instances.Count == 0)
31+
{
32+
// Try default query without options as fallback
33+
instances = MSBuildLocator.QueryVisualStudioInstances().ToList();
34+
}
35+
36+
if (instances.Count == 0)
37+
{
38+
// Try to detect MSBuild from MSBUILD_EXE_PATH or PATH
39+
var msbuildPath = Environment.GetEnvironmentVariable("MSBUILD_EXE_PATH");
40+
if (string.IsNullOrEmpty(msbuildPath))
41+
{
42+
// Try to find MSBuild in PATH
43+
var pathEnv = Environment.GetEnvironmentVariable("PATH") ?? "";
44+
var paths = pathEnv.Split(Path.PathSeparator);
45+
foreach (var p in paths)
46+
{
47+
var candidate = Path.Combine(p, "MSBuild.exe");
48+
if (File.Exists(candidate))
49+
{
50+
msbuildPath = candidate;
51+
break;
52+
}
53+
}
54+
}
55+
56+
if (!string.IsNullOrEmpty(msbuildPath) && File.Exists(msbuildPath))
57+
{
58+
var msbuildDir = Path.GetDirectoryName(msbuildPath)!;
59+
MSBuildLocator.RegisterMSBuildPath(msbuildDir);
60+
_msBuildRegistered = true;
61+
return;
62+
}
63+
64+
throw new InvalidOperationException(
65+
"No instances of MSBuild could be detected. " +
66+
"Ensure Visual Studio, VS Build Tools, or the .NET SDK is installed. " +
67+
"If using .NET SDK only, ensure the SDK includes MSBuild (run 'dotnet --list-sdks' to verify).");
68+
}
69+
70+
// Prefer the latest version
71+
var instance = instances.OrderByDescending(i => i.Version).First();
72+
MSBuildLocator.RegisterInstance(instance);
2173
_msBuildRegistered = true;
2274
}
2375
}

CLAUDE.md

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -59,17 +59,18 @@ This returns complexity, callers, callees, cluster membership, and duplicates in
5959
- Understand which intent cluster a method belongs to before refactoring
6060

6161
Available slash commands:
62-
- `/cg/analyze [solution]` - Analyze solution and build the graph
63-
- `/cg/context <method>` - Full method context before editing
64-
- `/cg/hotspots` - Top complexity hotspots
65-
- `/cg/callgraph <method>` - Explore call relationships
66-
- `/cg/similar <method>` - Find methods with similar intent
67-
- `/cg/token-search <query>` - Token-based code search
68-
- `/cg/duplicates` - Detected code clones
69-
- `/cg/clusters` - Intent clusters
70-
- `/cg/tree` - Code structure tree
71-
- `/cg/export` - Export graph data
72-
- `/cg/drift` - Architectural drift from baseline
62+
- `/cg:analyze [solution]` - Analyze solution and build the graph
63+
- `/cg:context <method>` - Full method context before editing
64+
- `/cg:hotspots` - Top complexity hotspots
65+
- `/cg:callgraph <method>` - Explore call relationships
66+
- `/cg:similar <method>` - Find methods with similar intent
67+
- `/cg:token-search <query>` - Token-based code search
68+
- `/cg:duplicates` - Detected code clones
69+
- `/cg:clusters` - Intent clusters
70+
- `/cg:tree` - Code structure tree
71+
- `/cg:export` - Export graph data
72+
- `/cg:drift` - Architectural drift from baseline
73+
- `/cg:churn` - Change-frequency x complexity hotspots
7374

7475
To rebuild the graph after significant changes: `ai-code-graph analyze AiCodeGraph.sln`
7576

README.md

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -138,18 +138,19 @@ ai-code-graph/
138138
│ ├── WorkspaceLoader.cs # Roslyn MSBuild workspace loader
139139
│ └── CodeModelExtractor.cs # Syntax/semantic model extraction
140140
├── AiCodeGraph.Tests/ # Unit and integration tests
141-
├── .claude/commands/ # Claude Code slash commands (11 commands)
142-
│ ├── cg:analyze.md # /cg:analyze - build code graph
143-
│ ├── cg:context.md # /cg:context - method context
144-
│ ├── cg:hotspots.md # /cg:hotspots - complexity hotspots
145-
│ ├── cg:callgraph.md # /cg:callgraph - call relationships
146-
│ ├── cg:similar.md # /cg:similar - find similar methods
147-
│ ├── cg:search.md # /cg:search - natural language search
148-
│ ├── cg:duplicates.md # /cg:duplicates - code clones
149-
│ ├── cg:clusters.md # /cg:clusters - intent clusters
150-
│ ├── cg:tree.md # /cg:tree - code structure
151-
│ ├── cg:export.md # /cg:export - export graph data
152-
│ └── cg:drift.md # /cg:drift - architectural drift
141+
├── .claude/commands/cg/ # Claude Code slash commands (12 commands)
142+
│ ├── analyze.md # /cg:analyze - build code graph
143+
│ ├── context.md # /cg:context - method context
144+
│ ├── hotspots.md # /cg:hotspots - complexity hotspots
145+
│ ├── callgraph.md # /cg:callgraph - call relationships
146+
│ ├── similar.md # /cg:similar - find similar methods
147+
│ ├── token-search.md # /cg:token-search - token-based search
148+
│ ├── duplicates.md # /cg:duplicates - code clones
149+
│ ├── clusters.md # /cg:clusters - intent clusters
150+
│ ├── tree.md # /cg:tree - code structure
151+
│ ├── export.md # /cg:export - export graph data
152+
│ ├── drift.md # /cg:drift - architectural drift
153+
│ └── churn.md # /cg:churn - churn hotspots
153154
├── tests/fixtures/ # Test fixture solutions
154155
└── .github/workflows/ # CI pipeline
155156
```
@@ -209,7 +210,7 @@ ai-code-graph analyze YourSolution.sln
209210
```
210211

211212
This creates:
212-
- `.claude/commands/*.md` - All 11 slash commands (analyze, context, hotspots, callgraph, similar, search, duplicates, clusters, tree, export, drift)
213+
- `.claude/commands/cg/*.md` - All 12 slash commands (analyze, context, hotspots, callgraph, similar, token-search, duplicates, clusters, tree, export, drift, churn)
213214
- `.mcp.json` - MCP server configuration exposing all 11 tools for IDE integration
214215
- `CLAUDE.md` snippet - Auto-context instructions for the agent
215216

@@ -222,12 +223,13 @@ This creates:
222223
| `/cg:hotspots` | Show top complexity hotspots as refactoring candidates |
223224
| `/cg:callgraph <method>` | Explore method call relationships (callers and callees) |
224225
| `/cg:similar <method>` | Find methods with similar semantic intent |
225-
| `/cg:search <query>` | Natural language code search via embeddings |
226+
| `/cg:token-search <query>` | Token-based code search |
226227
| `/cg:duplicates` | Show detected code clones grouped by type |
227228
| `/cg:clusters` | Show intent clusters (groups of related methods) |
228229
| `/cg:tree` | Display code structure (projects, namespaces, types) |
229230
| `/cg:export` | Export full code graph data as JSON |
230231
| `/cg:drift` | Run drift detection against a saved baseline |
232+
| `/cg:churn` | Show change-frequency x complexity hotspots |
231233

232234
**Auto-context:** The `CLAUDE.md` snippet instructs Claude Code to automatically run `ai-code-graph context` before modifying methods when the graph database exists. This gives the agent architectural awareness without manual intervention.
233235

0 commit comments

Comments
 (0)