refactor(hermes_cli): setup cluster — compact send arg table, quick-setup label builders, first-time mode table by name

This commit is contained in:
Teknium
2026-09-02 22:21:47 -07:00
parent 8ec7d0bfc5
commit 17d20ae1e5
4 changed files with 27 additions and 52 deletions
+3 -9
View File
@@ -59,9 +59,7 @@ def __getattr__(name: str):
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
# ---------------------------------------------------------------------------
# Argparse wiring — called from hermes_cli.main
# ---------------------------------------------------------------------------
# ── Argparse wiring — called from hermes_cli.main ──
def register_cli(parent_parser: argparse.ArgumentParser) -> None:
@@ -92,9 +90,7 @@ def register_cli(parent_parser: argparse.ArgumentParser) -> None:
))
# ---------------------------------------------------------------------------
# Handlers
# ---------------------------------------------------------------------------
# ── Handlers ──
def _step(console: Console, n: int, title: str) -> None:
@@ -422,9 +418,7 @@ def cmd_install(args: argparse.Namespace) -> int:
return 1
# ---------------------------------------------------------------------------
# Helpers
# ---------------------------------------------------------------------------
# ── Helpers ──
def _token_validation_status(
+13 -28
View File
@@ -128,18 +128,15 @@ def _list_targets(platform_filter: Optional[str], *, json_mode: bool) -> int:
return _SUCCESS_EXIT
for plat_name in sorted(platforms):
channels = platforms[plat_name]
print(f"{plat_name}:")
if not channels:
if not platforms[plat_name]:
print(" (no channels discovered yet)")
continue
for ch in channels:
for ch in platforms[plat_name]:
name = ch.get("name", "?")
chat_id = ch.get("id") or ch.get("chat_id") or ""
suffix = f" [{chat_id}]" if chat_id and chat_id != name else ""
print(f" {plat_name}:{name}{suffix}")
print(f" {plat_name}:{name}" + (f" [{chat_id}]" if chat_id and chat_id != name else ""))
print()
return _SUCCESS_EXIT
@@ -253,30 +250,18 @@ def cmd_send(args: argparse.Namespace) -> None:
# (flags, add_argument kwargs) in --help order.
_SEND_ARGUMENTS = (
(("-t", "--to"), dict(
metavar="TARGET",
default=None,
help=(
"Delivery target. Format: 'platform' (home channel), "
"'platform:chat_id', 'platform:chat_id:thread_id', or "
"'platform:#channel-name'. Examples: telegram, "
"telegram:-1001234567890:17585, discord:#ops, slack:C0123ABCD, signal:+15551234567."
),
)),
(("-t", "--to"), dict(metavar="TARGET", default=None, help=(
"Delivery target. Format: 'platform' (home channel), "
"'platform:chat_id', 'platform:chat_id:thread_id', or "
"'platform:#channel-name'. Examples: telegram, "
"telegram:-1001234567890:17585, discord:#ops, slack:C0123ABCD, signal:+15551234567."))),
(("message",), dict(nargs="?", default=None, help="Message text. If omitted, read from --file or stdin.")),
(("-f", "--file"), dict(
metavar="PATH",
default=None,
help=(
"Read message body from PATH (text only). Use '-' to force stdin. "
"To send an image/document as an attachment, use MEDIA:<path> in the message text instead."
),
)),
(("-f", "--file"), dict(metavar="PATH", default=None, help=(
"Read message body from PATH (text only). Use '-' to force stdin. "
"To send an image/document as an attachment, use MEDIA:<path> in the message text instead."))),
(("-s", "--subject"), dict(metavar="LINE", default=None, help="Prepend a subject/header line before the message body.")),
(("-l", "--list"), dict(
dest="list_targets", action="store_true", default=False,
help="List available targets. Optional positional filter: `hermes send --list telegram`.",
)),
(("-l", "--list"), dict(dest="list_targets", action="store_true", default=False,
help="List available targets. Optional positional filter: `hermes send --list telegram`.")),
(("-q", "--quiet"), dict(action="store_true", default=False, help="Suppress stdout on success (exit code only).")),
(("--json",), dict(action="store_true", default=False, help="Emit raw JSON result instead of human-readable output.")),
)
+5 -5
View File
@@ -718,13 +718,13 @@ def _run_full_setup(config: dict, hermes_home, *, is_existing: bool, migration_r
_step("tools", "Tools", lambda: setup_tools(config, first_install=not is_existing))])
# First-time mode picker: (menu label, runner) — a None runner falls through to Full Setup.
# First-time mode picker: (menu label, runner name on this module) — None falls through to Full
# Setup; runners resolve at call time so test patches on hermes_cli.setup apply.
_FIRST_TIME_MODES = (
("Quick Setup (Nous Portal) — free OAuth login, no API keys, model + tools (recommended)",
lambda *a: _run_first_time_quick_setup(*a)),
"_run_first_time_quick_setup"),
("Full setup — configure every provider, tool & option yourself (bring your own keys)", None),
("Blank Slate — everything off except the bare minimum; opt in to each capability",
lambda *a: _run_blank_slate_setup(*a)),
("Blank Slate — everything off except the bare minimum; opt in to each capability", "_run_blank_slate_setup"),
)
@@ -794,7 +794,7 @@ def _run_setup_wizard_impl(args):
setup_mode = prompt_choice("How would you like to set up Hermes?", [label for label, _ in _FIRST_TIME_MODES], 0)
label, runner = _FIRST_TIME_MODES[setup_mode]
if runner is not None:
_run_setup_steps([(label, lambda: runner(config, hermes_home, is_existing))])
_run_setup_steps([(label, lambda: globals()[runner](config, hermes_home, is_existing))])
return
_run_full_setup(config, hermes_home, is_existing=is_existing, migration_ran=migration_ran)
+6 -10
View File
@@ -371,11 +371,8 @@ def _run_quick_setup(config: dict, hermes_home):
if missing_tools: # checklist, then the API-key screen for each pick
print_header("Tool API Keys", gap=True)
labels = []
for var in missing_tools:
tools = var.get("tools", [])
tools_str = f" → {', '.join(tools[:2])}" if tools else ""
labels.append(f"{var.get('description', var['name'])}{tools_str}")
labels = [var.get("description", var["name"]) + (f" → {', '.join(var['tools'][:2])}" if var.get("tools") else "")
for var in missing_tools]
for idx in prompt_checklist("Which tools would you like to configure?", labels):
_prompt_api_key(missing_tools[idx])
@@ -387,11 +384,10 @@ def _run_quick_setup(config: dict, hermes_home):
grouped: dict[str, list] = {}
emojis = {}
for var in missing_messaging:
for needle, plat, emoji in _MESSAGING_PLATFORMS:
if needle in var["name"]:
grouped.setdefault(plat, []).append(var)
emojis[plat] = emoji
break
match = next(((plat, emoji) for needle, plat, emoji in _MESSAGING_PLATFORMS if needle in var["name"]), None)
if match:
grouped.setdefault(match[0], []).append(var)
emojis[match[0]] = match[1]
platform_order = list(grouped)
labels = [f"{emojis[p]} {p}" for p in platform_order]
for idx in prompt_checklist("Which platforms would you like to set up?", labels):