dsh-gitbash-shell 0.37.0 → 0.38.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.
package/CHANGELOG.md CHANGED
@@ -3,6 +3,27 @@
3
3
  > 倒序排列,新版本条目在最上面。条目格式:`## vX.Y.Z — YYYY-MM-DD` + 类型(feat / fix / docs / chore)+ 要点 + 相关链接。
4
4
  > 纪律见 AGENTS.md「变更记录纪律」:发版前先更新本文件并随版本提交;事故复盘、复现与真机验证记录也记在这里。
5
5
 
6
+ ## v0.38.1 — 2026-10-13
7
+
8
+ **类型**:fix(bash 补位在桌面版宿主解析不到官方包;真机反复确认的最后一个开放问题)。
9
+
10
+ - **根因(无日志下的代码级定位,待真机确认)**:bash 激活的解析通道用的是裸 `createRequire(ctx.baseUrl).resolve('@deepseek-ai/dsh-tool-bash')`——**桌面版宿主把官方包打进 `app.asar`,从插件的 profile 布局裸解析必然失败**(返回空 → 日志 "not resolvable" → bash 永缺)。这也解释了为何同一进程里 deny/pwsh7/gb_* 全部正常(插件自带代码,不依赖该解析)而唯独 bash 缺。
11
+ - **修复:解析通道改为宿主 loader 优先**——`ctx.loader.internal.import(name, ctx.baseUrl, {})`,与宿主挂载行包**完全相同的调用**(`vendor/loader/src/config/tree.ts:122`),走宿主自己的 resolve 钩子(可达 asar 内部);失败才退回裸 createRequire(旧通道,非桌面布局保底)。两通道都失败才如实记日志。
12
+ - `resolveToolBashEntry` 返回形状从 href 字符串改为 `{ load }` 惰性加载器;`activateOfficialBash` 接收 loader 对象;调用点与缓存变量同步更名。
13
+ - **冒烟**:118 项全绿;新增「bash resolution tries the HOST loader before a plain require」(断言通道顺序、官方包名、baseUrl 透传、惰性加载)。
14
+ - **待真机复验**:升级重启后官方模式新建会话,工具面应出现 `bash`;日志应出现 `official bash tool activated for this agent`。
15
+
16
+ ## v0.38.0 — 2026-10-13
17
+
18
+ **类型**:feat(设置卡折叠分区;用户反馈「开关堆一列不知道主题」)。
19
+
20
+ - **七分区全部改为可折叠卡片**:v0.36.0 只加了标题文字,视觉上仍是一列开关。现在每个分区是官方 `DisclosureRow`(seed `ui-primitives` 组件,client bundle 的 require 白名单内)**折叠卡**——默认全部收起,页面只剩七行分区标题(模式 / 行内工具 / 路径方言 / 执行器 / 终端 / 终端工具 / 插件联动),点哪行展开哪区,找设置 = 先认主题再点开(用户原话:「内部可以折叠,这样我找的时候就只需要去展开我大概知道的某个设置主题,然后去找更细节的按钮」)。
21
+ - **视觉卡片化**:每分区带边框 + 圆角(`.gb-fold`),分区边界一眼可辨;不再依赖上一分区底部的分隔线。
22
+ - **新增 `sec.mode` 分区标题 × 21 语言**(模式区此前借用变体开关的长文案做标题)。
23
+ - **退化路径**:极简宿主没有 `DisclosureRow` 导出时,分区退化为静态标题+内容(v0.36.0 形态),卡片永不白屏。
24
+ - 功能面零变化:所有开关的字段名、写入通道、默认值原样。
25
+ - **冒烟**:117 项全绿;七分区断言改锁 fold 形态(官方 DisclosureRow 接线、默认收起、退化路径)。
26
+
6
27
  ## v0.37.0 — 2026-10-13
7
28
 
8
29
  **类型**:feat(用户拍板的命名与开关重构;真机反馈驱动)。
package/dsh.plugin.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "id": "dsh-external/dsh-gitbash-shell",
3
- "version": "0.37.0",
3
+ "version": "0.38.1",
4
4
  "main": "./src/index.js",
5
5
  "description": "Windows 全模式 Git Bash:用 Git for Windows bash 替换 PowerShell 执行器;官方四个模式经行内工具补位直接获得 Git Bash(v0.35.0,默认),四个 *·Git Bash 变体 preset 可开关;附带 gitbash_pwsh(系统 PowerShell 7)与 gb_* FastCtx 文件工具,检测到 dsh-ops 自动让位。联动:dsh-ptc-cordis-preset(PTC 创造模式带 Git Bash 行且可去重)+ dsh-better-sidebar(终端标签自动切 Git Bash)。",
6
6
  "engines": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-gitbash-shell",
3
- "version": "0.37.0",
3
+ "version": "0.38.1",
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/client.js CHANGED
@@ -76,6 +76,7 @@ window.__ModuleLoader__.load({
76
76
  "switch.off": "停用",
77
77
  "error": "写入失败",
78
78
  "hint": "启用后:所有工具(bash 命令与 workdir、read/write/edit/read_image/glob/grep 与 present 的路径参数)统一使用 MSYS 盘根 POSIX 路径(/c/Users/...);bash 的原生习惯——~ 家目录、/tmp 临时目录、/dev/null、/usr 等——在所有工具中同样有效(与 Git Bash 挂载表一致),路径参数由宿主自动翻译,模型无感。停用后恢复 dsh 原生行为(文件工具用 Windows 路径)。bash 始终是 Git Bash,不受此开关影响。",
79
+ "sec.mode": "模式",
79
80
  "sec.inline": "行内工具",
80
81
  "sec.executor": "执行器",
81
82
  "sec.peer": "插件联动",
@@ -153,6 +154,7 @@ window.__ModuleLoader__.load({
153
154
  "switch.off": "Disable",
154
155
  "error": "write failed",
155
156
  "hint": "Enabled: every tool (bash commands and workdir, read/write/edit/read_image/glob/grep and present path arguments) uses MSYS drive-root POSIX paths (/c/Users/...); bash-native habits — the ~ home shorthand, /tmp, /dev/null, /usr — resolve in every tool exactly as bash itself resolves them, and the host translates the path fields automatically. Disabled restores dsh-native behavior (Windows paths for file tools). Bash is always Git Bash while the plugin is installed; this switch only governs the cross-tool path dialect.",
157
+ "sec.mode": "Mode",
156
158
  "sec.inline": "Inline tools",
157
159
  "sec.executor": "Executor",
158
160
  "sec.peer": "Plugin integrations",
@@ -240,6 +242,7 @@ window.__ModuleLoader__.load({
240
242
  "switch.off": "تعطيل",
241
243
  "error": "فشل الكتابة",
242
244
  "hint": "عند التفعيل: تستخدم كل الأدوات (أوامر bash و workdir، ومعاملات المسار في read/write/edit/read_image/glob/grep و present) مسارات POSIX من جذر قرص MSYS (/c/Users/...)؛ وعادات bash الأصلية — ~ للمجلد الرئيسي و /tmp و /dev/null و /usr — تعمل في كل أداة تمامًا كما تحلّها bash نفسها، ويتولّى المضيف ترجمة حقول المسار تلقائيًا. عند التعطيل يعود السلوك الأصلي لـ dsh (مسارات Windows لأدوات الملفات). يبقى bash دائمًا Git Bash ما دامت الإضافة مثبَّتة؛ هذا المفتاح لا يحكم سوى لهجة المسارات بين الأدوات.",
245
+ "sec.mode": "الوضع",
243
246
  "sec.inline": "الأدوات المضمنة",
244
247
  "sec.executor": "المنفّذ",
245
248
  "sec.peer": "تكامل الإضافات",
@@ -317,6 +320,7 @@ window.__ModuleLoader__.load({
317
320
  "switch.off": "Deaktivieren",
318
321
  "error": "Schreiben fehlgeschlagen",
319
322
  "hint": "Aktiviert: Alle Tools (bash-Befehle und workdir sowie Pfadargumente von read/write/edit/read_image/glob/grep und present) verwenden POSIX-Pfade ab der MSYS-Laufwerkswurzel (/c/Users/...); bash-eigene Gewohnheiten — ~ für das Home-Verzeichnis, /tmp, /dev/null, /usr — funktionieren in jedem Tool genau so, wie bash sie selbst auflöst, und der Host übersetzt die Pfadfelder automatisch. Deaktiviert stellt das dsh-native Verhalten wieder her (Windows-Pfade für Dateitools). Bash ist bei installiertem Plugin immer Git Bash; dieser Schalter steuert nur den Pfaddialekt zwischen den Tools.",
323
+ "sec.mode": "Modus",
320
324
  "sec.inline": "Inline-Werkzeuge",
321
325
  "sec.executor": "Executor",
322
326
  "sec.peer": "Plugin-Integrationen",
@@ -394,6 +398,7 @@ window.__ModuleLoader__.load({
394
398
  "switch.off": "Désactiver",
395
399
  "error": "échec de l'écriture",
396
400
  "hint": "Activé : tous les outils (commandes bash et workdir, arguments de chemin de read/write/edit/read_image/glob/grep et de present) utilisent des chemins POSIX à racine de lecteur MSYS (/c/Users/...) ; les habitudes natives de bash — ~ pour le dossier personnel, /tmp, /dev/null, /usr — fonctionnent dans chaque outil exactement comme bash les résout lui-même, et l'hôte traduit les champs de chemin automatiquement. Désactivé rétablit le comportement natif de dsh (chemins Windows pour les outils de fichiers). Bash reste toujours Git Bash tant que le plugin est installé ; ce commutateur ne régit que le dialecte de chemins entre outils.",
401
+ "sec.mode": "Mode",
397
402
  "sec.inline": "Outils en ligne",
398
403
  "sec.executor": "Exécuteur",
399
404
  "sec.peer": "Intégrations de plugins",
@@ -471,6 +476,7 @@ window.__ModuleLoader__.load({
471
476
  "switch.off": "अक्षम करें",
472
477
  "error": "लिखना विफल रहा",
473
478
  "hint": "सक्षम होने पर: सभी टूल (bash कमांड और workdir, तथा read/write/edit/read_image/glob/grep और present के पथ तर्क) MSYS ड्राइव-रूट POSIX पथ (/c/Users/...) का उपयोग करते हैं; bash की मूल आदतें — होम के लिए ~, /tmp, /dev/null, /usr — हर टूल में ठीक वैसे काम करती हैं जैसे bash स्वयं उन्हें हल करता है, और होस्ट पथ फ़ील्ड स्वतः अनुवादित करता है। अक्षम करने पर dsh का मूल व्यवहार बहाल होता है (फ़ाइल टूल के लिए Windows पथ)। जब तक प्लगइन इंस्टॉल है bash हमेशा Git Bash रहता है; यह स्विच केवल टूल के बीच पथ शैली नियंत्रित करता है।",
479
+ "sec.mode": "मोड",
474
480
  "sec.inline": "इनलाइन टूल्स",
475
481
  "sec.executor": "एक्ज़ीक्यूटर",
476
482
  "sec.peer": "प्लगइन एकीकरण",
@@ -548,6 +554,7 @@ window.__ModuleLoader__.load({
548
554
  "switch.off": "Nonaktifkan",
549
555
  "error": "gagal menulis",
550
556
  "hint": "Saat aktif: semua alat (perintah bash dan workdir, serta argumen path read/write/edit/read_image/glob/grep dan present) memakai path POSIX berakar drive MSYS (/c/Users/...); kebiasaan asli bash — ~ untuk direktori home, /tmp, /dev/null, /usr — bekerja di setiap alat persis seperti bash sendiri menyelesaikannya, dan host menerjemahkan bidang path secara otomatis. Saat nonaktif, perilaku asli dsh dipulihkan (path Windows untuk alat berkas). Bash selalu Git Bash selama plugin terpasang; sakelar ini hanya mengatur dialek path antaralat.",
557
+ "sec.mode": "Mode",
551
558
  "sec.inline": "Alat inline",
552
559
  "sec.executor": "Eksekutor",
553
560
  "sec.peer": "Integrasi plugin",
@@ -625,6 +632,7 @@ window.__ModuleLoader__.load({
625
632
  "switch.off": "Disattiva",
626
633
  "error": "scrittura non riuscita",
627
634
  "hint": "Attivato: tutti gli strumenti (comandi bash e workdir, argomenti di percorso di read/write/edit/read_image/glob/grep e di present) usano percorsi POSIX con radice di unità MSYS (/c/Users/...); le abitudini native di bash — ~ per la home, /tmp, /dev/null, /usr — funzionano in ogni strumento esattamente come le risolve bash stesso, e l'host traduce automaticamente i campi di percorso. Disattivato ripristina il comportamento nativo di dsh (percorsi Windows per gli strumenti per i file). Bash resta sempre Git Bash finché il plugin è installato; questo interruttore governa solo il dialetto dei percorsi tra gli strumenti.",
635
+ "sec.mode": "Modalità",
628
636
  "sec.inline": "Strumenti inline",
629
637
  "sec.executor": "Esecutore",
630
638
  "sec.peer": "Integrazioni plugin",
@@ -702,6 +710,7 @@ window.__ModuleLoader__.load({
702
710
  "switch.off": "無効にする",
703
711
  "error": "書き込みに失敗しました",
704
712
  "hint": "有効にすると、すべてのツール(bash コマンドと workdir、read/write/edit/read_image/glob/grep と present のパス引数)が MSYS ドライブルートの POSIX パス(/c/Users/...)を使います。bash のネイティブな習慣——ホームの ~、/tmp、/dev/null、/usr——も、bash 自身が解決するのとまったく同じようにすべてのツールで動作し、パスフィールドはホストが自動的に変換します。無効にすると dsh 本来の動作(ファイルツールは Windows パス)に戻ります。bash はプラグインがインストールされている限り常に Git Bash で、このスイッチの影響を受けません。",
713
+ "sec.mode": "モード",
705
714
  "sec.inline": "インラインツール",
706
715
  "sec.executor": "実行エンジン",
707
716
  "sec.peer": "プラグイン連携",
@@ -779,6 +788,7 @@ window.__ModuleLoader__.load({
779
788
  "switch.off": "사용 안 함",
780
789
  "error": "쓰기 실패",
781
790
  "hint": "켜면 모든 도구(bash 명령과 workdir, read/write/edit/read_image/glob/grep 및 present의 경로 인수)가 MSYS 드라이브 루트 POSIX 경로(/c/Users/...)를 사용합니다. bash 고유 습관——홈의 ~, /tmp, /dev/null, /usr——도 bash 자신이 해석하는 그대로 모든 도구에서 작동하며 호스트가 경로 필드를 자동 변환합니다. 끄면 dsh 기본 동작(파일 도구에 Windows 경로 사용)으로 돌아갑니다. 플러그인이 설치되어 있는 동안 bash는 항상 Git Bash이며 이 스위치의 영향을 받지 않습니다.",
791
+ "sec.mode": "모드",
782
792
  "sec.inline": "인라인 도구",
783
793
  "sec.executor": "실행기",
784
794
  "sec.peer": "플러그인 연동",
@@ -856,6 +866,7 @@ window.__ModuleLoader__.load({
856
866
  "switch.off": "Uitschakelen",
857
867
  "error": "schrijven mislukt",
858
868
  "hint": "Ingeschakeld: alle tools (bash-opdrachten en workdir, padargumenten van read/write/edit/read_image/glob/grep en present) gebruiken POSIX-paden vanaf de MSYS-schijfwortel (/c/Users/...); bash-eigen gewoonten — ~ voor de home-map, /tmp, /dev/null, /usr — werken in elke tool precies zoals bash ze zelf oplost, en de host vertaalt de padvelden automatisch. Uitgeschakeld herstelt het oorspronkelijke dsh-gedrag (Windows-paden voor bestandstools). Bash is altijd Git Bash zolang de plugin is geïnstalleerd; deze schakelaar bepaalt alleen het paddialect tussen de tools.",
869
+ "sec.mode": "Modus",
859
870
  "sec.inline": "Inline tools",
860
871
  "sec.executor": "Executor",
861
872
  "sec.peer": "Plug-in-integraties",
@@ -933,6 +944,7 @@ window.__ModuleLoader__.load({
933
944
  "switch.off": "Wyłącz",
934
945
  "error": "zapis nie powiódł się",
935
946
  "hint": "Po włączeniu: wszystkie narzędzia (polecenia bash i workdir, argumenty ścieżek w read/write/edit/read_image/glob/grep i w present) używają ścieżek POSIX od korzenia dysku MSYS (/c/Users/...); natywne nawyki basha — ~ dla katalogu domowego, /tmp, /dev/null, /usr — działają w każdym narzędziu dokładnie tak, jak rozwiązuje je sam bash, a host automatycznie tłumaczy pola ścieżek. Wyłączenie przywraca natywne zachowanie dsh (ścieżki Windows dla narzędzi plikowych). Bash jest zawsze Git Bash, dopóki wtyczka jest zainstalowana; ten przełącznik reguluje wyłącznie dialekt ścieżek między narzędziami.",
947
+ "sec.mode": "Tryb",
936
948
  "sec.inline": "Narzędzia wbudowane",
937
949
  "sec.executor": "Egzekutor",
938
950
  "sec.peer": "Integracje wtyczek",
@@ -1010,6 +1022,7 @@ window.__ModuleLoader__.load({
1010
1022
  "switch.off": "Desativar",
1011
1023
  "error": "falha ao gravar",
1012
1024
  "hint": "Ativada: todas as ferramentas (comandos bash e workdir, argumentos de caminho de read/write/edit/read_image/glob/grep e de present) usam caminhos POSIX a partir da raiz da unidade MSYS (/c/Users/...); os hábitos nativos do bash — ~ para a pasta pessoal, /tmp, /dev/null, /usr — funcionam em cada ferramenta exatamente como o próprio bash os resolve, e o host traduz os campos de caminho automaticamente. Desativada restaura o comportamento nativo do dsh (caminhos Windows para as ferramentas de arquivo). O bash é sempre Git Bash enquanto o plugin estiver instalado; este interruptor rege apenas o dialeto de caminhos entre ferramentas.",
1025
+ "sec.mode": "Modo",
1013
1026
  "sec.inline": "Ferramentas inline",
1014
1027
  "sec.executor": "Executor",
1015
1028
  "sec.peer": "Integrações de plugins",
@@ -1087,6 +1100,7 @@ window.__ModuleLoader__.load({
1087
1100
  "switch.off": "Выключить",
1088
1101
  "error": "не удалось записать",
1089
1102
  "hint": "Включено: все инструменты (команды bash и workdir, аргументы путей read/write/edit/read_image/glob/grep и present) используют POSIX-пути от корня диска MSYS (/c/Users/...); собственные привычки bash — ~ для домашнего каталога, /tmp, /dev/null, /usr — работают в каждом инструменте ровно так, как их разрешает сам bash, а хост автоматически преобразует поля путей. Выключение возвращает исходное поведение dsh (пути Windows для файловых инструментов). Пока плагин установлен, bash всегда остаётся Git Bash; этот переключатель управляет только диалектом путей между инструментами.",
1103
+ "sec.mode": "Режим",
1090
1104
  "sec.inline": "Встроенные инструменты",
1091
1105
  "sec.executor": "Исполнитель",
1092
1106
  "sec.peer": "Интеграции плагинов",
@@ -1164,6 +1178,7 @@ window.__ModuleLoader__.load({
1164
1178
  "switch.off": "Inaktivera",
1165
1179
  "error": "skrivning misslyckades",
1166
1180
  "hint": "Aktiverad: alla verktyg (bash-kommandon och workdir, sökvägsargument för read/write/edit/read_image/glob/grep och present) använder POSIX-sökvägar från MSYS-enhetsroten (/c/Users/...); bash egna vanor — ~ för hemkatalogen, /tmp, /dev/null, /usr — fungerar i varje verktyg exakt som bash själv löser dem, och värden översätter sökvägsfälten automatiskt. Inaktiverad återställer dsh:s ursprungliga beteende (Windows-sökvägar för filverktygen). Bash är alltid Git Bash så länge insticksprogrammet är installerat; den här växeln styr bara sökvägsdialekten mellan verktygen.",
1181
+ "sec.mode": "Läge",
1167
1182
  "sec.inline": "Inline-verktyg",
1168
1183
  "sec.executor": "Exekutor",
1169
1184
  "sec.peer": "Plugin-integrationer",
@@ -1241,6 +1256,7 @@ window.__ModuleLoader__.load({
1241
1256
  "switch.off": "ปิดใช้งาน",
1242
1257
  "error": "เขียนไม่สำเร็จ",
1243
1258
  "hint": "เมื่อเปิดใช้งาน: เครื่องมือทั้งหมด (คำสั่ง bash และ workdir รวมถึงอาร์กิวเมนต์พาธของ read/write/edit/read_image/glob/grep และ present) ใช้พาธ POSIX จากรากไดรฟ์ของ MSYS (/c/Users/...); พฤติกรรมดั้งเดิมของ bash — ~ สำหรับโฮม, /tmp, /dev/null, /usr — ทำงานในทุกเครื่องมือเหมือนที่ bash แก้เองพอดี และโฮสต์แปลฟิลด์พาธให้อัตโนมัติ เมื่อปิดใช้งานจะกลับสู่พฤติกรรมดั้งเดิมของ dsh (เครื่องมือจัดการไฟล์ใช้พาธ Windows) bash เป็น Git Bash เสมอเมื่อติดตั้งปลั๊กอินนี้ สวิตช์นี้ควบคุมเฉพาะรูปแบบพาธระหว่างเครื่องมือเท่านั้น",
1259
+ "sec.mode": "โหมด",
1244
1260
  "sec.inline": "เครื่องมือแบบ inline",
1245
1261
  "sec.executor": "ตัวรัน",
1246
1262
  "sec.peer": "การเชื่อมต่อปลั๊กอิน",
@@ -1318,6 +1334,7 @@ window.__ModuleLoader__.load({
1318
1334
  "switch.off": "Devre dışı bırak",
1319
1335
  "error": "yazma başarısız",
1320
1336
  "hint": "Etkinleştirildiğinde: tüm araçlar (bash komutları ve workdir ile read/write/edit/read_image/glob/grep ve present yol bağımsız değişkenleri) MSYS sürücü kökünden POSIX yolları (/c/Users/...) kullanır; bash'e özgü alışkanlıklar — ev için ~, /tmp, /dev/null, /usr — her araçta tam bash'in kendisinin çözdüğü gibi çalışır ve ana süreç yol alanlarını otomatik olarak çevirir. Devre dışı bırakıldığında dsh yerel davranışına döner (dosya araçları için Windows yolları). Eklenti kurulu olduğu sürece bash her zaman Git Bash olarak kalır; bu anahtar yalnızca araçlar arası yol lehçesini yönetir.",
1337
+ "sec.mode": "Mod",
1321
1338
  "sec.inline": "Satır içi araçlar",
1322
1339
  "sec.executor": "Yürütücü",
1323
1340
  "sec.peer": "Eklenti entegrasyonları",
@@ -1395,6 +1412,7 @@ window.__ModuleLoader__.load({
1395
1412
  "switch.off": "Tắt",
1396
1413
  "error": "ghi thất bại",
1397
1414
  "hint": "Khi bật: mọi công cụ (lệnh bash và workdir, tham số đường dẫn của read/write/edit/read_image/glob/grep và present) dùng đường dẫn POSIX từ gốc ổ đĩa MSYS (/c/Users/...); thói quen gốc của bash — ~ cho thư mục home, /tmp, /dev/null, /usr — hoạt động trong mọi công cụ đúng như chính bash giải quyết chúng, và máy chủ tự động chuyển đổi trường đường dẫn. Khi tắt, hành vi gốc của dsh được khôi phục (công cụ tệp dùng đường dẫn Windows). bash luôn là Git Bash khi plugin được cài đặt; công tắc này chỉ điều khiển phương ngữ đường dẫn giữa các công cụ.",
1415
+ "sec.mode": "Chế độ",
1398
1416
  "sec.inline": "Công cụ nội tuyến",
1399
1417
  "sec.executor": "Trình thực thi",
1400
1418
  "sec.peer": "Tích hợp plugin",
@@ -1472,6 +1490,7 @@ window.__ModuleLoader__.load({
1472
1490
  "switch.off": "停用",
1473
1491
  "error": "寫入失敗",
1474
1492
  "hint": "啟用後:所有工具(bash 指令同 workdir、read/write/edit/read_image/glob/grep 同 present 嘅路徑參數)統一使用 MSYS 磁碟根 POSIX 路徑(/c/Users/...);bash 原生習慣——~ 家目錄、/tmp、/dev/null、/usr——喺所有工具一樣有效(同 Git Bash 掛載表一致),路徑參數由宿主自動翻譯,模型無感。停用後回復 dsh 原生行為(檔案工具用 Windows 路徑)。bash 永遠係 Git Bash,唔受呢個開關影響。",
1493
+ "sec.mode": "模式",
1475
1494
  "sec.inline": "行內工具",
1476
1495
  "sec.executor": "執行器",
1477
1496
  "sec.peer": "外掛聯動",
@@ -1549,6 +1568,7 @@ window.__ModuleLoader__.load({
1549
1568
  "switch.off": "停用",
1550
1569
  "error": "寫入失敗",
1551
1570
  "hint": "啟用後:所有工具(bash 指令同 workdir、read/write/edit/read_image/glob/grep 同 present 嘅路徑參數)統一使用 MSYS 磁碟根 POSIX 路徑(/c/Users/...);bash 原生習慣——~ 家目錄、/tmp、/dev/null、/usr——喺所有工具一樣有效(同 Git Bash 掛載表一致),路徑參數由宿主自動翻譯,模型無感。停用後回復 dsh 原生行為(檔案工具用 Windows 路徑)。bash 永遠係 Git Bash,唔受呢個開關影響。",
1571
+ "sec.mode": "模式",
1552
1572
  "sec.inline": "行內工具",
1553
1573
  "sec.executor": "執行器",
1554
1574
  "sec.peer": "外掛聯動",
@@ -1626,6 +1646,7 @@ window.__ModuleLoader__.load({
1626
1646
  "switch.off": "停用",
1627
1647
  "error": "寫入失敗",
1628
1648
  "hint": "啟用後:所有工具(bash 指令與 workdir,以及 read/write/edit/read_image/glob/grep 與 present 的路徑參數)統一使用 MSYS 磁碟根 POSIX 路徑(/c/Users/...);bash 原生習慣——~ 家目錄、/tmp、/dev/null、/usr——在所有工具同樣有效(與 Git Bash 掛載表一致),路徑參數由宿主自動轉譯,模型無感。停用後恢復 dsh 原生行為(檔案工具使用 Windows 路徑)。bash 一律是 Git Bash,不受此開關影響。",
1649
+ "sec.mode": "模式",
1629
1650
  "sec.inline": "行內工具",
1630
1651
  "sec.executor": "執行器",
1631
1652
  "sec.peer": "外掛聯動",
@@ -1782,6 +1803,10 @@ window.__ModuleLoader__.load({
1782
1803
  ".gb-error{margin:0;font-size:12px;color:var(--dsw-alias-status-danger, #e5484d)}",
1783
1804
  ".gb-card{-webkit-backdrop-filter:var(--dsh-any-blur-card-panels,blur(12px) saturate(1.15));backdrop-filter:var(--dsh-any-blur-card-panels,blur(12px) saturate(1.15))}",
1784
1805
  ".gb-section+.gb-section{border-top:1px solid var(--dsw-alias-border-l2)}",
1806
+ /* v0.38.0 foldable sections: each theme is its own bordered card —
1807
+ seven header rows at a glance, switches only visible on expand. */
1808
+ ".gb-fold{border:1px solid var(--dsw-alias-border-l2);border-radius:10px;padding:4px 12px 12px;background:var(--dsw-alias-bg-layer-1,transparent)}",
1809
+ ".gb-fold .gb-stack{padding-top:10px}",
1785
1810
  /* Missing-Git-Bash popup (v0.28.0): a root-level modal, because the
1786
1811
  user may never be on the settings page when their shell dies. */
1787
1812
  ".gb-modalBackdrop{position:fixed;inset:0;z-index:2147483000;display:flex;align-items:center;justify-content:center;background:rgba(0,0,0,.45)}",
@@ -2009,6 +2034,23 @@ window.__ModuleLoader__.load({
2009
2034
  } catch (e) { /* keep empty draft */ }
2010
2035
  }, []);
2011
2036
 
2037
+ /* v0.38.0: the card's sections are FOLDERS. All seven stay collapsed
2038
+ by default — the user scans seven labelled header rows, expands the
2039
+ one theme they recognise, and finds the switch inside it (user
2040
+ request verbatim: "内部可以折叠,这样我找的时候就只需要去展开我大概
2041
+ 知道的某个设置主题"). State must sit before the early return. */
2042
+ var foldsState = useState({});
2043
+ var folds = foldsState[0];
2044
+ var setFolds = foldsState[1];
2045
+ function toggleFold(key) {
2046
+ setFolds(function (prev) {
2047
+ var next = {};
2048
+ for (var k in prev) next[k] = prev[k];
2049
+ next[key] = !prev[key];
2050
+ return next;
2051
+ });
2052
+ }
2053
+
2012
2054
  var scope = props.scope;
2013
2055
 
2014
2056
  var snap = { status: "unavailable" };
@@ -2058,6 +2100,33 @@ window.__ModuleLoader__.load({
2058
2100
 
2059
2101
  var Chevron = icon("IconChevronDownOutline14");
2060
2102
 
2103
+ /* v0.38.0: one FOLDABLE section. The header row is the OFFICIAL
2104
+ `DisclosureRow` from the seed ui-primitives package (required at
2105
+ the top of this file, same seam as every icon). All sections stay
2106
+ collapsed by default — the user scans seven labelled header rows
2107
+ and expands the one theme they recognise. A stripped-down host
2108
+ without the export degrades to the static title+stack card. */
2109
+ var DisclosureRowComponent = icon("DisclosureRow");
2110
+ function fold(key, titleKey) {
2111
+ var body = [];
2112
+ for (var i = 1; i < arguments.length; i++) body.push(arguments[i]);
2113
+ if (!DisclosureRowComponent || typeof DisclosureRowComponent !== "function") {
2114
+ return E("div", { className: "gb-section" },
2115
+ E("div", { className: "gb-sectionTitle" }, t(titleKey)),
2116
+ E("div", { className: "gb-stack" }, body),
2117
+ );
2118
+ }
2119
+ return E(DisclosureRowComponent, {
2120
+ className: "gb-fold",
2121
+ icon: null,
2122
+ title: t(titleKey),
2123
+ open: folds[key] === true,
2124
+ expandable: true,
2125
+ expandOnRowClick: true,
2126
+ onToggle: function () { toggleFold(key); },
2127
+ }, E("div", { className: "gb-stack" }, body));
2128
+ }
2129
+
2061
2130
  // dsh 0.1.6-alpha.2: the Plugins page renders this card through the
2062
2131
  // `plugins.bundle.config` slot with view="page" — the page draws the
2063
2132
  // title itself; the collapsible shell only shows on the popup seat.
@@ -2074,9 +2143,7 @@ window.__ModuleLoader__.load({
2074
2143
  var eolOn = snap.value.gitAutocrlf !== false;
2075
2144
  var dedupe = snap.value.suppressPeerCordis === true;
2076
2145
 
2077
- var dialectSection = E("div", { className: "gb-section" },
2078
- E("div", { className: "gb-sectionTitle" }, t("sec.dialect")),
2079
- E("div", { className: "gb-stack" },
2146
+ var dialectSection = fold("sec.dialect",
2080
2147
  E("div", { className: "gb-row" },
2081
2148
  E("span", { className: "gb-rowLabel" }, t("state.label") + ":"),
2082
2149
  E("span", { className: "gb-rowValue" }, enabled ? t("state.on") : t("state.off")),
@@ -2131,7 +2198,6 @@ window.__ModuleLoader__.load({
2131
2198
  E("button", { type: "button", className: "gb-segBtn" + (!subagents ? " gb-segActive" : ""), onClick: function () { if (subagents) writeField("subagentDialect", false); } }, t("switch.off")),
2132
2199
  ),
2133
2200
  E("p", { className: "gb-hint" }, t("sub.hint")),
2134
- ),
2135
2201
  );
2136
2202
 
2137
2203
  /* ── executor section (v0.36.0 regroup) ───────────────────────────
@@ -2139,9 +2205,7 @@ window.__ModuleLoader__.load({
2139
2205
  the executor injects. Split out of the dialect section — users
2140
2206
  hunting "why is my diff all red" or pasting a bash path should
2141
2207
  not scroll through six translation switches to find it. */
2142
- var executorSection = E("div", { className: "gb-section" },
2143
- E("div", { className: "gb-sectionTitle" }, t("sec.executor")),
2144
- E("div", { className: "gb-stack" },
2208
+ var executorSection = fold("sec.executor",
2145
2209
  E("div", { className: "gb-row" },
2146
2210
  E("span", { className: "gb-rowLabel" }, t("eol.label") + ":"),
2147
2211
  E("span", { className: "gb-rowValue" }, eolOn ? t("state.on") : t("state.off")),
@@ -2166,12 +2230,9 @@ window.__ModuleLoader__.load({
2166
2230
  }, bashSaved ? t("bash.saved") : t("bash.save")),
2167
2231
  ),
2168
2232
  E("p", { className: "gb-hint" }, t("bash.hint")),
2169
- ),
2170
2233
  );
2171
2234
 
2172
- var terminalSection = E("div", { className: "gb-section" },
2173
- E("div", { className: "gb-sectionTitle" }, t("sec.terminal")),
2174
- E("div", { className: "gb-stack" },
2235
+ var terminalSection = fold("sec.terminal",
2175
2236
  E("div", { className: "gb-row" },
2176
2237
  E("span", { className: "gb-rowLabel" }, t("term.label") + ":"),
2177
2238
  E("span", { className: "gb-rowValue" }, winshell ? t("state.on") : t("state.off")),
@@ -2190,7 +2251,6 @@ window.__ModuleLoader__.load({
2190
2251
  E("button", { type: "button", className: "gb-segBtn" + (!adopt ? " gb-segActive" : ""), onClick: function () { if (adopt) writeField("adoptSidebar", false); } }, t("switch.off")),
2191
2252
  ),
2192
2253
  E("p", { className: "gb-hint" }, t("adopt.hint")),
2193
- ),
2194
2254
  );
2195
2255
 
2196
2256
  /* Peer-gated section: rendered only while dsh-ptc-cordis-preset serves
@@ -2201,9 +2261,7 @@ window.__ModuleLoader__.load({
2201
2261
  var pwshOn = snap.value.pwshTool !== false;
2202
2262
  var fctxOn = snap.value.fastctxTools !== false;
2203
2263
 
2204
- var modeSection = E("div", { className: "gb-section" },
2205
- E("div", { className: "gb-sectionTitle" }, t("variant.label")),
2206
- E("div", { className: "gb-stack" },
2264
+ var modeSection = fold("sec.mode",
2207
2265
  E("div", { className: "gb-row" },
2208
2266
  E("span", { className: "gb-rowLabel" }, t("variant.label") + ":"),
2209
2267
  E("span", { className: "gb-rowValue" }, variantOn ? t("state.on") : t("state.off")),
@@ -2213,12 +2271,9 @@ window.__ModuleLoader__.load({
2213
2271
  E("button", { type: "button", className: "gb-segBtn" + (!variantOn ? " gb-segActive" : ""), onClick: function () { if (variantOn) writeField("variantPresets", false); } }, t("switch.off")),
2214
2272
  ),
2215
2273
  E("p", { className: "gb-hint" }, t("variant.hint")),
2216
- ),
2217
2274
  );
2218
2275
 
2219
- var inlineSection = E("div", { className: "gb-section" },
2220
- E("div", { className: "gb-sectionTitle" }, t("sec.inline")),
2221
- E("div", { className: "gb-stack" },
2276
+ var inlineSection = fold("sec.inline",
2222
2277
  E("div", { className: "gb-row" },
2223
2278
  E("span", { className: "gb-rowLabel" }, t("pwsh.label") + ":"),
2224
2279
  E("span", { className: "gb-rowValue" }, pwshOn ? t("state.on") : t("state.off")),
@@ -2237,7 +2292,6 @@ window.__ModuleLoader__.load({
2237
2292
  E("button", { type: "button", className: "gb-segBtn" + (!fctxOn ? " gb-segActive" : ""), onClick: function () { if (fctxOn) writeField("fastctxTools", false); } }, t("switch.off")),
2238
2293
  ),
2239
2294
  E("p", { className: "gb-hint" }, t("fctx.hint")),
2240
- ),
2241
2295
  );
2242
2296
 
2243
2297
  var peerSnap = { status: "unavailable" };
@@ -2293,9 +2347,7 @@ window.__ModuleLoader__.load({
2293
2347
 
2294
2348
  /* The merged integrations section: dedupe row + python row under one
2295
2349
  heading (v0.36.0). Exists only while the peer serves its row. */
2296
- var peerSection = peerSnap.status === "ready" ? E("div", { className: "gb-section" },
2297
- E("div", { className: "gb-sectionTitle" }, t("sec.peer")),
2298
- E("div", { className: "gb-stack" },
2350
+ var peerSection = peerSnap.status === "ready" ? fold("sec.peer",
2299
2351
  E("div", { className: "gb-row" },
2300
2352
  E("span", { className: "gb-rowLabel" }, t("dedupe.label") + ":"),
2301
2353
  E("span", { className: "gb-rowValue" }, dedupe ? t("state.on") : t("state.off")),
@@ -2318,7 +2370,6 @@ window.__ModuleLoader__.load({
2318
2370
  pythonOffered ? E("p", { className: "gb-hint" }, t("python.hint")) : null,
2319
2371
  pythonOffered && winHost ? E("p", { className: "gb-error" }, t("python.blocked")) : null,
2320
2372
  pythonDegraded ? E("p", { className: "gb-error" }, t("python.degraded")) : null,
2321
- ),
2322
2373
  ) : null;
2323
2374
 
2324
2375
  /* ── terminal toolchain (v0.30.0) ────────────────────────────────
@@ -2437,9 +2488,7 @@ window.__ModuleLoader__.load({
2437
2488
  return function () { clearTimeout(timer); };
2438
2489
  }, [toolJob]);
2439
2490
 
2440
- var toolsSection = E("div", { className: "gb-section" },
2441
- E("div", { className: "gb-sectionTitle" }, t("sec.tools")),
2442
- E("div", { className: "gb-stack" },
2491
+ var toolsSection = fold("sec.tools",
2443
2492
  toolsData === null && toolErr === "" ? E("p", { className: "gb-hint" }, t("tools.loading")) : null,
2444
2493
  toolErr !== "" ? E("p", { className: "gb-error" }, toolErr) : null,
2445
2494
  toolsData !== null && !wingetOk ? E("p", { className: "gb-error" }, t("tools.nowinget")) : null,
@@ -2511,7 +2560,6 @@ window.__ModuleLoader__.load({
2511
2560
  ),
2512
2561
  ) : null,
2513
2562
  E("p", { className: "gb-hint" }, t("tools.hint")),
2514
- ),
2515
2563
  );
2516
2564
 
2517
2565
  var bodyContent = E("div", { className: "gb-body" },
@@ -221,19 +221,40 @@ export function validatePwshArgs(args) {
221
221
  return undefined
222
222
  }
223
223
 
224
+ /** The official bash-tool package the inline patch activates. */
225
+ const TOOL_BASH_PACKAGE = '@deepseek-ai/dsh-tool-bash'
226
+
224
227
  /**
225
- * Resolve the OFFICIAL @deepseek-ai/dsh-tool-bash module entry from the
226
- * host's own resolution base (the same seam probeHostExtras uses). Returns
227
- * the absolute entry URL, or '' when the host does not ship the package.
228
+ * Resolve the OFFICIAL @deepseek-ai/dsh-tool-bash module. TWO channels, in
229
+ * order (v0.38.1, the desktop-host field report):
230
+ *
231
+ * ① THE HOST'S OWN LOADER — `ctx.loader.internal.import(name, baseUrl, {})`,
232
+ * the exact call the row mount itself uses
233
+ * (vendor/loader/src/config/tree.ts:122). It runs the host's resolve
234
+ * hooks, so it reaches packages inside the desktop app.asar that a bare
235
+ * Node resolver cannot see from the plugin's profile layout.
236
+ * ② A plain createRequire from the host base — the v0.35.0 channel, kept
237
+ * for layouts where the internal loader is absent.
238
+ *
239
+ * @returns {Promise<{ load: async () => object }|undefined>} a lazy loader for
240
+ * the module, or undefined when neither channel resolves it.
228
241
  */
229
242
  export async function resolveToolBashEntry(ctx) {
243
+ try {
244
+ const internal = ctx?.loader?.internal
245
+ if (internal && typeof internal.import === 'function') {
246
+ const mod = await internal.import(TOOL_BASH_PACKAGE, ctx?.baseUrl, {})
247
+ if (mod && typeof mod.apply === 'function') return { load: async () => mod }
248
+ }
249
+ } catch { /* fall through to the plain resolution */ }
230
250
  try {
231
251
  const { createRequire } = await import('node:module')
232
252
  const { pathToFileURL } = await import('node:url')
233
253
  const req = createRequire(ctx?.baseUrl ?? import.meta.url)
234
- return pathToFileURL(req.resolve('@deepseek-ai/dsh-tool-bash')).href
254
+ const href = pathToFileURL(req.resolve(TOOL_BASH_PACKAGE)).href
255
+ return { load: async () => import(href) }
235
256
  } catch {
236
- return ''
257
+ return undefined
237
258
  }
238
259
  }
239
260
 
@@ -245,10 +266,10 @@ export async function resolveToolBashEntry(ctx) {
245
266
  * prescribes for per-agent variants. The official module is loaded ONCE per
246
267
  * process; each agent gets a fresh scope and a fresh apply().
247
268
  */
248
- export async function activateOfficialBash(agent, toolBashHref, createScopeFn, log) {
269
+ export async function activateOfficialBash(agent, resolved, createScopeFn, log) {
249
270
  let mod
250
271
  try {
251
- mod = await import(toolBashHref)
272
+ mod = await resolved.load()
252
273
  } catch (error) {
253
274
  log(`official tool-bash module import failed: ${error?.message ?? error}`)
254
275
  return undefined
@@ -294,7 +315,7 @@ export function mountInlineTools(ctx, deps) {
294
315
  const { tools, agents, createScope, allowed, spawn, pwshPath, echo, log } = deps
295
316
  /** agent -> { timer, scope, denyPwsh, pwshScope }; named `tracked` because `agents` above is the host service */
296
317
  const tracked = new Map()
297
- let toolBashHrefPromise
318
+ let toolBashResolvePromise
298
319
 
299
320
  const faceNames = (agent) => {
300
321
  try {
@@ -383,13 +404,13 @@ export function mountInlineTools(ctx, deps) {
383
404
  }
384
405
  }
385
406
  if (needs.needsBash && !state.scope) {
386
- if (toolBashHrefPromise === undefined) toolBashHrefPromise = resolveToolBashEntry(ctx)
387
- void toolBashHrefPromise.then(async (href) => {
388
- if (href === '') {
389
- log('official @deepseek-ai/dsh-tool-bash is not resolvable from the host base; bash stays absent for this agent')
407
+ if (toolBashResolvePromise === undefined) toolBashResolvePromise = resolveToolBashEntry(ctx)
408
+ void toolBashResolvePromise.then(async (resolved) => {
409
+ if (!resolved) {
410
+ log('official @deepseek-ai/dsh-tool-bash is not resolvable (neither the host loader nor a plain resolution found it); bash stays absent for this agent')
390
411
  return
391
412
  }
392
- const scope = await activateOfficialBash(agent, href, createScope, log)
413
+ const scope = await activateOfficialBash(agent, resolved, createScope, log)
393
414
  if (scope && tracked.get(agent) === state) {
394
415
  state.scope = scope
395
416
  log('official bash tool activated for this agent (Git Bash host; fake pwsh denied)')