Skip to content

Conversation

@jdx
Copy link
Owner

@jdx jdx commented Feb 2, 2026

Summary

  • Add "Did you mean?" suggestions when a user types an unknown tool name, using Jaro-Winkler string similarity to suggest similar tools from both the mise registry and aqua registry
  • Warn when mise install is used for tools not in any config file, suggesting mise use instead
  • Bump xx dependency to 2.5 for the suggest module

Changes

"Did you mean?" suggestions for unknown tools

When a tool isn't found in the mise registry, we now suggest similar tools from:

  1. The mise registry (for typos, e.g., nodnode)
  2. The aqua registry (for tools available via aqua, e.g., 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 install

When running mise install <tool> for a tool not in any mise.toml or .tool-versions file, a warning is now shown:

mise WARN  zig installed but not activated — it is not in a mise.toml config file.
To install and activate, run:
  mise use zig

This helps new users who use mise install when they should be using mise use.

Test plan

  • E2E test: test_did_you_mean — verifies typo suggestions work and no suggestions for unrelated names
  • E2E test: test_install_inactive_hint — verifies warning for inactive tools and no warning for configured tools
  • All lint checks passing
  • Cargo check passing

🤖 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 xx and transitive upgrades like reqwest/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 suggests aqua:<owner>/<name> entries via a new aqua_suggest() helper backed by baked-in aqua package IDs.

Enhances mise install UX by warning (non-dry-run) when requested tools were installed from CLI args but are not present in any config source, printing corresponding mise use <tool> activation hints.

Updates dependencies/lockfile to support the suggestion feature (notably bumping xx and 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.

jdx and others added 2 commits February 2, 2026 12:44
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>
Copilot AI review requested due to automatic review settings February 2, 2026 14:23
@gemini-code-assist
Copy link

Summary of Changes

Hello @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

  • Enhanced User Experience: Implemented 'Did you mean?' suggestions for unknown tool names, leveraging Jaro-Winkler string similarity to provide relevant alternatives from both the mise and aqua registries.
  • Dependency Updates: The xx dependency has been bumped to version 2.5 to enable the new suggest module, which is crucial for the fuzzy matching functionality.
  • Aqua Registry Integration: The aqua-registry crate now exposes a package_ids() function, allowing the system to query available Aqua tool names for suggestion purposes.
  • Vfox Plugin Updates: Vfox embedded plugins have been updated to use the new RUNTIME.osType and RUNTIME.archType globals instead of the deprecated OS_TYPE and ARCH_TYPE, improving consistency and maintainability. LuaCATS type definitions were also added for better IDE support.
Using Gemini Code Assist

The 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 /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

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 .gemini/ folder in the base of the repository. Detailed instructions can be found here.

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

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

Copilot AI left a 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 xx dependency to version 2.5 to access the suggest module 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.

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()) {
Copy link

Copilot AI Feb 2, 2026

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.

Copilot uses AI. Check for mistakes.
Comment on lines 185 to 186
for aqua_id in crate::aqua::aqua_registry_wrapper::aqua_suggest(&self.short) {
suggestions.push(format!("aqua:{aqua_id}"));
Copy link

Copilot AI Feb 2, 2026

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.

Suggested change
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);
}

Copilot uses AI. Check for mistakes.
Copy link

@gemini-code-assist gemini-code-assist bot left a 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.

Comment on lines 121 to 147
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
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

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>
@jdx jdx changed the title feat: add "Did you mean?" suggestions for unknown tools feat: add "Did you mean?" suggestions and inactive tool warnings Feb 2, 2026
@jdx
Copy link
Owner Author

jdx commented Feb 2, 2026

bugbot run

Copy link

@cursor cursor bot left a 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.

@github-actions
Copy link

github-actions bot commented Feb 2, 2026

Hyperfine Performance

mise x -- echo

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>
@socket-security
Copy link

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Updatedcargo/​xx@​2.3.0 ⏵ 2.5.191 -410093100100

View full report

@jdx jdx merged commit 9c6074e into main Feb 2, 2026
49 of 51 checks passed
@jdx jdx deleted the feat/did-you-mean-suggestions branch February 2, 2026 17:47
mise-en-dev added a commit that referenced this pull request Feb 3, 2026
### 🚀 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)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants