diff options
Diffstat (limited to 'menubar/model.swift')
| -rw-r--r-- | menubar/model.swift | 52 |
1 files changed, 52 insertions, 0 deletions
diff --git a/menubar/model.swift b/menubar/model.swift index e891697..da5ad15 100644 --- a/menubar/model.swift +++ b/menubar/model.swift @@ -165,6 +165,58 @@ func tmux(_ args: [String]) -> String? { let dinggerBinary = environment["DINGGER_BIN"] ?? (NSHomeDirectory() + "/.local/bin/dingger") +// MARK: restore offer + +/// tmux sessions the daemon offers to restore after tmux stopped +/// (`offer.json`, written by `dingger watch`). +struct RestoreOffer: Decodable, Equatable { + struct Session: Decodable, Equatable { + let name: String + let windows: Int + let panes: Int + let agents: Int + } + let saved_at: Int + let sessions: [Session] + let agents: Int + let interrupted: Int + + /// "Restore 9 sessions · 22 agents" + var title: String { + var text = "Restore \(sessions.count) \(sessions.count == 1 ? "session" : "sessions")" + if agents > 0 { text += " · \(agents) \(agents == 1 ? "agent" : "agents")" } + return text + } + + /// "saved 13:01 · 1 was mid-turn" + var detail: String { + let formatter = DateFormatter() + let saved = Date(timeIntervalSince1970: TimeInterval(saved_at) / 1000) + formatter.dateFormat = Calendar.current.isDateInToday(saved) ? "HH:mm" : "MMM d, HH:mm" + var parts = ["tmux stopped · saved \(formatter.string(from: saved))"] + if interrupted > 0 { parts.append("\(interrupted) \(interrupted == 1 ? "was" : "were") mid-turn") } + return parts.joined(separator: " · ") + } +} + +let stateDirectory = environment["DINGGER_STATE_DIR"] ?? (NSHomeDirectory() + "/.local/state/dingger") + +func fetchRestoreOffer() -> RestoreOffer? { + guard let data = FileManager.default.contents(atPath: stateDirectory + "/offer.json") else { return nil } + return try? JSONDecoder().decode(RestoreOffer.self, from: data) +} + +/// Run `dingger <args>` through the user's login shell, the way a terminal +/// starts tmux: restored panes inherit this environment (PATH, LANG), and +/// launchd's is bare. DINGGER_RESTORE_DIRECT runs it directly (tests). +func runDinggerInLoginShell(_ args: [String]) -> (ok: Bool, output: String) { + if environment["DINGGER_RESTORE_DIRECT"] != nil { + return runReporting(dinggerBinary, args) + } + let shell = getpwuid(getuid()).flatMap { String(validatingUTF8: $0.pointee.pw_shell) } ?? "/bin/zsh" + return runReporting(shell, ["--login", "-i", "-c", "exec \"$0\" \"$@\"", dinggerBinary] + args) +} + private let home = NSHomeDirectory() /// Every agent pane, in herdr's priority order, oldest waiting first. |
