dsh-session-port
把会话连同附件导出为压缩包,或把这样的压缩包导入为当前工作区里的新会话。
安装
dsh plugin --profile web add dsh-session-port
沙箱测试结果
| 阶段 | 结果 |
|---|---|
| 1 安装 | ✓ |
| 2 列装 | ✓ |
| 3 挂载 | ✓ |
| 4 启动 | — |
四阶段在隔离沙箱里跑:安装(有网)→ 列装 → 挂载 → 启动(后三步断网)。
README
dsh-session-port · 会话导入导出
DeepSeek Harness plugin: export a session as a ZIP archive (attachments included) or import an
exported session back as a new conversation. Archive layout is byte-compatible with DSH's
built-in "Download session log" export.
把 DSH 的会话导出成压缩包带在身边,或把导出的会话导入成新会话继续用。
附件(截图、文件)随会话一起搬运。
安装
已发布到 npm 与 GitHub。安装方式取决于部署形态:
桌面版(DeepSeek Harness Desktop)——图形界面
桌面版不提供 dsh 命令行,插件在设置里安装:
1. 打开「设置 → 插件」,在插件列表或插件市场里找到 dsh-session-port 并安装
(bundle 名同为 dsh-session-port;已收录到 dshmarket 后可直接在市场里搜到);
2. 安装后重启桌面版应用(或刷新已打开的页面)。
Web / CLI 部署——命令行
自建 dsh web、CLI 或其它非桌面部署才有 dsh 命令;--profile 换成实际 profile
名(常见 web)。桌面版用户请用上面的图形界面方式,这一段不适用。
# 从 npm 安装(官方源;会自动写进 profile 的 bundles 列表) dsh plugin --profile web add dsh-session-port # 没装 dsh CLI 时用完整包名(npm 上那个 `dsh` 是同名旧包,不能用) npx @deepseek-ai/dsh plugin --profile web add dsh-session-port # 从 GitHub 仓库安装 dsh plugin --profile web add github:mswinandmc/dsh-session-port # 从本地打包安装(在仓库目录 `npm pack` 后,把生成的 .tgz 装进 profile) npm pack dsh plugin --profile web add '<repo>/dsh-session-port-<version>.tgz'
装好后用这些命令查看/升级/卸载:
dsh plugin --profile web list --depth 0 # 确认 dsh-session-port 在列表里 dsh plugin --profile web update dsh-session-port # 升级到 npm 最新版 dsh plugin --profile web remove dsh-session-port # 卸载
装好后重启 dsh 服务(或刷新已打开的页面),标题栏右侧出现导出按钮、
左侧栏全局导航里「插件」下方出现一行「导入会话」。
用起来
首次安装后需要刷新一次页面(F5 / Ctrl+R),页面才会加载插件的浏览器半边。
想做的事 · 操作
导出正在看的会话 · 打开会话 → 标题栏右侧的「导出」图标(↓)→ 浏览器下载 <标题>-<会话 id>.zip
导入一个会话 · 左侧栏「插件」下方那一行「导入会话」(↑)→ 打开导入面板 → 把 .zip / .jsonl 拖进去或点「选择文件…」→ 导入完成后点「打开会话」
导入的会话:
- 新建,绝不覆盖或删除已有会话;
- 落在当前会话所在的工作区(空闲时落在最近的工作区);
- 从原会话继承标题、完整对话与工具历史、模型/预设(预设在本机不存在时自动退回默认);
- 日志里指向原会话的内部标记(投递水位等)会自动改写成新会话,否则 DSH 会拒绝加载该会话的历史;
- fork/分支会话的继承标记(
session/end-seed {inherited:true})会被抹平,否则当前格式读取会以
「unseeded Session contains an inherited end-seed marker」拒绝打开——那是「导入成功、点开报错」的根因;
- 写完后会读回校验一次:DSH 自己打不开的会话会当场在结果里告警,而不是等用户点开才发现;
- 子会话(
subagents/)会随导出(与 DSH 自带导出一致),但导入只恢复主会话本身。
也可以用自然语言让本鲸帮忙,例如「把当前会话导出到 D 盘备份」——插件注册了 session_port 工具。
文件格式
导出格式与 DSH 自带的「下载会话日志」完全一致,两种来源的压缩包都能互相导入:
<标题>-<会话 id>.zip ├── session.v4.jsonl # 第一行会话头,随后每行一条会话事件 ├── subagents/<会话 id>/session.v4.jsonl # 每个子会话一份日志(与自带导出同名同层级) ├── media/<attachmentId>.<ext> # 会话(含子会话)引用的图片 └── files/<前缀>/<摘要>/<文件名> # 会话(含子会话)引用的文件
会话日志(.jsonl)本身就是合法的导入输入,便于人工检查或跨版本处理。
边界与已知限制
- 导入要求格式版本一致:v4 的压缩包导入当前 DSH;跨大版本请先用对应版本 DSH 打开再重新导出。
- 单次导入默认上限 512 MiB,可在插件配置里用
maxImportBytes调整。 - 解压有上限(防压缩炸弹):条目数 ≤ 20000、单条解压后 ≤ 512 MiB、解压后总计 ≤ 2 GiB,
且每条数据的实际解压大小必须与压缩包里声明的一致;超出或对不上按「ZIP 文件无法解析」拒绝。
- 导入只恢复主会话;子会话、会话收藏/置顶/归档等列表状态不迁移(子会话日志仍在压缩包里,可另行取用)。
- 会话的
cwd以当前工作区为准;原目录在本机不存在时不会被记录。 - 导出是流式的:归档逐条目写出,文件附件直接从磁盘流进压缩包,不会把整包和全部附件同时驻留内存;
代价是下载/写出中途失败时得到的是不完整文件(浏览器下载会丢弃,工具写出会删掉半成品)。
- 下载中断会取消导出:关掉标签页/断开连接时,路由立刻中止生产、关闭已打开的附件流,
不会留下一个永远挂起的导出任务;代理/工具侧的取消(exec.signal)同样会中止导出并删掉半成品。
配置(cordis.patch.yml 的插件行)
- id: session-port
name: dsh-session-port
config:
maxImportBytes: 536870912 # 单次导入上限,默认 512 MiB
includeAttachments: true # 导出时是否打包附件
sessionFormatVersion: 4 # 仅在会话库为空、无法自动探测时使用
exportDirectory: '' # agent 工具导出目录,默认 <DSH_HOME>/session-port/exports
实现
- 宿主端
index.js:/session-port/{info,export,import}认证路由 +session_port工具;
两个入口调用 lib/host.js 里的同一组实现,所以格式与失败语义不会分叉。
lib/host.js:导出走sessionQuery.readSession(与自带导出同一份已校验视图),并用
traceSession 把每个子会话按 subagents/<id>/ 写进同一个压缩包;openSessionExport
先解析出下载名/事件数/预检告警与附件计划,再按条目流式写包(浏览器路由和 agent 工具共用),
writeExportFile 直接流到磁盘、失败时删掉半成品。导入通过
sessionPersistence.create → append → flush → close 落盘,再挂到工作区,
最后用 readSession 读回校验一次。
lib/format.js:纯函数(JSONL 序列化/解析、附件引用收集与改写、文件名清洗),有单测。lib/zip.js:无依赖 ZIP 读写(基于node:zlib;读取带解压上限,写入支持增量流式 + 背压,
流式条目的字节从磁盘/服务直接进入压缩包),有单测。
lib/attachments.js:把附件引用解析成「打开器」,导出时一次只读一个附件;本地存储的文件
在计划阶段先 stat 预检,缺失/不可读的附件在响应头发出之前就降级为告警,其余读取失败在写入
该条目之前降级为告警。
client.js:没有@deepseek-ai/*运行时依赖的客户端半边,只用react与宿主主题变量。
导入入口注册成一行全局面板(main 键 + sidebar.panellist 行),所以侧栏里紧贴
「插件」下方、并与「插件 / 日程」一样是一行导航;点开是 session-port-import 导入面板。
验证
cd dsh-session-port node --test test/format.test.mjs # 16 项:JSONL 序列化/解析、附件引用、投递标记、继承标记、文件名 node --test test/host.test.mjs # 37 项:导出→导入往返、子会话打包、fork 标记抹平、写后校验、失败与取消路径 node --test test/client.test.mjs # 7 项:浏览器半边注册(面板行 + 插件行)、导入面板渲染(无浏览器沙箱) node --test test/abort.test.mjs # 5 项:断开/取消时的背压等待、稳定的取消错误码 node --test test/zip.test.mjs # 45 项:ZIP 读写、data descriptor 流式 zip、取消与损坏输入
已在本机完成的端到端验证:
- 用插件工具导出当前会话(948 条事件)→ 独立 Python
zipfile校验压缩包结构、JSONL 头与事件连续性; - 用插件工具把该压缩包导入回当前工作区 → 新会话落盘(
sessions/--D-hyw--/<新 id>/session.v4.jsonl.zstd,948 条事件、序号连续),并自动加入D:\hyw工作区的会话列表; - 浏览器路由已注册并通过 Connection 信任栅栏(未认证请求全部 401);
- 在真实桌面版页面里验收:侧栏全局导航order 依次为
插件(0) → 导入会话(5) → 日程(10),
点行打开导入面板、拖入 .zip 后显示「导入完成」并可一键打开新会话(0.2.0 起入口从脚底挪到此处)。
以上内容来自 npm 上的 README,我们只做格式化,不改内容。
版本
npm 上共发布:11,最后更新 2026-11-06