From 068079fbb75a02c9e2718453de72e96c98d7a15f Mon Sep 17 00:00:00 2001 From: Takeshi Sugita Date: Mon, 20 Jul 2026 02:56:40 +0900 Subject: [PATCH] fix(codex): migrate legacy env table configuration --- Assets/Tests/Editor/CodexConfigTests.cs | 47 +++++++++++++++++++ .../Editor/Config/CodexTomlConfigService.cs | 16 ++++++- 2 files changed, 62 insertions(+), 1 deletion(-) diff --git a/Assets/Tests/Editor/CodexConfigTests.cs b/Assets/Tests/Editor/CodexConfigTests.cs index c96ec94bf..14285c9f8 100644 --- a/Assets/Tests/Editor/CodexConfigTests.cs +++ b/Assets/Tests/Editor/CodexConfigTests.cs @@ -85,6 +85,46 @@ public void NormalizeForCompare_Should_ReturnEmpty_WhenInputIsEmpty() Assert.AreEqual(string.Empty, result); } + // ---------------------------------------------------------------- + // Legacy table-style env migration + // ---------------------------------------------------------------- + + [Test] + public void RemoveLegacyEnvSection_Should_RemoveOnlyLegacyULoopEnvTable() + { + string toml = @"[mcp_servers.uLoopMCP] +command = ""node"" +args = ['server.js'] +env = { ""UNITY_TCP_PORT"" = ""8700"" } + +[mcp_servers.uLoopMCP.env] +UNITY_TCP_PORT = ""8700"" + +[mcp_servers.other] +command = ""python"" +"; + + string result = InvokeRemoveLegacyEnvSection(toml); + + StringAssert.DoesNotContain("[mcp_servers.uLoopMCP.env]", result); + StringAssert.Contains("env = { \"UNITY_TCP_PORT\" = \"8700\" }", result); + StringAssert.Contains("[mcp_servers.other]", result); + } + + [Test] + public void RemoveLegacyEnvSection_Should_ReturnUnchanged_WhenLegacyTableIsAbsent() + { + string toml = @"[mcp_servers.uLoopMCP] +command = ""node"" +args = ['server.js'] +env = { ""UNITY_TCP_PORT"" = ""8700"" } +"; + + string result = InvokeRemoveLegacyEnvSection(toml); + + Assert.AreEqual(toml, result); + } + // ---------------------------------------------------------------- // MakeRelativeToConfigurationRoot // ---------------------------------------------------------------- @@ -188,5 +228,12 @@ private static string InvokeNormalizeForCompare(string path) Debug.Assert(method != null, "NormalizeForCompare method not found"); return (string)method.Invoke(null, new object[] { path }); } + + private static string InvokeRemoveLegacyEnvSection(string content) + { + MethodInfo method = CodexServiceType.GetMethod("RemoveLegacyEnvSection", PrivateStatic); + Debug.Assert(method != null, "RemoveLegacyEnvSection method not found"); + return (string)method.Invoke(null, new object[] { content }); + } } } diff --git a/Packages/src/Editor/Config/CodexTomlConfigService.cs b/Packages/src/Editor/Config/CodexTomlConfigService.cs index 23f2c9587..931c02fd0 100644 --- a/Packages/src/Editor/Config/CodexTomlConfigService.cs +++ b/Packages/src/Editor/Config/CodexTomlConfigService.cs @@ -12,6 +12,9 @@ public sealed class CodexTomlConfigService : IMcpConfigService private static readonly Regex SectionRegex = new Regex( @"(?ms)^\[mcp_servers\.uLoopMCP\]\s*.*?(?=^\[|\z)", RegexOptions.Compiled | RegexOptions.CultureInvariant); + private static readonly Regex LegacyEnvSectionRegex = new Regex( + @"(?ms)^\[mcp_servers\.uLoopMCP\.env\]\s*.*?(?=^\[|\z)", + RegexOptions.Compiled | RegexOptions.CultureInvariant); private static readonly Regex AnyMcpServerRegex = new Regex( @"(?ms)^\[mcp_servers\.[^\]]+\]\s*.*?(?=^\[|\z)", RegexOptions.Compiled | RegexOptions.CultureInvariant); @@ -50,6 +53,9 @@ public bool IsUpdateNeeded(int port) if (!File.Exists(path)) return true; string content = File.ReadAllText(path); + // Migrate the legacy table-style env section before writing the inline env value. + if (LegacyEnvSectionRegex.IsMatch(content)) return true; + string serverAbsolutePath = UnityMcpPathResolver.GetTypeScriptServerPath(); if (string.IsNullOrEmpty(serverAbsolutePath) || !File.Exists(serverAbsolutePath)) return false; string expectedArg0 = UnityMcpPathResolver.MakeRelativeToConfigurationRoot(serverAbsolutePath); @@ -81,6 +87,7 @@ public void AutoConfigure(int port) string path = UnityMcpPathResolver.GetCodexConfigPath(); EnsureDirectory(path); string content = File.Exists(path) ? File.ReadAllText(path) : string.Empty; + content = RemoveLegacyEnvSection(content); string serverPath = UnityMcpPathResolver.GetTypeScriptServerPath(); if (string.IsNullOrEmpty(serverPath) || !File.Exists(serverPath)) @@ -135,6 +142,7 @@ public void DeleteConfiguration() string content = File.ReadAllText(path); string result = SectionRegex.Replace(content, string.Empty); + result = LegacyEnvSectionRegex.Replace(result, string.Empty); if (ReferenceEquals(content, result)) { return; @@ -153,6 +161,7 @@ public void UpdateDevelopmentSettings(int port, bool developmentMode, bool enabl } string content = File.ReadAllText(path); + content = RemoveLegacyEnvSection(content); // If section not exists, create it first and reload if (!SectionRegex.IsMatch(content)) @@ -351,7 +360,12 @@ private static void EnsureDirectory(string filePath) string dir = Path.GetDirectoryName(filePath); if (!string.IsNullOrEmpty(dir) && !Directory.Exists(dir)) Directory.CreateDirectory(dir); } + + private static string RemoveLegacyEnvSection(string content) + { + string result = LegacyEnvSectionRegex.Replace(content, string.Empty); + return Regex.Replace(result, @"(\r?\n){3,}", System.Environment.NewLine + System.Environment.NewLine); + } } } -