DeepSeek Harness Plugin Hub

Publish and manage complete Harness Profiles. Discover Plugins for your next setup.

Explore

PluginsPresetsDocsNews

Community

Publish a pluginContactReport an issue

Resources

Plugin Hub on GitHubDeepSeek HarnessSystem statusPrivacy notice
© 2026 DeepSeek Harness Plugin HubPowered byPaxTech

Independent and unofficial. Not affiliated with, authorized by, or endorsed by DeepSeek.

Dschat — DSH Plugin for DeepSeek Harness
← Plugins
D

dsh-dschat

Dschat

Chat with DeepSeek's web端 (chat.deepseek.com) inside DeepSeek Harness as a native panel, then distill or replay the conversation into a new harness session.

The plugin will be installed here. Keep web if you are unsure.

npx -y @deepseek-ai/dsh plugin --profile web add github:CLnum42/dsh-DSchat#75b949f3bd13f4e77b772d503bfa941346f37c9f
READMECompatibilityVersions
dsh-DSchat 面板(浅色)dsh-DSchat 面板(深色)思考用时 / 引用芯片 / 参考来源

Compatibility and provenance

Dschat is published as dsh-dschat and currently resolves to version 0.12.0. The Hub verifies its manifest and preserves the exact installation source for reproducible installs.

DSH compatibility
*
Runtime surfaces
web
Release source
github
Registry updated
10/14/2026

Versions

0.12.0stable
10/14/2026
0.8.1stable
10/12/2026
0.7.0stable
10/10/2026
Show 4 more versionsCollapse versions
0.6.2stable
10/10/2026
0.6.1stable
10/10/2026
0.4.2stable
10/10/2026
0.3.10stable
10/4/2026

Related plugins

Loading related plugins…

Latest
0.12.0
DSH
*
HMR
Process restart
Tree shaking
Safe tree shaking not declared
Unpacked size
Unavailable
Files
Unavailable
Surface
web
License
Apache-2.0
Source
github
GitHub
★ 1
Weekly downloads
0
Last push
10/14/2026
View source ↗
README badge

Click the badge to copy Markdown for your README.

Do you maintain this Plugin?Claim benefit · Priority security scan

Verify the GitHub repository declared in package.json to manage this listing. After you claim it, Hub will prioritize a security scan of the current version and publish the result when it passes.

Claim this Plugin →
Report an issue
DeepSeek Harness Plugin Hub
ProfilesPluginsCategoriesNewsDocsSign inManage Profiles
ProfilesPluginsCategoriesNewsDocsSign in

Related plugins

More verified plugins in integrations-communication.

Acp App@deepseek-ai/dsh-acp-appThe dsh ACP profile bundle: automation-only JSON-RPC stdio and process lifecycle over dsh-baseAb Publishdsh-ab-publishBrowser-automation publishing tool that logs into and posts to arbitrary websites, in one publishable plugin packageAb Wechat Scrapedsh-ab-wechat-scrape--- description: "The out-of-tree wechat_scrape tool: retrieves WeChat official-account articles, filters promotional blocks, and saves each as a Markdown file, for maintainers of this machine's dsh profiles." kind: "package-reference" ---Im@xmanrui/dsh-im把微信、飞书、企微、钉钉、QQ、Telegram、WhatsApp、Slack、Discord、Matrix接入DSH。 Connect Telegram, WhatsApp, Slack, Discord, Matrix, WeChat, Feishu, WeCom, DingTalk, and QQ to DSH.

README

dsh-DSchat

中文

在 DeepSeek Harness 的原生面板里聊 DeepSeek 网页端(chat.deepseek.com),聊完把整段对话迁移成 harness 会话继续开发。复用你的网页登录,不消耗 API 额度。

包名 dsh-dschat(npm 强制小写),界面上显示为 dsh-DSchat;面板文案跟随 Harness 的界面语言,在中文与 英文之间自动切换。

浅色深色
dsh-DSchat 面板(浅色)dsh-DSchat 面板(深色)

思考用时、正文里的 [citation:N] 芯片、默认收起的参考来源:

思考用时 / 引用芯片 / 参考来源

图是真实组件在真实浏览器 + DSH 自己的主题表里渲染出来的(node scripts/ui-shot.mjs --synthetic), 会话内容是合成样例,公开的图里不会出现任何人的真实对话。

能做什么

  • 网页聊天:真实浏览器驱动 chat.deepseek.com,流式回复,可切「深度思考」与「智能搜索」。 打开侧栏的「聊天」就会自动启动网页端,不需要先在输入框或面板上点一次「重试启动」;启动失败时原因与 重试按钮就在对话里,成功前的长时间启动窗口由状态灯与「正在启动网页端…」说明。
  • 提问导航:消息区右缘一列刻度,一条提问一道;悬停展开成提问清单,点一下跳到那一条。
  • 新提问置顶:发出去的问题被顶到消息区顶端,回答在下面长出来,不用滚就能从第一行读起。答案还短于视口时 浏览器顶不到顶,面板就让它停在能停的位置,不去和滚动较劲;手动滚动、切换会话或从导航跳走都会解除锚点。 不在底部时右下浮出「↓ 最新」。
  • 回答下的操作栏:每条回答正下方一排按钮,与 chat.deepseek.com 一致 —— 复制 · 重新生成 · 喜欢 · 不喜欢 · 分享,然后用一条竖线隔开本插件自己的「复制思考过程」与「引用到输入框」(不做「朗读」:面板 没有音频出口)。回答还在生成的时候,这一排不存在:流式没有停止之前整排不渲染(半句话上的「复制」、 网页端还没有这一轮的「分享」,都是不该点得到的),回答一停就出现 —— 正常结束、手动「停止」、失败留下的 部分回答都算停。用户自己的消息也一样:复制 / 重新编辑就在气泡下面,不再悬停在气泡左侧。
    • 重新生成:把这条回答对应的问题重新发给网页端并替换旧回答(旧回答在网页端接下这一轮之后才删)。
    • 喜欢 / 不喜欢:评价落到网页端账号上,界面上的按钮同步显示本次会话的选择。网页端的「不喜欢」是 一个必填原因的反馈弹窗,所以本插件先问一次原因(有害不安全 / 虚假信息 / 没有帮助 / 其他 + 可选说明)再提交。
    • 分享:在网页端创建一条公开链接(与官方一致:任何拿到链接的人都能查看,无需登录)。点「分享」会先 打开一个问答选择器:默认勾中你点的那一组(和网页端点一次分享一样),可以继续勾别的组、也可以全选; 正文就是官方那句公开警告,确认后插件驱动网页端完成「进选择模式 → 勾选其余问答 → 创建并复制」,把链接给你; 链接可以在网页端「设置 → 数据管理」里删除。创建前会核对网页端自己数出来的「已选择 N 组对话」,对不上就 什么都不发;链接没读回来时会明说「可能已创建」并指路去删。
    • 评价要在网页端定位到那条回答,靠的是内容比对,对不上就不点并说明原因 —— 网页端是虚拟列表,按序号 点有评错别人回答的风险。
  • 附件:📎 走 macOS 原生文件对话框,也支持拖拽与粘贴;图片显示缩略图(单文件 ≤ 24 MB,单条 ≤ 10 个)。
  • 排队而不是被拒:回复还在生成时输入的消息会排队,上一轮结束自动发出。
  • 接力:输入框上方那排按钮里的「⇄ 接力」把这段网页对话蒸馏成任务简报(或按原文迁移),新建 harness 会话或追加到已有会话,可指定工作区。接力过去的上下文只有用户⇄模型的对话:R1 思考块被丢掉, [citation:N] / [reference:N] 标记被清掉,「参考来源」列表不跟着走。「导出 markdown」同样如此 —— 导出文件是这场问答本身的记录:用户问了什么、DeepSeek 答了什么,不再带上搜索来源与思考过程。 (按钮 0.12 之前叫「DSH 迁移」,右边那个展开箭头也去掉了:它开的是一个弹出菜单,不是折叠区。)
  • 置顶会话:会话列表里每条右侧有一个图钉,钉住的会话排到列表最上面、单独一组「置顶」,跟网页端侧栏 一样。钉住只是排列,不动会话的更新时间,也不影响下面的按时间排序。点「从网页同步」会按网页端账号的 置顶状态对齐(网页上钉了的会钉上,网页上没有的会取消)——置顶状态本身在网页账号上,这里只是镜像。
  • 从网页同步:把网页端的对话增量收进本地,成为可搜索、可迁移的记录 —— 已有的消息保留本地的 id、时间与 思考用时,只补缺失的那些,被截断的回复就地补全。会话列表读的是网页端自己的会话接口(不是侧栏 DOM), 所以整账号的会话都在。同步会分两步:先按网页端对齐置顶状态与每条会话的真实时间、并把旧版本留下的 重复记录合并成一条(这一步只读一次会话列表,不读任何会话内容,也不改写你原有记录的文字),再补没收过 的会话内容。列表按「最近使用」从新到旧排列,置顶的一律在上。 在面板里聊过的会话会记住自己的网页 session id,同步时按 id 合并回同一条记录,不会再多出一条同名的。
  • 导出 markdown:对话下面那排按钮的最后一个(箭头落入托盘那个图标,标签「导出」),选好要导出的问答 后写到对话框里那个文件夹(默认 ~/Downloads,可配置)。对话框里可以直接选文件夹(系统选择窗口), 也可以手动改路径;改过一次之后默认就是它,直到你下次再改 —— 这个选择记在 host 侧,重启也还在。 选择器默认全选,取消某一组时问题和回答一起取消;只导一部分时文件名带 -选中N条,不会覆盖整篇导出 的那份。文件里只有用户的问题与 DeepSeek 的回答。
  • 思考过程:回答上方的「已思考(用时 …)」一行,点开是完整推理(最高 340px,超出可滚),再点正文收起; 展开与收起是 200ms 的折叠动画,不是瞬间切换,并且跟随系统的「减少动态效果」设置。
  • 运行状态:··· 菜单里的诊断卡,看引擎、登录、浏览器与错误原因。

安装

用 DSH 自带的插件安装器(不要手改 profile,也不要在 profile 里跑 pnpm)。两种装法都能用,区别只在于谁 来准备插件自己的依赖:

方式一 · tarball(交付、给别人装)

npm pack --pack-destination ~/.dsh/dschat-dist    # 打成 tarball
plugin_manager action=install_bundle target=file:<tarball 绝对路径>

pnpm 会把插件自己的依赖(playwright-core)装进 profile 的 node_modules,这条路径不需要你先做什么。

方式二 · link:(开发;本机 desktop profile 现在就是这么装的)

cd <插件源码目录> && npm install --ignore-scripts   # 先在插件目录装好依赖
plugin_manager action=install_bundle target=link:<插件源码目录绝对路径>

link: 能正常工作的前提只有一个:插件目录自己有一份 node_modules。插件是按真实路径解析第三方 依赖的,playwright-core 从这一份里取,@deepseek-ai/* 由宿主提供;少了它才会出现 1 required plugin did not activate。

早先这里写的是「必须用 tarball,符号链接解析不到依赖」,那个结论是错的。2026-10-01 那次起不来的 真实原因写在崩溃日志里:client-modules: dsh-dschat dsh.client.platform must be a string —— package.json 的 dsh.client.platform 缺失,跟 link: 没有关系,现在已修。

确认装上了:重启 DSH 后面板能打开,或者

curl -s http://127.0.0.1:57531/api/dsh-dschat/state | head -c 120

返回以 {"ok":true 开头就是装载成功。

起不来怎么办

插件是声明式装载的:任何一个插件在 apply() 里抛异常,整个 profile 都可能装不起来。真遇到时按顺序做:

  1. 看日志:~/Library/Logs/DeepSeek Harness/ 里最新的一份,搜 dsh-dschat。 1 required plugin did not activate 这类消息后面通常紧跟真正的原因。
  2. 先停用、别急着删:在插件管理器里把 dsh-DSchat 停用,或把它在 profile composition 里的那一段 (- id: dschat / name: 'dsh-dschat')注释掉,让 DSH 先起来。
  3. 数据是安全的:对话记录在 ~/.dsh/dsh-dschat/transcripts.json,附件在同目录的 attachments/, 都与插件能否装载无关;读不出来时插件会把原文件改名备份成 transcripts.json.corrupt-<时间戳>, 不会覆盖它。

使用

  1. 侧边栏点「聊天」打开面板;第一次发消息时会在弹出的浏览器窗口里完成一次 DeepSeek 网页登录。
  2. 直接输入即可(Enter 发送,Shift+Enter 换行);输入框在引擎没起来时也能打字,点它就会在后台把网页端拉起来。
  3. 聊完点输入框上方的「接力」→ 选方式与目标 → 先看预览再写入:预览框里是即将成为新会话首条消息的 完整文本,可以直接改;确认后才创建会话,并自动打开它。如果蒸馏不可用(没有可用的模型),预览会明确写出 「本次为原文完整迁移」,不会再和成功蒸馏弹出同一句提示。
  4. 左侧「会话列表」是本机记录;左下「从网页同步」把网页端还没同步的会话收进来,某一条想单独补全就点它右侧的 同步按钮;agent 侧同样可以 dschat_recover。其余工具:dschat_status / dschat_send / dschat_stop / dschat_import / dschat_transfer(默认也只返回预览,用户确认后带 confirm: true 再调用一次才写入)。
  5. 出问题时打开 ··· → 「运行状态」 → 复制诊断:一次带上运行版本与构建时间、引擎与登录状态、最后的 错误(含错误码)、数据/配置目录,以及网页端的实时探测结果,直接贴进反馈即可。网页端没起来、没登录或 出错时,会话末尾也会出现对应的提示卡,每张卡带一个能真正解决问题的按钮(重试启动 / 打开登录窗口)。

配置

这一版没有自带设置表单:插件不注册 plugins.row.config 页面,插件页里不会为它渲染任何表单。配置来自 profile 的 cordis.patch.yml —— 在 dschat 那一行(name: 'dsh-dschat')下面加 config: 块,重启生效:

- id: dschat
  config: { browserHeadless: false, exportDir: ~/Notes }
键默认说明
enabledtrue插件总开关
announceToAgentfalse是否在 system prompt 里加一行说明这组工具。默认关闭:工具的 description 已自带触发词与用法,而提示词由每个会话、每个子 agent 共同承担
browserChannelautochrome / msedge / chromium / auto
browserExecutablePath空自备 Chromium 时可执行文件路径
browserProxydirectdirect 或代理地址
browserHeadlesstrue登录窗口不受它影响,始终可见
replyTimeoutMs180000单次回复超时(毫秒)
dataDir空数据目录(对话记录),空则 ~/.dsh/dsh-dschat
profileDir空浏览器 profile(登录态),空则复用 dsh-webchat 的目录
exportDir空导出目录的默认值,空则 ~/Downloads;相对路径按家目录解析。读者在导出对话框里选过的目录优先于它(记在 host 侧,重启还在)
transferDistilltrue迁移默认蒸馏成简报,false 为按原文迁移
transferProvider / transferModel空蒸馏用的模型,空则自动挑(优先名带 deepseek 的 provider 与带 chat 的模型)
transferMaxTokens / transferChunkTokens4096 / 1024蒸馏的输出与分块上限

已知限制

  • 依赖本机浏览器 + 网页登录态,没有 API Key 就不能工作;官网风控、改版或登录失效时会明确报错,而不是静默失败。
  • 网页端一次只回答一个问题,所以第二条消息只能排队。
  • 浏览器 profile 默认复用 ~/.dsh/dsh-webchat/browser-profile —— 从 dsh-webchat 切过来不用重新登录; 两个插件同时开着会争同一份 profile。
  • 网页端解析在 DOM 层,官网大改结构时可能读不到内容(此时会报解析失败)。
  • 本地 HTTP 接口只接受回环地址 + POST + 同源 + 每次运行生成的 CSRF 令牌(面板会自动带上)。所以面板 之外的脚本要调用它,得先 GET /api/dsh-dschat/state 取 csrfToken,再在后续请求里带 x-dschat-token 头;这是为了挡住本机其他网页用一张 <img> 就把记录清掉。
  • 附件只接受图片、文档与文本(有扩展名白名单),单个上限 24 MB、一次最多 10 个、单次总量 48 MB; /send 还要求路径落在插件自己的 attachments/ 目录内(agent 的 dschat_send 不受目录限制,但同样 受类型与大小规则约束)。
  • 同一份会话记录同时只允许一个实例写入:第一个 DSH 还开着时再开一个,第二个会转为只读并在「运行状态」 里说明原因与处置办法(否则两个实例会互相整份覆盖)。崩溃留下的锁会被自动接管,正常退出会交还。
  • 面板的 1.5 秒轮询只取会话摘要(标题/时间/条数),正文按需从 GET /api/dsh-dschat/chat?id= 取 —— 这是把轮询流量从 MiB 级降到 KB 级的原因。脚本要搜会话请用 GET /api/dsh-dschat/search-conversations?q=,它返回会话 id,不返回正文。

开发

npm install --ignore-scripts   # 依赖(含 @deepseek-ai/* 的类型,供类型检查用)
npm run build                  # 产出 lib/index.js(Host)与 lib/client.js(浏览器)
npm run typecheck              # tsc --noEmit,覆盖 src/(strict)
npm test                       # node --test,180 个用例,含真实浏览器 e2e

typecheck 只覆盖 src/(发布产物由它构建);test/ 是直接用 Node 的类型擦除运行的 ESM TypeScript,由执行验证,不参与类型检查。

⚠️ 链接安装(link:)时不要把 @deepseek-ai/* 装进插件自己的 node_modules。共享实例的 dsh 包必须由宿主提供:profile 内的副本会按「profile > runtime」的优先级遮蔽宿主版本。本仓库把 它们写在 devDependencies(只为类型检查),如果你把这份 checkout 以 link: 方式装进了正在使用的 profile,请在另一份 clone 里跑类型检查,或先 dsh plugin remove,避免副本进入运行期解析路径。

相关

引擎、网页端解析、蒸馏与迁移机制沿用 Apache-2.0 的 dsh-webchat;界面已重写为 DSH 原生面板(main 与 sidebar.panellist 两个槽位),命名空间独立成 dsh-dschat,两个插件可以共存。许可:Apache-2.0。

English

Chat with DeepSeek's web app (chat.deepseek.com) inside a native DeepSeek Harness panel, then hand the whole conversation off to a harness session and keep building on it. It reuses your browser sign-in, so no API credit is spent.

The npm package is dsh-dschat (npm forces lowercase); the product appears as dsh-DSchat. Every string in the panel follows the Harness UI language and switches between Chinese and English on its own.

LightDark
The dsh-DSchat panel, light themeThe dsh-DSchat panel, dark theme

Thinking time, the [citation:N] chips in the body, and the source list (collapsed by default):

Thinking time / citation chips / sources

These are real components rendered in a real browser with DSH's own theme tokens (node scripts/ui-shot.mjs --synthetic). The conversations shown are synthetic samples; no real user conversation appears in any published screenshot.

What it does

  • Web chat: a real browser drives chat.deepseek.com with streaming replies, plus the Deep think and Smart search toggles. Opening the sidebar's Chat row starts the web page by itself — no need to click into the composer or press 「Retry start」 first. A failed start puts its reason and a retry button in the conversation.
  • Question navigator: a tick rail down the right edge of the message area, one tick per question; hover to expand the list of questions, click to jump to one.
  • New questions anchor to the top: after a send, the question you just asked is placed at the top of the message area and the answer grows below it, so reading starts at line one without scrolling. When the answer below is still shorter than the viewport the browser cannot lift the question all the way up, and the panel deliberately does not fight that. Scrolling by hand, switching conversations, or jumping away releases the anchor. A Latest pill floats up whenever you are not at the bottom.
  • Actions under every answer: a row directly beneath each reply, matching chat.deepseek.com — copy · regenerate · like · dislike · share, plus this plugin's own 复制思考过程 / 引用到输入框 (朗读 is deliberately not carried: the panel has no audio surface).
    • Regenerate re-asks the question on the web page and replaces the stored answer.
    • Like / dislike lands on your DeepSeek web account, and the buttons show what this session sent. The page's dislike is a reason dialog, so the panel asks for the reason first (harmful / false / not helpful / other, plus an optional note) and submits both.
    • Share creates a public link on the web app (as the official control does: anyone with the link can view it, no sign-in). Clicking it opens a Q&A picker with the exchange you clicked already ticked — the web app's own behaviour — where you can add more exchanges or select everything; the card carries the web app's public-link warning, and confirming drives the page through selection mode → create-and-copy and hands you the URL. Before anything is created the page's own "N conversations selected" count is checked against your list: a mismatch publishes nothing. Links can be deleted in the web app under Settings → Data; if the URL cannot be read back, the panel says the link MAY exist and where to remove it.
    • Ratings are located in the page by content comparison, never by position: the page is virtualized, and rating the wrong answer would be invisible and unrecoverable. If the answer cannot be found, nothing is clicked.
  • Queue instead of refusal: messages typed while a reply is still generating wait in a queue and go out when the previous turn ends.

Installation

Use DSH's own plugin installer (do not hand-edit the profile, and do not run pnpm inside it). Both install forms work; the only difference is who prepares the plugin's own dependencies.

Option 1 — tarball (shipping it to someone else)

npm pack --pack-destination ~/.dsh/dschat-dist    # build a tarball
plugin_manager action=install_bundle target=file:<absolute tarball path>

pnpm installs the plugin's own dependency (playwright-core) into the profile's node_modules, so nothing has to be prepared first.

Option 2 — link: (development; what this machine's desktop profile uses today)

cd <plugin checkout> && npm install --ignore-scripts   # install the plugin's deps first
plugin_manager action=install_bundle target=link:<absolute plugin checkout path>

A link: install works as long as the plugin directory has its own node_modules: third-party imports resolve from the real path, so playwright-core comes from there while @deepseek-ai/* comes from the host. Without it the symptom is 1 required plugin did not activate.

This section used to say "install from the tarball, never with link:, because a symlink cannot resolve its dependencies" — that was wrong. The 2026-10-01 startup failure says what it really was, in the crash log: client-modules: dsh-dschat dsh.client.platform must be a string — a missing dsh.client.platform in package.json, nothing to do with link:. It is fixed.

Confirm it loaded: restart DSH and open the panel, or

curl -s http://127.0.0.1:57531/api/dsh-dschat/state | head -c 120

An answer starting with {"ok":true means it mounted.

When Harness will not start

Loading is declarative: a plugin that throws inside apply() can take the whole profile down with it. In order:

  1. Read the log: the newest file under ~/Library/Logs/DeepSeek Harness/, searching for dsh-dschat. 1 required plugin did not activate is usually followed by the real cause.
  2. Disable it rather than deleting it: turn dsh-DSchat off in the plugin manager, or comment out its entry (- id: dschat / name: 'dsh-dschat') in the profile composition, so Harness starts again.
  3. Your data is safe: transcripts live in ~/.dsh/dsh-dschat/transcripts.json and attachments in attachments/ beside it, independent of whether the plugin loads. An unreadable store is renamed to transcripts.json.corrupt-<timestamp> rather than overwritten.

Usage

  1. Click Chat in the sidebar to open the panel. The first message starts a browser window where you sign in to DeepSeek web once.
  2. Just type (Enter sends, Shift+Enter inserts a newline). The composer accepts text even while the engine is down — clicking it brings the web app up in the background.
  3. When you are done, click Hand off (「接力」 in Chinese) above the composer, pick a mode and a target, then read the preview before writing: it shows the exact first message the new session will get, and you can edit it. The session is created only when you confirm, and it opens by itself afterwards. If distillation was unavailable, the preview says so plainly ("the raw conversation") instead of arriving as the same success message a real brief produces.
  4. The conversation list on the left is the local record; Sync from web at its foot pulls in web conversations that are not here yet, and the sync button on a row completes that one alone. Agents can do the same through dschat_recover; the other tools are dschat_status, dschat_send, dschat_stop, dschat_import and dschat_transfer (which also previews by default and writes only on a second call with confirm: true).
  5. When something goes wrong, open ··· → Status → Copy diagnostics: one click carrying the running version and build time, the engine and sign-in state, the last error with its code, the data and configuration paths, and a live probe of the web page — ready to paste into a report. A web page that is down, signed out or broken also names itself at the end of the conversation, with the button that fixes it (retry / open the sign-in window).

Configuration

This build ships no settings form: the plugin registers no plugins.row.config page, so the Plugins page renders no form for it. Configuration lives in the profile's cordis.patch.yml — add a config: block under the dschat row (the one with name: 'dsh-dschat') and restart Harness:

- id: dschat
  config: { browserHeadless: false, exportDir: ~/Notes }
KeyDefaultMeaning
enabledtrueMaster switch for the plugin
announceToAgentfalseAdd one line naming these tools to the system prompt. Off by default: each tool's own description already carries its trigger words and usage, and prompt text is paid by every session and every subagent
browserChannelautochrome / msedge / chromium / auto
browserExecutablePathemptyPath to your own Chromium build
browserProxydirectdirect or a proxy URL
browserHeadlesstrueThe sign-in window ignores it and stays visible
replyTimeoutMs180000Timeout for a single reply (ms)
dataDiremptyTranscript directory; defaults to ~/.dsh/dsh-dschat
profileDiremptyBrowser profile (sign-in); defaults to the dsh-webchat one
exportDiremptyThe export folder's default; ~/Downloads when empty, relative paths resolve against home. A folder chosen in the export dialog outranks it (stored host-side, kept across restarts)
transferDistilltrueHand-offs distill by default; false replays the transcript
transferProvider / transferModelemptyDistillation model; empty auto-picks (a deepseek provider, a chat model)
transferMaxTokens / transferChunkTokens4096 / 1024Output and per-chunk token caps

Known limits

  • It needs a local browser plus a web sign-in; without one it cannot work at all. Vendor rate-limiting, a page redesign, or an expired session produce an explicit error rather than a silent failure.
  • The web app answers one question at a time, so a second message can only queue.
  • The browser profile defaults to ~/.dsh/dsh-webchat/browser-profile, so switching over from dsh-webchat needs no second sign-in; running both plugins at once makes them share it.
  • Parsing happens at the DOM layer, so a major redesign of the site can leave nothing to read (reported as a parse failure).
  • The local HTTP routes accept loopback + POST + same origin + a per-run CSRF token only (the panel sends it automatically). A script outside the panel must read csrfToken from GET /api/dsh-dschat/state and send it back in x-dschat-token; that is what stops another page on this machine from clearing your history with one <img> tag.
  • Attachments are limited to images, documents and text (an extension allow-list): 24 MB each, 10 per message, 48 MB per turn. /send additionally requires the path to be inside the plugin's own attachments/ directory; the agent's dschat_send is not confined to that directory but obeys the same type and size rules.
  • Only ONE instance may write a transcript store at a time: start a second Harness while the first is running and it turns read-only, saying why in the status card (two writers would each overwrite the other's whole history). A lock left by a crash is taken over automatically, and a clean shutdown hands it back.
  • The 1.5 s poll carries conversation SUMMARIES only (title, times, counts); a body is fetched on demand from GET /api/dsh-dschat/chat?id= — which is what took the poll from megabytes to kilobytes. Scripts that want to search conversations should use GET /api/dsh-dschat/search-conversations?q=, which answers ids, not bodies.

Development

npm install --ignore-scripts   # deps, including the @deepseek-ai/* types typechecking needs
npm run build                  # writes lib/index.js (host) and lib/client.js (browser)
npm run typecheck              # tsc --noEmit over src/ (strict)
npm test                       # node --test, 180 cases including real-browser e2e

typecheck covers src/ only — that is what ships, and what lib/ is built from. test/ is ESM TypeScript run directly by Node's type stripping and is verified by EXECUTION, not by the compiler.

⚠️ With a link: install, do not put @deepseek-ai/* into this checkout's own node_modules. Packages that must be a single shared instance come from the host: a copy inside the profile shadows the runtime one (profile > runtime). They are listed under devDependencies here purely so typechecking can resolve them, so if this checkout is linked into the profile you are running, typecheck from a separate clone — or dsh plugin remove first — instead of npm install-ing copies into the live resolution path.

Related

The engine, the web-page parsing, and the distillation/hand-off machinery come from the Apache-2.0 dsh-webchat plugin. The UI is rewritten as a native DSH panel (the main and sidebar.panellist slots) under the independent dsh-dschat namespace, so both plugins can be installed side by side. License: Apache-2.0.

  • Hand off: the Hand off menu (「接力」 in Chinese; it was called "Migrate to DSH" before 0.12, and the disclosure arrow is gone — it opens a popup, not a fold) distills the web conversation into a task brief (or replays it verbatim) and either starts a new harness session or appends to an existing one, optionally inside a workspace you pick. What crosses over is only the user⇄model conversation: the R1 reasoning block is dropped, [citation:N] / [reference:N] markers are removed, and the search-source list is not transferred. Export markdown works the same way — the exported file is a record of the exchange itself: what you asked and what DeepSeek answered, with no search sources and no reasoning block.
  • Pin conversations: every row in the conversation list carries a pin. Pinned conversations move to the top in their own Pinned block, the way the web sidebar does it. Pinning only rearranges the list — it does not touch a conversation's update time, so unpinning later does not leave the row sitting at the top of the recent list. Sync from web aligns the pins with the web account (pinned there → pinned here, not pinned there → unpinned here): the pins live on the web account, and this side mirrors them.
  • Sync from web: pulls web conversations into the local store incrementally, so they become searchable and transferable. Messages already stored keep their local ids, timestamps and thinking time; only what was missing is appended, and a truncated reply is completed in place. The list is read from the web's own conversation endpoint rather than from the rendered sidebar, so every conversation in the account is there. A sync has two steps: first it aligns the pins and each conversation's real time with the web and folds the duplicate rows older versions left behind into one (one list read, no conversation bodies, and no rewriting of the messages you already had), then it imports the ones never seen here. The list itself is ordered most-recently-used first, with the pinned rows above everything. A conversation you chatted in from the panel remembers its web session id, so syncing merges into that same row instead of adding a second copy of it.
  • Export markdown: the last button on the row under the conversation (the arrow-into-tray glyph, labelled Export). It opens the same Q&A picker, everything ticked by default; clearing one exchange clears its question and answer together, and a partial export is named …-选中N条.md so it cannot overwrite the whole-conversation file. The dialog carries an Export to row: choose a folder with the system picker or edit the path by hand, and that folder becomes the default from then on — the choice is stored on the host side, so it survives a restart. User questions and DeepSeek answers only.
  • Reasoning: the "Thought for …" line above an answer unfolds into the full reasoning (capped at 340px, then it scrolls) and folds back when you press the text. Both directions are a 200ms fold rather than an instant swap, and they honour the system's reduce-motion setting.
  • Runtime status: a diagnostic card in the ··· menu covering the engine, the sign-in, the browser, and the last error.