renaming from mybot to myclaude

This commit is contained in:
Zhengshou Lai
2026-04-06 14:04:11 +08:00
parent b98d35c387
commit 5ecf737de6
11 changed files with 55 additions and 37 deletions
+1
View File
@@ -0,0 +1 @@
"""Mybot CLI package."""
+3
View File
@@ -0,0 +1,3 @@
from myclaude.cli import main
main()
+32
View File
@@ -0,0 +1,32 @@
"""Myclaude CLI entrypoint."""
from importlib.metadata import PackageNotFoundError, version
import click
from myclaude.commands import chat_cmd, update_cmd
def _package_version() -> str:
try:
return version("myclaude")
except PackageNotFoundError:
return "0.0.0"
@click.group()
@click.version_option(version=_package_version())
def cli() -> None:
"""Myclaude: CLI (update package, chat = Claude Code in this repo)."""
cli.add_command(update_cmd)
cli.add_command(chat_cmd)
def main() -> None:
cli()
if __name__ == "__main__":
main()
+6
View File
@@ -0,0 +1,6 @@
"""CLI subcommands."""
from .chat import chat_cmd
from .update import update_cmd
__all__ = ["chat_cmd", "update_cmd"]
+62
View File
@@ -0,0 +1,62 @@
"""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()
def _resolve_chat_cwd() -> Path:
root = get_myclaude_project_root()
fallback = Path.home() / ".myclaude"
if root == fallback:
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
@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."""
binary = os.environ.get("CLAUDE_BIN") or shutil.which("claude")
if not binary:
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()
cmd: list[str] = [binary]
if dangerously_skip_permissions:
cmd.append("--dangerously-skip-permissions")
cmd.extend(ctx.args)
proc = subprocess.run(cmd, cwd=str(cwd), check=False)
raise SystemExit(proc.returncode)
+54
View File
@@ -0,0 +1,54 @@
"""Reinstall myclaude from the local repo."""
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()
def _run_make_install(root: Path) -> int:
return subprocess.run(
["make", "install"],
cwd=str(root),
check=False,
).returncode
def _run_pip_editable(root: Path) -> int:
cmd = [sys.executable, "-m", "pip", "install", "-e", str(root)]
return subprocess.run(cmd, cwd=str(root), check=False).returncode
@click.command("update")
def update_cmd() -> None:
"""Reinstall myclaude from this repository (make install, or pip install -e)."""
root = get_myclaude_project_root()
fallback = Path.home() / ".myclaude"
if root == fallback:
console.print(
"[red]Not inside myclaude repo.[/red] Set [cyan]MYCLAUDE_PROJECT_ROOT[/cyan] "
"or run from the clone.",
file=sys.stderr,
)
raise SystemExit(1)
console.print("[bold cyan]Updating myclaude…[/bold cyan]")
makefile = root / "Makefile"
if makefile.is_file():
rc = _run_make_install(root)
if rc != 0:
console.print("[yellow]make install failed, trying pip -e…[/yellow]")
rc = _run_pip_editable(root)
else:
rc = _run_pip_editable(root)
if rc != 0:
console.print("[red]Update failed.[/red]", file=sys.stderr)
raise SystemExit(rc)
console.print("[green]myclaude updated.[/green]")
+56
View File
@@ -0,0 +1,56 @@
"""Resolve myclaude repository root for make / editable install flows."""
import os
from pathlib import Path
def _pyproject_names_myclaude(path: Path) -> bool:
try:
text = path.read_text(encoding="utf-8", errors="ignore")
except OSError:
return False
return 'name = "myclaude"' in text or "name = 'myclaude'" in text
def _walk_up_for_pyproject(start: Path) -> Path | None:
p = start.resolve()
for _ in range(16):
candidate = p / "pyproject.toml"
if candidate.is_file() and _pyproject_names_myclaude(candidate):
return p
parent = p.parent
if parent == p:
break
p = parent
return None
def get_myclaude_project_root() -> Path:
"""
Root of the myclaude repo (contains Makefile + pyproject).
Order: MYCLAUDE_PROJECT_ROOT > walk from cwd > package source tree > ~/.myclaude
"""
env_root = os.environ.get("MYCLAUDE_PROJECT_ROOT")
if env_root:
return Path(env_root).resolve()
try:
cwd = Path.cwd()
except (OSError, PermissionError):
cwd = None
if cwd is not None:
found = _walk_up_for_pyproject(cwd)
if found is not None:
return found
here = Path(__file__).resolve().parent
for _ in range(8):
pyproject = here / "pyproject.toml"
if pyproject.is_file() and _pyproject_names_myclaude(pyproject):
return here
if here.parent == here:
break
here = here.parent
return Path.home() / ".myclaude"