diff --git a/cli.py b/cli.py index bc4f4a76bef..4ca07fa0bf5 100644 --- a/cli.py +++ b/cli.py @@ -12024,6 +12024,7 @@ class HermesCLI(CLIAgentSetupMixin, CLICommandsMixin): # Create the input area with multiline (Alt+Enter), autocomplete, and paste handling from prompt_toolkit.auto_suggest import AutoSuggestFromHistory + from prompt_toolkit.completion import ThreadedCompleter _completer = SlashCommandCompleter( @@ -12039,7 +12040,13 @@ class HermesCLI(CLIAgentSetupMixin, CLICommandsMixin): wrap_lines=True, read_only=Condition(lambda: bool(cli_ref._command_running)), history=FileHistory(str(self._history_file)), - completer=_completer, + # complete_while_typing fires the completer on every keystroke. The + # completer does blocking work — fuzzy @-file indexing shells out to + # rg/fd (up to a 2s timeout) and path completion hits os.listdir/stat + # — so running it inline would stall the render loop on each key (very + # noticeable on WSL2/slow filesystems). ThreadedCompleter moves it off + # the UI event loop, keeping typing responsive. + completer=ThreadedCompleter(_completer), complete_while_typing=True, auto_suggest=SlashCommandAutoSuggest( history_suggest=AutoSuggestFromHistory(), diff --git a/hermes_cli/commands.py b/hermes_cli/commands.py index a1e20dabc08..ed6f83f39e6 100644 --- a/hermes_cli/commands.py +++ b/hermes_cli/commands.py @@ -1291,6 +1291,12 @@ class SlashCommandCompleter(Completer): word = text[i + 1:] if not word: return None + # URLs contain "/" but are not local paths. Treating them as paths fires + # os.listdir on every keystroke while typing/pasting a link (e.g. an + # https:// URL becomes a listdir of "https:") — pure latency, never a + # useful completion. Skip any token with a scheme separator. + if "://" in word: + return None # Only trigger path completion for path-like tokens if word.startswith(("./", "../", "~/", "/")) or "/" in word: return word