Skip to content

feat(prepare): add --explain flag for provider diagnostics#8409

Merged
jdx merged 10 commits into
mainfrom
feat/prepare-explain
Mar 2, 2026
Merged

feat(prepare): add --explain flag for provider diagnostics#8409
jdx merged 10 commits into
mainfrom
feat/prepare-explain

Conversation

@jdx

@jdx jdx commented Mar 2, 2026

Copy link
Copy Markdown
Owner

Summary

  • Add mise prepare --explain <provider> flag to show detailed diagnostic info about a specific prepare provider
  • Shows sources (+/-), outputs (+/-), auto status, command, and fresh/stale verdict with reason
  • Exit code 0 if fresh, 1 if stale (useful for scripting)
  • Also adds FreshnessResult enum for structured freshness checking with human-readable stale reasons in dry-run output

Test plan

  • E2e tests for --explain with stale provider (missing output)
  • E2e tests for --explain with fresh provider
  • E2e tests for --explain with unknown provider
  • All existing prepare e2e tests pass

🤖 Generated with Claude Code


Note

Low Risk
Primarily adds an experimental CLI flag and supporting output paths; the main behavior change is new positional provider filtering and --explain returning non-zero when stale.

Overview
Adds provider-level diagnostics to mise prepare via a new --explain mode and an optional positional [PROVIDER] argument to target a single prepare provider.

--explain prints the provider’s sources/outputs (with existence markers), auto status, command, and a fresh/stale verdict (exiting non-zero when stale), backed by new PrepareEngine APIs to find a provider and expose its freshness check.

Updates generated CLI docs/man page/fig completions to reflect the new argument/flag and extends e2e/cli/test_prepare to cover --explain for fresh, stale, and unknown providers.

Written by Cursor Bugbot for commit e2580f1. This will update automatically on new commits. Configure here.

@gemini-code-assist

Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, 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 enhances the mise prepare command by introducing a new --explain flag. This feature provides users with in-depth diagnostic information about why a particular prepare provider is considered fresh or stale, making it easier to debug and understand the state of their development environment. The change also refines the internal freshness checking mechanism to offer more granular and descriptive reasons for a provider's status, improving the overall transparency and utility of the prepare command.

Highlights

  • New --explain flag: A new --explain flag has been added to mise prepare, allowing users to get detailed diagnostic information about a specific prepare provider.
  • Detailed Provider Diagnostics: The --explain flag outputs comprehensive details including sources, outputs, auto status, the command executed, and a clear verdict of 'fresh' or 'stale' with a specific reason.
  • Exit Code for Scripting: The mise prepare --explain command now exits with code 0 if the provider is fresh and 1 if it is stale, which is useful for scripting and automation.
  • Enhanced Freshness Logic: A new FreshnessResult enum was introduced to provide structured and human-readable reasons for a provider's freshness or staleness, improving clarity in dry-run outputs and diagnostics.
Changelog
  • e2e/cli/test_prepare
    • Added new end-to-end tests to verify the functionality of the mise prepare --explain command, covering scenarios for stale, fresh, and unknown providers.
  • src/cli/prepare.rs
    • Introduced the --explain CLI argument to the Prepare struct.
    • Implemented the explain_provider function to handle the logic for displaying detailed provider diagnostics.
    • Modified the PrepareStepResult::WouldRun variant to include a reason, enhancing dry-run output.
  • src/prepare/engine.rs
    • Defined a new FreshnessResult enum to encapsulate detailed reasons for a provider's freshness or staleness.
    • Updated the PrepareStepResult::WouldRun enum variant to accept a reason string.
    • Added find_provider and check_provider_freshness methods to the PrepareEngine for querying specific providers and their freshness.
    • Refactored the check_freshness method to return the new FreshnessResult enum, providing more informative outcomes instead of a simple boolean.
Activity
  • The initial code for this feature was generated using Claude Code.
  • End-to-end tests for the new --explain flag have been implemented and confirmed to pass, covering various scenarios including stale, fresh, and unknown providers.
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.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

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 --explain flag to mise prepare for diagnosing provider freshness, which is a great addition for usability and scripting. The implementation is solid, introducing a FreshnessResult enum for structured freshness checks and detailed reasons. The e2e tests are comprehensive. I've made a couple of suggestions to improve code quality by removing an explicit exit call in favor of standard error handling and pointing out some potentially unreachable code. Overall, this is a well-executed feature.

Comment thread src/cli/prepare.rs Outdated
Comment on lines +108 to +114
miseprintln!("Provider '{}' not found", provider_id);
miseprintln!("");
miseprintln!("Available providers:");
for p in engine.list_providers() {
miseprintln!(" {}", p.id());
}
std::process::exit(1);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

Calling std::process::exit here makes the function harder to test and reuse. It's better to return a Result and let the caller handle exiting. You can use eyre::bail! to return an error with a formatted message.

You'll need to add use itertools::Itertools; at the top of the file.

Suggested change
miseprintln!("Provider '{}' not found", provider_id);
miseprintln!("");
miseprintln!("Available providers:");
for p in engine.list_providers() {
miseprintln!(" {}", p.id());
}
std::process::exit(1);
let available_providers = engine
.list_providers()
.iter()
.map(|p| format!(" {}", p.id()))
.collect::<Vec<_>>()
.join("\n");
eyre::bail!("Provider '{}' not found.\n\nAvailable providers:\n{}", provider_id, available_providers);

Comment thread src/prepare/engine.rs Outdated
Comment on lines +489 to +491
(_, None) => Ok(FreshnessResult::OutputsMissing(
"outputs do not exist".to_string(),
)),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

This match arm appears to be unreachable. The loop at lines 455-462 checks for missing outputs and returns early if any are found. If execution reaches this point, it means all output paths exist, so Self::last_modified(&outputs) should always return Some, making outputs_mtime always Some. You can likely remove this arm.

Comment thread src/prepare/engine.rs
@greptile-apps

greptile-apps Bot commented Mar 2, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

adds --explain flag to provide detailed diagnostics for prepare providers

Key Changes

  • Introduces FreshnessResult enum to track staleness reasons (no outputs, missing outputs, sources newer, session stale)
  • New mise prepare --explain <provider> command shows sources/outputs existence, command to run, and fresh/stale verdict with reason
  • Exit code 0 for fresh providers, 1 for stale (useful for scripting)
  • Updates dry-run output to include staleness reason: Would prepare: npm (package.json is newer than outputs)

Implementation Quality

  • Well-structured enum design makes freshness logic explicit and testable
  • Comprehensive E2E tests cover stale, fresh, and unknown provider scenarios
  • Defensive fallback in mtime matching handles edge cases where metadata isn't readable

Confidence Score: 5/5

  • safe to merge - well-tested feature addition with clear semantics
  • comprehensive E2E tests cover all code paths, refactoring improves code clarity without changing existing behavior, defensive programming handles edge cases
  • no files require special attention

Important Files Changed

Filename Overview
e2e/cli/test_prepare adds comprehensive tests for --explain flag covering stale, fresh, and unknown provider cases
src/cli/prepare.rs implements --explain flag with diagnostic output and proper exit codes (0=fresh, 1=stale)
src/prepare/engine.rs refactors freshness checking to use FreshnessResult enum with detailed reasons for staleness

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    Start[check_freshness] --> CheckOutputs{outputs.is_empty?}
    CheckOutputs -->|yes| NoOutputs[Return NoOutputs]
    CheckOutputs -->|no| CheckSession{any output in STALE_OUTPUTS?}
    CheckSession -->|yes| SessionStale[Return SessionStale]
    CheckSession -->|no| CheckExists{all outputs exist?}
    CheckExists -->|no| Missing[Return OutputsMissing]
    CheckExists -->|yes| GetMtimes[Get sources & outputs mtimes]
    GetMtimes --> Match{Match mtimes}
    Match -->|src > out| Stale[Return Stale]
    Match -->|src <= out| Fresh[Return Fresh]
    Match -->|no sources| NoSources[Return NoSources]
    Match -->|outputs unreadable| MissingFallback[Return OutputsMissing]
Loading

Fix All in Claude Code

Last reviewed commit: 937dd23

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

3 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

Comment thread src/prepare/engine.rs Outdated
.map(|p| p.as_ref())
}

/// Check freshness for a specific provider (public API for --why)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

comment says --why but the actual flag is --explain

Suggested change
/// Check freshness for a specific provider (public API for --why)
/// Check freshness for a specific provider (public API for --explain)

Fix in Claude Code

@jdx jdx force-pushed the feat/prepare-explain branch from 11aa4f0 to da3c742 Compare March 2, 2026 02:43
@jdx

jdx commented Mar 2, 2026

Copy link
Copy Markdown
Owner Author

bugbot run

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

jdx and others added 9 commits March 2, 2026 03:06
Add `mise prepare --explain <provider>` to show detailed diagnostic
info about a specific provider: sources, outputs, command, auto status,
and fresh/stale verdict with reason. Exit code 0 if fresh, 1 if stale.

Also adds FreshnessResult enum for structured freshness checking with
human-readable stale reasons shown in dry-run output.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix check_staleness unwrap_or(true) -> unwrap_or(false) to preserve
  "assume fresh on error" behavior and avoid spurious stale warnings
- Replace std::process::exit with bail! in explain_provider
- Fix unreachable (_, None) match arm to use Stale instead of
  OutputsMissing since missing outputs are already handled above
- Fix comment referencing --why instead of --explain

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Change `mise prepare --explain <provider>` to `mise prepare <provider> --explain`.
The positional provider argument also works without --explain to run
just that provider (like --only).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Reorder struct fields so long-only flags appear in alphabetical order:
--explain, --list, --only, --skip.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Fixes test_subcommands_are_sorted failure by reordering struct fields
so -f (force) comes before -n (dry-run).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@jdx jdx force-pushed the feat/prepare-explain branch from b0e4ee7 to e2580f1 Compare March 2, 2026 03:07
@jdx jdx enabled auto-merge (squash) March 2, 2026 03:18
@jdx jdx merged commit 8709309 into main Mar 2, 2026
34 checks passed
@jdx jdx deleted the feat/prepare-explain branch March 2, 2026 03:29
@github-actions

github-actions Bot commented Mar 2, 2026

Copy link
Copy Markdown

Hyperfine Performance

mise x -- echo

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.2.24 x -- echo 28.4 ± 1.0 27.4 39.2 1.19 ± 0.06
mise x -- echo 24.0 ± 0.8 22.6 29.7 1.00
✅ Performance improvement for x -- echo is 19%

mise env

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.2.24 env 28.0 ± 0.7 27.0 32.7 1.21 ± 0.04
mise env 23.2 ± 0.4 22.4 25.7 1.00
✅ Performance improvement for env is 21%

mise hook-env

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.2.24 hook-env 29.1 ± 0.8 27.9 39.6 1.17 ± 0.05
mise hook-env 24.8 ± 0.8 23.2 30.2 1.00
✅ Performance improvement for hook-env is 17%

mise ls

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.2.24 ls 24.2 ± 0.8 22.4 29.5 1.02 ± 0.04
mise ls 23.6 ± 0.5 21.5 27.7 1.00

xtasks/test/perf

Command mise-2026.2.24 mise Variance
install (cached) 167ms 154ms +8%
ls (cached) 91ms 83ms +9%
bin-paths (cached) 99ms ✅ 88ms +12%
task-ls (cached) 856ms 845ms +1%

✅ Performance improvement: bin-paths cached is 12%

jdx pushed a commit that referenced this pull request Mar 2, 2026
### 🚀 Features

- **(hooks)** add task references to hooks and watch_files by @jdx in
[#8400](#8400)
- **(prepare)** add git-submodule built-in provider by @jdx in
[#8407](#8407)
- **(prepare)** add human-readable stale reasons to prepare output by
@jdx in [#8408](#8408)
- **(prepare)** add dependency ordering to prepare steps by @jdx in
[#8401](#8401)
- **(prepare)** add --explain flag for provider diagnostics by @jdx in
[#8409](#8409)
- **(prepare)** add per-provider timeout support by @jdx in
[#8405](#8405)
- **(prepare)** add blake3 content-hash freshness checking by @jdx in
[#8404](#8404)
- **(tasks)** monorepo vars and per-task vars by @halms in
[#8248](#8248)

### 🐛 Bug Fixes

- **(aqua)** restore bin_paths disk cache with fresh_file invalidation
by @jdx in [#8398](#8398)
- **(idiomatic)** use generic parser for idiomatic files by @risu729 in
[#8171](#8171)
- **(install)** apply precompiled options to all platforms in lockfile
by @jdx in [#8396](#8396)
- **(install)** normalize "v" prefix when matching lockfile versions by
@jdx in [#8413](#8413)
- **(prepare)** improve git submodule parser and fix check_staleness
error handling by @jdx in [#8412](#8412)
- **(python)** respect precompiled settings in lock file generation by
@jdx in [#8399](#8399)
- **(python)** clarify uv_venv_auto docs + prevent uv shim recursion in
venv creation by @halms in
[#8402](#8402)
- **(task)** remove deprecated `# mise` task header syntax by @jdx in
[#8403](#8403)
- **(vfox)** avoid eager metadata loading during config file detection
by @jdx in [#8397](#8397)
- clarify GitHub attestations to be artifact ones by @scop in
[#8394](#8394)
- ignore comments in idiomatic version files by @iloveitaly in
[#7682](#7682)

### 🚜 Refactor

- unify archive detection by @risu729 in
[#8137](#8137)

### 📚 Documentation

- remove duplicated docs for npm.package_manager by @risu729 in
[#8414](#8414)
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.

1 participant