Update to support Codex CLI
Fix the JSON installation on Codex in Wizard; Adding the lines to support Codex CLI on windows temporarily, thanks to https://github.com/openai/codex/issues/4180main
parent
90911aa4d7
commit
3d9860eb72
|
|
@ -43,15 +43,84 @@ namespace MCPForUnity.Editor.Helpers
|
||||||
public static string BuildCodexServerBlock(string uvPath, string serverSrc)
|
public static string BuildCodexServerBlock(string uvPath, string serverSrc)
|
||||||
{
|
{
|
||||||
string argsArray = FormatTomlStringArray(new[] { "run", "--directory", serverSrc, "server.py" });
|
string argsArray = FormatTomlStringArray(new[] { "run", "--directory", serverSrc, "server.py" });
|
||||||
return $"[mcp_servers.unityMCP]{Environment.NewLine}" +
|
|
||||||
$"command = \"{EscapeTomlString(uvPath)}\"{Environment.NewLine}" +
|
var sb = new StringBuilder();
|
||||||
$"args = {argsArray}";
|
sb.AppendLine("[mcp_servers.unityMCP]");
|
||||||
|
sb.AppendLine($"command = \"{EscapeTomlString(uvPath)}\"");
|
||||||
|
sb.AppendLine($"args = {argsArray}");
|
||||||
|
sb.AppendLine($"startup_timeout_sec = 30");
|
||||||
|
|
||||||
|
// Windows-specific environment block to help Codex locate needed paths
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (Environment.OSVersion.Platform == PlatformID.Win32NT)
|
||||||
|
{
|
||||||
|
string userProfile = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) ?? string.Empty;
|
||||||
|
string appData = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) ?? string.Empty; // Roaming
|
||||||
|
string localAppData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) ?? string.Empty;
|
||||||
|
string programData = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData) ?? string.Empty;
|
||||||
|
string programFiles = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles) ?? string.Empty;
|
||||||
|
string systemDrive = Environment.GetEnvironmentVariable("SystemDrive") ?? (Path.GetPathRoot(userProfile)?.TrimEnd('\\', '/') ?? "C:");
|
||||||
|
string systemRoot = Environment.GetEnvironmentVariable("SystemRoot") ?? Path.Combine(systemDrive + "\\", "Windows");
|
||||||
|
string comspec = Environment.GetEnvironmentVariable("COMSPEC") ?? Path.Combine(Environment.SystemDirectory ?? (systemRoot + "\\System32"), "cmd.exe");
|
||||||
|
string homeDrive = Environment.GetEnvironmentVariable("HOMEDRIVE");
|
||||||
|
string homePath = Environment.GetEnvironmentVariable("HOMEPATH");
|
||||||
|
if (string.IsNullOrEmpty(homeDrive))
|
||||||
|
{
|
||||||
|
homeDrive = systemDrive;
|
||||||
|
}
|
||||||
|
if (string.IsNullOrEmpty(homePath) && !string.IsNullOrEmpty(userProfile))
|
||||||
|
{
|
||||||
|
// Derive HOMEPATH from USERPROFILE (e.g., C:\\Users\\name -> \\Users\\name)
|
||||||
|
if (userProfile.StartsWith(homeDrive + "\\", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
homePath = userProfile.Substring(homeDrive.Length);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var root = Path.GetPathRoot(userProfile) ?? string.Empty; // e.g., C:\\
|
||||||
|
homePath = userProfile.Substring(root.Length - 1); // keep leading backslash
|
||||||
|
}
|
||||||
|
catch { homePath = "\\"; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
string powershell = Path.Combine(Environment.SystemDirectory ?? (systemRoot + "\\System32"), "WindowsPowerShell\\v1.0\\powershell.exe");
|
||||||
|
string pwsh = Path.Combine(programFiles, "PowerShell\\7\\pwsh.exe");
|
||||||
|
|
||||||
|
string tempDir = Path.Combine(localAppData, "Temp");
|
||||||
|
|
||||||
|
sb.AppendLine();
|
||||||
|
sb.AppendLine("[mcp_servers.unityMCP.env]");
|
||||||
|
sb.AppendLine($"SystemRoot = \"{EscapeTomlString(systemRoot)}\"");
|
||||||
|
sb.AppendLine($"APPDATA = \"{EscapeTomlString(appData)}\"");
|
||||||
|
sb.AppendLine($"COMSPEC = \"{EscapeTomlString(comspec)}\"");
|
||||||
|
sb.AppendLine($"HOMEDRIVE = \"{EscapeTomlString(homeDrive?.TrimEnd('\\') ?? string.Empty)}\"");
|
||||||
|
sb.AppendLine($"HOMEPATH = \"{EscapeTomlString(homePath ?? string.Empty)}\"");
|
||||||
|
sb.AppendLine($"LOCALAPPDATA = \"{EscapeTomlString(localAppData)}\"");
|
||||||
|
sb.AppendLine($"POWERSHELL = \"{EscapeTomlString(powershell)}\"");
|
||||||
|
sb.AppendLine($"PROGRAMDATA = \"{EscapeTomlString(programData)}\"");
|
||||||
|
sb.AppendLine($"PROGRAMFILES = \"{EscapeTomlString(programFiles)}\"");
|
||||||
|
sb.AppendLine($"PWSH = \"{EscapeTomlString(pwsh)}\"");
|
||||||
|
sb.AppendLine($"SYSTEMDRIVE = \"{EscapeTomlString(systemDrive)}\"");
|
||||||
|
sb.AppendLine($"SYSTEMROOT = \"{EscapeTomlString(systemRoot)}\"");
|
||||||
|
sb.AppendLine($"TEMP = \"{EscapeTomlString(tempDir)}\"");
|
||||||
|
sb.AppendLine($"TMP = \"{EscapeTomlString(tempDir)}\"");
|
||||||
|
sb.AppendLine($"USERPROFILE = \"{EscapeTomlString(userProfile)}\"");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch { /* best effort */ }
|
||||||
|
|
||||||
|
return sb.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string UpsertCodexServerBlock(string existingToml, string newBlock)
|
public static string UpsertCodexServerBlock(string existingToml, string newBlock)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(existingToml))
|
if (string.IsNullOrWhiteSpace(existingToml))
|
||||||
{
|
{
|
||||||
|
// Default to snake_case section when creating new files
|
||||||
return newBlock.TrimEnd() + Environment.NewLine;
|
return newBlock.TrimEnd() + Environment.NewLine;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -60,25 +129,62 @@ namespace MCPForUnity.Editor.Helpers
|
||||||
string line;
|
string line;
|
||||||
bool inTarget = false;
|
bool inTarget = false;
|
||||||
bool replaced = false;
|
bool replaced = false;
|
||||||
|
|
||||||
|
// Support both TOML section casings and nested subtables (e.g., env)
|
||||||
|
// Prefer the casing already present in the user's file; fall back to snake_case
|
||||||
|
bool hasCamelSection = existingToml.IndexOf("[mcpServers.unityMCP]", StringComparison.OrdinalIgnoreCase) >= 0
|
||||||
|
|| existingToml.IndexOf("[mcpServers.unityMCP.", StringComparison.OrdinalIgnoreCase) >= 0;
|
||||||
|
bool hasSnakeSection = existingToml.IndexOf("[mcp_servers.unityMCP]", StringComparison.OrdinalIgnoreCase) >= 0
|
||||||
|
|| existingToml.IndexOf("[mcp_servers.unityMCP.", StringComparison.OrdinalIgnoreCase) >= 0;
|
||||||
|
bool preferCamel = hasCamelSection || (!hasSnakeSection && existingToml.IndexOf("[mcpServers]", StringComparison.OrdinalIgnoreCase) >= 0);
|
||||||
|
|
||||||
|
// Prepare block variants matching the chosen casing, including nested tables
|
||||||
|
string newBlockCamel = newBlock
|
||||||
|
.Replace("[mcp_servers.unityMCP.env]", "[mcpServers.unityMCP.env]")
|
||||||
|
.Replace("[mcp_servers.unityMCP]", "[mcpServers.unityMCP]");
|
||||||
|
string newBlockEffective = preferCamel ? newBlockCamel : newBlock;
|
||||||
|
|
||||||
|
static bool IsSection(string s)
|
||||||
|
{
|
||||||
|
string t = s.Trim();
|
||||||
|
return t.StartsWith("[") && t.EndsWith("]") && !t.StartsWith("[[");
|
||||||
|
}
|
||||||
|
|
||||||
|
static string SectionName(string header)
|
||||||
|
{
|
||||||
|
string t = header.Trim();
|
||||||
|
if (t.StartsWith("[") && t.EndsWith("]")) t = t.Substring(1, t.Length - 2);
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TargetOrChild(string section)
|
||||||
|
{
|
||||||
|
// Compare case-insensitively; accept both snake and camel as the same logical table
|
||||||
|
string name = SectionName(section);
|
||||||
|
return name.StartsWith("mcp_servers.unityMCP", StringComparison.OrdinalIgnoreCase)
|
||||||
|
|| name.StartsWith("mcpServers.unityMCP", StringComparison.OrdinalIgnoreCase);
|
||||||
|
}
|
||||||
|
|
||||||
while ((line = reader.ReadLine()) != null)
|
while ((line = reader.ReadLine()) != null)
|
||||||
{
|
{
|
||||||
string trimmed = line.Trim();
|
string trimmed = line.Trim();
|
||||||
bool isSection = trimmed.StartsWith("[") && trimmed.EndsWith("]") && !trimmed.StartsWith("[[");
|
bool isSection = IsSection(trimmed);
|
||||||
if (isSection)
|
if (isSection)
|
||||||
{
|
{
|
||||||
bool isTarget = string.Equals(trimmed, "[mcp_servers.unityMCP]", StringComparison.OrdinalIgnoreCase);
|
// If we encounter the target section or any of its nested tables, mark/keep in-target
|
||||||
if (isTarget)
|
if (TargetOrChild(trimmed))
|
||||||
{
|
{
|
||||||
if (!replaced)
|
if (!replaced)
|
||||||
{
|
{
|
||||||
if (sb.Length > 0 && sb[^1] != '\n') sb.AppendLine();
|
if (sb.Length > 0 && sb[^1] != '\n') sb.AppendLine();
|
||||||
sb.AppendLine(newBlock.TrimEnd());
|
sb.AppendLine(newBlockEffective.TrimEnd());
|
||||||
replaced = true;
|
replaced = true;
|
||||||
}
|
}
|
||||||
inTarget = true;
|
inTarget = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A new unrelated section ends the target region
|
||||||
if (inTarget)
|
if (inTarget)
|
||||||
{
|
{
|
||||||
inTarget = false;
|
inTarget = false;
|
||||||
|
|
@ -96,7 +202,7 @@ namespace MCPForUnity.Editor.Helpers
|
||||||
if (!replaced)
|
if (!replaced)
|
||||||
{
|
{
|
||||||
if (sb.Length > 0 && sb[^1] != '\n') sb.AppendLine();
|
if (sb.Length > 0 && sb[^1] != '\n') sb.AppendLine();
|
||||||
sb.AppendLine(newBlock.TrimEnd());
|
sb.AppendLine(newBlockEffective.TrimEnd());
|
||||||
}
|
}
|
||||||
|
|
||||||
return sb.ToString().TrimEnd() + Environment.NewLine;
|
return sb.ToString().TrimEnd() + Environment.NewLine;
|
||||||
|
|
|
||||||
|
|
@ -626,7 +626,15 @@ namespace MCPForUnity.Editor.Setup
|
||||||
}
|
}
|
||||||
|
|
||||||
McpConfigurationHelper.EnsureConfigDirectoryExists(configPath);
|
McpConfigurationHelper.EnsureConfigDirectoryExists(configPath);
|
||||||
return McpConfigurationHelper.WriteMcpConfiguration(pythonDir, configPath, client);
|
// Use TOML writer for Codex; JSON writer for others
|
||||||
|
if (client != null && client.mcpType == McpTypes.Codex)
|
||||||
|
{
|
||||||
|
return McpConfigurationHelper.ConfigureCodexClient(pythonDir, configPath, client);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return McpConfigurationHelper.WriteMcpConfiguration(pythonDir, configPath, client);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ShowManualSetupInWizard(McpClient client)
|
private void ShowManualSetupInWizard(McpClient client)
|
||||||
|
|
@ -642,7 +650,9 @@ namespace MCPForUnity.Editor.Setup
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build manual configuration using the sophisticated helper logic
|
// Build manual configuration using the sophisticated helper logic
|
||||||
string result = McpConfigurationHelper.WriteMcpConfiguration(pythonDir, configPath, client);
|
string result = (client != null && client.mcpType == McpTypes.Codex)
|
||||||
|
? McpConfigurationHelper.ConfigureCodexClient(pythonDir, configPath, client)
|
||||||
|
: McpConfigurationHelper.WriteMcpConfiguration(pythonDir, configPath, client);
|
||||||
string manualConfig;
|
string manualConfig;
|
||||||
|
|
||||||
if (result == "Configured successfully")
|
if (result == "Configured successfully")
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue