Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 13 additions & 2 deletions hermes_cli/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,11 @@ def _is_gateway_available(cmd: CommandDef, config_overrides: set[str] | None = N
return False


def _requires_argument(args_hint: str) -> bool:
"""Return True when selecting a command without text would be incomplete."""
return args_hint.strip().startswith("<")


def gateway_help_lines() -> list[str]:
"""Generate gateway help text lines from the registry."""
overrides = _resolve_config_gates()
Expand Down Expand Up @@ -455,7 +460,9 @@ def telegram_bot_commands() -> list[tuple[str, str]]:

Telegram command names cannot contain hyphens, so they are replaced with
underscores. Aliases are skipped -- Telegram shows one menu entry per
canonical command.
canonical command. Commands that require arguments are skipped because
selecting a Telegram BotCommand sends only ``/command`` and would execute
an incomplete command.

Plugin-registered slash commands are included so plugins get native
autocomplete in Telegram without touching core code.
Expand All @@ -465,10 +472,14 @@ def telegram_bot_commands() -> list[tuple[str, str]]:
for cmd in COMMAND_REGISTRY:
if not _is_gateway_available(cmd, overrides):
continue
if _requires_argument(cmd.args_hint):
continue
tg_name = _sanitize_telegram_name(cmd.name)
if tg_name:
result.append((tg_name, cmd.description))
for name, description, _args_hint in _iter_plugin_command_entries():
for name, description, args_hint in _iter_plugin_command_entries():
if _requires_argument(args_hint):
continue
tg_name = _sanitize_telegram_name(name)
if tg_name:
result.append((tg_name, description))
Expand Down
1 change: 1 addition & 0 deletions scripts/release.py
Original file line number Diff line number Diff line change
Expand Up @@ -623,6 +623,7 @@
"cine.dreamer.one@gmail.com": "LeonSGP43",
"zyprothh@gmail.com": "Zyproth",
"amitgaur@gmail.com": "amitgaur",
"albuquerque.abner@gmail.com": "mrbob-git",
"leozeli@qq.com": "leozeli",
"linlehao@cuhk.edu.cn": "LehaoLin",
"liutong@isacas.ac.cn": "I3eg1nner",
Expand Down
20 changes: 20 additions & 0 deletions tests/hermes_cli/test_commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,13 @@ def test_excludes_cli_only_without_config_gate(self):
tg_name = cmd.name.replace("-", "_")
assert tg_name not in names

def test_excludes_commands_with_required_args(self):
names = {name for name, _ in telegram_bot_commands()}
assert "background" not in names
assert "queue" not in names
assert "steer" not in names
assert "background" in GATEWAY_KNOWN_COMMANDS


class TestSlackSubcommandMap:
def test_returns_dict(self):
Expand Down Expand Up @@ -1661,6 +1668,19 @@ def test_plugin_command_appears_in_telegram_menu(self, monkeypatch):
names = {name for name, _desc in telegram_bot_commands()}
assert "metricas" in names

def test_plugin_command_with_required_args_excluded_from_telegram_menu(self, monkeypatch):
"""Telegram BotCommand selections cannot supply required arguments."""
self._patch_plugin_commands(monkeypatch, {
"background-job": {
"handler": lambda _a: "ok",
"description": "Run a background job",
"args_hint": "<prompt>",
"plugin": "jobs-plugin",
}
})
names = {name for name, _desc in telegram_bot_commands()}
assert "background_job" not in names

def test_plugin_command_appears_in_slack_subcommand_map(self, monkeypatch):
"""/hermes metricas must route through the Slack subcommand map."""
self._patch_plugin_commands(monkeypatch, {
Expand Down
Loading