dsh-session-export

为 DeepSeek Harness(dsh)提供的会话导出与合规归档插件。
把当前或历史会话导出为可验证、经过脱敏的多格式归档文件,并在磁盘上管理这些文件,同时提供合规/趋势统计视图——全部以零运行时依赖的 [dsh bundle](#安装) 形式交付。
为什么
导出只有不泄漏信息,才可用于合规或归档。本插件在一个 bundle 中整合了:
- 默认开启的确定性脱敏——API key、token、JWT、
.env风格赋值行、URL 凭据与绝对文件路径在写盘*之前*即被掩码。相同输入永远得到相同输出;掩码值带有稳定指纹,归档之间可关联比对,却不会泄漏机密。 - 多格式导出——可读的 Markdown 叙事、机器可读的 JSONL 完整记录,以及 PDF(打印就绪 HTML + 可选的 headless Chromium 渲染)。
- 归档管理——导出按会话/日期目录组织、可检索、可删除(带路径穿越防护)。
- 合规元数据——每次导出都内嵌一个文件头,含会话 id、模型、脱敏级别、计数与可选 SHA-256 内容哈希;趋势/审计视图汇总“导出了什么、何时、敏感程度如何”。
- 不依赖模型——脱敏基于规则;如需在规则之上叠加可选的 LLM 辅助掩码,内置扩展钩子。
功能特性
1. 会话导出
- 支持当前或历史会话,数据来源为 harness 自身的事件日志(
ctx.sessionPersistence/ctx.sessions)。 - 格式:
markdown、jsonl、pdf或all。 - 事件日志折叠对未知事件类型与跨版本的负载形状保持容错。
- 大会话会被切分为编号分片(带
parts.json清单);Markdown 中可对超长消息截断并给出显式标记(JSONL 始终保留完整记录)。
2. 脱敏(默认开启)
| 规则 | 说明 |
|---|---|
api-key | sk-…、pk-…、GitHub ghp_/gho_/github_pat_、hf_、AKIA…、AIza…、长 base64 风格令牌 |
jwt | eyJ… 令牌 |
high-entropy-token | 任意 32+ 位字母数字连续段 |
env-value | KEY=value 赋值行(例如粘贴的 .env 内容) |
bearer | Bearer/token 值 |
url-credential | https://user:pass@host |
absolute-path | Windows 盘符 / UNC / POSIX 家目录路径——掩码,或在 pathMode: relative 时相对化为 <项目根> |
email | 可选开启 |
custom | 任意用户自定义正则 |
所有匹配值都被替换为 <redacted:<规则> sha256:<指纹>>,其中指纹为加盐 SHA-256(12 位十六进制)。确定性与可配置的 salt 让归档在文件与机器之间可关联,而不会暴露机密:由于指纹仅由机密值本身推导(与规则标签无关),同一机密无论被 env-value、api-key 还是 jwt 捕获,都得到相同的十六进制。env-value 规则最先执行,因此 KEY=sk-… 行会被一步缩减为 KEY=<redacted:env …>(掩码值 token 或带引号字符串,同时保留其后的叙述与命令文本),之后令牌规则不会再看到它。
3. 归档管理
<outDir>/
sessions/<会话>/<YYYY-MM-DD>/<YYYY-MM-DD>_<HHMMSS>-<tag>_<格式>.<扩展名>
<文件>.meta.json # 每次导出一个旁侧文件(见 ArchiveEntry)
<文件>.parts.json # 导出被分片时存在
archives.json # 可检索索引(丢失时可从旁侧文件重建)文件名带进程内唯一 tag,同一秒内的两次导出不会互相覆盖。可按会话、格式、ISO 日期区间、全文关键字与数量上限进行列举/检索;可按归档 id、文件名或相对路径删除——严格限定在归档根目录内(拒绝路径穿越)。索引写入在进程内串行化,并发工具调用不会丢失记录。
4. 合规
每次导出的文件头都内嵌元数据: plugin(名称、版本)、session(id、项目、cwd、创建时间)、exportedAt、所用 models、sanitization(是否启用、级别、触发的规则、盐指纹)、事件/消息计数、可选 contentHash 与告警。includeHash: true 时会对脱敏后的对话记录计算可选 SHA-256 哈希。
注意:只有在写入时才得知的告警(大会话分片、PDF 回退)无法注入已渲染的文件头;它们会记录在归档索引条目与 .meta.json 旁侧文件中,并在工具结果中再次呈现。
趋势/审计视图(/export-audit)按天、格式、会话与脱敏级别汇总导出记录。
5. 工具链
- 模型侧工具(
ctx.tools):session_export、session_export_list、export_delete、sanitize_config。 - 人类斜杠命令(
ctx.commands):/session-export、/session-export-list、/export-delete、/sanitize-config、/export-audit。 - 可复用库:通过
dsh-session-export/core子路径导入与 harness 解耦的核心。
环境要求
- Node.js 20+(直接运行
.ts测试套件建议 Node 24+)。 - 一个带 base bundle 的 DeepSeek Harness profile(提供
sessions、sessionPersistence、tools、commands)。
安装
这是一个标准的 dsh bundle:npm 包,其 package.json 声明 dsh.bundle 清单,附带一个 cordis.patch.yml 补丁层与导出 name/inject/apply 的入口模块。
# 从本仓库
dsh plugin --profile demo add github:JohnXu22786/session-export
# 或发布后通过 npm 全局安装
npm install -g dsh-session-export补丁插入一行配置:
# cordis.patch.yml
- insert:
- id: dsh-session-export
name: dsh-session-export
config:
outDir: !!js dshHomePath('exports')outDir 默认为 $DSH_HOME/exports(即 ~/.dsh/exports)。如需覆盖任一设置,可在后续补丁层以相同行 id 为目标(按 harness 语义,整行 config 会被整体替换)。
配置
- id: dsh-session-export
name: dsh-session-export
config:
outDir: !!js dshHomePath('exports')
enabled: true
defaultFormat: markdown # markdown | jsonl | pdf | auto
includeNotes: false # 是否包含 todo/命令/反馈等记录
includeDocuments: true # 是否输出文档树附录
maxChunkBytes: 4194304 # 大会话分片阈值(0 = 从不)
maxMessageChars: 0 # Markdown 中对单条消息的显示截断(0 = 从不)
prettyToolArgs: false
includeHash: true
redaction:
enabled: true
pathMode: mask # mask | relative | off
projectRoots: [] # 例如 ['C:\\Users\\you\\work']
maskApiKeys: true
maskEnvValues: true
maskBearerTokens: true
maskUrlCredentials: true
maskAbsolutePaths: true
maskEmails: false
salt: "" # 设置一个密钥以加固可关联指纹
customPatterns: # [{ pattern, flags?, replacement? }]
- pattern: '\\d{4}-\\d{4}'
replacement: '[CARD]'
aiMaskEnabled: false # 是否叠加用户提供的 aiMaskFn
pdf:
engine: auto # auto | chrome | html
chromePath: "" # 显式指定 chromium 系列可执行文件使用方式
工具(供模型调用)
session_export { format?, sessionId?, redact? }— 导出会话。返回产物路径与合规摘要。如需单次导出不脱敏可传redact: false。session_export_list { query?, sessionId?, format?, before?, after?, limit? }— 列出/检索归档。export_delete { target }— 按归档 id / 文件名 / 相对路径删除。sanitize_config { action?, sample? }—show显示当前规则,或test对示例文本执行脱敏。
斜杠命令
/session-export [format] [--id=<session>] [--no-redact]
/session-export-list [query] [--format=<f>] [--limit=<n>] [--id=<session>]
/export-delete <id|path|filename>
/sanitize-config [--test <text>]
/export-auditPDF 生成方案
pdf 为可选且刻意保持轻量:
1. 会话先渲染为打印就绪、自包含的 HTML 文件(内嵌 CSS、meta CSP、无脚本、@media print 规则)。 2. 当 pdf.engine 为 chrome(或 auto)时,插件通过 --headless --print-to-pdf 驱动 headless Chromium 系列浏览器(优先 chromePath 或 CHROME_PATH,其次常见安装路径)。 3. 若找不到浏览器二进制,则归档该 HTML 并给出提示——打开后使用系统“打印为 PDF”即可。
这样可避免引入沉重的 PDF 依赖(不随包内嵌原生渲染器)。
合规哈希
contentHash 为脱敏后对话记录的规范 JSON-Lines 序列化的 sha256(不含文件头),因此同一脱敏记录无论以何种格式导出,哈希都一致。
开发
npm install
npm test # node --test 运行 test/*.test.ts(直接跑 .ts 需 Node 24+)
npm run typecheck
npm run build # tsc → dist/目录结构:
src/
index.ts # bundle 入口:name / inject / apply
commands.ts # 斜杠命令定义
tools.ts # ctx.tools 定义与注册
adapter/ # 薄薄的 dsh<->core 桥接层(backend、types、defineTool)
engine.ts # 导出流水线编排
config.ts # 配置结构 + 归一化
core/ # 与 harness 解耦的库(./core 子路径)
fold.ts # 事件日志 → 对话文档
redact.ts # 确定性脱敏引擎
archive.ts # 磁盘归档、索引、分片、路径穿越防护
render/ # markdown / jsonl / html / pdf
meta.ts # 合规文件头
audit.ts # 趋势/审计聚合
filenames.ts # 跨平台安全文件名
hash.ts # sha256 / 指纹许可证
[MIT](./LICENSE)