Repository navigation
Releases
0.6.8 — listed in the plugin list
The plugin is in the curated list. Pull #5078 was merged on 2026-09-15T06:28:59Z, and the generated list now carries it in Usage & Billing:
- igormel81/dsh-chat-cost - Live token cost for every chat in the DSH Web UI: the chat, its subagents and the whole session tree, priced from a bundled models.dev snapshot of seven providers and 139 priced models, with cache read and write rates wherever the provider publishes them and DeepSeek from its own peak and off-peak table. Every finished answer carries its own price in the transcript…
Their badge is now in all three READMEs, pointing at the list itself. Checked before adding: awesome-dsh-plugin.com/badge.svg returns their own badge, while two guessed endpoints return 404 — a badge that does not render is worse than no badge.
Where the plugin now appears
| Channel | State |
|---|---|
| awesome-dsh-plugin | merged — Usage & Billing |
| npm | latest = 0.6.8, 14 versions, three broken ones deprecated |
| deepseek-plugin-store | bot approved issue #285, verified the commit, opened pull #286 with a generated registry entry — in review |
| dshmarketplace | listed, installable: true |
| dshfind.com | page and badge |
| dsh-plugin-radar | its snapshot predates the merge (2026-09-12); the next one picks us up |
| dsh-market | reads the generated list, follows on its own schedule |
Tests: 142 — 142 pass with 0 skipped where @deepseek-ai/cordis and @deepseek-ai/dsh-tools resolve, 138 pass with 4 reported skips in a plain checkout.
0.6.7 — the price of one answer, in a picture
The first still showed the session total. The differentiator — an answer carrying its own price — was still only described in words, and that is the one claim a reader cannot check without installing.
docs/answer.png: ≈ $0.0441 above the message actions. The figure was cross-checked against the host at the same moment — it reported turn 50 at $0.044123712, which is that turn and nothing else. The caption says exactly that, rather than describing the image.
Both stills (docs/readout.png, docs/answer.png) are referenced from all three READMEs by absolute raw URL, so they render on GitHub, on npm and in the catalogue mirrors. The promotion texts now point at the files instead of asking someone to take screenshots, and the optional third shot (the tooltip) is described but not required.
0.6.6 — the readout, in a picture
The strongest claim in this plugin — the session is priced from the log, not from a re-computation — had no picture, and a visitor decides in about ten seconds.
docs/readout.png, referenced from all three READMEs.
It is a plain still: the composer with the readout under the harness's own stats — ≈ $1.663 for a session at 49 turns, 894 steps, cache hit 99.5%. The ledger at that moment held the same figure, which is why the caption says the session is priced from the log rather than describing the image.
Referenced by an absolute raw URL on purpose: relative paths render on GitHub but not on npm or in the catalogue mirrors, and this image is the first thing a reader looks at. docs/ stays out of the npm tarball — the packaged README points at the raw URL, so shipping a duplicate 35 KB would buy nothing.
The tooltip shot is still missing; submission/promo/readme-screenshot.md now records that shot 1 is in and describes only what remains.
0.6.5 — updating, and knowing what you run
Updating was undocumented, and the mechanics are not obvious
The plugin is a profile dependency, so updating it is a pnpm operation in the profile directory — and three of the four obvious commands behave differently from what a user expects. All four were measured in a throwaway $DSH_HOME on this machine:
| Command | What actually happens |
|---|---|
add dsh-chat-cost@<version> |
installs exactly that version, immediately — the reliable path when a release is minutes old; naming it records a supply-chain exception in the profile's pnpm-workspace.yaml |
add dsh-chat-cost@latest |
resolved 0.6.3 while 0.6.4 was already latest in the registry, and resolved 0.6.4 a few minutes later: pnpm's minimum-release-age policy, not the tag, is what moves |
update dsh-chat-cost |
moves only inside the range declared in package.json; with an exact pin it does nothing at all |
add dsh-chat-cost (no range) |
resolves fresh and landed on the new version |
Knowing what you run
The summary now carries version, and the readout tooltip prints it, so "which release am I running?" is answerable from the interface. The cost log already answered it per record: every line carries plugin: dsh-chat-cost@<version>.
In the documentation
All three READMEs gained an Updating section with the table above, the restart requirement, and both ways to check the running version.
Tests: 142 — 142 pass with 0 skipped where @deepseek-ai/cordis and @deepseek-ai/dsh-tools resolve, 138 pass with 4 reported skips in a plain checkout. Docs parity, hashes and the prose gate pass.
0.6.4 — a tariff belongs to its interval, and a test to its clock
The suite was time-dependent, and the tariff label lied
Finishing the promotion texts, the suite went red for no visible reason: five tests asserting DeepSeek Flash at 0.15 per million failed with 0.30. It was 07:00 UTC on a Monday — inside the 06:00–10:00 peak window. Those tests had always depended on when they ran, and would have failed in CI for four hours every weekday.
- The tariff clock is now an argument:
buildSummary(..., now = new Date()), with the scheduled flush and the route passing nothing. Tests pin it. OFF_PEAKandPEAKare fixed instants in the host and concurrency suites, and a new test prices the same million tokens at both — 0.15 and 0.30 — then asserts that a recorded interval is not re-priced when a later look happens during a peak window.
That last assertion failed for a real reason, which is the second half of the fix: the summary reported tier from the clock rather than from the interval it priced, so an idle chat viewed at 07:00 was labelled peak while its money came from the off-peak record. The tariff now travels with the record — ledgerBase carries tier and pricingSource — and the current tariff is used only when there is new spend to price.
Also in this release
The promotion copy now lives in submission/promo/: the awesome-list pull request, the plugin-store issue, the screenshot instructions, and launch texts for Show HN, Reddit, X, Telegram and a technical article, each in the language its channel reads. The prose gate covers them, because they are texts we publish that make claims about the plugin.
Tests: 141 — 141 pass with 0 skipped where @deepseek-ai/cordis and @deepseek-ai/dsh-tools resolve, 137 pass with 4 reported skips in a plain checkout.
0.6.3 — the prose check tells a finding from a mistake
humanizer-ru is installed and wired in as npm run prose — with one defect of my own found and fixed on the way.
What the tool found in our documentation
- Insertion artefacts: none. All 40 markers of chat-copy leftovers (invisible characters, zero-width marks, paste debris) come back empty across the three READMEs, the i18n record, the bundle patch and the submission notes.
- Facts against v0.6.1: nothing lost — no number or quotation vanished while the documentation was rewritten.
- Two soft style signs in the Russian README, printed and deliberately not "fixed": the rule of three (nine occurrences, and each one is a substantive enumeration — the three levels a chat is priced at, the finished inventory in Status), and seventeen bolded lead-ins in the feature list, which is an ordinary README convention. Trimming those to please a counter would make the text worse.
What is wired in
uv tool install humanizer-ru
npm run prose # artefacts, facts against the last release, soft signs
npm run prose -- --strict # also fail when the tool is absent, for CI- Class A artefacts are a gate (the tool publishes a zero false-positive rate for them); class B — invisible characters, exotic spaces — is printed when it appears and never fails the run, because its measured rate is small but not zero.
- Protected terms live in
scripts/prose-terms.txt: the package name, the log path, the six tool names,PLUGIN_VERSION,models.devand the two client slots. Losing one fails; any other lost number or quotation is printed for a human, since a version bump legitimately changes numbers. - Not part of
npm teston purpose: the suite must run for anyone who installs the package, and a Python tool is not a dependency of a Node plugin.
The defect this release fixes
The first version accused the docs: running it inside a copy of the published package printed "chat-insertion artefacts found". The tarball ships the READMEs but not submission/, and the scanner treats a missing path as an error — so my script reported its own argument mistake as a finding. It now passes only files that exist, says which it skipped, and tells exit 1 (a finding) from any other exit (the tool failing). Verified: a planted zero-width space prints as class B and does not fail; a stub tool exiting 3 reports "could not run" and fails; a removed protected term still fails.
140 tests pass, 140 with 0 skipped where the harness packages resolve.
0.6.1 — the documentation a user meets
Documentation only — but the kind that was missing.
Added
- What it writes.
cost.jsonlwas documented;plan.json,budget.jsonandplan.md— the other three files a project folder receives — were only implied. Now they have a table, along with the fact that the log is append-only and that removing the folder loses nothing else. - Privacy. No account, no telemetry, and no outbound request at runtime: prices come from the bundled snapshot, the widget asks only the local host route, the log goes into your own folder.
npm run pricesis named as the one command that reaches the network, and as a maintainer task. - Uninstall and recovery. How to remove the plugin, and what to do when a plugin keeps the host from booting — a situation this project met twice, and the answer (remove the row, restart) belongs in the README rather than in a conversation.
- Compatibility. The bundle contract, Node ≥ 20, the loader's
apply(ctx, config), the two client slots the readout uses, and the npm CLI floor that applies to releasing rather than to installing.
Corrected
- Status listed five tools and predated interval pricing, per-turn pricing and chats priced from the log. It now describes six tools and what actually happens.
- The prices snapshot records
sourceandgeneratedAt, so how old a price is can be checked rather than assumed. package.json's description, the bundle's config block (which was also missingledgerTailBytes) and the awesome-list entry gained the per-answer price.
All three languages carry the same sections and code blocks; the hash record is re-recorded. 140 tests pass, 140 with 0 skipped where the harness packages resolve.
0.6.0 — every answer carries its own cost
The cost lived in the composer, where it reports the whole chat. An answer in the transcript had no price next to it, and a finished turn only appeared there after the next poll — up to half a minute later.
What changed
Host. Per-turn usage is folded from the session's own events (lib/turns.js), mirroring the harness's tokenUsage projection: a streamed sample is replaced by the final one for the same step, steps add up within a turn, and a model switch mid-session is attributed to the turn that used it. Each turn is priced on its own route and tariff, and the summary carries up to 50 of them.
Client. It registers into conversation.chat.turnTail — the slot under every finished answer — with the select a chain slot requires, and renders that turn's price there. When the Host has no price for the model, the badge says so rather than showing a number; a chat priced from the log carries no turn boundaries, so the badge stays quiet instead of inventing them.
Both displays share one summary store per session, so the dock readout and the badges poll once between them, and a turn closing refreshes both at once. A badge that finds no numbers for its turn looks again a few times, because the turn's usage may not have reached the Host at the instant it closed.
Checked against this session's real log
28,182 events, 39 turns, and the sum of the per-turn tokens and dollars equals the ledger's last cumulative record exactly — 192,753,094 tokens and $1.180602102, computed by an entirely different path.
Install
dsh plugin --profile web add dsh-chat-cost@0.6.0Then restart the host. Tests: 140 — 140 pass with 0 skipped where @deepseek-ai/cordis and @deepseek-ai/dsh-tools resolve, 136 pass with 4 reported skips in a plain checkout.
0.5.4 — every chat, open or not
The readout only appeared in the chat that happened to be live. The Host knows its live sessions and nothing else, so every other chat answered {"ok":false,"reason":"unknown-session"} — and the client rendered nothing at all for that answer. The widget silently vanished instead of saying it had nothing to say.
What changed
Host. A session that is not live is resolved through the query engine, which reads the persisted corpus, and its workspace comes from the session header. With a workspace the plugin can read that project's cost log, so the chat is priced from the last record the log holds for it — marked recorded: true and live: false, and never written to again, because a session that is not running has no new interval to record. A session the log has never seen is reported without a price rather than estimated.
Client. It always says something: an answer it cannot price renders the muted marker with the reason in the tooltip, and numbers taken from the log carry a tooltip line saying so.
Verified on a real host
Booted against a copy of this machine's session store and projection cache:
| Case | Answer |
|---|---|
| live session, same workspace | ok=true, 171,388,098 tokens, $1.0899 |
| not open, same workspace | ok=true, recorded=true, $1.0899 from the log |
| not open, other workspace | ok=true, recorded=true, workspace resolved, usd=null (no log there) |
Install
dsh plugin --profile web add dsh-chat-cost@0.5.4Then restart the host. Tests: 130 — 130 pass with 0 skipped where @deepseek-ai/cordis and @deepseek-ai/dsh-tools resolve, 126 pass with 4 reported skips in a plain checkout.
0.5.3 — the projection's totals wrapper
The plugin is live in the GUI now, and it reported $0 for a chat that has spent 158 million tokens. A third usage shape, after the two that already bit once:
// the tokenUsage session projection
{ totals: { uncachedInputTokens, outputTokens, cacheReadTokens, cacheWriteTokens },
last: { turn, step, buckets } | null }The reader looked at the top level, found no buckets, and priced zero — silently, because a missing bucket and an absent session both read as 0. readUsage now unwraps totals (plus buckets for a step value and val for the projection cache envelope), with totals winning over last.buckets, because only the former is cumulative.
Measured against the running host
This session's projection holds 1,151,264 uncached input, 156,179,072 cache read and 642,261 output tokens, which at the DeepSeek Flash off-peak tariff (0.15 / 0.003 / 0.6 per million) is $1.0266 — the number the readout has to show after this release.
Tests
126 in total: 126 pass with 0 skipped where @deepseek-ai/cordis and @deepseek-ai/dsh-tools resolve, 122 pass with 4 reported skips in a plain checkout. The new usage suite fails against the previous reader, and the host suite prices the wrapped shape and the flat shape to the same number.
Install
dsh plugin --profile web add dsh-chat-cost@0.5.3Pin the version: a plain add can resolve an older release from an existing lockfile.

