Files
ft/Client/Packages/io.github.hatayama.uloopmcp/Editor/Config/ToolSettings.cs

166 lines
5.5 KiB
C#

using System;
using System.IO;
using System.Linq;
using UnityEngine;
namespace io.github.hatayama.uLoopMCP
{
/// <summary>
/// Tool toggle settings management for .uloop/settings.tools.json.
/// Controls which tools are enabled/disabled in the MCP tool list.
/// </summary>
public static class ToolSettings
{
private static string SettingsFilePath =>
Path.Combine(McpConstants.ULOOP_DIR, McpConstants.ULOOP_TOOL_SETTINGS_FILE_NAME);
private static ToolSettingsData _cachedSettings;
public static ToolSettingsData GetSettings()
{
if (_cachedSettings == null)
{
LoadSettings();
}
return _cachedSettings;
}
public static void SaveSettings(ToolSettingsData settings)
{
Debug.Assert(settings != null, "settings must not be null");
ToolSettingsData normalizedSettings = NormalizeSettings(settings);
string directory = Path.GetDirectoryName(SettingsFilePath);
if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory))
{
Directory.CreateDirectory(directory);
}
string json = JsonUtility.ToJson(normalizedSettings, true);
Debug.Assert(json.Length <= McpConstants.MAX_SETTINGS_SIZE_BYTES,
"Settings JSON content exceeds size limit");
AtomicFileWriter.Write(SettingsFilePath, json);
_cachedSettings = normalizedSettings;
AtomicFileWriter.CleanupBackup(SettingsFilePath + ".bak");
}
public static bool IsToolEnabled(string toolName)
{
Debug.Assert(!string.IsNullOrEmpty(toolName), "toolName must not be null or empty");
string[] disabledTools = GetSettings().disabledTools;
return !disabledTools.Contains(toolName);
}
public static void SetToolEnabled(string toolName, bool enabled)
{
Debug.Assert(!string.IsNullOrEmpty(toolName), "toolName must not be null or empty");
ToolSettingsData settings = GetSettings();
string[] currentDisabled = settings.disabledTools;
string[] newDisabled;
if (enabled)
{
newDisabled = currentDisabled.Where(t => t != toolName).ToArray();
}
else
{
if (currentDisabled.Contains(toolName))
{
return;
}
newDisabled = currentDisabled.Append(toolName).ToArray();
}
ToolSettingsData updated = settings with { disabledTools = newDisabled };
SaveSettings(updated);
}
public static string[] GetDisabledTools()
{
return GetSettings().disabledTools;
}
public static string GetSkillCliInvocation()
{
return NormalizeSkillCliInvocation(GetSettings().skillCliInvocation);
}
public static void SetSkillCliInvocation(string invocation)
{
Debug.Assert(!string.IsNullOrEmpty(invocation), "invocation must not be null or empty");
ToolSettingsData settings = GetSettings();
string normalizedInvocation = NormalizeSkillCliInvocation(invocation);
if (settings.skillCliInvocation == normalizedInvocation)
{
return;
}
ToolSettingsData updated = settings with { skillCliInvocation = normalizedInvocation };
SaveSettings(updated);
}
public static void InvalidateCache()
{
_cachedSettings = null;
}
private static void LoadSettings()
{
AtomicFileWriter.RecoverSidecarFiles(SettingsFilePath);
if (File.Exists(SettingsFilePath))
{
FileInfo fileInfo = new FileInfo(SettingsFilePath);
Debug.Assert(fileInfo.Length <= McpConstants.MAX_SETTINGS_SIZE_BYTES,
$"Settings file exceeds size limit: {fileInfo.Length} bytes");
string json = File.ReadAllText(SettingsFilePath);
if (string.IsNullOrWhiteSpace(json))
{
_cachedSettings = new ToolSettingsData();
return;
}
ToolSettingsData loaded = JsonUtility.FromJson<ToolSettingsData>(json);
if (loaded == null)
{
_cachedSettings = new ToolSettingsData();
return;
}
_cachedSettings = NormalizeSettings(loaded);
return;
}
_cachedSettings = new ToolSettingsData();
}
private static ToolSettingsData NormalizeSettings(ToolSettingsData settings)
{
Debug.Assert(settings != null, "settings must not be null");
string[] disabledTools = settings.disabledTools ?? Array.Empty<string>();
string skillCliInvocation = NormalizeSkillCliInvocation(settings.skillCliInvocation);
return settings with
{
disabledTools = disabledTools,
skillCliInvocation = skillCliInvocation
};
}
private static string NormalizeSkillCliInvocation(string invocation)
{
return invocation == CliConstants.SKILL_CLI_INVOCATION_GLOBAL
? CliConstants.SKILL_CLI_INVOCATION_GLOBAL
: CliConstants.SKILL_CLI_INVOCATION_NPX;
}
}
}