{"_id":"@danglong0313/dsh-history-sync","_rev":"4-a1c15a7e9fa97b71adabe4d8c3fd3eea","name":"@danglong0313/dsh-history-sync","dist-tags":{"latest":"0.2.1"},"versions":{"0.1.0":{"name":"@danglong0313/dsh-history-sync","version":"0.1.0","license":"MIT","_id":"@danglong0313/dsh-history-sync@0.1.0","maintainers":[{"name":"danglong0313","email":"dl090313@163.com"}],"dsh":{"bundle":{"patch":"./cordis.patch.yml"}},"dist":{"shasum":"eaf31a5d60046ed628f6042e48a5d9cf6cc9a2fb","tarball":"https://registry.npmjs.org/@danglong0313/dsh-history-sync/-/dsh-history-sync-0.1.0.tgz","fileCount":40,"integrity":"sha512-MKPpcL0+YqMlWmzNql9jOYZ7UR1FB7n04HGmz+MMDttQvCy2Ksf3kwPt7kQEerVISr2WS9FJifL+tye9hJ4vjg==","signatures":[{"sig":"MEUCIQCjjhxeY2o0TggQxOBIrbTlAEZQTnyQ9z+Nb+RaaBMxUwIgRJ/0e+/Oxs9XKgLq9fZlNHVV3BYmi1avv3ECTeczzYo=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":128197},"main":"./lib/index.js","type":"module","types":"./lib/index.d.ts","engines":{"node":"^22.19.0 || >=24.0.0"},"exports":{".":{"types":"./lib/index.d.ts","default":"./lib/index.js"}},"gitHead":"ba99fe49a21962d8018eddfd0c48c63c83adddb8","scripts":{"test":"vitest run","build":"tsc -p tsconfig.build.json","clean":"node scripts/clean.mjs","prepack":"npm run clean && npm run build","typecheck":"tsc -p tsconfig.json --noEmit","test:coverage":"vitest run --coverage"},"_npmUser":{"name":"danglong0313","email":"dl090313@163.com"},"_npmVersion":"11.13.0","description":"Read-only Codex and Claude history importer for DeepSeek Harness","directories":{},"_nodeVersion":"24.13.0","dependencies":{"zod":"4.4.3","@anthropic-ai/sdk":"0.117.1","@deepseek-ai/cordis":"4.0.1","@deepseek-ai/dsh-llm":"0.1.0-rc.6","@deepseek-ai/dsh-brand":"0.1.0-rc.6","@deepseek-ai/dsh-scope":"0.1.0-rc.6","@deepseek-ai/dsh-session":"0.1.0-rc.6","@deepseek-ai/dsh-timeout":"0.1.0-rc.6","@deepseek-ai/schemastery":"3.18.1","@modelcontextprotocol/sdk":"1.30.0","@deepseek-ai/dsh-workspace":"0.1.0-rc.6","@deepseek-ai/dsh-attachment":"0.1.0-rc.6","@deepseek-ai/dsh-home-paths":"0.1.0-rc.6","@deepseek-ai/dsh-invariants":"0.1.0-rc.6","@anthropic-ai/claude-agent-sdk":"0.3.233","@deepseek-ai/dsh-typert-protocol":"0.1.0-rc.6"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vitest":"^4.1.8","typescript":"^6.0.3","@types/node":"^24.3.0","@deepseek-ai/cordis":"4.0.1","@vitest/coverage-v8":"^4.1.8","@deepseek-ai/dsh-llm":"0.1.0-rc.6","@deepseek-ai/dsh-session":"0.1.0-rc.6","@deepseek-ai/schemastery":"3.18.1","@deepseek-ai/dsh-commands":"0.1.0-rc.6","@deepseek-ai/dsh-workspace":"0.1.0-rc.6","@deepseek-ai/dsh-home-paths":"0.1.0-rc.6","@deepseek-ai/dsh-session-persistence":"0.1.0-rc.6","@deepseek-ai/dsh-session-persistence-jsonl":"0.1.0-rc.6"},"_npmOperationalInternal":{"tmp":"tmp/dsh-history-sync_0.1.0_1786820255507_0.903771832501786","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"@danglong0313/dsh-history-sync","version":"0.1.1","license":"MIT","_id":"@danglong0313/dsh-history-sync@0.1.1","maintainers":[{"name":"danglong0313","email":"dl090313@163.com"}],"dsh":{"bundle":{"patch":"./cordis.patch.yml"}},"dist":{"shasum":"f28081f058b4b5219ee4f1bc1d9f5d99f2973071","tarball":"https://registry.npmjs.org/@danglong0313/dsh-history-sync/-/dsh-history-sync-0.1.1.tgz","fileCount":40,"integrity":"sha512-Frq3VrmKuEXo4tfhtXS36CHHGJHEeaOe2avMBWLQbea0v3EreZes20/rhAKSNi5429IGdtvI3kO9YGt0pUhNlQ==","signatures":[{"sig":"MEUCIQDJXY6HlXH9wgL2MMdq83d6sPVp7kF3Umh0D1XT0hYpIgIgNjLmaokGmtK01xosDBTU174ScXZ/jiwyTfYBUQAGtU4=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":138735},"main":"./lib/index.js","type":"module","types":"./lib/index.d.ts","engines":{"node":"^22.19.0 || >=24.0.0"},"exports":{".":{"types":"./lib/index.d.ts","default":"./lib/index.js"}},"gitHead":"dce8529d3de013f180dbc9633a47b1719512cfea","scripts":{"test":"vitest run","build":"tsc -p tsconfig.build.json","clean":"node scripts/clean.mjs","prepack":"npm run clean && npm run build","typecheck":"tsc -p tsconfig.json --noEmit","test:coverage":"vitest run --coverage"},"_npmUser":{"name":"danglong0313","email":"dl090313@163.com"},"_npmVersion":"11.13.0","description":"Read-only Codex and Claude history importer for DeepSeek Harness","directories":{},"_nodeVersion":"24.13.0","dependencies":{"zod":"4.4.3","@anthropic-ai/sdk":"0.117.1","@deepseek-ai/cordis":"4.0.1","@deepseek-ai/dsh-llm":"0.1.0-rc.6","@deepseek-ai/dsh-brand":"0.1.0-rc.6","@deepseek-ai/dsh-scope":"0.1.0-rc.6","@deepseek-ai/dsh-session":"0.1.0-rc.6","@deepseek-ai/dsh-timeout":"0.1.0-rc.6","@deepseek-ai/schemastery":"3.18.1","@modelcontextprotocol/sdk":"1.30.0","@deepseek-ai/dsh-workspace":"0.1.0-rc.6","@deepseek-ai/dsh-attachment":"0.1.0-rc.6","@deepseek-ai/dsh-home-paths":"0.1.0-rc.6","@deepseek-ai/dsh-invariants":"0.1.0-rc.6","@anthropic-ai/claude-agent-sdk":"0.3.233","@deepseek-ai/dsh-typert-protocol":"0.1.0-rc.6"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vitest":"^4.1.8","typescript":"^6.0.3","@types/node":"^24.3.0","@deepseek-ai/cordis":"4.0.1","@vitest/coverage-v8":"^4.1.8","@deepseek-ai/dsh-llm":"0.1.0-rc.6","@deepseek-ai/dsh-session":"0.1.0-rc.6","@deepseek-ai/schemastery":"3.18.1","@deepseek-ai/dsh-commands":"0.1.0-rc.6","@deepseek-ai/dsh-workspace":"0.1.0-rc.6","@deepseek-ai/dsh-home-paths":"0.1.0-rc.6","@deepseek-ai/dsh-session-persistence":"0.1.0-rc.6","@deepseek-ai/dsh-session-persistence-jsonl":"0.1.0-rc.6"},"_npmOperationalInternal":{"tmp":"tmp/dsh-history-sync_0.1.1_1786852252114_0.2937631871775257","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@danglong0313/dsh-history-sync","version":"0.2.0","keywords":["deepseek-harness","dsh","codex","claude-code","history-sync"],"license":"MIT","_id":"@danglong0313/dsh-history-sync@0.2.0","maintainers":[{"name":"danglong0313","email":"dl090313@163.com"}],"homepage":"https://github.com/danglong0313/dsh-history-sync#readme","bugs":{"url":"https://github.com/danglong0313/dsh-history-sync/issues"},"dsh":{"bundle":{"patch":"./cordis.patch.yml"},"client":{"inject":["@deepseek-ai/dsh-client-runtime","@deepseek-ai/dsh-client-ui-settings-plugins","@deepseek-ai/dsh-client-ui-slots"],"platform":"web"}},"dist":{"shasum":"fe5cde5384cfe2f8285bffc68ff496ae80628654","tarball":"https://registry.npmjs.org/@danglong0313/dsh-history-sync/-/dsh-history-sync-0.2.0.tgz","fileCount":47,"integrity":"sha512-C80TLzIJzwgGtYaDiamSshUeG0BQ5xaCuUEZ8ZCUEsy0LG/EfbpX7jsdNBBv0DtOzqDokt9xh9xml6HfJCZtsQ==","signatures":[{"sig":"MEQCICLI8Ooa+T6hpruP8leRbpbs+ApdfYWLztNEw/iWOyZ+AiBiP1ROAjF0n1kSwbEg0DafRRIdOZdxcP8y1AIqWgaQFA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":180605},"main":"./lib/index.js","type":"module","types":"./lib/index.d.ts","engines":{"node":"^22.19.0 || >=24.0.0"},"exports":{".":{"types":"./lib/index.d.ts","default":"./lib/index.js"},"./client":{"types":"./lib/client.d.ts","default":"./lib/client.js"},"./package.json":"./package.json"},"gitHead":"da3e58bd8e7748473e889f0c2f73001a12642a2f","scripts":{"test":"vitest run","build":"tsc -p tsconfig.build.json && node scripts/build-client.mjs","clean":"node scripts/clean.mjs","prepack":"npm run clean && npm run build","typecheck":"tsc -p tsconfig.json --noEmit","test:coverage":"vitest run --coverage"},"_npmUser":{"name":"danglong0313","email":"dl090313@163.com"},"repository":{"url":"git+https://github.com/danglong0313/dsh-history-sync.git","type":"git"},"_npmVersion":"11.13.0","description":"Read-only Codex and Claude history importer for DeepSeek Harness","directories":{},"_nodeVersion":"24.13.0","dependencies":{"zod":"4.4.3","@anthropic-ai/sdk":"0.117.1","@deepseek-ai/cordis":"4.0.1","@deepseek-ai/dsh-llm":"0.1.0-rc.6","@deepseek-ai/dsh-brand":"0.1.0-rc.6","@deepseek-ai/dsh-scope":"0.1.0-rc.6","@deepseek-ai/dsh-session":"0.1.0-rc.6","@deepseek-ai/dsh-timeout":"0.1.0-rc.6","@deepseek-ai/schemastery":"3.18.1","@modelcontextprotocol/sdk":"1.30.0","@deepseek-ai/dsh-workspace":"0.1.0-rc.6","@deepseek-ai/dsh-attachment":"0.1.0-rc.6","@deepseek-ai/dsh-home-paths":"0.1.0-rc.6","@deepseek-ai/dsh-invariants":"0.1.0-rc.6","@anthropic-ai/claude-agent-sdk":"0.3.233","@deepseek-ai/dsh-typert-protocol":"0.1.0-rc.6"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vitest":"^4.1.8","typescript":"^6.0.3","@types/node":"^24.3.0","@deepseek-ai/cordis":"4.0.1","@vitest/coverage-v8":"^4.1.8","@deepseek-ai/dsh-llm":"0.1.0-rc.6","@deepseek-ai/dsh-session":"0.1.0-rc.6","@deepseek-ai/schemastery":"3.18.1","@deepseek-ai/dsh-commands":"0.1.0-rc.6","@deepseek-ai/dsh-workspace":"0.1.0-rc.6","@deepseek-ai/dsh-home-paths":"0.1.0-rc.6","@deepseek-ai/dsh-session-persistence":"0.1.0-rc.6","@deepseek-ai/dsh-session-persistence-jsonl":"0.1.0-rc.6"},"_npmOperationalInternal":{"tmp":"tmp/dsh-history-sync_0.2.0_1786861564302_0.00033264825371714934","host":"s3://npm-registry-packages-npm-production"}},"0.2.1":{"name":"@danglong0313/dsh-history-sync","version":"0.2.1","description":"Read-only Codex and Claude history importer for DeepSeek Harness","repository":{"type":"git","url":"git+https://github.com/danglong0313/dsh-history-sync.git"},"homepage":"https://github.com/danglong0313/dsh-history-sync#readme","bugs":{"url":"https://github.com/danglong0313/dsh-history-sync/issues"},"keywords":["deepseek-harness","dsh","codex","claude-code","history-sync"],"license":"MIT","type":"module","main":"./lib/index.js","types":"./lib/index.d.ts","exports":{".":{"types":"./lib/index.d.ts","default":"./lib/index.js"},"./client":{"types":"./lib/client.d.ts","default":"./lib/client.js"},"./package.json":"./package.json"},"scripts":{"build":"tsc -p tsconfig.build.json && node scripts/build-client.mjs","clean":"node scripts/clean.mjs","prepack":"npm run clean && npm run build","test":"vitest run","test:coverage":"vitest run --coverage","typecheck":"tsc -p tsconfig.json --noEmit"},"engines":{"node":"^22.19.0 || >=24.0.0"},"dsh":{"bundle":{"patch":"./cordis.patch.yml"},"client":{"inject":["@deepseek-ai/dsh-client-runtime","@deepseek-ai/dsh-client-ui-settings-plugins","@deepseek-ai/dsh-client-ui-slots"],"platform":"web"}},"publishConfig":{"access":"public"},"dependencies":{"@anthropic-ai/claude-agent-sdk":"0.3.233","@anthropic-ai/sdk":"0.117.1","@deepseek-ai/cordis":"4.0.1","@deepseek-ai/dsh-attachment":"0.1.0-rc.6","@deepseek-ai/dsh-brand":"0.1.0-rc.6","@deepseek-ai/dsh-home-paths":"0.1.0-rc.6","@deepseek-ai/dsh-invariants":"0.1.0-rc.6","@deepseek-ai/dsh-llm":"0.1.0-rc.6","@deepseek-ai/dsh-scope":"0.1.0-rc.6","@deepseek-ai/dsh-session":"0.1.0-rc.6","@deepseek-ai/dsh-timeout":"0.1.0-rc.6","@deepseek-ai/dsh-typert-protocol":"0.1.0-rc.6","@deepseek-ai/dsh-workspace":"0.1.0-rc.6","@deepseek-ai/schemastery":"3.18.1","@modelcontextprotocol/sdk":"1.30.0","zod":"4.4.3"},"devDependencies":{"@deepseek-ai/cordis":"4.0.1","@deepseek-ai/dsh-commands":"0.1.0-rc.6","@deepseek-ai/dsh-home-paths":"0.1.0-rc.6","@deepseek-ai/dsh-llm":"0.1.0-rc.6","@deepseek-ai/dsh-session":"0.1.0-rc.6","@deepseek-ai/dsh-session-persistence":"0.1.0-rc.6","@deepseek-ai/dsh-session-persistence-jsonl":"0.1.0-rc.6","@deepseek-ai/dsh-workspace":"0.1.0-rc.6","@deepseek-ai/schemastery":"3.18.1","@types/node":"^24.3.0","@vitest/coverage-v8":"^4.1.8","typescript":"^6.0.3","vitest":"^4.1.8"},"gitHead":"07ddd8620a62c053011d45fea73943ea9c95f5ff","_id":"@danglong0313/dsh-history-sync@0.2.1","_nodeVersion":"24.13.0","_npmVersion":"11.13.0","dist":{"integrity":"sha512-x1Pq/ohB315KKcMYufvBISTYSx53pEiUq4uWBbACcmmprb3uJ2TTcIZhfXy4fZLYAL41+ExrKBHjOxKwZ5kUxQ==","shasum":"330aa9ee0411de5bedafa50f6a123bc0c4a016cb","tarball":"https://registry.npmjs.org/@danglong0313/dsh-history-sync/-/dsh-history-sync-0.2.1.tgz","fileCount":47,"unpackedSize":182988,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIHaDTnbWN17Ugn8pP5z/L2ETmV8Pc6zLHjXnnhGe8B0KAiEA6oRGIvxIHb8T6vMhz7wjMnyQcukHKnFcLMlaDaGFoGk="}]},"_npmUser":{"name":"danglong0313","email":"dl090313@163.com"},"directories":{},"maintainers":[{"name":"danglong0313","email":"dl090313@163.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/dsh-history-sync_0.2.1_1787106466586_0.06291792615848091"},"_hasShrinkwrap":false}},"time":{"created":"2026-08-15T18:57:35.386Z","modified":"2026-08-19T02:27:46.830Z","0.1.0":"2026-08-15T18:57:35.646Z","0.1.1":"2026-08-16T03:50:52.261Z","0.2.0":"2026-08-16T06:26:04.448Z","0.2.1":"2026-08-19T02:27:46.710Z"},"bugs":{"url":"https://github.com/danglong0313/dsh-history-sync/issues"},"license":"MIT","homepage":"https://github.com/danglong0313/dsh-history-sync#readme","keywords":["deepseek-harness","dsh","codex","claude-code","history-sync"],"repository":{"type":"git","url":"git+https://github.com/danglong0313/dsh-history-sync.git"},"description":"Read-only Codex and Claude history importer for DeepSeek Harness","maintainers":[{"name":"danglong0313","email":"dl090313@163.com"}],"readme":"# @danglong0313/dsh-history-sync\n\n[![npm version](https://img.shields.io/npm/v/@danglong0313/dsh-history-sync.svg)](https://www.npmjs.com/package/@danglong0313/dsh-history-sync)\n[![license](https://img.shields.io/npm/l/@danglong0313/dsh-history-sync.svg)](./LICENSE)\n\n把本机 Codex 与 Claude Code 历史任务以只读镜像的形式单向导入 DeepSeek Harness（DSH）。插件只调用公开接口：Codex 使用 `codex app-server` 的 stdio 协议，Claude 使用官方 Claude Agent SDK；它不会读取、修改或重写两者的私有历史 JSONL。\n\n- npm：[@danglong0313/dsh-history-sync](https://www.npmjs.com/package/@danglong0313/dsh-history-sync)\n- 源码：[github.com/danglong0313/dsh-history-sync](https://github.com/danglong0313/dsh-history-sync)\n- 问题反馈：[GitHub Issues](https://github.com/danglong0313/dsh-history-sync/issues)\n- 核心宿主上游：[deepseek-ai/deepseek-harness](https://github.com/deepseek-ai/deepseek-harness)\n- 已适配桌面端：[anywhere-labs/deepseek-harness-desktop](https://github.com/anywhere-labs/deepseek-harness-desktop)\n\n## 上游项目与项目关系\n\n本插件的核心宿主上游是 [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness)。本文所称的 DSH Desktop 特指 [anywhere-labs/deepseek-harness-desktop](https://github.com/anywhere-labs/deepseek-harness-desktop)：它是基于 DeepSeek Harness 构建的社区桌面版本，负责本地 Harness 服务、桌面窗口、系统托盘和桌面插件管理。\n\n本仓库是独立开发和发布的第三方社区插件，不属于、也不代表 `deepseek-ai` 或 `anywhere-labs`。插件通过 DSH 当前公开的插件、Session 和持久化扩展点工作，不要求把代码写入或修改上述上游仓库。\n\n## 功能概览\n\n- 单向、只读镜像 Codex 与 Claude Code 的用户/助手对话，不写回来源。\n- 默认预览、默认不自动同步、默认只扫描最近 30 天。\n- 在 `设置 → 插件 → 插件配置 → History Sync` 中直接配置和启用自动同步。\n- 自动按原工作目录创建或复用 DSH Workspace，在左侧项目栏分组显示。\n- 使用内容指纹、追加水位和 generation 处理重复同步、增量追加及上游历史重写。\n- 过滤 system/developer、reasoning、工具调用、审批、命令输出和 Claude 控制标签，避免把协议消息当作真实聊天。\n\n## 兼容性\n\n- 已验证 DSH：`0.1.0-rc.6`\n- Node.js：`^22.19.0` 或 `>=24`\n- Claude Agent SDK：插件固定携带 `0.3.233`\n- Codex：需要支持稳定 `thread/list` 与 `thread/read` 的当前官方 Codex；Windows 下可自动发现 Codex Desktop 内置程序\n\nDSH 仍处于预发布阶段，Session 格式不保证跨预发布版本兼容。升级 DSH 后，请先在隔离 profile 中重新执行预览和安装验证。\n\n## 安装与卸载\n\n### DSH Desktop（推荐）\n\n这里的 DSH Desktop 指 [anywhere-labs/deepseek-harness-desktop](https://github.com/anywhere-labs/deepseek-harness-desktop)。完全退出桌面应用后，在 PowerShell 中执行：\n\n```powershell\ndsh plugin --profile desktop add @danglong0313/dsh-history-sync@0.2.0\ndsh --profile desktop --dump-config\n```\n\n第二条命令应显示固定 ID 为 `history-sync`、包名为 `@danglong0313/dsh-history-sync` 的配置层。重新启动 DSH Desktop 后，可在 `设置 → 插件 → 插件配置 → History Sync` 中配置插件。\n\nDSH 的插件安装是按 profile 隔离的：安装到 `web` 不会自动安装到 `desktop`，反之亦然。`dsh plugin` 会维护对应 profile 的 `package.json` 与 `dsh.profile.bundles`；不要手工编辑它们。\n\n### 浏览器 Web profile（可选）\n\n仅在使用 `dsh web` 或 `dsh --profile web` 时执行：\n\n```powershell\ndsh plugin --profile web add @danglong0313/dsh-history-sync@0.2.0\ndsh --profile web --dump-config\n```\n\n升级到最新版：\n\n```powershell\ndsh plugin --profile desktop update @danglong0313/dsh-history-sync\n# 如果同时使用 Web profile：\ndsh plugin --profile web update @danglong0313/dsh-history-sync\n```\n\n卸载：\n\n```powershell\ndsh plugin --profile desktop remove @danglong0313/dsh-history-sync\n# 如果同时安装在 Web profile：\ndsh plugin --profile web remove @danglong0313/dsh-history-sync\n```\n\n## 在 DSH 设置中配置\n\n安装并启动 DSH 后，打开：\n\n```text\n设置 → 插件 → 插件配置 → History Sync\n```\n\n这里可以直接选择 Codex/Claude 来源、最近天数、单次任务上限、工作目录过滤、项目分组、允许实际导入和自动同步。点击“保存并应用”后无需重启 DSH；开启“自动同步”会同时退出预览模式、立即启动一次同步，并在同步完成后自动刷新左侧项目栏。\n\n界面配置作为插件自有覆盖层保存在 `stateDirectory/settings.json`；同步游标和去重状态仍单独保存在 `stateDirectory/state.json`。两者都不会写入 `cordis.patch.yml`，也不会包含消息正文或密钥。卸载插件不会自动删除这些运行数据。\n\n## 首次预览与手动同步\n\n默认 `previewOnly: true` 且 `autoSync: false`。启动已经安装插件的 Desktop 或 Web profile，在任意 DSH 任务里执行：\n\n```text\n/history-sync preview\n```\n\n预览只报告发现、选择、新建、增量和新 generation 的数量，不创建 DSH Session，也不写同步状态。确认范围后，推荐在上述 History Sync 配置卡中开启“允许实际导入”，再执行：\n\n```text\n/history-sync run\n```\n\n不带参数的 `/history-sync` 等同于预览。自动同步默认关闭；先完成预览，再在配置卡中开启“自动同步”。插件会立即同步一次，随后按 `syncIntervalMinutes` 做幂等增量同步；导入的 Session 会按原工作目录出现在左侧项目/会话列表中，无需再输入命令。\n\n## 高级配置与完整 patch 覆盖\n\n普通设置请优先使用界面。部署级参数（Codex 命令、协议分页、超时、状态目录和消息纳入策略）仍可通过 profile patch 配置。DSH patch 对同一 ID 的 `config` 是整项替换，不是深度合并，因此覆盖时必须重述完整配置：\n\n```yaml\n- id: history-sync\n  name: '@danglong0313/dsh-history-sync'\n  config:\n    codexEnabled: true\n    claudeEnabled: true\n    autoSync: false\n    syncIntervalMinutes: 60\n    importDays: 30\n    maxSessionsPerSync: 50\n    workspaceRoots: []\n    groupByWorkspace: true\n    readOnly: true\n    previewOnly: true\n    stateDirectory: !!js dshHomePath('history-sync')\n    codexCommand: auto\n    codexArgs:\n      - app-server\n    codexPageSize: 100\n    codexRequestTimeoutMs: 30000\n    codexShutdownTimeoutMs: 3000\n    codexSourceKinds:\n      - cli\n      - vscode\n      - appServer\n    claudePageSize: 100\n    claudeIncludeSystemMessages: false\n    claudeIncludeWorktrees: true\n    claudeIncludeProgrammatic: true\n```\n\n字段说明：\n\n- `codexEnabled` / `claudeEnabled`：启用对应来源，至少开启一个。\n- `importDays`：只考虑最近 N 天，默认 30，不会无限扫描全部历史。\n- `maxSessionsPerSync`：两种来源合并排序后，单次最多处理的任务数。\n- `workspaceRoots`：可选绝对目录列表；任务工作目录必须等于或位于其中一个目录下。\n- `groupByWorkspace`：为现存的原工作目录创建或复用 DSH Workspace，并把镜像 Session 加入对应项目分组。\n- `readOnly`：v1 必须为 `true`；配置为 `false` 会在插件加载时失败。\n- `previewOnly`：为 `true` 时拒绝实际导入。\n- `stateDirectory`：插件自有界面设置、同步游标、fingerprint、pending 写前记录和 generation 状态目录；消息正文不写入这里。\n- `codexSourceKinds` 默认只纳入交互式主任务（`cli`、`vscode`、`appServer`）。`exec`、`subAgent*` 和 `unknown` 容易包含自动化、子代理提示词或协议消息，只有明确需要时才应手动加入。\n- `codexCommand: auto`：先使用 `DSH_HISTORY_SYNC_CODEX`，再查找 PATH；Windows 下还会通过 AppX 注册信息自动定位 Codex Desktop 内置的官方 `codex.exe`。由于 WindowsApps ACL 会阻止普通 DSH 子进程直接启动该路径，插件会把同一官方二进制缓存到 `stateDirectory/codex-bin` 后运行；也可改为官方可执行文件的绝对路径。\n- 其余 Codex/Claude 字段控制官方客户端分页、超时和纳入的公开来源类型。\n\n默认只镜像用户可见的用户文本和助手文本。Codex 的 system/developer 消息、reasoning、工具调用、审批和命令输出不会伪装成聊天消息；Claude 的 system、thinking、tool use/result，以及以 `<command-name>`、`<local-command-stdout>`、`<ide_opened_file>` 等 XML 风格控制标签开头的记录也会跳过。不完整且尚无助手回复的上游 turn 会等到完成后再导入。\n\n界面只暴露日常、安全的字段；保存时会原子写入并立即校验。错误配置会明确拒绝，例如两个来源均关闭、相对工作目录、关闭只读模式，或在仍为预览模式时开启自动同步。\n\n## 幂等与历史重写\n\n每个标准化 turn 都有内容 fingerprint。重复运行不会重复追加相同消息；上游仅追加完整 turn 时，插件会继续写入同一个 DSH Session。若上游历史缩短、压缩、回退或已有内容改变，插件不会重写 DSH 的追加日志，而是创建新的 import generation，并保留旧 generation。\n\n来源、上游任务 ID、原始工作目录、来源更新时间/修订、导入时间、导入版本、generation 与 fingerprint 保存在 `stateDirectory/state.json`。这些元数据不会伪装成可见聊天消息，也不会写入 `cordis.patch.yml`。\n\n## 隐私与安全\n\n**导入会在 DSH 持久化中产生第二份历史副本。** 原任务可能包含源码、命令输出、`.env` 内容、凭据或其他敏感信息；启用前请检查 DSH 的存储位置、访问权限、备份和保留策略。删除 Codex/Claude 原任务不会自动删除 DSH 副本，反之亦然。\n\n插件不会把密钥写入 patch 或同步状态，不记录消息正文到插件日志，也不会修改 Codex、Claude 的原始历史。同步状态本身仍包含上游任务 ID和原始工作目录，应按敏感运行数据保护。\n\n## 常见问题\n\n### 设置中没有 History Sync\n\n确认安装的是 `0.2.0` 或更高版本，并检查插件是否安装到了当前应用实际使用的 profile。DSH Desktop 使用 `desktop`；只安装到 `web` 不会出现在 Desktop 设置中。完全退出并重新启动 DSH Desktop，然后执行：\n\n```powershell\ndsh plugin --profile desktop add @danglong0313/dsh-history-sync@0.2.0\ndsh --profile desktop --dump-config\n```\n\n如果你运行的是浏览器 Web profile，则改用：\n\n```powershell\ndsh --profile web --dump-config\n```\n\n出现 `EPERM` 时，先确认 DSH Desktop 已经从系统托盘完全退出，再重新执行安装命令。\n\n### `spawn codex ENOENT` 或 Codex 无法启动\n\n默认 `codexCommand: auto` 会先检查 `DSH_HISTORY_SYNC_CODEX` 和 PATH，再自动发现 Windows Codex Desktop。WindowsApps 中的程序无法被普通子进程直接启动时，插件会把同一官方二进制缓存到 `stateDirectory/codex-bin` 后运行。仍失败时，可以把 `codexCommand` 配置为官方 `codex.exe` 的绝对路径。\n\n### 会话出现在“未分组”\n\n只有来源工作目录存在且 `groupByWorkspace: true` 时，插件才能创建或复用对应 Workspace。工作目录已经删除、不可访问或来源没有提供目录时，会话仍会导入，但可能显示在“未分组”。\n\n### 卸载后历史副本还在\n\n卸载只移除插件包，不会删除已经导入的 DSH Session，也不会删除 `stateDirectory` 中的设置和同步状态。请先确认备份和保留需求，再从 DSH 和文件系统中分别清理不再需要的数据。\n\n## 限制\n\n- 这是单向历史镜像，不是双向同步，也不能从 DSH 无损恢复 Codex/Claude 的模型、工具进程、审批、沙箱或运行状态。\n- DSH rc.6 没有公开的 Session 级“禁止继续对话”锁。镜像会明确标注只读并且永不写回上游，但用户仍可能在 DSH 中从该副本继续新对话；这些新内容仅属于 DSH。\n- v1 在 turn 边界增量导入。尚未完成的最后一个 turn 后续发生变化时，会被视为重写并创建新 generation。\n- Codex provider 使用稳定的 `thread/list` 和 `thread/read(includeTurns: true)`；不会启用实验性的分页 turn/item API。\n- Claude provider 使用 `listSessions()` 和分页的 `getSessionMessages()`；当前不需要调用 `getSessionInfo()`。\n\n## 开发验证\n\n```powershell\nnpm run typecheck\nnpm test\nnpm run build\nnpm pack --dry-run\n```\n\n测试只使用合成的 Codex App Server 与 Claude SDK 数据，不包含真实历史、私人绝对路径或凭据。\n\n## 版本说明\n\n### 0.2.0\n\n- 新增 DSH 内置“插件配置”页面。\n- 支持从界面开启自动同步，并在完成后刷新左侧项目栏。\n- 增加插件自有、原子写入的安全配置覆盖层。\n- 保留 0.1.1 的 Windows Codex Desktop 自动发现与官方二进制缓存机制。\n\n## 参与开发\n\n欢迎通过 [Issues](https://github.com/danglong0313/dsh-history-sync/issues) 报告可复现问题。提交日志或测试数据前请先移除源码、绝对私人路径、Token、Cookie、API Key 和真实历史正文。\n\n## License\n\nMIT\n","readmeFilename":"README.md"}