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.
- package/CHANGELOG.md +19 -0
- package/README.md +29 -13
- package/dist/browser.d.ts +2 -0
- package/dist/browser.js +10 -1
- package/dist/codexQuota.js +17 -4
- package/dist/esm/browser.js +2 -0
- package/dist/esm/codexQuota.js +18 -5
- package/dist/esm/index.js +3 -3
- package/dist/esm/multiProviderQuotaService.js +1 -1
- package/dist/esm/quota.js +356 -24
- package/dist/esm/quotaHistory.js +33 -8
- package/dist/esm/quotaPoller.js +5 -2
- package/dist/esm/quotaResolver.js +31 -6
- package/dist/esm/quotaSnapshots.js +65 -10
- package/dist/esm/quotaThresholds.js +7 -2
- package/dist/esm/schemas/index.js +2 -2
- package/dist/esm/schemas/quota.js +30 -0
- package/dist/esm/schemas/quotaHistory.js +10 -2
- package/dist/esm/schemas/stateFile.js +9 -0
- package/dist/esm/stateFile.js +18 -3
- package/dist/esm/statusline/claudeStatuslinePayload.js +16 -4
- package/dist/esm/statusline/formatter.js +57 -18
- package/dist/esm/statusline/index.js +2 -2
- package/dist/esm/zaiQuotaApi.js +4 -2
- package/dist/index.d.ts +6 -6
- package/dist/index.js +18 -5
- package/dist/multiProviderQuotaService.js +1 -1
- package/dist/quota.d.ts +131 -1
- package/dist/quota.js +366 -24
- package/dist/quotaHistory.d.ts +10 -0
- package/dist/quotaHistory.js +34 -8
- package/dist/quotaPoller.d.ts +11 -3
- package/dist/quotaPoller.js +5 -2
- package/dist/quotaResolver.js +30 -5
- package/dist/quotaSnapshots.js +64 -9
- package/dist/quotaThresholds.js +7 -2
- package/dist/schemas/index.d.ts +3 -3
- package/dist/schemas/index.js +5 -2
- package/dist/schemas/quota.d.ts +258 -0
- package/dist/schemas/quota.js +31 -1
- package/dist/schemas/quotaHistory.d.ts +2 -0
- package/dist/schemas/quotaHistory.js +10 -2
- package/dist/schemas/stateFile.d.ts +34 -0
- package/dist/schemas/stateFile.js +10 -1
- package/dist/stateFile.d.ts +18 -0
- package/dist/stateFile.js +17 -2
- package/dist/statusline/claudeStatuslinePayload.d.ts +4 -3
- package/dist/statusline/claudeStatuslinePayload.js +16 -4
- package/dist/statusline/formatter.d.ts +5 -0
- package/dist/statusline/formatter.js +56 -17
- package/dist/statusline/index.d.ts +4 -4
- package/dist/statusline/index.js +5 -1
- package/dist/zaiQuotaApi.js +3 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,25 @@ All notable changes to sidekick-shared will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.28.3] - 2026-10-31
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
|
|
12
|
+
- **`fetchQuota()` marks a missing window instead of reporting 0%.** Claude Ultra (formerly Max 20x) has no 5-hour limit since 2026-10-30, and the usage endpoint returns `five_hour: null`. `fetchQuota()` read that as `{ utilization: 0, resetsAt: '' }`, the same as an idle window. Null or missing windows are now `{ utilization: 0, resetsAt: '', absent: true }`, with no projection; consumers that ignore `absent` see the old values.
|
|
13
|
+
- **`writeQuotaSnapshot()` no longer freezes a provider's snapshot.** It kept the sample with the later first-window reset, so once that window disappeared or reset without restarting, every newer sample (empty reset) lost and readers kept the pre-change numbers. An existing window that had already reset at the newer sample's capture time now yields. A newer capture wins when a window appears or disappears (`absent` changes). Status-line and history writes keep an API sample's `planLabel`, `planType`, `extraUsage`, and still-running extra meters.
|
|
14
|
+
- **`quotaFromStatuslinePayload()` no longer resurrects expired windows.** It copies a missing window from the fallback only when the fallback is `absent` or has not reset yet.
|
|
15
|
+
- **`resolveQuota()` and `resolveZaiQuota()` report an expired cache.** A snapshot whose every window has reset since is returned as unavailable, with an error naming its date and age, instead of as live numbers.
|
|
16
|
+
- `evaluateQuotaThresholds()` never alerts on an absent window. Quota-history daily averages count only samples where the window exists, and history samples keep `absent`.
|
|
17
|
+
- `formatStatusline()` leads with the second window when the first is absent, shows its reset day when more than a day away, never prints the current time for an empty reset, and labels windows from `windowMs`.
|
|
18
|
+
- Codex quota from `quotaFromCodexRateLimits()` names windows by `window_minutes` (`5-Hour`, `Weekly`), falling back to `Primary` / `Secondary`. It sets `windowMs` and marks a null window `absent`.
|
|
19
|
+
|
|
20
|
+
### Added
|
|
21
|
+
|
|
22
|
+
- `quotaStateFromClaudeUsagePayload()` parses the usage endpoint's server-driven `limits[]` meters into `QuotaState.limits`: `QuotaLimitRow` with kind, group, a derived label such as `7-Day (Fable)`, utilization, reset, window length, projection, scope, severity, the headline pick, and `weekly_scoped_shares` allowances. Older servers' `seven_day_opus` / `seven_day_sonnet` / `seven_day_overage_included` fill it instead. It also parses `extra_usage` into `QuotaState.extraUsage`, and a missing headline window is filled from its `session` / `weekly_all` meter.
|
|
23
|
+
- `fetchQuota(token, { plan })` and `withClaudePlan()` stamp `planType` and `planLabel` from credential plan facts. `claudePlanLabel()` maps `default_claude_max_20x` to Ultra and `default_claude_max_5x` to Max. `resolveQuota()` passes the plan automatically, and `QuotaPoller`'s `getAccessToken` may return the credentials record (`QuotaPollerCredentials`) to do the same.
|
|
24
|
+
- Pure helpers on the root and `sidekick-shared/browser`: `quotaWindowApplies()`, `quotaWindowHasData()`, `quotaWindowLabel()`, `quotaWindowShortLabel()`, `extraQuotaRows()`, `formatExtraUsage()`, and `claudePlanLabel()`. Also `quotaSampleExpired()`, plus `quotaHistoryWindow()` on the root and statusline entries.
|
|
25
|
+
- Schemas: `quotaWindowSchema` gains `absent` / `windowMs`, `quotaStateSchema` gains `limits` / `extraUsage` / `planLabel` (`quotaLimitRowSchema`, `quotaExtraUsageSchema`), history samples gain `absent`, and `state.json` gains window `absent` plus quota `planLabel` / `extraLimits` (`stateFileQuotaLimitSchema`; `schemaVersion` stays 1).
|
|
26
|
+
|
|
8
27
|
## [0.28.2] - 2026-10-30
|
|
9
28
|
|
|
10
29
|
### Fixed
|
package/README.md
CHANGED
|
@@ -9,6 +9,7 @@ Types, parsers, providers, readers, formatters, aggregation, search, reporting,
|
|
|
9
9
|
|
|
10
10
|
## Recent additions
|
|
11
11
|
|
|
12
|
+
- **0.28.3: plans without a 5-hour window** — a null `five_hour` from the Claude usage endpoint (Ultra, since 2026-10-30) becomes `fiveHour.absent` instead of 0% used. The endpoint's server-driven `limits[]` meters, `extra_usage`, and the credential plan land on `QuotaState.limits` / `extraUsage` / `planLabel` (`quotaStateFromClaudeUsagePayload()`, `fetchQuota(token, { plan })`). Pure helpers `quotaWindowApplies()` / `quotaWindowHasData()` / `quotaWindowLabel()` / `quotaWindowShortLabel()` / `extraQuotaRows()` / `formatExtraUsage()` / `claudePlanLabel()` are on the root and browser entries, and `quotaHistoryWindow()` is on the root and statusline entries. `writeQuotaSnapshot()` no longer freezes once a window disappears or resets, and `resolveQuota()` reports a fully expired cache as unavailable.
|
|
12
13
|
- **0.28.1: credential guard keeps `promisify(execFile)`** — after `installCredentialGuard()`, `promisify(execFile)` and `promisify(exec)` resolve to `{ stdout, stderr }` again (0.28.0 dropped Node's `util.promisify.custom`, so they returned the bare stdout string), and the promisified calls are guarded too.
|
|
13
14
|
- **0.28.0: ES modules, narrow entries, and new readers** — a `module` export condition gives bundlers a tree-shakable ES-module build (Node keeps CommonJS); browser-safe parsers and helpers move onto `/browser` and the provider-home helpers onto `/node`; `sidekick-shared/testing` publishes the credential guard; `providerFailureDiagnosisSchema` joins `/schemas`; prompt history reports `changed` / `progressed` / `roots` and takes `sessionRefs`; signals carry `toolCategory` and `mcpServer`; `collectUsageEvents()` takes `workspacePaths`; `createJsonlTail()` is bounded and reports resets; and Claude sessions follow `CLAUDE_CONFIG_DIR` while Codex lookups include `archived_sessions/`.
|
|
14
15
|
- **0.27.6: one usable copy per login** — Claude Code and Codex rotate refresh tokens, so a second usable copy of a login invalidates the first ("Not logged in · Please run /login"). The live account now keeps no profile-home credential, only a private backup; `syncLiveAccountState()` demotes a leftover copy (installing it first when it is newer) and reports `demoted`, `repaired`, and `journal`. Live writes pass `decideLiveClaudeWrite()` or the Codex equivalent: a switch captures the outgoing login first even with `force`, holds Claude Code's refresh lock, is journaled so the next sync finishes or rolls it back, and keeps live MCP tokens. Claude Keychain writes use Claude Code's hex method and are read back (`ClaudeCredentialWriteError`), so blobs over about 4 KB are no longer truncated. New root APIs: `readClaudeCredentialStore()`, `inspectClaudeCredentialStores()` / `repairClaudeCredentialStores()`, `inspectCodexCredentialStores()` / `repairCodexCredentialStores()`, `readClaudeCredentialLedger()`, `readStoredCodexAccount()`, `syncCodexLiveStateAsync()`, `discardAccountLogin()`, `writeAccountLauncher()`, and non-persisting health inspection (`persist: false`). `writeActiveCredentials()` now requires a config directory; `writeLauncher()`, `applyActiveClaudeToLiveHome()`, and `resolveActiveClaudeHome()` are deprecated.
|
|
@@ -114,8 +115,8 @@ returns the platform default that both overrides bypass.
|
|
|
114
115
|
| **Session Context** | Provider-neutral context evidence snapshots (`buildSessionContextSnapshot()`, `calculateSessionContextPressure()`, `createSessionContextProjector()`, `readSessionContextSnapshot()`): layered evidence sources, low/medium/high context pressure, and observed capabilities (tools, MCP servers, permission mode, rate limits) |
|
|
115
116
|
| **Assistant Turns** | Browser-safe timeline/process/answer projection for provider-normalized assistant turns (`segmentAssistantTurn()`, `assistantTurnEventsFromSessionEvents()`), including interleaved reasoning, compact tool groups, and Claude `Task` subagent refs without prompt leakage |
|
|
116
117
|
| **Report** | Self-contained HTML session report generation; `readSessionReportInputs()` returns metrics, transcript, and `subagents` for the session total |
|
|
117
|
-
| **Credentials** | Claude Max OAuth credential reading (macOS Keychain with a `~/.claude/.credentials.json` fallback; the file on Linux and Windows). `readClaudeCredentialStore()` returns `ok` / `absent` / `corrupt` / `error`; `writeActiveCredentials()` requires a config directory and reads every write back (`ClaudeCredentialWriteError`). `decideLiveClaudeWrite()`, `claudeRefreshFingerprint()`, `claudeLoginOnly()`, and `mergeClaudeLoginIntoLive()` expose the live-write policy. As of 0.27.6, `inspectClaudeCredentialStores()` / `repairClaudeCredentialStores()` and `inspectCodexCredentialStores()` / `repairCodexCredentialStores()` find and repair unused, duplicate, and unreadable stores Sidekick provably owns (repairs are dry runs unless `dryRun: false`), with Claude ownership recorded by `readClaudeCredentialLedger()`
|
|
118
|
-
| **Quota** | Claude
|
|
118
|
+
| **Credentials** | Claude subscription (Pro / Max / Ultra) OAuth credential reading (macOS Keychain with a `~/.claude/.credentials.json` fallback; the file on Linux and Windows). `readClaudeCredentialStore()` returns `ok` / `absent` / `corrupt` / `error`; `writeActiveCredentials()` requires a config directory and reads every write back (`ClaudeCredentialWriteError`). `decideLiveClaudeWrite()`, `claudeRefreshFingerprint()`, `claudeLoginOnly()`, and `mergeClaudeLoginIntoLive()` expose the live-write policy. As of 0.27.6, `inspectClaudeCredentialStores()` / `repairClaudeCredentialStores()` and `inspectCodexCredentialStores()` / `repairCodexCredentialStores()` find and repair unused, duplicate, and unreadable stores Sidekick provably owns (repairs are dry runs unless `dryRun: false`), with Claude ownership recorded by `readClaudeCredentialLedger()` |
|
|
119
|
+
| **Quota** | Claude subscription quota fetching (5-hour and 7-day windows; `fiveHour.absent` on plans without a 5-hour limit such as Ultra; server meters in `limits`, `extraUsage`, and `planLabel`), Codex rate-limit extraction from event streams (plus Codex reset credits via `fetchCodexResetCreditsFromApi()`, attached to quota state by `fetchCodexQuotaFromApi()`), and authoritative z.ai Coding Plan quota fetching via `resolveZaiQuota()` / `fetchZaiQuotaFromApi()` (reads z.ai's `api/monitor/usage/quota/limit` endpoint with cached-snapshot fallback). The observed-traffic z.ai estimator was removed from the package root exports in 0.23.0 and every remaining export of it is `@deprecated` — `resolveZaiQuota()` is the single supported z.ai quota API |
|
|
119
120
|
| **Provider Status** | `fetchProviderServiceStatus()` returns explicit observed/unavailable public status with components and unresolved incidents from status.claude.com and status.openai.com; `fetchProviderStatus()` / `fetchOpenAIStatus()` remain as lossy legacy projections (`toLegacyProviderStatus()`) |
|
|
120
121
|
| **Doctor** | Typed cross-provider health diagnostics — `runDoctor()` checks project identity, sessions, accounts, providers, and dependencies into a `HealthReport`; `formatHealthReport()` renders it and `getSessionDiagnostics()` retains the legacy Claude Code path probe; `runDoctor({ provider })` diagnoses the selected session provider |
|
|
121
122
|
| **Schemas** | Zod schemas for runtime validation of data crossing process/IPC boundaries — JSONL session events (`sessionEventSchema`, `messageUsageSchema`, `sessionMessageSchema`), assistant turns, observed-session V1 records, quota, account status, account management, quota history, and the public `state.json` contract (`sidekickStateFileSchema`, exported only from `sidekick-shared/schemas`) — plus `extractSessionEvents()` to unwrap `progress`-wrapped events. Account and quota APIs guarantee results valid against the same-release schemas. Also published fs-free via the [`sidekick-shared/schemas`](#supported-import-paths) subpath |
|
|
@@ -138,14 +139,14 @@ returns the platform default that both overrides bypass.
|
|
|
138
139
|
| Path | Runtime | What it exposes |
|
|
139
140
|
| ------------------------------ | -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
140
141
|
| `sidekick-shared` | Node (CLI, extension host) | Full public API (readers, providers, parsers, pricing, …). |
|
|
141
|
-
| `sidekick-shared/browser` | **Browser / webview** | Pure helpers: usage normalization/pricing, token estimation, transcript and assistant-turn projection, model/context math, `parseMcpToolName()`, the `CodexRolloutParser` with the Codex rollout and session-event types, human-prompt detection (`isHumanPrompt()` / `humanPromptText()`), and `
|
|
142
|
+
| `sidekick-shared/browser` | **Browser / webview** | Pure helpers: usage normalization/pricing, token estimation, transcript and assistant-turn projection, model/context math, `parseMcpToolName()`, the `CodexRolloutParser` with the Codex rollout and session-event types, human-prompt detection (`isHumanPrompt()` / `humanPromptText()`), `renderHandoffUrlTemplate()`, and the quota window helpers (`quotaWindowApplies()`, `quotaWindowHasData()`, `quotaWindowLabel()`, `quotaWindowShortLabel()`, `extraQuotaRows()`, `formatExtraUsage()`, `claudePlanLabel()`). |
|
|
142
143
|
| `sidekick-shared/node` | Node only | LiteLLM pricing and context-window hydration, public provider service status (`fetchProviderServiceStatus()`), observed context-window persistence, recent-session/transcript reads, human prompt history (`collectPromptHistory()`, and whole sessions with `collectSessionPromptHistory()`), usage events from session logs (`collectUsageEvents()` with `createSessionProviders()` and `SYNTHETIC_MODEL`), session previews (`listSessionPreviews()` / `readSessionPreview()` plus the bounded-concurrency `listSessionPreviewsAsync()` / `readSessionPreviewAsync()`), Codex history/rollout lookup (`readCodexHistory()`, `findCodexRolloutFile()`), resilient observed-session collection (`fs` + providers), the provider homes the CLIs read (`getLiveClaudeHome()`, `getClaudeProjectsDir()`, `getSystemCodexHome()`, `getCodexMonitoringHomes()`, `getCodexExecutionEnv()`), Claude session-directory encoding (`encodeClaudeWorkspacePath()`, `getClaudeSessionDirectory()`), and the config root (`getConfigDir()`, `CONFIG_DIR_ENV_VAR`). |
|
|
143
144
|
| `sidekick-shared/phrases` | Any runtime | Phrase arrays + `getRandomPhrase()`. |
|
|
144
145
|
| `sidekick-shared/modelContext` | Any runtime | Direct access to the context-window module. |
|
|
145
146
|
| `sidekick-shared/modelInfo` | Any runtime | Direct access to model parsing and cost math. |
|
|
146
147
|
| `sidekick-shared/formatting` | Any runtime | Direct access to pure token and duration display helpers. |
|
|
147
148
|
| `sidekick-shared/schemas` | Any runtime | Pure Zod boundary schemas (session events, assistant turns, observed-session V1, quota, account status, account management, quota history, the `state.json` contract) — fs-free, no Node builtins. |
|
|
148
|
-
| `sidekick-shared/statusline` | Node only | Cache-only statusline surface: account status + quota snapshot readers and writers, `formatStatusline()`, burn-rate estimates, quota freshness helpers, `parseClaudeStatuslinePayload()` / `quotaFromStatuslinePayload()`, and `readStateFile()` / `writeStateFile()`.
|
|
149
|
+
| `sidekick-shared/statusline` | Node only | Cache-only statusline surface: account status + quota snapshot readers and writers, `formatStatusline()`, burn-rate estimates, quota freshness and window helpers (`quotaWindowApplies()`, `quotaWindowHasData()`, `quotaWindowShortLabel()`, `quotaHistoryWindow()`), `parseClaudeStatuslinePayload()` / `quotaFromStatuslinePayload()`, and `readStateFile()` / `writeStateFile()`. |
|
|
149
150
|
| `sidekick-shared/testing` | Node test runners | `installCredentialGuard()` keeps a test process away from the real `security` / `claude` / `codex` binaries and the real Claude, Codex, and Sidekick homes, and the Claude Code / Codex session-log builders (`createSessionLogFixtures()`, `writeJsonl()`, …). Framework-free. |
|
|
150
151
|
|
|
151
152
|
Since 0.28.0 every subpath also has a `module` condition pointing at an ES-module build in `dist/esm/`. Bundlers that read it (esbuild, Vite, Rollup, webpack) tree-shake unused exports, so importing one helper from `sidekick-shared/node` bundles a few hundred bytes instead of the whole entry. Node itself never reads `module` and keeps loading the CommonJS build for both `require` and `import`, so a process never holds two copies of module state.
|
|
@@ -723,7 +724,8 @@ if (!peak.unavailable && peak.isPeak) {
|
|
|
723
724
|
import { resolveQuota } from 'sidekick-shared';
|
|
724
725
|
|
|
725
726
|
// Default: fresh persisted sample (status line, session, or API; under five minutes) →
|
|
726
|
-
// session logs (Codex rollouts) → provider API → older sample labelled by age
|
|
727
|
+
// session logs (Codex rollouts) → provider API → older sample labelled by age
|
|
728
|
+
// (one whose every window has already reset resolves as 'unavailable').
|
|
727
729
|
const quota = await resolveQuota({ providerId: 'claude-code' });
|
|
728
730
|
console.log(quota.resolution); // 'snapshot-fresh' | 'session' | 'api' | 'snapshot-aging' | 'snapshot-stale' | 'unavailable'
|
|
729
731
|
console.log(quota.source, quota.capturedSource, quota.freshness, quota.ageMs);
|
|
@@ -735,21 +737,26 @@ await resolveQuota({ providerId: 'codex', workspacePath: process.cwd(), preferFr
|
|
|
735
737
|
await resolveQuota({ providerId: 'claude-code', allowApi: false });
|
|
736
738
|
```
|
|
737
739
|
|
|
738
|
-
`resolveQuota()` is shared by `sidekick quota`, `quota --all`, the MCP `get_quota_status` tool, and dashboard startup. CLI and MCP Codex queries pass `preferFresh: false` to fetch live utilization and reset credits every time; dashboard schedules and default cache preferences are unchanged. After a failed live query, the newer session or persisted sample wins by `capturedAt`, with ties going to the persisted sample and missing timestamps treated as oldest. Only a selected session sample is persisted. Fallback results keep their source and age plus the API `failure` descriptor. `allowApi: false` always prevents network access, including when `preferFresh` is false. Every side effect is injectable (`readSnapshot`, `writeSnapshot`, `fetchImpl`, `getClaudeAccessToken`, the account resolvers) for tests.
|
|
740
|
+
`resolveQuota()` is shared by `sidekick quota`, `quota --all`, the MCP `get_quota_status` tool, and dashboard startup. CLI and MCP Codex queries pass `preferFresh: false` to fetch live utilization and reset credits every time; dashboard schedules and default cache preferences are unchanged. After a failed live query, the newer session or persisted sample wins by `capturedAt`, with ties going to the persisted sample and missing timestamps treated as oldest. Only a selected session sample is persisted. Fallback results keep their source and age plus the API `failure` descriptor. `allowApi: false` always prevents network access, including when `preferFresh` is false. Claude results carry `planLabel` from the stored credentials (not when `getClaudeAccessToken` is injected), and a snapshot whose every window has reset resolves as `unavailable` with an error naming its date and age. Every side effect is injectable (`readSnapshot`, `writeSnapshot`, `fetchImpl`, `getClaudeAccessToken`, the account resolvers) for tests.
|
|
739
741
|
|
|
740
742
|
### Fetch subscription quota
|
|
741
743
|
|
|
742
744
|
```typescript
|
|
743
|
-
import { fetchQuota, readClaudeMaxCredentials } from 'sidekick-shared';
|
|
745
|
+
import { extraQuotaRows, fetchQuota, readClaudeMaxCredentials } from 'sidekick-shared';
|
|
744
746
|
|
|
745
747
|
// Returns a Promise — without `await`, the object is always truthy and
|
|
746
748
|
// `accessToken` is undefined, which surfaces later as an auth failure.
|
|
747
749
|
// Use `readClaudeMaxAccessTokenSync()` from a synchronous call site.
|
|
748
750
|
const creds = await readClaudeMaxCredentials();
|
|
749
751
|
if (creds) {
|
|
750
|
-
|
|
752
|
+
// Passing the credentials as `plan` stamps planLabel ('Pro' | 'Max' | 'Ultra' | …).
|
|
753
|
+
const quota = await fetchQuota(creds.accessToken, { plan: creds });
|
|
751
754
|
if (quota.available) {
|
|
752
|
-
console.log(`5-hour
|
|
755
|
+
if (quota.fiveHour.absent) console.log(`No 5-hour limit on ${quota.planLabel ?? 'this plan'}`);
|
|
756
|
+
else console.log(`5-hour utilization: ${quota.fiveHour.utilization}%`);
|
|
757
|
+
console.log(`7-day utilization: ${quota.sevenDay.utilization}%`);
|
|
758
|
+
// Extra meters beyond the two headline windows, e.g. "7-Day (Fable)".
|
|
759
|
+
for (const row of extraQuotaRows(quota)) console.log(`${row.label}: ${row.utilization}%`);
|
|
753
760
|
} else {
|
|
754
761
|
console.log(quota.failureKind, quota.httpStatus, quota.retryAfterMs);
|
|
755
762
|
}
|
|
@@ -762,6 +769,8 @@ Unavailable quota responses remain non-throwing and may include:
|
|
|
762
769
|
- `httpStatus`: HTTP response status when available
|
|
763
770
|
- `retryAfterMs`: retry delay in milliseconds for `429` responses when the API provides `Retry-After`
|
|
764
771
|
|
|
772
|
+
`fiveHour` and `sevenDay` are always present; `absent: true` marks a window the plan does not have (Claude Ultra's five-hour limit, a Codex plan's missing second window), with `0` / `''` placeholders so older readers keep working. Use `quotaWindowApplies()` / `quotaWindowHasData()` instead of testing `resetsAt` yourself, and `quotaStateFromClaudeUsagePayload()` to normalize a usage-endpoint body you fetched elsewhere.
|
|
773
|
+
|
|
765
774
|
For first-party style messaging, `describeQuotaFailure()` maps unavailable quota states to stable alert keys plus display-ready severity/title/message/detail fields for CLI and VS Code consumers.
|
|
766
775
|
|
|
767
776
|
### Model info and cost calculation
|
|
@@ -938,12 +947,13 @@ console.log(matches, report.sessionProvider, report.checks);
|
|
|
938
947
|
### Poll quota with backoff
|
|
939
948
|
|
|
940
949
|
```typescript
|
|
941
|
-
import { QuotaPoller } from 'sidekick-shared';
|
|
950
|
+
import { QuotaPoller, readClaudeMaxCredentials } from 'sidekick-shared';
|
|
942
951
|
|
|
943
952
|
const poller = new QuotaPoller({
|
|
944
953
|
activeIntervalMs: 300_000,
|
|
945
954
|
idleIntervalMs: 300_000,
|
|
946
|
-
|
|
955
|
+
// Return the token, or the credentials record to also stamp planLabel.
|
|
956
|
+
getAccessToken: async () => readClaudeMaxCredentials(),
|
|
947
957
|
});
|
|
948
958
|
poller.onUpdate((state) => console.log(state));
|
|
949
959
|
poller.start();
|
|
@@ -952,7 +962,7 @@ poller.start();
|
|
|
952
962
|
### Orchestrate quota across Claude and Codex
|
|
953
963
|
|
|
954
964
|
```typescript
|
|
955
|
-
import { MultiProviderQuotaService } from 'sidekick-shared';
|
|
965
|
+
import { MultiProviderQuotaService, quotaWindowApplies } from 'sidekick-shared';
|
|
956
966
|
|
|
957
967
|
const service = new MultiProviderQuotaService({
|
|
958
968
|
// Optional — when set, an internal CodexQuotaWatcher is created and managed.
|
|
@@ -960,7 +970,13 @@ const service = new MultiProviderQuotaService({
|
|
|
960
970
|
});
|
|
961
971
|
|
|
962
972
|
service.onUpdate(({ claude, codex }) => {
|
|
963
|
-
|
|
973
|
+
// Ultra has no five-hour window (`fiveHour.absent`); show the weekly one instead.
|
|
974
|
+
if (claude) {
|
|
975
|
+
const fiveHour = quotaWindowApplies(claude.fiveHour)
|
|
976
|
+
? `${claude.fiveHour.utilization}%`
|
|
977
|
+
: 'no 5-hour limit';
|
|
978
|
+
console.log('Claude:', fiveHour, `7d ${claude.sevenDay.utilization}%`, claude.peakHours?.label);
|
|
979
|
+
}
|
|
964
980
|
if (codex) console.log('Codex:', codex.fiveHour.utilization, codex.accountLabel);
|
|
965
981
|
});
|
|
966
982
|
|
package/dist/browser.d.ts
CHANGED
|
@@ -54,3 +54,5 @@ export { renderHandoffUrlTemplate } from './handoffUrl';
|
|
|
54
54
|
export type { HandoffUrlIdentifiers } from './handoffUrl';
|
|
55
55
|
export { classifyTool, TOOL_CATEGORIES } from './toolCategory';
|
|
56
56
|
export type { ClassifyToolOptions, ToolCategory } from './toolCategory';
|
|
57
|
+
export { claudePlanLabel, extraQuotaRows, formatExtraUsage, quotaWindowApplies, quotaWindowHasData, quotaWindowLabel, quotaWindowShortLabel, } from './quota';
|
|
58
|
+
export type { QuotaExtraUsage, QuotaLimitRow, QuotaWindow } from './quota';
|
package/dist/browser.js
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
*/
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
exports.compareModelIds = exports.getModelDisplayInfo = exports.shortModelName = exports.mergeCostSources = exports.calculateCostWithProvenance = exports.calculateCostWithPricing = exports.calculateCost = exports.getModelInfo = exports.resolveModelPricing = exports.getModelPricing = exports.parseModelId = exports.segmentAssistantTurn = exports.reasoningSummary = exports.isAssistantTurnSubagentTool = exports.extractTurnSubagents = exports.assistantTurnEventsFromSessionEvents = exports.SESSION_PROVIDER_IDS = exports.RUNTIME_QUOTA_PROVIDER_IDS = exports.QUOTA_PROVIDER_IDS = exports.MODEL_PROVIDER_IDS = exports.ACCOUNT_PROVIDER_IDS = exports.createSessionContextProjector = exports.calculateSessionContextPressure = exports.buildSessionContextSnapshot = exports.parseMcpToolName = exports.parseLocalDateKey = exports.formatTokenCount = exports.formatLocalDateKey = exports.formatDurationMs = exports.addLocalDays = exports.projectSessionTranscript = exports.estimateSerializedTokens = exports.estimateTextTokens = exports.ASCII_CHARS_PER_TOKEN = exports.SYNTHETIC_MODEL = exports.ClaudeUsageDeduper = exports.TOKEN_TOTAL_LABEL = exports.TOKEN_SUBAGENTS_LABEL = exports.TOKEN_SESSION_TOTAL_LABEL = exports.TOKEN_MAIN_THREAD_LABEL = exports.TOKEN_CONTEXT_LABEL = exports.sumTokenTotals = exports.summarizeTokens = exports.formatTokenBreakdown = exports.calculateNormalizedUsageCost = exports.extractNormalizedUsage = exports.normalizeProviderUsage = exports.DEFAULT_CONTEXT_WINDOW = exports.resolveModelContextWindow = exports.getModelContextWindowSize = void 0;
|
|
13
|
-
exports.TOOL_CATEGORIES = exports.classifyTool = exports.renderHandoffUrlTemplate = exports.isHumanPrompt = exports.humanPromptText = exports.HUMAN_CODEX_SOURCES = exports.HUMAN_CLAUDE_ENTRYPOINTS = exports.resolveCodexCallUsage = exports.normalizeCodexToolInput = exports.normalizeCodexToolName = exports.extractPatchFilePaths = exports.DEFAULT_MAX_TRACKED_TOOL_CALLS = exports.CodexRolloutParser = exports.isAggregateCodexLimit = 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.sessionSummaryFromStats = exports.removeSessionSummary = exports.markFileImported = exports.isFileImported = exports.applySessionSummary = exports.weekKey = exports.usageBucketKey = exports.summarizeUsageRows = exports.bucketUsage = exports.findActiveBillingBlock = exports.computeBillingBlocks = exports.BILLING_BLOCK_DURATION_MS = exports.RESOLVED_MODEL_CATALOG_SCHEMA_VERSION = exports.resolveModelAlias = exports.registerModelAlias = exports.importResolvedModelCatalog = exports.exportResolvedModelCatalog = exports.formatCost = exports.sortModelIds = void 0;
|
|
13
|
+
exports.quotaWindowShortLabel = exports.quotaWindowLabel = exports.quotaWindowHasData = exports.quotaWindowApplies = exports.formatExtraUsage = exports.extraQuotaRows = exports.claudePlanLabel = exports.TOOL_CATEGORIES = exports.classifyTool = exports.renderHandoffUrlTemplate = exports.isHumanPrompt = exports.humanPromptText = exports.HUMAN_CODEX_SOURCES = exports.HUMAN_CLAUDE_ENTRYPOINTS = exports.resolveCodexCallUsage = exports.normalizeCodexToolInput = exports.normalizeCodexToolName = exports.extractPatchFilePaths = exports.DEFAULT_MAX_TRACKED_TOOL_CALLS = exports.CodexRolloutParser = exports.isAggregateCodexLimit = 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.sessionSummaryFromStats = exports.removeSessionSummary = exports.markFileImported = exports.isFileImported = exports.applySessionSummary = exports.weekKey = exports.usageBucketKey = exports.summarizeUsageRows = exports.bucketUsage = exports.findActiveBillingBlock = exports.computeBillingBlocks = exports.BILLING_BLOCK_DURATION_MS = exports.RESOLVED_MODEL_CATALOG_SCHEMA_VERSION = exports.resolveModelAlias = exports.registerModelAlias = exports.importResolvedModelCatalog = exports.exportResolvedModelCatalog = exports.formatCost = exports.sortModelIds = void 0;
|
|
14
14
|
var modelContext_1 = require("./modelContext");
|
|
15
15
|
Object.defineProperty(exports, "getModelContextWindowSize", { enumerable: true, get: function () { return modelContext_1.getModelContextWindowSize; } });
|
|
16
16
|
Object.defineProperty(exports, "resolveModelContextWindow", { enumerable: true, get: function () { return modelContext_1.resolveModelContextWindow; } });
|
|
@@ -129,3 +129,12 @@ Object.defineProperty(exports, "renderHandoffUrlTemplate", { enumerable: true, g
|
|
|
129
129
|
var toolCategory_1 = require("./toolCategory");
|
|
130
130
|
Object.defineProperty(exports, "classifyTool", { enumerable: true, get: function () { return toolCategory_1.classifyTool; } });
|
|
131
131
|
Object.defineProperty(exports, "TOOL_CATEGORIES", { enumerable: true, get: function () { return toolCategory_1.TOOL_CATEGORIES; } });
|
|
132
|
+
// Quota window helpers (pure; safe for webviews)
|
|
133
|
+
var quota_1 = require("./quota");
|
|
134
|
+
Object.defineProperty(exports, "claudePlanLabel", { enumerable: true, get: function () { return quota_1.claudePlanLabel; } });
|
|
135
|
+
Object.defineProperty(exports, "extraQuotaRows", { enumerable: true, get: function () { return quota_1.extraQuotaRows; } });
|
|
136
|
+
Object.defineProperty(exports, "formatExtraUsage", { enumerable: true, get: function () { return quota_1.formatExtraUsage; } });
|
|
137
|
+
Object.defineProperty(exports, "quotaWindowApplies", { enumerable: true, get: function () { return quota_1.quotaWindowApplies; } });
|
|
138
|
+
Object.defineProperty(exports, "quotaWindowHasData", { enumerable: true, get: function () { return quota_1.quotaWindowHasData; } });
|
|
139
|
+
Object.defineProperty(exports, "quotaWindowLabel", { enumerable: true, get: function () { return quota_1.quotaWindowLabel; } });
|
|
140
|
+
Object.defineProperty(exports, "quotaWindowShortLabel", { enumerable: true, get: function () { return quota_1.quotaWindowShortLabel; } });
|
package/dist/codexQuota.js
CHANGED
|
@@ -93,6 +93,11 @@ function isPreferredQuotaHit(candidate, current) {
|
|
|
93
93
|
function normalizePercent(value) {
|
|
94
94
|
return typeof value === 'number' && Number.isFinite(value) ? value : 0;
|
|
95
95
|
}
|
|
96
|
+
function reportedWindowMs(value) {
|
|
97
|
+
return typeof value === 'number' && Number.isFinite(value) && value > 0
|
|
98
|
+
? value * 60_000
|
|
99
|
+
: undefined;
|
|
100
|
+
}
|
|
96
101
|
function windowMinutesToMs(value, fallbackMs) {
|
|
97
102
|
return typeof value === 'number' && Number.isFinite(value) && value > 0
|
|
98
103
|
? value * 60_000
|
|
@@ -235,26 +240,34 @@ function quotaFromCodexRateLimits(rateLimits, source = 'session', capturedAt = n
|
|
|
235
240
|
const secondary = rateLimits?.secondary;
|
|
236
241
|
if (!primary && !secondary)
|
|
237
242
|
return null;
|
|
243
|
+
const primaryMs = reportedWindowMs(primary?.window_minutes);
|
|
244
|
+
const secondaryMs = reportedWindowMs(secondary?.window_minutes);
|
|
238
245
|
return (0, quota_1.withQuotaProjections)({
|
|
246
|
+
// A plan can report one window only (e.g. a weekly primary with no
|
|
247
|
+
// secondary); the missing one is marked `absent` rather than shown as 0%.
|
|
239
248
|
fiveHour: primary
|
|
240
249
|
? {
|
|
241
250
|
utilization: normalizePercent(primary.used_percent),
|
|
242
251
|
resetsAt: timestampToIso(primary.resets_at),
|
|
252
|
+
...(primaryMs !== undefined ? { windowMs: primaryMs } : {}),
|
|
243
253
|
}
|
|
244
|
-
: { utilization: 0, resetsAt: '' },
|
|
254
|
+
: { utilization: 0, resetsAt: '', absent: true },
|
|
245
255
|
sevenDay: secondary
|
|
246
256
|
? {
|
|
247
257
|
utilization: normalizePercent(secondary.used_percent),
|
|
248
258
|
resetsAt: timestampToIso(secondary.resets_at),
|
|
259
|
+
...(secondaryMs !== undefined ? { windowMs: secondaryMs } : {}),
|
|
249
260
|
}
|
|
250
|
-
: { utilization: 0, resetsAt: '' },
|
|
261
|
+
: { utilization: 0, resetsAt: '', absent: true },
|
|
251
262
|
available: true,
|
|
252
263
|
providerId: 'codex',
|
|
253
264
|
source,
|
|
254
265
|
capturedAt,
|
|
255
266
|
stale: source === 'cache',
|
|
256
|
-
|
|
257
|
-
|
|
267
|
+
// Name each window by its reported length (`5-Hour`, `Weekly`), falling
|
|
268
|
+
// back to the positional names when the length is not reported.
|
|
269
|
+
fiveHourLabel: (0, quota_1.quotaWindowLabel)(primaryMs, 'Primary'),
|
|
270
|
+
sevenDayLabel: (0, quota_1.quotaWindowLabel)(secondaryMs, 'Secondary'),
|
|
258
271
|
limitId: rateLimits?.limit_id,
|
|
259
272
|
limitName: rateLimits?.limit_name ?? undefined,
|
|
260
273
|
credits: rateLimits?.credits,
|
package/dist/esm/browser.js
CHANGED
|
@@ -32,3 +32,5 @@ export { HUMAN_CLAUDE_ENTRYPOINTS, HUMAN_CODEX_SOURCES, humanPromptText, isHuman
|
|
|
32
32
|
export { renderHandoffUrlTemplate } from './handoffUrl';
|
|
33
33
|
// Tool categories across providers
|
|
34
34
|
export { classifyTool, TOOL_CATEGORIES } from './toolCategory';
|
|
35
|
+
// Quota window helpers (pure; safe for webviews)
|
|
36
|
+
export { claudePlanLabel, extraQuotaRows, formatExtraUsage, quotaWindowApplies, quotaWindowHasData, quotaWindowLabel, quotaWindowShortLabel, } from './quota';
|
package/dist/esm/codexQuota.js
CHANGED
|
@@ -2,7 +2,7 @@ import * as fs from 'fs';
|
|
|
2
2
|
import * as path from 'path';
|
|
3
3
|
import { getActiveCodexAccount, getCodexMonitoringHomes, resolveSidekickCodexHome, } from './codexProfiles';
|
|
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, quotaWindowLabel, withQuotaProjections, } from './quota';
|
|
6
6
|
import { CodexProvider } from './providers/codex';
|
|
7
7
|
import { walkRolloutFiles } from './providers/rolloutWalker';
|
|
8
8
|
import { isAggregateCodexLimit } from './types/codex';
|
|
@@ -51,6 +51,11 @@ function isPreferredQuotaHit(candidate, current) {
|
|
|
51
51
|
function normalizePercent(value) {
|
|
52
52
|
return typeof value === 'number' && Number.isFinite(value) ? value : 0;
|
|
53
53
|
}
|
|
54
|
+
function reportedWindowMs(value) {
|
|
55
|
+
return typeof value === 'number' && Number.isFinite(value) && value > 0
|
|
56
|
+
? value * 60_000
|
|
57
|
+
: undefined;
|
|
58
|
+
}
|
|
54
59
|
function windowMinutesToMs(value, fallbackMs) {
|
|
55
60
|
return typeof value === 'number' && Number.isFinite(value) && value > 0
|
|
56
61
|
? value * 60_000
|
|
@@ -193,26 +198,34 @@ export function quotaFromCodexRateLimits(rateLimits, source = 'session', capture
|
|
|
193
198
|
const secondary = rateLimits?.secondary;
|
|
194
199
|
if (!primary && !secondary)
|
|
195
200
|
return null;
|
|
201
|
+
const primaryMs = reportedWindowMs(primary?.window_minutes);
|
|
202
|
+
const secondaryMs = reportedWindowMs(secondary?.window_minutes);
|
|
196
203
|
return withQuotaProjections({
|
|
204
|
+
// A plan can report one window only (e.g. a weekly primary with no
|
|
205
|
+
// secondary); the missing one is marked `absent` rather than shown as 0%.
|
|
197
206
|
fiveHour: primary
|
|
198
207
|
? {
|
|
199
208
|
utilization: normalizePercent(primary.used_percent),
|
|
200
209
|
resetsAt: timestampToIso(primary.resets_at),
|
|
210
|
+
...(primaryMs !== undefined ? { windowMs: primaryMs } : {}),
|
|
201
211
|
}
|
|
202
|
-
: { utilization: 0, resetsAt: '' },
|
|
212
|
+
: { utilization: 0, resetsAt: '', absent: true },
|
|
203
213
|
sevenDay: secondary
|
|
204
214
|
? {
|
|
205
215
|
utilization: normalizePercent(secondary.used_percent),
|
|
206
216
|
resetsAt: timestampToIso(secondary.resets_at),
|
|
217
|
+
...(secondaryMs !== undefined ? { windowMs: secondaryMs } : {}),
|
|
207
218
|
}
|
|
208
|
-
: { utilization: 0, resetsAt: '' },
|
|
219
|
+
: { utilization: 0, resetsAt: '', absent: true },
|
|
209
220
|
available: true,
|
|
210
221
|
providerId: 'codex',
|
|
211
222
|
source,
|
|
212
223
|
capturedAt,
|
|
213
224
|
stale: source === 'cache',
|
|
214
|
-
|
|
215
|
-
|
|
225
|
+
// Name each window by its reported length (`5-Hour`, `Weekly`), falling
|
|
226
|
+
// back to the positional names when the length is not reported.
|
|
227
|
+
fiveHourLabel: quotaWindowLabel(primaryMs, 'Primary'),
|
|
228
|
+
sevenDayLabel: quotaWindowLabel(secondaryMs, 'Secondary'),
|
|
216
229
|
limitId: rateLimits?.limit_id,
|
|
217
230
|
limitName: rateLimits?.limit_name ?? undefined,
|
|
218
231
|
credits: rateLimits?.credits,
|
package/dist/esm/index.js
CHANGED
|
@@ -146,7 +146,7 @@ export { getCodexProfilesDir, getCodexProfileHome, getCodexMonitoringHomes, getS
|
|
|
146
146
|
export { writeAccountLauncher, writeLauncher, removeLauncher } from './terminalSync';
|
|
147
147
|
export { DEFAULT_AUTO_SWITCH_CONFIG, decideAutoSwitch, AutoSwitchController } from './autoSwitch';
|
|
148
148
|
// Quota
|
|
149
|
-
export { FIVE_HOUR_WINDOW_MS, QUOTA_PROVIDER_IDS, SEVEN_DAY_WINDOW_MS, fetchQuota, projectQuotaWindow, withQuotaProjections, } from './quota';
|
|
149
|
+
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';
|
|
150
150
|
export { describeQuotaFailure } from './quotaPresentation';
|
|
151
151
|
export { QuotaPoller } from './quotaPoller';
|
|
152
152
|
export { readQuotaSnapshot, writeQuotaSnapshot } from './quotaSnapshots';
|
|
@@ -154,7 +154,7 @@ export { resolveQuota } from './quotaResolver';
|
|
|
154
154
|
export { classifyQuotaFreshness, formatQuotaAge, QUOTA_AGING_MAX_AGE_MS, QUOTA_FRESH_MAX_AGE_MS, } from './quota';
|
|
155
155
|
export { DEFAULT_QUOTA_THRESHOLDS, describeQuotaThresholdAlert, evaluateQuotaThresholds, } from './quotaThresholds';
|
|
156
156
|
export { parseClaudeStatuslinePayload, quotaFromStatuslinePayload, } from './statusline/claudeStatuslinePayload';
|
|
157
|
-
export { appendQuotaHistorySample, readQuotaHistoryRange, readQuotaHistoryDailyBuckets, pruneQuotaHistory, getWorkspaceIdFromPath, } from './quotaHistory';
|
|
157
|
+
export { appendQuotaHistorySample, readQuotaHistoryRange, readQuotaHistoryDailyBuckets, pruneQuotaHistory, getWorkspaceIdFromPath, quotaHistoryWindow, } from './quotaHistory';
|
|
158
158
|
export { fetchCodexResetCreditsFromApi, fetchCodexQuotaFromApi, quotaFromCodexRateLimits, readLatestCodexQuotaFromRollouts, resolveCodexQuota, resolveCodexQuotaFromLocalSources, } from './codexQuota';
|
|
159
159
|
export { CodexQuotaWatcher } from './codexQuotaWatcher';
|
|
160
160
|
export { fetchZaiQuotaFromApi, quotaStateFromZaiQuotaLimitPayload, readZaiCredentials, resolveZaiQuota, } from './zaiQuotaApi';
|
|
@@ -185,7 +185,7 @@ export { extractToolCall, extractToolCalls, ToolCallTracker } from './extractors
|
|
|
185
185
|
// Schemas — Zod runtime validation for session events
|
|
186
186
|
export { messageUsageSchema, sessionMessageSchema, sessionEventSchema, permissionModeSchema, extractSessionEvents, } from './schemas/sessionEvent';
|
|
187
187
|
// Schemas — Zod runtime validation for quota / provider quota / peak hours
|
|
188
|
-
export { quotaWindowSchema, quotaStateSchema, quotaFailureKindSchema, quotaProviderIdSchema, quotaSourceSchema, codexResetCreditSchema, codexResetCreditsSnapshotSchema, peakHoursStateSchema, quotaFailureDescriptorSchema, runtimeQuotaProviderSchema, providerQuotaStateSchema, claudeProviderQuotaStateSchema, codexProviderQuotaStateSchema, zaiProviderQuotaStateSchema, providerQuotaMapSchema, } from './schemas/quota';
|
|
188
|
+
export { quotaWindowSchema, quotaStateSchema, quotaLimitRowSchema, quotaExtraUsageSchema, quotaFailureKindSchema, quotaProviderIdSchema, quotaSourceSchema, codexResetCreditSchema, codexResetCreditsSnapshotSchema, peakHoursStateSchema, quotaFailureDescriptorSchema, runtimeQuotaProviderSchema, providerQuotaStateSchema, claudeProviderQuotaStateSchema, codexProviderQuotaStateSchema, zaiProviderQuotaStateSchema, providerQuotaMapSchema, } from './schemas/quota';
|
|
189
189
|
// Schemas — Zod runtime validation for quota history
|
|
190
190
|
export { quotaHistoryRuntimeProviderSchema, quotaHistorySampleSchema, quotaHistoryDailyBucketSchema, } from './schemas/quotaHistory';
|
|
191
191
|
// Schemas — Zod runtime validation for provider-failure diagnoses
|
|
@@ -290,7 +290,7 @@ export class MultiProviderQuotaService {
|
|
|
290
290
|
await this.refreshPeakHours();
|
|
291
291
|
const creds = await this.readClaudeCredentials();
|
|
292
292
|
if (!creds) {
|
|
293
|
-
this.handleUnavailableState(makeUnavailableClaudeState('Renew your Claude
|
|
293
|
+
this.handleUnavailableState(makeUnavailableClaudeState('Renew your Claude login to view quota', 'auth'));
|
|
294
294
|
return;
|
|
295
295
|
}
|
|
296
296
|
const state = await this.fetchClaudeQuota(creds.accessToken);
|