9 Commits

Author SHA1 Message Date
Антонов Антон Владимирович 89cde16ddc Correct the install notes against a real install
The notes described a machine that no longer matches: the runtime paths
they hardcoded do not exist on this one, and three of their claims turned
out to be wrong when the plugin was actually installed.

What was wrong, and what is true:

1. Runtime paths. `~/.dsh/dsh-runtimes/...` is only where a downloaded
   runtime lives; this install carries it in the application. The notes
   now probe both locations and take the one that exists.

2. "You cannot install into the desktop profile from the CLI". The
   launcher refuses `desktop` only for booting and for --dump-config;
   `dsh plugin --profile desktop ...` is allowed because the Desktop
   carrier passes manageDesktopProfile. Verified: install, list, remove
   all work, and each one keeps dsh.profile.bundles in sync by itself.

3. "An application restart is required". Not on Desktop. The base bundle
   enables hmr whenever profileContext is supplied, and the application
   supplies it, so editing the profile manifest recomposes the tree live
   and the client half reaches an open page over the HMR transport. The
   application had started at 16:36 and the pill appeared in that same
   process after the 16:41 install.

Also documented, because it decides whether an edit reaches the harness:
`file:` on Windows produces hardlinks out of the pnpm store, so an
in-place write is visible immediately but an atomic replace silently
breaks the link; `link:` is a junction and always sees edits. The plugin
is now installed as `link:` for that reason.

The design note keeps its original text and carries dated corrections
plus a table of what was actually verified, so the next install does not
repeat the probing.
2026-10-28 16:51:26 +03:00
antonov 63f7a4b301 Keep build artifacts out of the repo
The tarball is produced by pnpm pack and should not be tracked; the
install notes say how to regenerate it.
2026-10-28 16:26:20 +03:00
antonov d3d12724aa Add the portable package and install notes for another machine
pnpm pack produces a 12 KB tarball with only the two halves and the bundle
patch; it was installed into a throwaway profile to prove it works and
that both halves parse. The notes make the composition step explicit,
because a package can sit in a profile without ever loading -- which is
the state dsh-bottom-info-bar is in on this machine.
2026-10-28 16:26:00 +03:00
antonov 6edd2e3d52 Fix the session id never reaching the host, and the split lost on restart
Two real defects, both found by testing rather than reading:

1. The client sent sessionId in the POST body while the route read it from
   the query string, so the host always saw an empty id and answered
   total:null -- the pill was correct to stay silent. The client now sends
   the id in both places and the route reads both.
2. The ledger stored only a session total, so a restart kept the sum but
   dropped the per-purpose split and the call count (9.99 total against
   6.24 in parts, seen on the live route). Sessions are now stored as
   objects; a bare number from an older ledger is still accepted.

Also made the client report why it cannot read a total: swallowing the
error made 'nothing spent yet' indistinguishable from 'request failed'.
2026-10-15 15:40:08 +03:00
antonov d2a9b5a0f5 Install into the desktop profile and diagnose browser delivery
The host half is confirmed working end to end: the ledger holds 24 calls
and the authenticated route returns a real total (6.42 RUB, 14 calls, all
attributed, zero unpriced or unattributed). The plugin is present in the
browser boot manifest, so its bundle is served.

Remaining issue is browser delivery only: the pill stays silent, and the
client swallows the transport error. Recon scripts added to pin down
whether the route answers 200, 401 or 404 from the page origin.
2026-10-15 15:35:58 +03:00
antonov b223f51540 Implement the session cost plugin
Host half wraps globalThis.fetch to read usage.cost out of provider
responses (tee, never clone) and listens on the llm/stream seam for the
session; the two halves join on the generation id. Client half adds one
pill to the composer dock under its own id, so the harness's native stats
stay where they are.

Verified against the live API: three calls in one session (agent reply,
compaction, session title) attributed with per-purpose totals, an unknown
session answered with null, the ledger written and reloaded across
instances, and the pill rendering only when a cost exists.
2026-10-15 13:33:05 +03:00
antonov aaeb0a908c Record install requirements and the restart constraint
The plugin manager accepts an absolute local path, so the package can be
installed from this workspace. Two requirements make or break it: a DSH
peer range (runtime is 0.2.0-rc.2) and a declared bundle patch. Notes that
HMR is absent from the desktop profile, so a restart is required and the
restart is therefore the last step.
2026-10-15 13:04:07 +03:00
antonov c9d2314bb2 Verify the tee interception on a live stream
Spike proves response.body.tee() splits a real routerai SSE stream: the
consumer sees chunks progressively (first at 1ms of 1643ms) and our branch
still recovers the generation id and usage.cost. It also found a real
defect -- a rebuilt Response loses url, which the OpenAI SDK reads -- and
that Object.defineProperty is the only way to restore it.
2026-10-15 13:02:32 +03:00
antonov 82f8b7baef Add design for session cost pill in the composer dock
Records what was verified against the live routerai API and the harness
code: the provider reports usage.cost on every response, the harness
discards it in mapUsage, and the cost can still be recovered by wrapping
globalThis.fetch while session attribution rides the llm/stream seam.
2026-10-15 13:00:55 +03:00