Skip to content
Merged
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
- AWS Bedrock: treat Cost Explorer's temporary data-unavailable response as zero usage instead of an HTTP 400 error (#1324). Thanks @enesteve0!
- Provider switcher: inset quota bars inside fixed-height segments so icons, labels, and selected pills remain vertically centered.
- Doubao: show an unavailable quota state when Ark omits trustworthy request-limit data instead of reporting 100% left.
- Weekly pace: use configured work days for standard weekly pace calculations while leaving historical Codex pacing unchanged (#1451, fixes #1356). Thanks @pstanton237!
- Menu bar: anchor merged provider dropdowns to the status item's trailing edge without marking preserved in-flight refresh content fresh, preventing horizontal drift while keeping deferred updates visible (#1288). Thanks @Yuxin-Qiao!
- Antigravity: fall back to the CLI usage server when the desktop app is closed, keep helper sessions owned and bounded without hidden sign-in flows, and show model rows with missing usage as unavailable instead of exhausted (#1313). Thanks @enieuwy!
- Cost usage: replace repeated Foundation metadata/root checks with one portable file-stat pass so expired Codex history refreshes stay responsive on very large session archives (#1392). Thanks @TheAngryPit and @ProspectOre!
Expand Down
33 changes: 27 additions & 6 deletions Sources/CodexBar/MenuCardView+ModelHelpers.swift
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,22 @@ extension UsageMenuCardView.Model {
paceOnTop: paceOnTop)
}

static func standardWeeklyPace(input: Input, window: RateWindow) -> UsagePace? {
if let weeklyPace = input.weeklyPace {
return weeklyPace
}
return Self.displayableWeeklyPace(UsagePace.weekly(
window: window,
now: input.now,
defaultWindowMinutes: 10080,
workDays: input.workDaysPerWeek))
}

private static func displayableWeeklyPace(_ pace: UsagePace?) -> UsagePace? {
guard let pace else { return nil }
return pace.expectedUsedPercent >= 3 || pace.etaSeconds == 0 ? pace : nil
}

static func cursorBillingCyclePaceDetail(
window: RateWindow,
input: Input,
Expand All @@ -181,10 +197,12 @@ extension UsageMenuCardView.Model {
guard input.provider == .cursor,
window.windowMinutes != nil
else { return nil }
let resolved = pace ?? UsagePace.weekly(window: window, now: input.now, defaultWindowMinutes: 10080)
guard let resolved,
resolved.expectedUsedPercent >= 3
else { return nil }
let resolved = pace ?? UsagePace.weekly(
window: window,
now: input.now,
defaultWindowMinutes: 10080,
workDays: input.workDaysPerWeek)
guard let resolved = Self.displayableWeeklyPace(resolved) else { return nil }
return Self.weeklyPaceDetail(
window: window,
now: input.now,
Expand Down Expand Up @@ -285,8 +303,11 @@ extension UsageMenuCardView.Model {
now: input.now,
showUsed: input.usageBarsShowUsed)
case 10080:
let pace = UsagePace.weekly(window: window, now: input.now, defaultWindowMinutes: 10080)
.flatMap { $0.expectedUsedPercent >= 3 ? $0 : nil }
let pace = Self.displayableWeeklyPace(UsagePace.weekly(
window: window,
now: input.now,
defaultWindowMinutes: 10080,
workDays: input.workDaysPerWeek))
return Self.weeklyPaceDetail(
window: window,
now: input.now,
Expand Down
4 changes: 1 addition & 3 deletions Sources/CodexBar/MenuCardView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1573,9 +1573,7 @@ extension UsageMenuCardView.Model {
paceDetail = Self.weeklyPaceDetail(
window: window,
now: input.now,
pace: input.weeklyPace
?? UsagePace.weekly(window: window, now: input.now, defaultWindowMinutes: 10080)
.flatMap { $0.expectedUsedPercent >= 3 ? $0 : nil },
pace: Self.standardWeeklyPace(input: input, window: window),
showUsed: input.usageBarsShowUsed)
}

Expand Down
2 changes: 2 additions & 0 deletions Sources/CodexBar/Resources/ca.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -491,6 +491,8 @@
"show_usage_as_used_subtitle" = "Les barres de progrés s'omplen a mesura que consumeixes la quota (en comptes de mostrar el que queda).";
"show_quota_warning_markers_title" = "Mostra els marcadors d'avís de quota";
"show_quota_warning_markers_subtitle" = "Dibuixa marques de llindar a les barres d'ús quan hi ha avisos de quota configurats.";
"weekly_progress_work_days_title" = "Dies laborables del progrés setmanal";
"weekly_progress_work_days_subtitle" = "Defineix els dies laborables per als marcadors de les barres d'ús setmanal i els càlculs de ritme.";
"show_reset_time_as_clock_title" = "Mostra l'hora de reinici com a rellotge";
"show_reset_time_as_clock_subtitle" = "Mostra les hores de reinici com a valors de rellotge absoluts en comptes de comptes enrere.";
"show_provider_changelog_links_title" = "Mostra els enllaços al registre de canvis del proveïdor";
Expand Down
2 changes: 1 addition & 1 deletion Sources/CodexBar/Resources/de.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -503,7 +503,7 @@
"show_quota_warning_markers_title" = "Quotenwarnmarkierungen anzeigen";
"show_quota_warning_markers_subtitle" = "Zeichnen Sie Schwellenwertmarkierungen auf Nutzungsbalken, wenn Kontingentwarnungen konfiguriert sind.";
"weekly_progress_work_days_title" = "Wöchentliche Fortschrittsarbeitstage";
"weekly_progress_work_days_subtitle" = "Zeichnen Sie Häkchenmarkierungen für die Tagesgrenzen auf den Balken für die wöchentliche Nutzung.";
"weekly_progress_work_days_subtitle" = "Legt Arbeitstage für Markierungen in wöchentlichen Nutzungsbalken und Tempo-Berechnungen fest.";
"show_reset_time_as_clock_title" = "Reset-Zeit als Uhr anzeigen";
"show_reset_time_as_clock_subtitle" = "Anzeige der Rücksetzzeiten als absolute Uhrwerte statt als Countdown.";
"show_provider_changelog_links_title" = "Links zum Änderungsprotokoll des Anbieters anzeigen";
Expand Down
2 changes: 1 addition & 1 deletion Sources/CodexBar/Resources/en.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -504,7 +504,7 @@
"show_quota_warning_markers_title" = "Show quota warning markers";
"show_quota_warning_markers_subtitle" = "Draw threshold tick marks on usage bars when quota warnings are configured.";
"weekly_progress_work_days_title" = "Weekly progress work days";
"weekly_progress_work_days_subtitle" = "Draw day-boundary tick marks on weekly usage bars.";
"weekly_progress_work_days_subtitle" = "Set work days for weekly usage-bar markers and pace calculations.";
"show_reset_time_as_clock_title" = "Show reset time as clock";
"show_reset_time_as_clock_subtitle" = "Display reset times as absolute clock values instead of countdowns.";
"show_provider_changelog_links_title" = "Show provider changelog links";
Expand Down
2 changes: 2 additions & 0 deletions Sources/CodexBar/Resources/es.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -491,6 +491,8 @@
"show_usage_as_used_subtitle" = "Las barras de progreso se llenan a medida que consumes la cuota (en lugar de mostrar lo restante).";
"show_quota_warning_markers_title" = "Mostrar marcadores de aviso de cuota";
"show_quota_warning_markers_subtitle" = "Dibuja marcas de umbral en las barras de uso cuando hay avisos de cuota configurados.";
"weekly_progress_work_days_title" = "Días laborables del progreso semanal";
"weekly_progress_work_days_subtitle" = "Define los días laborables para los marcadores de las barras de uso semanal y los cálculos de ritmo.";
"show_reset_time_as_clock_title" = "Mostrar la hora de reinicio como reloj";
"show_reset_time_as_clock_subtitle" = "Mostrar las horas de reinicio como valores de reloj absolutos en lugar de cuentas atrás.";
"show_provider_changelog_links_title" = "Mostrar enlaces al registro de cambios del proveedor";
Expand Down
2 changes: 1 addition & 1 deletion Sources/CodexBar/Resources/fr.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -503,7 +503,7 @@
"show_quota_warning_markers_title" = "Afficher les marqueurs d'avertissement de quota";
"show_quota_warning_markers_subtitle" = "Dessinez des coches de seuil sur les barres d’utilisation lorsque des avertissements de quota sont configurés.";
"weekly_progress_work_days_title" = "Jours de travail hebdomadaires";
"weekly_progress_work_days_subtitle" = "Dessinez des graduations journalières sur les barres d’utilisation hebdomadaire.";
"weekly_progress_work_days_subtitle" = "Définit les jours ouvrés pour les repères des barres d’utilisation hebdomadaire et le calcul du rythme.";
"show_reset_time_as_clock_title" = "Afficher l'heure de réinitialisation sous forme d'horloge";
"show_reset_time_as_clock_subtitle" = "Affichez les temps de réinitialisation sous forme de valeurs d'horloge absolues au lieu de comptes à rebours.";
"show_provider_changelog_links_title" = "Afficher les liens du journal des modifications du fournisseur";
Expand Down
2 changes: 1 addition & 1 deletion Sources/CodexBar/Resources/ja.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -501,7 +501,7 @@
"show_quota_warning_markers_title" = "クォータ警告マーカーを表示";
"show_quota_warning_markers_subtitle" = "クォータ警告が設定されている場合、使用量バーにしきい値の目盛りを描画します。";
"weekly_progress_work_days_title" = "週間進捗の作業日";
"weekly_progress_work_days_subtitle" = "週間使用量バーに日付の区切り目盛りを描画します。";
"weekly_progress_work_days_subtitle" = "週間使用量バーの目盛りとペース計算に使用する作業日を設定します。";
"show_reset_time_as_clock_title" = "リセット時刻を時計表示";
"show_reset_time_as_clock_subtitle" = "リセット時刻をカウントダウンではなく絶対時刻で表示します。";
"show_provider_changelog_links_title" = "プロバイダの変更履歴リンクを表示";
Expand Down
2 changes: 1 addition & 1 deletion Sources/CodexBar/Resources/ko.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -495,7 +495,7 @@
"show_quota_warning_markers_title" = "할당량 경고 표시기 표시";
"show_quota_warning_markers_subtitle" = "할당량 경고가 구성된 경우 사용량 막대에 임계값 눈금 표시를 그립니다.";
"weekly_progress_work_days_title" = "주간 진행률 근무일";
"weekly_progress_work_days_subtitle" = "주간 사용량 막대에 날짜 경계 눈금 표시를 그립니다.";
"weekly_progress_work_days_subtitle" = "주간 사용량 막대 눈금과 페이스 계산에 사용할 근무일을 설정합니다.";
"show_reset_time_as_clock_title" = "재설정 시간을 시계로 표시";
"show_reset_time_as_clock_subtitle" = "재설정 시간을 카운트다운 대신 절대 시각으로 표시합니다.";
"show_provider_changelog_links_title" = "공급자 변경 로그 링크 표시";
Expand Down
2 changes: 1 addition & 1 deletion Sources/CodexBar/Resources/nl.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -503,7 +503,7 @@
"show_quota_warning_markers_title" = "Toon waarschuwingsmarkeringen voor quota";
"show_quota_warning_markers_subtitle" = "Teken drempelmarkeringen op gebruiksbalken wanneer quotawaarschuwingen zijn geconfigureerd.";
"weekly_progress_work_days_title" = "Wekelijkse voortgang werkdagen";
"weekly_progress_work_days_subtitle" = "Teken daggrensmarkeringen op de wekelijkse gebruiksbalken.";
"weekly_progress_work_days_subtitle" = "Stel werkdagen in voor markeringen op wekelijkse gebruiksbalken en tempoberekeningen.";
"show_reset_time_as_clock_title" = "Toon resettijd als klok";
"show_reset_time_as_clock_subtitle" = "Geef resettijden weer als absolute klokwaarden in plaats van aftellingen.";
"show_provider_changelog_links_title" = "Toon provider changelog-links";
Expand Down
2 changes: 1 addition & 1 deletion Sources/CodexBar/Resources/pt-BR.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -501,7 +501,7 @@
"show_quota_warning_markers_title" = "Mostrar marcadores de alerta de cota";
"show_quota_warning_markers_subtitle" = "Desenha marcas de limite nas barras de uso quando os alertas de cota estão configurados.";
"weekly_progress_work_days_title" = "Dias úteis no progresso semanal";
"weekly_progress_work_days_subtitle" = "Desenha marcas de limite de dia nas barras de uso semanal.";
"weekly_progress_work_days_subtitle" = "Define os dias úteis para marcadores das barras de uso semanal e cálculos de ritmo.";
"show_reset_time_as_clock_title" = "Mostrar renovação como horário";
"show_reset_time_as_clock_subtitle" = "Mostra horários de renovação como horas absolutas, em vez de contagens regressivas.";
"show_provider_changelog_links_title" = "Mostrar links de changelog dos provedores";
Expand Down
2 changes: 1 addition & 1 deletion Sources/CodexBar/Resources/sv.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -502,7 +502,7 @@
"show_quota_warning_markers_title" = "Visa kvotvarningsmarkörer";
"show_quota_warning_markers_subtitle" = "Rita tröskelmarkeringar på användningsstaplar när kvotvarningar är konfigurerade.";
"weekly_progress_work_days_title" = "Arbetsdagar i veckoförlopp";
"weekly_progress_work_days_subtitle" = "Rita dagsgränsmarkeringar på veckostaplar.";
"weekly_progress_work_days_subtitle" = "Ställ in arbetsdagar för markeringar i veckostaplar och tempoberäkningar.";
"show_reset_time_as_clock_title" = "Visa återställningstid som klockslag";
"show_reset_time_as_clock_subtitle" = "Visa återställningstider som klockslag i stället för nedräkningar.";
"show_provider_changelog_links_title" = "Visa länkar till leverantörers ändringsloggar";
Expand Down
2 changes: 1 addition & 1 deletion Sources/CodexBar/Resources/tr.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -503,7 +503,7 @@
"show_quota_warning_markers_title" = "Kota uyarı işaretlerini göster";
"show_quota_warning_markers_subtitle" = "Kota uyarıları yapılandırıldığında kullanım çubuklarına eşik çizgileri çizer.";
"weekly_progress_work_days_title" = "Haftalık ilerleme iş günleri";
"weekly_progress_work_days_subtitle" = "Haftalık kullanım çubuklarına gün sınırı çizgileri çizer.";
"weekly_progress_work_days_subtitle" = "Haftalık kullanım çubuğu işaretleri ve tempo hesaplamaları için iş günlerini ayarlar.";
"show_reset_time_as_clock_title" = "Sıfırlama süresini saat olarak göster";
"show_reset_time_as_clock_subtitle" = "Sıfırlama sürelerini geri sayım yerine mutlak saat değerleri olarak göster.";
"show_provider_changelog_links_title" = "Sağlayıcı değişiklik günlüğü bağlantılarını göster";
Expand Down
2 changes: 1 addition & 1 deletion Sources/CodexBar/Resources/uk.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -503,7 +503,7 @@
"show_quota_warning_markers_title" = "Показати маркери попередження про квоти";
"show_quota_warning_markers_subtitle" = "Малюйте порогові позначки на панелях використання, коли налаштовано попередження про квоту.";
"weekly_progress_work_days_title" = "Щотижневі робочі дні";
"weekly_progress_work_days_subtitle" = "Позначте межі дня на смугах тижневого використання.";
"weekly_progress_work_days_subtitle" = "Задайте робочі дні для позначок на смугах тижневого використання та розрахунків темпу.";
"show_reset_time_as_clock_title" = "Показувати час скидання як годинник";
"show_reset_time_as_clock_subtitle" = "Відображення часу скидання як абсолютних значень годинника замість зворотного відліку.";
"show_provider_changelog_links_title" = "Показати посилання журналу змін провайдера";
Expand Down
2 changes: 1 addition & 1 deletion Sources/CodexBar/Resources/vi.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -501,7 +501,7 @@
"show_quota_warning_markers_title" = "Hiển thị Hạn mức dấu cảnh báo";
"show_quota_warning_markers_subtitle" = "Vẽ dấu kiểm ngưỡng trên thanh Mức sử dụng khi cảnh báo Hạn mức được định cấu hình.";
"weekly_progress_work_days_title" = "Tiến độ ngày làm việc hàng tuần";
"weekly_progress_work_days_subtitle" = "Vẽ các dấu kiểm ranh giới ngày trên các thanh Mức sử dụng hàng tuần.";
"weekly_progress_work_days_subtitle" = "Đặt ngày làm việc cho các vạch trên thanh sử dụng hằng tuần và phép tính nhịp độ.";
"show_reset_time_as_clock_title" = "Hiển thị Đặt lại thời gian dưới dạng đồng hồ";
"show_reset_time_as_clock_subtitle" = "Hiển thị Đặt lại thời gian dưới dạng giá trị đồng hồ tuyệt đối thay vì đếm ngược.";
"show_provider_changelog_links_title" = "Hiển thị Nhà cung cấp liên kết nhật ký thay đổi";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -846,7 +846,7 @@
"Cleanup ideas" = "清理建议";
"%d unreadable item(s) skipped" = "已跳过 %d 个不可读项目";
"weekly_progress_work_days_title" = "工作日刻度线";
"weekly_progress_work_days_subtitle" = "在每周用量条上显示按天分隔的刻度线。";
"weekly_progress_work_days_subtitle" = "设置用于每周用量条刻度和进度计算的工作日。";
"copilot_device_code" = "设备代码已复制到剪贴板:%1$@\n\n请在以下地址验证:%2$@";
"copilot_waiting_text" = "请在浏览器中完成登录。\n登录完成后,此窗口会自动关闭。";
"vertex_ai_login_instructions" = "要跟踪 Vertex AI 用量,请通过 Google Cloud 进行认证。\n\n1. 打开终端\n2. 运行:gcloud auth application-default login\n3. 按照浏览器提示登录\n4. 设置你的项目:gcloud config set project PROJECT_ID\n\n是否现在打开终端?";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -502,7 +502,7 @@
"show_quota_warning_markers_title" = "顯示配額提醒標記";
"show_quota_warning_markers_subtitle" = "設定配額提醒後,在使用量條上繪製門檻刻度標記。";
"weekly_progress_work_days_title" = "每週進度工作日標記";
"weekly_progress_work_days_subtitle" = "在每週使用量條上繪製日期邊界刻度標記。";
"weekly_progress_work_days_subtitle" = "設定用於每週用量條刻度與進度計算的工作日。";
"show_reset_time_as_clock_title" = "以時鐘時間顯示重置時間";
"show_reset_time_as_clock_subtitle" = "將重置時間顯示為絕對時鐘值,而不是倒數計時。";
"show_provider_changelog_links_title" = "顯示提供者版本資訊連結";
Expand Down
5 changes: 3 additions & 2 deletions Sources/CodexBar/UsageStore+HistoricalPace.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ extension UsageStore {
func weeklyPace(provider: UsageProvider, window: RateWindow, now: Date = .init()) -> UsagePace? {
guard window.remainingPercent > 0 else { return nil }
let resolved: UsagePace?
let workDays = self.settings.weeklyProgressWorkDays
// Codex can refine pace with historical samples because its dashboard exposes enough weekly history to build
// an account-scoped usage curve. Other providers should not need a hard-coded allowlist: if their RateWindow
// includes a reset time and window duration, the generic linear pace calculation is already defensible.
Expand All @@ -22,14 +23,14 @@ extension UsageStore {
{
resolved = historical
} else {
resolved = UsagePace.weekly(window: window, now: now, defaultWindowMinutes: 10080)
resolved = UsagePace.weekly(window: window, now: now, defaultWindowMinutes: 10080, workDays: workDays)
}
} else {
// Generic providers must carry an explicit window duration. Using the 10080-minute fallback for
// windows without windowMinutes would fabricate a weekly pace for non-weekly windows
// (e.g. Factory monthly with only resetsAt).
guard window.windowMinutes != nil else { return nil }
resolved = UsagePace.weekly(window: window, now: now, defaultWindowMinutes: 10080)
resolved = UsagePace.weekly(window: window, now: now, defaultWindowMinutes: 10080, workDays: workDays)
}

guard let resolved else { return nil }
Expand Down
Loading