From c07b132f6de9ae95e6100865a553a31c84fcdad6 Mon Sep 17 00:00:00 2001 From: Zhengshou Lai Date: Tue, 7 Jul 2026 09:05:09 +0800 Subject: [PATCH] =?UTF-8?q?feat(mycodex):=20=E5=AF=B9=E9=BD=90=20resume=20?= =?UTF-8?q?options=EF=BC=8C=E6=94=AF=E6=8C=81=20-r/--resume/--continue/--l?= =?UTF-8?q?ast/--all?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 _translate_codex_extra,将 -r/--resume 映射为 codex resume - --continue 映射为 codex continue,--last/--all 映射为 resume --last/--all - 更新 help 文案与 README 用法示例 - 补充 5 个 codex resume option 单元测试,50 tests passed --- README.md | 6 ++++-- myagents/launcher.py | 30 ++++++++++++++++++++++++++++-- tests/test_cli.py | 38 ++++++++++++++++++++++++++++++++++++++ tests/test_entrypoints.py | 5 ++--- 4 files changed, 72 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 9e7f2ce..693530c 100644 --- a/README.md +++ b/README.md @@ -82,7 +82,8 @@ myagents claude -r # 恢复指定 session myagents kimi # 启动 Kimi Code CLI myagents kimi -S # 恢复 Kimi session myagents codex # 启动 OpenAI Codex CLI -myagents codex resume # 恢复 Codex session +myagents codex -r # 恢复 Codex session(映射为 resume) +myagents codex resume # 原生 resume 子命令 myagents update # 重装 myagents 并同步 workspace 链接 myagents upgrade # update 别名 myagents completion # 安装/查看/卸载 shell 补全 @@ -93,10 +94,11 @@ myclaude --cwd . -r mykimi mykimi -S mycodex +mycodex -r mycodex resume ``` -各后端原生参数会原样透传。例如 Kimi npm 版支持 `--session`、`-c`(continue)、`-y`(yolo)等,Codex 支持 `resume`、`continue`、`exec` 等子命令,直接加在命令后即可。 +各后端原生参数会原样透传。例如 Kimi npm 版支持 `--session`、`-c`(continue)、`-y`(yolo)等,Codex 支持 `resume`、`continue`、`exec` 等子命令;`mycodex` 还会将 `-r` / `--resume` 映射为 `codex resume`,与 `myclaude` 体验保持一致。 ## 配置 diff --git a/myagents/launcher.py b/myagents/launcher.py index 04e6dc3..bbe94ee 100644 --- a/myagents/launcher.py +++ b/myagents/launcher.py @@ -67,6 +67,29 @@ def _resolve_chat_cwd(cwd: str | None) -> Path: return chat_cwd +def _translate_codex_extra(extra: list[str]) -> list[str]: + """Map myagents-style resume options to native codex subcommands. + + Codex CLI uses ``resume`` / ``continue`` subcommands rather than flags. + This keeps ``mycodex`` UX consistent with ``myclaude`` / ``mykimi``. + """ + if not extra: + return extra + head = extra[0] + tail = extra[1:] + if head in ("-r", "--resume"): + if not tail: + return ["resume"] + return ["resume", tail[0], *tail[1:]] + if head == "--continue": + return ["continue", *tail] + if head == "--last": + return ["resume", "--last", *tail] + if head == "--all": + return ["resume", "--all", *tail] + return extra + + def _launch(backend: str, chat_cwd: Path, extra: list[str]) -> None: """Run backend CLI in chat_cwd, forwarding extra args. Never returns.""" config = _BACKENDS[backend] @@ -75,6 +98,9 @@ def _launch(backend: str, chat_cwd: Path, extra: list[str]) -> None: stderr_console.print(config["not_found_msg"]) raise SystemExit(127) + if backend == "codex": + extra = _translate_codex_extra(extra) + cmd = [binary, *config["default_args"], *extra] proc = subprocess.run(cmd, cwd=str(chat_cwd), check=False) raise SystemExit(proc.returncode) @@ -239,11 +265,11 @@ def _first_prompt(backend: str, session_file: Path) -> str: def _resume_syntax(backend: str) -> str: - """Return the backend's resume flag syntax for use in help text.""" + """Return the backend's resume syntax for use in help text.""" if backend == "kimi": return "--session, -S " if backend == "codex": - return "resume " + return "-r, --resume or resume " return "--resume, -r " diff --git a/tests/test_cli.py b/tests/test_cli.py index 39dc2a7..8f60257 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -301,6 +301,44 @@ class TestCodexPassthrough: assert cmd == ["/usr/bin/codex", "continue"] +class TestCodexResumeOptions: + """Map myagents-style resume flags to codex resume subcommand.""" + + def _invoke(self, args: list[str], tmp_path: Path) -> list[str]: + runner = CliRunner() + with ( + patch("myagents.launcher.shutil.which", return_value="/usr/bin/codex"), + patch("myagents.launcher.subprocess.run") as mock_run, + ): + mock_run.return_value = MagicMock(returncode=0) + result = runner.invoke( + cli, ["codex", "--cwd", str(tmp_path), *args] + ) + assert result.exit_code == 0, result.output + mock_run.assert_called_once() + return mock_run.call_args[0][0] + + def test_r_flag_maps_to_resume(self, tmp_path: Path) -> None: + cmd = self._invoke(["-r", "abc123"], tmp_path) + assert cmd == ["/usr/bin/codex", "resume", "abc123"] + + def test_resume_flag_maps_to_resume(self, tmp_path: Path) -> None: + cmd = self._invoke(["--resume", "abc123"], tmp_path) + assert cmd == ["/usr/bin/codex", "resume", "abc123"] + + def test_continue_flag_maps_to_continue(self, tmp_path: Path) -> None: + cmd = self._invoke(["--continue"], tmp_path) + assert cmd == ["/usr/bin/codex", "continue"] + + def test_last_flag_maps_to_resume_last(self, tmp_path: Path) -> None: + cmd = self._invoke(["--last"], tmp_path) + assert cmd == ["/usr/bin/codex", "resume", "--last"] + + def test_all_flag_maps_to_resume_all(self, tmp_path: Path) -> None: + cmd = self._invoke(["--all"], tmp_path) + assert cmd == ["/usr/bin/codex", "resume", "--all"] + + class TestCodexListSessions: """``myagents codex --list`` reports resumable sessions.""" diff --git a/tests/test_entrypoints.py b/tests/test_entrypoints.py index 8b6a4ad..509d3d8 100644 --- a/tests/test_entrypoints.py +++ b/tests/test_entrypoints.py @@ -102,7 +102,6 @@ class TestMycodexEntrypoint: patch("myagents.launcher.subprocess.run") as mock_run, ): mock_run.return_value = MagicMock(returncode=0) - result = runner.invoke(codex_cli, ["--cwd", str(tmp_path), "resume", "abc123"]) + result = runner.invoke(codex_cli, ["--cwd", str(tmp_path), "-r", "abc123"]) assert result.exit_code == 0 - assert "resume" in mock_run.call_args[0][0] - assert "abc123" in mock_run.call_args[0][0] + assert mock_run.call_args[0][0] == ["/usr/bin/codex", "resume", "abc123"]