Skip to content

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

dsh-quicknav

English | 简体中文

A small, self-contained DSH WebUI plugin for quicker navigation through long conversations, with a little lightweight motion on top.

It has exactly two features:

  1. History — a floating conversation-history strip on the right edge of the conversation. One bar per user turn; hover shows the question and a pin control; click scrolls smoothly to that turn.
  2. Motion — entrance animation for transcript rows, the sidebar session tree, the active sidebar row's selection trace, and a new conversation's welcome dialog. On by default, with one master switch.

dsh-quicknav is especially useful if you run DSH on a server and access its WebUI remotely through a reverse proxy. That is the environment it was originally built for.

It works on a non-loopback WebUI (for example, https://<your-dsh-host>) without an SSH tunnel, without opening settings.describe or any other privileged RPC, and without weakening DSH's remote security boundary.

Version 0.1.0 · MIT · target DSH Web runtime 0.1.0-rc.8 (CLI 0.1.0-rc.7)


Why dsh-quicknav?

This plugin started with two things we liked in dsh-client-ui-custom: its conversation-history navigation and its motion.

The original plugin is a much broader UI-customization project. Some of its features depend on DSH host settings, which are intentionally unavailable when the WebUI is accessed remotely through a non-loopback connection. That makes several of those features unavailable in the server + reverse-proxy setup we actually use.

Rather than work around that security boundary, we wanted something much smaller:

  • keep the history navigation we use in long conversations;
  • keep a small set of fixed entrance animations;
  • use no privileged host settings or settings RPC;
  • store the few user preferences locally in the browser;
  • leave the rest of DSH alone.

So dsh-quicknav is deliberately not a general UI-customization suite. It does two small things and tries to do them without changing DSH's security model.

Scope

Implemented: history and motion.

Deliberately not implemented: Markdown rendering (DSH renders Markdown natively), appearance/theming, keyboard shortcuts, usage statistics, plugin marketplace, per-feature style pickers and presets, or settings-panel motion.


Requirements / compatibility

  • Target host: a DeepSeek DSH WebUI profile.
  • Verified versions: DSH CLI 0.1.0-rc.7 and client/runtime packages 0.1.0-rc.8. This is the only combination this release has been tested against.
  • DSH is still in release-candidate phase. This plugin relies on several internal or semi-internal UI hooks — DOM attributes, slots and snapshot shapes. Compatibility with future rc or stable versions is not guaranteed.
  • No runtime npm dependencies: the browser bundle consumes the DSH shell's own React seed (react, react/jsx-runtime, react-dom; React 18.3.1 in the verified shell).
  • Browser: a modern browser with localStorage, which is used for preferences.
  • Building from source: Node.js >= 20. This is only needed for maintainers and developers. Users installing the prebuilt release artifact do not need Node.

Because DSH is still changing, check the upgrade notes after upgrading DSH.


Install

Download dsh-quicknav-<version>.tgz from the corresponding GitHub Release, then install it into your DSH WebUI profile:

dsh plugin --profile <profile> add file:./dsh-quicknav-<version>.tgz

Reload the WebUI after installation.

That's it. The release artifact already contains the built browser bundle; no Node.js toolchain or manual profile editing is required.

Installing from source

For development, a source checkout can also be linked directly:

npm ci
npm run build
dsh plugin --profile <profile> add link:<path-to-dsh-quicknav>

This is a developer workflow rather than the recommended installation method.

Troubleshooting installation

dsh plugin normally reconciles the package and dsh.profile.bundles automatically. Do not manually add dsh-quicknav a second time if it is already registered.

If installation behaves unexpectedly, inspect the affected profile under:

$DSH_HOME/profiles/<profile>/

The relevant files are typically package.json, cordis.patch.yml and pnpm-lock.yaml.

The package's dsh.bundle.patch mounts the host half, while dsh.client exposes the browser bundle through DSH's client-module system.


Update

Download the new release artifact and run the same command against the same profile:

dsh plugin --profile <profile> add file:./dsh-quicknav-<version>.tgz

There is no separate upgrade subcommand. Re-running add with the new artifact updates the profile dependency.

Reload the WebUI afterward.

Your quicknav preferences survive an update because they are stored in the browser under:

localStorage['dsh-quicknav:prefs:v1']

After upgrading DSH itself, see Upgrade risk before assuming the plugin is still compatible.


Uninstall

dsh plugin --profile <profile> remove dsh-quicknav

Reload the WebUI afterward.

The plugin does not write DSH host settings, so there are no host-side preferences to remove. Its browser-side preference entry is intentionally left behind:

localStorage['dsh-quicknav:prefs:v1']

Clear that entry manually if you also want to remove the saved preferences.

If an older or unusual DSH version leaves dsh-quicknav in dsh.profile.bundles after removal, remove that stale entry manually. A normal uninstall on the verified DSH version cleans it up automatically.


Features

History strip

  • Floats over the conversation's right edge from the frame's shell.overlay layer. It is additive: it takes no column, replaces no panel, and does not touch DSH's tool-details column.
  • One bar per user turn, derived from the mounted chat snapshot.
  • Hovering a bar shows a tooltip with the question preview and reveals a pin control for that turn.
  • Clicking a bar smooth-scrolls to the message and briefly highlights its position.
  • The bar for the turn currently on screen keeps a subtle accent tint.
  • Older history is paged in automatically, with throttling and a safety cap.
  • Pinned turns ignore the count limit and are drawn with an accent frame.
  • The control at the top of the strip lets you choose how many entries to show (5 / 10 / 20 / all) and toggle motion globally.
  • The strip stays hidden on a blank, brand-new session.

Motion

Motion uses a small set of fixed effects — no picker and no presets.

Surface Effect
Transcript rows fade-up (8px rise), staggered 40ms/row, capped at 320ms; replayed on every conversation open/switch
Transcript column panel fade + 6px rise on each open/switch
Sidebar tree slide-left on wholesale loads only; group expansion and search results appear without delay
Active sidebar row a selection box traced in and kept while the row stays active
New conversation the welcome dialog fades in with a 4px rise (420ms)

prefers-reduced-motion: reduce downgrades every entrance to a 100ms opacity-only cross-fade and removes the selection trace.

The motion master switch is on by default. Turning it off immediately removes every class the motion engine applied.


Preferences

Preferences are stored in the browser under:

localStorage['dsh-quicknav:prefs:v1']

The document looks like this:

{
  "limit": 10,
  "pinned": {
    "<sessionId>": [3, 7]
  },
  "motionEnabled": true
}
  • limit — how many recent turns the strip shows (5 / 10 / 20 / all).
  • pinned — pinned turn numbers per session ID; pinned turns ignore limit.
  • motionEnabled — the entrance-motion master switch.

Only these values are persisted.

No message text is ever written to localStorage. Tooltip previews are read transiently from the current DSH session snapshot at render time.

Preference reads are sanitized: unknown or corrupt documents fall back to defaults, and an unavailable or read-only store degrades safely.

The plugin creates no DSH settings namespace and performs no host round-trip for preferences.


Privacy / network / telemetry

  • The plugin makes no network requests and calls no remote APIs.
  • It sends no telemetry or analytics.
  • It does not use DSH host settings (settingsScope / settings.*) and performs no privileged settings RPC.
  • The only persistent state is the preference document in the current browser's localStorage.
  • Message previews are read from the live session snapshot and are not persisted by the plugin.

Nothing is sent anywhere by dsh-quicknav.


Known limitations

  • Compatibility is not guaranteed across DSH versions. DSH is still in rc and several hooks used here are internal UI details.
  • "All" is not infinite history. The pager is currently capped at 120 bars. Older turns remain reachable in the conversation itself.
  • A blank session shows no strip. There are no user turns to list yet.
  • Motion is cosmetic and structural. If DSH changes the relevant transcript or sidebar DOM, an animation may simply stop applying.
  • If the session snapshot is temporarily unavailable, the strip renders nothing rather than crashing the page.

Upgrade risk

dsh-quicknav intentionally has very little integration surface, but some of that surface is internal to DSH.

Risk Breaks
High — data-chat-anchor-key changes jump + transcript motion
High — data-chat-flow / data-composer-seat change panel + welcome entrances
Medium — [role="tree"] / [role="treeitem"] / aria-selected change sidebar motion + selection trace
Medium — shell.overlay disappears or its pointer-events behaviour changes history strip
Medium — ctx.sessions.list / binding() shape changes history strip
Medium — chat node payloads (content, time, location) change previews/times degrade
Low — client ModuleLoader / dsh.client / dsh.bundle.patch changes bundle fails to load
Low — locale registration forms change labels fall back to raw keys
Low — --dsw-alias-* variables change colours degrade

Most UI-hook failures degrade quietly rather than crashing DSH: a missing chat snapshot renders no strip, a missing anchor makes a jump a no-op, and missing motion hooks simply leave the native UI unchanged.

Maintainers can revalidate the known contracts after a DSH upgrade with:

node scripts/check-dsh-contract.mjs
npm run verify

Technical notes

This section documents the DSH internals the plugin currently relies on. Regular users do not need any of this to install or use quicknav.

Why remote WebUI changes the design

The broader dsh-client-ui-custom plugin registers several features behind a settings-snapshot readiness check:

const snapshot = scope.getSnapshot()
if (snapshot.status !== 'ready' || snapshot.value === undefined) return

DSH intentionally gives non-loopback WebUI connections a non-host settings scope:

// dsh-client-ui-settings — SettingsScopeBinder.bind()
new SettingsScopeController(
  api,
  spec,
  mirror,
  connection.isLoopback ? 'host' : 'memory',
  schema,
)

In that memory scope, persistent host settings are unavailable.

This is part of DSH's remote security model, not a bug.

dsh-quicknav therefore does not try to make host settings available remotely. It simply does not participate in the settings transport: its few preferences live in browser localStorage, and its runtime functionality uses the existing client-side session and UI surfaces.

DSH surface this plugin depends on

Cordis services

Service Used for
ctx.slots inject('shell.overlay') + register(...)
ctx.sessions current session, conversation snapshot and loadOlder
ctx.locale labels and locale updates
ctx.effect fiber-scoped cleanup

Not used: settingsScope, connection, remote, workspaces, layout, conversation, or any settings.* RPC.

Slot

The history strip uses shell.overlay, an additive root-level list slot provided by DSH's UI layout.

The entry renders as a fixed overlay and opts into pointer events. It does not replace or resize any native DSH panel.

Host DOM hooks

Hook Used for
[data-chat-anchor-key] jump target + transcript motion rows
[data-chat-flow] transcript panel entrance
[data-composer-seat] new-conversation welcome entrance
[role="tree"] [role="treeitem"] sidebar motion
aria-selected on tree items active-row selection trace
--dsw-alias-* CSS variables strip / tooltip colouring

Runtime data shapes

The history implementation currently reads these DSH snapshot concepts:

  • ConversationSnapshot — blank, openState, hasMore, loadingOlder, chat
  • ChatSnapshot — order, nodes.get(key)
  • ChatConversationViewNode — kind, data, location
  • UserMessageNode — content, time

These are not treated as stable public APIs.


Development / maintainer

Regular users should install the prebuilt Release artifact. This section is for people building, extending or maintaining the plugin.

npm install            # Node >= 20
npm run typecheck      # tsc --noEmit (strict)
npm run build          # esbuild -> lib/index.js + lib/client.js
npm test               # vitest (jsdom); bundle rebuilt first via pretest
npm run verify         # typecheck + build + tests

Two additional maintainer tools require an installed DSH and are intentionally not part of npm run verify:

node scripts/check-dsh-contract.mjs
node scripts/verify-live-bundle.mjs --html <live-index.html>

check-dsh-contract.mjs revalidates the known host hooks against an installed DSH. DSH home resolution is:

argument > $DSH_HOME > ~/.dsh

verify-live-bundle.mjs materializes the built client bundle through DSH's real client module system against a captured WebUI page. See the script header for the capture procedure.

Client bundle format

DSH's own client bundles are produced by an internal monorepo pipeline that is not independently installable. This project reproduces the output format expected by the runtime:

window.__ModuleLoader__.load({
  id: 'dsh-quicknav',
  factory: (require) => {
    var module = { exports: {} }
    /* CJS body */
    return module.exports
  },
})

scripts/build.mjs bundles src/client/index.ts with esbuild (CJS, React external) and wraps the result in that envelope.

The build also enforces a purity gate: every require() in the generated client bundle must be one of the static modules provided by the DSH shell.

The current release requires only:

react
react/jsx-runtime
react-dom

React itself is not bundled into dsh-quicknav.


Licence and attribution

dsh-quicknav is released under the MIT License. See LICENSE.

Parts of the history and motion implementation are adapted from dsh-client-ui-custom by Yoli-mi, also released under MIT.

See NOTICE.md for the pinned upstream revision, exact derived-file mapping and upstream license text. Adapted files also carry provenance in their source headers.

Special thanks to Yoli-mi for open-sourcing dsh-client-ui-custom. dsh-quicknav grew out of its history-navigation and motion ideas, which gave this little plugin its starting point.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages