spb/zyquo-agent Public MIT
The autonomous agent that actually operates your Mac — plans, runs real commands, verifies its own work.
Swift 94.7%
Shell 4.1%
Python 0.7%
Makefile 0.5%
1//2// MainWindowView.swift3// Zyquo Agent4//5// Author: Simon-Pierre Boucher6// Mail: contact@spboucher.ai7//8// The command-center root: translucent 260pt sidebar (NavigationSplitView's9// native sidebar material) + the task detail. With no task selected, the10// "What should I do on your Mac?" hero creates one. Hosts the ⌘K command11// palette overlay and the template browser sheet; the root re-identifies on12// accent change so every ZyquoColor.accent token redraws immediately.13//1415import SwiftUI1617struct MainWindowView: View {18 @EnvironmentObject private var store: TaskStore19 @EnvironmentObject private var catalog: ModelCatalog20 @EnvironmentObject private var appearance: AppearanceStore21 @EnvironmentObject private var settings: AgentSettingsStore22 @EnvironmentObject private var templates: TemplateStore23 @EnvironmentObject private var personas: PersonaStore24 @EnvironmentObject private var uiState: AppUIState2526 var body: some View {27 ZStack(alignment: .top) {28 NavigationSplitView {29 SidebarView()30 .navigationSplitViewColumnWidth(31 min: ZyquoMetrics.sidebarWidth,32 ideal: ZyquoMetrics.sidebarWidth,33 max: 36034 )35 } detail: {36 if let id = store.selectedID, store.task(id: id) != nil {37 TaskDetailView(taskID: id)38 } else {39 AgentEmptyStateView(40 model: defaultModel,41 safetyMode: settings.settings.defaultSafetyMode,42 personaName: nil,43 onSelectModel: { model in44 store.newTask(model: model, safetyMode: settings.settings.defaultSafetyMode)45 },46 onSelectSafetyMode: { mode in47 store.newTask(model: defaultModel, safetyMode: mode)48 },49 onSelectPersona: { persona in50 newTask(with: persona)51 },52 onBrowseTemplates: {53 uiState.showTemplateBrowser = true54 },55 onSuggestion: { prompt in56 store.pendingDraft = prompt57 store.newTask(model: defaultModel, safetyMode: settings.settings.defaultSafetyMode)58 }59 )60 }61 }62 if uiState.showCommandPalette {63 paletteOverlay64 }65 }66 .frame(67 minWidth: ZyquoMetrics.windowMinWidth,68 minHeight: ZyquoMetrics.windowMinHeight69 )70 .sheet(isPresented: $uiState.showTemplateBrowser) {71 TemplateBrowserView { prompt, safetyMode in72 store.pendingDraft = prompt73 store.newTask(model: defaultModel, safetyMode: safetyMode)74 }75 }76 .preferredColorScheme(appearance.themeMode.colorScheme)77 .tint(appearance.accentColor)78 .id(appearance.accent)79 }8081 /// New tasks start with the persisted default agent model.82 private var defaultModel: AIModel? {83 settings.defaultAgentModel(in: catalog)84 }8586 private func newTask(with persona: Persona?) {87 let model: AIModel?88 if let persona, let id = persona.modelID, let provider = persona.provider,89 let preferred = catalog.model(id: id, provider: provider) {90 model = preferred91 } else {92 model = defaultModel93 }94 store.newTask(95 model: model,96 safetyMode: persona?.safetyMode ?? settings.settings.defaultSafetyMode,97 personaID: persona?.id98 )99 }100101 // MARK: - ⌘K palette102103 private var paletteOverlay: some View {104 ZStack(alignment: .top) {105 // Click-away scrim (transparent, keeps the window visible).106 Color.black.opacity(0.001)107 .onTapGesture { uiState.showCommandPalette = false }108 CommandPaletteView(items: paletteItems) {109 uiState.showCommandPalette = false110 }111 .padding(.top, ZyquoSpacing.xxl * 2)112 }113 .ignoresSafeArea()114 .transition(.opacity)115 }116117 private var paletteItems: [PaletteItem] {118 var items: [PaletteItem] = [119 PaletteItem(id: "action-new-task", kind: .action, title: "New Task", subtitle: "⌘N", symbolName: "plus.circle") {120 store.newTask(model: defaultModel, safetyMode: settings.settings.defaultSafetyMode)121 },122 PaletteItem(id: "action-settings", kind: .action, title: "Open Settings", subtitle: "⌘,", symbolName: "gearshape") {123 SettingsOpener.open()124 },125 PaletteItem(id: "action-templates", kind: .action, title: "Browse Templates", subtitle: nil, symbolName: "square.grid.2x2") {126 uiState.showTemplateBrowser = true127 },128 PaletteItem(id: "action-audit", kind: .action, title: "Open Audit Log", subtitle: "⌘⇧A", symbolName: "list.bullet.rectangle") {129 uiState.requestAuditLog()130 },131 PaletteItem(id: "action-drawer", kind: .action, title: "Toggle Activity Drawer", subtitle: nil, symbolName: "terminal") {132 uiState.requestDrawerToggle()133 },134 PaletteItem(id: "action-plan", kind: .action, title: "Toggle Plan Panel", subtitle: nil, symbolName: "sidebar.right") {135 uiState.requestPlanToggle()136 },137 ]138 for template in templates.all {139 items.append(PaletteItem(140 id: "template-\(template.id.uuidString)",141 kind: .template,142 title: template.title,143 subtitle: template.category.displayName,144 symbolName: template.displaySymbol145 ) {146 if template.variables.isEmpty {147 store.pendingDraft = template.prompt148 store.newTask(model: defaultModel, safetyMode: template.suggestedSafetyMode)149 } else {150 uiState.showTemplateBrowser = true151 }152 })153 }154 for task in store.tasks.prefix(60) {155 items.append(PaletteItem(156 id: "task-\(task.id.uuidString)",157 kind: .task,158 title: task.title,159 subtitle: task.status.displayName,160 symbolName: "checklist"161 ) {162 store.selectedID = task.id163 })164 }165 return items166 }167}168