Bundle
dsh-ezcommit-plugin
DSH「一键 Commit」静态双面插件:由当前会话模型按业务颗粒度拆分 git 改动并分批提交
- Source
- PenguinAndy
- stars
- 3 stars
- License
- MIT
- Updated
- Updated 4 days ago
Readme
# DSH-EZ Commit Plugin
> DSH(DeepSeek Harness)「一键 Commit」静态双面插件:安装并重启 profile 后,web 会话标题栏自动出现 **一键 Commit** 按钮,由**当前会话模型**按业务颗粒度把工作区 git 改动拆分为多个提交(Conventional Commits),经用户审查后分批执行;当模型判定改动为「环境噪音」时只提示、不执行任何 git 写操作。
[](./LICENSE)
[](./package.json)
[](./package.json)
[](https://github.com/PenguinAndy/dsh-ezcommit-plugin/releases)
[English](./docs/README.en.md) | 简体中文
## 目录
- [简介](#简介)
- [特性](#特性)
- [快速开始](#快速开始)
- [安装](#安装)
- [使用流程](#使用流程)
- [工作原理](#工作原理)
- [API 契约](#api-契约)
- [HTTP API 一览](#http-api-一览)
- [模型输出契约](#模型输出契约)
- [安全与隐私](#安全与隐私)
- [开发](#开发)
- [目录结构](#目录结构)
- [本地验证](#本地验证)
- [相关文档](#相关文档)
- [贡献](#贡献)
- [许可证](#许可证)
## 简介
DSH-EZ Commit 是一个 DSH 静态双面插件(与 `dsh-skin-market` 等第三方皮肤包同一机制):
- **一个包,双平面**:Client 半(`exports "./client"` + `dsh.client` 声明,浏览器模块工厂)负责 UI(按钮 + 弹窗);Host 半(`main` 入口)负责在 `webServer` 上挂载同源 HTTP API、git 采集、模型裁决与分批提交。
- **安装即生效**:`dsh plugin --profile <name> add dsh-ezcommit-plugin` 安装/升级(`dsh.bundle` 规范,见 [docs/INSTALL.md](./docs/INSTALL.md)),**重启 profile** 后会话标题栏自动出现按钮;无需 cordis preset,也无需 `cordis_define` / `cordis_run`。
- **零运行时依赖**:仅用 Node 内置模块与浏览器原生能力(`fetch` / `React.createElement`),`React` 由 web 外壳预置基线提供。
- **模型优先**:拆分与噪音裁决完全由当前会话模型完成,插件本身不做任何猜测性的 git 写操作。
## 特性
| # | 需求 | 实现 |
|---|------|------|
| 1 | 非 git 仓库 → 按钮置灰 | Host `shell` 执行 `git rev-parse --is-inside-work-tree` |
| 2 | 按钮左侧展示分支名 | `git symbolic-ref --short HEAD`(detached 退化为短 hash) |
| 3 | 点击弹二次确认框 | Client `shell.overlay` 插槽自绘 modal |
| 4 | 模型按业务颗粒度拆分 commit | Host `llm.stream()` 分析改动事实,输出 JSON 计划 |
| 5 | 无改动 → 置灰 | `git status --porcelain` 计数为 0 时禁用 |
| 6 | 模型判定「环境噪音」→ 提示不 commit | 裁决 `verdict: "noise"`,Host 零 git 写操作 |
## 快速开始
### 安装
安装用 DSH 官方 CLI 完成分发与版本管理(完整规范见 [docs/INSTALL.md](./docs/INSTALL.md),[English](./docs/INSTALL.en.md)):
```bash
# 从 npm 安装(发布后)——登记为 profile bundle 层,由 pnpm 管理版本
dsh plugin --profile web add dsh-ezcommit-plugin
# 或从 git 仓库 / 本地 checkout 安装
dsh plugin --profile web add git+https://github.com/PenguinAndy/dsh-ezcommit-plugin.git
dsh plugin --profile web add link:/path/to/dsh-ezcommit-plugin
```
安装完成后**重启 profile**(如 `dsh web`):启动日志打印 `[dsh-ezcommit-plugin] v<x.y.z> 已安装` 与路由挂载结果;刷新页面后,每个 web 会话标题栏出现 `[分支名] [一键 Commit]`,工作区非 git 仓库或无改动时按钮置灰。**无需任何会话内操作**(不需要 cordis preset / `cordis_define`)。
### 使用流程
1. 点击「一键 Commit」→ 确认框展示分支与改动计数(二次确认)。
2. 「开始分析」→ Host 采集 `status / diff / 未跟踪采样`(敏感路径自动过滤,不采样、不进入提示词),调用**当前会话已路由的模型**裁决:
- `noise` → 黄色提示框展示原因,不执行任何 git 写操作;
- `commit` → 计划审查框展示拆分批次(顺序、message、文件清单)、被过滤的敏感文件与未覆盖文件告警。
3. 「执行 N 批提交」→ 逐批 `git add --pathspec-from-file=- --`(文件清单经 stdin,天然规避空格/特殊字符路径)+ `git commit -m title [-m body]`,返回每批短 hash。
4. 完成后按钮立即刷新置灰;任一批失败即停止(不回滚),已成功批次照常报告。
## 工作原理
一个包、双平面:Client 半由 `dsh-client-modules` 打进 web 启动图(`/plugins/dsh-ezcommit-plugin/client.js`),按 `window.__ModuleLoader__` 工厂格式在浏览器加载并挂载客户端插件;Host 半在本进程加载,向 `webServer` 注册 `/ezcommit/api` 前缀路由。Client 通过同源 HTTP 调用 Host。一次完整操作的时序如下:
```mermaid
sequenceDiagram
participant C as Client(浏览器)
participant H as Host(Node 进程)
participant M as 当前会话模型
Note over C: setInterval:每 5s 轮询
C->>H: POST /ezcommit/api/git.state {sessionId}
H-->>C: { inRepo, branch, hasChanges, changedCount }
Note over C: 非 git 仓库 / 无改动 → 按钮置灰
C->>C: 点击「一键 Commit」→ 二次确认框
C->>H: POST /ezcommit/api/commit.analyze {sessionId}
H->>H: 采集 status / diff / 未跟踪采样<br/>截断上限 + 敏感路径过滤
H->>M: llm.stream(改动事实 + 系统提示词)
M-->>H: JSON 计划 { verdict, commits }
alt verdict = "noise"
H-->>C: 环境噪音 → 提示弹窗(零 git 写操作)
else verdict = "commit"
H-->>C: 拆分批次 + 文件清单(用户审查)
C->>H: POST /ezcommit/api/commit.execute {sessionId, commits}
H->>H: 逐批 git add + git commit<br/>任一批失败即停止(不回滚)
H-->>C: { results: [{ title, hash }], leftoverCount }
end
```
## API 契约
### HTTP API 一览
Host 半在 `webServer` 上挂载三个同源 JSON API(仅 POST,同源校验;参数与返回值仅无损 JSON):
| 方法 | 路径 | 入参 | 出参要点 |
|------|------|------|----------|
| `git.state` | `POST /ezcommit/api/git.state` | `{sessionId}` | `{ok, inRepo, branch, hasChanges, changedCount, untrackedCount}` |
| `commit.analyze` | `POST /ezcommit/api/commit.analyze` | `{sessionId}` | `{ok, verdict:'noise'\|'commit', reason, commits:[{title,body,files}], unplanned, problems, sensitive:[path], diffTruncated, target}` |
| `commit.execute` | `POST /ezcommit/api/commit.execute` | `{sessionId, commits}` | `{ok, results:[{title,hash}], leftoverCount}` |
失败统一返回 `{ok:false, error:{message, code}}`;非 POST → 405,未知方法 → 404,跨源 → 403。
### 模型输出契约
系统提示词要求模型仅输出如下 JSON(响应解析时自动剥离 markdown 代码围栏,解析失败自动重试一次):
```json
{
"verdict": "noise",
"reason": "一句话说明(noise 时必填)",
"commits": [
{ "title": "feat(scope): ...", "body": "可选多行说明", "files": ["相对路径..."] }
]
}
```
- `files` 必须逐字取自改动清单;不存在/重复的文件归入 `unplanned` 并在 UI 告警。
- 模型目标解析顺序:会话已路由配置(`session.requestHeader().config`)→ `agent.options` → 默认模型(`agentDefaultModel.currentSelection()`)。
## 安全与隐私
- 噪音裁决在 `git add`/`commit` 之前完成,noise 路径零 git 写操作。
- **敏感路径过滤**:`.env*`、`.npmrc`、`.pypirc`、`.netrc`、`.git-credentials`、`*.pem`、`*.key`、`id_rsa*`、`.ssh/`、`.aws/`、`.kube/`、`credentials*.json` 等文件的路径与内容不会发送给模型,也不会进入计划或被执行提交;计划/噪音弹窗会列出被过滤文件(仅本地展示)。
- **隐私边界**:点击「开始分析」后,工作区 `status`、`diff` 与未跟踪文本采样(每文件前 8KB、最多 32 个)会发送给当前会话模型服务商;敏感路径除外。请仅对允许发送给模型服务商的工作区使用。
- API 仅接受同源 POST(Origin 与 Host 一致),拒绝跨站调用。
- `commit.execute` 执行前用**当前** porcelain 重建已知文件集合,陈旧/发明路径一律无效。
- 不 `git push`、不 `--force`、不修改历史;多批次中某批失败 → 停止、不回滚、如实报告。
- 同一 sessionId 的 analyze/execute 有进程内 in-flight 锁,重复点击直接拒绝。
- 所有副作用(路由、插槽、轮询、样式)均挂在插件生命周期上,bundle 层卸载时自动清理。
## 开发
### 目录结构
```
.
├── .github/workflows/
│ └── release.yml 发布工作流
├── docs/
│ ├── README.en.md 英文版 README
│ ├── INSTALL.md 插件安装规范(中文)
│ ├── INSTALL.en.md 插件安装规范(English)
│ ├── dsh-ez-commit-design.md 设计文档(需求→契约映射、决策点、风险)
│ └── VERIFICATION.md 真机验证走查(六条需求)
├── src/
│ ├── index.js Host 半:/ezcommit/api 路由 + git/模型逻辑 + 公告/自检
│ └── client.js Client 半:按钮 + 弹窗 + 样式(__ModuleLoader__ 工厂)
├── scripts/
│ ├── verify.mjs 离线冒烟校验(不依赖 DSH 运行时,真实 git 集成)
│ └── stage-fixture.mjs 场景制备:demo | noise | clean
├── cordis.patch.yml profile bundle 层补丁(ezcommit 安装锚点行)
├── package.json 版本与 dsh.bundle + dsh.client 双面契约;零运行时依赖
├── pnpm-lock.yaml
└── LICENSE MIT
```
### 本地验证
```bash
pnpm verify # 或 npm run verify:包契约 + HTTP 路由集成(真实 git)+ client 工厂冒烟
```
运行时验证:安装并重启 profile 后,按 [docs/VERIFICATION.md](./docs/VERIFICATION.md) 的走查矩阵逐项验证六条需求(配 `node scripts/stage-fixture.mjs demo|noise|clean` 场景制备工具);模型裁决路径可用包含 `.DS_Store`、锁文件等「噪音」的工作区验证。
### 相关文档
- 安装规范:[docs/INSTALL.md](./docs/INSTALL.md) / [docs/INSTALL.en.md](./docs/INSTALL.en.md)
- 设计文档:[docs/dsh-ez-commit-design.md](./docs/dsh-ez-commit-design.md)
- 验证走查:[docs/VERIFICATION.md](./docs/VERIFICATION.md)
## 贡献
欢迎 Issue 与 PR。提交 PR 时请:
- 提交信息遵循 [Conventional Commits](https://www.conventionalcommits.org/) 规范;
- 修改 `src/` 后运行 `pnpm verify` 确保离线冒烟校验通过;
- 涉及行为变更时同步更新本 README 与 `docs/` 文档。
## 许可证
[MIT](./LICENSE) © [PenguinAndy](https://github.com/PenguinAndy)
Install
dsh plugin --profile web add github:PenguinAndy/dsh-ezcommit-plugin
Profile: web
With the hub plugin installed, ask your agent to install it by name — it resolves the same plan shown here.
dsh plugin --profile web add github:stvlynn/dsh.fish#path:packages/dsh-plugin-hub
install dsh-ezcommit-plugin from the hub
- This source has no pinned commit, so a later push upstream changes what installs. Prefer pinning a commit.