diff --git a/README.md b/README.md index 2376a27..6bc4e89 100644 --- a/README.md +++ b/README.md @@ -706,17 +706,17 @@ narrower question: “At published API text-token prices, roughly what would this observed mix of model work cost when mapped onto the movement in my quota meter?” -#### Fast mode and service-tier uncertainty +#### Service tiers and pricing uncertainty Codexometer prices each newly observed response separately. Standard token cost -and the requested-tier premium are maintained independently; quota learning uses +and the signed requested-tier adjustment are maintained independently; quota learning uses their sum. For example, $1 at standard prices plus a $1 Fast premium over **5 percentage points** of quota movement implies roughly **$40 per 100%**, compared with **$20 at standard prices**. It never multiplies the observed quota percentage or applies today's `/fast` setting retroactively. - `TIER*` means the estimate includes a **requested**, not billing-confirmed, - Fast premium. The current Codex sources expose persisted + tier adjustment (a premium for Fast/Ultrafast or a discount for Flex). The current Codex sources expose persisted `thread_settings_applied` settings, but neither local token events nor the shared app-server's response-usage notifications expose the actual billed tier. Settings are kept per session and captured for each turn; an in-flight turn @@ -736,13 +736,17 @@ or applies today's `/fast` setting retroactively. comparison** for the same sample windows. Narrower layouts omit that comparison. - A known default setting has no premium. An explicitly unsupported tier/model combination is unpriced and interrupts clean learning rather than silently - applying an invented multiplier. Standard benchmark rankings are unchanged. + applying an invented multiplier. Benchmark comparisons continue to use Standard rates. -Fast pricing was updated on **30 September 2026**: **GPT-6.1 Sol, GPT-6 (Astra, Sol, Luna) and GPT-5.6 +Tier pricing was reviewed on **12 October 2026**: **GPT-6.1 Sol, GPT-6 (Astra, Sol, Luna) and GPT-5.6 (Sol, Terra, Luna)** use **2× applicable standard API prices** for `fast` / the -legacy `priority` alias. The premium is applied after the existing per-response -long-context and cache-read/cache-write calculations; reasoning output is not -counted twice. Other models' Fast prices are not yet maintained. See the official +legacy `priority` alias. Astra and GPT-6.1 Sol **Ultrafast** use **6×** applicable standard API prices. +**Flex** uses **½×** on the maintained GPT-6/GPT-5.6 models, GPT-5.2 and GPT-5.5. +GPT-5.2 fallback pricing and published short-context Fast rates for GPT-5.2, +GPT-5.3 Codex, GPT-5.4/Mini and GPT-5.5 are also maintained; GPT-5.5 Fast is 2.5×. +Other explicit model/tier combinations and unpublished long-context Fast rates +remain unavailable. Adjustments follow per-response long-context and cache +calculations; reasoning output is not counted twice. See the official [Astra pricing](https://developers.openai.com/api/docs/models/gpt-6-astra), [Codex speed guidance](https://learn.chatgpt.com/docs/agent-configuration/speed), and [API Fast-mode guide](https://developers.openai.com/api/docs/guides/fast-mode). @@ -758,9 +762,21 @@ new evidence accumulates. Future improvement: consume the actual response `service_tier` if Codex exposes it with matching per-response token usage, then prefer that evidence to requested settings. -Codexometer normally prices each newly completed local model call using the -requested model durably recorded in its turn context. Current Codex rollout -files do not persist transient model-reroute events, so a reroute cannot be +Codexometer prefers Codex's durable **`token_usage_record`** entries for each +newly completed response. Exact records are counted independently of cumulative +context counters, with bounded response-ID deduplication; inherited parent +records are excluded from a child's own usage. Startup establishes a historical +baseline without charging past responses, using a bounded 4 MiB tail scan. +An exact record switches that rollout to response accounting: subsequent +`token_count` snapshots remain context/attribution baselines and never create +another billable response. Older rollouts retain the legacy token-count reader. A replacement rollout for +an existing thread establishes a new baseline rather than charging copied +history again; session settings come from its newest observed rollout. + +The requested model remains the fallback when actual per-response model evidence +is unavailable; durable usage records do not supply model or billed-tier fields. +Diagnostics explicitly distinguish requested-model attribution from a matching +live reroute. Current Codex rollout files do not persist transient model-reroute events, so a reroute cannot be reconstructed from that source alone. When Codexometer and the CLI share the managed daemon described above, Codexometer keeps a live subscription and matches reroute and token-usage events to rollout calls by thread ID, turn ID, @@ -779,7 +795,7 @@ cache-write input, and output are priced separately; requests above the published 272,000-input-token threshold use the corresponding long-context rates where OpenAI publishes them. Unknown models or missing price classes fail closed as `UNPRICED USAGE` rather than being guessed or treated as free. -Codex's context-window bookkeeping updates are recognised only when the window +In the legacy reader, Codex's context-window bookkeeping updates are recognised only when the window and both complete, explicit zero-token-class breakdowns match its synthetic fill record. They rebase the local counter without adding response costs, token totals or model-call graph pulses. Quota learning restarts as `LOCAL ACCOUNTING REBASED`. @@ -788,20 +804,32 @@ the current baseline, including inherited child history and historical scans. Missing input/output usage and inconsistent response/cumulative usage instead restart as `MISSING RESPONSE USAGE` or `INCONSISTENT RESPONSE USAGE`; no costs are guessed. Unknown model/tier or unavailable pricing remains `UNPRICED USAGE`. +The terminal Quota view retains a bounded issue panel with the reason, originating +session (including a child agent), model and its attribution basis, requested tier, +effort, response/legacy/benchmark source, response ID and timestamp. The panel +fits available terminal space; the browser Quota view shows the latest observed +issue with wrapping. Diagnostics retain accounting metadata, not prompt/reply +content, and are not persisted. A prior issue cannot be assigned to a later +learning restart. Reserve (`gpt-reserve`), custom/preview and provider-specific +model IDs stay unpriced where a price mapping is unverified; display aliases are +not billing evidence. Core, Extended, and DigBench trials use ephemeral threads that intentionally do not appear in normal persisted session telemetry. While a subscription-funded benchmark suite is active, Quota views replace the numeric API-equivalent estimate with `SUBSCRIPTION BENCHMARK ACTIVE` instead of presenting partial accounting. When each trial finishes, its authoritative benchmark usage is -folded into the same process-local accounting used for quota learning; missing -or unpriceable benchmark usage fails closed and restarts the learning anchor. +folded into the same process-local accounting used for quota learning; missing, +inconsistent or unpriceable benchmark usage fails closed with separate reasons +and restarts the learning anchor. Complete raw response usage takes precedence +over cumulative/context snapshots, each response retains its observed/requested +model, and identical notification replays do not duplicate costs. Benchmarks funded by `CODEXOMETER_BENCHMARK_API_KEY` are excluded because they do not consume the displayed subscription quota. Benchmark threads remain hidden from Sessions; hiding presentation does not exclude their aggregate subscription impact from Quota views. The embedded rates come from the [official OpenAI API pricing page](https://developers.openai.com/api/docs/pricing) -and were last updated on **2026-09-30**. +and were last reviewed on **2026-10-12**. Every Quota presentation repeats that retrieval date and a terminal hyperlink to the source in its footer when the terminal is wide enough, matching the Benchmark view and making stale compiled pricing conspicuous wherever a priced diff --git a/internal/codex/benchmark.go b/internal/codex/benchmark.go index 3470a52..f658769 100644 --- a/internal/codex/benchmark.go +++ b/internal/codex/benchmark.go @@ -33,7 +33,7 @@ const ( // the published rates compiled into this release. Keep both in sync whenever // standardAPIPrices changes. StandardAPIPricingSourceURL = "https://developers.openai.com/api/docs/pricing" - StandardAPIPricingRetrievedOn = "2026-09-30" + StandardAPIPricingRetrievedOn = "2026-10-12" ) // BenchmarkUsage is the app-server token breakdown for one isolated turn. @@ -111,9 +111,14 @@ func (c Client) BenchmarkBillingSource() BenchmarkBillingSource { // BenchmarkResponseUsage is the exact upstream usage for one Responses API // completion when the current Codex app-server exposes experimental raw events. +// Missing or conflicting usage retains response identity for diagnostics; +// UsageMissing distinguishes an omitted payload from valid all-zero usage. type BenchmarkResponseUsage struct { - ResponseID string - Usage BenchmarkUsage + ResponseID string + Model string + Usage BenchmarkUsage + UsageMissing bool + UsageIssue string } type BenchmarkInteractionKind string @@ -930,7 +935,7 @@ func (s *appServerSession) runBenchmark( Usage *BenchmarkUsage `json:"usage"` } if json.Unmarshal(params, &event) == nil && event.ThreadID == startedThread.Thread.ID && event.TurnID == startedTurn.Turn.ID { - telemetry.recordRawResponse(event.ResponseID, event.Usage) + telemetry.recordRawResponseForModel(event.ResponseID, event.Usage, result.ActualModel) } case "model/rerouted": var event struct { @@ -1163,6 +1168,8 @@ func (s *appServerSession) interruptBenchmarkTurn( } func applyBenchmarkMeasurements(result *BenchmarkResult, telemetry *benchmarkTelemetry) { + result.CostUSD, result.CostKnown, result.CostIssue = 0, false, "" + result.UsageKnown, result.UsageIssue = false, "" telemetry.apply(result) if result.ToolUsed { result.CostIssue = "tool use prohibited: " + result.ToolType @@ -1170,7 +1177,11 @@ func applyBenchmarkMeasurements(result *BenchmarkResult, telemetry *benchmarkTel if result.UsageSource == BenchmarkUsageRawResponses { result.CostKnown = true for _, response := range result.ResponseUsage { - cost, known, issue := estimateSingleResponseAPICostWithIssue(result.ActualModel, response.Usage) + model := response.Model + if model == "" { + model = result.ActualModel + } + cost, known, issue := estimateSingleResponseAPICostWithIssue(model, response.Usage) if !known { result.CostUSD, result.CostKnown, result.CostIssue = 0, false, issue break @@ -1191,23 +1202,24 @@ type benchmarkTelemetry struct { lastCumulative BenchmarkUsage hasLastCumulative bool rawResponses []BenchmarkResponseUsage - rawIDs map[string]struct{} + rawIDs map[string]int rawObserved bool rawMissingUsage bool issue string + cumulativeIssue string } func newBenchmarkTelemetry() *benchmarkTelemetry { - return &benchmarkTelemetry{rawIDs: make(map[string]struct{})} + return &benchmarkTelemetry{rawIDs: make(map[string]int)} } func (t *benchmarkTelemetry) recordCumulative(usage BenchmarkUsage) { t.cumulativeObserved = true if issue := validateBenchmarkUsage(usage); issue != "" { - t.setIssue("invalid cumulative usage: " + issue) + t.cumulativeIssue = "invalid cumulative usage: " + issue } if t.hasLastCumulative && !benchmarkUsageAtLeast(usage, t.lastCumulative) { - t.setIssue("cumulative usage regressed") + t.cumulativeIssue = "cumulative usage regressed" } t.cumulative = usage t.lastCumulative = usage @@ -1215,30 +1227,54 @@ func (t *benchmarkTelemetry) recordCumulative(usage BenchmarkUsage) { } func (t *benchmarkTelemetry) recordRawResponse(responseID string, usage *BenchmarkUsage) { + t.recordRawResponseForModel(responseID, usage, "") +} + +func (t *benchmarkTelemetry) recordRawResponseForModel(id string, usage *BenchmarkUsage, model string) { t.rawObserved = true - if strings.TrimSpace(responseID) == "" { - t.setIssue("raw response usage omitted response id") - return + response := BenchmarkResponseUsage{ResponseID: id, Model: model, UsageMissing: usage == nil} + if usage == nil { + response.UsageIssue = "raw response omitted usage" + } else { + response.Usage = *usage + if issue := validateBenchmarkUsage(*usage); issue != "" { + response.UsageIssue = "invalid raw response usage: " + issue + } } - if _, duplicate := t.rawIDs[responseID]; duplicate { - t.setIssue("duplicate raw response usage: " + responseID) + if strings.TrimSpace(id) == "" { + response.UsageIssue = "raw response usage omitted response id" + t.setIssue(response.UsageIssue) + t.rawResponses = append(t.rawResponses, response) return } - t.rawIDs[responseID] = struct{}{} - if usage == nil { - t.rawMissingUsage = true + if index, duplicate := t.rawIDs[id]; duplicate { + previous := &t.rawResponses[index] + if previous.Model == model && previous.UsageMissing == response.UsageMissing && previous.Usage == response.Usage { + return + } + previous.UsageIssue = "conflicting duplicate raw response usage: " + id + if previous.Model != model { + previous.UsageIssue = fmt.Sprintf("conflicting duplicate raw response model: %q versus %q", previous.Model, model) + } + t.setIssue(previous.UsageIssue) return } - if issue := validateBenchmarkUsage(*usage); issue != "" { - t.setIssue("invalid raw response usage: " + issue) + t.rawIDs[id] = len(t.rawResponses) + t.rawResponses = append(t.rawResponses, response) + if response.UsageMissing { + t.rawMissingUsage = true + } else if response.UsageIssue != "" { + t.setIssue(response.UsageIssue) } - t.rawResponses = append(t.rawResponses, BenchmarkResponseUsage{ResponseID: responseID, Usage: *usage}) } func (t *benchmarkTelemetry) apply(result *BenchmarkResult) { result.UsageObserved = t.cumulativeObserved || t.rawObserved result.UsageSource = BenchmarkUsageUnavailable result.ResponseUsage = append([]BenchmarkResponseUsage(nil), t.rawResponses...) + if t.rawObserved { + result.UsageSource = BenchmarkUsageRawResponses + } if t.issue != "" { result.UsageIssue = t.issue return @@ -1257,13 +1293,18 @@ func (t *benchmarkTelemetry) apply(result *BenchmarkResult) { result.UsageIssue = "invalid raw response total: " + issue return } - if t.cumulativeObserved && rawTotal != t.cumulative { - result.UsageIssue = "raw and cumulative usage disagree" - return - } + result.Usage, result.UsageKnown, result.UsageSource = rawTotal, true, BenchmarkUsageRawResponses return } + if t.rawObserved && t.rawMissingUsage { + result.UsageIssue = "raw response omitted usage" + return + } + if t.cumulativeIssue != "" { + result.UsageIssue = t.cumulativeIssue + return + } if t.cumulativeObserved { result.Usage, result.UsageKnown, result.UsageSource = t.cumulative, true, BenchmarkUsageCumulative return @@ -1609,6 +1650,7 @@ type apiPrice struct { } var standardAPIPrices = map[string]apiPrice{ + "gpt-5.2": {input: 1.75, cached: 0.175, output: 14.00}, "gpt-6.1-sol": {input: 2.00, cached: 0.10, cacheWrite: 2.50, cacheWriteKnown: true, output: 10.00, longInput: 4.00, longCached: 0.20, longCacheWrite: 5.00, longOutput: 15.00, longKnown: true}, "gpt-6-sol": {input: 2.00, cached: 0.20, cacheWrite: 2.50, cacheWriteKnown: true, output: 10.00, longInput: 4.00, longCached: 0.40, longCacheWrite: 5.00, longOutput: 15.00, longKnown: true}, "gpt-6-luna": {input: 0.10, cached: 0.01, cacheWrite: 0.125, cacheWriteKnown: true, output: 0.50, longInput: 0.20, longCached: 0.02, longCacheWrite: 0.25, longOutput: 0.75, longKnown: true}, @@ -1640,7 +1682,7 @@ func estimateSingleResponseAPICostWithIssue(model string, usage BenchmarkUsage) } price, ok := priceForModel(model) if !ok { - return 0, false, "no published price for model " + strings.TrimSpace(model) + return 0, false, "no maintained standard API price for model " + strings.TrimSpace(model) } if usage.CacheWriteInputTokens > 0 && !price.cacheWriteKnown { return 0, false, "no published cache-write price for model " + strings.TrimSpace(model) diff --git a/internal/codex/benchmark_test.go b/internal/codex/benchmark_test.go index 249caeb..3d480b0 100644 --- a/internal/codex/benchmark_test.go +++ b/internal/codex/benchmark_test.go @@ -628,12 +628,8 @@ func TestBenchmarkTelemetryRejectsInconsistentStreams(t *testing.T) { state.recordCumulative(valid) state.recordCumulative(BenchmarkUsage{TotalTokens: 55, InputTokens: 50, OutputTokens: 5}) }, want: "regressed"}, - {name: "raw mismatch", record: func(state *benchmarkTelemetry) { - state.recordRawResponse("response-1", &valid) - state.recordCumulative(BenchmarkUsage{TotalTokens: 120, InputTokens: 100, OutputTokens: 20}) - }, want: "disagree"}, {name: "duplicate response", record: func(state *benchmarkTelemetry) { - state.recordRawResponse("response-1", nil) + state.recordRawResponse("response-1", &valid) state.recordRawResponse("response-1", nil) }, want: "duplicate"}, {name: "raw aggregate overflow", record: func(state *benchmarkTelemetry) { @@ -654,15 +650,15 @@ func TestBenchmarkTelemetryRejectsInconsistentStreams(t *testing.T) { } } -func TestBenchmarkTelemetryFallsBackWhenRawUsageIsOmitted(t *testing.T) { +func TestBenchmarkTelemetryRejectsIncompleteRawUsageEvenWithCumulativeSnapshot(t *testing.T) { valid := BenchmarkUsage{TotalTokens: 110, InputTokens: 100, OutputTokens: 10} state := newBenchmarkTelemetry() state.recordRawResponse("response-1", nil) state.recordCumulative(valid) var result BenchmarkResult state.apply(&result) - if !result.UsageObserved || !result.UsageKnown || result.UsageSource != BenchmarkUsageCumulative || result.Usage != valid || result.UsageIssue != "" { - t.Fatalf("valid cumulative fallback was not used: %#v", result) + if !result.UsageObserved || result.UsageKnown || result.UsageIssue != "raw response omitted usage" { + t.Fatalf("missing exact response usage was hidden by a context snapshot: %#v", result) } } @@ -1212,6 +1208,7 @@ func TestEstimateAPICostUsesCachedAndOutputRates(t *testing.T) { func TestStandardAPIPricesMatchPublishedRates(t *testing.T) { want := map[string]apiPrice{ + "gpt-5.2": {input: 1.75, cached: 0.175, output: 14.00}, "gpt-6.1-sol": {input: 2.00, cached: 0.10, cacheWrite: 2.50, cacheWriteKnown: true, output: 10.00, longInput: 4.00, longCached: 0.20, longCacheWrite: 5.00, longOutput: 15.00, longKnown: true}, "gpt-6-sol": {input: 2.00, cached: 0.20, cacheWrite: 2.50, cacheWriteKnown: true, output: 10.00, longInput: 4.00, longCached: 0.40, longCacheWrite: 5.00, longOutput: 15.00, longKnown: true}, "gpt-6-luna": {input: 0.10, cached: 0.01, cacheWrite: 0.125, cacheWriteKnown: true, output: 0.50, longInput: 0.20, longCached: 0.02, longCacheWrite: 0.25, longOutput: 0.75, longKnown: true}, @@ -1373,3 +1370,67 @@ func TestFormatIntervalsAndReferenceMerge(t *testing.T) { t.Fatal("reference merge mutated input") } } + +func TestBenchmarkExactResponsesOverrideSyntheticSnapshotsAndRetainModels(t *testing.T) { + telemetry := newBenchmarkTelemetry() + first := BenchmarkUsage{InputTokens: 100, OutputTokens: 10, TotalTokens: 110} + second := BenchmarkUsage{InputTokens: 200, OutputTokens: 20, TotalTokens: 220} + telemetry.recordRawResponseForModel("one", &first, "gpt-6-astra") + telemetry.recordCumulative(BenchmarkUsage{TotalTokens: 128000}) // Context bookkeeping, not billable usage. + telemetry.recordRawResponseForModel("two", &second, "gpt-5.2") + telemetry.recordRawResponseForModel("two", &second, "gpt-5.2") // Identical transport replay. + result := BenchmarkResult{ActualModel: "gpt-5.2"} + applyBenchmarkMeasurements(&result, telemetry) + a, _, _ := EstimateStandardAPIEqCost("gpt-6-astra", first) + b, _, _ := EstimateStandardAPIEqCost("gpt-5.2", second) + if !result.CostKnown || !result.UsageKnown || result.Usage.TotalTokens != 330 || len(result.ResponseUsage) != 2 || math.Abs(result.CostUSD-a-b) > 1e-12 { + t.Fatal("exact usage depended on synthetic snapshots/final model", result) + } + applyBenchmarkMeasurements(&result, telemetry) + if math.Abs(result.CostUSD-a-b) > 1e-12 { + t.Fatal("repeated measurement added cost twice", result) + } + telemetry.recordRawResponse("two", &first) + applyBenchmarkMeasurements(&result, telemetry) + if result.UsageKnown || result.CostKnown || !strings.Contains(result.UsageIssue, "conflicting duplicate") { + t.Fatal("conflicting response ID was accepted", result) + } +} + +func TestBenchmarkRawMissingUsageRetainsAttribution(t *testing.T) { + telemetry := newBenchmarkTelemetry() + usage := BenchmarkUsage{InputTokens: 100, OutputTokens: 10, TotalTokens: 110} + telemetry.recordRawResponseForModel("missing", nil, "gpt-reserve") + telemetry.recordRawResponseForModel("missing", nil, "gpt-reserve") + telemetry.recordRawResponseForModel("later", &usage, "gpt-6-astra") + result := BenchmarkResult{ActualModel: "gpt-6-astra"} + applyBenchmarkMeasurements(&result, telemetry) + if result.UsageKnown || result.CostKnown || len(result.ResponseUsage) != 2 || result.UsageSource != BenchmarkUsageRawResponses { + t.Fatal("missing raw usage was priced or lost", result) + } + response := result.ResponseUsage[0] + if response.ResponseID != "missing" || response.Model != "gpt-reserve" || !response.UsageMissing || response.UsageIssue != "raw response omitted usage" { + t.Fatal("missing usage attribution lost", response) + } +} + +func TestBenchmarkRawReplayRejectsModelConflicts(t *testing.T) { + for _, missing := range []bool{false, true} { + telemetry := newBenchmarkTelemetry() + usage := &BenchmarkUsage{InputTokens: 100, OutputTokens: 10, TotalTokens: 110} + if missing { + usage = nil + } + telemetry.recordRawResponseForModel("same-response", usage, "gpt-6-astra") + telemetry.recordRawResponseForModel("same-response", usage, "gpt-6-astra") + if len(telemetry.rawResponses) != 1 || telemetry.issue != "" { + t.Fatal("identical replay was not idempotent", telemetry) + } + telemetry.recordRawResponseForModel("same-response", usage, "gpt-5.2") + result := BenchmarkResult{ActualModel: "gpt-5.2"} + applyBenchmarkMeasurements(&result, telemetry) + if result.UsageKnown || result.CostKnown || (!strings.Contains(result.UsageIssue, "gpt-6-astra") || !strings.Contains(result.UsageIssue, "gpt-5.2") || !strings.Contains(result.UsageIssue, "conflicting duplicate")) || len(result.ResponseUsage) != 1 || result.ResponseUsage[0].UsageIssue != result.UsageIssue { + t.Fatal("conflicting model replay was silently retained", missing, result) + } + } +} diff --git a/internal/codex/digbench.go b/internal/codex/digbench.go index 38f72c8..d9d917f 100644 --- a/internal/codex/digbench.go +++ b/internal/codex/digbench.go @@ -484,7 +484,7 @@ func (s *appServerSession) runDigBench( Usage *BenchmarkUsage `json:"usage"` } if json.Unmarshal(envelope.Params, &event) == nil && event.ThreadID == startedThread.Thread.ID && event.TurnID == startedTurn.Turn.ID { - telemetry.recordRawResponse(event.ResponseID, event.Usage) + telemetry.recordRawResponseForModel(event.ResponseID, event.Usage, result.ActualModel) } case "model/rerouted": var event struct { @@ -1008,6 +1008,7 @@ func digBenchFinalResponse(params json.RawMessage, threadID, turnID string, sens } func applyDigBenchMeasurements(result *DigBenchResult, telemetry *benchmarkTelemetry) { + result.CostUSD, result.CostKnown, result.CostIssue = 0, false, "" var measurements BenchmarkResult telemetry.apply(&measurements) result.Usage = measurements.Usage @@ -1026,7 +1027,11 @@ func applyDigBenchMeasurements(result *DigBenchResult, telemetry *benchmarkTelem } result.CostKnown = true for _, response := range result.ResponseUsage { - cost, known, issue := estimateSingleResponseAPICostWithIssue(result.ActualModel, response.Usage) + model := response.Model + if model == "" { + model = result.ActualModel + } + cost, known, issue := estimateSingleResponseAPICostWithIssue(model, response.Usage) if !known { result.CostUSD, result.CostKnown, result.CostIssue = 0, false, issue return diff --git a/internal/codex/live_usage.go b/internal/codex/live_usage.go index b4ea1ad..619cb0f 100644 --- a/internal/codex/live_usage.go +++ b/internal/codex/live_usage.go @@ -25,10 +25,11 @@ const ( ) // LiveUsageSnapshot is a process-local accounting view built from token-count -// events appended to locally persisted Codex rollouts. Finalized API-equivalent +// events or exact response records appended to local Codex rollouts. Finalized API-equivalent // totals increase monotonically; APIEqPendingCalls is an instantaneous count // kept separate until daemon model resolution or requested-model fallback. -// APIEqUSD remains standard cost. Quota learning adds APIEqTierPremiumUSD; +// APIEqUSD remains standard cost. Quota learning adds the signed requested-tier +// adjustment in APIEqTierPremiumUSD (negative for Flex); // APIEqUnknownTierCalls identifies standard fallbacks with missing tier evidence. // Missing/inconsistent response usage has separate monotonic counters from // unavailable pricing. AccountingAdjustments counts recognised synthetic context @@ -50,6 +51,7 @@ type LiveUsageSnapshot struct { APIEqPendingCalls int64 APIEqTierPremiumUSD float64 APIEqUnknownTierCalls int64 + APIEqDiagnostics []APIEqDiagnostic } // LiveUsageSession is one independently started local Codex session. Token @@ -100,6 +102,13 @@ type LiveModelCall struct { APIEqKnown bool APIEqIssue string apiEqFinalized bool + issueKind APIEqIssueKind + SessionID string + TurnID string + ResponseID string + Effort string + UsageSource string + ModelBasis string RequestedServiceTier string APIEqTierPremiumUSD float64 } @@ -140,6 +149,7 @@ type LiveUsageReader struct { apiEqMissingUsageCalls int64 apiEqInconsistentUsageCalls int64 apiEqAccountingAdjustments int64 + apiEqDiagnostics []APIEqDiagnostic lastActivity time.Time nextEventSequence uint64 daemonObservationSequence uint64 @@ -169,6 +179,11 @@ type rolloutCursor struct { modelCalls []LiveModelCall turnTimings []LiveTurnTiming attention sessionAttentionState + exactUsage bool + exactUsageUncertain bool + exactResponses map[string]BenchmarkUsage + exactConflicts map[string]bool + exactResponseOrder []string } type pendingModelResolution struct { @@ -177,6 +192,7 @@ type pendingModelResolution struct { turnID string usage BenchmarkUsage cumulativeTotal int64 + exact bool } type sessionAttentionState int @@ -204,6 +220,7 @@ type rolloutEvent struct { } type rolloutTokenUsage struct { + schemaIssue string InputTokens *int64 `json:"input_tokens"` CachedInputTokens *int64 `json:"cached_input_tokens"` CacheWriteInputTokens int64 `json:"cache_write_input_tokens"` @@ -227,6 +244,7 @@ func (u rolloutTokenUsage) benchmarkUsage() BenchmarkUsage { OutputTokens: optionalRolloutTokens(u.OutputTokens), ReasoningOutputTokens: optionalRolloutTokens(u.ReasoningOutputTokens), TotalTokens: optionalRolloutTokens(u.TotalTokens), + schemaIssue: u.schemaIssue, } } @@ -422,6 +440,7 @@ func (r *LiveUsageReader) fetchTokenUsage(ctx context.Context, forceFullDiscover APIEqPendingCalls: int64(len(r.pendingModelResolutions)), APIEqTierPremiumUSD: r.apiEqTierPremiumUSD, APIEqUnknownTierCalls: r.apiEqUnknownTierCalls, + APIEqDiagnostics: append([]APIEqDiagnostic(nil), r.apiEqDiagnostics...), }, nil } @@ -547,7 +566,18 @@ func (r *LiveUsageReader) addFile(path string, info os.FileInfo) error { cursor.attention = attention cursor.preview = latestSessionContext(path, cursor) } - if !r.initialized || !rolloutCreatedAfter(path, r.startedAt) { + // A new rollout filename can be a reverted/replaced history of an existing + // thread, not a new thread. Its copied responses are a baseline, not spend. + existingThread := false + if r.initialized && cursor.threadID != "" { + for _, known := range r.files { + if known.threadID == cursor.threadID { + existingThread = true + break + } + } + } + if !r.initialized || existingThread || !rolloutCreatedAfter(path, r.startedAt) { model, modelErr := latestRolloutModel(path, cursor) if modelErr != nil { return modelErr @@ -563,7 +593,14 @@ func (r *LiveUsageReader) addFile(path string, info os.FileInfo) error { return err } cursor.totalTokens = total - cursor.offset = info.Size() + baseline, err := restoreExactUsageBaseline(path, cursor, info.Size()) + if err != nil { + return err + } + cursor.offset = baseline + if existingThread { + r.apiEqAccountingAdjustments++ + } } r.files[path] = cursor return nil @@ -611,6 +648,11 @@ func (r *LiveUsageReader) consume(path string, cursor *rolloutCursor) error { } cursor.attention = attention cursor.preview = latestSessionContext(path, cursor) + baseline, err := restoreExactUsageBaseline(path, cursor, info.Size()) + if err != nil { + return err + } + cursor.offset = baseline return nil } if info.Size() == cursor.offset { @@ -648,7 +690,21 @@ func (r *LiveUsageReader) consume(path string, cursor *rolloutCursor) error { tokenRecordIsOwned(ordinal, cursor.subagentHistoryStartOrdinal, at, cursor.nonRoot, cursor.startedAt) { cursor.attention = attention } + if record, ok := exactUsageRecord(line); ok { + r.consumeExactUsage(cursor, record) + } if record, ok := tokenUsageRecord(line); ok { + if cursor.exactUsage || cursor.exactUsageUncertain { + if tokenRecordIsOwned(record.ordinal, cursor.subagentHistoryStartOrdinal, record.at, cursor.nonRoot, cursor.startedAt) { + r.attachExactCheckpoint(cursor, record) + if cursor.exactUsageUncertain && record.total != cursor.totalTokens { + r.apiEqMissingUsageCalls++ + r.rememberCallIssue(LiveModelCall{At: record.at, SessionID: cursor.threadID, Model: cursor.currentModel, RequestedServiceTier: cursor.currentServiceTier, Effort: cursor.modelSettings.ReasoningEffort, UsageSource: "rollout mode discovery", issueKind: UsageIssueMissing, APIEqIssue: "historical scan exceeded 4 MiB without establishing response usage mode; context snapshots cannot be billed until an exact response record arrives"}) + } + } + cursor.totalTokens = record.total + continue + } if !tokenRecordIsOwned(record.ordinal, cursor.subagentHistoryStartOrdinal, record.at, cursor.nonRoot, cursor.startedAt) { // Legacy child rollouts copy the parent's cumulative token // events. Preserve the latest inherited value as the child's @@ -695,6 +751,10 @@ func (r *LiveUsageReader) consume(path string, cursor *rolloutCursor) error { Sequence: r.nextEventSequence, At: record.at, OutputTokens: record.outputTokens, OutputAvailable: record.outputKnown, Model: model, RequestedServiceTier: cursor.currentServiceTier, + SessionID: cursor.threadID, TurnID: cursor.currentTurnID, Effort: cursor.modelSettings.ReasoningEffort, UsageSource: "legacy token snapshot", ModelBasis: "requested", + } + if resolved { + call.ModelBasis = "live reroute" } if usageMatchesDelta && (!resolutionPending || resolved) { r.finalizeCallPricing(&call, pricingUsage) @@ -702,8 +762,10 @@ func (r *LiveUsageReader) consume(path string, cursor *rolloutCursor) error { call.apiEqFinalized = true if !record.usageAvailable { call.APIEqIssue = "missing response input/output usage" + call.issueKind = UsageIssueMissing r.apiEqMissingUsageCalls++ } else { + call.issueKind = UsageIssueInconsistent call.APIEqIssue = validateBenchmarkUsage(record.usage) if call.APIEqIssue == "" { call.APIEqIssue = "cumulative token increase does not match last response usage" @@ -711,6 +773,9 @@ func (r *LiveUsageReader) consume(path string, cursor *rolloutCursor) error { r.apiEqInconsistentUsageCalls++ } } + if call.apiEqFinalized && call.APIEqIssue != "" { + r.rememberCallIssue(call) + } cursor.modelCalls = appendBounded(cursor.modelCalls, call, telemetryHistoryMax) if resolutionDeferred { r.pendingModelResolutions = append(r.pendingModelResolutions, pendingModelResolution{ @@ -772,18 +837,30 @@ func (r *LiveUsageReader) reconcilePendingModelResolutions() { // The response aged out before model resolution; the loss is a // usage-coverage issue, not evidence of an unsupported model. r.apiEqMissingUsageCalls++ + source := "legacy token snapshot" + if pending.exact { + source = "exact response" + } + r.rememberCallIssue(LiveModelCall{SessionID: pending.threadID, TurnID: pending.turnID, UsageSource: source, issueKind: UsageIssueMissing, APIEqIssue: "response aged out before model resolution"}) continue } if call.apiEqFinalized { continue } observation, ok := r.takeResolvedModelObservation(pending.threadID, pending.turnID, pending.usage, pending.cumulativeTotal) + if !ok && pending.exact && pending.cumulativeTotal < 0 { + observation, ok = r.takeUniqueExactModelObservation(pending.threadID, pending.turnID, pending.usage) + } pricingUsage := pending.usage if ok { call.Model = observation.Model + call.ModelBasis = "live reroute" pricingUsage = observation.Usage } r.finalizeCallPricing(call, pricingUsage) + if call.APIEqIssue != "" { + r.rememberCallIssue(*call) + } } r.pendingModelResolutions = nil } @@ -978,7 +1055,7 @@ func tokenUsageRecord(line []byte) (rolloutTokenRecord, bool) { // Require every core token field in both breakdowns. Missing legacy // telemetry must never be mistaken for Codex's synthetic full-context event. zeroClasses := func(u rolloutTokenUsage) bool { - return u.InputTokens != nil && *u.InputTokens == 0 && + return u.schemaIssue == "" && u.InputTokens != nil && *u.InputTokens == 0 && u.OutputTokens != nil && *u.OutputTokens == 0 && u.CachedInputTokens != nil && *u.CachedInputTokens == 0 && u.ReasoningOutputTokens != nil && *u.ReasoningOutputTokens == 0 && @@ -1249,7 +1326,10 @@ func (r *LiveUsageReader) sessionSnapshots(now time.Time, liveWriters map[string byID := make(map[string]*rolloutCursor, len(r.files)) for _, cursor := range r.files { if cursor.threadID != "" { - byID[cursor.threadID] = cursor + previous := byID[cursor.threadID] + if previous == nil || cursor.lastModified.After(previous.lastModified) { + byID[cursor.threadID] = cursor + } } } @@ -1485,3 +1565,29 @@ func contextErr(ctx context.Context) error { return nil } } + +func (u *rolloutTokenUsage) UnmarshalJSON(data []byte) error { + type wire rolloutTokenUsage + var value wire + if err := json.Unmarshal(data, &value); err != nil { + return err + } + var fields map[string]json.RawMessage + if err := json.Unmarshal(data, &fields); err != nil { + return err + } + *u = rolloutTokenUsage(value) + var unknown []string + for key := range fields { + switch key { + case "input_tokens", "cached_input_tokens", "cache_write_input_tokens", "output_tokens", "reasoning_output_tokens", "total_tokens", "codex_rollout_budget_units": + default: + unknown = append(unknown, key) + } + } + sort.Strings(unknown) + if len(unknown) > 0 { + u.schemaIssue = "unknown usage fields: " + strings.Join(unknown, ", ") + } + return nil +} diff --git a/internal/codex/live_usage_accounting_test.go b/internal/codex/live_usage_accounting_test.go index d5b2c61..e4ce133 100644 --- a/internal/codex/live_usage_accounting_test.go +++ b/internal/codex/live_usage_accounting_test.go @@ -143,7 +143,7 @@ func TestResponseUsageProblemsAreSeparateFromUnknownPrices(t *testing.T) { case "unknown-model": event = turnContextLine(now, "gpt-6-astra-preview") + "\n" + event case "unsupported-tier": - event = tierSettingsLine(now, `"flex"`) + "\n" + turnContextLine(now, "gpt-6-astra") + "\n" + event + event = tierSettingsLine(now, `"unadvertised-tier"`) + "\n" + turnContextLine(now, "gpt-6-astra") + "\n" + event } appendRollout(t, path, event+"\n") usage, err := r.FetchTokenUsage(context.Background()) diff --git a/internal/codex/live_usage_exact.go b/internal/codex/live_usage_exact.go new file mode 100644 index 0000000..731c2be --- /dev/null +++ b/internal/codex/live_usage_exact.go @@ -0,0 +1,207 @@ +package codex + +import ( + "bytes" + "encoding/json" + "errors" + "io" + "os" + "strings" + "time" +) + +// Codex added durable, exact response records on 2026-08-31. Context token +// snapshots remain useful as baselines, but are not response billing records. +type rolloutExactUsage struct { + Timestamp time.Time `json:"timestamp"` + Ordinal *uint64 `json:"ordinal"` + Type string `json:"type"` + Payload struct { + ThreadID string `json:"thread_id"` + TurnID string `json:"turn_id"` + ResponseID string `json:"response_id"` + Usage *rolloutTokenUsage `json:"usage"` + } `json:"payload"` +} + +func exactUsageRecord(line []byte) (rolloutExactUsage, bool) { + var record rolloutExactUsage + if !bytes.Contains(line, []byte(`"token_usage_record"`)) || json.Unmarshal(line, &record) != nil || record.Type != "token_usage_record" { + return record, false + } + return record, true +} + +func (c *rolloutCursor) ownsExactRecord(record rolloutExactUsage) bool { + return record.Payload.ThreadID == c.threadID && tokenRecordIsOwned(record.Ordinal, c.subagentHistoryStartOrdinal, record.Timestamp, c.nonRoot, c.startedAt) +} + +func (c *rolloutCursor) rememberExactResponse(id string, usage BenchmarkUsage) bool { + if c.exactResponses == nil { + c.exactResponses = make(map[string]BenchmarkUsage) + } + if _, exists := c.exactResponses[id]; exists { + return false + } + c.exactResponses[id] = usage + c.exactResponseOrder = append(c.exactResponseOrder, id) + if len(c.exactResponseOrder) > telemetryHistoryMax { + delete(c.exactResponses, c.exactResponseOrder[0]) + delete(c.exactConflicts, c.exactResponseOrder[0]) + c.exactResponseOrder = c.exactResponseOrder[1:] + } + return true +} + +// Establish the source and recent replay identities without counting history. +// Bound startup IO independently of the file's potentially large transcript. +// A truncated scan cannot prove the absence of older exact records. In that +// case suppress legacy billing until an owned exact record establishes the mode. +func restoreExactUsageBaseline(path string, cursor *rolloutCursor, baselineOffset int64) (int64, error) { + file, err := os.Open(path) + if err != nil { + return 0, err + } + defer file.Close() + info, err := file.Stat() + if err != nil { + return 0, err + } + end := min(info.Size(), baselineOffset) + size := min(end, int64(4*1024*1024)) + start := end - size + data := make([]byte, size) + _, err = file.ReadAt(data, start) + if err != nil && !errors.Is(err, io.EOF) { + return 0, err + } + // A writer can be midway through a small exact record at discovery. Leave + // its partial bytes for the incremental reader, rather than skipping them. + if last := bytes.LastIndexByte(data, '\n'); last >= 0 && last < len(data)-1 { + end = end - size + int64(last) + 1 + data = data[:last+1] + } + lines := bytes.Split(data, []byte{'\n'}) + if start > 0 { + lines = lines[1:] + } + for _, line := range lines { + record, ok := exactUsageRecord(line) + if !ok || !cursor.ownsExactRecord(record) { + continue + } + cursor.exactUsage = true + if id := strings.TrimSpace(record.Payload.ResponseID); id != "" { + usage := BenchmarkUsage{} + if record.Payload.Usage != nil { + usage = record.Payload.Usage.benchmarkUsage() + } + cursor.rememberExactResponse(id, usage) + } + } + cursor.exactUsageUncertain = start > 0 && !cursor.exactUsage + return end, nil +} + +func (r *LiveUsageReader) consumeExactUsage(cursor *rolloutCursor, record rolloutExactUsage) { + if !cursor.ownsExactRecord(record) { + return + } + cursor.exactUsage = true + cursor.exactUsageUncertain = false + id := strings.TrimSpace(record.Payload.ResponseID) + usage := BenchmarkUsage{} + if record.Payload.Usage != nil { + usage = record.Payload.Usage.benchmarkUsage() + } + if previous, seen := cursor.exactResponses[id]; id != "" && seen { + if previous != usage && !cursor.exactConflicts[id] { + if cursor.exactConflicts == nil { + cursor.exactConflicts = make(map[string]bool) + } + cursor.exactConflicts[id] = true + r.apiEqInconsistentUsageCalls++ + r.rememberCallIssue(LiveModelCall{At: record.Timestamp, SessionID: cursor.threadID, Model: cursor.currentModel, RequestedServiceTier: cursor.currentServiceTier, ResponseID: id, UsageSource: "exact response", Effort: cursor.modelSettings.ReasoningEffort, issueKind: UsageIssueInconsistent, APIEqIssue: "response ID replayed with conflicting usage"}) + } + return + } + if id != "" { + cursor.rememberExactResponse(id, usage) + } + r.nextEventSequence++ + at := record.Timestamp + if at.IsZero() { + at = time.Now() + } + call := LiveModelCall{Sequence: r.nextEventSequence, At: at, Model: cursor.currentModel, + SessionID: cursor.threadID, TurnID: record.Payload.TurnID, ResponseID: id, + Effort: cursor.modelSettings.ReasoningEffort, UsageSource: "exact response", ModelBasis: "requested", RequestedServiceTier: cursor.currentServiceTier} + call.OutputAvailable = record.Payload.Usage != nil && record.Payload.Usage.OutputTokens != nil + call.OutputTokens = usage.OutputTokens + if id == "" { + call.issueKind = UsageIssueInconsistent + call.APIEqIssue = "exact response record omitted response ID" + call.apiEqFinalized = true + r.apiEqInconsistentUsageCalls++ + } else if record.Payload.Usage == nil || record.Payload.Usage.InputTokens == nil || record.Payload.Usage.OutputTokens == nil || record.Payload.Usage.TotalTokens == nil || record.Payload.Usage.CachedInputTokens == nil || record.Payload.Usage.ReasoningOutputTokens == nil { + call.issueKind = UsageIssueMissing + call.APIEqIssue = "exact response record omitted required token breakdown fields" + call.apiEqFinalized = true + r.apiEqMissingUsageCalls++ + } else if issue := validateBenchmarkUsage(usage); issue != "" { + call.issueKind = UsageIssueInconsistent + call.APIEqIssue = issue + call.apiEqFinalized = true + r.apiEqInconsistentUsageCalls++ + } else { + // Exact usage is counted independently of synthetic context-counter resets. + r.totalTokens += usage.TotalTokens + cursor.observedTokens += usage.TotalTokens + if usage.TotalTokens > 0 && at.After(r.lastActivity) { + r.lastActivity = at + } + _, subscribed := r.daemonSubscribedThreads[cursor.threadID] + if subscribed && call.TurnID != "" { + r.pendingModelResolutions = append(r.pendingModelResolutions, pendingModelResolution{ + callSequence: call.Sequence, threadID: call.SessionID, turnID: call.TurnID, usage: usage, cumulativeTotal: -1, exact: true}) + } else { + r.finalizeCallPricing(&call, usage) + } + } + if call.apiEqFinalized && call.APIEqIssue != "" { + r.rememberCallIssue(call) + } + cursor.modelCalls = appendBounded(cursor.modelCalls, call, telemetryHistoryMax) +} + +// Exact records precede the corresponding context snapshot. Attach that +// checkpoint when available; it is attribution evidence, not a billing gate. +func (r *LiveUsageReader) attachExactCheckpoint(cursor *rolloutCursor, record rolloutTokenRecord) { + for i := len(r.pendingModelResolutions) - 1; i >= 0; i-- { + pending := &r.pendingModelResolutions[i] + if pending.exact && pending.threadID == cursor.threadID && (cursor.currentTurnID == "" || pending.turnID == cursor.currentTurnID) && pending.cumulativeTotal < 0 && sameBenchmarkUsage(pending.usage, record.usage) { + pending.cumulativeTotal = record.total + break + } + } +} + +// Without a context checkpoint, accept only a unique matching live observation. +// Repeated identical responses must not inherit an ambiguous rerouted model. +func (r *LiveUsageReader) takeUniqueExactModelObservation(threadID, turnID string, usage BenchmarkUsage) (resolvedModelObservation, bool) { + index := -1 + for i, observation := range r.resolvedObservations { + if observation.ThreadID == threadID && observation.TurnID == turnID && sameBenchmarkUsage(observation.Usage, usage) { + if index >= 0 { + return resolvedModelObservation{}, false + } + index = i + } + } + if index < 0 { + return resolvedModelObservation{}, false + } + observation := r.resolvedObservations[index] + r.resolvedObservations = append(r.resolvedObservations[:index], r.resolvedObservations[index+1:]...) + return observation, true +} diff --git a/internal/codex/live_usage_exact_test.go b/internal/codex/live_usage_exact_test.go new file mode 100644 index 0000000..eac8339 --- /dev/null +++ b/internal/codex/live_usage_exact_test.go @@ -0,0 +1,280 @@ +package codex + +import ( + "context" + "encoding/json" + "math" + "os" + "path/filepath" + "strings" + "testing" + "time" +) + +func exactLine(t *testing.T, at time.Time, thread, turn, response string, usage BenchmarkUsage) string { + t.Helper() + raw, err := json.Marshal(map[string]any{"type": "token_usage_record", "timestamp": at, "payload": map[string]any{ + "thread_id": thread, "turn_id": turn, "response_id": response, + "usage": map[string]any{"input_tokens": usage.InputTokens, "cached_input_tokens": usage.CachedInputTokens, + "cache_write_input_tokens": usage.CacheWriteInputTokens, "output_tokens": usage.OutputTokens, + "reasoning_output_tokens": usage.ReasoningOutputTokens, "total_tokens": usage.TotalTokens}}}) + if err != nil { + t.Fatal(err) + } + return string(raw) +} + +func TestExactUsageIgnoresContextCountersAndDeduplicatesAcrossPolls(t *testing.T) { + r, path, now := astraUsageReader(t, 100) + r.statusProvider = nil + u := BenchmarkUsage{InputTokens: 1000, CachedInputTokens: 200, CacheWriteInputTokens: 30, OutputTokens: 100, ReasoningOutputTokens: 80, TotalTokens: 1100} + appendRollout(t, path, exactLine(t, now, "astra-accounting", "t", "r1", u)+"\n"+richTokenCountLine(now, 9000, 1000, 200, 30, 100)+"\n") + first, err := r.FetchTokenUsage(context.Background()) + if err != nil { + t.Fatal(err) + } + want, _, _ := EstimateStandardAPIEqCost("gpt-6-astra", u) + if first.TotalTokens != 1100 || first.APIEqPricedCalls != 1 || first.APIEqUnpricedCalls != 0 || first.APIEqInconsistentUsageCalls != 0 || math.Abs(first.APIEqUSD-want) > 1e-12 { + t.Fatal("exact response depended on context counter", first) + } + appendRollout(t, path, exactLine(t, now, "astra-accounting", "t", "r1", u)+"\n"+contextFillLine(t, now, 128000, 119000)+"\n") + duplicate, err := r.FetchTokenUsage(context.Background()) + if err != nil { + t.Fatal(err) + } + if duplicate.TotalTokens != first.TotalTokens || duplicate.APIEqPricedCalls != 1 || duplicate.APIEqAccountingAdjustments != 0 || len(duplicate.Sessions[0].ModelCalls) != 1 { + t.Fatal("replay/bookkeeping affected exact accounting", duplicate) + } + appendRollout(t, path, exactLine(t, now, "astra-accounting", "t", "r2", u)+"\n") + next, err := r.FetchTokenUsage(context.Background()) + if err != nil || next.TotalTokens != 2200 || next.APIEqPricedCalls != 2 || math.Abs(next.APIEqUSD-2*want) > 1e-12 { + t.Fatal("next exact response was lost", next, err) + } +} + +func TestExactUsageStartupBetweenResponseAndContextSnapshot(t *testing.T) { + _, path, now := astraUsageReader(t, 100) + u := BenchmarkUsage{InputTokens: 1000, OutputTokens: 100, TotalTokens: 1100} + appendRollout(t, path, exactLine(t, now, "astra-accounting", "t", "old", u)+"\n") + + home := strings.Split(path, string(filepath.Separator)+"sessions"+string(filepath.Separator))[0] + r, err := NewLiveUsageReader(home) + if err != nil { + t.Fatal(err) + } + r.statusProvider = nil + baseline, err := r.FetchTokenUsage(context.Background()) + if err != nil || baseline.TotalTokens != 0 || baseline.APIEqPricedCalls != 0 { + t.Fatal("historical exact response counted", baseline, err) + } + appendRollout(t, path, exactLine(t, now, "astra-accounting", "t", "old", u)+"\n"+richTokenCountLine(now, 1200, 1000, 0, 0, 100)+"\n") + replay, err := r.FetchTokenUsage(context.Background()) + if err != nil || replay.TotalTokens != 0 || replay.APIEqPricedCalls != 0 { + t.Fatal("startup replay/context duplicate counted", replay, err) + } + appendRollout(t, path, exactLine(t, now, "astra-accounting", "t", "new", u)+"\n") + fresh, err := r.FetchTokenUsage(context.Background()) + if err != nil || fresh.TotalTokens != 1100 || fresh.APIEqPricedCalls != 1 { + t.Fatal("fresh exact response lost", fresh, err) + } + +} + +func TestExactUsageOwnedRecordsExcludeInheritedHistory(t *testing.T) { + r, path, now := astraUsageReader(t, 100) + r.statusProvider = nil + cursor := r.files[path] + ordinal := uint64(10) + cursor.nonRoot = true + cursor.subagentHistoryStartOrdinal = &ordinal + u := BenchmarkUsage{InputTokens: 1000, OutputTokens: 100, TotalTokens: 1100} + inherited := exactLine(t, now, "astra-accounting", "t", "inherited", u) + var frame map[string]any + _ = json.Unmarshal([]byte(inherited), &frame) + frame["ordinal"] = 9 + raw, _ := json.Marshal(frame) + appendRollout(t, path, exactLine(t, now, "parent-thread", "t", "parent", u)+"\n"+string(raw)+"\n") + first, err := r.FetchTokenUsage(context.Background()) + if err != nil || first.APIEqPricedCalls != 0 || first.TotalTokens != 0 { + t.Fatal("inherited response was charged", first, err) + } + frame["ordinal"] = 11 + frame["payload"].(map[string]any)["response_id"] = "owned" + raw, _ = json.Marshal(frame) + appendRollout(t, path, string(raw)+"\n") + owned, err := r.FetchTokenUsage(context.Background()) + if err != nil || owned.APIEqPricedCalls != 1 || owned.TotalTokens != 1100 { + t.Fatal("owned response was not charged", owned, err) + } +} + +func TestExactUsageSeparatesMissingInvalidAndUnpricedWithDiagnostics(t *testing.T) { + for _, kind := range []string{"missing", "invalid", "unknown-field", "reserve"} { + t.Run(kind, func(t *testing.T) { + r, path, now := astraUsageReader(t, 100) + r.statusProvider = nil + u := BenchmarkUsage{InputTokens: 1000, OutputTokens: 100, TotalTokens: 1100} + line := exactLine(t, now, "astra-accounting", "t", "r", u) + var frame map[string]any + _ = json.Unmarshal([]byte(line), &frame) + fields := frame["payload"].(map[string]any)["usage"].(map[string]any) + switch kind { + case "missing": + delete(fields, "cached_input_tokens") + case "invalid": + fields["cached_input_tokens"] = 1001 + case "unknown-field": + fields["future_billable_tokens"] = 20 + case "reserve": + appendRollout(t, path, turnContextLine(now, "gpt-reserve")+"\n") + } + raw, _ := json.Marshal(frame) + appendRollout(t, path, string(raw)+"\n") + got, err := r.FetchTokenUsage(context.Background()) + if err != nil { + t.Fatal(err) + } + wanted := UsageIssueInconsistent + if kind == "missing" { + wanted = UsageIssueMissing + } + if kind == "reserve" { + wanted = UsageIssueUnpriced + } + if len(got.APIEqDiagnostics) != 1 || got.APIEqDiagnostics[0].Kind != wanted || got.APIEqDiagnostics[0].SessionID != "astra-accounting" || got.APIEqDiagnostics[0].ResponseID != "r" || got.APIEqDiagnostics[0].Reason == "" { + t.Fatal("failure attribution lost", got) + } + if kind != "reserve" && got.APIEqUnpricedCalls != 0 { + t.Fatal("bad usage became missing pricing", got) + } + }) + } +} + +func TestExactUsageKeepsDaemonModelResolution(t *testing.T) { + r, path, now := astraUsageReader(t, 100) + u := BenchmarkUsage{InputTokens: 1000, OutputTokens: 100, TotalTokens: 1100} + r.statusProvider = stubSessionStatusProvider{subscribed: map[string]struct{}{"astra-accounting": {}}} + appendRollout(t, path, turnContextWithTurnIDLine(now, "turn", "gpt-6-astra")+"\n"+exactLine(t, now, "astra-accounting", "turn", "r", u)+"\n"+richTokenCountLine(now, 9999, 1000, 0, 0, 100)+"\n") + first, err := r.FetchTokenUsage(context.Background()) + if err != nil || first.APIEqPendingCalls != 1 || first.APIEqPricedCalls != 0 { + t.Fatal("response did not wait for attribution", first, err) + } + r.statusProvider = stubSessionStatusProvider{subscribed: map[string]struct{}{"astra-accounting": {}}, observations: []resolvedModelObservation{{Sequence: 1, ThreadID: "astra-accounting", TurnID: "turn", Model: "gpt-5.2", Usage: u, CumulativeTotal: 9999}}} + resolved, err := r.FetchTokenUsage(context.Background()) + if err != nil || resolved.APIEqPendingCalls != 0 || resolved.APIEqPricedCalls != 1 || resolved.Sessions[0].ModelCalls[0].Model != "gpt-5.2" { + t.Fatal("exact response lost reroute attribution", resolved, err) + } +} + +func TestExactConflictingReplayIsReportedOnceWithoutAdditionalCost(t *testing.T) { + r, path, now := astraUsageReader(t, 100) + r.statusProvider = nil + u := BenchmarkUsage{InputTokens: 1000, OutputTokens: 100, TotalTokens: 1100} + appendRollout(t, path, exactLine(t, now, "astra-accounting", "t", "r", u)+"\n") + first, _ := r.FetchTokenUsage(context.Background()) + u.InputTokens++ + u.TotalTokens++ + line := exactLine(t, now, "astra-accounting", "t", "r", u) + "\n" + appendRollout(t, path, line+line) + got, err := r.FetchTokenUsage(context.Background()) + if err != nil || got.APIEqUSD != first.APIEqUSD || got.TotalTokens != first.TotalTokens || got.APIEqInconsistentUsageCalls != 1 || len(got.APIEqDiagnostics) != 1 || !strings.Contains(got.APIEqDiagnostics[0].Reason, "conflicting usage") { + t.Fatal("conflicting replay charged or hidden", got, err) + } +} + +func TestExactDiscoveryDoesNotBaselineConcurrentAppendOrPartialRecord(t *testing.T) { + for _, partial := range []bool{false, true} { + r, path, now := astraUsageReader(t, 100) + r.statusProvider = nil + u := BenchmarkUsage{InputTokens: 1000, OutputTokens: 100, TotalTokens: 1100} + line := exactLine(t, now, "astra-accounting", "t", "concurrent", u) + "\n" + if partial { + appendRollout(t, path, line[:len(line)/2]) + } + file, err := os.Stat(path) + if err != nil { + t.Fatal(err) + } + if partial { + appendRollout(t, path, line[len(line)/2:]) + } else { + appendRollout(t, path, line) + } + delete(r.files, path) + if err := r.addFile(path, file); err != nil { + t.Fatal(err) + } + got, err := r.FetchTokenUsage(context.Background()) + if err != nil || got.APIEqPricedCalls != 1 || got.TotalTokens != 1100 { + t.Fatal("concurrent/partial append was silently baselined", partial, got, err) + } + } +} + +func TestExactReplacementRolloutDoesNotBillCopiedThreadHistory(t *testing.T) { + r, path, now := astraUsageReader(t, 100) + r.statusProvider = nil + u := BenchmarkUsage{InputTokens: 1000, OutputTokens: 100, TotalTokens: 1100} + line := exactLine(t, now, "astra-accounting", "t", "old", u) + "\n" + appendRollout(t, path, line) + first, _ := r.FetchTokenUsage(context.Background()) + home := strings.Split(path, string(filepath.Separator)+"sessions"+string(filepath.Separator))[0] + replacement := testRolloutPath(t, home, time.Now().Add(time.Second), "replacement-rollout") + writeRollout(t, replacement, sessionMetaLine("astra-accounting", `"cli"`, "/synthetic", nil)+"\n"+turnContextLine(now, "gpt-6-sol")+"\n"+line) + info, err := os.Stat(replacement) + if err != nil { + t.Fatal(err) + } + if err := r.addFile(replacement, info); err != nil { + t.Fatal(err) + } + got, err := r.FetchTokenUsage(context.Background()) + if err != nil || got.TotalTokens != first.TotalTokens || got.APIEqPricedCalls != 1 || got.APIEqAccountingAdjustments != 1 { + t.Fatal("replacement history billed again", got, err) + } + appendRollout(t, replacement, exactLine(t, now, "astra-accounting", "t", "new", u)+"\n") + next, err := r.FetchTokenUsage(context.Background()) + if err != nil || next.TotalTokens != 2200 || next.APIEqPricedCalls != 2 || len(next.Sessions) != 1 || next.Sessions[0].TotalTokens != 2200 || next.Sessions[0].ModelSettings.Model != "gpt-6-sol" { + t.Fatal("fresh replacement response was lost", next, err) + } +} + +func TestExactUsageOlderThanStartupTailCannotEnableLegacyBilling(t *testing.T) { + for _, historicalExact := range []bool{false, true} { + _, path, now := astraUsageReader(t, 100) + u := BenchmarkUsage{InputTokens: 1000, OutputTokens: 100, TotalTokens: 1100} + if historicalExact { + appendRollout(t, path, exactLine(t, now, "astra-accounting", "t", "old", u)+"\n") + } + // The last owned exact response, if present, is outside the discovery + // window. An otherwise identical large legacy file is also uncertain. + padding := `{"type":"response_item","payload":"` + strings.Repeat("x", 4096) + `"}` + "\n" + appendRollout(t, path, strings.Repeat(padding, 1100)) + home := strings.Split(path, string(filepath.Separator)+"sessions"+string(filepath.Separator))[0] + r, err := NewLiveUsageReader(home) + if err != nil { + t.Fatal(err) + } + r.statusProvider = nil + if _, err := r.FetchTokenUsage(context.Background()); err != nil { + t.Fatal(err) + } + checkpoint := richTokenCountLine(now, 1200, 1000, 0, 0, 100) + "\n" + appendRollout(t, path, checkpoint+checkpoint) + uncertain, err := r.FetchTokenUsage(context.Background()) + if err != nil || uncertain.TotalTokens != 0 || uncertain.APIEqPricedCalls != 0 || uncertain.APIEqUSD != 0 || uncertain.APIEqMissingUsageCalls != 1 || len(uncertain.APIEqDiagnostics) != 1 || !strings.Contains(uncertain.APIEqDiagnostics[0].Reason, "without establishing response usage mode") { + t.Fatal("truncated baseline enabled legacy billing or hid uncertainty", historicalExact, uncertain, err) + } + appendRollout(t, path, richTokenCountLine(now, 2300, 1000, 0, 0, 100)+"\n") + continued, err := r.FetchTokenUsage(context.Background()) + if err != nil || continued.APIEqMissingUsageCalls != 2 || continued.APIEqPricedCalls != 0 { + t.Fatal("ongoing uncertain usage failed to invalidate quota learning", continued, err) + } + appendRollout(t, path, exactLine(t, now, "astra-accounting", "t", "fresh", u)+"\n"+richTokenCountLine(now, 3400, 1000, 0, 0, 100)+"\n") + fresh, err := r.FetchTokenUsage(context.Background()) + if err != nil || fresh.APIEqPricedCalls != 1 || fresh.TotalTokens != 1100 || fresh.APIEqMissingUsageCalls != 2 || r.files[path].exactUsageUncertain { + t.Fatal("exact record did not restore reliable accounting", fresh, err) + } + } +} diff --git a/internal/codex/service_tier.go b/internal/codex/service_tier.go index 39d3168..d46486e 100644 --- a/internal/codex/service_tier.go +++ b/internal/codex/service_tier.go @@ -10,28 +10,41 @@ import ( // FastAPIPricingRetrievedOn is separate from the standard-price review date. // Sources: https://developers.openai.com/api/docs/pricing and // https://learn.chatgpt.com/docs/agent-configuration/speed (GPT-5.6 API rates). -const FastAPIPricingRetrievedOn = "2026-09-30" +const FastAPIPricingRetrievedOn = "2026-10-12" // requestedTierPremium prices a single response's requested tier. It does not // claim that the backend delivered/billed that tier. Empty means unavailable, // not confirmed standard. Unknown explicit tiers fail closed. func requestedTierPremium(model, tier string, standard float64) (float64, bool) { + multiplier, known := requestedTierMultiplier(model, tier) + return standard * (multiplier - 1), known +} + +// Only published model/tier combinations are maintained. The adjustment may +// be negative for Flex; Standard totals remain independently monotonic. +func requestedTierMultiplier(model, tier string) (float64, bool) { + name := pricedModelName(model) switch strings.ToLower(strings.TrimSpace(tier)) { case "", "default", "standard": - return 0, true + return 1, true case "fast", "priority": - // Only apply verified model-specific rates, never subscription credit - // multipliers. GPT-6 / GPT-5.6 Fast is 2x applicable rates, including long - // context and both cache classes. Dated snapshots share base pricing. - switch pricedModelName(model) { - case "gpt-6-astra", "gpt-6.1-sol", "gpt-6-sol", "gpt-6-luna", "gpt-5.6-sol", "gpt-5.6-terra", "gpt-5.6-luna": - return standard, true - default: - return 0, false + switch name { + case "gpt-6-astra", "gpt-6.1-sol", "gpt-6-sol", "gpt-6-luna", "gpt-5.6-sol", "gpt-5.6-terra", "gpt-5.6-luna", "gpt-5.2", "gpt-5.4", "gpt-5.4-mini", "gpt-5.3-codex": + return 2, true + case "gpt-5.5": + return 2.5, true + } + case "ultrafast": + if name == "gpt-6-astra" || name == "gpt-6.1-sol" { + return 6, true + } + case "flex": + switch name { + case "gpt-6-astra", "gpt-6.1-sol", "gpt-6-sol", "gpt-6-luna", "gpt-5.6-sol", "gpt-5.6-terra", "gpt-5.6-luna", "gpt-5.2", "gpt-5.5": + return 0.5, true } - default: - return 0, false } + return 1, false } // Codex persists settings separately from turn_context. A complete settings @@ -66,12 +79,19 @@ func rolloutTierRecord(line []byte) (string, *uint64, time.Time, bool) { func (r *LiveUsageReader) finalizeCallPricing(call *LiveModelCall, usage BenchmarkUsage) { if issue := validateBenchmarkUsage(usage); issue != "" { + call.issueKind = UsageIssueInconsistent call.APIEqIssue = issue call.apiEqFinalized = true r.apiEqInconsistentUsageCalls++ return } call.APIEqUSD, call.APIEqKnown, call.APIEqIssue = EstimateStandardAPIEqCost(call.Model, usage) + if call.APIEqKnown && usage.InputTokens > 272_000 && + (strings.EqualFold(strings.TrimSpace(call.RequestedServiceTier), "fast") || strings.EqualFold(strings.TrimSpace(call.RequestedServiceTier), "priority")) && + (pricedModelName(call.Model) == "gpt-5.4" || pricedModelName(call.Model) == "gpt-5.5") { + call.APIEqKnown = false + call.APIEqIssue = "no maintained long-context Fast price for model " + call.Model + } if call.APIEqKnown { call.APIEqTierPremiumUSD, call.APIEqKnown = requestedTierPremium(call.Model, call.RequestedServiceTier, call.APIEqUSD) if !call.APIEqKnown { diff --git a/internal/codex/service_tier_test.go b/internal/codex/service_tier_test.go index 284bd20..85daf3d 100644 --- a/internal/codex/service_tier_test.go +++ b/internal/codex/service_tier_test.go @@ -29,9 +29,9 @@ func TestRequestedTierPremium(t *testing.T) { {" GPT-6-ASTRA-2026-09-01 ", " PRIORITY ", 3, true}, {"gpt-6-astra", "default", 0, true}, {"gpt-6-astra", "", 0, true}, - {"gpt-6-astra", "flex", 0, false}, + {"gpt-6-astra", "flex", -1.5, true}, {"gpt-6-astra-preview", "fast", 0, false}, - {"gpt-5.4", "fast", 0, false}, + {"gpt-5.4", "fast", 3, true}, {"unknown", "fast", 0, false}, } { t.Run(test.model+test.tier, func(t *testing.T) { @@ -206,3 +206,28 @@ func TestTierAccountingIsPerSession(t *testing.T) { } } } + +func TestVerifiedTierPricingForAstraAndFallbacks(t *testing.T) { + for _, input := range []int64{272000, 272001} { + u := BenchmarkUsage{InputTokens: input, CachedInputTokens: 1000, CacheWriteInputTokens: 2000, OutputTokens: 100, ReasoningOutputTokens: 80, TotalTokens: input + 100} + standard, _, _ := EstimateStandardAPIEqCost("gpt-6-astra", u) + for tier, factor := range map[string]float64{"default": 1, "fast": 2, "ultrafast": 6, "flex": 0.5} { + r := &LiveUsageReader{} + call := LiveModelCall{Model: "gpt-6-astra", RequestedServiceTier: tier} + r.finalizeCallPricing(&call, u) + if !call.APIEqKnown || r.apiEqUnknownCalls != 0 || math.Abs((r.apiEqUSD+r.apiEqTierPremiumUSD)-standard*factor) > 1e-12 { + t.Fatal("tier lost token classes or context boundary", input, tier, call) + } + } + } + u := BenchmarkUsage{InputTokens: 1000, CachedInputTokens: 100, OutputTokens: 100, TotalTokens: 1100} + cost, known, _ := EstimateStandardAPIEqCost("gpt-5.2-2025-12-11", u) + if !known || math.Abs(cost-(900*1.75+100*.175+100*14)/1e6) > 1e-12 { + t.Fatal("fallback snapshot not priced", cost, known) + } + for _, model := range []string{"gpt-reserve", "openai.gpt-6-astra", "gpt-6-astra-preview"} { + if _, known, _ := EstimateStandardAPIEqCost(model, u); known { + t.Fatal("unverified model/provider mapping guessed", model) + } + } +} diff --git a/internal/codex/usage_diagnostics.go b/internal/codex/usage_diagnostics.go new file mode 100644 index 0000000..bab07d1 --- /dev/null +++ b/internal/codex/usage_diagnostics.go @@ -0,0 +1,78 @@ +package codex + +import ( + "strings" + "time" +) + +type APIEqIssueKind string + +const ( + UsageIssueUnpriced APIEqIssueKind = "UNPRICED USAGE" + UsageIssueMissing APIEqIssueKind = "MISSING RESPONSE USAGE" + UsageIssueInconsistent APIEqIssueKind = "INCONSISTENT RESPONSE USAGE" +) + +// A bounded, process-local diagnostic contains accounting metadata only. +// Counter belongs to Kind; it prevents old failures attaching to new intervals. +type APIEqDiagnostic struct { + Kind APIEqIssueKind + ObservedAt time.Time + At time.Time + Counter int64 + SessionID string + Model string + ModelBasis string + Tier string + Effort string + Source string + ResponseID string + Reason string +} + +func (r *LiveUsageReader) rememberCallIssue(call LiveModelCall) { + kind := call.issueKind + if kind == "" { + kind = UsageIssueUnpriced + } + counter := r.apiEqUnknownCalls + if kind == UsageIssueMissing { + counter = r.apiEqMissingUsageCalls + } + if kind == UsageIssueInconsistent { + counter = r.apiEqInconsistentUsageCalls + } + r.apiEqDiagnostics = appendBounded(r.apiEqDiagnostics, APIEqDiagnostic{ + Kind: kind, Counter: counter, ObservedAt: time.Now(), At: call.At, SessionID: call.SessionID, Model: call.Model, ModelBasis: call.ModelBasis, Tier: call.RequestedServiceTier, + Effort: call.Effort, Source: call.UsageSource, ResponseID: call.ResponseID, Reason: call.APIEqIssue}, 32) +} + +// DiagnosticText is safe for terminal output and browser text. Preserve model +// and tier identifiers without retaining request content or arbitrary errors. +func DiagnosticText(issue APIEqDiagnostic) string { + field := func(value string, limit int) string { + value = strings.Join(strings.Fields(SanitizeSessionContext(value)), " ") + runes := []rune(value) + if len(runes) > limit { + value = string(runes[:limit]) + "…" + } + if value == "" { + return "unknown" + } + return value + } + basis := issue.ModelBasis + if basis == "" { + basis = "requested" + } + result := string(issue.Kind) + " // " + field(issue.Reason, 180) + "\n" + + "MODEL " + field(issue.Model, 96) + " (" + field(basis, 32) + ") // TIER " + field(issue.Tier, 32) + " // EFFORT " + field(issue.Effort, 16) + "\n" + + "SESSION " + field(issue.SessionID, 12) + " // SOURCE " + field(issue.Source, 48) + if issue.ResponseID != "" { + result += " // RESPONSE " + field(issue.ResponseID, 16) + } + if !issue.At.IsZero() { + result += " // AT " + issue.At.UTC().Format(time.RFC3339) + } + return result +} diff --git a/internal/ui/benchmark_quota.go b/internal/ui/benchmark_quota.go index 4c3eeca..0380a83 100644 --- a/internal/ui/benchmark_quota.go +++ b/internal/ui/benchmark_quota.go @@ -4,6 +4,7 @@ import ( "fmt" "math" "strings" + "time" "charm.land/lipgloss/v2" @@ -19,15 +20,18 @@ type benchmarkBillingProvider interface { // ephemeral benchmark calls. These calls never enter the persisted rollout // reader, but subscription-funded calls do move the account quota windows. type benchmarkQuotaAccounting struct { - billingSource codex.BenchmarkBillingSource - revision uint64 - runSequence uint64 - active bool - settling bool - costUSD float64 - pricedCalls int64 - unpricedCalls int64 - accounted map[string]struct{} + billingSource codex.BenchmarkBillingSource + revision uint64 + runSequence uint64 + active bool + settling bool + costUSD float64 + pricedCalls int64 + unpricedCalls int64 + missingCalls int64 + inconsistentCalls int64 + diagnostics []codex.APIEqDiagnostic + accounted map[string]struct{} } func benchmarkQuotaAccountingFor(runner BenchmarkRunner) benchmarkQuotaAccounting { @@ -62,11 +66,15 @@ func (a *benchmarkQuotaAccounting) settle() { a.settling = false } -func (a *benchmarkQuotaAccounting) abandonActiveResult() { +func (a *benchmarkQuotaAccounting) abandonActiveResult(results ...codex.BenchmarkResult) { if a.billingSource != codex.BenchmarkBillingSubscription || !a.active { return } - a.unpricedCalls++ + result := codex.BenchmarkResult{} + if len(results) > 0 { + result = results[0] + } + a.recordIssue(result, codex.UsageIssueMissing, "benchmark cancelled before measured usage was available") a.revision++ } @@ -80,45 +88,132 @@ func (a *benchmarkQuotaAccounting) observe(result codex.BenchmarkResult) { } a.accounted[key] = struct{}{} - cost, known := benchmarkQuotaCost(result) - calls := int64(len(result.ResponseUsage)) - if calls == 0 { - calls = 1 - } - if known { - a.costUSD += cost - a.pricedCalls += calls - a.revision++ - return + cost, pricedCalls, issues := benchmarkQuotaCostDetail(result) + a.costUSD += cost + a.pricedCalls += pricedCalls + for _, issue := range issues { + if issue.response != nil { + a.recordIssue(result, issue.kind, issue.reason, *issue.response) + } else { + a.recordIssue(result, issue.kind, issue.reason) + } } - a.unpricedCalls += calls a.revision++ } -func benchmarkQuotaCost(result codex.BenchmarkResult) (float64, bool) { - if result.CostKnown && validBenchmarkQuotaCost(result.CostUSD) { - return result.CostUSD, true +type benchmarkQuotaIssue struct { + kind codex.APIEqIssueKind + reason string + response *codex.BenchmarkResponseUsage +} + +func benchmarkQuotaCostDetail(result codex.BenchmarkResult) (float64, int64, []benchmarkQuotaIssue) { + aggregateIssue := func(kind codex.APIEqIssueKind, reason string) (float64, int64, []benchmarkQuotaIssue) { + return 0, 0, []benchmarkQuotaIssue{{kind: kind, reason: reason}} + } + if result.CostKnown { + if validBenchmarkQuotaCost(result.CostUSD) { + return result.CostUSD, int64(max(len(result.ResponseUsage), 1)), nil + } + return aggregateIssue(codex.UsageIssueInconsistent, "benchmark returned an invalid measured cost") } model := strings.TrimSpace(result.ActualModel) if model == "" { model = result.Model } + var issues []benchmarkQuotaIssue + for i := range result.ResponseUsage { + response := &result.ResponseUsage[i] + if response.UsageIssue != "" { + issues = append(issues, benchmarkQuotaIssue{kind: benchmarkUsageIssueKind(response.UsageIssue), reason: response.UsageIssue, response: response}) + } else if response.UsageMissing { + issues = append(issues, benchmarkQuotaIssue{kind: codex.UsageIssueMissing, reason: "raw response omitted usage", response: response}) + } + } + if len(issues) > 0 { + return 0, 0, issues + } if !result.UsageKnown { - return 0, false + if result.UsageIssue != "" { + return aggregateIssue(benchmarkUsageIssueKind(result.UsageIssue), result.UsageIssue) + } + return aggregateIssue(codex.UsageIssueMissing, "benchmark omitted validated response usage") } if result.UsageSource == codex.BenchmarkUsageRawResponses && len(result.ResponseUsage) > 0 { var total float64 - for _, response := range result.ResponseUsage { - cost, known, _ := codex.EstimateStandardAPIEqCost(model, response.Usage) + var pricedCalls int64 + for i := range result.ResponseUsage { + response := &result.ResponseUsage[i] + responseModel := response.Model + if responseModel == "" { + responseModel = model + } + cost, known, reason := codex.EstimateStandardAPIEqCost(responseModel, response.Usage) if !known { - return 0, false + issues = append(issues, benchmarkQuotaIssue{kind: benchmarkCostIssueKind(reason), reason: reason, response: response}) + continue } total += cost + pricedCalls++ + } + if !validBenchmarkQuotaCost(total) { + return aggregateIssue(codex.UsageIssueInconsistent, "benchmark cost total was not finite") } - return total, validBenchmarkQuotaCost(total) + return total, pricedCalls, issues + } + cost, known, reason := codex.EstimateStandardAPIEqAggregateCost(model, result.Usage) + if !known { + return aggregateIssue(benchmarkCostIssueKind(reason), reason) + } + if !validBenchmarkQuotaCost(cost) { + return aggregateIssue(codex.UsageIssueInconsistent, "benchmark cost total was not finite") + } + return cost, 1, nil +} + +func benchmarkUsageIssueKind(reason string) codex.APIEqIssueKind { + if strings.Contains(reason, "omitted") || strings.Contains(reason, "not observed") { + return codex.UsageIssueMissing + } + return codex.UsageIssueInconsistent +} + +func benchmarkCostIssueKind(reason string) codex.APIEqIssueKind { + if strings.HasPrefix(reason, "invalid usage:") { + return codex.UsageIssueInconsistent + } + return codex.UsageIssueUnpriced +} + +func (a *benchmarkQuotaAccounting) recordIssue(result codex.BenchmarkResult, kind codex.APIEqIssueKind, reason string, responses ...codex.BenchmarkResponseUsage) { + var counter int64 + switch kind { + case codex.UsageIssueMissing: + a.missingCalls++ + counter = a.missingCalls + case codex.UsageIssueInconsistent: + a.inconsistentCalls++ + counter = a.inconsistentCalls + default: + kind = codex.UsageIssueUnpriced + a.unpricedCalls++ + counter = a.unpricedCalls + } + model := result.ActualModel + if model == "" { + model = result.Model + } + responseID := "" + if len(responses) > 0 { + responseID = responses[0].ResponseID + if responses[0].Model != "" { + model = responses[0].Model + } + } + a.diagnostics = append(a.diagnostics, codex.APIEqDiagnostic{Kind: kind, Counter: counter, ObservedAt: time.Now(), At: time.Now(), SessionID: "benchmark", Model: model, Effort: result.Effort, Source: "subscription benchmark", ResponseID: responseID, Reason: reason}) + if len(a.diagnostics) > 32 { + a.diagnostics = a.diagnostics[len(a.diagnostics)-32:] } - cost, known, _ := codex.EstimateStandardAPIEqAggregateCost(model, result.Usage) - return cost, known && validBenchmarkQuotaCost(cost) } func validBenchmarkQuotaCost(cost float64) bool { @@ -134,7 +229,31 @@ func (a benchmarkQuotaAccounting) combine(usage codex.LiveUsageSnapshot) codex.L // Benchmark results remain a standard-price comparison; their service // tier is not established by the benchmark result contract. usage.APIEqUnknownTierCalls += a.pricedCalls + all := append(append([]codex.APIEqDiagnostic(nil), usage.APIEqDiagnostics...), a.diagnostics...) + usage.APIEqMissingUsageCalls += a.missingCalls + usage.APIEqInconsistentUsageCalls += a.inconsistentCalls usage.APIEqUnpricedCalls += a.unpricedCalls + usage.APIEqDiagnostics = nil + for _, kind := range []codex.APIEqIssueKind{codex.UsageIssueUnpriced, codex.UsageIssueMissing, codex.UsageIssueInconsistent} { + var latest codex.APIEqDiagnostic + for _, diagnostic := range all { + if diagnostic.Kind == kind && (latest.Kind == "" || diagnostic.ObservedAt.After(latest.ObservedAt)) { + latest = diagnostic + } + } + if latest.Kind == "" { + continue + } + switch kind { + case codex.UsageIssueMissing: + latest.Counter = usage.APIEqMissingUsageCalls + case codex.UsageIssueInconsistent: + latest.Counter = usage.APIEqInconsistentUsageCalls + default: + latest.Counter = usage.APIEqUnpricedCalls + } + usage.APIEqDiagnostics = append(usage.APIEqDiagnostics, latest) + } if a.active { usage.APIEqPendingCalls++ } diff --git a/internal/ui/benchmark_quota_test.go b/internal/ui/benchmark_quota_test.go index 5075de7..b4ea478 100644 --- a/internal/ui/benchmark_quota_test.go +++ b/internal/ui/benchmark_quota_test.go @@ -55,6 +55,7 @@ func TestSubscriptionBenchmarkAccountingFailsClosedForUnknownCost(t *testing.T) accounting.start() accounting.observe(codex.BenchmarkResult{ TaskID: codex.BenchmarkDigBench, TaskName: "DIGBENCH P-6", Model: "future-model", Effort: "high", + UsageKnown: true, Usage: codex.BenchmarkUsage{InputTokens: 100, OutputTokens: 10, TotalTokens: 110}, }) accounting.finish() combined := accounting.combine(codex.LiveUsageSnapshot{}) @@ -72,7 +73,7 @@ func TestSubscriptionBenchmarkAccountingRejectsInvalidKnownCost(t *testing.T) { }) accounting.finish() combined := accounting.combine(codex.LiveUsageSnapshot{}) - if combined.APIEqUSD != 0 || combined.APIEqPricedCalls != 0 || combined.APIEqUnpricedCalls != 1 { + if combined.APIEqUSD != 0 || combined.APIEqPricedCalls != 0 || combined.APIEqInconsistentUsageCalls != 1 || combined.APIEqUnpricedCalls != 0 { t.Fatalf("invalid known benchmark cost was accepted: %#v", combined) } } @@ -89,7 +90,7 @@ func TestSubscriptionBenchmarkAccountingRejectsUnvalidatedResponseUsage(t *testi }) accounting.finish() combined := accounting.combine(codex.LiveUsageSnapshot{}) - if combined.APIEqUSD != 0 || combined.APIEqPricedCalls != 0 || combined.APIEqUnpricedCalls != 1 { + if combined.APIEqUSD != 0 || combined.APIEqPricedCalls != 0 || combined.APIEqMissingUsageCalls != 1 || combined.APIEqUnpricedCalls != 0 { t.Fatalf("unvalidated response usage was accepted: %#v", combined) } } @@ -115,8 +116,8 @@ func TestSubscriptionBenchmarkAccountingFailsClosedForAbandonedActiveResult(t *t accounting.abandonActiveResult() accounting.finish() combined := accounting.combine(codex.LiveUsageSnapshot{}) - if combined.APIEqUnpricedCalls != 1 || combined.APIEqPricedCalls != 0 || combined.APIEqUSD != 0 { - t.Fatalf("abandoned benchmark result was not marked unpriced: %#v", combined) + if combined.APIEqMissingUsageCalls != 1 || combined.APIEqUnpricedCalls != 0 || combined.APIEqPricedCalls != 0 || combined.APIEqUSD != 0 { + t.Fatalf("abandoned benchmark result was not marked as missing response usage: %#v", combined) } } @@ -249,3 +250,81 @@ func TestSubscriptionBenchmarkRerunIsAccountedAgain(t *testing.T) { t.Fatalf("rerun accounting = %#v", combined) } } + +func TestBenchmarkDiagnosticDoesNotMaskNewerSessionFailure(t *testing.T) { + a := benchmarkQuotaAccounting{billingSource: codex.BenchmarkBillingSubscription} + a.start() + a.observe(codex.BenchmarkResult{Model: "unknown-benchmark", UsageKnown: true, Usage: codex.BenchmarkUsage{InputTokens: 100, OutputTokens: 10, TotalTokens: 110}}) + old := a.diagnostics[0].ObservedAt + current := codex.APIEqDiagnostic{Kind: codex.UsageIssueUnpriced, Counter: 1, Model: "unknown-live", SessionID: "live", Source: "exact response", ObservedAt: old.Add(time.Second)} + combined := a.combine(codex.LiveUsageSnapshot{APIEqUnpricedCalls: 1, APIEqDiagnostics: []codex.APIEqDiagnostic{current}}) + if len(combined.APIEqDiagnostics) != 1 || combined.APIEqDiagnostics[0].Model != "unknown-live" || combined.APIEqDiagnostics[0].Counter != 2 { + t.Fatal("stale benchmark masked live failure", combined) + } +} + +func TestBenchmarkFailureIdentifiesEarlierResponseModelAndCancellationTrial(t *testing.T) { + a := benchmarkQuotaAccounting{billingSource: codex.BenchmarkBillingSubscription} + a.start() + usage := codex.BenchmarkUsage{InputTokens: 100, OutputTokens: 10, TotalTokens: 110} + a.observe(codex.BenchmarkResult{Model: "gpt-6-astra", ActualModel: "gpt-6-astra", Effort: "xhigh", UsageKnown: true, UsageSource: codex.BenchmarkUsageRawResponses, ResponseUsage: []codex.BenchmarkResponseUsage{{ResponseID: "failed", Model: "gpt-reserve", Usage: usage}, {ResponseID: "later", Model: "gpt-6-astra", Usage: usage}}}) + issue := a.diagnostics[len(a.diagnostics)-1] + if issue.Model != "gpt-reserve" || issue.ResponseID != "failed" || a.unpricedCalls != 1 || len(a.diagnostics) != 1 || a.pricedCalls != 1 { + t.Fatal("failure attributed to final model rather than offending response", issue) + } + a.abandonActiveResult(codex.BenchmarkResult{Model: "gpt-6-astra", Effort: "xhigh"}) + issue = a.diagnostics[len(a.diagnostics)-1] + if issue.Kind != codex.UsageIssueMissing || issue.Model != "gpt-6-astra" || issue.Effort != "xhigh" { + t.Fatal("cancellation lost known trial metadata", issue) + } +} + +func TestBenchmarkMissingUsageDiagnosticIdentifiesOriginatingResponse(t *testing.T) { + a := benchmarkQuotaAccounting{billingSource: codex.BenchmarkBillingSubscription} + a.start() + usage := codex.BenchmarkUsage{InputTokens: 100, OutputTokens: 10, TotalTokens: 110} + result := codex.BenchmarkResult{Model: "gpt-6-astra", ActualModel: "gpt-6-astra", UsageSource: codex.BenchmarkUsageRawResponses, UsageIssue: "raw response omitted usage", ResponseUsage: []codex.BenchmarkResponseUsage{ + {ResponseID: "missing", Model: "gpt-reserve", UsageMissing: true, UsageIssue: "raw response omitted usage"}, + {ResponseID: "later", Model: "gpt-6-astra", Usage: usage}, + }} + a.observe(result) + a.observe(result) + if a.missingCalls != 1 || a.unpricedCalls != 0 || a.pricedCalls != 0 || a.costUSD != 0 || len(a.diagnostics) != 1 { + t.Fatal("missing response inflated counters or priced incomplete telemetry", a) + } + issue := a.diagnostics[0] + if issue.Kind != codex.UsageIssueMissing || issue.Model != "gpt-reserve" || issue.ResponseID != "missing" { + t.Fatal("missing benchmark attributed to final response", issue) + } +} + +func TestBenchmarkAccountingReportsOnlyFailingResponses(t *testing.T) { + a := benchmarkQuotaAccounting{billingSource: codex.BenchmarkBillingSubscription} + a.start() + usage := codex.BenchmarkUsage{InputTokens: 100, OutputTokens: 10, TotalTokens: 110} + a.observe(codex.BenchmarkResult{Model: "gpt-6-astra", UsageKnown: true, UsageSource: codex.BenchmarkUsageRawResponses, ResponseUsage: []codex.BenchmarkResponseUsage{ + {ResponseID: "unknown", Model: "gpt-reserve", Usage: usage}, + {ResponseID: "known", Model: "gpt-6-astra", Usage: usage}, + {ResponseID: "another-unknown", Model: "unknown-provider", Usage: usage}, + }}) + want, _, _ := codex.EstimateStandardAPIEqCost("gpt-6-astra", usage) + if a.unpricedCalls != 2 || a.pricedCalls != 1 || math.Abs(a.costUSD-want) > 1e-12 || len(a.diagnostics) != 2 || a.diagnostics[0].ResponseID != "unknown" || a.diagnostics[1].ResponseID != "another-unknown" || a.diagnostics[1].Model != "unknown-provider" { + t.Fatal("mixed responses duplicated failures or discarded known cost", a) + } +} + +func TestBenchmarkAggregateFailureIsRecordedOnce(t *testing.T) { + for _, invalidMeasuredCost := range []bool{false, true} { + a := benchmarkQuotaAccounting{billingSource: codex.BenchmarkBillingSubscription} + a.start() + result := codex.BenchmarkResult{Model: "gpt-6-astra", UsageIssue: "invalid raw response total: totalTokens overflowed", ResponseUsage: []codex.BenchmarkResponseUsage{{ResponseID: "one"}, {ResponseID: "two"}}} + if invalidMeasuredCost { + result.CostKnown = true + result.CostUSD = math.Inf(1) + } + a.observe(result) + if a.inconsistentCalls != 1 || len(a.diagnostics) != 1 || a.diagnostics[0].ResponseID != "" || a.pricedCalls != 0 || a.costUSD != 0 { + t.Fatal("aggregate failure attributed to each response", a) + } + } +} diff --git a/internal/ui/english_snapshot_test.go b/internal/ui/english_snapshot_test.go index bfab44d..0c93121 100644 --- a/internal/ui/english_snapshot_test.go +++ b/internal/ui/english_snapshot_test.go @@ -38,8 +38,8 @@ func TestEnglishPresentationSnapshot(t *testing.T) { got := fmt.Sprintf("%x", hash.Sum(nil)) // Baseline includes Pace graph controls, explicit panel/border // backgrounds and Sessions Zero/Close All; every theme, view and size - // remains covered. - const want = "19ec27af5176579e3145b5af72749d86f293f9ab00e7d3358970eeee0b513e50" + // remains covered. The displayed pricing review date is now 2026-10-12. + const want = "fc7b2b5381dd43bac332748c9fca6ac4c53abfacb130bfa49de64e76fe27f4ba" if got != want { t.Fatalf("English presentation changed: got %s, want %s", got, want) } diff --git a/internal/ui/model.go b/internal/ui/model.go index 0c31655..5c6585b 100644 --- a/internal/ui/model.go +++ b/internal/ui/model.go @@ -1224,7 +1224,7 @@ func (m Model) Update(message tea.Msg) (tea.Model, tea.Cmd) { case benchmarkEventMsg: if !message.ok { if m.benchmarkActive != nil { - m.benchmarkQuotaAccounting.abandonActiveResult() + m.benchmarkQuotaAccounting.abandonActiveResult(*m.benchmarkActive) } if m.benchmarkState == benchmarkStopping { m.benchmarkState = benchmarkStopped @@ -1288,7 +1288,7 @@ func (m Model) Update(message tea.Msg) (tea.Model, tea.Cmd) { } if event.Done { if m.benchmarkActive != nil && event.Result == nil { - m.benchmarkQuotaAccounting.abandonActiveResult() + m.benchmarkQuotaAccounting.abandonActiveResult(*m.benchmarkActive) } if event.Stopped { m.benchmarkState = benchmarkStopped @@ -1620,6 +1620,7 @@ func (m Model) dashboardLayout() dashboardGeometry { const footerHeight = 2 extraHeight := 0 extraHeight += m.resetNoticeHeight(contentWidth) + extraHeight += m.quotaAPIDiagnosticHeight(contentWidth) if m.err != nil && m.meterView != viewUsage { extraHeight += framedErrorHeight } diff --git a/internal/ui/quota_api_eq.go b/internal/ui/quota_api_eq.go index 2464bea..0470c7e 100644 --- a/internal/ui/quota_api_eq.go +++ b/internal/ui/quota_api_eq.go @@ -60,6 +60,7 @@ type quotaAPIAnchor struct { inconsistentUsageCalls int64 accountingAdjustments int64 restartReason string + restartIssue codex.APIEqDiagnostic } const ( @@ -144,7 +145,7 @@ func (m *Model) observeQuotaAPIEq(snapshot codex.Snapshot, usage codex.LiveUsage continue } if current.costUSD < anchor.costUSD || current.pricedCalls < anchor.pricedCalls || - current.unpricedCalls < anchor.unpricedCalls || current.premiumUSD < anchor.premiumUSD || + current.unpricedCalls < anchor.unpricedCalls || current.unknownTierCalls < anchor.unknownTierCalls || current.missingUsageCalls < anchor.missingUsageCalls || current.inconsistentUsageCalls < anchor.inconsistentUsageCalls || @@ -164,6 +165,7 @@ func (m *Model) observeQuotaAPIEq(snapshot codex.Snapshot, usage codex.LiveUsage } if current.unpricedCalls > anchor.unpricedCalls { current.restartReason = quotaAPIRestartUnpricedUsage + current.restartIssue = latestIntervalDiagnostic(usage, codex.UsageIssueUnpriced, anchor.unpricedCalls) m.quotaAPIAnchors[key] = current m.quotaAPIIssues[key] = "" continue @@ -171,8 +173,10 @@ func (m *Model) observeQuotaAPIEq(snapshot codex.Snapshot, usage codex.LiveUsage switch { case current.missingUsageCalls > anchor.missingUsageCalls: current.restartReason = quotaAPIRestartMissingUsage + current.restartIssue = latestIntervalDiagnostic(usage, codex.UsageIssueMissing, anchor.missingUsageCalls) case current.inconsistentUsageCalls > anchor.inconsistentUsageCalls: current.restartReason = quotaAPIRestartInconsistentUsage + current.restartIssue = latestIntervalDiagnostic(usage, codex.UsageIssueInconsistent, anchor.inconsistentUsageCalls) case current.accountingAdjustments > anchor.accountingAdjustments: current.restartReason = quotaAPIRestartAccountingRebased } @@ -272,7 +276,7 @@ func validQuotaAPISamples(samples []quotaAPISample, now time.Time) []quotaAPISam sample.DeltaPercent < quotaAPIMinimumDelta || !positiveFinite(sample.CapacityUSD) || !positiveFinite(sample.LowUSD) || !positiveFinite(sample.HighUSD) || math.IsNaN(sample.PremiumCapacityUSD) || math.IsInf(sample.PremiumCapacityUSD, 0) || - sample.PremiumCapacityUSD < 0 || sample.PremiumCapacityUSD >= sample.CapacityUSD || + sample.PremiumCapacityUSD >= sample.CapacityUSD || sample.LowUSD > sample.CapacityUSD || sample.CapacityUSD > sample.HighUSD { continue } @@ -329,7 +333,7 @@ func (m Model) quotaAPIEstimate(snapshot codex.Snapshot, meter codex.Meter) (quo highs = append(highs, sample.HighUSD) centers = append(centers, sample.CapacityUSD) standardCenters = append(standardCenters, sample.CapacityUSD-sample.PremiumCapacityUSD) - hasPremium = hasPremium || sample.PremiumCapacityUSD > 0 + hasPremium = hasPremium || sample.PremiumCapacityUSD != 0 unknownTier = unknownTier || sample.UnknownTier totalDelta += sample.DeltaPercent } @@ -515,3 +519,74 @@ func formatUSD(value float64) string { return fmt.Sprintf("$%.0f", value) } } + +func latestIntervalDiagnostic(usage codex.LiveUsageSnapshot, kind codex.APIEqIssueKind, after int64) codex.APIEqDiagnostic { + for i := len(usage.APIEqDiagnostics) - 1; i >= 0; i-- { + issue := usage.APIEqDiagnostics[i] + if issue.Kind == kind && issue.Counter > after { + return issue + } + } + return codex.APIEqDiagnostic{} +} + +func (m Model) quotaAPIDiagnostic() codex.APIEqDiagnostic { + if !m.meterView.isQuota() { + return codex.APIEqDiagnostic{} + } + for _, meter := range m.snapshot.Meters() { + if quotaAPIMeterEligible(m.snapshot, meter) { + if issue := m.quotaAPIAnchors[quotaAPIKey(m.snapshot, meter)].restartIssue; issue.Kind != "" { + return issue + } + } + } + return codex.APIEqDiagnostic{} +} + +func (m Model) renderQuotaAPIDiagnostic(width int) string { + issue := m.quotaAPIDiagnostic() + if issue.Kind == "" { + return "" + } + c := paletteFor(m.theme) + text := codex.DiagnosticText(issue) + lines := strings.Split(ansi.Hardwrap(text, max(width-4, 1), true), "\n") + // A diagnostic must not push the footer off a short terminal. Preserve the + // reason first, with bounded metadata rows; the browser retains the full text. + height := m.height + if height == 0 { + height = 24 + } + header := 3 + if width < 64 { + header = 2 + } + tabs := 2 + if isQuotaGraph(m.meterView) { + tabs++ + } + meters := len(m.snapshot.Meters()) + columns := meterGridColumns(width, max(height-2, 1), meters, m.meterView) + minimumMeters := ((meters + columns - 1) / columns) * 3 + available := height - 2 - header - 1 - tabs - 2 - minimumMeters - m.resetNoticeHeight(width) + if m.err != nil { + available -= 3 + } + if available < 3 { + return "" + } + limit := min(max(height/3-2, 1), available-2) + if len(lines) > limit { + lines = lines[:limit] + lines[len(lines)-1] = ansi.Truncate(lines[len(lines)-1], max(width-5, 1), "") + "…" + } + return frame(width, "API-EQ ISSUE", c.label().Render(strings.Join(lines, "\n")), c.primary, c) +} + +func (m Model) quotaAPIDiagnosticHeight(width int) int { + if view := m.renderQuotaAPIDiagnostic(width); view != "" { + return strings.Count(view, "\n") + 1 + } + return 0 +} diff --git a/internal/ui/quota_api_eq_test.go b/internal/ui/quota_api_eq_test.go index 883f559..4916e2b 100644 --- a/internal/ui/quota_api_eq_test.go +++ b/internal/ui/quota_api_eq_test.go @@ -433,3 +433,63 @@ func TestQuotaAccountingBracketIncludesUsageIssuesAndAdjustments(t *testing.T) { } } } + +func TestQuotaFlexDiscountLearnsWithoutFalseRebase(t *testing.T) { + now := time.Now() + reset := now.Add(4 * time.Hour).Unix() + m := New(nil, time.Minute) + m.snapshot = apiEqSnapshot(10, reset) + m.observeQuotaAPIEq(m.snapshot, codex.LiveUsageSnapshot{}, now) + m.snapshot = apiEqSnapshot(15, reset) + m.observeQuotaAPIEq(m.snapshot, codex.LiveUsageSnapshot{APIEqUSD: 2, APIEqTierPremiumUSD: -1, APIEqPricedCalls: 1}, now.Add(time.Minute)) + estimate, ok := m.quotaAPIEstimate(m.snapshot, m.snapshot.Meters()[0]) + if !ok || !estimate.hasPremium || math.Abs(estimate.standardFull-40) > 1e-12 { + t.Fatal("discount mistaken for accounting regression", m.quotaAPIAnchors, estimate) + } + if !strings.Contains(m.quotaAPILine(m.snapshot.Meters()[0], 120), "TIER*") { + t.Fatal("discount lost requested-tier qualifier") + } +} + +func TestQuotaFailureDiagnosticRetainsSourceAndRejectsOldAttribution(t *testing.T) { + now := time.Now() + reset := now.Add(4 * time.Hour).Unix() + m := New(nil, time.Minute) + m.width, m.height = 100, 35 + m.loading = false + m.snapshot = apiEqSnapshot(10, reset) + m.observeQuotaAPIEq(m.snapshot, codex.LiveUsageSnapshot{APIEqUnpricedCalls: 1}, now) + m.snapshot = apiEqSnapshot(12, reset) + issue := codex.APIEqDiagnostic{Kind: codex.UsageIssueUnpriced, Counter: 2, SessionID: "child-agent", Model: "gpt-reserve", Tier: "fast", Effort: "xhigh", Source: "exact response", Reason: "no maintained standard API price for model gpt-reserve"} + m.observeQuotaAPIEq(m.snapshot, codex.LiveUsageSnapshot{APIEqUnpricedCalls: 2, APIEqDiagnostics: []codex.APIEqDiagnostic{issue}}, now.Add(time.Minute)) + view := ansi.Strip(m.render()) + for _, want := range []string{"UNPRICED USAGE", "child-agent", "gpt-reserve", "fast", "xhigh", "exact response", "no maintained standard API price"} { + if !strings.Contains(view, want) { + t.Fatal("diagnostic omitted", want, view) + } + } + m.snapshot = apiEqSnapshot(13, reset) + m.observeQuotaAPIEq(m.snapshot, codex.LiveUsageSnapshot{APIEqUnpricedCalls: 3, APIEqDiagnostics: []codex.APIEqDiagnostic{issue}}, now.Add(2*time.Minute)) + if m.quotaAPIDiagnostic().Kind != "" { + t.Fatal("old diagnostic assigned to a new failure") + } +} + +func TestQuotaDiagnosticPreservesFooterAcrossTerminalSizes(t *testing.T) { + now := time.Now() + reset := now.Add(time.Hour).Unix() + for _, size := range [][2]int{{40, 16}, {80, 18}, {80, 24}, {120, 35}} { + m := New(nil, time.Minute) + m.width, m.height = size[0], size[1] + m.loading = false + m.snapshot = apiEqSnapshot(10, reset) + m.observeQuotaAPIEq(m.snapshot, codex.LiveUsageSnapshot{}, now) + m.snapshot = apiEqSnapshot(12, reset) + issue := codex.APIEqDiagnostic{Kind: codex.UsageIssueUnpriced, Counter: 1, SessionID: "child", Model: "gpt-reserve", Tier: "fast", Source: "exact response", Reason: "no maintained standard API price for model gpt-reserve"} + m.observeQuotaAPIEq(m.snapshot, codex.LiveUsageSnapshot{APIEqUnpricedCalls: 1, APIEqDiagnostics: []codex.APIEqDiagnostic{issue}}, now.Add(time.Second)) + view := ansi.Strip(m.render()) + if strings.Count(view, "\n")+1 > size[1] { + t.Fatal("diagnostic pushed controls off screen", size, view) + } + } +} diff --git a/internal/ui/view.go b/internal/ui/view.go index 4406add..f1d4fd3 100644 --- a/internal/ui/view.go +++ b/internal/ui/view.go @@ -67,6 +67,9 @@ func (m Model) render() string { if m.meterView.isQuota() && m.resetNotice != "" { parts = append(parts, m.renderResetNotice(contentWidth)) } + if diagnostic := m.renderQuotaAPIDiagnostic(contentWidth); diagnostic != "" { + parts = append(parts, diagnostic) + } meters := m.snapshot.Meters() if m.meterView.isQuota() && m.meterView != viewResets && m.meterView != viewThresholds { meters = m.quotaMetersWithInsights(contentWidth) diff --git a/internal/web/dist/assets/index-Bd-Jwk4i.js b/internal/web/dist/assets/index-BWH3mrUB.js similarity index 77% rename from internal/web/dist/assets/index-Bd-Jwk4i.js rename to internal/web/dist/assets/index-BWH3mrUB.js index ea7c245..96305c6 100644 --- a/internal/web/dist/assets/index-Bd-Jwk4i.js +++ b/internal/web/dist/assets/index-BWH3mrUB.js @@ -5,41 +5,42 @@ observation.
`),xa=J(`
The longest Codex quota window selects one active model profile. ASK creates a per-session review; AUTO applies the profile on the next eligible check.
No threshold-based model steps were configured at launch.
`);function wa(e,t){Ue(t,!1),Ri();var n=Nr(),r=B(n),i=e=>{var t=Sa(),n=B(t),r=V(n),i=H(n,2),a=e=>{Y(e,ba())};Z(i,e=>{$.data.quotaError&&e(a)});var o=H(i,2),s=z(o),c=V(s),l=H(s,4);Xr(l,5,()=>$.data.thresholds,Kr,(e,t)=>{var n=xa();let r;var i=z(n),a=V(i),o=H(i,2),s=z(o),c=V(s,!0),l=V(H(s,2));P(o);var u=H(o,2),d=V(u,!0),f=V(H(u,2));P(n),U((e,i)=>{r=ci(n,1,``,null,r,{active:K(t).state===`ACTIVE`,next:K(t).state===`NEXT`}),X(a,`${K(t).threshold??``}%`),X(c,K(t).model),X(l,`${e??``} REASONING // ${i??``} - SPEED`),X(d,K(t).mode),X(f,`${K(t).state??``}${K(t).state===`NEXT`?` // ${K(t).remaining||0} PP TO GO`:``}`)},[()=>K(t).effort.toUpperCase(),()=>K(t).speed.toUpperCase()]),Y(e,n)}),P(l),P(o),U(e=>{X(r,`MODEL STEP POLICY // OBSERVED ${e??``}`),X(c,`THRESHOLDS // ${$.data.thresholds.length??``} CONFIGURED`)},[()=>ma($.data.quotaAt)]),Y(e,t)},a=e=>{Y(e,Ca())};Z(r,e=>{$.data?.thresholds?.length?e(i):e(a,-1)}),Y(e,n),We()}var Ta=jr(`| Observed at | Period elapsed | Consumed | Trail segment |
|---|
Quota refresh failed. Values below are the last successful observation.
`),La=J(`Expiry details unavailable. No listed expiry does not mean no expiry.
`),Ra=J(`
Read-only preview. Use the terminal to redeem a reset.
The backend may return only some credits. This list does not establish - redemption order.
Cycle duration or reset date unavailable — position cannot be - plotted.
`),Ga=J(`
`),Ya=J(`
No quota windows reported yet.
`),Za=J(` `,1),Qa=J(`
All reported windows are shown. API-equivalent learning and quota status - scoring remain in the terminal for this first preview.
`,1),$a=J(` `,1);function eo(e,t){Ue(t,!0);let n=Wi(t,`params`,19,()=>({})),r=F(()=>ea.filter(e=>e!==`thresholds`||!!$.data?.thresholds?.length)),i=L(Yt(Date.now())),a=F(()=>K(r).includes(ta(n().view))?ta(n().view):`bars`);Gi(()=>{let e=setInterval(()=>R(i,Date.now(),!0),1e3);return()=>clearInterval(e)});function o(e){return!e.duration||e.duration<=0||!e.reset?null:Math.max(0,Math.min(100,100*(1-(e.reset*1e3-K(i))/(e.duration*6e4))))}vn(()=>{aa.view=K(a),(n().view===`zone`||n().view===`consumption-pace`)&&Zi(`/quota/pace`)});function s(e){let t=e/100*Math.PI*2;return`M60 60 L60 14 A46 46 0 ${+(e>50)} 1 ${60+46*Math.sin(t)} ${60-46*Math.cos(t)} Z`}var c=$a(),l=B(c);Xr(l,21,()=>K(r),Kr,(e,t)=>{var n=Fa();let r;var i=V(n,!0);U(e=>{Q(n,`href`,`#/quota/`+K(t)),Q(n,`aria-current`,K(a)===K(t)?`page`:void 0),r=ci(n,1,``,null,r,{active:K(a)===K(t)}),X(i,e)},[()=>K(t)===`fuel`?`FUEL TANK`:K(t).toUpperCase()]),Y(e,n)}),P(l);var u=H(l,2),d=e=>{var t=Qa(),n=B(t),r=e=>{Y(e,Ia())};Z(n,e=>{$.data.quotaError&&e(r)});var i=H(n,2),c=V(i),l=H(i,2),u=e=>{wa(e,{})},d=e=>{var t=za(),n=z(t),r=V(n),i=H(n,4),a=e=>{Y(e,La())};Z(i,e=>{$.data.credits.length||e(a)}),Xr(H(i,2),17,()=>$.data.credits,Kr,(e,t)=>{var n=Ra(),r=z(n),i=V(r),a=V(H(r,2),!0);P(n),U(e=>{X(i,`${(K(t).title||`Quota reset`)??``} // ${K(t).status??``}`),X(a,e)},[()=>K(t).expiryKnown?K(t).expires?`EXPIRES `+ma(K(t).expires):`Does not expire`:`Expiry information unavailable`]),Y(e,n)}),xe(2),P(t),U(()=>X(r,`RESET INVENTORY // ${$.data.creditCount??``} AVAILABLE`)),Y(e,t)},f=e=>{var t=Za(),n=B(t);let r;Xr(n,21,()=>$.data.meters,Kr,(e,t)=>{let n=F(()=>o(K(t)));var r=Ya(),i=z(r),c=V(i,!0),l=H(i,2),u=z(l),d=e=>{var n=Ba(),r=B(n),i=V(r),a=V(H(r));U(()=>{X(i,`FREE ${100-K(t).used}%`),X(a,`USED ${K(t).used??``}%`)}),Y(e,n)},f=e=>{var n=Ba(),r=B(n),i=V(r),a=V(H(r));U(()=>{X(i,`USED ${K(t).used??``}%`),X(a,`FREE ${100-K(t).used}%`)}),Y(e,n)};Z(u,e=>{K(a)===`fuel`?e(d):e(f,-1)}),P(l);var p=H(l,2);let m;var h=z(p),g=e=>{var n=Ua(),r=z(n),i=H(z(r)),a=e=>{Y(e,Va())},o=e=>{var n=Ha();U(e=>Q(n,`d`,e),[()=>s(K(t).used)]),Y(e,n)};Z(i,e=>{K(t).used>=100?e(a):K(t).used>0&&e(o,1)}),P(r),P(n),U(()=>Q(r,`aria-label`,`${K(t).used}% quota used`)),Y(e,n)},_=e=>{var r=Nr(),i=B(r),a=e=>{{let r=F(()=>K(t).trail||[]);Pa(e,{get used(){return K(t).used},get elapsed(){return K(n)},get trail(){return K(r)},get duration(){return K(t).duration}})}},o=e=>{Y(e,Wa())};Z(i,e=>{K(n)===null?e(o,-1):e(a)}),Y(e,r)},v=e=>{var r=qa(),i=B(r),o=z(i);let s;P(i);var c=H(i,2),l=e=>{Y(e,Ga())};Z(c,e=>{K(a)===`fuel`&&e(l)});var u=H(c,2),d=e=>{var t=Ka(),r=B(t),i=V(r),o=H(r,2),s=z(o);let c;P(o),U(e=>{X(i,`RESET CYCLE // ${e??``}% ELAPSED`),c=ui(s,``,c,{width:`${K(a)===`fuel`?100-K(n):K(n)}%`})},[()=>Math.floor(K(n))]),Y(e,t)};Z(u,e=>{K(n)!==null&&e(d)}),U(()=>{Q(i,`aria-label`,K(a)===`fuel`?`Fuel remaining`:`Quota used`),Q(i,`aria-valuenow`,K(a)===`fuel`?100-K(t).used:K(t).used),s=ui(o,``,s,{width:`${K(a)===`fuel`?100-K(t).used:K(t).used}%`})}),Y(e,r)};Z(h,e=>{K(a)===`pie`?e(g):K(a)===`pace`?e(_,1):e(v,-1)}),P(p);var y=H(p,2),b=V(y),x=H(y,2),S=e=>{var n=Ja(),r=V(n,!0);U(()=>X(r,K(t).details)),Y(e,n)};Z(x,e=>{K(t).details&&e(S)}),P(r),U(e=>{X(c,K(t).name),m=ci(p,1,`meter-graphic`,null,m,{"bar-graphic":K(a)===`bars`||K(a)===`fuel`}),X(b,`RESETS // ${e??``}`)},[()=>ma(K(t).reset)]),Y(e,r)}),P(n);var i=H(n,2),c=e=>{Y(e,Xa())};Z(i,e=>{$.data.meters.length||e(c)}),U(()=>r=ci(n,1,`quota-grid`,null,r,{radial:K(a)===`pie`,zone:K(a)===`pace`})),Y(e,t)};Z(l,e=>{K(a)===`thresholds`?e(u):K(a)===`resets`?e(d,1):e(f,-1)}),xe(2),U(e=>X(c,`QUOTA // OBSERVED ${e??``}`),[()=>ma($.data.quotaAt)]),Y(e,t)};Z(u,e=>{$.data&&e(d)}),Y(e,c),We()}var to=J(``),no=J(``,1);function ro(e,t){Ue(t,!0);let n=Wi(t,`values`,19,()=>[]),r=Wi(t,`label`,3,`Token activity`),i=Wi(t,`capacity`,3,0),a=F(()=>Math.max(0,...n())),o=F(()=>i()>n().length?[...Array(i()-n().length).fill(0),...n()]:n());var s=no(),c=B(s),l=V(c),u=H(c,2);Xr(u,21,()=>K(o),Kr,(e,t)=>{var n=to();let r;U((e,t)=>{Q(n,`title`,e),r=ui(n,``,r,{height:t})},[()=>K(t).toLocaleString(`en-GB`)+` tokens`,()=>`${100*K(t)/Math.max(1,K(a))}%`]),Y(e,n)}),P(u),U((e,t)=>{X(l,`SCALE // 0 — ${e??``} TOKENS`),Q(u,`aria-label`,t)},[()=>K(a).toLocaleString(`en-GB`),()=>`${r()}. Peak ${K(a).toLocaleString(`en-GB`)} tokens.`]),Y(e,s),We()}function io(e){if(!e||![`LAST REPLY`,`LAST ACTIVITY`].includes(e.contextKind))return``;let t=e.text||e.contextKind===`LAST ACTIVITY`&&e.workingCommand||``;return t.trim()?t:``}var ao=J(` `),oo=J(``),so=J(`
`),co=J(`
`,1),lo=J(`
`),uo=J(`
Loading / sending…
`),fo=J(``),po=J(``),mo=J(`
Review expired. Press Enter to review again.
`),vo=J(``,1),yo=J(`
`,1),bo=J(`
No available matching commands.
`),xo=J(` `,1),So=J(``),Co=J(`
Review expired. Review the option again.
`),wo=J(``),To=J(``),Eo=J(``),Do=J(``),Oo=J(``),ko=J(``),Ao=J(``),jo=J(`| Observed at | Period elapsed | Consumed | Trail segment |
|---|
Quota refresh failed. Values below are the last successful observation.
`),La=J(``),Ra=J(`
Expiry details unavailable. No listed expiry does not mean no expiry.
`),za=J(`
Read-only preview. Use the terminal to redeem a reset.
The backend may return only some credits. This list does not establish + redemption order.
Cycle duration or reset date unavailable — position cannot be + plotted.
`),Ka=J(`
`),Xa=J(`
No quota windows reported yet.
`),Qa=J(` `,1),$a=J(`
All reported windows are shown. API-equivalent learning and quota status + scoring remain in the terminal for this first preview.
`,1),eo=J(` `,1);function to(e,t){Ue(t,!0);let n=Wi(t,`params`,19,()=>({})),r=F(()=>ea.filter(e=>e!==`thresholds`||!!$.data?.thresholds?.length)),i=L(Yt(Date.now())),a=F(()=>K(r).includes(ta(n().view))?ta(n().view):`bars`);Gi(()=>{let e=setInterval(()=>R(i,Date.now(),!0),1e3);return()=>clearInterval(e)});function o(e){return!e.duration||e.duration<=0||!e.reset?null:Math.max(0,Math.min(100,100*(1-(e.reset*1e3-K(i))/(e.duration*6e4))))}vn(()=>{aa.view=K(a),(n().view===`zone`||n().view===`consumption-pace`)&&Zi(`/quota/pace`)});function s(e){let t=e/100*Math.PI*2;return`M60 60 L60 14 A46 46 0 ${+(e>50)} 1 ${60+46*Math.sin(t)} ${60-46*Math.cos(t)} Z`}var c=eo(),l=B(c);Xr(l,21,()=>K(r),Kr,(e,t)=>{var n=Fa();let r;var i=V(n,!0);U(e=>{Q(n,`href`,`#/quota/`+K(t)),Q(n,`aria-current`,K(a)===K(t)?`page`:void 0),r=ci(n,1,``,null,r,{active:K(a)===K(t)}),X(i,e)},[()=>K(t)===`fuel`?`FUEL TANK`:K(t).toUpperCase()]),Y(e,n)}),P(l);var u=H(l,2),d=e=>{var t=$a(),n=B(t),r=e=>{Y(e,Ia())};Z(n,e=>{$.data.quotaError&&e(r)});var i=H(n,2),c=e=>{var t=La(),n=V(t);U(()=>X(n,`Last usage accounting issue: + ${$.data.usageDiagnostic??``}`)),Y(e,t)};Z(i,e=>{$.data.usageDiagnostic&&e(c)});var l=H(i,2),u=V(l),d=H(l,2),f=e=>{wa(e,{})},p=e=>{var t=Ba(),n=z(t),r=V(n),i=H(n,4),a=e=>{Y(e,Ra())};Z(i,e=>{$.data.credits.length||e(a)}),Xr(H(i,2),17,()=>$.data.credits,Kr,(e,t)=>{var n=za(),r=z(n),i=V(r),a=V(H(r,2),!0);P(n),U(e=>{X(i,`${(K(t).title||`Quota reset`)??``} // ${K(t).status??``}`),X(a,e)},[()=>K(t).expiryKnown?K(t).expires?`EXPIRES `+ma(K(t).expires):`Does not expire`:`Expiry information unavailable`]),Y(e,n)}),xe(2),P(t),U(()=>X(r,`RESET INVENTORY // ${$.data.creditCount??``} AVAILABLE`)),Y(e,t)},m=e=>{var t=Qa(),n=B(t);let r;Xr(n,21,()=>$.data.meters,Kr,(e,t)=>{let n=F(()=>o(K(t)));var r=Xa(),i=z(r),c=V(i,!0),l=H(i,2),u=z(l),d=e=>{var n=Va(),r=B(n),i=V(r),a=V(H(r));U(()=>{X(i,`FREE ${100-K(t).used}%`),X(a,`USED ${K(t).used??``}%`)}),Y(e,n)},f=e=>{var n=Va(),r=B(n),i=V(r),a=V(H(r));U(()=>{X(i,`USED ${K(t).used??``}%`),X(a,`FREE ${100-K(t).used}%`)}),Y(e,n)};Z(u,e=>{K(a)===`fuel`?e(d):e(f,-1)}),P(l);var p=H(l,2);let m;var h=z(p),g=e=>{var n=Wa(),r=z(n),i=H(z(r)),a=e=>{Y(e,Ha())},o=e=>{var n=Ua();U(e=>Q(n,`d`,e),[()=>s(K(t).used)]),Y(e,n)};Z(i,e=>{K(t).used>=100?e(a):K(t).used>0&&e(o,1)}),P(r),P(n),U(()=>Q(r,`aria-label`,`${K(t).used}% quota used`)),Y(e,n)},_=e=>{var r=Nr(),i=B(r),a=e=>{{let r=F(()=>K(t).trail||[]);Pa(e,{get used(){return K(t).used},get elapsed(){return K(n)},get trail(){return K(r)},get duration(){return K(t).duration}})}},o=e=>{Y(e,Ga())};Z(i,e=>{K(n)===null?e(o,-1):e(a)}),Y(e,r)},v=e=>{var r=Ja(),i=B(r),o=z(i);let s;P(i);var c=H(i,2),l=e=>{Y(e,Ka())};Z(c,e=>{K(a)===`fuel`&&e(l)});var u=H(c,2),d=e=>{var t=qa(),r=B(t),i=V(r),o=H(r,2),s=z(o);let c;P(o),U(e=>{X(i,`RESET CYCLE // ${e??``}% ELAPSED`),c=ui(s,``,c,{width:`${K(a)===`fuel`?100-K(n):K(n)}%`})},[()=>Math.floor(K(n))]),Y(e,t)};Z(u,e=>{K(n)!==null&&e(d)}),U(()=>{Q(i,`aria-label`,K(a)===`fuel`?`Fuel remaining`:`Quota used`),Q(i,`aria-valuenow`,K(a)===`fuel`?100-K(t).used:K(t).used),s=ui(o,``,s,{width:`${K(a)===`fuel`?100-K(t).used:K(t).used}%`})}),Y(e,r)};Z(h,e=>{K(a)===`pie`?e(g):K(a)===`pace`?e(_,1):e(v,-1)}),P(p);var y=H(p,2),b=V(y),x=H(y,2),S=e=>{var n=Ya(),r=V(n,!0);U(()=>X(r,K(t).details)),Y(e,n)};Z(x,e=>{K(t).details&&e(S)}),P(r),U(e=>{X(c,K(t).name),m=ci(p,1,`meter-graphic`,null,m,{"bar-graphic":K(a)===`bars`||K(a)===`fuel`}),X(b,`RESETS // ${e??``}`)},[()=>ma(K(t).reset)]),Y(e,r)}),P(n);var i=H(n,2),c=e=>{Y(e,Za())};Z(i,e=>{$.data.meters.length||e(c)}),U(()=>r=ci(n,1,`quota-grid`,null,r,{radial:K(a)===`pie`,zone:K(a)===`pace`})),Y(e,t)};Z(d,e=>{K(a)===`thresholds`?e(f):K(a)===`resets`?e(p,1):e(m,-1)}),xe(2),U(e=>X(u,`QUOTA // OBSERVED ${e??``}`),[()=>ma($.data.quotaAt)]),Y(e,t)};Z(u,e=>{$.data&&e(d)}),Y(e,c),We()}var no=J(``),ro=J(``,1);function io(e,t){Ue(t,!0);let n=Wi(t,`values`,19,()=>[]),r=Wi(t,`label`,3,`Token activity`),i=Wi(t,`capacity`,3,0),a=F(()=>Math.max(0,...n())),o=F(()=>i()>n().length?[...Array(i()-n().length).fill(0),...n()]:n());var s=ro(),c=B(s),l=V(c),u=H(c,2);Xr(u,21,()=>K(o),Kr,(e,t)=>{var n=no();let r;U((e,t)=>{Q(n,`title`,e),r=ui(n,``,r,{height:t})},[()=>K(t).toLocaleString(`en-GB`)+` tokens`,()=>`${100*K(t)/Math.max(1,K(a))}%`]),Y(e,n)}),P(u),U((e,t)=>{X(l,`SCALE // 0 — ${e??``} TOKENS`),Q(u,`aria-label`,t)},[()=>K(a).toLocaleString(`en-GB`),()=>`${r()}. Peak ${K(a).toLocaleString(`en-GB`)} tokens.`]),Y(e,s),We()}function ao(e){if(!e||![`LAST REPLY`,`LAST ACTIVITY`].includes(e.contextKind))return``;let t=e.text||e.contextKind===`LAST ACTIVITY`&&e.workingCommand||``;return t.trim()?t:``}var oo=J(` `),so=J(``),co=J(`
`),lo=J(`
`,1),uo=J(`
`),fo=J(`
Loading / sending…
`),po=J(``),mo=J(``),ho=J(`
Review expired. Press Enter to review again.
`),yo=J(``,1),bo=J(`
`,1),xo=J(`
No available matching commands.
`),So=J(` `,1),Co=J(``),wo=J(`
Review expired. Review the option again.
`),To=J(``),Eo=J(``),Do=J(``),Oo=J(``),ko=J(``),Ao=J(``),jo=J(``),Mo=J(` `),zo=J(`
Send this saved prompt now? This starts Codex work and consumes quota.
`,1),Bo=J(``),Vo=J(`
In memory only. Follows session model, reasoning and speed. Closing - Codexometer cancels pending work.
MODEL / REASONING LEVEL / SPEED
MODEL / REASONING LEVEL / SPEED
Applied settings remain after Codexometer closes.
`,1),Uo=J(``),Wo=J(`
`,1),Go=J(`
Command unavailable from this observation. Open Codex to inspect the - request.
`),Ko=J(`Session controls temporarily unavailable. Check Codex for current state.
`),qo=J(`Checking session controls…
`),Jo=J(``),Yo=J(`
Controls require a supported live request from a connected shared - app-server session. Local observations alone cannot provide them.
`),Qo=J(`Grants permission beyond this one action. Check the scope
- carefully.`),$o=J(``),es=J(``),ts=J(``),ns=J(``),rs=J(`Not before this time; when quota and idle allow.
`),is=J(``,1),as=J(`
The existing trigger remains active until saved or deleted. If - it changes or sends while you edit, saving is blocked.
`),os=J(` `,1),ss=J(``),cs=J(``),ls=J(``),us=J(` `,1),ds=J(`Type one of these choices exactly. Your answer stays masked.
`),hs=J(`
`,1),gs=J(` `,1),_s=J(``),vs=J(`
`,1),ys=J(`
`),Bo=J(`
Send this saved prompt now? This starts Codex work and consumes quota.
`,1),Vo=J(``),Ho=J(`
In memory only. Follows session model, reasoning and speed. Closing + Codexometer cancels pending work.
MODEL / REASONING LEVEL / SPEED
MODEL / REASONING LEVEL / SPEED
Applied settings remain after Codexometer closes.
`,1),Wo=J(``),Go=J(`
`,1),Ko=J(`
Command unavailable from this observation. Open Codex to inspect the + request.
`),qo=J(`Session controls temporarily unavailable. Check Codex for current state.
`),Jo=J(`Checking session controls…
`),Yo=J(``),Xo=J(`
Controls require a supported live request from a connected shared + app-server session. Local observations alone cannot provide them.
`),$o=J(`Grants permission beyond this one action. Check the scope
+ carefully.`),es=J(``),ts=J(``),ns=J(``),rs=J(``),is=J(`Not before this time; when quota and idle allow.
`),as=J(``,1),os=J(`
The existing trigger remains active until saved or deleted. If + it changes or sends while you edit, saving is blocked.
`),ss=J(` `,1),cs=J(``),ls=J(``),us=J(``),ds=J(` `,1),fs=J(`Type one of these choices exactly. Your answer stays masked.
`),gs=J(`
`,1),_s=J(` `,1),vs=J(``),ys=J(`
`,1),bs=J(`
Choose multiple fields and their order. These display preferences do not - change Codex CLI configuration. Missing values are omitted.
`,1),ks=J(`
`,1),As=J(`
`),Ms=J(`
`),Ps=J(`
`,1),Fs=J(`
`),Is=J(`
Command unavailable from this observation. Open Codex to inspect the - request.
`),Ls=J(``),zs=J(` `,1),Bs=J(`
Session connection or refresh unavailable. Context and telemetry may be - stale.
`),Hs=J(`Some quota profile checks are unavailable. Only sessions with freshly + reasoning and speed.`,U(e=>X(r,`Will send: ${e??``}`),[()=>K(T)===`quota`?`when quota is available and this session is idle`:Number.isFinite(K(me))?ge(K(me)):`choose a date and time`]),Y(e,t)};Z(p,e=>{K(T)!==`now`&&e(m)});var h=H(p,2),g=e=>{Y(e,os())};Z(h,e=>{K(x)&&e(g)}),hi(r,()=>K(T),e=>R(T,e)),Y(e,t)};Z(r,e=>{K(u).questions?.length||e(i)}),Xr(H(r,2),17,()=>K(fe),Kr,(e,n,r)=>{var i=ms(),o=B(i),s=e=>{{let n=F(()=>K(d)[0]||``);Ii(Po(e,{get session(){return t.session},get oncopy(){return l()},get query(){return K(n)},oncomplete:e=>{R(d,[e],!0),lr().then(()=>K(ne)?.focus())},onchange:()=>{R(d,[``],!0),lr().then(()=>K(ne)?.focus())}}),e=>R(re,e,!0),()=>K(re))}};Z(o,e=>{r===0&&a()!==`profile`&&K(u).kind===`prompt`&&!K(u).questions?.length&&e(s)});var c=H(o,2),f=z(c),p=H(f),m=e=>{var t=cs();xi(t),Ei(t,()=>K(d)[r],e=>K(d)[r]=e),Y(e,t)},h=e=>{var t=us(),i=z(t);i.value=i.__value=``,Xr(H(i),17,()=>K(n).options||[],Kr,(e,t)=>{var n=ls(),r=V(n,!0),i={};U(()=>{X(r,K(t)),i!==(i=K(t))&&(n.value=(n.__value=i)??``)}),Y(e,n)}),P(t),mi(t),hi(t,()=>K(d)[r],e=>K(d)[r]=e),Y(e,t)},g=e=>{var t=ds(),i=B(t);tt(i),Ii(i,e=>R(ne,e),()=>K(ne));var a=H(i,2),o=e=>{var t=Yo(),r=V(t);U(e=>X(r,`Suggested answers: ${e??``}`),[()=>K(n).options.join(` · `)]),Y(e,t)};Z(a,e=>{K(n).options?.length&&e(o)}),q(`keydown`,i,e=>{K(u)?.kind===`prompt`&&!K(u).questions?.length&&K(re)?.handleKey(e)}),Ei(i,()=>K(d)[r],e=>K(d)[r]=e),Y(e,t)};Z(p,e=>{K(n).secret?e(m):K(n).freeText?e(g,-1):e(h,1)}),P(c);var _=H(c,2),v=e=>{var t=ps(),r=H(z(t),4);Xr(r,21,()=>K(n).options||[],Kr,(e,t)=>{var n=fs(),r=V(n,!0);U(()=>X(r,K(t))),Y(e,n)}),P(r),P(t),Y(e,t)};Z(_,e=>{K(n).secret&&!K(n).freeText&&e(v)}),U(()=>X(f,`${K(n).text??``} `)),Y(e,i)}),Y(e,n)};Z(v,e=>{K(u).kind===`approval`||K(u).kind===`profile`?e(y):e(b,-1)}),P(s);var S=H(s,2),C=e=>{var t=gs(),n=B(t),r=e=>{var t=hs(),n=V(t);U(()=>X(n,`TRIGGER // ${K(te)??``}`)),Y(e,t)};Z(n,e=>{K(ee)&&e(r)});var i=H(n,2),a=V(i),o=H(i,2),s=V(o),c=H(o,2);U(e=>{X(a,`Check the target and ${K(u).kind===`profile`?`profile above`:K(u).kind===`approval`?K(u).fileChanges?.length?`proposed file changes above`:`exact command and permission scope`:`message above`}. ${K(ee)?`This schedules a follow-up that will send automatically when eligible`:`This will send to Codex`}; it may start work using your quota. + Confirmation expires in ${e??``}s.`),o.disabled=K(g)||K(A),X(s,`CONFIRM ${(K(u).kind===`approval`||K(u).kind===`profile`?K(u).choices?.[K(f)]?.label:K(ee)?K(x)?`SAVE CHANGES`:`SCHEDULE`:`SEND`)??``}`)},[()=>Math.max(0,Math.ceil((K(m)-K(h))/1e3))]),q(`click`,o,N),q(`click`,c,()=>{R(p,``)}),Y(e,t)},w=e=>{var t=_s(),n=B(t),r=e=>{var t=zo(),n=V(t,!0);U(()=>X(n,K(he))),Y(e,t)};Z(n,e=>{K(he)&&e(r)});var i=H(n,2),a=V(i,!0);U(()=>{i.disabled=K(g)||K(A)||!K(j)||!!K(he),X(a,K(g)?`SENDING…`:K(x)?`REVIEW CHANGES`:`REVIEW BEFORE SENDING`)}),q(`click`,i,()=>ve()),Y(e,t)};Z(S,e=>{K(de)?e(C):e(w,-1)});var O=H(S,2),k=e=>{var t=vs();q(`click`,t,()=>{R(x,!1),R(p,``),R(d,[],!0)}),Y(e,t)};Z(O,e=>{K(x)&&e(k)}),U(()=>{X(o,`TARGET // ${K(u).thread??``} // ${(K(u).directory||`Directory unavailable`)??``}`),s.disabled=K(g)||K(de)||K(A),X(_,K(u).kind===`approval`||K(u).kind===`profile`?`Choose a decision`:K(x)?`EDIT SCHEDULED FOLLOW-UP`:`Reply to this session`)}),Y(e,r)};Z(ce,e=>{K(A)||K(y)?e(pe):K(u)?K(u).id?K(b)!==K(u).id&&e(ye,3):e(M,2):e(_e,1)}),P(r),U(()=>X(s,a()===`profile`?`QUOTA THRESHOLD`:`SESSION CONTROL // EXPERIMENTAL`)),Y(e,r)};Z(we,e=>{!K(ce)&&(!K(k)||K(x)||a()||K(u)?.kind!==`prompt`||K(u).questions?.length)&&e(Te)}),Y(e,ye),We()}Sr([`click`,`keydown`]);var Ss=J(` `,1),Cs=J(`
Choose multiple fields and their order. These display preferences do not + change Codex CLI configuration. Missing values are omitted.
`,1),As=J(`
`,1),js=J(`
`),Ns=J(`
`),Fs=J(`
`,1),Is=J(`
`),Ls=J(`
Command unavailable from this observation. Open Codex to inspect the + request.
`),Rs=J(``),Bs=J(` `,1),Vs=J(`
Session connection or refresh unavailable. Context and telemetry may be + stale.
`),Us=J(`Some quota profile checks are unavailable. Only sessions with freshly verified quota and settings can be updated; previous outcome notices remain - visible.
`),Us=J(` `),Ws=J(` `),Gs=J(` `),Ks=J(``),qs=J(`Read only — reply or approve in Codex.
`),Ys=J(`QUOTA THRESHOLD // REVIEW PROFILE ↗`),Xs=J(`
This session is no longer in the current observation. Return to sessions.
`),$s=J(``),ec=J(``),tc=J(``),nc=J(` `),rc=J(`
`),ic=J(`QUOTA THRESHOLD // REVIEW PROFILE ↗`),ac=J(` `,1),oc=J(`
No locally observed sessions yet. Keep Codex running alongside - Codexometer.
`),uc=J(`↑ ↓ SELECT SESSION // ← LESS DETAIL // → MORE DETAIL // ESC BACK
`,1);function fc(e,t){Ue(t,!0);let n=(e,t=f,n,r)=>{let i=pt(()=>g(n?.(),!0)),a=pt(()=>g(r?.(),!1));var o=zs(),s=B(o),c=e=>{var n=Os(),r=B(n),i=V(r,!0),a=V(H(r,2),!0);U(()=>{X(i,t().contextKind===`LAST REPLY`&&!t().streaming?`TASK`:`CURRENT TASK`),X(a,t().currentTask)}),Y(e,n)};Z(s,e=>{t().currentTask&&e(c)});var l=H(s,2),u=e=>{var n=ks(),r=V(H(B(n),2),!0);U(()=>X(r,t().latestGuidance)),Y(e,n)};Z(l,e=>{t().latestGuidance&&e(u)});var d=H(l,2),p=e=>{var n=As(),r=V(H(B(n),2),!0);xe(2),U(()=>X(r,t().approvalContext)),Y(e,n)};Z(d,e=>{K(a)&&t().contextKind===`APPROVAL REQUEST`&&t().approvalContext&&e(p)});var m=H(d,2),h=e=>{var n=js();let r;var i=V(n,!0);U(e=>{r=ci(n,1,`attention-note`,null,r,{inferred:t().status===`CHECK SESSION`}),X(i,e)},[()=>w(t())]),Y(e,n)},_=F(()=>w(t())&&(!K(a)||K(v)||t().status===`CHECK SESSION`));Z(m,e=>{K(_)&&e(h)});var y=H(m,2),b=e=>{var n=Ms(),r=V(n,!0);U(e=>X(r,e),[()=>T(t())]),Y(e,n)};Z(y,e=>{K(i)&&e(b)});var x=H(y,2),S=e=>{var n=Ns(),r=V(n,!0);U(()=>X(r,t().text||`No session context available.`)),Y(e,n)};Z(x,e=>{(t().text||!t().workingCommand)&&e(S)});var C=H(x,2),E=e=>{var n=Ps(),r=H(B(n),2),i=z(r),a=H(i),o=e=>{var n=Mr();U(()=>X(n,`// +${(t().runningCommands||0)-+(t().commandStatus===`running`)} RUNNING`)),Y(e,n)};Z(a,e=>{!K(v)&&(t().runningCommands||0)>+(t().commandStatus===`running`)&&e(o)});var s=H(a,2),c=e=>{Y(e,Mr(`+`))};Z(s,e=>{t().runningLimited&&e(c)}),P(r);var l=V(H(r,2),!0);U(e=>{X(i,`COMMAND // ${e??``} `),X(l,t().workingCommand)},[()=>K(v)?`UNKNOWN`:(t().commandStatus||`unknown`).toUpperCase()]),Y(e,n)};Z(C,e=>{t().workingCommand&&e(E)});var D=H(C,2),ee=e=>{Lo(e,{get lines(){return t().fileChanges}})},te=e=>{var n=Ls(),r=H(B(n),2),i=V(r,!0),a=H(r,2),o=e=>{var n=Fs(),r=V(n,!0);U(()=>X(r,t().command)),Y(e,n)},s=e=>{Y(e,Is())};Z(a,e=>{t().command?e(o):e(s,-1)}),U(()=>X(i,K(v)||t().status!==`APPROVAL NEEDED`?`LAST OBSERVED COMMAND`:$.data?.control?`COMMAND REQUEST`:`COMMAND TO APPROVE IN CODEX`)),Y(e,n)};Z(D,e=>{(!K(a)||!$.data?.control)&&t().fileChanges?.length?e(ee):(!K(a)||!$.data?.control)&&(t().command||t().status===`APPROVAL NEEDED`)&&e(te,1)});var O=H(D,2),k=e=>{var n=Rs(),r=V(n);U(()=>X(r,`CONTEXT SOURCE // ${(t().source||`LOCAL`)??``} // OBSERVATION`)),Y(e,n)};Z(O,e=>{K(a)||e(k)}),Y(e,o)},r=L(void 0),i=Wi(t,`params`,19,()=>({})),a=F(()=>$.data?.sessions||[]),o=F(()=>$.data?.control&&$.data.profiles||[]),s=F(()=>($.data?.triggers||[]).filter(e=>K(a).some(t=>t.id===e.session)));function c(e,t){if(i().id&&i().id!==t&&K(u)){e.preventDefault();return}x(t)}function l(e){return[`TURN COMPLETE`,`IDLE`,`ACTIVE`].includes(e.status)&&K(s).some(t=>t.session===e.id)?`TRIGGER SET`:e.status}let u=L(!1);function d(e,t){if(i().id&&i().id!==t&&K(u)){e.preventDefault();return}x(t)}vn(()=>{let e=i().id;e&&fr(()=>{aa.selected=e,fa(e,2)})});let p=F(()=>K(a).find(e=>e.id===i().id)),m=F(()=>new URLSearchParams(Yi.querystring).get(`review`)===`profile`&&K(o).some(e=>e.session===i().id&&e.pending)),h=F(()=>K(a).some(e=>e.id===aa.selected)?aa.selected:K(a)[0]?.id),v=F(()=>!$.connected||!!$.data?.sessionsError),y=F(()=>[[`OBSERVED TOKENS`,pa(K(a).reduce((e,t)=>e+t.tokens,0))],[`LISTED SESSIONS`,pa(K(a).length)],...[[`WORKING`,`WORKING`],[`AWAITING APPROVAL`,`APPROVAL NEEDED`],[`AWAITING INPUT`,`INPUT NEEDED`],[`CHECK · INFERRED`,`CHECK SESSION`]].map(([e,t])=>[e,K(v)?`—`:pa(K(a).filter(e=>e.status===t).length)])]),b=F(()=>K(a).filter(e=>[`INPUT NEEDED`,`APPROVAL NEEDED`,`CHECK SESSION`].includes(e.status)));function x(e){aa.selected=e,lr().then(()=>document.querySelector(`.session-row.selected`)?.scrollIntoView({block:`nearest`}))}function S(e,t){if(x(e),i().id){t<0&&(fa(e,2),location.hash=`/sessions`);return}let n=ua(e)+t;n>2?location.hash=`/sessions/`+encodeURIComponent(e):fa(e,n)}function C(e){let t=e.target;if(!(e.altKey||e.ctrlKey||e.metaKey||e.shiftKey||t.closest(`input, textarea, select, [contenteditable="true"]`))){if(e.key===`Escape`&&i().id)e.preventDefault(),S(i().id,-1);else if([`ArrowLeft`,`ArrowRight`].includes(e.key)&&(i().id||K(h)))e.preventDefault(),S(i().id||K(h),e.key===`ArrowLeft`?-1:1);else if(!i().id&&[`ArrowUp`,`ArrowDown`].includes(e.key)&&K(a).length){e.preventDefault();let t=K(a).findIndex(e=>e.id===K(h));x(K(a)[Math.max(0,Math.min(K(a).length-1,t+(e.key===`ArrowUp`?-1:1)))].id)}}}function w(e){return K(v)?`Last observation only — refresh unavailable. Check Codex for current state.`:e.status===`CHECK SESSION`?`INFERRED INACTIVITY — a quiet session, not a confirmed input or approval request. Local tools may still be running.`:$.data?.control&&[`APPROVAL NEEDED`,`INPUT NEEDED`].includes(e.status)?`Open full detail for supported live controls; otherwise reply in Codex.`:e.status===`APPROVAL NEEDED`?`OBSERVED APPROVAL SIGNAL — approve or decline in Codex.`:e.status===`INPUT NEEDED`?`OBSERVED INPUT SIGNAL — reply in Codex.`:e.status===`TURN COMPLETE`?`OBSERVED TURN COMPLETION — informational, not an approval request.`:``}function T(e){return e.streaming&&e.contextKind===`LAST REPLY`?`REPLY // STREAMING`:e.contextKind||`LAST ACTIVITY`}var E=dc();xr(`keydown`,Qt,C);var D=B(E),ee=V(H(z(D),2));P(D);var te=H(D,2);let O;Xr(te,21,()=>K(y),Kr,(e,t)=>{var n=F(()=>_(K(t),2));let r=()=>K(n)[0],i=()=>K(n)[1];var a=Bs(),o=z(a),s=V(o,!0),c=V(H(o,2),!0);P(a),U(()=>{X(s,r()),X(c,i())}),Y(e,a)}),P(te);var k=H(te,2),ne=V(k),re=H(k,2),ie=e=>{Y(e,Vs())};Z(re,e=>{K(v)&&e(ie)});var ae=H(re,2),oe=e=>{Y(e,Hs())};Z(ae,e=>{$.data?.profileError&&e(oe)});var se=H(ae,2),A=e=>{var t=Ks(),n=z(t);Xr(n,17,()=>K(b),Kr,(e,t)=>{var n=Us();let r;var i=V(n);U((e,a)=>{r=ci(n,1,`button`,null,r,{approval:K(t).status===`APPROVAL NEEDED`}),Q(n,`href`,e),X(i,`${K(t).status??``} - ${a??``} // ${(K(t).name||K(t).directory||K(t).id)??``}`)},[()=>`#/sessions/`+encodeURIComponent(K(t).id),()=>Array.from(K(t).id).slice(-5).join(``).toUpperCase()]),q(`click`,n,()=>x(K(t).id)),Y(e,n)});var r=H(n,2);Xr(r,17,()=>K(o).filter(e=>e.pending&&K(a).some(t=>t.id===e.session)),Kr,(e,t)=>{var n=Ws(),r=V(n);U((e,a,o)=>{Q(n,`title`,i().id&&i().id!==K(t).session&&K(u)?`Finish sending or clear your current draft before switching sessions.`:`Review this session’s quota threshold`),Q(n,`href`,e),X(r,`QUOTA THRESHOLD ${a??``} // ${o??``}`)},[()=>`#/sessions/`+encodeURIComponent(K(t).session)+`?review=profile`,()=>Array.from(K(t).session).slice(-5).join(``).toUpperCase(),()=>K(a).find(e=>e.id===K(t).session)?.name||K(a).find(e=>e.id===K(t).session)?.directory||K(t).session]),q(`click`,n,e=>d(e,K(t).session)),Y(e,n)}),Xr(H(r,2),17,()=>K(s),Kr,(e,t)=>{var n=Gs(),r=V(n);U((e,t,i)=>{Q(n,`href`,e),X(r,`TRIGGER SET ${t??``} // ${i??``}`)},[()=>`#/sessions/`+encodeURIComponent(K(t).session),()=>Array.from(K(t).session).slice(-5).join(``).toUpperCase(),()=>K(a).find(e=>e.id===K(t).session)?.name||K(a).find(e=>e.id===K(t).session)?.directory]),q(`click`,n,e=>c(e,K(t).session)),Y(e,n)}),P(t),Y(e,t)},ce=F(()=>(K(b).length||K(o).some(e=>e.pending)||K(s).length)&&!K(v));Z(se,e=>{K(ce)&&e(A)});var le=H(se,2),ue=e=>{var t=Nr(),a=B(t),s=e=>{var t=Zs(),a=z(t),s=z(a),c=z(s);let d;var f=H(c);P(s);var h=H(s,2);P(a);var g=H(a,2),_=e=>{var t=Rs(),n=V(t,!0);U(()=>X(n,K(p).directory)),Y(e,t)};Z(g,e=>{K(p).name&&K(p).directory&&e(_)});var y=H(g,2),b=V(y),S=H(y,2);let C;var w=z(S),T=z(w);n(T,()=>K(p),()=>!0,()=>!0),P(w);var E=H(w,2),D=e=>{var t=Nr();Gr(B(t),()=>K(p).id,e=>{{let t=F(()=>new URLSearchParams(Yi.querystring).get(`schedule`)===`edit`),n=F(()=>K(p).fileChanges||[]);bs(e,{get session(){return K(p).id},oncopy:()=>K(r)?.copy(),get openScheduler(){return K(t)},get observedCommand(){return K(p).command},get observedFileChanges(){return K(n)},get suspended(){return K(m)},onProtectedChange:e=>{R(u,e,!0)}})}}),Y(e,t)},ee=e=>{var t=qs();Gr(H(z(t),2),()=>K(p).id,e=>{No(e,{get session(){return K(p).id},localOnly:!0,oncopy:()=>K(r)?.copy()})}),P(t),Y(e,t)};Z(E,e=>{$.data?.control?e(D):e(ee,-1)}),P(S);var te=H(S,2);Xr(te,17,()=>K(o).filter(e=>e.session===K(p).id),e=>e.session,(e,t)=>{var n=Xs(),r=z(n),i=e=>{var n=Js(),r=V(n,!0);U(()=>X(r,K(t).notice)),Y(e,n)};Z(r,e=>{K(t).notice&&e(i)});var a=H(r,2),o=e=>{bs(e,{get session(){return K(p).id},review:`profile`})},s=e=>{var t=Ys();U(e=>Q(t,`href`,e),[()=>`#/sessions/`+encodeURIComponent(K(p).id)+`?review=profile`]),Y(e,t)};Z(a,e=>{K(t).pending&&K(m)?e(o):K(t).pending&&e(s,1)}),P(n),U(()=>Q(n,`id`,`quota-profile-`+K(p).id)),Y(e,n)});var O=H(te,2),k=e=>{var t=Nr();Gr(B(t),()=>K(p).id,e=>{Ii(Ds(e,{get session(){return K(p)},active:!0}),e=>R(r,e,!0),()=>K(r))}),Y(e,t)};Z(O,e=>{K(m)||e(k)}),Gr(H(O,2),()=>K(p).id,e=>{Ts(e,{get session(){return K(p)},get stale(){return K(v)}})}),P(t),U((e,t)=>{d=ci(c,1,`lamp lit`,null,d,{working:K(p).status===`WORKING`&&!K(v)}),X(f,`${e??``} // ${(K(p).name||K(p).directory)??``}`),X(b,`${t??``} TOKENS // ${K(p).id??``} // CONTEXT SOURCE // ${(K(p).source||`LOCAL`)??``}`),C=ui(S,``,C,{display:K(m)?`none`:void 0})},[()=>K(v)?`STALE`:K(m)?`QUOTA THRESHOLD`:l(K(p)),()=>pa(K(p).tokens)]),q(`click`,h,()=>{x(i().id),fa(i().id,2)}),Y(e,t)},c=e=>{Y(e,Qs())};Z(a,e=>{K(p)?e(s):e(c,-1)}),Y(e,t)},de=e=>{var t=uc(),r=B(t),i=H(z(r),2),s=z(i),c=H(s,2);P(i),P(r);var u=H(r,2);Xr(u,17,()=>K(a),e=>e.id,(e,t)=>{let r=F(()=>ua(K(t).id));var i=cc();let a;var s=z(i),c=z(s),u=e=>{var n=$s(),r=z(n),i=V(r);P(n),U(e=>{Q(r,`aria-pressed`,K(h)===K(t).id),X(i,`${e??``} // ${K(t).name??``}`)},[()=>Array.from(K(t).id).slice(-5).join(``).toUpperCase()]),q(`click`,r,()=>x(K(t).id)),Y(e,n)};Z(c,e=>{K(t).name&&e(u)});var f=H(c,2),p=z(f),m=z(p);let g;var _=H(m,1,!0);P(p),P(f);var y=H(f,2),b=e=>{var n=ec(),r=V(n,!0);U(()=>{Q(n,`aria-pressed`,K(h)===K(t).id),X(r,K(t).directory||K(t).id)}),q(`click`,n,()=>x(K(t).id)),Y(e,n)};Z(y,e=>{K(t).name||e(b)});var C=H(y,2),w=z(C);xe(),P(C);var E=H(C,2),D=e=>{var n=Rs(),r=V(n,!0);U(()=>X(r,K(t).directory)),Y(e,n)};Z(E,e=>{K(t).name&&K(t).directory&&e(D)});var ee=H(E,2),te=V(ee),O=H(ee,2),k=V(O),ne=H(O,2),re=z(ne),ie=H(re,2),ae=V(ie,!0),oe=H(ie,2);P(ne);var se=H(ne,2),A=H(se,2),ce=e=>{var n=tc(),r=V(n,!0);U(()=>X(r,K(t).status===`CHECK SESSION`?`INFERRED INACTIVITY`:$.data?.control?`OPEN FULL DETAIL OR REPLY IN CODEX`:K(t).status===`APPROVAL NEEDED`?`APPROVE OR DECLINE IN CODEX`:`REPLY IN CODEX`)),Y(e,n)},le=F(()=>!K(v)&&[`APPROVAL NEEDED`,`INPUT NEEDED`,`CHECK SESSION`].includes(K(t).status));Z(A,e=>{K(le)&&e(ce)}),P(s);var ue=H(s,2),de=e=>{var r=oc(),i=z(r),a=z(i),s=V(a,!0),c=H(a,2),l=e=>{var n=nc(),r=V(n,!0);U(e=>{Q(n,`href`,e),X(r,$.data?.control?`REVIEW IN FULL DETAIL ↗`:`APPROVAL IN CODEX ↗`)},[()=>`#/sessions/`+encodeURIComponent(K(t).id)]),Y(e,n)};Z(c,e=>{!K(v)&&K(t).status===`APPROVAL NEEDED`&&e(l)}),P(i);var u=H(i,2);n(u,()=>K(t),()=>!1);var f=H(u,2);Xr(f,17,()=>K(o).filter(e=>e.session===K(t).id),Kr,(e,n)=>{var r=ac(),i=B(r),a=e=>{var t=rc(),r=V(t,!0);U(()=>X(r,K(n).notice)),Y(e,t)};Z(i,e=>{K(n).notice&&e(a)});var o=H(i,2),s=e=>{var n=ic();U(e=>Q(n,`href`,e),[()=>`#/sessions/`+encodeURIComponent(K(t).id)+`?review=profile`]),q(`click`,n,e=>d(e,K(t).id)),Y(e,n)};Z(o,e=>{K(n).pending&&e(s)}),Y(e,r)});var p=H(f,2);{let e=F(()=>K(h)===K(t).id);Ds(p,{get session(){return K(t)},get active(){return K(e)}})}P(r),U(e=>X(s,e),[()=>T(K(t))]),Y(e,r)};Z(ue,e=>{K(r)>0&&e(de)});var fe=H(ue,2),j=e=>{var n=sc(),r=H(z(n),2);{let e=F(()=>(K(t).samples||[]).map(e=>e.tokens));ro(r,{get values(){return K(e)},capacity:120})}var i=V(H(r,2));P(n),U(()=>X(i,`LAST ${(K(t).samples?.length||0)??``} SAMPLES // AUTO SCALE`)),Y(e,n)};Z(fe,e=>{K(r)<2&&e(j)}),P(i),U((e,n,o,s,c)=>{a=ci(i,1,`session-row`,null,a,{selected:K(h)===K(t).id,wide:K(r)===2,split:K(r)===1}),Q(i,`aria-label`,`Session `+(K(t).name||K(t).directory||K(t).id)),Q(p,`href`,e),g=ci(m,1,`lamp lit`,null,g,{working:K(t).status===`WORKING`&&!K(v)}),X(_,n),X(w,`${o??``} `),X(te,`${K(t).agents??``} LINKED AGENTS`),X(k,`ACTIVE // ${s??``}`),re.disabled=K(r)===0,Q(ie,`aria-expanded`,K(r)>0),X(ae,K(r)?`HIDE DETAIL`:`SHOW DETAIL`),Q(se,`href`,c)},[()=>`#/sessions/`+encodeURIComponent(K(t).id),()=>K(v)?`STALE`:l(K(t)),()=>pa(K(t).tokens),()=>ma(K(t).activity),()=>`#/sessions/`+encodeURIComponent(K(t).id)]),q(`click`,p,()=>x(K(t).id)),q(`click`,re,()=>S(K(t).id,-1)),q(`click`,ie,()=>{x(K(t).id),fa(K(t).id,+!K(r))}),q(`click`,oe,()=>S(K(t).id,1)),q(`click`,se,()=>x(K(t).id)),Y(e,i)});var f=H(u,2),p=e=>{Y(e,lc())};Z(f,e=>{K(a).length||e(p)}),q(`click`,s,()=>da(1)),q(`click`,c,()=>da(0)),Y(e,t)};Z(le,e=>{i().id?e(ue):e(de,-1)}),U(e=>{X(ee,`OBSERVED ${e??``}`),O=ci(te,1,`session-totals`,null,O,{stale:K(v)}),X(ne,`${K(v)?`LAST KNOWN TOTALS — live state counts unavailable. `:``}Tokens + visible.`),Ws=J(` `),Gs=J(` `),Ks=J(` `),qs=J(``),Js=J(`
Read only — reply or approve in Codex.
`),Xs=J(`QUOTA THRESHOLD // REVIEW PROFILE ↗`),Zs=J(`
This session is no longer in the current observation. Return to sessions.
`),ec=J(``),tc=J(``),nc=J(``),rc=J(` `),ic=J(`
`),ac=J(`QUOTA THRESHOLD // REVIEW PROFILE ↗`),oc=J(` `,1),sc=J(`
No locally observed sessions yet. Keep Codex running alongside + Codexometer.
`),dc=J(`↑ ↓ SELECT SESSION // ← LESS DETAIL // → MORE DETAIL // ESC BACK
`,1);function pc(e,t){Ue(t,!0);let n=(e,t=f,n,r)=>{let i=pt(()=>g(n?.(),!0)),a=pt(()=>g(r?.(),!1));var o=Bs(),s=B(o),c=e=>{var n=ks(),r=B(n),i=V(r,!0),a=V(H(r,2),!0);U(()=>{X(i,t().contextKind===`LAST REPLY`&&!t().streaming?`TASK`:`CURRENT TASK`),X(a,t().currentTask)}),Y(e,n)};Z(s,e=>{t().currentTask&&e(c)});var l=H(s,2),u=e=>{var n=As(),r=V(H(B(n),2),!0);U(()=>X(r,t().latestGuidance)),Y(e,n)};Z(l,e=>{t().latestGuidance&&e(u)});var d=H(l,2),p=e=>{var n=js(),r=V(H(B(n),2),!0);xe(2),U(()=>X(r,t().approvalContext)),Y(e,n)};Z(d,e=>{K(a)&&t().contextKind===`APPROVAL REQUEST`&&t().approvalContext&&e(p)});var m=H(d,2),h=e=>{var n=Ms();let r;var i=V(n,!0);U(e=>{r=ci(n,1,`attention-note`,null,r,{inferred:t().status===`CHECK SESSION`}),X(i,e)},[()=>w(t())]),Y(e,n)},_=F(()=>w(t())&&(!K(a)||K(v)||t().status===`CHECK SESSION`));Z(m,e=>{K(_)&&e(h)});var y=H(m,2),b=e=>{var n=Ns(),r=V(n,!0);U(e=>X(r,e),[()=>T(t())]),Y(e,n)};Z(y,e=>{K(i)&&e(b)});var x=H(y,2),S=e=>{var n=Ps(),r=V(n,!0);U(()=>X(r,t().text||`No session context available.`)),Y(e,n)};Z(x,e=>{(t().text||!t().workingCommand)&&e(S)});var C=H(x,2),E=e=>{var n=Fs(),r=H(B(n),2),i=z(r),a=H(i),o=e=>{var n=Mr();U(()=>X(n,`// +${(t().runningCommands||0)-+(t().commandStatus===`running`)} RUNNING`)),Y(e,n)};Z(a,e=>{!K(v)&&(t().runningCommands||0)>+(t().commandStatus===`running`)&&e(o)});var s=H(a,2),c=e=>{Y(e,Mr(`+`))};Z(s,e=>{t().runningLimited&&e(c)}),P(r);var l=V(H(r,2),!0);U(e=>{X(i,`COMMAND // ${e??``} `),X(l,t().workingCommand)},[()=>K(v)?`UNKNOWN`:(t().commandStatus||`unknown`).toUpperCase()]),Y(e,n)};Z(C,e=>{t().workingCommand&&e(E)});var D=H(C,2),ee=e=>{Ro(e,{get lines(){return t().fileChanges}})},te=e=>{var n=Rs(),r=H(B(n),2),i=V(r,!0),a=H(r,2),o=e=>{var n=Is(),r=V(n,!0);U(()=>X(r,t().command)),Y(e,n)},s=e=>{Y(e,Ls())};Z(a,e=>{t().command?e(o):e(s,-1)}),U(()=>X(i,K(v)||t().status!==`APPROVAL NEEDED`?`LAST OBSERVED COMMAND`:$.data?.control?`COMMAND REQUEST`:`COMMAND TO APPROVE IN CODEX`)),Y(e,n)};Z(D,e=>{(!K(a)||!$.data?.control)&&t().fileChanges?.length?e(ee):(!K(a)||!$.data?.control)&&(t().command||t().status===`APPROVAL NEEDED`)&&e(te,1)});var O=H(D,2),k=e=>{var n=zs(),r=V(n);U(()=>X(r,`CONTEXT SOURCE // ${(t().source||`LOCAL`)??``} // OBSERVATION`)),Y(e,n)};Z(O,e=>{K(a)||e(k)}),Y(e,o)},r=L(void 0),i=Wi(t,`params`,19,()=>({})),a=F(()=>$.data?.sessions||[]),o=F(()=>$.data?.control&&$.data.profiles||[]),s=F(()=>($.data?.triggers||[]).filter(e=>K(a).some(t=>t.id===e.session)));function c(e,t){if(i().id&&i().id!==t&&K(u)){e.preventDefault();return}x(t)}function l(e){return[`TURN COMPLETE`,`IDLE`,`ACTIVE`].includes(e.status)&&K(s).some(t=>t.session===e.id)?`TRIGGER SET`:e.status}let u=L(!1);function d(e,t){if(i().id&&i().id!==t&&K(u)){e.preventDefault();return}x(t)}vn(()=>{let e=i().id;e&&fr(()=>{aa.selected=e,fa(e,2)})});let p=F(()=>K(a).find(e=>e.id===i().id)),m=F(()=>new URLSearchParams(Yi.querystring).get(`review`)===`profile`&&K(o).some(e=>e.session===i().id&&e.pending)),h=F(()=>K(a).some(e=>e.id===aa.selected)?aa.selected:K(a)[0]?.id),v=F(()=>!$.connected||!!$.data?.sessionsError),y=F(()=>[[`OBSERVED TOKENS`,pa(K(a).reduce((e,t)=>e+t.tokens,0))],[`LISTED SESSIONS`,pa(K(a).length)],...[[`WORKING`,`WORKING`],[`AWAITING APPROVAL`,`APPROVAL NEEDED`],[`AWAITING INPUT`,`INPUT NEEDED`],[`CHECK · INFERRED`,`CHECK SESSION`]].map(([e,t])=>[e,K(v)?`—`:pa(K(a).filter(e=>e.status===t).length)])]),b=F(()=>K(a).filter(e=>[`INPUT NEEDED`,`APPROVAL NEEDED`,`CHECK SESSION`].includes(e.status)));function x(e){aa.selected=e,lr().then(()=>document.querySelector(`.session-row.selected`)?.scrollIntoView({block:`nearest`}))}function S(e,t){if(x(e),i().id){t<0&&(fa(e,2),location.hash=`/sessions`);return}let n=ua(e)+t;n>2?location.hash=`/sessions/`+encodeURIComponent(e):fa(e,n)}function C(e){let t=e.target;if(!(e.altKey||e.ctrlKey||e.metaKey||e.shiftKey||t.closest(`input, textarea, select, [contenteditable="true"]`))){if(e.key===`Escape`&&i().id)e.preventDefault(),S(i().id,-1);else if([`ArrowLeft`,`ArrowRight`].includes(e.key)&&(i().id||K(h)))e.preventDefault(),S(i().id||K(h),e.key===`ArrowLeft`?-1:1);else if(!i().id&&[`ArrowUp`,`ArrowDown`].includes(e.key)&&K(a).length){e.preventDefault();let t=K(a).findIndex(e=>e.id===K(h));x(K(a)[Math.max(0,Math.min(K(a).length-1,t+(e.key===`ArrowUp`?-1:1)))].id)}}}function w(e){return K(v)?`Last observation only — refresh unavailable. Check Codex for current state.`:e.status===`CHECK SESSION`?`INFERRED INACTIVITY — a quiet session, not a confirmed input or approval request. Local tools may still be running.`:$.data?.control&&[`APPROVAL NEEDED`,`INPUT NEEDED`].includes(e.status)?`Open full detail for supported live controls; otherwise reply in Codex.`:e.status===`APPROVAL NEEDED`?`OBSERVED APPROVAL SIGNAL — approve or decline in Codex.`:e.status===`INPUT NEEDED`?`OBSERVED INPUT SIGNAL — reply in Codex.`:e.status===`TURN COMPLETE`?`OBSERVED TURN COMPLETION — informational, not an approval request.`:``}function T(e){return e.streaming&&e.contextKind===`LAST REPLY`?`REPLY // STREAMING`:e.contextKind||`LAST ACTIVITY`}var E=fc();xr(`keydown`,Qt,C);var D=B(E),ee=V(H(z(D),2));P(D);var te=H(D,2);let O;Xr(te,21,()=>K(y),Kr,(e,t)=>{var n=F(()=>_(K(t),2));let r=()=>K(n)[0],i=()=>K(n)[1];var a=Vs(),o=z(a),s=V(o,!0),c=V(H(o,2),!0);P(a),U(()=>{X(s,r()),X(c,i())}),Y(e,a)}),P(te);var k=H(te,2),ne=V(k),re=H(k,2),ie=e=>{Y(e,Hs())};Z(re,e=>{K(v)&&e(ie)});var ae=H(re,2),oe=e=>{Y(e,Us())};Z(ae,e=>{$.data?.profileError&&e(oe)});var se=H(ae,2),A=e=>{var t=qs(),n=z(t);Xr(n,17,()=>K(b),Kr,(e,t)=>{var n=Ws();let r;var i=V(n);U((e,a)=>{r=ci(n,1,`button`,null,r,{approval:K(t).status===`APPROVAL NEEDED`}),Q(n,`href`,e),X(i,`${K(t).status??``} + ${a??``} // ${(K(t).name||K(t).directory||K(t).id)??``}`)},[()=>`#/sessions/`+encodeURIComponent(K(t).id),()=>Array.from(K(t).id).slice(-5).join(``).toUpperCase()]),q(`click`,n,()=>x(K(t).id)),Y(e,n)});var r=H(n,2);Xr(r,17,()=>K(o).filter(e=>e.pending&&K(a).some(t=>t.id===e.session)),Kr,(e,t)=>{var n=Gs(),r=V(n);U((e,a,o)=>{Q(n,`title`,i().id&&i().id!==K(t).session&&K(u)?`Finish sending or clear your current draft before switching sessions.`:`Review this session’s quota threshold`),Q(n,`href`,e),X(r,`QUOTA THRESHOLD ${a??``} // ${o??``}`)},[()=>`#/sessions/`+encodeURIComponent(K(t).session)+`?review=profile`,()=>Array.from(K(t).session).slice(-5).join(``).toUpperCase(),()=>K(a).find(e=>e.id===K(t).session)?.name||K(a).find(e=>e.id===K(t).session)?.directory||K(t).session]),q(`click`,n,e=>d(e,K(t).session)),Y(e,n)}),Xr(H(r,2),17,()=>K(s),Kr,(e,t)=>{var n=Ks(),r=V(n);U((e,t,i)=>{Q(n,`href`,e),X(r,`TRIGGER SET ${t??``} // ${i??``}`)},[()=>`#/sessions/`+encodeURIComponent(K(t).session),()=>Array.from(K(t).session).slice(-5).join(``).toUpperCase(),()=>K(a).find(e=>e.id===K(t).session)?.name||K(a).find(e=>e.id===K(t).session)?.directory]),q(`click`,n,e=>c(e,K(t).session)),Y(e,n)}),P(t),Y(e,t)},ce=F(()=>(K(b).length||K(o).some(e=>e.pending)||K(s).length)&&!K(v));Z(se,e=>{K(ce)&&e(A)});var le=H(se,2),ue=e=>{var t=Nr(),a=B(t),s=e=>{var t=Qs(),a=z(t),s=z(a),c=z(s);let d;var f=H(c);P(s);var h=H(s,2);P(a);var g=H(a,2),_=e=>{var t=zs(),n=V(t,!0);U(()=>X(n,K(p).directory)),Y(e,t)};Z(g,e=>{K(p).name&&K(p).directory&&e(_)});var y=H(g,2),b=V(y),S=H(y,2);let C;var w=z(S),T=z(w);n(T,()=>K(p),()=>!0,()=>!0),P(w);var E=H(w,2),D=e=>{var t=Nr();Gr(B(t),()=>K(p).id,e=>{{let t=F(()=>new URLSearchParams(Yi.querystring).get(`schedule`)===`edit`),n=F(()=>K(p).fileChanges||[]);xs(e,{get session(){return K(p).id},oncopy:()=>K(r)?.copy(),get openScheduler(){return K(t)},get observedCommand(){return K(p).command},get observedFileChanges(){return K(n)},get suspended(){return K(m)},onProtectedChange:e=>{R(u,e,!0)}})}}),Y(e,t)},ee=e=>{var t=Js();Gr(H(z(t),2),()=>K(p).id,e=>{Po(e,{get session(){return K(p).id},localOnly:!0,oncopy:()=>K(r)?.copy()})}),P(t),Y(e,t)};Z(E,e=>{$.data?.control?e(D):e(ee,-1)}),P(S);var te=H(S,2);Xr(te,17,()=>K(o).filter(e=>e.session===K(p).id),e=>e.session,(e,t)=>{var n=Zs(),r=z(n),i=e=>{var n=Ys(),r=V(n,!0);U(()=>X(r,K(t).notice)),Y(e,n)};Z(r,e=>{K(t).notice&&e(i)});var a=H(r,2),o=e=>{xs(e,{get session(){return K(p).id},review:`profile`})},s=e=>{var t=Xs();U(e=>Q(t,`href`,e),[()=>`#/sessions/`+encodeURIComponent(K(p).id)+`?review=profile`]),Y(e,t)};Z(a,e=>{K(t).pending&&K(m)?e(o):K(t).pending&&e(s,1)}),P(n),U(()=>Q(n,`id`,`quota-profile-`+K(p).id)),Y(e,n)});var O=H(te,2),k=e=>{var t=Nr();Gr(B(t),()=>K(p).id,e=>{Ii(Os(e,{get session(){return K(p)},active:!0}),e=>R(r,e,!0),()=>K(r))}),Y(e,t)};Z(O,e=>{K(m)||e(k)}),Gr(H(O,2),()=>K(p).id,e=>{Es(e,{get session(){return K(p)},get stale(){return K(v)}})}),P(t),U((e,t)=>{d=ci(c,1,`lamp lit`,null,d,{working:K(p).status===`WORKING`&&!K(v)}),X(f,`${e??``} // ${(K(p).name||K(p).directory)??``}`),X(b,`${t??``} TOKENS // ${K(p).id??``} // CONTEXT SOURCE // ${(K(p).source||`LOCAL`)??``}`),C=ui(S,``,C,{display:K(m)?`none`:void 0})},[()=>K(v)?`STALE`:K(m)?`QUOTA THRESHOLD`:l(K(p)),()=>pa(K(p).tokens)]),q(`click`,h,()=>{x(i().id),fa(i().id,2)}),Y(e,t)},c=e=>{Y(e,$s())};Z(a,e=>{K(p)?e(s):e(c,-1)}),Y(e,t)},de=e=>{var t=dc(),r=B(t),i=H(z(r),2),s=z(i),c=H(s,2);P(i),P(r);var u=H(r,2);Xr(u,17,()=>K(a),e=>e.id,(e,t)=>{let r=F(()=>ua(K(t).id));var i=lc();let a;var s=z(i),c=z(s),u=e=>{var n=ec(),r=z(n),i=V(r);P(n),U(e=>{Q(r,`aria-pressed`,K(h)===K(t).id),X(i,`${e??``} // ${K(t).name??``}`)},[()=>Array.from(K(t).id).slice(-5).join(``).toUpperCase()]),q(`click`,r,()=>x(K(t).id)),Y(e,n)};Z(c,e=>{K(t).name&&e(u)});var f=H(c,2),p=z(f),m=z(p);let g;var _=H(m,1,!0);P(p),P(f);var y=H(f,2),b=e=>{var n=tc(),r=V(n,!0);U(()=>{Q(n,`aria-pressed`,K(h)===K(t).id),X(r,K(t).directory||K(t).id)}),q(`click`,n,()=>x(K(t).id)),Y(e,n)};Z(y,e=>{K(t).name||e(b)});var C=H(y,2),w=z(C);xe(),P(C);var E=H(C,2),D=e=>{var n=zs(),r=V(n,!0);U(()=>X(r,K(t).directory)),Y(e,n)};Z(E,e=>{K(t).name&&K(t).directory&&e(D)});var ee=H(E,2),te=V(ee),O=H(ee,2),k=V(O),ne=H(O,2),re=z(ne),ie=H(re,2),ae=V(ie,!0),oe=H(ie,2);P(ne);var se=H(ne,2),A=H(se,2),ce=e=>{var n=nc(),r=V(n,!0);U(()=>X(r,K(t).status===`CHECK SESSION`?`INFERRED INACTIVITY`:$.data?.control?`OPEN FULL DETAIL OR REPLY IN CODEX`:K(t).status===`APPROVAL NEEDED`?`APPROVE OR DECLINE IN CODEX`:`REPLY IN CODEX`)),Y(e,n)},le=F(()=>!K(v)&&[`APPROVAL NEEDED`,`INPUT NEEDED`,`CHECK SESSION`].includes(K(t).status));Z(A,e=>{K(le)&&e(ce)}),P(s);var ue=H(s,2),de=e=>{var r=sc(),i=z(r),a=z(i),s=V(a,!0),c=H(a,2),l=e=>{var n=rc(),r=V(n,!0);U(e=>{Q(n,`href`,e),X(r,$.data?.control?`REVIEW IN FULL DETAIL ↗`:`APPROVAL IN CODEX ↗`)},[()=>`#/sessions/`+encodeURIComponent(K(t).id)]),Y(e,n)};Z(c,e=>{!K(v)&&K(t).status===`APPROVAL NEEDED`&&e(l)}),P(i);var u=H(i,2);n(u,()=>K(t),()=>!1);var f=H(u,2);Xr(f,17,()=>K(o).filter(e=>e.session===K(t).id),Kr,(e,n)=>{var r=oc(),i=B(r),a=e=>{var t=ic(),r=V(t,!0);U(()=>X(r,K(n).notice)),Y(e,t)};Z(i,e=>{K(n).notice&&e(a)});var o=H(i,2),s=e=>{var n=ac();U(e=>Q(n,`href`,e),[()=>`#/sessions/`+encodeURIComponent(K(t).id)+`?review=profile`]),q(`click`,n,e=>d(e,K(t).id)),Y(e,n)};Z(o,e=>{K(n).pending&&e(s)}),Y(e,r)});var p=H(f,2);{let e=F(()=>K(h)===K(t).id);Os(p,{get session(){return K(t)},get active(){return K(e)}})}P(r),U(e=>X(s,e),[()=>T(K(t))]),Y(e,r)};Z(ue,e=>{K(r)>0&&e(de)});var fe=H(ue,2),j=e=>{var n=cc(),r=H(z(n),2);{let e=F(()=>(K(t).samples||[]).map(e=>e.tokens));io(r,{get values(){return K(e)},capacity:120})}var i=V(H(r,2));P(n),U(()=>X(i,`LAST ${(K(t).samples?.length||0)??``} SAMPLES // AUTO SCALE`)),Y(e,n)};Z(fe,e=>{K(r)<2&&e(j)}),P(i),U((e,n,o,s,c)=>{a=ci(i,1,`session-row`,null,a,{selected:K(h)===K(t).id,wide:K(r)===2,split:K(r)===1}),Q(i,`aria-label`,`Session `+(K(t).name||K(t).directory||K(t).id)),Q(p,`href`,e),g=ci(m,1,`lamp lit`,null,g,{working:K(t).status===`WORKING`&&!K(v)}),X(_,n),X(w,`${o??``} `),X(te,`${K(t).agents??``} LINKED AGENTS`),X(k,`ACTIVE // ${s??``}`),re.disabled=K(r)===0,Q(ie,`aria-expanded`,K(r)>0),X(ae,K(r)?`HIDE DETAIL`:`SHOW DETAIL`),Q(se,`href`,c)},[()=>`#/sessions/`+encodeURIComponent(K(t).id),()=>K(v)?`STALE`:l(K(t)),()=>pa(K(t).tokens),()=>ma(K(t).activity),()=>`#/sessions/`+encodeURIComponent(K(t).id)]),q(`click`,p,()=>x(K(t).id)),q(`click`,re,()=>S(K(t).id,-1)),q(`click`,ie,()=>{x(K(t).id),fa(K(t).id,+!K(r))}),q(`click`,oe,()=>S(K(t).id,1)),q(`click`,se,()=>x(K(t).id)),Y(e,i)});var f=H(u,2),p=e=>{Y(e,uc())};Z(f,e=>{K(a).length||e(p)}),q(`click`,s,()=>da(1)),q(`click`,c,()=>da(0)),Y(e,t)};Z(le,e=>{i().id?e(ue):e(de,-1)}),U(e=>{X(ee,`OBSERVED ${e??``}`),O=ci(te,1,`session-totals`,null,O,{stale:K(v)}),X(ne,`${K(v)?`LAST KNOWN TOTALS — live state counts unavailable. `:``}Tokens observed since this server started for currently listed sessions; linked agents are already included. Totals can decrease when a session leaves the - list. History samples every 30 seconds. Not account-wide totals.`)},[()=>ma($.data?.sessionsAt)]),Y(e,E),We()}Sr([`click`]);var pc=J(`
`),mc=J(`
Relative usage/credits are not tokens or quota percentages. Groupings - describe the same usage, not additional consumption.
`,1),hc=J(`// APPROXIMATE`),gc=J(`Partial accounting: totals may still change.
`),_c=J(`
Percentage of this period's historical allowance, not today's limit. May - exceed 100%. This is not a manual/automatic reset log.
`,1),vc=J(`
`,1),yc=J(`
This optional account report is unavailable. Token history remains - available; missing data does not mean zero usage.
`),bc=J(`No usage reported for this day.
`),Cc=J(`Selected breakdown unavailable; missing does not mean zero.
`),wc=J(`
`),hc=J(`
Relative usage/credits are not tokens or quota percentages. Groupings + describe the same usage, not additional consumption.
`,1),gc=J(`// APPROXIMATE`),_c=J(`Partial accounting: totals may still change.
`),vc=J(`
Percentage of this period's historical allowance, not today's limit. May + exceed 100%. This is not a manual/automatic reset log.
`,1),yc=J(`
`,1),bc=J(`
This optional account report is unavailable. Token history remains + available; missing data does not mean zero usage.
`),xc=J(`No usage reported for this day.
`),wc=J(`Selected breakdown unavailable; missing does not mean zero.
`),Tc=J(`
History refresh failed. Any displayed history is the last successful - observation.
`),Mc=J(`Token history unavailable; other reports may still be available.
`),Nc=J(``),Pc=J(``),Fc=J(`LESS ░ ▒ ▓ █ MORE // HOVER FOR DATE AND TOKENS
`,1),Ic=J(`
DAYS
SECONDS
DAYS
OPENAI // UTC
| Date (UTC) | Tokens |
|---|
`,1),zc=J(`
History unavailable or awaiting a matching account observation. Missing - history is not treated as zero usage.
`),Bc=J(`Account-wide history reported by Codex, not the local Sessions counter. Dates + ${K(u)??``}`)},[()=>ma(K(i).fetchedAt),()=>m(K(f))]),Y(e,t)},ie=e=>{var t=yc(),n=B(t),r=z(n);let i;var o=V(r,!0),s=H(r),c=e=>{Y(e,gc())};Z(s,e=>{K(a).approximate&&e(c)});var u=H(s);P(n);var d=H(n,2),p=z(d),h=H(p),g=e=>{var t=Mr();U(()=>X(t,`// Boundary tolerance ${K(a).boundary_tolerance_seconds??``}s`)),Y(e,t)};Z(h,e=>{K(a).boundary_tolerance_seconds!=null&&e(g)}),P(d);var _=H(d,2),v=e=>{var t=vc(),n=B(t),r=z(n),i=H(r);let a;var o=V(i);P(n);var s=H(n,2),c=V(s),u=H(s,2),d=e=>{Y(e,_c())};Z(u,e=>{K(l).accounting_complete||e(d)}),xe(2),U(e=>{X(r,`${K(l).window_minutes??``} MIN // ${K(l).plan_type??``} // `),a=ci(i,1,`svelte-1fbui7h`,null,a,{muted:K(f)==null,"quota-near":K(f)!=null&&K(f)>=80&&K(f)<100,"quota-full":K(f)!=null&&K(f)>=100}),X(o,`USED ${e??``}${K(f)==null?``:`%`}`),X(c,`${K(l).starts_at??``} → ${K(l).ends_at??``}`)},[()=>m(K(f))]),Y(e,t)};Z(_,e=>{K(l)&&e(v)}),U(e=>{i=ci(r,1,`svelte-1fbui7h`,null,i,{"quality-warning":!K(a).coverage_complete}),X(o,K(a).coverage_complete?`Reported range complete`:`Partial coverage`),X(u,` // Latest fetch ${e??``}`),X(p,`Coverage starts ${(K(a).coverage_start||`unknown`)??``} // Data as of ${(K(a).data_as_of||`unknown`)??``}`)},[()=>ma(K(a).fetchedAt)]),Y(e,t)},ae=e=>{Y(e,bc())};Z(ne,e=>{t.mode===`breakdown`&&K(i)?e(re):t.mode===`periods`&&K(a)?e(ie,1):e(ae,-1)});var oe=H(ne,2),se=e=>{var n=Sc(),r=z(n),i=V(H(z(r),2),!0);P(r),Xr(H(r,2),17,()=>K(d),Kr,(e,n,r)=>{var i=F(()=>_(K(n),2));let a=()=>K(i)[0],o=()=>K(i)[1];var s=xc();let c;var l=z(s),u=V(l,!0),d=H(l,2),f=z(d);let h;P(d);var g=V(H(d,2));P(s),U((e,n,i)=>{c=ci(s,1,`report-row svelte-1fbui7h`,null,c,{unknown:e,alternate:r%2==1}),Q(l,`title`,a()),X(u,a()),h=ui(f,``,h,{width:n}),X(g,`${i??``}${t.mode===`periods`?`%`:``}`)},[()=>a().trim().toLowerCase()===`unknown`,()=>`${Math.max(0,100*o()/K(p))}%`,()=>m(o())]),Y(e,s)}),P(n),U(()=>X(i,t.mode===`breakdown`?K(u):`QUOTA USED`)),Y(e,n)},A=e=>{Y(e,Cc())},ce=e=>{Y(e,wc())};Z(oe,e=>{K(d).length?e(se):t.mode===`breakdown`&&K(c)?.total===0&&K(c)?.groups[K(n)]!=null?e(A,1):(K(i)&&t.mode===`breakdown`||K(a)&&t.mode===`periods`)&&e(ce,2)}),P(D),U(()=>{w.disabled=K(s)>=K(o)-1,T.disabled=K(s)===0,X(E,K(o)?`${K(s)+1} / ${K(o)}`:`NO DATA`),X(te,t.mode===`breakdown`?`DAILY BREAKDOWN`:`QUOTA WINDOWS`),X(k,`${(t.mode===`breakdown`?t.reports?.dailyStatus||`UNAVAILABLE`:t.reports?.planStatus||`UNAVAILABLE`)??``} // UTC`)}),hi(y,()=>K(n),e=>R(n,e)),q(`click`,w,()=>R(r,K(s)+1)),q(`click`,T,()=>R(r,K(s)-1)),Y(e,h),We()}Sr([`click`]);var Dc=864e5;function Oc(e,t){let n=new Date(e);n.setUTCDate(1),n.setUTCMonth(n.getUTCMonth()+t);let r=new Date(Date.UTC(n.getUTCFullYear(),n.getUTCMonth()+1,0)).getUTCDate();return n.setUTCDate(Math.min(e.getUTCDate(),r)),n}function kc(e,t,n){let r=new Date(Date.UTC(e.getUTCFullYear(),e.getUTCMonth(),e.getUTCDate()));for(let e=0;;e++){let i=Oc(r,-t),a=new Date(i.getTime()+Dc);if(e===n)return{start:a,end:r};r=i}}var Ac=J(``),jc=J(``,1),Mc=J(`
History refresh failed. Any displayed history is the last successful + observation.
`),Nc=J(`Token history unavailable; other reports may still be available.
`),Pc=J(``),Fc=J(``),Ic=J(`LESS ░ ▒ ▓ █ MORE // HOVER FOR DATE AND TOKENS
`,1),Lc=J(`
DAYS
SECONDS
DAYS
OPENAI // UTC
| Date (UTC) | Tokens |
|---|
`,1),Bc=J(`
History unavailable or awaiting a matching account observation. Missing + history is not treated as zero usage.
`),Vc=J(`Account-wide history reported by Codex, not the local Sessions counter. Dates use UTC. Allowance history is approximate where indicated; reset causes are - not provided.
`,1);function Vc(e,t){Ue(t,!0);let n=L(`daily`),r=L(12),i=L(0),a=F(()=>{let e=$.data?.usage?.dailyUsageBuckets;if(!e)return[];let{start:t,end:n}=Oc(new Date,K(r),K(i)),a=new Map;for(let t of e)!Number.isFinite(t.tokens)||t.tokens<0||a.set(t.startDate,(a.get(t.startDate)||0)+t.tokens);let o=[];for(let e=t;e<=n;e=new Date(e.getTime()+864e5)){let t=e.toISOString().slice(0,10);o.push({date:t,tokens:a.get(t)||0})}return o}),o=F(()=>Math.max(1,...K(a).map(e=>e.tokens))),s=F(()=>K(a).length?new Date(K(a)[0].date+`T00:00:00Z`).getUTCDay():0),c=F(()=>{if(K(n)===`monthly`){let e=new Map;for(let t of K(a))e.set(t.date.slice(0,7),(e.get(t.date.slice(0,7))||0)+t.tokens);return[...e].map(([e,t])=>({date:e,tokens:t}))}let e=0;return K(a).map(t=>({date:t.date,tokens:e+=t.tokens}))});var l=Bc(),u=H(B(l),4);Xr(u,20,()=>[[`daily`,`Daily`],[`monthly`,`Monthly`],[`cumulative`,`Cumulative`],[`breakdown`,`Breakdown`],[`periods`,`Windows`]],Kr,(e,t)=>{var r=F(()=>_(t,2));let a=()=>K(r)[0],o=()=>K(r)[1];var s=kc();let c;var l=V(s,!0);U(()=>{Q(s,`aria-pressed`,K(n)===a()),c=ci(s,1,``,null,c,{active:K(n)===a()}),X(l,o())}),q(`click`,s,()=>{R(n,a(),!0),R(i,0)}),Y(e,s)}),P(u);var d=H(u,2),f=z(d),p=e=>{var t=Ac(),n=B(t),a=H(z(n)),o=z(a);o.value=o.__value=6;var s=H(o);s.value=s.__value=12,P(a),mi(a),P(n);var c=H(n),l=H(c);U(()=>l.disabled=K(i)===0),q(`change`,a,()=>R(i,0)),hi(a,()=>K(r),e=>R(r,e)),q(`click`,c,()=>Kt(i)),q(`click`,l,()=>Kt(i,-1)),Y(e,t)};Z(f,e=>{K(n)!==`breakdown`&&K(n)!==`periods`&&e(p)}),P(d);var m=H(d,2),h=e=>{Y(e,jc())};Z(m,e=>{$.data?.usageError&&e(h)});var g=H(m,2),v=e=>{Y(e,Mc())};Z(g,e=>{$.data?.usage?.tokenStatus===`UNAVAILABLE`&&K(n)!==`breakdown`&&K(n)!==`periods`&&e(v)});var y=H(g,2),b=e=>{var t=Nr();Gr(B(t),()=>K(n),e=>{{let t=F(()=>$.data?.usage?.reports);Tc(e,{get reports(){return K(t)},get mode(){return K(n)}})}}),Y(e,t)},x=e=>{var t=Rc(),r=B(t),i=z(r),l=V(H(z(i),2),!0);P(i);var u=H(i,2),d=V(H(z(u),2),!0);P(u);var f=H(u,2),p=H(z(f),2),m=z(p);xe(),P(p),P(f);var h=H(f,2),g=H(z(h),2),_=z(g);xe(),P(g),P(h);var v=H(h,2),y=H(z(v),2),b=z(y);xe(),P(y),P(v),P(r);var x=H(r,4),S=z(x),C=V(S),w=H(S,2),T=e=>{var t=Fc(),n=B(t),r=z(n),i=z(r);Xr(i,17,()=>Array(K(s)),Kr,(e,t)=>{Y(e,Nc())}),Xr(H(i,2),17,()=>K(a),Kr,(e,t)=>{var n=Pc();let r,i;U(e=>{r=ci(n,1,`heat-cell`,null,r,{zero:K(t).tokens===0}),Q(n,`title`,e),i=ui(n,``,i,{opacity:K(t).tokens?.25+.75*K(t).tokens/K(o):1})},[()=>`${K(t).date}: ${pa(K(t).tokens)} tokens`]),Y(e,n)}),P(r),P(n),xe(2),Y(e,t)},E=e=>{var t=Ic(),r=B(t);{let e=F(()=>K(c).map(e=>e.tokens)),t=F(()=>K(n)+` usage`);ro(r,{get values(){return K(e)},get label(){return K(t)}})}var i=H(r,2),a=z(i),o=V(a,!0),s=V(H(a),!0);P(i),U(e=>{X(o,K(c)[0]?.date),X(s,e)},[()=>K(c).at(-1)?.date]),Y(e,t)};Z(w,e=>{K(n)===`daily`?e(T):e(E,-1)});var D=H(w,2),ee=H(z(D),2),te=z(ee),O=H(z(te));Xr(O,21,()=>K(n)===`daily`?K(a):K(c),Kr,(e,t)=>{var n=Lc(),r=z(n),i=V(r,!0),a=V(H(r),!0);P(n),U(e=>{X(i,K(t).date),X(a,e)},[()=>pa(K(t).tokens)]),Y(e,n)}),P(O),P(te),P(ee),P(D),P(x);var k=V(H(x,2));U((e,t,n,r,i,o,s)=>{X(l,e),X(d,t),X(m,`${n??``} `),X(_,`${r??``} `),X(b,`${i??``} `),X(C,`${K(a)[0]?.date??``} — ${o??``}`),X(k,`OBSERVED ${s??``} // CUMULATIVE IS FOR THE SELECTED PERIOD`)},[()=>pa($.data.usage.summary.lifetimeTokens),()=>pa($.data.usage.summary.peakDailyTokens),()=>pa($.data.usage.summary.currentStreakDays),()=>pa($.data.usage.summary.longestRunningTurnSec),()=>pa($.data.usage.summary.longestStreakDays),()=>K(a).at(-1)?.date,()=>ma($.data.usageAt)]),Y(e,t)},S=e=>{Y(e,zc())};Z(y,e=>{K(n)===`breakdown`||K(n)===`periods`?e(b):$.data?.usage&&$.data.usage.dailyUsageBuckets!==null?e(x,1):e(S,-1)}),Y(e,l),We()}Sr([`click`,`change`]);var Hc=J(``),dl=J(`
Connecting to your local Codexometer…
`),fl=J(``),pl=J(``);function ml(e,t){Ue(t,!0);let n={"/":eo,"/quota/:view?":eo,"/sessions/:id?":fc,"/usage":Vc,"*":Uc},r={quota:/^(?:\/|\/quota(?:\/[^/]+)?\/?)$/,sessions:/^\/sessions(?:\/[^/]+)?\/?$/,usage:/^\/usage\/?$/},i=L(`hacker`),a=L(!0),o=L(void 0);vn(()=>{sa.requests&&lr().then(()=>{K(o)?.focus(),K(o)?.scrollIntoView({block:`nearest`})})});let s=L(void 0),c=[`hacker`,`rust`,`blue-steel`,`ultraviolet`,`nightshade`];vn(()=>{ca()}),vn(()=>{if($.data)for(let[e,t]of Object.entries(r))t.test(Yi.location)&&(aa.tab=e)}),Gi(()=>{try{let e=localStorage.getItem(`codexometer.web.theme`);e&&c.includes(e)&&R(i,e,!0)}catch{}return ya()});function l(){try{localStorage.setItem(`codexometer.web.theme`,K(i))}catch{}}var u=pl(),d=z(u),f=z(d),p=z(f);al(z(p),{}),P(p),Ii(p,e=>R(s,e),()=>K(s)),xe(2),P(f);var m=H(f,2),h=z(m);let g;var v=H(h,1,!0),y=V(H(v));P(m),P(d);var b=H(d,2);Xr(b,21,()=>Object.entries(r),Kr,(e,t)=>{var n=F(()=>_(K(t),2));let r=()=>K(n)[0],i=()=>K(n)[1],a=F(()=>i().test(Yi.location));var o=ll();let s;var c=V(o,!0);U(e=>{Q(o,`href`,r()===`quota`?`#/quota/`+aa.view:`#/`+r()),Q(o,`aria-current`,K(a)?`page`:void 0),s=ci(o,1,``,null,s,{active:K(a)}),X(c,e)},[()=>r().toUpperCase()]),Y(e,o)}),P(b);var x=H(b,2),S=z(x),C=e=>{var t=ul(),n=V(t,!0);U(()=>X(n,$.error)),Y(e,t)};Z(S,e=>{$.error&&e(C)});var w=H(S,2),T=e=>{$i(e,{get routes(){return n}})},E=e=>{Y(e,dl())};Z(w,e=>{$.data?e(T):$.error||e(E,1)}),P(x);var D=H(x,2),ee=z(D),te=V(ee),O=H(ee,2),k=V(O,!0),ne=H(O,2),re=H(z(ne));Xr(re,21,()=>c,Kr,(e,t)=>{var n=fl(),r=V(n,!0),i={};U(e=>{X(r,e),i!==(i=K(t))&&(n.value=(n.__value=i)??``)},[()=>K(t).replace(`-`,` `).toUpperCase()]),Y(e,n)}),P(re),Ii(re,e=>R(o,e),()=>K(o)),mi(re),P(ne),P(D);var ie=H(D,2),ae=e=>{cl(e,{get target(){return K(s)},onfinish:()=>R(a,!1)})};Z(ie,e=>{K(a)&&e(ae)}),P(u),U(()=>{Q(u,`data-theme`,K(i)),Q(u,`data-starting`,K(a)),d.inert=K(a),g=ci(h,1,`lamp`,null,g,{lit:$.connected}),X(v,$.connected?`CONNECTED`:`OFFLINE`),X(y,`EXPERIMENTAL // ${$.data?.control?`SESSION CONTROL`:`READ ONLY`}`),b.inert=K(a),x.inert=K(a),D.inert=K(a),X(te,`v${($.data?.version||`…`)??``} // LOCAL ONLY`),X(k,$.data?.control?`Session control enabled. Stop the server to revoke access.`:`No actions can be sent from this preview.`)}),q(`change`,re,l),hi(re,()=>K(i),e=>R(i,e)),Y(e,u),We()}Sr([`change`]),zr(ml,{target:document.getElementById(`app`)}); \ No newline at end of file + not provided. `,1);function Hc(e,t){Ue(t,!0);let n=L(`daily`),r=L(12),i=L(0),a=F(()=>{let e=$.data?.usage?.dailyUsageBuckets;if(!e)return[];let{start:t,end:n}=kc(new Date,K(r),K(i)),a=new Map;for(let t of e)!Number.isFinite(t.tokens)||t.tokens<0||a.set(t.startDate,(a.get(t.startDate)||0)+t.tokens);let o=[];for(let e=t;e<=n;e=new Date(e.getTime()+864e5)){let t=e.toISOString().slice(0,10);o.push({date:t,tokens:a.get(t)||0})}return o}),o=F(()=>Math.max(1,...K(a).map(e=>e.tokens))),s=F(()=>K(a).length?new Date(K(a)[0].date+`T00:00:00Z`).getUTCDay():0),c=F(()=>{if(K(n)===`monthly`){let e=new Map;for(let t of K(a))e.set(t.date.slice(0,7),(e.get(t.date.slice(0,7))||0)+t.tokens);return[...e].map(([e,t])=>({date:e,tokens:t}))}let e=0;return K(a).map(t=>({date:t.date,tokens:e+=t.tokens}))});var l=Vc(),u=H(B(l),4);Xr(u,20,()=>[[`daily`,`Daily`],[`monthly`,`Monthly`],[`cumulative`,`Cumulative`],[`breakdown`,`Breakdown`],[`periods`,`Windows`]],Kr,(e,t)=>{var r=F(()=>_(t,2));let a=()=>K(r)[0],o=()=>K(r)[1];var s=Ac();let c;var l=V(s,!0);U(()=>{Q(s,`aria-pressed`,K(n)===a()),c=ci(s,1,``,null,c,{active:K(n)===a()}),X(l,o())}),q(`click`,s,()=>{R(n,a(),!0),R(i,0)}),Y(e,s)}),P(u);var d=H(u,2),f=z(d),p=e=>{var t=jc(),n=B(t),a=H(z(n)),o=z(a);o.value=o.__value=6;var s=H(o);s.value=s.__value=12,P(a),mi(a),P(n);var c=H(n),l=H(c);U(()=>l.disabled=K(i)===0),q(`change`,a,()=>R(i,0)),hi(a,()=>K(r),e=>R(r,e)),q(`click`,c,()=>Kt(i)),q(`click`,l,()=>Kt(i,-1)),Y(e,t)};Z(f,e=>{K(n)!==`breakdown`&&K(n)!==`periods`&&e(p)}),P(d);var m=H(d,2),h=e=>{Y(e,Mc())};Z(m,e=>{$.data?.usageError&&e(h)});var g=H(m,2),v=e=>{Y(e,Nc())};Z(g,e=>{$.data?.usage?.tokenStatus===`UNAVAILABLE`&&K(n)!==`breakdown`&&K(n)!==`periods`&&e(v)});var y=H(g,2),b=e=>{var t=Nr();Gr(B(t),()=>K(n),e=>{{let t=F(()=>$.data?.usage?.reports);Ec(e,{get reports(){return K(t)},get mode(){return K(n)}})}}),Y(e,t)},x=e=>{var t=zc(),r=B(t),i=z(r),l=V(H(z(i),2),!0);P(i);var u=H(i,2),d=V(H(z(u),2),!0);P(u);var f=H(u,2),p=H(z(f),2),m=z(p);xe(),P(p),P(f);var h=H(f,2),g=H(z(h),2),_=z(g);xe(),P(g),P(h);var v=H(h,2),y=H(z(v),2),b=z(y);xe(),P(y),P(v),P(r);var x=H(r,4),S=z(x),C=V(S),w=H(S,2),T=e=>{var t=Ic(),n=B(t),r=z(n),i=z(r);Xr(i,17,()=>Array(K(s)),Kr,(e,t)=>{Y(e,Pc())}),Xr(H(i,2),17,()=>K(a),Kr,(e,t)=>{var n=Fc();let r,i;U(e=>{r=ci(n,1,`heat-cell`,null,r,{zero:K(t).tokens===0}),Q(n,`title`,e),i=ui(n,``,i,{opacity:K(t).tokens?.25+.75*K(t).tokens/K(o):1})},[()=>`${K(t).date}: ${pa(K(t).tokens)} tokens`]),Y(e,n)}),P(r),P(n),xe(2),Y(e,t)},E=e=>{var t=Lc(),r=B(t);{let e=F(()=>K(c).map(e=>e.tokens)),t=F(()=>K(n)+` usage`);io(r,{get values(){return K(e)},get label(){return K(t)}})}var i=H(r,2),a=z(i),o=V(a,!0),s=V(H(a),!0);P(i),U(e=>{X(o,K(c)[0]?.date),X(s,e)},[()=>K(c).at(-1)?.date]),Y(e,t)};Z(w,e=>{K(n)===`daily`?e(T):e(E,-1)});var D=H(w,2),ee=H(z(D),2),te=z(ee),O=H(z(te));Xr(O,21,()=>K(n)===`daily`?K(a):K(c),Kr,(e,t)=>{var n=Rc(),r=z(n),i=V(r,!0),a=V(H(r),!0);P(n),U(e=>{X(i,K(t).date),X(a,e)},[()=>pa(K(t).tokens)]),Y(e,n)}),P(O),P(te),P(ee),P(D),P(x);var k=V(H(x,2));U((e,t,n,r,i,o,s)=>{X(l,e),X(d,t),X(m,`${n??``} `),X(_,`${r??``} `),X(b,`${i??``} `),X(C,`${K(a)[0]?.date??``} — ${o??``}`),X(k,`OBSERVED ${s??``} // CUMULATIVE IS FOR THE SELECTED PERIOD`)},[()=>pa($.data.usage.summary.lifetimeTokens),()=>pa($.data.usage.summary.peakDailyTokens),()=>pa($.data.usage.summary.currentStreakDays),()=>pa($.data.usage.summary.longestRunningTurnSec),()=>pa($.data.usage.summary.longestStreakDays),()=>K(a).at(-1)?.date,()=>ma($.data.usageAt)]),Y(e,t)},S=e=>{Y(e,Bc())};Z(y,e=>{K(n)===`breakdown`||K(n)===`periods`?e(b):$.data?.usage&&$.data.usage.dailyUsageBuckets!==null?e(x,1):e(S,-1)}),Y(e,l),We()}Sr([`click`,`change`]);var Uc=J(``),fl=J(`
Connecting to your local Codexometer…
`),pl=J(``),ml=J(``);function hl(e,t){Ue(t,!0);let n={"/":to,"/quota/:view?":to,"/sessions/:id?":pc,"/usage":Hc,"*":Wc},r={quota:/^(?:\/|\/quota(?:\/[^/]+)?\/?)$/,sessions:/^\/sessions(?:\/[^/]+)?\/?$/,usage:/^\/usage\/?$/},i=L(`hacker`),a=L(!0),o=L(void 0);vn(()=>{sa.requests&&lr().then(()=>{K(o)?.focus(),K(o)?.scrollIntoView({block:`nearest`})})});let s=L(void 0),c=[`hacker`,`rust`,`blue-steel`,`ultraviolet`,`nightshade`];vn(()=>{ca()}),vn(()=>{if($.data)for(let[e,t]of Object.entries(r))t.test(Yi.location)&&(aa.tab=e)}),Gi(()=>{try{let e=localStorage.getItem(`codexometer.web.theme`);e&&c.includes(e)&&R(i,e,!0)}catch{}return ya()});function l(){try{localStorage.setItem(`codexometer.web.theme`,K(i))}catch{}}var u=ml(),d=z(u),f=z(d),p=z(f);ol(z(p),{}),P(p),Ii(p,e=>R(s,e),()=>K(s)),xe(2),P(f);var m=H(f,2),h=z(m);let g;var v=H(h,1,!0),y=V(H(v));P(m),P(d);var b=H(d,2);Xr(b,21,()=>Object.entries(r),Kr,(e,t)=>{var n=F(()=>_(K(t),2));let r=()=>K(n)[0],i=()=>K(n)[1],a=F(()=>i().test(Yi.location));var o=ul();let s;var c=V(o,!0);U(e=>{Q(o,`href`,r()===`quota`?`#/quota/`+aa.view:`#/`+r()),Q(o,`aria-current`,K(a)?`page`:void 0),s=ci(o,1,``,null,s,{active:K(a)}),X(c,e)},[()=>r().toUpperCase()]),Y(e,o)}),P(b);var x=H(b,2),S=z(x),C=e=>{var t=dl(),n=V(t,!0);U(()=>X(n,$.error)),Y(e,t)};Z(S,e=>{$.error&&e(C)});var w=H(S,2),T=e=>{$i(e,{get routes(){return n}})},E=e=>{Y(e,fl())};Z(w,e=>{$.data?e(T):$.error||e(E,1)}),P(x);var D=H(x,2),ee=z(D),te=V(ee),O=H(ee,2),k=V(O,!0),ne=H(O,2),re=H(z(ne));Xr(re,21,()=>c,Kr,(e,t)=>{var n=pl(),r=V(n,!0),i={};U(e=>{X(r,e),i!==(i=K(t))&&(n.value=(n.__value=i)??``)},[()=>K(t).replace(`-`,` `).toUpperCase()]),Y(e,n)}),P(re),Ii(re,e=>R(o,e),()=>K(o)),mi(re),P(ne),P(D);var ie=H(D,2),ae=e=>{ll(e,{get target(){return K(s)},onfinish:()=>R(a,!1)})};Z(ie,e=>{K(a)&&e(ae)}),P(u),U(()=>{Q(u,`data-theme`,K(i)),Q(u,`data-starting`,K(a)),d.inert=K(a),g=ci(h,1,`lamp`,null,g,{lit:$.connected}),X(v,$.connected?`CONNECTED`:`OFFLINE`),X(y,`EXPERIMENTAL // ${$.data?.control?`SESSION CONTROL`:`READ ONLY`}`),b.inert=K(a),x.inert=K(a),D.inert=K(a),X(te,`v${($.data?.version||`…`)??``} // LOCAL ONLY`),X(k,$.data?.control?`Session control enabled. Stop the server to revoke access.`:`No actions can be sent from this preview.`)}),q(`change`,re,l),hi(re,()=>K(i),e=>R(i,e)),Y(e,u),We()}Sr([`change`]),zr(hl,{target:document.getElementById(`app`)}); \ No newline at end of file diff --git a/internal/web/dist/assets/index-Bjr_1drg.css b/internal/web/dist/assets/index-Bjr_1drg.css new file mode 100644 index 0000000..85fdd1b --- /dev/null +++ b/internal/web/dist/assets/index-Bjr_1drg.css @@ -0,0 +1 @@ +.observation-details.svelte-1vgdi83{font-size:12px}summary.svelte-1vgdi83{cursor:pointer;color:var(--accent)}.observation-table.svelte-1vgdi83{max-height:240px;overflow:auto}.zone-canvas.svelte-1vgdi83{flex:1;min-height:170px;margin-top:6px;position:relative}svg.svelte-1vgdi83{width:100%;height:100%;display:block;position:absolute;inset:0}text.svelte-1vgdi83{fill:var(--ink);font:14px Cascadia Code,Consolas,monospace}.axis-title.svelte-1vgdi83{letter-spacing:.04em;font-size:12px}.grid.svelte-1vgdi83{stroke:#fff;stroke-opacity:.14;stroke-width:1px}.axes.svelte-1vgdi83{stroke:var(--ink);stroke-width:1.5px;fill:none}.pace-line.svelte-1vgdi83{stroke:#fff;stroke-width:2px;stroke-dasharray:6 4}.position-halo.svelte-1vgdi83{fill:#101820;stroke:#fff;stroke-width:1.5px}.position-dot.svelte-1vgdi83{fill:#fff}.observation-trail.svelte-1vgdi83{fill:none;stroke:#101820;stroke-width:2.5px;stroke-linejoin:round}.observation-trail-casing.svelte-1vgdi83{fill:none;stroke:#ffffff73;stroke-width:4.5px;stroke-linejoin:round}.trail-start.svelte-1vgdi83{fill:#101820;stroke:#ffffffb3;stroke-width:2px}.trend-line.svelte-1vgdi83{fill:none;stroke:var(--trend-color);stroke-width:2px;stroke-dasharray:3 6}.trend-arrow.svelte-1vgdi83{fill:var(--trend-color);stroke:#ffffff73;stroke-width:.5px}.trend-casing.svelte-1vgdi83{fill:none;stroke:#ffffff73;stroke-width:4px;stroke-dasharray:3 6}.zone-caption.svelte-1vgdi83{min-width:0;color:var(--accent);flex:auto;margin:0}.trend-summary.svelte-1vgdi83{color:var(--ink)}.zone-footer.svelte-1vgdi83{justify-content:space-between;align-items:flex-start;gap:12px;margin-top:4px;display:flex}.zone-controls.svelte-1vgdi83{color:var(--muted);text-align:right;flex-direction:column;align-items:flex-end;gap:5px;font-size:11px;display:flex}.trace-control.svelte-1vgdi83,.trend-control.svelte-1vgdi83{cursor:pointer;white-space:nowrap}.trace-control.svelte-1vgdi83 input:where(.svelte-1vgdi83){accent-color:var(--accent)}.trend-control.svelte-1vgdi83 select:where(.svelte-1vgdi83){border:1px solid var(--edge);background:var(--panel);max-width:min(230px,45vw);color:var(--ink);font:inherit}.trend-control.svelte-1vgdi83 option:where(.svelte-1vgdi83):disabled{color:var(--muted)}.zone-controls.svelte-1vgdi83 small:where(.svelte-1vgdi83){font-size:10px}@container (width<=560px){.zone-footer.svelte-1vgdi83{flex-direction:column}.zone-controls.svelte-1vgdi83{align-self:stretch;align-items:flex-end}}.usage-diagnostic.svelte-16u6dmb{white-space:pre-wrap;overflow-wrap:anywhere}.slash-commands.svelte-7bfwr9{margin:.4rem 0;position:relative}.command-popup.svelte-7bfwr9{z-index:5;box-sizing:border-box;border:1px solid var(--accent);background:var(--panel);width:min(40rem,100%);padding:.35rem;position:absolute;bottom:100%;left:0;box-shadow:0 .3rem 1rem #0006}.command-popup.svelte-7bfwr9 p:where(.svelte-7bfwr9){margin:.3rem 0;font-size:.8em}.command-options.vertical.svelte-7bfwr9{flex-flow:column;gap:.15rem;display:flex}.vertical.svelte-7bfwr9 button:where(.svelte-7bfwr9){text-align:left;white-space:nowrap;width:100%;min-width:0;color:var(--muted);background:var(--panel);border-color:#0000;flex:none;align-items:baseline;gap:.4rem;display:flex}.vertical.svelte-7bfwr9 .command-name:where(.svelte-7bfwr9),.vertical.svelte-7bfwr9 .command-tail:where(.svelte-7bfwr9){flex:none}.vertical.svelte-7bfwr9 .command-name:where(.svelte-7bfwr9){text-overflow:ellipsis;max-width:100%;overflow:hidden}.vertical.svelte-7bfwr9 button.suggested:where(.svelte-7bfwr9){outline:none}.command-options.svelte-7bfwr9 button.suggested:where(.svelte-7bfwr9) .command-name:where(.svelte-7bfwr9){color:var(--ink);font-weight:700}.command-options.svelte-7bfwr9 button:where(.svelte-7bfwr9):not(.suggested):hover .command-name:where(.svelte-7bfwr9){text-decoration:underline}.command-options.svelte-7bfwr9 button:where(.svelte-7bfwr9){color:var(--muted)}.vertical.svelte-7bfwr9 .command-help:where(.svelte-7bfwr9){min-width:0;max-width:none;color:var(--muted);flex:1}.command-options.svelte-7bfwr9{flex-wrap:wrap;gap:.35rem;max-height:35vh;display:flex;overflow:auto}.command-options.svelte-7bfwr9 .suggested:where(.svelte-7bfwr9){outline:none}.command-help.svelte-7bfwr9{text-overflow:ellipsis;white-space:nowrap;opacity:.75;max-width:32ch;font-size:.8em;display:block;overflow:hidden}.command-actions.svelte-7bfwr9{flex-wrap:wrap;gap:.35rem;margin-top:.4rem;display:flex}.availability.svelte-7bfwr9{font-weight:600}.navigation.svelte-7bfwr9{font-size:.8em}pre.svelte-7bfwr9{white-space:pre-wrap;overflow-wrap:anywhere;max-height:35vh;overflow:auto}.file-diff.svelte-x4gtb6{border:1px solid var(--muted);max-height:60vh;padding:.5rem;font-family:monospace;overflow:auto}.diff-line.svelte-x4gtb6{white-space:pre;min-height:1.3em;display:flex}.line-number.svelte-x4gtb6{text-align:right;opacity:.75;-webkit-user-select:none;user-select:none;flex:0 0 5ch;padding-right:1ch;display:inline-block}.added.svelte-x4gtb6{color:#67d391;background:#67d39112}.removed.svelte-x4gtb6{color:#ff6b83;background:#ff6b8312}.heading.svelte-x4gtb6{padding:.5rem 0;font-weight:700}.saved-prompt.svelte-1oupzfc{white-space:pre-wrap;overflow-wrap:anywhere}fieldset.svelte-1oupzfc{border:1px solid;margin:.5rem 0;padding:.35rem .6rem}.decision.svelte-1oupzfc,.answer.svelte-1oupzfc{margin:.3rem 0;display:block}.decision.svelte-1oupzfc code:where(.svelte-1oupzfc),.decision.svelte-1oupzfc span:where(.svelte-1oupzfc){overflow-wrap:anywhere;margin:.3rem 0 .3rem 1.5rem;display:block}textarea.svelte-1oupzfc,.answer.svelte-1oupzfc input:where(.svelte-1oupzfc),.answer.svelte-1oupzfc select:where(.svelte-1oupzfc){box-sizing:border-box;background:var(--bg);width:100%;color:inherit;font:inherit;border:1px solid;margin-top:.4rem;padding:.5rem;display:block}textarea.svelte-1oupzfc{resize:vertical;background:color-mix(in srgb, currentColor 8%, var(--bg))}button.svelte-1oupzfc{margin:.3rem .5rem .3rem 0}h3.svelte-1oupzfc,p.svelte-1oupzfc{margin-block:.4rem}.sent.svelte-1oupzfc{color:var(--accent)}.status-line.svelte-gprptn{align-items:center;gap:.5rem;min-width:0;margin-top:.5rem;display:flex}.status-line.svelte-gprptn p:where(.svelte-gprptn){white-space:nowrap;text-overflow:ellipsis;flex:1;min-width:0;margin:0;font-size:.8rem;overflow:hidden}.configure.svelte-gprptn{padding:.15rem .35rem;font-size:.75rem}.status-picker.svelte-gprptn{border:1px solid var(--edge);margin:.5rem 0;padding:.6rem}.fields.svelte-gprptn{max-height:35vh;overflow:auto}.field.svelte-gprptn{align-items:center;gap:.35rem;display:flex}.field.svelte-gprptn label:where(.svelte-gprptn){flex:1;align-items:center;gap:.4rem;display:flex}.field.svelte-gprptn label:where(.svelte-gprptn) span:where(.svelte-gprptn){font-size:.75rem}.field.svelte-gprptn button:where(.svelte-gprptn){padding:.1rem .35rem}.session-copy.svelte-543j00{justify-content:flex-end;align-items:center;gap:8px;margin-top:auto;padding-top:6px;display:flex}span.svelte-543j00{color:var(--muted);overflow-wrap:anywhere;font-size:12px}button.svelte-543j00{color:var(--accent);flex-shrink:0;padding:3px 7px}button.svelte-543j00:hover,button.flashed.svelte-543j00{color:var(--bg);background:var(--accent)}h3.svelte-1fbui7h,.window-dates.svelte-1fbui7h,.report-value.svelte-1fbui7h{color:var(--accent);font-weight:700}.quality-warning.svelte-1fbui7h,.quota-near.svelte-1fbui7h{color:var(--approval)}.quota-full.svelte-1fbui7h{color:#ff6680}.alternate.svelte-1fbui7h .report-fill:where(.svelte-1fbui7h){background:radial-gradient(circle, var(--panel) .7px, transparent .9px) 0 0 / 3px 3px, var(--accent)}.unknown.svelte-1fbui7h,.unknown.svelte-1fbui7h .report-value:where(.svelte-1fbui7h){color:var(--muted)}.unknown.svelte-1fbui7h .report-fill:where(.svelte-1fbui7h){background:var(--muted);opacity:1}.report-bars.svelte-1fbui7h{grid-template-columns:minmax(5rem,1fr) minmax(2rem,3fr) auto;gap:.6rem;display:grid}.report-row.svelte-1fbui7h,.report-head.svelte-1fbui7h{grid-column:1/-1;grid-template-columns:subgrid;align-items:center;gap:.6rem;display:grid}.report-head.svelte-1fbui7h{color:var(--muted);font-size:.85rem}.report-head.svelte-1fbui7h>span:where(.svelte-1fbui7h):last-child,.report-value.svelte-1fbui7h{text-align:right}.report-row.svelte-1fbui7h>span:where(.svelte-1fbui7h):first-child{overflow-wrap:anywhere}.report-track.svelte-1fbui7h{background:var(--panel);height:1rem}.report-fill.svelte-1fbui7h{background:var(--accent);height:100%}svg.svelte-1jpy949{fill:currentColor;width:100%;height:auto;display:block}.startup.svelte-19xbbtg{z-index:100;background:var(--bg);color:var(--accent);position:fixed;inset:0;overflow:hidden}.wordmark.svelte-19xbbtg{position:absolute}button.svelte-19xbbtg{color:var(--muted);font:inherit;white-space:nowrap;background:0 0;border:0;font-size:12px;position:absolute;bottom:24px;left:50%;transform:translate(-50%)}:root{font-synthesis:none;--lightningcss-light: ;--lightningcss-dark:initial;color-scheme:dark;background:#080e0c;font-family:Cascadia Code,SFMono-Regular,Consolas,monospace}*{box-sizing:border-box}body{margin:0}.shell{--accent:#80edac;--approval:#ffca58;--muted:#98aaa0;--edge:#31473a;--panel:#101c16;--bg:#080e0c;--ink:#e2eee5;background:var(--bg);height:100dvh;color:var(--ink);grid-template-rows:auto auto minmax(0,1fr) auto;padding:clamp(10px,1.2vw,20px);display:grid}.shell[data-theme=rust]{--approval:#ff8a3d;--accent:#ffbc75;--muted:#bfac95;--edge:#59412c;--panel:#261b14;--bg:#140e0a}.shell[data-theme=blue-steel]{--approval:#e8c46a;--accent:#85c8ff;--muted:#9cacc4;--edge:#334d69;--panel:#142235;--bg:#0b1421}.shell[data-theme=ultraviolet]{--approval:#f9a8d4;--accent:#c5adff;--muted:#b3a6c9;--edge:#4b3c68;--panel:#241a35;--bg:#140d22}.shell[data-theme=nightshade]{--approval:#8f7cff;--accent:#e59bff;--muted:#c6a7cf;--edge:#673976;--panel:#301739;--bg:#1c0b24}header,.spread,footer,.controls{flex-wrap:wrap;justify-content:space-between;align-items:center;gap:10px;display:flex}header{margin-bottom:10px}.shell[data-starting=true]>header,.shell[data-starting=true]>nav,.shell[data-starting=true]>main,.shell[data-starting=true]>footer{visibility:hidden}.brand{width:clamp(240px,32vw,405px);max-width:calc(100vw - 40px);color:var(--accent);text-decoration:none;display:block}header p{color:var(--muted);margin:3px 0 0;font-size:13px}.connection{color:var(--accent);text-align:right}small,.eyebrow{letter-spacing:.04em;font-size:12px}.connection small{color:var(--muted);margin-top:4px;display:block}.lamp{background:var(--muted);border-radius:50%;width:9px;height:9px;margin-right:9px;display:inline-block}.lamp.lit{background:var(--accent);box-shadow:0 0 8px color-mix(in srgb, var(--accent) 40%, transparent)}.working{animation:1.5s ease-in-out infinite pulse}@keyframes pulse{50%{opacity:.3}}nav{flex-wrap:wrap;gap:6px;margin-bottom:10px;display:flex}nav a,button,.button,select{font:inherit;color:var(--accent);border:1px solid var(--edge);background:var(--panel);cursor:pointer;border-radius:3px;padding:7px 11px;font-size:13px;text-decoration:none}button:hover,.button:hover,nav a:hover{border-color:var(--accent)}nav a.active,nav button.active{background:var(--accent);color:var(--bg);border-color:var(--accent)}:focus-visible{outline:2px solid var(--accent);outline-offset:4px}.secondary{margin-bottom:8px}.secondary a,.secondary button{padding:6px 10px;font-size:12px}main{scrollbar-gutter:stable;flex-direction:column;min-width:0;min-height:0;display:flex;overflow:auto}main>*{flex-shrink:0}.panel{border:1px solid var(--edge);border-top:2px solid var(--accent);background:var(--panel);border-radius:4px;min-width:0;padding:clamp(10px,1vw,16px)}h1{color:var(--accent);font-size:20px}h2{letter-spacing:.04em;color:var(--accent);overflow-wrap:anywhere;margin:0 0 10px;font-size:13px}h3{overflow-wrap:anywhere;font-size:13px}p{margin:6px 0;font-size:13px;line-height:1.45}a{color:var(--accent)}.muted,.eyebrow{color:var(--muted)}.notice{color:#ffe0aa;background:#332611;border-left:3px solid #ffc26e;padding:12px 16px}.empty{color:var(--muted);padding:35px 0}.quota-grid{flex:1 0 auto;grid-auto-rows:minmax(220px,1fr);gap:10px;display:grid}.quota-card{flex-direction:column;min-height:0;display:flex;container-type:inline-size}.quota-card>:not(.meter-graphic){flex-shrink:0}.meter-graphic{flex-direction:column;flex:1;min-height:100px;display:flex}.bar-graphic{min-height:65px}.quota-card .gauge{flex:2;height:auto;min-height:16px;margin:7px 0}.quota-card .timeline{flex:1;min-height:8px}.quota-grid.zone{grid-template-columns:repeat(auto-fit,minmax(min(100%,420px),1fr));grid-auto-rows:minmax(330px,1fr)}.quota-grid.radial{grid-template-columns:repeat(auto-fit,minmax(min(100%,300px),1fr));grid-auto-rows:minmax(260px,1fr)}.gauge{background:var(--edge);height:35px;margin:15px 0;overflow:hidden}.gauge>div{background:repeating-linear-gradient(90deg, var(--accent) 0, var(--accent) 9px, transparent 9px, transparent 12px);height:100%;transition:width .5s}.gauge.timeline{height:14px}.pie-wrap{flex:1;min-height:100px;margin:6px 0;position:relative}.pie-wrap svg{width:100%;height:100%;position:absolute;inset:0}.pie-base{fill:var(--edge);stroke:var(--accent);stroke-width:1px}.pie-fill{fill:var(--accent)}.readout{overflow-wrap:anywhere;color:var(--accent);margin:18px 0;font-size:clamp(22px,3vw,34px)}.credit+.credit{border-top:1px solid var(--edge);padding-top:20px}.credit{margin-top:24px}.session-row{grid-template-columns:minmax(210px,1.1fr) minmax(0,1.2fr) minmax(0,1.5fr);align-items:stretch;gap:14px;margin:18px 0;display:grid}.session-totals{grid-template-columns:repeat(auto-fit,minmax(min(145px,100%),1fr));gap:8px;margin:8px 0;display:grid}.session-totals>div{border:1px solid var(--edge);min-width:0;padding:10px}.session-totals dt{color:var(--muted);font-size:11px}.session-totals dd{color:var(--accent);overflow-wrap:anywhere;margin:6px 0 0;font-size:24px}.session-totals.stale dd{color:var(--muted)}.session-row.selected{outline:1px solid var(--accent);outline-offset:4px}.session-row.wide .context{grid-column:2/-1}.detail-controls{flex-wrap:wrap;gap:6px;display:flex}.attention-summary{flex-wrap:wrap;gap:8px;margin-block:8px;display:flex}.attention-summary .approval{color:var(--approval);border-color:var(--approval)}.attention-summary .approval:hover{background:color-mix(in srgb, var(--approval) 12%, var(--panel))}.attention-summary .approval:focus-visible{outline-color:var(--approval)}.attention-note,.attention-badge{color:var(--accent);border-left:3px solid;padding-left:8px}.attention-note.inferred{color:var(--muted)}.attention-badge{font-size:12px}.session-select{text-align:left;overflow-wrap:anywhere;max-width:100%}.status-detail{color:inherit;text-decoration:none}.status-detail:hover{text-decoration:underline}button:disabled{opacity:.4;cursor:default}.session-row .graph-panel{flex-direction:column;grid-column:2/-1;display:flex}.session-row.split .graph-panel{grid-column:auto}.session-row .button,.session-row button{margin-top:8px;display:inline-block}.context pre{max-height:230px;overflow:auto}.session-row .context{flex-direction:column;display:flex}pre{font:inherit;white-space:pre-wrap;overflow-wrap:anywhere;font-size:13px;line-height:1.7}.full-detail{margin-top:6px}.detail-heading{flex-wrap:wrap;justify-content:space-between;align-items:center;gap:6px 12px;display:flex}.detail-heading h2{flex:250px;min-width:0;margin:0}.detail-metadata{overflow-wrap:anywhere}.detail-workspace{border-top:1px solid var(--edge);flex-direction:column;gap:10px;margin-top:8px;padding-top:4px;display:flex}.detail-context,.detail-workspace .session-actions{min-width:0}.detail-workspace .session-actions{border-top:1px solid var(--edge);padding-top:6px}.full-detail h3{margin-block:8px}.full-detail pre{margin-block:8px;line-height:1.5}.full-detail hr{margin-block:12px}.full-detail .command,.full-detail .notice{padding:8px 10px}.command{background:var(--bg);border-left:3px solid var(--accent);padding:16px}hr{border:0;border-top:1px solid var(--edge);margin:24px 0}.chart{border-bottom:1px solid var(--muted);align-items:flex-end;gap:2px;height:clamp(120px,22vh,320px);margin-top:18px;display:flex}.chart-bar{background:var(--accent);flex:1;min-width:0;max-height:100%}.controls{justify-content:flex-start;margin:20px 0}.summary-grid{grid-template-columns:repeat(auto-fit,minmax(min(100%,220px),1fr));gap:16px;margin:20px 0;display:grid}.thresholds-panel{padding:clamp(14px,2vw,22px)}.thresholds-panel h1{margin-top:0}.threshold-list{gap:8px;margin-top:16px;display:grid}.threshold-list article{border:1px solid var(--edge);grid-template-columns:minmax(64px,.5fr) minmax(220px,3fr) minmax(64px,.6fr) minmax(120px,1.2fr);align-items:center;gap:12px;padding:10px 12px;display:grid}.threshold-list article.active{border-color:var(--accent);box-shadow:inset 3px 0 0 var(--accent)}.threshold-list article.next{border-color:var(--approval);box-shadow:inset 3px 0 0 var(--approval)}.threshold-list p{color:var(--muted);margin:3px 0 0;font-size:12px}.threshold-trigger{color:var(--accent);font-size:22px;font-weight:800}.threshold-mode,.threshold-state{color:var(--muted);font-size:12px;font-weight:700}.threshold-list article.active .threshold-state{color:var(--accent)}.threshold-list article.next .threshold-state{color:var(--approval)}.heat-scroll{overflow-x:auto}.heatmap{grid-template-rows:repeat(7,13px);grid-auto-columns:minmax(9px,1fr);grid-auto-flow:column;gap:4px;min-width:620px;margin:25px 0;display:grid}.heat-cell{background:var(--accent);border-radius:2px}.heat-cell.zero{background:var(--edge)}.table-scroll{max-height:280px;overflow:auto}table{border-collapse:collapse;width:100%;margin-top:15px}th,td{text-align:left;border-bottom:1px solid var(--edge);padding:8px}summary{cursor:pointer;color:var(--accent);padding-top:14px}footer{border-top:1px solid var(--edge);color:var(--muted);margin-top:8px;padding-top:8px;font-size:11px}footer select{padding:6px}@media (width<=850px){.session-row{grid-template-columns:minmax(0,1fr)}.session-row.wide .context,.session-row .graph-panel{grid-column:auto}.connection{text-align:left}.threshold-list article{grid-template-columns:64px minmax(0,1fr)}.threshold-mode,.threshold-state{grid-column:2}}@media (prefers-reduced-motion:reduce){*,:before,:after{transition:none!important;animation:none!important}} diff --git a/internal/web/dist/assets/index-GcuOkuuL.css b/internal/web/dist/assets/index-GcuOkuuL.css deleted file mode 100644 index 56ca040..0000000 --- a/internal/web/dist/assets/index-GcuOkuuL.css +++ /dev/null @@ -1 +0,0 @@ -.observation-details.svelte-1vgdi83{font-size:12px}summary.svelte-1vgdi83{cursor:pointer;color:var(--accent)}.observation-table.svelte-1vgdi83{max-height:240px;overflow:auto}.zone-canvas.svelte-1vgdi83{flex:1;min-height:170px;margin-top:6px;position:relative}svg.svelte-1vgdi83{width:100%;height:100%;display:block;position:absolute;inset:0}text.svelte-1vgdi83{fill:var(--ink);font:14px Cascadia Code,Consolas,monospace}.axis-title.svelte-1vgdi83{letter-spacing:.04em;font-size:12px}.grid.svelte-1vgdi83{stroke:#fff;stroke-opacity:.14;stroke-width:1px}.axes.svelte-1vgdi83{stroke:var(--ink);stroke-width:1.5px;fill:none}.pace-line.svelte-1vgdi83{stroke:#fff;stroke-width:2px;stroke-dasharray:6 4}.position-halo.svelte-1vgdi83{fill:#101820;stroke:#fff;stroke-width:1.5px}.position-dot.svelte-1vgdi83{fill:#fff}.observation-trail.svelte-1vgdi83{fill:none;stroke:#101820;stroke-width:2.5px;stroke-linejoin:round}.observation-trail-casing.svelte-1vgdi83{fill:none;stroke:#ffffff73;stroke-width:4.5px;stroke-linejoin:round}.trail-start.svelte-1vgdi83{fill:#101820;stroke:#ffffffb3;stroke-width:2px}.trend-line.svelte-1vgdi83{fill:none;stroke:var(--trend-color);stroke-width:2px;stroke-dasharray:3 6}.trend-arrow.svelte-1vgdi83{fill:var(--trend-color);stroke:#ffffff73;stroke-width:.5px}.trend-casing.svelte-1vgdi83{fill:none;stroke:#ffffff73;stroke-width:4px;stroke-dasharray:3 6}.zone-caption.svelte-1vgdi83{min-width:0;color:var(--accent);flex:auto;margin:0}.trend-summary.svelte-1vgdi83{color:var(--ink)}.zone-footer.svelte-1vgdi83{justify-content:space-between;align-items:flex-start;gap:12px;margin-top:4px;display:flex}.zone-controls.svelte-1vgdi83{color:var(--muted);text-align:right;flex-direction:column;align-items:flex-end;gap:5px;font-size:11px;display:flex}.trace-control.svelte-1vgdi83,.trend-control.svelte-1vgdi83{cursor:pointer;white-space:nowrap}.trace-control.svelte-1vgdi83 input:where(.svelte-1vgdi83){accent-color:var(--accent)}.trend-control.svelte-1vgdi83 select:where(.svelte-1vgdi83){border:1px solid var(--edge);background:var(--panel);max-width:min(230px,45vw);color:var(--ink);font:inherit}.trend-control.svelte-1vgdi83 option:where(.svelte-1vgdi83):disabled{color:var(--muted)}.zone-controls.svelte-1vgdi83 small:where(.svelte-1vgdi83){font-size:10px}@container (width<=560px){.zone-footer.svelte-1vgdi83{flex-direction:column}.zone-controls.svelte-1vgdi83{align-self:stretch;align-items:flex-end}}.slash-commands.svelte-7bfwr9{margin:.4rem 0;position:relative}.command-popup.svelte-7bfwr9{z-index:5;box-sizing:border-box;border:1px solid var(--accent);background:var(--panel);width:min(40rem,100%);padding:.35rem;position:absolute;bottom:100%;left:0;box-shadow:0 .3rem 1rem #0006}.command-popup.svelte-7bfwr9 p:where(.svelte-7bfwr9){margin:.3rem 0;font-size:.8em}.command-options.vertical.svelte-7bfwr9{flex-flow:column;gap:.15rem;display:flex}.vertical.svelte-7bfwr9 button:where(.svelte-7bfwr9){text-align:left;white-space:nowrap;width:100%;min-width:0;color:var(--muted);background:var(--panel);border-color:#0000;flex:none;align-items:baseline;gap:.4rem;display:flex}.vertical.svelte-7bfwr9 .command-name:where(.svelte-7bfwr9),.vertical.svelte-7bfwr9 .command-tail:where(.svelte-7bfwr9){flex:none}.vertical.svelte-7bfwr9 .command-name:where(.svelte-7bfwr9){text-overflow:ellipsis;max-width:100%;overflow:hidden}.vertical.svelte-7bfwr9 button.suggested:where(.svelte-7bfwr9){outline:none}.command-options.svelte-7bfwr9 button.suggested:where(.svelte-7bfwr9) .command-name:where(.svelte-7bfwr9){color:var(--ink);font-weight:700}.command-options.svelte-7bfwr9 button:where(.svelte-7bfwr9):not(.suggested):hover .command-name:where(.svelte-7bfwr9){text-decoration:underline}.command-options.svelte-7bfwr9 button:where(.svelte-7bfwr9){color:var(--muted)}.vertical.svelte-7bfwr9 .command-help:where(.svelte-7bfwr9){min-width:0;max-width:none;color:var(--muted);flex:1}.command-options.svelte-7bfwr9{flex-wrap:wrap;gap:.35rem;max-height:35vh;display:flex;overflow:auto}.command-options.svelte-7bfwr9 .suggested:where(.svelte-7bfwr9){outline:none}.command-help.svelte-7bfwr9{text-overflow:ellipsis;white-space:nowrap;opacity:.75;max-width:32ch;font-size:.8em;display:block;overflow:hidden}.command-actions.svelte-7bfwr9{flex-wrap:wrap;gap:.35rem;margin-top:.4rem;display:flex}.availability.svelte-7bfwr9{font-weight:600}.navigation.svelte-7bfwr9{font-size:.8em}pre.svelte-7bfwr9{white-space:pre-wrap;overflow-wrap:anywhere;max-height:35vh;overflow:auto}.file-diff.svelte-x4gtb6{border:1px solid var(--muted);max-height:60vh;padding:.5rem;font-family:monospace;overflow:auto}.diff-line.svelte-x4gtb6{white-space:pre;min-height:1.3em;display:flex}.line-number.svelte-x4gtb6{text-align:right;opacity:.75;-webkit-user-select:none;user-select:none;flex:0 0 5ch;padding-right:1ch;display:inline-block}.added.svelte-x4gtb6{color:#67d391;background:#67d39112}.removed.svelte-x4gtb6{color:#ff6b83;background:#ff6b8312}.heading.svelte-x4gtb6{padding:.5rem 0;font-weight:700}.saved-prompt.svelte-1oupzfc{white-space:pre-wrap;overflow-wrap:anywhere}fieldset.svelte-1oupzfc{border:1px solid;margin:.5rem 0;padding:.35rem .6rem}.decision.svelte-1oupzfc,.answer.svelte-1oupzfc{margin:.3rem 0;display:block}.decision.svelte-1oupzfc code:where(.svelte-1oupzfc),.decision.svelte-1oupzfc span:where(.svelte-1oupzfc){overflow-wrap:anywhere;margin:.3rem 0 .3rem 1.5rem;display:block}textarea.svelte-1oupzfc,.answer.svelte-1oupzfc input:where(.svelte-1oupzfc),.answer.svelte-1oupzfc select:where(.svelte-1oupzfc){box-sizing:border-box;background:var(--bg);width:100%;color:inherit;font:inherit;border:1px solid;margin-top:.4rem;padding:.5rem;display:block}textarea.svelte-1oupzfc{resize:vertical;background:color-mix(in srgb, currentColor 8%, var(--bg))}button.svelte-1oupzfc{margin:.3rem .5rem .3rem 0}h3.svelte-1oupzfc,p.svelte-1oupzfc{margin-block:.4rem}.sent.svelte-1oupzfc{color:var(--accent)}.status-line.svelte-gprptn{align-items:center;gap:.5rem;min-width:0;margin-top:.5rem;display:flex}.status-line.svelte-gprptn p:where(.svelte-gprptn){white-space:nowrap;text-overflow:ellipsis;flex:1;min-width:0;margin:0;font-size:.8rem;overflow:hidden}.configure.svelte-gprptn{padding:.15rem .35rem;font-size:.75rem}.status-picker.svelte-gprptn{border:1px solid var(--edge);margin:.5rem 0;padding:.6rem}.fields.svelte-gprptn{max-height:35vh;overflow:auto}.field.svelte-gprptn{align-items:center;gap:.35rem;display:flex}.field.svelte-gprptn label:where(.svelte-gprptn){flex:1;align-items:center;gap:.4rem;display:flex}.field.svelte-gprptn label:where(.svelte-gprptn) span:where(.svelte-gprptn){font-size:.75rem}.field.svelte-gprptn button:where(.svelte-gprptn){padding:.1rem .35rem}.session-copy.svelte-543j00{justify-content:flex-end;align-items:center;gap:8px;margin-top:auto;padding-top:6px;display:flex}span.svelte-543j00{color:var(--muted);overflow-wrap:anywhere;font-size:12px}button.svelte-543j00{color:var(--accent);flex-shrink:0;padding:3px 7px}button.svelte-543j00:hover,button.flashed.svelte-543j00{color:var(--bg);background:var(--accent)}h3.svelte-1fbui7h,.window-dates.svelte-1fbui7h,.report-value.svelte-1fbui7h{color:var(--accent);font-weight:700}.quality-warning.svelte-1fbui7h,.quota-near.svelte-1fbui7h{color:var(--approval)}.quota-full.svelte-1fbui7h{color:#ff6680}.alternate.svelte-1fbui7h .report-fill:where(.svelte-1fbui7h){background:radial-gradient(circle, var(--panel) .7px, transparent .9px) 0 0 / 3px 3px, var(--accent)}.unknown.svelte-1fbui7h,.unknown.svelte-1fbui7h .report-value:where(.svelte-1fbui7h){color:var(--muted)}.unknown.svelte-1fbui7h .report-fill:where(.svelte-1fbui7h){background:var(--muted);opacity:1}.report-bars.svelte-1fbui7h{grid-template-columns:minmax(5rem,1fr) minmax(2rem,3fr) auto;gap:.6rem;display:grid}.report-row.svelte-1fbui7h,.report-head.svelte-1fbui7h{grid-column:1/-1;grid-template-columns:subgrid;align-items:center;gap:.6rem;display:grid}.report-head.svelte-1fbui7h{color:var(--muted);font-size:.85rem}.report-head.svelte-1fbui7h>span:where(.svelte-1fbui7h):last-child,.report-value.svelte-1fbui7h{text-align:right}.report-row.svelte-1fbui7h>span:where(.svelte-1fbui7h):first-child{overflow-wrap:anywhere}.report-track.svelte-1fbui7h{background:var(--panel);height:1rem}.report-fill.svelte-1fbui7h{background:var(--accent);height:100%}svg.svelte-1jpy949{fill:currentColor;width:100%;height:auto;display:block}.startup.svelte-19xbbtg{z-index:100;background:var(--bg);color:var(--accent);position:fixed;inset:0;overflow:hidden}.wordmark.svelte-19xbbtg{position:absolute}button.svelte-19xbbtg{color:var(--muted);font:inherit;white-space:nowrap;background:0 0;border:0;font-size:12px;position:absolute;bottom:24px;left:50%;transform:translate(-50%)}:root{font-synthesis:none;--lightningcss-light: ;--lightningcss-dark:initial;color-scheme:dark;background:#080e0c;font-family:Cascadia Code,SFMono-Regular,Consolas,monospace}*{box-sizing:border-box}body{margin:0}.shell{--accent:#80edac;--approval:#ffca58;--muted:#98aaa0;--edge:#31473a;--panel:#101c16;--bg:#080e0c;--ink:#e2eee5;background:var(--bg);height:100dvh;color:var(--ink);grid-template-rows:auto auto minmax(0,1fr) auto;padding:clamp(10px,1.2vw,20px);display:grid}.shell[data-theme=rust]{--approval:#ff8a3d;--accent:#ffbc75;--muted:#bfac95;--edge:#59412c;--panel:#261b14;--bg:#140e0a}.shell[data-theme=blue-steel]{--approval:#e8c46a;--accent:#85c8ff;--muted:#9cacc4;--edge:#334d69;--panel:#142235;--bg:#0b1421}.shell[data-theme=ultraviolet]{--approval:#f9a8d4;--accent:#c5adff;--muted:#b3a6c9;--edge:#4b3c68;--panel:#241a35;--bg:#140d22}.shell[data-theme=nightshade]{--approval:#8f7cff;--accent:#e59bff;--muted:#c6a7cf;--edge:#673976;--panel:#301739;--bg:#1c0b24}header,.spread,footer,.controls{flex-wrap:wrap;justify-content:space-between;align-items:center;gap:10px;display:flex}header{margin-bottom:10px}.shell[data-starting=true]>header,.shell[data-starting=true]>nav,.shell[data-starting=true]>main,.shell[data-starting=true]>footer{visibility:hidden}.brand{width:clamp(240px,32vw,405px);max-width:calc(100vw - 40px);color:var(--accent);text-decoration:none;display:block}header p{color:var(--muted);margin:3px 0 0;font-size:13px}.connection{color:var(--accent);text-align:right}small,.eyebrow{letter-spacing:.04em;font-size:12px}.connection small{color:var(--muted);margin-top:4px;display:block}.lamp{background:var(--muted);border-radius:50%;width:9px;height:9px;margin-right:9px;display:inline-block}.lamp.lit{background:var(--accent);box-shadow:0 0 8px color-mix(in srgb, var(--accent) 40%, transparent)}.working{animation:1.5s ease-in-out infinite pulse}@keyframes pulse{50%{opacity:.3}}nav{flex-wrap:wrap;gap:6px;margin-bottom:10px;display:flex}nav a,button,.button,select{font:inherit;color:var(--accent);border:1px solid var(--edge);background:var(--panel);cursor:pointer;border-radius:3px;padding:7px 11px;font-size:13px;text-decoration:none}button:hover,.button:hover,nav a:hover{border-color:var(--accent)}nav a.active,nav button.active{background:var(--accent);color:var(--bg);border-color:var(--accent)}:focus-visible{outline:2px solid var(--accent);outline-offset:4px}.secondary{margin-bottom:8px}.secondary a,.secondary button{padding:6px 10px;font-size:12px}main{scrollbar-gutter:stable;flex-direction:column;min-width:0;min-height:0;display:flex;overflow:auto}main>*{flex-shrink:0}.panel{border:1px solid var(--edge);border-top:2px solid var(--accent);background:var(--panel);border-radius:4px;min-width:0;padding:clamp(10px,1vw,16px)}h1{color:var(--accent);font-size:20px}h2{letter-spacing:.04em;color:var(--accent);overflow-wrap:anywhere;margin:0 0 10px;font-size:13px}h3{overflow-wrap:anywhere;font-size:13px}p{margin:6px 0;font-size:13px;line-height:1.45}a{color:var(--accent)}.muted,.eyebrow{color:var(--muted)}.notice{color:#ffe0aa;background:#332611;border-left:3px solid #ffc26e;padding:12px 16px}.empty{color:var(--muted);padding:35px 0}.quota-grid{flex:1 0 auto;grid-auto-rows:minmax(220px,1fr);gap:10px;display:grid}.quota-card{flex-direction:column;min-height:0;display:flex;container-type:inline-size}.quota-card>:not(.meter-graphic){flex-shrink:0}.meter-graphic{flex-direction:column;flex:1;min-height:100px;display:flex}.bar-graphic{min-height:65px}.quota-card .gauge{flex:2;height:auto;min-height:16px;margin:7px 0}.quota-card .timeline{flex:1;min-height:8px}.quota-grid.zone{grid-template-columns:repeat(auto-fit,minmax(min(100%,420px),1fr));grid-auto-rows:minmax(330px,1fr)}.quota-grid.radial{grid-template-columns:repeat(auto-fit,minmax(min(100%,300px),1fr));grid-auto-rows:minmax(260px,1fr)}.gauge{background:var(--edge);height:35px;margin:15px 0;overflow:hidden}.gauge>div{background:repeating-linear-gradient(90deg, var(--accent) 0, var(--accent) 9px, transparent 9px, transparent 12px);height:100%;transition:width .5s}.gauge.timeline{height:14px}.pie-wrap{flex:1;min-height:100px;margin:6px 0;position:relative}.pie-wrap svg{width:100%;height:100%;position:absolute;inset:0}.pie-base{fill:var(--edge);stroke:var(--accent);stroke-width:1px}.pie-fill{fill:var(--accent)}.readout{overflow-wrap:anywhere;color:var(--accent);margin:18px 0;font-size:clamp(22px,3vw,34px)}.credit+.credit{border-top:1px solid var(--edge);padding-top:20px}.credit{margin-top:24px}.session-row{grid-template-columns:minmax(210px,1.1fr) minmax(0,1.2fr) minmax(0,1.5fr);align-items:stretch;gap:14px;margin:18px 0;display:grid}.session-totals{grid-template-columns:repeat(auto-fit,minmax(min(145px,100%),1fr));gap:8px;margin:8px 0;display:grid}.session-totals>div{border:1px solid var(--edge);min-width:0;padding:10px}.session-totals dt{color:var(--muted);font-size:11px}.session-totals dd{color:var(--accent);overflow-wrap:anywhere;margin:6px 0 0;font-size:24px}.session-totals.stale dd{color:var(--muted)}.session-row.selected{outline:1px solid var(--accent);outline-offset:4px}.session-row.wide .context{grid-column:2/-1}.detail-controls{flex-wrap:wrap;gap:6px;display:flex}.attention-summary{flex-wrap:wrap;gap:8px;margin-block:8px;display:flex}.attention-summary .approval{color:var(--approval);border-color:var(--approval)}.attention-summary .approval:hover{background:color-mix(in srgb, var(--approval) 12%, var(--panel))}.attention-summary .approval:focus-visible{outline-color:var(--approval)}.attention-note,.attention-badge{color:var(--accent);border-left:3px solid;padding-left:8px}.attention-note.inferred{color:var(--muted)}.attention-badge{font-size:12px}.session-select{text-align:left;overflow-wrap:anywhere;max-width:100%}.status-detail{color:inherit;text-decoration:none}.status-detail:hover{text-decoration:underline}button:disabled{opacity:.4;cursor:default}.session-row .graph-panel{flex-direction:column;grid-column:2/-1;display:flex}.session-row.split .graph-panel{grid-column:auto}.session-row .button,.session-row button{margin-top:8px;display:inline-block}.context pre{max-height:230px;overflow:auto}.session-row .context{flex-direction:column;display:flex}pre{font:inherit;white-space:pre-wrap;overflow-wrap:anywhere;font-size:13px;line-height:1.7}.full-detail{margin-top:6px}.detail-heading{flex-wrap:wrap;justify-content:space-between;align-items:center;gap:6px 12px;display:flex}.detail-heading h2{flex:250px;min-width:0;margin:0}.detail-metadata{overflow-wrap:anywhere}.detail-workspace{border-top:1px solid var(--edge);flex-direction:column;gap:10px;margin-top:8px;padding-top:4px;display:flex}.detail-context,.detail-workspace .session-actions{min-width:0}.detail-workspace .session-actions{border-top:1px solid var(--edge);padding-top:6px}.full-detail h3{margin-block:8px}.full-detail pre{margin-block:8px;line-height:1.5}.full-detail hr{margin-block:12px}.full-detail .command,.full-detail .notice{padding:8px 10px}.command{background:var(--bg);border-left:3px solid var(--accent);padding:16px}hr{border:0;border-top:1px solid var(--edge);margin:24px 0}.chart{border-bottom:1px solid var(--muted);align-items:flex-end;gap:2px;height:clamp(120px,22vh,320px);margin-top:18px;display:flex}.chart-bar{background:var(--accent);flex:1;min-width:0;max-height:100%}.controls{justify-content:flex-start;margin:20px 0}.summary-grid{grid-template-columns:repeat(auto-fit,minmax(min(100%,220px),1fr));gap:16px;margin:20px 0;display:grid}.thresholds-panel{padding:clamp(14px,2vw,22px)}.thresholds-panel h1{margin-top:0}.threshold-list{gap:8px;margin-top:16px;display:grid}.threshold-list article{border:1px solid var(--edge);grid-template-columns:minmax(64px,.5fr) minmax(220px,3fr) minmax(64px,.6fr) minmax(120px,1.2fr);align-items:center;gap:12px;padding:10px 12px;display:grid}.threshold-list article.active{border-color:var(--accent);box-shadow:inset 3px 0 0 var(--accent)}.threshold-list article.next{border-color:var(--approval);box-shadow:inset 3px 0 0 var(--approval)}.threshold-list p{color:var(--muted);margin:3px 0 0;font-size:12px}.threshold-trigger{color:var(--accent);font-size:22px;font-weight:800}.threshold-mode,.threshold-state{color:var(--muted);font-size:12px;font-weight:700}.threshold-list article.active .threshold-state{color:var(--accent)}.threshold-list article.next .threshold-state{color:var(--approval)}.heat-scroll{overflow-x:auto}.heatmap{grid-template-rows:repeat(7,13px);grid-auto-columns:minmax(9px,1fr);grid-auto-flow:column;gap:4px;min-width:620px;margin:25px 0;display:grid}.heat-cell{background:var(--accent);border-radius:2px}.heat-cell.zero{background:var(--edge)}.table-scroll{max-height:280px;overflow:auto}table{border-collapse:collapse;width:100%;margin-top:15px}th,td{text-align:left;border-bottom:1px solid var(--edge);padding:8px}summary{cursor:pointer;color:var(--accent);padding-top:14px}footer{border-top:1px solid var(--edge);color:var(--muted);margin-top:8px;padding-top:8px;font-size:11px}footer select{padding:6px}@media (width<=850px){.session-row{grid-template-columns:minmax(0,1fr)}.session-row.wide .context,.session-row .graph-panel{grid-column:auto}.connection{text-align:left}.threshold-list article{grid-template-columns:64px minmax(0,1fr)}.threshold-mode,.threshold-state{grid-column:2}}@media (prefers-reduced-motion:reduce){*,:before,:after{transition:none!important;animation:none!important}} diff --git a/internal/web/dist/index.html b/internal/web/dist/index.html index fddfcbf..07fb2a8 100644 --- a/internal/web/dist/index.html +++ b/internal/web/dist/index.html @@ -5,8 +5,8 @@Quota refresh failed. Values below are the last successful observation.
{/if} + {#if live.data.usageDiagnostic}+ Last usage accounting issue: + {live.data.usageDiagnostic} +
{/if}QUOTA // OBSERVED {date(live.data.quotaAt)}
{#if view === 'thresholds'}