dsh-web
zhu1090093659/dsh-webDeepSeek Harness(DSH)Web 插件聚合生态包 · 一切皆插件,创意工坊分发(dsh-market.com)
Token usage, model cost analytics, trends, and activity heatmaps for DeepSeek Harness
A local-first DeepSeek Harness plugin for token usage, estimated model cost, trends, and a GitHub-style activity heatmap.
Status: MVP supporting the DSH
0.1.5-rc.2main-panel API, with a legacy navigation fallback for0.1.1-rc.2. The plugin is read-only: the durable Harness session log remains the single source of truth and no parallel telemetry database is created.
Rendered by the real plugin UI with deterministic demonstration data; no personal usage is shown.
<html lang>, maintained by DSH), not the browser's unrelated locale. English and Simplified Chinese match DSH's built-in languages; missing/unsupported languages fall back consistently to English. Language changes update the open panel and sidebar without resetting filters or refetching usage. Session titles and route IDs are never translated.appReady), so indexing never competes with plugin activation, route registration, or first paint; older Hosts without it start indexing at plugin init as before.Requirements: Node.js 22+ and a working dsh web profile.
From npm:
dsh plugin --profile web add @syncended/dsh-usage
Or from this checkout:
pnpm install
pnpm check
dsh plugin --profile web add .
The package declares a DSH bundle, so dsh plugin appends it to the Web profile automatically. Restart the running dsh web process after installing or upgrading, refresh the existing page, and open Usage from the sidebar. The browser client reads the same Host through a package-owned same-origin endpoint; no separate URL, token, telemetry service, or plugin-specific environment variable is required.
To remove it:
dsh plugin --profile web remove @syncended/dsh-usage
Token-rate estimates are not payment records. The dashboard distinguishes:
openai-codex provider. It is not an additional subscription charge; subscription fees and quotas cannot be reconstructed from these logs.$0.Classification uses the provider route (case-insensitive openai-codex), not the model name. A corporate gateway serving a GPT model is not automatically classified as subscription usage. This is a display convention, not a claim about the account's billing arrangement. Configured rates remain estimates too.
For compatibility, API cost fields retain the combined token-rate estimate. Summary/session rows additionally expose apiEstimateCost, subscriptionEquivalentCost, and actualCost: null; model rows expose costKind. The two estimate components sum to cost. Charts and sorting by API equivalent use the combined estimate, never actual spending.
Cost is an estimate derived from provider-reported token buckets and USD-per-million-token rules. The built-in catalog has a 2026-08-26 UTC baseline, with DeepSeek V4.1 Flash rates updated for the 2026-09-10 04:00 UTC transition, and contains 132 price/tier entries compiled into provider-route rules and model-name fallback rules for OpenAI GPT, Anthropic Claude, Google Gemini, DeepSeek, Z.AI GLM, Moonshot/Kimi, xAI Grok, Mistral, Cohere, Alibaba Qwen, and MiniMax.
See the complete generated catalog for every model, price, condition, caveat, and official source URL. The engine handles prompt-length tiers and DeepSeek's recurring UTC peak/off-peak windows. It deliberately does not guess broad future model families: a route without a matching rule remains visible as UNPRICED and is excluded from the API-equivalent estimate, while the dashboard reports pricing coverage.
Built-in rules try known provider/model routes first, then model-name fallbacks such as */glm-5.3. A corporate or custom provider with a recognized model ID therefore gets a public first-party list-price estimate, not its actual negotiated bill. Provider names and model names in the statistics are preserved. Matching is case-insensitive; unknown model IDs are not guessed or renamed. All context tiers, validity dates, and UTC schedules also apply to fallbacks. A custom pricing array replaces the entire catalog (including fallbacks), so explicit corporate rates or an empty array remain authoritative.
Rules are matched in order against provider/model; * is the only route wildcard. Prompt tiers use minPromptTokens / maxPromptTokens, while known promotions and retirements use inclusive validFrom / exclusive validTo ISO-8601 instants. Calls outside a known validity interval remain unpriced rather than silently inheriting an expired rate.
Pricing changes over time, and batch/flex/priority service tiers, regional uplifts, negotiated rates, subscription plans, tool fees, and cache-storage duration may not map to token billing, so override the catalog for your environment when necessary. Current rules without an explicit validity interval remain current-list-price estimates rather than a historical invoice reconstruction. In particular, GPT-5.6 Sol uses its published rates for older sessions too: the catalog verification date is not a price start date, and “at least through November 21” is not a confirmed expiry.
To override pricing or scan behavior, edit the existing usage row in $DSH_HOME/profiles/web/cordis.patch.yml; do not add a duplicate row with the same id. Restart the Host after changing it:
- id: usage
config:
scanConcurrency: 2
scanBatchSize: 32
refreshIntervalSeconds: 60
# Optional; by default $DSH_HOME/cache/usage/checkpoint.json (~/.dsh fallback).
# Set to "" to disable disk caching, or use a distinct absolute path per store/profile.
# cachePath: /absolute/path/to/usage-checkpoint.json
pricing:
- route: openai-codex/gpt-5.6-sol
minPromptTokens: 272000
input: 8
output: 30
cacheRead: 0.8
cacheWrite: 10
- route: openai-codex/gpt-5.6-sol
maxPromptTokens: 271999
input: 4
output: 20
cacheRead: 0.4
cacheWrite: 5
- route: my-provider/private-model
input: 0.8
output: 3.2
cacheRead: 0.08
cacheWrite: 0.8
All amounts are USD per one million tokens. Reasoning tokens are already included in the provider's output bucket and are not counted again.
The Sessions table shows token buckets, separate API estimates and Codex API equivalents, pricing coverage, model count, and calls for each session in the selected date range. Expand a session to see each provider/model's own tokens, calls, and estimate: a mixed session's total is not attributed to its first listed model. API session rows include a models breakdown that reconciles with the session total.
Search by title, session ID, or provider/model route; sort by API equivalent, tokens, calls, or title. Group sessions by their exact title to compare repeated tasks, or by creation day. Groups can be expanded to inspect their individual sessions and model breakdowns. Search filters sessions before grouping, so group totals reflect only matching sessions. Token totals include repeated reads of cached context across calls, not just unique text.
Titles come from saved session metadata, never reconstructed from prompts. Upgrading to session analytics invalidates the older title-less checkpoint (schema v1); the first scan rebuilds it as v2, so totals may initially be partial. Untitled sessions use Session <id>. Renames appear after the next confirmed scan. Costs and tokens include only calls inside the selected range, even when the session was created earlier; grouping by creation day does not change that usage window. Unknown prices remain UNPRICED or partially priced, including inside groups.
ctx.sessionPersistence.list() on current DSH, or listSnapshots() on legacy DSH. A disk checkpoint is reused after matching the fresh listing: legacy persistence compares source-qualified revisions, while current handle-API revisions are only comparable within one service instance, so an entry is accepted only when its stored identity also matches the physical size or the event count the provider reports for the log. Entries without a verifiable identity are reread once and rewritten with one.open(id, 'read'), handle.read(), and handle.close(); legacy DSH uses readFrom(). Read handles are always closed, including after errors or cancellation. Fork-inherited events are excluded using handle.inheritedEventCount on current DSH or the legacy header's seedLength. Usage chunks and final assistant-message usage are folded with one last-wins sample per (turn, step), matching Harness token-meter semantics.GET /api/usage returns the latest in-memory aggregate immediately, without waiting for persistence reads. Optional scan metadata reports initialization, background activity, pending/cached/total session counts, the currently unreadable session count, last completed scan time, and listing failure. The top-level errors count is that same unreadable-session count. Prompts, tool arguments, and message content are never returned.A new pass starts 60 seconds after the previous pass completes (refreshIntervalSeconds, 5–86400 seconds); scans never overlap. The first pass is scheduled by the launcher's successful-startup signal when the Host publishes one, so bootstrap is never delayed by indexing. Work yields between reads/batches, and unloading the plugin cancels pending work and its timer. Completed batches become visible progressively. While the dashboard is visible it polls every 2 seconds during scanning/initialization and every 30 seconds otherwise; Refresh retrieves the latest cached result, not a forced full scan.
Current DSH's finalized assistant/message usage is supported. Usage found only inside an assistant/attempt embedded stream is not yet included; totals are not an invoice reconstruction.
On the first run without a valid checkpoint, totals are explicitly partial until indexing catches up. Active sessions whose revisions change during a read are retried on the next pass; read failures retain the last in-memory values when available. Deleted sessions are removed when the next listing observes them. A listing failure retains the previous projection and is reported in the UI. Sessions skipped as unreadable are reported separately from pending work, so the dashboard shows them as a notice instead of staying in its fast polling mode.
Checkpoints are a disposable, versioned JSON projection, atomically replaced after confirmed batches (at most once per 5 seconds during scanning), at pass completion, and on clean shutdown when dirty. They live at $DSH_HOME/cache/usage/checkpoint.json (default home: ~/.dsh); cachePath: "" disables disk caching. Corrupt/incompatible checkpoints are ignored and rebuilt; write failures only disable persistence of the current update, not analytics. No checkpoint rewrite occurs for an unchanged scan. Use distinct cachePath values for multiple Hosts/profiles using different stores to avoid competing checkpoint writes. To reset the cache, stop the Host and delete that file.
Only usage records, revisions, identities, and unreadable-log backoff marks are persisted, not pricing or timezone-specific aggregates. Pricing changes therefore take effect after restarting with the new configuration; checkpoint reuse avoids rescanning unchanged logs on both persistence APIs. A small in-memory aggregate cache is invalidated on projection changes and local-day rollover.
0700) and checkpoint files use 0600 on POSIX.pnpm install
pnpm check
npm pack --dry-run
The host plugin is strict TypeScript compiled to dist/. The external Web Client Plugin is a ready lazy-CJS module in lib/client.js, so it does not depend on unpublished DSH monorepo frontend tooling.
MIT