feat(usage): open the TokenTracker dashboard from the usage monitor
The modal deliberately shows only a slice of the analytics; this hands off to TokenTracker's own local dashboard for the rest. The worker starts `tokentracker serve` on demand and returns the URL, the UI opens the browser. Three things the spawn has to get right: port 7680 is not free on Windows (Delivery Optimization holds [::]:7680) and serve does not fall back, so we scan 7680-7689 with a dual-stack bind probe; --no-open because the CLI would open the browser before the server answers; and the child is a cmd.exe shim, so shutdown kills the process tree. --no-sync keeps our no-cloud-sync rule.
This commit is contained in:
@@ -162,6 +162,17 @@ The per-model / per-task / cost view comes from **TokenTracker**, an external MI
|
||||
- **Fail-open everywhere:** `TokenTrackerState` mirrors `UsageState` — a failed or unparseable
|
||||
fetch never overwrites a good export, it only sets `LastError`. CLI missing → empty analytics
|
||||
plus a hint card in the UI. Nothing here can throw into the queue.
|
||||
- **Local dashboard:** `tokentracker serve --port <p> --no-open --no-sync`, started by the worker on
|
||||
demand (`ITokenTrackerClient.StartDashboardAsync`) for the "Open TokenTracker dashboard" button.
|
||||
Three things this path has to get right: TokenTracker's default port **7680 is not free** on
|
||||
Windows (Delivery Optimization holds `[::]:7680`) and `serve` exits instead of falling back, so
|
||||
we scan 7680–7689 with a **dual-stack** bind probe (an IPv4-only probe calls 7680 free and the
|
||||
spawn then dies); `--no-open` because the CLI would open the browser before the server answers,
|
||||
so we poll `GET http://127.0.0.1:<p>/` (30 s cap) and let the **UI** open the URL; and the child
|
||||
is a `cmd.exe` shim, so shutdown kills the **process tree** or node keeps listening. The
|
||||
spawned server is reused while alive and dies with the worker (`TokenTrackerClient` is
|
||||
`IDisposable`, registered as a singleton) — a worker *crash* leaks it until the port is scanned
|
||||
past.
|
||||
- **Limits, gate and throttle do *not* come from TokenTracker.** They are the OAuth poll above.
|
||||
A broken or absent TokenTracker costs you the cost columns, nothing else.
|
||||
|
||||
@@ -199,7 +210,9 @@ The per-model / per-task / cost view comes from **TokenTracker**, an external MI
|
||||
(`GetTaskUsageAsync`) over a 7d/30d preset or custom range — both with a **cost** column, the
|
||||
task table additionally with retries.
|
||||
- **Analytics header vs. hint card** — the modal shows exactly one of the two. With TokenTracker
|
||||
present: total tokens + total cost, a freshness stamp, and a manual `RefreshAnalytics` button.
|
||||
present: total tokens + total cost, a freshness stamp, a manual `RefreshAnalytics` button and an
|
||||
**Open TokenTracker dashboard** button (spinner while the server boots; everything this modal
|
||||
deliberately doesn't show lives there).
|
||||
Without it: a hint card explaining what TokenTracker is (local only, no `init`, no cloud sync)
|
||||
plus an `Install TokenTracker` button — which is hidden and replaced by a Node-version hint when
|
||||
Node < 20 or Node is missing, because the install would just fail. Install progress and every
|
||||
@@ -223,6 +236,9 @@ The per-model / per-task / cost view comes from **TokenTracker**, an external MI
|
||||
NodeVersion, LastFetchedUtc, LastError, FormatVersion, SessionCount)`. Never throws; an
|
||||
unconfigured worker comes back as not-installed with a reason.
|
||||
- `RefreshTokenTracker()` — forces a fetch, then re-probes and returns the status.
|
||||
- `OpenTokenTrackerDashboard()` — brings up the local dashboard server and returns
|
||||
`TokenTrackerDashboardDto(Ok, Url, Error)`; the UI opens the browser (`ShellOpen.Url`, which
|
||||
refuses anything that isn't http/https). Never throws — a failure also lands in `WorkerLog`.
|
||||
- `InstallTokenTracker()` — `npm i -g tokentracker-cli`, streaming npm's output line by line into
|
||||
`WorkerLog` (npm writes progress to stderr; forwarding it is what keeps a multi-minute global
|
||||
install from looking hung), then force-re-probes.
|
||||
|
||||
Reference in New Issue
Block a user