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

会话云同步 xfy2412/dsh-session-cloudsync

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

加密同步会话与附件到自建服务器,多设备共享

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

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

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

状态速览

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

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

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

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

可执行外部命令读写/删除本地文件读取剪贴板或密钥环境变量发起外部网络请求
查看扫描证据(共 75 处,展示前 71 条)
  • 读取密钥环境变量
    dev/console/server.mjs:54
    a: process.env.DEV_CONSOLE_SYNC_TOKEN_A?.trim() ?? '',
  • 读取密钥环境变量
    dev/console/server.mjs:55
    b: process.env.DEV_CONSOLE_SYNC_TOKEN_B?.trim() ?? '',
  • 读取本地文件
    dev/console/server.mjs:136
    return JSON.parse(readFileSync(file, 'utf8'))
  • 读取本地文件
    dev/console/server.mjs:152
    return existsSync(join(pluginDir, 'lib', 'index.js'))
  • 执行外部命令来自配置/变量
    dev/console/server.mjs:208
    const child = spawn(command, args, { cwd: repoRoot, env, stdio: ['ignore', 'pipe', 'pipe'] })
  • 发起网络请求
    dev/console/server.mjs:234
    const response = await fetch(`${url}/health`, { signal: AbortSignal.timeout(1500) })
  • 写入本地文件
    dev/console/server.mjs:270
    mkdirSync(dirname(syncCredentialsFile), { recursive: true })
  • 写入本地文件
    dev/console/server.mjs:271
    writeFileSync(syncCredentialsFile, `${JSON.stringify(value, null, 2)}\n`, { mode: 0o600 })
  • 写入本地文件
    dev/console/server.mjs:273
    chmodSync(syncCredentialsFile, 0o600)
  • 写入本地文件
    dev/console/server.mjs:300
    mkdirSync(syncDataDir, { recursive: true })
  • 读取本地文件
    dev/console/server.mjs:301
    const dbExists = existsSync(join(syncDataDir, 'db.sqlite'))
  • 执行外部命令来自配置/变量
    dev/console/server.mjs:365
    const child = spawn(process.execPath, [
  • 发起网络请求
    dev/console/server.mjs:466
    const response = await fetch(`${sync.url}/setup/state`, { signal: AbortSignal.timeout(2_000) })
  • 读取本地文件
    dev/console/server.mjs:477
    const parsed = JSON.parse(readFileSync(onboardingCodeFile, 'utf8'))
  • 执行外部命令固定命令
    dev/console/server.mjs:548
    const killer = spawn('taskkill', ['/pid', String(child.pid), '/T', '/F'], { stdio: 'ignore' })
  • 删除本地文件递归
    dev/console/server.mjs:594
    rmSync(dir, { recursive: true, force: true })
  • 删除本地文件递归
    dev/console/server.mjs:612
    rmSync(syncDataDir, { recursive: true, force: true })
  • 删除本地文件
    dev/console/server.mjs:614
    rmSync(syncCredentialsFile, { force: true })
  • 读取本地文件
    dev/console/server.mjs:643
    if (!existsSync(benchTracePath)) {
  • 读取本地文件
    dev/console/server.mjs:650
    const trace = JSON.parse(readFileSync(benchTracePath, 'utf8'))
  • 执行外部命令固定命令
    dev/console/server.mjs:902
    const killer = spawn('taskkill', ['/pid', String(child.pid), '/T', '/F'], { stdio: 'ignore' })
  • 执行外部命令固定命令
    dev/console/server.mjs:1037
    spawn('taskkill', ['/pid', String(sync.child.pid), '/T', '/F'], { stdio: 'ignore' })
  • 执行外部命令固定命令
    dev/console/server.mjs:1049
    spawn('taskkill', ['/pid', String(side.child.pid), '/T', '/F'], { stdio: 'ignore' })
  • 读取本地文件
    packages/plugin/src/bindings.ts:40
    const parsed = JSON.parse(await readFile(join(stateDir, 'bindings.json'), 'utf8')) as Record<string, unknown>
  • 写入本地文件
    packages/plugin/src/bindings.ts:92
    await mkdir(stateDir, { recursive: true })
  • 写入本地文件
    packages/plugin/src/bindings.ts:95
    await writeFile(temp, `${JSON.stringify(next, null, 2)}\n`, 'utf8')
  • 写入本地文件
    packages/plugin/src/bindings.ts:96
    await rename(temp, target)
  • 读取本地文件
    packages/plugin/src/host-api.ts:82
    markdown = readFileSync(file, 'utf8')
  • 读取密钥环境变量
    packages/plugin/src/index.ts:217
    const envSyncToken = process.env.DSH_SESSION_CLOUDSYNC_TOKEN?.trim() ?? ''
  • 发起网络请求
    packages/plugin/src/index.ts:466
    const response = await fetch(`${base}/v2/sessions?${query}`, {
  • 写入本地文件
    packages/plugin/src/replace.ts:48
    await mkdir(scriptDir, { recursive: true })
  • 读取本地文件
    packages/plugin/src/replace.ts:51
    const template = await readFile(new URL('../assets/replace-session.mjs', import.meta.url), 'utf8')
  • 写入本地文件
    packages/plugin/src/replace.ts:66
    await writeFile(scriptPath, script, { encoding: 'utf8', mode: 0o700 })
  • 写入本地文件
    packages/plugin/src/replace.ts:67
    await chmod(scriptPath, 0o700).catch(() => {})
  • 读取本地文件
    packages/plugin/src/state.ts:37
    parsed = JSON.parse(readFileSync(file, 'utf8'))
  • 写入本地文件
    packages/plugin/src/state.ts:175
    mkdirSync(dirname(file), { recursive: true })
  • 写入本地文件
    packages/plugin/src/state.ts:177
    writeFileSync(temp, `${JSON.stringify(journal)}\n`, { mode: 0o600 })
  • 写入本地文件
    packages/plugin/src/state.ts:178
    renameSync(temp, file)
  • 写入本地文件
    packages/plugin/src/vault-sync.ts:105
    await mkdir(dirname(statePath), { recursive: true })
  • 读取本地文件
    packages/plugin/src/vault-sync.ts:293
    const parsed = JSON.parse(await readFile(path, 'utf8')) as Record<string, unknown>
  • 写入本地文件
    packages/plugin/src/vault-sync.ts:315
    await mkdir(dirname(path), { recursive: true })
  • 写入本地文件
    packages/plugin/src/vault-sync.ts:317
    await writeFile(temp, `${JSON.stringify(state, null, 2)}\n`, 'utf8')
  • 写入本地文件
    packages/plugin/src/vault-sync.ts:318
    await rename(temp, path)
  • 写入本地文件
    packages/plugin/src/vault-sync.ts:561
    await mkdir(dirname(path), { recursive: true })
  • 写入本地文件
    packages/plugin/src/vault-sync.ts:565
    await writeFile(path, JSON.stringify({ pid: process.pid, clientId, at: Date.now() }), { flag: 'wx', encoding: 'utf8' })
  • 读取本地文件
    packages/plugin/src/vault-sync.ts:572
    holder = JSON.parse(await readFile(path, 'utf8')) as { pid?: unknown; clientId?: unknown }
  • 删除本地文件
    packages/plugin/src/vault-sync.ts:579
    await unlink(path).catch(() => undefined)
  • 读取本地文件
    packages/plugin/src/vault-sync.ts:588
    holder = JSON.parse(await readFile(path, 'utf8')) as { clientId?: unknown }
  • 删除本地文件
    packages/plugin/src/vault-sync.ts:592
    if (holder.clientId === clientId) await unlink(path).catch(() => undefined)
  • 读取本地文件
    packages/server/src/blobs.ts:33
    await stat(target)
  • 写入本地文件
    packages/server/src/blobs.ts:38
    await mkdir(dirname(target), { recursive: true })
  • 写入本地文件
    packages/server/src/blobs.ts:40
    await writeFile(temp, bytes)
  • 写入本地文件
    packages/server/src/blobs.ts:42
    await rename(temp, target)
  • 删除本地文件
    packages/server/src/blobs.ts:44
    await unlink(temp).catch(() => undefined)
  • 读取本地文件
    packages/server/src/blobs.ts:47
    await stat(target)
  • 读取本地文件
    packages/server/src/blobs.ts:63
    await stat(blobPath(dataDir, sha256))
  • 读取本地文件
    packages/server/src/blobs.ts:78
    return readFile(blobPath(dataDir, sha256))
  • 写入本地文件
    packages/server/src/db.ts:284
    mkdirSync(dataDir, { recursive: true })
  • 读取本地文件
    packages/server/src/http.ts:62
    const raw = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8')) as { version?: unknown }
  • 读取本地文件
    packages/server/src/http.ts:84
    return readFileSync(url)
  • 读取本地文件
    packages/server/src/http.ts:102
    return readFileSync(url, 'utf8')
  • 删除本地文件
    packages/server/src/http.ts:1272
    rmSync(join(options.dataDir, ONBOARDING_CODE_FILE), { force: true })
  • 写入本地文件
    packages/server/src/index.ts:32
    mkdirSync(dataDir, { recursive: true })
  • 写入本地文件
    packages/server/src/index.ts:35
    writeFileSync(temporary, `${JSON.stringify({ code, expiresAt: Date.now() + ONBOARDING_TTL_MS })}\n`, {
  • 写入本地文件
    packages/server/src/index.ts:39
    chmodSync(temporary, 0o600)
  • 写入本地文件
    packages/server/src/index.ts:43
    renameSync(temporary, file)
  • 删除本地文件
    packages/server/src/index.ts:48
    rmSync(join(dataDir, ONBOARDING_CODE_FILE), { force: true })
  • 写入本地文件
    packages/server/src/index.ts:149
    writeFileSync(join(dataDir, 'setup-token'), `${setup.token}\n`, { mode: 0o600 })
  • 写入本地文件
    packages/server/src/index.ts:151
    chmodSync(join(dataDir, 'setup-token'), 0o600)
  • 读取本地文件
    packages/server/src/sessions.ts:276
    if (!existsSync(blobPath(dataDir, frame.blobSha256))) throw new SyncError('bad-request', `帧 ${frame.index} 的 blob 尚未上传`)
  • 读取本地文件
    packages/server/src/vault.ts:219
    return readFileSync(blobPath(dataDir, sha256))
扫描于 2026/11/4(0 天前) · 范围 全包扫描 · 来源 GitHub 仓库

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

给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个

适用于dsh的会话同步插件及配套可自部署服务器

README

由 DeepSeek 最新模型翻译生成
dsh-session-cloudsync 给 DeepSeek Harness(DSH)做的会话云同步:自部署服务端、端到端加密,同步会话与附件;设备台账、agent 笔记与多工作区映射见 docs/sync/VAULT.md(V0–V2.1 已实现)。 状态:M1/M2 已完成,M3 已完成,M4 进行中。 帧工具/加密、服务端(含管理台与初始化)、M0 免重启 ingest 已经可跑;M3 的推送/拉取、安全边界、双 home E2E、durable journal 与错误退避已通过。M4 已完成 A1–A5、B1–B5(凭据、设置页、首启向导)、C1–C4/C6(composer block、列表拦截、行标记、同步气泡、入口守卫、全局单写者租约)与 E1(batches 规范字段);C5 GUI 回归、D5 故障文案演练与 E3 文档收口顺延到 Vault 之后。Vault V0–V2.1 已完成(本地记录链、服务端 Vault、writer 租约、设备台账、workspaceKey 一次性映射、根会话级同步选择与 label 映射),V3/V4 见 docs/sync/VAULT.md。 支持版本 DSH >=0.2.1-rc.1 <0.2.2-0。0.2.1 之前缺少本插件依赖的能力(如 appendPluginRecord),不做兼容。
展开完整文档(README 剩余 1 节)
dsh-session-cloudsync

给 DeepSeek Harness(DSH)做的会话云同步:自部署服务端、端到端加密,同步会话与附件;设备台账、agent 笔记与多工作区映射见 docs/sync/VAULT.md(V0–V2.1 已实现)。

状态:M1/M2 已完成,M3 已完成,M4 进行中。 帧工具/加密、服务端(含管理台与初始化)、M0 免重启 ingest 已经可跑;M3 的推送/拉取、安全边界、双 home E2E、durable journal 与错误退避已通过。M4 已完成 A1–A5、B1–B5(凭据、设置页、首启向导)、C1–C4/C6(composer block、列表拦截、行标记、同步气泡、入口守卫、全局单写者租约)与 E1(batches 规范字段);C5 GUI 回归、D5 故障文案演练与 E3 文档收口顺延到 Vault 之后。Vault V0–V2.1 已完成(本地记录链、服务端 Vault、writer 租约、设备台账、workspaceKey 一次性映射、根会话级同步选择与 label 映射),V3/V4 见 docs/sync/VAULT.md。

支持版本

DSH >=0.2.1-rc.1 <0.2.2-0。0.2.1 之前缺少本插件依赖的能力(如 appendPluginRecord),不做兼容。

安装

npm 包名:dsh-session-cloudsync。

dsh plugin --profile web add dsh-session-cloudsync

多设备密钥

所有设备必须使用同一个同步口令。主密钥由 scrypt(口令, salt) 派生;没有显式配置 salt 时,盐由 serverUrl 派生,所以各设备的服务端地址写法也要一致(建议统一使用 http://host:port,不要混用 localhost / 127.0.0.1 或省略 //)。设备 token 只用于服务端鉴权,不参与解密。

口令、默认盐或显式 salt 任一不一致,拉取都会报:

封帧的 keyId 与当前密钥不符

这意味着该设备派生出的会话密钥与远端封帧不一致,当前无法解密;需要先统一口令/地址/salt。

目录

packages/shared/ 帧处理(多帧 zstd)、端到端加密、线上类型;插件与服务端共用 packages/plugin/ DSH 宿主插件(install_bundle 的目标目录) packages/server/ 自部署服务端:node:http + node:sqlite + blob 目录,零运行时依赖 tests/ 临时 DSH home 的硬约束与夹具(见 tests/README.md) docs/ architecture/ 协议、封帧、cwd 与整体设计 sync/ Vault、安全、对账、性能与配置快照 ui/ 界面约定与同步列表状态 plans/ 里程碑与决策记录 guides/ 术语、提示与使用协议

开发

pnpm install
pnpm test # node --test(.ts 由 Node 24 直接运行)
pnpm typecheck
pnpm check # typecheck + test
pnpm fixtures # 重新生成夹具的 .zstd 兄弟文件
pnpm dev:server # 在 .tmp/dev-data 起服务端(127.0.0.1:8787)
pnpm dev:dsh # 起隔离的 DSH 开发实例(默认端口 3090)
pnpm dev:console # 起 M0 控制台(127.0.0.1:3091,见 tests/m0/README.md)

夹具由官方 @deepseek-ai/dsh-session 校验器验证(packages/shared 的 devDependencies,版本与 DSH 对齐)。

首次启动服务端:控制台会打印一次性初始化密钥,并提示打开 <http://127.0.0.1:8787/admin>;开发控制台顶部“同步服务端”徽标也会显示/复制这个密钥(同时写入数据目录的 onboarding-code.json,0600,初始化完成即删除)。按向导设置管理密码、存储配额,可选创建第一台设备。之后管理台用密码登录;忘记密码执行 node packages/server/src/index.ts admin reset(重启后重新打印初始化密钥)。

隔离的 DSH 开发实例

pnpm dev:dsh 会:

- 把 DSH_HOME 指到 .tmp/dev-dsh/home;
- 用 --patch 覆盖 workspace-controller 的 documentsDirectory,让默认工作区落在 .tmp/dev-dsh/documents/(否则 DSH 会建到系统 Documents 下);
- 清掉从当前会话继承的 DSH_ 变量,避免新实例误以为自己在嵌套运行。
需要保留已登录状态时:node scripts/dev-dsh.mjs --credentials <旧 home 的 .credentials.yaml>。脚本拒绝在 .tmp/ 之外创建实例目录。

双实例调试用 pnpm dev:panel:起一个本地控制台(默认 <http://127.0.0.1:3092/>),上方左右两个 iframe 分别是独立的 DSH A/B,下方左右两个控制台显示各自 host stdout 与插件 dev sink。首次启动会自动构建并安装本插件、带起本地同步服务端并给 A/B 预配置 token/口令;面板还提供 导入大会话(形状轨迹生成,约 69k 事件)、 恢复预配置 和勾选式 清理数据。配置快照与选择模型见 docs/sync/CONFIG-SNAPSHOT.md,详见 dev/console/README.md。

两条硬约定

- 测试绝不碰真实 ~/.dsh:所有临时 home 经 tests/helpers/tmp-home.mjs 创建,位于 .tmp/ 且被 git 忽略;规则与断言清单见 tests/README.md。
- 仓库文档写我们的选择与中性事实,不评价其他项目。

文档

- docs/README.md:完整文档索引(架构 / 同步 / 界面 / 计划 / 参考)。
- docs/sync/SYNC-PERF-PLAN.md:同步性能重构计划与实施记录。
- docs/ui/SYNC-STATE.md:同步列表稳定性、stage、气泡动效与自动滚动。
- dev/ui/README.md:设置页 / 首启 / 同步气泡的静态原型。
- dev/console/README.md:双实例 DSH 控制台(双 iframe + 双日志 + 插件 dev sink)。
- tests/README.md:临时 home 与夹具约定。

许可证

本仓库按目录拆分许可:

- packages/server/:AGPL-3.0-only*(全文)。对外提供修改后的服务端时,需按 AGPL §13 向使用者提供对应源码;个人自部署、仅自己使用不受影响。
- packages/plugin/、packages/shared/ 及其余部分:MIT(全文)。

根目录的 LICENSE 是拆分范围的简短说明;各 package 目录下也各有一份对应全文。
预览分享卡片长什么样 ↓xfy2412/dsh-session-cloudsync
分享 · DeepSeek Harness Hub
xfy2412/dsh-session-cloudsync

加密同步会话与附件到自建服务器,多设备共享

这是你的仓库?认领条目

回到顶部