dsh-gitbash-shell 0.7.1 → 0.8.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.
package/dsh.plugin.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "id": "dsh-external/dsh-gitbash-shell",
3
- "version": "0.7.1",
3
+ "version": "0.8.0",
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.7.1",
3
+ "version": "0.8.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
@@ -290,6 +290,50 @@ export function installRegisterShim(reg) {
290
290
  }
291
291
  }
292
292
 
293
+ // ── MSYS drive-root path translation (Windows, EVERY tool dispatch) ────────
294
+ //
295
+ // The directive below tells the model to use POSIX-style MSYS paths (/c/...)
296
+ // for EVERY tool. Bash digests those natively, but the Node-backed file tools
297
+ // resolve an MSYS root against the current drive (/c/Users -> C:/c/Users), so a
298
+ // global tools/execute wrapper rewrites the path-bearing ARGUMENT FIELDS (by
299
+ // field NAME, not by tool name — dynamic tools using the standard field names
300
+ // are covered too) into the drive-letter form the host accepts. The bash
301
+ // command field is deliberately untouched: MSYS roots are Git Bash native
302
+ // there. Defensive by design: the waterfall hands the same mutable exec object
303
+ // to the tool body, but if a future registry freezes it the write throws, is
304
+ // swallowed, and the call proceeds with the model original arguments (the
305
+ // directive still stands).
306
+
307
+ const MSYS_DRIVE_ROOT = /^\/([a-z])\/(.*)$/i
308
+ const TRANSLATABLE_PATH_FIELDS = new Set(['file_path', 'path', 'workdir'])
309
+
310
+ /** '/c/Users/x' -> 'C:/Users/x'; any other shape returns the input unchanged. */
311
+ export function translateMsysPath(value) {
312
+ if (typeof value !== 'string') return value
313
+ const match = MSYS_DRIVE_ROOT.exec(value)
314
+ if (!match) return value
315
+ return match[1].toUpperCase() + ':/' + match[2]
316
+ }
317
+
318
+ /**
319
+ * Rewrite MSYS drive roots in an arguments object path fields, in place.
320
+ * @returns {boolean} whether any field changed (false also when args is not
321
+ * an object — the caller treats that as nothing to do).
322
+ */
323
+ export function translatePathArguments(args) {
324
+ if (!args || typeof args !== 'object') return false
325
+ let changed = false
326
+ for (const key of Object.keys(args)) {
327
+ if (!TRANSLATABLE_PATH_FIELDS.has(key)) continue
328
+ const value = args[key]
329
+ if (typeof value !== 'string') continue
330
+ const translated = translateMsysPath(value)
331
+ if (translated === value) continue
332
+ try { args[key] = translated; changed = true } catch { /* frozen: degrade */ }
333
+ }
334
+ return changed
335
+ }
336
+
293
337
  // ── dsh-better-sidebar shell cooperation ───────────────────────────────────
294
338
  //
295
339
  // dsh-better-sidebar (v0.15.2+) resolves its terminal shell PER OPEN: a
@@ -428,15 +472,25 @@ export async function apply(ctx, config = {}) {
428
472
 
429
473
  // The shim rides along every mount of this plugin and degrades silently if
430
474
  // the upstream shape differs from what we verified.
431
- let shim = { installed: false, restore: () => {} }
475
+ //
476
+ // INSTALL TIMING (aligned with dsh-ptc-cordis-preset 0.6.3): the host
477
+ // runner row activates AFTER this plugin's row, so a one-shot
478
+ // installRegisterShim(ctx.get('cordisInspect')) sampled a service that was
479
+ // not provided yet and silently installed nothing — every later mount of a
480
+ // second cordis-mode preset (e.g. 'cordis · Git Bash' beside the built-in
481
+ // Creation mode) kept dying with 'Host Cordis inspect provider "Service"
482
+ // is already registered' for the rest of the process. ctx.inject schedules
483
+ // the install for the moment the service actually appears — independent of
484
+ // row activation order, and still a no-op in a runner-less deployment.
432
485
  try {
433
- shim = installRegisterShim(ctx.get('cordisInspect'))
434
- } catch {
435
- /* never block startup */
436
- }
437
- if (shim.installed) {
438
- ctx.effect(() => () => shim.restore(), 'dsh-gitbash-shell: inspect-registry shim')
439
- console.log(`${TAG} inspect-registry compatibility shim active (multiple cordis-mode sessions supported)`)
486
+ ctx.inject(['cordisInspect'], (inspectCtx) => {
487
+ const shim = installRegisterShim(inspectCtx.get('cordisInspect'))
488
+ if (!shim.installed) return
489
+ inspectCtx.effect(() => () => shim.restore(), 'dsh-gitbash-shell: inspect-registry shim')
490
+ console.log(`${TAG} inspect-registry compatibility shim active (multiple cordis-mode sessions supported)`)
491
+ })
492
+ } catch (error) {
493
+ console.log(`${TAG} inspect-registry shim wiring failed: ${error?.message ?? error}`)
440
494
  }
441
495
 
442
496
  // ── cooperation capability ────────────────────────────────────────────────
@@ -448,14 +502,35 @@ export async function apply(ctx, config = {}) {
448
502
  const disposeGitBash = ctx.provide('gitBash', gitBashCapability)
449
503
  ctx.effect(() => disposeGitBash, 'dsh-gitbash-shell: gitBash capability')
450
504
 
451
- // ── POSIX path directive (Windows Git Bash, EVERY session) ─────────────
452
- // The host shell is Git for Windows bash for every mode/preset on this
453
- // machine: drive-letter paths (C:/..., C:\...) are a Windows-shell idiom
454
- // that Git Bash only sometimes tolerates, /c/... is the unambiguous form.
455
- // One global runtime-context directive (same channel dsh-agent-lang uses;
505
+ // ── MSYS path translation on every tool dispatch (Windows only) ─────────
506
+ // Covers every preset and mode: the wrapper sits on the global
507
+ // tools/execute waterfall, through which model-direct calls, PTC run_code
508
+ // sub-dispatches, and dynamic-tool calls all pass.
509
+ if (process.platform === 'win32') {
510
+ try {
511
+ ctx.on('tools/execute', (exec, next) => {
512
+ try {
513
+ if (exec && exec.arguments && typeof exec.arguments === 'object') {
514
+ translatePathArguments(exec.arguments)
515
+ }
516
+ } catch { /* never block a call on translation */ }
517
+ return next()
518
+ })
519
+ console.log(TAG + ' MSYS drive-root translation active on tool dispatch')
520
+ } catch (error) {
521
+ console.log(TAG + ' tools/execute wiring failed: ' + (error?.message ?? error))
522
+ }
523
+ }
524
+
525
+ // ── Unified POSIX path directive (Windows Git Bash, EVERY session) ─────
526
+ // ONE path style for every tool: MSYS drive roots (/c/Users/...). Bash
527
+ // digests them natively; the file tools receive the drive-letter form
528
+ // through the translation wrapper above, so the model never has to switch
529
+ // dialects. The directive also pins the rewrite rules that neutralize the
530
+ // Windows-form facts the harness injects elsewhere (backslash cwd strings,
531
+ // tool results printing drive-letter paths). Same channel as dsh-agent-lang;
456
532
  // order 126 sits after the official CONTEXT_ORDERS 110/115/120 and beside
457
- // the 125 free slot) so no preset/persona has to carry it. Non-Windows
458
- // mounts inject nothing.
533
+ // the 125 free slot. Non-Windows mounts inject nothing.
459
534
  if (process.platform === 'win32') {
460
535
  try {
461
536
  ctx.inject(['systemPrompt'], (pctx) => {
@@ -463,9 +538,9 @@ export async function apply(ctx, config = {}) {
463
538
  pctx.effect(() => pctx.systemPrompt.context({
464
539
  name: 'gitbash-shell:posix-paths',
465
540
  order: 126,
466
- text: 'The working shell is Git for Windows bash: use POSIX-style paths only — drive roots are /c/, /d/, ... (/c/Users/..., /c/Program Files/...). Windows drive-letter path forms are not accepted.',
541
+ text: 'The host is Windows and the working shell is Git for Windows bash: use POSIX-style paths with MSYS drive roots everywhere — /c/Users/..., /e/project/... Every tool accepts this form: bash commands and the workdir parameter, and the file tools (read, write, edit, read_image, glob, grep) file_path/path arguments — MSYS roots are translated for them automatically, so never switch to a Windows form on their behalf. Never emit Windows drive-letter paths (C:\Users or C:/Users): when instructions, facts, or context show one, rewrite it to the POSIX form before use; when a tool result prints a Windows path, use its POSIX form (/c/...) in later calls.',
467
542
  }), 'dsh-gitbash-shell: posix-path context')
468
- console.log(TAG + ' POSIX-path directive context active (win32)')
543
+ console.log(TAG + ' unified POSIX-path directive context active (win32)')
469
544
  } catch (error) {
470
545
  console.log(TAG + ' context registration failed: ' + (error?.message ?? error))
471
546
  }
@@ -543,4 +618,4 @@ export async function apply(ctx, config = {}) {
543
618
  }
544
619
 
545
620
  // Test surface: pure helpers, no Cordis context required.
546
- export const _internal = { PRESET_IDS, MARKER_FILE, classify, materialize, cleanupOnDispose, firstUserRoot, hashTree, skillsHashes, syncDecision, installRegisterShim, baseForRoster, detectBase, pickComposition }
621
+ export const _internal = { PRESET_IDS, translateMsysPath, translatePathArguments, MARKER_FILE, classify, materialize, cleanupOnDispose, firstUserRoot, hashTree, skillsHashes, syncDecision, installRegisterShim, baseForRoster, detectBase, pickComposition }