tokentrace 0.10.0 → 0.11.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 +45 -0
- package/README.md +36 -15
- package/SECURITY.md +6 -2
- package/app/api/repair-items/route.ts +22 -0
- package/app/api/settings/route.ts +3 -1
- package/app/debug/page.tsx +22 -1
- package/app/diagnostics/page.tsx +31 -19
- package/app/discovery/page.tsx +9 -3
- package/app/evidence/page.tsx +165 -5
- package/app/global-error.tsx +2 -2
- package/app/guide/page.tsx +474 -441
- package/app/layout.tsx +1 -1
- package/app/loading.tsx +39 -0
- package/app/models/page.tsx +16 -0
- package/app/optimisation/page.tsx +63 -49
- package/app/page.tsx +647 -514
- package/app/parser-debug/page.tsx +10 -4
- package/app/pricing/page.tsx +2 -2
- package/app/projects/page.tsx +29 -0
- package/app/repair/page.tsx +150 -100
- package/app/sessions/[id]/page.tsx +59 -0
- package/app/sessions/page.tsx +2 -2
- package/app/tools/page.tsx +16 -0
- package/bin/tokentrace.js +1 -1
- package/components/charts/rank-bar-chart.tsx +13 -13
- package/components/charts/trend-chart.tsx +13 -14
- package/components/charts/trend-section.tsx +15 -4
- package/components/charts/use-chart-size.ts +41 -0
- package/components/empty-state.tsx +37 -5
- package/components/period-filter.tsx +23 -25
- package/components/pricing-settings.tsx +8 -8
- package/components/repair-bulk-actions.tsx +84 -0
- package/components/scan-health-summary.tsx +25 -4
- package/components/scan-now-button.tsx +122 -0
- package/components/session-explorer.tsx +32 -3
- package/components/settings-panel.tsx +105 -3
- package/components/sidebar.tsx +85 -30
- package/dist/runtime/agent.mjs +7 -7
- package/dist/runtime/db-seed.mjs +31 -6
- package/dist/runtime/digest.mjs +249 -37
- package/dist/runtime/doctor.mjs +277 -66
- package/dist/runtime/evidence.mjs +1 -1
- package/dist/runtime/insights.mjs +249 -37
- package/dist/runtime/pricing-refresh.mjs +34 -9
- package/dist/runtime/report.mjs +249 -37
- package/dist/runtime/reset.mjs +31 -6
- package/dist/runtime/review.mjs +249 -37
- package/dist/runtime/roadmap.mjs +102 -77
- package/dist/runtime/scan.mjs +427 -76
- package/docs/assets/evidence-0.10.0.png +0 -0
- package/docs/assets/overview-0.10.0.png +0 -0
- package/docs/assets/repair-0.10.0.png +0 -0
- package/docs/assets/scan-health-0.10.0.png +0 -0
- package/package.json +6 -4
- package/scripts/roadmap.ts +1 -1
- package/scripts/security-ioc.mjs +384 -0
- package/scripts/seed-screenshot-data.ts +503 -0
- package/scripts/smoke-cli.mjs +2 -2
- package/scripts/smoke-packed-install.mjs +2 -2
- package/src/db/settings.ts +6 -2
- package/src/ingestion/adapters/index.ts +2 -0
- package/src/ingestion/adapters/sqlite-history.ts +201 -0
- package/src/ingestion/discovery.ts +15 -18
- package/src/ingestion/persist.ts +33 -10
- package/src/ingestion/scan.ts +3 -1
- package/src/ingestion/types.ts +9 -1
- package/src/lib/agent-discovery.ts +7 -7
- package/src/lib/analytics.ts +102 -15
- package/src/lib/cost-recalculation.ts +28 -1
- package/src/lib/cost.ts +1 -1
- package/src/lib/data-confidence.ts +83 -0
- package/src/lib/doctor.ts +9 -9
- package/src/lib/evidence-trail.ts +1 -1
- package/src/lib/first-run-status.ts +11 -11
- package/src/lib/import-profiles.ts +124 -0
- package/src/lib/pricing-manifest.ts +4 -4
- package/src/lib/pricing-refresh.ts +3 -3
- package/src/lib/project-signals.ts +1 -1
- package/src/lib/recommendations.ts +4 -4
- package/src/lib/review-queue.ts +1 -1
- package/src/lib/roadmap-status.ts +107 -78
- package/src/lib/scan-health.ts +35 -8
- package/src/lib/session-timeline.ts +64 -0
- package/src/lib/supply-chain-health.ts +31 -0
- package/src/lib/support-matrix.ts +2 -2
- package/src/lib/token-estimator.ts +72 -5
- package/src/lib/unknown-cost-repair.ts +19 -0
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,51 @@ All notable changes to TokenTrace are documented here.
|
|
|
4
4
|
|
|
5
5
|
## Unreleased
|
|
6
6
|
|
|
7
|
+
## [0.11.0] - 2026-05-18
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- `npm run security:ioc` scans project files and local Claude/VS Code hook files for high-signal Mini Shai-Hulud/TanStack supply-chain indicators before release.
|
|
12
|
+
- Tokenizer-backed estimates for recognized OpenAI/Codex and Claude-family model names, with explicit `tokenizer estimate` and `simple estimate` confidence labels.
|
|
13
|
+
- Native SQLite history ingestion for local usage databases with usage-shaped tables, source-file evidence, import-profile metadata, and source-provided cost preservation.
|
|
14
|
+
- Data Confidence scoring on Overview, Projects, Sessions, and Session Timeline views, combining token source, cost coverage, parser confidence, and scan freshness.
|
|
15
|
+
- Import Profiles in Settings so users can define safe local wrapper-log matchers without writing parser code.
|
|
16
|
+
- Repair Workbench bulk actions for marking visible unknown-cost groups verified, parser-review, ignored, or reopened.
|
|
17
|
+
- Supply-chain IOC status in Scan Health, backed by the same local `security:ioc` scanner used by release checks.
|
|
18
|
+
|
|
19
|
+
### Changed
|
|
20
|
+
|
|
21
|
+
- Session Timeline pages now explain token spikes, model changes, cache activity, cost coverage, confidence drivers, and direct unknown-cost repair links.
|
|
22
|
+
- Scan Health now distinguishes exact, tokenizer-estimated, simple-estimated, high-confidence, low-confidence, and unknown token rows.
|
|
23
|
+
- The roadmap API and CLI now report the 0.11.0 Accuracy & Evidence release contract.
|
|
24
|
+
|
|
25
|
+
### Fixed
|
|
26
|
+
|
|
27
|
+
- Source-provided interaction costs are no longer overwritten as unknown during post-scan cost recalculation when model rates are missing.
|
|
28
|
+
|
|
29
|
+
## [0.10.1] - 2026-05-18
|
|
30
|
+
|
|
31
|
+
### Changed
|
|
32
|
+
|
|
33
|
+
- Guide now uses a manual-style layout with section navigation, compact setup status, workflow rows, command tables, and tighter troubleshooting copy.
|
|
34
|
+
- Sidebar Guide access now lives in a Help area above the version footer so it reads as documentation instead of a product feature.
|
|
35
|
+
- Guide section navigation now sticks while scrolling on desktop widths, and the standalone sidebar Guide link no longer shows redundant Help chrome.
|
|
36
|
+
- Guide Scan now controls now run the local scan directly with inline feedback instead of linking to Settings.
|
|
37
|
+
- Overview now groups processed, fresh, and cached token metrics into one Token Accounting card with direct evidence pivots.
|
|
38
|
+
- Evidence pages now include metric tabs and drill-down actions for source files, sessions, parser confidence, and model-rate or repair follow-up.
|
|
39
|
+
- User-facing model price configuration is now labeled Model Rates so it is not mistaken for TokenTrace product pricing.
|
|
40
|
+
- Overview Usage Pulse now labels current, previous, and change values explicitly inside each metric block.
|
|
41
|
+
- Overview now groups cost and sessions into one split card with a shared help tooltip, compact pane labels, and aligned trust notes/actions.
|
|
42
|
+
- Overview trend charts now default all-time views to the latest 30 days, while keeping 60-day, 90-day, and All history options available.
|
|
43
|
+
- Overview now compacts below-chart diagnostics into Review Status and Top repair items strips, with the full unknown-cost table moved to the Repair page.
|
|
44
|
+
- Evidence, repair, parser, and model-rate links now use consistent action labels: View evidence, Open repair, Set model rate, and Review parser.
|
|
45
|
+
- Sidebar navigation now shows the active page, first-run empty states point to the next useful action, direct scans return richer result feedback, and repair/evidence pages guide users through the next drill-down.
|
|
46
|
+
- Page names now stay aligned around Parsers, Discovery, Insights, Scan Health, Model Rates, and privacy-oriented Raw Data copy.
|
|
47
|
+
- User-facing diagnostic copy now uses Scan Health consistently instead of older mixed diagnostic wording.
|
|
48
|
+
- Product metadata, README, Guide, and agent discovery now point to the TokenTrace product website while creator attribution points to Abhi Yoheswaran's homepage.
|
|
49
|
+
- Period filters use a mobile-friendly preset scroller with custom dates on a compact second row, and trend controls now say Display window with a showing-latest badge.
|
|
50
|
+
- README screenshots were refreshed from a guarded public-safe screenshot database seeded by `npm run screenshots:seed`.
|
|
51
|
+
|
|
7
52
|
## [0.10.0] - 2026-05-18
|
|
8
53
|
|
|
9
54
|
### Added
|
package/README.md
CHANGED
|
@@ -4,11 +4,13 @@
|
|
|
4
4
|
|
|
5
5
|
# TokenTrace CLI
|
|
6
6
|
|
|
7
|
-
Local-first
|
|
7
|
+
Local-first AI CLI usage analytics. TokenTrace scans local CLI logs and local usage databases, normalizes token usage, estimates missing counts with confidence labels, and shows cost, model, project, session, repair, and evidence analytics in a browser dashboard.
|
|
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
|
-
|
|
11
|
+
[Website](https://www.abhiyoheswaran.com/apps/tokentrace) · [Source](https://github.com/abhiyoheswaran1/tokentrace)
|
|
12
|
+
|
|
13
|
+

|
|
12
14
|
|
|
13
15
|
## Start In Seconds
|
|
14
16
|
|
|
@@ -38,7 +40,7 @@ tokentrace agent --json # Print machine-readable agent discovery manifest
|
|
|
38
40
|
tokentrace capabilities --json
|
|
39
41
|
# Alias for agent discovery manifest
|
|
40
42
|
tokentrace roadmap --json
|
|
41
|
-
# Print
|
|
43
|
+
# Print Accuracy & Evidence release implementation status
|
|
42
44
|
tokentrace scan # Scan local AI CLI usage logs
|
|
43
45
|
tokentrace doctor --json
|
|
44
46
|
# Inspect scan health and repair recommendations
|
|
@@ -112,7 +114,7 @@ curl http://127.0.0.1:3030/api/agent
|
|
|
112
114
|
curl http://127.0.0.1:3030/api/capabilities
|
|
113
115
|
```
|
|
114
116
|
|
|
115
|
-
The
|
|
117
|
+
The Accuracy & Evidence release status is also machine-readable:
|
|
116
118
|
|
|
117
119
|
```bash
|
|
118
120
|
tokentrace roadmap --json
|
|
@@ -139,18 +141,36 @@ npm run start # Serve the production build
|
|
|
139
141
|
npm run scan # Scan default and configured folders
|
|
140
142
|
npm run db:migrate # Create/update local SQLite tables
|
|
141
143
|
npm run db:seed # Seed editable provider/model prices
|
|
144
|
+
npm run screenshots:seed
|
|
145
|
+
# Seed a guarded public-safe screenshot database
|
|
142
146
|
npm run reset # Clear imported data and scan history
|
|
143
147
|
npm test # Run parser and cost tests
|
|
144
148
|
npm run verify # Run Vitest, TypeScript, and ESLint checks
|
|
145
149
|
npm run package:test # Verify, build, and dry-run the npm package
|
|
146
150
|
npm run package:inspect
|
|
147
151
|
# Check package transparency guardrails
|
|
152
|
+
npm run security:ioc
|
|
153
|
+
# Scan lockfiles, workflows, and local AI-tool hooks for supply-chain IOCs
|
|
148
154
|
npm run smoke:packed
|
|
149
155
|
# Inspect packed tarball and smoke test packed CLI
|
|
150
156
|
tokentrace roadmap --json
|
|
151
|
-
# Inspect
|
|
157
|
+
# Inspect evidence gates and release status
|
|
152
158
|
```
|
|
153
159
|
|
|
160
|
+
## Accuracy And Evidence
|
|
161
|
+
|
|
162
|
+
TokenTrace labels the trust level behind imported numbers:
|
|
163
|
+
|
|
164
|
+
- exact provider token counts
|
|
165
|
+
- tokenizer estimates for recognized OpenAI/Codex and Claude-family model names
|
|
166
|
+
- simple estimates when only text-like content is available
|
|
167
|
+
- source-provided costs from local SQLite histories
|
|
168
|
+
- unknown cost repair groups when model, token, or rate evidence is missing
|
|
169
|
+
|
|
170
|
+
The dashboard surfaces a Data Confidence score on Overview, Projects, Sessions,
|
|
171
|
+
and Session Timeline pages. Scan Health also includes a supply-chain IOC check
|
|
172
|
+
so package trust is visible in the product, not only in release scripts.
|
|
173
|
+
|
|
154
174
|
Release work uses internal milestone commits until the next public minor
|
|
155
175
|
release. See [docs/RELEASE_CHECKLIST.md](docs/RELEASE_CHECKLIST.md) before
|
|
156
176
|
bumping versions, tagging, creating GitHub releases, or publishing npm.
|
|
@@ -190,7 +210,7 @@ Default discovery checks these locations when present:
|
|
|
190
210
|
- TokenTrace wrapper logs in the local app-data directory
|
|
191
211
|
- Any custom folders configured in Settings
|
|
192
212
|
|
|
193
|
-
Use **Settings** in the dashboard to add custom folders, toggle raw message storage, and trigger scans. Use **
|
|
213
|
+
Use **Settings** in the dashboard to add custom folders, toggle raw message storage, and trigger scans. Use **Scan Health**, **Discovery**, **Parsers**, and **Raw Data** to inspect discovered files, parser decisions, warnings, failures, extracted metadata, and confidence levels.
|
|
194
214
|
|
|
195
215
|
Settings also supports optional local monthly usage guardrails. Set a cost
|
|
196
216
|
limit, token limit, or both, and Overview will show month-to-date progress from
|
|
@@ -280,15 +300,15 @@ Codex CLI status-line integration is intentionally deferred until its status-lin
|
|
|
280
300
|
|
|
281
301
|
## Screenshots
|
|
282
302
|
|
|
283
|
-
|
|
303
|
+
Dashboard views:
|
|
284
304
|
|
|
285
|
-

|
|
286
306
|
|
|
287
|
-

|
|
288
308
|
|
|
289
|
-

|
|
290
310
|
|
|
291
|
-

|
|
292
312
|
|
|
293
313
|
CLI startup and help:
|
|
294
314
|
|
|
@@ -320,15 +340,16 @@ Stop the server with `Ctrl+C` in the terminal where `tokentrace` is running.
|
|
|
320
340
|
- The published package ships readable application source and the compiled CLI runtime, not generated `.next/server` route bundles.
|
|
321
341
|
- `tokentrace serve` prepares the local dashboard build in the user's TokenTrace app-data directory the first time it is needed.
|
|
322
342
|
- `npm run package:inspect` fails if generated Next.js build output appears in the published tarball.
|
|
343
|
+
- `npm run security:ioc` scans lockfiles, workflows, and local Claude/VS Code hook files for high-signal supply-chain compromise indicators.
|
|
323
344
|
- Public npm publishing is configured through GitHub Actions Trusted Publishing and provenance from version tags.
|
|
324
345
|
- Socket GitHub checks and ProjScan are used as release guardrails, alongside `npm audit --audit-level=moderate`.
|
|
325
346
|
- Release notes are published directly in GitHub Releases from the relevant changelog section, not as a link-only summary.
|
|
326
347
|
|
|
327
348
|
See [SECURITY.md](SECURITY.md) for the full security and privacy model.
|
|
328
349
|
|
|
329
|
-
##
|
|
350
|
+
## Model Rates
|
|
330
351
|
|
|
331
|
-
Model prices change. TokenTrace ships with bundled public list prices and can refresh them from a public TokenTrace
|
|
352
|
+
Model prices change. TokenTrace ships with bundled public list prices and can refresh them from a public TokenTrace model-rate manifest. Manual edits made in **Model Rates** are preserved by future refreshes.
|
|
332
353
|
|
|
333
354
|
The bundled catalog includes common OpenAI, Anthropic, Google Gemini, xAI, DeepSeek, Mistral, and Cohere models, checked on May 8, 2026.
|
|
334
355
|
|
|
@@ -342,7 +363,7 @@ Seed sources:
|
|
|
342
363
|
- [Mistral model docs](https://docs.mistral.ai/models)
|
|
343
364
|
- [Cohere pricing](https://cohere.com/pricing)
|
|
344
365
|
|
|
345
|
-
Review and update
|
|
366
|
+
Review and update rates in **Model Rates** before treating cost estimates as financial truth, especially if you use batch processing, priority/flex modes, data residency, long-context surcharges, subscriptions, or provider-specific discounts.
|
|
346
367
|
|
|
347
368
|
Refresh from the dashboard or from the CLI:
|
|
348
369
|
|
|
@@ -411,7 +432,7 @@ Contributions are welcome. See [CONTRIBUTING.md](CONTRIBUTING.md) for local setu
|
|
|
411
432
|
|
|
412
433
|
## License
|
|
413
434
|
|
|
414
|
-
Open source by [Abhi Yoheswaran](https://
|
|
435
|
+
Open source by [Abhi Yoheswaran](https://www.abhiyoheswaran.com). Released under the MIT License. See `LICENSE`.
|
|
415
436
|
|
|
416
437
|
## Next Improvements
|
|
417
438
|
|
package/SECURITY.md
CHANGED
|
@@ -40,8 +40,12 @@ When running from source, the default development database is
|
|
|
40
40
|
## Release Trust
|
|
41
41
|
|
|
42
42
|
Public package releases are built from Git tags. The release flow includes
|
|
43
|
-
package inspection, production dependency audit,
|
|
44
|
-
Trusted Publishing through GitHub Actions.
|
|
43
|
+
package inspection, supply-chain IOC scanning, production dependency audit,
|
|
44
|
+
ProjScan checks, and npm Trusted Publishing through GitHub Actions.
|
|
45
|
+
|
|
46
|
+
Run `npm run security:ioc` to check lockfiles, GitHub Actions workflows, and
|
|
47
|
+
local Claude/VS Code hook files for high-signal Mini Shai-Hulud/TanStack-style
|
|
48
|
+
indicators before release or after a dependency scare.
|
|
45
49
|
|
|
46
50
|
## Reporting
|
|
47
51
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { NextResponse } from "next/server";
|
|
2
2
|
import {
|
|
3
|
+
bulkUpdateUnknownCostRepairs,
|
|
3
4
|
buildUnknownCostRepairWorkbench,
|
|
4
5
|
getUnknownCostReview,
|
|
5
6
|
saveUnknownCostReview,
|
|
@@ -40,9 +41,30 @@ export async function PUT(request: Request) {
|
|
|
40
41
|
return NextResponse.json({ error: parsed.error }, { status: 400 });
|
|
41
42
|
}
|
|
42
43
|
const body = parsed.body;
|
|
44
|
+
const keys = Array.isArray(body.keys)
|
|
45
|
+
? body.keys.map((value) => text(value, 1000)).filter(Boolean)
|
|
46
|
+
: [];
|
|
43
47
|
const key = text(body.key, 1000);
|
|
44
48
|
const status = reviewState(body.status ?? body.state);
|
|
45
49
|
|
|
50
|
+
if (keys.length) {
|
|
51
|
+
if (!status) {
|
|
52
|
+
return NextResponse.json({ error: "status must be unresolved, ignored, resolved, or needs-parser-review" }, { status: 400 });
|
|
53
|
+
}
|
|
54
|
+
const currentKeys = new Set(buildUnknownCostRepairWorkbench().groups.map((group) => group.key));
|
|
55
|
+
const missingKey = keys.find((item) => !currentKeys.has(item) && !getUnknownCostReview(item)?.updatedAt);
|
|
56
|
+
if (missingKey) {
|
|
57
|
+
return NextResponse.json({ error: "one or more repair keys were not found in current workbench evidence" }, { status: 404 });
|
|
58
|
+
}
|
|
59
|
+
return NextResponse.json(
|
|
60
|
+
bulkUpdateUnknownCostRepairs({
|
|
61
|
+
keys,
|
|
62
|
+
status,
|
|
63
|
+
notes: text(body.notes ?? body.note, 500)
|
|
64
|
+
})
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
|
|
46
68
|
if (!key) {
|
|
47
69
|
return NextResponse.json({ error: "key is required" }, { status: 400 });
|
|
48
70
|
}
|
|
@@ -2,6 +2,7 @@ import { NextResponse } from "next/server";
|
|
|
2
2
|
import { getDatabasePath } from "@/src/db/client";
|
|
3
3
|
import { getAppSettings, normalizeUsageGuardrails, saveAppSettings } from "@/src/db/settings";
|
|
4
4
|
import { jsonBooleanFlag, readJsonObject } from "@/src/lib/api-json";
|
|
5
|
+
import { normalizeImportProfiles } from "@/src/lib/import-profiles";
|
|
5
6
|
|
|
6
7
|
export const dynamic = "force-dynamic";
|
|
7
8
|
|
|
@@ -27,7 +28,8 @@ export async function PUT(request: Request) {
|
|
|
27
28
|
const saved = saveAppSettings({
|
|
28
29
|
customFolders,
|
|
29
30
|
storeRawMessageContent: jsonBooleanFlag(body.storeRawMessageContent),
|
|
30
|
-
usageGuardrails: normalizeUsageGuardrails(body.usageGuardrails)
|
|
31
|
+
usageGuardrails: normalizeUsageGuardrails(body.usageGuardrails),
|
|
32
|
+
importProfiles: normalizeImportProfiles(body.importProfiles)
|
|
31
33
|
});
|
|
32
34
|
|
|
33
35
|
return NextResponse.json(saved);
|
package/app/debug/page.tsx
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { Badge } from "@/components/ui/badge";
|
|
2
|
+
import { EmptyState } from "@/components/empty-state";
|
|
3
|
+
import { ScanNowButton } from "@/components/scan-now-button";
|
|
2
4
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
|
|
3
5
|
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";
|
|
4
6
|
import { MonoText, PageHeader } from "@/components/ui/typography";
|
|
@@ -21,9 +23,26 @@ export default function DebugPage() {
|
|
|
21
23
|
<div className="space-y-6">
|
|
22
24
|
<PageHeader
|
|
23
25
|
title="Raw Data"
|
|
24
|
-
description="
|
|
26
|
+
description="Local raw data for scan runs, parser selection, imported records, warnings, and failures."
|
|
25
27
|
/>
|
|
26
28
|
|
|
29
|
+
<div className="rounded-md border bg-card p-3 text-sm leading-6 text-muted-foreground">
|
|
30
|
+
<span className="font-medium text-foreground">Local raw data:</span>{" "}
|
|
31
|
+
Treat file paths and parser metadata as local sensitive data. This page is for debugging imports, not sharing screenshots.
|
|
32
|
+
</div>
|
|
33
|
+
|
|
34
|
+
{!data.scanRuns.length && !data.scanFiles.length ? (
|
|
35
|
+
<EmptyState
|
|
36
|
+
title="No raw scan data yet"
|
|
37
|
+
description="Run a scan to populate local raw data. If nothing appears after a scan, open Scan Health to review roots and parser status."
|
|
38
|
+
actions={[
|
|
39
|
+
{ label: "Open Scan Health", href: "/diagnostics", variant: "outline" }
|
|
40
|
+
]}
|
|
41
|
+
>
|
|
42
|
+
<ScanNowButton size="sm" />
|
|
43
|
+
</EmptyState>
|
|
44
|
+
) : (
|
|
45
|
+
<>
|
|
27
46
|
<Card>
|
|
28
47
|
<CardHeader>
|
|
29
48
|
<CardTitle>Recent Scan Runs</CardTitle>
|
|
@@ -97,6 +116,8 @@ export default function DebugPage() {
|
|
|
97
116
|
</Table>
|
|
98
117
|
</CardContent>
|
|
99
118
|
</Card>
|
|
119
|
+
</>
|
|
120
|
+
)}
|
|
100
121
|
</div>
|
|
101
122
|
);
|
|
102
123
|
}
|
package/app/diagnostics/page.tsx
CHANGED
|
@@ -7,8 +7,10 @@ import { DataValue, FieldLabel, MonoText, PageHeader } from "@/components/ui/typ
|
|
|
7
7
|
import { ScanHealthSummary } from "@/components/scan-health-summary";
|
|
8
8
|
import { getAnalyticsData, getScanTrustData, type DebugScanRun } from "@/src/lib/analytics";
|
|
9
9
|
import { buildDoctorReport, type DoctorReport } from "@/src/lib/doctor";
|
|
10
|
+
import { buildScanHealth } from "@/src/lib/scan-health";
|
|
10
11
|
import { getDefaultSearchRoots } from "@/src/ingestion/discovery";
|
|
11
12
|
import { formatDate } from "@/src/lib/format";
|
|
13
|
+
import { getSupplyChainHealth } from "@/src/lib/supply-chain-health";
|
|
12
14
|
|
|
13
15
|
export const dynamic = "force-dynamic";
|
|
14
16
|
|
|
@@ -43,7 +45,7 @@ function TrustChecklist({
|
|
|
43
45
|
const hasInteractions = data.confidence.interactions > 0;
|
|
44
46
|
const unknownCauses = data.health.costCoverage.unknownCauses;
|
|
45
47
|
const unknownCauseText = [
|
|
46
|
-
unknownCauses.missingPricing > 0 ? `${unknownCauses.missingPricing.toLocaleString()} missing
|
|
48
|
+
unknownCauses.missingPricing > 0 ? `${unknownCauses.missingPricing.toLocaleString()} missing model rate` : null,
|
|
47
49
|
unknownCauses.missingModelName > 0 ? `${unknownCauses.missingModelName.toLocaleString()} missing model` : null,
|
|
48
50
|
unknownCauses.missingTokenCount > 0 ? `${unknownCauses.missingTokenCount.toLocaleString()} missing token count` : null,
|
|
49
51
|
unknownCauses.other > 0 ? `${unknownCauses.other.toLocaleString()} other` : null
|
|
@@ -51,11 +53,11 @@ function TrustChecklist({
|
|
|
51
53
|
|
|
52
54
|
const items: Array<{ label: string; detail: string; status: ChecklistStatus }> = [
|
|
53
55
|
{
|
|
54
|
-
label: "
|
|
56
|
+
label: "Model rates loaded",
|
|
55
57
|
status: data.pricedModelCount > 0 ? "pass" : "warn",
|
|
56
58
|
detail: data.pricedModelCount > 0
|
|
57
|
-
? `${data.pricedModelCount.toLocaleString()}
|
|
58
|
-
: "Seed
|
|
59
|
+
? `${data.pricedModelCount.toLocaleString()} rated models are available.`
|
|
60
|
+
: "Seed model rates before trusting cost totals."
|
|
59
61
|
},
|
|
60
62
|
{
|
|
61
63
|
label: "CLI roots found",
|
|
@@ -77,10 +79,10 @@ function TrustChecklist({
|
|
|
77
79
|
detail: latest ? `${latest.recordsImported.toLocaleString()} interactions imported in the latest scan.` : "No scan has imported records yet."
|
|
78
80
|
},
|
|
79
81
|
{
|
|
80
|
-
label: "Unknown
|
|
82
|
+
label: "Unknown cost",
|
|
81
83
|
status: !hasInteractions ? "pending" : data.health.costCoverage.unknown > 0 ? "warn" : "pass",
|
|
82
84
|
detail: !hasInteractions
|
|
83
|
-
? "
|
|
85
|
+
? "Model-rate coverage appears after records are imported."
|
|
84
86
|
: data.health.costCoverage.unknown > 0
|
|
85
87
|
? `${data.health.costCoverage.unknown.toLocaleString()} interactions need repair: ${unknownCauseText || "cause unavailable"}.`
|
|
86
88
|
: "Imported interactions have usable cost coverage."
|
|
@@ -153,9 +155,9 @@ function DoctorReportPanel({ report }: { report: DoctorReport }) {
|
|
|
153
155
|
return (
|
|
154
156
|
<Card>
|
|
155
157
|
<CardHeader>
|
|
156
|
-
<CardTitle>
|
|
158
|
+
<CardTitle>Scan Health report</CardTitle>
|
|
157
159
|
<CardDescription>
|
|
158
|
-
|
|
160
|
+
The same local Scan Health data returned by `tokentrace doctor --json`.
|
|
159
161
|
</CardDescription>
|
|
160
162
|
</CardHeader>
|
|
161
163
|
<CardContent className="space-y-4">
|
|
@@ -217,7 +219,7 @@ function DoctorReportPanel({ report }: { report: DoctorReport }) {
|
|
|
217
219
|
</div>
|
|
218
220
|
|
|
219
221
|
<div className="space-y-2">
|
|
220
|
-
<div className="text-sm font-semibold">
|
|
222
|
+
<div className="text-sm font-semibold">Recommended fixes</div>
|
|
221
223
|
<div className="grid gap-2 lg:grid-cols-2">
|
|
222
224
|
{report.recommendations.slice(0, 6).map((item) => (
|
|
223
225
|
<Link key={item.id} href={item.href ?? "/diagnostics"} className="border-t p-3 transition-colors hover:bg-muted/40">
|
|
@@ -236,7 +238,7 @@ function DoctorReportPanel({ report }: { report: DoctorReport }) {
|
|
|
236
238
|
|
|
237
239
|
<div className="space-y-3">
|
|
238
240
|
<div>
|
|
239
|
-
<div className="text-sm font-semibold">
|
|
241
|
+
<div className="text-sm font-semibold">Supported file types</div>
|
|
240
242
|
<div className="mt-1 text-xs text-muted-foreground">
|
|
241
243
|
{report.supportMatrix.summary.stable.toLocaleString()} stable,{" "}
|
|
242
244
|
{report.supportMatrix.summary.bestEffort.toLocaleString()} best-effort,{" "}
|
|
@@ -267,7 +269,7 @@ function ParserTrustPanel({ report }: { report: DoctorReport["parserTrust"] }) {
|
|
|
267
269
|
return (
|
|
268
270
|
<Card>
|
|
269
271
|
<CardHeader>
|
|
270
|
-
<CardTitle>
|
|
272
|
+
<CardTitle>File parser review</CardTitle>
|
|
271
273
|
<CardDescription>
|
|
272
274
|
Latest scan files grouped by parser, source family, version, status, and import yield. Ignored files are known support files, not usage transcripts. Unsupported files need parser review before they become usage.
|
|
273
275
|
</CardDescription>
|
|
@@ -342,7 +344,7 @@ function ScanDiffPanel({ report }: { report: DoctorReport["scanDiff"] }) {
|
|
|
342
344
|
return (
|
|
343
345
|
<Card>
|
|
344
346
|
<CardHeader>
|
|
345
|
-
<CardTitle>Scan
|
|
347
|
+
<CardTitle>Scan history comparison</CardTitle>
|
|
346
348
|
<CardDescription>
|
|
347
349
|
Latest scan compared with the previous scan using deterministic scan ordering. Ignored files are known support files, not usage transcripts.
|
|
348
350
|
</CardDescription>
|
|
@@ -461,7 +463,17 @@ function ScanHistoryPanel({ scanRuns }: { scanRuns: DebugScanRun[] }) {
|
|
|
461
463
|
}
|
|
462
464
|
|
|
463
465
|
export default async function DiagnosticsPage() {
|
|
464
|
-
const
|
|
466
|
+
const baseData = getScanTrustData();
|
|
467
|
+
const supplyChain = getSupplyChainHealth();
|
|
468
|
+
const data = {
|
|
469
|
+
...baseData,
|
|
470
|
+
health: buildScanHealth({
|
|
471
|
+
scanRuns: baseData.scanRuns,
|
|
472
|
+
scanFiles: baseData.scanFiles,
|
|
473
|
+
confidence: baseData.confidence,
|
|
474
|
+
supplyChain
|
|
475
|
+
})
|
|
476
|
+
};
|
|
465
477
|
const analytics = getAnalyticsData();
|
|
466
478
|
const roots = await getDefaultSearchRoots();
|
|
467
479
|
const doctorReport = buildDoctorReport({
|
|
@@ -472,8 +484,8 @@ export default async function DiagnosticsPage() {
|
|
|
472
484
|
return (
|
|
473
485
|
<div className="space-y-6">
|
|
474
486
|
<PageHeader
|
|
475
|
-
title="Scan
|
|
476
|
-
description="
|
|
487
|
+
title="Scan Health"
|
|
488
|
+
description="Shows whether local usage was imported, which files need review, and whether model-rate coverage is usable."
|
|
477
489
|
/>
|
|
478
490
|
|
|
479
491
|
<TrustChecklist data={data} rootCount={roots.length} />
|
|
@@ -481,7 +493,7 @@ export default async function DiagnosticsPage() {
|
|
|
481
493
|
<Card>
|
|
482
494
|
<CardHeader>
|
|
483
495
|
<CardTitle>Local recommendations</CardTitle>
|
|
484
|
-
<CardDescription>Deterministic next actions from local scan,
|
|
496
|
+
<CardDescription>Deterministic next actions from local scan, model rates, parser, project, and cache data.</CardDescription>
|
|
485
497
|
</CardHeader>
|
|
486
498
|
<CardContent className="grid divide-y overflow-hidden p-0 lg:grid-cols-3 lg:divide-x lg:divide-y-0">
|
|
487
499
|
{analytics.recommendations.slice(0, 3).map((item) => (
|
|
@@ -513,12 +525,12 @@ export default async function DiagnosticsPage() {
|
|
|
513
525
|
{[
|
|
514
526
|
{
|
|
515
527
|
href: "/discovery",
|
|
516
|
-
title: "
|
|
528
|
+
title: "Discovered files",
|
|
517
529
|
description: "Inspect which local files were discovered, skipped, imported, or unsupported."
|
|
518
530
|
},
|
|
519
531
|
{
|
|
520
532
|
href: "/parser-debug",
|
|
521
|
-
title: "Parser
|
|
533
|
+
title: "Parser review",
|
|
522
534
|
description: "Review adapter selection, parser confidence, warnings, errors, and extracted metadata."
|
|
523
535
|
},
|
|
524
536
|
{
|
|
@@ -543,7 +555,7 @@ export default async function DiagnosticsPage() {
|
|
|
543
555
|
|
|
544
556
|
<Card>
|
|
545
557
|
<CardHeader>
|
|
546
|
-
<CardTitle>
|
|
558
|
+
<CardTitle>Local privacy rules</CardTitle>
|
|
547
559
|
<CardDescription>TokenTrace uses direct local filesystem ingestion as the primary architecture.</CardDescription>
|
|
548
560
|
</CardHeader>
|
|
549
561
|
<CardContent className="flex flex-wrap gap-2">
|
package/app/discovery/page.tsx
CHANGED
|
@@ -3,6 +3,7 @@ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/com
|
|
|
3
3
|
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";
|
|
4
4
|
import { DataValue, FieldLabel, MonoText, PageHeader } from "@/components/ui/typography";
|
|
5
5
|
import { EmptyState } from "@/components/empty-state";
|
|
6
|
+
import { ScanNowButton } from "@/components/scan-now-button";
|
|
6
7
|
import { getScanTrustData } from "@/src/lib/analytics";
|
|
7
8
|
import { formatDate } from "@/src/lib/format";
|
|
8
9
|
|
|
@@ -27,7 +28,7 @@ export default function DiscoveryPage() {
|
|
|
27
28
|
return (
|
|
28
29
|
<div className="space-y-6">
|
|
29
30
|
<PageHeader
|
|
30
|
-
title="
|
|
31
|
+
title="Discovery"
|
|
31
32
|
description="Every file shown here was discovered by passive local filesystem scanning."
|
|
32
33
|
/>
|
|
33
34
|
<div className="grid overflow-hidden rounded-md border bg-card sm:grid-cols-2 lg:grid-cols-5">
|
|
@@ -55,8 +56,13 @@ export default function DiscoveryPage() {
|
|
|
55
56
|
{!scanFiles.length ? (
|
|
56
57
|
<EmptyState
|
|
57
58
|
title="No files discovered yet"
|
|
58
|
-
description="Run a scan from Settings to populate
|
|
59
|
-
|
|
59
|
+
description="Run a scan from Settings to populate Discovery. If expected folders are missing, add them in Settings."
|
|
60
|
+
actions={[
|
|
61
|
+
{ label: "Add folder", href: "/settings", variant: "outline" }
|
|
62
|
+
]}
|
|
63
|
+
>
|
|
64
|
+
<ScanNowButton size="sm" />
|
|
65
|
+
</EmptyState>
|
|
60
66
|
) : (
|
|
61
67
|
<Card>
|
|
62
68
|
<CardHeader>
|