@atelierai/uco 1.0.8 → 1.0.9

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 (31) hide show
  1. package/CHANGELOG.md +18 -8
  2. package/package.json +2 -2
  3. package/vendor/plugin/com.atelierai.unity.copilot/CHANGELOG.md +4 -4
  4. package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/API/Tool/ToolGroups.SetEnabled.cs +92 -92
  5. package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/CopilotServerManager.cs +0 -147
  6. package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/UI/Window/MainWindowEditor.CopilotServer.cs +3 -3
  7. package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/Utils/ToolGroupRegistry.cs +461 -460
  8. package/vendor/plugin/com.atelierai.unity.copilot/Editor/UI/uss/CopilotPromptsWindow.uss +11 -11
  9. package/vendor/plugin/com.atelierai.unity.copilot/Editor/UI/uss/CopilotResourcesWindow.uss +16 -16
  10. package/vendor/plugin/com.atelierai.unity.copilot/Editor/UI/uss/CopilotToolsWindow.uss +36 -36
  11. package/vendor/plugin/com.atelierai.unity.copilot/Editor/UI/uss/MainWindow.uss +183 -183
  12. package/vendor/plugin/com.atelierai.unity.copilot/Editor/UI/uss/common/{_mcp-list-window.uss → _copilot-list-window.uss} +18 -18
  13. package/vendor/plugin/com.atelierai.unity.copilot/Editor/UI/uss/common/_list-view.uss +77 -77
  14. package/vendor/plugin/com.atelierai.unity.copilot/Editor/UI/uxml/CopilotPromptsWindow.uxml +18 -18
  15. package/vendor/plugin/com.atelierai.unity.copilot/Editor/UI/uxml/CopilotResourcesWindow.uxml +18 -18
  16. package/vendor/plugin/com.atelierai.unity.copilot/Editor/UI/uxml/CopilotToolsWindow.uxml +18 -18
  17. package/vendor/plugin/com.atelierai.unity.copilot/Editor/UI/uxml/MainWindow.uxml +115 -115
  18. package/vendor/plugin/com.atelierai.unity.copilot/Plugins/ReflectorNet.dll +0 -0
  19. package/vendor/plugin/com.atelierai.unity.copilot/Plugins/Uco.Framework.Common.dll +0 -0
  20. package/vendor/plugin/com.atelierai.unity.copilot/Plugins/Uco.Framework.dll +0 -0
  21. package/vendor/plugin/com.atelierai.unity.copilot/README.md +88 -88
  22. package/vendor/plugin/com.atelierai.unity.copilot/Runtime/UnityCopilotPlugin.cs +1 -1
  23. package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/DependencyResolver/NuGetExtractorDevelopmentDependencyTests.cs +148 -148
  24. package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/DependencyResolver/NuGetExtractorFlatLayoutTests.cs +166 -166
  25. package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/DependencyResolver/NuGetInstallManifestTests.cs +436 -436
  26. package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/DependencyResolver/NuGetLegacyMigrationTests.cs +1 -1
  27. package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/DependencyResolver/NuGetPackageInstallerStaleVersionCleanupTests.cs +200 -200
  28. package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/Environment/EnvironmentUtilsTests.cs +1 -1
  29. package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/Tool/GameObject/TestJsonSchema.cs +199 -199
  30. package/vendor/plugin/com.atelierai.unity.copilot/package.json +1 -1
  31. /package/vendor/plugin/com.atelierai.unity.copilot/Editor/UI/uss/common/{_mcp-list-window.uss.meta → _copilot-list-window.uss.meta} +0 -0
@@ -1,88 +1,88 @@
1
- <div align="center">
2
- <h1>Unity Copilot</h1>
3
- <p>Drive the Unity Editor from any AI agent over plain REST + WebSocket — no MCP protocol on the wire.</p>
4
- <p><code>com.atelierai.unity.copilot</code></p>
5
- </div>
6
-
7
- Unity Copilot is a Unity Editor/Runtime plugin that exposes the Editor as an
8
- HTTP service: 160+ tools covering scenes, GameObjects, components, assets,
9
- prefabs, scripts, packages, screenshots, console, tests, and builds — plus
10
- prompts and resources. A self-hosted Node bridge connects the Editor to the
11
- outside world; the **uco** CLI drives the whole surface from any agent or
12
- terminal.
13
-
14
- ## Highlights
15
-
16
- - **160+ Editor tools** — authoring, code (including Roslyn compile-and-execute
17
- with confirmation gating for risky operations), diagnostics, build & tests,
18
- visuals, physics
19
- - **Three-surface AI skills** — `uco setup-skills` generates focused skill
20
- bundles (setup / lifecycle / live-editor) for Claude Code, Codex, Cursor,
21
- and other agents, refreshed from the live tool catalog
22
- - **Deterministic, safe connectivity** — one port per project (hashed from the
23
- project path), bearer-token auth, localhost by default, no vendor lock-in:
24
- anything that can speak HTTP or run a CLI can drive the Editor
25
- - **Durable calls** — async invocations return a call id queryable later
26
- (`uco call get <id>`); structured error envelopes survive the whole stack
27
- - **Dual-editor support** — gates run against Unity 2022.3 LTS and 6000.5
28
-
29
- ## Requirements
30
-
31
- - Unity **2022.3 or newer** (tested on 2022.3 LTS and 6000.5)
32
- - **Node.js 20+** for the bridge server (the plugin auto-discovers the `uco`
33
- npm package — global or project-local — or set `nodeServerPath` in the
34
- config to point at a specific install)
35
-
36
- ## Install
37
-
38
- ### Via the uco CLI (recommended)
39
-
40
- ```bash
41
- npm install -g @atelierai/uco
42
- uco install <path-to-your-unity-project>
43
- ```
44
-
45
- This embeds the plugin package, stages the framework DLLs, writes the initial
46
- config, and can generate agent skills and wrappers (`uco setup-skills`).
47
-
48
- ### Via OpenUPM
49
-
50
- Add the scoped registry to `Packages/manifest.json` and reference the package:
51
-
52
- ```json
53
- {
54
- "dependencies": {
55
- "com.atelierai.unity.copilot": "1.0.0"
56
- },
57
- "scopedRegistries": [
58
- {
59
- "name": "package.openupm.com",
60
- "url": "https://package.openupm.com",
61
- "scopes": [ "com.atelierai.unity.copilot" ]
62
- }
63
- ]
64
- }
65
- ```
66
-
67
- ## Quick start
68
-
69
- ```bash
70
- uco ping # health-check the bridge
71
- uco call unity-tool-list # list every tool the Editor exposes
72
- uco exec --method-body --return-type int --code 'return GameObject.FindObjectsOfType<Camera>().Length;'
73
- ```
74
-
75
- Configuration lives in `UserSettings/uco-config.json` (migrated automatically
76
- from the legacy filename by older→newer versions of the plugin).
77
-
78
- ## Wire protocol
79
-
80
- Plain HTTP + WebSocket with JSON envelopes (`/api/tools/...`). There is no MCP
81
- protocol on the wire — the bridge was deliberately stripped down to REST so
82
- any agent, script, or CI job can use it without an MCP SDK.
83
-
84
- ## Attribution & license
85
-
86
- Derived from [IvanMurzak/Unity-MCP](https://github.com/IvanMurzak/Unity-MCP)
87
- (Apache-2.0). Licensed under the Apache License 2.0 — see [LICENSE](LICENSE)
88
- for the dual copyright notice.
1
+ <div align="center">
2
+ <h1>Unity Copilot</h1>
3
+ <p>Drive the Unity Editor from any AI agent over plain REST + WebSocket — a single simple wire protocol on the wire.</p>
4
+ <p><code>com.atelierai.unity.copilot</code></p>
5
+ </div>
6
+
7
+ Unity Copilot is a Unity Editor/Runtime plugin that exposes the Editor as an
8
+ HTTP service: 160+ tools covering scenes, GameObjects, components, assets,
9
+ prefabs, scripts, packages, screenshots, console, tests, and builds — plus
10
+ prompts and resources. A self-hosted Node bridge connects the Editor to the
11
+ outside world; the **uco** CLI drives the whole surface from any agent or
12
+ terminal.
13
+
14
+ ## Highlights
15
+
16
+ - **160+ Editor tools** — authoring, code (including Roslyn compile-and-execute
17
+ with confirmation gating for risky operations), diagnostics, build & tests,
18
+ visuals, physics
19
+ - **Three-surface AI skills** — `uco setup-skills` generates focused skill
20
+ bundles (setup / lifecycle / live-editor) for Claude Code, Codex, Cursor,
21
+ and other agents, refreshed from the live tool catalog
22
+ - **Deterministic, safe connectivity** — one port per project (hashed from the
23
+ project path), bearer-token auth, localhost by default, no vendor lock-in:
24
+ anything that can speak HTTP or run a CLI can drive the Editor
25
+ - **Durable calls** — async invocations return a call id queryable later
26
+ (`uco call get <id>`); structured error envelopes survive the whole stack
27
+ - **Dual-editor support** — gates run against Unity 2022.3 LTS and 6000.5
28
+
29
+ ## Requirements
30
+
31
+ - Unity **2022.3 or newer** (tested on 2022.3 LTS and 6000.5)
32
+ - **Node.js 20+** for the bridge server (the plugin auto-discovers the `uco`
33
+ npm package — global or project-local — or set `nodeServerPath` in the
34
+ config to point at a specific install)
35
+
36
+ ## Install
37
+
38
+ ### Via the uco CLI (recommended)
39
+
40
+ ```bash
41
+ npm install -g @atelierai/uco
42
+ uco install <path-to-your-unity-project>
43
+ ```
44
+
45
+ This embeds the plugin package, stages the framework DLLs, writes the initial
46
+ config, and can generate agent skills and wrappers (`uco setup-skills`).
47
+
48
+ ### Via OpenUPM
49
+
50
+ Add the scoped registry to `Packages/manifest.json` and reference the package:
51
+
52
+ ```json
53
+ {
54
+ "dependencies": {
55
+ "com.atelierai.unity.copilot": "1.0.0"
56
+ },
57
+ "scopedRegistries": [
58
+ {
59
+ "name": "package.openupm.com",
60
+ "url": "https://package.openupm.com",
61
+ "scopes": [ "com.atelierai.unity.copilot" ]
62
+ }
63
+ ]
64
+ }
65
+ ```
66
+
67
+ ## Quick start
68
+
69
+ ```bash
70
+ uco ping # health-check the bridge
71
+ uco call unity-tool-list # list every tool the Editor exposes
72
+ uco exec --method-body --return-type int --code 'return GameObject.FindObjectsOfType<Camera>().Length;'
73
+ ```
74
+
75
+ Configuration lives in `UserSettings/uco-config.json` (migrated automatically
76
+ from the legacy filename by older→newer versions of the plugin).
77
+
78
+ ## Wire protocol
79
+
80
+ Plain HTTP + WebSocket with JSON envelopes (`/api/tools/...`). The wire is plain JSON
81
+ protocol on the wire — the bridge was deliberately stripped down to REST so
82
+ any agent, script, or CI job can drive it with nothing but an HTTP client.
83
+
84
+ ## Attribution & license
85
+
86
+ Derived from [IvanMurzak/Unity-MCP](https://github.com/IvanMurzak/Unity-MCP)
87
+ (Apache-2.0). Licensed under the Apache License 2.0 — see [LICENSE](LICENSE)
88
+ for the dual copyright notice.
@@ -26,7 +26,7 @@ namespace com.AtelierAI.Unity.Copilot
26
26
 
27
27
  public partial class UnityCopilotPlugin : IDisposable
28
28
  {
29
- public const string Version = "1.0.6";
29
+ public const string Version = "1.0.7";
30
30
 
31
31
  private static int _singletonCount = 0;
32
32
  public static bool HasAnyInstance => _singletonCount > 0;
@@ -1,148 +1,148 @@
1
- /*
2
- +------------------------------------------------------------------+
3
- | Author: Ivan Murzak (https://github.com/IvanMurzak) |
4
- | Repository: GitHub (https://github.com/IvanMurzak/Unity-MCP) |
5
- | Copyright (c) 2025 Ivan Murzak |
6
- | Licensed under the Apache License, Version 2.0. |
7
- | See the LICENSE file in the project root for more information. |
8
- +------------------------------------------------------------------+
9
- */
10
-
11
- #nullable enable
12
- using System.IO;
13
- using System.IO.Compression;
14
- using NUnit.Framework;
15
- using com.AtelierAI.Unity.Copilot.Editor.DependencyResolver;
16
-
17
- namespace com.AtelierAI.Unity.Copilot.Editor.Tests.DependencyResolverTests
18
- {
19
- /// <summary>
20
- /// Regression coverage for issue #670: DependencyResolver was logging
21
- /// "No compatible framework found" / "No DLLs extracted" warnings for
22
- /// Roslyn analyzer packages (e.g. Microsoft.CodeAnalysis.Analyzers), which
23
- /// are marked <c>&lt;developmentDependency&gt;true&lt;/developmentDependency&gt;</c>
24
- /// in their .nuspec and legitimately have no runtime DLLs under <c>lib/&lt;tfm&gt;/</c>.
25
- /// </summary>
26
- [TestFixture]
27
- public class NuGetExtractorDevelopmentDependencyTests
28
- {
29
- string _tempDir = string.Empty;
30
-
31
- [SetUp]
32
- public void SetUp()
33
- {
34
- _tempDir = Path.Combine(Path.GetTempPath(), "UnityMcp-NuGetExtractor-" + Path.GetRandomFileName());
35
- Directory.CreateDirectory(_tempDir);
36
- }
37
-
38
- [TearDown]
39
- public void TearDown()
40
- {
41
- if (Directory.Exists(_tempDir))
42
- {
43
- try { Directory.Delete(_tempDir, recursive: true); } catch { /* best-effort cleanup */ }
44
- }
45
- }
46
-
47
- [Test]
48
- public void IsDevelopmentDependency_ReturnsTrue_WhenNuspecDeclaresDevDependencyTrue()
49
- {
50
- var nupkg = BuildNupkg(
51
- id: "Example.Analyzer",
52
- version: "1.0.0",
53
- developmentDependencyElement: "<developmentDependency>true</developmentDependency>");
54
-
55
- Assert.IsTrue(NuGetExtractor.IsDevelopmentDependency(nupkg));
56
- }
57
-
58
- [Test]
59
- public void IsDevelopmentDependency_ReturnsTrue_WhenValueHasWhitespace()
60
- {
61
- // Some package authors pretty-print their nuspec; we must not choke on whitespace.
62
- var nupkg = BuildNupkg(
63
- id: "Example.Analyzer",
64
- version: "1.0.0",
65
- developmentDependencyElement: "<developmentDependency> true </developmentDependency>");
66
-
67
- Assert.IsTrue(NuGetExtractor.IsDevelopmentDependency(nupkg));
68
- }
69
-
70
- [Test]
71
- public void IsDevelopmentDependency_ReturnsFalse_WhenNuspecDeclaresDevDependencyFalse()
72
- {
73
- var nupkg = BuildNupkg(
74
- id: "Example.Library",
75
- version: "1.0.0",
76
- developmentDependencyElement: "<developmentDependency>false</developmentDependency>");
77
-
78
- Assert.IsFalse(NuGetExtractor.IsDevelopmentDependency(nupkg));
79
- }
80
-
81
- [Test]
82
- public void IsDevelopmentDependency_ReturnsFalse_WhenDevDependencyElementIsMissing()
83
- {
84
- // The overwhelmingly common case: normal runtime libraries simply omit the element.
85
- var nupkg = BuildNupkg(
86
- id: "Example.Library",
87
- version: "1.0.0",
88
- developmentDependencyElement: null);
89
-
90
- Assert.IsFalse(NuGetExtractor.IsDevelopmentDependency(nupkg));
91
- }
92
-
93
- [Test]
94
- public void IsDevelopmentDependency_ReturnsFalse_WhenNupkgIsCorrupt()
95
- {
96
- // An invalid zip header is not a valid zip archive; the helper must swallow the
97
- // exception and return false so the caller falls back to normal extraction.
98
- var bogus = Path.Combine(_tempDir, "corrupt.nupkg");
99
- File.WriteAllBytes(bogus, new byte[] { 0, 0, 0, 0 });
100
-
101
- Assert.IsFalse(NuGetExtractor.IsDevelopmentDependency(bogus));
102
- }
103
-
104
- [Test]
105
- public void IsDevelopmentDependency_ReturnsFalse_WhenNupkgHasNoNuspec()
106
- {
107
- var nupkg = Path.Combine(_tempDir, "no-nuspec.nupkg");
108
- using (var zip = ZipFile.Open(nupkg, ZipArchiveMode.Create))
109
- {
110
- var entry = zip.CreateEntry("readme.txt");
111
- using var writer = new StreamWriter(entry.Open());
112
- writer.Write("no nuspec here");
113
- }
114
-
115
- Assert.IsFalse(NuGetExtractor.IsDevelopmentDependency(nupkg));
116
- }
117
-
118
- /// <summary>
119
- /// Builds a minimal synthetic .nupkg containing a single .nuspec entry at the root.
120
- /// Mirrors enough of the real NuGet v3 layout to exercise the parser without downloading
121
- /// anything over the network.
122
- /// </summary>
123
- string BuildNupkg(string id, string version, string? developmentDependencyElement)
124
- {
125
- var nupkg = Path.Combine(_tempDir, $"{id}.{version}.nupkg");
126
- var nuspec =
127
- "<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
128
- "<package xmlns=\"http://schemas.microsoft.com/packaging/2011/10/nuspec.xsd\">" +
129
- " <metadata>" +
130
- $" <id>{id}</id>" +
131
- $" <version>{version}</version>" +
132
- " <authors>test</authors>" +
133
- " <description>test fixture package</description>" +
134
- (developmentDependencyElement ?? string.Empty) +
135
- " </metadata>" +
136
- "</package>";
137
-
138
- using (var zip = ZipFile.Open(nupkg, ZipArchiveMode.Create))
139
- {
140
- var entry = zip.CreateEntry($"{id}.nuspec");
141
- using var writer = new StreamWriter(entry.Open());
142
- writer.Write(nuspec);
143
- }
144
-
145
- return nupkg;
146
- }
147
- }
148
- }
1
+ /*
2
+ +------------------------------------------------------------------+
3
+ | Author: Ivan Murzak (https://github.com/IvanMurzak) |
4
+ | Repository: GitHub (https://github.com/IvanMurzak/Unity-MCP) |
5
+ | Copyright (c) 2025 Ivan Murzak |
6
+ | Licensed under the Apache License, Version 2.0. |
7
+ | See the LICENSE file in the project root for more information. |
8
+ +------------------------------------------------------------------+
9
+ */
10
+
11
+ #nullable enable
12
+ using System.IO;
13
+ using System.IO.Compression;
14
+ using NUnit.Framework;
15
+ using com.AtelierAI.Unity.Copilot.Editor.DependencyResolver;
16
+
17
+ namespace com.AtelierAI.Unity.Copilot.Editor.Tests.DependencyResolverTests
18
+ {
19
+ /// <summary>
20
+ /// Regression coverage for issue #670: DependencyResolver was logging
21
+ /// "No compatible framework found" / "No DLLs extracted" warnings for
22
+ /// Roslyn analyzer packages (e.g. Microsoft.CodeAnalysis.Analyzers), which
23
+ /// are marked <c>&lt;developmentDependency&gt;true&lt;/developmentDependency&gt;</c>
24
+ /// in their .nuspec and legitimately have no runtime DLLs under <c>lib/&lt;tfm&gt;/</c>.
25
+ /// </summary>
26
+ [TestFixture]
27
+ public class NuGetExtractorDevelopmentDependencyTests
28
+ {
29
+ string _tempDir = string.Empty;
30
+
31
+ [SetUp]
32
+ public void SetUp()
33
+ {
34
+ _tempDir = Path.Combine(Path.GetTempPath(), "Uco-NuGetExtractor-" + Path.GetRandomFileName());
35
+ Directory.CreateDirectory(_tempDir);
36
+ }
37
+
38
+ [TearDown]
39
+ public void TearDown()
40
+ {
41
+ if (Directory.Exists(_tempDir))
42
+ {
43
+ try { Directory.Delete(_tempDir, recursive: true); } catch { /* best-effort cleanup */ }
44
+ }
45
+ }
46
+
47
+ [Test]
48
+ public void IsDevelopmentDependency_ReturnsTrue_WhenNuspecDeclaresDevDependencyTrue()
49
+ {
50
+ var nupkg = BuildNupkg(
51
+ id: "Example.Analyzer",
52
+ version: "1.0.0",
53
+ developmentDependencyElement: "<developmentDependency>true</developmentDependency>");
54
+
55
+ Assert.IsTrue(NuGetExtractor.IsDevelopmentDependency(nupkg));
56
+ }
57
+
58
+ [Test]
59
+ public void IsDevelopmentDependency_ReturnsTrue_WhenValueHasWhitespace()
60
+ {
61
+ // Some package authors pretty-print their nuspec; we must not choke on whitespace.
62
+ var nupkg = BuildNupkg(
63
+ id: "Example.Analyzer",
64
+ version: "1.0.0",
65
+ developmentDependencyElement: "<developmentDependency> true </developmentDependency>");
66
+
67
+ Assert.IsTrue(NuGetExtractor.IsDevelopmentDependency(nupkg));
68
+ }
69
+
70
+ [Test]
71
+ public void IsDevelopmentDependency_ReturnsFalse_WhenNuspecDeclaresDevDependencyFalse()
72
+ {
73
+ var nupkg = BuildNupkg(
74
+ id: "Example.Library",
75
+ version: "1.0.0",
76
+ developmentDependencyElement: "<developmentDependency>false</developmentDependency>");
77
+
78
+ Assert.IsFalse(NuGetExtractor.IsDevelopmentDependency(nupkg));
79
+ }
80
+
81
+ [Test]
82
+ public void IsDevelopmentDependency_ReturnsFalse_WhenDevDependencyElementIsMissing()
83
+ {
84
+ // The overwhelmingly common case: normal runtime libraries simply omit the element.
85
+ var nupkg = BuildNupkg(
86
+ id: "Example.Library",
87
+ version: "1.0.0",
88
+ developmentDependencyElement: null);
89
+
90
+ Assert.IsFalse(NuGetExtractor.IsDevelopmentDependency(nupkg));
91
+ }
92
+
93
+ [Test]
94
+ public void IsDevelopmentDependency_ReturnsFalse_WhenNupkgIsCorrupt()
95
+ {
96
+ // An invalid zip header is not a valid zip archive; the helper must swallow the
97
+ // exception and return false so the caller falls back to normal extraction.
98
+ var bogus = Path.Combine(_tempDir, "corrupt.nupkg");
99
+ File.WriteAllBytes(bogus, new byte[] { 0, 0, 0, 0 });
100
+
101
+ Assert.IsFalse(NuGetExtractor.IsDevelopmentDependency(bogus));
102
+ }
103
+
104
+ [Test]
105
+ public void IsDevelopmentDependency_ReturnsFalse_WhenNupkgHasNoNuspec()
106
+ {
107
+ var nupkg = Path.Combine(_tempDir, "no-nuspec.nupkg");
108
+ using (var zip = ZipFile.Open(nupkg, ZipArchiveMode.Create))
109
+ {
110
+ var entry = zip.CreateEntry("readme.txt");
111
+ using var writer = new StreamWriter(entry.Open());
112
+ writer.Write("no nuspec here");
113
+ }
114
+
115
+ Assert.IsFalse(NuGetExtractor.IsDevelopmentDependency(nupkg));
116
+ }
117
+
118
+ /// <summary>
119
+ /// Builds a minimal synthetic .nupkg containing a single .nuspec entry at the root.
120
+ /// Mirrors enough of the real NuGet v3 layout to exercise the parser without downloading
121
+ /// anything over the network.
122
+ /// </summary>
123
+ string BuildNupkg(string id, string version, string? developmentDependencyElement)
124
+ {
125
+ var nupkg = Path.Combine(_tempDir, $"{id}.{version}.nupkg");
126
+ var nuspec =
127
+ "<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
128
+ "<package xmlns=\"http://schemas.microsoft.com/packaging/2011/10/nuspec.xsd\">" +
129
+ " <metadata>" +
130
+ $" <id>{id}</id>" +
131
+ $" <version>{version}</version>" +
132
+ " <authors>test</authors>" +
133
+ " <description>test fixture package</description>" +
134
+ (developmentDependencyElement ?? string.Empty) +
135
+ " </metadata>" +
136
+ "</package>";
137
+
138
+ using (var zip = ZipFile.Open(nupkg, ZipArchiveMode.Create))
139
+ {
140
+ var entry = zip.CreateEntry($"{id}.nuspec");
141
+ using var writer = new StreamWriter(entry.Open());
142
+ writer.Write(nuspec);
143
+ }
144
+
145
+ return nupkg;
146
+ }
147
+ }
148
+ }