dsh-web
zhu1090093659/dsh-webDeepSeek Harness(DSH)Web 插件聚合生态包 · 一切皆插件,创意工坊分发(dsh-market.com)
用 GitHub 私有仓库在多台机器之间同步 dsh 会话、插件清单与设置。
每个 dsh 实例在仓库里拥有自己的目录(instances/<实例ID>/…),互不重叠——所以两台机器永远不会争抢同一个文件,同步不需要合并、不会静默覆盖:
instances/
laptop-a-7f3c/
manifest.json 这台机器的清单(主机名/分组/统计/工作区)
sessions/<工作区目录名>/<会话ID>/session[.vN].jsonl.zstd
plugins/<profile>/{package.json,cordis.patch.yml,pnpm-lock.yaml,pnpm-workspace.yaml}
settings/settings.yaml 可选,默认关闭
desktop-2a91/
…
参考实现以 GitCode 为目标、用 git 二进制 + 影子工作树 + 分支/PR/冲突处理。这个插件面向 GitHub,并做了几处不同的取舍:
| 本插件 | 说明 | |
|---|---|---|
| 传输 | 纯 GitHub REST API(全局 fetch) | 不需要 git 二进制;token 不会落进 .git/config;沙箱/无 git 的机器也能用;走 dsh 启动器已装好的代理策略 |
| 冲突 | 结构上不存在 | 每台机器只写自己的 instances/<ID>/,没有共同文件可争 |
| 增量 | 内容寻址 | 本地算 sha1("blob <len>\0" + bytes),与远端树里的 blob sha 比对,未变的会话不重复上传 |
| PR | 可选 | pullRequest 打开后走「分支 → PR → 可合并则 squash 合并」,冲突则把 PR 留在仓库里 |
| 清单时标 | 不含时间戳 | manifest 对相同输入是确定性的,否则每次定时同步都会产生一个空提交;「何时备份」由 GitHub 的提交时间承担 |
dsh plugin --profile web add github:minghuo/dsh-github-sync
装完重启 dsh web 生效。发布到 npm 之后也可以直接用包名安装:
dsh plugin --profile web add dsh-github-sync
更新到最新提交:dsh plugin --profile web update dsh-github-sync,再重启 dsh web。
Contents: Read and write(要用 PR 模式再加 Pull requests: Read and write)。owner/repo 或完整 URL)、分支、令牌,保存。定时自动备份在「概览 → 自动备份」里开启;autoSync 打开后按 intervalMinutes(最小 5 分钟)执行,可选启动时备份一次。
三类内容各自独立开关,关掉的那一类既不上传、也不会删除云端已有内容:
| 分组 | 默认 | 内容 | 排除 |
|---|---|---|---|
sessions | 开 | $DSH_HOME/sessions/** 整目录 | *.tmp、session.lock、.dsh-mkdir* |
plugins | 开 | 各 profile 的 package.json、cordis.patch.yml、pnpm-lock.yaml、pnpm-workspace.yaml | node_modules/、cordis.yml(启动器每次覆写)、.dsh-market/、.dsh-module-fallback/ |
settings | 关 | $DSH_HOME/settings.yaml | — |
.credentials.yaml、.anonymous-user-id 之类的机器本地机密从不进入计划,无论开关怎么设。
session.jsonl.zstd 与更新的 session.vN.jsonl.zstd 可能同时存在,前者是迁移前身、别丢),按字节复制,不做解码/重编码。dryRun 预览。恢复前自动把当前状态拍成本地快照(pre-restore-*)。$DSH_HOME/dsh-github-sync/snapshots/),滚动保留 snapshotKeep 份,用于快速回滚。恢复前总会自动拍一份(pre-restore-*);推送前是否也拍由「高级 → 推送前先拍本地快照」控制。注意每份快照约等于会话总体积(40 MB 量级),默认「推送前也拍 + 保留 20 份」最坏情况约 900 MB —— 不想付这个代价就关掉推送前快照,或把保留份数调小。hasToken,不是令牌本身;令牌存在 settings 命名空间(role('secret'))或 $DSH_HOME/dsh-github-sync/config.json。POST /api/sync 每次都会先读仓库元数据,private !== true 直接拒绝。/api 那层 cookie 栅栏,因此对 PUT/POST 做了 Origin/Host 比对。--…-- 形状的单个路径段,会话日志读取被限制在 $DSH_HOME/sessions 之下。路由前缀 /dsh-github-sync/api(同源 fetch,无需额外认证头):
| 方法 | 路径 | 说明 |
|---|---|---|
| GET | /status | 实例 ID、配置、上次结果、本地统计、快照数 |
| PUT | /settings | 局部更新设置;token: '' 清除令牌 |
| POST | /verify | 读仓库元数据,判断私有/可推送 |
| POST | /sync | 立即推送(关掉的组不会删远端) |
| GET | /remote | 远端各实例清单(分支提交时间作为「最近备份」) |
| GET | /sessions/local | 本机会话清单 |
| POST | /sessions/restore | {instanceId, workspace?, map?, overwrite?, dryRun?} |
| GET | /sessions/text | ?local=1&workspace=&session=&file= 或 ?path=<仓库路径> |
| GET | /snapshots | 本地快照列表 |
| POST | /snapshots · /snapshots/restore · /snapshots/delete | 新建 / 恢复 / 删除快照 |
三件事互相独立:代码托管(GitHub 仓库)、可安装(git spec 或 npm 包)、上架(插件市场条目)。
# 需要 fine-grained PAT:Contents: write(首次建仓库再加 Administration: write)
GITHUB_TOKEN=github_pat_xxx node scripts/publish-github.mjs repo --owner <你的账号>
脚本走 GitHub REST(不需要 git 远端,也不读凭据管理器),会建仓库、推送工作树、写入 dsh-plugin 等 topics。--dry-run 只打印计划;status 汇报现状与上架条件;--description "<一句话>" 改写已存在仓库的描述。
⚠️ 脚本按工作树内容直接建提交,不读本地 git 历史。别在工作树有未提交改动时混用两条路,否则远端会多出一个本地没有的提交(
git fetch && git reset --hard origin/main可对齐)。日常用git push,脚本只负责 topics / 描述 / 上架。
环境里 git 可用时,普通 git push 也一样:
git remote add origin https://github.com/<你的账号>/dsh-github-sync.git
git push -u origin main
两条路,不必都做:
dsh plugin --profile web add github:<账号>/dsh-github-syncnpm version patch && git push --follow-tags,.github/workflows/publish.yml 会在 v* tag 上发布(需要仓库 secret NPM_TOKEN),之后 dsh plugin --profile web add dsh-github-sync 即可。市场目录来自 awesome-dsh-plugin:一个插件一个文件 data/plugins/<owner>__<repo>.yml。本仓库的条目在 docs/registry-entry.yml:
node scripts/publish-github.mjs registry # fork → 分支 → 条目 → PR
CI 会检查「仓库创建满 1 天」,所以仓库刚建的当天提交会被自动拒绝——脚本会算好还差几小时并拒绝执行,避免白发一个 PR。另外要求仓库带 dsh-plugin topic、package.json 声明 dsh.bundle(本仓库已有)。
npm test # node:test,含一个把 GitHub 换成内存实现的端到端集成测试
npm run build:client # 由 client/index.js 生成 client/bundle.js
npm run check # 两个入口的语法检查
client/bundle.js 是提交进仓库的构建产物(git 安装不会跑构建),CI 会重新构建并断言它与 client/index.js 一致。
export { name, inject, apply },apply(ctx, config) 里用 ctx.effect 包住 ctx.webServer.register。scripts/build-client.mjs 包成 window.__ModuleLoader__.load({ id, factory }),id 必须等于包名,exports["./client"] 指向构建产物。test/fake-github.mjs 是一个内存 GitHub,test/plugin.test.mjs 用假的 req/res 驱动真实路由。cwd。dsh 的 list() 只看目录,所以会话会出现在映射后的工作区下;但日志体里的绝对路径仍是原机器的。要做到无损,恢复时得解压/改序化/重压缩每一帧——那会破坏「源文件字节不变」的格式契约,因此没做。$DSH_HOME/storages/workspace.json(工作区注册表 / 归档会话 id)不参与同步。它是机器本地的,覆盖它会影响本机侧栏;需要时可手工处理。$DSH_HOME/attachments/)不在同步范围内。maxFileMb(45 MB)的单个文件并在结果里报告。truncated,此时只做增量比对(插件会在结果里标注)。~/.dsh git 仓库并存如果这台机器的 $DSH_HOME 曾经被某个旧同步插件初始化成 git 仓库(.git + 自动生成的 .gitignore),本插件不会碰它:它只使用 GitHub REST API,所有自身状态都在 $DSH_HOME/dsh-github-sync/ 下。两条链路可以并存;想彻底退役旧链路,需要手工删除 $DSH_HOME/.git、$DSH_HOME/.gitignore、$DSH_HOME/dsh-sync.json 与 .dsh-sync.state.json。
MIT