dsh-gitbash-shell 0.12.0 → 0.13.1
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.
|
@@ -7,13 +7,13 @@
|
|
|
7
7
|
# change across the 0.1.1 → 0.1.2 code→ptc rename, so no agent.cordis.ptc.yml
|
|
8
8
|
# twin exists here. The plugin probes the roster and writes this file as the
|
|
9
9
|
# preset's own agent.cordis.yml either way.
|
|
10
|
-
# The `minimal` agent preset: a fixed-prompt,
|
|
10
|
+
# The `minimal` agent preset: a fixed-prompt, single-tool coding-agent composition.
|
|
11
11
|
#
|
|
12
12
|
# The persona is the complete system prompt, so global identity, Web orientation,
|
|
13
13
|
# tool guidance, and later assembly listeners cannot add prompt text. Runtime
|
|
14
|
-
# context snapshots are suppressed for this preset, and the model
|
|
15
|
-
# the persistent shell (Git for Windows bash; bash on POSIX)
|
|
16
|
-
#
|
|
14
|
+
# context snapshots are suppressed for this preset, and the model receives only
|
|
15
|
+
# the persistent shell (Git for Windows bash; bash on POSIX). Context compaction
|
|
16
|
+
# is absent.
|
|
17
17
|
|
|
18
18
|
- id: persona
|
|
19
19
|
name: '@deepseek-ai/dsh-persona'
|
|
@@ -51,8 +51,7 @@
|
|
|
51
51
|
description: |-
|
|
52
52
|
Run commands in a bash shell (Git for Windows bash on Windows: native paths like C:/... work, and PATH plus the rest of the environment are inherited from the host)
|
|
53
53
|
* When invoking this tool, the contents of the "command" parameter does NOT need to be XML-escaped.
|
|
54
|
-
*
|
|
55
|
-
* You do have access to a mirror of common linux and python packages via apt and pip.
|
|
54
|
+
* Network access depends on the task environment. Prefer configured mirrors/proxies when they are available.
|
|
56
55
|
* State is persistent across command calls and discussions with the user.
|
|
57
56
|
* To inspect a particular line range of a file, e.g. lines 10-25, try 'sed -n 10,25p /path/to/the/file'.
|
|
58
57
|
* Please avoid commands that may produce a very large amount of output.
|
|
@@ -78,21 +77,3 @@
|
|
|
78
77
|
* Use native Windows paths (C:\...) and $env:NAME variables; this is PowerShell, not bash.
|
|
79
78
|
* Please avoid commands that may produce a very large amount of output.
|
|
80
79
|
* Please run long lived commands in the background, e.g. 'Start-Job' or start a server with Start-Process.
|
|
81
|
-
|
|
82
|
-
# The bare local filesystem shadows the host's sandboxed provider only for this
|
|
83
|
-
# preset. The editor shares that realm and requires absolute paths.
|
|
84
|
-
- id: filesystem
|
|
85
|
-
name: cordis:group
|
|
86
|
-
group: true
|
|
87
|
-
isolate:
|
|
88
|
-
fs: true
|
|
89
|
-
config:
|
|
90
|
-
- id: fs-local
|
|
91
|
-
name: '@deepseek-ai/dsh-fs-local'
|
|
92
|
-
config:
|
|
93
|
-
cwd: !!js process.env.DSH_CWD ?? process.cwd()
|
|
94
|
-
|
|
95
|
-
- id: str-replace-editor
|
|
96
|
-
name: '@deepseek-ai/dsh-tool-str-replace-editor'
|
|
97
|
-
config:
|
|
98
|
-
maxOutputChars: 16000
|
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
# change across the 0.1.1 → 0.1.2 code→ptc rename, so no agent.cordis.ptc.yml
|
|
3
3
|
# twin exists here. The plugin probes the roster and writes this file as the
|
|
4
4
|
# preset's own agent.cordis.yml either way.
|
|
5
|
-
# The `minimal` agent preset: a fixed-prompt,
|
|
5
|
+
# The `minimal` agent preset: a fixed-prompt, single-tool coding-agent composition.
|
|
6
6
|
#
|
|
7
7
|
# The persona is the complete system prompt, so global identity, Web orientation,
|
|
8
8
|
# tool guidance, and later assembly listeners cannot add prompt text. Runtime
|
|
9
|
-
# context snapshots are suppressed for this preset, and the model
|
|
10
|
-
# the persistent shell (Git for Windows bash; bash on POSIX)
|
|
11
|
-
#
|
|
9
|
+
# context snapshots are suppressed for this preset, and the model receives only
|
|
10
|
+
# the persistent shell (Git for Windows bash; bash on POSIX). Context compaction
|
|
11
|
+
# is absent.
|
|
12
12
|
|
|
13
13
|
- id: persona
|
|
14
14
|
name: '@deepseek-ai/dsh-persona'
|
|
@@ -46,8 +46,7 @@
|
|
|
46
46
|
description: |-
|
|
47
47
|
Run commands in a bash shell (Git for Windows bash on Windows: native paths like C:/... work, and PATH plus the rest of the environment are inherited from the host)
|
|
48
48
|
* When invoking this tool, the contents of the "command" parameter does NOT need to be XML-escaped.
|
|
49
|
-
*
|
|
50
|
-
* You do have access to a mirror of common linux and python packages via apt and pip.
|
|
49
|
+
* Network access depends on the task environment. Prefer configured mirrors/proxies when they are available.
|
|
51
50
|
* State is persistent across command calls and discussions with the user.
|
|
52
51
|
* To inspect a particular line range of a file, e.g. lines 10-25, try 'sed -n 10,25p /path/to/the/file'.
|
|
53
52
|
* Please avoid commands that may produce a very large amount of output.
|
|
@@ -73,21 +72,3 @@
|
|
|
73
72
|
* Use native Windows paths (C:\...) and $env:NAME variables; this is PowerShell, not bash.
|
|
74
73
|
* Please avoid commands that may produce a very large amount of output.
|
|
75
74
|
* Please run long lived commands in the background, e.g. 'Start-Job' or start a server with Start-Process.
|
|
76
|
-
|
|
77
|
-
# The bare local filesystem shadows the host's sandboxed provider only for this
|
|
78
|
-
# preset. The editor shares that realm and requires absolute paths.
|
|
79
|
-
- id: filesystem
|
|
80
|
-
name: cordis:group
|
|
81
|
-
group: true
|
|
82
|
-
isolate:
|
|
83
|
-
fs: true
|
|
84
|
-
config:
|
|
85
|
-
- id: fs-local
|
|
86
|
-
name: '@deepseek-ai/dsh-fs-local'
|
|
87
|
-
config:
|
|
88
|
-
cwd: !!js process.env.DSH_CWD ?? process.cwd()
|
|
89
|
-
|
|
90
|
-
- id: str-replace-editor
|
|
91
|
-
name: '@deepseek-ai/dsh-tool-str-replace-editor'
|
|
92
|
-
config:
|
|
93
|
-
maxOutputChars: 16000
|
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.1",
|
|
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.
|
|
3
|
+
"version": "0.13.1",
|
|
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
|
|
@@ -224,11 +250,18 @@ function pickComposition(base, persona, available) {
|
|
|
224
250
|
}
|
|
225
251
|
|
|
226
252
|
/** Startup decision for an existing unmodified tree: 'refresh' or 'idle'. */
|
|
227
|
-
function syncDecision({ state, marker, version, sourceHashes, base = 'code', persona = 'text' }) {
|
|
253
|
+
function syncDecision({ state, marker, version, sourceHashes, base = 'code', persona = 'text', present = false }) {
|
|
228
254
|
if (state !== 'unmodified' || !marker) return 'refresh'
|
|
229
255
|
if (marker.version !== version) return 'refresh'
|
|
230
256
|
if (marker.base !== base) return 'refresh'
|
|
231
257
|
if ((marker.persona ?? 'text') !== persona) return 'refresh'
|
|
258
|
+
// Host-capability flip: @deepseek-ai/dsh-tool-present first shipped with dsh
|
|
259
|
+
// 0.1.5-alpha.2. A preset composed with the row on a host that lacks the
|
|
260
|
+
// package REJECTS THE WHOLE MOUNT (mount.ts: a row whose module failed to
|
|
261
|
+
// import already rejects the mount), so the row is injected only when the
|
|
262
|
+
// host resolves it — and a host upgrade past that point must re-materialize
|
|
263
|
+
// to gain it (same marker-dimension pattern as persona).
|
|
264
|
+
if ((marker.present ?? false) !== present) return 'refresh'
|
|
232
265
|
const recorded = {}
|
|
233
266
|
for (const k of Object.keys(marker.files)) if (k.startsWith('skills/')) recorded[k] = marker.files[k]
|
|
234
267
|
if (sourceHashes === null) return Object.keys(recorded).length === 0 ? 'idle' : 'refresh'
|
|
@@ -241,14 +274,56 @@ function syncDecision({ state, marker, version, sourceHashes, base = 'code', per
|
|
|
241
274
|
|
|
242
275
|
// ── materialization ─────────────────────────────────────────────────────────
|
|
243
276
|
|
|
277
|
+
/*
|
|
278
|
+
* Conditional present-row injection (v0.13.0, dsh 0.1.5-alpha.2 sync). The
|
|
279
|
+
* official ptc/standard/cordis compositions appended `- id: present / name:
|
|
280
|
+
* '@deepseek-ai/dsh-tool-present'` (immutable file-delivery download cards).
|
|
281
|
+
* The row is NOT committed into the ptc-era twin files: a host older than
|
|
282
|
+
* 0.1.5-alpha.2 lacks the package, and a composition row that fails to
|
|
283
|
+
* import rejects the WHOLE preset mount. Instead the materializer probes the
|
|
284
|
+
* host (hostHasToolPresent) and splices the row in as PLAIN TEXT — anchor
|
|
285
|
+
* string surgery only, never a YAML round-trip, so !!js literals survive.
|
|
286
|
+
* Placement mirrors the official compositions: right after the
|
|
287
|
+
* tool-presentation block when the composition has one (all ptc-derived
|
|
288
|
+
* twins), otherwise appended at the tail (cordis/standard twins). Only
|
|
289
|
+
* `.ptc.` files are ever touched: code-era (<= 0.1.1) snapshots and the
|
|
290
|
+
* minimal variants are frozen history (official minimal never gained the
|
|
291
|
+
* row — it is the single-tool preset).
|
|
292
|
+
*/
|
|
293
|
+
const PRESENT_ROW = "\n- id: present\n name: '@deepseek-ai/dsh-tool-present'\n"
|
|
294
|
+
const PRESENT_ANCHOR = " name: '@deepseek-ai/dsh-agent-tool-presentation'\n config:\n mode: ptc\n"
|
|
295
|
+
|
|
296
|
+
function injectPresentRow(text) {
|
|
297
|
+
if (text.includes("'@deepseek-ai/dsh-tool-present'")) return text
|
|
298
|
+
const at = text.indexOf(PRESENT_ANCHOR)
|
|
299
|
+
if (at !== -1) return text.slice(0, at + PRESENT_ANCHOR.length) + PRESENT_ROW + text.slice(at + PRESENT_ANCHOR.length)
|
|
300
|
+
return text.endsWith('\n') ? text + PRESENT_ROW : text + '\n' + PRESENT_ROW
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
let toolPresentCache
|
|
304
|
+
/** Probe whether THIS host can resolve the present package (cached per boot). */
|
|
305
|
+
async function hostHasToolPresent() {
|
|
306
|
+
if (toolPresentCache !== undefined) return toolPresentCache
|
|
307
|
+
try {
|
|
308
|
+
const { createRequire } = await import('node:module')
|
|
309
|
+
createRequire(import.meta.url).resolve('@deepseek-ai/dsh-tool-present')
|
|
310
|
+
toolPresentCache = true
|
|
311
|
+
} catch {
|
|
312
|
+
toolPresentCache = false
|
|
313
|
+
}
|
|
314
|
+
return toolPresentCache
|
|
315
|
+
}
|
|
316
|
+
|
|
244
317
|
/** Write one preset directory from scratch. Returns 'ok' or 'no-skills-source'. */
|
|
245
|
-
function materialize({ target, presetId, skillsSource, version, base = 'code', persona = 'text' }) {
|
|
318
|
+
function materialize({ target, presetId, skillsSource, version, base = 'code', persona = 'text', present = false }) {
|
|
246
319
|
rmSync(target, { recursive: true, force: true })
|
|
247
320
|
mkdirSync(target, { recursive: true })
|
|
248
321
|
|
|
249
322
|
const available = readdirSync(join(pkgDir, 'assets', presetId)).filter((f) => f.endsWith('.yml'))
|
|
250
323
|
const compositionFile = pickComposition(base, persona, available)
|
|
251
|
-
|
|
324
|
+
let composition = readFileSync(join(pkgDir, 'assets', presetId, compositionFile), 'utf8')
|
|
325
|
+
if (present && compositionFile.includes('.ptc.')) composition = injectPresentRow(composition)
|
|
326
|
+
writeFileSync(join(target, 'agent.cordis.yml'), composition)
|
|
252
327
|
writeFileSync(join(target, 'preset.yml'), readFileSync(join(pkgDir, 'assets', presetId, 'preset.yml')))
|
|
253
328
|
|
|
254
329
|
let skills = 'none'
|
|
@@ -262,7 +337,7 @@ function materialize({ target, presetId, skillsSource, version, base = 'code', p
|
|
|
262
337
|
}
|
|
263
338
|
}
|
|
264
339
|
|
|
265
|
-
const marker = { managedBy: MANAGED_BY, version, presetId, base, persona, files: hashTree(target) }
|
|
340
|
+
const marker = { managedBy: MANAGED_BY, version, presetId, base, persona, present, files: hashTree(target) }
|
|
266
341
|
writeFileSync(join(target, MARKER_FILE), JSON.stringify(marker, null, 2) + '\n')
|
|
267
342
|
return skills
|
|
268
343
|
}
|
|
@@ -871,6 +946,11 @@ export async function apply(ctx, config = {}) {
|
|
|
871
946
|
const skillsSource = await findSkillsSource(ctx.agentPresets)
|
|
872
947
|
const base = await detectBase(ctx.agentPresets)
|
|
873
948
|
const persona = await detectPersonaEra(ctx.agentPresets)
|
|
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())
|
|
874
954
|
const userRootPath = userRoot.path
|
|
875
955
|
purgeOrphans(userRootPath, presetIds)
|
|
876
956
|
|
|
@@ -900,12 +980,12 @@ export async function apply(ctx, config = {}) {
|
|
|
900
980
|
|
|
901
981
|
const sourceHashes = presetId === 'cordis-gitbash' ? skillsHashes(skillsSource) : null
|
|
902
982
|
const marker = readMarker(target)
|
|
903
|
-
if (state === 'unmodified' && syncDecision({ state, marker, version, sourceHashes, base, persona }) === 'idle') {
|
|
983
|
+
if (state === 'unmodified' && syncDecision({ state, marker, version, sourceHashes, base, persona, present }) === 'idle') {
|
|
904
984
|
ctx.logger?.('gitbash-shell')?.debug?.( `preset '${presetId}' up to date (v${version}, ${base}-era${persona === 'split' ? ', persona-split' : ''}) — idle`)
|
|
905
985
|
continue
|
|
906
986
|
}
|
|
907
987
|
|
|
908
|
-
const skills = materialize({ target, presetId, skillsSource, version, base, persona })
|
|
988
|
+
const skills = materialize({ target, presetId, skillsSource, version, base, persona, present })
|
|
909
989
|
const verb = state === 'absent' ? 'materialized' : 'refreshed'
|
|
910
990
|
console.log(
|
|
911
991
|
`${TAG} ${verb} preset '${presetId}' into ${userRootPath} (v${version}, ${base}-era composition${persona === 'split' ? ', persona-split' : ''})` +
|
|
@@ -915,4 +995,4 @@ export async function apply(ctx, config = {}) {
|
|
|
915
995
|
}
|
|
916
996
|
|
|
917
997
|
// Test surface: pure helpers, no Cordis context required.
|
|
918
|
-
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 }
|
|
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 }
|