sidekick-shared 0.28.2 → 0.28.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.
Files changed (54) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/README.md +29 -13
  3. package/dist/browser.d.ts +2 -0
  4. package/dist/browser.js +10 -1
  5. package/dist/codexQuota.js +17 -4
  6. package/dist/esm/browser.js +2 -0
  7. package/dist/esm/codexQuota.js +18 -5
  8. package/dist/esm/index.js +3 -3
  9. package/dist/esm/multiProviderQuotaService.js +1 -1
  10. package/dist/esm/quota.js +356 -24
  11. package/dist/esm/quotaHistory.js +33 -8
  12. package/dist/esm/quotaPoller.js +5 -2
  13. package/dist/esm/quotaResolver.js +31 -6
  14. package/dist/esm/quotaSnapshots.js +65 -10
  15. package/dist/esm/quotaThresholds.js +7 -2
  16. package/dist/esm/schemas/index.js +2 -2
  17. package/dist/esm/schemas/quota.js +30 -0
  18. package/dist/esm/schemas/quotaHistory.js +10 -2
  19. package/dist/esm/schemas/stateFile.js +9 -0
  20. package/dist/esm/stateFile.js +18 -3
  21. package/dist/esm/statusline/claudeStatuslinePayload.js +16 -4
  22. package/dist/esm/statusline/formatter.js +57 -18
  23. package/dist/esm/statusline/index.js +2 -2
  24. package/dist/esm/zaiQuotaApi.js +4 -2
  25. package/dist/index.d.ts +6 -6
  26. package/dist/index.js +18 -5
  27. package/dist/multiProviderQuotaService.js +1 -1
  28. package/dist/quota.d.ts +131 -1
  29. package/dist/quota.js +366 -24
  30. package/dist/quotaHistory.d.ts +10 -0
  31. package/dist/quotaHistory.js +34 -8
  32. package/dist/quotaPoller.d.ts +11 -3
  33. package/dist/quotaPoller.js +5 -2
  34. package/dist/quotaResolver.js +30 -5
  35. package/dist/quotaSnapshots.js +64 -9
  36. package/dist/quotaThresholds.js +7 -2
  37. package/dist/schemas/index.d.ts +3 -3
  38. package/dist/schemas/index.js +5 -2
  39. package/dist/schemas/quota.d.ts +258 -0
  40. package/dist/schemas/quota.js +31 -1
  41. package/dist/schemas/quotaHistory.d.ts +2 -0
  42. package/dist/schemas/quotaHistory.js +10 -2
  43. package/dist/schemas/stateFile.d.ts +34 -0
  44. package/dist/schemas/stateFile.js +10 -1
  45. package/dist/stateFile.d.ts +18 -0
  46. package/dist/stateFile.js +17 -2
  47. package/dist/statusline/claudeStatuslinePayload.d.ts +4 -3
  48. package/dist/statusline/claudeStatuslinePayload.js +16 -4
  49. package/dist/statusline/formatter.d.ts +5 -0
  50. package/dist/statusline/formatter.js +56 -17
  51. package/dist/statusline/index.d.ts +4 -4
  52. package/dist/statusline/index.js +5 -1
  53. package/dist/zaiQuotaApi.js +3 -1
  54. package/package.json +1 -1
@@ -2,7 +2,7 @@ import * as fs from 'fs';
2
2
  import * as path from 'path';
3
3
  import { getConfigDir } from './paths';
4
4
  import { atomicWriteJsonSync, withFileLockSync } from './writers/atomic';
5
- import { classifyQuotaFreshness } from './quota';
5
+ import { classifyQuotaFreshness, extraQuotaRows } from './quota';
6
6
  import { isAggregateCodexLimit } from './types/codex';
7
7
  function getQuotaSnapshotPath() {
8
8
  return path.join(getConfigDir(), 'quota-snapshots.json');
@@ -46,6 +46,27 @@ function windowResetMs(value) {
46
46
  const ms = Date.parse(value);
47
47
  return Number.isFinite(ms) ? ms : 0;
48
48
  }
49
+ /**
50
+ * Rank two samples by one window's reset time. A later reset means a newer
51
+ * window, so it wins — except that an existing window which had already reset
52
+ * by the time the newer sample was captured is obsolete and always yields.
53
+ * Without that exception a pre-reset sample outranks every later sample whose
54
+ * window has not started yet (empty reset), and the snapshot freezes.
55
+ * Returns `undefined` when the reset times tie.
56
+ */
57
+ function compareWindowResets(existing, next, asOfMs) {
58
+ const existingReset = windowResetMs(existing.resetsAt);
59
+ const nextReset = windowResetMs(next.resetsAt);
60
+ if (existingReset === nextReset)
61
+ return undefined;
62
+ if (existingReset > 0 && asOfMs > 0 && existingReset <= asOfMs)
63
+ return false;
64
+ return existingReset > nextReset;
65
+ }
66
+ function windowPresenceChanged(existing, next) {
67
+ return (Boolean(existing.fiveHour.absent) !== Boolean(next.fiveHour.absent) ||
68
+ Boolean(existing.sevenDay.absent) !== Boolean(next.sevenDay.absent));
69
+ }
49
70
  // Preserve the best-known same-window snapshot while still allowing lower
50
71
  // utilization after Codex advances to a newer reset window.
51
72
  function shouldKeepExistingSnapshot(existing, next) {
@@ -58,20 +79,50 @@ function shouldKeepExistingSnapshot(existing, next) {
58
79
  const nextAggregate = isAggregateCodexLimit(next.limitId);
59
80
  if (existingAggregate !== nextAggregate)
60
81
  return existingAggregate;
61
- const existingPrimaryReset = windowResetMs(existing.fiveHour.resetsAt);
62
- const nextPrimaryReset = windowResetMs(next.fiveHour.resetsAt);
63
- if (existingPrimaryReset !== nextPrimaryReset)
64
- return existingPrimaryReset > nextPrimaryReset;
65
- const existingSecondaryReset = windowResetMs(existing.sevenDay.resetsAt);
66
- const nextSecondaryReset = windowResetMs(next.sevenDay.resetsAt);
67
- if (existingSecondaryReset !== nextSecondaryReset)
68
- return existingSecondaryReset > nextSecondaryReset;
82
+ // The plan's window layout changed (a window appeared or disappeared): the
83
+ // reset times are not comparable, so the newer capture wins.
84
+ if (windowPresenceChanged(existing, next)) {
85
+ return snapshotTimeMs(existing) > snapshotTimeMs(next);
86
+ }
87
+ const asOfMs = snapshotTimeMs(next);
88
+ const primary = compareWindowResets(existing.fiveHour, next.fiveHour, asOfMs);
89
+ if (primary !== undefined)
90
+ return primary;
91
+ const secondary = compareWindowResets(existing.sevenDay, next.sevenDay, asOfMs);
92
+ if (secondary !== undefined)
93
+ return secondary;
69
94
  const existingUtilization = existing.fiveHour.utilization + existing.sevenDay.utilization;
70
95
  const nextUtilization = next.fiveHour.utilization + next.sevenDay.utilization;
71
96
  if (existingUtilization !== nextUtilization)
72
97
  return existingUtilization > nextUtilization;
73
98
  return snapshotTimeMs(existing) > snapshotTimeMs(next);
74
99
  }
100
+ /**
101
+ * Status-line and history samples only know the two headline windows. Keep
102
+ * the plan label, extra usage, and still-running extra meters (e.g. a Fable
103
+ * weekly cap) an earlier API sample recorded, so a fresh status-line write
104
+ * does not erase them from every snapshot reader.
105
+ */
106
+ function carryApiOnlyFields(existing, next) {
107
+ const merged = { ...next };
108
+ if (merged.planLabel === undefined && existing.planLabel !== undefined) {
109
+ merged.planLabel = existing.planLabel;
110
+ }
111
+ if (merged.planType === undefined && existing.planType !== undefined) {
112
+ merged.planType = existing.planType;
113
+ }
114
+ if (merged.extraUsage === undefined && existing.extraUsage !== undefined) {
115
+ merged.extraUsage = existing.extraUsage;
116
+ }
117
+ if (merged.limits === undefined && existing.limits !== undefined) {
118
+ const asOfMs = snapshotTimeMs(next);
119
+ // Headline meters duplicate the fresher windows on `next`; carry only the extras.
120
+ const running = extraQuotaRows(existing).filter((row) => windowResetMs(row.resetsAt) > asOfMs);
121
+ if (running.length > 0)
122
+ merged.limits = running;
123
+ }
124
+ return merged;
125
+ }
75
126
  export function writeQuotaSnapshot(providerId, accountId, quota) {
76
127
  withSnapshotStoreLock(() => {
77
128
  const store = readStore();
@@ -93,7 +144,11 @@ export function writeQuotaSnapshot(providerId, accountId, quota) {
93
144
  };
94
145
  if (index >= 0 && shouldKeepExistingSnapshot(store.snapshots[index].quota, snapshot))
95
146
  return;
96
- const record = { providerId, accountId, quota: snapshot };
147
+ const record = {
148
+ providerId,
149
+ accountId,
150
+ quota: existingQuota ? carryApiOnlyFields(existingQuota, snapshot) : snapshot,
151
+ };
97
152
  if (index >= 0)
98
153
  store.snapshots[index] = record;
99
154
  else
@@ -50,8 +50,13 @@ function evaluateWindow(window, quota, thresholds, previous) {
50
50
  export function evaluateQuotaThresholds(quota, config = DEFAULT_QUOTA_THRESHOLDS, memory = {}) {
51
51
  if (!quota.available)
52
52
  return { alerts: [], memory };
53
- const fiveHour = evaluateWindow('fiveHour', quota.fiveHour, config.fiveHour, memory.fiveHour);
54
- const sevenDay = evaluateWindow('sevenDay', quota.sevenDay, config.sevenDay, memory.sevenDay);
53
+ // A window the plan does not have (Ultra's missing five-hour limit) never alerts.
54
+ const fiveHour = quota.fiveHour.absent
55
+ ? { alert: null, memory: memory.fiveHour ?? { resetsAt: '', level: 0 } }
56
+ : evaluateWindow('fiveHour', quota.fiveHour, config.fiveHour, memory.fiveHour);
57
+ const sevenDay = quota.sevenDay.absent
58
+ ? { alert: null, memory: memory.sevenDay ?? { resetsAt: '', level: 0 } }
59
+ : evaluateWindow('sevenDay', quota.sevenDay, config.sevenDay, memory.sevenDay);
55
60
  return {
56
61
  alerts: [fiveHour.alert, sevenDay.alert].filter((alert) => alert !== null),
57
62
  memory: { fiveHour: fiveHour.memory, sevenDay: sevenDay.memory },
@@ -17,9 +17,9 @@ export { tokenEstimateSchema } from './tokenEstimation';
17
17
  export { providerAuthenticationEvidenceSchema, providerFailureEvidenceSchema, providerRetryAfterSchema, providerFailureDiagnosisSchema, } from './providerFailure';
18
18
  export { transcriptSourceProvenanceSchema, canonicalTranscriptBlockSchema, canonicalToolCallSchema, canonicalTranscriptMessageSchema, canonicalSessionTranscriptSchema, } from './transcript';
19
19
  export { observationProvenanceV1Schema, observedAgentSessionV1Schema, observedValueV1Schema, pendingUserRequestV1Schema, providerCapabilitiesV1Schema, providerSessionAdapterV1Schema, sessionEvidenceRefV1Schema, } from './observedSessionV1';
20
- export { quotaWindowSchema, quotaStateSchema, quotaFailureKindSchema, quotaProviderIdSchema, quotaSourceSchema, codexResetCreditSchema, codexResetCreditsSnapshotSchema, peakHoursStateSchema, quotaFailureDescriptorSchema, runtimeQuotaProviderSchema, providerQuotaStateSchema, claudeProviderQuotaStateSchema, codexProviderQuotaStateSchema, zaiProviderQuotaStateSchema, providerQuotaMapSchema, } from './quota';
20
+ export { quotaWindowSchema, quotaStateSchema, quotaLimitRowSchema, quotaExtraUsageSchema, quotaFailureKindSchema, quotaProviderIdSchema, quotaSourceSchema, codexResetCreditSchema, codexResetCreditsSnapshotSchema, peakHoursStateSchema, quotaFailureDescriptorSchema, runtimeQuotaProviderSchema, providerQuotaStateSchema, claudeProviderQuotaStateSchema, codexProviderQuotaStateSchema, zaiProviderQuotaStateSchema, providerQuotaMapSchema, } from './quota';
21
21
  export { quotaHistoryRuntimeProviderSchema, quotaHistorySampleSchema, quotaHistoryDailyBucketSchema, } from './quotaHistory';
22
22
  export { activeProviderAccountStatusSchema, activeAccountStatusSchema } from './accountStatus';
23
23
  export { accountProviderIdSchema, accountManagerResultSchema, beginAccountLoginResultSchema, accountLoginStatusSchema, accountEntrySchema, savedAccountProfileSchema, listAllAccountsResultSchema, accountHealthStateSchema, accountHealthSourceSchema, accountHealthSidecarSchema, accountHealthSchema, accountViewSchema, runningProcessSchema, accountConsumerKindSchema, runningAccountConsumerSchema, switchAccountResultSchema, lastSwitchRecordSchema, providerSyncReportSchema, syncReportSchema, accountLaunchEnvSchema, } from './accountManager';
24
24
  export { assistantTurnEventSchema, assistantTurnEventTypeSchema, assistantTurnNarrationStepSchema, assistantTurnProcessSchema, assistantTurnProcessStepSchema, assistantTurnProjectionSchema, assistantTurnReasoningTimelineItemSchema, assistantTurnSubagentSchema, assistantTurnSubagentStatusSchema, assistantTurnTimelineItemSchema, assistantTurnToolGroupStepSchema, assistantTurnToolRefSchema, } from './assistantTurn';
25
- export { sidekickStateFileSchema, stateFileAccountSchema, stateFileBillingBlockSchema, stateFileContextSchema, stateFileQuotaSchema, stateFileQuotaWindowSchema, stateFileSessionSchema, stateFileWriterSchema, } from './stateFile';
25
+ export { sidekickStateFileSchema, stateFileAccountSchema, stateFileBillingBlockSchema, stateFileContextSchema, stateFileQuotaSchema, stateFileQuotaWindowSchema, stateFileQuotaLimitSchema, stateFileSessionSchema, stateFileWriterSchema, } from './stateFile';
@@ -14,6 +14,33 @@ import { QUOTA_PROVIDER_IDS, RUNTIME_QUOTA_PROVIDER_IDS } from '../providerIds';
14
14
  export const quotaWindowSchema = z.object({
15
15
  utilization: z.number(),
16
16
  resetsAt: z.string(),
17
+ absent: z.boolean().optional(),
18
+ windowMs: z.number().optional(),
19
+ });
20
+ // ── QuotaLimitRow / QuotaExtraUsage ──
21
+ export const quotaLimitRowSchema = z.object({
22
+ kind: z.string(),
23
+ group: z.string(),
24
+ label: z.string(),
25
+ utilization: z.number(),
26
+ resetsAt: z.string(),
27
+ windowMs: z.number().optional(),
28
+ projected: z.number().optional(),
29
+ scopeModel: z.string().optional(),
30
+ scopeSurface: z.string().optional(),
31
+ severity: z.string().optional(),
32
+ isActive: z.boolean().optional(),
33
+ allowancePercentOfWeekly: z.number().optional(),
34
+ usedPercentOfWeekly: z.number().optional(),
35
+ });
36
+ export const quotaExtraUsageSchema = z.object({
37
+ enabled: z.boolean(),
38
+ monthlyLimit: z.number().nullable(),
39
+ usedCredits: z.number().nullable(),
40
+ utilization: z.number().nullable(),
41
+ currency: z.string().optional(),
42
+ decimalPlaces: z.number().optional(),
43
+ disabledReason: z.string().optional(),
17
44
  });
18
45
  // ── QuotaState ──
19
46
  export const quotaFailureKindSchema = z.enum([
@@ -74,7 +101,10 @@ export const quotaStateSchema = z.object({
74
101
  credits: z.unknown().optional(),
75
102
  resetCredits: codexResetCreditsSnapshotSchema.optional(),
76
103
  planType: z.string().optional(),
104
+ planLabel: z.string().optional(),
77
105
  rateLimitReachedType: z.string().optional(),
106
+ limits: z.array(quotaLimitRowSchema).optional(),
107
+ extraUsage: quotaExtraUsageSchema.optional(),
78
108
  });
79
109
  // ── PeakHoursState ──
80
110
  export const peakHoursStateSchema = z.object({
@@ -21,8 +21,16 @@ export const quotaHistorySampleSchema = z.object({
21
21
  runtimeProvider: quotaHistoryRuntimeProviderSchema,
22
22
  providerId: z.string(),
23
23
  workspaceId: z.string(),
24
- fiveHour: z.object({ utilization: z.number(), resetsAt: z.string() }),
25
- sevenDay: z.object({ utilization: z.number(), resetsAt: z.string() }),
24
+ fiveHour: z.object({
25
+ utilization: z.number(),
26
+ resetsAt: z.string(),
27
+ absent: z.boolean().optional(),
28
+ }),
29
+ sevenDay: z.object({
30
+ utilization: z.number(),
31
+ resetsAt: z.string(),
32
+ absent: z.boolean().optional(),
33
+ }),
26
34
  available: z.boolean(),
27
35
  error: z.string().optional(),
28
36
  source: z.enum(['session', 'cache', 'api', 'statusline']).optional(),
@@ -16,6 +16,13 @@ export const stateFileWriterSchema = z.enum([
16
16
  export const stateFileQuotaWindowSchema = z.object({
17
17
  utilization: z.number(),
18
18
  resetsAt: z.string(),
19
+ absent: z.boolean().optional(),
20
+ });
21
+ export const stateFileQuotaLimitSchema = z.object({
22
+ kind: z.string(),
23
+ label: z.string(),
24
+ utilization: z.number(),
25
+ resetsAt: z.string(),
19
26
  });
20
27
  export const stateFileQuotaSchema = z.object({
21
28
  fiveHour: stateFileQuotaWindowSchema,
@@ -25,6 +32,8 @@ export const stateFileQuotaSchema = z.object({
25
32
  capturedAt: z.string().nullable(),
26
33
  ageMs: z.number().nullable(),
27
34
  freshness: z.enum(['fresh', 'aging', 'stale']).nullable(),
35
+ planLabel: z.string().optional(),
36
+ extraLimits: z.array(stateFileQuotaLimitSchema).optional(),
28
37
  });
29
38
  export const stateFileAccountSchema = z.object({
30
39
  providerId: z.enum(['claude-code', 'codex']),
@@ -15,7 +15,7 @@
15
15
  */
16
16
  import * as fs from 'fs';
17
17
  import { getGlobalDataPath } from './paths';
18
- import { classifyQuotaFreshness } from './quota';
18
+ import { classifyQuotaFreshness, extraQuotaRows } from './quota';
19
19
  import { atomicWriteJsonSync } from './writers/atomic';
20
20
  export const STATE_FILE_SCHEMA_VERSION = 1;
21
21
  export const STATE_FILE_NAME = 'state.json';
@@ -90,14 +90,29 @@ export function quotaToStateFile(quota, now = Date.now()) {
90
90
  freshness ??= classifyQuotaFreshness(ageMs);
91
91
  }
92
92
  }
93
+ const extraLimits = extraQuotaRows(quota).map((row) => ({
94
+ kind: row.kind,
95
+ label: row.label,
96
+ utilization: row.utilization,
97
+ resetsAt: row.resetsAt,
98
+ }));
93
99
  return {
94
- fiveHour: { utilization: quota.fiveHour.utilization, resetsAt: quota.fiveHour.resetsAt },
95
- sevenDay: { utilization: quota.sevenDay.utilization, resetsAt: quota.sevenDay.resetsAt },
100
+ fiveHour: stateFileWindow(quota.fiveHour),
101
+ sevenDay: stateFileWindow(quota.sevenDay),
96
102
  source: quota.source ?? null,
97
103
  capturedSource: quota.capturedSource ?? null,
98
104
  capturedAt: quota.capturedAt ?? null,
99
105
  ageMs,
100
106
  freshness,
107
+ ...(quota.planLabel ? { planLabel: quota.planLabel } : {}),
108
+ ...(extraLimits.length > 0 ? { extraLimits } : {}),
109
+ };
110
+ }
111
+ function stateFileWindow(window) {
112
+ return {
113
+ utilization: window.utilization,
114
+ resetsAt: window.resetsAt,
115
+ ...(window.absent ? { absent: true } : {}),
101
116
  };
102
117
  }
103
118
  /** Project a billing block onto the state-file shape (totals only). */
@@ -115,14 +115,26 @@ export function parseClaudeStatuslinePayload(text) {
115
115
  raw,
116
116
  };
117
117
  }
118
- function toWindow(live, fallback) {
118
+ /**
119
+ * Claude Code leaves a window out of the document once its reset has passed,
120
+ * and always for a window the plan does not have (Ultra has no five-hour
121
+ * limit). A fallback is carried over only while it can still be current: an
122
+ * `absent` marker from an earlier API read, or a window that has not reset yet.
123
+ * An expired fallback would otherwise be re-saved as a fresh sample forever.
124
+ */
125
+ function toWindow(live, fallback, nowMs) {
119
126
  if (live) {
120
127
  return {
121
128
  utilization: Math.max(0, live.usedPercentage),
122
129
  resetsAt: new Date(live.resetsAt * 1000).toISOString(),
123
130
  };
124
131
  }
125
- return fallback ?? { utilization: 0, resetsAt: '' };
132
+ if (fallback?.absent)
133
+ return { utilization: 0, resetsAt: '', absent: true };
134
+ const fallbackResetMs = fallback ? Date.parse(fallback.resetsAt) : NaN;
135
+ if (fallback && Number.isFinite(fallbackResetMs) && fallbackResetMs > nowMs)
136
+ return fallback;
137
+ return { utilization: 0, resetsAt: '' };
126
138
  }
127
139
  /**
128
140
  * Build a `QuotaState` from the official rate-limit block. Returns `null`
@@ -137,8 +149,8 @@ export function quotaFromStatuslinePayload(payload, options = {}) {
137
149
  const now = options.now ?? new Date();
138
150
  const fallback = options.fallback ?? undefined;
139
151
  return {
140
- fiveHour: toWindow(limits.fiveHour, fallback?.fiveHour),
141
- sevenDay: toWindow(limits.sevenDay, fallback?.sevenDay),
152
+ fiveHour: toWindow(limits.fiveHour, fallback?.fiveHour, now.getTime()),
153
+ sevenDay: toWindow(limits.sevenDay, fallback?.sevenDay, now.getTime()),
142
154
  available: true,
143
155
  providerId: 'claude-code',
144
156
  source: 'statusline',
@@ -1,4 +1,4 @@
1
- import { FIVE_HOUR_WINDOW_MS, formatQuotaAge } from '../quota';
1
+ import { FIVE_HOUR_WINDOW_MS, SEVEN_DAY_WINDOW_MS, formatQuotaAge, quotaWindowApplies, quotaWindowHasData, quotaWindowShortLabel, } from '../quota';
2
2
  import { estimateTimeToQuota } from './BurnRateCalculator';
3
3
  export function selectStatuslineAccount(input) {
4
4
  if (input.accounts.claude.present) {
@@ -23,6 +23,11 @@ export function selectStatuslineAccount(input) {
23
23
  * One-line status. Segments, in order, each omitted when unknown:
24
24
  * `acct:<label> · 5h 42% resets 14:00 · ~1h20m left · 7d 61% · (2h ago) · ctx 37% · $0.42 · cache 92%`
25
25
  *
26
+ * Plans without a five-hour window (Claude Ultra) lead with the weekly window
27
+ * instead: `acct:<label> · 7d 17% resets Fri 01:00 · ~2d3h left · …`. Window
28
+ * labels follow the reported window length, so a Codex weekly primary window
29
+ * reads `7d`, not `5h`.
30
+ *
26
31
  * The age segment appears only for cached quota older than five minutes, so
27
32
  * a snapshot from yesterday can no longer read like a live figure.
28
33
  */
@@ -37,20 +42,35 @@ export function formatStatusline(input) {
37
42
  if (!quota?.available) {
38
43
  return joinSegments([`acct:${account}`, 'quota unavailable', ...liveSegments]);
39
44
  }
40
- const utilization = clampPercent(quota.fiveHour.utilization);
41
- const reset = formatReset(quota.fiveHour.resetsAt, now);
42
- const eta = estimateWindowEta(quota, now);
43
- const segments = [`acct:${account}`, `5h ${Math.round(utilization)}% resets ${reset}`];
45
+ const first = describeWindow(quota.fiveHour, '5h', FIVE_HOUR_WINDOW_MS);
46
+ const second = describeWindow(quota.sevenDay, '7d', SEVEN_DAY_WINDOW_MS);
47
+ // Lead with the first window whenever the plan has it (even idle); fall back
48
+ // to the second window when the first does not exist for this plan.
49
+ const leadWithFirst = quotaWindowApplies(quota.fiveHour) || !quotaWindowHasData(quota.sevenDay);
50
+ const lead = leadWithFirst ? first : second;
51
+ const segments = [`acct:${account}`, formatLeadSegment(lead, now)];
52
+ const eta = estimateWindowEta(lead, quota.capturedAt, now);
44
53
  if (eta != null)
45
54
  segments.push(`~${formatMinutes(eta)} left`);
46
- if (quota.sevenDay.resetsAt && quota.sevenDay.utilization > 0) {
47
- segments.push(`7d ${Math.round(clampPercent(quota.sevenDay.utilization))}%`);
55
+ if (leadWithFirst && quotaWindowHasData(quota.sevenDay) && quota.sevenDay.utilization > 0) {
56
+ segments.push(`${second.label} ${Math.round(clampPercent(quota.sevenDay.utilization))}%`);
48
57
  }
49
58
  if (quota.freshness && quota.freshness !== 'fresh') {
50
59
  segments.push(`(${formatQuotaAge(quota.ageMs)})`);
51
60
  }
52
61
  return joinSegments([...segments, ...liveSegments]);
53
62
  }
63
+ function describeWindow(window, label, defaultMs) {
64
+ const windowMs = typeof window.windowMs === 'number' && Number.isFinite(window.windowMs) && window.windowMs > 0
65
+ ? window.windowMs
66
+ : defaultMs;
67
+ return { label: quotaWindowShortLabel(window.windowMs, label), window, windowMs };
68
+ }
69
+ function formatLeadSegment(lead, now) {
70
+ const percent = `${lead.label} ${Math.round(clampPercent(lead.window.utilization))}%`;
71
+ const reset = formatReset(lead.window.resetsAt, now);
72
+ return reset ? `${percent} resets ${reset}` : percent;
73
+ }
54
74
  function formatLiveSegments(live) {
55
75
  if (!live)
56
76
  return [];
@@ -76,22 +96,25 @@ function formatCost(value) {
76
96
  return value.toFixed(1);
77
97
  return value.toFixed(2);
78
98
  }
79
- function estimateWindowEta(quota, now) {
80
- const resetAt = Date.parse(quota.fiveHour.resetsAt);
99
+ function estimateWindowEta(lead, capturedAtIso, now) {
100
+ const { window, windowMs } = lead;
101
+ if (window.absent)
102
+ return null;
103
+ const resetAt = Date.parse(window.resetsAt);
81
104
  if (!Number.isFinite(resetAt))
82
105
  return null;
83
106
  const nowMs = now.getTime();
84
107
  if (resetAt <= nowMs)
85
108
  return null;
86
- const capturedAt = quota.capturedAt ? Date.parse(quota.capturedAt) : now.getTime();
109
+ const capturedAt = capturedAtIso ? Date.parse(capturedAtIso) : now.getTime();
87
110
  const sampleAt = Number.isFinite(capturedAt) ? capturedAt : now.getTime();
88
111
  if (sampleAt >= resetAt)
89
112
  return null;
90
- const elapsedMinutes = (sampleAt - (resetAt - FIVE_HOUR_WINDOW_MS)) / 60_000;
91
- if (elapsedMinutes <= 0 || quota.fiveHour.utilization <= 0)
113
+ const elapsedMinutes = (sampleAt - (resetAt - windowMs)) / 60_000;
114
+ if (elapsedMinutes <= 0 || window.utilization <= 0)
92
115
  return null;
93
- const burnRate = quota.fiveHour.utilization / elapsedMinutes;
94
- const eta = estimateTimeToQuota(quota.fiveHour.utilization, 100, burnRate);
116
+ const burnRate = window.utilization / elapsedMinutes;
117
+ const eta = estimateTimeToQuota(window.utilization, 100, burnRate);
95
118
  const minutesUntilReset = (resetAt - nowMs) / 60_000;
96
119
  return eta !== null && eta < minutesUntilReset ? eta : null;
97
120
  }
@@ -103,20 +126,36 @@ function compactLabel(value) {
103
126
  function clampPercent(value) {
104
127
  return Number.isFinite(value) ? Math.min(100, Math.max(0, value)) : 0;
105
128
  }
106
- function formatReset(value, fallback) {
129
+ /**
130
+ * Reset time as `HH:MM`, or `Fri 01:00` when it is more than a day away.
131
+ * Returns '' for an empty or unparseable value — never the current time.
132
+ */
133
+ function formatReset(value, now) {
134
+ if (!value)
135
+ return '';
107
136
  const reset = new Date(value);
108
- const date = Number.isNaN(reset.getTime()) ? fallback : reset;
109
- return new Intl.DateTimeFormat(undefined, {
137
+ if (Number.isNaN(reset.getTime()))
138
+ return '';
139
+ const time = new Intl.DateTimeFormat(undefined, {
110
140
  hour: '2-digit',
111
141
  minute: '2-digit',
112
142
  hour12: false,
113
- }).format(date);
143
+ }).format(reset);
144
+ if (reset.getTime() - now.getTime() <= 86_400_000)
145
+ return time;
146
+ const weekday = new Intl.DateTimeFormat(undefined, { weekday: 'short' }).format(reset);
147
+ return `${weekday} ${time}`;
114
148
  }
115
149
  function formatMinutes(value) {
116
150
  const minutes = Math.max(0, Math.round(value));
117
151
  if (minutes < 60)
118
152
  return `${minutes}min`;
119
153
  const hours = Math.floor(minutes / 60);
154
+ if (hours >= 48) {
155
+ const days = Math.floor(hours / 24);
156
+ const remainderHours = hours % 24;
157
+ return remainderHours ? `${days}d${remainderHours}h` : `${days}d`;
158
+ }
120
159
  const remainder = minutes % 60;
121
160
  return remainder ? `${hours}h${remainder}m` : `${hours}h`;
122
161
  }
@@ -1,7 +1,7 @@
1
1
  export { getActiveAccountStatus } from '../accountStatus';
2
2
  export { readQuotaSnapshot, writeQuotaSnapshot } from '../quotaSnapshots';
3
- export { appendQuotaHistorySample, getWorkspaceIdFromPath } from '../quotaHistory';
4
- export { classifyQuotaFreshness, formatQuotaAge } from '../quota';
3
+ export { appendQuotaHistorySample, getWorkspaceIdFromPath, quotaHistoryWindow, } from '../quotaHistory';
4
+ export { classifyQuotaFreshness, formatQuotaAge, quotaWindowApplies, quotaWindowHasData, quotaWindowShortLabel, } from '../quota';
5
5
  export { BurnRateCalculator, estimateTimeToQuota } from './BurnRateCalculator';
6
6
  export { formatStatusline, selectStatuslineAccount } from './formatter';
7
7
  export { parseClaudeStatuslinePayload, quotaFromStatuslinePayload, } from './claudeStatuslinePayload';
@@ -2,7 +2,7 @@ import fs from 'fs';
2
2
  import os from 'os';
3
3
  import path from 'path';
4
4
  import { readQuotaSnapshot, writeQuotaSnapshot } from './quotaSnapshots';
5
- import { FIVE_HOUR_WINDOW_MS, SEVEN_DAY_WINDOW_MS, withQuotaProjections } from './quota';
5
+ import { FIVE_HOUR_WINDOW_MS, SEVEN_DAY_WINDOW_MS, quotaSampleExpired, withQuotaProjections, } from './quota';
6
6
  const DEFAULT_ZAI_BASE_URL = 'https://api.z.ai/api/anthropic';
7
7
  const QUOTA_PATH = '/api/monitor/usage/quota/limit';
8
8
  const DEFAULT_ACCOUNT_ID = 'default';
@@ -257,7 +257,9 @@ export async function resolveZaiQuota(options = {}) {
257
257
  return enrichZaiQuota(apiQuota);
258
258
  }
259
259
  const cached = readSnapshot('zai', accountId);
260
- if (cached) {
260
+ // Every window of the cached sample has reset since it was taken: it would
261
+ // only show old percentages with "resets now", so report the API failure.
262
+ if (cached && !quotaSampleExpired(cached)) {
261
263
  return enrichZaiQuota({
262
264
  ...cached,
263
265
  providerId: 'zai',
package/dist/index.d.ts CHANGED
@@ -22,7 +22,7 @@ export { readSessionReportInputs } from './report/sessionReportInputs';
22
22
  export type { SessionReportInputs } from './report/sessionReportInputs';
23
23
  export { fingerprintString, sessionFingerprintParts } from './sessionFingerprint';
24
24
  export { STATE_FILE_NAME, STATE_FILE_SCHEMA_VERSION, billingBlockToStateFile, getStateFilePath, quotaToStateFile, readStateFile, writeStateFile, } from './stateFile';
25
- export type { SidekickStateFile, SidekickStateInput, StateFileAccount, StateFileBillingBlock, StateFileContext, StateFileQuota, StateFileQuotaWindow, StateFileSession, StateFileWriter, WriteStateFileOptions, } from './stateFile';
25
+ export type { SidekickStateFile, SidekickStateInput, StateFileAccount, StateFileBillingBlock, StateFileContext, StateFileQuota, StateFileQuotaWindow, StateFileQuotaLimit, StateFileSession, StateFileWriter, WriteStateFileOptions, } from './stateFile';
26
26
  export type { ComputeSessionFileStatsOptions, ReadSessionFileStatsOptions } from './sessionStats';
27
27
  export { BILLING_BLOCK_DURATION_MS, computeBillingBlocks, findActiveBillingBlock, } from './usage/billingBlocks';
28
28
  export type { BillingBlock, BillingBlockInput, BillingBlockModelUsage, BillingBlockTokens, ComputeBillingBlocksOptions, } from './usage/billingBlocks';
@@ -214,12 +214,12 @@ export type { CodexAccountManagerResult, CodexCredentialStoreMode } from './code
214
214
  export { writeAccountLauncher, writeLauncher, removeLauncher } from './terminalSync';
215
215
  export { DEFAULT_AUTO_SWITCH_CONFIG, decideAutoSwitch, AutoSwitchController } from './autoSwitch';
216
216
  export type { AutoSwitchActiveAccount, AutoSwitchCandidate, AutoSwitchConfig, AutoSwitchControllerOptions, AutoSwitchDecision, AutoSwitchTransitionEvent, } from './autoSwitch';
217
- export { FIVE_HOUR_WINDOW_MS, QUOTA_PROVIDER_IDS, SEVEN_DAY_WINDOW_MS, fetchQuota, projectQuotaWindow, withQuotaProjections, } from './quota';
218
- export type { CodexResetCredit, CodexResetCreditsSnapshot, QuotaProjectionInput, QuotaProviderId, QuotaWindow, QuotaState, } from './quota';
217
+ export { FIVE_HOUR_WINDOW_MS, QUOTA_PROVIDER_IDS, SEVEN_DAY_WINDOW_MS, claudePlanLabel, extraQuotaRows, fetchQuota, formatExtraUsage, projectQuotaWindow, quotaSampleExpired, quotaStateFromClaudeUsagePayload, quotaWindowApplies, quotaWindowHasData, quotaWindowLabel, quotaWindowShortLabel, withClaudePlan, withQuotaProjections, } from './quota';
218
+ export type { ClaudePlanInfo, CodexResetCredit, CodexResetCreditsSnapshot, QuotaExtraUsage, QuotaLimitRow, QuotaProjectionInput, QuotaProviderId, QuotaWindow, QuotaState, } from './quota';
219
219
  export { describeQuotaFailure } from './quotaPresentation';
220
220
  export type { QuotaFailureDescriptor } from './quotaPresentation';
221
221
  export { QuotaPoller } from './quotaPoller';
222
- export type { QuotaPollerOptions } from './quotaPoller';
222
+ export type { QuotaPollerCredentials, QuotaPollerOptions } from './quotaPoller';
223
223
  export { readQuotaSnapshot, writeQuotaSnapshot } from './quotaSnapshots';
224
224
  export type { QuotaSnapshotRecord } from './quotaSnapshots';
225
225
  export { resolveQuota } from './quotaResolver';
@@ -230,7 +230,7 @@ export { DEFAULT_QUOTA_THRESHOLDS, describeQuotaThresholdAlert, evaluateQuotaThr
230
230
  export type { QuotaAlertMemory, QuotaThresholdAlert, QuotaThresholdConfig, QuotaThresholdEvaluation, QuotaThresholdWindow, } from './quotaThresholds';
231
231
  export { parseClaudeStatuslinePayload, quotaFromStatuslinePayload, } from './statusline/claudeStatuslinePayload';
232
232
  export type { ClaudeStatuslinePayload, ClaudeStatuslineRateLimitWindow, QuotaFromStatuslineOptions, } from './statusline/claudeStatuslinePayload';
233
- export { appendQuotaHistorySample, readQuotaHistoryRange, readQuotaHistoryDailyBuckets, pruneQuotaHistory, getWorkspaceIdFromPath, } from './quotaHistory';
233
+ export { appendQuotaHistorySample, readQuotaHistoryRange, readQuotaHistoryDailyBuckets, pruneQuotaHistory, getWorkspaceIdFromPath, quotaHistoryWindow, } from './quotaHistory';
234
234
  export type { QuotaHistorySample, QuotaHistoryAppendOptions, QuotaHistoryRangeOptions, QuotaHistoryDailyBucket, QuotaHistoryRuntimeProvider, } from './quotaHistory';
235
235
  export { fetchCodexResetCreditsFromApi, fetchCodexQuotaFromApi, quotaFromCodexRateLimits, readLatestCodexQuotaFromRollouts, resolveCodexQuota, resolveCodexQuotaFromLocalSources, } from './codexQuota';
236
236
  export type { CodexQuotaApiOptions, CodexQuotaCreditsSnapshot, CodexQuotaResolveOptions, CodexQuotaResolveSource, } from './codexQuota';
@@ -267,7 +267,7 @@ export type { ErrorCategory } from './extractors/errorTaxonomy';
267
267
  export { extractToolCall, extractToolCalls, ToolCallTracker } from './extractors/toolCall';
268
268
  export type { GatherAssetsOptions, GatherAssetsResult } from './extractors/gatherAssets';
269
269
  export { messageUsageSchema, sessionMessageSchema, sessionEventSchema, permissionModeSchema, extractSessionEvents, } from './schemas/sessionEvent';
270
- export { quotaWindowSchema, quotaStateSchema, quotaFailureKindSchema, quotaProviderIdSchema, quotaSourceSchema, codexResetCreditSchema, codexResetCreditsSnapshotSchema, peakHoursStateSchema, quotaFailureDescriptorSchema, runtimeQuotaProviderSchema, providerQuotaStateSchema, claudeProviderQuotaStateSchema, codexProviderQuotaStateSchema, zaiProviderQuotaStateSchema, providerQuotaMapSchema, } from './schemas/quota';
270
+ export { quotaWindowSchema, quotaStateSchema, quotaLimitRowSchema, quotaExtraUsageSchema, quotaFailureKindSchema, quotaProviderIdSchema, quotaSourceSchema, codexResetCreditSchema, codexResetCreditsSnapshotSchema, peakHoursStateSchema, quotaFailureDescriptorSchema, runtimeQuotaProviderSchema, providerQuotaStateSchema, claudeProviderQuotaStateSchema, codexProviderQuotaStateSchema, zaiProviderQuotaStateSchema, providerQuotaMapSchema, } from './schemas/quota';
271
271
  export { quotaHistoryRuntimeProviderSchema, quotaHistorySampleSchema, quotaHistoryDailyBucketSchema, } from './schemas/quotaHistory';
272
272
  export { providerAuthenticationEvidenceSchema, providerFailureEvidenceSchema, providerRetryAfterSchema, providerFailureDiagnosisSchema, } from './schemas/providerFailure';
273
273
  export { activeProviderAccountStatusSchema, activeAccountStatusSchema, } from './schemas/accountStatus';
package/dist/index.js CHANGED
@@ -10,11 +10,11 @@ exports.extractProposedPlanShared = exports.parsePlanMarkdownShared = exports.Pl
10
10
  exports.calculateCodeImpact = exports.scoreSessionQuality = exports.calculateQualityTrend = exports.PatternExtractor = exports.HeatmapTracker = exports.FrequencyTracker = exports.readErrorHistory = exports.getTopFailingTools = exports.appendErrorHistory = exports.MAX_ERROR_HISTORY_SESSIONS = exports.ERROR_HISTORY_SCHEMA_VERSION = exports.getSnapshotPath = exports.MAX_SNAPSHOT_FILES = exports.pruneSnapshots = exports.isSnapshotValid = exports.deleteSnapshot = exports.loadSnapshot = exports.saveSnapshot = exports.SessionMonitor = exports.parseTodoDependencies = exports.EventAggregator = exports.getRandomPhrase = exports.PHRASE_CATEGORIES = exports.ALL_PHRASES = exports.HIGHLIGHT_CSS = exports.clearHighlightCache = exports.highlightEvent = exports.formatSessionJson = exports.formatSessionMarkdown = exports.formatSessionText = exports.classifyNoise = exports.shouldMergeWithPrevious = exports.classifyFollowEvent = exports.classifyMessage = exports.getSoftNoiseReason = exports.isHardNoiseFollowEvent = exports.isHardNoise = exports.formatToolSummary = exports.parseLocalDateKey = exports.formatTokenCount = exports.formatLocalDateKey = exports.formatDurationMs = exports.addLocalDays = exports.DEFAULT_JSONL_TAIL_READ_BYTES = exports.DEFAULT_JSONL_TAIL_MAX_LINE_BYTES = exports.createJsonlTail = exports.toFollowEvents = exports.resolveSessionPath = exports.createWatcher = exports.parseChangelog = void 0;
11
11
  exports.removeAccount = exports.reconcileClaudeAuthState = exports.applyActiveClaudeToLiveHome = exports.resolveActiveClaudeHome = exports.cleanupAbandonedClaudeLogins = exports.syncClaudeLiveState = exports.switchToAccountAsync = exports.switchToAccount = exports.addCurrentAccount = exports.readActiveClaudeAccount = exports.writeAccountRegistry = exports.readAccountRegistry = exports.ensureDefaultAccounts = exports.codexIdentitiesMatch = exports.readCodexAccessTokenExpiry = exports.readCodexLastRefresh = exports.readCodexAuthIdentity = exports.parseCodexAuthJson = exports.CLAUDE_REFRESH_TOKEN_LIFETIME_ESTIMATE_MS = exports.CLAUDE_ACCESS_TOKEN_LIFETIME_MS = exports.mergeClaudeLoginIntoLive = exports.claudeLoginOnly = exports.claudeRefreshFingerprint = exports.resolveClaudeRefreshExpiry = exports.isNewerClaudeCredential = exports.claudeCredentialFreshness = exports.parseClaudeCredentialBlob = exports.readClaudeMaxAccessTokenSync = exports.readClaudeMaxCredentialsRaw = exports.readClaudeMaxCredentials = exports.parseKeychainDump = exports.repairClaudeCredentialStores = exports.inspectClaudeCredentialStores = exports.getClaudeCredentialLedgerPath = exports.readClaudeCredentialLedger = exports.decideLiveClaudeWrite = exports.SIDEKICK_KEYCHAIN_COMMENT_PREFIX = exports.ClaudeCredentialWriteError = exports.deleteStoredCredentials = exports.writeActiveCredentials = exports.readClaudeCredentialStore = exports.readActiveCredentials = exports.openInBrowser = exports.parseTranscriptFromEvents = exports.parseTranscript = exports.generateHtmlReport = exports.formatCompactionLedger = exports.calculateCompactionLedger = exports.describeCostProvenance = exports.classifyCostProvenance = void 0;
12
12
  exports.getClaudeConfigPath = exports.getClaudeProfileHome = exports.getClaudeProfilesDir = exports.onAccountsChanged = exports.getActiveAccountStatus = exports.ACCOUNT_PROVIDER_IDS = exports.removeSavedAccountProfile = exports.replaceSavedAccountProfiles = exports.setActiveSavedAccount = exports.upsertSavedAccountProfile = exports.getActiveSavedAccount = exports.listSavedAccountProfiles = exports.writeSavedAccountRegistry = exports.readSavedAccountRegistry = exports.getAccountsDir = exports.ACCOUNT_CONSUMER_REACHABILITY = exports.describeAccountConsumer = exports.detectRunningAccountConsumersSync = exports.detectRunningAccountConsumers = exports.findRunningProcessesSync = exports.findRunningProcesses = exports.keepAliveCommand = exports.refreshInactiveAccounts = exports.getAccountLaunchEnv = exports.getHealthSidecarPath = exports.readHealthSidecar = exports.listAccountsWithHealth = exports.getAccountHealth = exports.cleanupAbandonedLogins = exports.syncLiveAccountStateSync = exports.syncLiveAccountState = exports.getLastSwitchPath = exports.readLastSwitch = exports.discardAccountLogin = exports.resolveClaudeLoginCommand = exports.listAllAccounts = exports.getLastSwitch = exports.undoLastSwitch = exports.switchAccountAsync = exports.switchAccount = exports.spawnAccountLogin = exports.finalizeAccountLoginAsync = exports.finalizeAccountLogin = exports.getAccountLoginStatusAsync = exports.getAccountLoginStatus = exports.beginAccountLogin = exports.isMultiAccountEnabled = exports.resolveActiveClaudeAccount = exports.getActiveAccount = exports.listAccounts = void 0;
13
- exports.classifyQuotaFreshness = exports.resolveQuota = exports.writeQuotaSnapshot = exports.readQuotaSnapshot = exports.QuotaPoller = exports.describeQuotaFailure = exports.withQuotaProjections = exports.projectQuotaWindow = exports.fetchQuota = exports.SEVEN_DAY_WINDOW_MS = exports.QUOTA_PROVIDER_IDS = exports.FIVE_HOUR_WINDOW_MS = exports.AutoSwitchController = exports.decideAutoSwitch = exports.DEFAULT_AUTO_SWITCH_CONFIG = exports.removeLauncher = exports.writeLauncher = exports.writeAccountLauncher = exports.CODEX_KEYRING_FIX_HINT = exports.getCodexCredentialStoreMode = exports.cleanupAbandonedCodexLogins = exports.syncCodexLiveState = exports.removeCodexAccount = exports.switchToCodexAccountAsync = exports.switchToCodexAccount = exports.finalizeCodexAccountAsync = exports.finalizeCodexAccount = exports.prepareCodexAccountAsync = exports.prepareCodexAccount = exports.getCodexExecutionEnv = exports.resolveSidekickCodexHome = exports.resolveActiveCodexAccount = exports.getActiveCodexAccount = exports.listCodexAccounts = exports.getSystemCodexHome = exports.getCodexMonitoringHomes = exports.getCodexProfileHome = exports.getCodexProfilesDir = exports.getClaudeProjectsDir = exports.isDefaultClaudeHome = exports.getDefaultClaudeHome = exports.getLiveClaudeHome = exports.readLiveClaudeIdentity = exports.readClaudeProfileIdentity = exports.isClaudeProfileAuthenticated = exports.CLAUDE_SECURESTORAGE_CONFIG_DIR_ENV = exports.buildClaudeChildEnv = exports.claudeKeychainAccountName = exports.claudeKeychainService = exports.claudeKeychainSuffix = void 0;
14
- exports.registerModelAlias = exports.importResolvedModelCatalog = exports.exportResolvedModelCatalog = exports.MODEL_PROVIDER_IDS = exports.formatCost = exports.sortModelIds = exports.compareModelIds = exports.getModelDisplayInfo = exports.shortModelName = exports.mergeCostSources = exports.calculateCostWithProvenance = exports.calculateCostWithPricing = exports.calculateCost = exports.getModelInfo = exports.resolveModelPricing = exports.getModelPricing = exports.parseModelId = exports.DEFAULT_CONTEXT_WINDOW = exports.resolveModelContextWindow = exports.getModelContextWindowSize = exports.selectStatuslineAccount = exports.formatStatusline = exports.estimateTimeToQuota = exports.BurnRateCalculator = exports.RUNTIME_QUOTA_PROVIDER_IDS = exports.MultiProviderQuotaService = exports.resolveZaiQuota = exports.readZaiCredentials = exports.quotaStateFromZaiQuotaLimitPayload = exports.fetchZaiQuotaFromApi = exports.CodexQuotaWatcher = exports.resolveCodexQuotaFromLocalSources = exports.resolveCodexQuota = exports.readLatestCodexQuotaFromRollouts = exports.quotaFromCodexRateLimits = exports.fetchCodexQuotaFromApi = exports.fetchCodexResetCreditsFromApi = exports.getWorkspaceIdFromPath = exports.pruneQuotaHistory = exports.readQuotaHistoryDailyBuckets = exports.readQuotaHistoryRange = exports.appendQuotaHistorySample = exports.quotaFromStatuslinePayload = exports.parseClaudeStatuslinePayload = exports.evaluateQuotaThresholds = exports.describeQuotaThresholdAlert = exports.DEFAULT_QUOTA_THRESHOLDS = exports.QUOTA_FRESH_MAX_AGE_MS = exports.QUOTA_AGING_MAX_AGE_MS = exports.formatQuotaAge = void 0;
15
- exports.providerFailureDiagnosisSchema = exports.providerRetryAfterSchema = exports.providerFailureEvidenceSchema = exports.providerAuthenticationEvidenceSchema = exports.quotaHistoryDailyBucketSchema = exports.quotaHistorySampleSchema = exports.quotaHistoryRuntimeProviderSchema = exports.providerQuotaMapSchema = exports.zaiProviderQuotaStateSchema = exports.codexProviderQuotaStateSchema = exports.claudeProviderQuotaStateSchema = exports.providerQuotaStateSchema = exports.runtimeQuotaProviderSchema = exports.quotaFailureDescriptorSchema = exports.peakHoursStateSchema = exports.codexResetCreditsSnapshotSchema = exports.codexResetCreditSchema = exports.quotaSourceSchema = exports.quotaProviderIdSchema = exports.quotaFailureKindSchema = exports.quotaStateSchema = exports.quotaWindowSchema = exports.extractSessionEvents = exports.permissionModeSchema = exports.sessionEventSchema = exports.sessionMessageSchema = exports.messageUsageSchema = exports.ToolCallTracker = exports.extractToolCalls = exports.extractToolCall = exports.extractErrorMessage = exports.categorizeError = exports.gatherAssetsForCwd = exports.codexSessions = exports.readCodexAssets = exports.claudeSessions = exports.readClaudeAssets = exports.extractCommands = exports.extractFilePaths = exports.extractUrls = exports.extractTokenUsage = exports.getObservedContextWindowPath = exports.recordObservedContextWindow = exports.loadObservedContextWindows = exports.LITELLM_CATALOG_URL = exports.normalizeLiteLlmContextWindows = exports.normalizeLiteLlmCatalog = exports.hydratePricingCatalog = exports.RESOLVED_MODEL_CATALOG_SCHEMA_VERSION = exports.resolveModelAlias = void 0;
16
- exports.readStoredCodexAccount = exports.repairCodexCredentialStores = exports.inspectCodexCredentialStores = exports.fetchProviderServiceStatus = exports.PROVIDER_RECOVERY_ACTIONS = exports.PROVIDER_FAILURE_EVIDENCE_SOURCES = exports.PROVIDER_FAILURE_CODES = exports.PROVIDER_CREDENTIAL_KINDS = exports.PROVIDER_AUTHENTICATION_STATES = exports.PROVIDER_AUTHENTICATION_SOURCES = exports.diagnoseProviderFailure = exports.mergeFailingToolWindows = exports.failingToolTrend = exports.FAILING_TOOL_TREND_ARROWS = exports.scopePeakHoursToSessionProvider = exports.PEAK_HOURS_DESCRIPTION = exports.PEAK_HOURS_CACHE_MS = exports.isClaudeCodeSessionProvider = exports.getScheduledPeakHoursState = exports.fetchPeakHoursStatus = exports.DEFAULT_PEAK_HOURS_TIMEOUT_MS = exports.createPeakHoursNotApplicableState = exports._resetPeakHoursCache = exports.runDoctor = exports.getSessionDiagnostics = exports.formatHealthReport = exports.toLegacyProviderStatus = exports.fetchOpenAIStatus = exports.fetchProviderStatus = exports.assistantTurnToolRefSchema = exports.assistantTurnToolGroupStepSchema = exports.assistantTurnTimelineItemSchema = exports.assistantTurnSubagentStatusSchema = exports.assistantTurnSubagentSchema = exports.assistantTurnReasoningTimelineItemSchema = exports.assistantTurnProjectionSchema = exports.assistantTurnProcessStepSchema = exports.assistantTurnProcessSchema = exports.assistantTurnNarrationStepSchema = exports.assistantTurnEventTypeSchema = exports.assistantTurnEventSchema = exports.listAllAccountsResultSchema = exports.savedAccountProfileSchema = exports.accountEntrySchema = exports.accountLoginStatusSchema = exports.beginAccountLoginResultSchema = exports.accountManagerResultSchema = exports.accountProviderIdSchema = exports.activeAccountStatusSchema = exports.activeProviderAccountStatusSchema = void 0;
17
- exports.resolveWorkspaceRoots = exports.TOOL_CATEGORIES = exports.classifyTool = exports.CODEX_ARCHIVED_SESSIONS_SUBDIR = exports.CODEX_SESSIONS_SUBDIR = exports.getCodexSessionsDirs = exports.syncCodexLiveStateAsync = void 0;
13
+ exports.quotaWindowHasData = exports.quotaWindowApplies = exports.quotaStateFromClaudeUsagePayload = exports.quotaSampleExpired = exports.projectQuotaWindow = exports.formatExtraUsage = exports.fetchQuota = exports.extraQuotaRows = exports.claudePlanLabel = exports.SEVEN_DAY_WINDOW_MS = exports.QUOTA_PROVIDER_IDS = exports.FIVE_HOUR_WINDOW_MS = exports.AutoSwitchController = exports.decideAutoSwitch = exports.DEFAULT_AUTO_SWITCH_CONFIG = exports.removeLauncher = exports.writeLauncher = exports.writeAccountLauncher = exports.CODEX_KEYRING_FIX_HINT = exports.getCodexCredentialStoreMode = exports.cleanupAbandonedCodexLogins = exports.syncCodexLiveState = exports.removeCodexAccount = exports.switchToCodexAccountAsync = exports.switchToCodexAccount = exports.finalizeCodexAccountAsync = exports.finalizeCodexAccount = exports.prepareCodexAccountAsync = exports.prepareCodexAccount = exports.getCodexExecutionEnv = exports.resolveSidekickCodexHome = exports.resolveActiveCodexAccount = exports.getActiveCodexAccount = exports.listCodexAccounts = exports.getSystemCodexHome = exports.getCodexMonitoringHomes = exports.getCodexProfileHome = exports.getCodexProfilesDir = exports.getClaudeProjectsDir = exports.isDefaultClaudeHome = exports.getDefaultClaudeHome = exports.getLiveClaudeHome = exports.readLiveClaudeIdentity = exports.readClaudeProfileIdentity = exports.isClaudeProfileAuthenticated = exports.CLAUDE_SECURESTORAGE_CONFIG_DIR_ENV = exports.buildClaudeChildEnv = exports.claudeKeychainAccountName = exports.claudeKeychainService = exports.claudeKeychainSuffix = void 0;
14
+ exports.calculateCostWithPricing = exports.calculateCost = exports.getModelInfo = exports.resolveModelPricing = exports.getModelPricing = exports.parseModelId = exports.DEFAULT_CONTEXT_WINDOW = exports.resolveModelContextWindow = exports.getModelContextWindowSize = exports.selectStatuslineAccount = exports.formatStatusline = exports.estimateTimeToQuota = exports.BurnRateCalculator = exports.RUNTIME_QUOTA_PROVIDER_IDS = exports.MultiProviderQuotaService = exports.resolveZaiQuota = exports.readZaiCredentials = exports.quotaStateFromZaiQuotaLimitPayload = exports.fetchZaiQuotaFromApi = exports.CodexQuotaWatcher = exports.resolveCodexQuotaFromLocalSources = exports.resolveCodexQuota = exports.readLatestCodexQuotaFromRollouts = exports.quotaFromCodexRateLimits = exports.fetchCodexQuotaFromApi = exports.fetchCodexResetCreditsFromApi = exports.quotaHistoryWindow = exports.getWorkspaceIdFromPath = exports.pruneQuotaHistory = exports.readQuotaHistoryDailyBuckets = exports.readQuotaHistoryRange = exports.appendQuotaHistorySample = exports.quotaFromStatuslinePayload = exports.parseClaudeStatuslinePayload = exports.evaluateQuotaThresholds = exports.describeQuotaThresholdAlert = exports.DEFAULT_QUOTA_THRESHOLDS = exports.QUOTA_FRESH_MAX_AGE_MS = exports.QUOTA_AGING_MAX_AGE_MS = exports.formatQuotaAge = exports.classifyQuotaFreshness = exports.resolveQuota = exports.writeQuotaSnapshot = exports.readQuotaSnapshot = exports.QuotaPoller = exports.describeQuotaFailure = exports.withQuotaProjections = exports.withClaudePlan = exports.quotaWindowShortLabel = exports.quotaWindowLabel = void 0;
15
+ exports.quotaFailureDescriptorSchema = exports.peakHoursStateSchema = exports.codexResetCreditsSnapshotSchema = exports.codexResetCreditSchema = exports.quotaSourceSchema = exports.quotaProviderIdSchema = exports.quotaFailureKindSchema = exports.quotaExtraUsageSchema = exports.quotaLimitRowSchema = exports.quotaStateSchema = exports.quotaWindowSchema = exports.extractSessionEvents = exports.permissionModeSchema = exports.sessionEventSchema = exports.sessionMessageSchema = exports.messageUsageSchema = exports.ToolCallTracker = exports.extractToolCalls = exports.extractToolCall = exports.extractErrorMessage = exports.categorizeError = exports.gatherAssetsForCwd = exports.codexSessions = exports.readCodexAssets = exports.claudeSessions = exports.readClaudeAssets = exports.extractCommands = exports.extractFilePaths = exports.extractUrls = exports.extractTokenUsage = exports.getObservedContextWindowPath = exports.recordObservedContextWindow = exports.loadObservedContextWindows = exports.LITELLM_CATALOG_URL = exports.normalizeLiteLlmContextWindows = exports.normalizeLiteLlmCatalog = exports.hydratePricingCatalog = exports.RESOLVED_MODEL_CATALOG_SCHEMA_VERSION = exports.resolveModelAlias = exports.registerModelAlias = exports.importResolvedModelCatalog = exports.exportResolvedModelCatalog = exports.MODEL_PROVIDER_IDS = exports.formatCost = exports.sortModelIds = exports.compareModelIds = exports.getModelDisplayInfo = exports.shortModelName = exports.mergeCostSources = exports.calculateCostWithProvenance = void 0;
16
+ exports.FAILING_TOOL_TREND_ARROWS = exports.scopePeakHoursToSessionProvider = exports.PEAK_HOURS_DESCRIPTION = exports.PEAK_HOURS_CACHE_MS = exports.isClaudeCodeSessionProvider = exports.getScheduledPeakHoursState = exports.fetchPeakHoursStatus = exports.DEFAULT_PEAK_HOURS_TIMEOUT_MS = exports.createPeakHoursNotApplicableState = exports._resetPeakHoursCache = exports.runDoctor = exports.getSessionDiagnostics = exports.formatHealthReport = exports.toLegacyProviderStatus = exports.fetchOpenAIStatus = exports.fetchProviderStatus = exports.assistantTurnToolRefSchema = exports.assistantTurnToolGroupStepSchema = exports.assistantTurnTimelineItemSchema = exports.assistantTurnSubagentStatusSchema = exports.assistantTurnSubagentSchema = exports.assistantTurnReasoningTimelineItemSchema = exports.assistantTurnProjectionSchema = exports.assistantTurnProcessStepSchema = exports.assistantTurnProcessSchema = exports.assistantTurnNarrationStepSchema = exports.assistantTurnEventTypeSchema = exports.assistantTurnEventSchema = exports.listAllAccountsResultSchema = exports.savedAccountProfileSchema = exports.accountEntrySchema = exports.accountLoginStatusSchema = exports.beginAccountLoginResultSchema = exports.accountManagerResultSchema = exports.accountProviderIdSchema = exports.activeAccountStatusSchema = exports.activeProviderAccountStatusSchema = exports.providerFailureDiagnosisSchema = exports.providerRetryAfterSchema = exports.providerFailureEvidenceSchema = exports.providerAuthenticationEvidenceSchema = exports.quotaHistoryDailyBucketSchema = exports.quotaHistorySampleSchema = exports.quotaHistoryRuntimeProviderSchema = exports.providerQuotaMapSchema = exports.zaiProviderQuotaStateSchema = exports.codexProviderQuotaStateSchema = exports.claudeProviderQuotaStateSchema = exports.providerQuotaStateSchema = exports.runtimeQuotaProviderSchema = void 0;
17
+ exports.resolveWorkspaceRoots = exports.TOOL_CATEGORIES = exports.classifyTool = exports.CODEX_ARCHIVED_SESSIONS_SUBDIR = exports.CODEX_SESSIONS_SUBDIR = exports.getCodexSessionsDirs = exports.syncCodexLiveStateAsync = exports.readStoredCodexAccount = exports.repairCodexCredentialStores = exports.inspectCodexCredentialStores = exports.fetchProviderServiceStatus = exports.PROVIDER_RECOVERY_ACTIONS = exports.PROVIDER_FAILURE_EVIDENCE_SOURCES = exports.PROVIDER_FAILURE_CODES = exports.PROVIDER_CREDENTIAL_KINDS = exports.PROVIDER_AUTHENTICATION_STATES = exports.PROVIDER_AUTHENTICATION_SOURCES = exports.diagnoseProviderFailure = exports.mergeFailingToolWindows = exports.failingToolTrend = void 0;
18
18
  var usageNormalization_1 = require("./usageNormalization");
19
19
  Object.defineProperty(exports, "normalizeProviderUsage", { enumerable: true, get: function () { return usageNormalization_1.normalizeProviderUsage; } });
20
20
  Object.defineProperty(exports, "extractNormalizedUsage", { enumerable: true, get: function () { return usageNormalization_1.extractNormalizedUsage; } });
@@ -552,8 +552,18 @@ var quota_1 = require("./quota");
552
552
  Object.defineProperty(exports, "FIVE_HOUR_WINDOW_MS", { enumerable: true, get: function () { return quota_1.FIVE_HOUR_WINDOW_MS; } });
553
553
  Object.defineProperty(exports, "QUOTA_PROVIDER_IDS", { enumerable: true, get: function () { return quota_1.QUOTA_PROVIDER_IDS; } });
554
554
  Object.defineProperty(exports, "SEVEN_DAY_WINDOW_MS", { enumerable: true, get: function () { return quota_1.SEVEN_DAY_WINDOW_MS; } });
555
+ Object.defineProperty(exports, "claudePlanLabel", { enumerable: true, get: function () { return quota_1.claudePlanLabel; } });
556
+ Object.defineProperty(exports, "extraQuotaRows", { enumerable: true, get: function () { return quota_1.extraQuotaRows; } });
555
557
  Object.defineProperty(exports, "fetchQuota", { enumerable: true, get: function () { return quota_1.fetchQuota; } });
558
+ Object.defineProperty(exports, "formatExtraUsage", { enumerable: true, get: function () { return quota_1.formatExtraUsage; } });
556
559
  Object.defineProperty(exports, "projectQuotaWindow", { enumerable: true, get: function () { return quota_1.projectQuotaWindow; } });
560
+ Object.defineProperty(exports, "quotaSampleExpired", { enumerable: true, get: function () { return quota_1.quotaSampleExpired; } });
561
+ Object.defineProperty(exports, "quotaStateFromClaudeUsagePayload", { enumerable: true, get: function () { return quota_1.quotaStateFromClaudeUsagePayload; } });
562
+ Object.defineProperty(exports, "quotaWindowApplies", { enumerable: true, get: function () { return quota_1.quotaWindowApplies; } });
563
+ Object.defineProperty(exports, "quotaWindowHasData", { enumerable: true, get: function () { return quota_1.quotaWindowHasData; } });
564
+ Object.defineProperty(exports, "quotaWindowLabel", { enumerable: true, get: function () { return quota_1.quotaWindowLabel; } });
565
+ Object.defineProperty(exports, "quotaWindowShortLabel", { enumerable: true, get: function () { return quota_1.quotaWindowShortLabel; } });
566
+ Object.defineProperty(exports, "withClaudePlan", { enumerable: true, get: function () { return quota_1.withClaudePlan; } });
557
567
  Object.defineProperty(exports, "withQuotaProjections", { enumerable: true, get: function () { return quota_1.withQuotaProjections; } });
558
568
  var quotaPresentation_1 = require("./quotaPresentation");
559
569
  Object.defineProperty(exports, "describeQuotaFailure", { enumerable: true, get: function () { return quotaPresentation_1.describeQuotaFailure; } });
@@ -582,6 +592,7 @@ Object.defineProperty(exports, "readQuotaHistoryRange", { enumerable: true, get:
582
592
  Object.defineProperty(exports, "readQuotaHistoryDailyBuckets", { enumerable: true, get: function () { return quotaHistory_1.readQuotaHistoryDailyBuckets; } });
583
593
  Object.defineProperty(exports, "pruneQuotaHistory", { enumerable: true, get: function () { return quotaHistory_1.pruneQuotaHistory; } });
584
594
  Object.defineProperty(exports, "getWorkspaceIdFromPath", { enumerable: true, get: function () { return quotaHistory_1.getWorkspaceIdFromPath; } });
595
+ Object.defineProperty(exports, "quotaHistoryWindow", { enumerable: true, get: function () { return quotaHistory_1.quotaHistoryWindow; } });
585
596
  var codexQuota_1 = require("./codexQuota");
586
597
  Object.defineProperty(exports, "fetchCodexResetCreditsFromApi", { enumerable: true, get: function () { return codexQuota_1.fetchCodexResetCreditsFromApi; } });
587
598
  Object.defineProperty(exports, "fetchCodexQuotaFromApi", { enumerable: true, get: function () { return codexQuota_1.fetchCodexQuotaFromApi; } });
@@ -680,6 +691,8 @@ Object.defineProperty(exports, "extractSessionEvents", { enumerable: true, get:
680
691
  var quota_3 = require("./schemas/quota");
681
692
  Object.defineProperty(exports, "quotaWindowSchema", { enumerable: true, get: function () { return quota_3.quotaWindowSchema; } });
682
693
  Object.defineProperty(exports, "quotaStateSchema", { enumerable: true, get: function () { return quota_3.quotaStateSchema; } });
694
+ Object.defineProperty(exports, "quotaLimitRowSchema", { enumerable: true, get: function () { return quota_3.quotaLimitRowSchema; } });
695
+ Object.defineProperty(exports, "quotaExtraUsageSchema", { enumerable: true, get: function () { return quota_3.quotaExtraUsageSchema; } });
683
696
  Object.defineProperty(exports, "quotaFailureKindSchema", { enumerable: true, get: function () { return quota_3.quotaFailureKindSchema; } });
684
697
  Object.defineProperty(exports, "quotaProviderIdSchema", { enumerable: true, get: function () { return quota_3.quotaProviderIdSchema; } });
685
698
  Object.defineProperty(exports, "quotaSourceSchema", { enumerable: true, get: function () { return quota_3.quotaSourceSchema; } });