dsh-gitbash-shell 0.28.0 → 0.29.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/CHANGELOG.md +54 -0
- package/README.md +25 -0
- package/dsh.plugin.json +1 -1
- package/package.json +1 -1
- package/src/client.js +52 -0
- package/src/index.js +62 -1
- package/src/terminal-shell.js +206 -0
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,60 @@
|
|
|
3
3
|
> 倒序排列,新版本条目在最上面。条目格式:`## vX.Y.Z — YYYY-MM-DD` + 类型(feat / fix / docs / chore)+ 要点 + 相关链接。
|
|
4
4
|
> 纪律见 AGENTS.md「变更记录纪律」:发版前先更新本文件并随版本提交;事故复盘、复现与真机验证记录也记在这里。
|
|
5
5
|
|
|
6
|
+
## v0.29.0 — 2026-09-26
|
|
7
|
+
|
|
8
|
+
**类型**:feat(用户实测需求 —— DSH 原生「新建终端」落到 **WSL**,插件只接管了 agent 的 shell 工具,没有接管官方侧栏终端)
|
|
9
|
+
|
|
10
|
+
> 用户原话:**"能不能让我的gitbash插件自动检测是不是没这个,然后帮忙补上一个 gitbash可以用,反正就自动的。"**
|
|
11
|
+
> 现象证据(用户自备):PATH 里 `bash` 只命中 `C:\WINDOWS\system32\bash.EXE`(Microsoft Bash Launcher)与
|
|
12
|
+
> `%LOCALAPPDATA%\Microsoft\WindowsApps\bash.EXE`,跑起来 `WSL_DISTRO_NAME=Ubuntu-20.04`;`C:\Program Files\Git\cmd`
|
|
13
|
+
> 虽在 PATH 但没有 `bash.exe`。本插件旧有的 `adoptSidebarShell` 写的是 **dsh-better-sidebar** 的命名空间,用户装的是
|
|
14
|
+
> dsh-better-workspace,那条通道被 skip。
|
|
15
|
+
|
|
16
|
+
### 一、调研结论(全部实测,装置见下)
|
|
17
|
+
1. **官方 settings 服务写不了 `terminal.shell`** —— 任务书设想的"正路"在当前 dsh 0.1.7-rc.2 上**不存在**:
|
|
18
|
+
`SettingsService.write()` 要求写入路径必须是 **volatile** 字段(`volatileForm(schema)` 为 `undefined` ⇒
|
|
19
|
+
`Plugin entry "…" has no volatile fields`),而 `TerminalController.Config` 的 `shell` 是普通字段;
|
|
20
|
+
隔离实例探针实测 `settings.update('terminal', {shell})` 直接抛
|
|
21
|
+
`No configurable plugin entry "terminal"`(`describe()` 里也没有 `terminal` 这一行)。
|
|
22
|
+
2. **可行且官方的通道是 `configEditor.edit()`** —— 官方设置 UI 持久化时用的同一个 API(注释:
|
|
23
|
+
"ordinary fields keep normal lifecycle rules")。探针写入后,**运行中的** `ctx.terminalController.config.shell`
|
|
24
|
+
立刻读到新值 ⇒ **无需重启**;落盘到 profile 的 patch 层,由官方 YAML 编辑器**保留文件头注释**、按 `id` 合并该行。
|
|
25
|
+
3. **`args: ['-i']` 有官方依据**:`shells.ts` 的 `profile()` 对非 cmd/pwsh 的 shell 一律给 `['-i']` —— 我们与官方一致,不是自创。
|
|
26
|
+
4. **配置的 shell 恒排首位**(`discoverShells()` 先 `resolveShell(configured)` 再解析 candidates,按 path 去重),
|
|
27
|
+
所以只需配 `shell`,**不动 `shellCandidates`**。另注意:菜单里仍可能出现一条候选 `bash`(在那些机器上解析到 WSL);
|
|
28
|
+
默认项是我们写入的 Git Bash。
|
|
29
|
+
5. **写错路径会直接把「新建终端」弄坏**:`resolveShell` 用 `subprocess.resolveExecutable()` 验证配置路径,
|
|
30
|
+
失败即抛 `SubprocessExecutableNotFoundError`,**没有回退** ⇒ 只允许写 `src/bash-path.js` 已通过四项判据的 Git Bash。
|
|
31
|
+
|
|
32
|
+
### 二、实现
|
|
33
|
+
- 新模块 `src/terminal-shell.js`:纯决策 `planTerminalAdopt()` + 执行器 `adoptTerminalShell()`,六态
|
|
34
|
+
`skip-platform` / `skip-disabled` / `skip-unresolved` / `skip-row-absent` / `unchanged` / `kept-user-choice` / `adopted` / `write-failed`。
|
|
35
|
+
- **只写"空"的**:该行没有自己的 shell ⇒ 写 `{path: <Git Bash>, name: 'bash', args: ['-i']}`;已是同一个(大小写/分隔符无关)⇒ 不写;
|
|
36
|
+
已指向别处 ⇒ **绝不覆盖**,日志说明"这是你的显式选择"以及如何交还给 Git Bash。
|
|
37
|
+
- **写入后读回校验**(`configuration()` 的 `override`/`inherited`):`edit()` resolve 不等于值落进去了,不符 ⇒ `write-failed` 并 fail-loud
|
|
38
|
+
(延续 v0.28.0 的"绝不假成功")。
|
|
39
|
+
- 新开关 `autoTerminalShell`(volatile,**默认开**;旧宿主 settings 命名空间同名字段,缺键 = 开)+ 21 语言卡片文案
|
|
40
|
+
(`term.label`/`term.hint`);保留原 `dsh-better-sidebar` 通道(两条通道各自独立探测);不碰官方包、不手写用户 patch 文件。
|
|
41
|
+
- README 新增该节 + **用户三步复验清单**(开关与日志 → 终端里 `uname -r` 判 `MINGW64_NT-*` → 回退办法)。
|
|
42
|
+
**回退语义写明**:关掉开关**只阻止以后的自动写入**,**不会**删除已经写进配置的 `shell` 字段;要彻底恢复原样需删掉
|
|
43
|
+
profile patch 里 `terminal-controller` 行的 `shell` 字段并重启(21 语言卡片 hint 同步写上这一句)。
|
|
44
|
+
**菜单如实说明**:未改 `shellCandidates` ⇒ 选择菜单里**仍可能列出**解析到 WSL 的候选 `bash`,被改的是**默认项/首项**。
|
|
45
|
+
|
|
46
|
+
### 三、验证
|
|
47
|
+
- `npm test` **99/99**(新增 5 条:空→写且形状为官方 `profile()` 约定 + 无关字段保留 / 同值→不写 + 异值→不写且日志含怎么交还 / 开关关·非 Windows·未解析·无该行→全只读 / 写入被拒或**未落盘**→ `write-failed` 不假成功 / 宿主侧只走 `configEditor` 且绝不调用 `settings.update('terminal')`);`align-official.mjs` 四变体仍逐字节对齐。
|
|
48
|
+
- **隔离实例真机(macOS,副本强制 win32 门 + 伪装已解析 Git Bash)**:
|
|
49
|
+
- 空值 ⇒ 日志 `switched to Git Bash: Q:/Git/bin/bash.exe (name bash, args -i) …`;
|
|
50
|
+
profile patch 里用户手写行与注释**原样保留**、新增 `- id: terminal-controller … shell {path,name,args}`;
|
|
51
|
+
`--dump-config` 读到 `terminal-controller.config.shell.path = Q:/Git/bin/bash.exe`;
|
|
52
|
+
- 第二次启动 ⇒ `already uses this Git Bash … (nothing written)`,patch **md5 未变**(幂等);
|
|
53
|
+
- 用户显式指向 `C:/Windows/System32/bash.exe` ⇒ `NOT adopted … an explicit choice is never overwritten`,patch **未变**;
|
|
54
|
+
- `autoTerminalShell: false` ⇒ `adoption is off …`,patch **未变**;
|
|
55
|
+
- 无头浏览器零 pageerror。
|
|
56
|
+
- **未在 Windows 验证**:真实 PATH/注册表命中、菜单里 shell 项、新终端里 `uname -r` 是否 `MINGW64_NT-*`;
|
|
57
|
+
设置卡新增开关行的截图级渲染(该行复用既有开关写法,21 语言键由冒烟 parity 覆盖)。需用户按 README 三步复验。
|
|
58
|
+
- 相关:issue #11 后续(同一用户的 Windows 实测反馈)
|
|
59
|
+
|
|
6
60
|
## v0.28.0 — 2026-09-26
|
|
7
61
|
|
|
8
62
|
**类型**:fix(issue #11 —— Git 没装在 `C:\Program Files\Git` 时,写死的默认 `bashPath` 让每条命令 `spawn … ENOENT`,而整个会话的命令能力归零且无提示)+ feat(fail-loud 引导:弹窗可填写路径 / 可跳转下载)
|
package/README.md
CHANGED
|
@@ -147,6 +147,31 @@ dsh-ptc-cordis-preset 报告它的 `PTC 创造模式` 已经是 Git Bash 版。
|
|
|
147
147
|
> 装了本插件就是要用 Git Bash,偷偷换一个能跑的顶上是错的。失败时弹窗给两件事:在弹窗里**直接填 bashPath**
|
|
148
148
|
> (写入设置卡同一字段)或**去下载 Git for Windows**;同一 boot 只弹一次,可关闭。
|
|
149
149
|
|
|
150
|
+
## 官方侧栏终端(「新建终端」)自动切到 Git Bash(v0.29.0)
|
|
151
|
+
|
|
152
|
+
DSH 自己的「新建终端」**不经过**本插件的执行器:它由官方的 `terminal-controller` 决定 shell,未配置时用
|
|
153
|
+
「执行环境的默认 shell」——而在 PATH 里 `bash` 指向 `C:\Windows\System32\bash.EXE`(WSL 启动器)的机器上,
|
|
154
|
+
新终端跑起来就是 Ubuntu。本插件现在会自动把它切过来:
|
|
155
|
+
|
|
156
|
+
- 仅 **Windows**、且已解析出**通过验证**的 Git Bash 时;设置开关 **「自动接管侧栏终端」默认开启**(`autoTerminalShell`)。
|
|
157
|
+
- 只在官方那一行**没有自己的 shell** 时写入 `{ path: <Git Bash>, name: bash, args: ['-i'] }`
|
|
158
|
+
(`-i` 就是官方对 bash 的默认参数)。**你已经手动指定过别的 shell(例如某个 WSL 配置)⇒ 绝不覆盖**,只在宿主日志里提示,
|
|
159
|
+
并告诉你如何交还给 Git Bash(清空该字段)。
|
|
160
|
+
- 写入走**官方配置编辑器**(设置 UI 用的同一个 API),落到 profile 的 patch 层;**新终端立即生效**,已打开的终端保持原样。
|
|
161
|
+
- **不需要重启**,也不会写坏「新建终端」:只写我们验证过存在的 Git Bash(官方对无法解析的路径没有回退,会直接启动失败)。
|
|
162
|
+
- 失败时 **fail-loud**:日志写清原因,并通过**读回校验**确认值真的落进去了(不出现"假成功")。
|
|
163
|
+
- ⚠️ **如实说明**:我们**没有**改 `shellCandidates`,所以「新建终端」的 shell 选择菜单里**仍可能列出**一条解析到 WSL 的
|
|
164
|
+
候选 `bash` —— 被改掉的是**默认项/首项**(它现在是我们写入的 Git Bash),不是整条菜单。想彻底不让 WSL 出现在菜单里,
|
|
165
|
+
需要另外调整 `terminal-controller` 行的 `shellCandidates`(本插件本轮**不做**,以免覆盖别人的部署配置)。
|
|
166
|
+
|
|
167
|
+
**三步复验(Windows)**:
|
|
168
|
+
1. 装好 Git for Windows,重启 DSH,打开本插件设置卡:开关「自动接管侧栏终端」为开;宿主日志出现
|
|
169
|
+
`official sidebar terminal switched to Git Bash: …`。
|
|
170
|
+
2. 新建终端,在终端里跑 `uname -r`:应看到 `MINGW64_NT-…`(WSL 会显示 Linux 内核版本如 `5.15…`)。
|
|
171
|
+
3. **回退**:⚠️ 关掉设置卡里的开关**只阻止以后的自动写入,不会删除已经写进配置的字段**。要彻底恢复原样,
|
|
172
|
+
请把 profile 的 patch 里 `terminal-controller` 行的 `shell` 字段**删掉**,再重启 DSH(终端随即回到原来的 shell);
|
|
173
|
+
只想让它别再自动改、但不介意保留现状的话,关开关即可。
|
|
174
|
+
|
|
150
175
|
## 配置(执行器)
|
|
151
176
|
|
|
152
177
|
`gitbash-executor` 行支持:
|
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.29.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.
|
|
3
|
+
"version": "0.29.0",
|
|
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
|
@@ -95,6 +95,8 @@ window.__ModuleLoader__.load({
|
|
|
95
95
|
"bashmiss.close": "关闭",
|
|
96
96
|
"sub.label": "子代理/队员使用 Git Bash",
|
|
97
97
|
"sub.hint": "默认开启:子代理与团队队员(含嵌套子代理)的提示词方言、路径参数翻译、结果回显与 DSH_PATH_DIALECT 环境事实与主代理一致。关闭后这些只对主代理生效,子代理按官方 shell 语义运行(提示词不改写、路径参数不翻译);注意 dsh 每个进程只有一个 shell 执行器,所以 Git Bash 二进制本身仍是全局的,此开关管的是方言/翻译层。",
|
|
98
|
+
"term.label": "自动接管侧栏终端",
|
|
99
|
+
"term.hint": "默认开启:Windows 上把官方「新建终端」的 shell 自动设成探测到的 Git Bash(写进官方 terminal-controller 行的配置,由官方配置编辑器落盘)——没有这一项时,dsh 会按环境默认 shell 启动终端,而 PATH 里的 bash 常常是 WSL 启动器,于是新终端跑的是 Ubuntu。只在该行**没有**自己的 shell 时才写;你已经手动指定过别的 shell 就绝不覆盖,只会在宿主日志里提示。新终端立即生效,已打开的终端保持原样。 注意:关掉这个开关只会阻止**以后**的自动写入,不会删除已经写进 profile 配置的 shell 字段 —— 要彻底恢复原样,请把 profile 的 patch 里 terminal-controller 行的 shell 字段删掉再重启 DSH。",
|
|
98
100
|
"eol.label": "Git 行尾(与 Linux 一致)",
|
|
99
101
|
"eol.hint": "模型跑的 git 命令按 Linux 行为:core.autocrlf=input、core.eol=lf。你自己终端的 git 与仓库里的 .gitattributes 都不受影响。",
|
|
100
102
|
"bash.label": "Git Bash 路径",
|
|
@@ -144,6 +146,8 @@ window.__ModuleLoader__.load({
|
|
|
144
146
|
"bashmiss.close": "Close",
|
|
145
147
|
"sub.label": "Subagents/teammates use Git Bash",
|
|
146
148
|
"sub.hint": "On (default): subagents and team members — nested ones included — get the same prompt dialect, path-argument translation, result echo and DSH_PATH_DIALECT fact as the main agent. Off: those apply to the main agent only, and delegated agents run with the official shell semantics (no prompt rewrite, no path translation). Note that dsh has exactly one shell executor per process, so the Git Bash binary stays global; this switch governs the dialect/translation layers.",
|
|
149
|
+
"term.label": "Adopt the sidebar terminal",
|
|
150
|
+
"term.hint": "On by default: on Windows the official “new terminal” shell is set to the detected Git Bash (written into the official terminal-controller row through the official config editor). Without it dsh starts the terminal with the environment default shell, and PATH's bash is often the WSL launcher — so the new terminal runs Ubuntu. It only writes when that row has NO shell of its own; an explicit choice is never overwritten, it just gets a host-log line. New terminals pick it up immediately, already-open ones keep their shell. Note: turning this switch off only stops FUTURE writes — it does not remove a shell field already written into the profile config. To restore the original exactly, delete the shell field from the terminal-controller row in the profile patch and restart DSH.",
|
|
147
151
|
"eol.label": "Git line endings (Linux match)",
|
|
148
152
|
"eol.hint": "Git commands the model runs behave like Linux: core.autocrlf=input, core.eol=lf. Your own terminal's git and a repository's .gitattributes are unaffected.",
|
|
149
153
|
"bash.label": "Git Bash path",
|
|
@@ -203,6 +207,8 @@ window.__ModuleLoader__.load({
|
|
|
203
207
|
"bashmiss.close": "إغلاق",
|
|
204
208
|
"sub.label": "استخدام الوكلاء الفرعيين لـ Git Bash",
|
|
205
209
|
"sub.hint": "مُفعَّل (افتراضيًا): يحصل الوكلاء الفرعيون وأعضاء الفريق — بما في ذلك المتداخلون — على لهجة المطالبة وترجمة مسارات الوسائط وصدى النتائج وحقيقة DSH_PATH_DIALECT نفسها التي يحصل عليها الوكيل الرئيسي. عند الإيقاف تُطبَّق هذه على الوكيل الرئيسي فقط ويعمل الوكلاء المفوَّضون بدلالات الصدفة الرسمية (دون إعادة كتابة المطالبة أو ترجمة المسارات). لاحظ أن dsh يملك مُنفِّذ صدفة واحدًا لكل عملية، لذا يبقى ثنائي Git Bash عامًّا؛ هذا المفتاح يحكم طبقتي اللهجة والترجمة.",
|
|
210
|
+
"term.label": "تبنّي طرفية الشريط الجانبي",
|
|
211
|
+
"term.hint": "مُفعَّل افتراضيًا: على Windows يُضبط shell الخاص بـ«الطرفية الجديدة» الرسمية على Git Bash المكتشف (يُكتب في صف terminal-controller الرسمي عبر محرر الإعدادات الرسمي). بدونه يبدأ dsh الطرفية بالـ shell الافتراضي للبيئة، وغالبًا ما يكون bash في PATH هو مشغّل WSL فتعمل الطرفية الجديدة على Ubuntu. لا يُكتب إلا عندما لا يملك ذلك الصف shell خاصًا به؛ ولا يُستبدل اختيار صريح أبدًا، بل يُسجَّل سطر في سجل المضيف. الطرفيات الجديدة تسري فورًا، والمفتوحة تبقى كما هي. ملاحظة: إيقاف هذا المفتاح يمنع الكتابات المستقبلية فقط ولا يحذف حقل shell المكتوب بالفعل في إعدادات الملف الشخصي؛ لاستعادة الأصل تمامًا احذف حقل shell من صف terminal-controller في patch الملف الشخصي ثم أعد تشغيل DSH.",
|
|
206
212
|
"eol.label": "نهايات أسطر Git (مطابقة لينكس)",
|
|
207
213
|
"eol.hint": "أوامر git التي يشغّلها النموذج تتبع سلوك لينكس: core.autocrlf=input و core.eol=lf؛ لا يتأثر طرفيتك ولا ملف .gitattributes للمستودع.",
|
|
208
214
|
"bash.label": "مسار Git Bash",
|
|
@@ -252,6 +258,8 @@ window.__ModuleLoader__.load({
|
|
|
252
258
|
"bashmiss.close": "Schließen",
|
|
253
259
|
"sub.label": "Subagenten/Teammitglieder nutzen Git Bash",
|
|
254
260
|
"sub.hint": "An (Standard): Subagenten und Teammitglieder — auch verschachtelte — erhalten denselben Prompt-Dialekt, dieselbe Pfadargument-Übersetzung, dieselbe Ergebnisanzeige und dieselbe DSH_PATH_DIALECT-Tatsache wie der Hauptagent. Aus: Das gilt nur für den Hauptagenten, delegierte Agenten laufen mit den offiziellen Shell-Semantiken (keine Prompt-Umschreibung, keine Pfadübersetzung). Beachte: dsh hat genau einen Shell-Executor pro Prozess, das Git-Bash-Binary bleibt also global; dieser Schalter steuert die Dialekt-/Übersetzungsschichten.",
|
|
261
|
+
"term.label": "Seitenleisten-Terminal übernehmen",
|
|
262
|
+
"term.hint": "Standardmäßig an: Unter Windows wird die Shell des offiziellen „Neuen Terminals“ auf die erkannte Git Bash gesetzt (geschrieben in die offizielle terminal-controller-Zeile über den offiziellen Konfigurationseditor). Ohne das startet dsh das Terminal mit der Umgebungs-Standardshell, und das bash im PATH ist oft der WSL-Starter — das neue Terminal läuft dann unter Ubuntu. Geschrieben wird nur, wenn diese Zeile KEINE eigene Shell hat; eine ausdrückliche Wahl wird nie überschrieben, sondern nur im Host-Protokoll vermerkt. Neue Terminals übernehmen es sofort, bereits offene behalten ihre Shell. Hinweis: Dieser Schalter verhindert nur KÜNFTIGE Schreibvorgänge — ein bereits in die Profilkonfiguration geschriebenes shell-Feld wird nicht entfernt. Für den exakten Originalzustand das shell-Feld in der terminal-controller-Zeile des Profil-Patchs löschen und DSH neu starten.",
|
|
255
263
|
"eol.label": "Git-Zeilenenden (Linux-gleich)",
|
|
256
264
|
"eol.hint": "Vom Modell ausgeführte git-Befehle verhalten sich wie unter Linux: core.autocrlf=input, core.eol=lf. Dein eigenes Terminal und die .gitattributes eines Repos bleiben unberührt.",
|
|
257
265
|
"bash.label": "Git-Bash-Pfad",
|
|
@@ -301,6 +309,8 @@ window.__ModuleLoader__.load({
|
|
|
301
309
|
"bashmiss.close": "Fermer",
|
|
302
310
|
"sub.label": "Les sous-agents utilisent Git Bash",
|
|
303
311
|
"sub.hint": "Activé (par défaut) : les sous-agents et membres d'équipe — y compris imbriqués — reçoivent le même dialecte de prompt, la même traduction des chemins d'arguments, le même écho de résultat et le même fait DSH_PATH_DIALECT que l'agent principal. Désactivé : ces éléments ne s'appliquent qu'à l'agent principal et les agents délégués suivent les sémantiques de shell officielles (pas de réécriture du prompt, pas de traduction des chemins). À noter : dsh n'a qu'un seul exécuteur de shell par processus, le binaire Git Bash reste donc global ; cet interrupteur régit les couches de dialecte et de traduction.",
|
|
312
|
+
"term.label": "Adopter le terminal latéral",
|
|
313
|
+
"term.hint": "Activé par défaut : sous Windows, le shell du « nouveau terminal » officiel est réglé sur le Git Bash détecté (écrit dans la ligne officielle terminal-controller via l'éditeur de configuration officiel). Sans cela, dsh démarre le terminal avec le shell par défaut de l'environnement, et le bash du PATH est souvent le lanceur WSL — le nouveau terminal tourne alors sous Ubuntu. L'écriture n'a lieu que si cette ligne n'a AUCUN shell propre ; un choix explicite n'est jamais écrasé, seulement consigné dans le journal de l'hôte. Les nouveaux terminaux en profitent immédiatement, ceux déjà ouverts gardent leur shell. Remarque : désactiver ce commutateur n'empêche que les écritures FUTURES — il ne supprime pas un champ shell déjà écrit dans la configuration du profil. Pour revenir exactement à l'état initial, supprimez le champ shell de la ligne terminal-controller du patch de profil puis redémarrez DSH.",
|
|
304
314
|
"eol.label": "fins de ligne Git (comme Linux)",
|
|
305
315
|
"eol.hint": "Les commandes git lancées par le modèle suivent le comportement Linux : core.autocrlf=input, core.eol=lf. Votre terminal et les .gitattributes du dépôt ne sont pas touchés.",
|
|
306
316
|
"bash.label": "Chemin Git Bash",
|
|
@@ -350,6 +360,8 @@ window.__ModuleLoader__.load({
|
|
|
350
360
|
"bashmiss.close": "बंद करें",
|
|
351
361
|
"sub.label": "सबएजेंट/टीम सदस्य Git Bash इस्तेमाल करें",
|
|
352
362
|
"sub.hint": "चालू (डिफ़ॉल्ट): सबएजेंट और टीम सदस्य — नेस्टेड सहित — मुख्य एजेंट जैसा ही प्रॉम्प्ट डायलेक्ट, पाथ आर्ग्युमेंट अनुवाद, परिणाम इको और DSH_PATH_DIALECT तथ्य पाते हैं। बंद: ये केवल मुख्य एजेंट पर लागू होते हैं और प्रतिनिधित एजेंट आधिकारिक शेल अर्थ में चलते हैं (प्रॉम्प्ट नहीं बदलता, पाथ अनुवाद नहीं होता)। ध्यान दें: dsh में प्रति प्रोसेस एक ही शेल एक्ज़ीक्यूटर होता है, इसलिए Git Bash बाइनरी वैश्विक रहती है; यह स्विच डायलेक्ट/अनुवाद परतों को नियंत्रित करता है।",
|
|
363
|
+
"term.label": "साइडबार टर्मिनल अपनाएँ",
|
|
364
|
+
"term.hint": "डिफ़ॉल्ट रूप से चालू: Windows पर आधिकारिक «नया टर्मिनल» का shell पहचाने गए Git Bash पर सेट होता है (आधिकारिक कॉन्फ़िग एडिटर के ज़रिए आधिकारिक terminal-controller पंक्ति में लिखा जाता है)। इसके बिना dsh टर्मिनल को पर्यावरण के डिफ़ॉल्ट shell से शुरू करता है, और PATH का bash अक्सर WSL लॉन्चर होता है — तब नया टर्मिनल Ubuntu पर चलता है। लिखा तभी जाता है जब उस पंक्ति का अपना कोई shell न हो; स्पष्ट चयन कभी अधिलेखित नहीं होता, केवल होस्ट लॉग में दर्ज होता है। नए टर्मिनल तुरंत इसे लेते हैं, खुले हुए अपना shell रखते हैं। ध्यान दें: यह स्विच बंद करने से केवल आगे की लेखन रुकती है — प्रोफ़ाइल कॉन्फ़िग में पहले से लिखा shell फ़ील्ड हटता नहीं। पूरी तरह मूल स्थिति में लौटने के लिए प्रोफ़ाइल patch की terminal-controller पंक्ति से shell फ़ील्ड हटाकर DSH पुनः आरंभ करें।",
|
|
353
365
|
"eol.label": "Git पंक्ति-अंत (Linux जैसा)",
|
|
354
366
|
"eol.hint": "मॉडल द्वारा चलाए git कमांड Linux व्यवहार अपनाते हैं: core.autocrlf=input, core.eol=lf। आपका टर्मिनल और रेपो का .gitattributes अछूते रहते हैं।",
|
|
355
367
|
"bash.label": "Git Bash पथ",
|
|
@@ -399,6 +411,8 @@ window.__ModuleLoader__.load({
|
|
|
399
411
|
"bashmiss.close": "Tutup",
|
|
400
412
|
"sub.label": "Subagen/teman tim memakai Git Bash",
|
|
401
413
|
"sub.hint": "Aktif (bawaan): subagen dan anggota tim — termasuk yang bersarang — mendapat dialek prompt, terjemahan argumen path, gema hasil, dan fakta DSH_PATH_DIALECT yang sama seperti agen utama. Nonaktif: semuanya hanya berlaku untuk agen utama dan agen yang didelegasikan berjalan dengan semantik shell resmi (prompt tidak ditulis ulang, path tidak diterjemahkan). Catatan: dsh hanya punya satu eksekutor shell per proses, jadi biner Git Bash tetap global; sakelar ini mengatur lapisan dialek/terjemahan.",
|
|
414
|
+
"term.label": "Adopsi terminal sidebar",
|
|
415
|
+
"term.hint": "Aktif secara bawaan: di Windows, shell «terminal baru» resmi disetel ke Git Bash yang terdeteksi (ditulis ke baris terminal-controller resmi lewat editor konfigurasi resmi). Tanpanya dsh memulai terminal dengan shell bawaan lingkungan, dan bash di PATH sering kali peluncur WSL — terminal baru pun berjalan di Ubuntu. Penulisan hanya terjadi bila baris itu TIDAK punya shell sendiri; pilihan eksplisit tidak pernah ditimpa, hanya dicatat di log host. Terminal baru langsung memakainya, yang sudah terbuka tetap seperti semula. Catatan: mematikan sakelar ini hanya menghentikan penulisan BERIKUTNYA — tidak menghapus bidang shell yang sudah tertulis di konfigurasi profil. Untuk kembali persis seperti semula, hapus bidang shell dari baris terminal-controller di patch profil lalu mulai ulang DSH.",
|
|
402
416
|
"eol.label": "akhir baris Git (sama seperti Linux)",
|
|
403
417
|
"eol.hint": "Perintah git yang dijalankan model mengikuti perilaku Linux: core.autocrlf=input, core.eol=lf. Terminal Anda dan .gitattributes repo tidak terpengaruh.",
|
|
404
418
|
"bash.label": "Path Git Bash",
|
|
@@ -448,6 +462,8 @@ window.__ModuleLoader__.load({
|
|
|
448
462
|
"bashmiss.close": "Chiudi",
|
|
449
463
|
"sub.label": "Subagenti/compagni usano Git Bash",
|
|
450
464
|
"sub.hint": "Attivo (predefinito): subagenti e membri del team — anche annidati — ricevono lo stesso dialetto del prompt, la stessa traduzione dei percorsi negli argomenti, lo stesso eco dei risultati e lo stesso fatto DSH_PATH_DIALECT dell'agente principale. Disattivo: valgono solo per l'agente principale e gli agenti delegati usano le semantiche di shell ufficiali (nessuna riscrittura del prompt, nessuna traduzione dei percorsi). Nota: dsh ha un solo esecutore di shell per processo, quindi il binario Git Bash resta globale; questo interruttore governa gli strati di dialetto e traduzione.",
|
|
465
|
+
"term.label": "Adotta il terminale laterale",
|
|
466
|
+
"term.hint": "Attivo per impostazione predefinita: su Windows la shell del «nuovo terminale» ufficiale viene impostata sul Git Bash rilevato (scritto nella riga ufficiale terminal-controller tramite l'editor di configurazione ufficiale). Senza questo dsh avvia il terminale con la shell predefinita dell'ambiente, e il bash nel PATH è spesso l'avviatore WSL — così il nuovo terminale gira su Ubuntu. La scrittura avviene solo se quella riga NON ha una shell propria; una scelta esplicita non viene mai sovrascritta, solo annotata nel log dell'host. I nuovi terminali la usano subito, quelli già aperti mantengono la loro shell. Nota: disattivare questo interruttore ferma solo le scritture FUTURE — non rimuove un campo shell già scritto nella configurazione del profilo. Per tornare esattamente allo stato iniziale, elimina il campo shell dalla riga terminal-controller nel patch del profilo e riavvia DSH.",
|
|
451
467
|
"eol.label": "fine riga Git (come Linux)",
|
|
452
468
|
"eol.hint": "I comandi git eseguiti dal modello seguono il comportamento Linux: core.autocrlf=input, core.eol=lf. Il tuo terminale e i .gitattributes del repo non vengono toccati.",
|
|
453
469
|
"bash.label": "Percorso Git Bash",
|
|
@@ -497,6 +513,8 @@ window.__ModuleLoader__.load({
|
|
|
497
513
|
"bashmiss.close": "閉じる",
|
|
498
514
|
"sub.label": "サブエージェント/チームメンバーも Git Bash を使う",
|
|
499
515
|
"sub.hint": "オン(既定):サブエージェントとチームメンバー(ネスト含む)は、メインエージェントと同じプロンプト方言・パス引数の翻訳・結果エコー・DSH_PATH_DIALECT の事実を受け取ります。オフ:これらはメインエージェントのみに適用され、委譲されたエージェントは公式の shell セマンティクスで動作します(プロンプト改写なし、パス翻訳なし)。なお dsh はプロセスごとに shell 実行器を 1 つだけ持つため、Git Bash バイナリ自体は常に全体共通です。このスイッチが制御するのは方言/翻訳の層です。",
|
|
516
|
+
"term.label": "サイドバー端末を引き継ぐ",
|
|
517
|
+
"term.hint": "既定でオン:Windows では公式の「新しいターミナル」の shell を検出した Git Bash に設定します(公式の設定エディター経由で公式 terminal-controller 行に書き込み)。これがないと dsh は環境既定の shell で端末を起動し、PATH の bash はしばしば WSL ランチャーなので新しい端末は Ubuntu で動きます。書き込むのはその行に独自の shell が**ない**ときだけです。明示的な選択は決して上書きせず、ホストログに記録するだけです。新しい端末には即時反映され、開いている端末はそのままです。 注意:このスイッチを切っても**今後**の自動書き込みが止まるだけで、すでにプロファイル設定に書き込まれた shell フィールドは削除されません。完全に元へ戻すには、プロファイル patch の terminal-controller 行から shell フィールドを削除して DSH を再起動してください。",
|
|
500
518
|
"eol.label": "Git の行末(Linux と同じ)",
|
|
501
519
|
"eol.hint": "モデルが実行する git コマンドは Linux と同じ挙動になります: core.autocrlf=input、core.eol=lf。あなたのターミナルやリポジトリの .gitattributes は影響を受けません。",
|
|
502
520
|
"bash.label": "Git Bash パス",
|
|
@@ -546,6 +564,8 @@ window.__ModuleLoader__.load({
|
|
|
546
564
|
"bashmiss.close": "닫기",
|
|
547
565
|
"sub.label": "서브에이전트/팀원도 Git Bash 사용",
|
|
548
566
|
"sub.hint": "켬(기본): 서브에이전트와 팀원(중첩 포함)은 메인 에이전트와 동일한 프롬프트 방언, 경로 인자 번역, 결과 에코, DSH_PATH_DIALECT 사실을 받습니다. 끔: 이것들은 메인 에이전트에만 적용되고 위임된 에이전트는 공식 shell 의미로 동작합니다(프롬프트 재작성 없음, 경로 번역 없음). 참고로 dsh는 프로세스당 shell 실행기가 하나뿐이라 Git Bash 바이너리 자체는 항상 전역입니다. 이 스위치는 방언/번역 계층을 제어합니다.",
|
|
567
|
+
"term.label": "사이드바 터미널 자동 인수",
|
|
568
|
+
"term.hint": "기본 켜짐: Windows에서 공식 «새 터미널»의 shell을 감지된 Git Bash로 설정합니다(공식 구성 편집기를 통해 공식 terminal-controller 행에 기록). 이것이 없으면 dsh는 환경 기본 shell로 터미널을 시작하고, PATH의 bash는 흔히 WSL 런처라서 새 터미널이 Ubuntu로 실행됩니다. 해당 행에 자체 shell이 **없을 때만** 기록하며, 명시적 선택은 절대 덮어쓰지 않고 호스트 로그에만 남깁니다. 새 터미널에는 즉시 적용되고 이미 열린 터미널은 그대로입니다. 참고: 이 스위치를 꺼도 앞으로의 자동 쓰기만 멈출 뿐, 이미 프로필 설정에 기록된 shell 필드는 삭제되지 않습니다. 완전히 원래대로 되돌리려면 프로필 patch의 terminal-controller 행에서 shell 필드를 지우고 DSH를 다시 시작하세요.",
|
|
549
569
|
"eol.label": "Git 줄바꿈(Linux와 동일)",
|
|
550
570
|
"eol.hint": "모델이 실행하는 git 명령은 Linux 동작을 따릅니다: core.autocrlf=input, core.eol=lf. 사용자의 터미널과 저장소의 .gitattributes는 영향을 받지 않습니다.",
|
|
551
571
|
"bash.label": "Git Bash 경로",
|
|
@@ -595,6 +615,8 @@ window.__ModuleLoader__.load({
|
|
|
595
615
|
"bashmiss.close": "Sluiten",
|
|
596
616
|
"sub.label": "Subagenten/teammaten gebruiken Git Bash",
|
|
597
617
|
"sub.hint": "Aan (standaard): subagenten en teamleden — ook geneste — krijgen hetzelfde promptdialect, dezelfde padargument-vertaling, dezelfde resultaat-echo en hetzelfde DSH_PATH_DIALECT-feit als de hoofdagent. Uit: die gelden alleen voor de hoofdagent en gedelegeerde agenten draaien met de officiële shell-semantiek (geen promptherschrijving, geen padvertaling). Let op: dsh heeft één shell-uitvoerder per proces, dus het Git Bash-binary blijft globaal; deze schakelaar beheert de dialect-/vertaallagen.",
|
|
618
|
+
"term.label": "Zijbalkterminal overnemen",
|
|
619
|
+
"term.hint": "Standaard aan: op Windows wordt de shell van de officiële ‘nieuwe terminal’ gezet op de gevonden Git Bash (geschreven in de officiële terminal-controller-regel via de officiële configuratie-editor). Zonder dit start dsh de terminal met de omgevings-standaardshell, en de bash in PATH is vaak de WSL-starter — dan draait de nieuwe terminal Ubuntu. Er wordt alleen geschreven als die regel GEEN eigen shell heeft; een expliciete keuze wordt nooit overschreven, alleen in het hostlogboek vermeld. Nieuwe terminals gebruiken het direct, al geopende behouden hun shell. Let op: deze schakelaar uitzetten stopt alleen TOEKOMSTIGE schrijfacties — een al in de profielconfiguratie geschreven shell-veld wordt niet verwijderd. Voor exact de oorspronkelijke staat: verwijder het shell-veld uit de terminal-controller-regel in de profielpatch en herstart DSH.",
|
|
598
620
|
"eol.label": "Git regeleinden (zoals Linux)",
|
|
599
621
|
"eol.hint": "Git-opdrachten die het model uitvoert volgen Linux-gedrag: core.autocrlf=input, core.eol=lf. Je eigen terminal en de .gitattributes van een repo blijven onaangetast.",
|
|
600
622
|
"bash.label": "Git Bash-pad",
|
|
@@ -644,6 +666,8 @@ window.__ModuleLoader__.load({
|
|
|
644
666
|
"bashmiss.close": "Zamknij",
|
|
645
667
|
"sub.label": "Subagenci/członkowie zespołu używają Git Bash",
|
|
646
668
|
"sub.hint": "Wł. (domyślnie): subagenci i członkowie zespołu — także zagnieżdżeni — otrzymują ten sam dialekt podpowiedzi, tłumaczenie argumentów ścieżek, echo wyników i fakt DSH_PATH_DIALECT co agent główny. Wył.: dotyczy to tylko agenta głównego, a agenci delegowani działają według oficjalnej semantyki powłoki (bez przepisywania podpowiedzi i tłumaczenia ścieżek). Uwaga: dsh ma jeden executor powłoki na proces, więc binarka Git Bash pozostaje globalna; ten przełącznik steruje warstwami dialektu i tłumaczenia.",
|
|
669
|
+
"term.label": "Przejmij terminal boczny",
|
|
670
|
+
"term.hint": "Domyślnie włączone: w Windows shell oficjalnego „nowego terminala“ jest ustawiany na wykryty Git Bash (zapis do oficjalnego wiersza terminal-controller przez oficjalny edytor konfiguracji). Bez tego dsh uruchamia terminal z domyślnym shellem środowiska, a bash w PATH to często launcher WSL — nowy terminal działa wtedy w Ubuntu. Zapis następuje tylko wtedy, gdy ten wiersz NIE ma własnego shella; wyraźny wybór nigdy nie jest nadpisywany, trafia jedynie do logu hosta. Nowe terminale korzystają od razu, otwarte zachowują swój shell. Uwaga: wyłączenie tego przełącznika wstrzymuje tylko PRZYSZŁE zapisy — nie usuwa pola shell już zapisanego w konfiguracji profilu. Aby wrócić dokładnie do stanu pierwotnego, usuń pole shell z wiersza terminal-controller w patchu profilu i uruchom DSH ponownie.",
|
|
647
671
|
"eol.label": "końce linii Git (jak w Linuksie)",
|
|
648
672
|
"eol.hint": "Polecenia git uruchamiane przez model działają jak w Linuksie: core.autocrlf=input, core.eol=lf. Twój terminal i .gitattributes repozytorium pozostają nietknięte.",
|
|
649
673
|
"bash.label": "Ścieżka Git Bash",
|
|
@@ -693,6 +717,8 @@ window.__ModuleLoader__.load({
|
|
|
693
717
|
"bashmiss.close": "Fechar",
|
|
694
718
|
"sub.label": "Subagentes/membros da equipa usam Git Bash",
|
|
695
719
|
"sub.hint": "Ligado (padrão): subagentes e membros da equipa — incluindo aninhados — recebem o mesmo dialeto de prompt, tradução de caminhos nos argumentos, eco de resultados e o mesmo facto DSH_PATH_DIALECT que o agente principal. Desligado: isso aplica-se apenas ao agente principal e os agentes delegados correm com a semântica oficial da shell (sem reescrita do prompt nem tradução de caminhos). Nota: o dsh tem um único executor de shell por processo, pelo que o binário Git Bash continua global; este interruptor governa as camadas de dialeto e tradução.",
|
|
720
|
+
"term.label": "Adotar o terminal lateral",
|
|
721
|
+
"term.hint": "Ativado por predefinição: no Windows, o shell do «novo terminal» oficial é definido para o Git Bash detetado (escrito na linha oficial terminal-controller através do editor de configuração oficial). Sem isto, o dsh inicia o terminal com o shell predefinido do ambiente, e o bash no PATH é muitas vezes o lançador WSL — o novo terminal corre então em Ubuntu. Só escreve quando essa linha NÃO tem shell próprio; uma escolha explícita nunca é substituída, apenas registada no log do anfitrião. Os novos terminais usam-no de imediato, os já abertos mantêm o seu shell. Nota: desligar este interruptor só impede escritas FUTURAS — não remove um campo shell já escrito na configuração do perfil. Para voltar exatamente ao original, apague o campo shell da linha terminal-controller no patch do perfil e reinicie o dsh.",
|
|
696
722
|
"eol.label": "fins de linha do Git (como no Linux)",
|
|
697
723
|
"eol.hint": "Os comandos git executados pelo modelo seguem o comportamento do Linux: core.autocrlf=input, core.eol=lf. O seu terminal e os .gitattributes do repositório não são afetados.",
|
|
698
724
|
"bash.label": "Caminho do Git Bash",
|
|
@@ -742,6 +768,8 @@ window.__ModuleLoader__.load({
|
|
|
742
768
|
"bashmiss.close": "Закрыть",
|
|
743
769
|
"sub.label": "Субагенты и участники команды используют Git Bash",
|
|
744
770
|
"sub.hint": "Вкл. (по умолчанию): субагенты и участники команды — включая вложенных — получают тот же диалект подсказки, перевод путей в аргументах, эхо результатов и факт DSH_PATH_DIALECT, что и главный агент. Выкл.: это применяется только к главному агенту, а делегированные агенты работают с официальной семантикой оболочки (без перезаписи подсказки и перевода путей). Учтите: в dsh один исполнитель оболочки на процесс, поэтому сам бинарник Git Bash остаётся общим; этот переключатель управляет слоями диалекта и перевода.",
|
|
771
|
+
"term.label": "Перенимать боковой терминал",
|
|
772
|
+
"term.hint": "Включено по умолчанию: в Windows shell официального «нового терминала» выставляется в найденный Git Bash (запись в официальную строку terminal-controller через официальный редактор конфигурации). Без этого dsh запускает терминал с shell по умолчанию из окружения, а bash в PATH часто оказывается лаунчером WSL — тогда новый терминал работает в Ubuntu. Запись происходит только если у этой строки НЕТ собственного shell; явный выбор никогда не перезаписывается, о нём лишь сообщается в журнале хоста. Новые терминалы подхватывают сразу, уже открытые сохраняют свой shell. Примечание: выключение этого переключателя останавливает только БУДУЩИЕ записи — уже записанное в конфигурацию профиля поле shell не удаляется. Чтобы вернуть всё точно как было, удалите поле shell из строки terminal-controller в патче профиля и перезапустите dsh.",
|
|
745
773
|
"eol.label": "переводы строк Git (как в Linux)",
|
|
746
774
|
"eol.hint": "Команды git, запускаемые моделью, ведут себя как в Linux: core.autocrlf=input, core.eol=lf. Ваш терминал и .gitattributes репозитория не затрагиваются.",
|
|
747
775
|
"bash.label": "Путь Git Bash",
|
|
@@ -791,6 +819,8 @@ window.__ModuleLoader__.load({
|
|
|
791
819
|
"bashmiss.close": "Stäng",
|
|
792
820
|
"sub.label": "Subagenter/teammedlemmar använder Git Bash",
|
|
793
821
|
"sub.hint": "På (standard): subagenter och teammedlemmar — även nästlade — får samma promptdialekt, samma sökvägsöversättning i argument, samma resultat-eko och samma DSH_PATH_DIALECT-faktum som huvudagenten. Av: detta gäller bara huvudagenten och delegerade agenter kör med officiell shell-semantik (ingen promptomskrivning, ingen sökvägsöversättning). Obs: dsh har en enda shell-exekutor per process, så Git Bash-binären är fortfarande global; den här växeln styr dialekt-/översättningslagren.",
|
|
822
|
+
"term.label": "Ta över sidofältsterminalen",
|
|
823
|
+
"term.hint": "På som standard: i Windows sätts det officiella ”nya terminalens” shell till den hittade Git Bash (skrivs till den officiella terminal-controller-raden via den officiella konfigurationsredigeraren). Utan detta startar dsh terminalen med miljöns standardshell, och bash i PATH är ofta WSL-startaren — då kör den nya terminalen Ubuntu. Det skrivs bara när raden INTE har ett eget shell; ett uttryckligt val skrivs aldrig över, det loggas bara hos värden. Nya terminaler tar det direkt, redan öppna behåller sitt shell. Obs: att stänga av reglaget stoppar bara FRAMTIDA skrivningar — ett shell-fält som redan skrivits till profilkofiguren tas inte bort. För att återställa exakt: ta bort shell-fältet från terminal-controller-raden i profilpatchningen och starta om dsh.",
|
|
794
824
|
"eol.label": "Git radslut (som Linux)",
|
|
795
825
|
"eol.hint": "Git-kommandon som modellen kör följer Linux-beteende: core.autocrlf=input, core.eol=lf. Din egen terminal och repots .gitattributes påverkas inte.",
|
|
796
826
|
"bash.label": "Git Bash-sökväg",
|
|
@@ -840,6 +870,8 @@ window.__ModuleLoader__.load({
|
|
|
840
870
|
"bashmiss.close": "ปิด",
|
|
841
871
|
"sub.label": "ซับเอเจนต์/สมาชิกทีมใช้ Git Bash",
|
|
842
872
|
"sub.hint": "เปิด (ค่าเริ่มต้น): ซับเอเจนต์และสมาชิกทีม — รวมถึงแบบซ้อน — ได้รับไดอาเลกต์พรอมป์ต์ การแปลพาธในอาร์กิวเมนต์ การสะท้อนผลลัพธ์ และข้อเท็จจริง DSH_PATH_DIALECT เหมือนเอเจนต์หลัก ปิด: สิ่งเหล่านี้มีผลกับเอเจนต์หลักเท่านั้น และเอเจนต์ที่ถูกมอบหมายทำงานด้วยความหมาย shell อย่างเป็นทางการ (ไม่เขียนพรอมป์ต์ใหม่ ไม่แปลพาธ) หมายเหตุ dsh มีตัวรัน shell เดียวต่อโปรเซส ไบนารี Git Bash จึงยังเป็นส่วนกลาง สวิตช์นี้ควบคุมชั้นไดอาเลกต์/การแปล",
|
|
873
|
+
"term.label": "รับช่วงเทอร์มินัลแถบข้าง",
|
|
874
|
+
"term.hint": "เปิดโดยค่าเริ่มต้น: บน Windows shell ของ «เทอร์มินัลใหม่» อย่างเป็นทางการจะถูกตั้งเป็น Git Bash ที่ตรวจพบ (เขียนลงแถว terminal-controller อย่างเป็นทางการผ่านตัวแก้ไขการตั้งค่าอย่างเป็นทางการ) หากไม่มีสิ่งนี้ dsh จะเริ่มเทอร์มินัลด้วย shell เริ่มต้นของสภาพแวดล้อม และ bash ใน PATH มักเป็นตัวเรียก WSL เทอร์มินัลใหม่จึงรันเป็น Ubuntu จะเขียนก็ต่อเมื่อแถวนั้นไม่มี shell ของตัวเองเท่านั้น การเลือกที่ผู้ใช้ระบุไว้จะไม่ถูกเขียนทับ เพียงบันทึกในบันทึกของโฮสต์ เทอร์มินัลใหม่ใช้ทันที ส่วนที่เปิดอยู่แล้วคงเดิม หมายเหตุ: การปิดสวิตช์นี้หยุดเฉพาะการเขียนครั้งต่อไป ไม่ได้ลบฟิลด์ shell ที่เขียนลงการตั้งค่าโปรไฟล์แล้ว หากต้องการกลับสู่สภาพเดิมจริง ๆ ให้ลบฟิลด์ shell ออกจากแถว terminal-controller ใน patch ของโปรไฟล์แล้วรีสตาร์ต dsh",
|
|
843
875
|
"eol.label": "อักขระขึ้นบรรทัด Git (เหมือน Linux)",
|
|
844
876
|
"eol.hint": "คำสั่ง git ที่โมเดลรันจะใช้พฤติกรรมแบบ Linux: core.autocrlf=input, core.eol=lf เทอร์มินัลของคุณและ .gitattributes ของ repo ไม่ได้รับผลกระทบ",
|
|
845
877
|
"bash.label": "เส้นทาง Git Bash",
|
|
@@ -889,6 +921,8 @@ window.__ModuleLoader__.load({
|
|
|
889
921
|
"bashmiss.close": "Kapat",
|
|
890
922
|
"sub.label": "Alt ajanlar/ekip üyeleri Git Bash kullansın",
|
|
891
923
|
"sub.hint": "Açık (varsayılan): alt ajanlar ve ekip üyeleri — iç içe olanlar dahil — ana ajanla aynı istem lehçesini, yol argümanı çevirisini, sonuç yankısını ve DSH_PATH_DIALECT gerçeğini alır. Kapalı: bunlar yalnızca ana ajan için geçerlidir ve devredilen ajanlar resmî shell semantiğiyle çalışır (istem yeniden yazılmaz, yollar çevrilmez). Not: dsh'de süreç başına tek bir shell yürütücüsü vardır, bu yüzden Git Bash ikilisi genele aittir; bu anahtar lehçe/çeviri katmanlarını yönetir.",
|
|
924
|
+
"term.label": "Kenar çubuğu terminalini devral",
|
|
925
|
+
"term.hint": "Varsayılan olarak açık: Windows'ta resmî «yeni terminal»in shell'i algılanan Git Bash olarak ayarlanır (resmî yapılandırma düzenleyicisi üzerinden resmî terminal-controller satırına yazılır). Bu olmadan dsh terminali ortamın varsayılan shell'iyle başlatır ve PATH'teki bash çoğu zaman WSL başlatıcısıdır — yeni terminal Ubuntu'da çalışır. Yalnızca o satırın KENDİ shell'i yoksa yazılır; açık bir seçim asla üzerine yazılmaz, sadece host günlüğüne düşer. Yeni terminaller anında kullanır, açık olanlar kendi shell'ini korur. Not: Bu anahtarı kapatmak yalnızca BUNDAN SONRAKİ yazmaları durdurur — profil yapılandırmasına yazılmış shell alanını silmez. Tam olarak eski hâle dönmek için profil patch'indeki terminal-controller satırından shell alanını silip dsh'yi yeniden başlatın.",
|
|
892
926
|
"eol.label": "Git satır sonları (Linux gibi)",
|
|
893
927
|
"eol.hint": "Modelin çalıştırdığı git komutları Linux davranışını izler: core.autocrlf=input, core.eol=lf. Kendi terminaliniz ve deponun .gitattributes dosyası etkilenmez.",
|
|
894
928
|
"bash.label": "Git Bash yolu",
|
|
@@ -938,6 +972,8 @@ window.__ModuleLoader__.load({
|
|
|
938
972
|
"bashmiss.close": "Đóng",
|
|
939
973
|
"sub.label": "Subagent/thành viên nhóm dùng Git Bash",
|
|
940
974
|
"sub.hint": "Bật (mặc định): subagent và thành viên nhóm — kể cả lồng nhau — nhận cùng phương ngữ prompt, cách dịch đường dẫn trong tham số, tiếng vọng kết quả và sự thật DSH_PATH_DIALECT như agent chính. Tắt: những thứ này chỉ áp dụng cho agent chính, còn agent được ủy quyền chạy theo ngữ nghĩa shell chính thức (không viết lại prompt, không dịch đường dẫn). Lưu ý dsh chỉ có một bộ thực thi shell mỗi tiến trình, nên tệp nhị phân Git Bash vẫn là toàn cục; công tắc này điều khiển tầng phương ngữ/dịch.",
|
|
975
|
+
"term.label": "Tiếp quản terminal thanh bên",
|
|
976
|
+
"term.hint": "Bật theo mặc định: trên Windows, shell của «terminal mới» chính thức được đặt thành Git Bash đã phát hiện (ghi vào dòng terminal-controller chính thức qua trình sửa cấu hình chính thức). Không có nó, dsh khởi động terminal bằng shell mặc định của môi trường, và bash trong PATH thường là trình khởi chạy WSL — terminal mới sẽ chạy Ubuntu. Chỉ ghi khi dòng đó KHÔNG có shell riêng; lựa chọn rõ ràng không bao giờ bị ghi đè, chỉ ghi vào nhật ký máy chủ. Terminal mới dùng ngay, terminal đang mở giữ nguyên. Lưu ý: tắt công tắc này chỉ dừng các lần ghi TIẾP THEO — không xóa trường shell đã ghi vào cấu hình hồ sơ. Để khôi phục y nguyên, hãy xóa trường shell khỏi dòng terminal-controller trong patch của hồ sơ rồi khởi động lại dsh.",
|
|
941
977
|
"eol.label": "kết thúc dòng Git (giống Linux)",
|
|
942
978
|
"eol.hint": "Các lệnh git do mô hình chạy theo hành vi Linux: core.autocrlf=input, core.eol=lf. Terminal của bạn và .gitattributes của repo không bị ảnh hưởng.",
|
|
943
979
|
"bash.label": "Đường dẫn Git Bash",
|
|
@@ -987,6 +1023,8 @@ window.__ModuleLoader__.load({
|
|
|
987
1023
|
"bashmiss.close": "閂咗佢",
|
|
988
1024
|
"sub.label": "子代理/隊員用 Git Bash",
|
|
989
1025
|
"sub.hint": "預設開啟:子代理同團隊隊員(連嵌套)嘅提示詞方言、路徑參數翻譯、結果回顯同 DSH_PATH_DIALECT 環境事實都同主代理一致。閂咗就淨係主代理有,子代理跟官方 shell 語義行(提示詞唔改寫、路徑參數唔翻譯);留意 dsh 每個進程只有一個 shell 執行器,所以 Git Bash 本身仍然係全局嘅,呢個開關管嘅係方言/翻譯層。",
|
|
1026
|
+
"term.label": "自動接管側欄終端",
|
|
1027
|
+
"term.hint": "預設開啟:Windows 上會將官方「開新終端」嘅 shell 自動設成探測到嘅 Git Bash(寫入官方 terminal-controller 行嘅設定,經官方設定編輯器落盤)。冇呢一項時,dsh 會用環境預設 shell 開終端,而 PATH 嘅 bash 好多時係 WSL 啟動器,於是新終端跑嘅係 Ubuntu。只喺該行**冇**自己嘅 shell 時才寫;你已經手動指定過其他 shell 就絕對唔會覆蓋,淨係喺宿主日誌提你一句。新終端即時生效,已開嘅終端保持原狀。 注意:閂咗呢個開關只係阻止**之後**嘅自動寫入,唔會刪走已經寫入 profile 設定嘅 shell 欄位 —— 想完全還原,請喺 profile 嘅 patch 度刪走 terminal-controller 行嘅 shell 欄位再重啟 DSH。",
|
|
990
1028
|
"eol.label": "Git 行尾(與 Linux 一致)",
|
|
991
1029
|
"eol.hint": "模型執行的 git 指令採 Linux 行為:core.autocrlf=input、core.eol=lf。你自己終端的 git 與倉庫的 .gitattributes 都不受影響。",
|
|
992
1030
|
"bash.label": "Git Bash 路徑",
|
|
@@ -1036,6 +1074,8 @@ window.__ModuleLoader__.load({
|
|
|
1036
1074
|
"bashmiss.close": "閂咗佢",
|
|
1037
1075
|
"sub.label": "子代理/隊員用 Git Bash",
|
|
1038
1076
|
"sub.hint": "預設開啟:子代理同團隊隊員(連嵌套)嘅提示詞方言、路徑參數翻譯、結果回顯同 DSH_PATH_DIALECT 環境事實都同主代理一致。閂咗就淨係主代理有,子代理跟官方 shell 語義行(提示詞唔改寫、路徑參數唔翻譯);留意 dsh 每個進程只有一個 shell 執行器,所以 Git Bash 本身仍然係全局嘅,呢個開關管嘅係方言/翻譯層。",
|
|
1077
|
+
"term.label": "自動接管側欄終端",
|
|
1078
|
+
"term.hint": "預設開啟:Windows 上會將官方「開新終端」嘅 shell 自動設成探測到嘅 Git Bash(寫入官方 terminal-controller 行嘅設定,經官方設定編輯器落盤)。冇呢一項時,dsh 會用環境預設 shell 開終端,而 PATH 嘅 bash 好多時係 WSL 啟動器,於是新終端跑嘅係 Ubuntu。只喺該行**冇**自己嘅 shell 時才寫;你已經手動指定過其他 shell 就絕對唔會覆蓋,淨係喺宿主日誌提你一句。新終端即時生效,已開嘅終端保持原狀。 注意:閂咗呢個開關只係阻止**之後**嘅自動寫入,唔會刪走已經寫入 profile 設定嘅 shell 欄位 —— 想完全還原,請喺 profile 嘅 patch 度刪走 terminal-controller 行嘅 shell 欄位再重啟 DSH。",
|
|
1039
1079
|
"eol.label": "Git 行尾(與 Linux 一致)",
|
|
1040
1080
|
"eol.hint": "模型執行的 git 指令採 Linux 行為:core.autocrlf=input、core.eol=lf。你自己終端的 git 與倉庫的 .gitattributes 都不受影響。",
|
|
1041
1081
|
"bash.label": "Git Bash 路徑",
|
|
@@ -1085,6 +1125,8 @@ window.__ModuleLoader__.load({
|
|
|
1085
1125
|
"bashmiss.close": "關閉",
|
|
1086
1126
|
"sub.label": "子代理/隊員使用 Git Bash",
|
|
1087
1127
|
"sub.hint": "預設開啟:子代理與團隊隊員(含巢狀)的提示詞方言、路徑參數翻譯、結果回顯與 DSH_PATH_DIALECT 環境事實都與主代理一致。關閉後僅對主代理生效,子代理依官方 shell 語意執行(提示詞不改寫、路徑參數不翻譯);請注意 dsh 每個行程只有一個 shell 執行器,因此 Git Bash 本身仍是全域的,這個開關管的是方言/翻譯層。",
|
|
1128
|
+
"term.label": "自動接管側邊終端",
|
|
1129
|
+
"term.hint": "預設開啟:Windows 上會把官方「新增終端」的 shell 自動設為探測到的 Git Bash(寫入官方 terminal-controller 列的設定,由官方設定編輯器落盤)。沒有這一項時,dsh 會以環境預設 shell 啟動終端,而 PATH 裡的 bash 往往是 WSL 啟動器,於是新終端跑的是 Ubuntu。只在該列**沒有**自己的 shell 時才寫入;你已手動指定其他 shell 就絕不覆蓋,僅在宿主日誌提示。新終端立即生效,已開啟的終端維持原狀。 注意:關掉這個開關只會阻止**之後**的自動寫入,不會刪除已經寫進 profile 設定的 shell 欄位 —— 要徹底還原,請把 profile 的 patch 裡 terminal-controller 列的 shell 欄位刪掉再重啟 DSH。",
|
|
1088
1130
|
"eol.label": "Git 行尾(與 Linux 一致)",
|
|
1089
1131
|
"eol.hint": "模型執行的 git 指令採 Linux 行為:core.autocrlf=input、core.eol=lf。你自己終端的 git 與倉庫的 .gitattributes 都不受影響。",
|
|
1090
1132
|
"bash.label": "Git Bash 路徑",
|
|
@@ -1428,6 +1470,7 @@ window.__ModuleLoader__.load({
|
|
|
1428
1470
|
// v0.27.0: delegated agents (subagents / team members / nested
|
|
1429
1471
|
// children) participate in the dialect unless this is switched off.
|
|
1430
1472
|
var subagents = snap.value.subagentDialect !== false;
|
|
1473
|
+
var winshell = snap.value.autoTerminalShell !== false;
|
|
1431
1474
|
var eolOn = snap.value.gitAutocrlf !== false;
|
|
1432
1475
|
var dedupe = snap.value.suppressPeerCordis === true;
|
|
1433
1476
|
|
|
@@ -1488,6 +1531,15 @@ window.__ModuleLoader__.load({
|
|
|
1488
1531
|
E("button", { type: "button", className: "gb-segBtn" + (!subagents ? " gb-segActive" : ""), onClick: function () { if (subagents) writeField("subagentDialect", false); } }, t("switch.off")),
|
|
1489
1532
|
),
|
|
1490
1533
|
E("p", { className: "gb-hint" }, t("sub.hint")),
|
|
1534
|
+
E("div", { className: "gb-row" },
|
|
1535
|
+
E("span", { className: "gb-rowLabel" }, t("term.label") + ":"),
|
|
1536
|
+
E("span", { className: "gb-rowValue" }, winshell ? t("state.on") : t("state.off")),
|
|
1537
|
+
),
|
|
1538
|
+
E("div", { className: "gb-seg" },
|
|
1539
|
+
E("button", { type: "button", className: "gb-segBtn" + (winshell ? " gb-segActive" : ""), onClick: function () { if (!winshell) writeField("autoTerminalShell", true); } }, t("switch.on")),
|
|
1540
|
+
E("button", { type: "button", className: "gb-segBtn" + (!winshell ? " gb-segActive" : ""), onClick: function () { if (winshell) writeField("autoTerminalShell", false); } }, t("switch.off")),
|
|
1541
|
+
),
|
|
1542
|
+
E("p", { className: "gb-hint" }, t("term.hint")),
|
|
1491
1543
|
E("div", { className: "gb-row" },
|
|
1492
1544
|
E("span", { className: "gb-rowLabel" }, t("eol.label") + ":"),
|
|
1493
1545
|
E("span", { className: "gb-rowValue" }, eolOn ? t("state.on") : t("state.off")),
|
package/src/index.js
CHANGED
|
@@ -254,6 +254,7 @@ import {
|
|
|
254
254
|
DEFAULT_GIT_BASH, GIT_BASH_DOWNLOAD_URL, bashResolutionReport,
|
|
255
255
|
effectiveConfiguredBashPath, executorConfiguredBashPath, resolveGitBashCached, settingsBashPath,
|
|
256
256
|
} from './bash-path.js'
|
|
257
|
+
import { adoptTerminalShell, terminalAdoptReport } from './terminal-shell.js'
|
|
257
258
|
|
|
258
259
|
/** The shipped preset whose skills/ dir seeds cordis-gitbash. */
|
|
259
260
|
const SKILLS_SOURCE_PRESET = 'cordis'
|
|
@@ -887,6 +888,16 @@ export const Config = Schema === null ? undefined : Schema.object({
|
|
|
887
888
|
gitAutocrlf: live(Schema.boolean().default(true)),
|
|
888
889
|
bashPath: live(Schema.string().default('')),
|
|
889
890
|
adoptSidebar: live(Schema.boolean().default(true)),
|
|
891
|
+
/**
|
|
892
|
+
* Whether the OFFICIAL sidebar terminal ("new terminal") is switched to the
|
|
893
|
+
* resolved Git Bash (v0.29.0, task-25). Default ON — the user asked for
|
|
894
|
+
* exactly this ("自动检测 … 帮忙补上一个 gitbash 可以用"). On Windows without
|
|
895
|
+
* this, dsh resolves the terminal shell from the environment, which on a
|
|
896
|
+
* machine whose PATH `bash` is the WSL launcher means the new terminal starts
|
|
897
|
+
* Ubuntu, not Git Bash. Only ever writes when the terminal has NO shell of
|
|
898
|
+
* its own: an explicit choice is never overwritten.
|
|
899
|
+
*/
|
|
900
|
+
autoTerminalShell: live(Schema.boolean().default(true)),
|
|
890
901
|
/**
|
|
891
902
|
* Dedupe switch against dsh-ptc-cordis-preset (their issue #7, v0.25.0):
|
|
892
903
|
* ON while that plugin is installed AND materializing its `PTC 创造模式`
|
|
@@ -934,12 +945,15 @@ function makeLiveReader(ctx, config) {
|
|
|
934
945
|
subagentDialect: valueOf(config.subagentDialect) !== false,
|
|
935
946
|
bashPath: typeof bash === 'string' ? bash : '',
|
|
936
947
|
adoptSidebar: valueOf(config.adoptSidebar) !== false,
|
|
948
|
+
// Default ON (v0.29.0): the official terminal is ours unless opted out.
|
|
949
|
+
autoTerminalShell: valueOf(config.autoTerminalShell) !== false,
|
|
937
950
|
}
|
|
938
951
|
}
|
|
939
952
|
return {
|
|
940
953
|
dialect,
|
|
941
954
|
posix: () => dialect().posixPaths === true,
|
|
942
955
|
adoptSidebar: () => dialect().adoptSidebar !== false,
|
|
956
|
+
autoTerminalShell: () => dialect().autoTerminalShell !== false,
|
|
943
957
|
// Default OFF on both eras: only an explicit true asks for deduplication.
|
|
944
958
|
suppressPeerCordis: () => (legacy || !hasConfig ? readSuppressPeerCordis(ctx) : valueOf(config.suppressPeerCordis) === true),
|
|
945
959
|
}
|
|
@@ -1006,7 +1020,7 @@ export function readPosixPaths(ctxLike) {
|
|
|
1006
1020
|
* first. All default ON (schema defaults); never throws.
|
|
1007
1021
|
*/
|
|
1008
1022
|
export function readDialectSettings(ctxLike) {
|
|
1009
|
-
const fallback = { posixPaths: false, virtualMounts: false, globSplit: false, errorDialect: false, codePaths: false, gitAutocrlf: false, bashPath: '', subagentDialect: true }
|
|
1023
|
+
const fallback = { posixPaths: false, virtualMounts: false, globSplit: false, errorDialect: false, codePaths: false, gitAutocrlf: false, bashPath: '', subagentDialect: true, autoTerminalShell: true }
|
|
1010
1024
|
try {
|
|
1011
1025
|
const settings = ctxLike && typeof ctxLike.get === 'function' ? ctxLike.get('settings') : undefined
|
|
1012
1026
|
const value = settings && typeof settings.get === 'function' ? settings.get(SETTINGS_NAMESPACE) : undefined
|
|
@@ -1019,6 +1033,8 @@ export function readDialectSettings(ctxLike) {
|
|
|
1019
1033
|
codePaths: v.codePaths === true,
|
|
1020
1034
|
// An old host without the key keeps the default (delegated agents covered).
|
|
1021
1035
|
subagentDialect: v.subagentDialect !== false,
|
|
1036
|
+
// Default ON: a host without the key still gets the terminal adoption.
|
|
1037
|
+
autoTerminalShell: v.autoTerminalShell !== false,
|
|
1022
1038
|
gitAutocrlf: v.gitAutocrlf === true,
|
|
1023
1039
|
bashPath: typeof v.bashPath === 'string' ? v.bashPath : '',
|
|
1024
1040
|
}
|
|
@@ -2415,6 +2431,8 @@ export async function apply(ctx, config = {}) {
|
|
|
2415
2431
|
gitAutocrlf: Schema.boolean().default(true),
|
|
2416
2432
|
bashPath: Schema.string().default(''),
|
|
2417
2433
|
adoptSidebar: Schema.boolean().default(true),
|
|
2434
|
+
// v0.29.0: official sidebar terminal adoption (default ON).
|
|
2435
|
+
autoTerminalShell: Schema.boolean().default(true),
|
|
2418
2436
|
// v0.25.0: same switch as the row Config carries on dsh >= 0.1.7
|
|
2419
2437
|
// (the OLD era has no cross-namespace edits, so this namespace is
|
|
2420
2438
|
// the only side that can change it here).
|
|
@@ -2754,6 +2772,49 @@ export async function apply(ctx, config = {}) {
|
|
|
2754
2772
|
}
|
|
2755
2773
|
}
|
|
2756
2774
|
|
|
2775
|
+
// ── OFFICIAL sidebar terminal adoption (v0.29.0, task-25) ──────────────
|
|
2776
|
+
// User report: dsh's own "new terminal" started WSL, because
|
|
2777
|
+
// `terminal-controller` falls back to the execution environment's default
|
|
2778
|
+
// shell and on that machine PATH's `bash` is the System32 WSL launcher.
|
|
2779
|
+
// The settings service CANNOT be used here (measured: `shell` is not a
|
|
2780
|
+
// volatile field, and there is no `terminal` configurable entry), so this
|
|
2781
|
+
// goes through `configEditor.edit()` — the API the official settings UI
|
|
2782
|
+
// persists through — and it only ever writes when the terminal has no shell
|
|
2783
|
+
// of its own. See src/terminal-shell.js for the full rationale.
|
|
2784
|
+
if (process.platform === 'win32') {
|
|
2785
|
+
try {
|
|
2786
|
+
ctx.inject(['configEditor'], (editorCtx) => {
|
|
2787
|
+
// The terminal row may activate after this plugin; retry a few times
|
|
2788
|
+
// (bounded) instead of silently giving up, and never spam the log.
|
|
2789
|
+
let attempts = 0
|
|
2790
|
+
const run = async () => {
|
|
2791
|
+
attempts += 1
|
|
2792
|
+
let result
|
|
2793
|
+
try {
|
|
2794
|
+
result = await adoptTerminalShell(editorCtx.configEditor, {
|
|
2795
|
+
platform: process.platform,
|
|
2796
|
+
enabled: liveSettings.autoTerminalShell(),
|
|
2797
|
+
resolved: bashResolution.ok ? bashResolution.path : '',
|
|
2798
|
+
})
|
|
2799
|
+
} catch (error) {
|
|
2800
|
+
// adoptTerminalShell reports expected conditions itself; reaching
|
|
2801
|
+
// here means something unexpected — say so instead of swallowing it.
|
|
2802
|
+
console.log(`${TAG} official sidebar terminal adoption crashed: ${error?.message ?? error}`)
|
|
2803
|
+
return
|
|
2804
|
+
}
|
|
2805
|
+
if (result.status === 'skip-row-absent' && attempts < 6) {
|
|
2806
|
+
setTimeout(() => { run().catch((error) => console.log(`${TAG} official sidebar terminal adoption retry failed: ${error?.message ?? error}`)) }, 3000)
|
|
2807
|
+
return
|
|
2808
|
+
}
|
|
2809
|
+
console.log(`${TAG} ${terminalAdoptReport(result)}`)
|
|
2810
|
+
}
|
|
2811
|
+
run().catch((error) => console.log(`${TAG} official sidebar terminal adoption failed: ${error?.message ?? error}`))
|
|
2812
|
+
})
|
|
2813
|
+
} catch (error) {
|
|
2814
|
+
console.log(`${TAG} official sidebar terminal adoption wiring failed: ${error?.message ?? error}`)
|
|
2815
|
+
}
|
|
2816
|
+
}
|
|
2817
|
+
|
|
2757
2818
|
// ── dsh-better-sidebar terminal adoption (Windows only) ────────────────
|
|
2758
2819
|
// The sidebar resolves its terminal shell through the settings seam per
|
|
2759
2820
|
// open; adopt it through that seam (see adoptSidebarShell for rationale).
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dsh-gitbash-shell — OFFICIAL sidebar terminal adoption (v0.29.0, task-25).
|
|
3
|
+
*
|
|
4
|
+
* THE PROBLEM (user report, Windows 11): dsh's own "new terminal" starts WSL,
|
|
5
|
+
* not Git Bash. `terminal-controller` resolves its shell from
|
|
6
|
+
* `subprocess.terminalEnvironment().defaultShell` when no `shell` is configured,
|
|
7
|
+
* and on that machine the PATH hit for `bash` is
|
|
8
|
+
* `C:\WINDOWS\system32\bash.EXE` — the Microsoft WSL launcher. The agent tools
|
|
9
|
+
* are already ours (`pwsh-sandbox` out, `gitbash-executor` in), but the sidebar
|
|
10
|
+
* terminal is a DIFFERENT row with a different shell resolution, so it kept
|
|
11
|
+
* starting WSL.
|
|
12
|
+
*
|
|
13
|
+
* WHY THIS MODULE TALKS TO `configEditor` AND NOT TO `settings`
|
|
14
|
+
* (measured on dsh 0.1.7-rc.2, probe readout in the task notes):
|
|
15
|
+
* - `settings.update('terminal', …)` is impossible twice over:
|
|
16
|
+
* `SettingsService.write()` requires every written path to be VOLATILE
|
|
17
|
+
* (`volatileForm(schema)` → `undefined` ⇒ "Plugin entry … has no volatile
|
|
18
|
+
* fields"), and `terminal-controller`'s Config declares `shell` as an
|
|
19
|
+
* ordinary field. The probe also showed no `terminal` entry at all
|
|
20
|
+
* ("No configurable plugin entry \"terminal\"").
|
|
21
|
+
* - `configEditor.edit(entry, change)` is the API the official settings UI
|
|
22
|
+
* itself persists through, documented as "ordinary fields keep normal
|
|
23
|
+
* lifecycle rules". The probe wrote `shell` and the RUNNING
|
|
24
|
+
* `ctx.terminalController.config.shell` carried it on the next read — no
|
|
25
|
+
* restart. The write lands in the profile patch document through the
|
|
26
|
+
* official YAML editor (comment-preserving, id-merged, file-locked); we
|
|
27
|
+
* never hand-edit that file ourselves.
|
|
28
|
+
*
|
|
29
|
+
* HARD RULES (same discipline as §4h):
|
|
30
|
+
* 1. NEVER overwrite an explicit choice. If the terminal already points
|
|
31
|
+
* somewhere else (another bash, a WSL profile, pwsh), we log and stop —
|
|
32
|
+
* the user's decision outranks our automation.
|
|
33
|
+
* 2. NEVER write a shell we have not verified. `resolveShell` rejects an
|
|
34
|
+
* unresolvable path with `SubprocessExecutableNotFoundError` and has NO
|
|
35
|
+
* fallback, so a bad write would break the new-terminal button outright.
|
|
36
|
+
* The path written here is always the one `src/bash-path.js` verified
|
|
37
|
+
* (exists + Git-for-Windows layout + `.windows.` fingerprint + `uname -s`
|
|
38
|
+
* = MINGW*_NT-*).
|
|
39
|
+
* 3. NEVER claim success without reading the value back. `edit()` resolving
|
|
40
|
+
* is not proof the row carries our shell, so `adoptTerminalShell` re-reads
|
|
41
|
+
* `configuration()` and reports `write-failed` when the value is not there
|
|
42
|
+
* (§4h: no silent false success).
|
|
43
|
+
*/
|
|
44
|
+
|
|
45
|
+
import { normalizeBashPath } from './bash-path.js'
|
|
46
|
+
|
|
47
|
+
/** The Loader row id of the official terminal controller. */
|
|
48
|
+
export const TERMINAL_ROW_ID = 'terminal-controller'
|
|
49
|
+
|
|
50
|
+
/** Profile name written for Git Bash — matches the official `profile()` output. */
|
|
51
|
+
export const TERMINAL_SHELL_NAME = 'bash'
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Arguments written for Git Bash. `['-i']` is not our invention: the official
|
|
55
|
+
* `profile()` in `packages/api/terminal-controller/src/shells.ts` derives
|
|
56
|
+
* exactly `['-i']` for any shell that is not cmd/pwsh/powershell, and `-i`
|
|
57
|
+
* makes bash read its rc files in the interactive terminal.
|
|
58
|
+
*/
|
|
59
|
+
export const TERMINAL_SHELL_ARGS = ['-i']
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* The shell profile we write into `terminal-controller`'s config.
|
|
63
|
+
* @param path - verified Git Bash path.
|
|
64
|
+
* @returns the `{ path, name, args }` profile.
|
|
65
|
+
*/
|
|
66
|
+
export function terminalShellProfile(path) {
|
|
67
|
+
return { path, name: TERMINAL_SHELL_NAME, args: [...TERMINAL_SHELL_ARGS] }
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* The effective explicit shell of the terminal row: the user patch's override
|
|
72
|
+
* wins over the composed bundle default (which is usually absent). Treats a
|
|
73
|
+
* malformed shape as "not set" so a broken hand edit cannot make us believe
|
|
74
|
+
* there is a user choice to respect.
|
|
75
|
+
* @param row - one `configEditor.configuration()` entry, or undefined.
|
|
76
|
+
* @returns the current shell profile, or undefined when unset.
|
|
77
|
+
*/
|
|
78
|
+
export function currentTerminalShell(row) {
|
|
79
|
+
if (row === null || row === undefined) return undefined
|
|
80
|
+
const value = row.override !== null && row.override !== undefined && 'shell' in row.override
|
|
81
|
+
? row.override.shell
|
|
82
|
+
: (row.inherited === null || row.inherited === undefined ? undefined : row.inherited.shell)
|
|
83
|
+
if (value === null || typeof value !== 'object') return undefined
|
|
84
|
+
const path = value.path
|
|
85
|
+
if (typeof path !== 'string' || path.trim() === '') return undefined
|
|
86
|
+
return {
|
|
87
|
+
path,
|
|
88
|
+
name: typeof value.name === 'string' ? value.name : '',
|
|
89
|
+
args: Array.isArray(value.args) ? value.args : [],
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Decide what to do about the terminal shell. Pure: every fact arrives as an
|
|
95
|
+
* argument, which is why the whole matrix (empty / same / other / disabled /
|
|
96
|
+
* unresolved / non-Windows) is unit-testable anywhere.
|
|
97
|
+
* @param {object} input - decision input.
|
|
98
|
+
* @param {string} input.platform - `process.platform` of the host.
|
|
99
|
+
* @param {boolean} input.enabled - the `autoTerminalShell` switch.
|
|
100
|
+
* @param {string} input.resolved - the verified Git Bash path ('' when unresolved).
|
|
101
|
+
* @param {object} [input.current] - current terminal shell profile, if any.
|
|
102
|
+
* @returns {{action: string, shell?: object, current?: object, reason: string}} the plan.
|
|
103
|
+
*/
|
|
104
|
+
export function planTerminalAdopt({ platform, enabled, resolved, current }) {
|
|
105
|
+
if (platform !== 'win32') return { action: 'skip-platform', reason: 'not a Windows host; the official terminal keeps its own shell' }
|
|
106
|
+
if (enabled !== true) return { action: 'skip-disabled', reason: 'the autoTerminalShell switch is off' }
|
|
107
|
+
if (typeof resolved !== 'string' || resolved.trim() === '') {
|
|
108
|
+
return { action: 'skip-unresolved', reason: 'no verified Git Bash to offer (see the bash resolution report)' }
|
|
109
|
+
}
|
|
110
|
+
if (current === undefined || current === null) {
|
|
111
|
+
return { action: 'adopt', shell: terminalShellProfile(resolved.trim()), reason: 'the terminal has no shell configured; offering the verified Git Bash' }
|
|
112
|
+
}
|
|
113
|
+
if (normalizeBashPath(current.path) === normalizeBashPath(resolved)) {
|
|
114
|
+
return { action: 'unchanged', current, reason: 'the terminal already uses this Git Bash' }
|
|
115
|
+
}
|
|
116
|
+
return {
|
|
117
|
+
action: 'kept-user-choice',
|
|
118
|
+
current,
|
|
119
|
+
reason: 'the terminal shell points at "' + current.path + '" — an explicit choice is never overwritten; clear that field (Settings → the terminal row) to let Git Bash take over',
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Apply the plan through the official config editor, then READ THE VALUE BACK.
|
|
125
|
+
* @param {object} editor - `ctx.configEditor` (or a stand-in in tests).
|
|
126
|
+
* @param {object} options - adoption options.
|
|
127
|
+
* @param {string} options.platform - host platform.
|
|
128
|
+
* @param {boolean} options.enabled - `autoTerminalShell` switch.
|
|
129
|
+
* @param {string} options.resolved - verified Git Bash path ('' when unresolved).
|
|
130
|
+
* @returns {Promise<{status: string, action?: string, path?: string, current?: object, detail?: string}>}
|
|
131
|
+
* the outcome; `status` is one of the plan actions plus `skip-row-absent`
|
|
132
|
+
* and `write-failed`. The caller logs it — this function never lies about
|
|
133
|
+
* success and never throws for an expected condition.
|
|
134
|
+
*/
|
|
135
|
+
export async function adoptTerminalShell(editor, { platform, enabled, resolved }) {
|
|
136
|
+
if (editor === null || editor === undefined || typeof editor.configuration !== 'function') {
|
|
137
|
+
return { status: 'skip-row-absent', detail: 'the config editor is unavailable, so the terminal row cannot be configured' }
|
|
138
|
+
}
|
|
139
|
+
const rows = editor.configuration()
|
|
140
|
+
const row = Array.isArray(rows) ? rows.find((candidate) => candidate.entry?.options?.id === TERMINAL_ROW_ID) : undefined
|
|
141
|
+
if (row === undefined) {
|
|
142
|
+
return { status: 'skip-row-absent', detail: 'the "' + TERMINAL_ROW_ID + '" row is not mounted in this profile' }
|
|
143
|
+
}
|
|
144
|
+
const current = currentTerminalShell(row)
|
|
145
|
+
const plan = planTerminalAdopt({ platform, enabled, resolved, current })
|
|
146
|
+
if (plan.action !== 'adopt') {
|
|
147
|
+
return { status: plan.action, current, detail: plan.reason }
|
|
148
|
+
}
|
|
149
|
+
if (typeof editor.edit !== 'function') {
|
|
150
|
+
return { status: 'write-failed', current, detail: 'the config editor exposes no edit()' }
|
|
151
|
+
}
|
|
152
|
+
try {
|
|
153
|
+
await editor.edit(row.entry, (raw) => ({ ...raw, shell: plan.shell }))
|
|
154
|
+
} catch (error) {
|
|
155
|
+
return { status: 'write-failed', current, detail: 'the official config editor refused the write: ' + (error && error.message ? error.message : String(error)) }
|
|
156
|
+
}
|
|
157
|
+
// Read back: `edit()` resolving is NOT proof the row now carries our shell.
|
|
158
|
+
let after
|
|
159
|
+
try {
|
|
160
|
+
const rowsAfter = editor.configuration()
|
|
161
|
+
after = Array.isArray(rowsAfter) ? rowsAfter.find((candidate) => candidate.entry?.options?.id === TERMINAL_ROW_ID) : undefined
|
|
162
|
+
} catch (error) {
|
|
163
|
+
return { status: 'write-failed', current, detail: 'the write succeeded but reading it back failed: ' + (error && error.message ? error.message : String(error)) }
|
|
164
|
+
}
|
|
165
|
+
const written = currentTerminalShell(after)
|
|
166
|
+
if (written === undefined || normalizeBashPath(written.path) !== normalizeBashPath(plan.shell.path)) {
|
|
167
|
+
return {
|
|
168
|
+
status: 'write-failed',
|
|
169
|
+
current,
|
|
170
|
+
detail: 'the write did not stick: the terminal row reads ' + (written === undefined ? '(no shell)' : '"' + written.path + '"'),
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
return { status: 'adopted', path: plan.shell.path, current }
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* The one-line log for an adoption outcome (the caller prints it). Kept here so
|
|
178
|
+
* the wording stays identical between the boot path and the tests.
|
|
179
|
+
* @param {object} result - an {@link adoptTerminalShell} result.
|
|
180
|
+
* @returns {string} the log line, without the plugin tag.
|
|
181
|
+
*/
|
|
182
|
+
export function terminalAdoptReport(result) {
|
|
183
|
+
switch (result.status) {
|
|
184
|
+
case 'adopted':
|
|
185
|
+
return 'official sidebar terminal switched to Git Bash: ' + result.path + ' (name bash, args -i) — new terminals use it immediately, already-open ones keep their shell'
|
|
186
|
+
case 'unchanged':
|
|
187
|
+
return 'official sidebar terminal already uses this Git Bash: ' + (result.current ? result.current.path : '') + ' (nothing written)'
|
|
188
|
+
case 'kept-user-choice':
|
|
189
|
+
return 'official sidebar terminal NOT adopted: ' + result.detail
|
|
190
|
+
case 'write-failed':
|
|
191
|
+
return 'official sidebar terminal adoption FAILED — ' + result.detail
|
|
192
|
+
+ ' | next steps: (1) the new-terminal shell is UNCHANGED, so dsh keeps its own resolution;'
|
|
193
|
+
+ ' (2) set the terminal by hand: add `shell: { path: <git-bash>, name: bash, args: [\'-i\'] }` to the'
|
|
194
|
+
+ ' `terminal-controller` row in the profile patch and restart dsh;'
|
|
195
|
+
+ ' (3) or turn this plugin\'s "autoTerminalShell" switch off to stop the attempts;'
|
|
196
|
+
+ ' (4) the full cause is in the lines above.'
|
|
197
|
+
case 'skip-disabled':
|
|
198
|
+
return 'official sidebar terminal adoption is off (autoTerminalShell = false) — the new-terminal shell stays whatever dsh resolves'
|
|
199
|
+
case 'skip-unresolved':
|
|
200
|
+
return 'official sidebar terminal adoption skipped: no verified Git Bash (nothing is substituted)'
|
|
201
|
+
case 'skip-platform':
|
|
202
|
+
return 'official sidebar terminal adoption applies to Windows only'
|
|
203
|
+
default:
|
|
204
|
+
return 'official sidebar terminal adoption skipped: ' + (result.detail ?? result.status)
|
|
205
|
+
}
|
|
206
|
+
}
|