-
Notifications
You must be signed in to change notification settings - Fork 5k
feat(shell): initial Fish support #1358
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -24,35 +24,35 @@ | |||||||||||||||
| specify init --here | ||||||||||||||||
| """ | ||||||||||||||||
|
|
||||||||||||||||
| import json | ||||||||||||||||
| import os | ||||||||||||||||
| import shlex | ||||||||||||||||
| import shutil | ||||||||||||||||
| import ssl | ||||||||||||||||
| import subprocess | ||||||||||||||||
| import sys | ||||||||||||||||
| import zipfile | ||||||||||||||||
| import tempfile | ||||||||||||||||
| import shutil | ||||||||||||||||
| import shlex | ||||||||||||||||
| import json | ||||||||||||||||
| import zipfile | ||||||||||||||||
| from datetime import datetime, timezone | ||||||||||||||||
| from pathlib import Path | ||||||||||||||||
| from typing import Optional, Tuple | ||||||||||||||||
|
|
||||||||||||||||
| import typer | ||||||||||||||||
| import httpx | ||||||||||||||||
|
|
||||||||||||||||
| # For cross-platform keyboard input | ||||||||||||||||
| import readchar | ||||||||||||||||
| import truststore | ||||||||||||||||
| import typer | ||||||||||||||||
| from rich.align import Align | ||||||||||||||||
| from rich.console import Console | ||||||||||||||||
| from rich.live import Live | ||||||||||||||||
| from rich.panel import Panel | ||||||||||||||||
| from rich.progress import Progress, SpinnerColumn, TextColumn | ||||||||||||||||
| from rich.text import Text | ||||||||||||||||
| from rich.live import Live | ||||||||||||||||
| from rich.align import Align | ||||||||||||||||
| from rich.table import Table | ||||||||||||||||
| from rich.text import Text | ||||||||||||||||
| from rich.tree import Tree | ||||||||||||||||
| from typer.core import TyperGroup | ||||||||||||||||
|
|
||||||||||||||||
| # For cross-platform keyboard input | ||||||||||||||||
| import readchar | ||||||||||||||||
| import ssl | ||||||||||||||||
| import truststore | ||||||||||||||||
| from datetime import datetime, timezone | ||||||||||||||||
|
|
||||||||||||||||
| ssl_context = truststore.SSLContext(ssl.PROTOCOL_TLS_CLIENT) | ||||||||||||||||
| client = httpx.Client(verify=ssl_context) | ||||||||||||||||
|
|
||||||||||||||||
|
|
@@ -228,7 +228,11 @@ def _format_rate_limit_error(status_code: int, headers: httpx.Headers, url: str) | |||||||||||||||
| }, | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| SCRIPT_TYPE_CHOICES = {"sh": "POSIX Shell (bash/zsh)", "ps": "PowerShell"} | ||||||||||||||||
| SCRIPT_TYPE_CHOICES = { | ||||||||||||||||
| "sh": "POSIX Shell (bash/zsh)", | ||||||||||||||||
| "fish": "Fish Shell", | ||||||||||||||||
| "ps": "PowerShell" | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| CLAUDE_LOCAL_PATH = Path.home() / ".claude" / "local" / "claude" | ||||||||||||||||
|
|
||||||||||||||||
|
|
@@ -481,6 +485,41 @@ def run_command(cmd: list[str], check_return: bool = True, capture: bool = False | |||||||||||||||
| raise | ||||||||||||||||
| return None | ||||||||||||||||
|
|
||||||||||||||||
|
|
||||||||||||||||
| def detect_shell() -> str: | ||||||||||||||||
| """Detect the current shell environment. | ||||||||||||||||
|
|
||||||||||||||||
| Returns: | ||||||||||||||||
| Shell type identifier: 'fish', 'sh' (for bash/zsh), or 'ps' (PowerShell) | ||||||||||||||||
| """ | ||||||||||||||||
| # Check for PowerShell first (Windows) | ||||||||||||||||
| if os.name == "nt" or "POWERSHELL" in os.environ.get("PSModulePath", "").upper(): | ||||||||||||||||
| return "ps" | ||||||||||||||||
|
|
||||||||||||||||
| # Check SHELL environment variable (Unix-like systems) | ||||||||||||||||
| shell_path = os.environ.get("SHELL", "") | ||||||||||||||||
| if "fish" in shell_path: | ||||||||||||||||
| return "fish" | ||||||||||||||||
| elif "bash" in shell_path or "zsh" in shell_path or "sh" in shell_path: | ||||||||||||||||
|
Comment on lines
+501
to
+503
|
||||||||||||||||
| if "fish" in shell_path: | |
| return "fish" | |
| elif "bash" in shell_path or "zsh" in shell_path or "sh" in shell_path: | |
| shell_name = os.path.basename(shell_path).lower() | |
| if shell_name == "fish": | |
| return "fish" | |
| elif shell_name in ("bash", "zsh", "sh"): |
Copilot
AI
Dec 20, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The psutil package is imported but not listed in the project dependencies. This will cause an ImportError for users who don't have psutil installed, preventing the fallback shell detection from working properly. Either add psutil to the dependencies in pyproject.toml, or handle the case where the import fails more gracefully by catching the exception at import time rather than during execution.
Copilot
AI
Dec 20, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The debug output shows the raw SHELL environment variable value rather than the detected shell type. This creates confusion as it displays "Detected shell: /usr/bin/fish" instead of "Detected shell: fish". Consider either changing the label to "Shell path" or displaying the detected shell type (the value of selected_script or default_script) to make this output more helpful for debugging.
| console.print(f"[dim]Detected shell:[/dim] {os.environ.get('SHELL', 'unknown')}") | |
| console.print(f"[dim]Detected shell type:[/dim] {selected_script}") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The docstring states the function returns 'fish', 'sh', or 'ps', but line 503 also checks for "bash" and "zsh" in the shell path. While these do eventually return "sh", the implementation comment suggests these are distinct shells being detected. Consider clarifying in the docstring that bash and zsh are detected and mapped to the "sh" return value for consistency.