@atelierai/uco 1.0.6 → 1.0.8
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.
- package/CHANGELOG.md +32 -0
- package/README.md +7 -8
- package/bin/server.mjs +1 -1
- package/bin/stub-plugin.mjs +3 -3
- package/dist/codegen/coerce.js +1 -1
- package/dist/codegen/coerce.js.map +1 -1
- package/dist/codegen/emit.js +2 -2
- package/dist/codegen/emit.js.map +1 -1
- package/dist/codegen/refs.js +1 -1
- package/dist/codegen/refs.js.map +1 -1
- package/dist/codegen/types.js +1 -1
- package/dist/codegen/types.js.map +1 -1
- package/dist/commands/call.js +1 -1
- package/dist/commands/call.js.map +1 -1
- package/dist/commands/devops/configure.js +1 -1
- package/dist/commands/devops/configure.js.map +1 -1
- package/dist/commands/devops/index.js +0 -4
- package/dist/commands/devops/index.js.map +1 -1
- package/dist/commands/devops/install-plugin.js +1 -1
- package/dist/commands/devops/install-plugin.js.map +1 -1
- package/dist/commands/devops/open.js +7 -7
- package/dist/commands/devops/open.js.map +1 -1
- package/dist/commands/devops/status.js +3 -3
- package/dist/commands/devops/status.js.map +1 -1
- package/dist/commands/exec.js +1 -1
- package/dist/commands/exec.js.map +1 -1
- package/dist/commands/install.js +2 -2
- package/dist/commands/install.js.map +1 -1
- package/dist/commands/prompt.js +2 -2
- package/dist/commands/prompt.js.map +1 -1
- package/dist/commands/resource.js +2 -2
- package/dist/commands/resource.js.map +1 -1
- package/dist/commands/update.js +1 -26
- package/dist/commands/update.js.map +1 -1
- package/dist/config/port.js +2 -2
- package/dist/config/port.js.map +1 -1
- package/dist/config/resolve.d.ts +1 -2
- package/dist/config/resolve.js +0 -12
- package/dist/config/resolve.js.map +1 -1
- package/dist/devops/lib/configure.d.ts +1 -1
- package/dist/devops/lib/configure.js +2 -2
- package/dist/devops/lib/configure.js.map +1 -1
- package/dist/devops/lib/install-plugin.d.ts +1 -1
- package/dist/devops/lib/install-plugin.js +1 -1
- package/dist/devops/lib/install-plugin.js.map +1 -1
- package/dist/devops/lib/install.d.ts +2 -2
- package/dist/devops/lib/install.js +5 -5
- package/dist/devops/lib/install.js.map +1 -1
- package/dist/devops/lib/open.js +11 -32
- package/dist/devops/lib/open.js.map +1 -1
- package/dist/devops/lib/remove-plugin.d.ts +1 -1
- package/dist/devops/lib/remove-plugin.js +3 -3
- package/dist/devops/lib/remove-plugin.js.map +1 -1
- package/dist/devops/lib/run-tool.d.ts +2 -2
- package/dist/devops/lib/run-tool.js +2 -2
- package/dist/devops/lib/types.d.ts +17 -54
- package/dist/devops/lib/types.js +2 -2
- package/dist/devops/lib/types.js.map +1 -1
- package/dist/devops/lib/update.d.ts +0 -15
- package/dist/devops/lib/update.js +2 -91
- package/dist/devops/lib/update.js.map +1 -1
- package/dist/devops/utils/agents.d.ts +0 -28
- package/dist/devops/utils/agents.js +0 -462
- package/dist/devops/utils/agents.js.map +1 -1
- package/dist/devops/utils/config.d.ts +9 -18
- package/dist/devops/utils/config.js +7 -20
- package/dist/devops/utils/config.js.map +1 -1
- package/dist/devops/utils/editor-cache.js +1 -1
- package/dist/devops/utils/editor-cache.js.map +1 -1
- package/dist/devops/utils/launch-error-dismiss.d.ts +2 -2
- package/dist/devops/utils/launch-error-dismiss.js +5 -5
- package/dist/devops/utils/manifest.d.ts +2 -2
- package/dist/devops/utils/manifest.js +3 -3
- package/dist/devops/utils/manifest.js.map +1 -1
- package/dist/devops/utils/port.d.ts +1 -1
- package/dist/devops/utils/port.js +1 -1
- package/dist/devops/utils/probe.d.ts +1 -1
- package/dist/devops/utils/probe.js +1 -1
- package/dist/devops/utils/ui.js +2 -2
- package/dist/devops/utils/ui.js.map +1 -1
- package/dist/devops/utils/unity-editor.js +4 -4
- package/dist/devops/utils/unity-editor.js.map +1 -1
- package/dist/devops/utils/unity-hub.js +1 -1
- package/dist/devops/utils/unity-hub.js.map +1 -1
- package/dist/devops/utils/unity-shutdown.d.ts +1 -1
- package/dist/devops/utils/unity-shutdown.js +1 -1
- package/dist/devops/utils/update-check.js +3 -3
- package/dist/devops/utils/update-check.js.map +1 -1
- package/dist/devops/utils/vendor.d.ts +2 -2
- package/dist/devops/utils/vendor.js +4 -4
- package/dist/devops/utils/vendor.js.map +1 -1
- package/dist/generated/tools.js +1 -1
- package/dist/generated/tools.js.map +1 -1
- package/dist/program.js +3 -3
- package/dist/program.js.map +1 -1
- package/dist/server/app.d.ts +5 -5
- package/dist/server/app.js +3 -3
- package/dist/server/app.js.map +1 -1
- package/dist/server/index.d.ts +2 -2
- package/dist/server/index.js +2 -2
- package/dist/server/index.js.map +1 -1
- package/dist/server/rest/auth.d.ts +1 -1
- package/dist/server/rest/auth.js +3 -3
- package/dist/server/rest/auth.js.map +1 -1
- package/dist/server/rest/context.d.ts +2 -2
- package/dist/server/rest/forward.d.ts +2 -2
- package/dist/server/session/store.d.ts +3 -3
- package/dist/server/session/store.js +4 -4
- package/dist/server/session/store.js.map +1 -1
- package/dist/server/stub-client/scenarios.js +8 -8
- package/dist/server/stub-client/scenarios.js.map +1 -1
- package/dist/server/types.d.ts +11 -11
- package/dist/server/types.js +9 -9
- package/dist/server/types.js.map +1 -1
- package/dist/server/ws/hub.d.ts +8 -8
- package/dist/server/ws/hub.js +13 -13
- package/dist/server/ws/hub.js.map +1 -1
- package/dist/server/ws/rpc.d.ts +3 -3
- package/dist/server/ws/rpc.js +4 -4
- package/dist/server/ws/rpc.js.map +1 -1
- package/dist/transport/index.d.ts +1 -1
- package/dist/transport/index.js +3 -3
- package/dist/transport/index.js.map +1 -1
- package/dist/transport/rest.js +1 -1
- package/dist/transport/rest.js.map +1 -1
- package/docs/INSTALL.zh-CN.md +2 -3
- package/package.json +1 -1
- package/skills/uco-setup/SKILL.md +1 -1
- package/skills/unity-editor/references/diagnostics.md +24 -24
- package/vendor/plugin/com.atelierai.unity.copilot/Editor/DependencyResolver/NuGetConfig.cs +132 -132
- package/vendor/plugin/com.atelierai.unity.copilot/Editor/DependencyResolver/NuGetDependencyResolver.cs +237 -237
- package/vendor/plugin/com.atelierai.unity.copilot/Editor/DependencyResolver/NuGetDownloader.cs +82 -82
- package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/API/Resource/MenuItems.cs +247 -247
- package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/API/Resource/ToolGroups.cs +153 -153
- package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/API/SystemTool/Skills.Create.SkillBody.cs +155 -155
- package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/API/Tool/Console.GetLogs.cs +95 -95
- package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/API/Tool/Docs.HttpFetcher.cs +139 -139
- package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/API/Tool/Instance.ListAll.cs +72 -72
- package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/API/Tool/PathReadHelper.cs +106 -106
- package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/API/Tool/Script.Validate.cs +252 -252
- package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/API/Tool/Tests/TestResultCollector.cs +537 -537
- package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/API/Tool/Tests.cs +400 -400
- package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/Branding/ProductInfo.cs +62 -62
- package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/CopilotServerManager.cs +1034 -1034
- package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/Skills/Skill_InitialSetup.cs +197 -197
- package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/Startup.Editor.cs +201 -201
- package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/Startup.cs +67 -67
- package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/UI/Components/ExtensionPanel.cs +379 -379
- package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/UI/MenuItems.cs +72 -72
- package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/UI/UnityCopilotProjectSettingsProvider.cs +64 -64
- package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/UI/Window/CopilotListWindowBase.cs +393 -393
- package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/UI/Window/CopilotWindowBase.cs +113 -113
- package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/UI/Window/MainWindowEditor.Connection.cs +3 -3
- package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/UI/Window/MainWindowEditor.CopilotFeatures.cs +195 -195
- package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/UI/Window/MainWindowEditor.CopilotServer.cs +372 -372
- package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/UI/Window/MainWindowEditor.CreateGUI.cs +354 -354
- package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/UI/Window/MainWindowEditor.cs +78 -78
- package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/UI/Window/MainWindowInitializer.cs +47 -47
- package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/UI/Window/SerializationCheckWindow.cs +190 -190
- package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/UnityCopilotPluginEditor.Build.cs +91 -91
- package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/UnityCopilotPluginEditor.Config.cs +298 -298
- package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/UnityCopilotPluginEditor.Static.cs +296 -296
- package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/UnityCopilotPluginEditor.cs +69 -69
- package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/Utils/PackageUtils.cs +168 -168
- package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/Utils/PrefsKeyMigration.cs +119 -119
- package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/Utils/SafeDefaultsGuard.cs +180 -180
- package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/Utils/ScriptUtils.cs +229 -229
- package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/Utils/ToolsManifestGenerator.cs +200 -200
- package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/Utils/UnityAuthoringAdapters.cs +1467 -1467
- package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/Utils/UnityAuthoringSafetyReloadGuard.cs +65 -65
- package/vendor/plugin/com.atelierai.unity.copilot/Editor/Scripts/Utils/UnityCopilotUpdateProjectSettings.cs +66 -66
- package/vendor/plugin/com.atelierai.unity.copilot/Plugins/ReflectorNet.dll +0 -0
- package/vendor/plugin/com.atelierai.unity.copilot/Plugins/Uco.Framework.Common.dll +0 -0
- package/vendor/plugin/com.atelierai.unity.copilot/Plugins/Uco.Framework.dll +0 -0
- package/vendor/plugin/com.atelierai.unity.copilot/Runtime/Converter/Json/Structures/EntityIdConverter.cs +120 -120
- package/vendor/plugin/com.atelierai.unity.copilot/Runtime/Data/GameObjectMetadata.cs +110 -110
- package/vendor/plugin/com.atelierai.unity.copilot/Runtime/Data/GameObjectMetadata.pre-Unity.6.5.cs +110 -110
- package/vendor/plugin/com.atelierai.unity.copilot/Runtime/Unity/Logs/FileLogStorage.cs +547 -547
- package/vendor/plugin/com.atelierai.unity.copilot/Runtime/UnityCopilotPlugin.Build.cs +243 -243
- package/vendor/plugin/com.atelierai.unity.copilot/Runtime/UnityCopilotPlugin.Config.cs +175 -175
- package/vendor/plugin/com.atelierai.unity.copilot/Runtime/UnityCopilotPlugin.cs +295 -295
- package/vendor/plugin/com.atelierai.unity.copilot/Runtime/UnityCopilotPluginBuilder.cs +105 -105
- package/vendor/plugin/com.atelierai.unity.copilot/Runtime/UnityCopilotPluginRuntime.Static.cs +155 -155
- package/vendor/plugin/com.atelierai.unity.copilot/Runtime/UnityCopilotPluginRuntime.cs +59 -59
- package/vendor/plugin/com.atelierai.unity.copilot/Runtime/Utils/EnvironmentUtils.cs +368 -368
- package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/AtomicApi/AtomicApiTestFixtures.cs +99 -99
- package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/AtomicApi/TryModifyAtTests.cs +227 -227
- package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/AuthoringSafetyPilotTests.cs +1050 -1050
- package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/DependencyResolver/NuGetLegacyMigrationTests.cs +304 -304
- package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/Environment/EnvironmentUtilsTests.cs +4 -4
- package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/ReflectionConverter/BlacklistTypeTests.cs +416 -416
- package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/ReflectionConverter/DataFieldScriptableObjectPopulationTests.cs +172 -172
- package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/ReflectionConverter/DataFieldScriptableObjectPopulationTests.pre-Unity.6.5.cs +169 -169
- package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/ReflectionConverter/DataPopulationTests.cs +182 -182
- package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/ReflectionConverter/DataPopulationTests.pre-Unity.6.5.cs +179 -179
- package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/ReflectionConverter/DataPropertyPopulationTests.cs +175 -175
- package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/ReflectionConverter/DataPropertyPopulationTests.pre-Unity.6.5.cs +174 -174
- package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/ReflectionConverter/DataPropertyScriptableObjectPopulationTests.cs +171 -171
- package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/ReflectionConverter/DataPropertyScriptableObjectPopulationTests.pre-Unity.6.5.cs +170 -170
- package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/Tool/Assets/AssetsCreateFolderTests.cs +243 -243
- package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/Tool/Assets/AssetsMaterialTests.cs +101 -101
- package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/Tool/Assets/AssetsPrefabCreateTests.cs +348 -348
- package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/Tool/Assets/AssetsPrefabCreateTests.pre-Unity.6.5.cs +348 -348
- package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/Tool/Assets/AssetsShaderTests.cs +194 -194
- package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/Tool/PathBasedToolTests.cs +573 -573
- package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/Tool/PathBasedToolTests.pre-Unity.6.5.cs +513 -513
- package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/Tool/Screenshot/ScreenshotCameraTests.cs +154 -154
- package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/Tool/Screenshot/ScreenshotCameraTests.pre-Unity.6.5.cs +154 -154
- package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/Tool/Screenshot/ScreenshotGameViewTests.cs +164 -164
- package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/Tool/Screenshot/ScreenshotSceneViewTests.cs +155 -155
- package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/Tool/ToolParameterTests.cs +56 -56
- package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/Tool/ToolThreadSafetyTests.cs +651 -651
- package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/Tool/ToolThreadSafetyTests.pre-Unity.6.5.cs +651 -651
- package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/ToolBatchExecutionIntegrationTests.cs +407 -407
- package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/{McpPluginTests.cs → UcoPluginTests.cs} +105 -105
- package/vendor/plugin/com.atelierai.unity.copilot/package.json +1 -1
- package/dist/commands/devops/login.d.ts +0 -2
- package/dist/commands/devops/login.js +0 -29
- package/dist/commands/devops/login.js.map +0 -1
- package/dist/commands/devops/setup-mcp.d.ts +0 -2
- package/dist/commands/devops/setup-mcp.js +0 -41
- package/dist/commands/devops/setup-mcp.js.map +0 -1
- package/dist/devops/commands-upstream/bootstrap-local.d.ts +0 -17
- package/dist/devops/commands-upstream/bootstrap-local.js +0 -87
- package/dist/devops/commands-upstream/bootstrap-local.js.map +0 -1
- package/dist/devops/commands-upstream/close.d.ts +0 -57
- package/dist/devops/commands-upstream/close.js +0 -188
- package/dist/devops/commands-upstream/close.js.map +0 -1
- package/dist/devops/commands-upstream/configure.d.ts +0 -2
- package/dist/devops/commands-upstream/configure.js +0 -87
- package/dist/devops/commands-upstream/configure.js.map +0 -1
- package/dist/devops/commands-upstream/create-project.d.ts +0 -2
- package/dist/devops/commands-upstream/create-project.js +0 -43
- package/dist/devops/commands-upstream/create-project.js.map +0 -1
- package/dist/devops/commands-upstream/install-plugin.d.ts +0 -2
- package/dist/devops/commands-upstream/install-plugin.js +0 -64
- package/dist/devops/commands-upstream/install-plugin.js.map +0 -1
- package/dist/devops/commands-upstream/install-unity.d.ts +0 -2
- package/dist/devops/commands-upstream/install-unity.js +0 -72
- package/dist/devops/commands-upstream/install-unity.js.map +0 -1
- package/dist/devops/commands-upstream/login.d.ts +0 -2
- package/dist/devops/commands-upstream/login.js +0 -33
- package/dist/devops/commands-upstream/login.js.map +0 -1
- package/dist/devops/commands-upstream/open.d.ts +0 -32
- package/dist/devops/commands-upstream/open.js +0 -282
- package/dist/devops/commands-upstream/open.js.map +0 -1
- package/dist/devops/commands-upstream/remove-plugin.d.ts +0 -2
- package/dist/devops/commands-upstream/remove-plugin.js +0 -41
- package/dist/devops/commands-upstream/remove-plugin.js.map +0 -1
- package/dist/devops/commands-upstream/run-system-tool.d.ts +0 -1
- package/dist/devops/commands-upstream/run-system-tool.js +0 -13
- package/dist/devops/commands-upstream/run-system-tool.js.map +0 -1
- package/dist/devops/commands-upstream/run-tool-builder.d.ts +0 -25
- package/dist/devops/commands-upstream/run-tool-builder.js +0 -125
- package/dist/devops/commands-upstream/run-tool-builder.js.map +0 -1
- package/dist/devops/commands-upstream/run-tool.d.ts +0 -1
- package/dist/devops/commands-upstream/run-tool.js +0 -13
- package/dist/devops/commands-upstream/run-tool.js.map +0 -1
- package/dist/devops/commands-upstream/setup-mcp.d.ts +0 -2
- package/dist/devops/commands-upstream/setup-mcp.js +0 -68
- package/dist/devops/commands-upstream/setup-mcp.js.map +0 -1
- package/dist/devops/commands-upstream/setup-skills.d.ts +0 -2
- package/dist/devops/commands-upstream/setup-skills.js +0 -167
- package/dist/devops/commands-upstream/setup-skills.js.map +0 -1
- package/dist/devops/commands-upstream/status.d.ts +0 -2
- package/dist/devops/commands-upstream/status.js +0 -87
- package/dist/devops/commands-upstream/status.js.map +0 -1
- package/dist/devops/commands-upstream/update.d.ts +0 -2
- package/dist/devops/commands-upstream/update.js +0 -77
- package/dist/devops/commands-upstream/update.js.map +0 -1
- package/dist/devops/commands-upstream/wait-for-ready.d.ts +0 -2
- package/dist/devops/commands-upstream/wait-for-ready.js +0 -93
- package/dist/devops/commands-upstream/wait-for-ready.js.map +0 -1
- package/dist/devops/lib/setup-mcp.d.ts +0 -35
- package/dist/devops/lib/setup-mcp.js +0 -177
- package/dist/devops/lib/setup-mcp.js.map +0 -1
- package/dist/devops/utils/cloud-login.d.ts +0 -7
- package/dist/devops/utils/cloud-login.js +0 -56
- package/dist/devops/utils/cloud-login.js.map +0 -1
- /package/vendor/plugin/com.atelierai.unity.copilot/Tests/Editor/{McpPluginTests.cs.meta → UcoPluginTests.cs.meta} +0 -0
|
@@ -1,372 +1,372 @@
|
|
|
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;
|
|
13
|
-
using System.Threading;
|
|
14
|
-
using com.AtelierAI.Uco.Framework.Common.Model;
|
|
15
|
-
using com.AtelierAI.Uco.Framework.Common.Utils;
|
|
16
|
-
using com.IvanMurzak.ReflectorNet.Utils;
|
|
17
|
-
using com.AtelierAI.Unity.Copilot.Editor.UI.Controls;
|
|
18
|
-
using Microsoft.Extensions.Logging;
|
|
19
|
-
using R3;
|
|
20
|
-
using UnityEngine;
|
|
21
|
-
using UnityEngine.UIElements;
|
|
22
|
-
using static com.AtelierAI.Uco.Framework.Common.Consts.
|
|
23
|
-
|
|
24
|
-
namespace com.AtelierAI.Unity.Copilot.Editor.UI
|
|
25
|
-
{
|
|
26
|
-
public partial class MainWindowEditor
|
|
27
|
-
{
|
|
28
|
-
private void
|
|
29
|
-
{
|
|
30
|
-
var btnStartStop = root.Q<Button>("btnStartStopServer") ?? throw new InvalidOperationException("Server start/stop button not found.");
|
|
31
|
-
var statusCircle = root.Q<VisualElement>("mcpServerStatusCircle") ?? throw new InvalidOperationException("Server status circle not found.");
|
|
32
|
-
var statusLabel = root.Q<Label>("mcpServerLabel") ?? throw new InvalidOperationException("Server status label not found.");
|
|
33
|
-
|
|
34
|
-
var
|
|
35
|
-
if (
|
|
36
|
-
|
|
37
|
-
statusCircle.tooltip =
|
|
38
|
-
statusLabel.tooltip =
|
|
39
|
-
|
|
40
|
-
Observable.CombineLatest(
|
|
41
|
-
source1: CopilotServerManager.ServerStatus,
|
|
42
|
-
source2: UnityCopilotPluginEditor.IsConnected,
|
|
43
|
-
resultSelector: CombineCopilotServerStatus)
|
|
44
|
-
.ThrottleLast(TimeSpan.FromMilliseconds(50))
|
|
45
|
-
.ObserveOnCurrentSynchronizationContext()
|
|
46
|
-
.Subscribe(status =>
|
|
47
|
-
.AddTo(_disposables);
|
|
48
|
-
|
|
49
|
-
btnStartStop.RegisterCallback<ClickEvent>(evt => HandleServerButton(btnStartStop, statusLabel));
|
|
50
|
-
|
|
51
|
-
// server authorization configuration UI elements
|
|
52
|
-
var labelAuthorizationToken = root.Q<Label>("labelAuthorizationToken");
|
|
53
|
-
var segmentAuthorization = root.Q<VisualElement>("segmentAuthorization");
|
|
54
|
-
var inputAuthorizationToken = root.Q<TextField>("inputAuthorizationToken");
|
|
55
|
-
var tokenSection = root.Q<VisualElement>("tokenSection");
|
|
56
|
-
var btnGenerateToken = root.Q<Button>("btnGenerateToken");
|
|
57
|
-
|
|
58
|
-
if (segmentAuthorization == null || inputAuthorizationToken == null
|
|
59
|
-
|| tokenSection == null || btnGenerateToken == null)
|
|
60
|
-
{
|
|
61
|
-
Debug.LogError("One or more authorization UI elements not found in UXML: " +
|
|
62
|
-
$"segmentAuthorization={segmentAuthorization != null}, " +
|
|
63
|
-
$"inputAuthorizationToken={inputAuthorizationToken != null}, " +
|
|
64
|
-
$"tokenSection={tokenSection != null}, " +
|
|
65
|
-
$"btnGenerateToken={btnGenerateToken != null}");
|
|
66
|
-
return;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
var authControl = new SegmentedControl("none", "required");
|
|
70
|
-
authControl.SetTooltips(Tooltip_ToggleAuthNone, Tooltip_ToggleAuthRequired);
|
|
71
|
-
segmentAuthorization.Add(authControl);
|
|
72
|
-
|
|
73
|
-
inputAuthorizationToken.isPasswordField = true;
|
|
74
|
-
inputAuthorizationToken.RegisterCallback<KeyDownEvent>(evt =>
|
|
75
|
-
{
|
|
76
|
-
if (evt.keyCode == KeyCode.C && (evt.ctrlKey || evt.commandKey))
|
|
77
|
-
{
|
|
78
|
-
GUIUtility.systemCopyBuffer = inputAuthorizationToken.value;
|
|
79
|
-
evt.StopPropagation();
|
|
80
|
-
}
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
if (labelAuthorizationToken != null) labelAuthorizationToken.tooltip = Tooltip_LabelAuthorizationToken;
|
|
84
|
-
btnGenerateToken.tooltip = Tooltip_BtnGenerateToken;
|
|
85
|
-
|
|
86
|
-
var authOption = UnityCopilotPluginEditor.AuthOption;
|
|
87
|
-
authControl.SetValueWithoutNotify(authOption == AuthOption.none ? 0 : 1);
|
|
88
|
-
inputAuthorizationToken.SetValueWithoutNotify(UnityCopilotPluginEditor.Token ?? string.Empty);
|
|
89
|
-
SetTokenFieldsVisible(inputAuthorizationToken, tokenSection, authOption == AuthOption.required);
|
|
90
|
-
|
|
91
|
-
authControl.RegisterCallback<ChangeEvent<int>>(evt =>
|
|
92
|
-
{
|
|
93
|
-
if (evt.newValue == 0)
|
|
94
|
-
{
|
|
95
|
-
ApplyServerSettingAndRestart(() =>
|
|
96
|
-
{
|
|
97
|
-
UnityCopilotPluginEditor.AuthOption = AuthOption.none;
|
|
98
|
-
});
|
|
99
|
-
SetTokenFieldsVisible(inputAuthorizationToken, tokenSection, false);
|
|
100
|
-
}
|
|
101
|
-
else
|
|
102
|
-
{
|
|
103
|
-
ApplyServerSettingAndRestart(() =>
|
|
104
|
-
{
|
|
105
|
-
UnityCopilotPluginEditor.AuthOption = AuthOption.required;
|
|
106
|
-
});
|
|
107
|
-
SetTokenFieldsVisible(inputAuthorizationToken, tokenSection, true);
|
|
108
|
-
}
|
|
109
|
-
});
|
|
110
|
-
|
|
111
|
-
inputAuthorizationToken.RegisterCallback<FocusOutEvent>(_ =>
|
|
112
|
-
{
|
|
113
|
-
var newToken = inputAuthorizationToken.value;
|
|
114
|
-
if (newToken == UnityCopilotPluginEditor.Token)
|
|
115
|
-
return;
|
|
116
|
-
|
|
117
|
-
ApplyServerSettingAndRestart(() =>
|
|
118
|
-
{
|
|
119
|
-
UnityCopilotPluginEditor.Token = newToken;
|
|
120
|
-
});
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
btnGenerateToken.RegisterCallback<ClickEvent>(_ =>
|
|
124
|
-
{
|
|
125
|
-
var newToken = UnityCopilotPlugin.GenerateToken();
|
|
126
|
-
inputAuthorizationToken.SetValueWithoutNotify(newToken);
|
|
127
|
-
|
|
128
|
-
ApplyServerSettingAndRestart(() =>
|
|
129
|
-
{
|
|
130
|
-
UnityCopilotPluginEditor.Token = newToken;
|
|
131
|
-
});
|
|
132
|
-
});
|
|
133
|
-
|
|
134
|
-
// ── Network Safety (fail-closed by default) ─────────────────────────────
|
|
135
|
-
// Build the UI programmatically and append it to the same flex column that
|
|
136
|
-
// hosts tokenSection so we don't have to introduce a new UXML asset. The
|
|
137
|
-
// three toggles map 1:1 to the static properties on UnityCopilotPluginEditor;
|
|
138
|
-
// each change is persisted immediately so the next StartServer() call sees
|
|
139
|
-
// the new state.
|
|
140
|
-
BuildNetworkSafetySection(tokenSection.parent);
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
private static void BuildNetworkSafetySection(VisualElement parent)
|
|
144
|
-
{
|
|
145
|
-
if (parent == null) return;
|
|
146
|
-
// If a previous CreateGUI cycle already added the section, recreate it idempotently
|
|
147
|
-
// so the toggles always reflect the current persisted state.
|
|
148
|
-
var existing = parent.Q<VisualElement>("networkSafetySection");
|
|
149
|
-
if (existing != null) parent.Remove(existing);
|
|
150
|
-
|
|
151
|
-
var section = new VisualElement { name = "networkSafetySection" };
|
|
152
|
-
section.style.flexDirection = FlexDirection.Column;
|
|
153
|
-
section.style.marginTop = 4;
|
|
154
|
-
section.style.marginBottom = 2;
|
|
155
|
-
|
|
156
|
-
var header = new Label("Network Safety");
|
|
157
|
-
header.AddToClassList("section-desc");
|
|
158
|
-
header.style.marginBottom = 2;
|
|
159
|
-
header.tooltip =
|
|
160
|
-
"Fail-closed defaults: by default the server only binds to localhost and " +
|
|
161
|
-
"refuses to start on a non-loopback URL until you opt in here. Existing " +
|
|
162
|
-
"configurations that already used a LAN address before this update were " +
|
|
163
|
-
"auto-granted on first load so behaviour is preserved — a one-time warning " +
|
|
164
|
-
"is written to the Editor console.";
|
|
165
|
-
section.Add(header);
|
|
166
|
-
|
|
167
|
-
var toggleAllowLan = new Toggle("Allow LAN Bind (HTTP)")
|
|
168
|
-
{
|
|
169
|
-
value = UnityCopilotPluginEditor.AllowLanBind,
|
|
170
|
-
tooltip =
|
|
171
|
-
"When OFF (safe default): the plugin refuses to start the server if " +
|
|
172
|
-
"the Server URL points at 0.0.0.0, ::, or a non-loopback IP/hostname.\n\n" +
|
|
173
|
-
"When ON: the plugin will start the server bound to whatever interface the " +
|
|
174
|
-
"Server URL specifies. Other machines on your network may be able to reach " +
|
|
175
|
-
"the server. Always pair this with a strong token."
|
|
176
|
-
};
|
|
177
|
-
toggleAllowLan.RegisterValueChangedCallback(evt =>
|
|
178
|
-
{
|
|
179
|
-
UnityCopilotPluginEditor.AllowLanBind = evt.newValue;
|
|
180
|
-
UnityCopilotPluginEditor.Instance.Save();
|
|
181
|
-
});
|
|
182
|
-
section.Add(toggleAllowLan);
|
|
183
|
-
|
|
184
|
-
var toggleAllowInsecure = new Toggle("Allow Insecure Remote HTTP")
|
|
185
|
-
{
|
|
186
|
-
value = UnityCopilotPluginEditor.AllowInsecureRemoteHttp,
|
|
187
|
-
tooltip =
|
|
188
|
-
"When OFF (safe default): the plugin logs a warning every time it emits an " +
|
|
189
|
-
"AI-agent client configuration that points at a remote host over plain " +
|
|
190
|
-
"http:// (no TLS).\n\n" +
|
|
191
|
-
"When ON: the warning is silenced. Tokens and tool payloads sent over " +
|
|
192
|
-
"plain HTTP are visible to anyone sniffing the network — only enable this " +
|
|
193
|
-
"for trusted local networks where TLS is not available."
|
|
194
|
-
};
|
|
195
|
-
toggleAllowInsecure.RegisterValueChangedCallback(evt =>
|
|
196
|
-
{
|
|
197
|
-
UnityCopilotPluginEditor.AllowInsecureRemoteHttp = evt.newValue;
|
|
198
|
-
UnityCopilotPluginEditor.Instance.Save();
|
|
199
|
-
});
|
|
200
|
-
section.Add(toggleAllowInsecure);
|
|
201
|
-
|
|
202
|
-
var toggleForceToken = new Toggle("Force Token When LAN Bind")
|
|
203
|
-
{
|
|
204
|
-
value = UnityCopilotPluginEditor.ForceTokenWhenLanBind,
|
|
205
|
-
tooltip =
|
|
206
|
-
"When ON (safe default): enabling 'Allow LAN Bind' is not enough to start " +
|
|
207
|
-
"the server — you must also set Authorization to 'required' and have a " +
|
|
208
|
-
"non-empty token. Prevents accidental exposure of an unauthenticated " +
|
|
209
|
-
"endpoint to the LAN.\n\n" +
|
|
210
|
-
"When OFF: LAN-bound servers may run with auth=none. Not recommended."
|
|
211
|
-
};
|
|
212
|
-
toggleForceToken.RegisterValueChangedCallback(evt =>
|
|
213
|
-
{
|
|
214
|
-
UnityCopilotPluginEditor.ForceTokenWhenLanBind = evt.newValue;
|
|
215
|
-
UnityCopilotPluginEditor.Instance.Save();
|
|
216
|
-
});
|
|
217
|
-
section.Add(toggleForceToken);
|
|
218
|
-
|
|
219
|
-
parent.Add(section);
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
private void ApplyServerSettingAndRestart(Action applySetting)
|
|
223
|
-
{
|
|
224
|
-
var wasRunning = CopilotServerManager.IsRunning;
|
|
225
|
-
applySetting();
|
|
226
|
-
UnityCopilotPluginEditor.Instance.Save();
|
|
227
|
-
RestartServerIfWasRunning(wasRunning);
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
internal static CopilotServerStatus CombineCopilotServerStatus(CopilotServerStatus status, bool isConnected)
|
|
231
|
-
{
|
|
232
|
-
if (isConnected && status != CopilotServerStatus.Running)
|
|
233
|
-
return CopilotServerStatus.External;
|
|
234
|
-
|
|
235
|
-
return status;
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
internal static string GetServerButtonText(CopilotServerStatus status) => status switch
|
|
239
|
-
{
|
|
240
|
-
CopilotServerStatus.Running => "Stop",
|
|
241
|
-
CopilotServerStatus.Starting => "Starting...",
|
|
242
|
-
CopilotServerStatus.Stopping => "Stopping...",
|
|
243
|
-
CopilotServerStatus.External => "External",
|
|
244
|
-
_ => "Start"
|
|
245
|
-
};
|
|
246
|
-
|
|
247
|
-
// The Node.js server exposes a single HTTP transport (REST + WebSocket), so the
|
|
248
|
-
// status label no longer carries a transport-mode suffix.
|
|
249
|
-
internal static string GetServerLabelText(CopilotServerStatus status) => status switch
|
|
250
|
-
{
|
|
251
|
-
CopilotServerStatus.Running => "Server: Running",
|
|
252
|
-
CopilotServerStatus.Starting => "Server: Starting...",
|
|
253
|
-
CopilotServerStatus.Stopping => "Server: Stopping...",
|
|
254
|
-
CopilotServerStatus.External => "Server: External",
|
|
255
|
-
_ => "Server"
|
|
256
|
-
};
|
|
257
|
-
|
|
258
|
-
internal static string GetServerStatusClass(CopilotServerStatus status) => status switch
|
|
259
|
-
{
|
|
260
|
-
CopilotServerStatus.Running => USS_Connected,
|
|
261
|
-
CopilotServerStatus.Starting or CopilotServerStatus.Stopping => USS_Connecting,
|
|
262
|
-
CopilotServerStatus.External => USS_External,
|
|
263
|
-
_ => USS_Disconnected
|
|
264
|
-
};
|
|
265
|
-
|
|
266
|
-
internal static bool IsServerButtonEnabled(CopilotServerStatus status) =>
|
|
267
|
-
status == CopilotServerStatus.Running || status == CopilotServerStatus.Stopped;
|
|
268
|
-
|
|
269
|
-
private static void HandleServerButton(Button btnStartStop, Label statusLabel)
|
|
270
|
-
{
|
|
271
|
-
// Disable button immediately to prevent double-clicks
|
|
272
|
-
btnStartStop.SetEnabled(false);
|
|
273
|
-
|
|
274
|
-
try
|
|
275
|
-
{
|
|
276
|
-
if (CopilotServerManager.IsRunning)
|
|
277
|
-
{
|
|
278
|
-
// User is stopping the server - remember not to auto-start
|
|
279
|
-
UnityCopilotPluginEditor.KeepServerRunning = false;
|
|
280
|
-
UnityCopilotPluginEditor.Instance.Save();
|
|
281
|
-
statusLabel.text = "Server: Stopping...";
|
|
282
|
-
CopilotServerManager.StopServer();
|
|
283
|
-
}
|
|
284
|
-
else
|
|
285
|
-
{
|
|
286
|
-
// User is starting the server - remember to auto-start
|
|
287
|
-
UnityCopilotPluginEditor.KeepServerRunning = true;
|
|
288
|
-
UnityCopilotPluginEditor.Instance.Save();
|
|
289
|
-
statusLabel.text = "Server: Starting...";
|
|
290
|
-
CopilotServerManager.StartServer();
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
catch
|
|
294
|
-
{
|
|
295
|
-
// Re-enable button on exception to avoid infinite lock
|
|
296
|
-
btnStartStop.SetEnabled(true);
|
|
297
|
-
throw;
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
private long
|
|
302
|
-
{
|
|
303
|
-
var version = Interlocked.Increment(ref
|
|
304
|
-
if (Logger.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Trace))
|
|
305
|
-
Logger.LogTrace("Setting server data: {status}, Data: {data}", status, data?.ToPrettyJson() ?? "null");
|
|
306
|
-
|
|
307
|
-
btnStartStop.text = GetServerButtonText(status);
|
|
308
|
-
var isStart = status == CopilotServerStatus.Stopped;
|
|
309
|
-
btnStartStop.EnableInClassList("btn-primary", isStart);
|
|
310
|
-
btnStartStop.EnableInClassList("btn-secondary", !isStart);
|
|
311
|
-
btnStartStop.SetEnabled(IsServerButtonEnabled(status));
|
|
312
|
-
statusLabel.text = GetServerLabelText(status);
|
|
313
|
-
SetStatusIndicator(statusCircle, GetServerStatusClass(status));
|
|
314
|
-
return version;
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
private void
|
|
318
|
-
{
|
|
319
|
-
// Update UI immediately with current status; capture the version atomically so that
|
|
320
|
-
// the async result can detect if a newer update has superseded it.
|
|
321
|
-
var fetchVersion =
|
|
322
|
-
|
|
323
|
-
// Then try to fetch additional data asynchronously
|
|
324
|
-
var
|
|
325
|
-
if (
|
|
326
|
-
{
|
|
327
|
-
Logger.LogDebug("Cannot fetch server data: UcoPluginInstance is null");
|
|
328
|
-
return;
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
var
|
|
332
|
-
if (
|
|
333
|
-
{
|
|
334
|
-
Logger.LogDebug("Cannot fetch server data: UcoManagerHub is null");
|
|
335
|
-
return;
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
var task =
|
|
339
|
-
if (task == null)
|
|
340
|
-
{
|
|
341
|
-
Logger.LogDebug("Cannot fetch server data:
|
|
342
|
-
return;
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
task.ContinueWith(t =>
|
|
346
|
-
{
|
|
347
|
-
if (Interlocked.Read(ref
|
|
348
|
-
{
|
|
349
|
-
Logger.LogTrace("Skipping server data update because a newer update was applied at {time}",
|
|
350
|
-
DateTime.UtcNow);
|
|
351
|
-
return;
|
|
352
|
-
}
|
|
353
|
-
MainThread.Instance.Run(() =>
|
|
354
|
-
{
|
|
355
|
-
// Second check: close the TOCTOU window between the thread-pool check above
|
|
356
|
-
// and the main-thread callback execution.
|
|
357
|
-
if (Interlocked.Read(ref
|
|
358
|
-
return;
|
|
359
|
-
if (t.IsCompletedSuccessfully)
|
|
360
|
-
{
|
|
361
|
-
var data = t.Result;
|
|
362
|
-
|
|
363
|
-
}
|
|
364
|
-
else if (t.IsFaulted)
|
|
365
|
-
{
|
|
366
|
-
Logger.LogDebug("Failed to fetch server data: {error}", t.Exception?.Message ?? "Unknown error");
|
|
367
|
-
}
|
|
368
|
-
});
|
|
369
|
-
});
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
|
-
}
|
|
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;
|
|
13
|
+
using System.Threading;
|
|
14
|
+
using com.AtelierAI.Uco.Framework.Common.Model;
|
|
15
|
+
using com.AtelierAI.Uco.Framework.Common.Utils;
|
|
16
|
+
using com.IvanMurzak.ReflectorNet.Utils;
|
|
17
|
+
using com.AtelierAI.Unity.Copilot.Editor.UI.Controls;
|
|
18
|
+
using Microsoft.Extensions.Logging;
|
|
19
|
+
using R3;
|
|
20
|
+
using UnityEngine;
|
|
21
|
+
using UnityEngine.UIElements;
|
|
22
|
+
using static com.AtelierAI.Uco.Framework.Common.Consts.Uco.Server;
|
|
23
|
+
|
|
24
|
+
namespace com.AtelierAI.Unity.Copilot.Editor.UI
|
|
25
|
+
{
|
|
26
|
+
public partial class MainWindowEditor
|
|
27
|
+
{
|
|
28
|
+
private void SetupServerSection(VisualElement root)
|
|
29
|
+
{
|
|
30
|
+
var btnStartStop = root.Q<Button>("btnStartStopServer") ?? throw new InvalidOperationException("Server start/stop button not found.");
|
|
31
|
+
var statusCircle = root.Q<VisualElement>("mcpServerStatusCircle") ?? throw new InvalidOperationException("Server status circle not found.");
|
|
32
|
+
var statusLabel = root.Q<Label>("mcpServerLabel") ?? throw new InvalidOperationException("Server status label not found.");
|
|
33
|
+
|
|
34
|
+
var timelinePointServer = root.Q<VisualElement>("TimelinePointMcpServer");
|
|
35
|
+
if (timelinePointServer != null)
|
|
36
|
+
timelinePointServer.tooltip = Tooltip_ServerTimelineLabel;
|
|
37
|
+
statusCircle.tooltip = Tooltip_ServerTimelineLabel;
|
|
38
|
+
statusLabel.tooltip = Tooltip_ServerTimelineLabel;
|
|
39
|
+
|
|
40
|
+
Observable.CombineLatest(
|
|
41
|
+
source1: CopilotServerManager.ServerStatus,
|
|
42
|
+
source2: UnityCopilotPluginEditor.IsConnected,
|
|
43
|
+
resultSelector: CombineCopilotServerStatus)
|
|
44
|
+
.ThrottleLast(TimeSpan.FromMilliseconds(50))
|
|
45
|
+
.ObserveOnCurrentSynchronizationContext()
|
|
46
|
+
.Subscribe(status => FetchServerData(status, btnStartStop, statusCircle, statusLabel))
|
|
47
|
+
.AddTo(_disposables);
|
|
48
|
+
|
|
49
|
+
btnStartStop.RegisterCallback<ClickEvent>(evt => HandleServerButton(btnStartStop, statusLabel));
|
|
50
|
+
|
|
51
|
+
// server authorization configuration UI elements
|
|
52
|
+
var labelAuthorizationToken = root.Q<Label>("labelAuthorizationToken");
|
|
53
|
+
var segmentAuthorization = root.Q<VisualElement>("segmentAuthorization");
|
|
54
|
+
var inputAuthorizationToken = root.Q<TextField>("inputAuthorizationToken");
|
|
55
|
+
var tokenSection = root.Q<VisualElement>("tokenSection");
|
|
56
|
+
var btnGenerateToken = root.Q<Button>("btnGenerateToken");
|
|
57
|
+
|
|
58
|
+
if (segmentAuthorization == null || inputAuthorizationToken == null
|
|
59
|
+
|| tokenSection == null || btnGenerateToken == null)
|
|
60
|
+
{
|
|
61
|
+
Debug.LogError("One or more authorization UI elements not found in UXML: " +
|
|
62
|
+
$"segmentAuthorization={segmentAuthorization != null}, " +
|
|
63
|
+
$"inputAuthorizationToken={inputAuthorizationToken != null}, " +
|
|
64
|
+
$"tokenSection={tokenSection != null}, " +
|
|
65
|
+
$"btnGenerateToken={btnGenerateToken != null}");
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
var authControl = new SegmentedControl("none", "required");
|
|
70
|
+
authControl.SetTooltips(Tooltip_ToggleAuthNone, Tooltip_ToggleAuthRequired);
|
|
71
|
+
segmentAuthorization.Add(authControl);
|
|
72
|
+
|
|
73
|
+
inputAuthorizationToken.isPasswordField = true;
|
|
74
|
+
inputAuthorizationToken.RegisterCallback<KeyDownEvent>(evt =>
|
|
75
|
+
{
|
|
76
|
+
if (evt.keyCode == KeyCode.C && (evt.ctrlKey || evt.commandKey))
|
|
77
|
+
{
|
|
78
|
+
GUIUtility.systemCopyBuffer = inputAuthorizationToken.value;
|
|
79
|
+
evt.StopPropagation();
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
if (labelAuthorizationToken != null) labelAuthorizationToken.tooltip = Tooltip_LabelAuthorizationToken;
|
|
84
|
+
btnGenerateToken.tooltip = Tooltip_BtnGenerateToken;
|
|
85
|
+
|
|
86
|
+
var authOption = UnityCopilotPluginEditor.AuthOption;
|
|
87
|
+
authControl.SetValueWithoutNotify(authOption == AuthOption.none ? 0 : 1);
|
|
88
|
+
inputAuthorizationToken.SetValueWithoutNotify(UnityCopilotPluginEditor.Token ?? string.Empty);
|
|
89
|
+
SetTokenFieldsVisible(inputAuthorizationToken, tokenSection, authOption == AuthOption.required);
|
|
90
|
+
|
|
91
|
+
authControl.RegisterCallback<ChangeEvent<int>>(evt =>
|
|
92
|
+
{
|
|
93
|
+
if (evt.newValue == 0)
|
|
94
|
+
{
|
|
95
|
+
ApplyServerSettingAndRestart(() =>
|
|
96
|
+
{
|
|
97
|
+
UnityCopilotPluginEditor.AuthOption = AuthOption.none;
|
|
98
|
+
});
|
|
99
|
+
SetTokenFieldsVisible(inputAuthorizationToken, tokenSection, false);
|
|
100
|
+
}
|
|
101
|
+
else
|
|
102
|
+
{
|
|
103
|
+
ApplyServerSettingAndRestart(() =>
|
|
104
|
+
{
|
|
105
|
+
UnityCopilotPluginEditor.AuthOption = AuthOption.required;
|
|
106
|
+
});
|
|
107
|
+
SetTokenFieldsVisible(inputAuthorizationToken, tokenSection, true);
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
inputAuthorizationToken.RegisterCallback<FocusOutEvent>(_ =>
|
|
112
|
+
{
|
|
113
|
+
var newToken = inputAuthorizationToken.value;
|
|
114
|
+
if (newToken == UnityCopilotPluginEditor.Token)
|
|
115
|
+
return;
|
|
116
|
+
|
|
117
|
+
ApplyServerSettingAndRestart(() =>
|
|
118
|
+
{
|
|
119
|
+
UnityCopilotPluginEditor.Token = newToken;
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
btnGenerateToken.RegisterCallback<ClickEvent>(_ =>
|
|
124
|
+
{
|
|
125
|
+
var newToken = UnityCopilotPlugin.GenerateToken();
|
|
126
|
+
inputAuthorizationToken.SetValueWithoutNotify(newToken);
|
|
127
|
+
|
|
128
|
+
ApplyServerSettingAndRestart(() =>
|
|
129
|
+
{
|
|
130
|
+
UnityCopilotPluginEditor.Token = newToken;
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
// ── Network Safety (fail-closed by default) ─────────────────────────────
|
|
135
|
+
// Build the UI programmatically and append it to the same flex column that
|
|
136
|
+
// hosts tokenSection so we don't have to introduce a new UXML asset. The
|
|
137
|
+
// three toggles map 1:1 to the static properties on UnityCopilotPluginEditor;
|
|
138
|
+
// each change is persisted immediately so the next StartServer() call sees
|
|
139
|
+
// the new state.
|
|
140
|
+
BuildNetworkSafetySection(tokenSection.parent);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
private static void BuildNetworkSafetySection(VisualElement parent)
|
|
144
|
+
{
|
|
145
|
+
if (parent == null) return;
|
|
146
|
+
// If a previous CreateGUI cycle already added the section, recreate it idempotently
|
|
147
|
+
// so the toggles always reflect the current persisted state.
|
|
148
|
+
var existing = parent.Q<VisualElement>("networkSafetySection");
|
|
149
|
+
if (existing != null) parent.Remove(existing);
|
|
150
|
+
|
|
151
|
+
var section = new VisualElement { name = "networkSafetySection" };
|
|
152
|
+
section.style.flexDirection = FlexDirection.Column;
|
|
153
|
+
section.style.marginTop = 4;
|
|
154
|
+
section.style.marginBottom = 2;
|
|
155
|
+
|
|
156
|
+
var header = new Label("Network Safety");
|
|
157
|
+
header.AddToClassList("section-desc");
|
|
158
|
+
header.style.marginBottom = 2;
|
|
159
|
+
header.tooltip =
|
|
160
|
+
"Fail-closed defaults: by default the server only binds to localhost and " +
|
|
161
|
+
"refuses to start on a non-loopback URL until you opt in here. Existing " +
|
|
162
|
+
"configurations that already used a LAN address before this update were " +
|
|
163
|
+
"auto-granted on first load so behaviour is preserved — a one-time warning " +
|
|
164
|
+
"is written to the Editor console.";
|
|
165
|
+
section.Add(header);
|
|
166
|
+
|
|
167
|
+
var toggleAllowLan = new Toggle("Allow LAN Bind (HTTP)")
|
|
168
|
+
{
|
|
169
|
+
value = UnityCopilotPluginEditor.AllowLanBind,
|
|
170
|
+
tooltip =
|
|
171
|
+
"When OFF (safe default): the plugin refuses to start the server if " +
|
|
172
|
+
"the Server URL points at 0.0.0.0, ::, or a non-loopback IP/hostname.\n\n" +
|
|
173
|
+
"When ON: the plugin will start the server bound to whatever interface the " +
|
|
174
|
+
"Server URL specifies. Other machines on your network may be able to reach " +
|
|
175
|
+
"the server. Always pair this with a strong token."
|
|
176
|
+
};
|
|
177
|
+
toggleAllowLan.RegisterValueChangedCallback(evt =>
|
|
178
|
+
{
|
|
179
|
+
UnityCopilotPluginEditor.AllowLanBind = evt.newValue;
|
|
180
|
+
UnityCopilotPluginEditor.Instance.Save();
|
|
181
|
+
});
|
|
182
|
+
section.Add(toggleAllowLan);
|
|
183
|
+
|
|
184
|
+
var toggleAllowInsecure = new Toggle("Allow Insecure Remote HTTP")
|
|
185
|
+
{
|
|
186
|
+
value = UnityCopilotPluginEditor.AllowInsecureRemoteHttp,
|
|
187
|
+
tooltip =
|
|
188
|
+
"When OFF (safe default): the plugin logs a warning every time it emits an " +
|
|
189
|
+
"AI-agent client configuration that points at a remote host over plain " +
|
|
190
|
+
"http:// (no TLS).\n\n" +
|
|
191
|
+
"When ON: the warning is silenced. Tokens and tool payloads sent over " +
|
|
192
|
+
"plain HTTP are visible to anyone sniffing the network — only enable this " +
|
|
193
|
+
"for trusted local networks where TLS is not available."
|
|
194
|
+
};
|
|
195
|
+
toggleAllowInsecure.RegisterValueChangedCallback(evt =>
|
|
196
|
+
{
|
|
197
|
+
UnityCopilotPluginEditor.AllowInsecureRemoteHttp = evt.newValue;
|
|
198
|
+
UnityCopilotPluginEditor.Instance.Save();
|
|
199
|
+
});
|
|
200
|
+
section.Add(toggleAllowInsecure);
|
|
201
|
+
|
|
202
|
+
var toggleForceToken = new Toggle("Force Token When LAN Bind")
|
|
203
|
+
{
|
|
204
|
+
value = UnityCopilotPluginEditor.ForceTokenWhenLanBind,
|
|
205
|
+
tooltip =
|
|
206
|
+
"When ON (safe default): enabling 'Allow LAN Bind' is not enough to start " +
|
|
207
|
+
"the server — you must also set Authorization to 'required' and have a " +
|
|
208
|
+
"non-empty token. Prevents accidental exposure of an unauthenticated " +
|
|
209
|
+
"endpoint to the LAN.\n\n" +
|
|
210
|
+
"When OFF: LAN-bound servers may run with auth=none. Not recommended."
|
|
211
|
+
};
|
|
212
|
+
toggleForceToken.RegisterValueChangedCallback(evt =>
|
|
213
|
+
{
|
|
214
|
+
UnityCopilotPluginEditor.ForceTokenWhenLanBind = evt.newValue;
|
|
215
|
+
UnityCopilotPluginEditor.Instance.Save();
|
|
216
|
+
});
|
|
217
|
+
section.Add(toggleForceToken);
|
|
218
|
+
|
|
219
|
+
parent.Add(section);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
private void ApplyServerSettingAndRestart(Action applySetting)
|
|
223
|
+
{
|
|
224
|
+
var wasRunning = CopilotServerManager.IsRunning;
|
|
225
|
+
applySetting();
|
|
226
|
+
UnityCopilotPluginEditor.Instance.Save();
|
|
227
|
+
RestartServerIfWasRunning(wasRunning);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
internal static CopilotServerStatus CombineCopilotServerStatus(CopilotServerStatus status, bool isConnected)
|
|
231
|
+
{
|
|
232
|
+
if (isConnected && status != CopilotServerStatus.Running)
|
|
233
|
+
return CopilotServerStatus.External;
|
|
234
|
+
|
|
235
|
+
return status;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
internal static string GetServerButtonText(CopilotServerStatus status) => status switch
|
|
239
|
+
{
|
|
240
|
+
CopilotServerStatus.Running => "Stop",
|
|
241
|
+
CopilotServerStatus.Starting => "Starting...",
|
|
242
|
+
CopilotServerStatus.Stopping => "Stopping...",
|
|
243
|
+
CopilotServerStatus.External => "External",
|
|
244
|
+
_ => "Start"
|
|
245
|
+
};
|
|
246
|
+
|
|
247
|
+
// The Node.js server exposes a single HTTP transport (REST + WebSocket), so the
|
|
248
|
+
// status label no longer carries a transport-mode suffix.
|
|
249
|
+
internal static string GetServerLabelText(CopilotServerStatus status) => status switch
|
|
250
|
+
{
|
|
251
|
+
CopilotServerStatus.Running => "Server: Running",
|
|
252
|
+
CopilotServerStatus.Starting => "Server: Starting...",
|
|
253
|
+
CopilotServerStatus.Stopping => "Server: Stopping...",
|
|
254
|
+
CopilotServerStatus.External => "Server: External",
|
|
255
|
+
_ => "Server"
|
|
256
|
+
};
|
|
257
|
+
|
|
258
|
+
internal static string GetServerStatusClass(CopilotServerStatus status) => status switch
|
|
259
|
+
{
|
|
260
|
+
CopilotServerStatus.Running => USS_Connected,
|
|
261
|
+
CopilotServerStatus.Starting or CopilotServerStatus.Stopping => USS_Connecting,
|
|
262
|
+
CopilotServerStatus.External => USS_External,
|
|
263
|
+
_ => USS_Disconnected
|
|
264
|
+
};
|
|
265
|
+
|
|
266
|
+
internal static bool IsServerButtonEnabled(CopilotServerStatus status) =>
|
|
267
|
+
status == CopilotServerStatus.Running || status == CopilotServerStatus.Stopped;
|
|
268
|
+
|
|
269
|
+
private static void HandleServerButton(Button btnStartStop, Label statusLabel)
|
|
270
|
+
{
|
|
271
|
+
// Disable button immediately to prevent double-clicks
|
|
272
|
+
btnStartStop.SetEnabled(false);
|
|
273
|
+
|
|
274
|
+
try
|
|
275
|
+
{
|
|
276
|
+
if (CopilotServerManager.IsRunning)
|
|
277
|
+
{
|
|
278
|
+
// User is stopping the server - remember not to auto-start
|
|
279
|
+
UnityCopilotPluginEditor.KeepServerRunning = false;
|
|
280
|
+
UnityCopilotPluginEditor.Instance.Save();
|
|
281
|
+
statusLabel.text = "Server: Stopping...";
|
|
282
|
+
CopilotServerManager.StopServer();
|
|
283
|
+
}
|
|
284
|
+
else
|
|
285
|
+
{
|
|
286
|
+
// User is starting the server - remember to auto-start
|
|
287
|
+
UnityCopilotPluginEditor.KeepServerRunning = true;
|
|
288
|
+
UnityCopilotPluginEditor.Instance.Save();
|
|
289
|
+
statusLabel.text = "Server: Starting...";
|
|
290
|
+
CopilotServerManager.StartServer();
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
catch
|
|
294
|
+
{
|
|
295
|
+
// Re-enable button on exception to avoid infinite lock
|
|
296
|
+
btnStartStop.SetEnabled(true);
|
|
297
|
+
throw;
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
private long SetServerData(UcoServerData? data, CopilotServerStatus status, Button btnStartStop, VisualElement statusCircle, Label statusLabel)
|
|
302
|
+
{
|
|
303
|
+
var version = Interlocked.Increment(ref _serverDataVersion);
|
|
304
|
+
if (Logger.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Trace))
|
|
305
|
+
Logger.LogTrace("Setting server data: {status}, Data: {data}", status, data?.ToPrettyJson() ?? "null");
|
|
306
|
+
|
|
307
|
+
btnStartStop.text = GetServerButtonText(status);
|
|
308
|
+
var isStart = status == CopilotServerStatus.Stopped;
|
|
309
|
+
btnStartStop.EnableInClassList("btn-primary", isStart);
|
|
310
|
+
btnStartStop.EnableInClassList("btn-secondary", !isStart);
|
|
311
|
+
btnStartStop.SetEnabled(IsServerButtonEnabled(status));
|
|
312
|
+
statusLabel.text = GetServerLabelText(status);
|
|
313
|
+
SetStatusIndicator(statusCircle, GetServerStatusClass(status));
|
|
314
|
+
return version;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
private void FetchServerData(CopilotServerStatus status, Button btnStartStop, VisualElement statusCircle, Label statusLabel)
|
|
318
|
+
{
|
|
319
|
+
// Update UI immediately with current status; capture the version atomically so that
|
|
320
|
+
// the async result can detect if a newer update has superseded it.
|
|
321
|
+
var fetchVersion = SetServerData(null, status, btnStartStop, statusCircle, statusLabel);
|
|
322
|
+
|
|
323
|
+
// Then try to fetch additional data asynchronously
|
|
324
|
+
var ucoPluginInstance = UnityCopilotPluginEditor.Instance.UcoPluginInstance;
|
|
325
|
+
if (ucoPluginInstance == null)
|
|
326
|
+
{
|
|
327
|
+
Logger.LogDebug("Cannot fetch server data: UcoPluginInstance is null");
|
|
328
|
+
return;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
var pluginManagerHub = ucoPluginInstance.UcoManagerHub;
|
|
332
|
+
if (pluginManagerHub == null)
|
|
333
|
+
{
|
|
334
|
+
Logger.LogDebug("Cannot fetch server data: UcoManagerHub is null");
|
|
335
|
+
return;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
var task = pluginManagerHub.GetServerData();
|
|
339
|
+
if (task == null)
|
|
340
|
+
{
|
|
341
|
+
Logger.LogDebug("Cannot fetch server data: GetServerData returned null");
|
|
342
|
+
return;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
task.ContinueWith(t =>
|
|
346
|
+
{
|
|
347
|
+
if (Interlocked.Read(ref _serverDataVersion) != fetchVersion)
|
|
348
|
+
{
|
|
349
|
+
Logger.LogTrace("Skipping server data update because a newer update was applied at {time}",
|
|
350
|
+
DateTime.UtcNow);
|
|
351
|
+
return;
|
|
352
|
+
}
|
|
353
|
+
MainThread.Instance.Run(() =>
|
|
354
|
+
{
|
|
355
|
+
// Second check: close the TOCTOU window between the thread-pool check above
|
|
356
|
+
// and the main-thread callback execution.
|
|
357
|
+
if (Interlocked.Read(ref _serverDataVersion) != fetchVersion)
|
|
358
|
+
return;
|
|
359
|
+
if (t.IsCompletedSuccessfully)
|
|
360
|
+
{
|
|
361
|
+
var data = t.Result;
|
|
362
|
+
SetServerData(data, status, btnStartStop, statusCircle, statusLabel);
|
|
363
|
+
}
|
|
364
|
+
else if (t.IsFaulted)
|
|
365
|
+
{
|
|
366
|
+
Logger.LogDebug("Failed to fetch server data: {error}", t.Exception?.Message ?? "Unknown error");
|
|
367
|
+
}
|
|
368
|
+
});
|
|
369
|
+
});
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
}
|