Unity MCP: Claude Code UX improvements: dynamic not-found state with inline help link; NVM auto-detection; path picker override; hide picker after detection; remove auto-connect toggle.
parent
bd6114b436
commit
5965158533
|
|
@ -35,6 +35,9 @@ namespace UnityMcpBridge.Editor.Helpers
|
|||
Path.Combine(home, ".local", "bin", "claude"),
|
||||
};
|
||||
foreach (string c in candidates) { if (File.Exists(c)) return c; }
|
||||
// Try NVM-installed claude under ~/.nvm/versions/node/*/bin/claude
|
||||
string nvmClaude = ResolveClaudeFromNvm(home);
|
||||
if (!string.IsNullOrEmpty(nvmClaude)) return nvmClaude;
|
||||
#if UNITY_EDITOR_OSX || UNITY_EDITOR_LINUX
|
||||
return Which("claude", "/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin");
|
||||
#else
|
||||
|
|
@ -70,6 +73,9 @@ namespace UnityMcpBridge.Editor.Helpers
|
|||
Path.Combine(home, ".local", "bin", "claude"),
|
||||
};
|
||||
foreach (string c in candidates) { if (File.Exists(c)) return c; }
|
||||
// Try NVM-installed claude under ~/.nvm/versions/node/*/bin/claude
|
||||
string nvmClaude = ResolveClaudeFromNvm(home);
|
||||
if (!string.IsNullOrEmpty(nvmClaude)) return nvmClaude;
|
||||
#if UNITY_EDITOR_OSX || UNITY_EDITOR_LINUX
|
||||
return Which("claude", "/usr/local/bin:/usr/bin:/bin");
|
||||
#else
|
||||
|
|
@ -78,6 +84,68 @@ namespace UnityMcpBridge.Editor.Helpers
|
|||
}
|
||||
}
|
||||
|
||||
// Attempt to resolve claude from NVM-managed Node installations, choosing the newest version
|
||||
private static string ResolveClaudeFromNvm(string home)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (string.IsNullOrEmpty(home)) return null;
|
||||
string nvmNodeDir = Path.Combine(home, ".nvm", "versions", "node");
|
||||
if (!Directory.Exists(nvmNodeDir)) return null;
|
||||
|
||||
string bestPath = null;
|
||||
Version bestVersion = null;
|
||||
foreach (string versionDir in Directory.EnumerateDirectories(nvmNodeDir))
|
||||
{
|
||||
string name = Path.GetFileName(versionDir);
|
||||
if (string.IsNullOrEmpty(name)) continue;
|
||||
if (name.StartsWith("v", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
if (Version.TryParse(name.Substring(1), out Version parsed))
|
||||
{
|
||||
string candidate = Path.Combine(versionDir, "bin", "claude");
|
||||
if (File.Exists(candidate))
|
||||
{
|
||||
if (bestVersion == null || parsed > bestVersion)
|
||||
{
|
||||
bestVersion = parsed;
|
||||
bestPath = candidate;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return bestPath;
|
||||
}
|
||||
catch { return null; }
|
||||
}
|
||||
|
||||
// Explicitly set the Claude CLI absolute path override in EditorPrefs
|
||||
internal static void SetClaudeCliPath(string absolutePath)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!string.IsNullOrEmpty(absolutePath) && File.Exists(absolutePath))
|
||||
{
|
||||
EditorPrefs.SetString(PrefClaude, absolutePath);
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
// Clear any previously set Claude CLI override path
|
||||
internal static void ClearClaudeCliPath()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (EditorPrefs.HasKey(PrefClaude))
|
||||
{
|
||||
EditorPrefs.DeleteKey(PrefClaude);
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
// Use existing UV resolver; returns absolute path or null.
|
||||
internal static string ResolveUv()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -438,14 +438,7 @@ namespace UnityMcpBridge.Editor.Windows
|
|||
EditorGUILayout.LabelField("MCP Client Configuration", sectionTitleStyle);
|
||||
EditorGUILayout.Space(10);
|
||||
|
||||
// Auto-connect toggle (moved from Server Status)
|
||||
bool newAuto = EditorGUILayout.ToggleLeft("Auto-connect to MCP Clients", autoRegisterEnabled);
|
||||
if (newAuto != autoRegisterEnabled)
|
||||
{
|
||||
autoRegisterEnabled = newAuto;
|
||||
EditorPrefs.SetBool("UnityMCP.AutoRegisterEnabled", autoRegisterEnabled);
|
||||
}
|
||||
EditorGUILayout.Space(6);
|
||||
// (Auto-connect toggle removed per design)
|
||||
|
||||
// Client selector
|
||||
string[] clientNames = mcpClients.clients.Select(c => c.name).ToArray();
|
||||
|
|
@ -697,6 +690,17 @@ namespace UnityMcpBridge.Editor.Windows
|
|||
|
||||
private void DrawClientConfigurationCompact(McpClient mcpClient)
|
||||
{
|
||||
// Special pre-check for Claude Code: if CLI missing, reflect in status UI
|
||||
if (mcpClient.mcpType == McpTypes.ClaudeCode)
|
||||
{
|
||||
string claudeCheck = ExecPath.ResolveClaude();
|
||||
if (string.IsNullOrEmpty(claudeCheck))
|
||||
{
|
||||
mcpClient.configStatus = "Claude Not Found";
|
||||
mcpClient.status = McpStatus.NotConfigured;
|
||||
}
|
||||
}
|
||||
|
||||
// Status display
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
Rect statusRect = GUILayoutUtility.GetRect(0, 28, GUILayout.Width(24));
|
||||
|
|
@ -710,6 +714,23 @@ namespace UnityMcpBridge.Editor.Windows
|
|||
};
|
||||
EditorGUILayout.LabelField(mcpClient.configStatus, clientStatusStyle, GUILayout.Height(28));
|
||||
EditorGUILayout.EndHorizontal();
|
||||
// When Claude CLI is missing, show a clear install hint directly below status
|
||||
if (mcpClient.mcpType == McpTypes.ClaudeCode && string.IsNullOrEmpty(ExecPath.ResolveClaude()))
|
||||
{
|
||||
GUIStyle installHintStyle = new GUIStyle(clientStatusStyle);
|
||||
installHintStyle.normal.textColor = new Color(1f, 0.5f, 0f); // orange
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
GUIContent installText = new GUIContent("Make sure Claude Code is installed!");
|
||||
Vector2 textSize = installHintStyle.CalcSize(installText);
|
||||
EditorGUILayout.LabelField(installText, installHintStyle, GUILayout.Height(22), GUILayout.Width(textSize.x + 2), GUILayout.ExpandWidth(false));
|
||||
GUIStyle helpLinkStyle = new GUIStyle(EditorStyles.linkLabel) { fontStyle = FontStyle.Bold };
|
||||
GUILayout.Space(6);
|
||||
if (GUILayout.Button("[CLICK]", helpLinkStyle, GUILayout.Height(22), GUILayout.ExpandWidth(false)))
|
||||
{
|
||||
Application.OpenURL("https://github.com/CoplayDev/unity-mcp/wiki/Troubleshooting-Unity-MCP-and-Claude-Code");
|
||||
}
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
EditorGUILayout.Space(10);
|
||||
|
||||
|
|
@ -723,23 +744,57 @@ namespace UnityMcpBridge.Editor.Windows
|
|||
ConfigureMcpClient(mcpClient);
|
||||
}
|
||||
}
|
||||
else if (mcpClient.mcpType == McpTypes.ClaudeCode)
|
||||
{
|
||||
bool isConfigured = mcpClient.status == McpStatus.Configured;
|
||||
string buttonText = isConfigured ? "Unregister UnityMCP with Claude Code" : "Register with Claude Code";
|
||||
if (GUILayout.Button(buttonText, GUILayout.Height(32)))
|
||||
{
|
||||
if (isConfigured)
|
||||
{
|
||||
UnregisterWithClaudeCode();
|
||||
}
|
||||
else
|
||||
{
|
||||
string pythonDir = FindPackagePythonDirectory();
|
||||
RegisterWithClaudeCode(pythonDir);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (mcpClient.mcpType == McpTypes.ClaudeCode)
|
||||
{
|
||||
bool claudeAvailable = !string.IsNullOrEmpty(ExecPath.ResolveClaude());
|
||||
if (claudeAvailable)
|
||||
{
|
||||
bool isConfigured = mcpClient.status == McpStatus.Configured;
|
||||
string buttonText = isConfigured ? "Unregister UnityMCP with Claude Code" : "Register with Claude Code";
|
||||
if (GUILayout.Button(buttonText, GUILayout.Height(32)))
|
||||
{
|
||||
if (isConfigured)
|
||||
{
|
||||
UnregisterWithClaudeCode();
|
||||
}
|
||||
else
|
||||
{
|
||||
string pythonDir = FindPackagePythonDirectory();
|
||||
RegisterWithClaudeCode(pythonDir);
|
||||
}
|
||||
}
|
||||
// Hide the picker once a valid binary is available
|
||||
EditorGUILayout.EndHorizontal();
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
GUIStyle pathLabelStyle = new GUIStyle(EditorStyles.miniLabel) { wordWrap = true };
|
||||
string resolvedClaude = ExecPath.ResolveClaude();
|
||||
EditorGUILayout.LabelField($"Claude CLI: {resolvedClaude}", pathLabelStyle);
|
||||
EditorGUILayout.EndHorizontal();
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
}
|
||||
// CLI picker row (only when not found)
|
||||
EditorGUILayout.EndHorizontal();
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
if (!claudeAvailable)
|
||||
{
|
||||
// Only show the picker button in not-found state (no redundant "not found" label)
|
||||
if (GUILayout.Button("Choose Claude Install Location", GUILayout.Width(260), GUILayout.Height(22)))
|
||||
{
|
||||
string suggested = RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? "/opt/homebrew/bin" : Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles);
|
||||
string picked = EditorUtility.OpenFilePanel("Select 'claude' CLI", suggested, "");
|
||||
if (!string.IsNullOrEmpty(picked))
|
||||
{
|
||||
ExecPath.SetClaudeCliPath(picked);
|
||||
// Auto-register after setting a valid path
|
||||
string pythonDir = FindPackagePythonDirectory();
|
||||
RegisterWithClaudeCode(pythonDir);
|
||||
Repaint();
|
||||
}
|
||||
}
|
||||
}
|
||||
EditorGUILayout.EndHorizontal();
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (GUILayout.Button($"Auto Configure", GUILayout.Height(32)))
|
||||
|
|
@ -793,13 +848,17 @@ namespace UnityMcpBridge.Editor.Windows
|
|||
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
EditorGUILayout.Space(8);
|
||||
// Quick info
|
||||
GUIStyle configInfoStyle = new GUIStyle(EditorStyles.miniLabel)
|
||||
{
|
||||
fontSize = 10
|
||||
};
|
||||
EditorGUILayout.LabelField($"Config: {Path.GetFileName(RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? mcpClient.windowsConfigPath : mcpClient.linuxConfigPath)}", configInfoStyle);
|
||||
EditorGUILayout.Space(8);
|
||||
// Quick info (hide when Claude is not found to avoid confusion)
|
||||
bool hideConfigInfo = (mcpClient.mcpType == McpTypes.ClaudeCode) && string.IsNullOrEmpty(ExecPath.ResolveClaude());
|
||||
if (!hideConfigInfo)
|
||||
{
|
||||
GUIStyle configInfoStyle = new GUIStyle(EditorStyles.miniLabel)
|
||||
{
|
||||
fontSize = 10
|
||||
};
|
||||
EditorGUILayout.LabelField($"Config: {Path.GetFileName(RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? mcpClient.windowsConfigPath : mcpClient.linuxConfigPath)}", configInfoStyle);
|
||||
}
|
||||
}
|
||||
|
||||
private void ToggleUnityBridge()
|
||||
|
|
|
|||
Loading…
Reference in New Issue