From f3f0a1fea3c62244c84113e1a01ab350711c4db5 Mon Sep 17 00:00:00 2001 From: banteg <4562643+banteg@users.noreply.github.com> Date: Mon, 29 Dec 2025 18:15:05 +0400 Subject: [PATCH] refactor: drop --cd and simplify config lookup --- developing.md | 6 +++--- readme.md | 3 --- src/takopi/config.py | 23 ++++++++--------------- src/takopi/exec_bridge.py | 26 +++----------------------- tests/test_exec_runner.py | 2 +- 5 files changed, 15 insertions(+), 45 deletions(-) diff --git a/developing.md b/developing.md index 0bdce6d..6a4419a 100644 --- a/developing.md +++ b/developing.md @@ -73,15 +73,15 @@ def render_markdown(md: str) -> tuple[str, list[dict[str, Any]]]: ### `config.py` — Configuration Loading ```python -def load_telegram_config(path=None, *, base_dir=None) -> tuple[dict, Path]: - # Loads /codex/takopi.toml (if set), then ./codex/takopi.toml, then ~/.codex/takopi.toml +def load_telegram_config(path=None) -> tuple[dict, Path]: + # Loads ./.codex/takopi.toml, then ~/.codex/takopi.toml ``` ### `constants.py` — Shared Constants ```python TELEGRAM_HARD_LIMIT = 4096 # Max message length -LOCAL_CONFIG_NAME = codex/takopi.toml +LOCAL_CONFIG_NAME = .codex/takopi.toml HOME_CONFIG_PATH = ~/.codex/takopi.toml ``` diff --git a/readme.md b/readme.md index 2e7e74b..4e3eb37 100644 --- a/readme.md +++ b/readme.md @@ -46,8 +46,6 @@ chat_id = 123456789 The bridge only accepts messages where the chat ID equals the sender ID and both match `chat_id` (i.e., private chat with that user). -When you pass `--cd`, Takopi looks for `.codex/takopi.toml` under that directory first. - ### Codex Profile (Optional) Create a Codex profile in `~/.codex/config.toml`: @@ -75,7 +73,6 @@ uv run takopi |------|---------|-------------| | `--final-notify` / `--no-final-notify` | `--final-notify` | Send final response as new message (vs. edit) | | `--debug` / `--no-debug` | `--no-debug` | Enable verbose logging | -| `--cd PATH` | cwd | Working directory for Codex | | `--profile NAME` | (codex default) | Codex profile name | ## Usage diff --git a/src/takopi/config.py b/src/takopi/config.py index 8568fd0..45c8d27 100644 --- a/src/takopi/config.py +++ b/src/takopi/config.py @@ -46,16 +46,10 @@ def _missing_config_message(primary: Path, alternate: Path | None = None) -> str ) -def _config_candidates(base_dir: Path | None) -> list[Path]: - candidates: list[Path] = [] - if base_dir is not None: - candidates.append(base_dir / LOCAL_CONFIG_NAME) - - cwd = Path.cwd() - if base_dir is None or base_dir != cwd: - candidates.append(cwd / LOCAL_CONFIG_NAME) - - candidates.append(HOME_CONFIG_PATH) +def _config_candidates() -> list[Path]: + candidates = [Path.cwd() / LOCAL_CONFIG_NAME, HOME_CONFIG_PATH] + if candidates[0] == candidates[1]: + return [candidates[0]] return candidates @@ -72,17 +66,16 @@ def _read_config(cfg_path: Path) -> dict: raise ConfigError(f"Malformed TOML in {cfg_path}: {e}") from None -def load_telegram_config( - path: str | Path | None = None, *, base_dir: str | Path | None = None -) -> tuple[dict, Path]: +def load_telegram_config(path: str | Path | None = None) -> tuple[dict, Path]: if path: cfg_path = Path(path).expanduser() return _read_config(cfg_path), cfg_path - base = Path(base_dir).expanduser() if base_dir is not None else None - candidates = _config_candidates(base) + candidates = _config_candidates() for candidate in candidates: if candidate.is_file(): return _read_config(candidate), candidate + if len(candidates) == 1: + raise ConfigError(_missing_config_message(candidates[0])) raise ConfigError(_missing_config_message(HOME_CONFIG_PATH, candidates[0])) diff --git a/src/takopi/exec_bridge.py b/src/takopi/exec_bridge.py index 78f14dc..af35400 100644 --- a/src/takopi/exec_bridge.py +++ b/src/takopi/exec_bridge.py @@ -194,11 +194,9 @@ class CodexExecRunner: def __init__( self, codex_cmd: str, - workspace: str | None, extra_args: list[str], ) -> None: self.codex_cmd = codex_cmd - self.workspace = workspace self.extra_args = extra_args # Per-session locks to prevent concurrent resumes to the same session_id. @@ -219,14 +217,10 @@ class CodexExecRunner: session_id: str | None, on_event: EventCallback | None = None, ) -> tuple[str, str, bool]: - logger.info( - "[codex] start run session_id=%r workspace=%r", session_id, self.workspace - ) + logger.info("[codex] start run session_id=%r", session_id) logger.debug("[codex] prompt: %s", prompt) args = [self.codex_cmd] args.extend(self.extra_args) - if self.workspace: - args.extend(["--cd", self.workspace]) args.extend(["exec", "--json"]) # Always pipe prompt via stdin ("-") to avoid quoting issues. @@ -355,19 +349,11 @@ class BridgeConfig: def _parse_bridge_config( *, final_notify: bool, - cd: str | None, profile: str | None, ) -> BridgeConfig: startup_pwd = os.getcwd() - workspace = None - if cd is not None: - expanded_cd = os.path.expanduser(cd) - if not os.path.isdir(expanded_cd): - raise ConfigError(f"--cd must be an existing directory: {expanded_cd}") - workspace = expanded_cd - startup_pwd = expanded_cd - config, config_path = load_telegram_config(base_dir=workspace) + config, config_path = load_telegram_config() try: token = config["bot_token"] except KeyError: @@ -396,7 +382,7 @@ def _parse_bridge_config( extra_args.extend(["--profile", profile]) bot = TelegramClient(token) - runner = CodexExecRunner(codex_cmd=codex_cmd, workspace=workspace, extra_args=extra_args) + runner = CodexExecRunner(codex_cmd=codex_cmd, extra_args=extra_args) return BridgeConfig( bot=bot, @@ -691,11 +677,6 @@ def run( "--debug/--no-debug", help="Log codex JSONL, Telegram requests, and rendered messages.", ), - cd: str | None = typer.Option( - None, - "--cd", - help="Pass through to `codex --cd`.", - ), profile: str | None = typer.Option( None, "--profile", @@ -706,7 +687,6 @@ def run( try: cfg = _parse_bridge_config( final_notify=final_notify, - cd=cd, profile=profile, ) except ConfigError as e: diff --git a/tests/test_exec_runner.py b/tests/test_exec_runner.py index 45b6836..cfa1158 100644 --- a/tests/test_exec_runner.py +++ b/tests/test_exec_runner.py @@ -4,7 +4,7 @@ from takopi.exec_bridge import CodexExecRunner def test_run_serialized_serializes_same_session() -> None: - runner = CodexExecRunner(codex_cmd="codex", workspace=None, extra_args=[]) + runner = CodexExecRunner(codex_cmd="codex", extra_args=[]) gate = asyncio.Event() in_flight = 0 max_in_flight = 0