dsh-gitbash-shell 0.29.2 → 0.30.1

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/CHANGELOG.md CHANGED
@@ -3,6 +3,107 @@
3
3
  > 倒序排列,新版本条目在最上面。条目格式:`## vX.Y.Z — YYYY-MM-DD` + 类型(feat / fix / docs / chore)+ 要点 + 相关链接。
4
4
  > 纪律见 AGENTS.md「变更记录纪律」:发版前先更新本文件并随版本提交;事故复盘、复现与真机验证记录也记在这里。
5
5
 
6
+ ## v0.30.1 — 2026-09-26
7
+
8
+ **类型**:fix(用户实测反馈 v0.30.0 的工具列表:点了按钮看不到进度、看不到在装哪一个、看不到报错、还能连点)
9
+
10
+ > 用户原话:**"我这点击升级了都不知道进度,有没有在升级,也看不到报错,你优化一下,可能看到目前按安装还是更新那个,进度条什么的放在那个列表里。然后不让我连点,开始了就不用再点。"**
11
+
12
+ ### 根因(两个都是真缺陷,不是用法问题)
13
+
14
+ 1. **busy 的生命周期错了**:`runTools()` 在 POST 收到 202 时就 `setToolBusy(false)`,而任务在**宿主侧继续跑**
15
+ —— 于是按钮在批次刚开始时就恢复可点。这正是"能连点"的来源:后端的单任务闸门确实会返回 409,
16
+ 但用户看到的是一个**亮着的按钮**,自然会再点。
17
+ 2. **进度放在了一个没人看的地方**:进度只渲染在按钮下方的一块区域,**不在工具列表行内**;
18
+ 每行也不显示自己的状态,失败原因混在一个游离的结果列表里,既不显眼也不对应行。
19
+
20
+ ### 改动(`src/client.js`)
21
+
22
+ - **busy 从「请求在飞」改为「任务在跑」**:新增派生状态 `jobRunning = toolJob && toolJob.finished !== true`
23
+ 与 `busyNow = toolBusy || jobRunning`;安装 / 刷新 / 全选三个按钮与**所有复选框**在整个批次期间禁用,
24
+ 主按钮文案变为「处理中」。开始之后不必也**不能**再点。
25
+ - **进度搬进列表行**:正在处理的那一行高亮,行内依次显示 spinner + **「安装中…」/「更新中…」**
26
+ (按该行 `state` 判断是装还是升,不靠猜)+ 一条扫动进度条;已完成的行保留 ✓/✗ 判定。
27
+ - **错误就地可见**:失败的行**正下方**用红字打印「安装中 — 失败: <winget 原文>」,不用再去别处找日志。
28
+ - **整体进度**:任务运行时显示 spinner + `当前工具 · 处理中: n / m` + 按完成数计算的进度条(宽度随 done/total 增长)。
29
+ - 移除原先那个游离的结果列表 —— 信息已全部进入对应行。
30
+ - 新增样式:行高亮、运行态徽章、行内扫动条、整体进度条、失败行、spinner,以及 `gb-spin` / `gb-slide` 两条 keyframes。
31
+ - 词典 **21 语言各补 2 键**(`tools.installing` / `tools.updating`),现共 **65 键**,键对齐由冒烟强制。
32
+
33
+ ### 验证
34
+
35
+ - `npm test` **112/112 全绿**(词典键对齐断言覆盖新键)。
36
+ - 静态校验:65 个词典键**全部**被代码引用,零悬空引用。
37
+ - ⚠️ 仍未做:浏览器端真机点击验证(需重启客户端后自测)。
38
+ - 版本号 `0.30.0` → **`0.30.1`**。
39
+
40
+ ### 附:一次误操作与回滚(如实记录)
41
+
42
+ 本次最初**误把第三方插件 `dshmarket` 当成了目标**,对
43
+ `~/.dsh/profiles/desktop/node_modules/dshmarket/client/client.js` 打了一处本地补丁(让自我更新时
44
+ dshmarket 自己出现在「已安装」列表里,以显示行内进度)。用户澄清后**已完整回滚**:
45
+ 与 npm 上的 `dshmarket@1.66.2` 逐字节 `cmp` 一致,零残留。
46
+ (该补丁对应的确实是一个真实缺陷 —— 自我更新按钮 `onClick` 会 `setTab("installed")` 想看进度,
47
+ 但列表又 `filter` 掉了 `selfName` —— 留作后续,未在本仓库处理。)
48
+
49
+ ## v0.30.0 — 2026-09-26
50
+
51
+ **类型**:feat(新能力 —— 设置卡里一键安装/升级一份**固定的终端工具清单**,全部经 winget 官方源)
52
+
53
+ > 用户需求原话:**"所有缺的工具,能不能在插件的设置里增加一个按钮,可以选择自己一次性安装升级到最新,用winget,或者可以自定义选择一部分安装升级"**
54
+ > 追加的硬要求:**"绝对要保证是下载的正确的源,你这些工具id都要查清楚"**
55
+ > 以及**"只要人家已经有了已经安装过了就不需要安装"** / **"有的人的电脑可能安装过llvm 之类的…这种情况下我们不需要帮忙winget安装,要跳过,也不帮忙升级"**。
56
+
57
+ ### 清单(`src/toolchain.js`,22 项,闭合集合)
58
+
59
+ - **基础补全(4)**:`make`(ezwinports.make)、`wget`(JernejSimoncic.Wget)、`yq`(MikeFarah.yq)、`xtree`(Excelano.xtree,现代 tree 替代)。
60
+ - **现代 CLI(13)**:bat、fzf、delta、zoxide、dust、procs、xh、just、shellcheck、hexyl、tldr、jj、gdu。
61
+ - **纳入版本管理(3)**:jq、ripgrep、fd(本机已有,交给插件统一升级)。
62
+ - **需要管理员(2)**:7-Zip、经典 tree —— manifest 写 `Scope: machine`,winget 必须提权,会弹 UAC。
63
+ - 每项自带 `publisher` + 安装器域名(`source`),**卡片上渲染出来**,让来源可核对而不是口头保证。
64
+
65
+ ### 源核实(逐包查证,三重证据)
66
+
67
+ - **源**:全部来自 `winget` 官方源(`cdn.winget.microsoft.com/cache`),本机未添加任何第三方源;`--source winget` 写死在 argv 里,msstore 与第三方源永不参与。
68
+ - **定义**:22 个包的 manifest 全部在 **microsoft/winget-pkgs** 官方仓库,逐个读取核对(发布者字段与真实项目作者一致:sharkdp→David Peter、BurntSushi、Casey Rodarmor、Vidar Holen…)。
69
+ - **完整性**:22/22 均有 `InstallerSha256`,winget 安装时强制校验;18 个安装器指向 `github.com/<官方项目>/releases`,其余指向官方站
70
+ (ezwinports→sourceforge、7-Zip→www.7-zip.org、wget→eternallybored.org —— 后者是 GNU wget 官方认可的 Windows 构建站)。
71
+
72
+ ### 实测发现(全部真机复现,并已固化为冒烟断言)
73
+
74
+ 1. **同一个工具存在多个 winget 包 ID**:本机装的 ripgrep 是 **`BurntSushi.ripgrep.GNU`**,而 MSVC 构建是**另一个包**。只认一个 ID 会导致"再装一份"。
75
+ ⇒ 清单支持 `ids[]` 变体:**识别**用任一变体,**升级**用 `winget export` 报出的**实际那个**,只有全新安装才用首选。
76
+ 2. **已装 ≠ 命令在 PATH**:本机 7-Zip 由 winget 装好,但 MSI 没有把目录加进 PATH,`7z` 命令根本不存在。按"命令是否存在"判断会把它当缺失并重复安装。
77
+ ⇒ 判定**以 winget 自己的库存为准**(`winget export` 的 JSON),命令存在性只用来识别"外部提供"。
78
+ 3. **两个"无事可做"的退出码都是非零,其中一个曾被误判**:实测 `winget upgrade` 对已最新的包返回 `0x8A15002B`("找不到可用的升级"),对未安装的包返回 `0x8A150014`。
79
+ Node 收到的是**完整 HRESULT**(Git Bash 里只显示低位 20)。初版把 `0x8A15002B` 错归为"需要管理员",会让**每台健康的机器在升级轮里误报失败** ——
80
+ 现按**码结构化判定**(辅以 21 语言文案兜底),并把两条断言锁进冒烟。`0x8A150014`(低位 0x14)与 `0x8A15002B`(低位 0x2B)不会互相误伤。
81
+ 4. **"外部提供"必须只读**:本机 `fd` 来自 kimi-code(`~/.kimi-code/bin`)、`tree` 来自 Windows 自带的 `C:\WINDOWS\system32\tree.com` ——
82
+ 两者都判为 `external`:**不安装、不升级、复选框不可勾**,只显示来源。LLVM/WinLibs 提供的工具链同理,永远不会被本插件动到。
83
+ 5. **只读探测也能拿到权威清单**:`winget export -o <file> --include-versions` 输出 **JSON**(`list` 的表格是本地化的、宽 ID 会被截断),
84
+ 是本插件唯一采信的库存来源;传给它的必须是 **Windows 路径**(原生程序不认 MSYS 的 `/tmp/...`)。
85
+
86
+ ### 安全边界
87
+
88
+ - **路由有副作用 ⇒ 有围栏**:`/dsh-gitbash-shell/api/tools` 只接受 **loopback** 调用,且**改动类请求必须带同源 `Origin`/`Referer`**;
89
+ 用户只是访问过的网页因此无法让他的机器装软件(跨站请求在 origin 检查处被拒)。
90
+ - **请求只能命名清单内的条目**:请求体里的 id 先映射到 `src/toolchain.js` 的闭合集合,未知 id 直接丢弃;`install`/`upgrade` 的 argv 一律带
91
+ **`--exact` + `--source winget`**,并且只由服务端拼装(`execFile` + argv 数组,永不拼 shell 字符串)。
92
+ - **无自由文本包 ID 输入框**(用户明确选择"固定清单就好"),所以不存在"用户填错 ID 装错包"的路径。
93
+ - 一次只跑一个 job(并发安装正是"半个清单已应用"的来源);进度经 `?job=1` 轻量轮询,不重复跑三个 winget 命令。
94
+
95
+ ### 验证
96
+
97
+ - `npm test`:**102 → 112 全绿**。新增 10 个用例覆盖:清单结构与来源字段齐备、argv 三重锁定、变体 ID 的安装/升级取向、PATH 扫描(首个命中优先/坏目录不致命)、
98
+ 四态状态机(`missing`/`external`/`managed`/`current`,含"winget 有而命令不在 PATH"、"外部提供即使有命令也不可动")、export JSON 只认 winget 源、
99
+ 两个实测退出码的分类、CSRF 围栏五态、请求 ID 闭合性、`auto` 模式的装/升分流、路由接线守卫。
100
+ - **真机读数**(本机):22 项判定为 `missing 16 / current 4 / external 2`,其中 `rg` 正确识别为 `BurntSushi.ripgrep.GNU 15.2.0`、`7z` 识别为 `7zip.7zip 26.03`(命令不在 PATH 也判对)、
101
+ `fd`/`tree` 如实标为外部提供。
102
+ - ⚠️ **尚未做**:设置卡 UI 的浏览器端真机点击验证(需重启 DSH 或起隔离实例);本次未替用户重启其运行中的实例。
103
+ - 版本号 `0.29.2` → **`0.30.0`**(`package.json` 与 `dsh.plugin.json` 一致)。
104
+ - 顺带修复:本仓库此前**从未跑过 `npm install`**(无 `node_modules`),导致 peer 依赖 `@deepseek-ai/schemastery` 不可解析、`Config` 导出缺失而有一条测试恒失败;
105
+ 已补装 devDependencies 并生成 `package-lock.json`。
106
+
6
107
  ## v0.29.2 — 2026-09-26
7
108
 
8
109
  **类型**:docs(纯文档 patch —— 更正复验判据:原先写成 `uname -r`,实为 `uname -s`;无任何代码/行为变更)
package/dsh.plugin.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "id": "dsh-external/dsh-gitbash-shell",
3
- "version": "0.29.2",
3
+ "version": "0.30.1",
4
4
  "main": "./src/index.js",
5
5
  "description": "Windows 全模式 Git Bash:用 Git for Windows bash 替换 PowerShell 执行器,并物化 standard/minimal/code/cordis 的 Git Bash 变体 preset。双 era 适配 dsh <= 0.1.1(内置 id 'code')与 >= 0.1.2(改名 'ptc'),启动探测自动选择,preset id 永不变。联动:dsh-ptc-cordis-preset(两者同装时 PTC 创造模式自动物化为 Git Bash 版)+ dsh-better-sidebar(终端 UI 标签与模型 terminal_* 工具自动切到 Git Bash)。",
6
6
  "engines": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-gitbash-shell",
3
- "version": "0.29.2",
3
+ "version": "0.30.1",
4
4
  "description": "Windows 上让 agent 的每条 shell 命令改经 Git for Windows bash 执行;物化四个内置预设的 Git Bash 变体,统一 MSYS 盘根路径方言,侧栏终端接管可开关。· Run every agent shell command through Git for Windows bash on Windows; materialize Git Bash variants of the built-in presets, unify the MSYS drive-root path dialect, and adopt the sidebar terminal behind a switch.",
5
5
  "type": "module",
6
6
  "repository": {