dsh-gitbash-shell 0.29.0 → 0.29.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 +25 -0
- package/README.md +5 -3
- package/dsh.plugin.json +1 -1
- package/package.json +1 -1
- package/src/terminal-shell.js +61 -8
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,31 @@
|
|
|
3
3
|
> 倒序排列,新版本条目在最上面。条目格式:`## vX.Y.Z — YYYY-MM-DD` + 类型(feat / fix / docs / chore)+ 要点 + 相关链接。
|
|
4
4
|
> 纪律见 AGENTS.md「变更记录纪律」:发版前先更新本文件并随版本提交;事故复盘、复现与真机验证记录也记在这里。
|
|
5
5
|
|
|
6
|
+
## v0.29.1 — 2026-09-26
|
|
7
|
+
|
|
8
|
+
**类型**:fix(用户实测:官方「新建终端」下拉里出现**两条 `bash`** —— 一条是 v0.29.0 写入的 Git Bash,另一条是官方 `shellCandidates` 解析到的 WSL,用户分不清)
|
|
9
|
+
|
|
10
|
+
> 用户原话:**"改一下,新增的gitbash显示名称得是gitbash,不然回合wsl的混了,你反正自动检查说gitbash的给改名为gitbash,别叫bash"**
|
|
11
|
+
> (现象:v0.29.0 写 `name: 'bash'`;官方 `shellCandidates` 那条 `bash` 在 PATH 命中 `C:\Windows\System32\bash.exe` 的机器上解析到 WSL)
|
|
12
|
+
|
|
13
|
+
- **显示名改为 `Git Bash`**(`TERMINAL_SHELL_NAME`):`name` 只是 `TerminalShell.name` 这个**用户可见 profile 名**,解析与执行看 `path`/`args`
|
|
14
|
+
⇒ 改它**不改变任何行为**,只让菜单里两项可区分;`args: ['-i']` 保留(官方 `profile()` 对 bash 的默认)。
|
|
15
|
+
- **只迁移我们自己写的旧默认名**:`name` 恰为 `'bash'`(v0.29.0 的默认值)⇒ 新增 `rename` 动作,**只改 `name`**
|
|
16
|
+
(path/args 原样保留),同样**写回后读回校验**(路径与名字都对才成功),不符 ⇒ `write-failed` + fail-loud;
|
|
17
|
+
迁移后**再跑一次仍 `unchanged`**(幂等,patch md5 不变)。
|
|
18
|
+
- **用户自起的名字绝不动(验收收窄,Lead 裁决)**:path 是我们的 Git Bash 但 `name` 是别的(`My Bash`/`Git`/空)
|
|
19
|
+
⇒ 新状态 **`kept-user-name`,零写入**——用户显式起的名就是用户选择,而且自定义名本来也不会与 WSL 候选混淆。
|
|
20
|
+
- **异值仍绝不覆盖**:path 指向别处(例如 WSL)⇒ 维持 `kept-user-choice`,只记日志。**`shellCandidates` 不动**
|
|
21
|
+
(与用户确认过的口径:改名即可区分;那条 WSL 候选仍会出现在菜单里,被区分开的是名字)。
|
|
22
|
+
- 文案:README 的写入形状示例与 AGENTS §4i 同步为 `name: 'Git Bash'`;21 语言卡片文案无需改动(未提名字)。
|
|
23
|
+
- **验证**:`npm test` **102/102**(新增「历史 `bash` 标签迁移 + 迁移后幂等 + 名字没落盘 ⇒ `write-failed [name mismatch]`」
|
|
24
|
+
与「用户自起名字 ⇒ `kept-user-name`、零写入、patch 不变(含 `My Bash`/`Git`/空名三态)」,
|
|
25
|
+
并把既有断言从 `name: 'bash'` 更新为 `name: 'Git Bash'`);`align-official` 四变体仍逐字节对齐。
|
|
26
|
+
真机(隔离 DSH_HOME + 副本强制 win32 门 + 伪装已解析 Git Bash):新建写入 ⇒ `--dump-config` 读出
|
|
27
|
+
`terminal-controller.config.shell.name = Git Bash`;预置历史 `name: bash` 的 patch ⇒ 日志 `renamed to "Git Bash"` 且
|
|
28
|
+
**只改这一行 name**、用户手写行与注释原样保留;二次启动 ⇒ patch **md5 未变**。
|
|
29
|
+
- **未在 Windows 验证**:菜单里实际显示成 `Git Bash`(需用户复验;本次只验证到配置层的 `name` 与迁移行为)。
|
|
30
|
+
|
|
6
31
|
## v0.29.0 — 2026-09-26
|
|
7
32
|
|
|
8
33
|
**类型**:feat(用户实测需求 —— DSH 原生「新建终端」落到 **WSL**,插件只接管了 agent 的 shell 工具,没有接管官方侧栏终端)
|
package/README.md
CHANGED
|
@@ -154,9 +154,11 @@ DSH 自己的「新建终端」**不经过**本插件的执行器:它由官方
|
|
|
154
154
|
新终端跑起来就是 Ubuntu。本插件现在会自动把它切过来:
|
|
155
155
|
|
|
156
156
|
- 仅 **Windows**、且已解析出**通过验证**的 Git Bash 时;设置开关 **「自动接管侧栏终端」默认开启**(`autoTerminalShell`)。
|
|
157
|
-
- 只在官方那一行**没有自己的 shell** 时写入 `{ path: <Git Bash>, name:
|
|
158
|
-
(`-i` 就是官方对 bash
|
|
159
|
-
|
|
157
|
+
- 只在官方那一行**没有自己的 shell** 时写入 `{ path: <Git Bash>, name: 'Git Bash', args: ['-i'] }`
|
|
158
|
+
(`-i` 就是官方对 bash 的默认参数;**显示名固定为 `Git Bash`**,这样菜单里不会与那条解析到 WSL 的候选 `bash` 混淆)。
|
|
159
|
+
已经由 v0.29.0 写入过、名字还是 `bash` 的历史配置会在启动时**只改名字**(path/args 原样保留,幂等);
|
|
160
|
+
**只迁移我们自己写的那个旧默认名 `bash`** —— 你自己起的名字(例如 `My Bash`)一律不动(它本来也不会与 WSL 候选混淆)。
|
|
161
|
+
**你已经手动指定过别的 shell(例如某个 WSL 配置)⇒ 绝不覆盖**,只在宿主日志里提示,并告诉你如何交还给 Git Bash(清空该字段)。
|
|
160
162
|
- 写入走**官方配置编辑器**(设置 UI 用的同一个 API),落到 profile 的 patch 层;**新终端立即生效**,已打开的终端保持原样。
|
|
161
163
|
- **不需要重启**,也不会写坏「新建终端」:只写我们验证过存在的 Git Bash(官方对无法解析的路径没有回退,会直接启动失败)。
|
|
162
164
|
- 失败时 **fail-loud**:日志写清原因,并通过**读回校验**确认值真的落进去了(不出现"假成功")。
|
package/dsh.plugin.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"id": "dsh-external/dsh-gitbash-shell",
|
|
3
|
-
"version": "0.29.
|
|
3
|
+
"version": "0.29.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.
|
|
3
|
+
"version": "0.29.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": {
|
package/src/terminal-shell.js
CHANGED
|
@@ -47,8 +47,18 @@ import { normalizeBashPath } from './bash-path.js'
|
|
|
47
47
|
/** The Loader row id of the official terminal controller. */
|
|
48
48
|
export const TERMINAL_ROW_ID = 'terminal-controller'
|
|
49
49
|
|
|
50
|
-
/**
|
|
51
|
-
|
|
50
|
+
/**
|
|
51
|
+
* User-visible profile NAME written for Git Bash (v0.29.1).
|
|
52
|
+
*
|
|
53
|
+
* NOT `'bash'`: the official `shellCandidates` still contribute a `bash`
|
|
54
|
+
* candidate that resolves to the WSL launcher on machines whose PATH has
|
|
55
|
+
* `C:\Windows\System32\bash.exe`, and the new-terminal menu then showed TWO
|
|
56
|
+
* entries called `bash` — the user could not tell Git Bash from WSL ("改一下,
|
|
57
|
+
* 新增的gitbash显示名称得是gitbash,不然回合wsl的混了"). This is the
|
|
58
|
+
* `TerminalShell.name` display field only: resolution and execution use
|
|
59
|
+
* `path`/`args`, so renaming changes nothing but the label.
|
|
60
|
+
*/
|
|
61
|
+
export const TERMINAL_SHELL_NAME = 'Git Bash'
|
|
52
62
|
|
|
53
63
|
/**
|
|
54
64
|
* Arguments written for Git Bash. `['-i']` is not our invention: the official
|
|
@@ -58,6 +68,15 @@ export const TERMINAL_SHELL_NAME = 'bash'
|
|
|
58
68
|
*/
|
|
59
69
|
export const TERMINAL_SHELL_ARGS = ['-i']
|
|
60
70
|
|
|
71
|
+
/**
|
|
72
|
+
* The ONLY historical name we may rewrite (v0.29.1). v0.29.0 wrote `'bash'`,
|
|
73
|
+
* which is indistinguishable from the WSL candidate in the new-terminal menu —
|
|
74
|
+
* that entry is ours and we fix it. Any OTHER name (`My Bash`, `Git`, a hand
|
|
75
|
+
* edit) is a user decision and is left completely alone, exactly like a shell
|
|
76
|
+
* path pointing elsewhere: this plugin never rewrites what the user chose.
|
|
77
|
+
*/
|
|
78
|
+
export const LEGACY_TERMINAL_SHELL_NAME = 'bash'
|
|
79
|
+
|
|
61
80
|
/**
|
|
62
81
|
* The shell profile we write into `terminal-controller`'s config.
|
|
63
82
|
* @param path - verified Git Bash path.
|
|
@@ -111,7 +130,28 @@ export function planTerminalAdopt({ platform, enabled, resolved, current }) {
|
|
|
111
130
|
return { action: 'adopt', shell: terminalShellProfile(resolved.trim()), reason: 'the terminal has no shell configured; offering the verified Git Bash' }
|
|
112
131
|
}
|
|
113
132
|
if (normalizeBashPath(current.path) === normalizeBashPath(resolved)) {
|
|
114
|
-
|
|
133
|
+
if (current.name === TERMINAL_SHELL_NAME) {
|
|
134
|
+
return { action: 'unchanged', current, reason: 'the terminal already uses this Git Bash under the right name' }
|
|
135
|
+
}
|
|
136
|
+
// Only OUR OWN legacy default is migrated: v0.29.0 wrote `name: 'bash'`,
|
|
137
|
+
// and that is the entry the user cannot tell apart from the WSL candidate.
|
|
138
|
+
// Every other name is a user decision (or a hand edit) — left untouched.
|
|
139
|
+
if (current.name === LEGACY_TERMINAL_SHELL_NAME) {
|
|
140
|
+
return {
|
|
141
|
+
action: 'rename',
|
|
142
|
+
current,
|
|
143
|
+
shell: { ...current, name: TERMINAL_SHELL_NAME },
|
|
144
|
+
reason: 'the terminal runs this Git Bash under our own legacy label "'
|
|
145
|
+
+ LEGACY_TERMINAL_SHELL_NAME + '" — renaming it to "' + TERMINAL_SHELL_NAME
|
|
146
|
+
+ '" so it cannot be confused with the WSL candidate',
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
return {
|
|
150
|
+
action: 'kept-user-name',
|
|
151
|
+
current,
|
|
152
|
+
reason: 'the terminal runs this Git Bash but you named it "' + current.name
|
|
153
|
+
+ '" — a chosen name is never rewritten (and a custom name cannot be confused with the WSL candidate)',
|
|
154
|
+
}
|
|
115
155
|
}
|
|
116
156
|
return {
|
|
117
157
|
action: 'kept-user-choice',
|
|
@@ -143,9 +183,13 @@ export async function adoptTerminalShell(editor, { platform, enabled, resolved }
|
|
|
143
183
|
}
|
|
144
184
|
const current = currentTerminalShell(row)
|
|
145
185
|
const plan = planTerminalAdopt({ platform, enabled, resolved, current })
|
|
146
|
-
if (plan.action !== 'adopt') {
|
|
186
|
+
if (plan.action !== 'adopt' && plan.action !== 'rename') {
|
|
147
187
|
return { status: plan.action, current, detail: plan.reason }
|
|
148
188
|
}
|
|
189
|
+
// `rename` keeps the profile the user already has and only rewrites the
|
|
190
|
+
// label; `adopt` writes the full profile. Both go through the same
|
|
191
|
+
// read-back verification below.
|
|
192
|
+
const renamed = plan.action === 'rename'
|
|
149
193
|
if (typeof editor.edit !== 'function') {
|
|
150
194
|
return { status: 'write-failed', current, detail: 'the config editor exposes no edit()' }
|
|
151
195
|
}
|
|
@@ -163,14 +207,18 @@ export async function adoptTerminalShell(editor, { platform, enabled, resolved }
|
|
|
163
207
|
return { status: 'write-failed', current, detail: 'the write succeeded but reading it back failed: ' + (error && error.message ? error.message : String(error)) }
|
|
164
208
|
}
|
|
165
209
|
const written = currentTerminalShell(after)
|
|
166
|
-
|
|
210
|
+
const pathOk = written !== undefined && normalizeBashPath(written.path) === normalizeBashPath(plan.shell.path)
|
|
211
|
+
const nameOk = written !== undefined && written.name === plan.shell.name
|
|
212
|
+
if (!pathOk || !nameOk) {
|
|
167
213
|
return {
|
|
168
214
|
status: 'write-failed',
|
|
169
215
|
current,
|
|
170
|
-
detail: 'the write did not stick: the terminal row reads '
|
|
216
|
+
detail: 'the write did not stick: the terminal row reads '
|
|
217
|
+
+ (written === undefined ? '(no shell)' : '"' + written.path + '" as "' + written.name + '"')
|
|
218
|
+
+ (pathOk ? '' : ' [path mismatch]') + (nameOk ? '' : ' [name mismatch]'),
|
|
171
219
|
}
|
|
172
220
|
}
|
|
173
|
-
return { status: 'adopted', path: plan.shell.path, current }
|
|
221
|
+
return { status: renamed ? 'renamed' : 'adopted', path: plan.shell.path, current, name: plan.shell.name }
|
|
174
222
|
}
|
|
175
223
|
|
|
176
224
|
/**
|
|
@@ -182,11 +230,16 @@ export async function adoptTerminalShell(editor, { platform, enabled, resolved }
|
|
|
182
230
|
export function terminalAdoptReport(result) {
|
|
183
231
|
switch (result.status) {
|
|
184
232
|
case 'adopted':
|
|
185
|
-
return 'official sidebar terminal switched to Git Bash: ' + result.path + ' (name
|
|
233
|
+
return 'official sidebar terminal switched to Git Bash: ' + result.path + ' (name "' + TERMINAL_SHELL_NAME + '", args -i) — new terminals use it immediately, already-open ones keep their shell'
|
|
234
|
+
case 'renamed':
|
|
235
|
+
return 'official sidebar terminal renamed to "' + TERMINAL_SHELL_NAME + '" (was displaying as "' + (result.current ? result.current.name : '?')
|
|
236
|
+
+ '", same Git Bash path ' + result.path + ') — the entry is no longer confusable with the WSL candidate'
|
|
186
237
|
case 'unchanged':
|
|
187
238
|
return 'official sidebar terminal already uses this Git Bash: ' + (result.current ? result.current.path : '') + ' (nothing written)'
|
|
188
239
|
case 'kept-user-choice':
|
|
189
240
|
return 'official sidebar terminal NOT adopted: ' + result.detail
|
|
241
|
+
case 'kept-user-name':
|
|
242
|
+
return 'official sidebar terminal NOT renamed: ' + result.detail
|
|
190
243
|
case 'write-failed':
|
|
191
244
|
return 'official sidebar terminal adoption FAILED — ' + result.detail
|
|
192
245
|
+ ' | next steps: (1) the new-terminal shell is UNCHANGED, so dsh keeps its own resolution;'
|