fix: support Visual Studio 2026 package loading
This commit is contained in:
@@ -7,11 +7,11 @@
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
<PackageReference Include="xunit" Version="2.9.2" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2" PrivateAssets="all" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="..\Prophet.CoopWithDsh\SnapshotModels.cs" Link="SnapshotModels.cs" />
|
||||
<Compile Include="..\Prophet.CoopWithDsh\SnapshotPublisher.cs" Link="SnapshotPublisher.cs" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using Xunit;
|
||||
|
||||
namespace Prophet.CoopWithDsh.Tests
|
||||
@@ -19,5 +20,32 @@ namespace Prophet.CoopWithDsh.Tests
|
||||
Assert.True(snapshot.Documents[0].Dirty);
|
||||
Assert.Equal("2026-01-01T00:00:00.0000000Z", snapshot.UpdatedAt);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PublisherWritesProtocolV1WithoutExternalJsonRuntime()
|
||||
{
|
||||
var root = Path.Combine(Path.GetTempPath(), "coop-with-dsh-test-" + Guid.NewGuid().ToString("N"));
|
||||
try
|
||||
{
|
||||
using (var publisher = new SnapshotPublisher(root))
|
||||
{
|
||||
var snapshot = SnapshotModel.Create(publisher.InstanceId, 42, null, new[] {
|
||||
new OpenDocument { Path = "F:\\Project\\main.cs", Label = "main.cs", Dirty = true },
|
||||
}, new DateTimeOffset(2026, 1, 1, 0, 0, 0, TimeSpan.Zero));
|
||||
publisher.Publish(snapshot);
|
||||
var json = File.ReadAllText(publisher.FilePath);
|
||||
|
||||
Assert.Contains("\"version\":1", json);
|
||||
Assert.Contains("\"ide\":\"visualstudio\"", json);
|
||||
Assert.Contains("\"documents\":[{", json);
|
||||
Assert.Contains("\"dirty\":true", json);
|
||||
Assert.DoesNotContain("\"workspace\"", json);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (Directory.Exists(root)) Directory.Delete(root, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
<AssemblyName>Prophet.CoopWithDsh</AssemblyName>
|
||||
<GenerateAssemblyInfo>true</GenerateAssemblyInfo>
|
||||
<GeneratePkgDefFile>true</GeneratePkgDefFile>
|
||||
<UseCodebase>true</UseCodebase>
|
||||
<CreateVsixContainer>true</CreateVsixContainer>
|
||||
<DeployExtension>false</DeployExtension>
|
||||
<IncludeAssemblyInVSIXContainer>true</IncludeAssemblyInVSIXContainer>
|
||||
@@ -17,7 +18,6 @@
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.VisualStudio.SDK" Version="17.0.31902.203" ExcludeAssets="runtime" />
|
||||
<PackageReference Include="Microsoft.VSSDK.BuildTools" Version="17.9.3168" PrivateAssets="all" GeneratePathProperty="true" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="source.extension.vsixmanifest" />
|
||||
|
||||
@@ -2,26 +2,28 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Prophet.CoopWithDsh
|
||||
{
|
||||
[DataContract]
|
||||
internal sealed class OpenDocument
|
||||
{
|
||||
[JsonProperty("path")] public string Path { get; set; } = string.Empty;
|
||||
[JsonProperty("label")] public string Label { get; set; } = string.Empty;
|
||||
[JsonProperty("dirty")] public bool Dirty { get; set; }
|
||||
[DataMember(Name = "path", Order = 1)] public string Path { get; set; } = string.Empty;
|
||||
[DataMember(Name = "label", Order = 2)] public string Label { get; set; } = string.Empty;
|
||||
[DataMember(Name = "dirty", Order = 3)] public bool Dirty { get; set; }
|
||||
}
|
||||
|
||||
[DataContract]
|
||||
internal sealed class OpenFileSnapshot
|
||||
{
|
||||
[JsonProperty("version")] public int Version { get; set; } = 1;
|
||||
[JsonProperty("instanceId")] public string InstanceId { get; set; } = string.Empty;
|
||||
[JsonProperty("ide")] public string Ide { get; set; } = "visualstudio";
|
||||
[JsonProperty("processId")] public int ProcessId { get; set; }
|
||||
[JsonProperty("workspace", NullValueHandling = NullValueHandling.Ignore)] public string? Workspace { get; set; }
|
||||
[JsonProperty("updatedAt")] public string UpdatedAt { get; set; } = string.Empty;
|
||||
[JsonProperty("documents")] public IReadOnlyList<OpenDocument> Documents { get; set; } = Array.Empty<OpenDocument>();
|
||||
[DataMember(Name = "version", Order = 1)] public int Version { get; set; } = 1;
|
||||
[DataMember(Name = "instanceId", Order = 2)] public string InstanceId { get; set; } = string.Empty;
|
||||
[DataMember(Name = "ide", Order = 3)] public string Ide { get; set; } = "visualstudio";
|
||||
[DataMember(Name = "processId", Order = 4)] public int ProcessId { get; set; }
|
||||
[DataMember(Name = "workspace", Order = 5, EmitDefaultValue = false)] public string? Workspace { get; set; }
|
||||
[DataMember(Name = "updatedAt", Order = 6)] public string UpdatedAt { get; set; } = string.Empty;
|
||||
[DataMember(Name = "documents", Order = 7)] public OpenDocument[] Documents { get; set; } = Array.Empty<OpenDocument>();
|
||||
}
|
||||
|
||||
internal static class SnapshotModel
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.Serialization.Json;
|
||||
using System.Text;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Prophet.CoopWithDsh
|
||||
{
|
||||
internal sealed class SnapshotPublisher : IDisposable
|
||||
{
|
||||
private static readonly DataContractJsonSerializer Serializer = new DataContractJsonSerializer(typeof(OpenFileSnapshot));
|
||||
private readonly object gate = new object();
|
||||
internal string InstanceId { get; } = Guid.NewGuid().ToString("N");
|
||||
internal string FilePath { get; }
|
||||
@@ -26,7 +27,11 @@ namespace Prophet.CoopWithDsh
|
||||
var directory = Path.GetDirectoryName(FilePath)!;
|
||||
Directory.CreateDirectory(directory);
|
||||
var temporary = FilePath + "." + Guid.NewGuid().ToString("N") + ".tmp";
|
||||
File.WriteAllText(temporary, JsonConvert.SerializeObject(snapshot) + Environment.NewLine, new UTF8Encoding(false));
|
||||
using (var stream = new MemoryStream())
|
||||
{
|
||||
Serializer.WriteObject(stream, snapshot);
|
||||
File.WriteAllText(temporary, Encoding.UTF8.GetString(stream.ToArray()) + Environment.NewLine, new UTF8Encoding(false));
|
||||
}
|
||||
try
|
||||
{
|
||||
if (File.Exists(FilePath)) File.Replace(temporary, FilePath, null);
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<PackageManifest Version="2.0.0" xmlns="http://schemas.microsoft.com/developer/vsx-schema/2011" xmlns:d="http://schemas.microsoft.com/developer/vsx-schema-design/2011">
|
||||
<Metadata>
|
||||
<Identity Id="Prophet.CoopWithDsh.1e02d547-499b-41ed-a25e-b356a9687e31" Version="0.1.0" Language="en-US" Publisher="Prophet" />
|
||||
<Identity Id="Prophet.CoopWithDsh.1e02d547-499b-41ed-a25e-b356a9687e31" Version="0.1.1" Language="en-US" Publisher="Prophet" />
|
||||
<DisplayName>DSH Open File Bridge</DisplayName>
|
||||
<Description xml:space="preserve">Publishes Visual Studio open file metadata for DeepSeek Harness @ references.</Description>
|
||||
<License>LICENSE.txt</License>
|
||||
</Metadata>
|
||||
<Installation>
|
||||
<InstallationTarget Id="Microsoft.VisualStudio.Community" Version="[17.0,18.0)"><ProductArchitecture>amd64</ProductArchitecture></InstallationTarget>
|
||||
<InstallationTarget Id="Microsoft.VisualStudio.Pro" Version="[17.0,18.0)"><ProductArchitecture>amd64</ProductArchitecture></InstallationTarget>
|
||||
<InstallationTarget Id="Microsoft.VisualStudio.Enterprise" Version="[17.0,18.0)"><ProductArchitecture>amd64</ProductArchitecture></InstallationTarget>
|
||||
<InstallationTarget Id="Microsoft.VisualStudio.Community" Version="[17.0,19.0)"><ProductArchitecture>amd64</ProductArchitecture></InstallationTarget>
|
||||
<InstallationTarget Id="Microsoft.VisualStudio.Pro" Version="[17.0,19.0)"><ProductArchitecture>amd64</ProductArchitecture></InstallationTarget>
|
||||
<InstallationTarget Id="Microsoft.VisualStudio.Enterprise" Version="[17.0,19.0)"><ProductArchitecture>amd64</ProductArchitecture></InstallationTarget>
|
||||
</Installation>
|
||||
<Dependencies />
|
||||
<Prerequisites>
|
||||
<Prerequisite Id="Microsoft.VisualStudio.Component.CoreEditor" Version="[17.0,18.0)" DisplayName="Visual Studio core editor" />
|
||||
<Prerequisite Id="Microsoft.VisualStudio.Component.CoreEditor" Version="[17.0,19.0)" DisplayName="Visual Studio core editor" />
|
||||
</Prerequisites>
|
||||
<Assets>
|
||||
<Asset Type="Microsoft.VisualStudio.VsPackage" d:Source="Project" d:ProjectName="Prophet.CoopWithDsh" Path="|Prophet.CoopWithDsh;PkgdefProjectOutputGroup|" />
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
# DSH Open File Bridge for Visual Studio 2022
|
||||
# DSH Open File Bridge for Visual Studio
|
||||
|
||||
This VSIX is a background-loaded `AsyncPackage`. Each Visual Studio process enumerates its own `IVsRunningDocumentTable`, listens for RDT changes, and publishes one protocol-v1 snapshot. This avoids the ambiguity and integrity-level failures of attaching externally through EnvDTE/ROT.
|
||||
This VSIX supports Visual Studio 2022 (17.x) and Visual Studio 2026 (18.x). It is a background-loaded `AsyncPackage`. Each Visual Studio process enumerates its own `IVsRunningDocumentTable`, listens for RDT changes, and publishes one protocol-v1 snapshot. This avoids the ambiguity and integrity-level failures of attaching externally through EnvDTE/ROT.
|
||||
|
||||
Only absolute, existing local files are published. Dirty state is read through `IVsPersistDocData`; source buffers are never copied.
|
||||
|
||||
## Build and test
|
||||
|
||||
Use a Visual Studio Developer PowerShell or a machine with the VS 2022 extension workload:
|
||||
Use a Visual Studio Developer PowerShell or a machine with the Visual Studio extension workload:
|
||||
|
||||
```powershell
|
||||
dotnet restore CoopWithDsh.sln
|
||||
|
||||
Reference in New Issue
Block a user