diff --git a/CHANGELOG.md b/CHANGELOG.md
index 10c09b1..6c4a053 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
+### Fixed
+
+- Detect the dotnet packs folder on macOS and Linux
+
## [0.22.1] - 2026-08-23
### Fixed
diff --git a/TypeContractor.Tests/Tool/ReflectionContextHelperTests.cs b/TypeContractor.Tests/Tool/ReflectionContextHelperTests.cs
new file mode 100644
index 0000000..6a1b434
--- /dev/null
+++ b/TypeContractor.Tests/Tool/ReflectionContextHelperTests.cs
@@ -0,0 +1,36 @@
+using TypeContractor.Tool;
+
+namespace TypeContractor.Tests.Tool
+{
+ public class ReflectionContextHelperTests
+ {
+ [Fact]
+ public void GetNetCorePack_Joins_Pack_Path_Without_Backslash()
+ {
+ var tempRoot = Path.Combine(Path.GetTempPath(), "typecontractor-" + Guid.NewGuid());
+ try
+ {
+ var expected = Path.Combine(tempRoot, "Microsoft.NETCore.App.Ref", "10.0.1", "ref", "net10.0");
+ Directory.CreateDirectory(expected);
+
+ var result = ReflectionContextHelper.GetNetCorePack(tempRoot, "Microsoft.NETCore.App.Ref", 10);
+
+ result.Should().Be(expected);
+ }
+ finally
+ {
+ if (Directory.Exists(tempRoot))
+ Directory.Delete(tempRoot, recursive: true);
+ }
+ }
+
+ [Fact]
+ public void GetDefaultPacksPath_Exists_And_Contains_NetCore_Ref_Pack()
+ {
+ var packsPath = ReflectionContextHelper.GetDefaultPacksPath();
+
+ Directory.Exists(packsPath).Should().BeTrue($"expected default packs path '{packsPath}' to exist");
+ Directory.Exists(Path.Combine(packsPath, "Microsoft.NETCore.App.Ref")).Should().BeTrue($"expected '{packsPath}' to contain 'Microsoft.NETCore.App.Ref'");
+ }
+ }
+}
diff --git a/TypeContractor.Tests/TypeContractor.Tests.csproj b/TypeContractor.Tests/TypeContractor.Tests.csproj
index 5b73865..9a224d3 100644
--- a/TypeContractor.Tests/TypeContractor.Tests.csproj
+++ b/TypeContractor.Tests/TypeContractor.Tests.csproj
@@ -34,6 +34,7 @@
+
diff --git a/TypeContractor.Tool/Program.cs b/TypeContractor.Tool/Program.cs
index 7af0500..b47c8a5 100644
--- a/TypeContractor.Tool/Program.cs
+++ b/TypeContractor.Tool/Program.cs
@@ -67,8 +67,8 @@
var packsOptions = new Option("--packs-path")
{
- DefaultValueFactory = (arg) => config.GetStringWithFallback("packs-path", @"C:\Program Files\dotnet\packs\"),
- Description = "Path where dotnet is installed and reference assemblies can be found.",
+ DefaultValueFactory = (arg) => config.GetStringWithFallback("packs-path", ReflectionContextHelper.GetDefaultPacksPath()),
+ Description = "Path where dotnet reference packs can be found. Defaults to the packs folder of the active .NET installation.",
};
var dotnetVersionOptions = new Option("--dotnet-version")
diff --git a/TypeContractor.Tool/ReflectionContextHelper.cs b/TypeContractor.Tool/ReflectionContextHelper.cs
index 45abb5a..544be97 100644
--- a/TypeContractor.Tool/ReflectionContextHelper.cs
+++ b/TypeContractor.Tool/ReflectionContextHelper.cs
@@ -44,7 +44,7 @@ internal static PathAssemblyResolver GetResolver(string packPath, int dotnetVers
internal static string? GetNetCorePack(string packPath, string packName, int dotnetVersion)
{
- var packPrefix = @$"{packPath}\{packName}";
+ var packPrefix = Path.Combine(packPath, packName);
if (!Directory.Exists(packPrefix))
return null;
@@ -59,4 +59,9 @@ internal static PathAssemblyResolver GetResolver(string packPath, int dotnetVers
return packDirectory;
}
+
+ internal static string GetDefaultPacksPath() =>
+ Path.GetFullPath(Path.Combine(
+ RuntimeEnvironment.GetRuntimeDirectory(),
+ "..", "..", "..", "packs"));
}
diff --git a/TypeContractor.Tool/TypeContractor.Tool.csproj b/TypeContractor.Tool/TypeContractor.Tool.csproj
index 7b39d1b..7e8ff39 100644
--- a/TypeContractor.Tool/TypeContractor.Tool.csproj
+++ b/TypeContractor.Tool/TypeContractor.Tool.csproj
@@ -33,6 +33,10 @@
+
+
+
+