ahvn.cli.config_cli 源代码

"""\
Configuration management commands for AgentHeaven CLI.
"""

import click
from ahvn.cli.utils import AliasedGroup

from typing import Optional, TYPE_CHECKING

if TYPE_CHECKING:
    from ahvn.utils.basic.config_utils import ConfigManager


[文档] def register_config_commands(cli, cm: Optional["ConfigManager"] = None, name: str = "ahvn"): """\ Register all configuration management commands to the CLI. """ if cm is None: from ahvn.utils.basic.config_utils import HEAVEN_CM cm = HEAVEN_CM @cli.group("config", cls=AliasedGroup, help="Config operations: show, set, unset configuration values.") def config(): """\ Config operations (show, set, unset). """ pass @config.command("show", help="Show config values for a given level.") @click.argument("key", metavar="KEY", nargs=1, required=False, default=None) @click.option("--global", "-g", "is_global", is_flag=True, help="Show global config (default: local)") @click.option("--system", "-s", "is_system", is_flag=True, help="Show system config") @click.option( "--cwd", "-c", "cwd", type=click.Path(exists=True, file_okay=False, dir_okay=True, resolve_path=True), help="Set working directory for local config" ) def show_config(key, is_global, is_system, cwd): """\ Show config values. """ from ahvn.utils.basic.serialize_utils import dumps_yaml from ahvn.utils.basic.config_utils import dget # Set cwd if provided if cwd: cm.set_cwd(cwd) if is_system: cfg = cm.get(None, level="system") elif is_global: cfg = cm.get(None, level="global") else: cfg = cm.get(None, level="local") # If key specified, show subconfig for that key path if key: subcfg = dget(cfg, key) click.echo(dumps_yaml(subcfg)) else: click.echo(dumps_yaml(cfg)) @config.command("set", help=f"Set a config value. Example: {name} config set [--global] [--json] KEY VALUE") @click.argument("key", metavar="KEY", nargs=1, required=True) @click.argument("value", metavar="VALUE", nargs=1, required=True) @click.option("--global", "-g", "is_global", is_flag=True, help="Set global config (default: local)") @click.option("--json", "-j", "is_json", is_flag=True, help="Parse value as JSON") @click.option( "--cwd", "-c", "cwd", type=click.Path(exists=True, file_okay=False, dir_okay=True, resolve_path=True), help="Set working directory for local config" ) def set_config(key, value, is_global, is_json, cwd): """\ Set a config value. Usage: {name} config set [--global] [--json] key value """ from ahvn.utils.basic.type_utils import autotype # Set cwd if provided if cwd: cm.set_cwd(cwd) if is_json: from ahvn.utils.basic.serialize_utils import loads_json try: value = loads_json(value) except Exception as e: from ahvn.utils.basic.color_utils import color_error click.echo(color_error(f"Invalid JSON value: {e}"), err=True) return level = "global" if is_global else "local" value = autotype(value) changed = cm.set(key, value, level=level) if not changed: from ahvn.utils.basic.color_utils import color_error click.echo(color_error(f"Failed to set {key}."), err=True) @config.command("unset", help=f"Unset a config value. Example: {name} config unset [--global] KEY") @click.argument("key", metavar="KEY", nargs=1, required=True) @click.option("--global", "-g", "is_global", is_flag=True, help="Unset global config (default: local)") @click.option( "--cwd", "-c", "cwd", type=click.Path(exists=True, file_okay=False, dir_okay=True, resolve_path=True), help="Set working directory for local config" ) def unset_config(key, is_global, cwd): """\ Unset a config value. Usage: {name} config unset [--global] key """ # Set cwd if provided if cwd: cm.set_cwd(cwd) level = "global" if is_global else "local" changed = cm.unset(key, level=level) if not changed: from ahvn.utils.basic.color_utils import color_error click.echo(color_error(f"Failed to unset {key}."), err=True) @config.command("copy", help=f"Copy a config value to local config. Example: {name} config copy [-g] [KEY]") @click.argument("key", metavar="KEY", nargs=1, required=False, default=None) @click.option("--global", "-g", "from_default", is_flag=True, help="Copy from system (default) config instead of global config") @click.option("--yes", "-y", "skip_confirm", is_flag=True, help="Skip confirmation prompt when copying all configs") @click.option( "--cwd", "-c", "cwd", type=click.Path(exists=True, file_okay=False, dir_okay=True, resolve_path=True), help="Set working directory for local config" ) def copy_config(key, from_default, skip_confirm, cwd): """\ Copy a config value from global or system config to local config. By default, copies from global config. Use -g to copy from system (default) config. If no key is specified, copies all configs (requires confirmation). """ from ahvn.utils.basic.config_utils import dget # Set cwd if provided if cwd: cm.set_cwd(cwd) source_level = "system" if from_default else "global" source_config = cm.get(None, level=source_level) # If no key specified, copy all configs if not key: if not skip_confirm: from ahvn.utils.basic.color_utils import color_warning click.echo(color_warning(f"This will replace ALL local config with {source_level} config.")) if not click.confirm("Are you sure you want to continue?"): click.echo("Aborted.") return # Replace entire local config with source config cm._local_config = dict(source_config) cm.save(level="local") from ahvn.utils.basic.color_utils import color_success click.echo(color_success(f"Successfully copied all configs from {source_level} to local.")) return value = dget(source_config, key) if value is None: from ahvn.utils.basic.color_utils import color_error click.echo(color_error(f"Key '{key}' not found in {source_level} config."), err=True) return changed = cm.set(key, value, level="local") if not changed: from ahvn.utils.basic.color_utils import color_error click.echo(color_error(f"Failed to copy {key} to local config."), err=True) @config.command("edit", help="Edit config file for a given level in your editor.") @click.option("--global", "-g", "is_global", is_flag=True, help="Edit global config (default: local)") @click.option("--system", "-s", "is_system", is_flag=True, help="Edit system config") @click.option( "--cwd", "-c", "cwd", type=click.Path(exists=True, file_okay=False, dir_okay=True, resolve_path=True), help="Set working directory for local config" ) def edit_config(is_global, is_system, cwd): """\ Edit config file in your default editor. """ import os import sys import subprocess # Set cwd if provided if cwd: cm.set_cwd(cwd) # Determine config level if is_system: level = "system" elif is_global: level = "global" else: level = "local" cfg_path = cm.config_path(level=level) if not cfg_path or not os.path.exists(cfg_path): from ahvn.utils.basic.color_utils import color_error click.echo(color_error(f"No config file found for level '{level}'."), err=True) sys.exit(1) editor = os.environ.get("EDITOR", "vim") try: subprocess.run([editor, cfg_path]) except Exception as e: from ahvn.utils.basic.color_utils import color_error click.echo(color_error(f"Failed to open editor: {e}"), err=True) sys.exit(1) @config.command("open", help="Open config file for a given level in your file explorer or editor.") @click.option("--global", "-g", "is_global", is_flag=True, help="Open global config (default: local)") @click.option("--system", "-s", "is_system", is_flag=True, help="Open system config") @click.option( "--cwd", "-c", "cwd", type=click.Path(exists=True, file_okay=False, dir_okay=True, resolve_path=True), help="Set working directory for local config" ) def open_config(is_global, is_system, cwd): """\ Open config file with system open. """ from ahvn.utils.basic.cmd_utils import browse import os import sys # Set cwd if provided if cwd: cm.set_cwd(cwd) # Determine config level if is_system: level = "system" elif is_global: level = "global" else: level = "local" cfg_path = cm.config_path(level=level) if not cfg_path or not os.path.exists(cfg_path): from ahvn.utils.basic.color_utils import color_error click.echo(color_error(f"No config file found for level '{level}'."), err=True) sys.exit(1) try: browse(cfg_path) except Exception as e: from ahvn.utils.basic.color_utils import color_error click.echo(color_error(f"Failed to open config file: {e}"), err=True) sys.exit(1)