Left-edge conversation rail for the Web UI: one bar per turn, length scaled to the turn text, hover for a question and answer preview, click to jump; bars come from a host-side outline of the whole session log, so turns outside the loaded window are drawn too and history is paged in on click.
Install
# from GitHub (first run asks for allowBuilds approval — follow the hint, retry)
dsh plugin --profile web add github:dingyi580/dsh-conversation-rail
Any plugin you install runs third-party code with your own permissions — it can read your files, use your credentials, and reach the network, and tool approvals don’t sandbox it. GitHub-sourced plugins also run build scripts at install time. Only install sources you trust, and pin a commit (github:owner/repo#sha).
README
English | 中文
A locator for long conversations in DSH Web. A vertical rail sits along the left edge of the conversation, one bar per turn; hover a bar for a preview card, click it to jump to that turn.
▏───── ┌──────────────────────────────┐
▏─────────── │ Can you patch this without… │ ← question (one line, dark)
▏━━━━━━━━━━━━━━ ◀━━━━━┤ CRLF is already ruled out… │
▏────── │ only the legal re-encodes… │ ← answer (up to four lines, dimmed)
▏──────── └──────────────────────────────┘
- Bar length = how much text that turn holds (square-root compressed, 10–34px).
- The bold bar = the turn currently at the top of the scroll area.
- The preview card carries prose only: your question plus the assistant's plain text. Fenced code blocks, tool calls, shell commands, reasoning traces and injected context never reach the card — you cannot skim JSON.
It draws the whole session, not the loaded window
Conversation history is paginated: the front-end snapshot usually holds only the
most recent stretch, so an 8-turn session may have 1 turn in the window. The
rail is not bound by that:
- The skeleton comes from the host's outline endpoint
(
GET /dsh-conversation-rail/api/outline?sessionId=). The host reads the full log withctx.sessionQuery.readSession(), folds it into a table of contents of roughly a hundred bytes per turn, and returns that — the history itself never crosses the network. - The live snapshot overrides the part that is loaded: it carries jumpable DOM
anchors, and for a turn that is still streaming it is the only current source.
The two are aligned by the
user/messageevent seq, live winning over outline. - Clicking a bar that isn't loaded yet calls
session.loadOlder()repeatedly until that turn enters the window, then jumps. The bar pulses while paging, with a ceiling of 40 pages — better to not reach a turn than to page through an entire log because of one click.
The outline uses readSession rather than the lighter filterEvents because the
latter does not return source. The user/message event type carries both real
questions and context injected by agent.inject() (file-change notices,
AGENTS.md, skill bodies…); the official docs state all three project content
verbatim and are told apart by source. Without that field, injected context
would be drawn as turns.
How it attaches
It takes one seat: conversation.session.header.utilities. Not to draw anything in
the header — that slot is session-scoped, so the component receives the framework's
useSession snapshot hook and sessionId, and its lifetime follows the session.
The component renders null in the header; the actual rail is a fixed overlay on
body, aligned to the measured rectangle of [data-conversation-scroll]. It stays
out of the host layout, so switching skins, collapsing the sidebar or changing the
grid cannot squeeze it.
Turn data comes from ConversationSnapshot.chat: walk order, open a turn on a
user node, attribute the following assistant-step text blocks to it. Jumping
uses the host's own anchors ([data-chat-anchor-key]), the same path its internal
scroll positioning takes.
Known boundaries
- The outline is fetched once per session. New turns arrive through the live snapshot and do not trigger a refetch; only leaving and returning to the session refetches (a 5-second host-side cache absorbs the back-and-forth).
- Jumping to a very early turn loads every page between it and the window. That is what pagination means: to show turn 1, everything from there up to the loaded window has to come in. Jumping to recent turns pages almost not at all.
- If the outline endpoint fails, the rail degrades to drawing only the loaded stretch rather than disappearing.
- Previews are rendered as plain text, not markdown: leading
#,-,1.and emphasis marks are stripped, fenced code is removed entirely.
Install
dsh plugin --profile web add github:dingyi580/dsh-conversation-rail
Then restart dsh web (a newly assembled plugin needs a restart; later code changes
can be hot-reloaded with dev_reload_package).
Put the plugin at ~/.dsh/plugins/dsh-conversation-rail, then add two entries to
~/.dsh/profiles/web/package.json:
{
"dsh": { "profile": { "bundles": ["…", "dsh-conversation-rail"] } },
"dependencies": {
"dsh-conversation-rail": "link:/Users/<you>/.dsh/plugins/dsh-conversation-rail"
}
}
and link it into the profile's node_modules:
ln -sfn ../../../plugins/dsh-conversation-rail ~/.dsh/profiles/web/node_modules/dsh-conversation-rail
Build
npm run build # tsc for the host entry + tsdown for src/client → lib/client.js
npm run typecheck # type check only
lib/ is committed so the plugin installs from GitHub without a build step.
Assembly goes through cordis.patch.yml plus the profile's dsh.profile.bundles.
License
BSD-3-Clause
Links
More in this category
zhu1090093659/dsh-web-ui#packages/dsh-web-ui-all★ 4430
Plugin and skin collection for the DSH Web UI: task board, Git graph, right-side panel, remote mobile UI, pet, live token stats, and a skin center.
omdsh-dev/DSH-better-sidebar★ 2101
Full sidebar workbench with file rendering and editing, terminal, Git, and subagents; third-party plugins can register new tabs.
ccch1mneyyy/dsh-TUI★ 1924
Claude Code-style full-screen terminal UI: pixel-whale header, live status line, and streaming thought expansion.
omdsh-dev/dsh-at-file★ 362
Codex-style `@file` mentions: search workspace files in the composer and attach their contents to prompts.
omdsh-dev/dsh-genui★ 214
Interactive UI components rendered inline in replies: layout, charts, forms, quizzes, mermaid, 3D scenes, and an action event loop back to the model.
huiliyi37/dsh-tianshu-tui★ 211
A terminal UI (TUI) for DeepSeek Harness.