技术文档:跨工具会话迁移插件 session-import
August 14, 2026 · View on GitHub
版本:v0.1(Draft) 日期:2026-08-14 对应需求:
plugin-req-session-import.md插件代号:session-import
1. 技术栈与运行时
- 运行时:Node 22.19+ / 24+(与 dsh dev-preview 对齐,NFR-03)。
- DI 框架:Cordis(插件容器、依赖注入、生命周期)。
- 语言:TypeScript(strict)。
- 解析:基于流式读取(按消息块增量解析),避免整文件载入。
- 知识抽取:调用 dsh 内置 LLM 通道(复用
llm-streamingseam)完成抽取,结果经memoryseam 写入。 - 加密:Web Crypto(AES-GCM)做原文加密归档。
2. 解析适配器接口规范
export type SourceType =
| 'claude_code' | 'codex' | 'chatgpt' | 'cursor' | 'gemini'
| 'reasonix' | 'opencode' | 'continue' | 'aider' | 'cline'
| 'github_copilot' | 'generic_json' | 'generic_markdown' | 'generic_transcript';
export interface RawInput {
path: string;
buf: Buffer; // 原始字节(用于 detect 嗅探)
text: string; // 解码文本
}
export interface ParserAdapter {
readonly source: SourceType;
readonly schemaVersion: string; // 版本门:源格式变更需升版
detect(raw: RawInput): boolean;
parse(raw: RawInput): NormalizedConversation;
}
detect()应快速、无副作用(读 magic header / 特定 key)。parse()抛错需可被上层捕获,标记为「坏文件」并继续(FR-16)。- 注册:
container.set(ParserAdapter, new ClaudeCodeAdapter()),Source Ingest收集全部实例。
3. 解析要素数据模型
映射后的统一中间表示(详见架构文档 §5.1)。解析器需尽量还原以下要素(FR-03):
| 要素 | 字段 | 说明 |
|---|---|---|
| 角色 | role | user / assistant / system |
| 文本 | content | 允许为空(如纯工具调用消息) |
| 推理 | thinking | Claude/Gemini 的 thinking/reasoning 块 |
| 工具调用 | toolCalls[] | name / args(对象)/ result(对象或原始 JSON) |
| 文件引用 | attachments[] | 路径或内联内容引用 |
| 代码块 | codeBlocks[] | language / code |
| 源专有 | extensions | citation、diff 等原样保留(FR-06) |
4. 保真映射规则(FR-04 / FR-05 / FR-06)
映射层 mapToEvents(nc): SessionEvent[] 遵循:
- 顺序保真:按
messages顺序逐个产出事件,不重排。 - 角色保真:
role直接映射到 dsh 事件角色。 - thinking 保真:落
thinking事件(或并入 assistant 事件的meta)。 - 工具调用还原:
- dsh 存在对应工具 → 还原为 dsh
tool_call+tool_result事件; - dsh 无对应工具 → 保留原始 JSON 于
tool_call.result,并置meta.unknownTool=true,供 UI 查看(FR-05)。
- dsh 存在对应工具 → 还原为 dsh
- 附件:作为
attachment事件或meta,保留引用路径。 - 源专有字段:全部落
meta.extensions,不丢弃信息(FR-06)。
5. 流式分片导入实现(FR-10 / NFR-02)
大会话采用「解析—映射—写入」三段流水线,分段 flush:
async function* streamImport(raw: RawInput, adapter: ParserAdapter) {
const nc = adapter.parse(raw); // 若支持流式则增量产出
for (const msg of nc.messages) {
const events = mapToEvents({ messages: [msg] });
await session.append(events); // 增量写入事件溯源日志
yield msg.id; // 进度反馈
}
}
- 不在内存中持有整段
NormalizedConversation的完整体积峰值;逐消息 map + append。 - UI 通过
yield进度条展示。
6. 知识抽取与聚类去重(FR-11 / FR-12)
- 抽取:对
NormalizedConversation调用 LLM,prompt 限定输出结构化KnowledgeItem[]:interface KnowledgeItem { type: 'decision' | 'code' | 'convention'; content: string; confidence: number; sourceRef: { sessionId: string; msgId: string }; } - 去重聚类(FR-12):对新 item 与
memoryseam 中已有条目做 embedding 相似度比对(阈值可调),命中则跳过或合并,避免重复沉淀。 - 人工确认开关:高敏感项目可开启「抽取后人工确认再写入」,防止误抽污染记忆。
7. 隐私脱敏检测(FR-15 / AC-3)
Privacy Scanner 实现:
- 规则集:正则匹配 API Key(
sk-...、AWS、ghp_...)、手机号、邮箱、身份证、内网 IP。 - 行为:返回
SensitiveHit[] { field, type, snippet, position }。 - 交互:UI 弹窗列出命中项,用户可「全部脱敏 / 逐项脱敏 / 忽略」。
- 加密归档:勾选时原文以 AES-GCM 加密落本地;密钥由用户管理,不进日志。
- 不落明文(NFR-01):密钥在内存临时处理,写入前必须脱敏或加密。
8. 双向导出格式规范(FR-13)
Exporter.export(sessionId, fmt) 支持:
| 格式 | 形态 | 用途 |
|---|---|---|
dsh_json | dsh 原生 session-log | 同 dsh 版本迁移/备份 |
generic_json | NormalizedConversation | 跨工具通用 |
generic_markdown | 角色分段 MD | 阅读/迁回支持 MD 的工具 |
transcript | 行式对话 | 轻量归档 |
实现要点:从 dsh session-log 逆向构建 NormalizedConversation,再序列化;meta.extensions 一并带出,保证往返不丢信息。
9. 错误处理与健壮性(FR-16)
- 坏 / 截断文件:parser
parse()抛错 → 捕获为SkipReport { path, reason },导入任务不中断,继续下一个文件。 - 部分失败:单条消息映射失败 → 记录到该会话的
import_warnings,不整体回滚。 - 冲突(FR-09):同名会话触发策略
rename | merge | skip,默认rename(追加-imported-N)。
10. 配置与持久化
- 配置项:默认冲突策略、是否开启知识抽取、是否人工确认、是否加密归档、脱敏规则开关。
- 持久化:
- 会话本体 → dsh
persistence(事件溯源日志)。 - 导入历史 →
ImportHistory[] { id, source, time, archivePath, status },原文归档可回溯(FR-14)。 - 加密归档密钥 → 用户本地密钥库,不进 dsh 日志。
- 会话本体 → dsh