🎁 福利专区全网大模型免费应用 + 新用户福利 + 注册活动入口,低成本玩转 AI

WebDAV 同步备份 alfredhuang211/dsh-webdav-sync

DeepSeek Harness
alfredhuang21124 天前有提交已提供中文文档扫描:含敏感能力

把会话日志与插件环境备份到 WebDAV 并恢复

29.9/100
综合分
0
GitHub 星标
—
npm 周下载
—/5
用户评分

数据截至 2026/10/9 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。

安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add alfredhuang211/dsh-webdav-sync
该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:待复验
是什么
dsh 原生插件 · chat
装得上吗
曾在 dsh 0.2.0-rc.2 下真实安装成功,但当前 dsh 已更新至 0.2.1-rc.5,本站尚未在新版下复验
L4 · 真实安装等级说明 →
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
活跃:最近一次提交在 24 天前
档位由哪些信号合成

本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。

验证判据与等级说明 →
社区实装还没有人打卡 · 装过的第一个就是你
安全扫描自动 · 静态分析源码
v2.7.0
🔵 扫描:含敏感能力尚无人工评估
展开查看扫描说明与证据 ↓

静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。

可执行外部命令读写/删除本地文件发起外部网络请求
查看扫描证据(共 35 处,展示前 34 条)
  • 读取本地文件
    lib/index.js:51
    if (existsSync(pkgPath)) {
  • 读取本地文件
    lib/index.js:52
    const pkg = JSON.parse(readFileSync(pkgPath, 'utf8'))
  • 执行外部命令来自配置/变量
    lib/index.js:149
    const child = spawn(command, args, {
  • 发起网络请求
    client/bundle.js:31
    var res = await fetch(API + path, init)
  • 读取本地文件
    lib/sync.js:85
    const buf = await readFile(absPath)
  • 写入本地文件
    lib/sync.js:224
    await mkdir(dirname(target), { recursive: true })
  • 写入本地文件
    lib/sync.js:225
    await writeFile(target, bytes)
  • 读取本地文件
    lib/sync.js:280
    const buf = local.bytes ?? (await readFile(local.absPath))
  • 读取本地文件
    lib/sync.js:387
    const file = await readFile(local.absPath)
  • 读取本地文件
    lib/sync.js:438
    const file = await readFile(local.absPath)
  • 读取本地文件
    lib/sync.js:450
    const merged = mergeSelfPatchRow(buf.toString('utf8'), await readFile(target, 'utf8'), SELF_ENTRY_ID)
  • 写入本地文件
    lib/sync.js:456
    await mkdir(dirname(target), { recursive: true })
  • 读取本地文件
    lib/sync.js:459
    await writeFile(`${target}.bak-${stamp}`, await readFile(target))
  • 写入本地文件
    lib/sync.js:459
    await writeFile(`${target}.bak-${stamp}`, await readFile(target))
  • 写入本地文件
    lib/sync.js:463
    await writeFile(tmp, payload)
  • 写入本地文件
    lib/sync.js:464
    await rename(tmp, target)
  • 发起网络请求
    lib/webdav.js:89
    await this.request('PUT', rel, { body: data, headers: { 'content-type': 'application/octet-stream' } })
  • 发起网络请求
    lib/webdav.js:101
    const res = await this.request('GET', rel, { expect: [404] })
  • 发起网络请求
    lib/webdav.js:108
    const res = await this.request('PROPFIND', rel, { headers: { depth: '1', 'content-type': 'application/xml' }, body: '<?xml version="1.0"?><propfind xm
  • 发起网络请求
    lib/webdav.js:130
    await this.request('DELETE', rel, { expect: [404] })
  • 发起网络请求
    lib/webdav.js:135
    const res = await this.request('PROPFIND', '', { headers: { depth: '0' }, expect: [207, 404] })
  • 读取本地文件
    lib/env.js:72
    info = await stat(spec.absPath)
  • 读取本地文件
    lib/env.js:78
    const bytes = await readFile(spec.absPath)
  • 读取本地文件
    lib/env.js:194
    return await readFile(path, 'utf8')
  • 读取本地文件
    lib/env.js:221
    return existsSync(join(profileDir, 'package.json')) && Boolean(home)
  • 读取本地文件
    lib/layout.js:62
    const stream = createReadStream(absPath).pipe(createZstdDecompress())
  • 读取本地文件
    lib/layout.js:90
    projectDirs = await readdir(sessionsRoot, { withFileTypes: true })
  • 读取本地文件
    lib/layout.js:99
    sessionDirs = await readdir(projectPath, { withFileTypes: true })
  • 读取本地文件
    lib/layout.js:108
    files = await readdir(sessionPath, { withFileTypes: true })
  • 读取本地文件
    lib/layout.js:119
    st = await stat(absPath)
  • 读取本地文件
    lib/state.js:25
    raw = JSON.parse(await readFile(stateFile(stateDir), 'utf8'))
  • 写入本地文件
    lib/state.js:55
    await mkdir(stateDir, { recursive: true })
  • 写入本地文件
    lib/state.js:58
    await writeFile(tmp, `${JSON.stringify(state, null, 2)}\n`, 'utf8')
  • 写入本地文件
    lib/state.js:59
    await rename(tmp, target)
扫描于 2026/10/31(1 天前) · 范围 入口闭包 + 发布文件清单 · 来源 GitHub 仓库

静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。

依赖的 DSH / Cordis 模块
@deepseek-ai/schemastery@deepseek-ai/cordis@deepseek-ai/dsh@deepseek-ai/dsh-settings
给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个

功能亮点

  • 备份会话日志与插件环境
  • 从WebDAV恢复数据
  • 版本比较与冲突策略

DeepSeek Harness 插件:把会话日志与插件环境备份到任意 WebDAV 服务,并可从 WebDAV 恢复(会话+环境双源同步、rev/generation 版本机制、三方比较与冲突策略)

README

由 DeepSeek 最新模型翻译生成
dsh-webdav-sync 把 DSH 的会话日志和插件环境同步到任意 WebDAV 服务,带版本号 / 时间 / 设备溯源,可增量备份与恢复。零运行时依赖(Node 内置 zstd + fetch),host + 客户端两半齐全,Desktop 与 CLI 都能用。 仓库内的参考实现(v0.2.1),已在真实 dsh 0.2.0-rc.1 的 web profile 上跑通双源同步、版本溯源、冲突处理与强制恢复。 它同步什么 | 源 | 内容 | 说明 | | 会话 | $DSH_HOME/sessions/*/.jsonl.zstd | 字节级;恢复时按日志头部的 cwd 重算落位目录 | | 插件环境 | profile 的 package.json、cordis.patch.yml、pnpm-lock.yaml、pnpm-workspace.yaml、$DSH_HOME/cordis.patch.yml(可选)、插件市场状态(可选) | 这些才是"环境真身";node_modules 是可重装的产物,永不同步 | | 插件清单 | 自动生成的 environment/inventory.json | 每个插件的名称 + 版本 + 启用状态——宿主自带的清单 API 不含版本号,所以版本是插件自己从 node_modules 里读的 |
展开完整文档(README 剩余 1 节)
dsh-webdav-sync

把 DSH 的会话日志和插件环境同步到任意 WebDAV 服务,带版本号 / 时间 / 设备溯源,可增量备份与恢复。零运行时依赖(Node 内置 zstd + fetch),host + 客户端两半齐全,Desktop 与 CLI 都能用。

仓库内的参考实现(v0.2.1),已在真实 dsh 0.2.0-rc.1 的 web profile 上跑通双源同步、版本溯源、冲突处理与强制恢复。

它同步什么

| 源 | 内容 | 说明 |
| 会话 | $DSH_HOME/sessions/*/.jsonl.zstd | 字节级;恢复时按日志头部的 cwd 重算落位目录 |
| 插件环境 | profile 的 package.json、cordis.patch.yml、pnpm-lock.yaml、pnpm-workspace.yaml、$DSH_HOME/cordis.patch.yml(可选)、插件市场状态(可选) | 这些才是"环境真身";node_modules 是可重装的产物,永不同步 |
| 插件清单 | 自动生成的 environment/inventory.json | 每个插件的名称 + 版本 + 启用状态——宿主自带的清单 API 不含版本号,所以版本是插件自己从 node_modules 里读的 |

版本机制:怎么知道哪一份是最新的

远端 manifest.json 是 v2 结构,每个文件都带三层信息:

{
"schema": 2,
"generation": 12, // 整份备份的代号,有变化才 +1 "updatedAt": "2026-09-30T10:12:54.873Z",
"device": { "id": "dev-98597ad2", "label": "sandbox-mac", "platform": "darwin" },
"devices": { "dev-98597ad2": { "label": "sandbox-mac", "lastSeen": "..." } },
"entries": {
"sessions/--Users-me-proj--/sess-x/session.v4.jsonl.zstd": {
"sha1": "…", "size": 12933, "rev": 3, // 逻辑版本号:内容变了才 +1 "updatedAt": "2026-09-30T09:02:08.000Z", // 源文件时间 "device": "dev-98597ad2" // 最后写入者 } } }

判定规则(lib/versioning.js):

1. sha1 相同 → 一致,什么都不做;
2. 本机存有 base(上次同步的共同祖先)时:只有一端变了 → 直接推进那一端,不是冲突;
3. 两端相对 base 都变了 → 冲突,按 conflictPolicy 取舍:
- prefer-newer(默认):先比 rev,再比 updatedAt,最后用 device 字典序收敛(保证两端算出同一结果,不会来回覆盖);
- keep-local / keep-remote / keep-both / manual;
4. 落败的一方默认另存为 .conflict-<设备>-r<版本> 副本,绝不静默丢弃。

安全红线

- push / pull 都不删除本机会话;
- 恢复覆盖的条件是"本机相对 base 没改过"(覆盖不丢东西);本机改过的文件必须显式开启 pullOverwrite 或走「以云端为准」(POST /pull?force=1);
- 环境文件被覆盖前先写 .bak-<时间戳>;
- 运行中的会话不参与覆盖;
- 同步两侧都剥离本插件自身的配置行:否则换机恢复后会把 WebDAV 同步目标改回旧机器;恢复时本机那一行会被保留(换机后你重新填的地址不会被云端旧值抹掉);
- 永不触碰 node_modules。

配置界面(已实测渲染)

设置 → WebDAV 同步,三组表单(连接 / 同步内容 / 版本与冲突)+ 状态面板:

连接 可达本机 sandbox-mac 云端 第 2 代,2026/9/30 18:13:39 由 sandbox-mac 写入,10 个文件差异 待上传 0,待恢复 0,冲突 0,一致 10 插件清单对照:一致

按钮:保存 / 状态/版本 / 测试连接 / 预演 / 立即备份 / 从云端恢复 / 以云端为准 / 安装依赖。

命令行也可用:/webdav-sync push|pull|plan|status|test|install(pull force = 以云端为准)。

环境恢复后的最后一步

恢复 package.json / pnpm-lock.yaml 之后需要重装依赖:

- 界面上点「安装依赖」,或命令 /webdav-sync install;
- 它调用 ctx.profileContext.packageManager(打包版用内置 pnpm、开发版用 PATH 里的 pnpm),在 profile 目录里执行 install;
- 等价手工命令:cd $DSH_HOME/profiles/<profile> && pnpm install。

测试

pnpm install # 只为 @deepseek-ai/schemastery
node --test test/.test.mjs

42 个用例:版本排序与三方比较矩阵、WebDAV 客户端路径与建目录(含 basePath 非空)、全新 state 面对已有云端的 base 落下、nextRev、v1 清单兼容、环境发现与清单版本、自指剥离、冲突各策略、双源端到端、force 恢复、恢复后收敛性(不抖动)、运行中会话跳过、鉴权失败。

目录结构

lib/index.js 入口:name/inject/Config/apply;接 profileContext、路由、命令、定时器、依赖安装 lib/config.js schemastery Config(.volatile() 子树决定哪些字段可被设置页写回)+ 到引擎配置的映射 lib/versioning.js 版本机制核心:compareVersion / decide(三方比较)/ nextRev / manifest v1→v2 归一化 lib/state.js 本机状态:设备 ID、base 三方基准、sha1 缓存 lib/env.js 环境采集:声明文件发现、插件清单(含版本)、patch 解析与自指剥离、清单 diff lib/layout.js 复刻宿主的 encodeSegment / projectKey / 日志识别 / 流式读 header lib/webdav.js 零依赖 WebDAV 客户端(Basic / MKCOL / PUT / GET / PROPFIND / DELETE) lib/sync.js 同步引擎:双源、manifest v2、冲突副本、原子写、force 恢复 lib/routes.js 同源 HTTP 路由(首行过 ctx.connection.requestRejection 信任栅栏) client/bundle.js 浏览器半边:window.__ModuleLoader__ 自注册 + settings.section 表单 test/ 42 个用例

安装

已发布到 npm 后(CLI 的 web / 自定义 profile)
dsh plugin --profile web add dsh-webdav-sync

直接从 GitHub 源码装(pnpm 的 git 协议,会按本地源码构建/链接)
dsh plugin --profile web add github:alfredhuang211/dsh-webdav-sync

Desktop:desktop profile 由 Electron 托管,CLI 拒绝操作,必须走 App 内的插件市场。package.json 已按市场契约声明 engines.dsh 与 @deepseek-ai/ peer。

仓库

源码:<https://github.com/alfredhuang211/dsh-webdav-sync>(MIT)

开发指引与踩坑记录另见上层文档《DSH插件开发指南-WebDAV会话同步.md》,本仓库只放插件本身。
预览分享卡片长什么样 ↓alfredhuang211/dsh-webdav-sync
分享 · DeepSeek Harness Hub
alfredhuang211/dsh-webdav-sync

把会话日志与插件环境备份到 WebDAV 并恢复

回到顶部