dsh-gitbash-shell 0.34.1 → 0.34.2
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 +11 -0
- package/dsh.plugin.json +1 -1
- package/package.json +1 -1
- package/src/compositions.js +10 -2
- package/src/index.js +34 -5
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,17 @@
|
|
|
3
3
|
> 倒序排列,新版本条目在最上面。条目格式:`## vX.Y.Z — YYYY-MM-DD` + 类型(feat / fix / docs / chore)+ 要点 + 相关链接。
|
|
4
4
|
> 纪律见 AGENTS.md「变更记录纪律」:发版前先更新本文件并随版本提交;事故复盘、复现与真机验证记录也记在这里。
|
|
5
5
|
|
|
6
|
+
## v0.34.2 — 2026-10-09
|
|
7
|
+
|
|
8
|
+
**类型**:fix([issue #15](https://github.com/KannaKuron/dsh-gitbash-shell/issues/15):极简模式 · Git Bash 的 PTY 终端无法启动,node-pty `File not found`)
|
|
9
|
+
|
|
10
|
+
- **根因**:`minimalPluginsFor()` 是四个变体里**唯一**给 terminal-bash 行写死 `shellPath: DEFAULT_GIT_BASH`(`C:/Program Files/Git/bin/bash.exe`)的地方——Git 装在自定义路径(Scoop / 便携版 / 其他盘符)的 Windows 机器上,PTY spawn 在进程创建阶段即失败,且本插件撤掉 `pwsh-sandbox` 而 dsh 每进程只允许一个 `ctx.shell`,极简模式 shell 能力完全归零、无备用。其余三个变体(`pluginsFor`)不含 `shellPath`、走 `src/shell.js` → `resolveGitBashCached()` 动态解析,天然正确——与 issue #11 同类残留,这次漏在 PTY 行上。
|
|
11
|
+
- **修法(采纳报告人 @Jingqi05 的「入参传入」变体,`compositions.js` 保持纯数据)**:`minimalPluginsFor({ bashPath })`——win32 下有解析结果用解析结果,否则兜底 `DEFAULT_GIT_BASH`(失败保持可见的 spawn 报错、绝不换成别的 shell,§4h 两条硬边界不变);非 win 恒 `/bin/bash`。
|
|
12
|
+
- **解析来源比报告人裸 `resolveGitBashCached({})` 更完整一层**:`src/index.js` 新增 `minimalPtyBashPath(readBashResolution)`,每次(重)注册时懒读(issue #13 纪律:不在 apply() 期冻结),喂的是**含显式配置层**的 `readConfiguredBashPath` 链(`gitbash-executor` 行 > `gitbash-shell` 行 `bashPath` > 自动链)——与执行器同一条解析链,设置里显式填的路径优先。
|
|
13
|
+
- **测试**:冒烟 +1 用例(win32 平台 stub 三态:解析成功用解析结果 / 失败与空值兜底默认 / 非 win `/bin/bash` + 读取器异常安全 + 接线断言);102 项全绿(基线 101:100 pass + 1 win32-only skip → 101 pass + 同一 skip,纯增量无回归);同步更新 3 处锁源码文本的既有断言(`registerVariant` / `runDeclarativeEra` 调用行、`pluginsFor` 形参)。
|
|
14
|
+
- **真机**:Windows 真机复现与修复 A/B 对照(真实 node-pty:修复前 spawn `File not found: C:/Program Files/Git/bin/bash.exe`,修复后 `D:/git/Git/bin/bash.exe` exit=0)由报告人 @Jingqi05 在 issue 中完成,修复评论已引用;本机(macOS)为逻辑级验证 + 全量测试。
|
|
15
|
+
- **已知边界(已在 issue 评论如实说明)**:极简变体行集是注册时快照,运行中改 `bashPath` 设置需重启 dsh 才进 PTY 行(其余三变体走执行器懒解析、无此限制);热重注册需跟踪 `registeredBashPath` 的 retire/重建模式,超出本次范围。
|
|
16
|
+
|
|
6
17
|
## v0.34.1 — 2026-10-05
|
|
7
18
|
|
|
8
19
|
**类型**:chore(清理 `dsh.client.inject` 里的死引用 `@deepseek-ai/dsh-client-runtime`)
|
package/dsh.plugin.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"id": "dsh-external/dsh-gitbash-shell",
|
|
3
|
-
"version": "0.34.
|
|
3
|
+
"version": "0.34.2",
|
|
4
4
|
"main": "./src/index.js",
|
|
5
5
|
"description": "Windows 全模式 Git Bash:用 Git for Windows bash 替换 PowerShell 执行器,声明式注册 standard/minimal/code/cordis 的 Git Bash 变体 preset(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.34.
|
|
3
|
+
"version": "0.34.2",
|
|
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/compositions.js
CHANGED
|
@@ -225,9 +225,17 @@ export function pluginsFor({ kind, gitBash, skillsDir, pythonActive = false, hos
|
|
|
225
225
|
* The minimal variant: the official single-tool preset with the Git Bash
|
|
226
226
|
* delta — bash rows always on (the terminal row pins the Git Bash binary on
|
|
227
227
|
* Windows), pwsh rows always off (pure).
|
|
228
|
+
* @param {object} [input]
|
|
229
|
+
* @param {string|undefined} [input.bashPath] - the RESOLVED Git for Windows
|
|
230
|
+
* bash (the ONE chain of src/bash-path.js, explicit tier first — the same
|
|
231
|
+
* resolver the executor runs; wired in src/index.js and read lazily at
|
|
232
|
+
* each registration). `undefined` when the chain failed: the row then
|
|
233
|
+
* pins the historical default, so a missing Git stays a VISIBLE spawn
|
|
234
|
+
* failure — never a substitute shell (issue #15: the hardcoded default
|
|
235
|
+
* broke every PTY spawn where Git lives outside `C:/Program Files/Git`).
|
|
228
236
|
* @returns {object[]} the declarative plugins list.
|
|
229
237
|
*/
|
|
230
|
-
export function minimalPluginsFor() {
|
|
238
|
+
export function minimalPluginsFor({ bashPath } = {}) {
|
|
231
239
|
const win = typeof process !== 'undefined' && process.platform === 'win32'
|
|
232
240
|
return [
|
|
233
241
|
{
|
|
@@ -252,7 +260,7 @@ export function minimalPluginsFor() {
|
|
|
252
260
|
disabled: false,
|
|
253
261
|
config: {
|
|
254
262
|
timeoutMs: 300000,
|
|
255
|
-
shellPath: win ? DEFAULT_GIT_BASH : '/bin/bash',
|
|
263
|
+
shellPath: win ? (typeof bashPath === 'string' && bashPath !== '' ? bashPath : DEFAULT_GIT_BASH) : '/bin/bash',
|
|
256
264
|
},
|
|
257
265
|
},
|
|
258
266
|
{
|
package/src/index.js
CHANGED
|
@@ -1674,16 +1674,42 @@ function safeProbe(ok, specifier) {
|
|
|
1674
1674
|
}
|
|
1675
1675
|
}
|
|
1676
1676
|
|
|
1677
|
+
/**
|
|
1678
|
+
* The minimal variant's PTY row (`terminal-bash`) pins the shell binary it
|
|
1679
|
+
* spawns; before issue #15 that was the one hardcoded `DEFAULT_GIT_BASH`
|
|
1680
|
+
* copy left in the tree while every other consumer had moved to the
|
|
1681
|
+
* resolver, so a Git installed outside `C:/Program Files/Git` failed every
|
|
1682
|
+
* PTY spawn with node-pty's "File not found". The row now rides the ONE
|
|
1683
|
+
* resolution chain (explicit config tier first — readConfiguredBashPath,
|
|
1684
|
+
* the same chain the executor runs), read LAZILY per registration
|
|
1685
|
+
* (issue #13: never frozen at apply time). An unresolved chain returns
|
|
1686
|
+
* `undefined` and the composition then pins the historical default: per the
|
|
1687
|
+
* two hard rules a missing Git Bash stays a VISIBLE spawn failure — never a
|
|
1688
|
+
* substitute shell.
|
|
1689
|
+
* @param {() => object} [readResolution] - the lazy resolution reader shared
|
|
1690
|
+
* with the executor and the capability service.
|
|
1691
|
+
* @returns {string|undefined} the resolved Git Bash path, or `undefined`
|
|
1692
|
+
* when unresolved (the composition falls back to the visible default).
|
|
1693
|
+
*/
|
|
1694
|
+
export function minimalPtyBashPath(readResolution) {
|
|
1695
|
+
try {
|
|
1696
|
+
const resolution = readResolution()
|
|
1697
|
+
return resolution && resolution.ok && resolution.path ? resolution.path : undefined
|
|
1698
|
+
} catch {
|
|
1699
|
+
return undefined
|
|
1700
|
+
}
|
|
1701
|
+
}
|
|
1702
|
+
|
|
1677
1703
|
/**
|
|
1678
1704
|
* Register one variant definition; returns the unregister function. Mount
|
|
1679
1705
|
* failures stay visible through the roster's broken diagnostic instead of
|
|
1680
1706
|
* failing the boot.
|
|
1681
1707
|
*/
|
|
1682
|
-
async function registerVariant(ctx, presetId, { gitBashActive, skillsDir, pythonActive, hostExtras = {} }) {
|
|
1708
|
+
async function registerVariant(ctx, presetId, { gitBashActive, skillsDir, pythonActive, hostExtras = {}, readBashResolution }) {
|
|
1683
1709
|
const meta = PRESET_META[presetId]
|
|
1684
1710
|
if (!meta) return undefined
|
|
1685
1711
|
const plugins = meta.kind === 'minimal'
|
|
1686
|
-
? minimalPluginsFor()
|
|
1712
|
+
? minimalPluginsFor({ bashPath: minimalPtyBashPath(readBashResolution) })
|
|
1687
1713
|
: pluginsFor({ kind: meta.kind, gitBash: gitBashActive, skillsDir, pythonActive, hostExtras })
|
|
1688
1714
|
return ctx.agentPresets.register({
|
|
1689
1715
|
id: presetId,
|
|
@@ -1711,9 +1737,12 @@ async function registerVariant(ctx, presetId, { gitBashActive, skillsDir, python
|
|
|
1711
1737
|
* @param {object} ctx - the plugin's mounting context.
|
|
1712
1738
|
* @param {string[]} presetIds - the row's configured variants.
|
|
1713
1739
|
* @param {() => boolean} readSuppress - live dedupe switch reader.
|
|
1740
|
+
* @param {() => object} readBashResolution - lazy Git Bash resolution reader
|
|
1741
|
+
* (the chain shared with the executor and the capability); the minimal
|
|
1742
|
+
* variant's PTY row reads it once per registration (issue #15).
|
|
1714
1743
|
* @returns {Promise<void>} resolves once the first reconcile finished.
|
|
1715
1744
|
*/
|
|
1716
|
-
async function runDeclarativeEra(ctx, presetIds, readSuppress) {
|
|
1745
|
+
async function runDeclarativeEra(ctx, presetIds, readSuppress, readBashResolution) {
|
|
1717
1746
|
cleanupLegacyTrees(presetIds)
|
|
1718
1747
|
const gitBashActive = process.platform === 'win32'
|
|
1719
1748
|
const skillsDir = await resolveSkillsDir()
|
|
@@ -1765,7 +1794,7 @@ async function runDeclarativeEra(ctx, presetIds, readSuppress) {
|
|
|
1765
1794
|
for (const presetId of want) {
|
|
1766
1795
|
if (live.has(presetId)) continue
|
|
1767
1796
|
try {
|
|
1768
|
-
const unregister = await registerVariant(ctx, presetId, { gitBashActive, skillsDir, pythonActive: peerPython, hostExtras })
|
|
1797
|
+
const unregister = await registerVariant(ctx, presetId, { gitBashActive, skillsDir, pythonActive: peerPython, hostExtras, readBashResolution })
|
|
1769
1798
|
if (unregister) {
|
|
1770
1799
|
live.set(presetId, unregister)
|
|
1771
1800
|
console.log(TAG + " preset '" + presetId + "' registered declaratively")
|
|
@@ -2486,7 +2515,7 @@ export async function apply(ctx, config = {}) {
|
|
|
2486
2515
|
// more), so this branch serves the variants and returns.
|
|
2487
2516
|
if (ctx.agentPresets && typeof ctx.agentPresets.register === 'function') {
|
|
2488
2517
|
try {
|
|
2489
|
-
await runDeclarativeEra(ctx, presetIds, () => liveSettings.suppressPeerCordis())
|
|
2518
|
+
await runDeclarativeEra(ctx, presetIds, () => liveSettings.suppressPeerCordis(), readBashResolution)
|
|
2490
2519
|
} catch (error) {
|
|
2491
2520
|
console.log(TAG + ' declarative registration failed: ' + (error && error.message ? error.message : error))
|
|
2492
2521
|
}
|