feat(cli): add dynamic shell completion for bash, zsh, and fish
Replaces the hardcoded completion stubs in profiles.py with a dynamic
generator that walks the live argparse parser tree at runtime.
- New hermes_cli/completion.py: _walk() recursively extracts all
subcommands and flags; generate_bash/zsh/fish() produce complete
scripts with nested subcommand support
- cmd_completion now accepts the parser via closure so completions
always reflect the actual registered commands (including plugin-
registered ones like honcho)
- completion subcommand now accepts bash | zsh | fish (fish requested
in issue comments)
- Fix _SUBCOMMANDS set: add honcho, claw, plugins, acp, webhook,
memory, dump, debug, backup, import, completion, logs so that
multi-word session names after -c/-r are not broken by these commands
- Add tests/hermes_cli/test_completion.py: 17 tests covering parser
extraction, alias deduplication, bash/zsh/fish output content,
bash syntax validation, fish syntax validation, and subcommand
drift prevention
Tested on Linux (Arch). bash and fish completion verified live.
zsh script passes syntax check (zsh not installed on test machine).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-14 11:33:46 +08:00
|
|
|
"""Shell completion script generation for hermes CLI.
|
|
|
|
|
|
|
|
|
|
Walks the live argparse parser tree to generate accurate, always-up-to-date
|
|
|
|
|
completion scripts — no hardcoded subcommand lists, no extra dependencies.
|
|
|
|
|
|
|
|
|
|
Supports bash, zsh, and fish.
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
from __future__ import annotations
|
|
|
|
|
|
|
|
|
|
import argparse
|
|
|
|
|
from typing import Any
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _walk(parser: argparse.ArgumentParser) -> dict[str, Any]:
|
|
|
|
|
"""Recursively extract subcommands and flags from a parser.
|
|
|
|
|
|
|
|
|
|
Uses _SubParsersAction._choices_actions to get canonical names (no aliases)
|
|
|
|
|
along with their help text.
|
|
|
|
|
"""
|
|
|
|
|
flags: list[str] = []
|
|
|
|
|
subcommands: dict[str, Any] = {}
|
|
|
|
|
|
|
|
|
|
for action in parser._actions:
|
|
|
|
|
if isinstance(action, argparse._SubParsersAction):
|
|
|
|
|
# _choices_actions has one entry per canonical name; aliases are
|
|
|
|
|
# omitted, which keeps completion lists clean.
|
|
|
|
|
seen: set[str] = set()
|
|
|
|
|
for pseudo in action._choices_actions:
|
|
|
|
|
name = pseudo.dest
|
|
|
|
|
if name in seen:
|
|
|
|
|
continue
|
|
|
|
|
seen.add(name)
|
|
|
|
|
subparser = action.choices.get(name)
|
|
|
|
|
if subparser is None:
|
|
|
|
|
continue
|
|
|
|
|
info = _walk(subparser)
|
|
|
|
|
info["help"] = _clean(pseudo.help or "")
|
|
|
|
|
subcommands[name] = info
|
|
|
|
|
elif action.option_strings:
|
|
|
|
|
flags.extend(o for o in action.option_strings if o.startswith("-"))
|
|
|
|
|
|
|
|
|
|
return {"flags": flags, "subcommands": subcommands}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _clean(text: str, maxlen: int = 60) -> str:
|
|
|
|
|
"""Strip shell-unsafe characters and truncate."""
|
|
|
|
|
return text.replace("'", "").replace('"', "").replace("\\", "")[:maxlen]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
# Bash
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
def generate_bash(parser: argparse.ArgumentParser) -> str:
|
|
|
|
|
tree = _walk(parser)
|
|
|
|
|
top_cmds = " ".join(sorted(tree["subcommands"]))
|
|
|
|
|
|
|
|
|
|
cases: list[str] = []
|
|
|
|
|
for cmd in sorted(tree["subcommands"]):
|
|
|
|
|
info = tree["subcommands"][cmd]
|
2026-04-14 10:30:43 -07:00
|
|
|
if cmd == "profile" and info["subcommands"]:
|
|
|
|
|
# Profile subcommand: complete actions, then profile names for
|
|
|
|
|
# actions that accept a profile argument.
|
|
|
|
|
subcmds = " ".join(sorted(info["subcommands"]))
|
|
|
|
|
profile_actions = "use delete show alias rename export"
|
|
|
|
|
cases.append(
|
|
|
|
|
f" profile)\n"
|
|
|
|
|
f" case \"$prev\" in\n"
|
|
|
|
|
f" profile)\n"
|
|
|
|
|
f" COMPREPLY=($(compgen -W \"{subcmds}\" -- \"$cur\"))\n"
|
|
|
|
|
f" return\n"
|
|
|
|
|
f" ;;\n"
|
|
|
|
|
f" {profile_actions.replace(' ', '|')})\n"
|
|
|
|
|
f" COMPREPLY=($(compgen -W \"$(_hermes_profiles)\" -- \"$cur\"))\n"
|
|
|
|
|
f" return\n"
|
|
|
|
|
f" ;;\n"
|
|
|
|
|
f" esac\n"
|
|
|
|
|
f" ;;"
|
|
|
|
|
)
|
|
|
|
|
elif info["subcommands"]:
|
feat(cli): add dynamic shell completion for bash, zsh, and fish
Replaces the hardcoded completion stubs in profiles.py with a dynamic
generator that walks the live argparse parser tree at runtime.
- New hermes_cli/completion.py: _walk() recursively extracts all
subcommands and flags; generate_bash/zsh/fish() produce complete
scripts with nested subcommand support
- cmd_completion now accepts the parser via closure so completions
always reflect the actual registered commands (including plugin-
registered ones like honcho)
- completion subcommand now accepts bash | zsh | fish (fish requested
in issue comments)
- Fix _SUBCOMMANDS set: add honcho, claw, plugins, acp, webhook,
memory, dump, debug, backup, import, completion, logs so that
multi-word session names after -c/-r are not broken by these commands
- Add tests/hermes_cli/test_completion.py: 17 tests covering parser
extraction, alias deduplication, bash/zsh/fish output content,
bash syntax validation, fish syntax validation, and subcommand
drift prevention
Tested on Linux (Arch). bash and fish completion verified live.
zsh script passes syntax check (zsh not installed on test machine).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-14 11:33:46 +08:00
|
|
|
subcmds = " ".join(sorted(info["subcommands"]))
|
|
|
|
|
cases.append(
|
|
|
|
|
f" {cmd})\n"
|
|
|
|
|
f" COMPREPLY=($(compgen -W \"{subcmds}\" -- \"$cur\"))\n"
|
|
|
|
|
f" return\n"
|
|
|
|
|
f" ;;"
|
|
|
|
|
)
|
|
|
|
|
elif info["flags"]:
|
|
|
|
|
flags = " ".join(info["flags"])
|
|
|
|
|
cases.append(
|
|
|
|
|
f" {cmd})\n"
|
|
|
|
|
f" COMPREPLY=($(compgen -W \"{flags}\" -- \"$cur\"))\n"
|
|
|
|
|
f" return\n"
|
|
|
|
|
f" ;;"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
cases_str = "\n".join(cases)
|
|
|
|
|
|
|
|
|
|
return f"""# Hermes Agent bash completion
|
|
|
|
|
# Add to ~/.bashrc:
|
|
|
|
|
# eval "$(hermes completion bash)"
|
|
|
|
|
|
2026-04-14 10:30:43 -07:00
|
|
|
_hermes_profiles() {{
|
|
|
|
|
local profiles_dir="$HOME/.hermes/profiles"
|
|
|
|
|
local profiles="default"
|
|
|
|
|
if [ -d "$profiles_dir" ]; then
|
|
|
|
|
profiles="$profiles $(ls "$profiles_dir" 2>/dev/null)"
|
|
|
|
|
fi
|
|
|
|
|
echo "$profiles"
|
|
|
|
|
}}
|
|
|
|
|
|
feat(cli): add dynamic shell completion for bash, zsh, and fish
Replaces the hardcoded completion stubs in profiles.py with a dynamic
generator that walks the live argparse parser tree at runtime.
- New hermes_cli/completion.py: _walk() recursively extracts all
subcommands and flags; generate_bash/zsh/fish() produce complete
scripts with nested subcommand support
- cmd_completion now accepts the parser via closure so completions
always reflect the actual registered commands (including plugin-
registered ones like honcho)
- completion subcommand now accepts bash | zsh | fish (fish requested
in issue comments)
- Fix _SUBCOMMANDS set: add honcho, claw, plugins, acp, webhook,
memory, dump, debug, backup, import, completion, logs so that
multi-word session names after -c/-r are not broken by these commands
- Add tests/hermes_cli/test_completion.py: 17 tests covering parser
extraction, alias deduplication, bash/zsh/fish output content,
bash syntax validation, fish syntax validation, and subcommand
drift prevention
Tested on Linux (Arch). bash and fish completion verified live.
zsh script passes syntax check (zsh not installed on test machine).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-14 11:33:46 +08:00
|
|
|
_hermes_completion() {{
|
|
|
|
|
local cur prev
|
|
|
|
|
COMPREPLY=()
|
|
|
|
|
cur="${{COMP_WORDS[COMP_CWORD]}}"
|
|
|
|
|
prev="${{COMP_WORDS[COMP_CWORD-1]}}"
|
|
|
|
|
|
2026-04-14 10:30:43 -07:00
|
|
|
# Complete profile names after -p / --profile
|
|
|
|
|
if [[ "$prev" == "-p" || "$prev" == "--profile" ]]; then
|
|
|
|
|
COMPREPLY=($(compgen -W "$(_hermes_profiles)" -- "$cur"))
|
|
|
|
|
return
|
|
|
|
|
fi
|
|
|
|
|
|
feat(cli): add dynamic shell completion for bash, zsh, and fish
Replaces the hardcoded completion stubs in profiles.py with a dynamic
generator that walks the live argparse parser tree at runtime.
- New hermes_cli/completion.py: _walk() recursively extracts all
subcommands and flags; generate_bash/zsh/fish() produce complete
scripts with nested subcommand support
- cmd_completion now accepts the parser via closure so completions
always reflect the actual registered commands (including plugin-
registered ones like honcho)
- completion subcommand now accepts bash | zsh | fish (fish requested
in issue comments)
- Fix _SUBCOMMANDS set: add honcho, claw, plugins, acp, webhook,
memory, dump, debug, backup, import, completion, logs so that
multi-word session names after -c/-r are not broken by these commands
- Add tests/hermes_cli/test_completion.py: 17 tests covering parser
extraction, alias deduplication, bash/zsh/fish output content,
bash syntax validation, fish syntax validation, and subcommand
drift prevention
Tested on Linux (Arch). bash and fish completion verified live.
zsh script passes syntax check (zsh not installed on test machine).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-14 11:33:46 +08:00
|
|
|
if [[ $COMP_CWORD -ge 2 ]]; then
|
|
|
|
|
case "${{COMP_WORDS[1]}}" in
|
|
|
|
|
{cases_str}
|
|
|
|
|
esac
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
if [[ $COMP_CWORD -eq 1 ]]; then
|
|
|
|
|
COMPREPLY=($(compgen -W "{top_cmds}" -- "$cur"))
|
|
|
|
|
fi
|
|
|
|
|
}}
|
|
|
|
|
|
|
|
|
|
complete -F _hermes_completion hermes
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
# Zsh
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
def generate_zsh(parser: argparse.ArgumentParser) -> str:
|
|
|
|
|
tree = _walk(parser)
|
|
|
|
|
|
|
|
|
|
top_cmds_lines: list[str] = []
|
|
|
|
|
for cmd in sorted(tree["subcommands"]):
|
|
|
|
|
help_text = _clean(tree["subcommands"][cmd].get("help", ""))
|
|
|
|
|
top_cmds_lines.append(f" '{cmd}:{help_text}'")
|
|
|
|
|
top_cmds_str = "\n".join(top_cmds_lines)
|
|
|
|
|
|
|
|
|
|
sub_cases: list[str] = []
|
|
|
|
|
for cmd in sorted(tree["subcommands"]):
|
|
|
|
|
info = tree["subcommands"][cmd]
|
|
|
|
|
if not info["subcommands"]:
|
|
|
|
|
continue
|
2026-04-14 10:30:43 -07:00
|
|
|
if cmd == "profile":
|
|
|
|
|
# Profile subcommand: complete actions, then profile names for
|
|
|
|
|
# actions that accept a profile argument.
|
|
|
|
|
sub_lines: list[str] = []
|
|
|
|
|
for sc in sorted(info["subcommands"]):
|
|
|
|
|
sh = _clean(info["subcommands"][sc].get("help", ""))
|
|
|
|
|
sub_lines.append(f" '{sc}:{sh}'")
|
|
|
|
|
sub_str = "\n".join(sub_lines)
|
|
|
|
|
sub_cases.append(
|
|
|
|
|
f" profile)\n"
|
|
|
|
|
f" case ${{line[2]}} in\n"
|
|
|
|
|
f" use|delete|show|alias|rename|export)\n"
|
|
|
|
|
f" _hermes_profiles\n"
|
|
|
|
|
f" ;;\n"
|
|
|
|
|
f" *)\n"
|
|
|
|
|
f" local -a profile_cmds\n"
|
|
|
|
|
f" profile_cmds=(\n"
|
|
|
|
|
f"{sub_str}\n"
|
|
|
|
|
f" )\n"
|
|
|
|
|
f" _describe 'profile command' profile_cmds\n"
|
|
|
|
|
f" ;;\n"
|
|
|
|
|
f" esac\n"
|
|
|
|
|
f" ;;"
|
|
|
|
|
)
|
|
|
|
|
else:
|
|
|
|
|
sub_lines = []
|
|
|
|
|
for sc in sorted(info["subcommands"]):
|
|
|
|
|
sh = _clean(info["subcommands"][sc].get("help", ""))
|
|
|
|
|
sub_lines.append(f" '{sc}:{sh}'")
|
|
|
|
|
sub_str = "\n".join(sub_lines)
|
|
|
|
|
safe = cmd.replace("-", "_")
|
|
|
|
|
sub_cases.append(
|
|
|
|
|
f" {cmd})\n"
|
|
|
|
|
f" local -a {safe}_cmds\n"
|
|
|
|
|
f" {safe}_cmds=(\n"
|
|
|
|
|
f"{sub_str}\n"
|
|
|
|
|
f" )\n"
|
|
|
|
|
f" _describe '{cmd} command' {safe}_cmds\n"
|
|
|
|
|
f" ;;"
|
|
|
|
|
)
|
feat(cli): add dynamic shell completion for bash, zsh, and fish
Replaces the hardcoded completion stubs in profiles.py with a dynamic
generator that walks the live argparse parser tree at runtime.
- New hermes_cli/completion.py: _walk() recursively extracts all
subcommands and flags; generate_bash/zsh/fish() produce complete
scripts with nested subcommand support
- cmd_completion now accepts the parser via closure so completions
always reflect the actual registered commands (including plugin-
registered ones like honcho)
- completion subcommand now accepts bash | zsh | fish (fish requested
in issue comments)
- Fix _SUBCOMMANDS set: add honcho, claw, plugins, acp, webhook,
memory, dump, debug, backup, import, completion, logs so that
multi-word session names after -c/-r are not broken by these commands
- Add tests/hermes_cli/test_completion.py: 17 tests covering parser
extraction, alias deduplication, bash/zsh/fish output content,
bash syntax validation, fish syntax validation, and subcommand
drift prevention
Tested on Linux (Arch). bash and fish completion verified live.
zsh script passes syntax check (zsh not installed on test machine).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-14 11:33:46 +08:00
|
|
|
sub_cases_str = "\n".join(sub_cases)
|
|
|
|
|
|
|
|
|
|
return f"""#compdef hermes
|
|
|
|
|
# Hermes Agent zsh completion
|
|
|
|
|
# Add to ~/.zshrc:
|
|
|
|
|
# eval "$(hermes completion zsh)"
|
|
|
|
|
|
2026-04-14 10:30:43 -07:00
|
|
|
_hermes_profiles() {{
|
|
|
|
|
local -a profiles
|
|
|
|
|
profiles=(default)
|
|
|
|
|
if [[ -d "$HOME/.hermes/profiles" ]]; then
|
|
|
|
|
profiles+=("${{(@f)$(ls $HOME/.hermes/profiles 2>/dev/null)}}")
|
|
|
|
|
fi
|
|
|
|
|
_describe 'profile' profiles
|
|
|
|
|
}}
|
|
|
|
|
|
feat(cli): add dynamic shell completion for bash, zsh, and fish
Replaces the hardcoded completion stubs in profiles.py with a dynamic
generator that walks the live argparse parser tree at runtime.
- New hermes_cli/completion.py: _walk() recursively extracts all
subcommands and flags; generate_bash/zsh/fish() produce complete
scripts with nested subcommand support
- cmd_completion now accepts the parser via closure so completions
always reflect the actual registered commands (including plugin-
registered ones like honcho)
- completion subcommand now accepts bash | zsh | fish (fish requested
in issue comments)
- Fix _SUBCOMMANDS set: add honcho, claw, plugins, acp, webhook,
memory, dump, debug, backup, import, completion, logs so that
multi-word session names after -c/-r are not broken by these commands
- Add tests/hermes_cli/test_completion.py: 17 tests covering parser
extraction, alias deduplication, bash/zsh/fish output content,
bash syntax validation, fish syntax validation, and subcommand
drift prevention
Tested on Linux (Arch). bash and fish completion verified live.
zsh script passes syntax check (zsh not installed on test machine).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-14 11:33:46 +08:00
|
|
|
_hermes() {{
|
|
|
|
|
local context state line
|
|
|
|
|
typeset -A opt_args
|
|
|
|
|
|
|
|
|
|
_arguments -C \\
|
|
|
|
|
'(-h --help){{-h,--help}}[Show help and exit]' \\
|
|
|
|
|
'(-V --version){{-V,--version}}[Show version and exit]' \\
|
2026-04-14 10:30:43 -07:00
|
|
|
'(-p --profile){{-p,--profile}}[Profile name]:profile:_hermes_profiles' \\
|
feat(cli): add dynamic shell completion for bash, zsh, and fish
Replaces the hardcoded completion stubs in profiles.py with a dynamic
generator that walks the live argparse parser tree at runtime.
- New hermes_cli/completion.py: _walk() recursively extracts all
subcommands and flags; generate_bash/zsh/fish() produce complete
scripts with nested subcommand support
- cmd_completion now accepts the parser via closure so completions
always reflect the actual registered commands (including plugin-
registered ones like honcho)
- completion subcommand now accepts bash | zsh | fish (fish requested
in issue comments)
- Fix _SUBCOMMANDS set: add honcho, claw, plugins, acp, webhook,
memory, dump, debug, backup, import, completion, logs so that
multi-word session names after -c/-r are not broken by these commands
- Add tests/hermes_cli/test_completion.py: 17 tests covering parser
extraction, alias deduplication, bash/zsh/fish output content,
bash syntax validation, fish syntax validation, and subcommand
drift prevention
Tested on Linux (Arch). bash and fish completion verified live.
zsh script passes syntax check (zsh not installed on test machine).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-14 11:33:46 +08:00
|
|
|
'1:command:->commands' \\
|
|
|
|
|
'*::arg:->args'
|
|
|
|
|
|
|
|
|
|
case $state in
|
|
|
|
|
commands)
|
|
|
|
|
local -a subcmds
|
|
|
|
|
subcmds=(
|
|
|
|
|
{top_cmds_str}
|
|
|
|
|
)
|
|
|
|
|
_describe 'hermes command' subcmds
|
|
|
|
|
;;
|
|
|
|
|
args)
|
|
|
|
|
case ${{line[1]}} in
|
|
|
|
|
{sub_cases_str}
|
|
|
|
|
esac
|
|
|
|
|
;;
|
|
|
|
|
esac
|
|
|
|
|
}}
|
|
|
|
|
|
|
|
|
|
_hermes "$@"
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
# Fish
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
def generate_fish(parser: argparse.ArgumentParser) -> str:
|
|
|
|
|
tree = _walk(parser)
|
|
|
|
|
top_cmds = sorted(tree["subcommands"])
|
|
|
|
|
top_cmds_str = " ".join(top_cmds)
|
|
|
|
|
|
|
|
|
|
lines: list[str] = [
|
|
|
|
|
"# Hermes Agent fish completion",
|
|
|
|
|
"# Add to your config:",
|
|
|
|
|
"# hermes completion fish | source",
|
|
|
|
|
"",
|
2026-04-14 10:30:43 -07:00
|
|
|
"# Helper: list available profiles",
|
|
|
|
|
"function __hermes_profiles",
|
|
|
|
|
" echo default",
|
|
|
|
|
" if test -d $HOME/.hermes/profiles",
|
|
|
|
|
" ls $HOME/.hermes/profiles 2>/dev/null",
|
|
|
|
|
" end",
|
|
|
|
|
"end",
|
|
|
|
|
"",
|
feat(cli): add dynamic shell completion for bash, zsh, and fish
Replaces the hardcoded completion stubs in profiles.py with a dynamic
generator that walks the live argparse parser tree at runtime.
- New hermes_cli/completion.py: _walk() recursively extracts all
subcommands and flags; generate_bash/zsh/fish() produce complete
scripts with nested subcommand support
- cmd_completion now accepts the parser via closure so completions
always reflect the actual registered commands (including plugin-
registered ones like honcho)
- completion subcommand now accepts bash | zsh | fish (fish requested
in issue comments)
- Fix _SUBCOMMANDS set: add honcho, claw, plugins, acp, webhook,
memory, dump, debug, backup, import, completion, logs so that
multi-word session names after -c/-r are not broken by these commands
- Add tests/hermes_cli/test_completion.py: 17 tests covering parser
extraction, alias deduplication, bash/zsh/fish output content,
bash syntax validation, fish syntax validation, and subcommand
drift prevention
Tested on Linux (Arch). bash and fish completion verified live.
zsh script passes syntax check (zsh not installed on test machine).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-14 11:33:46 +08:00
|
|
|
"# Disable file completion by default",
|
|
|
|
|
"complete -c hermes -f",
|
|
|
|
|
"",
|
2026-04-14 10:30:43 -07:00
|
|
|
"# Complete profile names after -p / --profile",
|
|
|
|
|
"complete -c hermes -f -s p -l profile"
|
|
|
|
|
" -d 'Profile name' -xa '(__hermes_profiles)'",
|
|
|
|
|
"",
|
feat(cli): add dynamic shell completion for bash, zsh, and fish
Replaces the hardcoded completion stubs in profiles.py with a dynamic
generator that walks the live argparse parser tree at runtime.
- New hermes_cli/completion.py: _walk() recursively extracts all
subcommands and flags; generate_bash/zsh/fish() produce complete
scripts with nested subcommand support
- cmd_completion now accepts the parser via closure so completions
always reflect the actual registered commands (including plugin-
registered ones like honcho)
- completion subcommand now accepts bash | zsh | fish (fish requested
in issue comments)
- Fix _SUBCOMMANDS set: add honcho, claw, plugins, acp, webhook,
memory, dump, debug, backup, import, completion, logs so that
multi-word session names after -c/-r are not broken by these commands
- Add tests/hermes_cli/test_completion.py: 17 tests covering parser
extraction, alias deduplication, bash/zsh/fish output content,
bash syntax validation, fish syntax validation, and subcommand
drift prevention
Tested on Linux (Arch). bash and fish completion verified live.
zsh script passes syntax check (zsh not installed on test machine).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-14 11:33:46 +08:00
|
|
|
"# Top-level subcommands",
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
for cmd in top_cmds:
|
|
|
|
|
info = tree["subcommands"][cmd]
|
|
|
|
|
help_text = _clean(info.get("help", ""))
|
|
|
|
|
lines.append(
|
|
|
|
|
f"complete -c hermes -f "
|
|
|
|
|
f"-n 'not __fish_seen_subcommand_from {top_cmds_str}' "
|
|
|
|
|
f"-a {cmd} -d '{help_text}'"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
lines.append("")
|
|
|
|
|
lines.append("# Subcommand completions")
|
|
|
|
|
|
2026-04-14 10:30:43 -07:00
|
|
|
profile_name_actions = {"use", "delete", "show", "alias", "rename", "export"}
|
|
|
|
|
|
feat(cli): add dynamic shell completion for bash, zsh, and fish
Replaces the hardcoded completion stubs in profiles.py with a dynamic
generator that walks the live argparse parser tree at runtime.
- New hermes_cli/completion.py: _walk() recursively extracts all
subcommands and flags; generate_bash/zsh/fish() produce complete
scripts with nested subcommand support
- cmd_completion now accepts the parser via closure so completions
always reflect the actual registered commands (including plugin-
registered ones like honcho)
- completion subcommand now accepts bash | zsh | fish (fish requested
in issue comments)
- Fix _SUBCOMMANDS set: add honcho, claw, plugins, acp, webhook,
memory, dump, debug, backup, import, completion, logs so that
multi-word session names after -c/-r are not broken by these commands
- Add tests/hermes_cli/test_completion.py: 17 tests covering parser
extraction, alias deduplication, bash/zsh/fish output content,
bash syntax validation, fish syntax validation, and subcommand
drift prevention
Tested on Linux (Arch). bash and fish completion verified live.
zsh script passes syntax check (zsh not installed on test machine).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-14 11:33:46 +08:00
|
|
|
for cmd in top_cmds:
|
|
|
|
|
info = tree["subcommands"][cmd]
|
|
|
|
|
if not info["subcommands"]:
|
|
|
|
|
continue
|
|
|
|
|
lines.append(f"# {cmd}")
|
|
|
|
|
for sc in sorted(info["subcommands"]):
|
|
|
|
|
sinfo = info["subcommands"][sc]
|
|
|
|
|
sh = _clean(sinfo.get("help", ""))
|
|
|
|
|
lines.append(
|
|
|
|
|
f"complete -c hermes -f "
|
|
|
|
|
f"-n '__fish_seen_subcommand_from {cmd}' "
|
|
|
|
|
f"-a {sc} -d '{sh}'"
|
|
|
|
|
)
|
2026-04-14 10:30:43 -07:00
|
|
|
# For profile subcommand, complete profile names for relevant actions
|
|
|
|
|
if cmd == "profile":
|
|
|
|
|
for action in sorted(profile_name_actions):
|
|
|
|
|
lines.append(
|
|
|
|
|
f"complete -c hermes -f "
|
|
|
|
|
f"-n '__fish_seen_subcommand_from {action}; "
|
|
|
|
|
f"and __fish_seen_subcommand_from profile' "
|
|
|
|
|
f"-a '(__hermes_profiles)' -d 'Profile name'"
|
|
|
|
|
)
|
feat(cli): add dynamic shell completion for bash, zsh, and fish
Replaces the hardcoded completion stubs in profiles.py with a dynamic
generator that walks the live argparse parser tree at runtime.
- New hermes_cli/completion.py: _walk() recursively extracts all
subcommands and flags; generate_bash/zsh/fish() produce complete
scripts with nested subcommand support
- cmd_completion now accepts the parser via closure so completions
always reflect the actual registered commands (including plugin-
registered ones like honcho)
- completion subcommand now accepts bash | zsh | fish (fish requested
in issue comments)
- Fix _SUBCOMMANDS set: add honcho, claw, plugins, acp, webhook,
memory, dump, debug, backup, import, completion, logs so that
multi-word session names after -c/-r are not broken by these commands
- Add tests/hermes_cli/test_completion.py: 17 tests covering parser
extraction, alias deduplication, bash/zsh/fish output content,
bash syntax validation, fish syntax validation, and subcommand
drift prevention
Tested on Linux (Arch). bash and fish completion verified live.
zsh script passes syntax check (zsh not installed on test machine).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-14 11:33:46 +08:00
|
|
|
|
|
|
|
|
lines.append("")
|
|
|
|
|
return "\n".join(lines)
|