fix(hermes): align myhermes resume flags with myclaude UX

Hermes -r/--resume requires a session id and has no -c shorthand, so
bare 'myhermes -r' failed with an argparse error. Translate
myagents-style flags like the codex backend:

- bare -r/--resume -> 'hermes sessions browse' (interactive picker)
- -r/--resume <id> -> '--resume <id> --no-restore-cwd'
- -c/--continue/--last -> '--continue --no-restore-cwd'

--no-restore-cwd keeps resumed sessions in the launch cwd, matching
myclaude semantics instead of jumping to the session's original cwd.
This commit is contained in:
Zhengshou Lai
2026-07-15 10:34:01 +08:00
parent 78ca74152f
commit 20e22eafd4
3 changed files with 82 additions and 4 deletions
+28 -1
View File
@@ -103,6 +103,28 @@ def _translate_codex_extra(extra: list[str]) -> list[str]:
return extra
def _translate_hermes_extra(extra: list[str]) -> list[str]:
"""Map myagents-style resume options to native hermes syntax.
Hermes ``-r``/``--resume`` requires a session id (no bare picker), has no
``-c`` shorthand, and restores the session's original cwd by default.
This keeps ``myhermes`` UX consistent with ``myclaude``: bare ``-r``
opens the interactive picker, ``-c`` continues the latest session, and
resumed sessions stay in the launch cwd.
"""
if not extra:
return extra
head = extra[0]
tail = extra[1:]
if head in ("-r", "--resume"):
if not tail or tail[0].startswith("-"):
return ["sessions", "browse", *tail]
return ["--resume", tail[0], "--no-restore-cwd", *tail[1:]]
if head in ("-c", "--continue", "--last"):
return ["--continue", *tail, "--no-restore-cwd"]
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]
@@ -113,6 +135,8 @@ def _launch(backend: str, chat_cwd: Path, extra: list[str]) -> None:
if backend == "codex":
extra = _translate_codex_extra(extra)
elif backend == "hermes":
extra = _translate_hermes_extra(extra)
cmd = [binary, *config["default_args"], *extra]
proc = subprocess.run(cmd, cwd=str(chat_cwd), check=False)
@@ -283,6 +307,8 @@ def _resume_syntax(backend: str) -> str:
return "--session, -S <id>"
if backend == "codex":
return "-r, --resume <id> or resume <id>"
if backend == "hermes":
return "-r, --resume <id> (bare -r opens the session picker)"
return "--resume, -r <id>"
@@ -335,7 +361,8 @@ def _list_sessions_hermes(chat_cwd: Path) -> None:
f"[dim]{mtime:%Y-%m-%d %H:%M}[/dim] {snippet or '[dim](empty)[/dim]'}"
)
console.print(
"\n[dim]Resume with[/dim] [green]hermes --resume <id>[/green]"
"\n[dim]Resume with[/dim] [green]myhermes -r <id>[/green] "
"[dim](bare myhermes -r opens the picker)[/dim]"
)
+49 -2
View File
@@ -473,11 +473,58 @@ class TestHermesPassthrough:
def test_resume_with_session_id(self, tmp_path: Path) -> None:
cmd = self._invoke(["--resume", "abc123"], tmp_path)
assert cmd == ["/usr/bin/hermes", "--yolo", "--resume", "abc123"]
assert cmd == [
"/usr/bin/hermes",
"--yolo",
"--resume",
"abc123",
"--no-restore-cwd",
]
def test_bare_r_flag_opens_session_picker(self, tmp_path: Path) -> None:
cmd = self._invoke(["-r"], tmp_path)
assert cmd == ["/usr/bin/hermes", "--yolo", "sessions", "browse"]
def test_bare_resume_flag_opens_session_picker(self, tmp_path: Path) -> None:
cmd = self._invoke(["--resume"], tmp_path)
assert cmd == ["/usr/bin/hermes", "--yolo", "sessions", "browse"]
def test_r_flag_with_session_id(self, tmp_path: Path) -> None:
cmd = self._invoke(["-r", "abc123"], tmp_path)
assert cmd == [
"/usr/bin/hermes",
"--yolo",
"--resume",
"abc123",
"--no-restore-cwd",
]
def test_c_flag_maps_to_continue(self, tmp_path: Path) -> None:
cmd = self._invoke(["-c"], tmp_path)
assert cmd == [
"/usr/bin/hermes",
"--yolo",
"--continue",
"--no-restore-cwd",
]
def test_continue_flag_passes_through(self, tmp_path: Path) -> None:
cmd = self._invoke(["--continue"], tmp_path)
assert cmd[-1] == "--continue"
assert cmd == [
"/usr/bin/hermes",
"--yolo",
"--continue",
"--no-restore-cwd",
]
def test_last_flag_maps_to_continue(self, tmp_path: Path) -> None:
cmd = self._invoke(["--last"], tmp_path)
assert cmd == [
"/usr/bin/hermes",
"--yolo",
"--continue",
"--no-restore-cwd",
]
class TestHermesListSessions:
+5 -1
View File
@@ -138,4 +138,8 @@ class TestMyhermesEntrypoint:
hermes_cli, ["--cwd", str(tmp_path), "--resume", "abc123"]
)
assert result.exit_code == 0
assert mock_run.call_args[0][0][-2:] == ["--resume", "abc123"]
assert mock_run.call_args[0][0][-3:] == [
"--resume",
"abc123",
"--no-restore-cwd",
]