tv-anarchy/Sources/TVAnarchyCore/HelperDeployment.swift
Natalie 4466ff72cd feat(@applications/tv-anarchy): implement parallel fleet completion modules
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
2026-06-09 21:30:14 -07:00

41 lines
2 KiB
Swift

import CryptoKit
import Foundation
/// Answers "is the helper a fleet device runs the same one vendored in this
/// repo?" the Devices tab's freshness badge. The repo copy is the source of
/// truth (mcp/README's deploy step ships it byte-for-byte), so freshness is a
/// straight content-hash comparison: the device's `stats` report carries the
/// sha256 of the script that produced it; the app hashes the vendored source.
/// No version constants to bump, nothing that can drift.
public enum HelperDeployment {
public enum Freshness: Equatable, Sendable {
case current
/// `deployed` is the device-reported hash; nil means the deployed helper
/// predates self-reporting entirely (necessarily stale).
case outdated(deployed: String?)
}
/// Repo source for each known helper bin, keyed by basename (the bin path on
/// the device e.g. `/usr/local/bin/black-tv` names the deployed copy).
private static let vendoredSources: [String: String] = [
"black-tv": "mcp/src/blacktv/black-tv.sh",
]
/// sha256 of the vendored source for `bin`, or nil when the bin is not a
/// known helper or the repo checkout is absent (an installed app without a
/// repo can't judge freshness the badge simply stays off).
public static func expectedSHA(forBin bin: String) -> String? {
let name = (bin as NSString).lastPathComponent
guard let rel = vendoredSources[name],
let data = try? Data(contentsOf: RepoPaths.root.appendingPathComponent(rel))
else { return nil }
return SHA256.hash(data: data).map { String(format: "%02x", $0) }.joined()
}
/// Judge a device report against an expectation. nil expectation (unknown
/// helper / no repo) nil: freshness can't be judged, show nothing.
public static func freshness(expected: String?, reported: String?) -> Freshness? {
guard let expected else { return nil }
return reported == expected ? .current : .outdated(deployed: reported)
}
}