🎁 福利专区全网大模型免费应用 + 新用户福利 + 注册活动入口,低成本玩转 AI

聊天记录导入器 Nwflower/dsh-chat-import

DeepSeek Harnessv0.26.3
Nwflower0 天前有提交已提供中文文档扫描:含敏感能力需联网

基于 DeepSeek Harness 构建的会话导入插件:把其他 Agent 的聊天历史一键导入,接着在…

66.2/100
综合分
280
GitHub 星标
4,985
npm 周下载
—/5
用户评分

数据截至 2026/11/3 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。

安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add dsh-chat-import
npm 源 · dsh-chat-import 的发布者账号已校验与本仓库一致

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:已验证
是什么
dsh 原生插件 · chat
装得上吗
本站已在 dsh 0.2.1-rc.2 下真实安装成功
非静态推断
L5 · 运行时冒烟等级说明 →
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
活跃:最近一次提交在 0 天前
档位由哪些信号合成

本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。

验证判据与等级说明 →
社区实装还没有人打卡 · 装过的第一个就是你
安装兼容性检查✓ 自动检查通过
展开查看检查明细 ↓

以下结论由程序自动检查 npm 包、engines 声明与入口文件得出,未做人工实机验证——能装不等于用着没问题。

✓npm 包dsh-chat-import @ 0.26.3
✓Node 引擎要求 >=22.13 · 基线 Node 22.19 满足
✓dsh CLI 依赖要求 >=0.1.5-rc.1 · 最新 0.2.1-rc.5 兼容
✓入口文件main/exports/bin 已声明

验证方式:npm registry 存在性 + package.json 静态校验 · 最后检查 2026/11/2 15:39:48

安全扫描自动 · 静态分析源码
v2.7.0
🔵 扫描:含敏感能力尚无人工评估
展开查看扫描说明与证据 ↓

静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。

可执行外部命令读写/删除本地文件写入剪贴板(不计风险)发起外部网络请求
查看扫描证据(共 88 处,展示前 82 条)
  • 发起网络请求
    lib/client.js:1640
    const resp = await fetch(path, {
  • 写入剪贴板
    lib/client.js:3952
    await window.navigator.clipboard.writeText(lines.join("\n"));
  • 读取本地文件
    bin/dsh-chat-import.mjs:23
    const logs = (await readdir(dir))
  • 读取本地文件
    bin/dsh-chat-import.mjs:32
    const file = (await stat(path)).isDirectory() ? await sessionLogIn(path) : path
  • 读取本地文件
    bin/dsh-chat-import.mjs:33
    if (/ zstd$/i.test(file)) return decodeZstdText(await readFile(file))
  • 读取本地文件
    bin/dsh-chat-import.mjs:34
    return readFile(file, 'utf8')
  • 写入本地文件
    bin/dsh-chat-import.mjs:44
    await mkdir(dirname(outPath), { recursive: true })
  • 写入本地文件
    bin/dsh-chat-import.mjs:45
    await writeFile(outPath, md, 'utf8')
  • 读取本地文件
    lib/imports.mjs:60
    const parsed = JSON.parse(await readFile(join(registryDir, 'imports.json'), 'utf8'))
  • 写入本地文件
    lib/imports.mjs:160
    await mkdir(registryDir, { recursive: true })
  • 删除本地文件
    lib/command.mjs:292
    await rm(cacheFile, { force: true })
  • 读取本地文件
    lib/prompt-hint.mjs:26
    const parsed = JSON.parse(await readFile(join(registryDir, HINTS_FILE), 'utf8'))
  • 写入本地文件
    lib/prompt-hint.mjs:35
    await mkdir(registryDir, { recursive: true })
  • 写入本地文件
    lib/prompt-hint.mjs:36
    await writeFile(join(registryDir, HINTS_FILE), JSON.stringify(hints, null, 2) + '\n', 'utf8')
  • 读取本地文件
    lib/context-bridge.mjs:28
    names = readdirSync(dir).filter((n) => /\.md$/i.test(n))
  • 读取本地文件
    lib/context-bridge.mjs:46
    const st = statSync(file)
  • 读取本地文件
    lib/context-bridge.mjs:49
    contents.push({ name, text: readFileSync(file, 'utf8') })
  • 读取本地文件
    lib/context-bridge.mjs:76
    st = statSync(file)
  • 读取本地文件
    lib/context-bridge.mjs:85
    text = readFileSync(file, 'utf8')
  • 读取本地文件
    lib/context-bridge.mjs:100
    st = statSync(file)
  • 读取本地文件
    lib/skill.mjs:67
    const read = readFile || ((p) => readFileSync(p, 'utf8'))
  • 读取本地文件
    lib/sources/zcode.mjs:159
    if (metaPath !== filePath && existsSync(metaPath)) {
  • 读取本地文件
    lib/sources/zcode.mjs:161
    const meta = JSON.parse(readFileSync(metaPath, 'utf8'))
  • 读取本地文件
    lib/sources/zcode.mjs:169
    for (const line of readFileSync(filePath, 'utf8').split(/ ? /)) {
  • 读取本地文件
    lib/doctor.mjs:24
    buckets = await readdir(root, { withFileTypes: true })
  • 读取本地文件
    lib/doctor.mjs:32
    entries = await readdir(join(root, bucket.name), { withFileTypes: true })
  • 读取本地文件
    lib/sources/dsh.mjs:50
    return decodeZstdText(readFileSync(path))
  • 写入本地文件
    lib/atomic-write.mjs:21
    await rename(tmp, filePath)
  • 删除本地文件
    lib/atomic-write.mjs:23
    await rm(tmp, { force: true })
  • 读取本地文件
    lib/ignore.mjs:63
    const parsed = JSON.parse(await readFile(resolveIgnoreFile(registryDir), 'utf8'))
  • 写入本地文件
    lib/ignore.mjs:99
    await mkdir(registryDir, { recursive: true })
  • 读取本地文件
    lib/discovery-host.mjs:203
    return await readFile(typeof fs.processPath === 'function' ? fs.processPath(target) : path)
  • 读取本地文件
    lib/discovery-host.mjs:214
    : createReadStream(typeof fs.processPath === 'function' ? fs.processPath(target) : path, { encoding: 'utf8' })
  • 读取本地文件
    lib/session-actions.mjs:72
    if ((await stat(sibling)).isDirectory()) files.push(sibling)
  • 执行外部命令固定命令
    lib/session-actions.mjs:91
    execFile('powershell.exe', ['-NoProfile', '-NonInteractive', '-ExecutionPolicy', 'Bypass', '-Command', script], {
  • 写入本地文件
    lib/session-actions.mjs:99
    await mkdir(dir, { recursive: true })
  • 写入本地文件
    lib/session-actions.mjs:100
    for (const p of paths) await rename(p, join(dir, basename(p)))
  • 读取本地文件
    lib/session-actions.mjs:109
    const info = await stat(sourcePath)
  • 读取本地文件
    lib/session-search.mjs:105
    for await (const chunk of createReadStream(file, { start })) {
  • 读取本地文件
    lib/session-search.mjs:127
    const raw = await readFile(file, 'utf8')
  • 读取本地文件
    lib/session-search.mjs:154
    const data = JSON.parse(await readFile(this.file, 'utf8'))
  • 写入本地文件
    lib/session-search.mjs:159
    await mkdir(this.dir, { recursive: true })
  • 读取本地文件
    lib/session-search.mjs:182
    info = await stat(path)
  • 读取本地文件
    lib/session-search.mjs:195
    return await readFile(cache, 'utf8')
  • 写入本地文件
    lib/session-search.mjs:203
    if (text) await appendFile(cache, text, 'utf8')
  • 写入本地文件
    lib/session-search.mjs:207
    await writeFile(cache, text, 'utf8')
  • 写入本地文件
    lib/session-search.mjs:210
    await writeFile(cache, await extractWholeJson(path), 'utf8')
  • 读取本地文件
    lib/session-search.mjs:214
    return readFile(cache, 'utf8')
  • 删除本地文件递归
    lib/purge.mjs:96
    await rm(dir, { recursive: true, force: true })
  • 读取本地文件
    lib/purge.mjs:101
    await access(dir)
  • 读取本地文件
    lib/purge.mjs:113
    await access(path)
  • 读取本地文件
    lib/purge.mjs:126
    projects = await readdir(root, { withFileTypes: true })
  • 读取本地文件
    lib/purge.mjs:134
    await access(dir)
  • 读取本地文件
    lib/upload.mjs:68
    return JSON.parse(await readFile(manifestPath(registryDir, uploadId), 'utf8'))
  • 写入本地文件
    lib/upload.mjs:76
    await mkdir(join(uploadsDir(registryDir), manifest.uploadId), { recursive: true })
  • 写入本地文件
    lib/upload.mjs:79
    await writeFile(tmp, JSON.stringify(manifest), 'utf8')
  • 写入本地文件
    lib/upload.mjs:80
    await rename(tmp, file)
  • 读取本地文件
    lib/upload.mjs:87
    try { ids = await readdir(root) } catch { return null }
  • 读取本地文件
    lib/upload.mjs:98
    try { ids = await readdir(root) } catch { return 0 }
  • 写入本地文件
    lib/upload.mjs:149
    await writeFile(dataPath(registryDir, uploadId), Buffer.alloc(0))
  • 写入本地文件
    lib/upload.mjs:172
    await appendFile(dataPath(registryDir, uploadId), buffer)
  • 读取本地文件
    lib/upload.mjs:187
    const bytes = await readFile(dataPath(registryDir, uploadId))
  • 写入本地文件
    lib/upload.mjs:194
    await rename(dataPath(registryDir, uploadId), finalPath)
  • 读取本地文件
    lib/upload.mjs:209
    try { ids = await readdir(root) } catch { return 0 }
  • 删除本地文件递归
    lib/upload.mjs:213
    if (!m) { await rm(join(root, id), { recursive: true, force: true }); removed += 1; continue }
  • 删除本地文件递归
    lib/upload.mjs:216
    await rm(join(root, id), { recursive: true, force: true })
  • 删除本地文件递归
    lib/upload.mjs:233
    await rm(join(uploadsDir(registryDir), uploadId), { recursive: true, force: true })
  • 读取本地文件
    lib/upload.mjs:245
    try { ids = await readdir(root) } catch { return { removed: 0, kept: 0 } }
  • 删除本地文件递归
    lib/upload.mjs:252
    await rm(join(root, id), { recursive: true, force: true })
  • 写入本地文件
    lib/workspace-group.mjs:78
    await mkdir(dir, { recursive: true })
  • 读取本地文件
    lib/discovery/scan-cache.mjs:60
    const parsed = JSON.parse(await readFile(join(cacheDir, SCAN_CACHE_FILE), 'utf8'))
  • 写入本地文件
    lib/discovery/scan-cache.mjs:75
    await mkdir(cacheDir, { recursive: true })
  • 读取本地文件
    lib/cwd-map.mjs:203
    const profiles = await readdir(profilesDir, { withFileTypes: true })
  • 读取本地文件
    lib/cwd-map.mjs:208
    const parsed = JSON.parse(await readFile(file, 'utf8'))
  • 读取本地文件
    lib/sources/chromium-indexeddb.mjs:325
    return readdirSync(dir).sort()
  • 读取本地文件
    lib/sources/chromium-indexeddb.mjs:341
    buf = readFileSync(join(dir, name))
  • 读取本地文件
    lib/sources/chromium-indexeddb.mjs:354
    buf = readFileSync(join(dir, name))
  • 读取本地文件
    lib/sources/chromium-indexeddb.mjs:377
    return readdirSync(dir).filter((n) => n.endsWith('.ldb') || n.endsWith('.log')).sort()
  • 读取本地文件
    lib/sources/chromium-indexeddb.mjs:388
    const st = statSync(join(dir, name))
  • 读取本地文件
    lib/discovery/git-status.mjs:29
    const st = await fstat(dotGit)
  • 读取本地文件
    lib/discovery/git-status.mjs:33
    const content = (await fread(dotGit, 'utf8')).trim()
  • 读取本地文件
    lib/discovery/git-status.mjs:50
    const head = (await fread(join(gitDir, 'HEAD'), 'utf8')).trim()
扫描于 2026/11/3(0 天前) · 范围 入口闭包 + 全包扫描 · 来源 npm 发布包

静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。

⚠ 该插件运行需访问外部网络 / 远程 API,部署在国内无外网环境时可能无法正常使用。

依赖的 DSH / Cordis 模块
@deepseek-ai/cordis@deepseek-ai/dsh@deepseek-ai/dsh-client-locale@deepseek-ai/dsh-tools@deepseek-ai/schemastery
给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个

界面预览

2 张 · 点击查看大图

功能亮点

  • 保留工具调用与推理
  • 支持反向导出与同步

把 25+ AI 编程智能体的对话记录导入 DeepSeek Harness,作为可恢复的会话继续对话,工具调用、推理与结果原样保留,还支持反向导出与同步。

v0.26.32026-10-28内容较长已截断
中文 | English 新增功能 · 新增 Copilot VS Code 导入源:import_chat({ format: "copilot-vscode", path }) 和面板支持 version 3 chatSessions/*.json,可传 workspaceStorage 根、会话目录或单个文件。保留标题、源时间、推理、已保存的工具输入与结果;相邻 workspace.json 提供单文件夹工作区。工具参数及结果缺失数量通过 missingToolInputs、missingToolOutputs 上报。 · 新增 Copilot CLI 导入源:import_chat({ format: "copilot-cli", path }) 与面板支持 Copilot CLI 的逐会话事件流 ~/.copilot/session-state//events.jsonl,可传 session-state 根、单个会话目录或单个文件;.copilot 根被迁移过时用 COPILOT_HOME 指向。事件流按顺序还原提问、回复、推理与按 toolCallId 配对的工具调用;session.compaction_complete 的摘要写为 DSH 原生压缩检查点(边界之前的轮标 log-only,正文保留在日志里),fullHistory: true 保留全量并进参数指纹。标题按首条人类提问兜底;事件格式上游无稳定承诺,未知类型、不可读行、未落地附件、未声明补出的调用与孤儿结果都计数进公开结果(unknownEvents、skippedLines、secrets、droppedAttachments、unannouncedToolCalls、orphanResults),不会让整份会话失败。 · 面板会话行新增四个行内工具:预览、正文搜索、隐藏、删除源文件,并支持拖到侧栏工作区导入:双击会话行打开预览卡,按顺序显示提问与回复,插件注入的消息不出现,连续工具调用折成一行(如 Bash ×2, Read),预览只跑导入的只读 dry-run;「搜内容」把面板搜索框从标题切到正文(只覆盖提问与回复文本,工具入参与结果不计,一库多会话或整份 JSON 的来源跳过并计数),同一条消息须包含全部关键词,命中数与高亮随列表轮询更新,换词或换来源会取消上一次检索;「隐藏」在忽略表里登记为可撤销的隐藏项,重扫不再出现,撤销即恢复,且不会覆盖已有的归档 / 撤回记录;「删除文件…」在确认后把源文件移进回收站,一库多会话的来源与按自定义路径扫描出来的行一律拒绝,DSH 侧已导入的副本保留;把行拖到左侧栏的工作区上即导入到该工作区,副本时间轴平移到「现在」,排在该工作区最上面。 · 新增豆包桌面版对话导入源:import_chat({ format: "doubao", path }) 与面板「导入会话」都能导入豆包的会话(默认根 Windows %LOCALAPPDATA%\Doubao\User Data,也可直接给某个库目录)。库是 Chromium IndexedDB 的 LevelDB 目录而不是单个文件,读出正文要过三层编码:LevelDB 的 SSTable 内部键带 8 字节尾标(WriteBatch 的键没有)、值是 FF 11 02(snappy)或 FF 11 01(外置 Blob)包装、剥完才是 Blink 的 SerializedScriptValue 头加 V8 结构化序列化流。正文在一条固定主键里,而豆包把流式生成状态整条写在该键上(每次增量都是一次重写,生成结束再写一条清空快照),所以必须扫该键的全部历史版本、按 taskId 取最长快照才能还原完整回答——只读当前值会得到空会话。有意的范围限制:豆包的会话列表在服务端,本地只为最近打开过的对话保留正文;因此只列出并导入本地确实有正文的会话,缺正文的不列出、不导入,也不拿标题凑空壳;一个都读不到时报错并点名库路径与解不开的记录数。 体验优化 · Kimi Code 导入保持源消息顺序,减少缓存前缀失效:同一步的并行工具结果按源转录里的完成顺序发射,不再重排成工具声明顺序;连续的同文注入也不再被去重吞掉。用一条 45 轮、327 条模型可见消息的真实 Kimi Code 会话逐条对照:修复后导入序列与源完全一致,除 DSH 自身的系统头与环境变更声明外,转换不再造成前缀偏移。 · Qoder 导入同时覆盖 Qoder CN 的数据根:Qoder CN 与 intl 版共用逐字相同的 transcript 格式,qoder 格式与面板现在同时扫描 ~/.qoder/projects 与 ~/.qoder-cn/projects,单文件路径也按 ~/.qod
v0.26.22026-10-20
中文 | English 新增功能 · 新增 oh-my-pi(omp)对话导入源:import_chat({ format: "omp", path }) 和面板「导入会话」都能导入 omp 的会话(默认根目录 ~/.omp/agent/sessions,一条会话一个 JSONL)。按 omp 的存储约定读取:首行是定宽 256 字节的标题槽,用作标题(旧文件没有标题槽时回退到 header.title,再回退到 title_change);会话头取 id、时间、cwd;id/parentId 树只重建活动分支。message 的 camelCase 角色(user / assistant / toolResult / bashExecution / pythonExecution / fileMention)、toolCall 块(arguments 对象)、压缩条目(firstKeptEntryId 划定保留窗口)都按源自身 convertToLlm 的口径转换,压缩摘要默认导入为原生压缩检查点。/clear 的 reset_boundary 只是标记,没有摘要载荷:与 Kimi「只有边界没有摘要」同口径,最后一次清空点之前的内容不进日志,结果里显式上报 resetBoundaries:(不静默),fullHistory: true 保留全量——该开关计入参数指纹。转换实现与 pi 共用同一引擎(lib/convert/pi-family.mjs),两个来源只保留各自的差异描述。 · 工具结果新增两个降级计数:resetBoundaries(omp 的 /clear 次数,见上)和 droppedInjected(无轮可挂的注入消息数:bash / python 执行活动)。后者此前在 pi 上叫 droppedBash,且没有在输出 schema 里声明,被宿主的输出校验丢掉,用户看不到——现已声明并随结果透出。 体验优化 · import_chat 的常驻 schema 瘦身 59%,长文改由运行时技能按需加载:schema 只留一次调用需要的东西——format 枚举、必填 path,以及「默认值会改变结果」的那几个参数各一行说明;30 个来源的 path 形状表、完整参数详解与重导规则下沉到 docs/IMPORT-GUIDE.md,并注册为宿主运行时技能 dsh-chat-import-usage(import_chat 的 description 点名它,模型在真要导入前加载一次)。口径是宿主真正发给模型的部分(name + description + parameters;output.schema 不上线、不计费),本机实测:import_chat 常驻 1633 → 663 tokens,全量 12 个工具 3720 → 2762 tokens;技能目录多出的一行约 46 tokens,故精简档净省约 0.9k/轮。设置页「精简档省多少」原先写的约 4.5k 有误,按同口径修正为约 2.1k;「关闭注入」的约 5k 修正为约 2.8k。22 个参数一个没少(全部保留声明,只是说明搬到了按需付费的地方);docs/USAGE*.md 与中英两份 README 的文档表同步。 · 常驻成本进护栏,防止说明重新长回 schema:test/tools-injection.test.mjs 的全量档 payload 上限从 15.3k 收紧到 12k,并单独钉住 import_chat ≤ 2.8k 字符;新增 test/import-guide.test.mjs 守住三条——指南的来源表与代码里的来源表逐字一致(中英两份)、每个声明的参数在指南里都有条目、schema 不再携带来源 path 形状表。 其他变更 · 发布流程移入 CI:发布不再在本地执行 npm publish / gh release。推送 v* tag 后,.github/workflows/release.yml 校验 tag 与 package.json 版本一致、tag 提交在 main 上、CHANGELOG 版本节版式正确(scripts/release-notes.mjs),跑完全部门禁后以 trusted publishing + provenance 发布到 npm,并用同一版本节建 / 更新 GitHub Release;重跑会跳过 npm 上已有的版本。手动 workflow_dispatch 只校验、不发布。 New Features · 新增导入源 oh-my-pi(omp):import_chat({ format: "omp", path }) 和「导入会话」面板都能导入 omp 会话(默认根目
v0.26.12026-10-17
中文 | English 问题修复 · Claude Code 的 fork 会话此前一条都扫不到,现在被发现并导入为独立会话:新版 Claude Code(桌面端会话菜单与 --fork-session)的 fork 转录把父会话的记录逐字拷贝在文件开头,自己的记录从 fork 点起追加——旧的「文件名 stem == 首条记录的 sessionId」口径把整份 fork 判成子代理辅助 transcript,发现层与导入层都看不到它(本机实测 ~/.claude/projects 下 35 份转录:4 份 fork 全部漏掉,只认出 31 份)。主转录判定改为看文件两端(文件名 stem 出现在头部或尾部即算该文件自己的会话),会话身份取转录里最后出现的 sessionId:fork 因此以自己的 id 落成 import-,不再与父会话的 import- 撞车、也不再被「文件名与 sessionId 不一致」的辅助转录判定跳过。拷贝段(父会话历史)照常进日志——fork 的上下文里本就有它,父会话与 fork 会话在 DSH 里因此重叠一份历史。 · Codex 会话标题优先取保存的标题索引:面板此前只按 rollout 里的首问起标题,Codex 里改过的名字显示不出来;现在优先读 session_index.jsonl 的 thread_name(按行流式读取,同一 thread 取最后一条有效记录),没有索引标题才回退首问。首问兜底同时与导入共用同一提取口径:注入的页面上下文信封被剥掉——信封独占一条消息、或与真实提问同在一段文本里都只保留提问,上下文不再变成标题。 · Codex 会话的活动时间改为取日志里的时间戳:面板排序此前用 rollout 文件的修改时间,复制、恢复或同步过的会话时间会整体失真;现在从每条 rollout 的头尾有界窗口取最新有效时间戳(滚过分页合并),文件修改时间只在日志里完全没有时间戳时兜底。被窗口截断的记录中的时间戳可能遗漏。 · Windows 下 Hermes 的默认扫描根补全:此前只扫 ~/.hermes,而 Windows 上的 Hermes 把数据放在 %LOCALAPPDATA%\hermes,面板一条会话都列不出来(手动填绝对路径可以导入)。现在 Windows 同时扫 %LOCALAPPDATA%\hermes 与 ~/.hermes,LOCALAPPDATA 未设置或为空时回退 ~/AppData/Local/hermes;macOS 与 Linux 仍为 ~/.hermes。每个根优先读 state.db,数据库不可用时回退 JSONL。 其他变更 · CI 覆盖率护栏恢复生效:check-coverage 解析器此前只认 ℹ 前缀,而 CI 的 Node 22 输出 # ,从 2026-10-13 起每个 PR 的 test job 都红(一行报告都解析不到,误报「目录下限有记账但目录下没有文件」)。现在两种前缀都收,coverage 脚本再固定 --test-reporter=spec,Node 22 / 24 口径一致;同时补上解析器与 clearSessionArtifactsForReplace 的用例,Node 22 下的逐文件下限继续有效。 Bug Fixes · Claude Code fork sessions were invisible; they are now discovered and imported as their own sessions: a fork transcript written by newer Claude Code (the desktop session menu and --fork-session) opens with a verbatim copy of the parent's records and appends its own from the fork point, so the old test — "file stem == the first record's sessionId" — classified the whole file as a subagent auxiliary transcript, invisible to both discovery and import (measured here: all 4 forks among the 35 transcripts under ~/.claude/projects were missed, only 31 recognised). The main-transcript test now looks
数据来自仓库的 GitHub Release,可能与插件实际版本不一致。

README

由 DeepSeek 最新模型翻译生成
DSH Chat Import 基于 DeepSeek Harness 构建的会话导入插件:把其他 Agent 的聊天历史一键导入,接着在 DeepSeek Harness 里继续对话。 所有会话,尽续于此。 Awesome DSH Plugin dsh.so install 支持数据源 Claude Code Codex Gemini CLI Goose Crush Qoder CLI Kimi CLI Kimi Code Reasonix OpenCode MiMo Code ZCode Grok Build OpenClaw Kilo Code Pi Coding Agent oh-my-pi Hermes Cursor Cline Continue Zed Antigravity ChatGPT WorkBuddy Qwen DSH TeleAgent Trae Work 豆包 Mistral Vibe CodeArts Desktop CodeBuddy Code 本地 JSONL Copilot VS Code Copilot CLI 安装 插件要求 dsh 0.1.5-rc.1 及以上。已在 0.1.x 与 0.2.x 上验证过,其中 dsh-tools 需满足 >=0.1.0-rc.6 <0.3.0。
展开完整文档(README 剩余 1 节)
DSH Chat Import

基于 DeepSeek Harness 构建的会话导入插件:把其他 Agent 的聊天历史一键导入,接着在 DeepSeek Harness 里继续对话。

所有会话,尽续于此。

Awesome DSH Plugin
dsh.so install

支持数据源

Claude Code
Codex
Gemini CLI
Goose
Crush

Qoder CLI
Kimi CLI
Kimi Code
Reasonix
OpenCode

MiMo Code
ZCode
Grok Build
OpenClaw
Kilo Code

Pi Coding Agent
oh-my-pi
Hermes
Cursor
Cline

Continue
Zed
Antigravity
ChatGPT
WorkBuddy

Qwen
DSH
TeleAgent
Trae Work
豆包 Mistral Vibe CodeArts Desktop CodeBuddy Code

本地 JSONL Copilot VS Code Copilot CLI

安装

插件要求 dsh 0.1.5-rc.1 及以上。已在 0.1.x 与 0.2.x 上验证过,其中 dsh-tools 需满足 >=0.1.0-rc.6 <0.3.0。

1. 用终端安装

dsh plugin --profile web add dsh-chat-import # npm 包

2. 或者从插件市场安装

使用

1. 通过 GUI 导入会话

点左侧栏底部的「导入会话」按钮打开导入窗口(用 DSH Claude Style 主题时,这个按钮收在左下角的账号菜单里),选好要导入的会话,一键导入。

会话行自带工具:双击行打开只读预览(跑的是导入的 dry-run,插件注入的消息不出现,工具调用折成一行);搜索框可切到「搜内容」按正文检索;可以把行隐藏(可撤销);可以把单会话来源的文件移进回收站;也可以把行拖到左侧栏的工作区上,导入到那个工作区并把时间轴平移到「现在」,让它排在最上面。规则细节见 docs/USAGE.zh-CN.md。

手上是别的工具导出的文件(网页版导出、自己写的脚本、列表里没有的工具)时,用同一个窗口顶部的「从文件导入」:填本机路径后回车,或者点「选择…」挑文件。路径是目录时会先问你要不要搜索子文件夹。预览确认之后再导入。识别不出格式时,会逐个列出候选解析器的失败原因,并给出把该格式转换过来的 Skill 指引。

截图界面用的是作者另一个主题插件 DSH Claude Style 的 DeepSeek 配色。它在 DSH 里复刻了 Claude Code Desktop 的视觉与交互,提供 Claude、DeepSeek 两套配色;看惯了默认主题的话可以试试。截图里的工作区与会话都是示例数据。

2. 让 Agent 调用工具导入

参考调用格式
import_chat({ format: "claude", path: "~/.claude/projects" })
import_chat({ format: "chatgpt", path: "~/Downloads/chatgpt-export/conversations.json" })
import_chat({ format: "local-jsonl", path: "D:\downloads\session.jsonl" })

Cursor 的工作区分组与导入优先按对话 id 查询本机 Cursor 工作区登记册,只采用现存目录。导入始终重新读取,发现缓存成功结果并在 DB/WAL 变化时失效;畸形 JSON 与文件系统读取失败会在诊断告警中计数。没有可用登记时,仍回退转录所在项目目录名的解码。

配置

为了照顾 TUI 用户,插件提供的工具默认会注入上下文。你可以在设置页里把它们设成不注入或只注入一部分,这样能省下不少 token。

每个工具、每条命令的完整用法见 docs/USAGE.zh-CN.md。

第三方插件可以通过可选的 chatImport Host Service 调用 scanDiscover()、importPath()、importAll() 和 resumeSummary()。这四个方法复用与工具、命令相同的发现、导入、批量导入与交接摘要管线;单会话导入的返回值带 sessionId。服务不存在时,调用方要自己降级。

功能一览

| 能力 | 入口 | 说明 |
| 导入 | 侧边栏面板的「导入」页 | 从其他 Agent 导入对话,保留推理过程、工具调用结果和系统提示词(可选) |
| 文件导入 | 面板「从文件导入」/ /import auto <path> | 任意本地文件或目录:三级探测(显式格式 > 内容标记 > 逐格式试跑)、预览先行、目录会问要不要搜索子文件夹。识别失败时摊开各解析器的原因,一键复制可直接发给 Agent 的任务模板,并注册 dsh-chat-import-convert 转换 skill |
| 撤回导入 | 侧边栏面板的「历史」页 | 查看导入记录,一键删除本插件创建的会话 |
| 导出 | 上下文工具 | 把 DSH 会话序列化回外部 Agent 的格式 |
| 忽略 | 自动登记 + /ignores 命令 | 归档、删除、删工作区时自动登记源,重扫时跳过;用 /ignore、/unignore 管理忽略表 |

Codex 的会话标题优先取 session_index.jsonl 里保存的标题(thread_name),所以 Codex 里改过的名字也能显示。没有索引标题时,才按与导入共用的提取逻辑回退到首条真实提问,并排除注入的页面上下文。标题索引按行流式读取,同一会话取最后一条有效记录。

Codex 的活动时间取日志头尾有界窗口里最新的有效时间戳,并合并所有 rollout 分页的结果。只有日志里完全没有时间时才回退文件修改时间,所以宿主文件服务不提供修改时间也能取到活动时间。被窗口截断的记录里的时间戳可能漏掉。

Claude Code 的 fork 会话(新版桌面端会话菜单与 --fork-session)同样会被发现并导入。fork 转录把父会话的记录逐字拷贝在文件开头,自己的记录从 fork 点开始追加。所以判定主转录时看文件的两端:文件名 stem 出现在头部或尾部,就算这个文件自己的会话。会话身份取转录里最后出现的 sessionId。以前这类文件被整类当成子代理辅助转录跳过,一条都扫不到。拷贝过来的父会话历史会留在日志里,因为 fork 的上下文本来就有它,于是父会话与 fork 会话会重叠一段历史。

Hermes 在 Windows 上默认扫描 %LOCALAPPDATA%\hermes 与 ~/.hermes;LOCALAPPDATA 没有设置时,回退到 ~/AppData/Local/hermes。macOS 与 Linux 默认扫描 ~/.hermes。

文档

| 文档 | 说明 |
| 使用详解 | 每个工具、每条命令的完整参数、示例与边界行为 |
| 互转协议 | Interchange v1 协议与 bundle 格式 |
| 转换指南 | 给 Agent 的 Skill 指令:把任意转录转成可导入的 interchange v1 文档 |
| 导入指南 | 给 Agent 的 Skill 指令:import_chat 的来源格式表、参数详解与重导规则 |
| 设置页迁移 | DSH 0.1.5 → 0.1.7 插件设置页迁移(实测报错、兼容写法) |
| 更新日志 | 版本历史(英文) |
| 路线图 | 未完成、计划与明确不做的事项 |
| 贡献指南 | 开发环境、提交规范、安全与隐私 |

友链

只需要迁移配置(技能、hooks、全局设置等)、不需要会话历史的话,推荐用 dsh-movein。

Star History
预览分享卡片长什么样 ↓Nwflower/dsh-chat-import
分享 · DeepSeek Harness Hub
Nwflower/dsh-chat-import

基于 DeepSeek Harness 构建的会话导入插件:把其他 Agent 的聊天历史一键导入,接着在…

回到顶部