tokentrace 0.19.2 → 0.21.0
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 +55 -0
- package/README.md +17 -4
- package/TOKENTRACE_AGENT.md +32 -5
- package/app/api/evidence-pack/route.ts +3 -40
- package/app/evidence/evidence-context-panel.tsx +1 -1
- package/app/guide/guide-content.ts +9 -6
- package/app/guide/page.tsx +4 -4
- package/app/page.tsx +6 -6
- package/app/repair/page.tsx +2 -2
- package/components/overview/summary-cards.tsx +64 -34
- package/components/sidebar.tsx +72 -28
- package/dist/cli/main.mjs +22 -0
- package/dist/runtime/agent.mjs +65 -3
- package/dist/runtime/anomalies.mjs +7 -2
- package/dist/runtime/chatgpt-app.mjs +3901 -0
- package/dist/runtime/digest.mjs +7 -2
- package/dist/runtime/doctor.mjs +7 -2
- package/dist/runtime/evidence.mjs +7 -2
- package/dist/runtime/insights.mjs +7 -2
- package/dist/runtime/mcp.mjs +3540 -3137
- package/dist/runtime/pricing-refresh.mjs +7 -2
- package/dist/runtime/query.mjs +7 -2
- package/dist/runtime/repair.mjs +7 -2
- package/dist/runtime/report.mjs +7 -2
- package/dist/runtime/review.mjs +7 -2
- package/dist/runtime/scan.mjs +7 -2
- package/dist/runtime/status.mjs +7 -2
- package/docs/CHATGPT_APP_PROTOTYPE.md +103 -0
- package/docs/CHATGPT_APP_RELEASE.md +131 -0
- package/docs/agent-adoption.md +24 -10
- package/docs/chatgpt-app/README.md +58 -0
- package/docs/chatgpt-app/assets/icon.png +0 -0
- package/docs/chatgpt-app/assets/listing-card.svg +34 -0
- package/docs/chatgpt-app/assets/widget-preview.svg +24 -0
- package/docs/chatgpt-app/dashboard-fields.json +52 -0
- package/docs/chatgpt-app/manual-release-steps.md +139 -0
- package/docs/chatgpt-app/privacy-and-data.md +39 -0
- package/docs/chatgpt-app/review-response-template.md +53 -0
- package/docs/chatgpt-app/screenshot-checklist.md +46 -0
- package/docs/chatgpt-app/submission-copy.md +45 -0
- package/docs/chatgpt-app/test-prompts-and-responses.md +61 -0
- package/llms.txt +24 -0
- package/next.config.mjs +8 -2
- package/package.json +11 -4
- package/scripts/build-cli-runtime.mjs +1 -0
- package/scripts/chatgpt-app-release-check.mjs +489 -0
- package/scripts/chatgpt-app.ts +107 -0
- package/scripts/package-inspect.mjs +6 -1
- package/scripts/preflight.ts +26 -0
- package/scripts/smoke-packed-install.mjs +5 -0
- package/scripts/visual-smoke.mjs +19 -7
- package/server.json +3 -3
- package/src/cli/commands.ts +18 -0
- package/src/cli/help.ts +6 -0
- package/src/lib/agent-discovery.ts +60 -1
- package/src/lib/chatgpt-app/prototype.ts +452 -0
- package/src/lib/chatgpt-app/server.ts +162 -0
- package/src/lib/evidence-pack.ts +47 -0
- package/src/lib/first-run-status.ts +3 -3
- package/src/lib/mcp/agent-guide.ts +8 -2
- package/src/lib/mcp/tools.ts +7 -0
- package/src/lib/mcp-server.ts +20 -0
- package/src/lib/overview-data.ts +29 -3
- package/src/lib/preflight.ts +431 -0
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,61 @@ All notable changes to TokenTrace are documented here.
|
|
|
4
4
|
|
|
5
5
|
## Unreleased
|
|
6
6
|
|
|
7
|
+
## [0.21.0] - 2026-06-26
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- **Local agent preflight.** Added `tokentrace preflight --json` and MCP
|
|
12
|
+
`get_preflight`, a read-only readiness report that returns proceed, caution,
|
|
13
|
+
or blocked before another coding-agent run. It combines scan freshness, data
|
|
14
|
+
confidence, guardrails, anomaly signals, findings, next actions, and privacy
|
|
15
|
+
notes without scanning files or inspecting raw prompts.
|
|
16
|
+
|
|
17
|
+
### Changed
|
|
18
|
+
|
|
19
|
+
- **Simpler dashboard shell.** Primary navigation now follows the daily loop:
|
|
20
|
+
Today, Sessions, Evidence, Fix Data, Reports, and Settings. Diagnostic
|
|
21
|
+
surfaces such as Tools, Models, Projects, Query, Scan Health, Discovery,
|
|
22
|
+
Parsers, Raw Data, and Model Rates remain available under Advanced.
|
|
23
|
+
|
|
24
|
+
### Fixed
|
|
25
|
+
|
|
26
|
+
- **First-run scan state uses latest scan evidence.** The Today first-run panel
|
|
27
|
+
now distinguishes "scan ran but imported no usage" from "no scan has run,"
|
|
28
|
+
preserving zero-import explanations from Scan Health.
|
|
29
|
+
|
|
30
|
+
## [0.20.0] - 2026-06-12
|
|
31
|
+
|
|
32
|
+
### Changed
|
|
33
|
+
|
|
34
|
+
- **Overview and shell UI polish.** The dashboard shell now groups navigation by
|
|
35
|
+
task area, and the Overview summary surface makes local evidence,
|
|
36
|
+
cached/non-cache token states, and exact/estimated/unknown cost distinctions
|
|
37
|
+
easier to scan.
|
|
38
|
+
- **ChatGPT app feasibility documented.** Added a recommendation to prototype
|
|
39
|
+
only a private, redacted evidence-pack ChatGPT app workflow until public
|
|
40
|
+
distribution can preserve TokenTrace's local-first privacy boundary.
|
|
41
|
+
- **Private ChatGPT app prototype.** Added `tokentrace chatgpt-app` with a
|
|
42
|
+
local HTTP `/mcp` server, one read-only `get_redacted_evidence_pack` Apps SDK
|
|
43
|
+
tool, a compact MCP Apps widget resource, and a developer-mode runbook. The
|
|
44
|
+
prototype uses redacted evidence packs and does not scan files on startup or
|
|
45
|
+
publish a public app.
|
|
46
|
+
- **ChatGPT app release readiness.** Added `npm run release:chatgpt:check`, a
|
|
47
|
+
hosted `/mcp` validator, a release runbook, and optional tag-workflow wiring
|
|
48
|
+
so ChatGPT app readiness can be checked alongside npm and MCP registry
|
|
49
|
+
releases while keeping OpenAI Dashboard submission and publishing manual.
|
|
50
|
+
- **ChatGPT app submission kit.** Added `docs/chatgpt-app/` with step-by-step
|
|
51
|
+
personal-account Dashboard release instructions, ready-to-paste submission
|
|
52
|
+
copy, privacy and review templates, test prompts, screenshot guidance, and
|
|
53
|
+
reusable SVG app assets for the manual ChatGPT app submission flow.
|
|
54
|
+
- **Development dashboard CSP avoids React issue noise.** The local dev server
|
|
55
|
+
now allows React's development-only diagnostics without relaxing the
|
|
56
|
+
production Content Security Policy.
|
|
57
|
+
- **Product website moved to Baseframe Labs.** The package `homepage`, MCP
|
|
58
|
+
registry `websiteUrl`, README link, and in-app guide link now point to
|
|
59
|
+
`https://www.baseframelabs.com/apps/tokentrace`. The previous
|
|
60
|
+
`abhiyoheswaran.com` URL redirects there.
|
|
61
|
+
|
|
7
62
|
## [0.19.2] - 2026-06-05
|
|
8
63
|
|
|
9
64
|
### Changed
|
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@ Local-first AI CLI usage analytics. TokenTrace scans local CLI logs and local us
|
|
|
8
8
|
|
|
9
9
|
TokenTrace is designed for local development machines first, with macOS-oriented defaults. It does not require a cloud account and does not send telemetry or logs anywhere.
|
|
10
10
|
|
|
11
|
-
[Website](https://www.
|
|
11
|
+
[Website](https://www.baseframelabs.com/apps/tokentrace) · [Source](https://github.com/abhiyoheswaran1/tokentrace)
|
|
12
12
|
|
|
13
13
|

|
|
14
14
|
|
|
@@ -45,6 +45,8 @@ tokentrace mcp # Start the local stdio MCP server
|
|
|
45
45
|
tokentrace scan # Scan local AI CLI usage logs
|
|
46
46
|
tokentrace doctor --json
|
|
47
47
|
# Inspect scan health and repair recommendations
|
|
48
|
+
tokentrace preflight --json
|
|
49
|
+
# Check readiness before another coding-agent run
|
|
48
50
|
tokentrace evidence --json
|
|
49
51
|
# Print metric evidence trails as JSON
|
|
50
52
|
tokentrace repair --json
|
|
@@ -126,11 +128,22 @@ tokentrace mcp selftest --json
|
|
|
126
128
|
```
|
|
127
129
|
|
|
128
130
|
The MCP server exposes the same local-first surfaces as tools: capabilities,
|
|
129
|
-
status, Scan Health, evidence, repair queue, reports, and an
|
|
130
|
-
It does not scan files on startup, and its scan tool requires
|
|
131
|
+
preflight, status, Scan Health, evidence, repair queue, reports, and an
|
|
132
|
+
explicit scan tool. It does not scan files on startup, and its scan tool requires
|
|
131
133
|
`confirmLocalScan=true` before reading local usage files or writing the local
|
|
132
134
|
database.
|
|
133
135
|
|
|
136
|
+
Before starting another long coding-agent run, use the read-only preflight
|
|
137
|
+
surface:
|
|
138
|
+
|
|
139
|
+
```bash
|
|
140
|
+
tokentrace preflight --json
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
In MCP clients, call `get_preflight` for the same proceed, caution, or blocked
|
|
144
|
+
decision with local scan freshness, confidence, guardrail, anomaly, and repair
|
|
145
|
+
findings. Preflight does not scan files or inspect raw prompts.
|
|
146
|
+
|
|
134
147
|
When the local dashboard is already running, agents can fetch the same manifest
|
|
135
148
|
over localhost:
|
|
136
149
|
|
|
@@ -216,7 +229,7 @@ TokenTrace labels the trust level behind imported numbers:
|
|
|
216
229
|
- source-provided costs from local SQLite histories
|
|
217
230
|
- unknown cost repair groups when model, token, or rate evidence is missing
|
|
218
231
|
|
|
219
|
-
The dashboard surfaces a Data Confidence score on
|
|
232
|
+
The dashboard surfaces a Data Confidence score on Today, Projects, Sessions,
|
|
220
233
|
and Session Timeline pages. Scan Health also includes a supply-chain IOC check
|
|
221
234
|
so package trust is visible in the product, not only in release scripts.
|
|
222
235
|
|
package/TOKENTRACE_AGENT.md
CHANGED
|
@@ -44,6 +44,27 @@ The MCP server does not scan on startup. Its `run_scan` tool requires
|
|
|
44
44
|
`confirmLocalScan=true` before reading local usage files or writing the local
|
|
45
45
|
database.
|
|
46
46
|
|
|
47
|
+
Before starting another long coding-agent run, use the read-only preflight:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
tokentrace preflight --json
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
The matching MCP tool is `get_preflight`. It returns a proceed, caution, or
|
|
54
|
+
blocked decision with local scan freshness, data confidence, guardrail status,
|
|
55
|
+
anomaly signals, findings, and next actions. It does not scan files.
|
|
56
|
+
|
|
57
|
+
Private ChatGPT developer-mode prototype:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
tokentrace chatgpt-app selftest --json
|
|
61
|
+
tokentrace chatgpt-app --port 8787 --hostname 127.0.0.1
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
This starts a local HTTP `/mcp` server for one read-only redacted evidence-pack
|
|
65
|
+
tool. ChatGPT requires an HTTPS tunnel for developer-mode connector testing.
|
|
66
|
+
See `docs/CHATGPT_APP_PROTOTYPE.md`.
|
|
67
|
+
|
|
47
68
|
If the local dashboard is already running, the same manifest is available from:
|
|
48
69
|
|
|
49
70
|
```bash
|
|
@@ -74,19 +95,25 @@ curl http://127.0.0.1:3030/api/roadmap
|
|
|
74
95
|
get_agent_guide
|
|
75
96
|
```
|
|
76
97
|
|
|
77
|
-
3.
|
|
98
|
+
3. Check whether local evidence is ready for the next agent run:
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
tokentrace preflight --json
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
4. Refresh local data when the human expects current usage:
|
|
78
105
|
|
|
79
106
|
```bash
|
|
80
107
|
tokentrace scan --json
|
|
81
108
|
```
|
|
82
109
|
|
|
83
|
-
|
|
110
|
+
5. Check trust before making claims:
|
|
84
111
|
|
|
85
112
|
```bash
|
|
86
113
|
tokentrace doctor --json
|
|
87
114
|
```
|
|
88
115
|
|
|
89
|
-
|
|
116
|
+
6. Explain totals with evidence:
|
|
90
117
|
|
|
91
118
|
```bash
|
|
92
119
|
tokentrace evidence --json
|
|
@@ -117,8 +144,8 @@ Get deterministic classification suggestions for the unknown-cost queue:
|
|
|
117
144
|
tokentrace repair auto-classify --json [--min-confidence=N]
|
|
118
145
|
```
|
|
119
146
|
|
|
120
|
-
The matching MCP tools are `get_anomalies`, `query_usage`, and
|
|
121
|
-
`get_classifications`. All
|
|
147
|
+
The matching MCP tools are `get_preflight`, `get_anomalies`, `query_usage`, and
|
|
148
|
+
`get_classifications`. All four are read-only and require no
|
|
122
149
|
`confirmLocalScan` acknowledgement.
|
|
123
150
|
|
|
124
151
|
## Guardrails
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { NextResponse } from "next/server";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { buildEvidenceTrail, parseEvidenceMetric } from "@/src/lib/evidence-trail";
|
|
2
|
+
import { buildMetricEvidencePack, renderEvidencePackMarkdown } from "@/src/lib/evidence-pack";
|
|
3
|
+
import { parseEvidenceMetric } from "@/src/lib/evidence-trail";
|
|
5
4
|
|
|
6
5
|
export const dynamic = "force-dynamic";
|
|
7
6
|
|
|
@@ -9,43 +8,7 @@ export async function GET(request: Request) {
|
|
|
9
8
|
const url = new URL(request.url);
|
|
10
9
|
const format = url.searchParams.get("format") === "markdown" ? "markdown" : "json";
|
|
11
10
|
const metric = parseEvidenceMetric(url.searchParams.get("metric"));
|
|
12
|
-
const
|
|
13
|
-
const analytics = getAnalyticsData();
|
|
14
|
-
const pack = buildEvidencePack({
|
|
15
|
-
scope: {
|
|
16
|
-
type: "metric",
|
|
17
|
-
id: metric,
|
|
18
|
-
label: trail.title
|
|
19
|
-
},
|
|
20
|
-
totals: trail.totals,
|
|
21
|
-
confidenceDrivers: [
|
|
22
|
-
`${trail.confidence.exact.toLocaleString()} exact interactions`,
|
|
23
|
-
`${trail.confidence.estimated.toLocaleString()} estimated interactions`,
|
|
24
|
-
`${trail.confidence.unknown.toLocaleString()} unknown interactions`,
|
|
25
|
-
`Data confidence ${analytics.dataConfidence.score}/100`
|
|
26
|
-
],
|
|
27
|
-
sourceFiles: trail.sourceFiles.map((source) => source.sourceFile),
|
|
28
|
-
parserNotes: trail.sessions
|
|
29
|
-
.map((session) => `${session.parser ?? "unknown parser"}: ${session.parserStatus ?? "unknown status"}`)
|
|
30
|
-
.slice(0, 20),
|
|
31
|
-
modelRateState: trail.sessions
|
|
32
|
-
.map((session) =>
|
|
33
|
-
session.pricingHref ? `${session.model}: model-rate link available` : `${session.model}: no model-rate link`
|
|
34
|
-
)
|
|
35
|
-
.slice(0, 20),
|
|
36
|
-
repairLinks: trail.sessions
|
|
37
|
-
.filter((session) => session.unknownCostInteractions > 0)
|
|
38
|
-
.map((session) => `/repair?source=${encodeURIComponent(session.sourceFile)}`),
|
|
39
|
-
records: trail.sessions.map((session) => ({
|
|
40
|
-
id: session.id,
|
|
41
|
-
role: "session",
|
|
42
|
-
model: session.model,
|
|
43
|
-
sourceFile: session.sourceFile,
|
|
44
|
-
totalTokens: session.totalTokens,
|
|
45
|
-
cost: session.cost,
|
|
46
|
-
interactions: session.interactions
|
|
47
|
-
}))
|
|
48
|
-
});
|
|
11
|
+
const pack = buildMetricEvidencePack({ metric });
|
|
49
12
|
|
|
50
13
|
if (format === "markdown") {
|
|
51
14
|
return new NextResponse(renderEvidencePackMarkdown(pack), {
|
|
@@ -16,7 +16,7 @@ export function EvidenceContextPanel({ actions }: { actions: EvidenceContextActi
|
|
|
16
16
|
<div className="max-w-[72ch]">
|
|
17
17
|
<FieldLabel>Evidence path</FieldLabel>
|
|
18
18
|
<p className="mt-1 text-sm leading-6 text-muted-foreground">
|
|
19
|
-
Evidence is a contextual drill-down from
|
|
19
|
+
Evidence is a contextual drill-down from Today, Sessions, Fix Data, and exported packs. If you opened this page directly, start with processed tokens, then pivot by metric or follow the next action that matches what looks incomplete.
|
|
20
20
|
</p>
|
|
21
21
|
</div>
|
|
22
22
|
<div className="grid min-w-0 gap-2 sm:grid-cols-2 xl:grid-cols-4">
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ClipboardList, Gauge, Search, Wrench } from "lucide-react";
|
|
2
2
|
|
|
3
|
-
export const PRODUCT_WEBSITE_URL = "https://www.
|
|
3
|
+
export const PRODUCT_WEBSITE_URL = "https://www.baseframelabs.com/apps/tokentrace";
|
|
4
4
|
|
|
5
5
|
export const guideNav = [
|
|
6
6
|
["#start", "Start here", "First scan to first evidence"],
|
|
@@ -13,8 +13,8 @@ export const guideNav = [
|
|
|
13
13
|
export const dailyLoop = [
|
|
14
14
|
{
|
|
15
15
|
title: "Read the pulse",
|
|
16
|
-
page: "
|
|
17
|
-
detail: "Check
|
|
16
|
+
page: "Today",
|
|
17
|
+
detail: "Check readiness, usage, cost, sessions, unknown cost, and the latest trend window before chasing details.",
|
|
18
18
|
href: "/",
|
|
19
19
|
icon: Gauge
|
|
20
20
|
},
|
|
@@ -27,7 +27,7 @@ export const dailyLoop = [
|
|
|
27
27
|
},
|
|
28
28
|
{
|
|
29
29
|
title: "Repair what blocks trust",
|
|
30
|
-
page: "
|
|
30
|
+
page: "Fix Data",
|
|
31
31
|
detail: "Unknown cost usually needs a known model name, nonzero tokens, or an editable provider model rate.",
|
|
32
32
|
href: "/repair",
|
|
33
33
|
icon: Wrench
|
|
@@ -86,8 +86,11 @@ export const mcpAgentEntries = [
|
|
|
86
86
|
];
|
|
87
87
|
|
|
88
88
|
export const pageMap = [
|
|
89
|
-
["
|
|
89
|
+
["Today", "Top-level readiness, totals, trends, repair queue, guardrails, and recommended next actions."],
|
|
90
90
|
["Sessions", "Per-session evidence with models, costs, cache activity, parser provenance, and tool calls."],
|
|
91
|
+
["Evidence", "Trace a metric back to sessions, source files, confidence drivers, and model-rate state."],
|
|
92
|
+
["Fix Data", "Repair unknown cost, missing model names, missing token counts, and trust blockers."],
|
|
93
|
+
["Reports", "Reusable local reports for weekly usage, high-cost sessions, confidence trends, and source coverage."],
|
|
91
94
|
["Model Rates", "Editable provider model rates used for dashboard cost estimates and unknown-cost repair."],
|
|
92
95
|
["Scan Health", "First-run checklist, scan health, supply-chain IOC check, supported file types, and diagnostics for missing data."],
|
|
93
96
|
["Discovery", "Recently scanned files grouped by parser, source family, status, and import yield."],
|
|
@@ -97,7 +100,7 @@ export const pageMap = [
|
|
|
97
100
|
export const emptyStatePlaybook = [
|
|
98
101
|
["No data", "Run Scan now from Settings, then use Scan Health if records stay at zero."],
|
|
99
102
|
["No logs found", "Add a custom folder or use Claude Code, Codex, or another supported CLI before scanning again."],
|
|
100
|
-
["Unknown cost", "Open
|
|
103
|
+
["Unknown cost", "Open Fix Data or Model Rates to decide whether the missing piece is model name, token count, or provider rate."],
|
|
101
104
|
["Parser warnings", "Open Discovery and Parsers to separate unsupported files from imported-with-errors rows."],
|
|
102
105
|
["Sandbox smoke skipped", "Local sandbox runs can skip server binding checks. Run the packed smoke or release check outside that constraint before release."]
|
|
103
106
|
];
|
package/app/guide/page.tsx
CHANGED
|
@@ -55,7 +55,7 @@ const firstRunSteps: FirstRunStep[] = [
|
|
|
55
55
|
number: "5",
|
|
56
56
|
title: "Inspect evidence",
|
|
57
57
|
page: "Sessions",
|
|
58
|
-
detail: "Use Sessions, Evidence,
|
|
58
|
+
detail: "Use Sessions, Evidence, Fix Data, and Projects after the first useful import.",
|
|
59
59
|
href: "/sessions",
|
|
60
60
|
action: "Open Sessions"
|
|
61
61
|
}
|
|
@@ -69,12 +69,12 @@ const workflows: GuideWorkflow[] = [
|
|
|
69
69
|
},
|
|
70
70
|
{
|
|
71
71
|
problem: "Unknown cost",
|
|
72
|
-
path: "
|
|
72
|
+
path: "Fix Data, Model Rates, Evidence",
|
|
73
73
|
action: "Find whether the missing piece is model name, token count, or editable provider rate."
|
|
74
74
|
},
|
|
75
75
|
{
|
|
76
76
|
problem: "High token usage",
|
|
77
|
-
path: "
|
|
77
|
+
path: "Today, Sessions, Projects",
|
|
78
78
|
action: "Compare processed, non-cache, and cache totals before treating a spike as fresh context growth."
|
|
79
79
|
},
|
|
80
80
|
{
|
|
@@ -111,7 +111,7 @@ export default function GuidePage() {
|
|
|
111
111
|
{
|
|
112
112
|
label: "Unknown cost",
|
|
113
113
|
value: `${unknownCosts.toLocaleString()} unknown costs`,
|
|
114
|
-
detail: unknownCosts > 0 ? "Open
|
|
114
|
+
detail: unknownCosts > 0 ? "Open Fix Data or Model Rates." : "Cost coverage is clear.",
|
|
115
115
|
ok: unknownCosts === 0
|
|
116
116
|
},
|
|
117
117
|
{
|
package/app/page.tsx
CHANGED
|
@@ -53,11 +53,11 @@ async function OverviewPrimarySection({ range }: { range: ResolvedDateRange }) {
|
|
|
53
53
|
.map((entry) => ({ date: entry.date, value: entry.value, severity: entry.severity }));
|
|
54
54
|
|
|
55
55
|
return (
|
|
56
|
-
<div className="space-y-
|
|
56
|
+
<div className="overview-primary-section space-y-7">
|
|
57
57
|
{summary.interactions === 0 ? <FirstRunPanel status={firstRunStatus} /> : null}
|
|
58
58
|
<UsagePulsePanel comparison={data.comparison} />
|
|
59
59
|
<DataConfidenceStrip confidence={data.dataConfidence} />
|
|
60
|
-
<div className="grid gap-3 md:grid-cols-2 xl:grid-cols-6">
|
|
60
|
+
<div className="overview-summary-grid grid gap-3 md:grid-cols-2 xl:grid-cols-6">
|
|
61
61
|
<TokenAccountingCard
|
|
62
62
|
summary={summary}
|
|
63
63
|
processedHref={evidenceLinks["processed-tokens"]}
|
|
@@ -109,7 +109,7 @@ async function OverviewRepairSection({ range }: { range: ResolvedDateRange }) {
|
|
|
109
109
|
}
|
|
110
110
|
|
|
111
111
|
return (
|
|
112
|
-
<div className="space-y-
|
|
112
|
+
<div className="overview-repair-section space-y-7">
|
|
113
113
|
{summary.interactions > 0 ? (
|
|
114
114
|
<OverviewReviewStatusStrip
|
|
115
115
|
report={doctorReport}
|
|
@@ -140,10 +140,10 @@ export default async function OverviewPage({ searchParams }: OverviewPageProps)
|
|
|
140
140
|
const range = resolveDateRange(params);
|
|
141
141
|
|
|
142
142
|
return (
|
|
143
|
-
<div className="space-y-
|
|
143
|
+
<div className="overview-workbench space-y-7">
|
|
144
144
|
<PageHeader
|
|
145
|
-
title="
|
|
146
|
-
description="Local
|
|
145
|
+
title="Today"
|
|
146
|
+
description="Local readiness, cost, token, session, and repair signals before the next AI CLI run."
|
|
147
147
|
actions={
|
|
148
148
|
<Button asChild>
|
|
149
149
|
<Link href="/settings#scan-controls">
|
package/app/repair/page.tsx
CHANGED
|
@@ -22,8 +22,8 @@ export default async function RepairPage({ searchParams }: RepairPageProps) {
|
|
|
22
22
|
return (
|
|
23
23
|
<div className="space-y-6">
|
|
24
24
|
<PageHeader
|
|
25
|
-
title="
|
|
26
|
-
description="Grouped local evidence for interactions that could not be priced."
|
|
25
|
+
title="Fix Data"
|
|
26
|
+
description="Grouped local evidence for interactions that could not be priced or trusted yet."
|
|
27
27
|
actions={
|
|
28
28
|
<div className="flex flex-wrap gap-2">
|
|
29
29
|
<Button asChild variant="outline">
|
|
@@ -6,6 +6,34 @@ import { DataValue, FieldLabel } from "@/components/ui/typography";
|
|
|
6
6
|
import { formatCurrency, formatTokens } from "@/src/lib/format";
|
|
7
7
|
import { cn } from "@/src/lib/utils";
|
|
8
8
|
|
|
9
|
+
type DetailItem = {
|
|
10
|
+
label: string;
|
|
11
|
+
value: string;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
function EvidenceAction({
|
|
15
|
+
href,
|
|
16
|
+
label,
|
|
17
|
+
muted = false
|
|
18
|
+
}: {
|
|
19
|
+
href: string;
|
|
20
|
+
label: string;
|
|
21
|
+
muted?: boolean;
|
|
22
|
+
}) {
|
|
23
|
+
return (
|
|
24
|
+
<Link
|
|
25
|
+
href={href}
|
|
26
|
+
className={cn(
|
|
27
|
+
"inline-flex w-fit items-center gap-1.5 text-xs font-medium underline-offset-4 hover:underline",
|
|
28
|
+
muted ? "text-muted-foreground hover:text-foreground" : "text-primary"
|
|
29
|
+
)}
|
|
30
|
+
>
|
|
31
|
+
<span>{label}</span>
|
|
32
|
+
<ArrowRight className="h-3.5 w-3.5" aria-hidden="true" />
|
|
33
|
+
</Link>
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
|
|
9
37
|
function CostSessionsMetricPane({
|
|
10
38
|
label,
|
|
11
39
|
value,
|
|
@@ -22,7 +50,7 @@ function CostSessionsMetricPane({
|
|
|
22
50
|
}: {
|
|
23
51
|
label: string;
|
|
24
52
|
value: string;
|
|
25
|
-
detailItems:
|
|
53
|
+
detailItems: DetailItem[];
|
|
26
54
|
href: string;
|
|
27
55
|
actionLabel: string;
|
|
28
56
|
secondaryHref?: string;
|
|
@@ -36,7 +64,7 @@ function CostSessionsMetricPane({
|
|
|
36
64
|
return (
|
|
37
65
|
<section
|
|
38
66
|
className={cn(
|
|
39
|
-
"cost-sessions-section grid min-w-0 grid-rows-[auto_auto_auto_auto_1fr_auto] p-4 md:row-span-6 md:grid-rows-subgrid",
|
|
67
|
+
"cost-sessions-section cost-sessions-metric-pane grid min-w-0 grid-rows-[auto_auto_auto_auto_1fr_auto] p-4 md:row-span-6 md:grid-rows-subgrid",
|
|
40
68
|
className
|
|
41
69
|
)}
|
|
42
70
|
>
|
|
@@ -53,8 +81,9 @@ function CostSessionsMetricPane({
|
|
|
53
81
|
|
|
54
82
|
<div className="mt-3 flex flex-wrap items-start gap-x-2 gap-y-1 text-xs leading-snug text-muted-foreground">
|
|
55
83
|
{detailItems.map((item, index) => (
|
|
56
|
-
<span key={item} className="inline-flex min-w-0 items-center gap-
|
|
57
|
-
<span className="
|
|
84
|
+
<span key={item.label} className="inline-flex min-w-0 items-center gap-1.5">
|
|
85
|
+
<span className="font-medium text-foreground">{item.label}</span>
|
|
86
|
+
<span className="min-w-0">{item.value}</span>
|
|
58
87
|
{index < detailItems.length - 1 ? <span className="hidden text-border sm:inline">/</span> : null}
|
|
59
88
|
</span>
|
|
60
89
|
))}
|
|
@@ -67,16 +96,14 @@ function CostSessionsMetricPane({
|
|
|
67
96
|
|
|
68
97
|
<div aria-hidden="true" />
|
|
69
98
|
|
|
70
|
-
<div className="
|
|
71
|
-
<
|
|
72
|
-
|
|
73
|
-
<
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
</Link>
|
|
79
|
-
) : null}
|
|
99
|
+
<div className="pt-4">
|
|
100
|
+
<FieldLabel className="mb-2">Local evidence</FieldLabel>
|
|
101
|
+
<div className="flex flex-wrap items-center gap-x-3 gap-y-1">
|
|
102
|
+
<EvidenceAction href={href} label={actionLabel} />
|
|
103
|
+
{secondaryHref ? (
|
|
104
|
+
<EvidenceAction href={secondaryHref} label={secondaryActionLabel ?? "View details"} muted />
|
|
105
|
+
) : null}
|
|
106
|
+
</div>
|
|
80
107
|
</div>
|
|
81
108
|
</section>
|
|
82
109
|
);
|
|
@@ -124,9 +151,9 @@ export function CostSessionsCard({
|
|
|
124
151
|
value={formatCurrency(summary.totalCost)}
|
|
125
152
|
valueClassName="wrap-break-word text-2xl"
|
|
126
153
|
detailItems={[
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
154
|
+
{ label: "Exact", value: formatCurrency(summary.exactCost) },
|
|
155
|
+
{ label: "Estimated", value: formatCurrency(summary.estimatedCost) },
|
|
156
|
+
{ label: "Unknown", value: summary.unknownCostInteractions.toLocaleString() }
|
|
130
157
|
]}
|
|
131
158
|
href={costHref}
|
|
132
159
|
actionLabel={costActionLabel}
|
|
@@ -140,7 +167,7 @@ export function CostSessionsCard({
|
|
|
140
167
|
className="border-t md:border-l md:border-t-0"
|
|
141
168
|
label="Sessions"
|
|
142
169
|
value={summary.sessions.toLocaleString()}
|
|
143
|
-
detailItems={[
|
|
170
|
+
detailItems={[{ label: "Interactions", value: summary.interactions.toLocaleString() }]}
|
|
144
171
|
href={sessionsHref}
|
|
145
172
|
actionLabel="View evidence"
|
|
146
173
|
trustLabel="Session trust"
|
|
@@ -195,8 +222,8 @@ export function TokenAccountingCard({
|
|
|
195
222
|
}) {
|
|
196
223
|
const evidenceActions = [
|
|
197
224
|
{ label: "Processed", href: processedHref },
|
|
198
|
-
{ label: "Fresh", href: freshHref },
|
|
199
|
-
{ label: "Cache", href: cacheHref }
|
|
225
|
+
{ label: "Fresh / non-cache", href: freshHref },
|
|
226
|
+
{ label: "Cache read/write", href: cacheHref }
|
|
200
227
|
];
|
|
201
228
|
|
|
202
229
|
return (
|
|
@@ -248,7 +275,7 @@ export function TokenAccountingCard({
|
|
|
248
275
|
detail={`${formatTokens(summary.inputTokens)} input / ${formatTokens(summary.outputTokens)} output / ${formatTokens(summary.reasoningTokens)} reasoning`}
|
|
249
276
|
/>
|
|
250
277
|
<TokenAccountingSlice
|
|
251
|
-
label="Cache"
|
|
278
|
+
label="Cache read/write"
|
|
252
279
|
value={formatTokens(summary.cachedTokens)}
|
|
253
280
|
detail={`${formatTokens(summary.cacheReadTokens)} read / ${formatTokens(summary.cacheWriteTokens)} write`}
|
|
254
281
|
/>
|
|
@@ -261,19 +288,22 @@ export function TokenAccountingCard({
|
|
|
261
288
|
</span>
|
|
262
289
|
</p>
|
|
263
290
|
|
|
264
|
-
<div className="mt-auto
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
291
|
+
<div className="mt-auto pt-4">
|
|
292
|
+
<FieldLabel className="mb-2">Local evidence</FieldLabel>
|
|
293
|
+
<div className="flex flex-wrap items-center gap-x-3 gap-y-1">
|
|
294
|
+
{evidenceActions.map((action) => (
|
|
295
|
+
<Link
|
|
296
|
+
key={action.href}
|
|
297
|
+
href={action.href}
|
|
298
|
+
aria-label={`View ${action.label.toLowerCase()} token evidence`}
|
|
299
|
+
className="inline-flex w-fit items-center gap-1.5 text-xs font-medium text-primary underline-offset-4 hover:underline"
|
|
300
|
+
>
|
|
301
|
+
<span className="text-muted-foreground">{action.label}</span>
|
|
302
|
+
<span>View evidence</span>
|
|
303
|
+
<ArrowRight className="h-3.5 w-3.5" aria-hidden="true" />
|
|
304
|
+
</Link>
|
|
305
|
+
))}
|
|
306
|
+
</div>
|
|
277
307
|
</div>
|
|
278
308
|
</CardContent>
|
|
279
309
|
</Card>
|