Bundle
dsh-chat-offscreen
Keep long DSH chat sessions responsive: skip layout/paint for off-screen transcript rows (content-visibility).
- Source
- publieople
- License
- MIT
- Updated
- Updated 18 hours ago
Readme
# dsh-chat-offscreen
Keep long DeepSeek Harness (DSH) Web chat sessions responsive.
## The problem
The DSH chat transcript is **not virtualized** upstream: every loaded history
page stays in the DOM. Backwards paging pulls 50 messages per `loadOlder()`
page, and the turn rail's jump loader pulls 200-message pages until the window
covers the target — with no eviction. On a long session, dragging the
transcript width handle, the sidebar divider, or simply scrolling forces
layout + paint across thousands of nodes, which makes the UI stutter.
## What this plugin does
It is a tiny client-side plugin that installs one stylesheet:
```css
[data-chat-flow-kind="assistant-step"]:not(:has(.md-table-wide)),
[data-chat-flow-kind="tool-call"]:not(:has(.md-table-wide)) {
content-visibility: auto;
contain-intrinsic-size: auto 120px;
}
[data-chat-flow-kind="assistant-step"]:has(.md-table-wide),
[data-chat-flow-kind="tool-call"]:has(.md-table-wide) {
content-visibility: visible !important;
contain: none !important;
}
```
`content-visibility: auto` lets the browser skip layout and paint for
off-screen assistant steps and tool calls — a cheap approximation of
virtualization — while `contain-intrinsic-size: auto 120px` keeps the scroll
range stable and remembers a row's measured height once seen. Rows containing a
wide markdown table opt out so their breakout width is never mis-estimated.
This is a rendering-layer workaround, not a data change: no messages, session
events, or host state are touched. It composes with the retired
`@linxin666/dsh-perf` P0 rule of the same shape.
## Install
```sh
dsh plugin --profile web add github:publieople/dsh-chat-offscreen
```
Then restart the web profile (`dsh web ...`) and hard-refresh the page
(`Ctrl+Shift+R`). The `lib/` build is committed, so no package build script
runs and no `allowBuilds` entry is required.
The bundle patch inserts the plugin row automatically. If you install by hand:
```sh
cd "$DSH_HOME/profiles/web"
pnpm add github:publieople/dsh-chat-offscreen
```
then add `dsh-chat-offscreen` to `dsh.profile.bundles` in that profile's
`package.json` and restart.
## Verify
Open a long session and drag the transcript width handle / sidebar divider, or
scroll fast. In DevTools → Elements, an off-screen assistant step should carry
`content-visibility: auto`.
## Disable / uninstall
```sh
dsh plugin --profile web remove dsh-chat-offscreen
```
then restart. Removing the plugin removes the stylesheet; nothing is persisted.
## Compatibility
- Client platform: `web`. Host half is intentionally empty.
- Depends only on the browser `content-visibility` feature (Chrome/Edge 85+,
Firefox 125+, Safari 18+). On older engines the rules are inert and the UI
simply stays as before.
- Built against DSH `0.1.5-rc.1`; the plugin uses no DSH runtime imports.
## Development
```sh
npm install
npm run typecheck
npm run build # tsdown -> lib/index.js (ESM) + lib/client.js (ModuleLoader)
npm test # drives the built client bundle against a fake DOM
```
`lib/` is committed on purpose so Git installs need no build step. If you change
`src/`, re-run `npm run build` and commit the result.
## If upstream virtualizes the chat
When the DSH chat surface gains real virtualization, delete this plugin row.
The upstream trajectory view (`ui-trajectory`) is already virtualized; the chat
surface is not.
Install
dsh plugin --profile web add github:publieople/dsh-chat-offscreen
Profile: web
With the hub plugin installed, ask your agent to install it by name — it resolves the same plan shown here.
dsh plugin --profile web add github:stvlynn/dsh.fish#path:packages/dsh-plugin-hub
install dsh-chat-offscreen from the hub
- This package builds from source on install. pnpm will ask you to allow its build script — that is permission to run the package’s code on your machine, outside the agent sandbox. Only allow sources you trust.
- This source has no pinned commit, so a later push upstream changes what installs. Prefer pinning a commit.