# WebDAV 双设备同步(0.7.0) 设置页统一为“同步与备份”。沿用现有包名、插件 ID、API 路径和本机设置文件;没有重命名已有目录,也没有注册登录启动项。参考 [Magpie 的类别同步思路](https://github.com/yetone/magpie/blob/main/internal/davsync/davsync.go),实现独立的采集、三方比较、存储和应用适配器;没有复制它的实现或按时间覆盖冲突的策略。 ## 如何连接两台设备 1. 在当前运行的 Harness profile 中打开“同步与备份”,配置并保存 WebDAV 地址与账号。 2. 开启跨设备同步。两台设备填写相同的同步空间,选择各自要同步的类别。空间名支持 1–64 位英文字母、数字、下划线和连字符,首位为字母或数字。 3. 保存后,在“设备同步状态”输入独立的加密口令,点击“解锁并检查”。两台设备的同步口令相同,且不能与 WebDAV 密码相同。口令仅在宿主进程内保留,重启需重新解锁;也可由宿主环境 `DSH_VAULT_PASSPHRASE` 提供。 4. 第一台设备看到云端为空,比较后选择本机版本并确认。第二台设备看到差异,逐项选择本机或云端并确认;两端本来就一致的项可以直接建立基线。 5. 后续默认每 3 分钟核对,也可选 15、30、60 分钟或点击“立即同步”。关闭页面不会停止宿主同步,关闭同步或卸载插件后停止后续同步并清除会话口令。 **同步作用于当前运行的 profile**,不是下方历史备份选中的所有 profile。不同名称的本机 profile 可以通过相同空间连接;不要让不希望互相同步的 profile 使用同一空间。 ## 本版范围 | 类别 | 在线支持内容 | | --- | --- | | 界面偏好 | 官方主题插件的主题、正文/代码/终端字号和字体 | | 界面语言 | 官方 locale 插件的语言偏好 | | 模型 | 官方默认模型插件的 provider/model/reasoningEffort 作为一组;DeepSeek 插件的 thinking、reasoningEffort、maxTokens、defaultContextWindow、streamIdleTimeoutMs 作为一组 | | Profile 插件清单 | manifest 中 bundle 顺序、依赖名称、可识别的精确版本及 bundle 选择状态;接收差异列为待手动处理 | 只采集实际 `settings.describe({redactSecrets:true})` 提供的在线字段和用户显式覆盖值,按插件模块、稳定 entry id 和字段匹配。空对象表示继承默认配置。采用 `settings.mutate` 和当前 revision 写入,等待接口完成并再次读取确认。继承值归一化时分别保存本机/云端基线,避免不必要的回传和反复应用。 目标插件缺失、entry id 不同或字段不可用时,列为待手动处理,不猜测映射。模型设置不会重写现有会话的独立选择,也不会调用外部模型接口。API Key 按下方独立开关处理。本版不传输登录态、端点、机器路径、任意第三方插件配置、MCP/技能文件或会话。没有自动安装、卸载、升级插件,也不覆盖运行中 profile 的 package.json、YAML 或 lockfile。请通过 Harness 管理插件或使用现有离线恢复流程,随后再次核对。 ## API Key:独立开关,默认关闭 在设置页勾选“同时同步供应商 API Key(默认关闭)”,保存后重新解锁。也可以取消普通类别,仅选择 Key。两台设备均需开启;关闭时不会读取或写入本机供应商凭据,仍保留云端已有的加密 Key,不会远端删除。更改开关会切换独立同步基线,首次差异需要确认。 - 当前支持 `@deepseek-ai/dsh-llm-deepseek-api-key` 的有效 `apiKeyEnv` 引用,以及 `@deepseek-ai/dsh-llm-pi-ai` 的显式 `providers..apiKeyEnv` 引用和 `llm-pi-ai/` 的 `api-key` 记录。通过本机已安装的官方适配器及设置发现引用,不接受云端指定引用名、文件路径或任意凭据地址。两端引用按稳定 entry id/route 对应;pi-ai Key 记录按 provider id 对应,缺失记录可初始化,但不会安装插件或创建供应商配置。 - 通过普通 `credentials.resolve/describe`、可选原子引用能力及 `listRecords/describeRecord/readRecord/modifyRecord` 访问,不直接读写凭据文件或枚举 `process.env`。仅解析明确绑定供应商的引用;它的值可能由 Harness 从已保存凭据或环境回退提供。Key 记录接收端写入 Harness 的托管凭据层;普通 provider 的引用型 Key 不由同步写入;可选原子 provider 的已托管引用通过 CAS 接收。不会修改环境或 `.env`。凭据通常由同一 DSH_HOME 的多个 profile 共享,更新某个引用/记录也会影响使用它的其他 profile。 - 只传 `api-key` 的 Key 字段。OAuth/grant、record.env 环境变量包、其他插件的记录、WebDAV 密码、同步口令均不传输;更新已有 Key 记录时保留接收端自己的 env。 - 同步头、本机基线及最近 10 次操作前副本始终加密;普通备份选择明文也不能改变这一点。Key 不会进入普通设置 JSON、响应 DTO、共享浏览器状态、预览文本或原始错误日志。页面只显示“已配置(内容隐藏)/未配置”;冲突选择仅提交 item id、版本 token 和本机/云端方向。关闭 Key 同步不会清除已有加密历史。 - 首次接入和两端同时轮换仍需选择;Key 记录的正常单端轮换可传播;普通 provider 的引用型 Key 可上传,云端接收变化只列为待手动处理。Key 缺失不代表撤销,不会以空值清空另一设备;有基线后删除 Key 会显示待处理。撤销泄漏 Key 应在供应商后台完成。本版没有跨设备撤销功能。 - 只读凭据服务、OAuth 已占用的记录或缺少适配器均不会强制写入。多个路由共用一个本机引用时,同值只写一次,云端不同值则写入前拒绝并提示拆分引用。 - `modifyRecord` 在 Harness 提供的原子回调中核对当前 Key,避免覆盖同时发生的记录轮换。**引用的公开 `set` API 不支持 expected revision/CAS,因此普通 provider 不提供引用型 Key 的同步写入;0.7.0 可通过[可选原子凭据 provider](atomic-credentials.md)恢复已托管引用的自动接收**。以下手动保护针对普通 provider 或未托管引用。不论目标为空、自动接收、首次连接、冲突选择云端或重新核对,都不会调用引用的 `set/unset`。插件锁只覆盖插件自身,反复重读和写后回滚也无法保证不覆盖用户新值,因此不采用这些办法伪装原子性。 - 引用型 Key 选择云端时仅标记“需在 Harness 手动配置”,不写入、不确认该项基线。待处理状态加密落盘,跨轮询和重启保留;两端未变化时不反复要求首次选择。用户在 Harness 手动配置到相同 Key 后,下一轮核对可建立基线;用户改成另一个不同 Key 时重新比较,仍不会自动覆盖。本页不显示、复制或导出密钥。需要自动双向同步时,使用支持 `modifyRecord` 的 pi-ai Key 记录,或显式接入可选原子 provider 并统一该引用的所有写入入口。 两端建议升级到 0.7.0 后再开启 Key 同步;0.5.0 不识别新的 API Key 条目,会拒绝该同步文档。原有完整快照恢复仍只允许离线确认。 ## 冲突和不确定状态 - 对比本机值、云端值以及上次确认的两端基线。仅一端变化则传播,独立项目可合并;同一项两端均变化则暂停本轮应用,显示两份值供选择。 - 首次连接与冲突都需要明确选择;可以逐项选择,也可以全部选择本机/云端。确认 token 使用进程内随机密钥的 HMAC,绑定当前云端 ETag、本机内容、凭据绑定/版本、同步范围和基线;不输出可离线猜测 Key 的明文哈希,预览过期时拒绝执行。 - 每次应用前检查本机当前值和 Harness revision;操作完成后再检查一次,上传或应用期间发生的新修改不会被错误确认。 - 在修改任一端之前,将操作前本机与云端副本加密保存到本机同步状态,保留最近 10 次操作;这与远端完整快照的默认 30 份保留策略不同。这些副本不是 CLI 完整恢复快照,不提供自动回放。 - 应用失败、上传回读未确认或进程中断时保留 pending,重启仍暂停。用户检查状态后点击“重新核对两端”,清除尝试标记并基于当前数据重新规划;仍有差异时再次确认后才应用,**不是回滚或重放**。原有加密副本保留。 - 关闭再开启不会丢弃同一空间的持久化基线。修改空间、账号或类别范围会使用独立本机状态,并重新比较。 ## 存储、安全与性能 云端仅维护 `sync/.vault` 加密当前状态,不使用 `snapshots/` 的快照列表,快照保留清理不会删除它。本机 `config-vault/sync-.vault` 保存加密基线、操作前副本和 pending;这些文件都不属于备份采集范围。保留加密原口令,本版不提供在线口令轮换。 首次访问 WebDAV 时,用随机非秘密探针验证强 ETag、If-Match 和 If-None-Match 语义,完成后条件删除探针。缺少支持则暂停同步,不降级为无条件覆盖;无法取得强 ETag 的服务器可能留下一个非秘密探针。失败能力检查不会在同一进程内不断自动创建探针,手动检查可重新验证。探针结果只缓存到本次进程。 同步头使用条件 PUT,412 只重新规划;PUT 后回读比较密文字节。数据须通过解密认证、格式/运行时/空间检查、字段白名单和尺寸校验后才能进入应用计划。同步内容上限 256 KiB/256 项,网络响应上限 1 MiB。凭据由 Harness 凭据服务读取,DTO 不含密码或口令。 每个本机 profile 有跨进程 PID 锁;与插件现有备份和 UI 动作共用宿主排队,不会同时堆积任务。关闭/锁定时不访问 WebDAV;定时只在间隔到期时读取线上支持字段,没有新增递归文件扫描。未变化时不上传头文件、不重复应用配置;自动备份仍沿用原有 5 秒轻量检测、防抖与限频。网络失败指数退避,最长一小时。不确定操作等待人工核对,不能靠退避重复 PUT。 ## 与离线恢复的边界 设备同步没有文件恢复接口。原来的手动/自动快照、校验、保留策略、恢复预览、离线 token 确认、加密回滚日志和 recover 流程继续保留。同步始终加密,与历史快照允许显式明文的开关独立。