Skip to content

fix(tool-stub): detect binary names from single-file downloads#6281

Merged
jdx merged 4 commits intomainfrom
fix/tool-stub-bin-detection
Sep 13, 2025
Merged

fix(tool-stub): detect binary names from single-file downloads#6281
jdx merged 4 commits intomainfrom
fix/tool-stub-bin-detection

Conversation

@jdx
Copy link
Owner

@jdx jdx commented Sep 12, 2025

Summary

  • Fixed binary name detection for single-file downloads in tool-stub generation
  • Added helper function to extract tool names from URLs by removing platform/arch suffixes
  • Binary name detection now works even when --skip-download is used

Problem

When generating tool stubs for single binary files (not archives), the bin field was being left empty or set incorrectly. For example, a stub named "jq-test" downloading "jq-macos-arm64" should set bin="jq" since the actual binary command is "jq", not "jq-macos-arm64".

Solution

  1. Added extract_tool_name_from_filename() function that removes common platform/architecture suffixes from filenames
  2. Updated the tool-stub generation logic to detect binary names from URLs even when skipping downloads
  3. For single binary files, the tool name is extracted from the URL and set as the bin field when it differs from the stub filename

Test Plan

  • Added e2e test test_generate_tool_stub that verifies:
    • Single binary files get correct bin field detection
    • Archives are handled properly
    • Bin field is omitted when it matches the stub name
    • Explicit bin parameter works correctly
  • All existing tests pass
  • Manual testing with jq and other single-binary tools

🤖 Generated with Claude Code

When generating tool stubs for single binary files (not archives), the
binary name should be extracted from the URL by removing platform/arch
suffixes. This allows the bin field to be correctly set when it differs
from the stub filename.

For example, a stub named "jq-test" downloading "jq-macos-arm64" will
now correctly set bin="jq" since the actual binary is "jq", not
"jq-macos-arm64".

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings September 12, 2025 23:41
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 fixes binary name detection for single-file downloads in tool-stub generation, ensuring that the bin field is correctly set to the actual binary command name rather than the filename with platform/architecture suffixes.

  • Added helper function to extract tool names from URLs by removing platform/arch suffixes
  • Updated tool-stub generation logic to detect binary names even when --skip-download is used
  • Enhanced binary name detection for single binary files vs archives

Reviewed Changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
src/cli/generate/tool_stub.rs Added extract_tool_name_from_filename() function and updated logic to detect binary names from URLs when skipping downloads
e2e/cli/test_generate_tool_stub Added comprehensive e2e test covering single binary files, archives, explicit bin parameters, and download scenarios

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

Comment on lines +674 to +713
let suffixes = [
"-linux-x64",
"-linux-x86_64",
"-linux-amd64",
"-linux-arm64",
"-linux-aarch64",
"-darwin-x64",
"-darwin-x86_64",
"-darwin-amd64",
"-darwin-arm64",
"-darwin-aarch64",
"-macos-x64",
"-macos-x86_64",
"-macos-amd64",
"-macos-arm64",
"-macos-aarch64",
"-windows-x64",
"-windows-x86_64",
"-windows-amd64",
"-windows-arm64",
"-windows-aarch64",
"-win-x64",
"-win-x86_64",
"-win-amd64",
"-win-arm64",
"-win-aarch64",
"-x86_64",
"-x64",
"-amd64",
"-arm64",
"-aarch64",
"-linux",
"-darwin",
"-macos",
"-windows",
"-win",
];

let mut result = name.to_string();
for suffix in &suffixes {
Copy link

Copilot AI Sep 12, 2025

Choose a reason for hiding this comment

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

[nitpick] The hardcoded suffix array could be difficult to maintain as new platform/architecture combinations emerge. Consider extracting this to a constant or configuration file to improve maintainability and make it easier to add new suffixes in the future.

Suggested change
let suffixes = [
"-linux-x64",
"-linux-x86_64",
"-linux-amd64",
"-linux-arm64",
"-linux-aarch64",
"-darwin-x64",
"-darwin-x86_64",
"-darwin-amd64",
"-darwin-arm64",
"-darwin-aarch64",
"-macos-x64",
"-macos-x86_64",
"-macos-amd64",
"-macos-arm64",
"-macos-aarch64",
"-windows-x64",
"-windows-x86_64",
"-windows-amd64",
"-windows-arm64",
"-windows-aarch64",
"-win-x64",
"-win-x86_64",
"-win-amd64",
"-win-arm64",
"-win-aarch64",
"-x86_64",
"-x64",
"-amd64",
"-arm64",
"-aarch64",
"-linux",
"-darwin",
"-macos",
"-windows",
"-win",
];
let mut result = name.to_string();
for suffix in &suffixes {
let suffixes = &TOOL_NAME_SUFFIXES;
let mut result = name.to_string();
for suffix in suffixes {

Copilot uses AI. Check for mistakes.
Comment on lines +713 to +715
for suffix in &suffixes {
if let Some(pos) = result.rfind(suffix) {
result.truncate(pos);
Copy link

Copilot AI Sep 12, 2025

Choose a reason for hiding this comment

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

The current logic only removes the first matching suffix found, but this could lead to incorrect results. For example, a filename like 'tool-linux-x64-linux' would only remove '-linux-x64' and leave '-linux' at the end. Consider iterating until no more suffixes can be removed or using a more sophisticated pattern matching approach.

Suggested change
for suffix in &suffixes {
if let Some(pos) = result.rfind(suffix) {
result.truncate(pos);
loop {
let mut found = false;
for suffix in &suffixes {
if result.ends_with(suffix) {
let len = result.len() - suffix.len();
result.truncate(len);
found = true;
break;
}
}
if !found {

Copilot uses AI. Check for mistakes.
cursor[bot]

This comment was marked as outdated.

@github-actions
Copy link

github-actions bot commented Sep 12, 2025

Hyperfine Performance

mise x -- echo

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2025.9.9 x -- echo 19.1 ± 0.3 18.7 21.6 1.00
mise x -- echo 19.2 ± 0.4 18.6 23.4 1.00 ± 0.03

mise env

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2025.9.9 env 18.6 ± 0.3 18.2 21.8 1.00
mise env 18.9 ± 0.7 18.1 26.6 1.02 ± 0.04

mise hook-env

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2025.9.9 hook-env 18.7 ± 0.5 17.8 22.2 1.02 ± 0.04
mise hook-env 18.3 ± 0.4 17.8 22.7 1.00

mise ls

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2025.9.9 ls 16.2 ± 0.3 15.7 17.7 1.00
mise ls 17.8 ± 1.6 15.9 45.6 1.10 ± 0.10

xtasks/test/perf

Command mise-2025.9.9 mise Variance
install (cached) 173ms ✅ 111ms +55%
ls (cached) 63ms 63ms +0%
bin-paths (cached) 69ms 70ms -1%
task-ls (cached) 482ms 481ms +0%

✅ Performance improvement: install cached is 55%

jdx added 3 commits September 13, 2025 07:39
Simplified the test to just generate a git-branchless tool stub and
attempt to execute it, which directly reproduces the original issue
where the bin field was empty.
When strip_components removes all path components (e.g., stripping
'git-branchless' results in empty string), don't set an empty bin
field. Instead, keep the original binary name.

This fixes the issue where tool stubs had bin="" which prevented
the HTTP backend from using its auto-detection logic.

Also updated CLAUDE.md with correct debug environment variables.
@jdx jdx merged commit 758bab3 into main Sep 13, 2025
18 checks passed
@jdx jdx deleted the fix/tool-stub-bin-detection branch September 13, 2025 15:09
@jdx jdx mentioned this pull request Sep 13, 2025
jdx added a commit that referenced this pull request Sep 13, 2025
### 📦 Registry

- use asdf to install semver-tool by @jylenhof in
[#6233](#6233)

### 🐛 Bug Fixes

- **(tool-stub)** detect binary names from single-file downloads by @jdx
in [#6281](#6281)

### 🚜 Refactor

- allow any collection types in deserialize_arr by @risu729 in
[#6282](#6282)
- use deserialize_arr for task runs by @risu729 in
[#6253](#6253)

### 📚 Documentation

- **(getting-started)** add backends step with diagram, github example,
env vars and simple tasks by @jdx in
[#6288](#6288)
- simplify OS detection in tool plugin development by @jdx in
[#6287](#6287)
- update backend plugin template references by @jdx in
[942f5eb](942f5eb)

### 📦️ Dependency Updates

- update rust crate chrono to v0.4.42 by @renovate[bot] in
[#6274](#6274)
- update taiki-e/install-action digest to 0154864 by @renovate[bot] in
[#6273](#6273)

### Chore

- **(schema)** fix schema for subtasks by @risu729 in
[#6289](#6289)
- update render:schema task by @risu729 in
[#6275](#6275)

Co-authored-by: mise-en-dev <release@mise.jdx.dev>
netbsd-srcmastr pushed a commit to NetBSD/pkgsrc that referenced this pull request Sep 19, 2025
## [2025.9.12](https://github.com/jdx/mise/compare/v2025.9.11..v2025.9.12) - 2025-09-16

### 🐛 Bug Fixes

- **(ci)** properly exclude aqua-registry files from hk linting by @jdx in [42d7758](jdx/mise@42d7758)

### Chore

- **(release)** embed aqua-registry under crate and publish like vfox by @jdx in [#6306](jdx/mise#6306)
- ignore aqua-registry assets from prettier by @jdx in [047d77b](jdx/mise@047d77b)
- disable "useless cat" shellcheck by @jdx in [a6def59](jdx/mise@a6def59)

## [2025.9.11](https://github.com/jdx/mise/compare/v2025.9.10..v2025.9.11) - 2025-09-16

### 📦 Registry

- indicate aws-cli is v2 by @jayvdb in [#6300](jdx/mise#6300)

### 🚀 Features

- **(ci)** run all registry tools when workflow_dispatch is triggered by @jdx in [#6295](jdx/mise#6295)
- **(cli)** handle non-existent working directories gracefully by @jdx in [#6304](jdx/mise#6304)
- **(set)** add -E/--env flag to mise set command by @jdx in [#6291](jdx/mise#6291)
- **(tasks)** make auto outputs default by @risu729 in [#6137](jdx/mise#6137)

### 🐛 Bug Fixes

- align crate versions to fix release-plz script by @jdx in [5a464e9](jdx/mise@5a464e9)

### 🚜 Refactor

- **(aqua)** extract aqua registry into internal subcrate by @jdx in [#6293](jdx/mise#6293)

### 📚 Documentation

- fix mkdir paths by @risu729 in [#6298](jdx/mise#6298)
- fix rust profile default by @risu729 in [#6305](jdx/mise#6305)

### Chore

- **(aqua-registry)** remove unused aqua-registry files by @jdx in [#6294](jdx/mise#6294)
- **(release)** make release-plz idempotent for existing crate versions by @jdx in [dbdfd6a](jdx/mise@dbdfd6a)
- **(release)** skip publishing mise when aqua-registry is a path dep by @jdx in [47efffd](jdx/mise@47efffd)
- keep aqua-registry LICENSE file by @risu729 in [#6297](jdx/mise#6297)

### New Contributors

- @jayvdb made their first contribution in [#6300](jdx/mise#6300)

## [2025.9.10](https://github.com/jdx/mise/compare/v2025.9.9..v2025.9.10) - 2025-09-13

### 📦 Registry

- use asdf to install semver-tool by @jylenhof in [#6233](jdx/mise#6233)

### 🐛 Bug Fixes

- **(tool-stub)** detect binary names from single-file downloads by @jdx in [#6281](jdx/mise#6281)

### 🚜 Refactor

- allow any collection types in deserialize_arr by @risu729 in [#6282](jdx/mise#6282)
- use deserialize_arr for task runs by @risu729 in [#6253](jdx/mise#6253)

### 📚 Documentation

- **(getting-started)** add backends step with diagram, github example, env vars and simple tasks by @jdx in [#6288](jdx/mise#6288)
- simplify OS detection in tool plugin development by @jdx in [#6287](jdx/mise#6287)
- update backend plugin template references by @jdx in [942f5eb](jdx/mise@942f5eb)

### 📦️ Dependency Updates

- update rust crate chrono to v0.4.42 by @renovate[bot] in [#6274](jdx/mise#6274)
- update taiki-e/install-action digest to 0154864 by @renovate[bot] in [#6273](jdx/mise#6273)

### Chore

- **(schema)** fix schema for subtasks by @risu729 in [#6289](jdx/mise#6289)
- update render:schema task by @risu729 in [#6275](jdx/mise#6275)

## [2025.9.9](https://github.com/jdx/mise/compare/v2025.9.8..v2025.9.9) - 2025-09-11

### 🐛 Bug Fixes

- **(backend)** make HTTP installs atomic and serialize with cache lock by @jdx in [#6259](jdx/mise#6259)
- **(env)** allow nested env._.path directives by @risu729 in [#6160](jdx/mise#6160)
- **(env)** disallow nested env objects by @risu729 in [#6268](jdx/mise#6268)
- **(schema)** allow nested arrays in task.depends by @risu729 in [#6265](jdx/mise#6265)
- **(task)** resolve jobs=1 hang and keep-order panic; improve Ctrl-C handling by @jdx in [#6264](jdx/mise#6264)
- **(tasks)** stop CLI group after first failure without --continue-on-error by @jdx in [#6270](jdx/mise#6270)

### 📚 Documentation

- fixed toml issues in URL replacements settings documentation by @ThomasSteinbach in [#6269](jdx/mise#6269)

### Chore

- **(schema)** strict oneOf branches and DRY env_directive in schemas by @jdx in [#6271](jdx/mise#6271)
- add schema linter by @risu729 in [#6267](jdx/mise#6267)

## [2025.9.8](https://github.com/jdx/mise/compare/v2025.9.7..v2025.9.8) - 2025-09-10

### 🐛 Bug Fixes

- **(tasks)** prevent hang when task fails in sequence by @jdx in [#6260](jdx/mise#6260)
- **(version)** fetch mise version if cached version is older than the current by @risu729 in [#6252](jdx/mise#6252)

### 📦️ Dependency Updates

- update rhysd/action-setup-vim action to v1.4.3 by @renovate[bot] in [#6249](jdx/mise#6249)

## [2025.9.7](https://github.com/jdx/mise/compare/v2025.9.6..v2025.9.7) - 2025-09-09

### 🐛 Bug Fixes

- **(env)** allow mixed map for env._.file by @risu729 in [#6148](jdx/mise#6148)
- **(tasks)** restore parallel starts with poetry via list_paths cache and stable exec-env cache by @jdx in [#6237](jdx/mise#6237)
- add 'unknown' to the list of OS patterns by @efussi in [#6235](jdx/mise#6235)
- propagate errors from backend installs by @jdx in [#6236](jdx/mise#6236)

### 📦️ Dependency Updates

- update taiki-e/install-action digest to 0c5db7f by @renovate[bot] in [#6244](jdx/mise#6244)
- update golang docker tag to v1.25.1 by @renovate[bot] in [#6247](jdx/mise#6247)
- update dependency vitepress to v1.6.4 by @renovate[bot] in [#6246](jdx/mise#6246)

### New Contributors

- @efussi made their first contribution in [#6235](jdx/mise#6235)
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