relay-codex 0.5.2 → 0.5.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -8,8 +8,8 @@ Friends can run `npx relay-codex` or install it with `npm install -g relay-codex
8
8
  The GitHub repository is enough for friends to install or try Relay:
9
9
 
10
10
  ```sh
11
- npm install -g github:blackspider-ops/relay#v0.5.2
12
- npx --yes github:blackspider-ops/relay#v0.5.2 --version
11
+ npm install -g github:blackspider-ops/relay#v0.5.3
12
+ npx --yes github:blackspider-ops/relay#v0.5.3 --version
13
13
  ```
14
14
 
15
15
  `npx` runs packages; it is not a separate publishing service. Publishing
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "relay-codex",
3
- "version": "0.5.2",
3
+ "version": "0.5.3",
4
4
  "description": "Keep your Codex sessions moving between your own accounts.",
5
5
  "license": "MIT",
6
6
  "author": "blackspider-ops",
package/python/Menu.swift CHANGED
@@ -127,8 +127,28 @@ final class MenuController: NSObject, NSApplicationDelegate, NSMenuDelegate {
127
127
  entry.target = self; entry.representedObject = args
128
128
  entry.identifier = NSUserInterfaceItemIdentifier("action:" + args.joined(separator: "|")); menu.addItem(entry)
129
129
  }
130
+ struct TimingRow {
131
+ let title: String
132
+ let at: Double?
133
+ }
134
+ static func timestamp(_ value: Any?) -> Double? {
135
+ guard let seconds = value as? Double, seconds.isFinite, seconds > 0 else { return nil }
136
+ return seconds
137
+ }
138
+ static func accountTimingRows(_ account: [String: Any]) -> [TimingRow] {
139
+ var rows: [TimingRow] = []
140
+ if let primary = account["primary"] as? [String: Any], let at = timestamp(primary["resetsAt"]) {
141
+ rows.append(TimingRow(title: "Short reset", at: at))
142
+ }
143
+ if let secondary = account["secondary"] as? [String: Any], let at = timestamp(secondary["resetsAt"]) {
144
+ rows.append(TimingRow(title: "Weekly reset", at: at))
145
+ }
146
+ if let at = timestamp(account["next_check"]) { rows.append(TimingRow(title: "Next allowance check", at: at)) }
147
+ else { rows.append(TimingRow(title: "Allowance checked when needed", at: nil)) }
148
+ return rows
149
+ }
130
150
  func date(_ value: Any?) -> String {
131
- guard let seconds = value as? Double else { return "unknown" }
151
+ guard let seconds = MenuController.timestamp(value) else { return "Not available" }
132
152
  return Date(timeIntervalSince1970: seconds).formatted(date: .abbreviated, time: .shortened)
133
153
  }
134
154
  func countdown(_ title: String, value: Any, into menu: NSMenu) {
@@ -140,8 +160,9 @@ final class MenuController: NSObject, NSApplicationDelegate, NSMenuDelegate {
140
160
  for entry in menu.items {
141
161
  if let data = entry.representedObject as? [String: Any], let at = data["at"] as? Double, let label = data["label"] as? String {
142
162
  let seconds = max(0, Int(at - Date().timeIntervalSince1970))
143
- let remaining = seconds < 60 ? "under a minute" : seconds < 3600 ? "\(seconds / 60)m" : "\(seconds / 3600)h \((seconds % 3600) / 60)m"
144
- entry.title = label + ": " + (seconds == 0 ? "due now" : "in " + remaining) + " · " + date(at)
163
+ let remaining = seconds < 60 ? "under a minute" : seconds < 3600 ? "\(seconds / 60)m" : seconds < 86400 ? "\(seconds / 3600)h \((seconds % 3600) / 60)m" : "\(seconds / 86400)d \((seconds % 86400) / 3600)h"
164
+ let elapsed = label.contains("reset") ? "reported time passed" : "due now"
165
+ entry.title = label + ": " + (seconds == 0 ? elapsed : "in " + remaining) + " · " + date(at)
145
166
  }
146
167
  if let child = entry.submenu { updateTimes(child) }
147
168
  }
@@ -168,8 +189,12 @@ final class MenuController: NSObject, NSApplicationDelegate, NSMenuDelegate {
168
189
  if let email = account["email"] as? String { text(email, into: submenu) }
169
190
  text("Short window: \(remaining)", into: submenu)
170
191
  if weekly != "?" { text("Weekly window: \(weekly) left", into: submenu) }
171
- if let reset = account["next_check"] { countdown("Next check", value: reset, into: submenu) }
172
- text("Last checked: \(date(account["usage_checked_at"]))", into: submenu)
192
+ for row in MenuController.accountTimingRows(account) {
193
+ if let at = row.at { countdown(row.title, value: at, into: submenu) }
194
+ else { text(row.title, into: submenu) }
195
+ }
196
+ let lastChecked = MenuController.timestamp(account["usage_checked_at"]).map { date($0) } ?? "Not checked yet"
197
+ text("Last checked: \(lastChecked)", into: submenu)
173
198
  let entry = NSMenuItem(title: "\(name) · \(label)", action: nil, keyEquivalent: "")
174
199
  entry.identifier = NSUserInterfaceItemIdentifier("account:" + (account["id"] as? String ?? name))
175
200
  entry.submenu = submenu; menu.addItem(entry)
@@ -182,7 +207,7 @@ final class MenuController: NSObject, NSApplicationDelegate, NSMenuDelegate {
182
207
  let submenu = NSMenu()
183
208
  text("Account: \(session["account_name"] as? String ?? session["account"] as? String ?? "unknown")", into: submenu)
184
209
  text("Model: \(session["model"] as? String ?? "unknown")", into: submenu)
185
- if let next = session["next_wake"] { countdown("Next action", value: next, into: submenu) }
210
+ if let next = MenuController.timestamp(session["next_wake"]) { countdown("Next action", value: next, into: submenu) }
186
211
  if let reason = session["reason"] as? String { text(reason.replacingOccurrences(of: "_", with: " "), into: submenu) }
187
212
  action("Copy reconnect command", args: ["copy", "relay attach " + id], into: submenu)
188
213
  action("Pause recovery", args: ["pause", id, "--wait"], into: submenu)
@@ -199,6 +224,7 @@ final class MenuController: NSObject, NSApplicationDelegate, NSMenuDelegate {
199
224
  login.state = FileManager.default.fileExists(atPath: NSHomeDirectory() + "/Library/LaunchAgents/local.relay.menu.plist") ? .on : .off
200
225
  menu.addItem(login)
201
226
  let quit = NSMenuItem(title: "Quit Relay menu", action: #selector(quitMenu), keyEquivalent: "q"); quit.target = self; menu.addItem(quit)
227
+ updateTimes(menu)
202
228
  if let visible = item.menu { MenuController.synchronise(visible, with: menu) }
203
229
  else { item.menu = menu }
204
230
  }
@@ -251,7 +277,11 @@ if CommandLine.arguments.contains("--self-check") {
251
277
  MenuController.synchronise(visible, with: replacement)
252
278
  let safeIdentity = visible.items[0] !== existing && visible.items[0].identifier == newItem.identifier
253
279
  print("Session action identity preserved: \(safeIdentity)")
254
- exit(normal != nil && attention != nil && liveUpdate && safeIdentity ? 0 : 1)
280
+ let timing = MenuController.accountTimingRows(["next_check": NSNull(), "primary": ["resetsAt": 2000000000.0], "secondary": ["resetsAt": 2000100000.0]])
281
+ let scheduled = MenuController.accountTimingRows(["next_check": 2000200000.0])
282
+ let correctTiming = timing.map { $0.title } == ["Short reset", "Weekly reset", "Allowance checked when needed"] && scheduled.first?.title == "Next allowance check" && scheduled.first?.at == 2000200000.0
283
+ print("Empty retry schedule handled: \(correctTiming)")
284
+ exit(normal != nil && attention != nil && liveUpdate && safeIdentity && correctTiming ? 0 : 1)
255
285
  } else {
256
286
  let app = NSApplication.shared
257
287
  let delegate = MenuController(); app.delegate = delegate; app.run()
package/python/router.py CHANGED
@@ -24,7 +24,7 @@ from pool import Pool, blocked, reset_time, failure_kind, file_lock
24
24
  from launch import translate, RESUME_FIELDS
25
25
  import settings
26
26
 
27
- VERSION = "0.5.2"
27
+ VERSION = "0.5.3"
28
28
  _support = Path.home() / "Library/Application Support"
29
29
  _legacy = _support / "Codex Accounts"
30
30
  _default_state = _legacy if (_legacy / "accounts").exists() else _support / "Relay"