feat: внедрение RazorConsole TUI с runtime-управлением MCP-инструментами
- Добавлен RazorConsole.Core для интерактивного TUI-дашборда - ToolRegistryService: живое включение/отключение модулей и отдельных методов - InMemoryLogSink: кольцевой буфер логов с фильтрацией по модулю - TUI: 3 таба (Overview, Logs, Settings) - IToolModule: generic-интерфейс для легкого добавления новых MCP-модулей - Guard-проверка TryCheckEnabled() во всех существующих инструментах
This commit is contained in:
96
LazyBear.MCP/Services/ToolRegistry/ToolRegistryService.cs
Normal file
96
LazyBear.MCP/Services/ToolRegistry/ToolRegistryService.cs
Normal file
@@ -0,0 +1,96 @@
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
namespace LazyBear.MCP.Services.ToolRegistry;
|
||||
|
||||
/// <summary>
|
||||
/// Singleton. Хранит runtime-состояние включённости модулей и отдельных инструментов.
|
||||
/// Thread-safe. Уведомляет подписчиков при любом изменении.
|
||||
/// </summary>
|
||||
public sealed class ToolRegistryService
|
||||
{
|
||||
private readonly ConcurrentDictionary<string, bool> _moduleEnabled = new(StringComparer.OrdinalIgnoreCase);
|
||||
private readonly ConcurrentDictionary<string, bool> _toolEnabled = new(StringComparer.OrdinalIgnoreCase);
|
||||
private readonly List<IToolModule> _modules = [];
|
||||
private readonly Lock _modulesLock = new();
|
||||
|
||||
/// <summary>Вызывается при любом изменении состояния.</summary>
|
||||
public event Action? StateChanged;
|
||||
|
||||
// ── Регистрация ──────────────────────────────────────────────────────────
|
||||
|
||||
public void RegisterModule(IToolModule module)
|
||||
{
|
||||
lock (_modulesLock)
|
||||
{
|
||||
if (_modules.Any(m => string.Equals(m.ModuleName, module.ModuleName, StringComparison.OrdinalIgnoreCase)))
|
||||
return;
|
||||
|
||||
_modules.Add(module);
|
||||
}
|
||||
|
||||
_moduleEnabled.TryAdd(module.ModuleName, true);
|
||||
|
||||
foreach (var tool in module.ToolNames)
|
||||
{
|
||||
_toolEnabled.TryAdd(MakeKey(module.ModuleName, tool), true);
|
||||
}
|
||||
}
|
||||
|
||||
// ── Запросы состояния ────────────────────────────────────────────────────
|
||||
|
||||
public IReadOnlyList<IToolModule> GetModules()
|
||||
{
|
||||
lock (_modulesLock)
|
||||
{
|
||||
return _modules.ToList();
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsModuleEnabled(string moduleName) =>
|
||||
_moduleEnabled.GetValueOrDefault(moduleName, true);
|
||||
|
||||
public bool IsToolEnabled(string moduleName, string toolName) =>
|
||||
IsModuleEnabled(moduleName) &&
|
||||
_toolEnabled.GetValueOrDefault(MakeKey(moduleName, toolName), true);
|
||||
|
||||
// ── Переключение ─────────────────────────────────────────────────────────
|
||||
|
||||
public void SetModuleEnabled(string moduleName, bool enabled)
|
||||
{
|
||||
_moduleEnabled[moduleName] = enabled;
|
||||
StateChanged?.Invoke();
|
||||
}
|
||||
|
||||
public void SetToolEnabled(string moduleName, string toolName, bool enabled)
|
||||
{
|
||||
_toolEnabled[MakeKey(moduleName, toolName)] = enabled;
|
||||
StateChanged?.Invoke();
|
||||
}
|
||||
|
||||
public void ToggleModule(string moduleName) =>
|
||||
SetModuleEnabled(moduleName, !IsModuleEnabled(moduleName));
|
||||
|
||||
public void ToggleTool(string moduleName, string toolName) =>
|
||||
SetToolEnabled(moduleName, toolName, !IsToolEnabled(moduleName, toolName));
|
||||
|
||||
// ── Счётчики для Overview ─────────────────────────────────────────────────
|
||||
|
||||
public (int Active, int Total) GetToolCounts(string moduleName)
|
||||
{
|
||||
lock (_modulesLock)
|
||||
{
|
||||
var module = _modules.FirstOrDefault(m =>
|
||||
string.Equals(m.ModuleName, moduleName, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
if (module is null) return (0, 0);
|
||||
|
||||
var total = module.ToolNames.Count;
|
||||
var active = module.ToolNames.Count(t => IsToolEnabled(moduleName, t));
|
||||
return (active, total);
|
||||
}
|
||||
}
|
||||
|
||||
// ── Helpers ───────────────────────────────────────────────────────────────
|
||||
|
||||
private static string MakeKey(string module, string tool) => $"{module}::{tool}";
|
||||
}
|
||||
Reference in New Issue
Block a user