// // Main.swift // Zyquo Router // // Author: Simon-Pierre Boucher // Mail: contact@spboucher.ai // // Entry point. CLI modes (verification harness, vault seeding) hang off this // in later phases; otherwise the SwiftUI app launches. // // Deliberately a synchronous main: launching NSApplicationMain from an async // main() corrupts Swift concurrency's executor setup (background tasks stop // being scheduled), so CLI modes must drive their async work explicitly. // import Foundation @main enum Main { static func main() { let arguments = CommandLine.arguments if arguments.contains("--load-vault") { loadVaultFromEnvironment() exit(0) } if let flagIndex = arguments.firstIndex(of: "--serve") { // Headless mode for scripted verification (`ZyquoRouter --serve [port]`). let port = arguments.indices.contains(flagIndex + 1) ? Int(arguments[flagIndex + 1]) ?? 8787 : 8787 Task.detached { let localKeys = PersistenceService.shared.load([APIKeyRecord].self, from: "local-keys.json") ?? [] let routerConfig = PersistenceService.shared.load(RouterConfig.self, from: RouterConfig.fileName) ?? RouterConfig() let routes = Routes( router: RequestRouter( aliases: routerConfig.aliases, disabledIDs: routerConfig.disabledIDs, fallbackChains: routerConfig.fallbackChains ), auth: AuthMiddleware(keys: localKeys) ) let server = HTTPServer(host: "127.0.0.1", port: port) { request in await routes.handle(request) } do { try await server.run { print("Zyquo Router serving on http://127.0.0.1:\(port)/v1") } exit(0) } catch { FileHandle.standardError.write(Data("\(error.localizedDescription)\n".utf8)) exit(1) } } // Park the main thread servicing the main queue so MainActor work // can run (a blocking semaphore here would deadlock). dispatchMain() } ZyquoRouterApp.main() } /// Seeds the encrypted vault from environment variables (testing/setup). /// Key values are never printed — only which providers were stored. private static func loadVaultFromEnvironment() { let mapping: [(ProviderID, String)] = [ (.openai, "OPENAI_API_KEY"), (.anthropic, "ANTHROPIC_API_KEY"), (.xai, "XAI_API_KEY"), (.mistral, "MISTRAL_API_KEY"), (.gemini, "GEMINI_API_KEY"), (.qwen, "DASHSCOPE_API_KEY"), (.deepseek, "DEEPSEEK_API_KEY"), (.kimi, "KIMI_API_KEY"), (.perplexity, "PERPLEXITY_API_KEY"), (.together, "TOGETHER_API_KEY"), (.deepinfra, "DEEPINFRA_API_KEY"), (.cerebras, "CEREBRAS_API_KEY"), ] let store = SecureKeyStore() var stored: [String] = [] for (provider, variable) in mapping { if let value = ProcessInfo.processInfo.environment[variable], !value.isEmpty { try? store.setKey(value, for: provider) stored.append(provider.rawValue) } } print("Vault updated (\(stored.count) providers): \(stored.joined(separator: ", "))") } }