tokentrace 0.8.2 → 0.8.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +13 -0
- package/app/api/prices/route.ts +9 -2
- package/app/evidence/page.tsx +95 -6
- package/app/page.tsx +288 -48
- package/app/pricing/page.tsx +2 -1
- package/app/repair/page.tsx +135 -17
- package/components/period-filter.tsx +26 -24
- package/components/pricing-settings.tsx +74 -2
- package/dist/runtime/digest.mjs +10 -6
- package/dist/runtime/doctor.mjs +10 -6
- package/dist/runtime/evidence.mjs +68 -15
- package/dist/runtime/insights.mjs +10 -6
- package/dist/runtime/repair.mjs +25 -2
- package/dist/runtime/scan.mjs +6 -6
- package/package.json +2 -1
- package/scripts/visual-smoke.mjs +30 -0
- package/src/ingestion/adapters/codex-cli.ts +6 -6
- package/src/lib/analytics.ts +10 -6
- package/src/lib/date-range.ts +22 -0
- package/src/lib/evidence-trail.ts +112 -16
- package/src/lib/pricing.ts +36 -3
- package/src/lib/unknown-cost-repair.ts +29 -2
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to TokenTrace are documented here.
|
|
4
4
|
|
|
5
|
+
## [0.8.4] - 2026-05-13
|
|
6
|
+
|
|
7
|
+
### Changed
|
|
8
|
+
|
|
9
|
+
- Overview now shows Usage Pulse, top-level metric cards, and token/cost trend graphs before trust and Data Readiness diagnostics, so the first viewport focuses on primary usage status before repair-readiness details.
|
|
10
|
+
|
|
11
|
+
## [0.8.3] - 2026-05-13
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
|
|
15
|
+
- Codex CLI `token_count` JSON imports now subtract cached input from non-cached input and keep cached input separate, so processed Codex totals count cache exactly once instead of double-counting it.
|
|
16
|
+
- Codex parser provenance is bumped to version 4 so previously imported version-3 Codex session rows are reprocessed on the next scan with corrected token and cost totals.
|
|
17
|
+
|
|
5
18
|
## [0.8.2] - 2026-05-13
|
|
6
19
|
|
|
7
20
|
### Fixed
|
package/app/api/prices/route.ts
CHANGED
|
@@ -45,7 +45,7 @@ export async function POST(request: Request) {
|
|
|
45
45
|
if (!cachedInputTokenPrice.ok) return NextResponse.json({ error: cachedInputTokenPrice.error }, { status: 400 });
|
|
46
46
|
if (!cacheWriteTokenPrice.ok) return NextResponse.json({ error: cacheWriteTokenPrice.error }, { status: 400 });
|
|
47
47
|
|
|
48
|
-
const
|
|
48
|
+
const result = upsertPricing({
|
|
49
49
|
providerId,
|
|
50
50
|
providerName: requiredText(body.providerName) || undefined,
|
|
51
51
|
model,
|
|
@@ -56,5 +56,12 @@ export async function POST(request: Request) {
|
|
|
56
56
|
currency: requiredText(body.currency) || "USD"
|
|
57
57
|
});
|
|
58
58
|
|
|
59
|
-
return NextResponse.json({
|
|
59
|
+
return NextResponse.json({
|
|
60
|
+
id: result.id,
|
|
61
|
+
costsRecalculated: result.interactionsUpdated,
|
|
62
|
+
interactionsChecked: result.interactionsChecked,
|
|
63
|
+
unknownCostInteractions: result.unknownCostInteractions,
|
|
64
|
+
modelAliasesUpdated: result.modelsUpdated,
|
|
65
|
+
resolvedRepairItems: result.resolvedRepairItems
|
|
66
|
+
});
|
|
60
67
|
}
|
package/app/evidence/page.tsx
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import Link from "next/link";
|
|
2
2
|
import { ArrowLeft, ArrowRight } from "lucide-react";
|
|
3
|
+
import { PeriodFilter } from "@/components/period-filter";
|
|
3
4
|
import { Badge } from "@/components/ui/badge";
|
|
4
5
|
import { Button } from "@/components/ui/button";
|
|
5
6
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
|
|
6
7
|
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";
|
|
7
8
|
import { DataValue, FieldLabel, MonoText, PageHeader } from "@/components/ui/typography";
|
|
9
|
+
import { dateRangeQueryParams, mergeHrefParams, resolveDateRange } from "@/src/lib/date-range";
|
|
8
10
|
import { buildEvidenceTrail, parseEvidenceMetric } from "@/src/lib/evidence-trail";
|
|
9
11
|
import { formatCurrency, formatExactTokens, percent } from "@/src/lib/format";
|
|
10
12
|
|
|
@@ -29,7 +31,14 @@ function parserStatusVariant(value: string | null) {
|
|
|
29
31
|
|
|
30
32
|
export default async function EvidencePage({ searchParams }: EvidencePageProps) {
|
|
31
33
|
const params = (await searchParams) ?? {};
|
|
32
|
-
const
|
|
34
|
+
const range = resolveDateRange(params);
|
|
35
|
+
const metric = parseEvidenceMetric(params?.metric);
|
|
36
|
+
const trail = buildEvidenceTrail({ metric, filters: range.filters });
|
|
37
|
+
const rangeLinkParams = dateRangeQueryParams(range);
|
|
38
|
+
const overviewHref = mergeHrefParams("/", rangeLinkParams);
|
|
39
|
+
const currentEvidenceHref = mergeHrefParams(`/evidence?metric=${trail.metric}`, rangeLinkParams);
|
|
40
|
+
const pricingReturnParams = { returnTo: currentEvidenceHref };
|
|
41
|
+
const confidenceTotal = Math.max(1, trail.confidence.exact + trail.confidence.estimated + trail.confidence.unknown);
|
|
33
42
|
|
|
34
43
|
return (
|
|
35
44
|
<div className="space-y-6">
|
|
@@ -38,7 +47,7 @@ export default async function EvidencePage({ searchParams }: EvidencePageProps)
|
|
|
38
47
|
description={trail.description}
|
|
39
48
|
actions={
|
|
40
49
|
<Button asChild variant="outline" size="sm">
|
|
41
|
-
<Link href=
|
|
50
|
+
<Link href={overviewHref}>
|
|
42
51
|
<ArrowLeft className="h-4 w-4" />
|
|
43
52
|
Overview
|
|
44
53
|
</Link>
|
|
@@ -46,6 +55,8 @@ export default async function EvidencePage({ searchParams }: EvidencePageProps)
|
|
|
46
55
|
}
|
|
47
56
|
/>
|
|
48
57
|
|
|
58
|
+
<PeriodFilter range={range} />
|
|
59
|
+
|
|
49
60
|
<Card>
|
|
50
61
|
<CardHeader>
|
|
51
62
|
<CardTitle>Metric Totals</CardTitle>
|
|
@@ -79,6 +90,84 @@ export default async function EvidencePage({ searchParams }: EvidencePageProps)
|
|
|
79
90
|
</CardContent>
|
|
80
91
|
</Card>
|
|
81
92
|
|
|
93
|
+
<div className="grid gap-4 xl:grid-cols-[minmax(0,0.75fr)_minmax(0,1.25fr)]">
|
|
94
|
+
<Card>
|
|
95
|
+
<CardHeader>
|
|
96
|
+
<CardTitle>Confidence Split</CardTitle>
|
|
97
|
+
<CardDescription>Interaction-level token confidence for this metric and period.</CardDescription>
|
|
98
|
+
</CardHeader>
|
|
99
|
+
<CardContent className="space-y-3">
|
|
100
|
+
{[
|
|
101
|
+
{ label: "Exact", value: trail.confidence.exact, variant: "success" as const },
|
|
102
|
+
{ label: "Estimated", value: trail.confidence.estimated, variant: "secondary" as const },
|
|
103
|
+
{ label: "Unknown", value: trail.confidence.unknown, variant: "warning" as const }
|
|
104
|
+
].map((item) => (
|
|
105
|
+
<div key={item.label} className="grid grid-cols-[5.5rem_minmax(0,1fr)_4rem] items-center gap-3 text-sm">
|
|
106
|
+
<Badge variant={item.variant}>{item.label}</Badge>
|
|
107
|
+
<div className="h-2 overflow-hidden rounded-full bg-muted">
|
|
108
|
+
<div className="h-full rounded-full bg-primary" style={{ width: `${(item.value / confidenceTotal) * 100}%` }} />
|
|
109
|
+
</div>
|
|
110
|
+
<div className="text-right tabular-nums text-muted-foreground">{item.value.toLocaleString()}</div>
|
|
111
|
+
</div>
|
|
112
|
+
))}
|
|
113
|
+
</CardContent>
|
|
114
|
+
</Card>
|
|
115
|
+
|
|
116
|
+
<Card>
|
|
117
|
+
<CardHeader>
|
|
118
|
+
<CardTitle>Top Source Files</CardTitle>
|
|
119
|
+
<CardDescription>Largest contributing local files for the same metric definition.</CardDescription>
|
|
120
|
+
</CardHeader>
|
|
121
|
+
<CardContent className="table-scroll">
|
|
122
|
+
<Table>
|
|
123
|
+
<TableHeader>
|
|
124
|
+
<TableRow>
|
|
125
|
+
<TableHead>Source</TableHead>
|
|
126
|
+
<TableHead>Tokens</TableHead>
|
|
127
|
+
<TableHead>Interactions</TableHead>
|
|
128
|
+
<TableHead>Unknown cost</TableHead>
|
|
129
|
+
<TableHead>Actions</TableHead>
|
|
130
|
+
</TableRow>
|
|
131
|
+
</TableHeader>
|
|
132
|
+
<TableBody>
|
|
133
|
+
{trail.sourceFiles.length ? (
|
|
134
|
+
trail.sourceFiles.map((source) => (
|
|
135
|
+
<TableRow key={source.sourceFile}>
|
|
136
|
+
<TableCell className="max-w-96">
|
|
137
|
+
<Link href={mergeHrefParams(source.sourceHref, rangeLinkParams)} title={source.sourceFile}>
|
|
138
|
+
<MonoText className="block truncate text-muted-foreground underline-offset-4 hover:underline">
|
|
139
|
+
{source.sourceFile}
|
|
140
|
+
</MonoText>
|
|
141
|
+
</Link>
|
|
142
|
+
</TableCell>
|
|
143
|
+
<TableCell>{formatExactTokens(source.tokens)}</TableCell>
|
|
144
|
+
<TableCell>{source.interactions.toLocaleString()}</TableCell>
|
|
145
|
+
<TableCell>{source.unknownCostInteractions.toLocaleString()}</TableCell>
|
|
146
|
+
<TableCell>
|
|
147
|
+
<div className="flex flex-wrap gap-2">
|
|
148
|
+
<Link href={mergeHrefParams(source.sourceHref, rangeLinkParams)} className="font-medium text-primary underline-offset-4 hover:underline">
|
|
149
|
+
Sessions
|
|
150
|
+
</Link>
|
|
151
|
+
<Link href={mergeHrefParams(source.parserHref, rangeLinkParams)} className="font-medium text-muted-foreground underline-offset-4 hover:underline">
|
|
152
|
+
Parser
|
|
153
|
+
</Link>
|
|
154
|
+
</div>
|
|
155
|
+
</TableCell>
|
|
156
|
+
</TableRow>
|
|
157
|
+
))
|
|
158
|
+
) : (
|
|
159
|
+
<TableRow>
|
|
160
|
+
<TableCell colSpan={5} className="h-20 text-center text-muted-foreground">
|
|
161
|
+
No source-file evidence is available for this metric yet.
|
|
162
|
+
</TableCell>
|
|
163
|
+
</TableRow>
|
|
164
|
+
)}
|
|
165
|
+
</TableBody>
|
|
166
|
+
</Table>
|
|
167
|
+
</CardContent>
|
|
168
|
+
</Card>
|
|
169
|
+
</div>
|
|
170
|
+
|
|
82
171
|
<Card>
|
|
83
172
|
<CardHeader>
|
|
84
173
|
<CardTitle>Session, Source, Parser, And Pricing Evidence</CardTitle>
|
|
@@ -104,7 +193,7 @@ export default async function EvidencePage({ searchParams }: EvidencePageProps)
|
|
|
104
193
|
trail.sessions.map((session) => (
|
|
105
194
|
<TableRow key={session.id}>
|
|
106
195
|
<TableCell className="min-w-64">
|
|
107
|
-
<Link href={session.sessionHref} className="font-medium text-primary underline-offset-4 hover:underline">
|
|
196
|
+
<Link href={mergeHrefParams(session.sessionHref, rangeLinkParams)} className="font-medium text-primary underline-offset-4 hover:underline">
|
|
108
197
|
{session.title}
|
|
109
198
|
</Link>
|
|
110
199
|
<div className="mt-1 text-xs text-muted-foreground">
|
|
@@ -114,7 +203,7 @@ export default async function EvidencePage({ searchParams }: EvidencePageProps)
|
|
|
114
203
|
<TableCell>{formatExactTokens(session.totalTokens)}</TableCell>
|
|
115
204
|
<TableCell>{formatCurrency(session.cost)}</TableCell>
|
|
116
205
|
<TableCell className="max-w-80">
|
|
117
|
-
<Link href={session.sourceHref} title={session.sourceFile}>
|
|
206
|
+
<Link href={mergeHrefParams(session.sourceHref, rangeLinkParams)} title={session.sourceFile}>
|
|
118
207
|
<MonoText className="block truncate text-muted-foreground underline-offset-4 hover:underline">
|
|
119
208
|
{session.sourceFile}
|
|
120
209
|
</MonoText>
|
|
@@ -125,7 +214,7 @@ export default async function EvidencePage({ searchParams }: EvidencePageProps)
|
|
|
125
214
|
<Badge variant={parserStatusVariant(session.parserStatus)}>
|
|
126
215
|
{session.parserStatus ?? "not scanned"}
|
|
127
216
|
</Badge>
|
|
128
|
-
<Link href={session.parserHref} className="text-xs font-medium text-primary underline-offset-4 hover:underline">
|
|
217
|
+
<Link href={mergeHrefParams(session.parserHref, rangeLinkParams)} className="text-xs font-medium text-primary underline-offset-4 hover:underline">
|
|
129
218
|
Parser <ArrowRight className="inline h-3.5 w-3.5" />
|
|
130
219
|
</Link>
|
|
131
220
|
</div>
|
|
@@ -135,7 +224,7 @@ export default async function EvidencePage({ searchParams }: EvidencePageProps)
|
|
|
135
224
|
</TableCell>
|
|
136
225
|
<TableCell className="min-w-44">
|
|
137
226
|
{session.pricingHref ? (
|
|
138
|
-
<Link href={session.pricingHref} className="font-medium text-primary underline-offset-4 hover:underline">
|
|
227
|
+
<Link href={mergeHrefParams(session.pricingHref, pricingReturnParams)} className="font-medium text-primary underline-offset-4 hover:underline">
|
|
139
228
|
{session.model}
|
|
140
229
|
</Link>
|
|
141
230
|
) : (
|