Skip to content
dsh-market Browse plugins GitHub 中文

MarchLiu/dsh-rich-editor

Rich Markdown notebook for the composer region: a tool-row toggle plus a CodeMirror editor card with Codex-style list editing, submitted through the conversation service.

Stars ★ 2 Category UI Enhancements Listed 2026-09-15

Install

Inside DeepSeek Harness, with dsh-market

dsh plugin --profile web add dshmarket

Or from the command line

dsh plugin --profile web add github:MarchLiu/dsh-rich-editor

Installing runs third-party code with your own permissions — it can read your files, use your credentials and reach the network. Review the source first, and pin a commit (github:owner/repo#sha) when you can.

Screenshots

README

English | 中文

Markdown notebook open above the plain composer

Third-party DeepSeek Harness web plugin: a rich Markdown notebook for the composer region. Its browser half contributes two entries to the composer region that dsh-client-ui-conversation owns: a tool-row toggle (conversation.input.left) and an editor card in the composer context stack (conversation.input.dock). Both entries share one per-session store handle, so the in-progress draft survives closing and reopening the panel, surface remounts, and — because the engine scopes session stores by session id — each session keeps its own notebook.

The editor is a CodeMirror 6 instance over the Markdown language: syntax highlighting for the draft (GFM tables included), native undo/redo and selection, and Enter-key list editing in the Codex style — pressing Enter on a non-empty list item opens the next item (ordered markers increment 1. → 2., checkbox items reopen unchecked, indentation is preserved, and a mid-line caret splits the item), while Enter on an empty item drops the marker and returns the line to plain-text editing. Enter on a non-list line falls through to a plain newline. Tab and Shift-Tab steer list depth: Tab on a list item indents it one level, Shift-Tab outdents one level, and Shift-Tab on a top-level item exits the list (marker and checkbox drop, the text stays); both decline on non-list lines to the editor defaults. Mod+Enter submits.

An Edit / Preview pair of tabs sits at the card's top edge. Preview renders the live draft through marked and sanitizes the result with DOMPurify before it touches the DOM — a read-only look at the formatted Markdown (GFM tables, task lists, fenced code, blockquotes), never a modification of what gets submitted: the draft text rides the send path verbatim. Toggling to Preview hides the CodeMirror host instead of unmounting it, so undo history and caret survive the round-trip.

Enter-key list editing: next item, unchecked checkbox, marker dropped

Submission rides the scope-addressed conversation service's send verb — the same path the plain composer's submit rides — so adjudication, queueing, and prompt-error reporting behave exactly like a typed prompt. A failed send surfaces on the session's composer notice channel and the panel keeps its draft.

The notebook and the native composer are two editing surfaces over one draft: opening the panel adopts whatever the native editor already holds (an empty composer instead receives the notebook's kept draft); while the panel is open, every edit on either side mirrors live to the other — notebook edits ride the session input facade's single setDraft write path, native edits flow back through a subscription on the facade's InputState store applied as a minimal-diff splice (an equality guard breaks the echo loop and preserves a caret outside the edited range); closing leaves the final text in the native editor, and a successful submit clears both surfaces.

How the pieces connect: two composer slots, one session store, one send verb

Install

dsh plugin --profile web add @mars.liu/dsh-rich-editor

The package carries its own bundle patch (cordis.patch.yml adds the ui-rich-editor row); list the bundle in the profile's dsh.profile.bundles if you compose profiles by hand. From a checkout:

pnpm install && pnpm run build && pnpm test

Requires the dsh family at ^0.1.2-alpha.5 (published on npm; the 0.1.2 line removed dsh-client-runtime / dsh-client-web-react, whose APIs now come from dsh-client-store, dsh-client-ui-renderer, dsh-api-session-controller and dsh-session) and a dsh web composition that mounts dsh-client-ui-conversation.

⚠️ Compatibility notice (read before installing on 0.1.5-rc.x)

Installing this plugin re-resolves the profile's shared @deepseek-ai/* dependency tree. On DSH 0.1.5-rc.1 / 0.1.5-rc.2, this can land the profile on a mutually incompatible pair of @deepseek-ai/* builds of the same version line — the core dsh-api-session-controller entry may then fail to import from dsh-attachment and dsh web will not boot at all (#4).

  • Try it in a dedicated profile first (e.g. a scratch web-test profile), not your daily-driver one.
  • Disabling the plugin is NOT a rollback. The breakage lives in the resolved package versions under node_modules, not in the plugin manifest; toggling plugin entries or safe mode never rewrites them. Only a pnpm-level operation re-resolves the tree.
  • Recovery: removing the package re-resolves the dependency tree and restores a consistent pair immediately:
dsh plugin --profile web remove @mars.liu/dsh-rich-editor
dsh web   # boots normally again

This project does not pin the @deepseek-ai/* range for now (pinning would fight other plugins in the same profile). Instead, every release is smoke-tested against the 5 most recent versions published on npm at or after the current latest tag of the dsh family, and the README states the verified compatibility range for each release. If your installed versions fall outside that range, prefer a dedicated profile for the first install.

Development notes

The npm 0.0.1-rc.1 dsh snapshot ships browser loader bundles only — its node halves export almost nothing, and several pre-rename dependency names (dsh-compact, dsh-user-interaction, dsh-type-meta, dsh-client-ui-slash) were never published. This repo works around both:

  • package.json > overrides points the missing names at empty stubs under vendor/stubs/ (nothing in this plugin's surface imports them);
  • vitest.config.ts resolves every @deepseek-ai/* specifier through the paths map of a local harness checkout's tsconfig.base.json (DSH_CHECKOUT, default ../deepseek-harness) and inlines all @deepseek-ai/dsh-client-* packages, mirroring how in-repo dsh tests reach client APIs.

Drop both workarounds when the dsh family republishes a complete, installable closure.

Known Limitations and Deferred Work

  • Ordered renumbering is deferred — continuing an ordered list increments the new item's marker, but editing or removing earlier items does not renumber the following ones.
  • No / and @ trigger integration yet — the notebook does not participate in the slash-command and file-mention pipeline; those gestures belong to the plain composer below it.
  • Draft is session-lifetime only — the store keeps the draft across remounts and tab switches, but a full page reload discards it (no persistence key).
  • No attachment intake — pasting or dropping images into the notebook is not wired to the session's image attachment path.
  • The browser bundle inlines ~268 kB gzip of CodeMirror — @codemirror/lang-markdown statically depends on @codemirror/lang-html (which pulls the JavaScript and CSS parsers) even with embedded code highlighting off (codeLanguages: []), and the client bundler inlines the whole chain; a deferred trim would split the editor mount behind a dynamic import.

License

MIT

Content from the project README on GitHub ↗

Comments

Comments live in GitHub Discussions. Sign in with GitHub to post or react.