Skip to content

Commit 5a46746

Browse files
committed
Fixed restart; added run on startup
1 parent 154a435 commit 5a46746

5 files changed

Lines changed: 45 additions & 3 deletions

File tree

singularity/AppModel.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -467,6 +467,10 @@ final class AppModel: NSObject, ObservableObject {
467467
@Published var cfgAutoHideOnDefocus: Bool = ConfigService.autoHideOnDefocus()
468468
// Option: allow automatic updates at launch (persisted, defaults on)
469469
@Published var cfgAutoUpdateEnabled: Bool = ConfigService.autoUpdateEnabled()
470+
// Option: run on startup (persisted via SMAppService)
471+
@Published var cfgRunOnStartup: Bool = ConfigService.runOnStartup() {
472+
didSet { ConfigService.setRunOnStartup(cfgRunOnStartup) }
473+
}
470474
// Overlay level suppression for app-modal panels (e.g., NSOpenPanel) so we can keep overlay visible on defocus
471475
private var overlayLevelSuppressedCount: Int = 0
472476
private var overlayOriginalLevel: NSWindow.Level? = nil

singularity/ConfigService.swift

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import Foundation
22
import Security
3+
import ServiceManagement
34

45
enum ConfigService {
56
// Preferred: EXT API key used by the gateway
@@ -239,4 +240,30 @@ enum ConfigService {
239240
} catch { /* ignore individual write errors; best-effort */ }
240241
}
241242
}
243+
244+
// MARK: - Run on Startup (SMAppService)
245+
static func runOnStartup() -> Bool {
246+
return SMAppService.mainApp.status == .enabled
247+
}
248+
249+
static func setRunOnStartup(_ enabled: Bool) {
250+
do {
251+
if enabled {
252+
try SMAppService.mainApp.register()
253+
} else {
254+
try SMAppService.mainApp.unregister()
255+
}
256+
} catch {
257+
print("Failed to update run on startup status: \(error)")
258+
}
259+
}
260+
261+
static func enforceRunOnStartupDefault() {
262+
let key = "RunOnStartupInitialized"
263+
if !UserDefaults.standard.bool(forKey: key) {
264+
// First run (or migration), default to ON
265+
setRunOnStartup(true)
266+
UserDefaults.standard.set(true, forKey: key)
267+
}
268+
}
242269
}

singularity/PanelView.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6439,6 +6439,13 @@ extension PanelView {
64396439
Text("On click outside, hide overlay like ⌘B.")
64406440
.font(.caption)
64416441
.foregroundStyle(.secondary)
6442+
HStack {
6443+
Text("Run on Startup").frame(width: 180, alignment: .leading)
6444+
Toggle("", isOn: $model.cfgRunOnStartup).labelsHidden()
6445+
}
6446+
Text("Automatically launch Singularity when you log in.")
6447+
.font(.caption)
6448+
.foregroundStyle(.secondary)
64426449
HStack {
64436450
Text("Auto Update Singularity").frame(width: 180, alignment: .leading)
64446451
Toggle("", isOn: $model.cfgAutoUpdateEnabled).labelsHidden()

singularity/StartupUpdateCoordinator.swift

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -586,9 +586,12 @@ extension StartupUpdateCoordinator {
586586
}
587587

588588
nonisolated private static func relaunchApp(at appURL: URL) async throws {
589-
try await runProcess(tool: "/usr/bin/open", arguments: [appURL.path], treatNonZeroAsError: { code in
590-
AppUpdateError.processFailed(tool: "open", code: code)
591-
})
589+
// Use a detached shell process to wait for termination before opening
590+
let process = Process()
591+
process.executableURL = URL(fileURLWithPath: "/bin/sh")
592+
process.arguments = ["-c", "sleep 1; open \"$0\"", appURL.path]
593+
try process.run()
594+
592595
await MainActor.run {
593596
NSApp.terminate(nil)
594597
}

singularity/singularityApp.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ struct interview_coderApp: App {
3030
AppModel.globalFinishOnboarding = { onboardingActive = false }
3131
NetworkMonitor.shared.start()
3232
SupabaseAuthService.shared.start()
33+
ConfigService.enforceRunOnStartupDefault()
3334
}
3435
.onDisappear { AppModel.globalFinishOnboarding = nil }
3536
}

0 commit comments

Comments
 (0)