diff --git a/benchmark/benchmark.py b/benchmark/benchmark.py index 3c83ba0b0a6..243c6aff8f9 100755 --- a/benchmark/benchmark.py +++ b/benchmark/benchmark.py @@ -40,7 +40,7 @@ # Cache for commit-hash -> version lookup _VERSION_CACHE = {} -BENCHMARK_DNAME = Path(os.environ.get("CECLIBENCHMARK_DIR", "tmp.benchmarks")) +BENCHMARK_DNAME = Path(os.environ.get("CECLI_BENCHMARK_DIR", "tmp.benchmarks")) EXERCISES_DIR_DEFAULT = "cecli-cat" RESULTS_DIR_DEFAULT = "cat-results" @@ -209,9 +209,11 @@ def main( return 1 results_dir = resolved_results_dir - if not dry and "CECLIDOCKER" not in os.environ: + if not dry and "CECLI_DOCKER" not in os.environ: logger.warning("Warning: Benchmarking runs unvetted code. Run in a docker container.") - logger.warning("Set CECLIDOCKER in the environment to by-pass this check at your own risk.") + logger.warning( + "Set CECLI_DOCKER in the environment to by-pass this check at your own risk." + ) return # Check dirs exist diff --git a/benchmark/benchmark_classic.py b/benchmark/benchmark_classic.py index b6e79240b69..89ee057a860 100755 --- a/benchmark/benchmark_classic.py +++ b/benchmark/benchmark_classic.py @@ -34,7 +34,7 @@ # Cache for commit-hash -> version lookup _VERSION_CACHE = {} -BENCHMARK_DNAME = Path(os.environ.get("CECLIBENCHMARK_DIR", "tmp.benchmarks")) +BENCHMARK_DNAME = Path(os.environ.get("CECLI_BENCHMARK_DIR", "tmp.benchmarks")) EXERCISES_DIR_DEFAULT = "polyglot-benchmark" @@ -267,7 +267,7 @@ def main( if repo.is_dirty(): commit_hash += "-dirty" - if "CECLIDOCKER" not in os.environ: + if "CECLI_DOCKER" not in os.environ: print("Warning: benchmarking runs unvetted code from GPT, run in a docker container") return diff --git a/cecli/__init__.py b/cecli/__init__.py index 67dfd72b26a..c4d6fec1512 100644 --- a/cecli/__init__.py +++ b/cecli/__init__.py @@ -1,6 +1,6 @@ from packaging import version -__version__ = "0.92.0.dev" +__version__ = "0.92.1.dev" safe_version = __version__ try: diff --git a/cecli/args.py b/cecli/args.py index b62a6c3cf9f..4c0434672ce 100644 --- a/cecli/args.py +++ b/cecli/args.py @@ -38,7 +38,7 @@ def get_parser(default_config_files, git_root): add_config_file_help=True, default_config_files=default_config_files, config_file_parser_class=configargparse.YAMLConfigFileParser, - auto_env_var_prefix="CECLI", + auto_env_var_prefix="CECLI_", ) # List of valid edit formats for argparse validation & shtab completion. # Dynamically gather them from the registered coder classes so the list @@ -567,7 +567,7 @@ def get_parser(default_config_files, git_root): group.add_argument( "--cecli-ignore", - metavar="CECLIIGNORE", + metavar="CECLI_IGNORE", type=lambda path_str: resolve_cecli_ignore_path(path_str, git_root), default=default_cecli_ignore_file, help="Specify the cecli ignore file (default: .cecli.ignore in git root)", diff --git a/cecli/coders/architect_coder.py b/cecli/coders/architect_coder.py index a5382f44aa8..75a1d7f4156 100644 --- a/cecli/coders/architect_coder.py +++ b/cecli/coders/architect_coder.py @@ -1,6 +1,6 @@ import asyncio -from ..commands import SwitchCoder +from ..commands import SwitchCoderSignal from .ask_coder import AskCoder from .base_coder import Coder @@ -60,4 +60,4 @@ async def reply_completed(self): except Exception as e: self.io.tool_error(e) - raise SwitchCoder(main_model=self.main_model, edit_format="architect") + raise SwitchCoderSignal(main_model=self.main_model, edit_format="architect") diff --git a/cecli/coders/base_coder.py b/cecli/coders/base_coder.py index fa2d262c911..039b194420c 100755 --- a/cecli/coders/base_coder.py +++ b/cecli/coders/base_coder.py @@ -36,7 +36,7 @@ import cecli.prompts.utils.system as prompts from cecli import __version__, models, urls, utils -from cecli.commands import Commands, SwitchCoder +from cecli.commands import Commands, SwitchCoderSignal from cecli.exceptions import LiteLLMExceptions from cecli.helpers import coroutines from cecli.helpers.profiler import TokenProfiler @@ -1370,7 +1370,7 @@ async def _run_parallel(self, with_message=None, preproc=True): if task.exception(): raise task.exception() - except (SwitchCoder, SystemExit): + except (SwitchCoderSignal, SystemExit): # Re-raise SwitchCoder to be handled by outer try block raise except KeyboardInterrupt: @@ -1461,7 +1461,7 @@ async def input_task(self, preproc): self.io.set_placeholder("") self.keyboard_interrupt() await self.io.stop_task_streams() - except (SwitchCoder, SystemExit): + except (SwitchCoderSignal, SystemExit): raise except Exception as e: if self.verbose or self.args.debug: @@ -1496,7 +1496,7 @@ async def output_task(self, preproc): if self.io.output_task.done(): exception = self.io.output_task.exception() if exception: - if isinstance(exception, SwitchCoder): + if isinstance(exception, SwitchCoderSignal): await self.io.output_task raise exception @@ -1519,7 +1519,7 @@ async def output_task(self, preproc): self.io.stop_spinner() self.keyboard_interrupt() await self.io.stop_task_streams() - except (SwitchCoder, SystemExit): + except (SwitchCoderSignal, SystemExit): raise except Exception as e: if self.verbose or self.args.debug: @@ -2138,7 +2138,7 @@ def warm_cache(self, chunks): return delay = 5 * 60 - 5 - delay = float(os.environ.get("CECLICACHE_KEEPALIVE_DELAY", delay)) + delay = float(os.environ.get("CECLI_CACHE_KEEPALIVE_DELAY", delay)) self.next_cache_warm = time.time() + delay self.warming_pings_left = self.num_cache_warming_pings self.cache_warming_chunks = chunks @@ -2741,7 +2741,7 @@ async def get_server_tools(server): ) return (server.name, server_tools) except Exception as e: - if server.name != "unnamed-server" and server.name != "local_tools": + if server.name != "unnamed-server" and server.name != "Local": self.io.tool_warning(f"Error initializing MCP server {server.name}: {e}") return None diff --git a/cecli/commands/__init__.py b/cecli/commands/__init__.py index 183a13e1aec..6b118475204 100644 --- a/cecli/commands/__init__.py +++ b/cecli/commands/__init__.py @@ -5,10 +5,6 @@ BaseCommand pattern for modular, testable command execution. """ -import sys -import traceback -from pathlib import Path - from .add import AddCommand from .agent import AgentCommand from .architect import ArchitectCommand @@ -22,6 +18,7 @@ from .context_management import ContextManagementCommand from .copy import CopyCommand from .copy_context import CopyContextCommand +from .core import Commands, SwitchCoderSignal from .diff import DiffCommand # Import and register commands @@ -127,50 +124,6 @@ CommandRegistry.register(LoadSkillCommand) CommandRegistry.register(RemoveSkillCommand) -# Import SwitchCoder and Commands directly from commands.py -# We need to handle the circular import carefully - -# Add parent directory to path to import commands.py directly -parent_dir = str(Path(__file__).parent.parent) -if parent_dir not in sys.path: - sys.path.insert(0, parent_dir) - -# Import the commands module directly -try: - import importlib.util - - spec = importlib.util.spec_from_file_location( - "cecli.commands_module", Path(__file__).parent.parent / "commands.py" - ) - commands_module = importlib.util.module_from_spec(spec) - sys.modules["cecli.commands_module"] = commands_module - spec.loader.exec_module(commands_module) - - # Get the classes from the module - Commands = getattr(commands_module, "Commands", None) - SwitchCoder = getattr(commands_module, "SwitchCoder", None) - - if Commands is None or SwitchCoder is None: - raise ImportError("Commands or SwitchCoder not found in commands.py") - -except Exception as e: - # Print the error for debugging - print(f"Error importing commands.py: {e}") - traceback.print_exc() - - # Fallback: define simple placeholder classes - class SwitchCoder(Exception): - def __init__(self, placeholder=None, **kwargs): - self.kwargs = kwargs - self.placeholder = placeholder - - class Commands: - """Placeholder for Commands class defined in original commands.py""" - - def __init__(self, *args, **kwargs): - # Accept any arguments but do nothing - pass - __all__ = [ "BaseCommand", @@ -234,6 +187,6 @@ def __init__(self, *args, **kwargs): "CommandPrefixCommand", "LoadSkillCommand", "RemoveSkillCommand", - "SwitchCoder", + "SwitchCoderSignal", "Commands", ] diff --git a/cecli/commands/add.py b/cecli/commands/add.py index c3e6b620efd..00ea6cb9073 100644 --- a/cecli/commands/add.py +++ b/cecli/commands/add.py @@ -137,9 +137,9 @@ async def execute(cls, io, coder, args, **kwargs): map_tokens = 0 map_mul_no_files = 1 - from cecli.commands import SwitchCoder + from cecli.commands import SwitchCoderSignal - raise SwitchCoder( + raise SwitchCoderSignal( edit_format=coder.edit_format, summarize_from_coder=False, from_coder=coder, diff --git a/cecli/commands.py b/cecli/commands/core.py similarity index 89% rename from cecli/commands.py rename to cecli/commands/core.py index 6e2d65a94d4..7a6d5aead1e 100644 --- a/cecli/commands.py +++ b/cecli/commands/core.py @@ -3,16 +3,32 @@ import sys from pathlib import Path +from cecli.commands.utils.registry import CommandRegistry from cecli.helpers.file_searcher import handle_core_files from cecli.repo import ANY_GIT_ERROR -from .commands.utils.registry import CommandRegistry +class SwitchCoderSignal(BaseException): + """ + Signal to switch the current Coder instance to a new configuration. + + This is NOT an error - it's a control flow signal used to propagate + coder switching requests up through the async call stack. It carries + the kwargs needed to create a new Coder instance. + + Note: Inherits from BaseException (like KeyboardInterrupt and SystemExit) + to avoid being caught by generic `except Exception` handlers, making the + non-error nature of this signal explicit. + + Attributes: + kwargs: Configuration dict passed to Coder.create() for the new instance + placeholder: Optional placeholder text for the input prompt + """ -class SwitchCoder(Exception): def __init__(self, placeholder=None, **kwargs): self.kwargs = kwargs self.placeholder = placeholder + super().__init__() class Commands: @@ -119,7 +135,7 @@ async def do_run(self, cmd_name, args, **kwargs): except ANY_GIT_ERROR as err: self.io.tool_error(f"Unable to complete {cmd_name}: {err}") return - except SwitchCoder as e: + except SwitchCoderSignal as e: raise e except Exception as e: self.io.tool_error(f"Error executing command {cmd_name}: {str(e)}") diff --git a/cecli/commands/drop.py b/cecli/commands/drop.py index d438d50998c..13d72951852 100644 --- a/cecli/commands/drop.py +++ b/cecli/commands/drop.py @@ -82,7 +82,7 @@ async def execute(cls, io, coder, args, **kwargs): return format_command_result(io, "drop", "Removed files from chat") finally: - # This mimics the SwitchCoder behavior in the original cmd_drop + # This mimics the SwitchCoderSignal behavior in the original cmd_drop if coder.repo_map: map_tokens = coder.repo_map.max_map_tokens map_mul_no_files = coder.repo_map.map_mul_no_files @@ -90,10 +90,10 @@ async def execute(cls, io, coder, args, **kwargs): map_tokens = 0 map_mul_no_files = 1 - # Raise SwitchCoder to trigger coder recreation - from . import SwitchCoder + # Raise SwitchCoderSignal to trigger coder recreation + from . import SwitchCoderSignal - raise SwitchCoder( + raise SwitchCoderSignal( edit_format=coder.edit_format, summarize_from_coder=False, from_coder=coder, diff --git a/cecli/commands/help.py b/cecli/commands/help.py index 3a943bdd456..0a344a20db2 100644 --- a/cecli/commands/help.py +++ b/cecli/commands/help.py @@ -70,9 +70,9 @@ async def execute(cls, io, coder, args, **kwargs): map_tokens = 0 map_mul_no_files = 1 - from cecli.commands import SwitchCoder + from cecli.commands import SwitchCoderSignal - raise SwitchCoder( + raise SwitchCoderSignal( edit_format=coder.edit_format, summarize_from_coder=False, from_coder=help_coder, diff --git a/cecli/commands/load.py b/cecli/commands/load.py index a32655dd402..80fb743d040 100644 --- a/cecli/commands/load.py +++ b/cecli/commands/load.py @@ -46,9 +46,9 @@ async def execute(cls, io, coder, args, **kwargs): try: await commands_instance.run(cmd) except Exception as e: - # Handle SwitchCoder exception specifically - if type(e).__name__ == "SwitchCoder": - # SwitchCoder is raised when switching between coder types (e.g., /architect, /ask). + # Handle SwitchCoderSignal exception specifically + if type(e).__name__ == "SwitchCoderSignal": + # SwitchCoderSignal is raised when switching between coder types (e.g., /architect, /ask). # This is expected behavior, not an error. But this gets in the way when running `/load` so we # ignore it and continue processing remaining commands. should_raise_at_end = e diff --git a/cecli/commands/model.py b/cecli/commands/model.py index 5bb6edeac34..028a4d6736e 100644 --- a/cecli/commands/model.py +++ b/cecli/commands/model.py @@ -73,23 +73,25 @@ async def execute(cls, io, coder, args, **kwargs): coder.coder_commit_hashes = temp_coder.coder_commit_hashes # Restore the original model configuration - from cecli.commands import SwitchCoder + from cecli.commands import SwitchCoderSignal - raise SwitchCoder(main_model=original_main_model, edit_format=original_edit_format) + raise SwitchCoderSignal( + main_model=original_main_model, edit_format=original_edit_format + ) except Exception as e: # If there's an error, still restore the original model - if not isinstance(e, SwitchCoder): + if not isinstance(e, SwitchCoderSignal): io.tool_error(str(e)) - raise SwitchCoder( + raise SwitchCoderSignal( main_model=original_main_model, edit_format=original_edit_format ) else: - # Re-raise SwitchCoder if that's what was thrown + # Re-raise SwitchCoderSignal if that's what was thrown raise else: - from cecli.commands import SwitchCoder + from cecli.commands import SwitchCoderSignal - raise SwitchCoder(main_model=model, edit_format=new_edit_format) + raise SwitchCoderSignal(main_model=model, edit_format=new_edit_format) @classmethod def get_completions(cls, io, coder, args) -> List[str]: diff --git a/cecli/commands/reset.py b/cecli/commands/reset.py index 608123345d6..d01e2b4a835 100644 --- a/cecli/commands/reset.py +++ b/cecli/commands/reset.py @@ -40,10 +40,10 @@ async def execute(cls, io, coder, args, **kwargs): map_tokens = 0 map_mul_no_files = 1 - # Raise SwitchCoder to trigger coder recreation - from . import SwitchCoder + # Raise SwitchCoderSignal to trigger coder recreation + from . import SwitchCoderSignal - raise SwitchCoder( + raise SwitchCoderSignal( edit_format=coder.edit_format, summarize_from_coder=False, from_coder=coder, diff --git a/cecli/commands/utils/base_command.py b/cecli/commands/utils/base_command.py index b36ea5cd59a..c94206ee45c 100644 --- a/cecli/commands/utils/base_command.py +++ b/cecli/commands/utils/base_command.py @@ -96,9 +96,9 @@ async def _generic_chat_command(cls, io, coder, args, edit_format, placeholder=N """ if not args.strip(): # Switch to the corresponding chat mode - from cecli.commands import SwitchCoder + from cecli.commands import SwitchCoderSignal - raise SwitchCoder(edit_format=edit_format) + raise SwitchCoderSignal(edit_format=edit_format) from cecli.coders.base_coder import Coder @@ -121,9 +121,9 @@ async def _generic_chat_command(cls, io, coder, args, edit_format, placeholder=N await new_coder.generate(user_message=user_msg, preproc=False) coder.coder_commit_hashes = new_coder.coder_commit_hashes - from cecli.commands import SwitchCoder + from cecli.commands import SwitchCoderSignal - raise SwitchCoder( + raise SwitchCoderSignal( main_model=original_main_model, edit_format=original_edit_format, done_messages=new_coder.done_messages, diff --git a/cecli/commands/weak_model.py b/cecli/commands/weak_model.py index be1a1ead4aa..01437c1e000 100644 --- a/cecli/commands/weak_model.py +++ b/cecli/commands/weak_model.py @@ -70,23 +70,25 @@ async def execute(cls, io, coder, args, **kwargs): coder.coder_commit_hashes = temp_coder.coder_commit_hashes # Restore the original model configuration - from cecli.commands import SwitchCoder + from cecli.commands import SwitchCoderSignal - raise SwitchCoder(main_model=original_main_model, edit_format=original_edit_format) + raise SwitchCoderSignal( + main_model=original_main_model, edit_format=original_edit_format + ) except Exception as e: # If there's an error, still restore the original model - if not isinstance(e, SwitchCoder): + if not isinstance(e, SwitchCoderSignal): io.tool_error(str(e)) - raise SwitchCoder( + raise SwitchCoderSignal( main_model=original_main_model, edit_format=original_edit_format ) else: - # Re-raise SwitchCoder if that's what was thrown + # Re-raise SwitchCoderSignal if that's what was thrown raise else: - from cecli.commands import SwitchCoder + from cecli.commands import SwitchCoderSignal - raise SwitchCoder(main_model=model, edit_format=coder.edit_format) + raise SwitchCoderSignal(main_model=model, edit_format=coder.edit_format) @classmethod def get_completions(cls, io, coder, args) -> List[str]: diff --git a/cecli/main.py b/cecli/main.py index 8d1f46d934d..f82c665d8c5 100644 --- a/cecli/main.py +++ b/cecli/main.py @@ -3,7 +3,7 @@ from cecli.helpers.file_searcher import handle_core_files try: - if not os.getenv("CECLIDEFAULT_TLS"): + if not os.getenv("CECLI_DEFAULT_TLS"): import truststore truststore.inject_into_ssl() @@ -39,7 +39,7 @@ from cecli.args import get_parser from cecli.coders import Coder from cecli.coders.base_coder import UnknownEditFormat -from cecli.commands import Commands, SwitchCoder +from cecli.commands import Commands, SwitchCoderSignal from cecli.deprecated_args import handle_deprecated_model_args from cecli.format_settings import format_settings, scrub_sensitive_info from cecli.helpers.copypaste import ClipboardWatcher @@ -1127,7 +1127,7 @@ def apply_model_overrides(model_name): io.tool_output() try: await coder.run(with_message=args.message) - except (SwitchCoder, KeyboardInterrupt, SystemExit): + except (SwitchCoderSignal, KeyboardInterrupt, SystemExit): pass return await graceful_exit(coder) if args.message_file: @@ -1135,7 +1135,7 @@ def apply_model_overrides(model_name): message_from_file = io.read_text(args.message_file) io.tool_output() await coder.run(with_message=message_from_file) - except (SwitchCoder, KeyboardInterrupt, SystemExit): + except (SwitchCoderSignal, KeyboardInterrupt, SystemExit): pass except FileNotFoundError: io.tool_error(f"Message file not found: {args.message_file}") @@ -1167,7 +1167,7 @@ def apply_model_overrides(model_name): coder.ok_to_warm_cache = bool(args.cache_keepalive_pings) await coder.run() return await graceful_exit(coder) - except SwitchCoder as switch: + except SwitchCoderSignal as switch: coder.ok_to_warm_cache = False if hasattr(switch, "placeholder") and switch.placeholder is not None: io.placeholder = switch.placeholder diff --git a/cecli/mcp/__init__.py b/cecli/mcp/__init__.py index f40c27af978..44d1e6a5f15 100644 --- a/cecli/mcp/__init__.py +++ b/cecli/mcp/__init__.py @@ -11,7 +11,7 @@ def _parse_mcp_servers_from_json_string(json_string, io, verbose=False, mcp_tran try: config = json.loads(json_string) if verbose: - io.tool_output("Loading MCP servers from provided JSON string") + io.tool_output("Loading MCP servers from provided JSON") if "mcpServers" in config: for name, server_config in config["mcpServers"].items(): @@ -22,21 +22,21 @@ def _parse_mcp_servers_from_json_string(json_string, io, verbose=False, mcp_tran server_config["name"] = name transport = server_config.get("transport", mcp_transport) if transport == "stdio": - servers.append(McpServer(server_config)) + servers.append(McpServer(server_config, io=io, verbose=verbose)) elif transport == "http": - servers.append(HttpStreamingServer(server_config)) + servers.append(HttpStreamingServer(server_config, io=io, verbose=verbose)) elif transport == "sse": - servers.append(SseServer(server_config)) + servers.append(SseServer(server_config, io=io, verbose=verbose)) if verbose: - io.tool_output(f"Loaded {len(servers)} MCP servers from JSON string") + io.tool_output(f"Loaded {len(servers)} MCP servers") return servers else: - io.tool_warning("No 'mcpServers' key found in MCP config JSON string") + io.tool_warning("No 'mcpServers' key found in MCP config") except json.JSONDecodeError: - io.tool_error("Invalid JSON in MCP config string") + io.tool_error("Invalid JSON in MCP config") except Exception as e: - io.tool_error(f"Error loading MCP config from string: {e}") + io.tool_error(f"Error loading MCP config: {e}") return servers @@ -100,44 +100,24 @@ def _resolve_mcp_config_path(file_path, io, verbose=False): def _parse_mcp_servers_from_file(file_path, io, verbose=False, mcp_transport="stdio"): """Parse MCP servers from a JSON file.""" - servers = [] - # Resolve the file path relative to closest cecli.conf.yml, git directory, or CWD resolved_file_path = _resolve_mcp_config_path(file_path, io, verbose) try: with open(resolved_file_path, "r") as f: - config = json.load(f) + json_string = f.read() if verbose: io.tool_output(f"Loading MCP servers from file: {file_path}") - if "mcpServers" in config: - for name, server_config in config["mcpServers"].items(): - if verbose: - io.tool_output(f"Loading MCP server: {name}") + return _parse_mcp_servers_from_json_string(json_string, io, verbose, mcp_transport) - # Create a server config with name included - server_config["name"] = name - transport = server_config.get("transport", mcp_transport) - if transport == "stdio": - servers.append(McpServer(server_config)) - elif transport == "http": - servers.append(HttpStreamingServer(server_config)) - - if verbose: - io.tool_output(f"Loaded {len(servers)} MCP servers from {file_path}") - return servers - else: - io.tool_warning(f"No 'mcpServers' key found in MCP config file: {file_path}") except FileNotFoundError: io.tool_warning(f"MCP config file not found: {file_path}") - except json.JSONDecodeError: - io.tool_error(f"Invalid JSON in MCP config file: {file_path}") except Exception as e: - io.tool_error(f"Error loading MCP config from file: {e}") + io.tool_error(f"Error reading MCP config file: {e}") - return servers + return [] def load_mcp_servers(mcp_servers, mcp_servers_file, io, verbose=False, mcp_transport="stdio"): @@ -169,6 +149,6 @@ def load_mcp_servers(mcp_servers, mcp_servers_file, io, verbose=False, mcp_trans # and maybe it is actually prompt_toolkit's fault # but this hack works swimmingly because ??? # so sure! why not - servers = [McpServer(json.loads('{"cecli_default": {}}'))] + servers = [McpServer(json.loads('{"cecli_default": {}}'), io=io, verbose=verbose)] return servers diff --git a/cecli/mcp/oauth.py b/cecli/mcp/oauth.py new file mode 100644 index 00000000000..c9d9897116f --- /dev/null +++ b/cecli/mcp/oauth.py @@ -0,0 +1,250 @@ +import asyncio +import base64 +import hashlib +import http.server +import json +import os +import secrets +import socketserver +import threading +import time +from pathlib import Path +from typing import Awaitable, Callable, Optional, Tuple +from urllib.parse import parse_qs, urlparse + +from mcp.client.auth import TokenStorage +from mcp.shared.auth import OAuthClientInformationFull, OAuthToken + + +def find_available_port(start_port=8484, end_port=8584): + """Find an available port in the given range.""" + for port in range(start_port, end_port + 1): + try: + # Check if the port is available by trying to bind to it + with socketserver.TCPServer(("localhost", port), None): + return port + except OSError: + # Port is likely already in use + continue + return None + + +def create_oauth_callback_server( + port, path="/callback" +) -> Tuple[Callable[[], Awaitable[Tuple[str, str]]], Callable[[], None]]: + """ + Create a local HTTP server to handle OAuth callback. + + Returns: + Tuple of (async callback handler function, shutdown function) + """ + auth_code = None + state = None + server_error = None + callback_received = threading.Event() + server = None + + class OAuthCallbackHandler(http.server.SimpleHTTPRequestHandler): + def do_GET(self): + nonlocal auth_code, state, server_error + parsed_path = urlparse(self.path) + + if parsed_path.path == path: + query_params = parse_qs(parsed_path.query) + if "code" in query_params: + auth_code = query_params["code"][0] + if "state" in query_params: + state = query_params["state"][0] + + self.send_response(200) + self.send_header("Content-type", "text/html") + self.end_headers() + self.wfile.write( + b"

Success!

" + b"

Authentication successful. You can close this browser tab.

" + b"" + ) + callback_received.set() + elif "error" in query_params: + error = query_params["error"][0] + error_desc = query_params.get("error_description", [""])[0] + server_error = f"OAuth error: {error} - {error_desc}" + + self.send_response(400) + self.send_header("Content-type", "text/html") + self.end_headers() + self.wfile.write( + "

Authentication Failed

" + f"

{error}: {error_desc}

".encode() + ) + callback_received.set() + else: + self.send_response(400) + self.send_header("Content-type", "text/html") + self.end_headers() + self.wfile.write(b"

Invalid Request

") + else: + self.send_response(404) + self.send_header("Content-type", "text/html") + self.end_headers() + self.wfile.write(b"

Not Found

") + + def log_message(self, format, *args): + pass + + # Start server in a separate thread + def start_server(): + nonlocal server + try: + server = socketserver.TCPServer(("localhost", port), OAuthCallbackHandler) + server.serve_forever() + except Exception as e: + server_error = f"Server error: {e}" # noqa + callback_received.set() + + server_thread = threading.Thread(target=start_server, daemon=True) + server_thread.start() + + # Shutdown function + def shutdown(): + nonlocal server + if server: + server.shutdown() + server = None + + async def get_auth_code() -> Tuple[str, str]: + # Wait for callback to be received + MINUTES = 5 + timeout = MINUTES * 60 + + start_time = time.time() + while not callback_received.is_set(): + if time.time() - start_time > timeout: + shutdown() + raise Exception(f"OAuth callback timed out after {MINUTES} minutes") + + # Small sleep to avoid busy waiting + await asyncio.sleep(0.1) + + if server_error: + shutdown() + raise Exception(server_error) + + if not auth_code: + shutdown() + raise Exception("No authorization code received") + + return auth_code, state + + return get_auth_code, shutdown + + +def generate_pkce_codes(): + """Generate PKCE code verifier and challenge.""" + code_verifier = secrets.token_urlsafe(64) + hasher = hashlib.sha256() + hasher.update(code_verifier.encode("utf-8")) + code_challenge = base64.urlsafe_b64encode(hasher.digest()).rstrip(b"=").decode("utf-8") + return code_verifier, code_challenge + + +def get_token_file_path(): + """Get the path to the MCP OAuth tokens file.""" + config_dir = Path.home() / ".cecli" + config_dir.mkdir(parents=True, exist_ok=True) + return config_dir / "mcp-oauth-tokens.json" + + +def load_mcp_oauth_tokens(): + """Load stored OAuth tokens from file.""" + token_file = get_token_file_path() + if not token_file.exists(): + return {} + + try: + with open(token_file, "r", encoding="utf-8") as f: + # File might be empty + return json.load(f) or {} + except Exception: + return {} + + +def save_mcp_oauth_token(server_name, token_data): + """Save OAuth token for an MCP server.""" + tokens = load_mcp_oauth_tokens() + tokens[server_name] = token_data + + token_file = get_token_file_path() + try: + with open(token_file, "w", encoding="utf-8") as f: + json.dump(tokens, f, indent=2) + # Set restrictive permissions (owner read/write only) + os.chmod(token_file, 0o600) + except Exception as e: + raise Exception(f"Failed to save OAuth token: {e}") + + +def save_mcp_oauth_tokens(tokens_dict): + """Save all OAuth tokens to file.""" + token_file = get_token_file_path() + try: + with open(token_file, "w", encoding="utf-8") as f: + json.dump(tokens_dict, f, indent=2) + # Set restrictive permissions (owner read/write only) + os.chmod(token_file, 0o600) + except Exception as e: + raise Exception(f"Failed to save OAuth tokens: {e}") + + +def get_mcp_oauth_token(server_name): + """Retrieve stored OAuth token for an MCP server.""" + tokens = load_mcp_oauth_tokens() + return tokens.get(server_name, {}) + + +class FileBasedTokenStorage(TokenStorage): + """File-based token storage for MCP OAuth using the SDK's TokenStorage interface.""" + + def __init__(self, server_name: str): + self.server_name = server_name + + async def get_tokens(self) -> Optional[OAuthToken]: + """Get stored tokens for this server.""" + all_tokens = load_mcp_oauth_tokens() + server_data = all_tokens.get(self.server_name, {}) + + if "tokens" not in server_data: + return None + + return OAuthToken.model_validate(server_data["tokens"]) + + async def set_tokens(self, tokens: OAuthToken) -> None: + """Store tokens for this server.""" + all_tokens = load_mcp_oauth_tokens() + + if self.server_name not in all_tokens: + all_tokens[self.server_name] = {} + + tokens_dict = tokens.model_dump() + all_tokens[self.server_name]["tokens"] = tokens_dict + save_mcp_oauth_tokens(all_tokens) + + async def get_client_info(self) -> Optional[OAuthClientInformationFull]: + """Get stored client information.""" + all_tokens = load_mcp_oauth_tokens() + server_data = all_tokens.get(self.server_name, {}) + + if "client_info" not in server_data: + return None + + return OAuthClientInformationFull.model_validate(server_data["client_info"]) + + async def set_client_info(self, client_info: OAuthClientInformationFull) -> None: + """Store client information.""" + all_tokens = load_mcp_oauth_tokens() + + if self.server_name not in all_tokens: + all_tokens[self.server_name] = {} + + all_tokens[self.server_name]["client_info"] = json.loads(client_info.model_dump_json()) + save_mcp_oauth_tokens(all_tokens) diff --git a/cecli/mcp/server.py b/cecli/mcp/server.py index 9d4162fb666..58c2bcb661e 100644 --- a/cecli/mcp/server.py +++ b/cecli/mcp/server.py @@ -1,12 +1,25 @@ import asyncio import logging import os +import webbrowser from contextlib import AsyncExitStack +from urllib.parse import urlparse +import httpx from mcp import ClientSession, StdioServerParameters +from mcp.client.auth import OAuthClientProvider from mcp.client.sse import sse_client from mcp.client.stdio import stdio_client -from mcp.client.streamable_http import streamablehttp_client +from mcp.client.streamable_http import streamable_http_client +from mcp.shared.auth import OAuthClientMetadata + +from cecli.mcp.oauth import ( + FileBasedTokenStorage, + create_oauth_callback_server, + find_available_port, + get_mcp_oauth_token, + save_mcp_oauth_token, +) class McpServer: @@ -17,14 +30,18 @@ class McpServer: Uses the mcp library to create and initialize ClientSession objects. """ - def __init__(self, server_config): + def __init__(self, server_config, io=None, verbose=False): """Initialize the MCP tool provider. Args: server_config: Configuration for the MCP server + io: InputOutput object for user interaction + verbose: Whether to output verbose logging """ self.config = server_config self.name = server_config.get("name", "unnamed-server") + self.io = io + self.verbose = verbose self.session = None self._cleanup_lock: asyncio.Lock = asyncio.Lock() self.exit_stack = AsyncExitStack() @@ -39,15 +56,21 @@ async def connect(self): ClientSession: The active session """ if self.session is not None: - logging.info(f"Using existing session for MCP server: {self.name}") + if self.verbose and self.io: + self.io.tool_output(f"Using existing session for MCP server: {self.name}") return self.session - logging.info(f"Establishing new connection to MCP server: {self.name}") + if self.verbose and self.io: + self.io.tool_output(f"Establishing new connection to MCP server: {self.name}") + command = self.config["command"] + + env = {**os.environ, **self.config["env"]} if self.config.get("env") else None + server_params = StdioServerParameters( command=command, args=self.config.get("args"), - env={**os.environ, **self.config["env"]} if self.config.get("env") else None, + env=env, ) try: @@ -76,58 +99,163 @@ async def disconnect(self): logging.error(f"Error during cleanup of server {self.name}: {e}") -class HttpStreamingServer(McpServer): - """HTTP streaming MCP server using mcp.client.streamablehttp_client.""" +class HttpBasedMcpServer(McpServer): + """Base class for HTTP-based MCP servers (HTTP streaming and SSE).""" - async def connect(self): - if self.session is not None: - logging.info(f"Using existing session for MCP server: {self.name}") - return self.session + async def _create_oauth_provider(self): + """Create an OAuthClientProvider using the MCP SDK.""" + parsed = urlparse(self.config.get("url")) + server_url = f"{parsed.scheme}://{parsed.netloc}" + if self.verbose and self.io: + self.io.tool_output(f"Auto-derived OAuth server URL: {server_url}", log_only=True) - logging.info(f"Establishing new connection to HTTP MCP server: {self.name}") - try: - url = self.config.get("url") - headers = self.config.get("headers", {}) - http_transport = await self.exit_stack.enter_async_context( - streamablehttp_client(url, headers=headers) - ) - read, write, _response = http_transport + # Check if we have existing client info with a redirect URI + server_info = get_mcp_oauth_token(self.name) + existing_redirect_uri = None - session = await self.exit_stack.enter_async_context(ClientSession(read, write)) - await session.initialize() - self.session = session - return session - except Exception as e: - logging.error(f"Error initializing HTTP server {self.name}: {e}") - await self.disconnect() - raise + if "client_info" in server_info and "redirect_uris" in server_info["client_info"]: + redirect_uris = server_info["client_info"].get("redirect_uris", []) + if redirect_uris: + existing_redirect_uri = redirect_uris[0] + if self.verbose and self.io: + self.io.tool_output( + f"Found existing redirect URI: {existing_redirect_uri}", log_only=True + ) + + # If we have an existing redirect URI, parse it to get the port + if existing_redirect_uri: + try: + parsed_uri = urlparse(existing_redirect_uri) + port = int(parsed_uri.netloc.split(":")[1]) + if self.verbose and self.io: + self.io.tool_output(f"Reusing existing port: {port}", log_only=True) + except (ValueError, IndexError): + # If we can't parse the port, find a new one + port = find_available_port() + else: + # No existing redirect URI, find an available port + port = find_available_port() + if not port: + raise Exception("Could not find available port for OAuth callback") -class SseServer(McpServer): - """SSE (Server-Sent Events) MCP server using mcp.client.sse_client.""" + redirect_uri = f"http://localhost:{port}/callback" + + get_auth_code, shutdown = create_oauth_callback_server(port) + + # Store shutdown function for cleanup + self._oauth_shutdown = shutdown + + async def handle_redirect(auth_url: str) -> None: + if self.io: + self.io.tool_output(f"\nAuthentication required for MCP server: {self.name}") + self.io.tool_output("\nPlease open this URL in your browser to authenticate:") + self.io.tool_output(f"\n{auth_url}\n") + self.io.tool_output("\nWaiting for you to complete authentication...") + self.io.tool_output("Use Control-C to interrupt.") + try: + webbrowser.open(auth_url) + except Exception: + pass + + client_metadata = OAuthClientMetadata( + client_name="Cecli", + redirect_uris=[redirect_uri], + grant_types=["authorization_code", "refresh_token"], + ) + oauth_provider = OAuthClientProvider( + server_url=server_url, + client_metadata=client_metadata, + storage=FileBasedTokenStorage(self.name), + redirect_handler=handle_redirect, + callback_handler=get_auth_code, + ) + + return oauth_provider + + def _create_transport(self, url, http_client): + """ + Create the transport for this server type. + Must be implemented by subclasses. + """ + raise NotImplementedError("Subclasses must implement _create_transport") async def connect(self): if self.session is not None: - logging.info(f"Using existing session for SSE MCP server: {self.name}") + if self.verbose and self.io: + self.io.tool_output(f"Using existing session for {self.name}") return self.session - logging.info(f"Establishing new connection to SSE MCP server: {self.name}") + if self.verbose and self.io: + self.io.tool_output(f"Establishing new connection to {self.name}") + try: url = self.config.get("url") headers = self.config.get("headers", {}) - sse_transport = await self.exit_stack.enter_async_context( - sse_client(url, headers=headers) + oauth_provider = await self._create_oauth_provider() + + http_client = await self.exit_stack.enter_async_context( + httpx.AsyncClient( + auth=oauth_provider, + follow_redirects=True, + headers=headers, + timeout=30, + ) + ) + + transport = await self.exit_stack.enter_async_context( + self._create_transport(url, http_client=http_client) ) - read, write, _response = sse_transport + + read, write, _ = transport + session = await self.exit_stack.enter_async_context(ClientSession(read, write)) await session.initialize() self.session = session + + if oauth_provider.context.oauth_metadata: + token_endpoint = oauth_provider._get_token_endpoint() + server_info = get_mcp_oauth_token(self.name) + if "client_info" not in server_info: + server_info["client_info"] = {} + + server_info["client_info"]["token_endpoint"] = token_endpoint + + save_mcp_oauth_token(self.name, server_info) + return session except Exception as e: - logging.error(f"Error initializing SSE server {self.name}: {e}") + logging.error(f"Error initializing {self.name}: {e}") await self.disconnect() raise + async def disconnect(self): + """Disconnect from the MCP server and clean up resources.""" + async with self._cleanup_lock: + try: + if hasattr(self, "_oauth_shutdown"): + self._oauth_shutdown() + await self.exit_stack.aclose() + self.session = None + except Exception as e: + logging.error(f"Error during cleanup of server {self.name}: {e}") + + +class HttpStreamingServer(HttpBasedMcpServer): + """HTTP streaming MCP server using mcp.client.streamable_http_client.""" + + def _create_transport(self, url, http_client): + """Create the HTTP streaming transport.""" + return streamable_http_client(url, http_client=http_client) + + +class SseServer(HttpBasedMcpServer): + """SSE (Server-Sent Events) MCP server using mcp.client.sse_client.""" + + def _create_transport(self, url, http_client): + """Create the SSE transport.""" + return sse_client(url, http_client=http_client) + class LocalServer(McpServer): """ @@ -138,7 +266,8 @@ class LocalServer(McpServer): async def connect(self): """Local tools don't need a connection.""" if self.session is not None: - logging.info(f"Using existing session for local tools: {self.name}") + if self.verbose and self.io: + self.io.tool_output(f"Using existing session for local tools: {self.name}") return self.session self.session = object() # Dummy session object diff --git a/cecli/models.py b/cecli/models.py index 04c035ab0c8..42410231d8b 100644 --- a/cecli/models.py +++ b/cecli/models.py @@ -892,7 +892,7 @@ def is_ollama(self): async def send_completion( self, messages, functions, stream, temperature=None, tools=None, max_tokens=None ): - if os.environ.get("CECLISANITY_CHECK_TURNS"): + if os.environ.get("CECLI_SANITY_CHECK_TURNS"): sanity_check_messages(messages) messages = model_request_parser(self, messages) if self.verbose: @@ -1169,7 +1169,39 @@ def print_matching_models(io, search): if matches: io.tool_output(f'Models which match "{search}":') for model in matches: - io.tool_output(f"- {model}") + # Get model info to check for prices + info = model_info_manager.get_model_info(model) + + # Build price string + price_parts = [] + + # Check for input cost + input_cost = info.get("input_cost_per_token") + if input_cost is not None: + # Convert from per-token to per-1M tokens + input_cost_per_1m = input_cost * 1000000 + price_parts.append(f"${input_cost_per_1m:.2f}/1m/input") + + # Check for output cost + output_cost = info.get("output_cost_per_token") + if output_cost is not None: + # Convert from per-token to per-1M tokens + output_cost_per_1m = output_cost * 1000000 + price_parts.append(f"${output_cost_per_1m:.2f}/1m/output") + + # Check for cache cost (if available) + cache_cost = info.get("cache_cost_per_token") + if cache_cost is not None: + # Convert from per-token to per-1M tokens + cache_cost_per_1m = cache_cost * 1000000 + price_parts.append(f"${cache_cost_per_1m:.2f}/1m/cache") + + # Format the output + if price_parts: + price_str = " (" + ", ".join(price_parts) + ")" + io.tool_output(f"- {model}{price_str}") + else: + io.tool_output(f"- {model}") else: io.tool_output(f'No models match "{search}".') diff --git a/cecli/onboarding.py b/cecli/onboarding.py index 72d49ff4c51..a0037520d1f 100644 --- a/cecli/onboarding.py +++ b/cecli/onboarding.py @@ -1,8 +1,5 @@ -import base64 -import hashlib import http.server import os -import secrets import socketserver import threading import time @@ -13,6 +10,7 @@ from cecli import urls from cecli.io import InputOutput +from cecli.mcp.oauth import find_available_port, generate_pkce_codes def check_openrouter_tier(api_key): @@ -117,24 +115,7 @@ async def select_default_model(args, io): await io.offer_url(urls.models_and_keys, "Open documentation URL for more info?") -def find_available_port(start_port=8484, end_port=8584): - for port in range(start_port, end_port + 1): - try: - with socketserver.TCPServer(("localhost", port), None): - return port - except OSError: - continue - return None - - -def generate_pkce_codes(): - code_verifier = secrets.token_urlsafe(64) - hasher = hashlib.sha256() - hasher.update(code_verifier.encode("utf-8")) - code_challenge = base64.urlsafe_b64encode(hasher.digest()).rstrip(b"=").decode("utf-8") - return code_verifier, code_challenge - - +# Function to exchange the authorization code for an API key def exchange_code_for_key(code, code_verifier, io): try: response = requests.post( diff --git a/cecli/tools/context_manager.py b/cecli/tools/context_manager.py index 216dca67750..652185c8780 100644 --- a/cecli/tools/context_manager.py +++ b/cecli/tools/context_manager.py @@ -102,10 +102,10 @@ def _remove(coder, file_path): coder.abs_read_only_fnames.remove(abs_path) removed = True if not removed: - coder.io.tool_output("⚠️ File '{file_path}' not in context") + coder.io.tool_output(f"⚠️ File '{file_path}' not in context") return f"File not in context: {file_path}" coder.recently_removed[rel_path] = {"removed_at": time.time()} - coder.io.tool_output("🗑️ Removed '{file_path}' from context") + coder.io.tool_output(f"🗑️ Removed '{file_path}' from context") return f"Removed: {file_path}" except Exception as e: coder.io.tool_error(f"Error removing file '{file_path}': {str(e)}") @@ -117,10 +117,10 @@ def _editable(coder, file_path): try: abs_path = coder.abs_root_path(file_path) if abs_path in coder.abs_fnames: - coder.io.tool_output("📝 File '{file_path}' is already editable") + coder.io.tool_output(f"📝 File '{file_path}' is already editable") return f"Already editable: {file_path}" if not os.path.isfile(abs_path): - coder.io.tool_output("⚠️ File '{file_path}' not found on disk") + coder.io.tool_output(f"⚠️ File '{file_path}' not found on disk") return f"File not found: {file_path}" was_read_only = False if abs_path in coder.abs_read_only_fnames: @@ -128,10 +128,10 @@ def _editable(coder, file_path): was_read_only = True coder.abs_fnames.add(abs_path) if was_read_only: - coder.io.tool_output("📝 Moved '{file_path}' from read-only to editable") + coder.io.tool_output(f"📝 Moved '{file_path}' from read-only to editable") return f"Made editable (moved): {file_path}" else: - coder.io.tool_output("📝 Added '{file_path}' directly to editable context") + coder.io.tool_output(f"📝 Added '{file_path}' directly to editable context") return f"Made editable (added): {file_path}" except Exception as e: coder.io.tool_error(f"Error making editable '{file_path}': {str(e)}") @@ -154,7 +154,7 @@ def _create(coder, file_path): # Check if file already exists if os.path.exists(abs_path): - coder.io.tool_output("⚠️ File '{file_path}' already exists") + coder.io.tool_output(f"⚠️ File '{file_path}' already exists") return f"File already exists: {file_path}" # Create parent directories if they don't exist @@ -167,7 +167,7 @@ def _create(coder, file_path): # Add the file to editable context coder.abs_fnames.add(abs_path) - coder.io.tool_output("📝 Created '{file_path}' and made it editable") + coder.io.tool_output(f"📝 Created '{file_path}' and made it editable") return f"Created and made editable: {file_path}" except Exception as e: diff --git a/cecli/tui/worker.py b/cecli/tui/worker.py index 551c4047ed1..68c08775b0e 100644 --- a/cecli/tui/worker.py +++ b/cecli/tui/worker.py @@ -7,7 +7,7 @@ from typing import Optional from cecli.coders import Coder -from cecli.commands import SwitchCoder +from cecli.commands import SwitchCoderSignal # Suppress asyncio task destroyed warnings during shutdown logging.getLogger("asyncio").setLevel(logging.CRITICAL) @@ -91,7 +91,7 @@ async def _async_run(self): break # Normal exit except asyncio.CancelledError: break - except SwitchCoder as switch: + except SwitchCoderSignal as switch: # Handle chat mode switches (e.g., /chat-mode architect) try: kwargs = dict(io=self.coder.io, from_coder=self.coder) diff --git a/cecli/versioncheck.py b/cecli/versioncheck.py index 5e099b40a7c..0563cd618d6 100644 --- a/cecli/versioncheck.py +++ b/cecli/versioncheck.py @@ -34,7 +34,7 @@ async def install_upgrade(io, latest_version=None): new_ver_text = f"Newer cecli version v{latest_version} is available." else: new_ver_text = "Install latest version of cecli?" - docker_image = os.environ.get("CECLIDOCKER_IMAGE") + docker_image = os.environ.get("CECLI_DOCKER_IMAGE") if docker_image: text = f"\n{new_ver_text} To upgrade, run:\n\n docker pull {docker_image}\n" io.tool_warning(text) @@ -60,7 +60,7 @@ async def check_version(io, just_check=False, verbose=False): import requests try: - response = requests.get("https://pypi.org/pypi/cecli-ce/json") + response = requests.get("https://pypi.org/pypi/aider-ce/json") data = response.json() latest_version = data["info"]["version"] current_version = cecli.__version__ diff --git a/cecli/website/HISTORY.md b/cecli/website/HISTORY.md index d32a1215ac1..f3354c25312 100644 --- a/cecli/website/HISTORY.md +++ b/cecli/website/HISTORY.md @@ -696,7 +696,7 @@ versions. - Still auto-completes the full paths of the repo files like `/add`. - Now supports globs like `src/**/*.py` - Renamed `--yes` to `--yes-always`. - - Now uses `AIDER_YES_ALWAYS` env var and `yes-always:` YAML key. + - Now uses `CECLI_YES_ALWAYS` env var and `yes-always:` YAML key. - Existing YAML and .env files will need to be updated. - Can still abbreviate to `--yes` on the command line. - Config file now uses standard YAML list syntax with ` - list entries`, one per line. @@ -1125,7 +1125,7 @@ versions. ### Aider v0.39.0 - Use `--sonnet` for Claude 3.5 Sonnet, which is the top model on [aider's LLM code editing leaderboard](https://aider.chat/docs/leaderboards/#claude-35-sonnet-takes-the-top-spot). -- All `AIDER_xxx` environment variables can now be set in `.env` (by @jpshack-at-palomar). +- All `CECLI_xxx` environment variables can now be set in `.env` (by @jpshack-at-palomar). - Use `--llm-history-file` to log raw messages sent to the LLM (by @daniel-vainsencher). - Commit messages are no longer prefixed with "aider:". Instead the git author and committer names have "(aider)" added. diff --git a/cecli/website/docs/config.md b/cecli/website/docs/config.md index 299ec5979eb..5a12fcb0eb9 100644 --- a/cecli/website/docs/config.md +++ b/cecli/website/docs/config.md @@ -11,7 +11,7 @@ command line switches. Most options can also be set in an `.aider.conf.yml` file which can be placed in your home directory or at the root of your git repo. -Or by setting environment variables like `AIDER_xxx` +Or by setting environment variables like `CECLI_xxx` either in your shell or a `.env` file. Here are 4 equivalent ways of setting an option. @@ -31,13 +31,13 @@ dark-mode: true By setting an environment variable: ``` -export AIDER_DARK_MODE=true +export CECLI_DARK_MODE=true ``` Using an `.env` file: ``` -AIDER_DARK_MODE=true +CECLI_DARK_MODE=true ``` {% include keys.md %} diff --git a/cecli/website/docs/config/agent-mode.md b/cecli/website/docs/config/agent-mode.md index 30100782ced..2216b6492b5 100644 --- a/cecli/website/docs/config/agent-mode.md +++ b/cecli/website/docs/config/agent-mode.md @@ -41,9 +41,9 @@ This loop continues automatically until the `Finished` tool is called, or the ma Agent Mode uses a centralized local tool registry that manages all available tools: -- **File Discovery Tools**: `View`, `ViewFilesMatching`, `ViewFilesWithSymbol`, `Ls`, `Grep` +- **File Discovery Tools**: `ViewFilesMatching`, `ViewFilesWithSymbol`, `Ls`, `Grep` - **Editing Tools**: `ReplaceText`, `InsertBlock`, `DeleteBlock`, `ReplaceLines`, `DeleteLines` -- **Context Management Tools**: `MakeEditable`, `MakeReadonly`, `Remove` +- **Context Management Tools**: `ContextManager` - **Git Tools**: `GitDiff`, `GitLog`, `GitShow`, `GitStatus` - **Utility Tools**: `UpdateTodoList`, `ListChanges`, `UndoChange`, `Finished` - **Skill Management**: `LoadSkill`, `RemoveSkill` @@ -154,7 +154,7 @@ Agent Mode can also be configured directly in the relevant config.yml file: agent: true agent-config: # Tool configuration - tools_includelist: ["view", "makeeditable", "replacetext", "finished"] # Optional: Whitelist of tools + tools_includelist: [contextmanager", "replacetext", "finished"] # Optional: Whitelist of tools tools_excludelist: ["command", "commandinteractive"] # Optional: Blacklist of tools # Context blocks configuration @@ -184,9 +184,8 @@ agent-config: Certain tools are always available regardless of includelist/excludelist settings: -- `makeeditable` - Make files editable +- `ContextManager` - Add, drop, and make files editable in the context - `replacetext` - Basic text replacement -- `view` - View files - `finished` - Complete the task #### Context Blocks @@ -202,7 +201,7 @@ The following context blocks are available by default and can be customized usin When `include_context_blocks` is specified, only the listed blocks will be included. When `exclude_context_blocks` is specified, the listed blocks will be removed from the default set. -#### Other CECLI CLI/Config Options for Agent Mode +#### Other Cecli Config Options for Agent Mode - `use-enhanced-map` - Use enhanced repo map that takes into account import relationships between files @@ -221,7 +220,7 @@ agent: true # Agent Mode configuration agent-config: # Tool configuration - tools_includelist: ["view", "makeeditable", "replacetext", "finished"] # Optional: Whitelist of tools + tools_includelist: ["contextmanager", "replacetext", "finished"] # Optional: Whitelist of tools tools_excludelist: ["command", "commandinteractive"] # Optional: Blacklist of tools # Context blocks configuration diff --git a/cecli/website/docs/config/dotenv.md b/cecli/website/docs/config/dotenv.md index 5bd249f7c48..408255be1c0 100644 --- a/cecli/website/docs/config/dotenv.md +++ b/cecli/website/docs/config/dotenv.md @@ -62,432 +62,432 @@ cog.outl("```") # Main model: ## Specify the model to use for the main chat -#AIDER_MODEL= +#CECLI_MODEL= ######################## # API Keys and settings: ## Specify the OpenAI API key -#AIDER_OPENAI_API_KEY= +#CECLI_OPENAI_API_KEY= ## Specify the Anthropic API key -#AIDER_ANTHROPIC_API_KEY= +#CECLI_ANTHROPIC_API_KEY= ## Specify the api base url -#AIDER_OPENAI_API_BASE= +#CECLI_OPENAI_API_BASE= ## (deprecated, use --set-env OPENAI_API_TYPE=) -#AIDER_OPENAI_API_TYPE= +#CECLI_OPENAI_API_TYPE= ## (deprecated, use --set-env OPENAI_API_VERSION=) -#AIDER_OPENAI_API_VERSION= +#CECLI_OPENAI_API_VERSION= ## (deprecated, use --set-env OPENAI_API_DEPLOYMENT_ID=) -#AIDER_OPENAI_API_DEPLOYMENT_ID= +#CECLI_OPENAI_API_DEPLOYMENT_ID= ## (deprecated, use --set-env OPENAI_ORGANIZATION=) -#AIDER_OPENAI_ORGANIZATION_ID= +#CECLI_OPENAI_ORGANIZATION_ID= ## Set an environment variable (to control API settings, can be used multiple times) -#AIDER_SET_ENV= +#CECLI_SET_ENV= ## Set an API key for a provider (eg: --api-key provider= sets PROVIDER_API_KEY=) -#AIDER_API_KEY= +#CECLI_API_KEY= ################# # Model settings: ## List known models which match the (partial) MODEL name -#AIDER_LIST_MODELS= +#CECLI_LIST_MODELS= ## Specify a file with aider model settings for unknown models -#AIDER_MODEL_SETTINGS_FILE=.aider.model.settings.yml +#CECLI_MODEL_SETTINGS_FILE=.aider.model.settings.yml ## Specify a file with context window and costs for unknown models -#AIDER_MODEL_METADATA_FILE=.aider.model.metadata.json +#CECLI_MODEL_METADATA_FILE=.aider.model.metadata.json ## Add a model alias (can be used multiple times) -#AIDER_ALIAS= +#CECLI_ALIAS= ## Set the reasoning_effort API parameter (default: not set) -#AIDER_REASONING_EFFORT= +#CECLI_REASONING_EFFORT= ## Set the thinking token budget for models that support it. Use 0 to disable. (default: not set) -#AIDER_THINKING_TOKENS= +#CECLI_THINKING_TOKENS= ## Verify the SSL cert when connecting to models (default: True) -#AIDER_VERIFY_SSL=true +#CECLI_VERIFY_SSL=true ## Timeout in seconds for API calls (default: None) -#AIDER_TIMEOUT= +#CECLI_TIMEOUT= ## Specify what edit format the LLM should use (default depends on model) -#AIDER_EDIT_FORMAT= +#CECLI_EDIT_FORMAT= ## Use architect edit format for the main chat -#AIDER_ARCHITECT= +#CECLI_ARCHITECT= ## Enable/disable automatic acceptance of architect changes (default: True) -#AIDER_AUTO_ACCEPT_ARCHITECT=true +#CECLI_AUTO_ACCEPT_ARCHITECT=true ## Specify the model to use for commit messages and chat history summarization (default depends on --model) -#AIDER_WEAK_MODEL= +#CECLI_WEAK_MODEL= ## Specify the model to use for editor tasks (default depends on --model) -#AIDER_EDITOR_MODEL= +#CECLI_EDITOR_MODEL= ## Specify the edit format for the editor model (default: depends on editor model) -#AIDER_EDITOR_EDIT_FORMAT= +#CECLI_EDITOR_EDIT_FORMAT= ## Only work with models that have meta-data available (default: True) -#AIDER_SHOW_MODEL_WARNINGS=true +#CECLI_SHOW_MODEL_WARNINGS=true ## Check if model accepts settings like reasoning_effort/thinking_tokens (default: True) -#AIDER_CHECK_MODEL_ACCEPTS_SETTINGS=true +#CECLI_CHECK_MODEL_ACCEPTS_SETTINGS=true ## Soft limit on tokens for chat history, after which summarization begins. If unspecified, defaults to the model's max_chat_history_tokens. -#AIDER_MAX_CHAT_HISTORY_TOKENS= +#CECLI_MAX_CHAT_HISTORY_TOKENS= ################# # Cache settings: ## Enable caching of prompts (default: False) -#AIDER_CACHE_PROMPTS=false +#CECLI_CACHE_PROMPTS=false ## Number of times to ping at 5min intervals to keep prompt cache warm (default: 0) -#AIDER_CACHE_KEEPALIVE_PINGS=false +#CECLI_CACHE_KEEPALIVE_PINGS=false ################### # Repomap settings: ## Suggested number of tokens to use for repo map, use 0 to disable -#AIDER_MAP_TOKENS= +#CECLI_MAP_TOKENS= ## Control how often the repo map is refreshed. Options: auto, always, files, manual (default: auto) -#AIDER_MAP_REFRESH=auto +#CECLI_MAP_REFRESH=auto ## Multiplier for map tokens when no files are specified (default: 2) -#AIDER_MAP_MULTIPLIER_NO_FILES=true +#CECLI_MAP_MULTIPLIER_NO_FILES=true ## Maximum line length for the repo map code. Prevents sending crazy long lines of minified JS files etc. (default: 100) -#AIDER_MAP_MAX_LINE_LENGTH=100 +#CECLI_MAP_MAX_LINE_LENGTH=100 ################ # History Files: ## Specify the chat input history file (default: .aider.input.history) -#AIDER_INPUT_HISTORY_FILE=.aider.input.history +#CECLI_INPUT_HISTORY_FILE=.aider.input.history ## Specify the chat history file (default: .aider.chat.history.md) -#AIDER_CHAT_HISTORY_FILE=.aider.chat.history.md +#CECLI_CHAT_HISTORY_FILE=.aider.chat.history.md ## Restore the previous chat history messages (default: False) -#AIDER_RESTORE_CHAT_HISTORY=false +#CECLI_RESTORE_CHAT_HISTORY=false ## Log the conversation with the LLM to this file (for example, .aider.llm.history) -#AIDER_LLM_HISTORY_FILE= +#CECLI_LLM_HISTORY_FILE= ################## # Output settings: ## Use colors suitable for a dark terminal background (default: False) -#AIDER_DARK_MODE=false +#CECLI_DARK_MODE=false ## Use colors suitable for a light terminal background (default: False) -#AIDER_LIGHT_MODE=false +#CECLI_LIGHT_MODE=false ## Enable/disable pretty, colorized output (default: True) -#AIDER_PRETTY=true +#CECLI_PRETTY=true ## Enable/disable streaming responses (default: True) -#AIDER_STREAM=true +#CECLI_STREAM=true ## Set the color for user input (default: #00cc00) -#AIDER_USER_INPUT_COLOR=#00cc00 +#CECLI_USER_INPUT_COLOR=#00cc00 ## Set the color for tool output (default: None) -#AIDER_TOOL_OUTPUT_COLOR= +#CECLI_TOOL_OUTPUT_COLOR= ## Set the color for tool error messages (default: #FF2222) -#AIDER_TOOL_ERROR_COLOR=#FF2222 +#CECLI_TOOL_ERROR_COLOR=#FF2222 ## Set the color for tool warning messages (default: #FFA500) -#AIDER_TOOL_WARNING_COLOR=#FFA500 +#CECLI_TOOL_WARNING_COLOR=#FFA500 ## Set the color for assistant output (default: #0088ff) -#AIDER_ASSISTANT_OUTPUT_COLOR=#0088ff +#CECLI_ASSISTANT_OUTPUT_COLOR=#0088ff ## Set the color for the completion menu (default: terminal's default text color) -#AIDER_COMPLETION_MENU_COLOR= +#CECLI_COMPLETION_MENU_COLOR= ## Set the background color for the completion menu (default: terminal's default background color) -#AIDER_COMPLETION_MENU_BG_COLOR= +#CECLI_COMPLETION_MENU_BG_COLOR= ## Set the color for the current item in the completion menu (default: terminal's default background color) -#AIDER_COMPLETION_MENU_CURRENT_COLOR= +#CECLI_COMPLETION_MENU_CURRENT_COLOR= ## Set the background color for the current item in the completion menu (default: terminal's default text color) -#AIDER_COMPLETION_MENU_CURRENT_BG_COLOR= +#CECLI_COMPLETION_MENU_CURRENT_BG_COLOR= ## Set the markdown code theme (default: default, other options include monokai, solarized-dark, solarized-light, or a Pygments builtin style, see https://pygments.org/styles for available themes) -#AIDER_CODE_THEME=default +#CECLI_CODE_THEME=default ## Show diffs when committing changes (default: False) -#AIDER_SHOW_DIFFS=false +#CECLI_SHOW_DIFFS=false ############### # Git settings: ## Enable/disable looking for a git repo (default: True) -#AIDER_GIT=true +#CECLI_GIT=true ## Enable/disable adding .aider* to .gitignore (default: True) -#AIDER_GITIGNORE=true +#CECLI_GITIGNORE=true ## Enable/disable the addition of files listed in .gitignore to Aider's editing scope. -#AIDER_ADD_GITIGNORE_FILES=false +#CECLI_ADD_GITIGNORE_FILES=false ## Specify the aider ignore file (default: .aiderignore in git root) -#AIDER_AIDERIGNORE=.aiderignore +#CECLI_AIDERIGNORE=.aiderignore ## Only consider files in the current subtree of the git repository -#AIDER_SUBTREE_ONLY=false +#CECLI_SUBTREE_ONLY=false ## Enable/disable auto commit of LLM changes (default: True) -#AIDER_AUTO_COMMITS=true +#CECLI_AUTO_COMMITS=true ## Enable/disable commits when repo is found dirty (default: True) -#AIDER_DIRTY_COMMITS=true +#CECLI_DIRTY_COMMITS=true ## Attribute aider code changes in the git author name (default: True). If explicitly set to True, overrides --attribute-co-authored-by precedence. -#AIDER_ATTRIBUTE_AUTHOR= +#CECLI_ATTRIBUTE_AUTHOR= ## Attribute aider commits in the git committer name (default: True). If explicitly set to True, overrides --attribute-co-authored-by precedence for aider edits. -#AIDER_ATTRIBUTE_COMMITTER= +#CECLI_ATTRIBUTE_COMMITTER= ## Prefix commit messages with 'aider: ' if aider authored the changes (default: False) -#AIDER_ATTRIBUTE_COMMIT_MESSAGE_AUTHOR=false +#CECLI_ATTRIBUTE_COMMIT_MESSAGE_AUTHOR=false ## Prefix all commit messages with 'aider: ' (default: False) -#AIDER_ATTRIBUTE_COMMIT_MESSAGE_COMMITTER=false +#CECLI_ATTRIBUTE_COMMIT_MESSAGE_COMMITTER=false ## Attribute aider edits using the Co-authored-by trailer in the commit message (default: True). If True, this takes precedence over default --attribute-author and --attribute-committer behavior unless they are explicitly set to True. -#AIDER_ATTRIBUTE_CO_AUTHORED_BY=true +#CECLI_ATTRIBUTE_CO_AUTHORED_BY=true ## Enable/disable git pre-commit hooks with --no-verify (default: False) -#AIDER_GIT_COMMIT_VERIFY=false +#CECLI_GIT_COMMIT_VERIFY=false ## Commit all pending changes with a suitable commit message, then exit -#AIDER_COMMIT=false +#CECLI_COMMIT=false ## Specify a custom prompt for generating commit messages -#AIDER_COMMIT_PROMPT= +#CECLI_COMMIT_PROMPT= ## Perform a dry run without modifying files (default: False) -#AIDER_DRY_RUN=false +#CECLI_DRY_RUN=false ## Skip the sanity check for the git repository (default: False) -#AIDER_SKIP_SANITY_CHECK_REPO=false +#CECLI_SKIP_SANITY_CHECK_REPO=false ## Enable/disable watching files for ai coding comments (default: False) -#AIDER_WATCH_FILES=false +#CECLI_WATCH_FILES=false ######################## # Fixing and committing: ## Lint and fix provided files, or dirty files if none provided -#AIDER_LINT=false +#CECLI_LINT=false ## Specify lint commands to run for different languages, eg: "python: flake8 --select=..." (can be used multiple times) -#AIDER_LINT_CMD= +#CECLI_LINT_CMD= ## Enable/disable automatic linting after changes (default: True) -#AIDER_AUTO_LINT=true +#CECLI_AUTO_LINT=true ## Specify command to run tests -#AIDER_TEST_CMD= +#CECLI_TEST_CMD= ## Enable/disable automatic testing after changes (default: False) -#AIDER_AUTO_TEST=false +#CECLI_AUTO_TEST=false ## Run tests, fix problems found and then exit -#AIDER_TEST=false +#CECLI_TEST=false ############ # Analytics: ## Enable/disable analytics for current session (default: random) -#AIDER_ANALYTICS= +#CECLI_ANALYTICS= ## Specify a file to log analytics events -#AIDER_ANALYTICS_LOG= +#CECLI_ANALYTICS_LOG= ## Permanently disable analytics -#AIDER_ANALYTICS_DISABLE=false +#CECLI_ANALYTICS_DISABLE=false ## Send analytics to custom PostHog instance -#AIDER_ANALYTICS_POSTHOG_HOST= +#CECLI_ANALYTICS_POSTHOG_HOST= ## Send analytics to custom PostHog project -#AIDER_ANALYTICS_POSTHOG_PROJECT_API_KEY= +#CECLI_ANALYTICS_POSTHOG_PROJECT_API_KEY= ############ # Upgrading: ## Check for updates and return status in the exit code -#AIDER_JUST_CHECK_UPDATE=false +#CECLI_JUST_CHECK_UPDATE=false ## Check for new aider versions on launch -#AIDER_CHECK_UPDATE=true +#CECLI_CHECK_UPDATE=true ## Show release notes on first run of new version (default: None, ask user) -#AIDER_SHOW_RELEASE_NOTES= +#CECLI_SHOW_RELEASE_NOTES= ## Install the latest version from the main branch -#AIDER_INSTALL_MAIN_BRANCH=false +#CECLI_INSTALL_MAIN_BRANCH=false ## Upgrade aider to the latest version from PyPI -#AIDER_UPGRADE=false +#CECLI_UPGRADE=false ######## # Modes: ## Specify a single message to send the LLM, process reply then exit (disables chat mode) -#AIDER_MESSAGE= +#CECLI_MESSAGE= ## Specify a file containing the message to send the LLM, process reply, then exit (disables chat mode) -#AIDER_MESSAGE_FILE= +#CECLI_MESSAGE_FILE= ## Run aider in your browser (default: False) -#AIDER_GUI=false +#CECLI_GUI=false ## Enable automatic copy/paste of chat between aider and web UI (default: False) -#AIDER_COPY_PASTE=false +#CECLI_COPY_PASTE=false ## Apply the changes from the given file instead of running the chat (debug) -#AIDER_APPLY= +#CECLI_APPLY= ## Apply clipboard contents as edits using the main model's editor format -#AIDER_APPLY_CLIPBOARD_EDITS=false +#CECLI_APPLY_CLIPBOARD_EDITS=false ## Do all startup activities then exit before accepting user input (debug) -#AIDER_EXIT=false +#CECLI_EXIT=false ## Print the repo map and exit (debug) -#AIDER_SHOW_REPO_MAP=false +#CECLI_SHOW_REPO_MAP=false ## Print the system prompts and exit (debug) -#AIDER_SHOW_PROMPTS=false +#CECLI_SHOW_PROMPTS=false ################# # Voice settings: ## Audio format for voice recording (default: wav). webm and mp3 require ffmpeg -#AIDER_VOICE_FORMAT=wav +#CECLI_VOICE_FORMAT=wav ## Specify the language for voice using ISO 639-1 code (default: auto) -#AIDER_VOICE_LANGUAGE=en +#CECLI_VOICE_LANGUAGE=en ## Specify the input device name for voice recording -#AIDER_VOICE_INPUT_DEVICE= +#CECLI_VOICE_INPUT_DEVICE= ################# # Other settings: ## Never prompt for or attempt to install Playwright for web scraping (default: False). -#AIDER_DISABLE_PLAYWRIGHT=false +#CECLI_DISABLE_PLAYWRIGHT=false ## specify a file to edit (can be used multiple times) -#AIDER_FILE= +#CECLI_FILE= ## specify a read-only file (can be used multiple times) -#AIDER_READ= +#CECLI_READ= ## Use VI editing mode in the terminal (default: False) -#AIDER_VIM=false +#CECLI_VIM=false ## Specify the language to use in the chat (default: None, uses system settings) -#AIDER_CHAT_LANGUAGE= +#CECLI_CHAT_LANGUAGE= ## Specify the language to use in the commit message (default: None, user language) -#AIDER_COMMIT_LANGUAGE= +#CECLI_COMMIT_LANGUAGE= ## Always say yes to every confirmation -#AIDER_YES_ALWAYS= +#CECLI_YES_ALWAYS= ## Enable verbose output -#AIDER_VERBOSE=false +#CECLI_VERBOSE=false ## Load and execute /commands from a file on launch -#AIDER_LOAD= +#CECLI_LOAD= ## Specify the encoding for input and output (default: utf-8) -#AIDER_ENCODING=utf-8 +#CECLI_ENCODING=utf-8 ## Line endings to use when writing files (default: platform) -#AIDER_LINE_ENDINGS=platform +#CECLI_LINE_ENDINGS=platform ## Specify the .env file to load (default: .env in git root) -#AIDER_ENV_FILE=.env +#CECLI_ENV_FILE=.env ## Enable/disable suggesting shell commands (default: True) -#AIDER_SUGGEST_SHELL_COMMANDS=true +#CECLI_SUGGEST_SHELL_COMMANDS=true ## Enable/disable fancy input with history and completion (default: True) -#AIDER_FANCY_INPUT=true +#CECLI_FANCY_INPUT=true ## Enable/disable multi-line input mode with Meta-Enter to submit (default: False) -#AIDER_MULTILINE=false +#CECLI_MULTILINE=false ## Enable/disable terminal bell notifications when LLM responses are ready (default: False) -#AIDER_NOTIFICATIONS=false +#CECLI_NOTIFICATIONS=false ## Specify a command to run for notifications instead of the terminal bell. If not specified, a default command for your OS may be used. -#AIDER_NOTIFICATIONS_COMMAND= +#CECLI_NOTIFICATIONS_COMMAND= ## Enable/disable detection and offering to add URLs to chat (default: True) -#AIDER_DETECT_URLS=true +#CECLI_DETECT_URLS=true ## Specify which editor to use for the /editor command -#AIDER_EDITOR= +#CECLI_EDITOR= ## Print shell completion script for the specified SHELL and exit. Supported shells: bash, tcsh, zsh. Example: aider --shell-completions bash -#AIDER_SHELL_COMPLETIONS= +#CECLI_SHELL_COMPLETIONS= ############################ # Deprecated model settings: ## Use claude-3-opus-20240229 model for the main chat (deprecated, use --model) -#AIDER_OPUS=false +#CECLI_OPUS=false ## Use anthropic/claude-3-7-sonnet-20250219 model for the main chat (deprecated, use --model) -#AIDER_SONNET=false +#CECLI_SONNET=false ## Use claude-3-5-haiku-20241022 model for the main chat (deprecated, use --model) -#AIDER_HAIKU=false +#CECLI_HAIKU=false ## Use gpt-4-0613 model for the main chat (deprecated, use --model) -#AIDER_4=false +#CECLI_4=false ## Use gpt-4o model for the main chat (deprecated, use --model) -#AIDER_4O=false +#CECLI_4O=false ## Use gpt-4o-mini model for the main chat (deprecated, use --model) -#AIDER_MINI=false +#CECLI_MINI=false ## Use gpt-4-1106-preview model for the main chat (deprecated, use --model) -#AIDER_4_TURBO=false +#CECLI_4_TURBO=false ## Use gpt-3.5-turbo model for the main chat (deprecated, use --model) -#AIDER_35TURBO=false +#CECLI_35TURBO=false ## Use deepseek/deepseek-chat model for the main chat (deprecated, use --model) -#AIDER_DEEPSEEK=false +#CECLI_DEEPSEEK=false ## Use o1-mini model for the main chat (deprecated, use --model) -#AIDER_O1_MINI=false +#CECLI_O1_MINI=false ## Use o1-preview model for the main chat (deprecated, use --model) -#AIDER_O1_PREVIEW=false +#CECLI_O1_PREVIEW=false ``` diff --git a/cecli/website/docs/config/editor.md b/cecli/website/docs/config/editor.md index dc1d74df866..1b3262e855c 100644 --- a/cecli/website/docs/config/editor.md +++ b/cecli/website/docs/config/editor.md @@ -18,7 +18,7 @@ You can specify the text editor with the `--editor` switch or using Aider checks the following environment variables in order to determine which editor to use: -1. `AIDER_EDITOR` +1. `CECLI_EDITOR` 2. `VISUAL` 3. `EDITOR` @@ -35,7 +35,7 @@ If no editor is configured, aider will use these platform-specific defaults: You can set your preferred editor in your shell's configuration file (e.g., `.bashrc`, `.zshrc`): ```bash -export AIDER_EDITOR=vim +export CECLI_EDITOR=vim ``` ## Popular Editors by Platform @@ -44,71 +44,71 @@ export AIDER_EDITOR=vim 1. **vim** ```bash - export AIDER_EDITOR=vim + export CECLI_EDITOR=vim ``` 2. **Emacs** ```bash - export AIDER_EDITOR=emacs + export CECLI_EDITOR=emacs ``` 3. **VSCode** ```bash - export AIDER_EDITOR="code --wait" + export CECLI_EDITOR="code --wait" ``` 4. **Sublime Text** ```bash - export AIDER_EDITOR="subl --wait" + export CECLI_EDITOR="subl --wait" ``` 5. **BBEdit** ```bash - export AIDER_EDITOR="bbedit --wait" + export CECLI_EDITOR="bbedit --wait" ``` ### Linux 1. **vim** ```bash - export AIDER_EDITOR=vim + export CECLI_EDITOR=vim ``` 2. **Emacs** ```bash - export AIDER_EDITOR=emacs + export CECLI_EDITOR=emacs ``` 3. **nano** ```bash - export AIDER_EDITOR=nano + export CECLI_EDITOR=nano ``` 4. **VSCode** ```bash - export AIDER_EDITOR="code --wait" + export CECLI_EDITOR="code --wait" ``` 5. **Sublime Text** ```bash - export AIDER_EDITOR="subl --wait" + export CECLI_EDITOR="subl --wait" ``` ### Windows 1. **Notepad** ```bat - set AIDER_EDITOR=notepad + set CECLI_EDITOR=notepad ``` 2. **VSCode** ```bat - set AIDER_EDITOR="code --wait" + set CECLI_EDITOR="code --wait" ``` 3. **Notepad++** ```bat - set AIDER_EDITOR="notepad++ -multiInst -notabbar -nosession -noPlugin -waitForClose" + set CECLI_EDITOR="notepad++ -multiInst -notabbar -nosession -noPlugin -waitForClose" ``` ## Editor command arguments @@ -123,5 +123,5 @@ If you encounter issues with your editor not blocking (returning to the prompt i 2. You've included the necessary command-line arguments for blocking mode 3. The editor command is properly quoted if it contains spaces or special characters, e.g.: ```bash - export AIDER_EDITOR="code --wait" + export CECLI_EDITOR="code --wait" ``` diff --git a/cecli/website/docs/config/mcp.md b/cecli/website/docs/config/mcp.md index 8d67ee28464..bd824b5c453 100644 --- a/cecli/website/docs/config/mcp.md +++ b/cecli/website/docs/config/mcp.md @@ -102,13 +102,13 @@ aider --mcp-transport http You can also configure MCP servers using environment variables in your `.env` file using JSON or YAML format: ``` -AIDER_MCP_SERVERS={"mcpServers":{"git":{"transport": "stdio", "command":"uvx","args":["mcp-server-git"]}}} +CECLI_MCP_SERVERS={"mcpServers":{"git":{"transport": "stdio", "command":"uvx","args":["mcp-server-git"]}}} ``` Or specify a configuration file: ``` -AIDER_MCP_SERVERS_FILE=/path/to/mcp.json +CECLI_MCP_SERVERS_FILE=/path/to/mcp.json ``` ## Troubleshooting diff --git a/cecli/website/docs/config/options.md b/cecli/website/docs/config/options.md index 974b2a5a007..e09260e647d 100644 --- a/cecli/website/docs/config/options.md +++ b/cecli/website/docs/config/options.md @@ -108,53 +108,53 @@ Aliases: ### `--model MODEL` Specify the model to use for the main chat -Environment variable: `AIDER_MODEL` +Environment variable: `CECLI_MODEL` ## API Keys and settings: ### `--openai-api-key VALUE` Specify the OpenAI API key -Environment variable: `AIDER_OPENAI_API_KEY` +Environment variable: `CECLI_OPENAI_API_KEY` ### `--anthropic-api-key VALUE` Specify the Anthropic API key -Environment variable: `AIDER_ANTHROPIC_API_KEY` +Environment variable: `CECLI_ANTHROPIC_API_KEY` ### `--openai-api-base VALUE` Specify the api base url -Environment variable: `AIDER_OPENAI_API_BASE` +Environment variable: `CECLI_OPENAI_API_BASE` ### `--openai-api-type VALUE` (deprecated, use --set-env OPENAI_API_TYPE=) -Environment variable: `AIDER_OPENAI_API_TYPE` +Environment variable: `CECLI_OPENAI_API_TYPE` ### `--openai-api-version VALUE` (deprecated, use --set-env OPENAI_API_VERSION=) -Environment variable: `AIDER_OPENAI_API_VERSION` +Environment variable: `CECLI_OPENAI_API_VERSION` ### `--openai-api-deployment-id VALUE` (deprecated, use --set-env OPENAI_API_DEPLOYMENT_ID=) -Environment variable: `AIDER_OPENAI_API_DEPLOYMENT_ID` +Environment variable: `CECLI_OPENAI_API_DEPLOYMENT_ID` ### `--openai-organization-id VALUE` (deprecated, use --set-env OPENAI_ORGANIZATION=) -Environment variable: `AIDER_OPENAI_ORGANIZATION_ID` +Environment variable: `CECLI_OPENAI_ORGANIZATION_ID` ### `--set-env ENV_VAR_NAME=value` Set an environment variable (to control API settings, can be used multiple times) Default: [] -Environment variable: `AIDER_SET_ENV` +Environment variable: `CECLI_SET_ENV` ### `--api-key PROVIDER=KEY` Set an API key for a provider (eg: --api-key provider= sets PROVIDER_API_KEY=) Default: [] -Environment variable: `AIDER_API_KEY` +Environment variable: `CECLI_API_KEY` ## Model settings: ### `--list-models MODEL` List known models which match the (partial) MODEL name -Environment variable: `AIDER_LIST_MODELS` +Environment variable: `CECLI_LIST_MODELS` Aliases: - `--list-models MODEL` - `--models MODEL` @@ -162,72 +162,72 @@ Aliases: ### `--model-settings-file MODEL_SETTINGS_FILE` Specify a file with aider model settings for unknown models Default: .aider.model.settings.yml -Environment variable: `AIDER_MODEL_SETTINGS_FILE` +Environment variable: `CECLI_MODEL_SETTINGS_FILE` ### `--model-metadata-file MODEL_METADATA_FILE` Specify a file with context window and costs for unknown models Default: .aider.model.metadata.json -Environment variable: `AIDER_MODEL_METADATA_FILE` +Environment variable: `CECLI_MODEL_METADATA_FILE` ### `--alias ALIAS:MODEL` Add a model alias (can be used multiple times) -Environment variable: `AIDER_ALIAS` +Environment variable: `CECLI_ALIAS` ### `--reasoning-effort VALUE` Set the reasoning_effort API parameter (default: not set) -Environment variable: `AIDER_REASONING_EFFORT` +Environment variable: `CECLI_REASONING_EFFORT` ### `--thinking-tokens VALUE` Set the thinking token budget for models that support it. Use 0 to disable. (default: not set) -Environment variable: `AIDER_THINKING_TOKENS` +Environment variable: `CECLI_THINKING_TOKENS` ### `--verify-ssl` Verify the SSL cert when connecting to models (default: True) Default: True -Environment variable: `AIDER_VERIFY_SSL` +Environment variable: `CECLI_VERIFY_SSL` Aliases: - `--verify-ssl` - `--no-verify-ssl` ### `--timeout VALUE` Timeout in seconds for API calls (default: None) -Environment variable: `AIDER_TIMEOUT` +Environment variable: `CECLI_TIMEOUT` ### `--edit-format EDIT_FORMAT` Specify what edit format the LLM should use (default depends on model) -Environment variable: `AIDER_EDIT_FORMAT` +Environment variable: `CECLI_EDIT_FORMAT` Aliases: - `--edit-format EDIT_FORMAT` - `--chat-mode EDIT_FORMAT` ### `--architect` Use architect edit format for the main chat -Environment variable: `AIDER_ARCHITECT` +Environment variable: `CECLI_ARCHITECT` ### `--auto-accept-architect` Enable/disable automatic acceptance of architect changes (default: True) Default: True -Environment variable: `AIDER_AUTO_ACCEPT_ARCHITECT` +Environment variable: `CECLI_AUTO_ACCEPT_ARCHITECT` Aliases: - `--auto-accept-architect` - `--no-auto-accept-architect` ### `--weak-model WEAK_MODEL` Specify the model to use for commit messages and chat history summarization (default depends on --model) -Environment variable: `AIDER_WEAK_MODEL` +Environment variable: `CECLI_WEAK_MODEL` ### `--editor-model EDITOR_MODEL` Specify the model to use for editor tasks (default depends on --model) -Environment variable: `AIDER_EDITOR_MODEL` +Environment variable: `CECLI_EDITOR_MODEL` ### `--editor-edit-format EDITOR_EDIT_FORMAT` Specify the edit format for the editor model (default: depends on editor model) -Environment variable: `AIDER_EDITOR_EDIT_FORMAT` +Environment variable: `CECLI_EDITOR_EDIT_FORMAT` ### `--show-model-warnings` Only work with models that have meta-data available (default: True) Default: True -Environment variable: `AIDER_SHOW_MODEL_WARNINGS` +Environment variable: `CECLI_SHOW_MODEL_WARNINGS` Aliases: - `--show-model-warnings` - `--no-show-model-warnings` @@ -235,40 +235,40 @@ Aliases: ### `--check-model-accepts-settings` Check if model accepts settings like reasoning_effort/thinking_tokens (default: True) Default: True -Environment variable: `AIDER_CHECK_MODEL_ACCEPTS_SETTINGS` +Environment variable: `CECLI_CHECK_MODEL_ACCEPTS_SETTINGS` Aliases: - `--check-model-accepts-settings` - `--no-check-model-accepts-settings` ### `--max-chat-history-tokens VALUE` Soft limit on tokens for chat history, after which summarization begins. If unspecified, defaults to the model's max_chat_history_tokens. -Environment variable: `AIDER_MAX_CHAT_HISTORY_TOKENS` +Environment variable: `CECLI_MAX_CHAT_HISTORY_TOKENS` ## Context Compaction: ### `--enable-context-compaction` Enable automatic compaction of chat history to conserve tokens (default: False) Default: False -Environment variable: `AIDER_ENABLE_CONTEXT_COMPACTION` +Environment variable: `CECLI_ENABLE_CONTEXT_COMPACTION` Aliases: - `--enable-context-compaction` - `--no-enable-context-compaction` ### `--context-compaction-max-tokens VALUE` The maximum number of tokens in the conversation before context compaction is triggered. (default: 80% of model's context window) -Environment variable: `AIDER_CONTEXT_COMPACTION_MAX_TOKENS` +Environment variable: `CECLI_CONTEXT_COMPACTION_MAX_TOKENS` ### `--context-compaction-summary-tokens VALUE` The target maximum number of tokens for the generated summary. (default: 4096) Default: 4096 -Environment variable: `AIDER_CONTEXT_COMPACTION_SUMMARY_TOKENS` +Environment variable: `CECLI_CONTEXT_COMPACTION_SUMMARY_TOKENS` ## Cache settings: ### `--cache-prompts` Enable caching of prompts (default: False) Default: False -Environment variable: `AIDER_CACHE_PROMPTS` +Environment variable: `CECLI_CACHE_PROMPTS` Aliases: - `--cache-prompts` - `--no-cache-prompts` @@ -276,69 +276,69 @@ Aliases: ### `--cache-keepalive-pings VALUE` Number of times to ping at 5min intervals to keep prompt cache warm (default: 0) Default: 0 -Environment variable: `AIDER_CACHE_KEEPALIVE_PINGS` +Environment variable: `CECLI_CACHE_KEEPALIVE_PINGS` ## Repomap settings: ### `--map-tokens VALUE` Suggested number of tokens to use for repo map, use 0 to disable -Environment variable: `AIDER_MAP_TOKENS` +Environment variable: `CECLI_MAP_TOKENS` ### `--map-refresh VALUE` Control how often the repo map is refreshed. Options: auto, always, files, manual (default: auto) Default: auto -Environment variable: `AIDER_MAP_REFRESH` +Environment variable: `CECLI_MAP_REFRESH` ### `--map-multiplier-no-files VALUE` Multiplier for map tokens when no files are specified (default: 2) Default: 2 -Environment variable: `AIDER_MAP_MULTIPLIER_NO_FILES` +Environment variable: `CECLI_MAP_MULTIPLIER_NO_FILES` ### `--map-max-line-length VALUE` Maximum line length for the repo map code. Prevents sending crazy long lines of minified JS files etc. (default: 100) Default: 100 -Environment variable: `AIDER_MAP_MAX_LINE_LENGTH` +Environment variable: `CECLI_MAP_MAX_LINE_LENGTH` ## History Files: ### `--input-history-file INPUT_HISTORY_FILE` Specify the chat input history file (default: .aider.input.history) Default: .aider.input.history -Environment variable: `AIDER_INPUT_HISTORY_FILE` +Environment variable: `CECLI_INPUT_HISTORY_FILE` ### `--chat-history-file CHAT_HISTORY_FILE` Specify the chat history file (default: .aider.chat.history.md) Default: .aider.chat.history.md -Environment variable: `AIDER_CHAT_HISTORY_FILE` +Environment variable: `CECLI_CHAT_HISTORY_FILE` ### `--restore-chat-history` Restore the previous chat history messages (default: False) Default: False -Environment variable: `AIDER_RESTORE_CHAT_HISTORY` +Environment variable: `CECLI_RESTORE_CHAT_HISTORY` Aliases: - `--restore-chat-history` - `--no-restore-chat-history` ### `--llm-history-file LLM_HISTORY_FILE` Log the conversation with the LLM to this file (for example, .aider.llm.history) -Environment variable: `AIDER_LLM_HISTORY_FILE` +Environment variable: `CECLI_LLM_HISTORY_FILE` ## Output settings: ### `--dark-mode` Use colors suitable for a dark terminal background (default: False) Default: False -Environment variable: `AIDER_DARK_MODE` +Environment variable: `CECLI_DARK_MODE` ### `--light-mode` Use colors suitable for a light terminal background (default: False) Default: False -Environment variable: `AIDER_LIGHT_MODE` +Environment variable: `CECLI_LIGHT_MODE` ### `--pretty` Enable/disable pretty, colorized output (default: True) Default: True -Environment variable: `AIDER_PRETTY` +Environment variable: `CECLI_PRETTY` Aliases: - `--pretty` - `--no-pretty` @@ -346,7 +346,7 @@ Aliases: ### `--stream` Enable/disable streaming responses (default: True) Default: True -Environment variable: `AIDER_STREAM` +Environment variable: `CECLI_STREAM` Aliases: - `--stream` - `--no-stream` @@ -354,59 +354,59 @@ Aliases: ### `--user-input-color VALUE` Set the color for user input (default: #00cc00) Default: #00cc00 -Environment variable: `AIDER_USER_INPUT_COLOR` +Environment variable: `CECLI_USER_INPUT_COLOR` ### `--tool-output-color VALUE` Set the color for tool output (default: None) -Environment variable: `AIDER_TOOL_OUTPUT_COLOR` +Environment variable: `CECLI_TOOL_OUTPUT_COLOR` ### `--tool-error-color VALUE` Set the color for tool error messages (default: #FF2222) Default: #FF2222 -Environment variable: `AIDER_TOOL_ERROR_COLOR` +Environment variable: `CECLI_TOOL_ERROR_COLOR` ### `--tool-warning-color VALUE` Set the color for tool warning messages (default: #FFA500) Default: #FFA500 -Environment variable: `AIDER_TOOL_WARNING_COLOR` +Environment variable: `CECLI_TOOL_WARNING_COLOR` ### `--assistant-output-color VALUE` Set the color for assistant output (default: #0088ff) Default: #0088ff -Environment variable: `AIDER_ASSISTANT_OUTPUT_COLOR` +Environment variable: `CECLI_ASSISTANT_OUTPUT_COLOR` ### `--completion-menu-color COLOR` Set the color for the completion menu (default: terminal's default text color) -Environment variable: `AIDER_COMPLETION_MENU_COLOR` +Environment variable: `CECLI_COMPLETION_MENU_COLOR` ### `--completion-menu-bg-color COLOR` Set the background color for the completion menu (default: terminal's default background color) -Environment variable: `AIDER_COMPLETION_MENU_BG_COLOR` +Environment variable: `CECLI_COMPLETION_MENU_BG_COLOR` ### `--completion-menu-current-color COLOR` Set the color for the current item in the completion menu (default: terminal's default background color) -Environment variable: `AIDER_COMPLETION_MENU_CURRENT_COLOR` +Environment variable: `CECLI_COMPLETION_MENU_CURRENT_COLOR` ### `--completion-menu-current-bg-color COLOR` Set the background color for the current item in the completion menu (default: terminal's default text color) -Environment variable: `AIDER_COMPLETION_MENU_CURRENT_BG_COLOR` +Environment variable: `CECLI_COMPLETION_MENU_CURRENT_BG_COLOR` ### `--code-theme VALUE` Set the markdown code theme (default: default, other options include monokai, solarized-dark, solarized-light, or a Pygments builtin style, see https://pygments.org/styles for available themes) Default: default -Environment variable: `AIDER_CODE_THEME` +Environment variable: `CECLI_CODE_THEME` ### `--show-diffs` Show diffs when committing changes (default: False) Default: False -Environment variable: `AIDER_SHOW_DIFFS` +Environment variable: `CECLI_SHOW_DIFFS` ## Git settings: ### `--git` Enable/disable looking for a git repo (default: True) Default: True -Environment variable: `AIDER_GIT` +Environment variable: `CECLI_GIT` Aliases: - `--git` - `--no-git` @@ -414,7 +414,7 @@ Aliases: ### `--gitignore` Enable/disable adding .aider* to .gitignore (default: True) Default: True -Environment variable: `AIDER_GITIGNORE` +Environment variable: `CECLI_GITIGNORE` Aliases: - `--gitignore` - `--no-gitignore` @@ -422,7 +422,7 @@ Aliases: ### `--add-gitignore-files` Enable/disable the addition of files listed in .gitignore to Aider's editing scope. Default: False -Environment variable: `AIDER_ADD_GITIGNORE_FILES` +Environment variable: `CECLI_ADD_GITIGNORE_FILES` Aliases: - `--add-gitignore-files` - `--no-add-gitignore-files` @@ -430,17 +430,17 @@ Aliases: ### `--aiderignore AIDERIGNORE` Specify the aider ignore file (default: .aiderignore in git root) Default: .aiderignore -Environment variable: `AIDER_AIDERIGNORE` +Environment variable: `CECLI_AIDERIGNORE` ### `--subtree-only` Only consider files in the current subtree of the git repository Default: False -Environment variable: `AIDER_SUBTREE_ONLY` +Environment variable: `CECLI_SUBTREE_ONLY` ### `--auto-commits` Enable/disable auto commit of LLM changes (default: True) Default: True -Environment variable: `AIDER_AUTO_COMMITS` +Environment variable: `CECLI_AUTO_COMMITS` Aliases: - `--auto-commits` - `--no-auto-commits` @@ -448,21 +448,21 @@ Aliases: ### `--dirty-commits` Enable/disable commits when repo is found dirty (default: True) Default: True -Environment variable: `AIDER_DIRTY_COMMITS` +Environment variable: `CECLI_DIRTY_COMMITS` Aliases: - `--dirty-commits` - `--no-dirty-commits` ### `--attribute-author` Attribute aider code changes in the git author name (default: True). If explicitly set to True, overrides --attribute-co-authored-by precedence. -Environment variable: `AIDER_ATTRIBUTE_AUTHOR` +Environment variable: `CECLI_ATTRIBUTE_AUTHOR` Aliases: - `--attribute-author` - `--no-attribute-author` ### `--attribute-committer` Attribute aider commits in the git committer name (default: True). If explicitly set to True, overrides --attribute-co-authored-by precedence for aider edits. -Environment variable: `AIDER_ATTRIBUTE_COMMITTER` +Environment variable: `CECLI_ATTRIBUTE_COMMITTER` Aliases: - `--attribute-committer` - `--no-attribute-committer` @@ -470,7 +470,7 @@ Aliases: ### `--attribute-commit-message-author` Prefix commit messages with 'aider: ' if aider authored the changes (default: False) Default: False -Environment variable: `AIDER_ATTRIBUTE_COMMIT_MESSAGE_AUTHOR` +Environment variable: `CECLI_ATTRIBUTE_COMMIT_MESSAGE_AUTHOR` Aliases: - `--attribute-commit-message-author` - `--no-attribute-commit-message-author` @@ -478,7 +478,7 @@ Aliases: ### `--attribute-commit-message-committer` Prefix all commit messages with 'aider: ' (default: False) Default: False -Environment variable: `AIDER_ATTRIBUTE_COMMIT_MESSAGE_COMMITTER` +Environment variable: `CECLI_ATTRIBUTE_COMMIT_MESSAGE_COMMITTER` Aliases: - `--attribute-commit-message-committer` - `--no-attribute-commit-message-committer` @@ -486,7 +486,7 @@ Aliases: ### `--attribute-co-authored-by` Attribute aider edits using the Co-authored-by trailer in the commit message (default: True). If True, this takes precedence over default --attribute-author and --attribute-committer behavior unless they are explicitly set to True. Default: True -Environment variable: `AIDER_ATTRIBUTE_CO_AUTHORED_BY` +Environment variable: `CECLI_ATTRIBUTE_CO_AUTHORED_BY` Aliases: - `--attribute-co-authored-by` - `--no-attribute-co-authored-by` @@ -494,7 +494,7 @@ Aliases: ### `--git-commit-verify` Enable/disable git pre-commit hooks with --no-verify (default: False) Default: False -Environment variable: `AIDER_GIT_COMMIT_VERIFY` +Environment variable: `CECLI_GIT_COMMIT_VERIFY` Aliases: - `--git-commit-verify` - `--no-git-commit-verify` @@ -502,16 +502,16 @@ Aliases: ### `--commit` Commit all pending changes with a suitable commit message, then exit Default: False -Environment variable: `AIDER_COMMIT` +Environment variable: `CECLI_COMMIT` ### `--commit-prompt PROMPT` Specify a custom prompt for generating commit messages -Environment variable: `AIDER_COMMIT_PROMPT` +Environment variable: `CECLI_COMMIT_PROMPT` ### `--dry-run` Perform a dry run without modifying files (default: False) Default: False -Environment variable: `AIDER_DRY_RUN` +Environment variable: `CECLI_DRY_RUN` Aliases: - `--dry-run` - `--no-dry-run` @@ -519,12 +519,12 @@ Aliases: ### `--skip-sanity-check-repo` Skip the sanity check for the git repository (default: False) Default: False -Environment variable: `AIDER_SKIP_SANITY_CHECK_REPO` +Environment variable: `CECLI_SKIP_SANITY_CHECK_REPO` ### `--watch-files` Enable/disable watching files for ai coding comments (default: False) Default: False -Environment variable: `AIDER_WATCH_FILES` +Environment variable: `CECLI_WATCH_FILES` Aliases: - `--watch-files` - `--no-watch-files` @@ -534,17 +534,17 @@ Aliases: ### `--lint` Lint and fix provided files, or dirty files if none provided Default: False -Environment variable: `AIDER_LINT` +Environment variable: `CECLI_LINT` ### `--lint-cmd` Specify lint commands to run for different languages, eg: "python: flake8 --select=..." (can be used multiple times) Default: [] -Environment variable: `AIDER_LINT_CMD` +Environment variable: `CECLI_LINT_CMD` ### `--auto-lint` Enable/disable automatic linting after changes (default: True) Default: True -Environment variable: `AIDER_AUTO_LINT` +Environment variable: `CECLI_AUTO_LINT` Aliases: - `--auto-lint` - `--no-auto-lint` @@ -552,12 +552,12 @@ Aliases: ### `--test-cmd VALUE` Specify command to run tests Default: [] -Environment variable: `AIDER_TEST_CMD` +Environment variable: `CECLI_TEST_CMD` ### `--auto-test` Enable/disable automatic testing after changes (default: False) Default: False -Environment variable: `AIDER_AUTO_TEST` +Environment variable: `CECLI_AUTO_TEST` Aliases: - `--auto-test` - `--no-auto-test` @@ -565,52 +565,52 @@ Aliases: ### `--test` Run tests, fix problems found and then exit Default: False -Environment variable: `AIDER_TEST` +Environment variable: `CECLI_TEST` ## Analytics: ### `--analytics` Enable/disable analytics for current session (default: random) -Environment variable: `AIDER_ANALYTICS` +Environment variable: `CECLI_ANALYTICS` Aliases: - `--analytics` - `--no-analytics` ### `--analytics-log ANALYTICS_LOG_FILE` Specify a file to log analytics events -Environment variable: `AIDER_ANALYTICS_LOG` +Environment variable: `CECLI_ANALYTICS_LOG` ### `--analytics-disable` Permanently disable analytics Default: False -Environment variable: `AIDER_ANALYTICS_DISABLE` +Environment variable: `CECLI_ANALYTICS_DISABLE` ### `--analytics-posthog-host ANALYTICS_POSTHOG_HOST` Send analytics to custom PostHog instance -Environment variable: `AIDER_ANALYTICS_POSTHOG_HOST` +Environment variable: `CECLI_ANALYTICS_POSTHOG_HOST` ### `--analytics-posthog-project-api-key ANALYTICS_POSTHOG_PROJECT_API_KEY` Send analytics to custom PostHog project -Environment variable: `AIDER_ANALYTICS_POSTHOG_PROJECT_API_KEY` +Environment variable: `CECLI_ANALYTICS_POSTHOG_PROJECT_API_KEY` ## Upgrading: ### `--just-check-update` Check for updates and return status in the exit code Default: False -Environment variable: `AIDER_JUST_CHECK_UPDATE` +Environment variable: `CECLI_JUST_CHECK_UPDATE` ### `--check-update` Check for new aider versions on launch Default: True -Environment variable: `AIDER_CHECK_UPDATE` +Environment variable: `CECLI_CHECK_UPDATE` Aliases: - `--check-update` - `--no-check-update` ### `--show-release-notes` Show release notes on first run of new version (default: None, ask user) -Environment variable: `AIDER_SHOW_RELEASE_NOTES` +Environment variable: `CECLI_SHOW_RELEASE_NOTES` Aliases: - `--show-release-notes` - `--no-show-release-notes` @@ -618,12 +618,12 @@ Aliases: ### `--install-main-branch` Install the latest version from the main branch Default: False -Environment variable: `AIDER_INSTALL_MAIN_BRANCH` +Environment variable: `CECLI_INSTALL_MAIN_BRANCH` ### `--upgrade` Upgrade aider to the latest version from PyPI Default: False -Environment variable: `AIDER_UPGRADE` +Environment variable: `CECLI_UPGRADE` Aliases: - `--upgrade` - `--update` @@ -635,7 +635,7 @@ Show the version number and exit ### `--message COMMAND` Specify a single message to send the LLM, process reply then exit (disables chat mode) -Environment variable: `AIDER_MESSAGE` +Environment variable: `CECLI_MESSAGE` Aliases: - `--message COMMAND` - `--msg COMMAND` @@ -643,7 +643,7 @@ Aliases: ### `--message-file MESSAGE_FILE` Specify a file containing the message to send the LLM, process reply, then exit (disables chat mode) -Environment variable: `AIDER_MESSAGE_FILE` +Environment variable: `CECLI_MESSAGE_FILE` Aliases: - `--message-file MESSAGE_FILE` - `-f MESSAGE_FILE` @@ -651,7 +651,7 @@ Aliases: ### `--gui` Run aider in your browser (default: False) Default: False -Environment variable: `AIDER_GUI` +Environment variable: `CECLI_GUI` Aliases: - `--gui` - `--no-gui` @@ -661,104 +661,104 @@ Aliases: ### `--copy-paste` Enable automatic copy/paste of chat between aider and web UI (default: False) Default: False -Environment variable: `AIDER_COPY_PASTE` +Environment variable: `CECLI_COPY_PASTE` Aliases: - `--copy-paste` - `--no-copy-paste` ### `--apply FILE` Apply the changes from the given file instead of running the chat (debug) -Environment variable: `AIDER_APPLY` +Environment variable: `CECLI_APPLY` ### `--apply-clipboard-edits` Apply clipboard contents as edits using the main model's editor format Default: False -Environment variable: `AIDER_APPLY_CLIPBOARD_EDITS` +Environment variable: `CECLI_APPLY_CLIPBOARD_EDITS` ### `--exit` Do all startup activities then exit before accepting user input (debug) Default: False -Environment variable: `AIDER_EXIT` +Environment variable: `CECLI_EXIT` ### `--show-repo-map` Print the repo map and exit (debug) Default: False -Environment variable: `AIDER_SHOW_REPO_MAP` +Environment variable: `CECLI_SHOW_REPO_MAP` ### `--show-prompts` Print the system prompts and exit (debug) Default: False -Environment variable: `AIDER_SHOW_PROMPTS` +Environment variable: `CECLI_SHOW_PROMPTS` ## Voice settings: ### `--voice-format VOICE_FORMAT` Audio format for voice recording (default: wav). webm and mp3 require ffmpeg Default: wav -Environment variable: `AIDER_VOICE_FORMAT` +Environment variable: `CECLI_VOICE_FORMAT` ### `--voice-language VOICE_LANGUAGE` Specify the language for voice using ISO 639-1 code (default: auto) Default: en -Environment variable: `AIDER_VOICE_LANGUAGE` +Environment variable: `CECLI_VOICE_LANGUAGE` ### `--voice-input-device VOICE_INPUT_DEVICE` Specify the input device name for voice recording -Environment variable: `AIDER_VOICE_INPUT_DEVICE` +Environment variable: `CECLI_VOICE_INPUT_DEVICE` ## Other settings: ### `--disable-playwright` Never prompt for or attempt to install Playwright for web scraping (default: False). Default: False -Environment variable: `AIDER_DISABLE_PLAYWRIGHT` +Environment variable: `CECLI_DISABLE_PLAYWRIGHT` ### `--file FILE` specify a file to edit (can be used multiple times) -Environment variable: `AIDER_FILE` +Environment variable: `CECLI_FILE` ### `--read FILE` specify a read-only file (can be used multiple times) -Environment variable: `AIDER_READ` +Environment variable: `CECLI_READ` ### `--vim` Use VI editing mode in the terminal (default: False) Default: False -Environment variable: `AIDER_VIM` +Environment variable: `CECLI_VIM` ### `--chat-language CHAT_LANGUAGE` Specify the language to use in the chat (default: None, uses system settings) -Environment variable: `AIDER_CHAT_LANGUAGE` +Environment variable: `CECLI_CHAT_LANGUAGE` ### `--commit-language COMMIT_LANGUAGE` Specify the language to use in the commit message (default: None, user language) -Environment variable: `AIDER_COMMIT_LANGUAGE` +Environment variable: `CECLI_COMMIT_LANGUAGE` ### `--yes-always` Always say yes to every confirmation -Environment variable: `AIDER_YES_ALWAYS` +Environment variable: `CECLI_YES_ALWAYS` ### `--verbose` Enable verbose output Default: False -Environment variable: `AIDER_VERBOSE` +Environment variable: `CECLI_VERBOSE` Aliases: - `-v` - `--verbose` ### `--load LOAD_FILE` Load and execute /commands from a file on launch -Environment variable: `AIDER_LOAD` +Environment variable: `CECLI_LOAD` ### `--encoding VALUE` Specify the encoding for input and output (default: utf-8) Default: utf-8 -Environment variable: `AIDER_ENCODING` +Environment variable: `CECLI_ENCODING` ### `--line-endings VALUE` Line endings to use when writing files (default: platform) Default: platform -Environment variable: `AIDER_LINE_ENDINGS` +Environment variable: `CECLI_LINE_ENDINGS` ### `--config CONFIG_FILE` Specify the config file (default: search for .aider.conf.yml in git root, cwd or home directory) @@ -769,12 +769,12 @@ Aliases: ### `--env-file ENV_FILE` Specify the .env file to load (default: .env in git root) Default: .env -Environment variable: `AIDER_ENV_FILE` +Environment variable: `CECLI_ENV_FILE` ### `--suggest-shell-commands` Enable/disable suggesting shell commands (default: True) Default: True -Environment variable: `AIDER_SUGGEST_SHELL_COMMANDS` +Environment variable: `CECLI_SUGGEST_SHELL_COMMANDS` Aliases: - `--suggest-shell-commands` - `--no-suggest-shell-commands` @@ -782,7 +782,7 @@ Aliases: ### `--fancy-input` Enable/disable fancy input with history and completion (default: True) Default: True -Environment variable: `AIDER_FANCY_INPUT` +Environment variable: `CECLI_FANCY_INPUT` Aliases: - `--fancy-input` - `--no-fancy-input` @@ -790,7 +790,7 @@ Aliases: ### `--multiline` Enable/disable multi-line input mode with Meta-Enter to submit (default: False) Default: False -Environment variable: `AIDER_MULTILINE` +Environment variable: `CECLI_MULTILINE` Aliases: - `--multiline` - `--no-multiline` @@ -798,52 +798,52 @@ Aliases: ### `--notifications` Enable/disable terminal bell notifications when LLM responses are ready (default: False) Default: False -Environment variable: `AIDER_NOTIFICATIONS` +Environment variable: `CECLI_NOTIFICATIONS` Aliases: - `--notifications` - `--no-notifications` ### `--notifications-command COMMAND` Specify a command to run for notifications instead of the terminal bell. If not specified, a default command for your OS may be used. -Environment variable: `AIDER_NOTIFICATIONS_COMMAND` +Environment variable: `CECLI_NOTIFICATIONS_COMMAND` ### `--detect-urls` Enable/disable detection and offering to add URLs to chat (default: True) Default: True -Environment variable: `AIDER_DETECT_URLS` +Environment variable: `CECLI_DETECT_URLS` Aliases: - `--detect-urls` - `--no-detect-urls` ### `--editor VALUE` Specify which editor to use for the /editor command -Environment variable: `AIDER_EDITOR` +Environment variable: `CECLI_EDITOR` ### `--shell-completions SHELL` Print shell completion script for the specified SHELL and exit. Supported shells: bash, tcsh, zsh. Example: aider --shell-completions bash -Environment variable: `AIDER_SHELL_COMPLETIONS` +Environment variable: `CECLI_SHELL_COMPLETIONS` ## Deprecated model settings: ### `--opus` Use claude-3-opus-20240229 model for the main chat (deprecated, use --model) Default: False -Environment variable: `AIDER_OPUS` +Environment variable: `CECLI_OPUS` ### `--sonnet` Use anthropic/claude-3-7-sonnet-20250219 model for the main chat (deprecated, use --model) Default: False -Environment variable: `AIDER_SONNET` +Environment variable: `CECLI_SONNET` ### `--haiku` Use claude-3-5-haiku-20241022 model for the main chat (deprecated, use --model) Default: False -Environment variable: `AIDER_HAIKU` +Environment variable: `CECLI_HAIKU` ### `--4` Use gpt-4-0613 model for the main chat (deprecated, use --model) Default: False -Environment variable: `AIDER_4` +Environment variable: `CECLI_4` Aliases: - `--4` - `-4` @@ -851,22 +851,22 @@ Aliases: ### `--4o` Use gpt-4o model for the main chat (deprecated, use --model) Default: False -Environment variable: `AIDER_4O` +Environment variable: `CECLI_4O` ### `--mini` Use gpt-4o-mini model for the main chat (deprecated, use --model) Default: False -Environment variable: `AIDER_MINI` +Environment variable: `CECLI_MINI` ### `--4-turbo` Use gpt-4-1106-preview model for the main chat (deprecated, use --model) Default: False -Environment variable: `AIDER_4_TURBO` +Environment variable: `CECLI_4_TURBO` ### `--35turbo` Use gpt-3.5-turbo model for the main chat (deprecated, use --model) Default: False -Environment variable: `AIDER_35TURBO` +Environment variable: `CECLI_35TURBO` Aliases: - `--35turbo` - `--35-turbo` @@ -876,15 +876,15 @@ Aliases: ### `--deepseek` Use deepseek/deepseek-chat model for the main chat (deprecated, use --model) Default: False -Environment variable: `AIDER_DEEPSEEK` +Environment variable: `CECLI_DEEPSEEK` ### `--o1-mini` Use o1-mini model for the main chat (deprecated, use --model) Default: False -Environment variable: `AIDER_O1_MINI` +Environment variable: `CECLI_O1_MINI` ### `--o1-preview` Use o1-preview model for the main chat (deprecated, use --model) Default: False -Environment variable: `AIDER_O1_PREVIEW` +Environment variable: `CECLI_O1_PREVIEW` diff --git a/cecli/website/docs/scripting.md b/cecli/website/docs/scripting.md index 71bb3282a59..30f2035e926 100644 --- a/cecli/website/docs/scripting.md +++ b/cecli/website/docs/scripting.md @@ -33,25 +33,25 @@ but these are useful for scripting: ``` --stream, --no-stream Enable/disable streaming responses (default: True) [env var: - AIDER_STREAM] + CECLI_STREAM] --message COMMAND, --msg COMMAND, -m COMMAND Specify a single message to send GPT, process reply then exit - (disables chat mode) [env var: AIDER_MESSAGE] + (disables chat mode) [env var: CECLI_MESSAGE] --message-file MESSAGE_FILE, -f MESSAGE_FILE Specify a file containing the message to send GPT, process reply, - then exit (disables chat mode) [env var: AIDER_MESSAGE_FILE] ---yes Always say yes to every confirmation [env var: AIDER_YES] + then exit (disables chat mode) [env var: CECLI_MESSAGE_FILE] +--yes Always say yes to every confirmation [env var: CECLI_YES] --auto-commits, --no-auto-commits Enable/disable auto commit of GPT changes (default: True) [env var: - AIDER_AUTO_COMMITS] + CECLI_AUTO_COMMITS] --dirty-commits, --no-dirty-commits Enable/disable commits when repo is found dirty (default: True) [env - var: AIDER_DIRTY_COMMITS] + var: CECLI_DIRTY_COMMITS] --dry-run, --no-dry-run Perform a dry run without modifying files (default: False) [env var: - AIDER_DRY_RUN] + CECLI_DRY_RUN] --commit Commit all pending changes with a suitable commit message, then exit - [env var: AIDER_COMMIT] + [env var: CECLI_COMMIT] ``` diff --git a/cecli/website/docs/usage/notifications.md b/cecli/website/docs/usage/notifications.md index ee7febb72e7..8f11827b6fd 100644 --- a/cecli/website/docs/usage/notifications.md +++ b/cecli/website/docs/usage/notifications.md @@ -82,6 +82,6 @@ notifications_command: "your-custom-command" Or in your `.env` file: ``` -AIDER_NOTIFICATIONS=true -AIDER_NOTIFICATIONS_COMMAND=your-custom-command +CECLI_NOTIFICATIONS=true +CECLI_NOTIFICATIONS_COMMAND=your-custom-command ``` diff --git a/cecli/website/examples/update-docs.md b/cecli/website/examples/update-docs.md index d0ff405f03a..b580ed528f8 100644 --- a/cecli/website/examples/update-docs.md +++ b/cecli/website/examples/update-docs.md @@ -16,21 +16,21 @@ In this chat transcript, the user asks to automatically update the Usage docs ba ```markdown README.md <<<<<<< ORIGINAL -- `--history-file HISTORY_FILE`: Specify the chat input history file (default: .aider.history). Override the default with the environment variable `AIDER_HISTORY_FILE`. -- `--model MODEL`: Specify the model to use for the main chat (default: gpt-4). Override the default with the environment variable `AIDER_MODEL`. +- `--history-file HISTORY_FILE`: Specify the chat input history file (default: .aider.history). Override the default with the environment variable `CECLI_HISTORY_FILE`. +- `--model MODEL`: Specify the model to use for the main chat (default: gpt-4). Override the default with the environment variable `CECLI_MODEL`. - `-3`: Use gpt-3.5-turbo model for the main chat (basically won't work). No environment variable override. -- `--no-pretty`: Disable pretty, colorized output. Override the default with the environment variable `AIDER_PRETTY` (default: 1 for enabled, 0 for disabled). -- `--show-diffs`: Show diffs when committing changes (default: False). Override the default with the environment variable `AIDER_SHOW_DIFFS` (default: 0 for False, 1 for True). -- `--no-auto-commits`: Disable auto commit of changes. Override the default with the environment variable `AIDER_AUTO_COMMITS` (default: 1 for enabled, 0 for disabled). +- `--no-pretty`: Disable pretty, colorized output. Override the default with the environment variable `CECLI_PRETTY` (default: 1 for enabled, 0 for disabled). +- `--show-diffs`: Show diffs when committing changes (default: False). Override the default with the environment variable `CECLI_SHOW_DIFFS` (default: 0 for False, 1 for True). +- `--no-auto-commits`: Disable auto commit of changes. Override the default with the environment variable `CECLI_AUTO_COMMITS` (default: 1 for enabled, 0 for disabled). ======= -- `--input-history-file INPUT_HISTORY_FILE`: Specify the chat input history file (default: .aider.input.history). Override the default with the environment variable `AIDER_INPUT_HISTORY_FILE`. -- `--chat-history-file CHAT_HISTORY_FILE`: Specify the chat history file (default: .aider.chat.history.md). Override the default with the environment variable `AIDER_CHAT_HISTORY_FILE`. -- `--model MODEL`: Specify the model to use for the main chat (default: gpt-4). Override the default with the environment variable `AIDER_MODEL`. +- `--input-history-file INPUT_HISTORY_FILE`: Specify the chat input history file (default: .aider.input.history). Override the default with the environment variable `CECLI_INPUT_HISTORY_FILE`. +- `--chat-history-file CHAT_HISTORY_FILE`: Specify the chat history file (default: .aider.chat.history.md). Override the default with the environment variable `CECLI_CHAT_HISTORY_FILE`. +- `--model MODEL`: Specify the model to use for the main chat (default: gpt-4). Override the default with the environment variable `CECLI_MODEL`. - `-3`: Use gpt-3.5-turbo model for the main chat (basically won't work). No environment variable override. -- `--no-pretty`: Disable pretty, colorized output. Override the default with the environment variable `AIDER_PRETTY` (default: 1 for enabled, 0 for disabled). +- `--no-pretty`: Disable pretty, colorized output. Override the default with the environment variable `CECLI_PRETTY` (default: 1 for enabled, 0 for disabled). - `--apply FILE`: Apply the changes from the given file instead of running the chat (debug). -- `--no-auto-commits`: Disable auto commit of changes. Override the default with the environment variable `AIDER_AUTO_COMMITS` (default: 1 for enabled, 0 for disabled). -- `--show-diffs`: Show diffs when committing changes (default: False). Override the default with the environment variable `AIDER_SHOW_DIFFS` (default: 0 for False, 1 for True). +- `--no-auto-commits`: Disable auto commit of changes. Override the default with the environment variable `CECLI_AUTO_COMMITS` (default: 1 for enabled, 0 for disabled). +- `--show-diffs`: Show diffs when committing changes (default: False). Override the default with the environment variable `CECLI_SHOW_DIFFS` (default: 0 for False, 1 for True). - `--yes`: Always say yes to every confirmation (default: False). >>>>>>> UPDATED ``` diff --git a/requirements.txt b/requirements.txt index 187e4ad233a..70573b62c5f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -254,7 +254,7 @@ mccabe==0.7.0 # via # -c requirements/common-constraints.txt # flake8 -mcp==1.22.0 +mcp==1.25.0 # via # -c requirements/common-constraints.txt # -r requirements/requirements.in diff --git a/requirements/common-constraints.txt b/requirements/common-constraints.txt index f1e5ab20765..8ec0b86ea0b 100644 --- a/requirements/common-constraints.txt +++ b/requirements/common-constraints.txt @@ -259,7 +259,7 @@ matplotlib==3.10.7 # via -r requirements/requirements-dev.in mccabe==0.7.0 # via flake8 -mcp==1.22.0 +mcp==1.25.0 # via -r requirements/requirements.in mdit-py-plugins==0.5.0 # via textual diff --git a/requirements/requirements.in b/requirements/requirements.in index 306eda36193..1c9e9384e42 100644 --- a/requirements/requirements.in +++ b/requirements/requirements.in @@ -28,7 +28,7 @@ pillow>=11.3.0 shtab>=1.7.2 oslex>=0.1.3 google-generativeai>=0.8.5 -mcp>=1.12.3 +mcp>=1.24.0 textual>=6.0.0 truststore diff --git a/scripts/30k-image.py b/scripts/30k-image.py index c5e9d093d6b..6b7938c6cd2 100644 --- a/scripts/30k-image.py +++ b/scripts/30k-image.py @@ -12,8 +12,8 @@ from pathlib import Path # Default colors for the celebration image -CECLIGREEN = "#14b014" -CECLIBLUE = "#4C6EF5" +CECLI_GREEN = "#14b014" +CECLI_BLUE = "#4C6EF5" DARK_COLOR = "#212529" LIGHT_COLOR = "#F8F9FA" GOLD_COLOR = "#f1c40f" @@ -46,7 +46,7 @@ def embed_font(): def generate_confetti(count=150, width=DEFAULT_WIDTH, height=DEFAULT_HEIGHT): """Generate SVG confetti elements for the celebration.""" confetti = [] - colors = [CECLIGREEN, CECLIBLUE, GOLD_COLOR, "#e74c3c", "#9b59b6", "#3498db", "#2ecc71"] + colors = [CECLI_GREEN, CECLI_BLUE, GOLD_COLOR, "#e74c3c", "#9b59b6", "#3498db", "#2ecc71"] # Define text safe zones # Main content safe zone (centered area) @@ -169,7 +169,7 @@ def generate_celebration_svg(output_path=None, width=DEFAULT_WIDTH, height=DEFAU