easy-codex 0.2.0 → 0.2.1
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.
package/README.md
CHANGED
|
@@ -19,7 +19,7 @@ easy-codex
|
|
|
19
19
|
显示透明圆环(macOS):
|
|
20
20
|
|
|
21
21
|
```sh
|
|
22
|
-
easy-codex
|
|
22
|
+
easy-codex show
|
|
23
23
|
```
|
|
24
24
|
|
|
25
25
|
需要 Node.js 22+ 和已登录的官方 Codex CLI。安装包自带浮窗,使用者无需下载源码、安装依赖或编译。
|
|
@@ -48,7 +48,7 @@ npm test
|
|
|
48
48
|
macOS 14+ 安装后运行:
|
|
49
49
|
|
|
50
50
|
```sh
|
|
51
|
-
easy-codex
|
|
51
|
+
easy-codex show
|
|
52
52
|
```
|
|
53
53
|
|
|
54
54
|
独立 AppKit 浮窗在 Codex 位于前台时显示,切到其他应用、最小化或关闭 Codex 窗口后隐藏。默认位于 Codex 窗口左下角头像上方;拖动可校准位置,偏移量保存在本机。它按窗口边界跟随,不自动识别头像;侧栏布局变化后可再次拖动。首版跟随最前面的一个 Codex 普通窗口。
|
|
@@ -81,3 +81,9 @@ GitHub Actions 在 `v*` 标签上测试、构建通用 macOS 浮窗,并发布
|
|
|
81
81
|
## 电子时钟
|
|
82
82
|
|
|
83
83
|
透明时钟位于圆环上方,竖排居中,默认间距10px,可独立拖动。默认硅谷,城市顺序为硅谷、洛杉矶、西雅图、华盛顿特区、哥伦布(俄亥俄州)、新加坡、上海,也可自定义 IANA 时区;设置自动保存。仅显示时分,按目标当地时间00–09红色、09–15绿色、15–24橙色,自动处理夏令时,不修改电脑系统时区。菜单“恢复默认位置”应用竖排默认布局;已有拖动位置继续保留。
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
浮窗使用 `easy-codex show` 启动;原 `overlay` 命令保留兼容。
|
|
88
|
+
|
|
89
|
+
周倒计时只显示最大单位,例如“6天后 25日 06:17 重置”,不足一天按小时、不足一小时按分钟。5小时窗口保留时分组合,例如“3小时2分后 07:59 重置”,没有小时则“22分后 07:59 重置”,省略为零的单位。绝对重置时刻使用电脑本地时区;周含日,5小时不含日期。
|
package/bin/easy-codex.js
CHANGED
|
@@ -5,16 +5,16 @@ import { readUsage, formatUsage } from '../src/usage.js';
|
|
|
5
5
|
|
|
6
6
|
const args = process.argv.slice(2);
|
|
7
7
|
if (args.length === 1 && ['--help', '-h'].includes(args[0])) {
|
|
8
|
-
console.log('用法:easy-codex [usage|overlay]\n显示已登录 Codex 账号的剩余百分比和重置时间。需要官方 Codex CLI。');
|
|
8
|
+
console.log('用法:easy-codex [usage|show|overlay]\n显示已登录 Codex 账号的剩余百分比和重置时间。需要官方 Codex CLI。');
|
|
9
9
|
} else if (args.length === 1 && ['--version', '-v'].includes(args[0])) {
|
|
10
10
|
console.log(version);
|
|
11
|
-
} else if (args.length === 1 &&
|
|
11
|
+
} else if (args.length === 1 && ['show', 'overlay'].includes(args[0])) {
|
|
12
12
|
try { const { launchOverlay } = await import('../src/overlay.js'); await launchOverlay(); }
|
|
13
13
|
catch (error) { console.error(`easy-codex: ${error.message}`); process.exitCode = 1; }
|
|
14
14
|
} else if (args.length === 0 || (args.length === 1 && args[0] === 'usage')) {
|
|
15
15
|
try { console.log(formatUsage(await readUsage())); }
|
|
16
16
|
catch (error) { console.error(`easy-codex: ${error.message}`); process.exitCode = 1; }
|
|
17
17
|
} else {
|
|
18
|
-
console.error('未知参数。用法:easy-codex [usage|overlay],或 easy-codex --help');
|
|
18
|
+
console.error('未知参数。用法:easy-codex [usage|show|overlay],或 easy-codex --help');
|
|
19
19
|
process.exitCode = 1;
|
|
20
20
|
}
|
package/native/Overlay.swift
CHANGED
|
@@ -161,6 +161,29 @@ struct ClockCity {
|
|
|
161
161
|
]
|
|
162
162
|
}
|
|
163
163
|
|
|
164
|
+
func resetDescription(_ resetsAt: Double?, weekly: Bool, now: Date = Date(), zone: TimeZone = .current) -> String {
|
|
165
|
+
guard let resetsAt, resetsAt.isFinite, abs(resetsAt) < 8.64e12 else { return "重置时间未知" }
|
|
166
|
+
let remaining = resetsAt - now.timeIntervalSince1970
|
|
167
|
+
guard remaining > 0 else { return "已到重置时间,等待更新" }
|
|
168
|
+
let formatter = DateFormatter()
|
|
169
|
+
formatter.locale = Locale(identifier: "zh_CN")
|
|
170
|
+
formatter.timeZone = zone
|
|
171
|
+
formatter.dateFormat = weekly ? "d'日' HH:mm" : "HH:mm"
|
|
172
|
+
let time = formatter.string(from: Date(timeIntervalSince1970: resetsAt))
|
|
173
|
+
let duration: String
|
|
174
|
+
if weekly {
|
|
175
|
+
if remaining >= 86400 { duration = "\(Int(remaining / 86400))天" }
|
|
176
|
+
else if remaining >= 3600 { duration = "\(Int(remaining / 3600))小时" }
|
|
177
|
+
else { duration = "\(Int(ceil(remaining / 60)))分钟" }
|
|
178
|
+
} else {
|
|
179
|
+
let totalMinutes = Int(ceil(remaining / 60))
|
|
180
|
+
let hours = totalMinutes / 60
|
|
181
|
+
let minutes = totalMinutes % 60
|
|
182
|
+
duration = (hours > 0 ? "\(hours)小时" : "") + (minutes > 0 ? "\(minutes)分" : "")
|
|
183
|
+
}
|
|
184
|
+
return "\(duration)后 \(time) 重置"
|
|
185
|
+
}
|
|
186
|
+
|
|
164
187
|
func clockText(at date: Date, zone: TimeZone) -> String {
|
|
165
188
|
let formatter = DateFormatter()
|
|
166
189
|
formatter.locale = Locale(identifier: "en_US_POSIX")
|
|
@@ -372,15 +395,8 @@ final class Overlay: NSObject, NSApplicationDelegate, NSMenuDelegate {
|
|
|
372
395
|
let id = minutes == 10080 ? "weekly" : "fiveHour"
|
|
373
396
|
guard let window = codexWindow(snapshot?.windows ?? [], minutes: minutes) else { continue }
|
|
374
397
|
let remaining = window.remaining.map { "\(Int($0.rounded()))%" } ?? "未知"
|
|
375
|
-
let reset:
|
|
376
|
-
|
|
377
|
-
let formatter = DateFormatter()
|
|
378
|
-
formatter.locale = Locale(identifier: "zh_CN")
|
|
379
|
-
formatter.timeZone = .current
|
|
380
|
-
formatter.dateFormat = "MM-dd HH:mm"
|
|
381
|
-
reset = formatter.string(from: Date(timeIntervalSince1970: seconds))
|
|
382
|
-
} else { reset = "未知" }
|
|
383
|
-
let option = item("\(label) · \(remaining) · 重置 \(reset)", #selector(selectPercentage(_:)))
|
|
398
|
+
let reset = resetDescription(window.resetsAt, weekly: minutes == 10080)
|
|
399
|
+
let option = item("\(label) · \(remaining) · \(reset)", #selector(selectPercentage(_:)))
|
|
384
400
|
option.representedObject = id
|
|
385
401
|
option.state = (ring.displaysWeeklyPercentage == (id == "weekly")) ? .on : .off
|
|
386
402
|
menu.addItem(option)
|
|
@@ -388,7 +404,7 @@ final class Overlay: NSObject, NSApplicationDelegate, NSMenuDelegate {
|
|
|
388
404
|
menu.addItem(item(query == nil ? "立即刷新" : "正在刷新…", query == nil ? #selector(refresh) : nil))
|
|
389
405
|
menu.addItem(item("恢复默认位置", #selector(resetPosition)))
|
|
390
406
|
menu.addItem(.separator())
|
|
391
|
-
let toggle = item("
|
|
407
|
+
let toggle = item("显示时间", #selector(toggleClock))
|
|
392
408
|
toggle.state = clockEnabled ? .on : .off
|
|
393
409
|
menu.addItem(toggle)
|
|
394
410
|
let zones = NSMenu()
|
|
@@ -399,7 +415,7 @@ final class Overlay: NSObject, NSApplicationDelegate, NSMenuDelegate {
|
|
|
399
415
|
zones.addItem(option)
|
|
400
416
|
}
|
|
401
417
|
zones.addItem(item("自定义时区…", #selector(customTimeZone)))
|
|
402
|
-
let zoneItem = item("
|
|
418
|
+
let zoneItem = item("\(clock.cityName)·\(clockText(at: Date(), zone: clock.zone))", nil)
|
|
403
419
|
zoneItem.submenu = zones
|
|
404
420
|
menu.addItem(zoneItem)
|
|
405
421
|
menu.addItem(.separator())
|
|
@@ -479,6 +495,19 @@ struct Main {
|
|
|
479
495
|
let otherHours = UsageWindow(id: "other:primary", label: "5小时", name: "other", remaining: 10, resetsAt: nil, windowDurationMins: 300)
|
|
480
496
|
precondition(codexWindow([otherHours, weekOnly], minutes: 10080)?.remaining == 80)
|
|
481
497
|
precondition(codexWindow([otherHours, weekOnly], minutes: 300) == nil)
|
|
498
|
+
let countdownStart = ISO8601DateFormatter().date(from: "2026-10-15T04:57:00Z")!
|
|
499
|
+
let countdownUTC = TimeZone(secondsFromGMT: 0)!
|
|
500
|
+
precondition(resetDescription(countdownStart.timeIntervalSince1970 + 10920, weekly: false, now: countdownStart, zone: countdownUTC) == "3小时2分后 07:59 重置")
|
|
501
|
+
let weekStart = ISO8601DateFormatter().date(from: "2026-10-14T08:03:00Z")!
|
|
502
|
+
precondition(resetDescription(weekStart.timeIntervalSince1970 + 345360, weekly: true, now: weekStart, zone: countdownUTC) == "3天后 18日 07:59 重置")
|
|
503
|
+
precondition(resetDescription(nil, weekly: true) == "重置时间未知")
|
|
504
|
+
precondition(resetDescription(countdownStart.timeIntervalSince1970, weekly: false, now: countdownStart) == "已到重置时间,等待更新")
|
|
505
|
+
precondition(resetDescription(countdownStart.timeIntervalSince1970 + 1, weekly: false, now: countdownStart, zone: countdownUTC) == "1分后 04:57 重置")
|
|
506
|
+
precondition(resetDescription(countdownStart.timeIntervalSince1970 + 86160, weekly: true, now: countdownStart, zone: countdownUTC) == "23小时后 16日 04:53 重置")
|
|
507
|
+
precondition(resetDescription(countdownStart.timeIntervalSince1970 + 120, weekly: true, now: countdownStart, zone: countdownUTC) == "2分钟后 15日 04:59 重置")
|
|
508
|
+
precondition(resetDescription(countdownStart.timeIntervalSince1970 + 86400, weekly: true, now: countdownStart, zone: countdownUTC) == "1天后 16日 04:57 重置")
|
|
509
|
+
precondition(resetDescription(countdownStart.timeIntervalSince1970 + 86399, weekly: true, now: countdownStart, zone: countdownUTC) == "23小时后 16日 04:56 重置")
|
|
510
|
+
precondition(resetDescription(countdownStart.timeIntervalSince1970 + 3599, weekly: false, now: countdownStart, zone: countdownUTC) == "1小时后 05:56 重置")
|
|
482
511
|
let testRing = RingView()
|
|
483
512
|
testRing.showFiveHourRing = false
|
|
484
513
|
precondition(testRing.displaysWeeklyPercentage)
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
<key>CFBundleIdentifier</key><string>com.unionschool.easy-codex.overlay</string>
|
|
6
6
|
<key>CFBundleName</key><string>Easy Codex Overlay</string>
|
|
7
7
|
<key>CFBundlePackageType</key><string>APPL</string>
|
|
8
|
-
<key>CFBundleShortVersionString</key><string>0.2.
|
|
8
|
+
<key>CFBundleShortVersionString</key><string>0.2.1</string>
|
|
9
9
|
<key>LSMinimumSystemVersion</key><string>14.0</string>
|
|
10
10
|
<key>LSUIElement</key><true/>
|
|
11
11
|
<key>NSHighResolutionCapable</key><true/>
|
|
Binary file
|