native macOS codings agent orchestrator prowl.onev.cat
Something went wrong. Try again.
3.2 kB · 82 lines
Swift
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283import Foundation
// Decides which worktrees a periodic refresh asks GitHub about. A pull request whose state can// change soon is refreshed on every sweep; one that has settled is asked about less often, so the// batched query stays small on an account other tools share.nonisolated enum PullRequestRefreshCadence { /// An open pull request with nothing in flight: reviews and new pushes still change it. static let settledOpenInterval: Duration = .seconds(180) /// No pull request yet: one appears when someone opens it, from Prowl or elsewhere. static let noPullRequestInterval: Duration = .seconds(300) /// Merged or closed: only a reopened or new pull request for the same branch changes it. static let finishedInterval: Duration = .seconds(1_800)
/// What GitHub's last complete answer tells a periodic refresh about one worktree: the branch it /// answered for, when, and how long the answer stays good. The interval comes from the answer as /// GitHub gave it, not from the pull request on screen, which keeps the previous mergeability /// while GitHub still computes the new one. nonisolated struct Checkpoint: Equatable, Sendable { let branch: String let answeredAt: Date /// nil means every sweep. let interval: Duration?
init(branch: String, pullRequest: GithubPullRequest?, answeredAt: Date) { self.branch = branch self.answeredAt = answeredAt self.interval = PullRequestRefreshCadence.interval(for: pullRequest) } }
static func isDue( branch: String, checkpoint: Checkpoint?, now: Date, isSelected: Bool ) -> Bool { if isSelected { return true } // A checkpoint answers for the branch it was recorded for; a switched branch starts over. guard let checkpoint, checkpoint.branch == branch else { return true } guard let interval = checkpoint.interval else { return true } return now.timeIntervalSince(checkpoint.answeredAt) >= interval.seconds }
/// nil means every sweep. static func interval(for pullRequest: GithubPullRequest?) -> Duration? { guard let pullRequest else { return noPullRequestInterval } switch pullRequest.state.uppercased() { case "MERGED", "CLOSED": return finishedInterval default: return isActive(pullRequest) ? nil : settledOpenInterval } }
// Checks still running, GitHub still computing mergeability, or a place in the merge queue. A background // refresh carries only the per-state check counts, so the breakdown is read, never the check list. private static func isActive(_ pullRequest: GithubPullRequest) -> Bool { let checks = pullRequest.checkBreakdown if checks.inProgress + checks.expected > 0 { return true } if pullRequest.mergeable?.uppercased() == "UNKNOWN" || pullRequest.mergeStateStatus?.uppercased() == "UNKNOWN" { return true } return pullRequest.mergeQueueEntry != nil }}
extension Duration { nonisolated fileprivate var seconds: TimeInterval { let parts = components return TimeInterval(parts.seconds) + TimeInterval(parts.attoseconds) / 1e18 }}