dsh-gitbash-shell 0.38.0 → 0.38.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 CHANGED
@@ -3,6 +3,24 @@
3
3
  > 倒序排列,新版本条目在最上面。条目格式:`## vX.Y.Z — YYYY-MM-DD` + 类型(feat / fix / docs / chore)+ 要点 + 相关链接。
4
4
  > 纪律见 AGENTS.md「变更记录纪律」:发版前先更新本文件并随版本提交;事故复盘、复现与真机验证记录也记在这里。
5
5
 
6
+ ## v0.38.2 — 2026-10-13
7
+
8
+ **类型**:fix(v0.38.0 折叠分区在真机上完全失效;用户截图定位)。
9
+
10
+ - **`fold()` helper 签名与调用点不匹配(实锤 bug)**:七个调用点是 `fold("sec.xxx", 行, 行, ...)`,实现却按 `(key, titleKey, ...行)` 解析——**每个分区的第一行内容被吞进标题参数**,`t(<React元素>)` 得到空标题,卡片退化成一列无标题的平铺开关(v0.38.0 的折叠在真机从未生效)。修复:实现改为 `(titleKey, ...行)`,折叠状态键直接用词典键,调用点零改动。
11
+ - 官方用法核对(SystemPromptRow/PresentRow):`DisclosureRow` 的 props 形状(icon/title/open/expandable/expandOnRowClick/onToggle/children)与本插件用法一致,问题只在签名错乱。
12
+ - **冒烟**:118 项全绿;断言改锁 `folds[titleKey]`。
13
+
14
+ ## v0.38.1 — 2026-10-13
15
+
16
+ **类型**:fix(bash 补位在桌面版宿主解析不到官方包;真机反复确认的最后一个开放问题)。
17
+
18
+ - **根因(无日志下的代码级定位,待真机确认)**:bash 激活的解析通道用的是裸 `createRequire(ctx.baseUrl).resolve('@deepseek-ai/dsh-tool-bash')`——**桌面版宿主把官方包打进 `app.asar`,从插件的 profile 布局裸解析必然失败**(返回空 → 日志 "not resolvable" → bash 永缺)。这也解释了为何同一进程里 deny/pwsh7/gb_* 全部正常(插件自带代码,不依赖该解析)而唯独 bash 缺。
19
+ - **修复:解析通道改为宿主 loader 优先**——`ctx.loader.internal.import(name, ctx.baseUrl, {})`,与宿主挂载行包**完全相同的调用**(`vendor/loader/src/config/tree.ts:122`),走宿主自己的 resolve 钩子(可达 asar 内部);失败才退回裸 createRequire(旧通道,非桌面布局保底)。两通道都失败才如实记日志。
20
+ - `resolveToolBashEntry` 返回形状从 href 字符串改为 `{ load }` 惰性加载器;`activateOfficialBash` 接收 loader 对象;调用点与缓存变量同步更名。
21
+ - **冒烟**:118 项全绿;新增「bash resolution tries the HOST loader before a plain require」(断言通道顺序、官方包名、baseUrl 透传、惰性加载)。
22
+ - **待真机复验**:升级重启后官方模式新建会话,工具面应出现 `bash`;日志应出现 `official bash tool activated for this agent`。
23
+
6
24
  ## v0.38.0 — 2026-10-13
7
25
 
8
26
  **类型**:feat(设置卡折叠分区;用户反馈「开关堆一列不知道主题」)。
package/dsh.plugin.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "id": "dsh-external/dsh-gitbash-shell",
3
- "version": "0.38.0",
3
+ "version": "0.38.2",
4
4
  "main": "./src/index.js",
5
5
  "description": "Windows 全模式 Git Bash:用 Git for Windows bash 替换 PowerShell 执行器;官方四个模式经行内工具补位直接获得 Git Bash(v0.35.0,默认),四个 *·Git Bash 变体 preset 可开关;附带 gitbash_pwsh(系统 PowerShell 7)与 gb_* FastCtx 文件工具,检测到 dsh-ops 自动让位。联动:dsh-ptc-cordis-preset(PTC 创造模式带 Git Bash 行且可去重)+ dsh-better-sidebar(终端标签自动切 Git Bash)。",
6
6
  "engines": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-gitbash-shell",
3
- "version": "0.38.0",
3
+ "version": "0.38.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/client.js CHANGED
@@ -2107,7 +2107,11 @@ window.__ModuleLoader__.load({
2107
2107
  and expands the one theme they recognise. A stripped-down host
2108
2108
  without the export degrades to the static title+stack card. */
2109
2109
  var DisclosureRowComponent = icon("DisclosureRow");
2110
- function fold(key, titleKey) {
2110
+ /* v0.38.2 BUGFIX: the call sites are `fold("sec.xxx", row, row, ...)`
2111
+ — one dictionary key followed by the section's rows. The previous
2112
+ draft parsed (key, titleKey, ...) and ATE the first row into the
2113
+ title slot (t(<element>) → empty header, nothing folded). */
2114
+ function fold(titleKey) {
2111
2115
  var body = [];
2112
2116
  for (var i = 1; i < arguments.length; i++) body.push(arguments[i]);
2113
2117
  if (!DisclosureRowComponent || typeof DisclosureRowComponent !== "function") {
@@ -2120,10 +2124,10 @@ window.__ModuleLoader__.load({
2120
2124
  className: "gb-fold",
2121
2125
  icon: null,
2122
2126
  title: t(titleKey),
2123
- open: folds[key] === true,
2127
+ open: folds[titleKey] === true,
2124
2128
  expandable: true,
2125
2129
  expandOnRowClick: true,
2126
- onToggle: function () { toggleFold(key); },
2130
+ onToggle: function () { toggleFold(titleKey); },
2127
2131
  }, E("div", { className: "gb-stack" }, body));
2128
2132
  }
2129
2133
 
@@ -221,19 +221,40 @@ export function validatePwshArgs(args) {
221
221
  return undefined
222
222
  }
223
223
 
224
+ /** The official bash-tool package the inline patch activates. */
225
+ const TOOL_BASH_PACKAGE = '@deepseek-ai/dsh-tool-bash'
226
+
224
227
  /**
225
- * Resolve the OFFICIAL @deepseek-ai/dsh-tool-bash module entry from the
226
- * host's own resolution base (the same seam probeHostExtras uses). Returns
227
- * the absolute entry URL, or '' when the host does not ship the package.
228
+ * Resolve the OFFICIAL @deepseek-ai/dsh-tool-bash module. TWO channels, in
229
+ * order (v0.38.1, the desktop-host field report):
230
+ *
231
+ * ① THE HOST'S OWN LOADER — `ctx.loader.internal.import(name, baseUrl, {})`,
232
+ * the exact call the row mount itself uses
233
+ * (vendor/loader/src/config/tree.ts:122). It runs the host's resolve
234
+ * hooks, so it reaches packages inside the desktop app.asar that a bare
235
+ * Node resolver cannot see from the plugin's profile layout.
236
+ * ② A plain createRequire from the host base — the v0.35.0 channel, kept
237
+ * for layouts where the internal loader is absent.
238
+ *
239
+ * @returns {Promise<{ load: async () => object }|undefined>} a lazy loader for
240
+ * the module, or undefined when neither channel resolves it.
228
241
  */
229
242
  export async function resolveToolBashEntry(ctx) {
243
+ try {
244
+ const internal = ctx?.loader?.internal
245
+ if (internal && typeof internal.import === 'function') {
246
+ const mod = await internal.import(TOOL_BASH_PACKAGE, ctx?.baseUrl, {})
247
+ if (mod && typeof mod.apply === 'function') return { load: async () => mod }
248
+ }
249
+ } catch { /* fall through to the plain resolution */ }
230
250
  try {
231
251
  const { createRequire } = await import('node:module')
232
252
  const { pathToFileURL } = await import('node:url')
233
253
  const req = createRequire(ctx?.baseUrl ?? import.meta.url)
234
- return pathToFileURL(req.resolve('@deepseek-ai/dsh-tool-bash')).href
254
+ const href = pathToFileURL(req.resolve(TOOL_BASH_PACKAGE)).href
255
+ return { load: async () => import(href) }
235
256
  } catch {
236
- return ''
257
+ return undefined
237
258
  }
238
259
  }
239
260
 
@@ -245,10 +266,10 @@ export async function resolveToolBashEntry(ctx) {
245
266
  * prescribes for per-agent variants. The official module is loaded ONCE per
246
267
  * process; each agent gets a fresh scope and a fresh apply().
247
268
  */
248
- export async function activateOfficialBash(agent, toolBashHref, createScopeFn, log) {
269
+ export async function activateOfficialBash(agent, resolved, createScopeFn, log) {
249
270
  let mod
250
271
  try {
251
- mod = await import(toolBashHref)
272
+ mod = await resolved.load()
252
273
  } catch (error) {
253
274
  log(`official tool-bash module import failed: ${error?.message ?? error}`)
254
275
  return undefined
@@ -294,7 +315,7 @@ export function mountInlineTools(ctx, deps) {
294
315
  const { tools, agents, createScope, allowed, spawn, pwshPath, echo, log } = deps
295
316
  /** agent -> { timer, scope, denyPwsh, pwshScope }; named `tracked` because `agents` above is the host service */
296
317
  const tracked = new Map()
297
- let toolBashHrefPromise
318
+ let toolBashResolvePromise
298
319
 
299
320
  const faceNames = (agent) => {
300
321
  try {
@@ -383,13 +404,13 @@ export function mountInlineTools(ctx, deps) {
383
404
  }
384
405
  }
385
406
  if (needs.needsBash && !state.scope) {
386
- if (toolBashHrefPromise === undefined) toolBashHrefPromise = resolveToolBashEntry(ctx)
387
- void toolBashHrefPromise.then(async (href) => {
388
- if (href === '') {
389
- log('official @deepseek-ai/dsh-tool-bash is not resolvable from the host base; bash stays absent for this agent')
407
+ if (toolBashResolvePromise === undefined) toolBashResolvePromise = resolveToolBashEntry(ctx)
408
+ void toolBashResolvePromise.then(async (resolved) => {
409
+ if (!resolved) {
410
+ log('official @deepseek-ai/dsh-tool-bash is not resolvable (neither the host loader nor a plain resolution found it); bash stays absent for this agent')
390
411
  return
391
412
  }
392
- const scope = await activateOfficialBash(agent, href, createScope, log)
413
+ const scope = await activateOfficialBash(agent, resolved, createScope, log)
393
414
  if (scope && tracked.get(agent) === state) {
394
415
  state.scope = scope
395
416
  log('official bash tool activated for this agent (Git Bash host; fake pwsh denied)')