dsh-gitbash-shell 0.12.0 → 0.13.0

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, two-tool coding-agent composition.
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 composes only
15
- # the persistent shell (Git for Windows bash; bash on POSIX) and
16
- # `str_replace_editor`. Context compaction is absent.
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
- * You don't have access to the internet via this tool.
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, two-tool coding-agent composition.
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 composes only
10
- # the persistent shell (Git for Windows bash; bash on POSIX) and
11
- # `str_replace_editor`. Context compaction is absent.
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
- * You don't have access to the internet via this tool.
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
@@ -1,3 +1,3 @@
1
1
  name: 极简模式 · Git Bash
2
- description: 仅提供持久 bash 与 str_replace_editor 的双工具编码 Agent。(Shell 使用 Git Bash)
2
+ description: 仅提供持久 shell 的单工具编码 Agent。(Shell 使用 Git Bash)
3
3
  order: 3
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-gitbash-shell",
3
- "version": "0.12.0",
3
+ "version": "0.13.0",
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": {
package/src/index.js CHANGED
@@ -224,11 +224,18 @@ function pickComposition(base, persona, available) {
224
224
  }
225
225
 
226
226
  /** Startup decision for an existing unmodified tree: 'refresh' or 'idle'. */
227
- function syncDecision({ state, marker, version, sourceHashes, base = 'code', persona = 'text' }) {
227
+ function syncDecision({ state, marker, version, sourceHashes, base = 'code', persona = 'text', present = false }) {
228
228
  if (state !== 'unmodified' || !marker) return 'refresh'
229
229
  if (marker.version !== version) return 'refresh'
230
230
  if (marker.base !== base) return 'refresh'
231
231
  if ((marker.persona ?? 'text') !== persona) return 'refresh'
232
+ // Host-capability flip: @deepseek-ai/dsh-tool-present first shipped with dsh
233
+ // 0.1.5-alpha.2. A preset composed with the row on a host that lacks the
234
+ // package REJECTS THE WHOLE MOUNT (mount.ts: a row whose module failed to
235
+ // import already rejects the mount), so the row is injected only when the
236
+ // host resolves it — and a host upgrade past that point must re-materialize
237
+ // to gain it (same marker-dimension pattern as persona).
238
+ if ((marker.present ?? false) !== present) return 'refresh'
232
239
  const recorded = {}
233
240
  for (const k of Object.keys(marker.files)) if (k.startsWith('skills/')) recorded[k] = marker.files[k]
234
241
  if (sourceHashes === null) return Object.keys(recorded).length === 0 ? 'idle' : 'refresh'
@@ -241,14 +248,56 @@ function syncDecision({ state, marker, version, sourceHashes, base = 'code', per
241
248
 
242
249
  // ── materialization ─────────────────────────────────────────────────────────
243
250
 
251
+ /*
252
+ * Conditional present-row injection (v0.13.0, dsh 0.1.5-alpha.2 sync). The
253
+ * official ptc/standard/cordis compositions appended `- id: present / name:
254
+ * '@deepseek-ai/dsh-tool-present'` (immutable file-delivery download cards).
255
+ * The row is NOT committed into the ptc-era twin files: a host older than
256
+ * 0.1.5-alpha.2 lacks the package, and a composition row that fails to
257
+ * import rejects the WHOLE preset mount. Instead the materializer probes the
258
+ * host (hostHasToolPresent) and splices the row in as PLAIN TEXT — anchor
259
+ * string surgery only, never a YAML round-trip, so !!js literals survive.
260
+ * Placement mirrors the official compositions: right after the
261
+ * tool-presentation block when the composition has one (all ptc-derived
262
+ * twins), otherwise appended at the tail (cordis/standard twins). Only
263
+ * `.ptc.` files are ever touched: code-era (<= 0.1.1) snapshots and the
264
+ * minimal variants are frozen history (official minimal never gained the
265
+ * row — it is the single-tool preset).
266
+ */
267
+ const PRESENT_ROW = "\n- id: present\n name: '@deepseek-ai/dsh-tool-present'\n"
268
+ const PRESENT_ANCHOR = " name: '@deepseek-ai/dsh-agent-tool-presentation'\n config:\n mode: ptc\n"
269
+
270
+ function injectPresentRow(text) {
271
+ if (text.includes("'@deepseek-ai/dsh-tool-present'")) return text
272
+ const at = text.indexOf(PRESENT_ANCHOR)
273
+ if (at !== -1) return text.slice(0, at + PRESENT_ANCHOR.length) + PRESENT_ROW + text.slice(at + PRESENT_ANCHOR.length)
274
+ return text.endsWith('\n') ? text + PRESENT_ROW : text + '\n' + PRESENT_ROW
275
+ }
276
+
277
+ let toolPresentCache
278
+ /** Probe whether THIS host can resolve the present package (cached per boot). */
279
+ async function hostHasToolPresent() {
280
+ if (toolPresentCache !== undefined) return toolPresentCache
281
+ try {
282
+ const { createRequire } = await import('node:module')
283
+ createRequire(import.meta.url).resolve('@deepseek-ai/dsh-tool-present')
284
+ toolPresentCache = true
285
+ } catch {
286
+ toolPresentCache = false
287
+ }
288
+ return toolPresentCache
289
+ }
290
+
244
291
  /** Write one preset directory from scratch. Returns 'ok' or 'no-skills-source'. */
245
- function materialize({ target, presetId, skillsSource, version, base = 'code', persona = 'text' }) {
292
+ function materialize({ target, presetId, skillsSource, version, base = 'code', persona = 'text', present = false }) {
246
293
  rmSync(target, { recursive: true, force: true })
247
294
  mkdirSync(target, { recursive: true })
248
295
 
249
296
  const available = readdirSync(join(pkgDir, 'assets', presetId)).filter((f) => f.endsWith('.yml'))
250
297
  const compositionFile = pickComposition(base, persona, available)
251
- writeFileSync(join(target, 'agent.cordis.yml'), readFileSync(join(pkgDir, 'assets', presetId, compositionFile)))
298
+ let composition = readFileSync(join(pkgDir, 'assets', presetId, compositionFile), 'utf8')
299
+ if (present && compositionFile.includes('.ptc.')) composition = injectPresentRow(composition)
300
+ writeFileSync(join(target, 'agent.cordis.yml'), composition)
252
301
  writeFileSync(join(target, 'preset.yml'), readFileSync(join(pkgDir, 'assets', presetId, 'preset.yml')))
253
302
 
254
303
  let skills = 'none'
@@ -262,7 +311,7 @@ function materialize({ target, presetId, skillsSource, version, base = 'code', p
262
311
  }
263
312
  }
264
313
 
265
- const marker = { managedBy: MANAGED_BY, version, presetId, base, persona, files: hashTree(target) }
314
+ const marker = { managedBy: MANAGED_BY, version, presetId, base, persona, present, files: hashTree(target) }
266
315
  writeFileSync(join(target, MARKER_FILE), JSON.stringify(marker, null, 2) + '\n')
267
316
  return skills
268
317
  }
@@ -871,6 +920,7 @@ export async function apply(ctx, config = {}) {
871
920
  const skillsSource = await findSkillsSource(ctx.agentPresets)
872
921
  const base = await detectBase(ctx.agentPresets)
873
922
  const persona = await detectPersonaEra(ctx.agentPresets)
923
+ const present = await hostHasToolPresent()
874
924
  const userRootPath = userRoot.path
875
925
  purgeOrphans(userRootPath, presetIds)
876
926
 
@@ -900,12 +950,12 @@ export async function apply(ctx, config = {}) {
900
950
 
901
951
  const sourceHashes = presetId === 'cordis-gitbash' ? skillsHashes(skillsSource) : null
902
952
  const marker = readMarker(target)
903
- if (state === 'unmodified' && syncDecision({ state, marker, version, sourceHashes, base, persona }) === 'idle') {
953
+ if (state === 'unmodified' && syncDecision({ state, marker, version, sourceHashes, base, persona, present }) === 'idle') {
904
954
  ctx.logger?.('gitbash-shell')?.debug?.( `preset '${presetId}' up to date (v${version}, ${base}-era${persona === 'split' ? ', persona-split' : ''}) — idle`)
905
955
  continue
906
956
  }
907
957
 
908
- const skills = materialize({ target, presetId, skillsSource, version, base, persona })
958
+ const skills = materialize({ target, presetId, skillsSource, version, base, persona, present })
909
959
  const verb = state === 'absent' ? 'materialized' : 'refreshed'
910
960
  console.log(
911
961
  `${TAG} ${verb} preset '${presetId}' into ${userRootPath} (v${version}, ${base}-era composition${persona === 'split' ? ', persona-split' : ''})` +
@@ -915,4 +965,4 @@ export async function apply(ctx, config = {}) {
915
965
  }
916
966
 
917
967
  // 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 }
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 }