diff --git a/README.md b/README.md
index c4fba9b..92874d6 100644
--- a/README.md
+++ b/README.md
@@ -8,7 +8,9 @@ Track coding-agent token usage and estimated API cost across every machine enrol
- Collect usage from Codex, Claude Code, DeepSeek Harness, Devin, FX, Grok Agent, OpenCode, Pi, Prime Agent, Antigravity, and Thaura.
- Separate the coding agent from the underlying model provider.
-- Group charts and cost summaries by agent or model provider.
+- Group charts and usage shares by agent or model provider.
+- Switch the chart and provider shares between cost and tokens.
+- Sort breakdowns by tokens or cost using column headers, with each metric’s share shown beneath its value. Unknown costs stay visible without a misleading percentage.
- Break usage down by model, project, or day.
- Filter by machine, agent, model provider, and the last 7, 30, or 90 days.
- Show exact, alias-matched, agent-reported, and unknown pricing in the breakdown table.
diff --git a/app.tsx b/app.tsx
index 891c700..a1e42c2 100644
--- a/app.tsx
+++ b/app.tsx
@@ -11,6 +11,7 @@ import { useMediaQuery } from "@/components/ui/hooks/use-media-query";
import { ProviderLimitsSkeleton, UsageDashboardSkeleton } from "@/components/usage-dashboard-skeleton";
import { ProviderLogo, BRAND_COLORS, modelLogoId } from "@/components/provider-logo";
import { paginateItems } from "@/lib/pagination";
+import { compareUsage, nextUsageSort, type MetricMode, type UsageSort } from "@/lib/usage-sort";
import type { UsageSyncSnapshot } from "@/lib/sync-coordinator";
import { isUsageSyncInProgress, shouldPollUsage, shouldShowInitialUsageLoading, usageRefreshError } from "@/lib/usage-sync-state";
import { getEmptyUsageView, getSourceIssueMessage } from "@/lib/usage-view-state";
@@ -18,7 +19,6 @@ import { clampPercent, formatLimitReset, formatLimitValue, isLimitVisibleOnMachi
import { formatLocalMoney, localCurrency, usdToLocalRate } from "@/lib/local-currency";
type Range = 7 | 30 | 90;
-type ChartMode = "cost" | "tokens";
type BreakdownMode = "model" | "project" | "day";
type DimensionMode = "agent" | "provider";
@@ -176,6 +176,61 @@ function CostValue({ value, className }: { value: number; className?: string })
);
}
+// A row whose priced cost is zero but has unpriced usage shows "Unknown"; a
+// partially priced row gets a "+" marker since its share understates usage.
+function PricedCost({ cost, unknown }: { cost: number; unknown?: boolean }) {
+ return (
+
+ {unknown && cost === 0 ? "Unknown" : <>
| + | {breakdownMode === "model" ? "Model" : breakdownMode === "project" ? "Project" : "Day"} | {breakdownMode !== "day" && ( -Agent | +Agent | )} -Cost | -Share | -Tokens | + {(["tokens", "cost"] as const).map((metric) => ( +
+ |
+ ))}
- |
)}
- {row.unknown && row.cost === 0 ? "Unknown" : <> |
- {row.unknown && row.cost === 0 ? "—" : `${row.unknown ? "+" : ""}${percentage(row.cost, totals.cost)}`} | -{compact(row.tokens)} | +
+ |
+
+ |
))}
-
|---|
| Model | -Agent | -Cost | -Share | -Tokens | -
|---|---|---|---|---|
|
-
-
- |
-
-
-
- |
-
- |
-
- |
-
- |
-
| Model | +Agent | ++ Tokens + | ++ Cost + | +
|---|---|---|---|
|
+
+
+ |
+
+
+
+ |
+ {[0, 1].map((metric) => (
+
+ |
+ ))}
+