"""Start Claude Code in the myclaude project directory.""" import os import shutil import subprocess import sys from pathlib import Path import click from rich.console import Console from myclaude.project_root import get_myclaude_project_root console = Console() stderr_console = Console(stderr=True) def _resolve_chat_cwd() -> Path: root = get_myclaude_project_root() fallback = Path.home() / ".myclaude" if root == fallback: stderr_console.print( "[red]Cannot resolve myclaude project root.[/red] Run from the repo or set " "[cyan]MYCLAUDE_PROJECT_ROOT[/cyan].", ) raise SystemExit(1) return root def _parse_cwd_from_args(args: list[str]) -> tuple[str | None, list[str]]: """ Parse --cwd with optional value from args. Returns (cwd_value, remaining_args). --cwd alone -> cwd_value='.' --cwd /path -> cwd_value='/path' --cwd . -> cwd_value='.' """ cwd_value: str | None = None remaining: list[str] = [] skip_next = False for i, arg in enumerate(args): if skip_next: skip_next = False continue if arg in ("--cwd", "-C"): # Check if next arg exists and is not a flag if i + 1 < len(args) and not args[i + 1].startswith("-"): cwd_value = args[i + 1] skip_next = True else: # --cwd alone, default to current directory cwd_value = "." elif arg.startswith("--cwd="): cwd_value = arg[6:] elif arg.startswith("-C="): cwd_value = arg[3:] elif arg.startswith("-C") and len(arg) > 2: # -C/path or -C. cwd_value = arg[2:] else: remaining.append(arg) return cwd_value, remaining @click.command( "chat", context_settings={ "ignore_unknown_options": True, "allow_extra_args": True, }, ) @click.option( "--dangerously-skip-permissions", is_flag=True, default=False, help="Forward to claude: bypass permission checks (sandbox / isolated use only).", ) @click.pass_context def chat_cmd(ctx: click.Context, dangerously_skip_permissions: bool) -> None: """Run `claude` in the myclaude repo so CLAUDE.md and .claude/ apply; extra args pass through. \b Working directory options: --cwd, -C Use current directory as working directory --cwd /path, -C/path Use specified path as working directory (none) Use myclaude project root (default) """ binary = os.environ.get("CLAUDE_BIN") or shutil.which("claude") if not binary: stderr_console.print( "[red]claude CLI not found in PATH.[/red] Install Claude Code or set " "[cyan]CLAUDE_BIN[/cyan].", ) raise SystemExit(127) # Parse --cwd from raw args (Click doesn't support optional values natively) cwd_value, remaining_args = _parse_cwd_from_args(ctx.args) if cwd_value is None: chat_cwd = _resolve_chat_cwd() else: chat_cwd = Path(cwd_value).resolve() if not chat_cwd.is_dir(): stderr_console.print(f"[red]Not a directory:[/red] {cwd_value}") raise SystemExit(1) cmd: list[str] = [binary] if dangerously_skip_permissions: cmd.append("--dangerously-skip-permissions") cmd.extend(remaining_args) proc = subprocess.run(cmd, cwd=str(chat_cwd), check=False) raise SystemExit(proc.returncode)