tokentrace 0.21.0 → 0.21.2
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 +22 -0
- package/README.md +35 -20
- package/TOKENTRACE_AGENT.md +11 -3
- package/docs/agent-adoption.md +3 -0
- package/docs/assets/evidence-0.21.0.png +0 -0
- package/docs/assets/fix-data-0.21.0.png +0 -0
- package/docs/assets/scan-health-0.21.0.png +0 -0
- package/docs/assets/today-0.21.0.png +0 -0
- package/llms.txt +4 -0
- package/package.json +1 -1
- package/server.json +2 -2
- package/src/lib/analytics-types.ts +56 -5
- package/src/lib/evidence/query.ts +1 -1
- package/src/lib/evidence-trail.ts +1 -1
- package/src/lib/project-signals.ts +2 -13
- package/src/lib/review-queue.ts +4 -21
- package/src/lib/scan-health-rules.ts +1 -1
- package/src/lib/scan-health-types.ts +104 -0
- package/src/lib/scan-health.ts +16 -104
- package/src/lib/session-comparison.ts +2 -20
- package/src/lib/unknown-cost-repair/auto-classify.ts +16 -41
- package/src/lib/unknown-cost-repair/classification-types.ts +41 -0
- package/src/lib/unknown-cost-repair/types.ts +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,28 @@ All notable changes to TokenTrace are documented here.
|
|
|
4
4
|
|
|
5
5
|
## Unreleased
|
|
6
6
|
|
|
7
|
+
## [0.21.2] - 2026-06-26
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- **ProjScan circular-import warnings removed.** Shared scan-health, analytics,
|
|
12
|
+
evidence, review-queue, project-signal, session-comparison, and unknown-cost
|
|
13
|
+
repair contracts now live in leaf type modules so the import graph stays
|
|
14
|
+
acyclic. Added a regression test for these architecture boundaries.
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
|
|
18
|
+
- **Low-risk dependency refresh.** Updated patch and minor dependencies within
|
|
19
|
+
the existing major-version ranges after audit and package-security checks.
|
|
20
|
+
|
|
21
|
+
## [0.21.1] - 2026-06-26
|
|
22
|
+
|
|
23
|
+
### Changed
|
|
24
|
+
|
|
25
|
+
- **README and website handoff now match the simplified product.** Refreshed the
|
|
26
|
+
public docs around preflight, Today, Evidence, Fix Data, and current
|
|
27
|
+
Playwright-captured `0.21.0` dashboard screenshots.
|
|
28
|
+
|
|
7
29
|
## [0.21.0] - 2026-06-26
|
|
8
30
|
|
|
9
31
|
### Added
|
package/README.md
CHANGED
|
@@ -4,13 +4,26 @@
|
|
|
4
4
|
|
|
5
5
|
# TokenTrace CLI
|
|
6
6
|
|
|
7
|
-
Local-first AI CLI usage analytics
|
|
7
|
+
Local-first AI CLI usage analytics for developers and coding agents.
|
|
8
|
+
|
|
9
|
+
TokenTrace answers one practical question before the next expensive AI CLI run:
|
|
10
|
+
is your local usage evidence ready to trust? It scans local Claude Code, Codex,
|
|
11
|
+
structured usage logs, and usage-shaped local databases, then labels token and
|
|
12
|
+
cost data as exact, estimated, unknown, cached, or non-cache. The dashboard
|
|
13
|
+
opens on **Today**, with direct paths into Sessions, Evidence, and Fix Data.
|
|
8
14
|
|
|
9
15
|
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
16
|
|
|
11
17
|
[Website](https://www.baseframelabs.com/apps/tokentrace) · [Source](https://github.com/abhiyoheswaran1/tokentrace)
|
|
12
18
|
|
|
13
|
-

|
|
20
|
+
|
|
21
|
+
## What TokenTrace Helps You Do
|
|
22
|
+
|
|
23
|
+
- Check readiness before another coding-agent run with `tokentrace preflight --json` or MCP `get_preflight`.
|
|
24
|
+
- See today’s local cost, tokens, sessions, confidence, anomalies, and repair signals in one first screen.
|
|
25
|
+
- Trace every important number back to local files, parser state, sessions, model rates, and confidence labels.
|
|
26
|
+
- Fix missing cost data through a guided repair queue without uploading prompts or message bodies.
|
|
14
27
|
|
|
15
28
|
## Start In Seconds
|
|
16
29
|
|
|
@@ -133,8 +146,7 @@ explicit scan tool. It does not scan files on startup, and its scan tool require
|
|
|
133
146
|
`confirmLocalScan=true` before reading local usage files or writing the local
|
|
134
147
|
database.
|
|
135
148
|
|
|
136
|
-
Before starting another long coding-agent run, use
|
|
137
|
-
surface:
|
|
149
|
+
Before starting another long coding-agent run, use preflight:
|
|
138
150
|
|
|
139
151
|
```bash
|
|
140
152
|
tokentrace preflight --json
|
|
@@ -195,13 +207,17 @@ tokentrace roadmap --json
|
|
|
195
207
|
# Inspect roadmap handoff, action recipes, and release status
|
|
196
208
|
```
|
|
197
209
|
|
|
198
|
-
##
|
|
210
|
+
## Daily Loop And Trust
|
|
199
211
|
|
|
200
|
-
TokenTrace
|
|
201
|
-
scheduling, scoped guardrails, parser profile preview, saved reports, and
|
|
202
|
-
agent-readable release status.
|
|
212
|
+
TokenTrace now organizes the product around the daily loop:
|
|
203
213
|
|
|
204
|
-
|
|
214
|
+
1. **Preflight**: decide whether local evidence is ready before another agent run.
|
|
215
|
+
2. **Today**: review cost, token, session, confidence, anomaly, and repair signals.
|
|
216
|
+
3. **Evidence**: trace numbers back to source files, parser confidence, sessions, and model-rate state.
|
|
217
|
+
4. **Fix Data**: resolve unknown cost, parser review, and model-rate gaps.
|
|
218
|
+
5. **Advanced**: inspect Scan Health, Discovery, Parsers, Raw Data, Query, and Model Rates when you need the full diagnostic surface.
|
|
219
|
+
|
|
220
|
+
Trust surfaces include:
|
|
205
221
|
|
|
206
222
|
- native structured usage log and Cursor-style chat export ingestion
|
|
207
223
|
- Source Coverage in Scan Health for native, profile-assisted, fallback, and
|
|
@@ -214,11 +230,6 @@ New trust surfaces include:
|
|
|
214
230
|
cost, high-cost sessions, and confidence trends
|
|
215
231
|
- operating metadata export without raw usage records
|
|
216
232
|
|
|
217
|
-
The 0.12.0 dashboard also tightens the daily operator path: setup buttons now
|
|
218
|
-
open the exact Settings section, scan results show what changed and where to go
|
|
219
|
-
next, and Evidence explains when it is being opened as a contextual drill-down
|
|
220
|
-
rather than a sidebar destination.
|
|
221
|
-
|
|
222
233
|
## Accuracy And Evidence
|
|
223
234
|
|
|
224
235
|
TokenTrace labels the trust level behind imported numbers:
|
|
@@ -270,10 +281,13 @@ Default discovery checks these locations when present:
|
|
|
270
281
|
- TokenTrace wrapper logs in the local app-data directory
|
|
271
282
|
- Any custom folders configured in Settings
|
|
272
283
|
|
|
273
|
-
Use **Settings**
|
|
284
|
+
Use **Settings** to add custom folders, toggle raw message storage, and trigger
|
|
285
|
+
scans. Use **Scan Health**, **Discovery**, **Parsers**, and **Raw Data** to
|
|
286
|
+
inspect discovered files, parser decisions, warnings, failures, extracted
|
|
287
|
+
metadata, and confidence levels.
|
|
274
288
|
|
|
275
289
|
Settings also supports optional local monthly usage guardrails. Set a cost
|
|
276
|
-
limit, token limit, or both, and
|
|
290
|
+
limit, token limit, or both, and Today will show month-to-date progress from
|
|
277
291
|
imported local CLI usage.
|
|
278
292
|
|
|
279
293
|
Sessions includes built-in and local saved views for recurring review paths:
|
|
@@ -362,13 +376,13 @@ Codex CLI status-line integration is intentionally deferred until its status-lin
|
|
|
362
376
|
|
|
363
377
|
Dashboard views:
|
|
364
378
|
|
|
365
|
-

|
|
366
380
|
|
|
367
|
-

|
|
368
382
|
|
|
369
|
-

|
|
370
384
|
|
|
371
|
-

|
|
372
386
|
|
|
373
387
|
CLI startup and help:
|
|
374
388
|
|
|
@@ -403,6 +417,7 @@ Stop the server with `Ctrl+C` in the terminal where `tokentrace` is running.
|
|
|
403
417
|
- `npm run security:ioc` scans lockfiles, workflows, and local Claude/VS Code hook files for high-signal supply-chain compromise indicators.
|
|
404
418
|
- Public npm publishing is configured through GitHub Actions Trusted Publishing and provenance from version tags.
|
|
405
419
|
- Socket GitHub checks and ProjScan are used as release guardrails, alongside `npm audit --audit-level=moderate`.
|
|
420
|
+
- `npm run release:check` fails when a gate command exits non-zero. The import graph is expected to remain free of circular dependencies; `tests/import-boundaries.test.ts` protects shared type/helper modules from importing higher-level orchestration barrels.
|
|
406
421
|
- Release notes are published directly in GitHub Releases from the relevant changelog section, not as a link-only summary.
|
|
407
422
|
|
|
408
423
|
See [SECURITY.md](SECURITY.md) for the full security and privacy model.
|
package/TOKENTRACE_AGENT.md
CHANGED
|
@@ -3,6 +3,11 @@
|
|
|
3
3
|
TokenTrace is a local-first CLI and dashboard for AI coding-agent token, cost,
|
|
4
4
|
session, parser, and evidence analytics.
|
|
5
5
|
|
|
6
|
+
The current product loop is: run preflight, review Today, inspect Sessions or
|
|
7
|
+
Evidence, then use Fix Data when model rates or parser confidence block trusted
|
|
8
|
+
costs. Advanced pages remain available for diagnostics, but agents should start
|
|
9
|
+
from preflight before long runs.
|
|
10
|
+
|
|
6
11
|
## Start Here
|
|
7
12
|
|
|
8
13
|
Use the read-only discovery manifest before running any other TokenTrace command:
|
|
@@ -101,19 +106,22 @@ curl http://127.0.0.1:3030/api/roadmap
|
|
|
101
106
|
tokentrace preflight --json
|
|
102
107
|
```
|
|
103
108
|
|
|
104
|
-
4.
|
|
109
|
+
4. Follow the preflight decision. Use Today for the human-facing status, Evidence
|
|
110
|
+
for numeric claims, and Fix Data for unknown-cost work.
|
|
111
|
+
|
|
112
|
+
5. Refresh local data when the human expects current usage:
|
|
105
113
|
|
|
106
114
|
```bash
|
|
107
115
|
tokentrace scan --json
|
|
108
116
|
```
|
|
109
117
|
|
|
110
|
-
|
|
118
|
+
6. Check trust before making claims:
|
|
111
119
|
|
|
112
120
|
```bash
|
|
113
121
|
tokentrace doctor --json
|
|
114
122
|
```
|
|
115
123
|
|
|
116
|
-
|
|
124
|
+
7. Explain totals with evidence:
|
|
117
125
|
|
|
118
126
|
```bash
|
|
119
127
|
tokentrace evidence --json
|
package/docs/agent-adoption.md
CHANGED
|
@@ -5,6 +5,9 @@ session, parser, and repair questions. The goal is not to make agents guess from
|
|
|
5
5
|
terminal history. The goal is to make them check local TokenTrace data first,
|
|
6
6
|
then report with confidence labels and evidence.
|
|
7
7
|
|
|
8
|
+
The current workflow is short: preflight first, Today for status, Evidence for
|
|
9
|
+
numbers, and Fix Data for unknown-cost or parser-confidence repairs.
|
|
10
|
+
|
|
8
11
|
## MCP Install
|
|
9
12
|
|
|
10
13
|
MCP registry name:
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/llms.txt
CHANGED
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
> Local-first analytics for AI CLI usage, focused on coding-agent tokens, costs, sessions, parser confidence, and evidence trails.
|
|
4
4
|
|
|
5
|
+
Current product loop: preflight before long runs, Today for local readiness and
|
|
6
|
+
daily usage, Sessions for conversation detail, Evidence for numeric claims, and
|
|
7
|
+
Fix Data for unknown cost or parser-confidence work.
|
|
8
|
+
|
|
5
9
|
## Agent Entry Point
|
|
6
10
|
|
|
7
11
|
Start with:
|
package/package.json
CHANGED
package/server.json
CHANGED
|
@@ -8,12 +8,12 @@
|
|
|
8
8
|
"url": "https://github.com/abhiyoheswaran1/tokentrace",
|
|
9
9
|
"source": "github"
|
|
10
10
|
},
|
|
11
|
-
"version": "0.21.
|
|
11
|
+
"version": "0.21.2",
|
|
12
12
|
"packages": [
|
|
13
13
|
{
|
|
14
14
|
"registryType": "npm",
|
|
15
15
|
"identifier": "tokentrace",
|
|
16
|
-
"version": "0.21.
|
|
16
|
+
"version": "0.21.2",
|
|
17
17
|
"runtimeHint": "npx",
|
|
18
18
|
"packageArguments": [
|
|
19
19
|
{
|
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
import type { DataConfidenceGrade, DataConfidenceScore } from "@/src/lib/data-confidence";
|
|
2
|
-
import type { EvidenceMetric } from "@/src/lib/evidence
|
|
2
|
+
import type { EvidenceMetric } from "@/src/lib/evidence/metrics";
|
|
3
3
|
import type { LocalRecommendation } from "@/src/lib/recommendations";
|
|
4
|
-
import type {
|
|
5
|
-
import type { ReviewQueueItem } from "@/src/lib/review-queue";
|
|
6
|
-
import type { ScanConfidenceSummary, ScanHealth } from "@/src/lib/scan-health";
|
|
7
|
-
import type { SessionComparisonRow } from "@/src/lib/session-comparison";
|
|
4
|
+
import type { ScanConfidenceSummary, ScanHealth } from "@/src/lib/scan-health-types";
|
|
8
5
|
import type { UsageGuardrailProgress } from "@/src/lib/usage-guardrails";
|
|
9
6
|
|
|
10
7
|
export type TrendPoint = {
|
|
@@ -172,6 +169,60 @@ export type ModelAliasSuggestion = {
|
|
|
172
169
|
parserHref: string;
|
|
173
170
|
};
|
|
174
171
|
|
|
172
|
+
export type ReviewQueueCategory =
|
|
173
|
+
| "guardrail"
|
|
174
|
+
| "cost-repair"
|
|
175
|
+
| "session"
|
|
176
|
+
| "project"
|
|
177
|
+
| "model"
|
|
178
|
+
| "cache"
|
|
179
|
+
| "baseline";
|
|
180
|
+
|
|
181
|
+
export type ReviewQueueItem = {
|
|
182
|
+
id: string;
|
|
183
|
+
severity: "high" | "medium" | "low";
|
|
184
|
+
category: ReviewQueueCategory;
|
|
185
|
+
title: string;
|
|
186
|
+
evidence: string;
|
|
187
|
+
action: string;
|
|
188
|
+
href: string;
|
|
189
|
+
impactLabel: string;
|
|
190
|
+
impactValue: string;
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
export type SessionComparisonRow = {
|
|
194
|
+
sessionId: string;
|
|
195
|
+
title: string;
|
|
196
|
+
project: string;
|
|
197
|
+
tool: string;
|
|
198
|
+
models: string;
|
|
199
|
+
totalTokens: number;
|
|
200
|
+
cost: number | null;
|
|
201
|
+
peerSessions: number;
|
|
202
|
+
peerMedianTokens: number;
|
|
203
|
+
peerMedianCost: number | null;
|
|
204
|
+
tokenMultiple: number;
|
|
205
|
+
costMultiple: number | null;
|
|
206
|
+
severity: "high" | "medium" | "low";
|
|
207
|
+
flag: "token outlier" | "cost outlier";
|
|
208
|
+
evidence: string;
|
|
209
|
+
action: string;
|
|
210
|
+
href: string;
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
export type ProjectSignalRow = {
|
|
214
|
+
id: string;
|
|
215
|
+
severity: "high" | "medium" | "low";
|
|
216
|
+
project: string;
|
|
217
|
+
path: string;
|
|
218
|
+
signal: "dominant usage" | "unknown cost" | "estimated tokens" | "model concentration";
|
|
219
|
+
evidence: string;
|
|
220
|
+
action: string;
|
|
221
|
+
href: string;
|
|
222
|
+
metricLabel: string;
|
|
223
|
+
metricValue: string;
|
|
224
|
+
};
|
|
225
|
+
|
|
175
226
|
export type DebugScanFile = {
|
|
176
227
|
id: string;
|
|
177
228
|
scanRunId: string;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { sqlite } from "@/src/db/client";
|
|
2
|
-
import type { AnalyticsFilters } from "@/src/lib/analytics";
|
|
2
|
+
import type { AnalyticsFilters } from "@/src/lib/analytics-types";
|
|
3
3
|
import type { EvidenceMetric } from "@/src/lib/evidence/metrics";
|
|
4
4
|
|
|
5
5
|
export type EvidenceSessionRow = {
|
|
@@ -1,18 +1,7 @@
|
|
|
1
|
-
import type { ProjectAnalyticsRow, SessionRow } from "@/src/lib/analytics";
|
|
1
|
+
import type { ProjectAnalyticsRow, ProjectSignalRow, SessionRow } from "@/src/lib/analytics-types";
|
|
2
2
|
import { formatTokens } from "@/src/lib/format";
|
|
3
3
|
|
|
4
|
-
export type ProjectSignalRow
|
|
5
|
-
id: string;
|
|
6
|
-
severity: "high" | "medium" | "low";
|
|
7
|
-
project: string;
|
|
8
|
-
path: string;
|
|
9
|
-
signal: "dominant usage" | "unknown cost" | "estimated tokens" | "model concentration";
|
|
10
|
-
evidence: string;
|
|
11
|
-
action: string;
|
|
12
|
-
href: string;
|
|
13
|
-
metricLabel: string;
|
|
14
|
-
metricValue: string;
|
|
15
|
-
};
|
|
4
|
+
export type { ProjectSignalRow } from "@/src/lib/analytics-types";
|
|
16
5
|
|
|
17
6
|
type ProjectSignalInput = {
|
|
18
7
|
totalTokens: number;
|
package/src/lib/review-queue.ts
CHANGED
|
@@ -2,33 +2,16 @@ import { formatCurrency, formatTokens } from "@/src/lib/format";
|
|
|
2
2
|
import type {
|
|
3
3
|
ModelAnalyticsRow,
|
|
4
4
|
ProjectAnalyticsRow,
|
|
5
|
+
ReviewQueueCategory,
|
|
6
|
+
ReviewQueueItem,
|
|
5
7
|
SessionRow,
|
|
6
8
|
SummaryMetrics,
|
|
7
9
|
ToolComparisonRow,
|
|
8
10
|
UnknownCostQueueRow
|
|
9
|
-
} from "@/src/lib/analytics";
|
|
11
|
+
} from "@/src/lib/analytics-types";
|
|
10
12
|
import type { UsageGuardrailProgress, UsageGuardrailMetric } from "@/src/lib/usage-guardrails";
|
|
11
13
|
|
|
12
|
-
export type ReviewQueueCategory
|
|
13
|
-
| "guardrail"
|
|
14
|
-
| "cost-repair"
|
|
15
|
-
| "session"
|
|
16
|
-
| "project"
|
|
17
|
-
| "model"
|
|
18
|
-
| "cache"
|
|
19
|
-
| "baseline";
|
|
20
|
-
|
|
21
|
-
export type ReviewQueueItem = {
|
|
22
|
-
id: string;
|
|
23
|
-
severity: "high" | "medium" | "low";
|
|
24
|
-
category: ReviewQueueCategory;
|
|
25
|
-
title: string;
|
|
26
|
-
evidence: string;
|
|
27
|
-
action: string;
|
|
28
|
-
href: string;
|
|
29
|
-
impactLabel: string;
|
|
30
|
-
impactValue: string;
|
|
31
|
-
};
|
|
14
|
+
export type { ReviewQueueCategory, ReviewQueueItem } from "@/src/lib/analytics-types";
|
|
32
15
|
|
|
33
16
|
type ReviewQueueInput = {
|
|
34
17
|
summary: Pick<SummaryMetrics, "totalTokens" | "totalCost" | "inputTokens" | "cachedTokens" | "unknownCostInteractions">;
|
|
@@ -6,7 +6,7 @@ import type {
|
|
|
6
6
|
ScanHealthNoteGroup,
|
|
7
7
|
ScanHealthRun,
|
|
8
8
|
SupplyChainHealth
|
|
9
|
-
} from "@/src/lib/scan-health";
|
|
9
|
+
} from "@/src/lib/scan-health-types";
|
|
10
10
|
|
|
11
11
|
export function incrementCount(target: Record<string, number>, key: string, amount = 1) {
|
|
12
12
|
target[key] = (target[key] ?? 0) + amount;
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
export type ScanHealthRun = {
|
|
2
|
+
id: string;
|
|
3
|
+
startedAt: number;
|
|
4
|
+
completedAt: number | null;
|
|
5
|
+
filesScanned: number;
|
|
6
|
+
recordsImported: number;
|
|
7
|
+
warnings: string[];
|
|
8
|
+
errors: string[];
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export type ScanHealthFile = {
|
|
12
|
+
id: string;
|
|
13
|
+
scanRunId: string;
|
|
14
|
+
path: string;
|
|
15
|
+
modifiedTime: number | null;
|
|
16
|
+
sizeBytes: number;
|
|
17
|
+
parser: string | null;
|
|
18
|
+
status: string;
|
|
19
|
+
recordsImported: number;
|
|
20
|
+
warnings: string[];
|
|
21
|
+
errors: string[];
|
|
22
|
+
rawMetadata: Record<string, unknown>;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export type ScanConfidenceSummary = {
|
|
26
|
+
interactions: number;
|
|
27
|
+
exactTokenInteractions: number;
|
|
28
|
+
tokenizerEstimateInteractions?: number;
|
|
29
|
+
simpleEstimateInteractions?: number;
|
|
30
|
+
highConfidenceTokenInteractions: number;
|
|
31
|
+
lowConfidenceTokenInteractions: number;
|
|
32
|
+
unknownTokenInteractions: number;
|
|
33
|
+
estimatedTokenInteractions: number;
|
|
34
|
+
exactCostInteractions: number;
|
|
35
|
+
estimatedCostInteractions: number;
|
|
36
|
+
unknownCostInteractions: number;
|
|
37
|
+
unknownCostCauses: {
|
|
38
|
+
missingModelName: number;
|
|
39
|
+
missingPricing: number;
|
|
40
|
+
missingTokenCount: number;
|
|
41
|
+
other: number;
|
|
42
|
+
};
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export type ScanHealthAction = {
|
|
46
|
+
label: string;
|
|
47
|
+
href: string;
|
|
48
|
+
reason: string;
|
|
49
|
+
tone: "default" | "warning" | "destructive";
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export type SupplyChainHealth = {
|
|
53
|
+
status: "passed" | "failed" | "not-run";
|
|
54
|
+
checkedAt: number | null;
|
|
55
|
+
findings: number;
|
|
56
|
+
summary: string;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
export type ScanHealthNoteGroup = {
|
|
60
|
+
severity: "warning" | "error";
|
|
61
|
+
message: string;
|
|
62
|
+
count: number;
|
|
63
|
+
examples: string[];
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
export type ScanHealth = {
|
|
67
|
+
latestRun: ScanHealthRun | null;
|
|
68
|
+
lastSuccessfulRun: ScanHealthRun | null;
|
|
69
|
+
latestFiles: ScanHealthFile[];
|
|
70
|
+
headline: string;
|
|
71
|
+
description: string;
|
|
72
|
+
tone: "success" | "warning" | "destructive" | "secondary";
|
|
73
|
+
latestStatusCounts: Record<string, number>;
|
|
74
|
+
parserCounts: Record<string, number>;
|
|
75
|
+
latestWarnings: string[];
|
|
76
|
+
latestErrors: string[];
|
|
77
|
+
latestNoteGroups: ScanHealthNoteGroup[];
|
|
78
|
+
freshness: {
|
|
79
|
+
state: "no-scan" | "no-successful-scan" | "fresh" | "stale";
|
|
80
|
+
lastSuccessfulCompletedAt: number | null;
|
|
81
|
+
staleAfterMs: number;
|
|
82
|
+
description: string;
|
|
83
|
+
};
|
|
84
|
+
tokenCoverage: {
|
|
85
|
+
exact: number;
|
|
86
|
+
tokenizerEstimate: number;
|
|
87
|
+
simpleEstimate: number;
|
|
88
|
+
highConfidenceEstimate: number;
|
|
89
|
+
lowConfidenceEstimate: number;
|
|
90
|
+
unknown: number;
|
|
91
|
+
estimated: number;
|
|
92
|
+
total: number;
|
|
93
|
+
};
|
|
94
|
+
costCoverage: {
|
|
95
|
+
priced: number;
|
|
96
|
+
exact: number;
|
|
97
|
+
estimated: number;
|
|
98
|
+
unknown: number;
|
|
99
|
+
unknownCauses: ScanConfidenceSummary["unknownCostCauses"];
|
|
100
|
+
total: number;
|
|
101
|
+
};
|
|
102
|
+
supplyChain: SupplyChainHealth;
|
|
103
|
+
actions: ScanHealthAction[];
|
|
104
|
+
};
|
package/src/lib/scan-health.ts
CHANGED
|
@@ -8,111 +8,23 @@ import {
|
|
|
8
8
|
uniqueMessages,
|
|
9
9
|
type ScanHealthRuleStats
|
|
10
10
|
} from "@/src/lib/scan-health-rules";
|
|
11
|
+
import type {
|
|
12
|
+
ScanConfidenceSummary,
|
|
13
|
+
ScanHealth,
|
|
14
|
+
ScanHealthFile,
|
|
15
|
+
ScanHealthRun,
|
|
16
|
+
SupplyChainHealth
|
|
17
|
+
} from "@/src/lib/scan-health-types";
|
|
11
18
|
|
|
12
|
-
export type
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
export type ScanHealthFile = {
|
|
23
|
-
id: string;
|
|
24
|
-
scanRunId: string;
|
|
25
|
-
path: string;
|
|
26
|
-
modifiedTime: number | null;
|
|
27
|
-
sizeBytes: number;
|
|
28
|
-
parser: string | null;
|
|
29
|
-
status: string;
|
|
30
|
-
recordsImported: number;
|
|
31
|
-
warnings: string[];
|
|
32
|
-
errors: string[];
|
|
33
|
-
rawMetadata: Record<string, unknown>;
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
export type ScanConfidenceSummary = {
|
|
37
|
-
interactions: number;
|
|
38
|
-
exactTokenInteractions: number;
|
|
39
|
-
tokenizerEstimateInteractions?: number;
|
|
40
|
-
simpleEstimateInteractions?: number;
|
|
41
|
-
highConfidenceTokenInteractions: number;
|
|
42
|
-
lowConfidenceTokenInteractions: number;
|
|
43
|
-
unknownTokenInteractions: number;
|
|
44
|
-
estimatedTokenInteractions: number;
|
|
45
|
-
exactCostInteractions: number;
|
|
46
|
-
estimatedCostInteractions: number;
|
|
47
|
-
unknownCostInteractions: number;
|
|
48
|
-
unknownCostCauses: {
|
|
49
|
-
missingModelName: number;
|
|
50
|
-
missingPricing: number;
|
|
51
|
-
missingTokenCount: number;
|
|
52
|
-
other: number;
|
|
53
|
-
};
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
export type ScanHealthAction = {
|
|
57
|
-
label: string;
|
|
58
|
-
href: string;
|
|
59
|
-
reason: string;
|
|
60
|
-
tone: "default" | "warning" | "destructive";
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
export type SupplyChainHealth = {
|
|
64
|
-
status: "passed" | "failed" | "not-run";
|
|
65
|
-
checkedAt: number | null;
|
|
66
|
-
findings: number;
|
|
67
|
-
summary: string;
|
|
68
|
-
};
|
|
69
|
-
|
|
70
|
-
export type ScanHealthNoteGroup = {
|
|
71
|
-
severity: "warning" | "error";
|
|
72
|
-
message: string;
|
|
73
|
-
count: number;
|
|
74
|
-
examples: string[];
|
|
75
|
-
};
|
|
76
|
-
|
|
77
|
-
export type ScanHealth = {
|
|
78
|
-
latestRun: ScanHealthRun | null;
|
|
79
|
-
lastSuccessfulRun: ScanHealthRun | null;
|
|
80
|
-
latestFiles: ScanHealthFile[];
|
|
81
|
-
headline: string;
|
|
82
|
-
description: string;
|
|
83
|
-
tone: "success" | "warning" | "destructive" | "secondary";
|
|
84
|
-
latestStatusCounts: Record<string, number>;
|
|
85
|
-
parserCounts: Record<string, number>;
|
|
86
|
-
latestWarnings: string[];
|
|
87
|
-
latestErrors: string[];
|
|
88
|
-
latestNoteGroups: ScanHealthNoteGroup[];
|
|
89
|
-
freshness: {
|
|
90
|
-
state: "no-scan" | "no-successful-scan" | "fresh" | "stale";
|
|
91
|
-
lastSuccessfulCompletedAt: number | null;
|
|
92
|
-
staleAfterMs: number;
|
|
93
|
-
description: string;
|
|
94
|
-
};
|
|
95
|
-
tokenCoverage: {
|
|
96
|
-
exact: number;
|
|
97
|
-
tokenizerEstimate: number;
|
|
98
|
-
simpleEstimate: number;
|
|
99
|
-
highConfidenceEstimate: number;
|
|
100
|
-
lowConfidenceEstimate: number;
|
|
101
|
-
unknown: number;
|
|
102
|
-
estimated: number;
|
|
103
|
-
total: number;
|
|
104
|
-
};
|
|
105
|
-
costCoverage: {
|
|
106
|
-
priced: number;
|
|
107
|
-
exact: number;
|
|
108
|
-
estimated: number;
|
|
109
|
-
unknown: number;
|
|
110
|
-
unknownCauses: ScanConfidenceSummary["unknownCostCauses"];
|
|
111
|
-
total: number;
|
|
112
|
-
};
|
|
113
|
-
supplyChain: SupplyChainHealth;
|
|
114
|
-
actions: ScanHealthAction[];
|
|
115
|
-
};
|
|
19
|
+
export type {
|
|
20
|
+
ScanConfidenceSummary,
|
|
21
|
+
ScanHealth,
|
|
22
|
+
ScanHealthAction,
|
|
23
|
+
ScanHealthFile,
|
|
24
|
+
ScanHealthNoteGroup,
|
|
25
|
+
ScanHealthRun,
|
|
26
|
+
SupplyChainHealth
|
|
27
|
+
} from "@/src/lib/scan-health-types";
|
|
116
28
|
|
|
117
29
|
export function buildScanHealth({
|
|
118
30
|
scanRuns,
|
|
@@ -1,25 +1,7 @@
|
|
|
1
|
-
import type { SessionRow } from "@/src/lib/analytics";
|
|
1
|
+
import type { SessionComparisonRow, SessionRow } from "@/src/lib/analytics-types";
|
|
2
2
|
import { formatCurrency, formatTokens } from "@/src/lib/format";
|
|
3
3
|
|
|
4
|
-
export type SessionComparisonRow
|
|
5
|
-
sessionId: string;
|
|
6
|
-
title: string;
|
|
7
|
-
project: string;
|
|
8
|
-
tool: string;
|
|
9
|
-
models: string;
|
|
10
|
-
totalTokens: number;
|
|
11
|
-
cost: number | null;
|
|
12
|
-
peerSessions: number;
|
|
13
|
-
peerMedianTokens: number;
|
|
14
|
-
peerMedianCost: number | null;
|
|
15
|
-
tokenMultiple: number;
|
|
16
|
-
costMultiple: number | null;
|
|
17
|
-
severity: "high" | "medium" | "low";
|
|
18
|
-
flag: "token outlier" | "cost outlier";
|
|
19
|
-
evidence: string;
|
|
20
|
-
action: string;
|
|
21
|
-
href: string;
|
|
22
|
-
};
|
|
4
|
+
export type { SessionComparisonRow } from "@/src/lib/analytics-types";
|
|
23
5
|
|
|
24
6
|
function median(values: number[]) {
|
|
25
7
|
if (!values.length) return 0;
|
|
@@ -1,46 +1,21 @@
|
|
|
1
1
|
import { prepareCached } from "@/src/db/prepared";
|
|
2
2
|
import { modelNameCandidates } from "@/src/lib/model-aliases";
|
|
3
|
-
import type {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
cause: UnknownCostRepairWorkbenchGroup["cause"];
|
|
20
|
-
providerId: string;
|
|
21
|
-
model: string;
|
|
22
|
-
sourceFile: string;
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
export type PricedModelRow = {
|
|
26
|
-
providerId: string;
|
|
27
|
-
providerName: string;
|
|
28
|
-
modelName: string;
|
|
29
|
-
usageCount: number;
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
export type SourcePricedRow = {
|
|
33
|
-
sourceFile: string;
|
|
34
|
-
providerId: string;
|
|
35
|
-
providerName: string;
|
|
36
|
-
modelName: string;
|
|
37
|
-
usageCount: number;
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
export type ClassificationLookups = {
|
|
41
|
-
pricedByProvider: Map<string, PricedModelRow[]>;
|
|
42
|
-
pricedBySource: Map<string, SourcePricedRow>;
|
|
43
|
-
};
|
|
3
|
+
import type {
|
|
4
|
+
AutoClassification,
|
|
5
|
+
ClassificationLookups,
|
|
6
|
+
ClassifyInput,
|
|
7
|
+
PricedModelRow,
|
|
8
|
+
SourcePricedRow
|
|
9
|
+
} from "@/src/lib/unknown-cost-repair/classification-types";
|
|
10
|
+
|
|
11
|
+
export type {
|
|
12
|
+
AutoClassification,
|
|
13
|
+
AutoClassificationRule,
|
|
14
|
+
ClassificationLookups,
|
|
15
|
+
ClassifyInput,
|
|
16
|
+
PricedModelRow,
|
|
17
|
+
SourcePricedRow
|
|
18
|
+
} from "@/src/lib/unknown-cost-repair/classification-types";
|
|
44
19
|
|
|
45
20
|
export function buildClassificationLookups(): ClassificationLookups {
|
|
46
21
|
const pricedRows = prepareCached(
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { UnknownCostRepairCause } from "@/src/lib/repair-actions";
|
|
2
|
+
|
|
3
|
+
export type AutoClassificationRule = "exact-model" | "family-fragment" | "parser-source" | "none";
|
|
4
|
+
|
|
5
|
+
export type AutoClassification = {
|
|
6
|
+
suggestedModel: string | null;
|
|
7
|
+
suggestedProvider: string | null;
|
|
8
|
+
confidence: number;
|
|
9
|
+
rule: AutoClassificationRule;
|
|
10
|
+
evidence: {
|
|
11
|
+
matchedRows: number;
|
|
12
|
+
sampleSourceFile: string | null;
|
|
13
|
+
};
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export type ClassifyInput = {
|
|
17
|
+
cause: UnknownCostRepairCause;
|
|
18
|
+
providerId: string;
|
|
19
|
+
model: string;
|
|
20
|
+
sourceFile: string;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export type PricedModelRow = {
|
|
24
|
+
providerId: string;
|
|
25
|
+
providerName: string;
|
|
26
|
+
modelName: string;
|
|
27
|
+
usageCount: number;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export type SourcePricedRow = {
|
|
31
|
+
sourceFile: string;
|
|
32
|
+
providerId: string;
|
|
33
|
+
providerName: string;
|
|
34
|
+
modelName: string;
|
|
35
|
+
usageCount: number;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export type ClassificationLookups = {
|
|
39
|
+
pricedByProvider: Map<string, PricedModelRow[]>;
|
|
40
|
+
pricedBySource: Map<string, SourcePricedRow>;
|
|
41
|
+
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AutoClassification } from "@/src/lib/unknown-cost-repair/
|
|
1
|
+
import type { AutoClassification } from "@/src/lib/unknown-cost-repair/classification-types";
|
|
2
2
|
import type { UnknownCostRepairAction, UnknownCostRepairCause } from "@/src/lib/repair-actions";
|
|
3
3
|
|
|
4
4
|
export type UnknownCostRepairStatus = "unresolved" | "ignored" | "resolved" | "needs-parser-review";
|