fix(shim): detect shims by checking shims directory instead of binary name#8694
fix(shim): detect shims by checking shims directory instead of binary name#8694
Conversation
… name Previously, shim detection used `is_mise_binary()` which checked if the binary name started with "mise-". This broke when package managers named the binary something like "mise-2026.3.7", causing the shim to be incorrectly identified as a mise binary. Arguments like `-json` would then be parsed as mise's `-j` flag instead of being passed through. Now checks if a file matching argv[0]'s basename exists in the shims directory, which is robust regardless of how the mise binary is named. Fixes #8641 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Summary of ChangesHello, 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 enhances the robustness of shim detection within the application. Previously, shim identification could be flawed when the main binary was renamed by package managers, leading to incorrect argument parsing. The updated logic now directly verifies the executable's presence in the designated shims directory, ensuring that shimmed tools correctly receive their intended arguments without interference from the application's own CLI flags. 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. Footnotes
|
There was a problem hiding this comment.
Code Review
This pull request refactors the shim detection logic to be more robust, especially for cases where mise is installed by package managers that rename the binary. The new approach checks for the existence of a file in the shims directory matching the executable name, which is a more reliable method. The changes look good and are supported by a new e2e test. I've added a few suggestions to refactor the new is_in_shims_dir function to make it a pure function, improving code clarity and avoiding repeated access to a global variable.
|
|
||
| let bin_name = *MISE_BIN_NAME; | ||
| !is_mise_binary(bin_name) | ||
| crate::shims::is_in_shims_dir() |
There was a problem hiding this comment.
To make is_in_shims_dir a pure utility function, it's better to pass bin_name as an argument instead of accessing the global env::MISE_BIN_NAME within it. This change updates the call site here accordingly. This is part of a set of related suggestions.
| crate::shims::is_in_shims_dir() | |
| crate::shims::is_in_shims_dir(*MISE_BIN_NAME) |
| if !is_in_shims_dir() || cfg!(test) { | ||
| return Ok(()); | ||
| } | ||
| let bin_name = *env::MISE_BIN_NAME; |
There was a problem hiding this comment.
To avoid multiple lookups of env::MISE_BIN_NAME, it can be fetched once and passed to the proposed pure version of is_in_shims_dir. This makes the data flow more explicit.
| if !is_in_shims_dir() || cfg!(test) { | |
| return Ok(()); | |
| } | |
| let bin_name = *env::MISE_BIN_NAME; | |
| let bin_name = *env::MISE_BIN_NAME; | |
| if !is_in_shims_dir(bin_name) || cfg!(test) { | |
| return Ok(()); | |
| } |
| pub fn is_in_shims_dir() -> bool { | ||
| let bin_name = *env::MISE_BIN_NAME; | ||
| let shim_path = dirs::SHIMS.join(bin_name); | ||
| // is_symlink() catches broken symlinks that .exists() would miss | ||
| shim_path.is_symlink() || shim_path.exists() | ||
| } |
There was a problem hiding this comment.
To improve modularity and make this function's dependencies explicit, consider making it a pure function by accepting bin_name as an argument instead of accessing the global env::MISE_BIN_NAME.
pub fn is_in_shims_dir(bin_name: &str) -> bool {
let shim_path = dirs::SHIMS.join(bin_name);
// is_symlink() catches broken symlinks that .exists() would miss
shim_path.is_symlink() || shim_path.exists()
}
Greptile SummaryThis PR fixes a shim-detection regression where package managers that name the mise binary Key changes:
Confidence Score: 5/5
Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[Process starts with argv0] --> B{cfg test?}
B -- yes --> C[IS_RUNNING_AS_SHIM = false]
B -- no --> D{MISE_TOOL_STUB?}
D -- yes --> E[IS_RUNNING_AS_SHIM = true]
D -- no --> F[is_in_shims_dir]
F --> G{shims dir contains bin_name?}
G -- yes --> H[IS_RUNNING_AS_SHIM = true]
G -- no --> I[IS_RUNNING_AS_SHIM = false]
C --> J[handle_shim]
I --> J
E --> J
H --> J
J --> K{MISE_TOOL_STUB OR NOT IS_RUNNING_AS_SHIM?}
K -- yes --> L[Return early - direct mise or tool-stub path]
K -- no --> M[Exec as shim - resolve tool binary and exec]
Last reviewed commit: "fix(shim): skip shim..." |
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Hyperfine Performance
|
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.3.10 x -- echo |
24.3 ± 0.7 | 23.2 | 28.8 | 1.00 |
mise x -- echo |
24.3 ± 0.8 | 23.4 | 32.2 | 1.00 ± 0.04 |
mise env
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.3.10 env |
24.0 ± 1.0 | 22.7 | 29.6 | 1.00 ± 0.05 |
mise env |
23.9 ± 0.5 | 23.0 | 27.4 | 1.00 |
mise hook-env
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.3.10 hook-env |
24.4 ± 0.6 | 23.4 | 27.2 | 1.00 |
mise hook-env |
24.6 ± 0.8 | 23.7 | 35.7 | 1.01 ± 0.04 |
mise ls
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.3.10 ls |
23.4 ± 0.6 | 22.6 | 26.8 | 1.00 |
mise ls |
23.7 ± 0.7 | 22.7 | 28.0 | 1.01 ± 0.04 |
xtasks/test/perf
| Command | mise-2026.3.10 | mise | Variance |
|---|---|---|---|
| install (cached) | 152ms | 151ms | +0% |
| ls (cached) | 84ms | 83ms | +1% |
| bin-paths (cached) | 88ms | 86ms | +2% |
| task-ls (cached) | 823ms | 837ms | -1% |
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
MISE_TOOL_STUB causes IS_RUNNING_AS_SHIM to be true, but tool stubs should not go through handle_shim() since argv[0] is "mise", not a shim name. Add an explicit guard to prevent infinite recursion. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
### 🚀 Features - **(github)** read tokens from gh CLI hosts.yml config by @jdx in [#8692](#8692) - **(task)** support optional `args` and `env` fields in `run` entries by @jdx in [#8687](#8687) - **(task)** add --skip-tools flag to mise run by @jdx in [#8699](#8699) - **(vfox)** add try_get, try_head, try_download_file to Lua HTTP module by @jdx in [#8697](#8697) ### 🐛 Bug Fixes - **(config)** recognize SSH and other non-HTTPS URLs in get_repo_url by @modestman in [#8666](#8666) - **(docs)** add dark mode support to favicon by @jdx in [#8678](#8678) - **(env)** support multiple --env/-E flags by @jdx in [#8686](#8686) - **(github)** rename_exe renames correct binary when archive contains multiple executables by @jdx in [#8700](#8700) - **(implode)** include system data dir in implode cleanup by @jdx in [#8696](#8696) - **(install)** skip GitHub API calls for aqua tools in --locked mode by @jdx in [#8679](#8679) - **(install)** skip redundant provenance verification when lockfile has integrity data by @jdx in [#8688](#8688) - **(lock)** respect existing platforms in lockfile when running `mise lock` by @jdx in [#8708](#8708) - **(lock)** skip global config lockfile by default by @jdx in [#8707](#8707) - **(node)** expand tilde in default_packages_file path by @jdx in [#8709](#8709) - **(shell)** error when no version specified instead of silent no-op by @jdx in [#8693](#8693) - **(shim)** detect shims by checking shims directory instead of binary name by @jdx in [#8694](#8694) - **(task)** inherit task_config.dir for included TOML and file tasks by @jdx in [#8689](#8689) - **(task)** strip inline args when validating run.tasks references by @jdx in [#8701](#8701) - **(task)** include idiomatic version files in monorepo task toolset by @jdx in [#8702](#8702) - **(task)** improve error message when task files are not executable by @jdx in [#8705](#8705) - **(test)** update vfox provenance test for checksum-backed skip by @jdx in [#8703](#8703) - improve usage spec element support in tasks by @nkakouros in [#8623](#8623) - make env plugin (Module) vars available in Tera template context by @victor-founder in [#8682](#8682) - respect MISE_COLOR=0 for color_eyre error output by @jdx in [#8690](#8690) - add windows support for usage tool registry by @jdx in [#8713](#8713) ### 📚 Documentation - **(task)** clarify interactive task blocking behavior by @jdx in [#8685](#8685) - improve visibility of install_before setting by @jdx in [#8712](#8712) ### 📦 Registry - add rtk ([github:rtk-ai/rtk](https://github.com/rtk-ai/rtk)) by @bricelalu in [#8683](#8683) ### New Contributors - @victor-founder made their first contribution in [#8682](#8682) - @modestman made their first contribution in [#8666](#8666) - @bricelalu made their first contribution in [#8683](#8683)
| #!/usr/bin/env bash | ||
|
|
||
| # Regression test: shim must pass through flags like "-j" that overlap with | ||
| # mise's own CLI flags (e.g. --jobs / -j). See: | ||
| # https://github.com/jdx/mise/discussions/8641 | ||
|
|
||
| export PATH="$MISE_DATA_DIR/shims:$PATH" | ||
|
|
||
| mise use -g dummy@1.0.0 | ||
| mise reshim | ||
|
|
||
| # The dummy shim should execute the underlying tool, not mise itself. | ||
| # If shim detection is broken, mise would try to parse these as its own args. | ||
| assert_contains "dummy hello world" "This is Dummy 1.0.0!" | ||
| assert_not_contains "dummy" "mise manages dev tools" | ||
|
|
||
| # Verify that flags which collide with mise flags are passed through to the tool. | ||
| # -j is mise's --jobs flag; if the shim is not detected, mise parses "-json" as | ||
| # "-j son" and errors with "invalid value 'son' for '--jobs'". | ||
| assert_contains "dummy -json foo" "This is Dummy 1.0.0!" |
There was a problem hiding this comment.
Did anyone ever see this regression test fail with the original code?

Summary
argv[0]'s basename exists in the shims directory, instead of usingis_mise_binary()which checked if the binary name started with"mise-"mise-<version>(e.g.mise-2026.3.7), causing shims to be incorrectly identified as mise itself and arguments like-jsonto be parsed as mise's-jflagis_mise_binary()functionFixes #8641
Test plan
e2e/cli/test_shims_argstest that verifies shim args (including-jsonwhich collides with mise's-j) are passed throughtest_shimsandtest_shims_fallbacke2e tests pass🤖 Generated with Claude Code
Note
Medium Risk
Changes shim detection logic that affects how
misedecides whether to execute a tool vs parse its own CLI flags; regressions could break command invocation for renamed binaries or nonstandard shim setups.Overview
Fixes shim detection by switching from binary-name prefix checks to verifying
argv[0]exists in the shims directory (is_in_shims_dir()), and removes the now-unusedis_mise_binary()helper.Updates shim handling to rely on
IS_RUNNING_AS_SHIMand adds an e2e regression test (e2e/cli/test_shims_args) to ensure shim-invoked tools receive flags like-jsoneven when they collide withmise’s own options (e.g.-j/--jobs).Written by Cursor Bugbot for commit 251ac24. This will update automatically on new commits. Configure here.