mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-06-09 08:21:50 +00:00
Phase 2 of the god-file decomposition plan. main()'s argparse tree is 179 inline add_parser calls in one 3,297-line function. This establishes the hermes_cli/subcommands/ package and extracts the first group (cron) as the proof-of-pattern: - hermes_cli/subcommands/_shared.py: shared parser helpers (add_accept_hooks_flag), re-exported from main.py for backwards compat. - hermes_cli/subcommands/cron.py: build_cron_parser(subparsers, cmd_cron=...). Handler injected so the module never imports main (cycle avoidance). - main()'s ~155-line inline cron block becomes one build_cron_parser() call. Behavior-neutral: 'hermes cron create --help' output is byte-identical to origin/main. main() 3297 -> 3143 LOC. Validation: tests/hermes_cli/ 6466 passed / 0 failed under per-file process isolation; new test_subcommands_cron.py covers subactions, aliases, options, no-agent tristate, injected dispatch, and --accept-hooks.
86 lines
2.9 KiB
Python
86 lines
2.9 KiB
Python
"""Unit tests for the extracted ``hermes cron`` parser builder.
|
|
|
|
Confirms ``build_cron_parser`` wires up the same subactions, aliases, options,
|
|
and ``func=cmd_cron`` dispatch that lived inline in ``main()`` before the
|
|
god-file Phase 2 extraction.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
|
|
from hermes_cli.subcommands.cron import build_cron_parser
|
|
|
|
|
|
def _sentinel_handler(args): # pragma: no cover - only identity is asserted
|
|
return "cron-handler"
|
|
|
|
|
|
def _build():
|
|
parser = argparse.ArgumentParser(prog="hermes")
|
|
subparsers = parser.add_subparsers(dest="command")
|
|
build_cron_parser(subparsers, cmd_cron=_sentinel_handler)
|
|
return parser
|
|
|
|
|
|
def test_cron_subactions_present():
|
|
parser = _build()
|
|
for action in ("list", "create", "edit", "pause", "resume", "run", "remove", "status", "tick"):
|
|
ns = parser.parse_args(["cron", action] if action in ("list", "status", "tick")
|
|
else ["cron", action, "jobid"] if action in ("pause", "resume", "run", "remove", "edit")
|
|
else ["cron", "create", "30m"])
|
|
assert ns.command == "cron"
|
|
assert ns.cron_command == action
|
|
|
|
|
|
def test_cron_aliases():
|
|
parser = _build()
|
|
# create has alias "add"
|
|
ns = parser.parse_args(["cron", "add", "30m"])
|
|
assert ns.cron_command == "add"
|
|
# remove has aliases rm / delete
|
|
for alias in ("rm", "delete"):
|
|
ns = parser.parse_args(["cron", alias, "jid"])
|
|
assert ns.cron_command == alias
|
|
|
|
|
|
def test_cron_create_options():
|
|
parser = _build()
|
|
ns = parser.parse_args([
|
|
"cron", "create", "0 9 * * *", "do the thing",
|
|
"--name", "daily", "--deliver", "origin", "--repeat", "3",
|
|
"--skill", "a", "--skill", "b", "--no-agent",
|
|
"--workdir", "/tmp/x", "--profile", "work",
|
|
])
|
|
assert ns.schedule == "0 9 * * *"
|
|
assert ns.prompt == "do the thing"
|
|
assert ns.name == "daily"
|
|
assert ns.deliver == "origin"
|
|
assert ns.repeat == 3
|
|
assert ns.skills == ["a", "b"]
|
|
assert ns.no_agent is True
|
|
assert ns.workdir == "/tmp/x"
|
|
assert ns.profile == "work"
|
|
|
|
|
|
def test_cron_edit_no_agent_tristate():
|
|
parser = _build()
|
|
# --no-agent -> True, --agent -> False, neither -> None
|
|
assert parser.parse_args(["cron", "edit", "j", "--no-agent"]).no_agent is True
|
|
assert parser.parse_args(["cron", "edit", "j", "--agent"]).no_agent is False
|
|
assert parser.parse_args(["cron", "edit", "j"]).no_agent is None
|
|
|
|
|
|
def test_cron_dispatch_func_is_injected_handler():
|
|
parser = _build()
|
|
ns = parser.parse_args(["cron", "list"])
|
|
assert ns.func is _sentinel_handler
|
|
|
|
|
|
def test_cron_accept_hooks_flag_on_run_and_tick():
|
|
parser = _build()
|
|
# --accept-hooks is suppressed-default; present only when passed.
|
|
ns = parser.parse_args(["cron", "run", "jid", "--accept-hooks"])
|
|
assert ns.accept_hooks is True
|
|
ns2 = parser.parse_args(["cron", "tick", "--accept-hooks"])
|
|
assert ns2.accept_hooks is True
|