dsh-gitbash-shell 0.38.2 → 0.38.4
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 +18 -0
- package/dsh.plugin.json +1 -1
- package/package.json +1 -1
- package/src/client.js +27 -26
- package/src/index.js +8 -1
- package/src/inline-tools.js +28 -9
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.4 — 2026-10-13
|
|
7
|
+
|
|
8
|
+
**类型**:fix(bash 挂载的服务授权 + 折叠分区自绘;两条真机日志驱动)。
|
|
9
|
+
|
|
10
|
+
- **bash 挂载改走 cordis 官方插件通道**(`agent.ctx.plugin(mod)`):官方 tool-bash 模块对象自带 `inject: ['tools','shell','systemPrompt','shellEnv','workingDirectory']` 声明;此前手动 `mod.apply(scope.ctx)` 绕过声明,被 cordis 拒读服务(`cannot get property "shell" without inject`——上一版 fiber 时序修复的后续,ctx 已就绪、死在授权)。`ctx.plugin(mod)` 注册**真正的 fiber**(声明生效、cordis 自己跑 apply、Config 走官方 schema),`await fiber` 等激活完成;卸载 = `fiber.dispose()`,回滚语义由 cordis 保证。
|
|
11
|
+
- **折叠分区改为自绘**(按钮头 + 条件体,零外部组件):官方 `DisclosureRow` 在真机的插件受限 require 形状里拿不到(`icon("DisclosureRow")` 为 null),v0.38.0–0.38.3 的每个分区都在静默退化成「静态标题 + 平铺」——正是用户截图里那个"一条线分割的一列"。自绘后:七个带边框卡片、标题行常驻可点、默认全收起。
|
|
12
|
+
- **冒烟**:118 项全绿;断言改锁自绘形态(无外部组件依赖、折叠头、条件体)。
|
|
13
|
+
- **真机判据**:升级重启新建会话 → bash 出现 + 日志 `official bash tool activated for this agent`;设置卡 = 七个可折叠卡片。
|
|
14
|
+
|
|
15
|
+
## v0.38.3 — 2026-10-13
|
|
16
|
+
|
|
17
|
+
**类型**:fix(补位激活的 scope 上下文时序;用户终端日志一锤定音)。
|
|
18
|
+
|
|
19
|
+
- **根因(日志 `official tool-bash activation failed: Cannot read properties of undefined (reading 'shell')`)**:cordis 的 `ctx.plugin()` **只创建 Fiber 就返回,插件的 apply 回调是异步启动的**(`vendor/cordis/lib/index.js:1619`,wrapped fiber 是 thenable)——`createScope` 返回时 `childCtx` 还是 `undefined`,`mod.apply(undefined, {})` 在官方模块第一行 `ctx.shell.sandboxMode` 上炸。此前的解析修复(v0.38.1)已生效:模块拿到了,死在最后一步。
|
|
20
|
+
- **修复**:`createScope` 返回 `{ fiber, get ctx(), dispose }`;`activateOfficialBash` 与 `providePwsh`(同款隐患,此前 pwsh7 开了也会静默发不出)在动手前 `await scope.fiber` 等回调跑完,再校验 `scope.ctx` 就绪。
|
|
21
|
+
- **冒烟**:118 项全绿。
|
|
22
|
+
- **真机判据**:升级重启新建会话 → 工具面出现 `bash`;日志出现 `official bash tool activated for this agent`。若再现 activation failed,错误行会指向官方模块内部的真实原因(而非 ctx undefined)。
|
|
23
|
+
|
|
6
24
|
## v0.38.2 — 2026-10-13
|
|
7
25
|
|
|
8
26
|
**类型**:fix(v0.38.0 折叠分区在真机上完全失效;用户截图定位)。
|
package/dsh.plugin.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"id": "dsh-external/dsh-gitbash-shell",
|
|
3
|
-
"version": "0.38.
|
|
3
|
+
"version": "0.38.4",
|
|
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.
|
|
3
|
+
"version": "0.38.4",
|
|
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
|
@@ -1807,6 +1807,11 @@ window.__ModuleLoader__.load({
|
|
|
1807
1807
|
seven header rows at a glance, switches only visible on expand. */
|
|
1808
1808
|
".gb-fold{border:1px solid var(--dsw-alias-border-l2);border-radius:10px;padding:4px 12px 12px;background:var(--dsw-alias-bg-layer-1,transparent)}",
|
|
1809
1809
|
".gb-fold .gb-stack{padding-top:10px}",
|
|
1810
|
+
".gb-foldHead{display:flex;align-items:center;gap:8px;width:100%;appearance:none;background:none;border:0;padding:6px 0;font:inherit;font-size:13px;font-weight:600;letter-spacing:.02em;color:var(--dsw-alias-label-secondary);cursor:pointer;text-align:left}",
|
|
1811
|
+
".gb-foldHead:hover{color:var(--dsw-alias-label-primary)}",
|
|
1812
|
+
".gb-foldChevron{flex:none;display:inline-block;color:var(--dsw-alias-label-tertiary);transition:transform .16s}",
|
|
1813
|
+
".gb-foldChevron.gb-foldChevronOpen{transform:rotate(90deg)}",
|
|
1814
|
+
".gb-foldTitle{min-width:0;overflow-wrap:anywhere}",
|
|
1810
1815
|
/* Missing-Git-Bash popup (v0.28.0): a root-level modal, because the
|
|
1811
1816
|
user may never be on the settings page when their shell dies. */
|
|
1812
1817
|
".gb-modalBackdrop{position:fixed;inset:0;z-index:2147483000;display:flex;align-items:center;justify-content:center;background:rgba(0,0,0,.45)}",
|
|
@@ -2100,35 +2105,31 @@ window.__ModuleLoader__.load({
|
|
|
2100
2105
|
|
|
2101
2106
|
var Chevron = icon("IconChevronDownOutline14");
|
|
2102
2107
|
|
|
2103
|
-
/* v0.38.
|
|
2104
|
-
|
|
2105
|
-
the
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
draft parsed (key, titleKey, ...) and ATE the first row into the
|
|
2113
|
-
title slot (t(<element>) → empty header, nothing folded). */
|
|
2108
|
+
/* v0.38.4: one FOLDABLE section, HAND-DRAWN. The official disclosure
|
|
2109
|
+
component was tried first (v0.38.0-0.38.3) but never rendered on
|
|
2110
|
+
the real machine — the ui-primitives module shape the plugin's
|
|
2111
|
+
restricted require returns does not expose it (the icon lookup
|
|
2112
|
+
comes back null there), so every section silently degraded to a
|
|
2113
|
+
static title+stack pile. Self-drawing costs one button + one
|
|
2114
|
+
conditional: header row visible at all times, body only while
|
|
2115
|
+
open. All sections stay collapsed by default — seven labelled
|
|
2116
|
+
header rows to scan. */
|
|
2114
2117
|
function fold(titleKey) {
|
|
2115
2118
|
var body = [];
|
|
2116
2119
|
for (var i = 1; i < arguments.length; i++) body.push(arguments[i]);
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
onToggle: function () { toggleFold(titleKey); },
|
|
2131
|
-
}, E("div", { className: "gb-stack" }, body));
|
|
2120
|
+
var open = folds[titleKey] === true;
|
|
2121
|
+
return E("div", { className: "gb-fold" },
|
|
2122
|
+
E("button", {
|
|
2123
|
+
type: "button",
|
|
2124
|
+
className: "gb-foldHead",
|
|
2125
|
+
"aria-expanded": open ? "true" : "false",
|
|
2126
|
+
onClick: function () { toggleFold(titleKey); },
|
|
2127
|
+
},
|
|
2128
|
+
E("span", { className: "gb-foldChevron" + (open ? " gb-foldChevronOpen" : ""), "aria-hidden": "true" }, "▸"),
|
|
2129
|
+
E("span", { className: "gb-foldTitle" }, t(titleKey)),
|
|
2130
|
+
),
|
|
2131
|
+
open ? E("div", { className: "gb-stack" }, body) : null,
|
|
2132
|
+
);
|
|
2132
2133
|
}
|
|
2133
2134
|
|
|
2134
2135
|
// dsh 0.1.6-alpha.2: the Plugins page renders this card through the
|
package/src/index.js
CHANGED
|
@@ -2618,7 +2618,14 @@ export async function apply(ctx, config = {}) {
|
|
|
2618
2618
|
let childCtx
|
|
2619
2619
|
const fiber = agentCtx.plugin((c) => { childCtx = c })
|
|
2620
2620
|
return {
|
|
2621
|
-
|
|
2621
|
+
// cordis plugin() starts the fiber ASYNCHRONOUSLY — the apply
|
|
2622
|
+
// callback that captures childCtx has NOT run when plugin()
|
|
2623
|
+
// returns. The wrapped fiber is a thenable (`fiber.await()`):
|
|
2624
|
+
// awaiting it is the only way to observe childCtx being set
|
|
2625
|
+
// (v0.38.3, real machine: apply(undefined) crashed with
|
|
2626
|
+
// "Cannot read properties of undefined (reading 'shell')").
|
|
2627
|
+
fiber,
|
|
2628
|
+
get ctx() { return childCtx },
|
|
2622
2629
|
dispose: async () => { try { await fiber?.dispose?.() } catch { /* already gone */ } },
|
|
2623
2630
|
}
|
|
2624
2631
|
},
|
package/src/inline-tools.js
CHANGED
|
@@ -266,7 +266,7 @@ export async function resolveToolBashEntry(ctx) {
|
|
|
266
266
|
* prescribes for per-agent variants. The official module is loaded ONCE per
|
|
267
267
|
* process; each agent gets a fresh scope and a fresh apply().
|
|
268
268
|
*/
|
|
269
|
-
export async function activateOfficialBash(agent, resolved,
|
|
269
|
+
export async function activateOfficialBash(agent, resolved, log) {
|
|
270
270
|
let mod
|
|
271
271
|
try {
|
|
272
272
|
mod = await resolved.load()
|
|
@@ -278,15 +278,31 @@ export async function activateOfficialBash(agent, resolved, createScopeFn, log)
|
|
|
278
278
|
log('official tool-bash module has no apply(); activation skipped')
|
|
279
279
|
return undefined
|
|
280
280
|
}
|
|
281
|
-
|
|
281
|
+
// Mount through cordis's OWN plugin path. The official module object
|
|
282
|
+
// DECLARES its service needs (`inject: ['tools','shell','systemPrompt',
|
|
283
|
+
// 'shellEnv','workingDirectory']`); a hand-called mod.apply(ctx) has no
|
|
284
|
+
// such declaration, so cordis refuses every service read with
|
|
285
|
+
// `cannot get property "shell" without inject` (v0.38.2 field report).
|
|
286
|
+
// ctx.plugin(mod) registers a REAL fiber with the declaration honored,
|
|
287
|
+
// runs apply itself, and the wrapped fiber is a thenable — awaiting it
|
|
288
|
+
// waits for the activation (and its async fiber start) to finish.
|
|
289
|
+
let fiber
|
|
282
290
|
try {
|
|
283
|
-
|
|
284
|
-
return scope
|
|
291
|
+
fiber = agent.ctx.plugin(mod)
|
|
285
292
|
} catch (error) {
|
|
286
|
-
|
|
287
|
-
log(`official tool-bash activation failed: ${error?.message ?? error}`)
|
|
293
|
+
log(`official tool-bash mount failed: ${error?.message ?? error}`)
|
|
288
294
|
return undefined
|
|
289
295
|
}
|
|
296
|
+
try {
|
|
297
|
+
await fiber
|
|
298
|
+
} catch (error) {
|
|
299
|
+
log(`official tool-bash fiber failed: ${error?.message ?? error}`)
|
|
300
|
+
return undefined
|
|
301
|
+
}
|
|
302
|
+
return {
|
|
303
|
+
fiber,
|
|
304
|
+
dispose: async () => { try { await fiber?.dispose?.() } catch { /* already gone */ } },
|
|
305
|
+
}
|
|
290
306
|
}
|
|
291
307
|
|
|
292
308
|
/**
|
|
@@ -332,12 +348,15 @@ export function mountInlineTools(ctx, deps) {
|
|
|
332
348
|
* pure ADDITION — it shadows nothing and requires no deny juggling. The
|
|
333
349
|
* scope keeps the registration revertible at agent disposal.
|
|
334
350
|
*/
|
|
335
|
-
const providePwsh = (agent, state) => {
|
|
351
|
+
const providePwsh = async (agent, state) => {
|
|
336
352
|
if (state.pwshScope) return
|
|
337
353
|
if (typeof spawn !== 'function' || !pwshPath) return
|
|
338
354
|
if (!createScope) return
|
|
339
355
|
try {
|
|
340
356
|
const scope = createScope(agent.ctx)
|
|
357
|
+
// Same asynchronous-fiber shape as activateOfficialBash: wait for the
|
|
358
|
+
// apply callback to capture scope.ctx before touching its tools.
|
|
359
|
+
if (scope.fiber) { try { await scope.fiber } catch { /* disposed */ } }
|
|
341
360
|
const registry = scope.ctx?.tools
|
|
342
361
|
if (!registry || typeof registry.register !== 'function') {
|
|
343
362
|
void scope.dispose().catch(() => {})
|
|
@@ -400,7 +419,7 @@ export function mountInlineTools(ctx, deps) {
|
|
|
400
419
|
log(`fake-pwsh deny failed: ${error?.message ?? error}`)
|
|
401
420
|
}
|
|
402
421
|
}
|
|
403
|
-
if (deps.pwshEnabled && deps.pwshEnabled() === true) providePwsh(agent, state)
|
|
422
|
+
if (deps.pwshEnabled && deps.pwshEnabled() === true) void providePwsh(agent, state)
|
|
404
423
|
}
|
|
405
424
|
}
|
|
406
425
|
if (needs.needsBash && !state.scope) {
|
|
@@ -410,7 +429,7 @@ export function mountInlineTools(ctx, deps) {
|
|
|
410
429
|
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')
|
|
411
430
|
return
|
|
412
431
|
}
|
|
413
|
-
const scope = await activateOfficialBash(agent, resolved,
|
|
432
|
+
const scope = await activateOfficialBash(agent, resolved, log)
|
|
414
433
|
if (scope && tracked.get(agent) === state) {
|
|
415
434
|
state.scope = scope
|
|
416
435
|
log('official bash tool activated for this agent (Git Bash host; fake pwsh denied)')
|