-
-
Notifications
You must be signed in to change notification settings - Fork 860
feat: add "Did you mean?" suggestions and inactive tool warnings #7965
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When a user types an unknown tool name (e.g. `mise use foo`), instead of just failing with "not found in registry", suggest similar tools from both the mise registry and aqua registry using Jaro-Winkler string similarity. - Bump xx to 2.5 for the suggest module - Add package_ids() to aqua-registry crate for querying available tools - Add aqua_suggest() for fuzzy-matching aqua package names - Replace plain error in backend_arg with "Did you mean?" suggestions Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Summary of ChangesHello @jdx, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request significantly improves the user experience when encountering mistyped or unknown tool names by introducing intelligent 'Did you mean?' suggestions. By integrating fuzzy matching capabilities from both internal mise registries and external Aqua registries, users will receive helpful recommendations, reducing frustration and improving discoverability of available tools. The changes involve core logic for suggestion generation, dependency updates, and refactoring of Vfox plugin internals to support these new features and enhance development workflows. Highlights
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR enhances the user experience by providing "Did you mean?" suggestions when users attempt to use an unknown tool name. The feature uses Jaro-Winkler string similarity to suggest similar tools from both the mise registry and aqua registry, with a similarity threshold of 0.8 to reduce noise.
Changes:
- Added fuzzy tool name matching to suggest alternatives when a tool is not found in the registry
- Updated the
xxdependency to version 2.5 to access thesuggestmodule with Jaro-Winkler similarity algorithm - Exposed
package_ids()function from the aqua-registry crate to enable querying available aqua tool names
Reviewed changes
Copilot reviewed 14 out of 15 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| Cargo.toml | Bumped xx dependency from "2" to "2.5" to enable string similarity features |
| crates/aqua-registry/src/registry.rs | Added package_ids() function to return all baked-in aqua package IDs |
| crates/aqua-registry/src/lib.rs | Re-exported package_ids from registry module |
| src/aqua/aqua_registry_wrapper.rs | Added aqua_suggest() function for fuzzy matching aqua package names |
| src/cli/args/backend_arg.rs | Enhanced error message with "Did you mean?" suggestions from both registries |
| crates/vfox/types/mise-plugin.lua | New file with LuaCATS type definitions for mise vfox plugins |
| crates/vfox/src/runtime.rs | Added with_platform() method for creating Runtime with custom OS/arch |
| crates/vfox/src/hooks/pre_install.rs | Updated to use RUNTIME.osType/archType instead of deprecated OS_TYPE/ARCH_TYPE globals |
| crates/vfox/plugins/.luarc.json | Updated Lua version to 5.1 and configured workspace library path |
| crates/vfox/embedded-plugins/vfox-clickhouse/hooks/pre_install.lua | Migrated from OS_TYPE to RUNTIME.osType |
| crates/vfox/embedded-plugins/vfox-clickhouse/hooks/post_install.lua | Migrated from OS_TYPE to RUNTIME.osType |
| crates/vfox/embedded-plugins/vfox-carthage/hooks/post_install.lua | Migrated from OS_TYPE to RUNTIME.osType |
| crates/vfox/embedded-plugins/vfox-aapt2/lib/util.lua | Migrated from OS_TYPE to RUNTIME.osType |
| crates/vfox/embedded-plugins/vfox-aapt2/hooks/post_install.lua | Migrated from OS_TYPE to RUNTIME.osType |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
src/aqua/aqua_registry_wrapper.rs
Outdated
| let mut results = Vec::new(); | ||
| for matched_name in similar_names { | ||
| for (name, full_id) in &pairs { | ||
| if *name == matched_name && !results.contains(&full_id.to_string()) { |
Copilot
AI
Feb 2, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The nested loop performs an O(n²) search to map matched names back to IDs, and the results.contains() check adds another O(n) operation for each iteration. Consider using a HashSet to track added IDs (O(1) lookups) or using a more direct mapping approach to avoid quadratic complexity.
src/cli/args/backend_arg.rs
Outdated
| for aqua_id in crate::aqua::aqua_registry_wrapper::aqua_suggest(&self.short) { | ||
| suggestions.push(format!("aqua:{aqua_id}")); |
Copilot
AI
Feb 2, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The aqua suggestions are appended after mise suggestions without deduplication. If a tool exists in both registries with the same name, it could appear twice in the suggestions list (once without prefix, once with 'aqua:' prefix). Consider deduplicating or clearly separating the suggestion sources.
| for aqua_id in crate::aqua::aqua_registry_wrapper::aqua_suggest(&self.short) { | |
| suggestions.push(format!("aqua:{aqua_id}")); | |
| // Build sets to deduplicate suggestions across mise and aqua sources | |
| let registry_short_set: HashSet<&str> = registry_shorts.iter().copied().collect(); | |
| let mut suggestion_set: HashSet<String> = suggestions.iter().cloned().collect(); | |
| for aqua_id in crate::aqua::aqua_registry_wrapper::aqua_suggest(&self.short) { | |
| // Skip aqua suggestions that already exist as a mise tool with the same name | |
| if registry_short_set.contains(aqua_id.as_str()) { | |
| continue; | |
| } | |
| let formatted = format!("aqua:{aqua_id}"); | |
| // Only add if this formatted suggestion is not already present | |
| if suggestion_set.insert(formatted.clone()) { | |
| suggestions.push(formatted); | |
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code Review
This pull request introduces a helpful "Did you mean?" feature for unknown tools, improving user experience by suggesting similar tools from both mise and aqua registries. It also includes a nice refactoring in the vfox Lua plugins, replacing the global OS_TYPE and ARCH_TYPE variables with a more structured RUNTIME object, and adds LuaCATS type definitions for better developer experience.
I have one suggestion to improve the performance and correctness of the new aqua_suggest function.
| pub fn aqua_suggest(query: &str) -> Vec<String> { | ||
| let ids = aqua_registry::package_ids(); | ||
| // Build (name_part, full_id) pairs, keeping them aligned | ||
| let pairs: Vec<(&str, &str)> = ids | ||
| .iter() | ||
| .filter_map(|id| id.rsplit_once('/').map(|(_, name)| (name, *id))) | ||
| .collect(); | ||
| let names: Vec<&str> = pairs.iter().map(|(name, _)| *name).collect(); | ||
|
|
||
| // Use a higher threshold (0.8) to avoid noisy suggestions | ||
| let similar_names = xx::suggest::similar_n_with_threshold(query, &names, 5, 0.8); | ||
|
|
||
| // Map back to full IDs | ||
| let mut results = Vec::new(); | ||
| for matched_name in similar_names { | ||
| for (name, full_id) in &pairs { | ||
| if *name == matched_name && !results.contains(&full_id.to_string()) { | ||
| results.push(full_id.to_string()); | ||
| break; | ||
| } | ||
| } | ||
| if results.len() >= 5 { | ||
| break; | ||
| } | ||
| } | ||
| results | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The current implementation of aqua_suggest has a nested loop that can be inefficient, especially as the number of aqua packages grows. It also has a subtle bug where it will only return the first matching full_id for a given tool name, even if multiple packages share that name (e.g., from different authors).
I suggest refactoring this function to use a HashMap to build a mapping from tool names to their full IDs. This will make the lookup more efficient (O(1) on average instead of O(N)) and ensure all matching full_ids are considered for suggestions.
Here is a more efficient and correct implementation:
use std::collections::{HashMap, HashSet};
/// Search aqua packages by tool name, returning "owner/name" IDs
/// where the name part is similar to the query.
pub fn aqua_suggest(query: &str) -> Vec<String> {
let ids = aqua_registry::package_ids();
let mut name_to_ids: HashMap<&str, Vec<&str>> = HashMap::new();
for id in ids {
if let Some((_, name)) = id.rsplit_once('/') {
name_to_ids.entry(name).or_default().push(id);
}
}
let names: Vec<&str> = name_to_ids.keys().copied().collect();
let similar_names = xx::suggest::similar_n_with_threshold(query, &names, 5, 0.8);
let mut results = Vec::new();
let mut seen_ids = HashSet::new();
for matched_name in similar_names {
if let Some(full_ids) = name_to_ids.get(matched_name) {
for full_id in full_ids {
if seen_ids.insert(*full_id) {
results.push(full_id.to_string());
if results.len() >= 5 {
return results;
}
}
}
}
}
results
}This version first builds a map of names to full IDs, then efficiently retrieves all matching IDs for the suggested names.
pub fn aqua_suggest(query: &str) -> Vec<String> {
let ids = aqua_registry::package_ids();
let mut name_to_ids: std::collections::HashMap<&str, Vec<&str>> = std::collections::HashMap::new();
for id in ids {
if let Some((_, name)) = id.rsplit_once('/') {
name_to_ids.entry(name).or_default().push(id);
}
}
let names: Vec<&str> = name_to_ids.keys().copied().collect();
let similar_names = xx::suggest::similar_n_with_threshold(query, &names, 5, 0.8);
let mut results = Vec::new();
let mut seen_ids = std::collections::HashSet::new();
for matched_name in similar_names {
if let Some(full_ids) = name_to_ids.get(matched_name) {
for full_id in full_ids {
if seen_ids.insert(*full_id) {
results.push(full_id.to_string());
if results.len() >= 5 {
return results;
}
}
}
}
}
results
}When running `mise install <tool>` for a tool not in any mise.toml or .tool-versions file, show a warning suggesting `mise use` instead. Also adds e2e tests for both the "Did you mean?" and inactive tool features. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
|
bugbot run |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Bugbot Autofix is ON, but a Cloud Agent failed to start.
Hyperfine Performance
|
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.2.1 x -- echo |
20.7 ± 0.3 | 19.9 | 22.2 | 1.00 |
mise x -- echo |
21.1 ± 0.4 | 20.1 | 22.6 | 1.02 ± 0.02 |
mise env
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.2.1 env |
20.1 ± 0.6 | 19.5 | 25.4 | 1.00 |
mise env |
20.5 ± 0.4 | 19.6 | 22.2 | 1.02 ± 0.04 |
mise hook-env
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.2.1 hook-env |
21.0 ± 0.3 | 20.2 | 22.4 | 1.00 |
mise hook-env |
21.5 ± 0.5 | 20.6 | 23.8 | 1.02 ± 0.03 |
mise ls
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.2.1 ls |
19.0 ± 0.3 | 18.3 | 20.0 | 1.00 |
mise ls |
19.5 ± 0.5 | 18.7 | 27.1 | 1.03 ± 0.03 |
xtasks/test/perf
| Command | mise-2026.2.1 | mise | Variance |
|---|---|---|---|
| install (cached) | 115ms | 114ms | +0% |
| ls (cached) | 72ms | 72ms | +0% |
| bin-paths (cached) | 76ms | 77ms | -1% |
| task-ls (cached) | 535ms | 538ms | +0% |
- Use HashMap for O(1) lookup in aqua_suggest instead of nested loops - Deduplicate suggestions: skip aqua tools whose name matches a mise suggestion - Skip inactive tool warning in dry-run mode Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
### 🚀 Features - **(asset-matcher)** enable `mingw-w64` detection for windows packages by @lchagnoleau in [#7981](#7981) - **(crates/vfox)** add download_path to BackendInstall context by @malept in [#7959](#7959) - **(python)** rework `python.uv_venv_auto` setting by @halms in [#7905](#7905) - add "Did you mean?" suggestions and inactive tool warnings by @jdx in [#7965](#7965) ### 🐛 Bug Fixes - **(hook-env)** skip remote version fetching for uninstalled tools in prefer-offline mode by @jdx in [#7976](#7976) - **(install.sh)** Corret `setup` to `set up` by @gogolok in [#7980](#7980) - retry spawn on ETXTBSY (Text file busy) by @jdx in [#7964](#7964) - improve ToolOptions parsing to support comma separated values by @roele in [#7971](#7971) ### 📚 Documentation - improve plugin documentation with comparisons and template links by @jdx in [#7962](#7962) ### 📦️ Dependency Updates - bump hyper-util, system-configuration, lru, aws-sdk, and others by @jdx in [#7977](#7977) ### Chore - **(vfox)** add LuaCATS type definitions for plugin IDE support by @jdx in [#7961](#7961) - **(vfox)** add `download_path` to `BackendInstallCtx` type defintion by @malept in [#7973](#7973) - add stylua linting for vfox plugin Lua files by @jdx in [#7960](#7960) - use system Rust for PPA builds on Ubuntu 26.04+ by @jdx in [#7956](#7956) ### New Contributors - @gogolok made their first contribution in [#7980](#7980) ## 📦 Aqua Registry Updates #### New Packages (4) - [`autobrr/mkbrr`](https://github.com/autobrr/mkbrr) - [`dodobrands/Peekie`](https://github.com/dodobrands/Peekie) - [`grpc/grpc-java/protoc-gen-grpc-java`](https://github.com/grpc/grpc-java/protoc-gen-grpc-java) - [`str4d/age-plugin-yubikey`](https://github.com/str4d/age-plugin-yubikey) #### Updated Packages (3) - [`biomejs/biome`](https://github.com/biomejs/biome) - [`rust-cross/cargo-zigbuild`](https://github.com/rust-cross/cargo-zigbuild) - [`siderolabs/talos`](https://github.com/siderolabs/talos)
Summary
mise installis used for tools not in any config file, suggestingmise useinsteadxxdependency to 2.5 for thesuggestmoduleChanges
"Did you mean?" suggestions for unknown tools
When a tool isn't found in the mise registry, we now suggest similar tools from:
nod→node)aqua:nodejs/node)Uses Jaro-Winkler similarity (threshold 0.8) to avoid noisy suggestions — completely unrelated names show no suggestions.
Inactive tool warning on
mise installWhen running
mise install <tool>for a tool not in any mise.toml or .tool-versions file, a warning is now shown:This helps new users who use
mise installwhen they should be usingmise use.Test plan
test_did_you_mean— verifies typo suggestions work and no suggestions for unrelated namestest_install_inactive_hint— verifies warning for inactive tools and no warning for configured tools🤖 Generated with Claude Code
Note
Medium Risk
Medium risk due to changes in CLI error/warning behavior and new fuzzy-matching logic that affects tool resolution, plus dependency updates (notably
xxand transitive upgrades likereqwest/zip) that could impact build/runtime behavior.Overview
Adds "Did you mean?" suggestions when a tool name can’t be resolved:
BackendArg::backend()now fuzzy-matches against mise registry shorts and also suggestsaqua:<owner>/<name>entries via a newaqua_suggest()helper backed by baked-in aqua package IDs.Enhances
mise installUX by warning (non-dry-run) when requested tools were installed from CLI args but are not present in any config source, printing correspondingmise use <tool>activation hints.Updates dependencies/lockfile to support the suggestion feature (notably bumping
xxand related transitive crates) and adds E2E coverage for both the suggestion output and the inactive-install warning.Written by Cursor Bugbot for commit 775045a. This will update automatically on new commits. Configure here.