Files
gronodandDevin <158243242+devin-ai-integration[bot]@users.noreply.github.com> a7f13542ae feat(alerts): implement threshold alert engine and Notification Center integration (fixes #24)
Introduce Sources/Intelligence with an @Observable AlertEngine that evaluates
five configurable rules (CPU temperature, fan stall, low memory, low storage,
low battery) against a Sendable AlertEvaluationContext built after each
telemetry decode pass. Breached conditions dispatch through a mockable
AlertNotificationDispatching protocol to UNUserNotificationCenter with
per-alert cooldowns, edge-triggered resolve detection, and a capped
in-memory history log.

Add a macOS Settings scene (AlertsSettingsView) for thresholds, cooldown,
permission status, and test notifications; a new Alerts and Notifications
sidebar tab with active-alert cards and the history log; header and menu bar
warning indicators; and an AppNavigationBus so notification actions
(Open MacMonitor, View Processes) steer the main window.

Also fix the memory snapshot decode to read memoryPressureStatus so
pressureLevel is populated correctly.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-08 13:53:48 +01:00

42 lines
1.2 KiB
Swift

import SwiftUI
/// Bridges app-lifecycle events into SwiftUI: requests Notification Center
/// authorization once at launch so threshold alerts can post banners.
final class AppDelegate: NSObject, NSApplicationDelegate {
func applicationDidFinishLaunching(_ notification: Notification) {
if AlertEngine.shared.configuration.alertsEnabled {
AlertEngine.shared.requestNotificationAuthorization()
}
}
}
@main
struct MacMonitorApp: App {
@NSApplicationDelegateAdaptor(AppDelegate.self) private var appDelegate
@State private var store = SystemTelemetryStore.shared
var body: some Scene {
WindowGroup {
ContentView()
}
.windowStyle(.titleBar)
.windowToolbarStyle(.unified)
.defaultSize(width: 960, height: 640)
MenuBarExtra {
QuickGlancePopoverView(store: store)
} label: {
MenuBarStatusView(
cpuLoad: store.cpuLoad.totalLoad,
memoryPercent: store.memory.utilizationPercentage,
activeAlertCount: store.alertEngine.activeAlerts.count
)
}
.menuBarExtraStyle(.window)
Settings {
AlertsSettingsView()
}
}
}