dsh-plugin-repoflow
Deployment-level Git plugin for DeepSeek Harness (DSH) — a Git settings section after 通用设置 / 模型 / 插件 / agent 预设, with global GitHub account configuration and visual local repository management.
中文简介:在设置页「模型 / 插件 / agent 预设」之后新增「Git」入口。全局保存 GitHub 账号信息(用户名 / 邮箱 / Token / Host / 默认可见性),并针对本地目录提供仓库可视化:分支、领先/落后、暂存/未暂存/未跟踪/冲突、最近提交、变更文件,以及初始化、创建 GitHub 仓库、提交、推送等常用操作。
当前版本 0.2.0:针对 DSH 0.2.0-rc.2 适配 —— 请求来源围栏、凭证不再进入进程命令行、GitHub 错误明细解析、空仓库分支名修复、Tool 取消信号与并行调度声明。详见变更日志。
🧭 Compatibility / 兼容性
| 项 | 要求 |
|---|---|
| DSH | 0.2.0-rc.2(本机自带运行时实测);对照 @deepseek-ai/dsh-host-webserver、@deepseek-ai/dsh-tools、@deepseek-ai/dsh-client-modules 的实际契约核验 |
| Node | >= 20(使用 AbortSignal.any / AbortSignal.timeout,缺失时自动降级) |
| Git | 任意版本;git init -b 不支持时回退到 git init + symbolic-ref |
| 外部依赖 | 无。Host 半区只用 Node 内置模块,Client 半区只 require react(平台基线模块) |
✨ Features / 功能特性
- 设置页入口:与通用设置 / 模型 / 插件 / agent 预设同一视觉语言,注册在
settings.section,顺序在 agent 预设之后(order: 40,与内置分区 -10/0/10/15/20 无冲突)。 - 全局 GitHub 配置:保存到
~/.dsh/git/config.json(version: 1,权限0600),Token 不会明文回显;支持一键清除 Token。 - 连接测试:通过 GitHub API
/user验证 Token 与 Host 是否可用。 - 仓库可视化:
- 当前分支、ahead / behind、远程仓库
- 已暂存 / 未暂存 / 未跟踪 / 冲突统计
- 最近 12 条提交
- 变更文件列表(porcelain 状态码)
- 常用操作:
初始化仓库:git init -b main,并把已保存的用户名/邮箱写入该仓库本地配置创建 GitHub 仓库并推送:自动初始化(如需要)→ GitHub API 创建仓库(同名仓库视为已存在,继续推送)→ 设置干净 remote → 创建初始提交(如需要)→ 推送提交:git add -A && git commit推送:使用保存的 Token 经GIT_CONFIG_*环境变量认证推送,Token 既不写入 remote URL,也不出现在进程命令行分支管理:查看本地分支、一键切换分支、创建并切换到新分支提交分支图:git log --graph --oneline --decorate --all图形化展示提交历史与分支拓扑GitHub 仓库列表:连接后自动展示当前账号已有的远程仓库
- 模型工具(Agent 可用):
git_status/git_repos/git_init/git_commit/git_push/git_create_repo/git_branch/git_checkout/git_log- 只读工具(
git_status/git_repos/git_branch/git_log)声明isConcurrencySafe,可被调度器并行执行;写操作保持独占 - 全部工具透传
ToolRunContext.signal,取消时终止 git 子进程或 GitHub 请求并返回{ ok: false, aborted: true }
- 只读工具(
🔐 Security model / 安全模型
本插件在宿主进程里以当前用户身份执行 git 与 GitHub API 调用,因此请求入口按 DSH「路由属主自负其责」的约定自行加固:
- Host / Origin / Sec-Fetch-Site 围栏:与
@deepseek-ai/dsh-client-connection为/api网桥实现的浏览器信任围栏同构。Host必须是回环(localhost/127.0.0.0/8/[::1])、本机字面量地址或config.trustedHosts声明的权威;带Origin时必须同源;Sec-Fetch-Site: cross-site直接拒绝。这道围栏同时挡住 DNS rebinding 与恶意网页发起的跨站请求。 - POST 只收 JSON:
Content-Type非application/json的请求体直接415。浏览器对跨站fetch只能免预检地发送text/plain/ 表单,因此这一层独立地掐断了盲发 CSRF(合法客户端始终发送 JSON)。 - Token 处理:仅存本机
~/.dsh/git/config.json(0600);HTTP 响应只返回hasToken与••••••••xxxx预览;不写入 remote URL;推送时通过GIT_CONFIG_COUNT/KEY_0/VALUE_0环境变量传给 git,不出现在ps可见的命令行参数里。 - 请求体上限 1MB,错误信息截断 300/500 字符,响应带
Cache-Control: no-store与X-Content-Type-Options: nosniff。 - 局域网部署:webserver 绑定
0.0.0.0时,本机字面量地址自动放行;反向代理 / Tailscale 等额外权威通过 loader 条目的config.trustedHosts声明(见cordis.patch.yml注释示例)。围栏不是鉴权层:把服务暴露到不可信网络仍会暴露这些路由。
🔑 Required Permissions / GitHub 权限说明
本插件使用 GitHub Personal Access Token 完成以下操作:
- 测试 GitHub 连接(
GET /user) - 列出当前账号已有的远程仓库(
GET /user/repos) - 创建 GitHub 仓库(
POST /user/repos) - 通过 HTTPS 推送代码到远程仓库
如果你只使用本地 Git 功能(init / commit / branch / checkout / log / status),不需要 Token。
Classic PAT 推荐权限
| 场景 | 所需 Scope |
|---|---|
| 仅操作公开仓库 / 创建公开仓库 | public_repo |
| 操作私有仓库 / 创建私有仓库 | repo |
| 推荐直接使用 | repo(包含公开与私有仓库的完整读写) |
Fine-grained PAT 推荐权限
| 设置项 | 推荐值 |
|---|---|
| Repository access | All repositories,或至少选择需要操作的仓库 |
| Contents | Read and write |
| Administration | Read and write(仅当需要通过 API 创建/删除仓库时必需) |
| Metadata | Read(GitHub 自动包含) |
如果只用现有仓库进行提交和推送,
Administration可以不开;如果需要“创建 GitHub 仓库并推送”,则必须开启Administration: Read and write。
🚀 Install / 安装
方式 A:官方 CLI(本地目录 / npm / GitHub 仓库)
# 本地目录安装(开发调试推荐;<profile> 例如 desktop / web)
dsh plugin --profile <profile> add /path/to/dsh-plugin-repoflow
# 已发布到 npm / GitHub 时
npx -p @deepseek-ai/dsh dsh plugin --profile <profile> add @dsh-community/dsh-plugin-repoflow
方式 B:手动安装
# 1. 将插件复制到 profile 的插件目录(<profile> 用实际 profile 名,如 desktop)
mkdir -p ~/.dsh/profiles/<profile>/node_modules/@dsh-community
cp -R dsh-plugin-repoflow ~/.dsh/profiles/<profile>/node_modules/@dsh-community/
# 2. 在 profile 的用户补丁层注册插件行
cat >> ~/.dsh/profiles/<profile>/cordis.patch.yml << 'EOF'
- insert:
- id: ui-repoflow
name: '@dsh-community/dsh-plugin-repoflow'
EOF
# 3. 重启 profile(或等待 HMR 事务性重读用户补丁)
若同时存在 bundle 层与手动补丁行(双重挂载),第二次加载会跳过已注册的路由与工具并打印
already registered (skip),不会报错。
🧩 Architecture / 架构
浏览器 (client, lib/client.js) Node (host, lib/index.js)
┌──────────────────────────────────────┐ fetch ┌──────────────────────────────────────┐
│ settings.section "Git" │ ─────────▶ │ webServer.register({kind:'exact'}) │
│ 账号配置 / 仓库可视化 / 操作按钮 │ /git-api/* │ 围栏 → JSON 门禁 → 配置持久化 │
│ <style data-plugin> 注入 │ ◀───────── │ git CLI + GitHub API + 9 个模型工具 │
└──────────────────────────────────────┘ └──────────────────────────────────────┘
- Host 半区注册 10 条精确路由:
config(GET/POST) /test/repos/status/init/create/commit/push/branches/checkout。 - Client 半区注册
settings.section(id: git、order: 40、label: () => 'Git'),样式标签带data-plugin+data-plugin-css,随模块系统卸载自动回收。 - 零外部依赖:Host 只用
node:child_process/node:fs/node:os/node:path/node:util。
✅ Verify / 离线验证
node scripts/verify.mjs
覆盖(24 项断言,无需 dsh 服务、不触碰真实 ~/.dsh/git/config.json):
- 双半区语法检查 → Host ESM 导出(
apply/inject/name) - mock ctx(重复注册即抛错的严格注册表)下 10 条路由 + 9 个工具注册
- 请求策略:9 组 Host/Origin/Sec-Fetch-Site 用例 + 非 JSON POST 415 + 非法 JSON 400
- 配置往返(沙箱 HOME):
0600、Token 不回显、留空保旧值、clearToken清除、version: 1 - 真实 git 行为(临时仓库):空仓库分支名、计数/提交图/分支、路径错误
- 工具契约:
output.schema + render、只读工具isConcurrencySafe、AbortSignal取消 - 客户端 bundle:浏览器沙箱执行 →
settings.section选项与组件、样式记账属性
📦 Package structure / 包结构
dsh-plugin-repoflow/
├── package.json # dsh.bundle + dsh.client 声明、exports["./client"]、engines、peerDependencies(optional)
├── cordis.patch.yml # bundle 补丁:插入 ui-repoflow 设置页(含 trustedHosts 示例)
├── lib/
│ ├── index.js # host 半区(围栏 + /git-api/* + 9 个工具)
│ ├── client.js # client 半区(settings.section Git 页)
│ └── types/index.d.ts # host 类型声明
├── scripts/verify.mjs # 离线验证
└── README.md / LICENSE
⚠️ Known limitations / 已知限制
- 界面文案为硬编码中文,未接入
ctx.locale本地化体系。 - GitHub 仓库列表只取第一页(100 个),未做分页。
- 路径语义:
~不展开;相对路径按宿主进程 cwd 解析(模型工具文档要求绝对路径)。部分失败的 HTTP 错误仍以200 + {ok:false}返回(如push),客户端按ok判定。 - 客户端走相对路径
/git-api/*,适用于 HTTP 载体;若以非 HTTP 载体(如 Electronfile://)加载,需要改用@deepseek-ai/dsh-api-remotes之类的远程服务通道。 - 围栏不提供身份鉴权;请勿在不可信网络上暴露 webserver。
📝 Changelog / 变更日志
0.2.0 — DSH 0.2.0-rc.2 适配
- 🔒 新增请求来源围栏(Host/Origin/Sec-Fetch-Site),并对 POST 强制
application/json;此前/git-api/*可被恶意页面盲发跨站请求或经 DNS rebinding 读取。 - 🔒 Token 移出进程命令行:推送改用
GIT_CONFIG_*环境变量,ps不再可见。 - 🐛 修复空仓库分支名:
git init后未提交时,## No commits yet on main曾被当作分支名返回。 - 🐛 修复同名仓库识别:GitHub 的 422 明细在
errors[].message,此前只读顶层message("Repository creation failed.")导致去重分支失效;现在合并明细并保留status,远程已存在时继续推送,non-fast-forward给出明确提示。 - ✨ 清除 Token:
POST /git-api/config { clearToken: true }+ 设置页「清除 Token」按钮。 - ✨ 工具契约更新:只读工具声明
isConcurrencySafe;全部工具透传ToolRunContext.signal(git 子进程与 GitHub 请求均可取消,超时 30s / 推送 300s)。 - ✨ 配置与错误契约:配置文件写入
version: 1;请求体解析返回结构化 400/413;sentJson增加nosniff。 - 🔧 打包与声明:
dsh.client.inject从已不存在的@deepseek-ai/dsh-client-runtime改为真实的@deepseek-ai/dsh-client-ui-slots;补engines.node >= 20、optionalpeerDependencies、files增加scripts/(此前发布包内pnpm verify必然失败)。 - 🔧 创建流程:remote 用
set-url/add幂等设置,优先使用 API 返回的clone_url。 - ✅ 验证脚本:从 4 项扩展到 24 项断言,覆盖围栏、门禁、配置往返、真实 git 行为、工具契约与客户端注册。
0.1.0
- 首个版本:设置页 Git 分区、GitHub 账号配置、仓库可视化、10 条
/git-api/*路由与 9 个git_*工具。
License
This project is licensed under the Apache License 2.0. See the full license at https://www.apache.org/licenses/LICENSE-2.0.
No comments yet. Be the first to write one.