deepseek-harness
deepseek-ai
DeepSeek Harness: Everything is a Plugin.
PROJECT TOPICS
PROJECT README
A DeepSeek Harness (DSH) web plugin that renders assistant messages in the conversation stream with markstream-react — the low-jitter streaming Markdown renderer for AI chat (streamed code blocks, Mermaid, KaTeX, safe HTML).
English | 中文
assistant-step renderer in the conversation.chat.node keyed slot with a markstream-based implementation, registered with priority: -10 (slot priority is ascending — lowest renders) to shadow the shipped renderer's same-key entry at default priority 0. Registering the same key at the same priority throws:<MarkdownRender content final fade> with low-jitter incremental streaming, including intermediate states of incomplete Markdown;stream-diffs package), Mermaid (optional mermaid), KaTeX (inlined with the dependency tree in the current build), and safe HTML;turn-tail, including IconActions / produced-file rows) and tool-row rendering remain the product's own.t locale seat is bound to the conversation namespace by the slot declaration, so it reuses ui-conversation's dictionary (row.running / message.stopped / message.unknownBlock / json.truncated) without registering a new namespace.The config surface is modeled on the demo site markstream-react.pages.dev (CODE THEME / DARK MODE etc.), the component docs, and the recommended code-block config, delivered as two layers:
config (full template in cordis.patch.yml) — deployment defaults, validated by the Config schema and used as the settings namespace base.shell.overlay entry dsh-markstream-config) opens a non-modal floating panel (DeepSeek-web style: 70% of the conversation window's height, vertically centered on it, non-blocking — the rest of the page stays interactive); the header × closes it back to the gear. Fields override and persist to $DSH_HOME/settings.yaml; the "reset" affordance next to a field clears the user override and falls back to the composition value (a field's presence in the user layer marks it as overridden). Writes go through a revision-fenced settings scope and take effect immediately (the renderer re-installs itself on config changes). Every field row is two lines — the config item title on its own line, the control (value) below — so the control never covers the title, and every interactive control (toggle / select / number / button) is the unified component set in controls.tsx (no raw HTML components in the settings surface).Settings → Plugins → Config no longer shows a Markstream card; the gear panel is the single config entry point.
| Field | Default | Meaning |
|---|---|---|
enabled |
true |
Enable switch: false restores the shipped Markdown renderer (the gear panel stays reachable) |
theme |
auto |
auto follows the DSH theme (body[data-ds-dark-theme]) / light / dark (maps to MarkdownRender isDark) |
fade |
true |
Fade-in animation for streamed non-code nodes |
typewriter |
false |
Blinking typewriter cursor while content streams |
Code blocks (codeBlockProps header toggles + codeBlockOptions, following the stream-diffs surface recommendation; effective only with stream-diffs, falls back to a plain <pre> without it):
| Field | Default | Meaning |
|---|---|---|
codeBlockShowHeader |
true |
Show the code-block header |
codeBlockShowTooltips |
true |
Show tooltips |
codeBlockShowFontSizeButtons |
true |
Show font-size buttons |
codeBlockShowCollapseButton |
false |
Show collapse button |
codeBlockDiffStyle |
unified |
unified / split |
codeBlockOverflow |
wrap |
wrap / scroll |
codeBlockExpandUnchanged |
false |
Collapse unchanged diff regions |
codeBlockEnableLineSelection |
true |
Enable line selection |
codeBlockDisableLineNumbers |
false |
Hide line numbers |
codeBlockFontSize |
13 |
Code font size in px (13 recommended) |
codeBlockTabSize |
2 |
Tab width |
codeBlockPadding |
12 |
Symmetric code padding in px |
codeBlockMaxHeight |
480 |
Max height in px (0 = unlimited) |
codeBlockLightTheme |
vitesse-light |
Light code theme (Shiki registration name) |
codeBlockDarkTheme |
vitesse-dark |
Dark code theme |
Diagrams (each needs its optional dependency; without it the source is shown as fallback):
| Field | Default | Meaning |
|---|---|---|
mermaidEnabled |
false |
Forward mermaidProps (needs mermaid) |
mermaidIsStrict |
true |
mermaidProps.isStrict |
mermaidMaxHeight |
480 |
mermaidProps.maxHeight in px (0 = unlimited) |
d2Enabled |
false |
Forward d2Props (needs @terrastruct/d2) |
d2MaxHeight |
480 |
d2Props.maxHeight in px (0 = unlimited) |
dsh-markstream/
├── package.json # dsh.client manifest + dsh.bundle.patch declaration
├── cordis.patch.yml # plugin-row insert + composition config template (bundle channel)
├── tsconfig.json # typecheck (@deepseek-ai/* types from npm peers 0.1.0-rc.8)
├── tsconfig.build.json # tsc full emit to lib/types (JS + d.ts)
├── tsdown.config.ts # emits lib/client.js (browser half)
├── scripts/stage-node.mjs # stages the Node-half files from lib/types to lib/
└── src/
├── index.ts # Node half: registers the dsh-markstream settings namespace (base = row config)
├── schema.ts # flat schema (schemastery z; row Config = namespace schema)
├── config.ts # shared field definitions / defaults / option tables
├── invariant.ts # invariant companion
└── client/
├── index.ts # browser half: shell.overlay floating panel + assistant-step renderer
├── card-store.ts # snapshot store (settings scope binding + set/unset)
├── ConfigSurface.tsx # bottom-right gear + 70%-height centered floating panel
├── ConfigSurface.module.css
├── ConfigFields.tsx # shared 2-line field rows (title line + control line)
├── ConfigFields.module.css
├── controls.tsx # unified settings controls (toggle / select / number / buttons)
├── controls.module.css
├── AssistantMarkstream.tsx # config-driven assistant-step renderer (markstream-react)
├── AssistantMarkstream.module.css
├── locales.ts # dsh-markstream dictionaries (zh/en)
└── css-modules.d.ts
pnpm install
pnpm build # tsc -p tsconfig.build.json && node scripts/stage-node.mjs && tsdown
Artifacts:
lib/client.js — the browser half in the DSH client-bundle format (window.__ModuleLoader__.load({ id, factory })): markstream-react / markstream-core / stream-markdown-parser / @floating-ui/* / katex are all inlined into one file (inlineDynamicImports; the module loader serves only /plugins/<id>/client.js); react / react-dom / react/jsx-runtime / @deepseek-ai/dsh-client-ui-primitives stay as module-table externals; markstream-react/index.css is compiled and injected as a tagged data-plugin-css style.lib/index.js / lib/invariant.js — the Node halves (plus config.js / schema.js staged by stage-node; Node resolves the plain .js relative imports; @deepseek-ai/dsh-settings / @deepseek-ai/schemastery stay external).lib/types/**/*.d.ts — declarations.@deepseek-ai/* types come from the auto-installed npm peers (0.1.0-rc.8, the same release the deployed GUI runs); at runtime the DSH client module table provides them.
This package declares dsh.bundle.patch, so it installs through the official CLI channel:
dsh plugin --profile web add dsh-markstream
For an unpublished local package, wire it manually (local ~/.dsh/profiles/web):
Add the package to the profile dependencies and install (heal node_modules). For local development use link:: file: makes pnpm pack and copy the package, so every plugin edit needs a reinstall; link: is a symlink, so after pnpm build rebuilds lib/client.js the server serves the new file directly (client-hmr picks up the change and hot-reloads without a restart):
# edit ~/.dsh/profiles/web/package.json
# "dependencies": { "dsh-markstream": "link:D:/path/to/dsh-markstream" }
# "dsh": { "profile": { "bundles": [ ..., "dsh-markstream" ] } }
cd ~/.dsh/profiles/web && pnpm install
Restart dsh web and refresh the page. The plugin row mounts through the insert in cordis.patch.yml; you can also append it manually to the profile's cordis.patch.yml:
- insert:
- id: markstream
name: 'dsh-markstream'
| Feature | Package | Notes |
|---|---|---|
| Enhanced code blocks | stream-diffs (bundled dependency) |
File/FileDiff surface + syntax highlighting; registered theme names resolve exact colors, unregistered names fall back through the documented seam (--markstream-code-fallback-*) to the selected theme's bg/fg |
| Mermaid diagrams | mermaid |
Mermaid blocks degrade when absent |
| KaTeX math | katex |
Inlined with the @deepseek-ai/dsh-client-ui-primitives dependency tree in the current build |
| D2 diagrams | @terrastruct/d2 |
Unresolved at build time, treated as external (only needed when rendering d2 blocks) |
| Infographics | @antv/infographic |
Same, treated as external |
MarkdownRender independently (matching the shipped per-block renderer); Markdown structures split across text blocks (e.g. a code fence spanning two blocks) are not merged.MarkdownText's fileMentions inline-code highlighting is not replicated in v1 (markstream renders them as plain inline code).assistant-step is a keyed slot, so registering the same key replaces the shipped implementation wholesale; this plugin replicates text / reasoning / image / unknown-block / stopped-marker presentation, but later product changes are not synced automatically.enabled / theme / …); writes persist to $DSH_HOME/settings.yaml.CLASSIFICATION EVIDENCE
系统优先读取 GitHub Topics,再与站内分类词典和词根规则比对。当前命中: 无有效分类标签。