dsh-gitbash-shell 0.13.0 → 0.13.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/dsh.plugin.json +1 -1
- package/package.json +3 -2
- package/src/index.js +32 -2
- package/src/shell.js +38 -1
package/dsh.plugin.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"id": "dsh-external/dsh-gitbash-shell",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.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。双 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.13.
|
|
3
|
+
"version": "0.13.2",
|
|
4
4
|
"description": "DSH plugin: run every agent shell command through Git for Windows bash on Windows instead of PowerShell. Replaces the pwsh executor with a Git Bash ctx.shell provider and materializes Git Bash variants of the standard/minimal/code/cordis agent presets into your user preset root at startup. On Windows it also adopts dsh-better-sidebar's terminal shell (UI tabs and the model-facing terminal_* tools) through the sidebar's official settings seam, and pairs with dsh-ptc-cordis-preset so the PTC Creation-mode preset materializes as its Git Bash variant. Ships both composition eras for dsh <= 0.1.1 (built-in preset id 'code') and dsh >= 0.1.2 (renamed id 'ptc') — the era is probed per boot and re-materialized automatically after a dsh upgrade, in either upgrade order; preset ids never change so pinned sessions stay valid.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
|
@@ -41,7 +41,8 @@
|
|
|
41
41
|
"LICENSE"
|
|
42
42
|
],
|
|
43
43
|
"scripts": {
|
|
44
|
-
"test": "node --test tests/smoke.mjs"
|
|
44
|
+
"test": "node --test tests/smoke.mjs",
|
|
45
|
+
"version": "node -e \"const fs=require('fs');const m=JSON.parse(fs.readFileSync('dsh.plugin.json','utf8'));const v=JSON.parse(fs.readFileSync('package.json','utf8')).version;m.version=v;fs.writeFileSync('dsh.plugin.json',JSON.stringify(m,null,2)+'\\n')\" && git add dsh.plugin.json"
|
|
45
46
|
},
|
|
46
47
|
"keywords": [
|
|
47
48
|
"dsh",
|
package/src/index.js
CHANGED
|
@@ -205,6 +205,32 @@ export async function detectPersonaEra(agentPresets) {
|
|
|
205
205
|
}
|
|
206
206
|
}
|
|
207
207
|
|
|
208
|
+
/**
|
|
209
|
+
* Does the SHIPPED composition already carry the official `present` row? The
|
|
210
|
+
* row (`@deepseek-ai/dsh-tool-present`, immutable file-delivery download
|
|
211
|
+
* cards) first shipped with dsh 0.1.5-alpha.2, and a composition row that
|
|
212
|
+
* cannot be imported rejects the WHOLE preset mount — so the row is injected
|
|
213
|
+
* only on hosts whose own shipped presets have it. The live roster is the
|
|
214
|
+
* authority: package resolution alone would lie on CLI installs (first-party
|
|
215
|
+
* packages live outside the profile) and on linked development trees.
|
|
216
|
+
* `minimal` never gains the row (single-tool preset). Never throws.
|
|
217
|
+
*/
|
|
218
|
+
async function detectPresentSupport(agentPresets) {
|
|
219
|
+
try {
|
|
220
|
+
const list = await agentPresets.list()
|
|
221
|
+
const entries = Array.isArray(list) ? list : []
|
|
222
|
+
const entry = ['ptc', 'standard', 'cordis']
|
|
223
|
+
.map((id) => entries.find((p) => p && p.id === id && typeof p.path === 'string'))
|
|
224
|
+
.find(Boolean)
|
|
225
|
+
if (!entry) return false
|
|
226
|
+
const file = /\.yml$/.test(entry.path) ? entry.path : join(entry.path, 'agent.cordis.yml')
|
|
227
|
+
return readFileSync(file, 'utf8').includes("'@deepseek-ai/dsh-tool-present'")
|
|
228
|
+
} catch (error) {
|
|
229
|
+
console.log(`${TAG} present-row probe failed (${error?.message ?? error}) — not injecting the row`)
|
|
230
|
+
return false
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
208
234
|
/**
|
|
209
235
|
* Pick the committed composition asset inside one variant directory (pure).
|
|
210
236
|
* The ptc-era twin is preferred when the roster says `ptc`; the persona-split
|
|
@@ -920,7 +946,11 @@ export async function apply(ctx, config = {}) {
|
|
|
920
946
|
const skillsSource = await findSkillsSource(ctx.agentPresets)
|
|
921
947
|
const base = await detectBase(ctx.agentPresets)
|
|
922
948
|
const persona = await detectPersonaEra(ctx.agentPresets)
|
|
923
|
-
|
|
949
|
+
// Two independent signals, either of which is sufficient: the shipped
|
|
950
|
+
// composition text (authoritative on every install layout) and the package
|
|
951
|
+
// resolving from this plugin's own tree (covers hosts where the roster
|
|
952
|
+
// probe is unavailable).
|
|
953
|
+
const present = (await detectPresentSupport(ctx.agentPresets)) || (await hostHasToolPresent())
|
|
924
954
|
const userRootPath = userRoot.path
|
|
925
955
|
purgeOrphans(userRootPath, presetIds)
|
|
926
956
|
|
|
@@ -965,4 +995,4 @@ export async function apply(ctx, config = {}) {
|
|
|
965
995
|
}
|
|
966
996
|
|
|
967
997
|
// Test surface: pure helpers, no Cordis context required.
|
|
968
|
-
export const _internal = { PRESET_IDS, translateMsysPath, translatePathArguments, readPosixPaths, windowsToMsys, rewriteResultPaths, MARKER_FILE, classify, materialize, cleanupOnDispose, firstUserRoot, hashTree, skillsHashes, syncDecision, installRegisterShim, baseForRoster, detectBase, pickComposition, personaEraForText, detectPersonaEra, injectPresentRow, hostHasToolPresent }
|
|
998
|
+
export const _internal = { PRESET_IDS, translateMsysPath, translatePathArguments, readPosixPaths, windowsToMsys, rewriteResultPaths, MARKER_FILE, classify, materialize, cleanupOnDispose, firstUserRoot, hashTree, skillsHashes, syncDecision, installRegisterShim, baseForRoster, detectBase, pickComposition, personaEraForText, detectPersonaEra, injectPresentRow, hostHasToolPresent, detectPresentSupport }
|
package/src/shell.js
CHANGED
|
@@ -15,7 +15,18 @@
|
|
|
15
15
|
* - overrides run/start ONLY for danger-full-access (the parent's
|
|
16
16
|
* full-access branch calls LocalBashExecutor.run, which hardcodes the
|
|
17
17
|
* bare `bash` name), routing through runArgv/startArgv with the same
|
|
18
|
-
* argv as the confined branch
|
|
18
|
+
* argv as the confined branch;
|
|
19
|
+
* - on Windows ALSO overrides the confined branch itself (issue #1):
|
|
20
|
+
* MSYS2 cannot start under the restricted-token sandbox — msys-2.0.dll
|
|
21
|
+
* init creates its cygheap mapping and signal pipe with DACLs naming
|
|
22
|
+
* only the user SID, a WRITE_RESTRICTED token's pass-2 write check
|
|
23
|
+
* demands a restricting-SID ACE, so init dies with Win32 error 5 /
|
|
24
|
+
* 0xC0000142 before argv ever runs (silent fake-success or a hard
|
|
25
|
+
* crash, every version since 0.6.0; cmd/pwsh are unaffected —
|
|
26
|
+
* anonymous pipes). OS-level conflict with no in-plugin cure, so
|
|
27
|
+
* confined Windows calls run Git Bash UNCONFINED, labelled as such in
|
|
28
|
+
* the result (sandbox.enforcement === 'unconfined') plus a one-time
|
|
29
|
+
* notice. The fs-tool sandbox policy still applies to file tools.
|
|
19
30
|
*
|
|
20
31
|
* Environment inheritance: bash.exe is spawned as a direct child of the host
|
|
21
32
|
* process (never through the git-bash.exe login launcher), so it inherits the
|
|
@@ -32,6 +43,9 @@ import z from '@deepseek-ai/schemastery'
|
|
|
32
43
|
/** Default Git for Windows bash (forward slashes work on Windows too). */
|
|
33
44
|
export const DEFAULT_GIT_BASH = 'C:/Program Files/Git/bin/bash.exe'
|
|
34
45
|
|
|
46
|
+
/** Log prefix, matching src/index.js. */
|
|
47
|
+
const TAG = '[gitbash-shell]'
|
|
48
|
+
|
|
35
49
|
/** Resolved configuration: the local executor's knobs, plus the Git Bash path. */
|
|
36
50
|
export const Config = z.object({
|
|
37
51
|
cwd: z.string(),
|
|
@@ -69,6 +83,11 @@ export class GitBashSandboxExecutor extends SandboxBashExecutor {
|
|
|
69
83
|
* delegates to LocalBashExecutor.run, which hardcodes the bare `bash`
|
|
70
84
|
* name, so override that branch here and keep everything else inherited.
|
|
71
85
|
*/
|
|
86
|
+
/**
|
|
87
|
+
* Confined Windows calls cannot use the restricted-token runner (issue
|
|
88
|
+
* #1, see the file header): route them through the unconfined argv path
|
|
89
|
+
* and label the result honestly so callers can tell.
|
|
90
|
+
*/
|
|
72
91
|
async run(spec) {
|
|
73
92
|
const policy = spec.sandboxPolicy
|
|
74
93
|
if (policy === undefined) return super.run(spec)
|
|
@@ -77,6 +96,11 @@ export class GitBashSandboxExecutor extends SandboxBashExecutor {
|
|
|
77
96
|
const result = await this.runArgv(spec, [this.bashPath, '-c', spec.command])
|
|
78
97
|
return { ...result, sandbox: { mode, denied: false } }
|
|
79
98
|
}
|
|
99
|
+
if (process.platform === 'win32') {
|
|
100
|
+
this.warnConfinedUnconfined(mode)
|
|
101
|
+
const result = await this.runArgv(spec, [this.bashPath, '-c', spec.command])
|
|
102
|
+
return { ...result, sandbox: { mode, denied: false, enforcement: 'unconfined' } }
|
|
103
|
+
}
|
|
80
104
|
return super.run(spec)
|
|
81
105
|
}
|
|
82
106
|
|
|
@@ -89,8 +113,21 @@ export class GitBashSandboxExecutor extends SandboxBashExecutor {
|
|
|
89
113
|
proc.sandbox = { mode, denied: false }
|
|
90
114
|
return proc
|
|
91
115
|
}
|
|
116
|
+
if (process.platform === 'win32') {
|
|
117
|
+
this.warnConfinedUnconfined(mode)
|
|
118
|
+
const proc = this.startArgv(spec, [this.bashPath, '-c', spec.command])
|
|
119
|
+
proc.sandbox = { mode, denied: false, enforcement: 'unconfined' }
|
|
120
|
+
return proc
|
|
121
|
+
}
|
|
92
122
|
return super.start(spec)
|
|
93
123
|
}
|
|
124
|
+
|
|
125
|
+
/** One-per-instance notice that confined Windows calls run unconfined. */
|
|
126
|
+
warnConfinedUnconfined(mode) {
|
|
127
|
+
if (this._warnedUnconfined) return
|
|
128
|
+
this._warnedUnconfined = true
|
|
129
|
+
console.log(TAG + ' Windows: MSYS2 cannot start under the restricted-token sandbox (msys-2.0.dll init: cygheap/signal-pipe DACLs carry no restricting-SID ACE -> Win32 error 5 / 0xC0000142; issue #1). Confined call (' + mode + ') ran Git Bash UNCONFINED; the fs-tool sandbox policy still applies.')
|
|
130
|
+
}
|
|
94
131
|
}
|
|
95
132
|
|
|
96
133
|
export default GitBashSandboxExecutor
|