Skip to content

fix(terminals): correct Windows shell defaults#2385

Open
Drakaniia wants to merge 4 commits into
generalaction:mainfrom
Drakaniia:drakaniia/issue-2383-terminal-shell-windows
Open

fix(terminals): correct Windows shell defaults#2385
Drakaniia wants to merge 4 commits into
generalaction:mainfrom
Drakaniia:drakaniia/issue-2383-terminal-shell-windows

Conversation

@Drakaniia

@Drakaniia Drakaniia commented Jun 5, 2026

Copy link
Copy Markdown
Contributor

Description

Corrects Windows terminal shell behavior so the default terminal flow matches the selected shell and avoids the empty terminal placeholder after the last terminal is closed.

Implementation notes:

  • Resolves the bash shell id to Git Bash on Windows instead of the Windows WSL bash.exe launcher.
  • Adds an explicit wsl shell id for WSL-backed terminals.
  • Shows a single PowerShell option in Windows terminal settings, while keeping explicit pwsh resolution available for existing stored settings.
  • Hides the terminal drawer when the last terminal is closed.
  • Makes Ctrl+J create/open the configured default terminal when no terminal tabs exist, and hide the drawer when it is already open.

Related issues

Fixes #2383.

Testing

  • pnpm exec vitest run src/renderer/features/tasks/commands.test.ts src/renderer/features/tasks/stores/workspace-view-model.test.ts src/renderer/features/tasks/terminals/terminal-manager.test.ts
  • pnpm exec vitest run src/main/core/terminal-shell/resolver.test.ts src/main/core/pty/pty-spawn-platform.test.ts src/renderer/features/tasks/commands.test.ts src/renderer/features/tasks/stores/workspace-view-model.test.ts src/renderer/features/tasks/terminals/terminal-manager.test.ts
  • pnpm run typecheck
  • pnpm run lint
  • pnpm exec oxfmt --check src/main/core/pty/pty-spawn-platform.test.ts src/main/core/pty/pty-spawn-platform.ts src/main/core/terminal-shell/resolver.test.ts src/main/core/terminal-shell/resolver.ts src/renderer/features/tasks/commands.test.ts src/renderer/features/tasks/commands.ts src/renderer/features/tasks/stores/workspace-view-model.test.ts src/renderer/features/tasks/stores/workspace-view-model.tsx src/renderer/lib/components/terminal-shell-option-label.tsx src/shared/terminal-settings.ts
  • git diff --check

Note: pnpm run test was also attempted locally, but it fails on this Windows checkout in unrelated path/temp-fixture and native PTY suites. The focused terminal-related tests above pass.

Recording

Video_260605094718.mp4
Checklist
  • I kept this PR small and focused
  • I ran a self-review before opening this PR
  • I ran the relevant local checks or explained why not
  • I updated docs when behavior or setup changed
  • I added or updated tests when behavior changed, or explained why not
  • I only added comments where the logic is not obvious
  • I used Conventional Commits for commit
    messages and, when possible, the PR title

@Drakaniia Drakaniia marked this pull request as ready for review June 5, 2026 01:51
@greptile-apps

greptile-apps Bot commented Jun 5, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes Windows terminal shell defaults: bash now resolves to Git Bash instead of the WSL launcher, a dedicated wsl shell id is introduced with System32-only detection, pwsh is hidden from the UI while remaining resolvable for stored settings, and the terminal drawer now closes automatically when the last terminal is removed or a session is restored with no terminals.

  • Shell resolver: windowsSystemCommand restricts wsl.exe lookup to %SystemRoot%\\System32 (no PATH fallback); findWindowsGitBash probes known Git install paths first, then falls back to PATH with a filter that rejects the WSL bash launcher; shellIdsForLocalPlatform drops pwsh from the display list and adds wsl.
  • PTY spawn: The wsl family is wired through the Windows spawn path — interactive shells launch wsl.exe with no args, run-command routes through argvToPosixShellLine + windowsShellLineSpawn, and POSIX spawn guards throw for the wsl family.
  • UI / UX: The closeEmptyTerminalDrawer reaction replaces the old auto-create reaction, using fireImmediately: true to handle both session-restore and last-terminal-closed scenarios while guarding against mid-flight closure; Ctrl+J creates a new terminal instead of toggling the drawer when no tabs exist.

Confidence Score: 5/5

Safe to merge; all changed paths are well-tested and the one cosmetic regression is minor and easily patched.

The shell resolver, PTY spawn, and drawer-management changes are each covered by focused regression tests that were run and passed. The previous two thread concerns (System32-only WSL detection and the session-restore empty-drawer edge case) are both addressed with test coverage. The only new finding is a cosmetic icon regression in the system shell row of the terminal shell picker, which does not affect functionality.

src/renderer/lib/components/terminal-shell-option-label.tsx — the entry.id change loses the shell icon for the system entry.

Important Files Changed

Filename Overview
src/main/core/terminal-shell/resolver.ts Adds wsl shell id with System32-only detection (no PATH fallback), Git Bash resolution that filters WSL's bash launcher, consolidated explicitShellLabel helper, and removes pwsh from the default display list while preserving stored-settings resolution.
src/main/core/pty/pty-spawn-platform.ts Adds wsl family support throughout the Windows spawn path: interactive shells launch wsl.exe directly with no args, run-command routes through argvToPosixShellLine + windowsShellLineSpawn, and POSIX spawn guards throw for wsl family.
src/renderer/features/tasks/stores/workspace-view-model.tsx Replaces the old auto-create-terminal reaction with a close-empty-drawer reaction using fireImmediately:true, handling both the session-restore case (previous===undefined) and the last-terminal-closed case (previous.terminalCount > 0). The isCreatingTerminal guard prevents mid-flight closure.
src/renderer/features/tasks/commands.ts Ctrl+J now opens a new terminal when no tabs exist instead of toggling the drawer; closes the drawer when already open, and opens it when tabs exist. openNewTerminal already sets isTerminalDrawerOpen=true internally so the UX flow is consistent.
src/renderer/lib/components/terminal-shell-option-label.tsx Switches icon lookup from entry.label to entry.id, fixing icon resolution for human-readable labels like "Git Bash" and "PowerShell", but causes the system entry (id='system') to always render the generic Terminal icon instead of the actual shell's icon.
src/shared/terminal-settings.ts Adds wsl to TERMINAL_SHELL_IDS, RUNTIME_TERMINAL_SHELL_IDS, TerminalShellFamily, terminalShellFamily, terminalInteractiveShellArgs, terminalCommandArgs, and terminalEnvCaptureArgs with appropriate wsl semantics (--exec sh -lc, no env capture).
src/main/core/terminal-shell/resolver.test.ts Adds tests for WSL System32-only resolution, WSL rejection from arbitrary PATH, Git Bash vs WSL bash launcher distinction, and the new single-PowerShell availability display.
src/renderer/features/tasks/stores/workspace-view-model.test.ts Adds three new reaction tests: restore with already-loaded empty state, restore with late-loading empty state (isLoaded transitions to true), and user-closes-last-terminal; all verify the drawer closes and focusedRegion resets to main.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["Ctrl+J pressed"] --> B{drawer open?}
    B -- yes --> C[close drawer]
    B -- no --> D{terminal tabs exist?}
    D -- yes --> E[open drawer]
    D -- no --> F[openNewTerminal]
    F --> G[isTerminalDrawerOpen = true
_isCreatingTerminal = true]
    G --> H[createDefaultTerminal]
    H --> I[terminal added to registry]
    I --> J[_isCreatingTerminal = false]

    K["Session restored / terminal closed"] --> L{isLoaded && terminalCount==0
&& isDrawerOpen}
    L -- "previous==undefined OR
prev.terminalCount>0 OR
!prev.isLoaded" --> M[close drawer
clear activeItem
focusedRegion → main]
    L -- no --> N[no-op]

    subgraph "bash resolve - Windows"
        O["intent: bash"] --> P{Git Bash in known paths?}
        P -- yes --> Q[return Git Bash exe]
        P -- no --> R[findOnPath bash.exe
excluding WSL launcher]
        R --> S{isWindowsWslBashLauncher?}
        S -- yes --> T[skip candidate]
        S -- no --> U[return candidate]
    end

    subgraph "wsl resolve - Windows"
        V["intent: wsl"] --> W{SystemRoot set?}
        W -- yes --> X[check System32/wsl.exe only]
        X -- exists --> Y[return wsl.exe]
        X -- missing --> Z[ShellUnavailableError]
        W -- no --> Z
    end
Loading
Prompt To Fix All With AI
Fix the following 1 code review issue. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 1
src/renderer/lib/components/terminal-shell-option-label.tsx:58
The `system` entry has `id === 'system'`, which is not in `SHELL_DEVICON_CLASS`, so it always falls through to the generic `Terminal` lucide icon. On macOS the zsh or bash icon disappears; on Windows the cmd or PowerShell icon disappears. The `system` entry's `label` still carries the actual shell basename (e.g. `"zsh"`, `"bash"`, `"cmd"`), so a simple fallback — try the `id` first, then fall back to the `label` — restores the correct icon for the system row while keeping the explicit-shell fix intact.

```suggestion
      <TerminalShellIcon shell={entry.id === 'system' ? entry.label : entry.id} />
```

Reviews (2): Last reviewed commit: "fix(terminals): address Windows shell re..." | Re-trigger Greptile

Comment thread apps/emdash-desktop/src/main/core/terminal-shell/resolver.ts
@Drakaniia

Drakaniia commented Jun 5, 2026

Copy link
Copy Markdown
Contributor Author

@greptile-apps Updated summary:

This PR fixes Windows terminal shell defaults and terminal drawer behavior.

  • Shell resolver: bash now resolves to Git Bash instead of the WSL launcher. windowsSystemCommand restricts wsl.exe lookup to %SystemRoot%\System32 with no PATH fallback. findWindowsGitBash probes known Git install paths first, then falls back to PATH while rejecting the WSL bash launcher. shellIdsForLocalPlatform removes pwsh from the display list and adds wsl; pwsh remains resolvable for stored settings.
  • PTY spawn: the wsl shell family now uses the Windows spawn path. Interactive shells launch wsl.exe with no args, run-command shells route through argvToPosixShellLine and windowsShellLineSpawn, and POSIX spawn guards reject the wsl family.
  • UI / UX: closeEmptyTerminalDrawer replaces the old auto-create reaction. It uses fireImmediately: true to cover session restore with no terminals and last-terminal-closed cases, while guarding against mid-flight closure. Ctrl+J now creates a terminal instead of toggling the drawer when no tabs exist.

@arnestrickmann

Copy link
Copy Markdown
Contributor

Hi @Drakaniia,

Thank you for opening this PR, and for your other contributions and issue reports lately. The feedback has been highly valuable and is much appreciated.

Since this PR was opened, we’ve done some refactoring across the codebase to prepare for the next larger topic we’re working toward.

That said, the changes in this PR still make a lot of sense.

Would you be able to resolve the merge conflicts caused by the file moves? Once that’s done, I’d be happy to merge it into main and include it in the next production release.

- Move the terminal shell fixes onto apps/emdash-desktop after the upstream monorepo refactor.

- Preserve the new browser command tests alongside the terminal drawer regression test.

- Apply the system shell icon fallback requested in the PR review.
@Drakaniia

Copy link
Copy Markdown
Contributor Author

Resolved and pushed PR #2385 conflict.

Merged current upstream/main into drakaniia/issue-2383-terminal-shell-windows, resolved the moved-path test conflict, kept both browser command tests and the terminal drawer regression test, and applied the PR review icon fallback in terminal-shell-option-label.tsx.

Verification passed:

  • vitest focused run: 4 files, 70 tests
  • oxfmt --check on touched files
  • oxlint on touched files
  • pnpm --filter @emdash/emdash-desktop run typecheck

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[bug]: default terminal shell selection opens wrong shell on Windows

2 participants