feat(edit): add interactive config editor (mise edit)#7930
Conversation
|
Warning You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again! |
There was a problem hiding this comment.
Pull request overview
This PR adds an interactive wizard to mise config generate that auto-detects tools from project files and provides a user-friendly configuration experience. The command now defaults to interactive mode when TTY is detected and writes directly to mise.toml.
Changes:
- Interactive wizard with tool detection from package.json, go.mod, pyproject.toml, and version files
- Multi-select interface for adding tools from the registry with searchable filtering
- New flags:
-n/--dry-runfor preview mode and-y/--yesto skip interactive mode - Changed default output from stdout to
mise.tomlfile
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
src/cli/config/generate.rs
Outdated
| detected.push(DetectedTool { | ||
| name: "bun".to_string(), | ||
| version: None, | ||
| source: "bun.lock".to_string(), |
There was a problem hiding this comment.
The source is always set to 'bun.lock' even when 'bun.lockb' is detected. This should reflect the actual file found (either 'bun.lockb' or 'bun.lock').
| detected.push(DetectedTool { | |
| name: "bun".to_string(), | |
| version: None, | |
| source: "bun.lock".to_string(), | |
| let source = if cwd.join("bun.lockb").exists() { | |
| "bun.lockb" | |
| } else { | |
| "bun.lock" | |
| }; | |
| detected.push(DetectedTool { | |
| name: "bun".to_string(), | |
| version: None, | |
| source: source.to_string(), |
src/cli/config/generate.rs
Outdated
| if !env_vars.is_empty() || load_dotenv { | ||
| config.push_str("[env]\n"); | ||
| if load_dotenv { | ||
| config.push_str("mise.file = \".env\"\n"); |
There was a problem hiding this comment.
The key 'mise.file' is inconsistent with TOML convention. Consider using an underscore separator like 'mise_file' or a nested structure to follow common TOML naming patterns.
| config.push_str("mise.file = \".env\"\n"); | |
| config.push_str("[env.mise]\n"); | |
| config.push_str("file = \".env\"\n"); |
src/cli/config/generate.rs
Outdated
| fn quote_toml_value(s: &str) -> String { | ||
| format!("\"{}\"", s.replace('\\', "\\\\").replace('"', "\\\"")) | ||
| } |
There was a problem hiding this comment.
This function manually escapes TOML values, which is error-prone. Consider using the toml crate's serialization functionality to properly escape values according to the TOML specification.
Hyperfine Performance
|
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.1.12 x -- echo |
19.7 ± 0.2 | 19.2 | 20.9 | 1.01 ± 0.02 |
mise x -- echo |
19.6 ± 0.4 | 19.0 | 24.2 | 1.00 |
mise env
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.1.12 env |
19.2 ± 0.6 | 18.5 | 24.7 | 1.00 ± 0.04 |
mise env |
19.1 ± 0.3 | 18.4 | 21.2 | 1.00 |
mise hook-env
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.1.12 hook-env |
19.8 ± 0.3 | 19.3 | 21.2 | 1.00 ± 0.02 |
mise hook-env |
19.8 ± 0.3 | 19.2 | 21.1 | 1.00 |
mise ls
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.1.12 ls |
17.7 ± 0.3 | 17.2 | 19.3 | 1.00 |
mise ls |
17.8 ± 0.4 | 17.1 | 20.7 | 1.00 ± 0.03 |
xtasks/test/perf
| Command | mise-2026.1.12 | mise | Variance |
|---|---|---|---|
| install (cached) | 109ms | 110ms | +0% |
| ls (cached) | 69ms | 69ms | +0% |
| bin-paths (cached) | 73ms | 73ms | +0% |
| task-ls (cached) | 529ms | 530ms | +0% |
mise config generatemise edit)
27849d1 to
ec8a68e
Compare
mise edit)mise edit)
| self.mode = Mode::RenameKey(section_idx, entry_idx, InlineEdit::new(&key)); | ||
| // Note: We'll need to track the field_idx somehow | ||
| // For now, we only support entry rename | ||
| } |
There was a problem hiding this comment.
Rename inline table field modifies wrong key
Medium Severity
When renaming an inline table field (e.g., version in node = { version = "20" }), the field_idx is not stored in Mode::RenameKey. The edit box misleadingly shows the field's key name, but when confirmed, handle_rename_key renames entry.key (the parent entry) instead of the field. A comment acknowledges this: "We'll need to track the field_idx somehow. For now, we only support entry rename" — but the UI still shows "r rename" for inline table fields, misleading users.
Additional Locations (1)
| } | ||
| } | ||
| } | ||
| Ok(None) |
There was a problem hiding this comment.
Text editing key handlers duplicate cursor navigation logic
Low Severity
handle_backend_tool_name_key and handle_rename_key (lines 673-737) duplicate nearly identical key handling patterns for ArrowLeft, ArrowRight, Home, End, Backspace, Del, and Char(c). Both methods call the same InlineEdit methods and only differ in how they restore the mode. This pattern could be extracted into a helper method or macro.
- Interactive by default when TTY detected, skipped with `-y` - Auto-detects tools from project files: - Node.js from package.json, .nvmrc, .node-version - Python from .python-version, pyproject.toml - Go from go.mod - Ruby from .ruby-version, Gemfile - Package managers (pnpm, yarn, bun, uv, poetry) from lockfiles - Searchable multi-select to add tools from registry - Prompts for environment variables and .env file loading - Writes to mise.toml by default (not stdout) - Add `-n`/`--dry-run` flag to preview without writing Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add `detect` field to registry schema for tool detection - Add detect patterns for node, python, go, ruby, bun, pnpm, yarn, uv, poetry - Replace hardcoded detection with registry-driven detection - Use menu-driven interface instead of linear wizard flow - Add mise.lock prompt to wizard Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add config preview displayed above menu each iteration - Separate add/edit tool operations for better UX with large registry - Truncate tool descriptions to 60 chars to prevent UI overflow - Use FOO=bar format for env vars (KEY= to remove) - Add min_version option to wizard state and menu - Document config generate in walkthrough guide Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Detects useful settings based on project context: - idiomatic_version_file when .nvmrc/.python-version etc. exist - _.path for node_modules/.bin, .venv/bin, or ./bin - python.uv_venv_auto when Python + uv detected Shows "Suggested settings" menu option with context-aware recommendations that users can select. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replace deprecated idiomatic_version_file boolean with the per-tool idiomatic_version_file_enable_tools list setting. Now suggests per-tool settings like: idiomatic_version_file_enable_tools = ["node", "python"] Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Remove confirmation prompt - detected tools are now automatically added to the config. Users can remove unwanted tools via the "Edit/remove tools" menu option. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add comprehensive undo system covering all actions (add/edit/delete/rename) - Extract schema info from mise.json at build time for validation - Classify top-level properties as sections vs entries (min_version is entry, not section) - Generate settings keys with dot notation for nested settings - Add common hook names for autocomplete - Rename command from `mise config generate` to `mise edit` Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add picker for [settings] section with all valid settings from schema - Add picker for [hooks] section with common hook names - Filter out already-existing keys in pickers Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add picker for [task_config] section with dir, includes keys - Add picker for [monorepo] section with config_roots key - Add missing descriptions to schema for env, hooks, vars, watch_files, etc. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add support for top-level TOML entries (like min_version, experimental_monorepo_root) that are not part of a section: - Parse top-level entries into a root section with empty name - Serialize root section entries directly to document root - Display root section as "(root)" in the UI - Allow adding entries from schema's SCHEMA_ENTRIES via section picker - Section picker now shows both sections and top-level entries - Selected items are correctly added as sections or entries based on type Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Extract type information from JSON schema at build time for settings, entries, task_config, monorepo (boolean, integer, number, array, object) - Add type-appropriate defaults: booleans default to true, arrays to [], objects to empty inline tables, numbers prompt for input - Fix _.path serialization: use dotted key notation in env section instead of quoted key "_.path" (creates nested _.path structure) - Add Prepare section support: prepare providers default to inline tables - Handle redactions as array type, experimental_monorepo_root as boolean - Add tests for dotted key serialization and type detection Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Split 1867-line editor.rs into focused modules: - editor/mod.rs (265 lines) - Main struct, construction, run loop - editor/handlers.rs (715 lines) - Key handlers for each mode - editor/actions.rs (890 lines) - Business logic for mutations - editor/undo.rs (34 lines) - UndoAction enum - Add boolean true/false picker for boolean schema types - Box PickerState in Mode enum to reduce variant size - Update docs/walkthrough.md to reference `mise edit` with tip callout Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Shows a spinner with status messages while: - Loading existing config file - Detecting tools from project files - Detecting prepare providers The spinner clears with "Ready" before the TUI starts. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Show loading indicator in TUI while fetching version info for tools - Add Mode::Loading variant for transient loading states - Store path_display in InteractiveConfig for handlers to trigger renders - Fix single-character quote causing slice panic in env variables - Fix undo tracking for duplicate sections (no-op add_section) - Clear undo stack when creating root section to prevent index corruption Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Detect boolean settings by schema type when editing entries - Use left/right arrow keys to toggle true/false instead of text input - Support boolean editing for inline table fields (e.g., compile = true) - Display boolean values without quotes in the TUI Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Sort failed installations alphabetically for deterministic output (from #7936) - Add cargo-machete ignore for serde_json build dependency Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Fix nested TOML tables silently ignored in document.rs parse_entry - Add undo tracking for version selection edits - Fix generate config test to use -n flag for stdout output Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
cf03f94 to
2290440
Compare
When all predefined items exist in these sections, the add button falls
back to manual text entry. Previously, apply_new_key had no handlers for
Hook, TaskConfig, or Monorepo - they fell through to _ => {} and silently
discarded user input.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
### 🚀 Features - **(edit)** add interactive config editor (`mise edit`) by @jdx in [#7930](#7930) - **(lockfile)** graduate lockfiles from experimental by @jdx in [#7929](#7929) - **(task)** add support for usage values in task confirm dialog by @roele in [#7924](#7924) - **(task)** improve source freshness checking with edge case handling by @jdx in [#7932](#7932) ### 🐛 Bug Fixes - **(activate)** preserve ordering of paths appended after mise activate by @jdx in [#7919](#7919) - **(install)** sort failed installations for deterministic error output by @jdx in [#7936](#7936) - **(lockfile)** preserve URL and prefer sha256 when merging platform info by @jdx in [#7923](#7923) - **(lockfile)** add atomic writes and cache invalidation by @jdx in [#7927](#7927) - **(templates)** use sha256 for hash filter instead of blake3 by @jdx in [#7925](#7925) - **(upgrade)** respect tracked configs when pruning old versions by @jdx in [#7926](#7926) ### 🚜 Refactor - **(progress)** migrate from indicatif to clx by @jdx in [#7928](#7928) ### 📚 Documentation - improve clarity on uvx and pipx dependencies by @ygormutti in [#7878](#7878) ### ⚡ Performance - **(install)** use Kahn's algorithm for dependency scheduling by @jdx in [#7933](#7933) - use Aho-Corasick for efficient redaction by @jdx in [#7931](#7931) ### 🧪 Testing - remove flaky test_http_version_list test by @jdx in [#7934](#7934) ### Chore - use github backend instead of ubi in mise.lock by @jdx in [#7922](#7922) ### New Contributors - @ygormutti made their first contribution in [#7878](#7878)
## Summary Adds a new `mise edit` command that provides an interactive TUI for editing mise configuration files. The editor treats the TOML config as a navigable menu where users can: - **Navigate** sections and entries with arrow keys or vim bindings (j/k/h/l) - **Add tools** via fuzzy-searchable picker with ~500+ tools from the registry - **Select versions** with smart version cycling (latest → major → minor → full) - **Edit values** inline with cursor navigation - **Undo changes** with `u` key - **Auto-detect tools** from project files (.nvmrc, pyproject.toml, etc.) ### Key Features - **Schema-aware editing**: Uses JSON schema to provide appropriate defaults and pickers for settings, hooks, task_config, and monorepo sections - **Type-aware inputs**: Boolean settings show true/false picker, arrays start empty, numbers prompt for input - **Section-specific add buttons**: [tools] shows "Add tool from registry" and "Add tool from backend", [env] shows "Add PATH", "Load .env", "Add variable" - **Dotted key support**: Properly handles `_.path` and `_.source` notation for env section - **Dry-run mode**: Preview changes without writing to disk ### Architecture The editor is implemented in a separate `mise-interactive-config` crate with clear module separation: ``` mise-interactive-config/ ├── cursor.rs - Navigation state and position tracking ├── document.rs - TOML document model and serialization ├── editor/ │ ├── mod.rs - Main editor struct and run loop │ ├── handlers.rs - Key handlers for each mode │ ├── actions.rs - Business logic for mutations │ └── undo.rs - Undo system ├── picker.rs - Fuzzy search picker ├── render.rs - Terminal rendering ├── schema.rs - Build-time schema extraction └── providers.rs - Trait interfaces for tool/version data ``` ## Test plan - [x] `cargo build` compiles successfully - [x] `cargo test -p mise-interactive-config` - 37 tests pass - [x] Manual testing of interactive editor - [ ] Test tool picker with registry tools - [ ] Test version selector cycling - [ ] Test undo/redo functionality - [ ] Test dry-run mode 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Medium risk due to introducing a large new TUI/editor codepath that reads/writes config files and adds new schema/registry build-time codegen (`detect`), which could affect tooling detection and config serialization behavior. > > **Overview** > Introduces a new workspace crate, `mise-interactive-config`, implementing an interactive terminal editor for `mise.toml` (navigation, inline edits, fuzzy pickers, undo, type-aware defaults, and schema-driven key pickers). > > Adds the `mise edit` CLI command wired to this editor, including registry-backed tool and backend pickers, async version lookup, dry-run support, and automatic tool/prepare detection based on registry `detect` files. > > Updates build/codegen and dependencies to support this: registry codegen now emits a `detect` field for tools, the workspace and root crate depend on the new crate, and `Cargo.lock` is updated accordingly. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 0c42b63. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
### 🚀 Features - **(edit)** add interactive config editor (`mise edit`) by @jdx in [jdx#7930](jdx#7930) - **(lockfile)** graduate lockfiles from experimental by @jdx in [jdx#7929](jdx#7929) - **(task)** add support for usage values in task confirm dialog by @roele in [jdx#7924](jdx#7924) - **(task)** improve source freshness checking with edge case handling by @jdx in [jdx#7932](jdx#7932) ### 🐛 Bug Fixes - **(activate)** preserve ordering of paths appended after mise activate by @jdx in [jdx#7919](jdx#7919) - **(install)** sort failed installations for deterministic error output by @jdx in [jdx#7936](jdx#7936) - **(lockfile)** preserve URL and prefer sha256 when merging platform info by @jdx in [jdx#7923](jdx#7923) - **(lockfile)** add atomic writes and cache invalidation by @jdx in [jdx#7927](jdx#7927) - **(templates)** use sha256 for hash filter instead of blake3 by @jdx in [jdx#7925](jdx#7925) - **(upgrade)** respect tracked configs when pruning old versions by @jdx in [jdx#7926](jdx#7926) ### 🚜 Refactor - **(progress)** migrate from indicatif to clx by @jdx in [jdx#7928](jdx#7928) ### 📚 Documentation - improve clarity on uvx and pipx dependencies by @ygormutti in [jdx#7878](jdx#7878) ### ⚡ Performance - **(install)** use Kahn's algorithm for dependency scheduling by @jdx in [jdx#7933](jdx#7933) - use Aho-Corasick for efficient redaction by @jdx in [jdx#7931](jdx#7931) ### 🧪 Testing - remove flaky test_http_version_list test by @jdx in [jdx#7934](jdx#7934) ### Chore - use github backend instead of ubi in mise.lock by @jdx in [jdx#7922](jdx#7922) ### New Contributors - @ygormutti made their first contribution in [jdx#7878](jdx#7878)


Summary
Adds a new
mise editcommand that provides an interactive TUI for editing mise configuration files. The editor treats the TOML config as a navigable menu where users can:ukeyKey Features
_.pathand_.sourcenotation for env sectionArchitecture
The editor is implemented in a separate
mise-interactive-configcrate with clear module separation:Test plan
cargo buildcompiles successfullycargo test -p mise-interactive-config- 37 tests pass🤖 Generated with Claude Code
Note
Medium Risk
Medium risk due to introducing a large new TUI/editor codepath that reads/writes config files and adds new schema/registry build-time codegen (
detect), which could affect tooling detection and config serialization behavior.Overview
Introduces a new workspace crate,
mise-interactive-config, implementing an interactive terminal editor formise.toml(navigation, inline edits, fuzzy pickers, undo, type-aware defaults, and schema-driven key pickers).Adds the
mise editCLI command wired to this editor, including registry-backed tool and backend pickers, async version lookup, dry-run support, and automatic tool/prepare detection based on registrydetectfiles.Updates build/codegen and dependencies to support this: registry codegen now emits a
detectfield for tools, the workspace and root crate depend on the new crate, andCargo.lockis updated accordingly.Written by Cursor Bugbot for commit 0c42b63. This will update automatically on new commits. Configure here.