{"_id":"@asong111/dsh-cloud-sync","_rev":"6-e369d7b3e9f43c43dee3d18d15f3c48d","name":"@asong111/dsh-cloud-sync","dist-tags":{"latest":"0.3.12"},"versions":{"0.1.0":{"name":"@asong111/dsh-cloud-sync","version":"0.1.0","license":"Apache-2.0","_id":"@asong111/dsh-cloud-sync@0.1.0","maintainers":[{"name":"asong111","email":"asong1232021@163.com"}],"homepage":"https://github.com/ASong111/dsh-cloud-sync#readme","bugs":{"url":"https://github.com/ASong111/dsh-cloud-sync/issues"},"dsh":{"bundle":{"patch":"./cordis.patch.yml"},"client":{"inject":["@deepseek-ai/dsh-client-runtime","@deepseek-ai/dsh-client-connection","@deepseek-ai/dsh-client-ui-settings"],"platform":"web"}},"dist":{"shasum":"903fc0c31264db76f55ba2a2435970847ad39027","tarball":"https://registry.npmjs.org/@asong111/dsh-cloud-sync/-/dsh-cloud-sync-0.1.0.tgz","fileCount":24,"integrity":"sha512-X5I+ojn/JOvdiuJxpTA8gJQqAI1j6cPpllNLOk4iUG+nlSNRmqwp65JKEA7MSZMBN9P9nD6kbLuNRjagMXy5/Q==","signatures":[{"sig":"MEUCIQDBN15upXBHfUI3Oqdk23Ya+19HVUWnIG7WF5U2fdzdZQIgPAop8fFbBhJ8e4jLnGkeVKkivWTgK/GyyUjs1UmOnEY=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":1113424},"main":"dist/index.mjs","type":"module","types":"dist/index.d.mts","engines":{"node":"^22.19.0 || >=24.0.0"},"exports":{".":{"types":"./dist/index.d.mts","default":"./dist/index.mjs"},"./client":{"types":"./dist/client.d.mts","default":"./dist/client.mjs"},"./package.json":"./package.json"},"gitHead":"d3e55c1671ae7775fe0594d6a9524b89ce9eeec0","scripts":{"test":"vitest run","build":"tsdown","watch":"tsdown --watch","bundle":"tsdown","typecheck":"tsc --noEmit"},"_npmUser":{"name":"asong111","email":"asong1232021@163.com"},"repository":{"url":"git+https://github.com/ASong111/dsh-cloud-sync.git","type":"git"},"_npmVersion":"10.9.4","description":"Cloud sync for the dsh web GUI: bidirectionally sync plugins, config, agent-presets, skills and task history between two machines through a private Git remote (default SSH). Auto-installs dependencies after pull; excludes plaintext secrets (credentials/SS","directories":{},"_nodeVersion":"22.22.0","dependencies":{"schemastery":"^3.18.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsdown":"0.22.2","vitest":"^3.0.0","typescript":"~5.7.2","@types/node":"^22.20.0","@types/react":"~18.3.1","@types/react-dom":"^18.3.5","@deepseek-ai/cordis":"^4.0.1","@deepseek-ai/dsh-llm":"^0.1.0-rc.7","@deepseek-ai/dsh-tools":"^0.1.0-rc.7","@deepseek-ai/dsh-system-prompt":"^0.1.0-rc.7","@deepseek-ai/dsh-host-webserver":"^0.1.0-rc.7"},"peerDependencies":{"react":"^18.2.0","react-dom":"^18.2.0"},"_npmOperationalInternal":{"tmp":"tmp/dsh-cloud-sync_0.1.0_1787133994907_0.1640227207425229","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@asong111/dsh-cloud-sync","version":"0.2.0","license":"Apache-2.0","_id":"@asong111/dsh-cloud-sync@0.2.0","maintainers":[{"name":"asong111","email":"asong1232021@163.com"}],"homepage":"https://github.com/ASong111/dsh-cloud-sync#readme","bugs":{"url":"https://github.com/ASong111/dsh-cloud-sync/issues"},"dsh":{"bundle":{"patch":"./cordis.patch.yml"},"client":{"inject":["@deepseek-ai/dsh-client-runtime","@deepseek-ai/dsh-client-connection","@deepseek-ai/dsh-client-ui-settings"],"platform":"web"}},"dist":{"shasum":"afde6e7b5074fc17d324ef310888af91adc6a6e1","tarball":"https://registry.npmjs.org/@asong111/dsh-cloud-sync/-/dsh-cloud-sync-0.2.0.tgz","fileCount":24,"integrity":"sha512-UxdRkoHdYKHYuNN95q+bsXUlNVmUjjQx/L4aVDUaCaRTbllEx9JVA36xizl/3EBgLDJ4pZ+YVJpCcbBHwo6R6w==","signatures":[{"sig":"MEUCIQDoXfuKnUYI+MdzyLSsT5KBEw/1xv+w+lXEjXthMm9XnAIgQdQgAH/wsKy5UuHH1ftf2kINPN8VxjsQ00HXXkVcZdQ=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":1143282},"main":"dist/index.mjs","type":"module","types":"dist/index.d.mts","engines":{"node":"^22.19.0 || >=24.0.0"},"exports":{".":{"types":"./dist/index.d.mts","default":"./dist/index.mjs"},"./client":{"types":"./dist/client.d.mts","default":"./dist/client.mjs"},"./package.json":"./package.json"},"gitHead":"87c1f92db1f4e3bc0b9405cf43589f4071ec6f9c","scripts":{"test":"vitest run","build":"tsdown","watch":"tsdown --watch","bundle":"tsdown","typecheck":"tsc --noEmit"},"_npmUser":{"name":"asong111","email":"asong1232021@163.com"},"repository":{"url":"git+https://github.com/ASong111/dsh-cloud-sync.git","type":"git"},"_npmVersion":"10.9.4","description":"Cloud sync for the dsh web GUI: bidirectionally sync plugins, config, agent-presets, skills and task history between two machines through a private Git remote (default SSH). Auto-installs dependencies after pull; excludes plaintext secrets (credentials/SS","directories":{},"_nodeVersion":"22.22.0","dependencies":{"schemastery":"^3.18.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsdown":"0.22.2","vitest":"^3.0.0","typescript":"~5.7.2","@types/node":"^22.20.0","@types/react":"~18.3.1","@types/react-dom":"^18.3.5","@deepseek-ai/cordis":"^4.0.1","@deepseek-ai/dsh-llm":"^0.1.0-rc.7","@deepseek-ai/dsh-tools":"^0.1.0-rc.7","@deepseek-ai/dsh-system-prompt":"^0.1.0-rc.7","@deepseek-ai/dsh-host-webserver":"^0.1.0-rc.7"},"peerDependencies":{"react":"^18.2.0","react-dom":"^18.2.0"},"_npmOperationalInternal":{"tmp":"tmp/dsh-cloud-sync_0.2.0_1787219505667_0.7118555880517339","host":"s3://npm-registry-packages-npm-production"}},"0.2.1":{"name":"@asong111/dsh-cloud-sync","version":"0.2.1","license":"Apache-2.0","_id":"@asong111/dsh-cloud-sync@0.2.1","maintainers":[{"name":"asong111","email":"asong1232021@163.com"}],"homepage":"https://github.com/ASong111/dsh-cloud-sync#readme","bugs":{"url":"https://github.com/ASong111/dsh-cloud-sync/issues"},"dsh":{"bundle":{"patch":"./cordis.patch.yml"},"client":{"inject":[],"platform":"web"}},"dist":{"shasum":"79c4102a31c8beee9eb0fc53966c828d8abe7a8e","tarball":"https://registry.npmjs.org/@asong111/dsh-cloud-sync/-/dsh-cloud-sync-0.2.1.tgz","fileCount":23,"integrity":"sha512-v6JI64RjLCZkiZykxY75sIaeumItKft12dMrLws6LAMQn+lHrh9GK8EyTEENuZSsgyERztLM82wKCyp0VkZkVg==","signatures":[{"sig":"MEQCIF9z1U2XmZRjOI8H+Wc7sEW5ABe/BjCD7JIlzkz7RlVjAiBz9O7aT/tEb9xY9ysnxLusUyOM5CFuHj0P7k1kf9Y09Q==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":1146744},"main":"dist/index.mjs","type":"module","types":"dist/index.d.mts","engines":{"node":"^22.19.0 || >=24.0.0"},"exports":{".":{"types":"./dist/index.d.mts","default":"./dist/index.mjs"},"./client":{"types":"./dist/client.d.mts","default":"./dist/client.js"},"./package.json":"./package.json"},"gitHead":"aa1270a26882753f381d0a3bf6bd0a106da25e53","scripts":{"test":"vitest run","build":"tsdown","watch":"tsdown --watch","bundle":"tsdown","typecheck":"tsc --noEmit"},"_npmUser":{"name":"asong111","email":"asong1232021@163.com"},"repository":{"url":"git+https://github.com/ASong111/dsh-cloud-sync.git","type":"git"},"_npmVersion":"10.9.4","description":"Cloud sync for the dsh web GUI: bidirectionally sync plugins, config, agent-presets, skills and task history between two machines through a private Git remote (default SSH). Auto-installs dependencies after pull; excludes plaintext secrets (credentials/SS","directories":{},"_nodeVersion":"22.22.0","dependencies":{"schemastery":"^3.18.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsdown":"0.22.2","vitest":"^3.0.0","typescript":"~5.7.2","@types/node":"^22.20.0","@types/react":"~18.3.1","@types/react-dom":"^18.3.5","@deepseek-ai/cordis":"^4.0.1","@deepseek-ai/dsh-llm":"^0.1.0-rc.7","@deepseek-ai/dsh-tools":"^0.1.0-rc.7","@deepseek-ai/dsh-system-prompt":"^0.1.0-rc.7","@deepseek-ai/dsh-host-webserver":"^0.1.0-rc.7"},"peerDependencies":{"react":"^18.2.0","react-dom":"^18.2.0"},"_npmOperationalInternal":{"tmp":"tmp/dsh-cloud-sync_0.2.1_1787220686922_0.1665314561390574","host":"s3://npm-registry-packages-npm-production"}},"0.2.2":{"name":"@asong111/dsh-cloud-sync","version":"0.2.2","license":"Apache-2.0","_id":"@asong111/dsh-cloud-sync@0.2.2","maintainers":[{"name":"asong111","email":"asong1232021@163.com"}],"homepage":"https://github.com/ASong111/dsh-cloud-sync#readme","bugs":{"url":"https://github.com/ASong111/dsh-cloud-sync/issues"},"dsh":{"bundle":{"patch":"./cordis.patch.yml"},"client":{"inject":[],"platform":"web"}},"dist":{"shasum":"a932b270a2f02dda2aff3f822b77df10a7e3e1e1","tarball":"https://registry.npmjs.org/@asong111/dsh-cloud-sync/-/dsh-cloud-sync-0.2.2.tgz","fileCount":23,"integrity":"sha512-wPFBHrkyxrIaFnjfCu9tw7PD58J7kv+YT0G8xSd6h4WRstr6OmAfHjb5LsCyNYjhMdelExwZauKDNHeG6ptd3Q==","signatures":[{"sig":"MEYCIQCT3YbSfvbuX25Ub4vNK3peyBQLfVBypYtTdz0iwFavIwIhAM0rhoZqmQK3TRP2m+WIyQVzxHRXaQS+8IBXXyw+5Yi6","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":1147922},"main":"dist/index.mjs","type":"module","types":"dist/index.d.mts","engines":{"node":"^22.19.0 || >=24.0.0"},"exports":{".":{"types":"./dist/index.d.mts","default":"./dist/index.mjs"},"./client":{"types":"./dist/client.d.mts","default":"./dist/client.js"},"./package.json":"./package.json"},"gitHead":"34cc18b8c12c6a5928ed711b9d910a82d2314ee2","scripts":{"test":"vitest run","build":"tsdown","watch":"tsdown --watch","bundle":"tsdown","typecheck":"tsc --noEmit"},"_npmUser":{"name":"asong111","email":"asong1232021@163.com"},"repository":{"url":"git+https://github.com/ASong111/dsh-cloud-sync.git","type":"git"},"_npmVersion":"10.9.4","description":"Cloud sync for the dsh web GUI: bidirectionally sync plugins, config, agent-presets, skills and task history between two machines through a private Git remote (default SSH). Auto-installs dependencies after pull; excludes plaintext secrets (credentials/SS","directories":{},"_nodeVersion":"22.22.0","dependencies":{"schemastery":"^3.18.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsdown":"0.22.2","vitest":"^3.0.0","typescript":"~5.7.2","@types/node":"^22.20.0","@types/react":"~18.3.1","@types/react-dom":"^18.3.5","@deepseek-ai/cordis":"^4.0.1","@deepseek-ai/dsh-llm":"^0.1.0-rc.7","@deepseek-ai/dsh-tools":"^0.1.0-rc.7","@deepseek-ai/dsh-system-prompt":"^0.1.0-rc.7","@deepseek-ai/dsh-host-webserver":"^0.1.0-rc.7"},"peerDependencies":{"react":"^18.2.0","react-dom":"^18.2.0"},"_npmOperationalInternal":{"tmp":"tmp/dsh-cloud-sync_0.2.2_1787278008706_0.33298740147775385","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"@asong111/dsh-cloud-sync","version":"0.3.0","license":"Apache-2.0","_id":"@asong111/dsh-cloud-sync@0.3.0","maintainers":[{"name":"asong111","email":"asong1232021@163.com"}],"homepage":"https://github.com/ASong111/dsh-cloud-sync#readme","bugs":{"url":"https://github.com/ASong111/dsh-cloud-sync/issues"},"dsh":{"bundle":{"patch":"./cordis.patch.yml"},"client":{"inject":[],"platform":"web"}},"dist":{"shasum":"08d823f824c1937cbfbab0d51d299dfa90b41ca4","tarball":"https://registry.npmjs.org/@asong111/dsh-cloud-sync/-/dsh-cloud-sync-0.3.0.tgz","fileCount":23,"integrity":"sha512-CqEKDkXT+X9N6szlFoDFLXiT/KY9bwfi9It7oPwxCLkI9kj/DMqgd1I8YXVbrc/Xq5yJYMd8FyRYztY+j1OmoA==","signatures":[{"sig":"MEUCIHeAJ+H55yj/F5nKWLtttMrC4iFcS7lizDjjc8DacTp0AiEA8pcSiFvQaLcRbmSmIATTjFkwjUwZDWxbYIyjhjQQh0w=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":351402},"main":"dist/index.mjs","type":"module","types":"dist/index.d.mts","engines":{"node":"^22.19.0 || >=24.0.0"},"exports":{".":{"types":"./dist/index.d.mts","default":"./dist/index.mjs"},"./client":{"types":"./dist/client.d.mts","default":"./dist/client.js"},"./package.json":"./package.json"},"gitHead":"f3a37984b25653477fecad607afeea6df4755c10","scripts":{"test":"vitest run","build":"tsdown","watch":"tsdown --watch","bundle":"tsdown","typecheck":"tsc --noEmit"},"_npmUser":{"name":"asong111","email":"asong1232021@163.com"},"repository":{"url":"git+https://github.com/ASong111/dsh-cloud-sync.git","type":"git"},"_npmVersion":"10.9.4","description":"Cloud sync for the dsh web GUI: bidirectionally sync plugins, config, agent-presets, skills and task history between two machines through a private Git remote (default SSH). Auto-installs dependencies after pull; excludes plaintext secrets (credentials/SS","directories":{},"_nodeVersion":"22.22.0","dependencies":{"schemastery":"^3.18.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsdown":"0.22.2","vitest":"^3.0.0","typescript":"~5.7.2","@types/node":"^22.20.0","@types/react":"~18.3.1","@types/react-dom":"^18.3.5","@deepseek-ai/cordis":"^4.0.1","@deepseek-ai/dsh-llm":"^0.1.0-rc.7","@deepseek-ai/dsh-tools":"^0.1.0-rc.7","@deepseek-ai/dsh-system-prompt":"^0.1.0-rc.7","@deepseek-ai/dsh-host-webserver":"^0.1.0-rc.7"},"peerDependencies":{"react":"^18.2.0","react-dom":"^18.2.0"},"_npmOperationalInternal":{"tmp":"tmp/dsh-cloud-sync_0.3.0_1787306680091_0.22475230687320336","host":"s3://npm-registry-packages-npm-production"}},"0.3.12":{"name":"@asong111/dsh-cloud-sync","version":"0.3.12","description":"Cloud sync for the dsh web GUI: bidirectionally sync plugins, config, agent-presets, skills and task history between two machines through a private Git remote (default SSH). Auto-installs dependencies after pull; excludes plaintext secrets (credentials/SS","type":"module","engines":{"node":"^22.19.0 || >=24.0.0"},"main":"dist/index.mjs","types":"dist/index.d.mts","exports":{".":{"types":"./dist/index.d.mts","default":"./dist/index.mjs"},"./client":{"types":"./dist/client.d.mts","default":"./dist/client.js"},"./package.json":"./package.json"},"dsh":{"bundle":{"patch":"./cordis.patch.yml"},"client":{"inject":[],"platform":"web"}},"dependencies":{"schemastery":"^3.18.0"},"peerDependencies":{"react":"^18.2.0","react-dom":"^18.2.0"},"devDependencies":{"@deepseek-ai/cordis":"^4.0.1","@deepseek-ai/dsh-host-webserver":"^0.1.0-rc.7","@deepseek-ai/dsh-llm":"^0.1.0-rc.7","@deepseek-ai/dsh-system-prompt":"^0.1.0-rc.7","@deepseek-ai/dsh-tools":"^0.1.0-rc.7","@types/node":"^22.20.0","@types/react":"~18.3.1","@types/react-dom":"^18.3.5","tsdown":"0.22.2","typescript":"~5.7.2","vitest":"^3.0.0"},"license":"Apache-2.0","repository":{"type":"git","url":"git+https://github.com/ASong111/dsh-cloud-sync.git"},"publishConfig":{"access":"public"},"scripts":{"build":"tsdown","bundle":"tsdown","watch":"tsdown --watch","typecheck":"tsc --noEmit","test":"vitest run"},"_id":"@asong111/dsh-cloud-sync@0.3.12","gitHead":"9834ed4da60f31fd2a1d73e52498eeabc6fb515c","bugs":{"url":"https://github.com/ASong111/dsh-cloud-sync/issues"},"homepage":"https://github.com/ASong111/dsh-cloud-sync#readme","_nodeVersion":"22.22.0","_npmVersion":"10.9.4","dist":{"integrity":"sha512-ei7oVo2+Ko5XfYtJGjxJP7zmxVQsA1stZUzyqQ/HuFOA8W+Rysu56Ix79l2u2sWQzVq+YS82KhR46Lmr7wXSfQ==","shasum":"7e36c378e8a24bcdbad09d2169c04f8186da61bc","tarball":"https://registry.npmjs.org/@asong111/dsh-cloud-sync/-/dsh-cloud-sync-0.3.12.tgz","fileCount":23,"unpackedSize":459284,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIH6cZZTk4PAouXdyH0BEw1UJp70jQhBvUACjhfWS2xnrAiA7wdsu4Fwmr8J68/ughjLKQkErPUOoSAdPkwRxXSzhqA=="}]},"_npmUser":{"name":"asong111","email":"asong1232021@163.com"},"directories":{},"maintainers":[{"name":"asong111","email":"asong1232021@163.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/dsh-cloud-sync_0.3.12_1788144381611_0.6268883144815782"},"_hasShrinkwrap":false}},"time":{"created":"2026-08-19T10:06:34.665Z","modified":"2026-08-31T02:46:21.921Z","0.1.0":"2026-08-19T10:06:35.068Z","0.2.0":"2026-08-20T09:51:45.828Z","0.2.1":"2026-08-20T10:11:27.054Z","0.2.2":"2026-08-21T02:06:48.880Z","0.3.0":"2026-08-21T10:04:40.242Z","0.3.12":"2026-08-31T02:46:21.775Z"},"bugs":{"url":"https://github.com/ASong111/dsh-cloud-sync/issues"},"license":"Apache-2.0","homepage":"https://github.com/ASong111/dsh-cloud-sync#readme","repository":{"type":"git","url":"git+https://github.com/ASong111/dsh-cloud-sync.git"},"description":"Cloud sync for the dsh web GUI: bidirectionally sync plugins, config, agent-presets, skills and task history between two machines through a private Git remote (default SSH). Auto-installs dependencies after pull; excludes plaintext secrets (credentials/SS","maintainers":[{"name":"asong111","email":"asong1232021@163.com"}],"readme":"# dsh-cloud-sync\n\n在两台**不同网络**的电脑之间，通过一个**私有 Git 远端**（默认 SSH 免密）做 **DSH 云端同步**：把 `~/.dsh` 下的**插件清单、配置、agent presets、skills、任务历史**双向同步，做到**换台电脑接着干**。拉取后**自动安装依赖**，并**默认排除明文密钥**。\n\n> 独立插件项目（不依赖 dsh-web-ui 全家桶），与 DSH 本身同款双 face（host + client）插件范式，热插拔、不改 dsh 源码。\n\n## 特性\n\n- **双向同步**：`push`（本机 → 云端远端）、`pull`（云端远端 → 本机）。\n- **自动接力**：`autoSync` 定时「先拉后推」——`autoPush` 默认开，A/B 机顺序切换时本机变更自动上传，无需手动点「上传」。\n- **自动装依赖**：`pull` 后检测到 `package.json` / `pnpm-lock.yaml` 变化时，自动 `dsh plugin install` 复现插件（`installAfterPull` 默认开，可在 GUI 关）。\n- **安全**：默认排除 `.credentials.yaml`、`dsh-ssh.json`（含明文 SSH 密码）、设备匿名 ID、`pet.json`；`node_modules` / `.git` 一律不进镜像。\n- **冲突保守**：不静默覆盖；冲突时先备份本机旧文件，标记「待处理」，绝不 `--force` 推送。\n- **GUI**：侧边栏「云同步」面板（配置远端 / 一键上传 / 一键拉取 / 自动同步开关与间隔 / 拉后自动推送开关）。\n- **动作日志**：面板「日志」页按天展示每次 push/pull/resolve 新增/修改/删除的**具体文件**；原始数据落盘 `~/dsh-sync/logs/<profile>/sync-<日期>.jsonl`。\n- **同步介质**：Git（有版本历史、可冲突检测、可 `age`/`git-crypt` 加密）。\n\n## 支持的同步内容\n\n| 内容 | 路径 | 说明 |\n|---|---|---|\n| 插件清单 | `profiles/<profile>/package.json` + `pnpm-lock.yaml` | 不拷 `node_modules`，拉取后自动 `install` |\n| 配置 | `profiles/<profile>/cordis.patch.yml`、`settings.yaml`、`cordis.patch.yml`(home) | `settings.yaml` 已确认无明文密钥 |\n| agent presets | `.agent-presets/` | 梁神等预设 |\n| skills | `skills/` | |\n| 任务历史 | `sessions/`、`storages/`、`task-board/` | |\n\n> **明确不同步（不计划纳入）**：`attachments/`（会话附件对象，换机后旧会话中的贴图/附件不迁移）——需要的话请自行用云盘同步目录（Drive/坚果云）管理；skill 内容（含其展示/媒体资产）**照常同步**，作为 skill 的组成部分跟随版本。运行时/临时态同样永不入镜像（见安全红线）。\n\n## 架构 — 同步是怎么工作的\n\n给开发者看的三张图，覆盖整个设计。引擎（host 半）在 `src/engine.ts`，面板（browser 半）在 `src/client/`。\n\n### 1. 数据流（单机）\n\n```text\n                       ~/.dsh   (live dsh data)\n   +------------------------------------------------------------------+\n   | profiles/<profile>/   package.json  cordis.patch.yml             |\n   |                       pnpm-lock.yaml  pnpm-workspace.yaml        |\n   | .agent-presets/   skills/   sessions/   storages/   task-board/  |\n   | settings.yaml   cordis.patch.yml                                 |\n   +---------------------------------+--------------------------------+\n                                     |\n        push: content-hash copy ①   |   pull: copy back ③ (union rules,\n        (skip node_modules/.git,     |        backup before overwrite,\n         secret blacklist,           |        active files <60s skipped)\n         active files <60s)          |\n                                     v\n   +------------------------------------------------------------------+\n   | ~/dsh-sync/<profile>/   mirror working tree (a git repo)         |\n   +---------------------------------+--------------------------------+\n                                     |\n              git pull --rebase ②    |    git add -A && commit ②\n              (remote -> mirror)     |    && git push (mirror -> remote)\n                                     v\n   +------------------------------------------------------------------+\n   |  private Git remote   git@github.com:<user>/dsh-sync.git         |\n   |  (SSH; history + conflict detection come free with git)          |\n   +------------------------------------------------------------------+\n\n   per-machine side stores (never synced):\n     ~/dsh-cloud-sync-backup/<ts>/<dsh-rel>   pre-overwrite backups\n     ~/dsh-sync/logs/<profile>/sync-YYYY-MM-DD.jsonl   action log\n```\n\n- ① `push`：把 `~/.dsh` 增量复制进镜像（按 sha256 内容哈希，相同则跳过；排除黑名单与近 60 秒内仍在变动的文件），然后 `git add -A && commit && push`。\n- ② git 负责镜像 ↔ 远端，pull 用 `--rebase`，冲突时保留镜像原地不动、提示处理，绝不 `--force`。\n- ③ `pull`：镜像复制回 `~/.dsh`；覆盖/删除前先备份到 `~/dsh-cloud-sync-backup/<时间戳>/`（保留 dsh 相对路径）；`sessions/` `storages/` `task-board/` 是**并集**语义——远端没有的本地内容**绝不删除**（防止误删未推送的会话）。\n\n### 2. 双机接力（顺序切换，时间段不重叠）\n\n`autoSync`（定时）+ `autoPush`（默认开）让同步循环变成全自动接力：A 机在本机周期内就把变更推上云端，B 机下次拉取即可接上，无需手动点「上传」。\n\n```text\n    ┌──────────────┐                         ┌──────────────┐\n    │  Machine A   │                         │  Machine B   │\n    │   (works)    │                         │   (works)    │\n    │              │                         │              │\n    │  autoSync    │                         │  autoSync    │\n    │  every N min │                         │  every N min │\n    └──────┬───────┘                         └──────┬───────┘\n           │                                       │\n           │   ┌─────────────────────────────┐     │\n           └──►│  private Git remote (SSH)   │◄────┘\n               │  git@github.com:<user>/sync │\n               └─────────────────────────────┘\n      A pulls (enter) then pushes its        B pulls A's work on\n      work every tick (autoPush ON)          boot, then pushes back\n```\n\n### 3. 单次 autoSync 的决策流程\n\n```text\n autoSync tick (every autoSyncIntervalMin)\n        │\n        ▼\n  fetch probe  (1 network round-trip)\n        │\n        ├── fetch failed? ──────────► skip — retry next tick (no log)\n        │\n        ▼\n  remote has new commits (behind > 0)?\n        │\n        ├── no: nothing new on remote\n        │        ├─ autoPush on ──► local content-hash scan, push if changed\n        │        └─ autoPush off ─► done — full no-op, no log\n        │\n        ▼  yes\n  pull --rebase   (remote → mirror)\n        │\n        ├── conflict? ──────────────► STOP — mirror left pending;\n        │                              resolve via GUI「以远端为准」\n        ├── hard error? ─────────────► STOP — retry at the next tick\n        │\n        ▼  ok\n  copy mirror → ~/.dsh\n   • backup before every overwrite / delete\n   • sessions/ storages/ task-board/ are a UNION — never pruned\n   • files modified within 60s are skipped (reported as skipped)\n        │\n        ├─ deps changed && installAfterPull? ──► dsh plugin install\n        │\n        ▼\n  autoPush on? ── no ──► done\n        │ yes\n        ▼\n  copy ~/.dsh → mirror (content-hash aware)\n        │\n        ├─ nothing changed? ────────► skip — no empty commit\n        ├─ only active files? ──────► skip them too, push nothing\n        ▼\n  git add -A && commit && push\n```\n\n### 关键行为\n\n- **复制以内容哈希（sha256）为准，而非 mtime**：字节相同的文件不会重复拷贝，空闲机器不产生空提交。\n- **60 秒活跃窗口保护**（`DSH_CLOUD_SYNC_ACTIVE_MS` 可覆盖）：push/pull 双向都不拷贝、不覆盖、不删除「可能正在写入」的文件；在 mtime 窗口之上加 **size 稳定判定**（`DSH_CLOUD_SYNC_SETTLE_MS`，默认 10s）——同一文件连续多次同步观测字节数不变即视为写完放行，长流式会话写入不再被永久跳过；跳过结果进入 `skipped` 并在面板/日志显示。\n- **定时 tick 探测优先**：每个 tick 只做 1 次 fetch + 本地 rev-list 判断 `behind`；远端无新提交且无需推送时**完全 no-op**——不扫描文件树、不写日志（日志只记录真实发生的 pull/push）。\n- **`autoPush` 只在「拉取成功且无冲突」后触发**：失败或冲突的 pull 绝不自动推送（镜像保持待处理，等待 GUI 处理）。\n- **本机改动保护（基线）**：本机自上次成功同步后改动过的文件（如手动卸载插件改动的 `package.json`）不会被 pull 覆盖或删除，而是保留并在下次 push 推上云端——「卸载了又被拉回来」不再发生；首次同步（无本机基线）仍以云端为准。\n- **密钥与运行时态永不进镜像**：`.credentials.yaml`、`dsh-ssh.json`、`.anonymous-user-id`、`pet.json`、`node_modules/`、`.git/`。\n\n### 单写者契约（接力模型）\n\n插件按**顺序接力**设计：任何时刻只有一台机器在写，另一台 pull 后接管。在该约束下：\n\n- `storages/workspace.json` 是 **dsh 的全局权威注册表**（工作区列表与 `archivedSessionIds` 归档标签）。**当前使用的机器独占它**，另一台 pull 时整文件覆盖——**不做字段级合并**。合并且要猜测 dsh 的 schema，且无法表达「删除」（归档=加标签、恢复=删标签，纯 union 会把已经恢复的会话又归档回去）。\n- 若 `workspace.json`（或任何文件）出现冲突，说明接力断了一环：某台机器改了它却没先 push。解决方式：确认「后使用的那台」的版本为最新后「以远端为准」（本机冲突版本已备份在 `~/dsh-cloud-sync-backup/`）。\n## 安装与使用\n\n```sh\n# A 机 / B 机都执行一次\ndsh plugin --profile web add @asong111/dsh-cloud-sync\n\n# GUI 侧边栏「云同步」：\n#   1) 填远端仓库地址（如 git@github.com:ASong111/dsh-sync.git）\n#   2) 点「↑ 上传到云端」完成首次 push\n#   3) 另一台电脑点「↓ 从云端拉取」→ 自动装依赖\n```\n\n### 两机 SSH 免密（Git 鉴权，一次配置）\n\n- **同一把密钥**：把 A 机 `~/.ssh/id_rsa` + `id_rsa.pub` 复制到 B 机 `~/.ssh/`；或\n- **各自密钥**：在 B 机新生成密钥，把公钥加到 GitHub 账号。\n\n> `installAfterPull` 走 npm registry 网络，与 Git 的 SSH 鉴权相互独立。\n\n完整的两机部署走查（首次上传/拉取、`link:` 依赖注意事项、`ERR_PNPM_UNEXPECTED_STORE` 修复、冲突恢复）见 [DEPLOY.md](DEPLOY.md)。\n\n## 开发\n\n```sh\npnpm install\npnpm test      # vitest：excludes / store / engine(双机模拟)\npnpm build     # tsc + tsdown -> lib/\npnpm watch\n```\n\n## 安全红线\n\n以下文件**永不进入同步**（硬编码黑名单，无法通过配置强行纳入）：\n\n- `~/.dsh/.credentials.yaml`\n- `~/.dsh/dsh-ssh.json`\n- `~/.dsh/.anonymous-user-id`\n- `~/.dsh/pet.json`\n- `node_modules/`、`.git/`\n- 运行时/临时态永不同步：`*.lock`（如 `ledger-v2.lock`）、`*.tmp`、`*.writing` 后缀，以及 `scheduler-v2.json`（task-board 调度心跳）——每机临时状态（`ledger-v2.json` 任务数据仍正常同步）\n\n## 许可证\n\nApache-2.0\n","readmeFilename":"README.zh.md"}