From 250e3dd096376de4311a5f67c71a0de6b11c17c9 Mon Sep 17 00:00:00 2001 From: Zhengshou Lai Date: Mon, 13 Apr 2026 09:02:16 +0800 Subject: [PATCH] =?UTF-8?q?feat(chat):=20--cwd=20=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E5=8F=AF=E9=80=89=E5=80=BC=EF=BC=8C=E7=BC=BA=E7=9C=81=E4=B8=BA?= =?UTF-8?q?=E5=BD=93=E5=89=8D=E7=9B=AE=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 使 --cwd 选项支持无值调用: - --cwd 单独使用 → 默认为当前目录 "." - --cwd /path → 使用指定路径 - --cwd=. / -C. → 等号或短选项语法 修复:--cwd 后接其他 flag 时被误认为值的歧义问题。 --- myclaude/commands/chat.py | 81 ++++++++++++++++++++++++++++++++++----- 1 file changed, 72 insertions(+), 9 deletions(-) diff --git a/myclaude/commands/chat.py b/myclaude/commands/chat.py index 10f4f2a..265dd3b 100644 --- a/myclaude/commands/chat.py +++ b/myclaude/commands/chat.py @@ -12,21 +12,60 @@ 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: - console.print( + stderr_console.print( "[red]Cannot resolve myclaude project root.[/red] Run from the repo or set " "[cyan]MYCLAUDE_PROJECT_ROOT[/cyan].", - file=sys.stderr, ) 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={ @@ -40,23 +79,47 @@ def _resolve_chat_cwd() -> Path: default=False, help="Forward to claude: bypass permission checks (sandbox / isolated use only).", ) +@click.option( + "--cwd", + "-C", + multiple=True, + metavar="PATH", + help="Working directory for claude (default: myclaude project root; '--cwd' uses current dir; '--cwd /path' uses specific path).", +) @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.""" +def chat_cmd(ctx: click.Context, dangerously_skip_permissions: bool, cwd: tuple[str, ...]) -> 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: - console.print( + stderr_console.print( "[red]claude CLI not found in PATH.[/red] Install Claude Code or set " "[cyan]CLAUDE_BIN[/cyan].", - file=sys.stderr, ) raise SystemExit(127) - cwd = _resolve_chat_cwd() + # Parse --cwd from raw args since Click doesn't support optional values natively + # (We ignore the 'cwd' parameter from Click and parse manually from ctx.args) + 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(ctx.args) + cmd.extend(remaining_args) - proc = subprocess.run(cmd, cwd=str(cwd), check=False) + proc = subprocess.run(cmd, cwd=str(chat_cwd), check=False) raise SystemExit(proc.returncode)