dsh-gitbash-shell 0.24.3 → 0.24.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/dsh.plugin.json +1 -1
- package/package.json +1 -1
- package/src/index.js +16 -4
- package/src/shell.js +149 -17
package/dsh.plugin.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"id": "dsh-external/dsh-gitbash-shell",
|
|
3
|
-
"version": "0.24.
|
|
3
|
+
"version": "0.24.4",
|
|
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.24.
|
|
3
|
+
"version": "0.24.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/index.js
CHANGED
|
@@ -1692,10 +1692,22 @@ function adoptSidebarShell(ctx, bashPath, readAdopt) {
|
|
|
1692
1692
|
|
|
1693
1693
|
const readShell = () => {
|
|
1694
1694
|
const settings = ctx.get('settings')
|
|
1695
|
-
if (!settings || typeof settings.
|
|
1695
|
+
if (!settings || typeof settings.update !== 'function') return null
|
|
1696
1696
|
try {
|
|
1697
|
-
|
|
1698
|
-
|
|
1697
|
+
// <=0.1.6: the sidebar registers a settings namespace and `get(ns)` reads
|
|
1698
|
+
// it. >=0.1.7: that API is gone (the service exposes describe/update
|
|
1699
|
+
// only), so the value comes from the row Config's projected form —
|
|
1700
|
+
// without this branch the adoption was silently skipped on the new host.
|
|
1701
|
+
if (typeof settings.get === 'function') {
|
|
1702
|
+
const value = settings.get(SIDEBAR_NS)
|
|
1703
|
+
return value && typeof value === 'object' && typeof value.terminalShell === 'string' ? value.terminalShell : ''
|
|
1704
|
+
}
|
|
1705
|
+
if (typeof settings.describe === 'function') {
|
|
1706
|
+
const entry = settings.describe().find((row) => row !== null && typeof row === 'object' && row.ns === SIDEBAR_NS)
|
|
1707
|
+
const value = entry === undefined ? undefined : entry.value
|
|
1708
|
+
return value && typeof value === 'object' && typeof value.terminalShell === 'string' ? value.terminalShell : ''
|
|
1709
|
+
}
|
|
1710
|
+
return null
|
|
1699
1711
|
} catch {
|
|
1700
1712
|
return null // namespace not registered yet / sidebar absent
|
|
1701
1713
|
}
|
|
@@ -2375,4 +2387,4 @@ export async function apply(ctx, config = {}) {
|
|
|
2375
2387
|
}
|
|
2376
2388
|
|
|
2377
2389
|
// Test surface: pure helpers, no Cordis context required.
|
|
2378
|
-
export const _internal = { PRESET_IDS, translateMsysPath, translatePathArguments, rewriteCodePaths, scanCodeLiterals, programPrelude, translateGlobArguments, buildTranslateEnv, rewriteErrorContent, rewriteErrorMessage, rewriteFailureMessage, msysEcho, driveToMsys, pathEcho, ERROR_CONTENT_TOOLS, readPosixPaths, readAdoptSidebar, readDialectSettings, windowsToMsys, rewriteResultPaths, MARKER_FILE, classify, materialize, cleanupOnDispose, firstUserRoot, hashTree, skillsHashes, syncDecision, installRegisterShim, baseForRoster, detectBase, pickComposition, personaEraForText, detectPersonaEra, injectPresentRow, hostHasToolPresent, detectPresentSupport, injectPluginManagerRow, hostHasPluginManagerTools, rowFormOf, rowFormsOf, alignEngineRow, alignRalphRow, ROW_SOURCE }
|
|
2390
|
+
export const _internal = { PRESET_IDS, translateMsysPath, translatePathArguments, rewriteCodePaths, scanCodeLiterals, programPrelude, translateGlobArguments, buildTranslateEnv, rewriteErrorContent, rewriteErrorMessage, rewriteFailureMessage, msysEcho, driveToMsys, pathEcho, ERROR_CONTENT_TOOLS, readPosixPaths, readAdoptSidebar, readDialectSettings, windowsToMsys, rewriteResultPaths, adoptSidebarShell, MARKER_FILE, classify, materialize, cleanupOnDispose, firstUserRoot, hashTree, skillsHashes, syncDecision, installRegisterShim, baseForRoster, detectBase, pickComposition, personaEraForText, detectPersonaEra, injectPresentRow, hostHasToolPresent, detectPresentSupport, injectPluginManagerRow, hostHasPluginManagerTools, rowFormOf, rowFormsOf, alignEngineRow, alignRalphRow, ROW_SOURCE }
|
package/src/shell.js
CHANGED
|
@@ -46,16 +46,61 @@ export const DEFAULT_GIT_BASH = 'C:/Program Files/Git/bin/bash.exe'
|
|
|
46
46
|
/** Log prefix, matching src/index.js. */
|
|
47
47
|
const TAG = '[gitbash-shell]'
|
|
48
48
|
|
|
49
|
+
/**
|
|
50
|
+
* The plugin row's id, which doubles as the settings namespace on <= 0.1.6 and
|
|
51
|
+
* as the row-config namespace on 0.1.7+ (same string by design).
|
|
52
|
+
*/
|
|
53
|
+
const SETTINGS_NAMESPACE = 'gitbash-shell'
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Mark one schema field live-editable when the HOST's schemastery supports it.
|
|
57
|
+
*
|
|
58
|
+
* dsh 0.1.7-alpha.1 (`feat(settings): project volatile Config through
|
|
59
|
+
* profile-backed forms`, #4587) made `LocalBashExecutor.Config` declare
|
|
60
|
+
* `cwd`/`timeoutMs`/`maxTimeoutMs`/`maxOutputBytes`/`maxSpillBytes`/`graceMs`
|
|
61
|
+
* with `.volatile()` and read every one of them through `.get()`
|
|
62
|
+
* (`packages/shell/bash-local/src/index.ts:100-107` and its
|
|
63
|
+
* `assertServiceableBashConfig`/`resolve`). A subclass that REDECLARES those
|
|
64
|
+
* fields as plain values therefore throws
|
|
65
|
+
* `TypeError: config.timeoutMs.get is not a function` on the first shell call
|
|
66
|
+
* and takes the whole `ctx.shell` down with it (issue #6, 0.24.2).
|
|
67
|
+
* `SandboxBashExecutor` — our parent — declares no Config of its own: it
|
|
68
|
+
* inherits `LocalBashExecutor`'s verbatim, so this redeclaration IS the
|
|
69
|
+
* executor's contract.
|
|
70
|
+
*
|
|
71
|
+
* The probe keeps one build serving both eras: hosts whose schemastery has
|
|
72
|
+
* `volatile()` (0.1.7+) get the Volatile refs their base class calls `.get()`
|
|
73
|
+
* on, while older hosts — whose base class reads plain values — keep plain
|
|
74
|
+
* ones. Published schemastery 3.18.2 has no `volatile()`, which is exactly why
|
|
75
|
+
* the probe (not an unconditional call) is required.
|
|
76
|
+
*/
|
|
77
|
+
function live(schema) {
|
|
78
|
+
return typeof schema.volatile === 'function' ? schema.volatile() : schema
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Build the executor's Config against a given schemastery module. Exported so
|
|
83
|
+
* the smoke test can drive BOTH eras with a recording stand-in instead of
|
|
84
|
+
* depending on which schemastery happens to be installed here.
|
|
85
|
+
* @param z schemastery module (real one, or the test's recorder).
|
|
86
|
+
* @returns the object schema for the `gitbash-executor` row.
|
|
87
|
+
*/
|
|
88
|
+
export function gitBashShellConfig(z) {
|
|
89
|
+
return z.object({
|
|
90
|
+
cwd: live(z.string()),
|
|
91
|
+
timeoutMs: live(z.number().default(120000)),
|
|
92
|
+
maxTimeoutMs: live(z.number().default(600000)),
|
|
93
|
+
maxOutputBytes: live(z.number().default(64000)),
|
|
94
|
+
maxSpillBytes: live(z.number().default(64 * 1024 * 1024)),
|
|
95
|
+
graceMs: live(z.number().default(3000)),
|
|
96
|
+
// Our own knob: the base class neither declares nor `.get()`s it, and
|
|
97
|
+
// `get bashPath()` below reads it as a plain value, so it stays plain.
|
|
98
|
+
bashPath: z.string().default(DEFAULT_GIT_BASH),
|
|
99
|
+
})
|
|
100
|
+
}
|
|
101
|
+
|
|
49
102
|
/** Resolved configuration: the local executor's knobs, plus the Git Bash path. */
|
|
50
|
-
export const Config = z
|
|
51
|
-
cwd: z.string(),
|
|
52
|
-
timeoutMs: z.number().default(120000),
|
|
53
|
-
maxTimeoutMs: z.number().default(600000),
|
|
54
|
-
maxOutputBytes: z.number().default(64000),
|
|
55
|
-
maxSpillBytes: z.number().default(64 * 1024 * 1024),
|
|
56
|
-
graceMs: z.number().default(3000),
|
|
57
|
-
bashPath: z.string().default(DEFAULT_GIT_BASH),
|
|
58
|
-
})
|
|
103
|
+
export const Config = gitBashShellConfig(z)
|
|
59
104
|
|
|
60
105
|
/** Git Bash executor — mirrors the shipped bash/pwsh sandbox executors. */
|
|
61
106
|
export class GitBashSandboxExecutor extends SandboxBashExecutor {
|
|
@@ -119,15 +164,72 @@ export class GitBashSandboxExecutor extends SandboxBashExecutor {
|
|
|
119
164
|
}
|
|
120
165
|
|
|
121
166
|
/**
|
|
122
|
-
*
|
|
123
|
-
*
|
|
124
|
-
* name
|
|
167
|
+
* Decide whether one spec takes the Git Bash argv path, and how to label it
|
|
168
|
+
* (pure). Full access always does — the shipped executor hardcodes the bare
|
|
169
|
+
* `bash` name there. A Windows confined call does too (issue #1: MSYS2 cannot
|
|
170
|
+
* start under the restricted-token runner). Everything else inherits the
|
|
171
|
+
* parent's sandbox path, which already runs Git Bash because `confine` below
|
|
172
|
+
* substitutes the argv.
|
|
173
|
+
* @param spec the shell request.
|
|
174
|
+
* @returns `{ mode, unconfined }`, or undefined to inherit the parent path.
|
|
125
175
|
*/
|
|
176
|
+
gitBashRoute(spec) {
|
|
177
|
+
const policy = spec.sandboxPolicy
|
|
178
|
+
const mode = policy === undefined ? undefined : policy.mode
|
|
179
|
+
if (mode === undefined) return undefined
|
|
180
|
+
if (mode === 'danger-full-access') return { mode, unconfined: false }
|
|
181
|
+
if (process.platform === 'win32') return { mode, unconfined: true }
|
|
182
|
+
return undefined
|
|
183
|
+
}
|
|
184
|
+
|
|
126
185
|
/**
|
|
127
|
-
*
|
|
128
|
-
*
|
|
129
|
-
*
|
|
186
|
+
* Label one execution handle's foreground result without changing its
|
|
187
|
+
* identity (the parent's `decorateResult` is private to the shipped class, so
|
|
188
|
+
* the same memoized in-place wrapper lives here).
|
|
189
|
+
* @param ex the handle returned by `executeArgv`.
|
|
190
|
+
* @param sandbox sandbox facts to stamp onto the result.
|
|
191
|
+
* @returns the same handle, with `result()` mapped.
|
|
130
192
|
*/
|
|
193
|
+
static decorateExecution(ex, sandbox) {
|
|
194
|
+
const base = ex.result.bind(ex)
|
|
195
|
+
let decorated
|
|
196
|
+
ex.result = () => {
|
|
197
|
+
decorated ??= base().then((result) => ({ ...result, sandbox }))
|
|
198
|
+
return decorated
|
|
199
|
+
}
|
|
200
|
+
return ex
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* dsh 0.1.7 execution entry point (the shipped `ShellExecutor` now declares
|
|
205
|
+
* `execute(spec): Promise<ShellExecution>`; `run`/`start` were removed and
|
|
206
|
+
* background work is an `onExpiry: 'none'` execution the caller stops
|
|
207
|
+
* waiting on). Overriding it is what keeps the two Git Bash substitutions
|
|
208
|
+
* alive on the new host: without it the full-access branch spawns the bare
|
|
209
|
+
* `bash` name hardcoded in `LocalBashExecutor.execute`, and a Windows
|
|
210
|
+
* confined call goes back through the restricted-token runner MSYS2 cannot
|
|
211
|
+
* survive.
|
|
212
|
+
* On hosts without `execute` (<= 0.1.6) this method is never called by the
|
|
213
|
+
* runtime; it delegates to `run` so the class still behaves if it is.
|
|
214
|
+
* @param spec resolved execution settings and caller-owned command metadata.
|
|
215
|
+
* @returns the live execution handle.
|
|
216
|
+
*/
|
|
217
|
+
execute(spec) {
|
|
218
|
+
if (typeof super.execute !== 'function') return this.run(spec)
|
|
219
|
+
const routed = this.withParityEnv(spec)
|
|
220
|
+
const route = this.gitBashRoute(routed)
|
|
221
|
+
if (route === undefined) return super.execute(routed)
|
|
222
|
+
const argv = [this.bashPath, '-c', routed.command]
|
|
223
|
+
if (route.unconfined) this.warnConfinedUnconfined(route.mode)
|
|
224
|
+
const sandbox = route.unconfined
|
|
225
|
+
? { mode: route.mode, denied: false, enforcement: 'unconfined' }
|
|
226
|
+
: { mode: route.mode, denied: false }
|
|
227
|
+
// `executeArgv` is the shipped helper for exactly this: run an explicit
|
|
228
|
+
// argv with the executor's own lifecycle, output and deadline semantics.
|
|
229
|
+
return Promise.resolve(this.executeArgv(routed, argv))
|
|
230
|
+
.then((ex) => GitBashSandboxExecutor.decorateExecution(ex, sandbox))
|
|
231
|
+
}
|
|
232
|
+
|
|
131
233
|
/**
|
|
132
234
|
* Linux-parity environment for the MODEL's shell (v0.21.1). The official
|
|
133
235
|
* shell-env registry accepts DSH_* facts only — registering anything else
|
|
@@ -146,10 +248,33 @@ export class GitBashSandboxExecutor extends SandboxBashExecutor {
|
|
|
146
248
|
* @param {object} spec the shell request
|
|
147
249
|
* @returns {object} the request with the parity facts merged in
|
|
148
250
|
*/
|
|
149
|
-
|
|
251
|
+
/**
|
|
252
|
+
* The plugin row's live dialect settings, across eras. dsh 0.1.7 replaced the
|
|
253
|
+
* settings namespace API: the service still exists but exposes only
|
|
254
|
+
* `describe()` / `update()` — `get(ns)` is gone — so the old read silently
|
|
255
|
+
* returned undefined on the new host and the Linux-parity env below never
|
|
256
|
+
* applied. The new era reads the row Config's projected values from the form
|
|
257
|
+
* descriptors (the same read dsh-agent-lang uses for the `locale` namespace).
|
|
258
|
+
* @returns the row's settings object, or undefined when unavailable.
|
|
259
|
+
*/
|
|
260
|
+
dialectSettings() {
|
|
150
261
|
try {
|
|
151
262
|
const settings = this.ctx && typeof this.ctx.get === 'function' ? this.ctx.get('settings') : undefined
|
|
152
|
-
|
|
263
|
+
if (settings === undefined || settings === null) return undefined
|
|
264
|
+
if (typeof settings.get === 'function') return settings.get(SETTINGS_NAMESPACE)
|
|
265
|
+
if (typeof settings.describe === 'function') {
|
|
266
|
+
const entry = settings.describe().find((row) => row !== null && typeof row === 'object' && row.ns === SETTINGS_NAMESPACE)
|
|
267
|
+
return entry === undefined ? undefined : entry.value
|
|
268
|
+
}
|
|
269
|
+
return undefined
|
|
270
|
+
} catch {
|
|
271
|
+
return undefined
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
withParityEnv(spec) {
|
|
276
|
+
try {
|
|
277
|
+
const value = this.dialectSettings()
|
|
153
278
|
if (!value || value.posixPaths !== true || value.gitAutocrlf === false) return spec
|
|
154
279
|
const dshEnv = {
|
|
155
280
|
...(spec.dshEnv === undefined ? {} : spec.dshEnv),
|
|
@@ -165,6 +290,13 @@ export class GitBashSandboxExecutor extends SandboxBashExecutor {
|
|
|
165
290
|
}
|
|
166
291
|
}
|
|
167
292
|
|
|
293
|
+
/**
|
|
294
|
+
* 0.1.6-era full-access path with Git Bash argv: the parent's full-access
|
|
295
|
+
* branch delegates to LocalBashExecutor.run, which hardcodes the bare `bash`
|
|
296
|
+
* name, so override that branch here and keep everything else inherited.
|
|
297
|
+
* On 0.1.7+ the runtime calls `execute` above instead; this stays as the
|
|
298
|
+
* old-era entry point.
|
|
299
|
+
*/
|
|
168
300
|
async run(spec) {
|
|
169
301
|
spec = this.withParityEnv(spec)
|
|
170
302
|
const policy = spec.sandboxPolicy
|