From 686c0f736c5eb4ac78a7944ae69642f0e884b46c Mon Sep 17 00:00:00 2001 From: Zhengshou Lai Date: Fri, 17 Apr 2026 00:00:49 +0800 Subject: [PATCH] fix(chat): register --cwd as Click option for shell completion Replace manual ctx.args parsing with a proper @click.option using is_flag=False and flag_value='.'. This enables tab completion for the --cwd / -C option and directory-only path completion after it. Also bump click dependency to >=8.3.2 to avoid the optional-value regression in 8.3.0/8.3.1. --- myclaude/commands/chat.py | 66 +++++++++++---------------------------- pyproject.toml | 2 +- 2 files changed, 19 insertions(+), 49 deletions(-) diff --git a/myclaude/commands/chat.py b/myclaude/commands/chat.py index b7dacd0..d5ff82a 100644 --- a/myclaude/commands/chat.py +++ b/myclaude/commands/chat.py @@ -3,7 +3,6 @@ import os import shutil import subprocess -import sys from pathlib import Path import click @@ -27,45 +26,6 @@ def _resolve_chat_cwd() -> Path: 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={ @@ -79,8 +39,21 @@ def _parse_cwd_from_args(args: list[str]) -> tuple[str | None, list[str]]: default=False, help="Forward to claude: bypass permission checks (sandbox / isolated use only).", ) +@click.option( + "--cwd", + "-C", + is_flag=False, + flag_value=".", + default=None, + type=click.Path(dir_okay=True, file_okay=False), + help="Use specified path as working directory (default: myclaude project root).", +) @click.pass_context -def chat_cmd(ctx: click.Context, dangerously_skip_permissions: bool) -> None: +def chat_cmd( + ctx: click.Context, + dangerously_skip_permissions: bool, + cwd: str | None, +) -> None: """Run `claude` in the myclaude repo so CLAUDE.md and .claude/ apply; extra args pass through. \b @@ -97,21 +70,18 @@ def chat_cmd(ctx: click.Context, dangerously_skip_permissions: bool) -> None: ) 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: + if cwd is None: chat_cwd = _resolve_chat_cwd() else: - chat_cwd = Path(cwd_value).resolve() + chat_cwd = Path(cwd).resolve() if not chat_cwd.is_dir(): - stderr_console.print(f"[red]Not a directory:[/red] {cwd_value}") + stderr_console.print(f"[red]Not a directory:[/red] {cwd}") raise SystemExit(1) cmd: list[str] = [binary] if dangerously_skip_permissions: cmd.append("--dangerously-skip-permissions") - cmd.extend(remaining_args) + cmd.extend(ctx.args) proc = subprocess.run(cmd, cwd=str(chat_cwd), check=False) raise SystemExit(proc.returncode) diff --git a/pyproject.toml b/pyproject.toml index 2990a9c..7271432 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ version = "0.1.0" description = "Myclaude CLI: package update and Claude Code launcher for this repo" requires-python = ">=3.10" dependencies = [ - "click>=8.0.0", + "click>=8.3.2", "rich>=13.0.0", ]