[Bug] 默认 Shell 失效(如卸载 WSL 发行版)后无法打开终端:失败标签静默自灭、无回退、恢复计数虚报
Summary (EN) — When the configured default shell stops existing (the WSL distro behind
"Ubuntu" is uninstalled, or PowerShell 7 is removed), Pebrel offers no existence check and no
fallback for restored tabs. Two failure modes result: (a) if the launcher exe still exists
(wsl.exe does even with no distro installed), the tab is created, the process exits within
milliseconds, and the Exited event makes the workspace close the pane and then the tab —
restoring tabs one by one silently vanish; when the last one goes, the window hides (resident) or
closes. The user sees "Pebrel won't open". (b) if the executable itself is gone, the pane stays
with a bare red "PTY 启动失败" line — no toast, no fallback, no retry. The session-recovery toast
still reports success ("已恢复 N 个标签") even as the tabs disappear. Verified live on 2.1.1.
通过命令行提交,无法填写网页表单。以下按 bug_report 模板字段组织。
Operating system / 操作系统
Windows
OS version and display / 系统版本与显示
Windows 11(build 26300)
Pebrel version / 版本号
2.1.1 (d574856)
How did you install Pebrel? / 安装方式
GitHub Release (.exe)
Shell in the affected pane / 出问题的面板用的 Shell
WSL (bash / zsh inside WSL)
Program running in the pane / 面板里正在跑的程序
Nothing, plain shell prompt / 什么都没跑
Connection type / 连接方式
WSL
Affected area / 影响范围
- Shell startup / PATH / start directory / context menu — Shell 启动、环境变量、起始目录、右键菜单
- Tabs / splits / session restore / window size — 标签页、分屏、会话恢复、窗口尺寸
- Startup crash / hang / cannot exit — 启动崩溃、卡死、无法退出(「终端打不开」一类)
Did it work in a previous version? / 旧版本是否正常?
Not sure / 不确定(代码路径显示为一直存在的设计缺口)
Can you reproduce it? / 复现概率
Always (100%) / 必现(默认 shell 指向已失效的解释器时每次复现)
Steps to reproduce / 复现步骤
- 设置 → 默认 Shell 选 Ubuntu(WSL),在 WSL 中正常使用并留下若干标签与分屏;
- 卸载该 WSL 发行版。卸载后
wsl -l -v 报无分发,但 C:\Windows\System32\wsl.exe 启动器仍在
(本机当前即此状态);
- 重新启动 Pebrel:恢复出的标签逐个消失,全部消失后窗口一并隐藏/关闭——表现为「打不开」;
- 新建标签同样立即消失(默认 shell 仍指向该发行版);
- 等价变体:卸载 PowerShell 7 后恢复旧标签(窗口能开,但恢复标签停留在红色错误文字)。
Expected behavior / 期望结果
- 启动/恢复前校验 shell 可达性(可执行文件与 WSL 发行版两层);失效时给出用户可见、可操作的
提示(如「默认 Shell 『Ubuntu』已不存在,已临时回退到 PowerShell,请到设置更换」)并回退打开;
- 恢复会话时对冻结在 session.json 里的旧 shell 同样校验并回退,而不是原样重放;
- 启动即失败的标签不要静默自灭:至少保留错误 pane 或弹 toast 说明失败原因
(现有「PTY 启动失败」红字页面就是比静默消失更可诊断的形态);
- 恢复统计如实:哪些标签恢复成功、哪些启动失败。
Actual behavior / 实际结果
WSL 发行版被卸载(wsl.exe 仍在)时,失败完全是静默的:
- 会话恢复照常重放冻结的
wsl.exe -d <发行版> → 进程启动后立即报「没有已安装的分发」并退出 →
工作区收到 Exited 即关闭该 pane、pane 是标签内唯一叶子时连标签一并关闭 →
全部标签如此时不剩任何内容,窗口转入隐藏(驻留)或直接关闭;
- 恢复完成时照常弹出成功 toast「已恢复 N 个标签」——紧接着标签消失,前后矛盾;
- 通过右键「在 Pebrel 中打开(Ubuntu)」等携带
--shell wsl:<发行版> 的入口:解析被 WSL
合成兜底放行,标签创建后立刻自灭,用户看不到任何结果;
- 对照形态(可执行文件本身不存在,如卸载 PowerShell 7 后恢复旧标签):CreateProcess 失败, pane 不走
Exited,停留在红色「PTY 启动失败:…」文字上,无 toast、无回退、无重试入口。
本机(无发行版、wsl.exe 仍在)实测记录:
pebrel --shell wsl:Ubuntu 连续执行:launcher 立即以 exit 0 交接成功,驻留实例无任何可见变化;
ctl snapshot 的 pane_lifecycles 中留有 3 个对应 pane 的 exited 记录,快照中已不存在;
- 机制对照实验(排除 WSL 因素):
pebrel ctl new-tab 建一个正常 pwsh 标签 → pebrel ctl prompt --pane <id> --text exit 让 shell 正常退出 → 该标签整体从快照消失, pane_lifecycles 记录
{"pane_id":13,"event":"exited"}。即「进程退出 → 标签自动关闭」
全链贯通;正常退出自动关标签是常见终端语义,问题在于启动即失败走同一条轨道且无声。
Logs / screenshots / 日志或截图
事发时未留存日志(事故后默认 shell 已改回 pwsh,旧日志已滚动)。以上实测与以下源码定位可替代
(基准 main@b99383c;本机复现版本 2.1.1 (d574856),ctl 实验在 2.1.1 实机上完成):
1. 全链无 shell 存在性校验;WSL 还刻意合成注定失败的启动
nebula_app/src/gpui_shell/workspace/shell_launch.rs:51-63 configured_local_launch():
设置里的 shell id 解析失败时吞掉错误回落 Default(新标签由此隐式回退);
shell_launch.rs:125-140 wsl_launch_for_id():对 wsl:<发行版> 故意合成 wsl.exe -d <发行版>(注释明言「枚举不到也合成,让 wsl.exe 自己报错」)—— 而 platform/shell.rs:12-23
wsl_executable() 只检查 System32\wsl.exe 是文件,
不检查发行版是否仍注册。于是「发行版已卸载」在解析层是成功,必然走到 spawn 后即死;
- 恢复路径
session_recovery.rs:109-123:直接原样重放会话文件里冻结的
LaunchSession::Shell{program, args},只有 Default 才重新解析。
2. 「进程退出 → pane 关闭 → 标签关闭 → 窗口隐藏/关闭」链路
gpui_shell/terminal/view.rs:167-168:Exited 语义为「会话结束(子进程退出或 PTY 故障)」;
:635-643 中 ChildExit / PtyFailure / Exit 三个事件都走 mark_exited(:735-748)
并 emit Exited(只发一次);
gpui_shell/workspace/terminal_activity.rs:45-49:收到 Exited → record_pane_exited +
close_pane;
gpui_shell/workspace.rs:1485-1524 close_pane():pane 是标签根叶子时 RemoveOutcome::WasRoot => close_tab;:1641-1681 finish_close_tab():tabs 为空时 close_empty_workspace;
gpui_shell/workspace/residency.rs:992-997 → windowing.rs:1559-1580:空工作区按
驻留策略隐藏窗口或 window.remove_window()。
3. 失败反馈仅剩两条弱路径
- 构造期失败:
terminal/view/startup.rs:193-231,spawn Err → (None, Some("PTY 启动失败: …")),文案硬编码未进 i18n;terminal/view.rs:1438-1439
仅把它渲染为红色文字;工作区层对此无任何处理(无 toast、无回退、无重试);
- 进程启动后秒退:连红字都没有——直接走上面第 2 条的自动关闭链。
4. 恢复计数虚报
session_recovery.rs:56-76:restored 只统计「标签是否被建出」(pane 对象与 shell 能否
启动无关,总会建出),随后 :69-74 弹 ToastKind::Success「已恢复 {N} 个标签」。
5. 启动目录(次要,与用户的第二组猜测对应)
- 五处
is_dir 惰性回退覆盖了主要入口(nebula_settings/src/lib.rs:1159-1167、
session_recovery.rs:126-131、terminal/view.rs:986-992、main.rs:225-228),
所以「只删默认目录」多数入口能兜住;缺口在 IPC 的 tab.new/window.create cwd 未校验
(workspace/residency.rs:254-267),不存在的目录直达 CreateProcessW 的 lpCurrentDirectory →
ERROR_DIRECTORY (267)(nebula_terminal/src/tty/windows/conpty.rs:304-318);
- 旧壳有 spawn 前兜底(
window_context.rs:510-520),GPUI 壳没有等价咽喉守卫;
- 次级风险(推断,未实测):启动目录指向
\\wsl$\... 时目录探测在 UI 线程, WSL
卸载后可能以超时方式阻塞开窗——仓库注释自证 UNC 探测会阻塞 UI (tab_duplication.rs:81-83)。
Non-default settings / 改过的设置
事发时:默认 Shell = Ubuntu (WSL)、启动目录 = WSL 路径(即触发条件本身)。其余默认。
修复方向(供维护者参考,按性价比排序)
- 把「启动即失败」与「正常退出」分开:pane 首次
ChildExit 且生存时间极短(或启动阶段
PtyFailure)时不要走 close_pane,改为保留错误 pane / toast 说明原因;
- shell 可达性校验 + 回退:
shell_launch.rs:51-63 与 :125-140(发行版不在注册表或
wsl_executable() 为 None 时不合成)、session_recovery.rs:109-123(重放冻结 Shell{program}
前校验 program 可达,不可达回落 configured_local_launch 并提示);
- 恢复计数如实:
session_recovery.rs:56-76 同时统计启动失败/自灭的标签,成功 toast 与之吻合;
- spawn 咽喉统一守卫(cwd 的
is_dir() 或捕获 ERROR_DIRECTORY 重试一次),等价于把旧壳
window_context.rs:510-520 的兜底搬进 GPUI;IPC cwd 校验返回 invalid_params;
- 设置页对「检测不到但仍被选中」的 shell id 加失效标记(
settings_pane/shell_picker.rs:126-137
目前会把它插到列表首位继续显示为可用)。
Before submitting / 提交前确认
[Bug] 默认 Shell 失效(如卸载 WSL 发行版)后无法打开终端:失败标签静默自灭、无回退、恢复计数虚报
Operating system / 操作系统
Windows
OS version and display / 系统版本与显示
Windows 11(build 26300)
Pebrel version / 版本号
2.1.1 (d574856)
How did you install Pebrel? / 安装方式
GitHub Release (.exe)
Shell in the affected pane / 出问题的面板用的 Shell
WSL (bash / zsh inside WSL)
Program running in the pane / 面板里正在跑的程序
Nothing, plain shell prompt / 什么都没跑
Connection type / 连接方式
WSL
Affected area / 影响范围
Did it work in a previous version? / 旧版本是否正常?
Not sure / 不确定(代码路径显示为一直存在的设计缺口)
Can you reproduce it? / 复现概率
Always (100%) / 必现(默认 shell 指向已失效的解释器时每次复现)
Steps to reproduce / 复现步骤
wsl -l -v报无分发,但C:\Windows\System32\wsl.exe启动器仍在(本机当前即此状态);
Expected behavior / 期望结果
提示(如「默认 Shell 『Ubuntu』已不存在,已临时回退到 PowerShell,请到设置更换」)并回退打开;
(现有「PTY 启动失败」红字页面就是比静默消失更可诊断的形态);
Actual behavior / 实际结果
WSL 发行版被卸载(
wsl.exe仍在)时,失败完全是静默的:wsl.exe -d <发行版>→ 进程启动后立即报「没有已安装的分发」并退出 →工作区收到
Exited即关闭该 pane、pane 是标签内唯一叶子时连标签一并关闭 →全部标签如此时不剩任何内容,窗口转入隐藏(驻留)或直接关闭;
--shell wsl:<发行版>的入口:解析被 WSL合成兜底放行,标签创建后立刻自灭,用户看不到任何结果;
Exited,停留在红色「PTY 启动失败:…」文字上,无 toast、无回退、无重试入口。本机(无发行版、wsl.exe 仍在)实测记录:
pebrel --shell wsl:Ubuntu连续执行:launcher 立即以 exit 0 交接成功,驻留实例无任何可见变化;ctl snapshot的pane_lifecycles中留有 3 个对应 pane 的exited记录,快照中已不存在;pebrel ctl new-tab建一个正常 pwsh 标签 →pebrel ctl prompt --pane <id> --text exit让 shell 正常退出 → 该标签整体从快照消失,pane_lifecycles记录{"pane_id":13,"event":"exited"}。即「进程退出 → 标签自动关闭」全链贯通;正常退出自动关标签是常见终端语义,问题在于启动即失败走同一条轨道且无声。
Logs / screenshots / 日志或截图
事发时未留存日志(事故后默认 shell 已改回 pwsh,旧日志已滚动)。以上实测与以下源码定位可替代
(基准 main@b99383c;本机复现版本 2.1.1 (d574856),ctl 实验在 2.1.1 实机上完成):
1. 全链无 shell 存在性校验;WSL 还刻意合成注定失败的启动
nebula_app/src/gpui_shell/workspace/shell_launch.rs:51-63configured_local_launch():设置里的 shell id 解析失败时吞掉错误回落
Default(新标签由此隐式回退);shell_launch.rs:125-140wsl_launch_for_id():对wsl:<发行版>故意合成wsl.exe -d <发行版>(注释明言「枚举不到也合成,让 wsl.exe 自己报错」)—— 而platform/shell.rs:12-23wsl_executable()只检查System32\wsl.exe是文件,不检查发行版是否仍注册。于是「发行版已卸载」在解析层是成功,必然走到 spawn 后即死;
session_recovery.rs:109-123:直接原样重放会话文件里冻结的LaunchSession::Shell{program, args},只有Default才重新解析。2. 「进程退出 → pane 关闭 → 标签关闭 → 窗口隐藏/关闭」链路
gpui_shell/terminal/view.rs:167-168:Exited语义为「会话结束(子进程退出或 PTY 故障)」;:635-643中ChildExit/PtyFailure/Exit三个事件都走mark_exited(:735-748)并 emit
Exited(只发一次);gpui_shell/workspace/terminal_activity.rs:45-49:收到Exited→record_pane_exited+close_pane;gpui_shell/workspace.rs:1485-1524close_pane():pane 是标签根叶子时RemoveOutcome::WasRoot => close_tab;:1641-1681finish_close_tab():tabs为空时close_empty_workspace;gpui_shell/workspace/residency.rs:992-997→windowing.rs:1559-1580:空工作区按驻留策略隐藏窗口或
window.remove_window()。3. 失败反馈仅剩两条弱路径
terminal/view/startup.rs:193-231,spawn Err →(None, Some("PTY 启动失败: …")),文案硬编码未进 i18n;terminal/view.rs:1438-1439仅把它渲染为红色文字;工作区层对此无任何处理(无 toast、无回退、无重试);
4. 恢复计数虚报
session_recovery.rs:56-76:restored只统计「标签是否被建出」(pane 对象与 shell 能否启动无关,总会建出),随后
:69-74弹ToastKind::Success「已恢复 {N} 个标签」。5. 启动目录(次要,与用户的第二组猜测对应)
is_dir惰性回退覆盖了主要入口(nebula_settings/src/lib.rs:1159-1167、session_recovery.rs:126-131、terminal/view.rs:986-992、main.rs:225-228),所以「只删默认目录」多数入口能兜住;缺口在 IPC 的
tab.new/window.createcwd 未校验(
workspace/residency.rs:254-267),不存在的目录直达CreateProcessW的lpCurrentDirectory→ERROR_DIRECTORY (267)(nebula_terminal/src/tty/windows/conpty.rs:304-318);window_context.rs:510-520),GPUI 壳没有等价咽喉守卫;\\wsl$\...时目录探测在 UI 线程, WSL卸载后可能以超时方式阻塞开窗——仓库注释自证 UNC 探测会阻塞 UI (
tab_duplication.rs:81-83)。Non-default settings / 改过的设置
事发时:默认 Shell = Ubuntu (WSL)、启动目录 = WSL 路径(即触发条件本身)。其余默认。
修复方向(供维护者参考,按性价比排序)
ChildExit且生存时间极短(或启动阶段PtyFailure)时不要走close_pane,改为保留错误 pane / toast 说明原因;shell_launch.rs:51-63与:125-140(发行版不在注册表或wsl_executable()为 None 时不合成)、session_recovery.rs:109-123(重放冻结Shell{program}前校验 program 可达,不可达回落
configured_local_launch并提示);session_recovery.rs:56-76同时统计启动失败/自灭的标签,成功 toast 与之吻合;is_dir()或捕获 ERROR_DIRECTORY 重试一次),等价于把旧壳window_context.rs:510-520的兜底搬进 GPUI;IPC cwd 校验返回invalid_params;settings_pane/shell_picker.rs:126-137目前会把它插到列表首位继续显示为可用)。
Before submitting / 提交前确认
([Bug] PowerShell 面板以 WSL 的 UNC 路径为起始目录,cmd.exe 系启动器(claude.cmd 等)回退到 C:\Windows #195/[Bug] 设置启动目录后,开机自启动的首个终端仍打开在 %USERPROFILE% #479 为启动目录相关但症状与根因不同;[Bug] 关闭软件后无法恢复之前打开的 session #370/[Bug] 1.8.2:session.json 从未被写入,关窗不驻留,「启动时恢复上次标签」完全无效 #228 为「关窗不保存/无法恢复」类,
与本问题的「恢复后即自灭」不同)