Repository navigation
feat(bootstrap): add package manager plugin support - #11023
Conversation
Entire-Checkpoint: 374a4c107b0d
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdds package-plugin support through typed Lua hooks, plugin discovery and configuration, package state/actions, and integration with the system package-manager registry. ChangesPackage plugin support
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant PackagePluginManager
participant Vfox
participant LuaHook
PackagePluginManager->>Vfox: dispatch package action
Vfox->>LuaHook: evaluate package hook
LuaHook-->>Vfox: return package response
Vfox-->>PackagePluginManager: map result to package status
Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Greptile SummaryThis PR introduces
Confidence Score: 4/5The new package plugin path is optional and collision-guarded, so it cannot corrupt existing workflows. The issues flagged in earlier review rounds — particularly the permanent VersionMismatch loop when a plugin confirms installation without reporting a version, and the lock dropped before directory cleanup — are real behavioral defects in the new code paths and warrant fixing before the feature is relied upon in production configs. src/system/packages/plugin.rs (version-mismatch with None version) and src/system/packages/mod.rs (all_managers rebuilds the full list including TOML reads on every call) Important Files Changed
Reviews (6): Last reviewed commit: "fix(plugins): require complete package h..." | Re-trigger Greptile |
| pub fn all_managers() -> Vec<Arc<dyn SystemPackageManager>> { | ||
| let mut managers = builtin_managers(); | ||
| let builtins = managers | ||
| .iter() | ||
| .map(|manager| manager.name().to_string()) | ||
| .collect::<std::collections::HashSet<_>>(); | ||
| for (name, plugin_type) in crate::toolset::install_state::list_plugins().iter() { | ||
| if *plugin_type != crate::plugins::PluginType::Package { | ||
| continue; | ||
| } | ||
| if builtins.contains(name) { | ||
| warn!( | ||
| "package plugin '{name}' collides with a built-in package manager; ignoring plugin" | ||
| ); | ||
| continue; | ||
| } | ||
| match plugin::PackagePluginManager::new(name.clone()) { | ||
| Ok(manager) => managers.push(Arc::new(manager)), | ||
| Err(err) => warn!("failed to load package plugin '{name}': {err:#}"), | ||
| } | ||
| } | ||
| managers | ||
| } | ||
|
|
||
| pub fn get_manager(name: &str) -> Option<Arc<dyn SystemPackageManager>> { | ||
| all_managers().into_iter().find(|m| m.name() == name) | ||
| } |
There was a problem hiding this comment.
Repeated disk I/O on every
all_managers() call
all_managers() is synchronous and rebuilds the full manager list on every invocation, which now includes reading mise.plugin.toml from disk for each installed package plugin (inside PackagePluginManager::new). get_manager() calls all_managers() to find a single entry, meaning a lookup for any package triggers a full plugin-directory scan and TOML parse for every registered package plugin. If bootstrap has several package plugins or if get_manager / all_managers is called on a hot path (e.g. per-package install loop), this accumulates redundant I/O. Consider memoising the list — a once_cell::sync::Lazy or a short-lived cache passed through the call stack would eliminate the repeated work without changing the calling convention.
Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
Entire-Checkpoint: 524def15396b
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (2)
crates/vfox/src/hooks/package.rs (1)
76-128: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueLeverage
mlua's sequence traits for cleaner serialization.Instead of manually constructing and iterating tables for the arrays, you can implement
IntoLuaforPackageRequestandFromLuaforInstalledPackage.mluaautomatically providesIntoLuaandFromLuaforVec<T>, making the context and response conversions more concise and idiomatic.♻️ Proposed refactor
-fn packages_into_lua(packages: Vec<PackageRequest>, lua: &Lua) -> mlua::Result<Value> { - let list = lua.create_table()?; - for (index, package) in packages.into_iter().enumerate() { - let item = lua.create_table()?; - item.set("name", package.name)?; - item.set("version", package.version)?; - list.set(index + 1, item)?; - } - Ok(Value::Table(list)) -} - +impl IntoLua for PackageRequest { + fn into_lua(self, lua: &Lua) -> mlua::Result<Value> { + let table = lua.create_table()?; + table.set("name", self.name)?; + table.set("version", self.version)?; + Ok(Value::Table(table)) + } +} + impl IntoLua for PackageInstalledContext { fn into_lua(self, lua: &Lua) -> mlua::Result<Value> { let table = lua.create_table()?; - table.set("packages", packages_into_lua(self.packages, lua)?)?; + table.set("packages", self.packages)?; Ok(Value::Table(table)) } } impl IntoLua for PackageActionContext { fn into_lua(self, lua: &Lua) -> mlua::Result<Value> { let table = lua.create_table()?; - table.set("packages", packages_into_lua(self.packages, lua)?)?; + table.set("packages", self.packages)?; table.set("dry_run", self.dry_run)?; table.set("update", self.update)?; Ok(Value::Table(table)) } } +impl FromLua for InstalledPackage { + fn from_lua(value: Value, _: &Lua) -> mlua::Result<Self> { + let Value::Table(table) = value else { + return Err(LuaError::FromLuaConversionError { + from: value.type_name(), + to: "InstalledPackage".to_string(), + message: Some("Expected table".to_string()), + }); + }; + Ok(Self { + name: table.get("name")?, + state: table.get("state")?, + version: table.get("version")?, + }) + } +} + impl FromLua for PackageInstalledResponse { fn from_lua(value: Value, _: &Lua) -> mlua::Result<Self> { let Value::Table(table) = value else { return Err(LuaError::FromLuaConversionError { from: value.type_name(), to: "PackageInstalledResponse".to_string(), message: Some("Expected table".to_string()), }); }; - let packages = table - .get::<mlua::Table>("packages")? - .sequence_values::<mlua::Table>() - .map(|item| { - let item = item?; - Ok(InstalledPackage { - name: item.get("name")?, - state: item.get("state")?, - version: item.get("version")?, - }) - }) - .collect::<mlua::Result<Vec<_>>>()?; + let packages = table.get("packages")?; Ok(Self { packages }) } }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@crates/vfox/src/hooks/package.rs` around lines 76 - 128, Refactor the Lua conversions by implementing IntoLua for PackageRequest and FromLua for InstalledPackage, moving each item’s field mapping into its respective conversion. Then replace packages_into_lua and the manual sequence iteration in PackageInstalledResponse::from_lua with direct Vec<PackageRequest>/Vec<InstalledPackage> table conversions, while preserving the existing field names and error behavior.src/system/packages/plugin.rs (1)
1-232: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winNo unit tests for the new
PackagePluginManagerlogic.Pure helpers like
platform_available(),missing_from_path(), and the state-mapping logic ininstalled()are new and non-trivial (opaque version matching, OS filtering, upgrade-hook fallback) but this file has no#[cfg(test)]module. Consider at least coveringplatform_available/missing_from_pathwith a temp-dir fixture and theinstalled()state-mapping branches (installed/missing/mismatch/invalid-state/unreturned) with a fakePackageInstalledResponse.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/system/packages/plugin.rs` around lines 1 - 232, Add a #[cfg(test)] module for PackagePluginManager covering platform_available and missing_from_path with temporary PATH fixtures, plus installed state mapping using a fake PackageInstalledResponse for installed, missing, version mismatch, invalid-state, and unreturned-package cases. Reuse existing constructors or test helpers where possible and keep production behavior unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/system/packages/plugin.rs`:
- Around line 41-66: Update the availability checks around platform_available,
sync_lookup_path, and missing_from_path to construct the lookup PATH using the
hook environment’s toolset.list_paths(&config) entries in addition to the
process PATH and shims directory. Ensure is_available() and unavailable_reason()
use this same hook PATH when resolving required binaries, so tools declared in
[tools] are recognized before install() or upgrade() is skipped.
---
Nitpick comments:
In `@crates/vfox/src/hooks/package.rs`:
- Around line 76-128: Refactor the Lua conversions by implementing IntoLua for
PackageRequest and FromLua for InstalledPackage, moving each item’s field
mapping into its respective conversion. Then replace packages_into_lua and the
manual sequence iteration in PackageInstalledResponse::from_lua with direct
Vec<PackageRequest>/Vec<InstalledPackage> table conversions, while preserving
the existing field names and error behavior.
In `@src/system/packages/plugin.rs`:
- Around line 1-232: Add a #[cfg(test)] module for PackagePluginManager covering
platform_available and missing_from_path with temporary PATH fixtures, plus
installed state mapping using a fake PackageInstalledResponse for installed,
missing, version mismatch, invalid-state, and unreturned-package cases. Reuse
existing constructors or test helpers where possible and keep production
behavior unchanged.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Central YAML (base), Organization UI (inherited)
Review profile: CHILL
Plan: Pro Plus
Run ID: bb52afcb-d922-467b-908c-240f36907ca9
📒 Files selected for processing (21)
crates/vfox/src/hooks/mod.rscrates/vfox/src/hooks/package.rscrates/vfox/src/lib.rscrates/vfox/src/lua_mod/hooks.rscrates/vfox/src/vfox.rssrc/cli/args/backend_arg.rssrc/cli/doctor/mod.rssrc/plugins/mise_plugin_toml.rssrc/plugins/mod.rssrc/plugins/vfox_plugin.rssrc/system/packages/apk.rssrc/system/packages/apt.rssrc/system/packages/brew/cask.rssrc/system/packages/brew/mod.rssrc/system/packages/dnf.rssrc/system/packages/flatpak.rssrc/system/packages/mas.rssrc/system/packages/mod.rssrc/system/packages/pacman.rssrc/system/packages/plugin.rssrc/toolset/install_state.rs
| fn platform_available(&self) -> bool { | ||
| self.config.os.as_ref().is_none_or(|oses| { | ||
| oses.iter() | ||
| .any(|os| os == crate::config::Settings::get().os()) | ||
| }) | ||
| } | ||
|
|
||
| fn sync_lookup_path() -> Vec<PathBuf> { | ||
| let mut paths: Vec<PathBuf> = std::env::var_os("PATH") | ||
| .map(|path| split_paths(&path).collect()) | ||
| .unwrap_or_default(); | ||
| if !paths.iter().any(|path| path == *crate::dirs::SHIMS) { | ||
| paths.push(crate::dirs::SHIMS.to_path_buf()); | ||
| } | ||
| paths | ||
| } | ||
|
|
||
| fn missing_from_path(&self, paths: &[PathBuf]) -> Option<&str> { | ||
| let path = join_paths(paths).ok()?; | ||
| let cwd = std::env::current_dir().ok()?; | ||
| self.config | ||
| .requires | ||
| .iter() | ||
| .find(|binary| which::which_in(binary, Some(&path), &cwd).is_err()) | ||
| .map(String::as_str) | ||
| } |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check how is_available()/unavailable_reason() are consumed for package managers,
# to confirm whether unavailable managers are filtered out before install/upgrade runs.
rg -n -B3 -A10 'is_available\(\)' src/cli/system/driver.rs src/system/packages/mod.rsRepository: jdx/mise
Length of output: 2223
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Map the plugin and package manager files first.
ast-grep outline src/system/packages/plugin.rs --view expanded
echo '---'
ast-grep outline src/system/packages/mod.rs --view expanded
echo '---'
rg -n -A4 -B4 'hook_env|checked_hook_env|list_paths|sync_lookup_path|missing_from_path|is_available|unavailable_reason' src/system/packages/plugin.rs src/system/packages/mod.rs src/cli/system/driver.rsRepository: jdx/mise
Length of output: 12169
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Read the relevant slices if outlines are too coarse.
sed -n '1,220p' src/system/packages/plugin.rsRepository: jdx/mise
Length of output: 7767
Use the hook PATH for availability checks is_available() / unavailable_reason() only inspect the raw process PATH, but the hook env also adds toolset.list_paths(&config). A package plugin whose required binary comes from [tools] can still run in install()/upgrade(), yet it gets skipped before those paths are considered.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/system/packages/plugin.rs` around lines 41 - 66, Update the availability
checks around platform_available, sync_lookup_path, and missing_from_path to
construct the lookup PATH using the hook environment’s
toolset.list_paths(&config) entries in addition to the process PATH and shims
directory. Ensure is_available() and unavailable_reason() use this same hook
PATH when resolving required binaries, so tools declared in [tools] are
recognized before install() or upgrade() is skipped.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/cli/bootstrap.rs`:
- Around line 1155-1161: Short-circuit asynchronous availability checks for
disabled package managers. In src/cli/bootstrap.rs lines 1155-1161,
src/cli/doctor/mod.rs lines 481-487 and 717-723, and src/cli/system/status.rs
lines 31-37, update each reason-selection flow to use the disabled-manager
message directly when mp.disabled is true and only await
mp.manager.unavailable_reason_async() when it is false, preserving the existing
unavailable-reason behavior otherwise.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Central YAML (base), Organization UI (inherited)
Review profile: CHILL
Plan: Pro Plus
Run ID: af7d5b13-1a66-497d-998c-09b33fe217d5
📒 Files selected for processing (8)
src/cli/bootstrap.rssrc/cli/doctor/mod.rssrc/cli/install.rssrc/cli/system/driver.rssrc/cli/system/status.rssrc/cli/system/use.rssrc/system/packages/mod.rssrc/system/packages/plugin.rs
🚧 Files skipped from review as they are similar to previous changes (2)
- src/system/packages/mod.rs
- src/system/packages/plugin.rs
| let unavailable = mp.manager.unavailable_reason_async().await; | ||
| if mp.disabled || unavailable.is_some() { | ||
| let reason = if mp.disabled { | ||
| "excluded by the system_packages.managers setting".to_string() | ||
| } else { | ||
| mp.manager.unavailable_reason() | ||
| unavailable.unwrap() | ||
| }; |
There was a problem hiding this comment.
🚀 Performance & Scalability | 🟡 Minor | ⚡ Quick win
Short-circuit async availability checks for disabled package managers.
mp.manager.unavailable_reason_async().await is awaited unconditionally before checking mp.disabled. For package plugins, computing this reason involves spawning a vfox subprocess to extract the plugin's environment variables. If a package manager is disabled via settings, we shouldn't pay the cost of executing its hook or risk a failure if the plugin is broken.
Refactor these sites to lazily evaluate the async availability check only when mp.disabled is false:
src/cli/bootstrap.rs#L1155-L1161: defer the async call by determining thereasondirectly.src/cli/doctor/mod.rs#L481-L487: apply the same short-circuit logic here.src/cli/doctor/mod.rs#L717-L723: apply the same short-circuit logic here.src/cli/system/status.rs#L31-L37: apply the same short-circuit logic here.
⚡ Proposed fix (applicable to all occurrences)
- let unavailable = mp.manager.unavailable_reason_async().await;
- if mp.disabled || unavailable.is_some() {
- let reason = if mp.disabled {
- "excluded by the system_packages.managers setting".to_string()
- } else {
- unavailable.unwrap()
- };
+ let reason = if mp.disabled {
+ Some("excluded by the system_packages.managers setting".to_string())
+ } else {
+ mp.manager.unavailable_reason_async().await
+ };
+ if let Some(reason) = reason {📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| let unavailable = mp.manager.unavailable_reason_async().await; | |
| if mp.disabled || unavailable.is_some() { | |
| let reason = if mp.disabled { | |
| "excluded by the system_packages.managers setting".to_string() | |
| } else { | |
| mp.manager.unavailable_reason() | |
| unavailable.unwrap() | |
| }; | |
| let reason = if mp.disabled { | |
| Some("excluded by the system_packages.managers setting".to_string()) | |
| } else { | |
| mp.manager.unavailable_reason_async().await | |
| }; | |
| if let Some(reason) = reason { |
📍 Affects 3 files
src/cli/bootstrap.rs#L1155-L1161(this comment)src/cli/doctor/mod.rs#L481-L487src/cli/doctor/mod.rs#L717-L723src/cli/system/status.rs#L31-L37
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/cli/bootstrap.rs` around lines 1155 - 1161, Short-circuit asynchronous
availability checks for disabled package managers. In src/cli/bootstrap.rs lines
1155-1161, src/cli/doctor/mod.rs lines 481-487 and 717-723, and
src/cli/system/status.rs lines 31-37, update each reason-selection flow to use
the disabled-manager message directly when mp.disabled is true and only await
mp.manager.unavailable_reason_async() when it is false, preserving the existing
unavailable-reason behavior otherwise.
Hyperfine Performance
|
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.7.7 x -- echo |
22.9 ± 1.7 | 19.9 | 37.4 | 1.02 ± 0.11 |
mise x -- echo |
22.4 ± 1.7 | 18.8 | 35.9 | 1.00 |
mise env
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.7.7 env |
22.1 ± 0.9 | 19.8 | 25.8 | 1.02 ± 0.09 |
mise env |
21.7 ± 1.7 | 18.8 | 28.6 | 1.00 |
mise hook-env
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.7.7 hook-env |
23.2 ± 1.4 | 20.2 | 27.7 | 1.01 ± 0.11 |
mise hook-env |
22.9 ± 2.0 | 19.6 | 35.4 | 1.00 |
mise ls
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.7.7 ls |
23.2 ± 2.5 | 18.4 | 32.5 | 1.14 ± 0.15 |
mise ls |
20.4 ± 1.6 | 16.7 | 27.4 | 1.00 |
✅ Performance improvement for ls is 14% |
xtasks/test/perf
| Command | mise-2026.7.7 | mise | Variance |
|---|---|---|---|
| install (cached) | 191ms | 190ms | +0% |
| ls (cached) | 73ms | 73ms | +0% |
| bin-paths (cached) | 80ms | 76ms | +5% |
| task-ls (cached) | 163ms | 164ms | +0% |
Entire-Checkpoint: 8164a9ce23de
Entire-Checkpoint: e0ec02b5b8d1
Entire-Checkpoint: d7e9753e768b
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 05666e8. Configure here.
There was a problem hiding this comment.
🧹 Nitpick comments (1)
src/system/deps.rs (1)
476-481: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick winShort-circuit the async availability check.
Check if
dep.packagescontains the manager's name before awaiting its availability. This avoids potentially slow async checks (such as spawning a subprocess to verify the manager) for package managers that the dependency does not even support.⚡ Proposed optimization
- if m.unavailable_reason_async().await.is_some() { - continue; - } - if dep.packages.contains_key(name) { - return Some(m); - } + if !dep.packages.contains_key(name) { + continue; + } + if m.unavailable_reason_async().await.is_some() { + continue; + } + return Some(m);🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/system/deps.rs` around lines 476 - 481, In the manager selection flow, update the logic around unavailable_reason_async() so dep.packages.contains_key(name) is checked first and managers absent from the dependency are skipped without awaiting availability. Preserve returning Some(m) only for supported managers that pass the availability check.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@src/system/deps.rs`:
- Around line 476-481: In the manager selection flow, update the logic around
unavailable_reason_async() so dep.packages.contains_key(name) is checked first
and managers absent from the dependency are skipped without awaiting
availability. Preserve returning Some(m) only for supported managers that pass
the availability check.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Central YAML (base), Organization UI (inherited)
Review profile: CHILL
Plan: Pro Plus
Run ID: 48cd6849-f786-4dbb-89c5-56de35b5ef69
📒 Files selected for processing (2)
src/system/deps.rssrc/toolset/helpers.rs
Entire-Checkpoint: 1fbf88e7c9c2

Summary
PluginType::Packageand Lua package installed/install/upgrade hooks to the vfox runtimeSystemPackageManager, including metadata-driven requirements, OS filtering, opaque version matching, and upgrade fallbackValidation
mise run lint-fixmise run test(1,703 unit tests plus E2E task)mise --cd crates/vfox run test(91 passed, 2 ignored)Follow-up
A stacked PR adds
[bootstrap.plugins], two-phase bootstrap orchestration, generated CLI/schema artifacts, end-to-end coverage, and documentation.Out of scope (v1)
PackageUninstallremains a future extension)Note
Medium Risk
Touches system package orchestration and plugin classification across bootstrap, doctor, and install paths; incorrect availability or hook env could skip or mis-run package installs, but built-in precedence and collision guards limit blast radius.
Overview
Adds package manager plugins as a first-class
PluginType::Package, wired through new vfox Lua hooks (PackageInstalled,PackageInstall,PackageUpgrade) and Rust↔Lua types for package lists, dry-run, and opaque version strings.Plugins that expose
hooks/package_install.luaandhooks/package_installed.luaare discovered as managers alongside built-ins viaPackagePluginManager, which implementsSystemPackageManagerusingmise.plugin.toml[package-manager](required binaries, OS filter, version-pin support). Hook subprocesses get PATH from shims plus the global toolset; built-in manager names win on collisions and install is rejected if a package plugin shadows a built-in.unavailable_reason_asyncreplaces syncis_available()checks in bootstrap, doctor, install hints, system driver/status/use, and system-deps remediation so plugin managers can resolve host tools asynchronously. Package plugins are explicitly not tool backends inBackendArgresolution.Reviewed by Cursor Bugbot for commit f88dfea. Bugbot is set up for automated code reviews on this repo. Configure here.
Summary by CodeRabbit
New Features
[package-manager]configuration section for package-manager plugins (requirements, version-pin support, optional platform constraints).package:identifiers, including hook loading and install/upgrade dispatch.Bug Fixes