claire-tray/src/client/DaemonControl.swift

36 lines
1.3 KiB
Swift
Raw Normal View History

import AppKit
import Foundation
/// OS-level control of the `claire web` daemon and dashboard. All entry points
/// are nonisolated and safe to call from a detached task they shell out to
/// `launchctl` / open a URL and don't touch UI state.
enum DaemonControl {
/// Restart the daemon: `launchctl kickstart -k gui/<uid>/<label>`.
/// `-k` kills the running instance first, then relaunches it under launchd.
/// This is the watchdog's recovery action and the "Restart" menu item.
static func restartDaemon(label: String) {
let status = run(["/bin/launchctl", "kickstart", "-k", "gui/\(getuid())/\(label)"])
NSLog("ClaireTray: kickstart \(label) -> exit \(status)")
}
static func openDashboard(baseURL: String) {
guard let url = URL(string: baseURL) else { return }
NSWorkspace.shared.open(url)
}
@discardableResult
private static func run(_ argv: [String]) -> Int32 {
let p = Process()
p.executableURL = URL(fileURLWithPath: argv[0])
p.arguments = Array(argv.dropFirst())
do {
try p.run()
p.waitUntilExit()
return p.terminationStatus
} catch {
NSLog("ClaireTray: process \(argv) failed: \(error)")
return -1
}
}
}