deepseek-harness
deepseek-ai
DeepSeek Harness: Everything is a Plugin.
PROJECT TOPICS
INSTALL REFERENCE
dsh plugin --profile web add github:devmom/dsh-session-import
该命令指向仓库当前默认分支;尚无绑定当前 commit 的完整验证结果。
PROJECT README
中文 · English
跨工具会话迁移插件(对标/增强 dsh-chat-import),现已作为 真实 dsh bundle 插件 接入 DeepSeek Harness:
turn/start · user/message · assistant/message(含 thinking 推理块与 tool-call 块)· tool/call · tool/result · turn/end),经 ctx.sessions 写入并随官方 JSONL 持久化落盘 —— 导入的会话在 dsh Web UI 中原样渲染、可续聊;memory seam 接口)。设计文档:见 docs/ — PRD(需求/验收)· ARCH(架构)· TECH(技术细节)。
| 模块 | 文件 | 覆盖需求 |
|---|---|---|
| 解析适配器(可插拔,14 种源) | src/parsers/*.ts |
FR-01/02/03/16 |
| 适配器注册与探测 | src/registry.ts |
FR-02 — detect() 嗅探 + 通用兜底 |
| 真实 dsh 会话事件映射 | src/mapping.ts |
FR-04/05/06 — 原生 Session.append 词汇(turn/user/assistant/tool),thinking→reasoning 块,未知工具→tool/result.meta.unknownTool |
| 隐私脱敏 | src/privacy.ts |
FR-15/AC-3 |
| 双向导出(事件逆向) | src/exporter.ts |
FR-13 |
| 知识抽取 | src/knowledge.ts, src/heuristicJudge.ts |
FR-11/12 |
| 导入编排 | src/importService.ts |
FR-07/08/09/14/15/16 — 冲突 rename/merge/skip、归档、健壮性 SkipError |
| 流式分片导入 | src/streamImport.ts |
FR-10/NFR-02 |
| 真实 dsh seam 适配 | src/dsh/dshRuntime.ts |
对接 ctx.sessions / ctx.sessionTitle / ctx.credentials;归档/历史/记忆走 $DSH_HOME/session-import |
| Cordis 插件入口 | src/plugin.ts |
apply(ctx, config):提供 sessionImport 服务、注册 /session-import 命令、挂载 /api/session-import/* REST 路由 |
| bundle 清单 | cordis.patch.yml, package.json#dsh.bundle |
标准 dsh profile bundle 协议 |
| 独立开发向导(可选) | src/server.ts, public/* |
无 harness 时的本地 Wizard(npm run wizard) |
# pnpm 9.x 的 workspace-root 检查需要 -w 标志(dsh plugin 原样转发 pnpm 参数)
dsh plugin --profile web add -w session-import
# dsh 会自动把包加入 profile 的 dsh.profile.bundles(检测到 dsh.bundle 声明),重启 dsh 即生效
# 在插件目录构建一次(产出 dist/ 与 lib/)
npm install && npm run build && npm run bundle:client
# 安装到你的 profile(web 示例)
dsh plugin --profile web add -w link:D:/work/DeepSeekHarness/Plugins/session-import
# 或手动:profile/package.json dependencies 加 "session-import": "link:<本目录绝对路径>",
# 并在 dsh.profile.bundles 追加 "session-import",然后在该 profile 目录 pnpm install
# 重启 dsh,即可用:
# - Web UI 输入 /session-import <导出文件路径> [--redact] [--extract-knowledge]
# - 或调用 REST:POST /api/session-import/import
Windows 注意:pnpm 9.x 对
file:D:/...绝对路径解析有已知问题(会把盘符拼到 profile 目录下), 本地开发请用link:<绝对路径>说明符(pnpm 会建 junction)。registry 安装不受影响。
npm login # 需要 npm 账号(包名 session-import 已无 scope)
npm version patch|minor|major # 提升版本
npm publish # prepublishOnly 自动 build:all + test
/api/session-import/scan-dir 与 /api/session-import/import-paths。chat_import_discover:自动探测本机已知 agent 工具会话目录(注册表见下文),返回带编号的候选列表(会话名/路径/消息数/大小/时间),只读不写入;支持 titleFromFirstMessage 选项(同向导)。chat_import_import:按用户确认的路径列表导入为新 dsh 会话(支持 redact / extractKnowledge / titleFromFirstMessage),失败文件跳过并说明;标题自动取源标题(Codex 线程名 / Claude Code ai-title),无标题的默认用可读时间回退,开启 titleFromFirstMessage 则取首条用户消息。用户:帮我把最近的 Codex 会话导入进来 Agent:
chat_import_discover→ 列出候选 → 用户:导入 1、3、5 → Agent:chat_import_import→ 汇总
enableModelTools: false 可关闭。/session-import 斜杠命令(Web UI / 任何 commands 适配器):/session-import C:\path\to\chatgpt\conversations.json # 单文件
/session-import C:\Users\PC\.codex\sessions # 目录(递归扫描全部会话)
/session-import C:\Users\PC\.codex\sessions --source codex # 只导 codex
/session-import <path> --redact --extract-knowledge # 脱敏 + 知识抽取
目录导入返回汇总(imported 21/21 session(s) (codex×21)),坏文件跳过不中断(FR-16)。
sessionImport 服务(其它插件 / 脚本):const svc = ctx.get('sessionImport') // { ingest, sources, detectSource, parseCount, scanDirectory, ingestDirectory }
const preview = await svc.scanDirectory('C:/Users/PC/.codex/sessions', { sourceFilter: ['codex'] })
const batch = await svc.ingestDirectory('C:/Users/PC/.codex/sessions', { sourceFilter: ['codex'], redact: true })
// batch: { dir, total, imported: ImportResult[], skipped: {path,reason}[], ignored: number }
GET /api/session-import/adapters — 已注册源列表POST /api/session-import/import — { fileName, text, options } 单文件导入POST /api/session-import/scan-dir — { sourceFilter?, maxFiles? } 发现式扫描(返回带编号/标题的候选组,不写入)POST /api/session-import/import-dir — { dir, options, sourceFilter?, maxFiles? } 目录批量导入POST /api/session-import/import-paths — { paths, options } 按确认路径逐个导入(向导/对话共用)GET /api/session-import/history — 导入历史$DSH_HOME/sessions,JSONL,绑定源 cwd 的 workspace 分组);原文归档/导入历史/本地记忆 → $DSH_HOME/session-import/(可用 bundle config dataDir 覆盖)。| 框架 | 源 id | 自动发现目录(env 可覆盖) | 解析器 | 状态 |
|---|---|---|---|---|
| Codex CLI | codex |
~/.codex/sessions(CODEX_HOME) |
专用(rollout + legacy;标题链:session_index.jsonl 线程名 → 首条用户消息(可选)→ 时间戳回退;session_meta.cwd 绑定) |
✅ 本机实测(真实会话导入验证) |
| Claude Code | claude_code |
~/.claude/projects(CLAUDE_CONFIG_DIR) |
专用(session-based + legacy;ai-title 标题、cwd 绑定) |
✅ 本机实测(真实会话导入验证) |
| Kimi Code | kimi_code |
~/.kimi-code/sessions(KIMI_CODE_HOME) |
专用(真实 wire.jsonl 事件流 v2:turn.prompt/context.append_loop_event(content.part think/text、tool.call/tool.result);state.json 标题 + session_index.jsonl 工作目录;子代理 agents/agent-N 同样解析) |
✅ 本机实测(真实会话导入验证) |
| ZCode(智谱 GLM) | zcode |
~/.zcode/cli(ZCODE_HOME) |
专用 v2(真实双格式:子代理 transcript.jsonl(turn_started/model_streaming/tool_call_scheduled/turn_complete)+ 主会话 rollout/model-io-sess_*.jsonl(model_io 快照,含 reasoning/toolCalls,过滤 system-reminder/task-notification 噪声);metadata.json → 标题 description + cwd 绑定) |
✅ 本机实测(真实主会话 32 条 + 子代理导入验证) |
| WorkBuddy / CodeBuddy(腾讯) | workbuddy |
~/.codebuddy(CODEBUDDY_HOME) |
OpenAI 消息格式 / 通用 JSON(导出会话) | ✅ 合成会话导入验证(本机无会话数据) |
| OpenClaw (claw.so) | openclaw |
~/.openclaw/agents(OPENCLAW_HOME) |
专用(真实 session log:session(cwd 绑定)/ message(text / thinking / toolCall / toolResult 块)) |
✅ 本机实测(真实会话导入验证) |
| Gemini CLI | gemini |
~/.gemini(GEMINI_HOME) |
专用(chats.history) |
✅ 合成会话导入验证(本机未安装) |
| Cursor | cursor |
~/.cursor(CURSOR_HOME) |
专用(source:cursor/toolCalls) |
✅ 合成会话导入验证(本机未安装) |
| Aider | aider |
~/.aider(AIDER_HOME) |
专用(markdown 历史) | ✅ 合成会话导入验证(本机未安装) |
| Continue | continue |
~/.continue/history(CONTINUE_HOME) |
OpenAI 消息格式(目录内文件检测为 openai_family) |
✅ 合成会话导入验证(本机未安装) |
| OpenCode | opencode |
~/.opencode/sessions(OPENCODE_HOME) |
OpenAI 消息格式(目录内文件检测为 openai_family) |
✅ 合成会话导入验证(本机未安装) |
| Cline / Copilot Chat 等导出 | openai_family |
自定义 CHAT_IMPORT_OPENAI_DIR |
OpenAI 消息格式 | ✅ 合成会话导入验证 |
| ChatGPT | chatgpt |
手动指定导出文件 | 专用(mapping 图) |
✅ 单元测试覆盖(导出文件) |
| 任意 JSON | generic_json |
手动指定文件 | 通用兜底 | ✅ |
每个框架在
src/discovery.ts的AGENT_SOURCES注册表中一行即接入自动发现; 会话存储为 SQLite 的框架(Cline/Continue 新版、Trae、通义灵码、DevChat 等)以导出 JSON 方式接入,本地 sqlite 解析留作后续。chat_import_discover/ 向导只会列出本机实际存在的框架目录。 验证方式:node scripts/verify-all-sources.mjs— 对全部已注册框架逐个执行 检测 → 解析 → 导入(本机有真实数据的用真实会话:codex / claude_code / kimi_code / zcode / openclaw;其余用合成夹具:gemini / cursor / aider / continue / opencode / openai_family / workbuddy)。
npm test # 89 个用例(node --import tsx --test)
npm run build # tsc 严格编译 → dist/
npm run wizard # 独立导入向导 http://localhost:4173(纯本地文件 seams)
端到端脚本(真实 dsh profile):
node scripts/verify-dsh.mjs — 服务/命令/导入/持久化断言node scripts/verify-all-sources.mjs — 全部已注册框架 检测 → 解析 → 导入(真实/合成)node scripts/verify-zcode.mjs — ZCode 主会话 rollout + 子代理 真实导入验证(标题/cwd 持久化)node scripts/verify-install.mjs — tarball 安装后的插件可用性验证(npm pack → dsh plugin add 到临时 DSH_HOME → boot → 导入,自包含)node scripts/demo-codex.mjs <rollout.jsonl> — 导入单个真实 Codex 会话node scripts/demo-scan.mjs <dir> [--import] [--source codex] [--redact] [--limit N] — 目录扫描/批量导入演示node scripts/demo-discover.mjs [--import-limit N] — 模型工具闭环:discover 真实候选 → import → 持久化验证上述脚本会 boot 一个真实的 dsh 安装(
dsh-app-boot)。dsh checkout 路径通过scripts/lib/dsh-env.mjs解析:$DSH_CHECKOUT环境变量 > PATH 上的dshCLI 反推 > npm 全局目录。 无需改脚本;把dsh装进 PATH 或设置DSH_CHECKOUT即可在其他机器上运行。
CI(GitHub Actions,.github/workflows/ci.yml):push/PR 时执行
Node 18/20/22 的 类型检查 → 构建 → 客户端打包 → 单元测试 → npm pack 内容校验,
以及一次 dsh 集成 job(安装 dsh CLI 后跑 verify-dsh + verify-all-sources 合成夹具)。
最小使用示例(无 harness):
import { buildHeadlessContainer } from './dist/plugin.js';
import { HeuristicLlmJudge } from './dist/heuristicJudge.js';
const { service } = buildHeadlessContainer(new HeuristicLlmJudge());
const result = await service.ingest(
{ path: 'codex-session.jsonl', text: '<Codex transcript JSONL>' },
{ redact: true, extractKnowledge: true },
);
console.log(result.sessionId, result.messageCount);
scripts/verify-dsh.mjs 会用与 dsh CLI 完全相同的方式 boot 一个含本插件的 profile,
并断言:sessionImport 服务可用、/session-import 命令已注册、导入产出真实会话事件且 JSONL 持久化成功:
node scripts/verify-dsh.mjs # 依赖 $DSH_HOME/profiles/ci-chat-headless(已按上文方式安装)
dsh plugin --profile web remove session-import
# 或从 profile package.json 删除依赖与 bundles 条目后重启 harness
# 历史数据:删除 $DSH_HOME/session-import 即清除归档/历史/记忆;会话本体保留在 dsh 会话库中
import { ParserAdapter, RawInput, msg } from './src/parsers/base.js';
export class MyToolAdapter implements ParserAdapter {
readonly source = 'mytool';
readonly schemaVersion = '1.0';
detect(raw: RawInput) { /* 嗅探特征,避免误判其它源 */ return false; }
parse(raw: RawInput) { return { source: this.source, messages: [] }; }
}
// 在 src/registry.ts 的 createDefaultRegistry() 中按"具体源优先"顺序 register(new MyToolAdapter())
HeuristicLlmJudge(defaultExtractKnowledge: true 时启用);
接真实 LLM 通道(ctx.llm)留作后续。import-<uuid> 命名,避免 store 每进程自增 id 与磁盘既有日志冲突。session_meta.cwd 会写入导入会话的
SessionHeader.cwd —— 会话因此落在对应 workspace(侧边栏分组)下,并满足 dsh
冷恢复/模型选择对 cwd 的硬性要求(无 cwd 的会话无法 resume/续聊)。~/.codex/session_index.jsonl(thread_name),
chat_import_import 导入时自动作为会话标题(session/title,user source 固定,
不会被回退覆盖);无名字的会话由 dsh 按首条消息回退生成。ICredentials 已对接真实 ctx.credentials。CLASSIFICATION EVIDENCE
系统优先读取 GitHub Topics,再与站内分类词典和词根规则比对。当前命中: 无有效分类标签。