@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,201 +1,201 @@
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 com.AtelierAI.Unity.Copilot.Runtime.Utils;
13
- using com.AtelierAI.Unity.Copilot.Editor.Utils;
14
- using com.AtelierAI.Uco.Framework;
15
- using Microsoft.Extensions.Logging;
16
- using UnityEditor;
17
- using UnityEngine;
18
-
19
- namespace com.AtelierAI.Unity.Copilot.Editor
20
- {
21
- public static partial class Startup
22
- {
23
- static void SubscribeOnEditorEvents()
24
- {
25
- Application.unloading += OnApplicationUnloading;
26
- Application.quitting += OnApplicationQuitting;
27
-
28
- AssemblyReloadEvents.beforeAssemblyReload += OnBeforeAssemblyReload;
29
- AssemblyReloadEvents.afterAssemblyReload += OnAfterAssemblyReload;
30
-
31
- // Handle Play mode state changes to ensure reconnection after exiting Play mode
32
- EditorApplication.playModeStateChanged += OnPlayModeStateChanged;
33
- }
34
- static void OnApplicationUnloading() => TryDisconnectAndCleanup(nameof(OnApplicationUnloading));
35
- static void OnApplicationQuitting() => TryDisconnectAndCleanup(nameof(OnApplicationQuitting));
36
- static void OnBeforeAssemblyReload()
37
- {
38
- EditorToolExecutionScheduler.Shared.InvalidateInstance();
39
- EditorOperationOwnerRegistry.InvalidateGeneration();
40
- UnityAuthoringSafetyReloadGuard.InvalidateConfirmationPlans();
41
- TryDisconnectAndCleanup(nameof(OnBeforeAssemblyReload));
42
- }
43
-
44
- /// <summary>
45
- /// Safely disconnects and cleans up the MCP plugin instance.
46
- /// Catches exceptions to prevent blocking Unity's shutdown/reload process.
47
- /// </summary>
48
- /// <param name="callerName">Name of the calling method for logging.</param>
49
- /// <param name="onlyIfConnected">If true, only disconnects when in Connected state.
50
- /// This prevents issues when cancelling in-progress connection attempts during assembly reload.
51
- /// Note: Log collector disposal always occurs regardless of this flag.</param>
52
- static void TryDisconnectAndCleanup(string callerName, bool onlyIfConnected = false)
53
- {
54
- if (!UnityCopilotPluginEditor.HasInstance)
55
- {
56
- _logger.LogDebug("{class} {method} triggered: No UnityCopilotPluginEditor instance to disconnect",
57
- nameof(Startup), callerName);
58
- return;
59
- }
60
-
61
- _logger.LogInformation("{method} triggered", callerName);
62
-
63
- var plugin = UnityCopilotPluginEditor.Instance;
64
- if (plugin.HasMcpPluginInstance)
65
- {
66
- var connectionState = UnityCopilotPluginEditor.ConnectionState.CurrentValue;
67
-
68
- // When onlyIfConnected is true, skip disconnect unless we have an established connection.
69
- // This prevents hanging when cancelling in-progress connection attempts (Connecting/Reconnecting states).
70
- if (onlyIfConnected && connectionState != ConnectionState.Connected)
71
- {
72
- _logger.LogTrace("Skipping {method} - not connected (state: {state})",
73
- nameof(plugin.DisconnectImmediate), connectionState);
74
- }
75
- else
76
- {
77
- try
78
- {
79
- plugin.DisconnectImmediate();
80
- }
81
- catch (System.Exception e)
82
- {
83
- _logger.LogWarning(e, "{class} {method}: Exception during disconnect (non-blocking): {message}",
84
- nameof(Startup), callerName, e.Message);
85
- }
86
- }
87
- }
88
-
89
- try
90
- {
91
- plugin.DisposeLogCollector();
92
- }
93
- catch (System.Exception e)
94
- {
95
- _logger.LogWarning(e, "{class} {method}: Exception during log collector disposal (non-blocking): {message}",
96
- nameof(Startup), callerName, e.Message);
97
- }
98
-
99
- if (UnityCopilotPluginRuntime.HasInstance)
100
- {
101
- try
102
- {
103
- UnityCopilotPluginRuntime.DisposeInstance();
104
- }
105
- catch (System.Exception e)
106
- {
107
- _logger.LogWarning(e, "{class} {method}: Exception during runtime plugin disposal (non-blocking): {message}",
108
- nameof(Startup), callerName, e.Message);
109
- }
110
- }
111
- }
112
- static void OnAfterAssemblyReload()
113
- {
114
- var isCi = EnvironmentUtils.IsCi();
115
- var isBatchMode = EnvironmentUtils.IsBatchMode();
116
- var keepConnected = UnityCopilotPluginEditor.KeepConnected;
117
- // COCli-13: batchmode launches (offline builds, command-line
118
- // automation) skip the connection retry loop unless the
119
- // configuration explicitly keeps the server running — connection
120
- // warnings would otherwise pollute BuildReport output.
121
- var connectionAllowed = keepConnected || (!isCi && !isBatchMode);
122
-
123
- _logger.LogInformation("{method} triggered - BuildAndStart with connectionAllowed: {connectionAllowed} (isCi: {isCi}, isBatchMode: {isBatchMode}, keepConnected: {keepConnected})",
124
- nameof(OnAfterAssemblyReload), connectionAllowed, isCi, isBatchMode, keepConnected);
125
-
126
- UnityCopilotPluginEditor.Instance.BuildMcpPluginIfNeeded();
127
- UnityCopilotPluginEditor.Instance.AddUnityLogCollectorIfNeeded(() => new BufferedFileLogStorage());
128
-
129
- if (connectionAllowed)
130
- UnityCopilotPluginEditor.ConnectIfNeeded();
131
- }
132
-
133
- static void OnPlayModeStateChanged(PlayModeStateChange state)
134
- {
135
- if (!UnityCopilotPluginEditor.HasInstance)
136
- {
137
- _logger.LogDebug("{class} {method} triggered: No UnityCopilotPluginEditor instance available. State: {state}",
138
- nameof(Startup), nameof(OnPlayModeStateChanged), state);
139
- return;
140
- }
141
-
142
- // Log Play mode state changes for debugging
143
- _logger.LogInformation("Play mode state changed: {state}", state);
144
-
145
- switch (state)
146
- {
147
- case PlayModeStateChange.ExitingPlayMode:
148
- // Dispose the runtime plugin instance created by Initialize().Build().
149
- // This handles the no-domain-reload case; TryDisconnectAndCleanup covers the domain-reload case.
150
- _logger.LogTrace("Exiting Play mode - disposing runtime plugin instance if present");
151
- if (UnityCopilotPluginRuntime.HasInstance)
152
- UnityCopilotPluginRuntime.DisposeInstance();
153
- break;
154
-
155
- case PlayModeStateChange.EnteredEditMode:
156
- // Unity has returned to Edit mode - ensure connection is re-established
157
- // if the configuration expects it to be connected
158
- var isCi = EnvironmentUtils.IsCi();
159
- var isBatchMode = EnvironmentUtils.IsBatchMode();
160
- var keepConnected = UnityCopilotPluginEditor.KeepConnected;
161
- _logger.LogTrace("Entered Edit mode - KeepConnected: {keepConnected}, IsCi: {isCi}, IsBatchMode: {isBatchMode}",
162
- keepConnected, isCi, isBatchMode);
163
-
164
- if ((isCi || isBatchMode) && !keepConnected)
165
- {
166
- _logger.LogTrace("Skipping reconnection in CI/batchmode environment (KeepConnected is false)");
167
- break;
168
- }
169
-
170
- _logger.LogTrace("Scheduling reconnection after Play mode exit");
171
-
172
- // Small delay to ensure Unity is fully settled in Edit mode
173
- EditorApplication.delayCall += () =>
174
- {
175
- _logger.LogTrace("Initiating delayed reconnection after Play mode exit");
176
-
177
- UnityCopilotPluginEditor.Instance.BuildMcpPluginIfNeeded();
178
- UnityCopilotPluginEditor.Instance.AddUnityLogCollectorIfNeeded(() => new BufferedFileLogStorage());
179
- UnityCopilotPluginEditor.ConnectIfNeeded();
180
- };
181
-
182
- // No delay, immediate reconnection for the case if Unity Editor in background
183
- // (has no focus)
184
- _logger.LogTrace("Initiating reconnection after Play mode exit");
185
-
186
- UnityCopilotPluginEditor.Instance.BuildMcpPluginIfNeeded();
187
- UnityCopilotPluginEditor.Instance.AddUnityLogCollectorIfNeeded(() => new BufferedFileLogStorage());
188
- UnityCopilotPluginEditor.ConnectIfNeeded();
189
- break;
190
-
191
- case PlayModeStateChange.ExitingEditMode:
192
- _logger.LogTrace("Exiting Edit mode to enter Play mode");
193
- break;
194
-
195
- case PlayModeStateChange.EnteredPlayMode:
196
- _logger.LogTrace("Entered Play mode");
197
- break;
198
- }
199
- }
200
- }
201
- }
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 com.AtelierAI.Unity.Copilot.Runtime.Utils;
13
+ using com.AtelierAI.Unity.Copilot.Editor.Utils;
14
+ using com.AtelierAI.Uco.Framework;
15
+ using Microsoft.Extensions.Logging;
16
+ using UnityEditor;
17
+ using UnityEngine;
18
+
19
+ namespace com.AtelierAI.Unity.Copilot.Editor
20
+ {
21
+ public static partial class Startup
22
+ {
23
+ static void SubscribeOnEditorEvents()
24
+ {
25
+ Application.unloading += OnApplicationUnloading;
26
+ Application.quitting += OnApplicationQuitting;
27
+
28
+ AssemblyReloadEvents.beforeAssemblyReload += OnBeforeAssemblyReload;
29
+ AssemblyReloadEvents.afterAssemblyReload += OnAfterAssemblyReload;
30
+
31
+ // Handle Play mode state changes to ensure reconnection after exiting Play mode
32
+ EditorApplication.playModeStateChanged += OnPlayModeStateChanged;
33
+ }
34
+ static void OnApplicationUnloading() => TryDisconnectAndCleanup(nameof(OnApplicationUnloading));
35
+ static void OnApplicationQuitting() => TryDisconnectAndCleanup(nameof(OnApplicationQuitting));
36
+ static void OnBeforeAssemblyReload()
37
+ {
38
+ EditorToolExecutionScheduler.Shared.InvalidateInstance();
39
+ EditorOperationOwnerRegistry.InvalidateGeneration();
40
+ UnityAuthoringSafetyReloadGuard.InvalidateConfirmationPlans();
41
+ TryDisconnectAndCleanup(nameof(OnBeforeAssemblyReload));
42
+ }
43
+
44
+ /// <summary>
45
+ /// Safely disconnects and cleans up the Uco plugin instance.
46
+ /// Catches exceptions to prevent blocking Unity's shutdown/reload process.
47
+ /// </summary>
48
+ /// <param name="callerName">Name of the calling method for logging.</param>
49
+ /// <param name="onlyIfConnected">If true, only disconnects when in Connected state.
50
+ /// This prevents issues when cancelling in-progress connection attempts during assembly reload.
51
+ /// Note: Log collector disposal always occurs regardless of this flag.</param>
52
+ static void TryDisconnectAndCleanup(string callerName, bool onlyIfConnected = false)
53
+ {
54
+ if (!UnityCopilotPluginEditor.HasInstance)
55
+ {
56
+ _logger.LogDebug("{class} {method} triggered: No UnityCopilotPluginEditor instance to disconnect",
57
+ nameof(Startup), callerName);
58
+ return;
59
+ }
60
+
61
+ _logger.LogInformation("{method} triggered", callerName);
62
+
63
+ var plugin = UnityCopilotPluginEditor.Instance;
64
+ if (plugin.HasUcoPluginInstance)
65
+ {
66
+ var connectionState = UnityCopilotPluginEditor.ConnectionState.CurrentValue;
67
+
68
+ // When onlyIfConnected is true, skip disconnect unless we have an established connection.
69
+ // This prevents hanging when cancelling in-progress connection attempts (Connecting/Reconnecting states).
70
+ if (onlyIfConnected && connectionState != ConnectionState.Connected)
71
+ {
72
+ _logger.LogTrace("Skipping {method} - not connected (state: {state})",
73
+ nameof(plugin.DisconnectImmediate), connectionState);
74
+ }
75
+ else
76
+ {
77
+ try
78
+ {
79
+ plugin.DisconnectImmediate();
80
+ }
81
+ catch (System.Exception e)
82
+ {
83
+ _logger.LogWarning(e, "{class} {method}: Exception during disconnect (non-blocking): {message}",
84
+ nameof(Startup), callerName, e.Message);
85
+ }
86
+ }
87
+ }
88
+
89
+ try
90
+ {
91
+ plugin.DisposeLogCollector();
92
+ }
93
+ catch (System.Exception e)
94
+ {
95
+ _logger.LogWarning(e, "{class} {method}: Exception during log collector disposal (non-blocking): {message}",
96
+ nameof(Startup), callerName, e.Message);
97
+ }
98
+
99
+ if (UnityCopilotPluginRuntime.HasInstance)
100
+ {
101
+ try
102
+ {
103
+ UnityCopilotPluginRuntime.DisposeInstance();
104
+ }
105
+ catch (System.Exception e)
106
+ {
107
+ _logger.LogWarning(e, "{class} {method}: Exception during runtime plugin disposal (non-blocking): {message}",
108
+ nameof(Startup), callerName, e.Message);
109
+ }
110
+ }
111
+ }
112
+ static void OnAfterAssemblyReload()
113
+ {
114
+ var isCi = EnvironmentUtils.IsCi();
115
+ var isBatchMode = EnvironmentUtils.IsBatchMode();
116
+ var keepConnected = UnityCopilotPluginEditor.KeepConnected;
117
+ // COCli-13: batchmode launches (offline builds, command-line
118
+ // automation) skip the connection retry loop unless the
119
+ // configuration explicitly keeps the server running — connection
120
+ // warnings would otherwise pollute BuildReport output.
121
+ var connectionAllowed = keepConnected || (!isCi && !isBatchMode);
122
+
123
+ _logger.LogInformation("{method} triggered - BuildAndStart with connectionAllowed: {connectionAllowed} (isCi: {isCi}, isBatchMode: {isBatchMode}, keepConnected: {keepConnected})",
124
+ nameof(OnAfterAssemblyReload), connectionAllowed, isCi, isBatchMode, keepConnected);
125
+
126
+ UnityCopilotPluginEditor.Instance.BuildUcoPluginIfNeeded();
127
+ UnityCopilotPluginEditor.Instance.AddUnityLogCollectorIfNeeded(() => new BufferedFileLogStorage());
128
+
129
+ if (connectionAllowed)
130
+ UnityCopilotPluginEditor.ConnectIfNeeded();
131
+ }
132
+
133
+ static void OnPlayModeStateChanged(PlayModeStateChange state)
134
+ {
135
+ if (!UnityCopilotPluginEditor.HasInstance)
136
+ {
137
+ _logger.LogDebug("{class} {method} triggered: No UnityCopilotPluginEditor instance available. State: {state}",
138
+ nameof(Startup), nameof(OnPlayModeStateChanged), state);
139
+ return;
140
+ }
141
+
142
+ // Log Play mode state changes for debugging
143
+ _logger.LogInformation("Play mode state changed: {state}", state);
144
+
145
+ switch (state)
146
+ {
147
+ case PlayModeStateChange.ExitingPlayMode:
148
+ // Dispose the runtime plugin instance created by Initialize().Build().
149
+ // This handles the no-domain-reload case; TryDisconnectAndCleanup covers the domain-reload case.
150
+ _logger.LogTrace("Exiting Play mode - disposing runtime plugin instance if present");
151
+ if (UnityCopilotPluginRuntime.HasInstance)
152
+ UnityCopilotPluginRuntime.DisposeInstance();
153
+ break;
154
+
155
+ case PlayModeStateChange.EnteredEditMode:
156
+ // Unity has returned to Edit mode - ensure connection is re-established
157
+ // if the configuration expects it to be connected
158
+ var isCi = EnvironmentUtils.IsCi();
159
+ var isBatchMode = EnvironmentUtils.IsBatchMode();
160
+ var keepConnected = UnityCopilotPluginEditor.KeepConnected;
161
+ _logger.LogTrace("Entered Edit mode - KeepConnected: {keepConnected}, IsCi: {isCi}, IsBatchMode: {isBatchMode}",
162
+ keepConnected, isCi, isBatchMode);
163
+
164
+ if ((isCi || isBatchMode) && !keepConnected)
165
+ {
166
+ _logger.LogTrace("Skipping reconnection in CI/batchmode environment (KeepConnected is false)");
167
+ break;
168
+ }
169
+
170
+ _logger.LogTrace("Scheduling reconnection after Play mode exit");
171
+
172
+ // Small delay to ensure Unity is fully settled in Edit mode
173
+ EditorApplication.delayCall += () =>
174
+ {
175
+ _logger.LogTrace("Initiating delayed reconnection after Play mode exit");
176
+
177
+ UnityCopilotPluginEditor.Instance.BuildUcoPluginIfNeeded();
178
+ UnityCopilotPluginEditor.Instance.AddUnityLogCollectorIfNeeded(() => new BufferedFileLogStorage());
179
+ UnityCopilotPluginEditor.ConnectIfNeeded();
180
+ };
181
+
182
+ // No delay, immediate reconnection for the case if Unity Editor in background
183
+ // (has no focus)
184
+ _logger.LogTrace("Initiating reconnection after Play mode exit");
185
+
186
+ UnityCopilotPluginEditor.Instance.BuildUcoPluginIfNeeded();
187
+ UnityCopilotPluginEditor.Instance.AddUnityLogCollectorIfNeeded(() => new BufferedFileLogStorage());
188
+ UnityCopilotPluginEditor.ConnectIfNeeded();
189
+ break;
190
+
191
+ case PlayModeStateChange.ExitingEditMode:
192
+ _logger.LogTrace("Exiting Edit mode to enter Play mode");
193
+ break;
194
+
195
+ case PlayModeStateChange.EnteredPlayMode:
196
+ _logger.LogTrace("Entered Play mode");
197
+ break;
198
+ }
199
+ }
200
+ }
201
+ }
@@ -1,67 +1,67 @@
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 com.AtelierAI.Unity.Copilot.Editor.UI;
13
- using com.AtelierAI.Unity.Copilot.Editor.Utils;
14
- using com.AtelierAI.Unity.Copilot.Utils;
15
- using Microsoft.Extensions.Logging;
16
- using UnityEditor;
17
- using UnityEngine;
18
- using ILogger = Microsoft.Extensions.Logging.ILogger;
19
-
20
- namespace com.AtelierAI.Unity.Copilot.Editor
21
- {
22
- [InitializeOnLoad]
23
- public static partial class Startup
24
- {
25
- static readonly ILogger _logger = UnityLoggerFactory.LoggerFactory.CreateLogger(nameof(Startup));
26
-
27
- static Startup()
28
- {
29
- if (!UnityProcessGuard.ShouldInitialize(AssetDatabase.IsAssetImportWorkerProcess()))
30
- {
31
- return;
32
- }
33
-
34
- EditorOperationOwners.RegisterAndReconcile();
35
- UnityCopilotPluginEditor.Instance.BuildMcpPluginIfNeeded();
36
- UnityCopilotPluginEditor.Instance.AddUnityLogCollectorIfNeeded(() => new BufferedFileLogStorage());
37
-
38
- // Informational notice — historically the plugin treated a space in the project
39
- // path as a hard error, but in practice the modern startup pipeline (structured
40
- // ProcessStartInfo, JSON/TOML client configs with quoted command strings,
41
- // Path.Combine-based file IO) handles spaces correctly. We keep a one-shot
42
- // warning so users have a breadcrumb if they hit a third-party tool that does
43
- // not tolerate spaces in paths.
44
- if (Application.dataPath.Contains(" "))
45
- Debug.LogWarning("Unity Copilot: project path contains spaces. The plugin will start normally; if any specific workflow misbehaves with this path, please report it so we can fix the underlying issue.");
46
-
47
- SubscribeOnEditorEvents();
48
-
49
- // Initialize sub-systems
50
- API.Tool_Tests.Init();
51
- UpdateChecker.Init();
52
- PackageUtils.Init();
53
- }
54
- }
55
-
56
- /// <summary>
57
- /// Asset Import Workers inherit the main Editor's environment variables but
58
- /// must never create their own MCP plugin/server lifecycle. A worker bridge
59
- /// advertises the same project instance ID, cannot complete normal Editor
60
- /// registration, and can otherwise displace the main Editor connection.
61
- /// </summary>
62
- internal static class UnityProcessGuard
63
- {
64
- internal static bool ShouldInitialize(bool isAssetImportWorkerProcess)
65
- => !isAssetImportWorkerProcess;
66
- }
67
- }
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 com.AtelierAI.Unity.Copilot.Editor.UI;
13
+ using com.AtelierAI.Unity.Copilot.Editor.Utils;
14
+ using com.AtelierAI.Unity.Copilot.Utils;
15
+ using Microsoft.Extensions.Logging;
16
+ using UnityEditor;
17
+ using UnityEngine;
18
+ using ILogger = Microsoft.Extensions.Logging.ILogger;
19
+
20
+ namespace com.AtelierAI.Unity.Copilot.Editor
21
+ {
22
+ [InitializeOnLoad]
23
+ public static partial class Startup
24
+ {
25
+ static readonly ILogger _logger = UnityLoggerFactory.LoggerFactory.CreateLogger(nameof(Startup));
26
+
27
+ static Startup()
28
+ {
29
+ if (!UnityProcessGuard.ShouldInitialize(AssetDatabase.IsAssetImportWorkerProcess()))
30
+ {
31
+ return;
32
+ }
33
+
34
+ EditorOperationOwners.RegisterAndReconcile();
35
+ UnityCopilotPluginEditor.Instance.BuildUcoPluginIfNeeded();
36
+ UnityCopilotPluginEditor.Instance.AddUnityLogCollectorIfNeeded(() => new BufferedFileLogStorage());
37
+
38
+ // Informational notice — historically the plugin treated a space in the project
39
+ // path as a hard error, but in practice the modern startup pipeline (structured
40
+ // ProcessStartInfo, JSON/TOML client configs with quoted command strings,
41
+ // Path.Combine-based file IO) handles spaces correctly. We keep a one-shot
42
+ // warning so users have a breadcrumb if they hit a third-party tool that does
43
+ // not tolerate spaces in paths.
44
+ if (Application.dataPath.Contains(" "))
45
+ Debug.LogWarning("Unity Copilot: project path contains spaces. The plugin will start normally; if any specific workflow misbehaves with this path, please report it so we can fix the underlying issue.");
46
+
47
+ SubscribeOnEditorEvents();
48
+
49
+ // Initialize sub-systems
50
+ API.Tool_Tests.Init();
51
+ UpdateChecker.Init();
52
+ PackageUtils.Init();
53
+ }
54
+ }
55
+
56
+ /// <summary>
57
+ /// Asset Import Workers inherit the main Editor's environment variables but
58
+ /// must never create their own Uco plugin/server lifecycle. A worker bridge
59
+ /// advertises the same project instance ID, cannot complete normal Editor
60
+ /// registration, and can otherwise displace the main Editor connection.
61
+ /// </summary>
62
+ internal static class UnityProcessGuard
63
+ {
64
+ internal static bool ShouldInitialize(bool isAssetImportWorkerProcess)
65
+ => !isAssetImportWorkerProcess;
66
+ }
67
+ }