refactor(hermes_cli): setup cluster — compact send arg table, quick-setup label builders, first-time mode table by name
This commit is contained in:
@@ -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
@@ -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
@@ -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)
|
||||
|
||||
@@ -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):
|
||||
|
||||
Reference in New Issue
Block a user