Commit Graph
718 Commits
Author SHA1 Message Date
bowenliang123 d72b6f8d12 feat: support dsh 0.1.7-rc.1 as the supported V4 line
Every runtime seam the plugin rides is source-identical from
0.1.7-alpha.2, so no code changes; the supported V4 baseline moves
from 0.1.7-alpha.2 to 0.1.7-rc.1 (the alphas leave the matrix). rc.1
adds the harness-side plugin peer-compatibility admission gate
(evaluatePluginCompatibility); the plugin's >=0.1.2-rc.1 dsh peers
satisfy it under the gate's includePrerelease check, so the bundle
composes with no exemption. The release workflow fetches the rc.1 tag
for the compat matrix and points the plugin checker at the npm next
dist-tag (0.1.7-rc.1).
2026-09-24 11:05:05 +08:00
bowenliang123 091a8b3521 chore: release v0.55.0 2026-09-23 17:20:56 +08:00
bowenliang123 de1c848698 test: let the meta dictionaries diverge from the manifest copy
The en/zh title and description are the canonical Plugins-page copy, not
a restatement of the package.json fields - the manifest values only
back the en fallback when a dictionary entry is absent. The en/manifest
equality assertions drop; the zh spec now pins that it is a real
translation (same fields, different copy) instead of only matching
en's shape.
2026-09-23 17:00:38 +08:00
bowenliang123 aa0c0a5f57 feat: localize the Plugins-page title and description
The Host's package-meta reader serves each plugin's localized
title/description from the dictionaries exported under locale/ - the
same surface the official plugins use, so the Plugins page and the
settings inventory present dsh-context in the active locale instead of
the raw manifest fields. en carries the canonical copy (matching the
manifest name/description it overlays), zh the translation; the
exports pattern and the files list ship both dictionaries. A spec pins
the dictionaries' shape, the exports/files alignment, and the en/manifest
agreement.
2026-09-23 16:52:20 +08:00
bowenliang123 bdb63a1aed feat(client): brand the Plugins page cards with the package icon.svg
The Plugins page's package cards draw each bundle's icon from the Host's
package metadata (manifest-relative SVG/PNG/JPEG/WebP, inlined as a data
URI), which we never declared - the cards fell back to the default
artwork. The Context emblem's single graphic source is now the
package-root icon.svg: the package.json "icon" field points the Host's
reader at it, and the client build inlines the same file through a
"*.svg?raw" channel (the bundled ContextIcon re-renders it at every
requested size), so the code carries no second copy of the paths. A spec
pins the file and the component in lockstep; the files list ships the
asset.
2026-09-23 16:44:08 +08:00
bowenliang123 0016d9c62f feat(client): land the preferences jump on the bundle's Plugins page
The Config-form jump stops settling for the card list: after the panel
entry's click, a bounded poll (40 ticks at 100ms, riding the same
scheduler contract the tests drive) follows the page's package load and
opens the bundle's page through the card's title control — the one
button inside the shipped data-plugin-package list item that is not the
enable switch, so the match survives every locale. A poll that finds
nothing (still loading, plugin absent, or the page already open on the
detail view, where the list is unmounted) silently degrades to the card
list.
2026-09-23 16:18:37 +08:00
bowenliang123 a2874ebeb8 docs: describe the shipped V4 preferences surface
The User preferences delta moves from deferred to shipped: one schemastery
entry schema serves both generations, the browser seat and transport per
line, the deliberate strict-key relaxation, and the settings.yaml legacy
import that carries persisted values into the profile entry. The README's
Settings section names where the card lives on each release.
2026-09-23 15:59:15 +08:00
bowenliang123 325f3f4024 test(compat): pin the preferences card seat and transport per baseline
The settings seam now names the browser half's faces per generation —
the keyed card slot (settings.plugin.item vs plugins.bundle.config) and
the transport service (settingsScope vs configForms) — each asserted
both ways against the tag's sources, like the sidebar seam, so a moved
seat cannot read as unsupported.
2026-09-23 15:58:48 +08:00
bowenliang123 3260d2acf1 feat(client): jump to the Plugins panel on Config-form hosts
The preferences jump prefers the Plugins main-panel entry (matched by
its shipped aria-label) where the generation ships it — one click and
done, the page's internal view state has no external face — and falls
back to the settings-dialog choreography for the older lines. The jump
copy becomes generation-neutral (Open preferences).
2026-09-23 15:58:21 +08:00
bowenliang123 6d27a351ed feat(client): mount the preferences card on the Plugins page seat
The Config-form generation retired the settingsScope service and the
settings.plugin.item slot, which took the preferences card with them.
A second deferred inject — fired only where the configForms service
exists, so each line runs exactly one transport — binds the shared
settings store onto the dsh-context config form and registers the flat
card on the Plugins page's keyed plugins.bundle.config seat, alive only
while the Host serves the namespace (whileServed). Both seats render the
same six preference rows over the same store; the settings-section card
keeps its shape for the older lines.
2026-09-23 15:57:54 +08:00
bowenliang123 bc2544adfa feat(host): serve the preferences through the entry Config schema
The Config-form generation (dsh 0.1.7+) derives the Plugins page's live
form from each loader entry's own Config schema, so the entry schema must
be the schemastery one: cordis keeps validating the config: block through
its Standard Schema face, and the same schema now carries the six display
preferences as .volatile() fields (live-editable there, namespace = the
entry id). The fold bounds stay ordinary fields — their edit remounts the
entry, a preference edit commits volatile-only.

The .volatile() modifier ships only with the newer schemastery, so the
builder feature-detects it and the same bundle loads on the older lines
(3.18.2 predates the modifier). The devDependency bumps to 3.18.4 to
exercise the marked path in tests. Deliberate relaxations against the
replaced zod schema: unknown keys merge through, and integers are
expressed as min 1 + step 1.
2026-09-23 15:57:28 +08:00
bowenliang123 2ae7cfa7f8 test(host): seal the version-probe fixtures against ambient NODE_PATH installs
The version.spec fixtures relied on clean CJS walk-up failure from the
tmpdir scratch tree, but Node consults NODE_PATH after the walk-up
fails - and a pnpm-managed environment (a `pnpm` binary running from a
sibling checkout, as on a dev machine with the harness repo alongside)
injects that checkout's virtual store into NODE_PATH. Every probe
package ABSENT from a fixture home then resolved to the ambient harness
install, and the four fall-through / degradation arms answered with its
real version instead of nothing.

Each scratch home now SHADOWS every probe package its failing probes
could reach with an entry that resolves at the fixture level but
answers no version (exports gate on the manifest subpath, versionless
own manifest on the entry ascend), so resolution never leaves the
fixture regardless of the environment. Two coverage-preserving additions
ride along: an entry-gone home pinning versionViaEntry's unresolvable
branch, and a stamped-slot merge test for the additive-optional blocks
record the timing tallies introduced.
2026-09-23 13:12:14 +08:00
bowenliang123 f723cddb30 feat(timing): tally the decode slices' counted blocks on the timing card
The generation split (thinking / answer / tool args) already tiles its
window off the stream's block-start markers; the same markers now count
into additive-optional per-bucket tallies (reasoningBlocks / textBlocks /
toolArgBlocks), so the card qualifies each decode slice with the number
of blocks actually decoded - the honest per-slice counterpart of TTFT's
call count and tools' run count (one model call emits zero to many
blocks, so a call count there would be a false tally). Overhead stays
unqualified: it is the residue, with nothing behind it to count.

Both log generations carry the markers: the V0 chunk flood counts them
into the step slot alongside the spans, and the V2+ embedded stream
yields them from the same single pass that prices the split
(decodeSpansOfStream -> decodeTallyOfStream). Counts ride the split's
own first-token gate, and rows cached before the fields existed render
the duration alone.
2026-09-23 13:11:39 +08:00
bowenliang123 6064731c9f chore(compat): advance the V4 baseline to dsh 0.1.7-alpha.2
dsh 0.1.7-alpha.2 introduces no breaking change for the plugin: the
vendored cordis 4.0.3 -> 4.0.4 bump is version-metadata only, the
durable log stays at V4 with an unchanged event vocabulary, and every
seam the plugin rides (session-projection registry, right-Sidebar tab
and navigation faces, connection RPC, settings namespace, agent-loop
pre-step, ui-primitives icons and markdown labels, the plugins.bundle
config slot) is source-identical or additively extended. The remaining
deltas are internal to the harness: an optional turnWindow on history
page requests, client-module batch-failure recovery, and host-side
tool-result retention (the already-documented deferred image-offload
area).

Per the one-representative-per-generation convention, replace the
alpha.1 baseline with alpha.2 across the declared releases, the seam
matrix, the release workflow's tag fetch, and the compatibility page.
The compat matrix now boots the real alpha.2 sources on cordis 4.0.4.
2026-09-23 00:11:24 +08:00
听语惊花andNwflower 22eb2ed2f4 perf(host): cut the timeline fold's per-event cost and fix the Windows cross-drive path check
Three per-event costs leave the fold: every state-changing event shallow-copied
all seven retained collections, every event re-scanned the retained requests to
count turn runs, and every tool call stringified its arguments even when the
tool can never row a file op. Cloning now follows the branch's own mutation
list, the run count rides an incremental ledger (recomputed only where a trim
replaces the array), and raw arguments are kept only where they are read.
Measured over 279 real sessions (282,783 events): the fold drops 16.8% corpus
wide, ~51% on V3-shaped logs and ~57% on sessions at the retention caps, with
state output field-identical apart from the new optional `turnRuns` field and
the intended `argsRaw` omission. `stateVersion` is unchanged, so cached rows
keep parsing and stay usable.

The Windows check rode along: `path.relative` returns an ABSOLUTE path across
drives, so the old `..`-prefix test read a foreign drive's module as a child of
the plugin's own tree and degraded version detection; `!isAbsolute(rel)` closes
it.

Review follow-up on top of the original six-file change:

- an absent `timing` slot stays absent. The selective clone materialized
  `timing: undefined`, which is not losslessly JSON-serializable, so
  `snapshotJsonValue` rejected the whole checkpoint: every projection-cache
  write for that session was skipped, and a log ending on an unpaired
  `tool/result` never got a cache row at all — every reopen then paid the full
  cold fold this change set aimed to cut;
- the no-`undefined`-member rule is now pinned on every intermediate fold
  state, not only the last one — the gap that let the above ride through a
  green suite, since reading the slot cannot tell an absent key from an
  `undefined`-valued one;
- the "which tool needs its raw arguments" gate moved beside the file-op
  parser (`opBearingTool` / `rawArgsNeeded`), so the fold no longer restates
  the tool list.

Verified: `pnpm run lint:fix && pnpm run test && pnpm run build` green (1763
tests, per-file coverage 100%), plus a field-level diff of the fold over
282,783 real events (no divergence beyond the intended deltas), the
incremental ledger cross-checked against a full scan on every event including
both trims, and a frozen-predecessor run proving no in-place write.

Co-authored-by: Nwflower <1679659@qq.com>
2026-09-22 18:16:22 +08:00
bowenliang123 9932d84d32 fix(ci): pin the plugin checker's dsh to the alpha line
npm's 0.1.5-rc closure is broken upstream: dsh-web-app 0.1.5-rc.3 was
published while the dsh-client-ui-sidebar-documentpreview rc.3 it
requests never was, and every ^0.1.5-rc range (including `latest`'s own)
resolves to it — so installing the checker's `@deepseek-ai/dsh@latest`
fails with ETARGET before any check runs. Pin the checker to `alpha`
(0.1.7-alpha.1), whose closure is complete and which is the release this
cut declares compatibility with.
2026-09-22 16:52:27 +08:00
bowenliang123 c53d40a45e chore: release v0.54.4 2026-09-22 16:41:30 +08:00
bowenliang123 390399ff24 feat(compat): support dsh 0.1.7-alpha.1
Add the V4 baseline (session format 4, cordis 4.0.3): the fold's switched
event families are unchanged, so its entry rides the V3 seam face with a
per-generation settings surface — the `register` face and the retired
`settings.plugin.item` slot are asserted BOTH ways (present through V3,
absent on V4+), and the modal dock probe now pins the sidebar-leading
grid track the measure actually reads instead of one generation's exact
template. New ICON_SEAMS probe: every icon the client renders must exist
in at least one spelling per tag, so a platform rename fails the matrix
instead of the browser. Declare the release in the manifest, fetch its
tag in the release workflow, and document the V4 generation with its
known deltas (deferred: the preferences card's Plugins-page migration,
image-offload accounting).
2026-09-22 16:28:46 +08:00
bowenliang123 dd7a346c59 fix(client): resolve icons across the renamed ui-primitives vocabulary
dsh 0.1.7 renamed every `Icon*Outline16`/`Icon*Outline14` to
`Icon*OutlineRegular`/`Icon*OutlineMedium`, so the plugin's named imports
arrived as `undefined` at runtime and the Context tab crashed with React
error #130. Each icon now resolves through BOTH spellings at module load —
modern first, legacy fallback — with a render-nothing component and a
bounded property-read catch so any future rename degrades to a missing
glyph instead of a crashed tab.
2026-09-22 16:28:21 +08:00
bowenliang123 7b09055193 fix(host): read the V4 tool-result error mark
V4 lifted `isError` from the tool-result content wrapper onto the message
and made the event-level `data.error` identity optional, so a failing
result could lose its error flag. The fold now reads the mark from BOTH
spellings — surface nodes and file-op rows keep it on every generation.
2026-09-22 16:27:55 +08:00
bowenliang123 274b50f0c8 fix(host): feature-detect the settings register face
dsh 0.1.7 (session format V4) removed `settings.register` — configuration
forms derive from each loader entry's own Config schema there. The inject
callback now probes the method and stays inert on a generation without it
instead of throwing inside the fiber.
2026-09-22 16:27:30 +08:00
bowenliang123 df06e62d0b chore: release v0.54.3 2026-09-22 13:03:21 +08:00
bowenliang123 c55519d18d fix(client): weigh the settings row's value like its siblings
The regular 400 override made "Open in Settings" look larger than the
semibold values beside it; all three share the same 13px/600 face.
2026-09-22 08:08:22 +08:00
bowenliang123 f3b4c88390 feat(client): lead the Plugin Info rows with site marks
The Plugin / GitHub / Settings labels open with siDeepseek, siGithub,
and the harness's IconSettingsOutline14 gear, riding currentColor at the
label's baseline. simple-icons is a dev-only dependency pinned to the
harness ui-primitives' own 16.31.0 and tree-shakes into lib/client.js as
exactly the two mark paths, so no runtime dependency is added and the
marks are identical to the harness's own SiteGlyph artwork.
2026-09-22 08:08:22 +08:00
bowenliang123 5121e0bdee feat(client): split the head row's stats and plugin cards 3:1
The context stats card takes three flex parts and the plugin card one,
with the plugin card's floor lowered to 240px so the ratio shows at
common widths (its rows ellipsize and recover values on hover). Below
the 360 + 240px floors the pair wraps onto full-width lines as before.
2026-09-22 08:08:22 +08:00
bowenliang123 c8e1b16b75 chore: release v0.54.2 2026-09-21 10:37:08 +08:00
bowenliang123 61415ade19 fix(balance): notify every open riding the in-flight read
A dashboard reopen landing inside the balance read's window joined the
in-flight route read but never registered its landing callback — the
read reported only to the open that started it, so the reopened
dashboard showed the stale remembered figure for its whole session
(issue #82, exactly as reported). The landing callbacks now collect in
a set and all fire when the read lands; the previous behavior was even
pinned by a test asserting the joiner stayed silent, which now asserts
the opposite. The store-level join test and a capsule-level
close-reopen repro pin the regression both ways.
2026-09-21 10:36:38 +08:00
bowenliang123 cd53e1403c chore: release v0.54.1 2026-09-21 10:20:40 +08:00
bowenliang123 e42f994cca feat(client): show the decode throughput on the timing card
The timing card gains a top-right tok/s chip, computed over the same
pairing as the harness's own session-stats fold: per assistant call,
the provider-reported output tokens paired with the first-token →
message window, summed only over calls carrying BOTH — so the plugin's
figure equals the harness pill's by construction (verified against the
running harness). The formatter mirrors the harness's too: whole tokens
from ten up, one decimal below.

The seat rides TimingTotals as additive-optional fields (speedTokens /
speedMs — a usage-gated subset of genMs), so cached rows written before
it simply render no chip, with no stateVersion bump. Unreadable or
absent pairing renders no chip; the tooltip names the pairing.
2026-09-21 10:11:10 +08:00
bowenliang123 069249cf4d feat(client): add a last-24-hours range to the Context Dashboard
The range selector gains 近 24 小时 (Last 24 hours) ahead of 7d — the
finest window the dashboard offered was a week, too coarse for the
hour-scale sessions a working day produces. The window filters by the
rows' last activity exactly like the other ranges; the heatmap keeps
its own fixed 8-week view.
2026-09-20 23:27:19 +08:00
bowenliang123 d2ac56aa49 fix(client): show only the non-zero breakdown in the balance tooltip
The tooltip repeated the pill's own total, and a zero side (granted or
topped-up) rode the bubble as a meaningless line. The pill keeps
carrying the total; the tooltip now lists only the non-zero parts, and
an all-zero account renders the pill bare — no bubble, nothing to break
down. The unused balance.tip.total key drops from both dictionaries.
2026-09-20 23:19:01 +08:00
bowenliang123 502c59aa2c fix(balance): make the capsule agree with the platform console
The capsule's figure could come from two stale layers, and its total could
disagree with its own breakdown. Both are gone.

The host route remembered a successful read for five minutes, so opening the
console first pinned the capsule to that older snapshot — and the balance
moves with every billed request, so the two could not agree. Nothing outlives
a read now beyond the outbound fetch already in flight.

The client paints the remembered figure (memory, then storage) while it
revalidates in the background, so a reopening panel shows a number at once and
settles on the live one without ever trading it for a blank pill: a failed or
absent read notifies nobody and keeps serving what it remembered.

The total is now the granted and topped-up parts summed rather than the
platform's own `total_balance`, which rounds independently of them and can
land a cent away from what the breakdown beside it adds up to (the viewer's
arithmetic is the authority); an entry no longer needs `total_balance` to
prove its shape at all.

The specs cover the storage and transport failures that must keep the figure,
the per-open revalidation, and the disagreeing total.
2026-09-20 22:14:42 +08:00
bowenliang123 d7ac0e7cd8 fix(balance): lead the breakdown with the topped-up line
Read total / topped-up / granted, so the top-up figure sits before the
granted one. The spec's exact three-line assertions follow in both locales.
2026-09-20 21:26:04 +08:00
bowenliang123 4b40427c1e fix(balance): show the capsule tooltip at once
Replace the native `title` on the balance pill — browser-throttled to about
a second — with the harness Tooltip primitive, the same zero-delay seam the
heatmap cells and the assistant jump action already use. The multi-line
breakdown keeps its shape through the bubble's `pre-line`, and an
`aria-label` carries the same text for assistive tech.

The spec drives the bubble through real hover events instead of reading
`title`, and covers the leave that drops it.
2026-09-20 21:25:27 +08:00
bowenliang123 fa43340a7b feat(client): open the platform usage console from the balance capsule
The Context Dashboard's balance pill becomes a link to
platform.deepseek.com/usage — the console page behind the figure it
shows — opened in a new tab with noreferrer, the same external-link
shape the Plugin Info rows use. Hover underlines the figure as the
click affordance; the read, degradation, and tooltip behavior are
unchanged.
2026-09-20 11:25:46 +08:00
bowenliang123 f90d398eb7 chore: release v0.54.0 2026-09-20 11:18:18 +08:00
bowenliang123 95f187d308 feat: show the DeepSeek platform balance in the Context Dashboard
The dashboard header gains a capsule with the DeepSeek open-platform
balance (issue #80). The host mounts a /api/dsh-context/balance route
through the same Connection exact-route registry as the detail and
backfill routes, resolves the connection facts per request the way
llm-deepseek serves its own requests (its llm-deepseek settings section
for the credential ref and endpoint override, the credentials service
for the key), and reads /user/balance behind a short TTL cache — the
key never leaves the host process.

Every face is optional and runtime-proved: a deployment without the
DeepSeek provider, without a resolvable credential, without the route
registry, or whose platform read fails (network, non-2xx, malformed
payload, hostile entries dropped whole) answers a typed null, and the
capsule renders nothing — no pill, no spinner, no error state. The
entry follows the display locale (zh → CNY) with the account's first
currency as fallback, and the tooltip carries the granted/topped-up
breakdown.
2026-09-20 11:16:39 +08:00
bowenliang123 af9c69bd09 fix(host): classify backfill format refusals by the observable name family
The persistence seam translates the format edge's
SessionFormatUnsupportedMigrationError into SessionFormatUnsupportedError
(with the "source vN artifact remains unchanged" suffix) before the error
escapes, so the exact-name check never matched on any supported dsh
baseline: the skip summary never fired and every refused legacy session
kept its own WARN (issue #75). Classify by the SessionFormatUnsupported
prefix instead, and cover both faces of the translation in the fixture.
2026-09-20 10:30:01 +08:00
bowenliang123 0b8175e721 chore: release v0.53.4 2026-09-19 21:53:54 +08:00
bowenliang123 716497fac2 fix(client): price DeepSeek peak windows at twice the models.dev list
The models.dev deepseek branch publishes the official OFF-PEAK rates
(deepseek-flash: 0.15/0.6/0.003 USD per 1M = api-docs.deepseek.com's
valley tier), but the estimator read the book as the peak list and then
halved the off bucket — every DeepSeek session under-estimated ~2x in
both periods. Flip the semantics: DeepSeek's peak bucket prices at
twice the book rate and the off bucket at book; the tooltip's peak
column doubles for DeepSeek rows with its structure untouched, so
deepseek-flash now reproduces the official peak|off-peak list exactly.
Fixes #78
2026-09-19 21:39:55 +08:00
bowenliang123 670a0fb83b feat(client): land the jump on the Current Composition card
The jump's landing used to reset the scrollport to the top, where the
stats cards hide the composition card and the pinned turn's trend chart
below the fold. The landing now reveals the Current Composition card
(`data-lc-current`) so the card and the trend chart share the
scrollport.

The reveal walks from the anchor to the nearest scrollable ancestor —
host-agnostic by need: the conversation tab scrolls the shared
`[data-conversation-scroll]` container while the right Sidebar scrolls
dockkit's pane body, a CSS-module class with no stable attribute of its
own. The rect delta lands the anchor flush regardless of the
container's current position, overriding the scroll ledger's restore;
repeat jumps re-reveal. No scrollable ancestor (or a hostile chain)
degrades to a quiet no-op.
2026-09-19 08:54:56 +08:00
bowenliang123 f8abef8c40 fix(client): make the chat-to-Context jump actually pin the clicked turn
The jump's seq resolution ran inside the click handler, but the
assistant-actions seat's `useChat` is a real React hook — calling it
off-render throws the dispatcher guard (React #321), which the seat
guard swallowed, so no focus was ever recorded and the landing view
stayed on its default selection. The button now resolves the reply's
seq at RENDER time (unconditional seat read, click consumes the
captured value), so the pin finally fires in production.

The relay also wakes mounted views now: the sidebar landing keeps the
Context panel mounted across jumps, so repeat clicks re-pin it instead
of recording a focus nothing consumes (the conversation-tab landing had
the same gap whenever the tab was already active).
2026-09-18 15:19:37 +08:00
bowenliang123 a1277bac34 feat(client): land the chat-to-Context jump in the right Sidebar
The assistant-action jump now opens the Context tab on the right Sidebar
over the guarded `ctx.sidebarRight.openTab` optional seam (the column
expands in the same step, keeping the clicked reply in view) instead of
switching the conversation tab. Every harness or placement the seam
cannot serve — lines older than 0.1.5-rc.1, tab-only placement, no
mounted session surface, a hostile face — keeps the conversation-tab
activation as fallback. The tooltip is reworded neutrally ("Context
view") since the landing follows what the harness serves.
2026-09-18 14:49:03 +08:00
Bowen Liang 60598ae0e4 chore: release v0.53.3 2026-09-17 23:28:52 +08:00
Bowen Liang bf0bba886f docs: document the on-demand projection warm-up in the compatibility page
The warm-up paragraphs (the lastUser stateVersion bump and the
contextActivity dashboard key) now describe the trigger route, the
one-pass-per-process arm, the migration-refusal skip accounting, and the
deployment shapes that never arm the pass.
2026-09-17 22:46:53 +08:00
Bowen Liang 73dd36418c fix(host): arm the projection warm-up behind the dashboard's first open
The contextActivity/contextTimeline warm-up used to cold-read the whole
session corpus at every startup, whether the dashboard was ever opened or
not — and a legacy log the running harness refuses to migrate re-attempted
and re-warned per session on every boot (one reporter measured 115 warn
lines, ~60 KB per start; #75). Under that sustained read pressure the host
also stalls its own client handshake, leaving the workspace sidebar to
mount without its session rows until a restart.

The pass now runs on demand, once per host process: the client POSTs the
plugin's /api/dsh-context/backfill fetch route (the same authenticated
/api fence as the detail route) the first time the Context Insights panel
opens, and every later hit is a no-op. The route and the cold-path faces
compose in either order; a deployment without the connection service or
the exact-route registry never arms the pass — such a client could not
open the dashboard to read the rows anyway.

Skips are accounted instead of spammed: a migration-refused log
(permanent, source-side) drops to a per-session debug line and joins one
summary info line per pass; unexpected per-session failures keep their
own warn, now proof against hostile error objects whose toString throws.
The inter-session yield widens to 100 ms so an on-demand pass never
squeezes the host's other services.
2026-09-17 22:44:22 +08:00
bowenliang123 e5ed03b4aa chore: release v0.53.2 2026-09-17 17:04:26 +08:00
bowenliang123 ffee2a6652 fix(client): drop the running-sessions badge from the Context Insights entry
The green pill on the sidebar-foot entry read as a notification badge
(#74): a running-task count is not something a footer control should
surface as an attention marker. The entry returns to a plain icon +
label; the count's only consumer was the badge, so the tally helper and
the button's useSessions seat plumbing go with it.

Fixes #74.
2026-09-17 17:01:01 +08:00
bowenliang123 b6eda0833c chore(client): keep expected-path noise out of the test output
The three local until-polling copies let the debounced detail updates
land outside act — React warned 19 times per run. They collapse into
one shared act-per-tick until in the kit: timers and promise chains
only fire while a tick's sleep is awaiting, so the updates stay
act-attributed and commit as each scope exits.

The four browser specs that arm the fetch-on-miss retry with a
deliberately failing fetcher silence the production console.warn the
failure legitimately emits, restored by a file-level afterEach.

A default-reporter run now prints zero stderr.
2026-09-17 13:58:08 +08:00
bowenliang123 bda3537b2c chore: add 'dot' reporter to Vitest configuration 2026-09-17 13:06:14 +08:00