New:Introducing Socket Scanning for VS Code Marketplace Extensions.Learn more →
Get Started

dsh-turn-navigator

Package Overview
Dependencies
Maintainers
1
Versions
10
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

dsh-turn-navigator

Smoothly Turn Nav (Smoothly TN): full-history piano-key turn rail for DeepSeek Harness (dsh) web conversations — see every turn at a glance, hover to preview, click to jump anywhere, and replace the official (non-disableable) turn rail.

latest
Source
npmnpm
Version
0.4.8
Version published
Weekly downloads
10
-83.87%
Maintainers
1
Weekly downloads
 
Created
Source

Smoothly Turn Nav (Smoothly TN)

Smoothly · 思磨力 — brand · 中文名:思磨力轮次胶囊条

English · 简体中文

Every turn of your conversation, one glance away.

Smoothly Turn Nav (Smoothly TN) — 思磨力轮次胶囊条 — is an external plugin for DeepSeek Harness (dsh) that puts a piano-key turn rail on the right edge of every conversation — a vertical column of tiny capsules, one per turn. It gives you a full minimap of the conversation: every turn ever made (not just the ones currently loaded), hover previews, click-to-jump to any turn's start, and follow-scroll highlighting. It can also replace the official built-in turn rail, which has no off-switch of its own.

Turn navigation rail

Why

In the default DSH web UI, the official turn rail historically showed only the currently loaded window of turns — in a long conversation, most turns are invisible until you scroll and load more. As of dsh 0.1.3-alpha.1 the built-in rail also gained full-session scope and out-of-window jumps through a host-side turnOutline projection, but it still cannot be switched off. Smoothly TN solves the long-session problem and stays fully replaceable:

  • Full history at a glance — every persisted turn is shown as plain data, including turns far outside the loaded window. No scrolling, no loading, no waiting.
  • Hover to preview — the capsule glows with the theme color and widens in a wave ripple; a DSH-style tooltip shows the turn's number, time, prompt, and a response preview (two content lines, like the official rail). The prompt falls back in order: the full first human message read from the journal → the host's bounded preview for turns in the loaded window → the host turnOutline projection → the localized turn number (Turn N, always the first line). The response preview comes from the same host projections (the window's own response first, turnOutline.response as the whole-log fallback, 120 chars). A machine-woken turn (goal continuation, plugin waking, background-job notice, subagent settlement, compaction checkpoint — turns that have no human prompt by construction) therefore shows its turn number plus the response preview, never a placeholder or injected text.
  • Click to jump anywhere — jumps to any turn's start, even turns not yet loaded (the window is extended on demand with instant feedback).
  • Know where you are — the current turn is highlighted as you scroll.

Features

🗺️ Full-history minimapAll turns visible immediately — read from the persisted session log as data, zero prepends into the conversation flow on open (long sessions stay responsive)
🎹 Piano-key designOne capsule per turn, ~3px tall, right-aligned on the right edge; auto-sizing (up to 30vh) with an internal hidden scrollbar
🌊 Wave hoverHovered capsule glows with the theme color and widens 150% leftward; its two neighbours widen 125% — a ripple across the rail
💬 Rich tooltipTurn number, timestamp, prompt, and response preview (prompt fallback chain: the journal's full first human message → the window's bounded host preview → the host turnOutline projection → the localized Turn N; the response preview comes from the window/turnOutline projections), clamped inside the viewport
🎯 Jump to any turnPrecise scrollTop targeting (no scrollIntoView fights); out-of-window jumps extend the window on demand with a "Locating turn N…" pulse + bubble; the oldest-turn jump loads to the true first turn (hasMore = false)
👁️ Follow-scroll highlightThe capsule of the turn at the reading line is tinted as you scroll — and the rail's own viewport keeps the active turn in view
⬆️⬇️ Scroll buttonsClick or hover-hold to scroll the rail; greyed out when there is nothing to scroll
🎛️ Rail mode switchSettings → General → Turn navigation: DSH official / Smoothly TN (default) / Hide all — persisted across reloads, so the official rail can finally be turned off
🔌 Pure external pluginNo DSH source code modified; no host changes; no new dependencies; no conversation writes (the only DOM writes are an injected style tag, one body class and a transient jump highlight)

vs. the official DSH turn rail

The official built-in TurnNavigator has no off-switch and is always rendered in the chat view. The table below compares it at dsh 0.1.3-alpha.1 (the current DSH web TurnNavigator, which re-added full-session scope via its own host projection) against this plugin, Smoothly TN v0.4.8:

CapabilityDSH official rail (0.1.3-alpha.1)Smoothly TN (v0.4.8)
Turns shownEvery turn — host turnOutline projection (0.1.3+)Every persisted turn — client-side journal read
Full-history robustnessDepends on the host turnOutline projection — not driven by browser-synthesized sessions (e.g. ?fixture), where it falls back to the loaded windowAlways full — reads the persisted journal directly, no host projection required (verified full on both real and fixture sessions)
How full history is readHost-side turnOutline projection, read by the chat view (the conversation snapshot carries no projection values)Client pages the persisted journal (session/page); older dsh falls back to sessions.history RPC — zero host changes
Jump to a turn outside the window✅ (0.1.3+ unloaded anchor pages history by seq)✅ on-demand window extension + "Locating turn N…" pulse/bubble
Long-session open performanceReads the projectionZero prepend — plain data, no flow re-render, no stall
Follow-scroll highlight✅ (0.1.3+ keeps the active mark in the rail viewport, with a pointer guard)✅ (v0.4.1+, same pointer-guarded follow)
Hover previewPrompt (1 line) + response (≤3 lines), no timestamp; a turn with no human prompt shows only its turn number in the prompt lineTurn number + timestamp + prompt (the full first human message for journal-read turns; the host's bounded prompt preview for turns in the loaded window; the turnOutline prompt when neither read one; the localized Turn N last) + response preview (host projection, ≤120 chars — same source as the official rail)
Wave ripple animation❌ (fixed-pitch ticks widen instead)✅ wave ripple
Scroll buttons (click / hover-hold)❌ (wheel + gradient fade)✅ click / hover-hold
Rail heightDynamic band (natural height … 420px)Auto-sized (≤30vh), internal hidden scrollbar
Narrow viewport (<900px)Auto-hiddenAuto-hidden (mirrors official)
Hide / switch rail❌ no off-switch✅ Settings → General → 3 modes; Hide all hides both
Keyboard accessibility✅ focus ring + aria-current/aria-busy/aria-describedby✅ same pattern: the accessible name is the action (Jump to turn N / Load and jump to turn N for a turn still outside the window) with aria-current/aria-busy, and the preview is linked through aria-describedby → role="tooltip"; tabbing to a capsule shows the preview (no pointer required)
SourceBuilt-in, cannot be disabledExternal plugin, can be replaced/disabled

As of dsh 0.1.3 the built-in rail caught up on full-session scope and out-of-window jumps. What still sets Smoothly TN apart: you can switch it off (the official rail cannot), the tooltip carries the timestamp, the full first human message for turns read from the journal, and the same response preview the official rail shows (falling back to the localized turn number when a turn has no human prompt), there are scroll buttons and wave hover, and it remains an external plugin with zero host changes and no conversation writes. And on dsh ≤ 0.1.2 the built-in rail is simpler still (loaded window only), so the gap Smoothly TN closes is even larger there.

Verified on dsh 0.1.3-alpha.1 (2026-09-06, Playwright against the live web UI): on a real 42-turn session both rails show all 42 turns (the official one via its host projection, ours via the journal); on a ?fixture browser-synthesized session the official rail degrades to the loaded window (24/75) while Smoothly TN still shows all 75 — because our full history never depends on the host projection. Jumps, follow-scroll highlight, the mode switch, and the subtractive takeover of the official rail (display: none via the stylesheet override) all verified working.

Version map

Which Smoothly TN release matches which dsh:

Smoothly TNdshNotes
v0.1.xdsh ≤ 0.1.1Full history via the legacy sessions.history browser→host RPC
v0.2.x – v0.4.1dsh 0.1.2+Adapted to the ui-chat refactor; full history via the journal session/page channel; v0.4.1 fixed true turn numbers and rail-viewport follow
v0.4.2dsh 0.1.2+, incl. 0.1.3-alpha.1Comparison/positioning updated against the 0.1.3 official rail (see above)
v0.4.3dsh 0.1.2+, incl. 0.1.3-alpha.1This release: brand naming standardized to Smoothly(思磨力)/ Smoothly Turn Nav(Smoothly TN)/ 思磨力轮次胶囊条 — technical IDs (npm package dsh-turn-navigator, plugin/slot IDs, locale namespace, CSS prefix, localStorage key) unchanged
v0.4.4dsh 0.1.2+, client contract re-checked against 0.1.6-alpha.2This release: the official-rail body class gained a dispose hook (disabling or reloading the bundle live from the dsh Plugins page restores the built-in rail), and two stale inject entries are gone
v0.4.5dsh 0.1.7+This release: icon imports follow the 0.1.7 visual-language rename (*Regular stroke variants; rendered sizes unchanged) — the client half requires 0.1.7 from here; v0.4.4 remains the release for 0.1.2–0.1.6
v0.4.6dsh 0.1.7+This release: the 0.1.7 floor is declared in package.json as an optional peer dependency on @deepseek-ai/dsh-client-ui-conversation (>=0.1.7-rc.1); a host that ships dsh's peer evaluator (0.1.7-rc.1+) can refuse to load a plugin whose floor it does not meet and print the exact dsh plugin allow-version remedy. No behaviour change; runtimes without the evaluator are unaffected — use v0.4.4 on 0.1.2–0.1.6
v0.4.8dsh 0.1.7+This release: the tooltip gains the response preview (window response → turnOutline.response, matching the official rail's two content lines); a turn without a human prompt no longer shows its number alone
v0.4.7dsh 0.1.7+This release: a turn's tooltip label is no longer fabricated — the data layer keeps an empty label for a machine-woken turn and the tooltip falls back to the localized turn number (official semantics), the journal fold requires an appended human message, and the host turnOutline projection is merged in as the third label source. New behavioural gate scripts/test-turn-labels.mjs (in npm test/verify:all) and live gate npm run verify:turn-labels

The official-rail comparison in this README targets dsh 0.1.3-alpha.1; on older dsh the official rail is simpler, so Smoothly TN's advantage is larger there. v0.4.6 declares the 0.1.7 floor in package.json (see the version map above). DSH's peer evaluator ships from 0.1.7-rc.1, and every runtime that has it already satisfies >=0.1.7-rc.1 — so the declaration puts the floor in machine-readable form and is what lets a later raised floor be refused by the host with the dsh plugin allow-version remedy; it is not a guard for older runtimes (0.1.6 and earlier, and 0.1.7-alpha.N, ship no evaluator and simply load the bundle), so v0.4.4 remains the release for 0.1.2–0.1.6. The explicit -rc.1 floor is deliberate: >=0.1.7 and ^0.1.7 do not match a 0.1.7-rc.N runtime.

Installation

dsh plugin --profile web add dsh-turn-navigator

Then restart dsh web:

dsh web

Usage

  • Choose which rail to show (Settings → General → Turn navigation): DSH official (the built-in rail), Smoothly TN (this plugin's rail — default), or Hide all. The official rail has no off-switch, so choosing Smoothly TN hides it with a stylesheet override and our rail takes over the right-edge center position. The choice persists across reloads.
  • Open any conversation with at least one completed turn.
  • A vertical rail of grey capsules appears on the right edge (one per turn). It auto-sizes — short conversations get a short rail, long ones hit the 30vh cap and scroll internally (hidden scrollbar, no layout jitter).
  • Hover a capsule: it glows, widens in a wave, and shows the turn's number, timestamp, prompt, and response preview in a tooltip to the left of the rail (a turn with no human prompt shows its turn number plus the response preview).
  • Click a capsule to jump to that turn's start. Out-of-window turns pulse the capsule and show a "Locating turn N…" bubble while the window is extended on demand; the target row is highlighted on arrival. The activated capsule centers in the rail (unless it is the first or last turn).
  • Scroll with the mouse wheel, the up/down buttons, or hover-hold on the buttons.

How it works

The plugin registers two additive slots — no DSH source code is modified:

SlotScopeRole
conversation.session.header.utilitiessessionThe floating turn rail (renders position: fixed; reads the live chat snapshot via the framework useChat/useSession kit)
settings.general.itemrootThe Turn navigation mode switch in Settings → General
  • Full history as data: on dsh 0.1.2+ the rail pages the same persisted log the official window reads, through the Typert Remote session/page channel (ctx.remote.session — mounted by the base web assembly; no host changes, no new dependencies). On older dsh it uses the sessions.history RPC. Every turn is derived from raw turn/start / user/message / turn/end events as plain data.
  • On-demand jumps: clicking a turn already in the window scrolls directly; for a turn outside it, the rail extends the window page by page through the official session store (loadOlder, with the authoritative hasMore as the loop terminator) until the target is in view — the only path that touches the flow, and it runs only when you click.
  • Precise scrolling: the rail locates the turn's first chat-node key, finds its DOM row via data-chat-anchor-key, and sets the scrollport's scrollTop directly (more predictable than scrollIntoView).
  • Replacing the official rail: the official rail lives inside the conversation scroll container; a container-scoped stylesheet rule (driven by the mode switch) hides it, and the rail takes over its right-edge center position. Verified structurally against dsh 0.1.3-alpha.1 — the [data-conversation-scroll] nav hide rule still matches. If a future dsh changes that structure, the worst case is the official rail reappearing (side by side) — never a crash.
  • No data leaves the browser, no conversation writes: the plugin never sends data anywhere, never writes conversation content, and only reads the DOM to find jump targets. Its visible side effects are the injected style tag, the tn-hide-official body class (removed on dispose), a transient highlight class on the target row, and the on-demand window extension you trigger by clicking an out-of-window turn.

Compatibility

  • DeepSeek Harness (dsh) with the web client (dsh web); developed and verified against dsh 0.1.2+ and verified against dsh 0.1.3-alpha.1 (Playwright re-test, 2026-09-06: full-history rail, jumps, follow highlight, mode switch, and the official-rail stylesheet takeover all passing).
  • Requires the conversation.session.header.utilities and settings.general.item slot declarations (present in current DSH).
  • Client contract re-checked against dsh 0.1.6-alpha.2 (2026-09-22): the conversation.session.header.utilities and settings.general.item slot declarations, the ui-primitives exports the rail uses, and the --dsw-alias-* tokens it references all still exist. The interactive Playwright re-test was not re-run on 0.1.6 (the 2026-09-06 run remains the last interactive verification).
  • Default Smoothly TN mode hides the official rail (stylesheet override) and centers our rail in its place; DSH official mode shows the built-in rail instead; Hide all hides both. Both rails auto-hide below 900px width.
  • Coexists with DSH global panels (e.g. the kanban board): a panel takes over the main slot entry, so the conversation view (and this rail with it) is swapped out rather than layered under.
  • Known limitation (DOM fallback): when there is no session store to read (older hosts), the rail extends the window by clicking the flow's own paging control, and that path recognises only the control's Chinese and English labels (idle and in-flight) — on a third-language shell it cannot extend the window. The primary journal path (dsh 0.1.2+) does not read labels at all.

Development

  • pnpm typecheck — TypeScript check (tsdown does not typecheck).
  • pnpm test — typecheck plus scripts/test-client-dispose.mjs, which loads the built bundle in a DOM stub and asserts the apply/dispose contract of the official-rail body class.
  • pnpm bundle — build the module-table client bundle into lib/.
  • scripts/verify-*.mjs — Playwright acceptance scripts against a live dsh web (rail, full-history journal, mode switch, jump, feedback, overlay, sizing, UI).
  • pnpm release:check — release gates (version, tag, tree, build, registry).

License

MIT

Keywords

deepseek-harness

FAQs

Package last updated on 02 Oct 2026

Related posts