@xia-sc/dsh-git 0.5.2 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.en.md +51 -8
- package/README.md +34 -8
- package/lib/client.js +748 -255
- package/lib/index.js +27 -7
- package/package.json +3 -2
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 xia-sc
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.en.md
CHANGED
|
@@ -15,13 +15,22 @@ new-branch-from-base.
|
|
|
15
15
|
## UI
|
|
16
16
|
|
|
17
17
|
- **Floating block** (`shell.overlay`): collapsed = renders nothing (no
|
|
18
|
-
floating element that could cover the input); expanded =
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
the affected files instead of switching,
|
|
22
|
-
hatch
|
|
23
|
-
|
|
24
|
-
|
|
18
|
+
floating element that could cover the input); expanded = one workflow read
|
|
19
|
+
top-down: status line (pending count, ahead/behind, upstream) → the branch
|
|
20
|
+
switcher with its **dirty-tree pre-check** (selecting a branch while
|
|
21
|
+
uncommitted changes exist warns with the affected files instead of switching,
|
|
22
|
+
plus a "switch anyway" escape hatch) → a **network toolbar** (Fetch / Pull /
|
|
23
|
+
Push, three equal columns, Push being the primary button) → a **commit card**
|
|
24
|
+
(Stage all + draft basis + "✨ AI draft" in equal columns, the message input
|
|
25
|
+
below it and the commit button) → two list cards. Every button group is split
|
|
26
|
+
evenly instead of sizing itself to its label.
|
|
27
|
+
**Operation feedback is pinned to the very
|
|
28
|
+
top of the panel and stays one line tall** — the busy label and the last
|
|
29
|
+
operation's result are the first rows of the body. The result is a localized
|
|
30
|
+
phrase ("Pushed", "Staged everything", "Switched to x"); git's own output (a
|
|
31
|
+
push sideband banner, the `LF will be replaced by CRLF` advice) sits behind a
|
|
32
|
+
"Details ▾" toggle on the right, so the change list and the log can never push
|
|
33
|
+
the notification out of sight. The panel is
|
|
25
34
|
**draggable by its header bar**
|
|
26
35
|
(the top row with the Git title — press, drag, release; it stays where
|
|
27
36
|
dropped and is clamped inside the viewport; header buttons/inputs never
|
|
@@ -30,6 +39,18 @@ new-branch-from-base.
|
|
|
30
39
|
new branch name + base-branch picker (local branches or full remote refs
|
|
31
40
|
like `origin/feature/x`) — confirming creates the branch from the base and
|
|
32
41
|
switches to it.
|
|
42
|
+
- **Changes and recent commits are two cards**: a change row is "monospace path
|
|
43
|
+
+ status chip" (path first, so the paths line up in a column; modified=amber,
|
|
44
|
+
added/untracked=green, deleted/conflict=red, renamed=blue; the file the diff
|
|
45
|
+
pane is showing is highlighted), a commit row is "short sha + subject". Each
|
|
46
|
+
card's header (`▾ Changes 12`) collapses the whole section and starts
|
|
47
|
+
**expanded** — a Git panel must not hide the user's own changes; a list past
|
|
48
|
+
8 / 5 rows offers "Show all N" at the bottom, which is a separate state, so the
|
|
49
|
+
chevron always points the right way.
|
|
50
|
+
- **Refreshing never flashes**: clicking ↻ or any post-action re-read keeps the
|
|
51
|
+
panel's content (a same-workspace re-read does not fall back to a "loading"
|
|
52
|
+
line and snap back); the header's refresh button greys out and reads
|
|
53
|
+
"Refreshing…".
|
|
33
54
|
- **Click a change to see its diff**: clicking any row of the change list grows
|
|
34
55
|
the panel from its 400px single column into two panes — the full workbench on
|
|
35
56
|
the left, that file's unified diff on the right (see *The diff viewer* below).
|
|
@@ -40,6 +61,11 @@ new-branch-from-base.
|
|
|
40
61
|
- Both seats share one store, so they always agree, and both re-bind when the
|
|
41
62
|
current session (and its cwd) changes. Rebinding clears the selected file —
|
|
42
63
|
the panel never shows another repository's content.
|
|
64
|
+
- **ANSI colour codes are stripped from git's text output**: remotes colour
|
|
65
|
+
their own banner (gitee's `Powered by GITEE.COM` does), and the panel is a DOM,
|
|
66
|
+
not a terminal — the ESC byte has no glyph, so only the parameters survived
|
|
67
|
+
and read as `[0[01;33m`. Only `message` text is stripped; **diff bodies and
|
|
68
|
+
paths stay byte-faithful**.
|
|
43
69
|
|
|
44
70
|
### The diff viewer
|
|
45
71
|
|
|
@@ -51,6 +77,10 @@ the first selection expands the list to its full length.
|
|
|
51
77
|
panel (the workbench keeps its width) and the diff takes the rest, 1:1 with the
|
|
52
78
|
pointer because the panel anchors its left edge on grab. Double-clicking the
|
|
53
79
|
edge resets the width, and the panel always stays inside the viewport.
|
|
80
|
+
- **A stable box while the diff is open**: selecting a file pins the panel's height
|
|
81
|
+
(both columns run to the bottom), so the diff arriving, switching files and
|
|
82
|
+
collapsing again only scroll inside the panes — the panel never resizes under
|
|
83
|
+
the pointer.
|
|
54
84
|
- **Staged / unstaged**: by default the pane follows the data — unstaged when
|
|
55
85
|
that side has anything, staged otherwise — with two chips to switch by hand
|
|
56
86
|
(an empty side is dimmed). When a file has changes on both sides, one click
|
|
@@ -202,11 +232,16 @@ shell metacharacters, and leading dashes are all recorded verbatim.
|
|
|
202
232
|
| `commit` | `{ cwd, message }` | `{ message }`; `missing-author` error when `user.name/email` unset |
|
|
203
233
|
| `push` | `{ cwd }` | `{ message }` (120s timeout) |
|
|
204
234
|
| `log` | `{ cwd, count? }` | `{ repo, commits: [{sha, author, subject, refs}] }` (clamped 1..50) |
|
|
205
|
-
| `generateMessage` | `{ cwd, mode?, provider?, model? }` | `{ message, mode, provider, model }`. `mode` is `staged` (default) / `unstaged` / `all`; anything else is `invalid-mode`. Failure code in `error.details.code`: `no-changes`, `no-provider`, `no-model`, `llm-empty`, `cancelled`, `llm-failed`. |
|
|
235
|
+
| `generateMessage` | `{ cwd, mode?, provider?, model? }` | `{ message, mode, provider, model }`. `mode` is `staged` (default) / `unstaged` / `all`; anything else is `invalid-mode`. Failure code in `error.details.code`: `no-changes`, `no-provider`, `no-model`, `llm-truncated` (the output cap ran out before any text was written), `llm-empty`, `cancelled`, `llm-failed`. |
|
|
206
236
|
|
|
207
237
|
> A failed result carries `error.code === "internal"` on the wire (the Connection
|
|
208
238
|
> envelope only requires a string), with the plugin's own diagnostic in
|
|
209
239
|
> `error.details.code`; the client localizes from that code.
|
|
240
|
+
>
|
|
241
|
+
> The `message` of `fetch`/`pull`/`push`/`stage`/`commit` is **git's own output**
|
|
242
|
+
> (ANSI colour codes stripped): an empty string when git said nothing. The panel
|
|
243
|
+
> notifies with an `output.<action>` phrase and keeps that text behind its
|
|
244
|
+
> expandable "Details".
|
|
210
245
|
|
|
211
246
|
## Design decisions & boundaries
|
|
212
247
|
|
|
@@ -219,6 +254,10 @@ shell metacharacters, and leading dashes are all recorded verbatim.
|
|
|
219
254
|
configured** — possibly a third-party gateway. It only happens when you click
|
|
220
255
|
"✨ AI draft"; the plugin itself never calls the network. The diff is
|
|
221
256
|
truncated to 12000 characters, and nothing outside the repository is sent.
|
|
257
|
+
The output cap is 8192 tokens: a reasoning model shares that completion budget
|
|
258
|
+
between its thinking and the message, so a cap sized for the message alone
|
|
259
|
+
produces "hit the cap before writing anything" — reported as `llm-truncated`
|
|
260
|
+
rather than a vague `llm-empty`.
|
|
222
261
|
- **push/pull credentials** come from the system (Git Credential Manager /
|
|
223
262
|
SSH agent); the plugin never touches credential storage. AI drafting never
|
|
224
263
|
touches credentials either — the model adapter resolves its own API key.
|
|
@@ -282,3 +321,7 @@ shell metacharacters, and leading dashes are all recorded verbatim.
|
|
|
282
321
|
- The last two need piped child-process stdio, so they are deliberately **not**
|
|
283
322
|
part of `npm test` — run them from an ordinary terminal.
|
|
284
323
|
- The git command set is verified end-to-end against the running server.
|
|
324
|
+
|
|
325
|
+
## License
|
|
326
|
+
|
|
327
|
+
MIT — see [LICENSE](LICENSE).
|
package/README.md
CHANGED
|
@@ -13,17 +13,28 @@ DeepSeek Harness Web GUI 的完整 Git 管理插件,形态为一个**可折叠
|
|
|
13
13
|
## 界面
|
|
14
14
|
|
|
15
15
|
- **悬浮面板**(`shell.overlay`):折叠时不渲染任何元素(不会遮挡输入框);
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
"仍要切换"
|
|
19
|
-
|
|
20
|
-
Ctrl/Cmd+Enter
|
|
21
|
-
|
|
16
|
+
展开后自上而下是一条工作流:状态行(未提交计数、领先/落后、上游)→
|
|
17
|
+
带 **脏树预检** 的分支切换器(有未提交修改时选择分支,会先显示受影响文件列表
|
|
18
|
+
警告而不是直接切换,并提供"仍要切换"按钮)→ **网络工具条**(拉取更新 / 拉取合并 /
|
|
19
|
+
推送,三等宽,"推送"是主按钮)→ **提交卡片**("暂存全部" + AI 生成依据 +
|
|
20
|
+
"✨ AI 生成"三等宽,下面是提交信息输入框(多行文本框,回车换行、Ctrl/Cmd+Enter
|
|
21
|
+
提交)与提交按钮)→ 两张列表卡片。按钮一律**等宽分栏**,不再是一排宽窄不一的按钮。
|
|
22
|
+
**操作反馈固定钉在面板最上边,而且只有一行**——"推送中…"和上次操作的结果都在
|
|
23
|
+
body 的第一行;结果是一个中文短句("已推送"/"已暂存全部"/"已切换到 xxx"),git 自己的输出
|
|
24
|
+
(push 的 sideband banner、`LF will be replaced by CRLF` 这类提示)收在右侧的"详情 ▾"里,点开才展开,
|
|
25
|
+
不会被变更列表和最近提交顶到看不见的地方。面板**可通过顶栏拖动**(按住带 Git 标题的
|
|
22
26
|
那一行,拖到哪里就停在哪里,不会拖出视口;顶栏上的按钮/输入框不会触发
|
|
23
27
|
拖动;双击顶栏回到居中位置)。
|
|
24
28
|
分支切换器旁边的"+ 新建分支"按钮会展开一个内联表单:新分支名 + 基分支
|
|
25
29
|
选择器(本地分支或 `origin/feature/x` 这样的完整远端引用)——确认后从
|
|
26
30
|
该基分支创建新分支并切换过去。
|
|
31
|
+
- **变更 / 最近提交两张卡片**:变更列表每行是「等宽路径 + 状态色标签」(路径在左,
|
|
32
|
+
所以一列路径对得齐;修改=橙、新增·未跟踪=绿、删除·冲突=红、重命名=蓝,
|
|
33
|
+
当前正在看的那一行整行高亮);最近提交每行是「短 sha + 主题」。两张卡片的标题行
|
|
34
|
+
(`▾ 变更 12`)点一下整段收起/展开,**默认展开**——面板不该把用户自己的改动藏起来;
|
|
35
|
+
列表超过 8 / 5 行时底部出现「显示全部 N 项」,与折叠是两件事,所以箭头永远指对方向。
|
|
36
|
+
- **刷新不闪**:点 ↻ 或任何操作之后的重读都**保留面板内容**(同一个工作区不会退回
|
|
37
|
+
一行 "读取中…" 再弹回来),只在标题栏把刷新按钮置灰并写着"刷新中…"。
|
|
27
38
|
- **点击变更看差异**:点变更列表里的任意一行,面板会从 400px 的单栏展开成
|
|
28
39
|
两栏——左边照旧是完整工作台,右边是该文件的 unified diff(见下文
|
|
29
40
|
「差异查看」)。再点同一行、或点差异标题栏的 `×`,就收回单栏。
|
|
@@ -31,6 +42,10 @@ DeepSeek Harness Web GUI 的完整 Git 管理插件,形态为一个**可折叠
|
|
|
31
42
|
状态胶囊(分支摘要,或"当前工作区不是 Git 仓库");点击它展开/收起悬浮面板。
|
|
32
43
|
- 两处界面共享同一个 store,状态永远一致,并都会随当前会话(及其 cwd)
|
|
33
44
|
切换而重新绑定。切换工作区会清空已选中的文件——绝不让面板显示别的仓库的内容。
|
|
45
|
+
- **git 的文字输出会剥掉 ANSI 颜色码**:远端会给自己的 banner 上色(gitee 的
|
|
46
|
+
`Powered by GITEE.COM` 就是),面板是 DOM 不是终端,ESC 没有字形可渲染,
|
|
47
|
+
不剥就只剩 `[0[01;33m` 这类参数当正文显示。只剥"消息"文本(`message`),
|
|
48
|
+
**diff 内容与文件名一律逐字节保真**。
|
|
34
49
|
|
|
35
50
|
### 差异查看
|
|
36
51
|
|
|
@@ -40,6 +55,8 @@ DeepSeek Harness Web GUI 的完整 Git 管理插件,形态为一个**可折叠
|
|
|
40
55
|
- **可拖拽调宽**:拖动**面板最右侧那条边**即改差异栏宽度——左栏(工作台)宽度不变,
|
|
41
56
|
面板整体变宽、差异栏跟着长;双击这条边复位。面板始终留在视口内,窗口变窄时
|
|
42
57
|
会自动收回;拖动时面板会就地锚定左边缘,所以指针与这条边是 1:1 跟手的。
|
|
58
|
+
- **打开差异时尺寸是稳定的**:一选中文件,面板就定好了高度(两栏都铺到面板底部),
|
|
59
|
+
diff 读回来、切文件、来回点收起都只在栏内滚动,面板本身不会跟着内容跳一下。
|
|
43
60
|
- **未暂存 / 已暂存**:默认自动跟随数据——未暂存有内容就显示未暂存,否则显示
|
|
44
61
|
已暂存;顶部两个 chip 可手动切换,空的一侧置灰。同一个文件两边都有改动时,
|
|
45
62
|
一次点击看到的是最关心的那一侧,另一侧一键可达。
|
|
@@ -163,10 +180,13 @@ dsh plugin --profile web remove @xia-sc/dsh-git
|
|
|
163
180
|
| `commit` | `{ cwd, message }` | `{ message }`;未配置 `user.name/email` 时报 `missing-author` 错误 |
|
|
164
181
|
| `push` | `{ cwd }` | `{ message }`(120s 超时) |
|
|
165
182
|
| `log` | `{ cwd, count? }` | `{ repo, commits: [{sha, author, subject, refs}] }`(钳制 1..50) |
|
|
166
|
-
| `generateMessage` | `{ cwd, mode?, provider?, model? }` | `{ message, mode, provider, model }`。`mode` 为 `staged`(默认)/`unstaged`/`all`,非法值报 `invalid-mode`;失败码见 `error.details.code`:`no-changes`、`no-provider`、`no-model`、`llm-empty`、`cancelled`、`llm-failed`。 |
|
|
183
|
+
| `generateMessage` | `{ cwd, mode?, provider?, model? }` | `{ message, mode, provider, model }`。`mode` 为 `staged`(默认)/`unstaged`/`all`,非法值报 `invalid-mode`;失败码见 `error.details.code`:`no-changes`、`no-provider`、`no-model`、`llm-truncated`(输出上限用尽、一个字都没写出来)、`llm-empty`、`cancelled`、`llm-failed`。 |
|
|
167
184
|
|
|
168
185
|
> 失败结果的 `error.code` 在线路上固定为 `"internal"`(Connection 信封只要求它是字符串),
|
|
169
186
|
> 插件自己的诊断码放在 `error.details.code`;客户端按该码做本地化文案。
|
|
187
|
+
>
|
|
188
|
+
> `fetch`/`pull`/`push`/`stage`/`commit` 的 `message` 就是 **git 自己的输出**(已剥掉 ANSI 颜色码):
|
|
189
|
+
> git 什么都没说时是空串,界面用 `output.<action>` 的中文短句做通知、把这段原文放进可展开的"详情"。
|
|
170
190
|
|
|
171
191
|
## 设计决策与边界
|
|
172
192
|
|
|
@@ -176,7 +196,9 @@ dsh plugin --profile web remove @xia-sc/dsh-git
|
|
|
176
196
|
"暂存全部"按钮(`git add --all`),而不是让提交隐式暂存。
|
|
177
197
|
- **AI 生成会把改动的 diff 发给你配置的模型提供方**——可能是第三方网关。
|
|
178
198
|
这是显式点击"✨ AI 生成"才会发生的联网行为;插件本身不联网。diff 截断到
|
|
179
|
-
12000
|
|
199
|
+
12000 字符后发送,且不发送任何仓库外的内容。输出上限 8192 token:思考型
|
|
200
|
+
模型的 reasoning 与正文共用同一份 completion 预算,上限太小会"一个字都没
|
|
201
|
+
写就超限",此时报 `llm-truncated` 而不是含糊的 `llm-empty`。
|
|
180
202
|
- **push/pull 凭据**来自系统(Git Credential Manager / SSH agent);插件
|
|
181
203
|
绝不碰凭据存储。AI 生成同样不接触凭据——API key 由模型适配器自己解析。
|
|
182
204
|
- **插件绝不修改 git config**;缺 author 时给出明确错误而不是悄悄补写。
|
|
@@ -223,3 +245,7 @@ dsh plugin --profile web remove @xia-sc/dsh-git
|
|
|
223
245
|
- 后两个都必须 spawn git 的管道 stdio,故**不在 `npm test` 内**——请在没有
|
|
224
246
|
该限制的环境(普通终端)单独运行。
|
|
225
247
|
git 命令集对照运行中的服务端做端到端验证。
|
|
248
|
+
|
|
249
|
+
## 许可
|
|
250
|
+
|
|
251
|
+
MIT,见 [LICENSE](LICENSE)。
|