using ClawdDotNet.Core.Api; using ClawdDotNet.Core.Config; using ClawdDotNet.Core.Engine; using ClawdDotNet.Core.Logging; using ClawdDotNet.Core.Security; using ClawdDotNet.Core.Scheduling; using ClawdDotNet.Core.Tools; using ClawdDotNet.Core.State; using ClawdDotNet.Core.Storage; using ClawdDotNet.Core.Memory; using ClawdDotNet.Services; using ClawdDotNet.Tools.FileRW; using ClawdDotNet.Tools.Telegram; using ClawdDotNet.Tools.Mail; using ClawdDotNet.Tools.Database; using ClawdDotNet.Tools.FTP; using ClawdDotNet.Tools.DirectAPI; using ClawdDotNet.Tools.WebFetch; using ClawdDotNet.Tools.WebMonitor; using ClawdDotNet.Tools.AgentComm; using ClawdDotNet.Tools.AgentSpawn; using ClawdDotNet.Tools.SocialMediaManager; using ClawdDotNet.Tools.AgentEditor; using ClawdDotNet.Tools.TelegramClient; using ClawdDotNet.UI; using Microsoft.Extensions.Logging; namespace ClawdDotNet; internal static class Program { [STAThread] static void Main(string[] args) { ApplicationConfiguration.Initialize(); // ─── 0. Embedded UI extrahieren ─── EmbeddedUiManager.ExtractToTemp(); // ─── 1. App-Settings laden ─── var settingsManager = new SettingsManager(); settingsManager.Load(); var appSettings = settingsManager.AppSettings; // ─── 2. InstanceDirectoryManager erstellen ─── var instancesDir = Path.GetFullPath(appSettings.InstancesDirectory); var dirManager = new InstanceDirectoryManager(instancesDir); // ─── 3. Instanz-Verzeichnis auswählen ─── string instancePath; #if DEBUG // Im Debug-Modus: Dev-Instanz automatisch erstellen/starten const string devInstanceName = "Dev"; instancePath = dirManager.GetInstancePath(devInstanceName); if (!Directory.Exists(instancePath)) { dirManager.CreateInstance(devInstanceName); } #else // Im Release-Modus: InstanceManager anzeigen var instanceManager = new frm_InstanceManager(dirManager, settingsManager); var dialogResult = instanceManager.ShowDialog(); if (dialogResult != DialogResult.OK || string.IsNullOrWhiteSpace(instanceManager.SelectedInstancePath)) { return; // Benutzer hat abgebrochen } instancePath = instanceManager.SelectedInstancePath; instanceManager.Dispose(); #endif // ─── 4. Instanz-Config aus Verzeichnisstruktur laden ─── InstanceConfig instanceConfig; try { instanceConfig = dirManager.LoadInstanceConfig(instancePath); } catch (Exception ex) { MessageBox.Show( $"Fehler beim Laden der Instanz:\n{instancePath}\n\n{ex.Message}", "ClawdDotNet – Fehler", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } // ─── 5. Logging-System initialisieren ─── var logDir = Path.GetFullPath( !string.IsNullOrWhiteSpace(instanceConfig.LogDirectory) ? instanceConfig.LogDirectory : appSettings.LogDirectory); var minLevel = Enum.TryParse( appSettings.MinimumLogLevel, true, out var ml) ? ml : ClawdDotNet.Core.Logging.LogLevel.Info; var loggerFactory = LoggingExtensions.CreateClawdLoggerFactory(logDir, minLevel); var coreLogger = loggerFactory.CreateLogger("ClawdDotNet.Core.Startup"); coreLogger.LogInformation("ClawdDotNet startet – Instanz: {Instance} ({Id})", instanceConfig.InstanceName, instanceConfig.InstanceId); coreLogger.LogInformation("Instanz-Verzeichnis: {Path}", instancePath); // ─── 6. Core-Komponenten erzeugen ─── var toolRegistry = new ToolRegistry(); toolRegistry.Register(new FileRWTool()); toolRegistry.Register(new TelegramTool()); toolRegistry.Register(new MailTool()); toolRegistry.Register(new DatabaseTool()); toolRegistry.Register(new FTPTool()); toolRegistry.Register(new DirectApiTool()); toolRegistry.Register(new WebFetchTool()); toolRegistry.Register(new WebMonitorTool()); toolRegistry.Register(new AgentCommTool()); toolRegistry.Register(new SocialMediaManagerTool()); toolRegistry.Register(new AgentSpawnTool()); toolRegistry.Register(new AgentEditorTool()); toolRegistry.Register(new ClawdDotNet.Tools.Memory.MemoryTool()); // ─── 6a. TelegramClient (MTProto User-API) ─── TelegramClientManager? tgClientManager = null; if (instanceConfig.TelegramClient is not null) { tgClientManager = new TelegramClientManager( instanceConfig, instancePath, loggerFactory.CreateLogger("ClawdDotNet.Tools.TelegramClient")); toolRegistry.Register(new TelegramClientTool(tgClientManager)); coreLogger.LogInformation("TelegramClient-Tool registriert"); } var permissionGate = new PermissionGate(); // TODO: Tools aus tools/ Ordner laden // foreach (var toolDll in Directory.GetFiles("./tools", "*.dll")) // LoadToolPlugin(toolDll, toolRegistry); OpenRouterClient? openRouterClient = null; AgentEngine? agentEngine = null; AgentScheduler? agentScheduler = null; ToolJobScheduler? toolJobScheduler = null; if (!string.IsNullOrWhiteSpace(instanceConfig.OpenRouterApiKey)) { openRouterClient = new OpenRouterClient( instanceConfig.OpenRouterApiKey, loggerFactory.CreateLogger("ClawdDotNet.Core.Api.OpenRouterClient")); // ModelTypeConverter mit dem Client verbinden für PropertyGrid-Dropdown ClawdDotNet.Models.ModelTypeConverter.Client = openRouterClient; // ─── 6.1. Speicher initialisieren ─── // Eine Datenbank je Instanz; StateStore und Gedächtnis teilen sie sich. var storage = new SqliteStorage(Path.Combine(instancePath, "state.db")); var stateStore = new SqliteStateStore(storage); var memoryRepository = new SqliteMemoryRepository(storage); agentEngine = new AgentEngine( openRouterClient, toolRegistry, permissionGate, stateStore, loggerFactory, memoryRepository); agentEngine.SetAgentConfigProvider( () => instanceConfig.Agents, instanceConfig.InstanceId, agentId => { var agent = instanceConfig.Agents.FirstOrDefault(a => a.AgentId == agentId); if (agent is null) return null; return string.IsNullOrWhiteSpace(agent.AgentDir) ? null : agent.AgentDir; }); agentEngine.LoadPersistedChats(); agentScheduler = new AgentScheduler(agentEngine, instanceConfig.InstanceId, loggerFactory); agentScheduler.RegisterAll(instanceConfig.Agents); toolJobScheduler = new ToolJobScheduler(agentEngine, toolRegistry, stateStore, loggerFactory, instanceConfig.InstanceId); toolJobScheduler.RegisterAll(instanceConfig.Agents); coreLogger.LogInformation("AgentEngine und Scheduler erstellt, Chat-Verläufe geladen"); } else { coreLogger.LogWarning("Kein OpenRouter API-Key konfiguriert – Agenten sind deaktiviert"); } // ─── 6b. TelegramClient verbinden (Session oder interaktiver Login) ─── if (tgClientManager is not null) { tgClientManager.OnLoginCodeRequired += async (prompt) => { string? code = null; await Task.Run(() => { code = Microsoft.VisualBasic.Interaction.InputBox( prompt, "Telegram Verifizierung", ""); }); return code ?? ""; }; tgClientManager.On2FAPasswordRequired += async () => { string? pw = null; await Task.Run(() => { pw = Microsoft.VisualBasic.Interaction.InputBox( "Bitte 2FA-Passwort eingeben:", "Telegram 2FA", ""); }); return pw ?? ""; }; try { tgClientManager.ConnectAsync(CancellationToken.None) .GetAwaiter().GetResult(); } catch (Exception ex) { coreLogger.LogError(ex, "Telegram: Login fehlgeschlagen"); } } // ─── 7. MainForm starten ─── var form = new frm_main( settingsManager, instanceConfig, instancePath, logDir, loggerFactory, toolRegistry, dirManager, agentEngine, agentScheduler, toolJobScheduler); Application.Run(form); // ─── 8. Aufräumen ─── coreLogger.LogInformation("ClawdDotNet wird beendet"); if (toolJobScheduler is not null) toolJobScheduler.DisposeAsync().AsTask().GetAwaiter().GetResult(); if (agentScheduler is not null) agentScheduler.DisposeAsync().AsTask().GetAwaiter().GetResult(); if (tgClientManager is not null) tgClientManager.DisposeAsync().AsTask().GetAwaiter().GetResult(); openRouterClient?.Dispose(); loggerFactory.Dispose(); } }