Files
myagents/myclaude/commands/chat.py
T
Zhengshou Lai 929d808b3e fix(chat): remove --cwd from Click options to allow optional value parsing
--cwd was defined as a Click option but also parsed manually from ctx.args,
which caused conflicts when --cwd was followed by another flag (like
--dangerously-skip-permissions). Now --cwd is parsed entirely manually,
allowing:
  --cwd alone -> use current directory
  --cwd /path -> use specified path
  (none)      -> use myclaude project root (default)
2026-04-13 09:09:53 +08:00

118 lines
3.4 KiB
Python

"""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)