@atelierai/uco 1.0.7 → 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 (107) hide show
  1. package/CHANGELOG.md +29 -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/DependencyResolver/NuGetConfig.cs +132 -132
  5. package/vendor/plugin/com.atelierai.unity.copilot/Editor/DependencyResolver/NuGetDependencyResolver.cs +237 -237
  6. package/vendor/plugin/com.atelierai.unity.copilot/Editor/DependencyResolver/NuGetDownloader.cs +82 -82
  7. package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/API/Resource/MenuItems.cs +247 -247
  8. package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/API/Resource/ToolGroups.cs +153 -153
  9. package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/API/SystemTool/Skills.Create.SkillBody.cs +155 -155
  10. package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/API/Tool/Console.GetLogs.cs +95 -95
  11. package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/API/Tool/Docs.HttpFetcher.cs +139 -139
  12. package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/API/Tool/Instance.ListAll.cs +72 -72
  13. package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/API/Tool/PathReadHelper.cs +106 -106
  14. package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/API/Tool/Script.Validate.cs +252 -252
  15. package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/API/Tool/Tests/TestResultCollector.cs +537 -537
  16. package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/API/Tool/Tests.cs +400 -400
  17. package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/API/Tool/ToolGroups.SetEnabled.cs +92 -92
  18. package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/Branding/ProductInfo.cs +62 -62
  19. package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/CopilotServerManager.cs +887 -1034
  20. package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/Skills/Skill_InitialSetup.cs +197 -197
  21. package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/Startup.Editor.cs +201 -201
  22. package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/Startup.cs +67 -67
  23. package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/UI/Window/CopilotListWindowBase.cs +393 -393
  24. package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/UI/Window/CopilotWindowBase.cs +113 -113
  25. package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/UI/Window/MainWindowEditor.Connection.cs +3 -3
  26. package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/UI/Window/MainWindowEditor.CopilotFeatures.cs +195 -195
  27. package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/UI/Window/MainWindowEditor.CopilotServer.cs +22 -22
  28. package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/UI/Window/MainWindowEditor.CreateGUI.cs +354 -354
  29. package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/UI/Window/MainWindowEditor.cs +78 -78
  30. package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/UI/Window/MainWindowInitializer.cs +47 -47
  31. package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/UI/Window/SerializationCheckWindow.cs +190 -190
  32. package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/UnityCopilotPluginEditor.Build.cs +91 -91
  33. package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/UnityCopilotPluginEditor.Config.cs +298 -298
  34. package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/UnityCopilotPluginEditor.Static.cs +296 -296
  35. package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/UnityCopilotPluginEditor.cs +69 -69
  36. package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/Utils/PackageUtils.cs +168 -168
  37. package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/Utils/PrefsKeyMigration.cs +119 -119
  38. package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/Utils/SafeDefaultsGuard.cs +180 -180
  39. package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/Utils/ScriptUtils.cs +229 -229
  40. package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/Utils/ToolGroupRegistry.cs +461 -460
  41. package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/Utils/ToolsManifestGenerator.cs +200 -200
  42. package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/Utils/UnityAuthoringAdapters.cs +1467 -1467
  43. package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/Utils/UnityAuthoringSafetyReloadGuard.cs +65 -65
  44. package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/Utils/UnityCopilotUpdateProjectSettings.cs +66 -66
  45. package/vendor/plugin/com.atelierai.unity.copilot/Editor/UI/uss/CopilotPromptsWindow.uss +11 -11
  46. package/vendor/plugin/com.atelierai.unity.copilot/Editor/UI/uss/CopilotResourcesWindow.uss +16 -16
  47. package/vendor/plugin/com.atelierai.unity.copilot/Editor/UI/uss/CopilotToolsWindow.uss +36 -36
  48. package/vendor/plugin/com.atelierai.unity.copilot/Editor/UI/uss/MainWindow.uss +183 -183
  49. package/vendor/plugin/com.atelierai.unity.copilot/Editor/UI/uss/common/{_mcp-list-window.uss → _copilot-list-window.uss} +18 -18
  50. package/vendor/plugin/com.atelierai.unity.copilot/Editor/UI/uss/common/_list-view.uss +77 -77
  51. package/vendor/plugin/com.atelierai.unity.copilot/Editor/UI/uxml/CopilotPromptsWindow.uxml +18 -18
  52. package/vendor/plugin/com.atelierai.unity.copilot/Editor/UI/uxml/CopilotResourcesWindow.uxml +18 -18
  53. package/vendor/plugin/com.atelierai.unity.copilot/Editor/UI/uxml/CopilotToolsWindow.uxml +18 -18
  54. package/vendor/plugin/com.atelierai.unity.copilot/Editor/UI/uxml/MainWindow.uxml +115 -115
  55. package/vendor/plugin/com.atelierai.unity.copilot/Plugins/ReflectorNet.dll +0 -0
  56. package/vendor/plugin/com.atelierai.unity.copilot/Plugins/Uco.Framework.Common.dll +0 -0
  57. package/vendor/plugin/com.atelierai.unity.copilot/Plugins/Uco.Framework.dll +0 -0
  58. package/vendor/plugin/com.atelierai.unity.copilot/README.md +88 -88
  59. package/vendor/plugin/com.atelierai.unity.copilot/Runtime/Converter/Json/Structures/EntityIdConverter.cs +120 -120
  60. package/vendor/plugin/com.atelierai.unity.copilot/Runtime/Data/GameObjectMetadata.cs +110 -110
  61. package/vendor/plugin/com.atelierai.unity.copilot/Runtime/Data/GameObjectMetadata.pre-Unity.6.5.cs +110 -110
  62. package/vendor/plugin/com.atelierai.unity.copilot/Runtime/Unity/Logs/FileLogStorage.cs +547 -547
  63. package/vendor/plugin/com.atelierai.unity.copilot/Runtime/UnityCopilotPlugin.Build.cs +243 -243
  64. package/vendor/plugin/com.atelierai.unity.copilot/Runtime/UnityCopilotPlugin.Config.cs +3 -3
  65. package/vendor/plugin/com.atelierai.unity.copilot/Runtime/UnityCopilotPlugin.cs +295 -295
  66. package/vendor/plugin/com.atelierai.unity.copilot/Runtime/UnityCopilotPluginBuilder.cs +105 -105
  67. package/vendor/plugin/com.atelierai.unity.copilot/Runtime/UnityCopilotPluginRuntime.Static.cs +155 -155
  68. package/vendor/plugin/com.atelierai.unity.copilot/Runtime/UnityCopilotPluginRuntime.cs +59 -59
  69. package/vendor/plugin/com.atelierai.unity.copilot/Runtime/Utils/EnvironmentUtils.cs +11 -11
  70. package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/AtomicApi/AtomicApiTestFixtures.cs +99 -99
  71. package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/AtomicApi/TryModifyAtTests.cs +227 -227
  72. package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/AuthoringSafetyPilotTests.cs +1050 -1050
  73. package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/DependencyResolver/NuGetExtractorDevelopmentDependencyTests.cs +148 -148
  74. package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/DependencyResolver/NuGetExtractorFlatLayoutTests.cs +166 -166
  75. package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/DependencyResolver/NuGetInstallManifestTests.cs +436 -436
  76. package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/DependencyResolver/NuGetLegacyMigrationTests.cs +304 -304
  77. package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/DependencyResolver/NuGetPackageInstallerStaleVersionCleanupTests.cs +200 -200
  78. package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/Environment/EnvironmentUtilsTests.cs +2 -2
  79. package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/ReflectionConverter/BlacklistTypeTests.cs +416 -416
  80. package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/ReflectionConverter/DataFieldScriptableObjectPopulationTests.cs +172 -172
  81. package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/ReflectionConverter/DataFieldScriptableObjectPopulationTests.pre-Unity.6.5.cs +169 -169
  82. package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/ReflectionConverter/DataPopulationTests.cs +182 -182
  83. package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/ReflectionConverter/DataPopulationTests.pre-Unity.6.5.cs +179 -179
  84. package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/ReflectionConverter/DataPropertyPopulationTests.cs +175 -175
  85. package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/ReflectionConverter/DataPropertyPopulationTests.pre-Unity.6.5.cs +174 -174
  86. package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/ReflectionConverter/DataPropertyScriptableObjectPopulationTests.cs +171 -171
  87. package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/ReflectionConverter/DataPropertyScriptableObjectPopulationTests.pre-Unity.6.5.cs +170 -170
  88. package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/Tool/Assets/AssetsCreateFolderTests.cs +243 -243
  89. package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/Tool/Assets/AssetsMaterialTests.cs +101 -101
  90. package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/Tool/Assets/AssetsPrefabCreateTests.cs +348 -348
  91. package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/Tool/Assets/AssetsPrefabCreateTests.pre-Unity.6.5.cs +348 -348
  92. package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/Tool/Assets/AssetsShaderTests.cs +194 -194
  93. package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/Tool/GameObject/TestJsonSchema.cs +199 -199
  94. package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/Tool/PathBasedToolTests.cs +573 -573
  95. package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/Tool/PathBasedToolTests.pre-Unity.6.5.cs +513 -513
  96. package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/Tool/Screenshot/ScreenshotCameraTests.cs +154 -154
  97. package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/Tool/Screenshot/ScreenshotCameraTests.pre-Unity.6.5.cs +154 -154
  98. package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/Tool/Screenshot/ScreenshotGameViewTests.cs +164 -164
  99. package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/Tool/Screenshot/ScreenshotSceneViewTests.cs +155 -155
  100. package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/Tool/ToolParameterTests.cs +56 -56
  101. package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/Tool/ToolThreadSafetyTests.cs +651 -651
  102. package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/Tool/ToolThreadSafetyTests.pre-Unity.6.5.cs +651 -651
  103. package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/ToolBatchExecutionIntegrationTests.cs +407 -407
  104. package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/{McpPluginTests.cs → UcoPluginTests.cs} +105 -105
  105. package/vendor/plugin/com.atelierai.unity.copilot/package.json +1 -1
  106. /package/vendor/plugin/com.atelierai.unity.copilot/Editor/UI/uss/common/{_mcp-list-window.uss.meta → _copilot-list-window.uss.meta} +0 -0
  107. /package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/{McpPluginTests.cs.meta → UcoPluginTests.cs.meta} +0 -0
@@ -1,252 +1,252 @@
1
- /*
2
- * Design inspired by MCP for Unity (CoplayDev/unity-mcp), Copyright (c) Coplay Inc., MIT License.
3
- */
4
-
5
- /*
6
- ┌──────────────────────────────────────────────────────────────────┐
7
- │ Author: Ivan Murzak (https://github.com/IvanMurzak) │
8
- │ Repository: GitHub (https://github.com/IvanMurzak/Unity-MCP) │
9
- │ Copyright (c) 2025 Ivan Murzak │
10
- │ Licensed under the Apache License, Version 2.0. │
11
- │ See the LICENSE file in the project root for more information. │
12
- └──────────────────────────────────────────────────────────────────┘
13
- */
14
-
15
- #nullable enable
16
- using System;
17
- using System.Collections.Generic;
18
- using System.ComponentModel;
19
- using System.IO;
20
- using System.Linq;
21
- using com.AtelierAI.Uco.Framework;
22
- using com.IvanMurzak.ReflectorNet.Utils;
23
- using com.AtelierAI.Unity.Copilot.Utils;
24
- using Microsoft.CodeAnalysis;
25
- using Microsoft.CodeAnalysis.CSharp;
26
- using RoslynDiagnostic = Microsoft.CodeAnalysis.Diagnostic;
27
-
28
- namespace com.AtelierAI.Unity.Copilot.Editor.API
29
- {
30
- public static partial class Tool_Script
31
- {
32
- /// <summary>
33
- /// Validation strictness for <see cref="Validate"/>.
34
- /// </summary>
35
- public enum ValidationLevel
36
- {
37
- /// <summary>Syntax-only: parser checks, no compilation. Fastest, no project references resolved.</summary>
38
- Syntax = 0,
39
- /// <summary>Syntax + semantic: type resolution against project assemblies (catches unknown types/methods/namespaces).</summary>
40
- Semantic = 1,
41
- /// <summary>Strict: Semantic + warnings-as-errors + nullable strictness. Catches latent issues but can be noisy.</summary>
42
- Strict = 2,
43
- }
44
-
45
- /// <summary>
46
- /// Diagnostic entry returned by <see cref="Validate"/>.
47
- /// </summary>
48
- public class ValidationDiagnostic
49
- {
50
- public string Severity { get; set; } = string.Empty; // "Error" | "Warning" | "Info" | "Hidden"
51
- public string Code { get; set; } = string.Empty; // e.g. "CS1002"
52
- public string Message { get; set; } = string.Empty;
53
- public int Line { get; set; } // 1-based
54
- public int Column { get; set; } // 1-based
55
- public int EndLine { get; set; } // 1-based
56
- public int EndColumn { get; set; } // 1-based
57
- }
58
-
59
- /// <summary>
60
- /// Aggregated result returned by <see cref="Validate"/>.
61
- /// </summary>
62
- public class ValidationResult
63
- {
64
- public bool Ok { get; set; }
65
- public ValidationLevel Level { get; set; }
66
- public int ErrorCount { get; set; }
67
- public int WarningCount { get; set; }
68
- public ValidationDiagnostic[] Diagnostics { get; set; } = Array.Empty<ValidationDiagnostic>();
69
- }
70
-
71
- public const string ScriptValidateToolId = "script-validate";
72
-
73
- // Hard cap on input size to avoid OOM from runaway inputs. 1 MiB of C# source is already huge.
74
- private const int MaxValidateCodeBytes = 1 * 1024 * 1024;
75
-
76
- [UcoTool
77
- (
78
- ScriptValidateToolId,
79
- Title = "Script / Validate",
80
- ReadOnlyHint = true,
81
- IdempotentHint = true
82
- )]
83
- [UcoSkillDescription("Validate C# source with Roslyn at three strictness levels (Syntax / Semantic / Strict). " +
84
- "Does NOT execute or write to disk — safe pre-flight lint before '" + ScriptUpdateOrCreateToolId + "'. " +
85
- "Strict / Semantic catch references to unknown namespaces, types, and methods against the project's loaded assemblies.")]
86
- [UcoSkillBody("Validates a C# source string with Roslyn and returns structured diagnostics. " +
87
- "Pure read-only — does NOT compile to an assembly, write any file, or invoke any code. " +
88
- "Pair with '" + ScriptUpdateOrCreateToolId + "' as a pre-flight check before writing scripts to disk.\n\n" +
89
- "## Inputs\n\n" +
90
- "- `code` — required C# source text (the entire file contents). Throws if empty or larger than 1 MiB.\n" +
91
- "- `level` — validation strictness:\n" +
92
- " - `Syntax` (default) — parser-only, fastest. Catches malformed C# (`CS1002` missing `;`, `CS1513` unmatched braces, etc.).\n" +
93
- " - `Semantic` — parser + symbol resolution against all loaded project assemblies. Catches `CS0246` (unknown type), `CS0103` (name not in scope), `CS1061` (no such member), unknown namespaces.\n" +
94
- " - `Strict` — Semantic + warnings-as-errors + nullable context enabled. Useful but can be noisy on legacy code.\n" +
95
- "- `fileName` — optional display name shown in `Diagnostic.Code` paths. Defaults to `Submitted.cs`.\n\n" +
96
- "## Output\n\n" +
97
- "Returns a `ValidationResult`:\n" +
98
- "- `Ok` — true iff zero diagnostics with `Severity == Error`.\n" +
99
- "- `Level` — the level that was actually run.\n" +
100
- "- `ErrorCount` / `WarningCount` — totals.\n" +
101
- "- `Diagnostics[]` — each with `Severity`, `Code` (e.g. `CS0246`), `Message`, and 1-based `Line`/`Column`/`EndLine`/`EndColumn`.\n\n" +
102
- "## Notes\n\n" +
103
- "- `Semantic` and `Strict` reuse the assembly reference set used by '" + ScriptExecuteToolId + "' " +
104
- " (all non-dynamic assemblies in the current AppDomain with a non-empty `Location`).\n" +
105
- "- Semantic resolution covers anything visible to your project — Unity APIs, packages, your own scripts " +
106
- " that compiled successfully. If your project has compile errors, those types won't be resolvable here either.\n" +
107
- "- This tool never runs the code. For execution use '" + ScriptExecuteToolId + "'.")]
108
- [Description("Validates C# source via Roslyn at Syntax / Semantic / Strict levels without compiling to an assembly or " +
109
- "writing any file. Use as a pre-flight check before '" + ScriptUpdateOrCreateToolId + "'. Semantic/Strict catch " +
110
- "references to unknown namespaces, types, and methods against the project's loaded assemblies.")]
111
- public static ValidationResult Validate
112
- (
113
- [Description("C# source code to validate (full file text).")]
114
- string code,
115
- [Description("Validation strictness. 'Syntax' (default) = parser only. 'Semantic' = parser + project-assembly symbol " +
116
- "resolution (catches unknown types/methods/namespaces). 'Strict' = Semantic + warnings-as-errors + nullable.")]
117
- ValidationLevel level = ValidationLevel.Syntax,
118
- [Description("Optional file name shown in diagnostic locations. Defaults to 'Submitted.cs'.")]
119
- string? fileName = null
120
- )
121
- {
122
- if (string.IsNullOrEmpty(code))
123
- throw new ArgumentException($"'{nameof(code)}' is null or empty. Please provide C# source to validate.", nameof(code));
124
-
125
- // Defensive size cap. Roslyn handles large inputs but we don't want runaway memory from malformed clients.
126
- // 2 bytes per char overestimates UTF-16 but is the right thing to compare against `byte` budget.
127
- if ((long)code.Length * 2 > MaxValidateCodeBytes)
128
- throw new ArgumentException(
129
- $"'{nameof(code)}' is too large ({code.Length} chars). Limit: {MaxValidateCodeBytes / 1024} KiB.",
130
- nameof(code));
131
-
132
- var effectiveFileName = string.IsNullOrWhiteSpace(fileName) ? "Submitted.cs" : fileName!;
133
-
134
- try
135
- {
136
- var syntaxTree = CSharpSyntaxTree.ParseText(code, path: effectiveFileName);
137
-
138
- IEnumerable<RoslynDiagnostic> diagnostics;
139
-
140
- if (level == ValidationLevel.Syntax)
141
- {
142
- diagnostics = syntaxTree.GetDiagnostics();
143
- }
144
- else
145
- {
146
- // Reused from Script.Execute.cs: aggregate non-dynamic AppDomain assemblies as MetadataReferences.
147
- // Roslyn parsing/compilation is pure CPU and does NOT require Unity main thread.
148
- var references = BuildProjectReferences();
149
-
150
- var options = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)
151
- .WithWarningLevel(4);
152
-
153
- if (level == ValidationLevel.Strict)
154
- {
155
- options = options
156
- .WithGeneralDiagnosticOption(ReportDiagnostic.Error)
157
- .WithNullableContextOptions(NullableContextOptions.Enable);
158
- }
159
-
160
- var compilation = CSharpCompilation.Create(
161
- assemblyName: "ValidationAssembly",
162
- syntaxTrees: new[] { syntaxTree },
163
- references: references,
164
- options: options
165
- );
166
-
167
- // GetDiagnostics runs parse + declaration + method-body binding without emitting an assembly.
168
- diagnostics = compilation.GetDiagnostics();
169
- }
170
-
171
- var diagList = diagnostics.ToList();
172
-
173
- var errorCount = diagList.Count(d => d.Severity == DiagnosticSeverity.Error);
174
- var warningCount = diagList.Count(d => d.Severity == DiagnosticSeverity.Warning);
175
-
176
- return new ValidationResult
177
- {
178
- Ok = errorCount == 0,
179
- Level = level,
180
- ErrorCount = errorCount,
181
- WarningCount = warningCount,
182
- Diagnostics = diagList.Select(MapDiagnostic).ToArray(),
183
- };
184
- }
185
- catch (ArgumentException)
186
- {
187
- // Preserve clean caller errors (size/empty checks above bubble through unchanged).
188
- throw;
189
- }
190
- catch (Exception ex)
191
- {
192
- // Roslyn occasionally throws on pathological inputs; surface as a single synthetic error rather than 500ing.
193
- return new ValidationResult
194
- {
195
- Ok = false,
196
- Level = level,
197
- ErrorCount = 1,
198
- WarningCount = 0,
199
- Diagnostics = new[]
200
- {
201
- new ValidationDiagnostic
202
- {
203
- Severity = "Error",
204
- Code = "MCP_VALIDATE_INTERNAL",
205
- Message = $"Validation failed internally: {ex.GetType().Name}: {ex.Message}",
206
- Line = 1, Column = 1, EndLine = 1, EndColumn = 1,
207
- }
208
- },
209
- };
210
- }
211
- }
212
-
213
- /// <summary>
214
- /// Reused from Script.Execute.cs (ExecuteCSharpCode): build a MetadataReference[] from every loaded,
215
- /// non-dynamic AppDomain assembly with a resolvable on-disk Location. Silently skips assemblies whose
216
- /// files have moved or been unloaded — same forgiving behavior as the executor.
217
- /// </summary>
218
- static List<MetadataReference> BuildProjectReferences()
219
- {
220
- var result = new List<MetadataReference>();
221
- foreach (var assembly in AssemblyUtils.AllAssemblies)
222
- {
223
- if (assembly.IsDynamic) continue;
224
- if (string.IsNullOrEmpty(assembly.Location)) continue;
225
- try
226
- {
227
- result.Add(MetadataReference.CreateFromFile(assembly.Location));
228
- }
229
- catch (DirectoryNotFoundException) { /* assembly unloaded / moved — skip */ }
230
- catch (FileNotFoundException) { /* assembly unloaded / moved — skip */ }
231
- catch (Exception) { /* defensive — never let a single bad assembly kill validation */ }
232
- }
233
- return result;
234
- }
235
-
236
- static ValidationDiagnostic MapDiagnostic(RoslynDiagnostic d)
237
- {
238
- // Roslyn FileLinePositionSpan is 0-based; we surface 1-based to match human/IDE expectations.
239
- var span = d.Location.GetLineSpan();
240
- return new ValidationDiagnostic
241
- {
242
- Severity = d.Severity.ToString(),
243
- Code = d.Id,
244
- Message = d.GetMessage(),
245
- Line = span.StartLinePosition.Line + 1,
246
- Column = span.StartLinePosition.Character + 1,
247
- EndLine = span.EndLinePosition.Line + 1,
248
- EndColumn = span.EndLinePosition.Character + 1,
249
- };
250
- }
251
- }
252
- }
1
+ /*
2
+ * Design inspired by MCP for Unity (CoplayDev/unity-mcp), Copyright (c) Coplay Inc., MIT License.
3
+ */
4
+
5
+ /*
6
+ ┌──────────────────────────────────────────────────────────────────┐
7
+ │ Author: Ivan Murzak (https://github.com/IvanMurzak) │
8
+ │ Repository: GitHub (https://github.com/IvanMurzak/Unity-MCP) │
9
+ │ Copyright (c) 2025 Ivan Murzak │
10
+ │ Licensed under the Apache License, Version 2.0. │
11
+ │ See the LICENSE file in the project root for more information. │
12
+ └──────────────────────────────────────────────────────────────────┘
13
+ */
14
+
15
+ #nullable enable
16
+ using System;
17
+ using System.Collections.Generic;
18
+ using System.ComponentModel;
19
+ using System.IO;
20
+ using System.Linq;
21
+ using com.AtelierAI.Uco.Framework;
22
+ using com.IvanMurzak.ReflectorNet.Utils;
23
+ using com.AtelierAI.Unity.Copilot.Utils;
24
+ using Microsoft.CodeAnalysis;
25
+ using Microsoft.CodeAnalysis.CSharp;
26
+ using RoslynDiagnostic = Microsoft.CodeAnalysis.Diagnostic;
27
+
28
+ namespace com.AtelierAI.Unity.Copilot.Editor.API
29
+ {
30
+ public static partial class Tool_Script
31
+ {
32
+ /// <summary>
33
+ /// Validation strictness for <see cref="Validate"/>.
34
+ /// </summary>
35
+ public enum ValidationLevel
36
+ {
37
+ /// <summary>Syntax-only: parser checks, no compilation. Fastest, no project references resolved.</summary>
38
+ Syntax = 0,
39
+ /// <summary>Syntax + semantic: type resolution against project assemblies (catches unknown types/methods/namespaces).</summary>
40
+ Semantic = 1,
41
+ /// <summary>Strict: Semantic + warnings-as-errors + nullable strictness. Catches latent issues but can be noisy.</summary>
42
+ Strict = 2,
43
+ }
44
+
45
+ /// <summary>
46
+ /// Diagnostic entry returned by <see cref="Validate"/>.
47
+ /// </summary>
48
+ public class ValidationDiagnostic
49
+ {
50
+ public string Severity { get; set; } = string.Empty; // "Error" | "Warning" | "Info" | "Hidden"
51
+ public string Code { get; set; } = string.Empty; // e.g. "CS1002"
52
+ public string Message { get; set; } = string.Empty;
53
+ public int Line { get; set; } // 1-based
54
+ public int Column { get; set; } // 1-based
55
+ public int EndLine { get; set; } // 1-based
56
+ public int EndColumn { get; set; } // 1-based
57
+ }
58
+
59
+ /// <summary>
60
+ /// Aggregated result returned by <see cref="Validate"/>.
61
+ /// </summary>
62
+ public class ValidationResult
63
+ {
64
+ public bool Ok { get; set; }
65
+ public ValidationLevel Level { get; set; }
66
+ public int ErrorCount { get; set; }
67
+ public int WarningCount { get; set; }
68
+ public ValidationDiagnostic[] Diagnostics { get; set; } = Array.Empty<ValidationDiagnostic>();
69
+ }
70
+
71
+ public const string ScriptValidateToolId = "script-validate";
72
+
73
+ // Hard cap on input size to avoid OOM from runaway inputs. 1 MiB of C# source is already huge.
74
+ private const int MaxValidateCodeBytes = 1 * 1024 * 1024;
75
+
76
+ [UcoTool
77
+ (
78
+ ScriptValidateToolId,
79
+ Title = "Script / Validate",
80
+ ReadOnlyHint = true,
81
+ IdempotentHint = true
82
+ )]
83
+ [UcoSkillDescription("Validate C# source with Roslyn at three strictness levels (Syntax / Semantic / Strict). " +
84
+ "Does NOT execute or write to disk — safe pre-flight lint before '" + ScriptUpdateOrCreateToolId + "'. " +
85
+ "Strict / Semantic catch references to unknown namespaces, types, and methods against the project's loaded assemblies.")]
86
+ [UcoSkillBody("Validates a C# source string with Roslyn and returns structured diagnostics. " +
87
+ "Pure read-only — does NOT compile to an assembly, write any file, or invoke any code. " +
88
+ "Pair with '" + ScriptUpdateOrCreateToolId + "' as a pre-flight check before writing scripts to disk.\n\n" +
89
+ "## Inputs\n\n" +
90
+ "- `code` — required C# source text (the entire file contents). Throws if empty or larger than 1 MiB.\n" +
91
+ "- `level` — validation strictness:\n" +
92
+ " - `Syntax` (default) — parser-only, fastest. Catches malformed C# (`CS1002` missing `;`, `CS1513` unmatched braces, etc.).\n" +
93
+ " - `Semantic` — parser + symbol resolution against all loaded project assemblies. Catches `CS0246` (unknown type), `CS0103` (name not in scope), `CS1061` (no such member), unknown namespaces.\n" +
94
+ " - `Strict` — Semantic + warnings-as-errors + nullable context enabled. Useful but can be noisy on legacy code.\n" +
95
+ "- `fileName` — optional display name shown in `Diagnostic.Code` paths. Defaults to `Submitted.cs`.\n\n" +
96
+ "## Output\n\n" +
97
+ "Returns a `ValidationResult`:\n" +
98
+ "- `Ok` — true iff zero diagnostics with `Severity == Error`.\n" +
99
+ "- `Level` — the level that was actually run.\n" +
100
+ "- `ErrorCount` / `WarningCount` — totals.\n" +
101
+ "- `Diagnostics[]` — each with `Severity`, `Code` (e.g. `CS0246`), `Message`, and 1-based `Line`/`Column`/`EndLine`/`EndColumn`.\n\n" +
102
+ "## Notes\n\n" +
103
+ "- `Semantic` and `Strict` reuse the assembly reference set used by '" + ScriptExecuteToolId + "' " +
104
+ " (all non-dynamic assemblies in the current AppDomain with a non-empty `Location`).\n" +
105
+ "- Semantic resolution covers anything visible to your project — Unity APIs, packages, your own scripts " +
106
+ " that compiled successfully. If your project has compile errors, those types won't be resolvable here either.\n" +
107
+ "- This tool never runs the code. For execution use '" + ScriptExecuteToolId + "'.")]
108
+ [Description("Validates C# source via Roslyn at Syntax / Semantic / Strict levels without compiling to an assembly or " +
109
+ "writing any file. Use as a pre-flight check before '" + ScriptUpdateOrCreateToolId + "'. Semantic/Strict catch " +
110
+ "references to unknown namespaces, types, and methods against the project's loaded assemblies.")]
111
+ public static ValidationResult Validate
112
+ (
113
+ [Description("C# source code to validate (full file text).")]
114
+ string code,
115
+ [Description("Validation strictness. 'Syntax' (default) = parser only. 'Semantic' = parser + project-assembly symbol " +
116
+ "resolution (catches unknown types/methods/namespaces). 'Strict' = Semantic + warnings-as-errors + nullable.")]
117
+ ValidationLevel level = ValidationLevel.Syntax,
118
+ [Description("Optional file name shown in diagnostic locations. Defaults to 'Submitted.cs'.")]
119
+ string? fileName = null
120
+ )
121
+ {
122
+ if (string.IsNullOrEmpty(code))
123
+ throw new ArgumentException($"'{nameof(code)}' is null or empty. Please provide C# source to validate.", nameof(code));
124
+
125
+ // Defensive size cap. Roslyn handles large inputs but we don't want runaway memory from malformed clients.
126
+ // 2 bytes per char overestimates UTF-16 but is the right thing to compare against `byte` budget.
127
+ if ((long)code.Length * 2 > MaxValidateCodeBytes)
128
+ throw new ArgumentException(
129
+ $"'{nameof(code)}' is too large ({code.Length} chars). Limit: {MaxValidateCodeBytes / 1024} KiB.",
130
+ nameof(code));
131
+
132
+ var effectiveFileName = string.IsNullOrWhiteSpace(fileName) ? "Submitted.cs" : fileName!;
133
+
134
+ try
135
+ {
136
+ var syntaxTree = CSharpSyntaxTree.ParseText(code, path: effectiveFileName);
137
+
138
+ IEnumerable<RoslynDiagnostic> diagnostics;
139
+
140
+ if (level == ValidationLevel.Syntax)
141
+ {
142
+ diagnostics = syntaxTree.GetDiagnostics();
143
+ }
144
+ else
145
+ {
146
+ // Reused from Script.Execute.cs: aggregate non-dynamic AppDomain assemblies as MetadataReferences.
147
+ // Roslyn parsing/compilation is pure CPU and does NOT require Unity main thread.
148
+ var references = BuildProjectReferences();
149
+
150
+ var options = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)
151
+ .WithWarningLevel(4);
152
+
153
+ if (level == ValidationLevel.Strict)
154
+ {
155
+ options = options
156
+ .WithGeneralDiagnosticOption(ReportDiagnostic.Error)
157
+ .WithNullableContextOptions(NullableContextOptions.Enable);
158
+ }
159
+
160
+ var compilation = CSharpCompilation.Create(
161
+ assemblyName: "ValidationAssembly",
162
+ syntaxTrees: new[] { syntaxTree },
163
+ references: references,
164
+ options: options
165
+ );
166
+
167
+ // GetDiagnostics runs parse + declaration + method-body binding without emitting an assembly.
168
+ diagnostics = compilation.GetDiagnostics();
169
+ }
170
+
171
+ var diagList = diagnostics.ToList();
172
+
173
+ var errorCount = diagList.Count(d => d.Severity == DiagnosticSeverity.Error);
174
+ var warningCount = diagList.Count(d => d.Severity == DiagnosticSeverity.Warning);
175
+
176
+ return new ValidationResult
177
+ {
178
+ Ok = errorCount == 0,
179
+ Level = level,
180
+ ErrorCount = errorCount,
181
+ WarningCount = warningCount,
182
+ Diagnostics = diagList.Select(MapDiagnostic).ToArray(),
183
+ };
184
+ }
185
+ catch (ArgumentException)
186
+ {
187
+ // Preserve clean caller errors (size/empty checks above bubble through unchanged).
188
+ throw;
189
+ }
190
+ catch (Exception ex)
191
+ {
192
+ // Roslyn occasionally throws on pathological inputs; surface as a single synthetic error rather than 500ing.
193
+ return new ValidationResult
194
+ {
195
+ Ok = false,
196
+ Level = level,
197
+ ErrorCount = 1,
198
+ WarningCount = 0,
199
+ Diagnostics = new[]
200
+ {
201
+ new ValidationDiagnostic
202
+ {
203
+ Severity = "Error",
204
+ Code = "UCO_VALIDATE_INTERNAL",
205
+ Message = $"Validation failed internally: {ex.GetType().Name}: {ex.Message}",
206
+ Line = 1, Column = 1, EndLine = 1, EndColumn = 1,
207
+ }
208
+ },
209
+ };
210
+ }
211
+ }
212
+
213
+ /// <summary>
214
+ /// Reused from Script.Execute.cs (ExecuteCSharpCode): build a MetadataReference[] from every loaded,
215
+ /// non-dynamic AppDomain assembly with a resolvable on-disk Location. Silently skips assemblies whose
216
+ /// files have moved or been unloaded — same forgiving behavior as the executor.
217
+ /// </summary>
218
+ static List<MetadataReference> BuildProjectReferences()
219
+ {
220
+ var result = new List<MetadataReference>();
221
+ foreach (var assembly in AssemblyUtils.AllAssemblies)
222
+ {
223
+ if (assembly.IsDynamic) continue;
224
+ if (string.IsNullOrEmpty(assembly.Location)) continue;
225
+ try
226
+ {
227
+ result.Add(MetadataReference.CreateFromFile(assembly.Location));
228
+ }
229
+ catch (DirectoryNotFoundException) { /* assembly unloaded / moved — skip */ }
230
+ catch (FileNotFoundException) { /* assembly unloaded / moved — skip */ }
231
+ catch (Exception) { /* defensive — never let a single bad assembly kill validation */ }
232
+ }
233
+ return result;
234
+ }
235
+
236
+ static ValidationDiagnostic MapDiagnostic(RoslynDiagnostic d)
237
+ {
238
+ // Roslyn FileLinePositionSpan is 0-based; we surface 1-based to match human/IDE expectations.
239
+ var span = d.Location.GetLineSpan();
240
+ return new ValidationDiagnostic
241
+ {
242
+ Severity = d.Severity.ToString(),
243
+ Code = d.Id,
244
+ Message = d.GetMessage(),
245
+ Line = span.StartLinePosition.Line + 1,
246
+ Column = span.StartLinePosition.Character + 1,
247
+ EndLine = span.EndLinePosition.Line + 1,
248
+ EndColumn = span.EndLinePosition.Character + 1,
249
+ };
250
+ }
251
+ }
252
+ }