Commit Graph
192 Commits
Author SHA1 Message Date
bowenliang123 021db5f2a2 build: migrate tsup to tsdown, mirroring the official client-bundle preset
- banner/intro/footer three-part closure-factory wrap (verbatim from
  packages/client/tsdown.client.ts), intro now owns var module/exports
- deps.neverBundle/alwaysBundle guards: host keeps production deps
  external, client keeps only module-table specifiers external
- bundle purity gate: any non-requested @deepseek-ai/* value import is
  a build error (INLINE_SAFE / vendored-library / generated-remote
  allowances mirrored)
- NODE_ENV + import.meta.env defines for inlined node-idiom deps
- client sourcemap on, matching the official artifact contract
- client smoke test now runs the bundle verbatim through the
  __ModuleLoader__ handoff instead of slicing the factory body by
  exact output strings (decoupled from bundler layout)
2026-08-22 02:14:44 +08:00
bowenliang123 7df335114a docs(research): dsh monorepo and plugin practices investigation 2026-08-22 02:09:21 +08:00
bowenliang123 798d902c4d chore: bump version to 0.22.0 2026-08-22 01:43:37 +08:00
bowenliang123 af14769c0f feat(client): card-style message detail with image attachment rendering
Adapt to DeepSeek Harness 0.1.1's multimodal pipeline (and the vision
capability of DeepSeek-V4-Flash-Vision-Exp): a user message carrying
durable image refs expands into a card layout — prose in the text card,
image attachments as thumbnail cards (name, normalized + original
dimensions, stored size), and unrecognized blocks as raw JSON. Image
blocks in assistant messages and tool results (e.g. read_image output)
now render too, instead of being dropped or dumped as JSON.

Thumbnails load through the harness conversation service's resolveImage
(the same session-authorized loader the chat history uses); when the
service is absent the cards degrade to metadata only. The text card
uses an un-padded RichCard variant so all cards align at one indent.
2026-08-22 01:43:37 +08:00
bowenliang123 587d55f0da chore: avoid adding unnecessary code comments 2026-08-22 01:30:15 +08:00
bowenliang123 2ca9f76720 feat(client): title reasoning/response blocks in assistant message detail 2026-08-22 01:27:46 +08:00
bowenliang123 bfb99a4827 chore: bump version to 0.21.1 2026-08-21 23:15:22 +08:00
bowenliang123 925c9ccca6 fix(client): no white screen on malformed backend timeline payload
Sanitize the contextTimeline projection into a render-safe shape at the
services boundary (collections -> arrays, non-object entries dropped,
current -> numeric breakdown, wrong-typed scalars dropped) so a corrupt
or failed host payload degrades to empty sections instead of throwing
during render, keeping every usable piece of data visible.

Wrap the Context tab and /context dialog bodies in a React error
boundary (styled error card + Retry) as the backstop for any residual
render error; harden fmtTime against invalid timestamps, headersOf
against malformed epochs, and the cache-hit/cost math against NaN.

Add client regression tests: corrupt payloads render with usable data,
the modal degrades, and a throwing projection reader lands in the error
card.
2026-08-21 23:12:51 +08:00
bowenliang123 0a028ace6f chore: bump version to 0.21.0 2026-08-21 20:41:18 +08:00
bowenliang123 1a625fef96 fix(host): dual-contract session-projection units for dsh 0.1.1-rc.1 compatibility
dsh 0.1.1-rc.1 changed the session-projection unit contract: registration
now reads stateSchema (persisted fold state) + wire (client view), and a
unit without a wire block is treated as host-only — its value is never
delivered to the browser. The units still emitted only the pre-0.1.1
fields (schema + top-level view), so on 0.1.1-rc.1 the Context tab stayed
on its loading screen forever: contextTimeline/contextHeaders never
arrived through useProjection.

Emit BOTH contracts on each unit: schema/view for dsh <= 0.1.0-rc.8, and
stateSchema/wire for dsh >= 0.1.1-rc.1 (each registry reads its own
fields off the same definition and ignores the extras). Added a strict
timelineStateSchema for the persisted state (the cold-read rung also
parses checkpoint rows with it) and mirror checks in host.test.mjs.

Verified against the real registries of both versions (snapshot
delivery, change feed, checkpoint, viewCheckpoint, restore) and the real
plugin-install flow on the 0.1.0-rc.7 and 0.1.1-rc.1 CLIs.
2026-08-21 20:41:10 +08:00
bowenliang123 57f7ca013d chore: move zod from dependencies to peerDependencies (optional)
zod is already a dependency of @deepseek-ai/dsh-session-projection,
so the host dsh environment always provides it. Moving it to
peerDependencies avoids duplicate zod installations and lets the
plugin resolve the same zod instance as the framework.

- dependencies: remove zod (now empty)
- peerDependencies: add zod ^4.4.3
- peerDependenciesMeta: mark zod as optional
- tsup.config.ts: update comment to reflect peer dep status
- version: bump 0.20.0 -> 0.20.1
2026-08-21 18:00:41 +08:00
bowenliang123 52fbb1bfa7 chore: bump version to 0.20.0 2026-08-21 17:01:32 +08:00
bowenliang123 1cc4da0a9f feat(stats): estimate whole-session cost at DeepSeek V4 list prices
Stats board gains an 预估费用/Est. Cost cell pricing the complete
session's billed tokens at hardcoded DeepSeek V4 list prices: the host
folds per-request usage totals (peak/off-peak split, cache hit/miss
input, output incl. reasoning) from the session log, flash and pro on
any provider, displayed in the locale's currency. The cell carries a
"?" marker whose hover bubble explains the whole-session estimate and
lists the per-1M-token price table straight from the pricing table, so
the printed rates can never drift from the math.
2026-08-21 17:01:22 +08:00
bowenliang123 dec8b16e62 chore: shorten homepage link 2026-08-21 14:05:13 +08:00
Bowen Liang 85076ae10c chore: bump version to 0.19.2
Lower @deepseek-ai/dsh-client-ui-primitives, @deepseek-ai/dsh-session and
@deepseek-ai/dsh-session-projection peer and dev deps from ^0.1.0-rc.8 to
^0.1.0-rc.7 so the package declares compatibility with the DSH Community
Market desktop runtime (currently @deepseek-ai/dsh 0.1.0-rc.7).
2026-08-20 23:38:48 +08:00
Bowen Liang aa768c76a1 chore: bump version to 0.19.1 2026-08-20 22:44:29 +08:00
4d9ffcd3ca fix(host): keep timeline state plain JSON for the projection cache
The contextTimeline fold persisted `undefined`-valued properties (model/provider/lastModel/contextWindow at init, pendingShadowedSeqs set to undefined on consume, and turn/step written as undefined when absent from assistant/message data). The harness projection cache snapshots the whole session checkpoint through the lossless-JSON snapshotter, which rejects any `undefined` property — so every projection-cache write failed and the `title` projection (session list) degraded after restart. stateVersion 3→4 discards stale rows; a regression test now drives the real snapshotJsonValue.

Fixes #5, #7.

Co-authored-by: kiligzzz <kiligzzz@users.noreply.github.com>
Co-authored-by: Bowen Liang <liang.bowen.123@qq.com>
2026-08-20 22:39:42 +08:00
Bowen Liang ad5433bf34 chore: bump version to 0.19.0 2026-08-20 21:59:11 +08:00
Bowen Liang 81415caad4 browser: raw/markdown view switch on detail cards
The context browser's detail cards (system prompt, tool description,
user/assistant message and injection bodies) gain a segmented Raw |
Markdown switch at the card's top-right corner — the same pill chrome
as the trend chart's Step/Turn control. Markdown is the default view,
rendered through the harness's shared MarkdownText (GFM, sanitized,
resolved from the platform module table — zero plugin-side markdown
dependency); Raw restores the exact source <pre>. Each card owns its
mode state via the new shared richText kit (explicit render props, no
React context), so two open details switch independently. Reasoning
blocks, tool-call args and tool results stay raw.

Markdown chrome is scoped to the detail cards: base size 13px (a
proportional face matching the raw view's 12px monospace in visual
weight), headings collapse to a weight-only bump, inline code keeps
full size and is pinned under the paragraph line so wrapped chips no
longer stick across lines.
2026-08-20 21:55:27 +08:00
bowenliang123 35e6a8b2e8 doc: update build instructions to use pnpm and add watch command 2026-08-20 17:07:54 +08:00
bowenliang123 b34b24b971 build: add watch script for tsup 2026-08-20 17:06:26 +08:00
bowenliang123 54fadb8b83 chore: bump version to 0.18.0 2026-08-20 16:16:53 +08:00
bowenliang123 dab80c6232 build: switch to tsup and declare harness runtime deps as peers
Replace the hand-rolled esbuild script (scripts/build.mjs) with a single
tsup config that already existed but never ran: tsup re-bundles the config
into a temp .mjs, so import.meta.url pointed at the temp dir and the
package.json read failed, silently leaving no entries. Read the manifest
from process.cwd() instead. The host half now keeps @deepseek-ai/dsh-session
external (resolving to the harness's single runtime instance) instead of
inlining it; the client half keeps the __ModuleLoader__.load wrap.

Align deps with the official dsh convention: runtime harness packages
(cordis, dsh-session, client-ui-primitives, react) move to peerDependencies
with dev mirrors (client-only ones optional); zod stays a dependency;
exact rc pins become caret ranges (^0.1.0-rc.8) so rc9/0.2 releases don't
break installs. Drop the esbuild devDependency (tsup brings its own) and
add tsup itself.
2026-08-20 16:09:16 +08:00
bowenliang123 c347dd5b60 trend: keep the locked bar's solid frame on click
The selected (locked) bar was declared before the hovered rule at equal
specificity, so the dashed hover frame kept overriding the solid lock
frame while the pointer was still on the just-clicked bar — the lock only
became visible after the pointer left. Declare .lc-bar-selected last and
use the label-primary (near-black) frame so clicking immediately shows
the black solid frame and clicking again reverts to the dashed one.
2026-08-20 10:58:18 +08:00
Bowen Liang 19731afd86 chore: bump version to 0.17.0 2026-08-20 05:02:43 +08:00
Bowen Liang cd32b489d0 docs: describe the new /context modal (composition card + browser) 2026-08-20 05:00:38 +08:00
Bowen Liang b6668cdf5b docs: add the /context entry screenshot and refresh the command image 2026-08-20 04:59:25 +08:00
Bowen Liang 1ee0a70433 overview: extract CurrentComposition and reuse it in the /context modal
Pull the tab's inline 当前构成 card (headline + composition bar with the
auto-compaction reserve band + legend + the ranked tool-chip bridge) into
a shared pure CurrentComposition component. The Context tab and the
/context modal now render the SAME card, and the modal wires the tool
chips into its embedded Context browser and drops the duplicated
model/provider from the dialog header (the card subtitle carries it).
2026-08-20 04:53:04 +08:00
Bowen Liang 6c924251b9 context command: swap the modal's trend for the Context browser
The /context dialog drops the last-10-turn history chart (TrendChart +
RequestDetail + markers) and hosts the shared ContextBrowser card
instead, so step picking, accordion, reconstruction and paging ride the
same component as the tab. The modal now reads the contextHeaders key for
the browser's system/tools sections, its command description is updated,
the dead lc-modal-trend rule is removed, and the modal render test is
rewritten to assert the embedded browser.
2026-08-20 04:52:44 +08:00
Bowen Liang 24a7707872 overview: mark the auto-compaction reserve band
The current-composition bar gains a striped band over the rightmost
(1-ratio) of the window (AUTO_COMPACT_RATIO = 0.8, mirroring DSH's
dsh-compaction-basic default thresholdRatio, which DSH does not publish
to plugins): hovering it explains that this area is auto-compaction
headroom, normally not actually occupied, and clears the segment hover.
Rendered whenever the window is known, on both the overview card and the
/context modal bar, laid out in window units so it stays correct once use
passes the threshold. Mirrored/detail bars stay clean.
2026-08-20 04:30:54 +08:00
Bowen Liang a0cda34b0c overview: swap and soften the composition hover frames
The occupied-region frame turns from a dashed black box into a SOLID
light-gray box (label-tertiary), and the free track mirrors it with a
dashed 2px box (border, not the old 1px inset shadow) — the two strokes
now share one 2px weight with roles inverted. box-sizing on the free
track keeps the hover border from shifting its width.
2026-08-20 04:15:23 +08:00
Bowen Liang 498cda5acc browser: show per-category deltas vs the previous turn step
Each category row gains two direction-colored pills — an element-count Δ
after the item count and a token Δ hugging the left of the token figure —
each hidden while its figure held. Both baseline against the PREVIOUS
turn's last request regardless of step/turn granularity (live = last
request), with a short caption in the card header stating that baseline.
The count pill's redundant tooltip is dropped now that the token swing is
a visible pill.
2026-08-20 04:06:38 +08:00
Bowen Liang b2104fb745 overview: lay the category legend out as an aligned grid
The Current Composition legend stops being wrapped inline chips and
becomes an auto-flowing grid: each category is a label-left /
numbers-right cell (as many columns as the card fits, fewer as it
narrows) with the name bold at rest and a pointer cursor on hover.

The chip hover-link assertion now compares the label text via textOf,
since the label is its own span.
2026-08-20 03:35:36 +08:00
Bowen Liang 6a3caac925 stats: add cache-hit cell from the official tokenUsage projection
The context stats board gains a right-most 缓存命中 cell that reuses the
token-meter tokenUsage projection read through the standard useProjection
seat — the exact same data and buckets as the chat stats line below the
input box. The share is truncated (not rounded) to two decimal places,
with a float-noise guard; absent the projection it shows a dash. Adds the
bilingual stats.cacheHit label and test coverage (sixth cell, 80.00%
case, and a truncation proof).
2026-08-20 03:20:40 +08:00
Bowen Liang 9aad20a20e chore: bump version to 0.16.0 2026-08-20 01:29:37 +08:00
Bowen Liang cc84af28b6 browser: cap tool description body at ~8 rows with scroll
A 320px cap (matching the raw JSON block) swallowed most real tool
descriptions whole — they read as a wall of text instead of a header-style
prose summary. 160px gives ~8 lines visible at the body font, so a
reader sees the gist at a glance and scrolls for the rest.

scrollbar-width: thin keeps the cap from looking heavy when the body
stays short enough to fit.
2026-08-20 01:25:33 +08:00
Bowen Liang d1e0fbd507 browser: parse tool schema into a parameter table above a collapsed raw JSON
Each tool row in the Context browser now reads as three stacked titled
sections:

  * Description  - the prose, in its own card
  * Parameters   - one row per JSON-Schema property (name, type, required
                   chip, description); type labels cover the common
                   vocabulary (array<inner>, object{N}, enum, anyOf/oneOf
                   unions)
  * Raw JSON     - collapsed behind a slim toggle; the <pre> only mounts
                   when opened, so the default body stays compact and the
                   JSON.stringify pass runs on demand instead of every
                   render

The two top sections share one card chrome (bordered block with a small
title), so a reader can scan them as siblings rather than mixed prose and
UI.
2026-08-20 01:22:33 +08:00
Bowen Liang c535c3b7bc chore: align @deepseek-ai/dsh-* devDeps with dsh 0.1.0-rc.8
Bump @deepseek-ai/dsh-session, dsh-session-projection, dsh-client-ui-primitives
to 0.1.0-rc.8 to match the released @deepseek-ai/dsh@0.1.0-rc.8 contract.

Drop @deepseek-ai/dsh-token-meter: only referenced in comments, never
imported. Runtime occupancy is read from the official 'contextPressure'
projection key registered by dsh itself; pricing is computed locally in
src/host/pricing.ts.

@deepseek-ai/cordis stays at ^4.0.1 (already matches dsh 0.1.0-rc.8).
2026-08-20 00:59:23 +08:00
Bowen Liang e90bd7617d browser: rank tool schemas by token price in the tools category
List the HeaderTools largest-first instead of the producer's header
order, mirroring the overview's top-tools chips. Tests: extended the
header fixture with a deliberately out-of-order pair and assert the
rows come back ranked.
2026-08-20 00:12:22 +08:00
Bowen Liang dc306d2d10 overview: link tool chips and label into the context browser
Make the overview '工具定义 Top' label, its '等 N 个' overflow link and
each tool chip clickable (hover underline) and bridge them into the
Context browser: the label/overflow link open the tools category, a chip
also expands that specific tool's row. One-shot focus is applied by the
browser and cleared back so the same chip can be clicked again.
2026-08-20 00:09:42 +08:00
Bowen Liang 4d4ae62f34 browser: list timestamped category messages newest first
Surface-node category rows in the Context browser were shown oldest
first; reverse them so the newest timestamped message is at the top,
mirroring the NodeList card.
2026-08-19 22:35:26 +08:00
Bowen Liang e06178795a chore: bump version to 0.15.0 2026-08-19 19:57:00 +08:00
Bowen Liang 9e3434d093 chore: move playwright-core to devDependencies 2026-08-19 19:56:45 +08:00
bowenliang123 2c08ab7971 doc: fix social-preview.png link 2026-08-19 17:41:53 +08:00
bowenliang123 6402424b19 doc: use plain markdown image for social preview in README 2026-08-19 17:38:54 +08:00
bowenliang123 15a822d237 doc: refresh social preview with updated context-overview screenshot
Add docs/social-preview/ template + Node.js generator (playwright-core,
2x render + high-quality downsample) and register npm run social-preview.
2026-08-19 17:37:29 +08:00
bowenliang123 686151c74c doc: update context-overview screenshot for context browser 2026-08-19 17:03:32 +08:00
bowenliang123 23d67b9d46 feat(i18n): rename context categories for the agent/LLM-context mental model
Align category naming with harness terminology (ToolSchema, 系统提示词)
and noun-phrase symmetry across zh/en; English UI labels switch to Title
Case.
2026-08-19 16:56:11 +08:00
bowenliang123 485da5486e chore: bump version to 0.14.0 2026-08-19 15:54:03 +08:00
bowenliang123 e8d8326842 fix(ui): keep card titles on a single line
Card titles are bare text nodes inside the .lc-card-title flex row;
when a longer title (e.g. Context History) shares the row with the
hint and the Step/Turn toggle, it could wrap in place. Wrap every
title in an explicit span with flex: none + white-space: nowrap so
titles never break, while sibling hints/toggles keep their layout.
2026-08-19 14:49:47 +08:00