mirror of
https://github.com/AgentSeal/codeburn.git
synced 2026-04-30 16:09:39 +00:00
Remove the broken "Connect Claude" / "Reconnect Claude" buttons from the Plan pane -- they opened a terminal session that did nothing useful for already-logged-in users. Keep only the "Retry" button. Add an auto-update checker that queries GitHub releases every 2 days in the background. When a newer menubar build is available, an "Update" pill appears in the header. Clicking it runs the existing installer flow (download, replace, relaunch) with no manual steps.
87 lines
2.9 KiB
Swift
87 lines
2.9 KiB
Swift
import Foundation
|
|
import Observation
|
|
|
|
private let releasesAPI = "https://api.github.com/repos/getagentseal/codeburn/releases/latest"
|
|
private let checkIntervalSeconds: TimeInterval = 2 * 24 * 60 * 60
|
|
private let lastCheckKey = "UpdateChecker.lastCheckDate"
|
|
private let cachedVersionKey = "UpdateChecker.latestVersion"
|
|
|
|
@MainActor
|
|
@Observable
|
|
final class UpdateChecker {
|
|
var latestVersion: String?
|
|
var isUpdating = false
|
|
var updateError: String?
|
|
|
|
var updateAvailable: Bool {
|
|
guard let latest = latestVersion else { return false }
|
|
let current = currentVersion
|
|
return !current.isEmpty && current != "dev" && latest != current
|
|
}
|
|
|
|
var currentVersion: String {
|
|
Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? ""
|
|
}
|
|
|
|
func checkIfNeeded() async {
|
|
let lastCheck = UserDefaults.standard.double(forKey: lastCheckKey)
|
|
let now = Date().timeIntervalSince1970
|
|
if now - lastCheck < checkIntervalSeconds {
|
|
latestVersion = UserDefaults.standard.string(forKey: cachedVersionKey)
|
|
return
|
|
}
|
|
await check()
|
|
}
|
|
|
|
func check() async {
|
|
guard let url = URL(string: releasesAPI) else { return }
|
|
var request = URLRequest(url: url)
|
|
request.setValue("codeburn-menubar-updater", forHTTPHeaderField: "User-Agent")
|
|
request.setValue("application/vnd.github+json", forHTTPHeaderField: "Accept")
|
|
|
|
do {
|
|
let (data, _) = try await URLSession.shared.data(for: request)
|
|
let release = try JSONDecoder().decode(GitHubRelease.self, from: data)
|
|
guard let asset = release.assets.first(where: {
|
|
$0.name.hasPrefix("CodeBurnMenubar-") && $0.name.hasSuffix(".zip")
|
|
}) else { return }
|
|
|
|
let version = asset.name
|
|
.replacingOccurrences(of: "CodeBurnMenubar-", with: "")
|
|
.replacingOccurrences(of: ".zip", with: "")
|
|
|
|
latestVersion = version
|
|
UserDefaults.standard.set(Date().timeIntervalSince1970, forKey: lastCheckKey)
|
|
UserDefaults.standard.set(version, forKey: cachedVersionKey)
|
|
} catch {
|
|
NSLog("CodeBurn: update check failed: \(error)")
|
|
}
|
|
}
|
|
|
|
func performUpdate() {
|
|
isUpdating = true
|
|
updateError = nil
|
|
|
|
let process = CodeburnCLI.makeProcess(subcommand: ["menubar", "--force"])
|
|
process.standardOutput = FileHandle.nullDevice
|
|
process.standardError = FileHandle.nullDevice
|
|
|
|
do {
|
|
try process.run()
|
|
} catch {
|
|
isUpdating = false
|
|
updateError = error.localizedDescription
|
|
NSLog("CodeBurn: update spawn failed: \(error)")
|
|
}
|
|
}
|
|
}
|
|
|
|
private struct GitHubRelease: Decodable {
|
|
let tag_name: String
|
|
let assets: [GitHubAsset]
|
|
}
|
|
|
|
private struct GitHubAsset: Decodable {
|
|
let name: String
|
|
let browser_download_url: String
|
|
}
|