Skip to content

feat/try compat - #108

Merged
tonythethompson merged 29 commits into
masterfrom
feat/try-compat
Aug 8, 2026
Merged

feat/try compat#108
tonythethompson merged 29 commits into
masterfrom
feat/try-compat

Conversation

@tonythethompson

@tonythethompson tonythethompson commented Aug 7, 2026

Copy link
Copy Markdown
Collaborator
  • Report versioned managed Nu installs in doctor.
  • Improve registry packages listing readability.
  • Auto-deactivate and restore packages on numan use.
  • Update src/cmd/activation_switch.rs
  • Update src/cmd/activation_switch.rs
  • Update src/state/activation_profile.rs
  • Update src/cmd/remove.rs
  • fix: apply CodeRabbit auto-fixes
  • feat(try): make numan try compatibility-first

Review in cubic

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@sourcery-ai sourcery-ai 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.

Sorry @tonythethompson, your pull request is larger than the review limit of 150000 diff characters

@tonythethompson

Copy link
Copy Markdown
Collaborator Author

Note: cargo test --lib on this branch still shows 3 unrelated pre-existing/environmental failures that are not part of the try rewrite: cmd::activation_switch::tests::teardown_order_modules_then_plugins, cmd::use_cmd::tests::execute_with_hooks_and_refresh_integration, and nu::bootstrap::tests::register_existing_nu_refuses_non_tty_without_yes_before_path_mutation. The try_cmd and core::resolve tests pass, and cargo clippy -- -D warnings and cargo fmt --check are clean.

@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It 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 reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The PR adds per-Nu-minor activation profiles, lifecycle-aware version switching, explicit package resolution for numan try, compatibility recommendations, versioned managed-Nu diagnostics, formatted registry listings, and updated documentation.

Changes

Activation and compatibility workflows

Layer / File(s) Summary
Activation profile state and lifecycle integration
src/state/activation_profile.rs, src/state/snapshot.rs, src/state/rollback.rs, src/cmd/activate.rs, src/cmd/deactivate.rs, src/cmd/remove.rs
Adds persistent per-minor plugin and module profiles. Activation, deactivation, removal, snapshots, and rollback synchronize or restore profile state.
Nu switching and activation restoration
src/cmd/activation_switch.rs, src/cmd/use_cmd.rs, src/cmd/mod.rs
Adds lifecycle-aware Nu switching with teardown ordering, path refreshes, profile restoration, injectable hooks, failure reporting, and integration tests.
Lock-aware activation orchestration
src/cmd/activate.rs, src/cmd/deactivate.rs
Shares mutation-lock handling, target preparation, snapshots, candidate runners, profile synchronization, and unlocked module operations.
Explicit package trials and compatibility resolution
src/cmd/try_cmd.rs, src/core/resolve.rs, src/cli.rs
numan try accepts explicit package specifications, filters compatible versions and platforms, recommends managed Nu versions, installs selected packages, and conditionally activates them.
Diagnostics, registry output, and documentation
src/cmd/doctor.rs, src/cmd/registry.rs, src/nu/bootstrap.rs, README.md, CHANGELOG.md, AGENTS.md, .markdownlint.json
Updates managed-Nu reporting, terminal-aware registry output, PATH-sensitive tests, command guidance, project documentation, and Markdownlint rules.

Estimated code review effort: 5 (Critical) | ~120 minutes

Possibly related PRs

Suggested reviewers: greptile-apps

🚥 Pre-merge checks | ✅ 8
✅ Passed checks (8 passed)
Check name Status Explanation
Title check ✅ Passed The title identifies the main compatibility-focused change to numan try and is concise enough for the pull request scope.
Description check ✅ Passed The description lists the compatibility, activation, doctor, registry, and state changes included in the pull request.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 60.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Pipeline Stage Enum Ordering ✅ Passed The repository contains no SessionWorkflowStage enum, listed members, or related comparisons; the changed files also contain no such references, so this check is not applicable.
Gpu/Cpu Runtime Boundary ✅ Passed The PR changes only Rust and documentation paths; no inference/, managed CPU/GPU requirements, main.py, or C# files exist or were modified, so this boundary check is not applicable.
Managed Host Restart Safety ✅ Passed The repository contains none of the managed-host, containerized readiness, lease, or health APIs named by the check; the PR changes Nu plugin/module activation only, so the check is not applicable.
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/try-compat
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch feat/try-compat

Warning

Review ran into problems

🔥 Problems

Linked repositories: Public OSS repositories can only analyze public repositories installed in this organization. Analyzed tonythethompson/QuickShell, tonythethompson/numan, tonythethompson/dependency-chain-substrate, skipped Trackdubllc/Trackdub.


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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@qodo-code-review

Copy link
Copy Markdown
Contributor

PR Summary by Qodo

Make numan try compatibility-first and add activation profiles for cross-minor use

✨ Enhancement 🐞 Bug fix 📝 Documentation 🕐 40+ Minutes

Grey Divider

AI Description

• Make numan try  compatibility-first with managed Nu recommendations.
• Add per-Nu-minor activation profiles to auto leave/restore packages during numan use.
• Improve doctor reporting for versioned Nu installs and polish registry package listings.
Diagram

graph TD
  A["CLI"] --> B["use_cmd.rs"] --> C["activation_switch.rs"] --> D["activation_profile.rs"] --> E[("activation-profile.json")]
  C --> F["activate/deactivate"]
  C --> G["version_manager + NuPaths"]
  A --> H["try_cmd + resolve"] --> G
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Store desired activation per minor inside lockfile
  • ➕ Fewer state files to manage; single source of truth
  • ➕ Atomicity might be simpler if lockfile writes already guarded
  • ➖ Lockfile becomes more semantically overloaded (installed vs desired state)
  • ➖ Harder to reason about merge/union semantics and migration
  • ➖ Increases churn risk for other features that touch lockfile
2. Track activation desire per exact Nu version (X.Y.Z) instead of minor (X.Y)
  • ➕ More precise when patch releases break ABI or behavior unexpectedly
  • ➕ Easier to reproduce exact environments
  • ➖ Does not match the plugin ABI reality (minor-scoped) and increases profile fragmentation
  • ➖ Worse UX: patch bumps would “lose” desired activations unless merged
3. Auto-switch Nu inside `numan try` when incompatible
  • ➕ One-command success path for new users
  • ➕ Fewer steps when a compatible managed Nu is already installed
  • ➖ Violates stated product constraint: never silently switch Nu
  • ➖ Risky side effects (activation teardown/restore) during what appears to be an install command

Recommendation: The PR’s approach (separate desired-state activation profile keyed by Nu minor, with use orchestrating leave/restore and try only recommending) best matches the ABI boundary and the product requirement to avoid silent Nu switching. Alternatives were considered but either overload the lockfile, fragment state unnecessarily, or change user expectations in risky ways.

Files changed (16) +3244 / -593

Enhancement (12) +3116 / -573
cli.rsAdjust CLI help text for updated 'try' behavior +1/-1

Adjust CLI help text for updated 'try' behavior

• Updates the 'Try' command description to reflect compatibility-first behavior and guidance instead of starter installation.

src/cli.rs

activate.rsSync activation profile after user activate and add unlocked module activation helper +68/-0

Sync activation profile after user activate and add unlocked module activation helper

• Ensures activation profile desired-state is updated even when there is nothing to activate (already-active/idempotent). Adds 'activate_modules_unlocked' for switch orchestration to activate modules under an existing mutation lock without extra snapshot/profile sync.

src/cmd/activate.rs

activation_switch.rsAdd shared leave/restore orchestration for 'numan use' +1284/-0

Add shared leave/restore orchestration for 'numan use'

• Introduces a new module that: collects currently active packages, unions leave evidence into per-minor profiles, deactivates modules then plugins on cross-minor switches, refreshes cached Nu paths post-marker-write, and restores desired packages (plugins then modules) with compatibility/missing checks and a summarized report.

src/cmd/activation_switch.rs

deactivate.rsMake module deactivation idempotent and sync profile on user deactivate +121/-7

Make module deactivation idempotent and sync profile on user deactivate

• Runs activation profile sync even when requested targets are already inactive, and skips inactive modules instead of erroring. Adds 'deactivate_modules_unlocked' helper for cross-minor leave behavior and ensures profile is cleared only for packages that are actually inactive post-run.

src/cmd/deactivate.rs

mod.rsExport new activation switch module +1/-0

Export new activation switch module

• Adds 'pub mod activation_switch;' so 'use'/lifecycle commands can reuse the shared switch logic.

src/cmd/mod.rs

registry.rsImprove 'registry packages' listing formatting and wrapping +130/-4

Improve 'registry packages' listing formatting and wrapping

• Styles package IDs/versions/types, inserts blank lines between packages, and soft-wraps descriptions based on terminal width. Adds unit tests for wrapping and terminal-width conversion logic, including non-ASCII display width handling.

src/cmd/registry.rs

remove.rsClear activation profile entries when removing a package +3/-0

Clear activation profile entries when removing a package

• On successful remove, attempts to remove the package id from all minors in the activation profile, emitting a warning on failure instead of aborting the remove flow.

src/cmd/remove.rs

try_cmd.rsMake 'numan try' package-driven and compatibility-first +652/-447

Make 'numan try' package-driven and compatibility-first

• Changes 'try' to require a package spec and, on incompatibility, enumerates compatible managed Nu versions (marking installed ones) and suggests a nearest recommended 'numan use' target. Removes the curated-starter behavior in favor of metadata-driven compatibility guidance.

src/cmd/try_cmd.rs

use_cmd.rsRoute 'use' through activation switch hooks with leave/restore semantics +207/-113

Route 'use' through activation switch hooks with leave/restore semantics

• Refactors 'use' to delegate to 'activation_switch::switch_active_nu_version' and adds injectable hooks for testing registrar/unregistrar/module runner and post-switch path refresh. Enhances 'use latest' to self-heal dangling off-tree binary markers before running same-target reconcile.

src/cmd/use_cmd.rs

resolve.rsAdd compatibility helper APIs for recommending managed Nu versions +310/-1

Add compatibility helper APIs for recommending managed Nu versions

• Introduces utilities to derive candidate Nu versions from constraints, compute compatible Nu versions for a package+platform, and select a recommended version favoring installed candidates and nearest versions. Adds substantial test coverage for candidate derivation, compatibility listing, and recommendation selection.

src/core/resolve.rs

activation_profile.rsAdd persisted per-Nu-minor activation profile state +338/-0

Add persisted per-Nu-minor activation profile state

• Implements 'nu_state/activation-profile.json' desired-state storage with schema versioning, union-only leave merges, and idempotent ensure/clear operations. Provides helpers to key by Nu minor, update profile on user activate/deactivate, and remove a package from all minors, with unit tests.

src/state/activation_profile.rs

mod.rsExport activation profile state module +1/-0

Export activation profile state module

• Adds 'pub mod activation_profile;' so commands can load/update the new activation profile file.

src/state/mod.rs

Bug fix (1) +108 / -7
doctor.rsReport versioned managed Nu installs in doctor +108/-7

Report versioned managed Nu installs in doctor

• Doctor now resolves the active managed Nu binary via the versioned layout ('tools/nushell/<version>/nu') with fallbacks to legacy paths and latest installed version. Adds tests covering correct reporting and warning behavior when a marker exists but the binary is missing.

src/cmd/doctor.rs

Documentation (3) +20 / -13
AGENTS.mdDocument activation profiles and new switch orchestrator module +9/-6

Document activation profiles and new switch orchestrator module

• Updates command/file map to reflect 'try' argument changes and 'use' cross-minor leave/restore behavior. Adds documentation for the new activation profile state and 'activation_switch' orchestration role.

AGENTS.md

CHANGELOG.mdChangelog entries for activation profiles, try compat UX, registry formatting, doctor fix +4/-0

Changelog entries for activation profiles, try compat UX, registry formatting, doctor fix

• Adds release notes describing 'numan use' activation profiles, compatibility-first 'numan try', improved 'registry packages' output, and doctor reporting of versioned managed Nu installs.

CHANGELOG.md

README.mdUpdate usage docs for compatibility-first 'numan try' and 'use' leave/restore behavior +7/-7

Update usage docs for compatibility-first 'numan try' and 'use' leave/restore behavior

• Replaces starter-based 'numan try' docs with required package argument and compatibility guidance messaging. Expands 'numan use' docs to explain cross-minor deactivation/restore behavior and recommended workflow.

README.md

@greptile-apps

greptile-apps Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

The PR introduces compatibility-first numan try, activation profiles for managed Nu switching, and supporting lifecycle, doctor, registry-output, state, and documentation changes.

  • Keeps package installation and activation serialized under one mutation lock.
  • Scopes pinned-package compatibility guidance to the requested release.
  • Automatically records, tears down, and restores package activations across managed Nu versions.
  • Improves managed Nu diagnostics and registry package-list readability.

Confidence Score: 5/5

The PR appears safe to merge because no blocking failure remains in the previously reported paths.

The nested-lock failure, pinned-release compatibility leak, and concurrent install-to-activate handoff race are all resolved in the current code.

Important Files Changed

Filename Overview
src/cmd/try_cmd.rs Implements package-specific compatibility resolution and retains the root mutation lock continuously across install and activation; the previously reported pinned-scope and handoff issues are fixed.
src/cmd/activate.rs Adds an under-lock activation entry point that skips nested lock acquisition while preserving the existing activation lifecycle.
src/cmd/activation_switch.rs Adds activation-profile leave and restore orchestration for managed Nu version switches without introducing a finding eligible for this follow-up.
src/state/activation_profile.rs Persists desired plugin and module activation sets by Nu minor and supports synchronization and rollback.
src/cmd/use_cmd.rs Integrates managed Nu selection with activation-profile teardown and restoration.
src/core/resolve.rs Adds compatibility helpers that correctly evaluate candidate Nu versions against a specific pinned release when requested.

Reviews (16): Last reviewed commit: "fix: classify modules by on-disk state a..." | Re-trigger Greptile

Comment thread src/cmd/try_cmd.rs
Comment thread src/cmd/try_cmd.rs Outdated
@qodo-code-review

qodo-code-review Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📜 Skill insights (0)

Grey Divider


Action required

1. Try self-blocks activation ✓ Resolved 🐞 Bug ≡ Correctness
Description
try_package retains the root mutation lock while calling the normal activation entry point, which
immediately tries to acquire the same non-blocking lock. Every compatible plugin or module is
therefore installed but fails activation with a lock-contention error.
Code

src/cmd/try_cmd.rs[294]

+    let _lock = acquire_mutation_lock(root)?;
Relevance

●●● Strong

Lock-scope/concurrency issues are treated seriously; prior accepted changes fix lock
lifetime/serialization problems.

PR-#71
PR-#5

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The guard created in try_package remains in scope through the activation call. The called
activation flow acquires mutation.lock during planning, and the lock implementation uses
try_write, returning an error whenever the exclusive lock is already held.

src/cmd/try_cmd.rs[294-339]
src/cmd/activate.rs[126-164]
src/util/fs_safety.rs[51-96]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`numan try` holds the mutation lock while calling `activate`, but the activation command acquires that same non-blocking lock and therefore fails deterministically after installation.

## Issue Context
Script and completion packages return before activation and are unaffected. For plugins and modules, either drop the install lock before invoking the regular activation command or use a complete unlocked activation path designed for callers that already own the lock.

## Fix Focus Areas
- src/cmd/try_cmd.rs[294-339]
- src/cmd/activate.rs[126-164]
- src/util/fs_safety.rs[51-96]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

2. Restore treats unknown registry state as compatible ✗ Dismissed 🐞 Bug ≡ Correctness
Description
classify_restore_target only marks a package Incompatible when the registry lookup succeeds and
returns package data; if registry is None, find_package errors, or the package/version is
absent from the index, the function falls through to RestoreClass::Ok with no compatibility check,
so numan use can restore a plugin/module without verifying it actually works with the target Nu
identity.
Code

src/cmd/activation_switch.rs[R373-389]

+    if let Some(reg) = registry {
+        if let Ok(Some(pkg)) = reg.find_package(id) {
+            if let Some(ver) = pkg
+                .versions
+                .iter()
+                .find(|v| v.version.to_string() == entry.version)
+            {
+                if !resolver.is_compatible(ver) {
+                    return RestoreClass::Incompatible;
+                }
+            } else if expected_type == "plugin" && !resolver.has_compatible_version(&pkg) {
+                // Installed version not in index; still refuse if no version works.
+                return RestoreClass::Incompatible;
+            }
+        }
+    }
+    RestoreClass::Ok
Relevance

●●● Strong

Team often hardens state/compat gates; no close rejection precedent for fail-closed restore
compatibility checks.

PR-#50
PR-#41

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
classify_restore_target's if let Some(reg) = registry { ... } block is the only place
compatibility is checked, and it is entirely skipped when registry is None (e.g.,
RegistryManager::new(root).ok() failed in restore_desired) or when find_package returns Err/None;
execution falls through to RestoreClass::Ok unconditionally in all those cases, defeating the
fail-closed compatibility gate that restore_one_plugin/restore_desired rely on when switching Nu
versions.

src/cmd/activation_switch.rs[360-390]
src/cmd/activation_switch.rs[271-273]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
classify_restore_target silently approves restore (RestoreClass::Ok) whenever the registry manager is unavailable, the package lookup errors, or the installed version isn't found in the index, skipping the Nu-compatibility check that is otherwise enforced.

## Issue Context
This function backs numan use's plugin/module restore-after-switch logic; a fail-open path here can restore Nu-incompatible plugins after a version switch when the local registry index is stale/missing (e.g., offline).

## Fix Focus Areas
- src/cmd/activation_switch.rs[360-390]
- src/cmd/activation_switch.rs[271-273]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Pinned guidance ignores pin ✓ Resolved 🐞 Bug ≡ Correctness
Description
For an incompatible explicit owner/name@version, try_package derives Nu compatibility guidance
by considering compatible Nus across all releases rather than the selected pinned entry, and its
incompatibility reporting drops the @version from the suggested retry. As a result, it can
recommend a Nu that doesn’t support the requested pin and prints an unpinned `numan try
{package_id}` command that may silently select a different (latest-compatible) package version than
the user asked for.
Code

src/cmd/try_cmd.rs[R287-289]

+    if let Some(issue) = resolver.classify_version(target_entry) {
+        let installed = list_installed_nu_versions(root);
+        return report_incompatible(package, platform, nu, package_id, &issue, &installed);
Relevance

●●● Strong

They’ve accepted fixes ensuring user hints/selection match the actually chosen version; pinned
@version preservation aligns.

PR-#95
PR-#41

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The flow selects the exact requested entry first, but when incompatibility is detected it reports
using broader package context: candidate collection iterates all package versions and the
compatibility check can accept any package entry, which allows computing “compatible Nu versions”
from releases other than the explicitly pinned one. Additionally, try_package calls
report_incompatible(...) passing only package_id even though the version is still available in
try_package’s scope, and report_incompatible’s message builder emits a retry hint of the form
numan try {package_id} (around lines ~178–181) without appending the originally requested
@version, so following the hint can lead to selecting a different release.

src/cmd/try_cmd.rs[39-75]
src/cmd/try_cmd.rs[149-180]
src/cmd/try_cmd.rs[253-289]
src/core/resolve.rs[504-523]
src/cmd/try_cmd.rs[287-290]
src/cmd/try_cmd.rs[178-181]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
When a user runs `numan try <owner/name>@<version>` and that version is incompatible, the compatibility guidance and retry hint are computed/printed as if the user had not pinned a version: compatibility is derived across all package releases and the suggested retry command omits the original `@version`, which can recommend an irrelevant Nu and cause a retry to silently select a different package release.

## Issue Context
The exact entry is already resolved before incompatibility is detected, but the incompatible branch passes broader package context into reporting and collects compatibility candidates across every version, allowing any entry to satisfy compatibility. Separately, `try_package` calls `report_incompatible` using only `package_id` (not the original version-qualified spec), and `report_incompatible` builds the final `Try:` hint using only `package_id`, so the output command loses the user’s explicit pin.

## Fix Focus Areas
- src/cmd/try_cmd.rs[39-75]
- src/cmd/try_cmd.rs[92-184]
- src/cmd/try_cmd.rs[178-181]
- src/cmd/try_cmd.rs[253-289]
- src/cmd/try_cmd.rs[287-290]
- src/core/resolve.rs[504-523]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


4. Redundant registry helper comments ✓ Resolved 📘 Rule violation ⚙ Maintainability
Description
New doc comments in registry.rs restate what the adjacent code already makes obvious, adding noise
without documenting non-obvious rationale. This violates the requirement to keep comments focused on
rationale/invariants rather than behavior narration.
Code

src/cmd/registry.rs[R210-212]

+/// Convert terminal column count to usable description width.
+fn terminal_cols_to_description_width(terminal_cols: usize) -> usize {
+    let available = terminal_cols.saturating_sub(4);
Relevance

●●● Strong

Repo prefers minimizing misleading/comments and keeping docs meaningful; removing redundant
narration is typically accepted.

PR-#66
PR-#53

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
PR Compliance ID 2452624 forbids comments that simply restate directly inferable behavior. The added
comment at src/cmd/registry.rs[210-212] (“Convert terminal column count to usable description
width.”) is an obvious restatement of the function immediately below it.

Rule 2452624: Restrict code comments to non-obvious rationale, not restating behavior
src/cmd/registry.rs[210-212]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Newly added comments restate adjacent code behavior instead of documenting non-obvious rationale.

## Issue Context
The review checklist requires comments to capture rationale/constraints rather than narrate what the code is doing.

## Fix Focus Areas
- src/cmd/registry.rs[210-212]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


View more (1)
5. Latest self-heal skips cached path refresh ✗ Dismissed 🐞 Bug ☼ Reliability
Description
In execute_latest, if the active marker’s off-tree binary_path is dangling for an already-active
target version, the code rewrites the marker via write_active_version but never refreshes
nu_state/paths.json, and the subsequent same-target path in switch_active_nu_version reconciles
and returns without refreshing or verifying the cache against the marker. As a result, stale cached
Nu paths can persist (until a manual init --refresh) and package restoration can target the wrong
Nu executable, registry, and autoload paths when the marker and cache diverge but the cached
executable remains hash-valid.
Code

src/cmd/use_cmd.rs[R131-143]

+    // Self-heal dangling off-tree `binary_path` before same-target reconcile so
+    // a later `use list` / resolver sees a valid on-tree selection.
+    if let Some(existing) = version_manager::read_active_version(root)? {
+        if existing.version == version {
+            if let Some(path) = existing.binary_path.as_deref() {
+                if !std::path::Path::new(path).is_file() {
+                    version_manager::write_active_version(root, &version)?;
                }
            }
-            version_manager::write_active_version(root, &version)?;
-            println!("Switched to Nu {} (latest installed).", version);
-            refresh_cached_nu_paths_after_switch(root)?;
-            Ok(())
-        }
-        None => {
-            bail!(
-                "No Nu versions installed.\n\
-                 Run 'numan setup nu' or 'numan setup nu <version>' first."
-            )
        }
    }
-}

-/// Switch to a specific Nu version.
-fn execute_switch(root: &Path, version: &str) -> Result<()> {
-    let version = version_manager::normalize_version(version)?;
-    // Resolve on-tree or off-tree so versions shown by `numan use list`
-    // (including off-tree marker selections) remain switchable.
-    let Some(resolved) = version_manager::resolve_installed_version(root, &version)? else {
-        let installed = version_manager::list_installed_versions(root)?;
-        let hint = if installed.is_empty() {
-            format!(
-                "No Nu versions installed.\n\
-                 Run 'numan setup nu {}' to install.",
-                version
-            )
-        } else {
-            format!(
-                "Nu {} is not installed.\n\
-                 Installed versions: {}\n\
-                 Run 'numan setup nu {}' to install, or 'numan use list' to see available versions.",
-                version,
-                installed.join(", "),
-                version
-            )
-        };
-        bail!("{}", hint);
-    };
-
-    let on_tree = version_manager::version_binary(root, &version);
-    if resolved == on_tree {
-        version_manager::write_active_version(root, &version)
-            .with_context(|| format!("Failed to switch to Nu {}", version))?;
-    } else {
-        version_manager::write_active_version_with_binary(root, &version, &resolved)
-            .with_context(|| format!("Failed to switch to Nu {}", version))?;
-    }
-    println!("Switched to Nu {}.", version);
-    refresh_cached_nu_paths_after_switch(root)?;
-    Ok(())
-}
-
-/// Keep `nu_state/paths.json` aligned with the newly selected active Nu.
-///
-/// `activate` loads the cached paths and only checks that the cached binary
-/// still hashes — side-by-side installs leave the previous binary intact, so
-/// a stale cache would silently keep activating against the old Nu. Re-probe
-/// when possible; if probing fails, delete the cache so callers fail closed
-/// with an `init --refresh` hint instead of using the wrong Nu.
-fn refresh_cached_nu_paths_after_switch(root: &Path) -> Result<()> {
-    let paths_file = root.join("nu_state").join("paths.json");
-    if !paths_file.is_file() {
-        return Ok(());
-    }
-
-    match NuPaths::detect_with_root(root) {
-        Ok(refreshed) => {
-            refreshed.save(root).with_context(|| {
-                format!(
-                    "Failed to write refreshed Nu paths to '{}'",
-                    paths_file.display()
-                )
-            })?;
-            println!("Refreshed cached Nu paths for the selected version.");
-            Ok(())
-        }
-        Err(e) => {
-            std::fs::remove_file(&paths_file).with_context(|| {
-                format!(
-                    "Failed to clear stale Nu paths at '{}' after version switch",
-                    paths_file.display()
-                )
-            })?;
-            eprintln!(
-                "warning: could not re-probe Nu after switch ({e:#}). \
-                 Cleared cached paths; run '{CMD_INIT_REFRESH}' before activating packages."
-            );
-            Ok(())
-        }
-    }
+    activation_switch::switch_active_nu_version(root, &version, hooks)
Relevance

●● Moderate

Cache/marker drift is plausible, but fix impacts refresh semantics; no direct precedent requiring
refresh on same-target self-heal.

PR-#83
PR-#35

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The self-heal logic updates the active marker by calling
version_manager::write_active_version(root, &version) and then proceeds into
activation_switch::switch_active_nu_version, whose same-target branch
(src/cmd/activation_switch.rs lines 460-471) invokes reconciliation (including loading paths.json)
and returns without any cached-path refresh, while the cross-minor path (lines 493-498) explicitly
refreshes cached Nu paths after a marker write. Because the only refresh occurs after the
early-return same-target case, and validate_drift checks only the cached executable/hash and
registry parent validity rather than comparing cached paths to what the active marker selects, the
cache can remain internally “valid” yet belong to a different Nu than the marker—especially after
flows like numan setup nu updating the marker before a recommended later numan init --refresh or
other incomplete state transitions.

src/cmd/use_cmd.rs[131-143]
src/cmd/activation_switch.rs[460-471]
src/cmd/activation_switch.rs[493-498]
src/cmd/activation_switch.rs[123-145]
src/cmd/activation_switch.rs[455-500]
src/nu/paths.rs[120-163]
src/nu/bootstrap.rs[887-935]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
When `execute_latest` self-heals a dangling off-tree `binary_path` by rewriting the active-version marker, it does not refresh `nu_state/paths.json`, and `switch_active_nu_version`’s same-target branch (used when the marker already names the requested version) also returns after reconciliation without refreshing or verifying cached paths against the active marker. This can leave `paths.json` stale relative to the corrected marker, so restoration and activation may use the wrong Nu executable, registry, and autoload paths even though the cached executable/hash appears valid.

## Issue Context
- There is an asymmetry in `activation_switch.rs`: the cross-minor switch path explicitly refreshes cached Nu paths after writing the marker, but the same-target early-return path does not.
- The problematic scenario includes cases where the marker and cache diverge while the previously cached binary still exists (e.g., `numan setup nu` writes a new active marker and only recommends a later `numan init --refresh`, or after an incomplete state transition).
- Reconciliation/`validate_drift` validates cached identity internally (cached executable/hash and registry parent) but does not establish that cached paths correspond to the Nu selected by the active-version marker.

## Fix Focus Areas
- src/cmd/use_cmd.rs[131-143]
- src/cmd/activation_switch.rs[123-145]
- src/cmd/activation_switch.rs[455-471]
- src/cmd/activation_switch.rs[561-590]
- src/nu/paths.rs[120-163]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Context used
✅ Compliance rules (platform): 27 rules
✅ REVIEW.md
Review mode: 🧠 Deep: This is a bug-dense, cross-cutting change spanning 16 files, 51 independent hunks, and substantial new activation, state, resolution, and compatibility logic where redundant review is materially valuable.

To customize comments, go to the Qodo configuration screen, or learn more in the docs.

Qodo Logo

Comment thread src/cmd/registry.rs Outdated
Comment thread src/cmd/try_cmd.rs Outdated
Comment thread src/cmd/try_cmd.rs Outdated
Comment thread src/cmd/use_cmd.rs Outdated
Comment thread src/cmd/activation_switch.rs
@qodo-code-review

Copy link
Copy Markdown
Contributor

Qodo Fixer

✅ Committed (1) · ☑ Fixed (1)

Grey Divider

Commits pushed directly to this PR — no separate fix PR opened.

Process — 1 fixed
  • ☑ Fixed: Try self-blocks activation

@coderabbitai coderabbitai 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.

Actionable comments posted: 18

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/cmd/try_cmd.rs (1)

294-342: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Drop the install lock before activating in numan try.

try_package holds _lock for the whole function, then calls activate::execute, which re-acquires the same root mutation lock. try_write() fails immediately on the second acquisition, so non---no-activate installs fail with Activated "<id>" but activation failed: Another Numan mutation is already in progress for this root. Scope _lock to install only, and update the lock-held tests if they check the outer lock from try_cmd.

🤖 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/cmd/try_cmd.rs` around lines 294 - 342, In try_package, scope the
acquire_mutation_lock(root) guard only around the install operation so it is
dropped before the activate call. Keep installation setup and result handling
under the lock, then release it before invoking activate; update any try_cmd
tests that assert the outer lock remains held.

Source: Coding guidelines

🤖 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 `@AGENTS.md`:
- Line 240: Insert a blank line immediately before the “Learned Workspace Facts”
heading in AGENTS.md, separating it from the preceding list so the markdownlint
MD022 requirement is satisfied.

In `@README.md`:
- Line 215: The compatibility retry guidance must preserve an explicitly
supplied package version. Update README.md lines 215-215 to instruct users to
retry the same <owner/name[`@version`]> specification, and update AGENTS.md lines
252-252 so the learned workspace guidance preserves the explicit `@version`;
ensure both references cover versioned and unversioned inputs.
- Around line 357-358: Update the documentation for numan use restoration
semantics: in README.md lines 357-358, state that activations are restored after
successful restoration and that restoration can fail; in CHANGELOG.md line 14,
remove any implication that target restoration is guaranteed; and in AGENTS.md
line 152, document that post-marker restoration may be partial and can fail
while leaving the activation profile unchanged.

In `@src/cmd/activate.rs`:
- Around line 244-247: Filter the packages passed to sync_user_activate_profile
in the post-activation flow so only packages with successfully written
activation records are included, matching the deactivate path’s liveness check.
Apply this to the explicit-packages branch before syncing, while preserving the
existing no-op sync behavior and any_failed handling.

In `@src/cmd/activation_switch.rs`:
- Around line 383-386: Update the comment above the plugin-only
has_compatible_version fallback in the restore classification logic to state
that modules with installed versions absent from the index are intentionally
classified as Ok and restored, while plugins must still have a compatible
version. Keep the condition and behavior unchanged.
- Around line 157-163: Update the Lockfile::load handling in leave_current_nu so
load failures propagate as errors instead of returning an empty report and
success. Preserve Lockfile::load’s existing behavior for a missing lockfile,
while ensuring malformed or unreadable lockfiles stop the switch before
active-version markers or paths are updated.

In `@src/cmd/doctor.rs`:
- Around line 530-534: Remove the behavior-narrating helper comment in
src/cmd/registry.rs lines 210-230 unless it documents a non-obvious output
constraint. In src/cmd/doctor.rs lines 530-534, replace the summary with a brief
comment explaining that the legacy-path fallback is required for pre-migration
roots, or remove the comment entirely.
- Around line 535-552: Update resolve_managed_nu_binary to add descriptive
context to errors from version_manager::active_nu_binary(root) and
version_manager::latest_installed_version(root), using .context(...) that
identifies the failed managed Nu resolution operation while preserving the
existing error propagation and fallback behavior.

In `@src/cmd/try_cmd.rs`:
- Around line 668-809: Add tests around the explicit-version handling in
try_package: cover an unknown requested version and verify the error lists
available versions, and cover an incompatible requested version while asserting
the retry hint preserves the `@version` suffix. Also add coverage for an
unparsable explicit version returning the expected Invalid version error; ensure
install and activation callbacks are not invoked on these failures.
- Around line 178-181: Update report_incompatible and its retry-hint formatting
to accept and use the original package_spec instead of package_id for the numan
try command. Modify both report_incompatible call sites in try_package (the
indicated branches) to pass package_spec, preserving the explicitly requested
version in retry instructions.
- Around line 159-182: Update the recommendation flow around
select_recommended_nu so an explicit package version only considers Nu
candidates compatible with that requested version entry, or suppresses the
recommendation when the selected rec equals current_nu. Ensure the output never
labels the current Nu as a recommendation or emits a no-op numan use command,
while preserving recommendations for other compatible Nu versions.

In `@src/cmd/use_cmd.rs`:
- Around line 646-651: Remove the vacuous comparison in the ordering test around
order and unreg_pos. Instrument the observable path_refresh boundary used by
switch_active_nu_version after the active-version marker write, record its
position in order, and assert that the unregister hook position precedes that
boundary while preserving the existing presence assertion and message intent.

In `@src/core/resolve.rs`:
- Around line 526-528: Update src/core/resolve.rs lines 526-528 in version_score
to avoid packed u64 arithmetic by returning a non-overflowing version
representation, then update lines 594-621 to extract one shared nearest-version
comparator used by both min_by sites. Compare version components with abs_diff
and remove the duplicated closures and unsafe i64 casts.
- Around line 464-468: Update the public doc comment for the candidate-version
function in resolve.rs to remove the claim that it includes verified-with
versions; describe only candidates derived from the nu_version constraint, while
preserving the existing lower-bound and exclusive-upper-bound behavior.
- Around line 941-984: Remove the unused verified parameter from
plugin_with_verified and update both callers to construct the fixture without
it, unless the tests are intended to validate verified_with; in that case, add
an assertion whose result depends on the fixture’s verified_with value.
- Around line 594-621: Extract the duplicated nearest-version comparison logic
from the installed_all and compatible min_by calls into one reusable comparator
near the surrounding resolution logic. Define its parameter signature to
accommodate the differing reference depth at both call sites, use u64::abs_diff
instead of casting scores through i64, and invoke the shared comparator in both
places while preserving the existing tie-breaker favoring the higher version
score.

In `@src/state/activation_profile.rs`:
- Around line 190-225: Introduce a batch profile-update API alongside
ensure_contains_for_paths and ensure_absent_for_paths that loads the profile
once, applies the requested operation to all package IDs, and saves at most once
when changes occur. Update sync_profile_after_user_activate and
sync_profile_after_user_deactivate to classify all IDs first and call the batch
API instead of invoking the per-ID helpers in a loop, preserving the existing
minor/version and ProfileKind behavior.
- Around line 85-130: Update ActivationProfile::profile_path to store
activation-profile.json under the state directory so create_snapshot rollback
captures it with the related state. Keep load, load_or_default, and save using
this centralized path helper, preserving their existing behavior.

---

Outside diff comments:
In `@src/cmd/try_cmd.rs`:
- Around line 294-342: In try_package, scope the acquire_mutation_lock(root)
guard only around the install operation so it is dropped before the activate
call. Keep installation setup and result handling under the lock, then release
it before invoking activate; update any try_cmd tests that assert the outer lock
remains held.
🪄 Autofix

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: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 96daf7ba-7c48-4cac-b5a8-0ee2fad1ade7

📥 Commits

Reviewing files that changed from the base of the PR and between de690bc and 21bdc2e.

📒 Files selected for processing (16)
  • AGENTS.md
  • CHANGELOG.md
  • README.md
  • src/cli.rs
  • src/cmd/activate.rs
  • src/cmd/activation_switch.rs
  • src/cmd/deactivate.rs
  • src/cmd/doctor.rs
  • src/cmd/mod.rs
  • src/cmd/registry.rs
  • src/cmd/remove.rs
  • src/cmd/try_cmd.rs
  • src/cmd/use_cmd.rs
  • src/core/resolve.rs
  • src/state/activation_profile.rs
  • src/state/mod.rs
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • tonythethompson/QuickShell (manual)
  • tonythethompson/numan (manual)
  • tonythethompson/dependency-chain-substrate (manual)
📜 Review details
⏰ Context from checks skipped due to timeout. (1)
  • GitHub Check: Greptile Review
🧰 Additional context used
📓 Path-based instructions (15)
**/*

📄 CodeRabbit inference engine (CLAUDE.md)

**/*: Use Serena's semantic, symbol-aware tools as the primary tools for reading and editing code; use built-in Read, Glob, Grep, and Edit only under the stated exceptions.
Before editing a code file, inspect its symbol overview, read the specific symbols being changed, and edit them with Serena's symbol-aware tools.
Understand the existing code before changing it and make the smallest change that satisfies the request; avoid unrelated cleanup, premature abstractions, unnecessary error handling, feature flags, and compatibility shims.
Prefer editing existing files over creating new ones, and never create Markdown or README files unless explicitly requested.
For exploratory questions, provide a 2–3 sentence recommendation with the main tradeoff and do not implement until the user agrees.
For UI or frontend changes that cannot be tested in a browser, explicitly state that browser testing was not performed rather than claiming success.
Address security issues when discovered, including injection, XSS, SQL injection, path traversal, and secret leaks.
Pause and obtain confirmation before destructive, hard-to-reverse, externally visible, or third-party-upload actions, including deleting files or branches, dropping tables, force-pushing, modifying CI/CD, posting externally, or uploading content.
When blocked, investigate the root cause instead of bypassing it with --no-verify, --force, or deletion; investigate unfamiliar files, branches, and configuration before deleting them.
Only commit when explicitly asked; do not proactively update git configuration or push changes.
Do not skip Git hooks unless explicitly asked; if a pre-commit hook fails, fix the issue, re-stage, and create a new commit rather than amending.
Stage files by name rather than using git add -A or git add ., to avoid accidentally including secrets or large binaries.
Use a HEREDOC for commit messages, and add co-author attribution only when the user explicitly requests the exact trailer.
Do not force-pus...

Files:

  • src/cmd/mod.rs
  • src/state/mod.rs
  • CHANGELOG.md
  • src/cmd/registry.rs
  • src/cmd/remove.rs
  • src/cli.rs
  • src/cmd/doctor.rs
  • README.md
  • AGENTS.md
  • src/cmd/activate.rs
  • src/state/activation_profile.rs
  • src/cmd/deactivate.rs
  • src/cmd/use_cmd.rs
  • src/core/resolve.rs
  • src/cmd/activation_switch.rs
  • src/cmd/try_cmd.rs
**/*.{js,jsx,ts,tsx,py,java,go,rs,rb,php,c,cpp,h,hpp,cs,swift,kt,kts}

📄 CodeRabbit inference engine (CLAUDE.md)

Add comments only when the WHY is non-obvious; do not narrate what the code does, reference the current task, or reference the PR in comments.

Files:

  • src/cmd/mod.rs
  • src/state/mod.rs
  • src/cmd/registry.rs
  • src/cmd/remove.rs
  • src/cli.rs
  • src/cmd/doctor.rs
  • src/cmd/activate.rs
  • src/state/activation_profile.rs
  • src/cmd/deactivate.rs
  • src/cmd/use_cmd.rs
  • src/core/resolve.rs
  • src/cmd/activation_switch.rs
  • src/cmd/try_cmd.rs
!**/.env,!**/credentials.json,!**/*.pem

📄 CodeRabbit inference engine (CLAUDE.md)

Do not commit files that appear to contain secrets, including .env, credentials.json, and PEM files; warn before doing so even if explicitly requested.

Files:

  • src/cmd/mod.rs
  • src/state/mod.rs
  • CHANGELOG.md
  • src/cmd/registry.rs
  • src/cmd/remove.rs
  • src/cli.rs
  • src/cmd/doctor.rs
  • README.md
  • AGENTS.md
  • src/cmd/activate.rs
  • src/state/activation_profile.rs
  • src/cmd/deactivate.rs
  • src/cmd/use_cmd.rs
  • src/core/resolve.rs
  • src/cmd/activation_switch.rs
  • src/cmd/try_cmd.rs
**/*.rs

📄 CodeRabbit inference engine (CONTRIBUTING.md)

**/*.rs: Use the Rust 2021 edition.
Use anyhow::Result with .context(...) in application code; use thiserror for library error types that callers match on.
Use clap derive macros for CLI definitions.
Use serde with serde_json or toml for serialization.
Function parameters must use &Path, not &PathBuf.
Library code must not panic; error paths should return anyhow::Result with context where appropriate.
Add or update tests for behavior changes, including relevant failure paths.
New mutating code paths must acquire the mutation lock via acquire_mutation_lock(root) and snapshot the lockfile before writes.
Lockfile, journal, and state-file JSON writes must use write_json_atomic.
numan install must write only to $NUMAN_ROOT; it must not invoke Nu or register plugins/autoloads.
Only activate and deactivate may modify Nu integration state.
Treat the lockfile as the authoritative source of truth; derived projections such as autoload state must not be authoritative.
Install payloads under versioned, content-addressed paths and never overwrite them in place.
Never overwrite foreign autoload files; respect OWNERSHIP_MARKER.
Pass plugin paths through environment variables only; do not use runtime interpolation in Nu program strings.

**/*.rs: All CI gates must pass: cargo test, cargo clippy -- -D warnings, and cargo fmt --check.
Every mutating command—including install, remove, update, gc, and future nupm import—must call acquire_mutation_lock(root).
Lockfiles, journals, and state files must use write_json_atomic; partial writes are not allowed.
Pending activation, autoload, and lifecycle journals must be stored under $NUMAN_ROOT/state/.
Module autoload identity must match all four fields: Nu executable hash, Nu version, vendor autoload directory, and managed file path; the lockfile module_activation value is authoritative.
Never overwrite foreign autoload files; respect OWNERSHIP_MARKER.
Pass paths to Nu only throu...

Files:

  • src/cmd/mod.rs
  • src/state/mod.rs
  • src/cmd/registry.rs
  • src/cmd/remove.rs
  • src/cli.rs
  • src/cmd/doctor.rs
  • src/cmd/activate.rs
  • src/state/activation_profile.rs
  • src/cmd/deactivate.rs
  • src/cmd/use_cmd.rs
  • src/core/resolve.rs
  • src/cmd/activation_switch.rs
  • src/cmd/try_cmd.rs
**/*.{rs,toml}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Run and keep cargo fmt/rustfmt clean, and ensure cargo clippy -- -D warnings passes.

Use clap derive macros for the CLI and serde/serde_json/toml for serialization according to the established crate conventions.

Files:

  • src/cmd/mod.rs
  • src/state/mod.rs
  • src/cmd/registry.rs
  • src/cmd/remove.rs
  • src/cli.rs
  • src/cmd/doctor.rs
  • src/cmd/activate.rs
  • src/state/activation_profile.rs
  • src/cmd/deactivate.rs
  • src/cmd/use_cmd.rs
  • src/core/resolve.rs
  • src/cmd/activation_switch.rs
  • src/cmd/try_cmd.rs
**/*.{rs,nu}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

**/*.{rs,nu}: Real-Nu acceptance tests must be marked #[ignore] and should be run when changes affect activation or nupm import; unit tests must not spawn real nu and should use injectable seams such as FakeCandidateRunner or registrars.
The nupm integration must be read-only toward NUPM_HOME, must not execute build.nu, and must not perform bidirectional synchronization.

Unit tests must use FakeCandidateRunner or injectable registrars and must not spawn a real nu process.

Files:

  • src/cmd/mod.rs
  • src/state/mod.rs
  • src/cmd/registry.rs
  • src/cmd/remove.rs
  • src/cli.rs
  • src/cmd/doctor.rs
  • src/cmd/activate.rs
  • src/state/activation_profile.rs
  • src/cmd/deactivate.rs
  • src/cmd/use_cmd.rs
  • src/core/resolve.rs
  • src/cmd/activation_switch.rs
  • src/cmd/try_cmd.rs
**/*.{rs,md}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Match existing naming, module layout, and documentation level in the file being edited; update AGENTS.md, docs/, or command help when structure, conventions, or user-visible behavior changes.

Tests must cover failure modes, not only successful execution.

Files:

  • src/cmd/mod.rs
  • src/state/mod.rs
  • CHANGELOG.md
  • src/cmd/registry.rs
  • src/cmd/remove.rs
  • src/cli.rs
  • src/cmd/doctor.rs
  • README.md
  • AGENTS.md
  • src/cmd/activate.rs
  • src/state/activation_profile.rs
  • src/cmd/deactivate.rs
  • src/cmd/use_cmd.rs
  • src/core/resolve.rs
  • src/cmd/activation_switch.rs
  • src/cmd/try_cmd.rs
**/*.{rs,md,toml}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Use the repository's established serialization and module conventions rather than introducing unrelated refactors.

Files:

  • src/cmd/mod.rs
  • src/state/mod.rs
  • CHANGELOG.md
  • src/cmd/registry.rs
  • src/cmd/remove.rs
  • src/cli.rs
  • src/cmd/doctor.rs
  • README.md
  • AGENTS.md
  • src/cmd/activate.rs
  • src/state/activation_profile.rs
  • src/cmd/deactivate.rs
  • src/cmd/use_cmd.rs
  • src/core/resolve.rs
  • src/cmd/activation_switch.rs
  • src/cmd/try_cmd.rs
src/**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

Platform detection must use compile-time #[cfg(target_env)] information from the build target, not std::env::consts.

Files:

  • src/cmd/mod.rs
  • src/state/mod.rs
  • src/cmd/registry.rs
  • src/cmd/remove.rs
  • src/cli.rs
  • src/cmd/doctor.rs
  • src/cmd/activate.rs
  • src/state/activation_profile.rs
  • src/cmd/deactivate.rs
  • src/cmd/use_cmd.rs
  • src/core/resolve.rs
  • src/cmd/activation_switch.rs
  • src/cmd/try_cmd.rs
src/state/**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

src/state/**/*.rs: The lockfile is authoritative for module activation; autoload-state.json is only a derived fast-check projection.
All JSON state files, including lockfiles, journals, and nu_state/paths.json, must be written atomically with write_json_atomic using a temporary file in the same directory.
Acquire acquire_mutation_lock(root) before mutations; a second acquisition for the same root must fail immediately rather than block.
Create a snapshot before install, update, remove, activate, deactivate, nupm import, and init --refresh mutations; snapshots must capture nu_state/paths.json when present.

Files:

  • src/state/mod.rs
  • src/state/activation_profile.rs
**/*.md

📄 CodeRabbit inference engine (REVIEW.md)

Update documentation and AGENTS.md when project structure or conventions change.

Files:

  • CHANGELOG.md
  • README.md
  • AGENTS.md
src/cmd/{doctor,use_cmd,init}.rs

📄 CodeRabbit inference engine (AGENTS.md)

Migration journals must be reconciled only when valid and safe; refuse reconciliation when tools/nushell is a symlink or reparse point, and retain journals when repair fails.

Files:

  • src/cmd/doctor.rs
  • src/cmd/use_cmd.rs
src/cmd/{activate,deactivate,plugin_lifecycle,update}.rs

📄 CodeRabbit inference engine (AGENTS.md)

Nu plugin register/unregister callbacks are owned by the activate/deactivate lifecycle boundary; only explicitly opted-in update orchestration may coordinate that boundary and must not invoke callbacks directly.

Files:

  • src/cmd/activate.rs
  • src/cmd/deactivate.rs
src/cmd/{activate,deactivate}.rs

📄 CodeRabbit inference engine (AGENTS.md)

Keep activation and deactivation testable through injected registrar, unregistrar, and candidate-runner seams; unit tests must not spawn a real Nu binary.

Files:

  • src/cmd/activate.rs
  • src/cmd/deactivate.rs
src/state/activation_profile.rs

📄 CodeRabbit inference engine (AGENTS.md)

Activation profiles store desired plugin/module sets per Nu minor; cross-minor switching tears down modules then plugins and restores plugins then modules. Same-target switching is restore-only.

Files:

  • src/state/activation_profile.rs
🪛 markdownlint-cli2 (0.23.2)
AGENTS.md

[warning] 240-240: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)

🔍 Remote MCP DeepWiki, GitHub Copilot

Additional review context

  • The repository treats Lockfile activation records as authoritative; plugin/module activity is tied to exact Nu identity fields, while journals support crash recovery. ``
  • PR #108 adds a 1,284-line activation-switch module coordinating teardown, marker writes, path refresh, and restoration. ``
  • Potential issue: leave_current_nu treats all Lockfile::load errors as “no lockfile,” although malformed/unreadable lockfiles are otherwise propagated. This could permit switching with corrupted state.
  • Potential issue: activation-profile synchronization after activate uses every requested ID even when some activations failed, potentially recording failed packages as desired restorations. ``
  • Potential issue: an incompatible explicit try owner/name@version reports a retry command without @version, so the suggested retry may target a different package version. ``
  • Restore failures caused by missing/drifted cached paths are emitted as warnings after the active-version marker has been written; the switch can therefore complete without restoring the desired profile. ``
  • CI currently reports Rust analysis, CodeQL, CodeFactor, and other analysis checks successful; Greptile remains in progress. Sourcery skipped review because the diff exceeded its 150,000-character limit. ``
🔇 Additional comments (51)
src/cmd/doctor.rs (2)

493-528: LGTM!


2343-2410: LGTM!

src/cmd/registry.rs (3)

183-207: LGTM!


231-255: LGTM!


257-323: LGTM!

AGENTS.md (1)

68-70: LGTM!

Also applies to: 88-88, 235-239, 241-251

CHANGELOG.md (1)

18-20: LGTM!

Also applies to: 24-24

README.md (1)

202-202: LGTM!

Also applies to: 246-246, 263-263, 337-337

src/cli.rs (1)

62-62: LGTM!

src/cmd/try_cmd.rs (10)

4-25: LGTM!


27-37: LGTM!


39-90: LGTM!


194-232: LGTM!


253-290: LGTM!


388-479: LGTM!


481-506: LGTM!


508-666: LGTM!


811-839: LGTM!


188-192: 📐 Maintainability & Code Quality

Run cargo fmt --all -- --check before merge.

This expression has long call-chains and a long string literal; the CI formatter job runs cargo fmt --all -- --check, so manual formatter status is needed before merge.

src/core/resolve.rs (5)

469-502: LGTM!


504-524: LGTM!


530-590: LGTM!


924-939: LGTM!


986-1070: LGTM!

src/state/activation_profile.rs (4)

1-68: LGTM!


132-158: LGTM!


161-169: LGTM!


227-338: LGTM!

src/state/mod.rs (1)

1-1: LGTM!

src/cmd/activate.rs (2)

140-145: LGTM!

Also applies to: 181-185


601-638: LGTM!

src/cmd/deactivate.rs (6)

128-128: LGTM!

Also applies to: 166-166, 266-281


189-200: LGTM!


231-256: LGTM!


405-458: LGTM!


481-482: LGTM!

Also applies to: 570-574


1556-1574: LGTM!

src/cmd/remove.rs (1)

164-166: LGTM!

src/cmd/activation_switch.rs (8)

1-82: LGTM!


124-146: LGTM!


184-221: LGTM!


264-344: LGTM!


426-514: LGTM!

Also applies to: 517-559, 562-593


595-1284: LGTM!


86-91: 🎯 Functional Correctness

No change needed: managed autoload paths use the normalized /numan.nu form.


236-243: 🎯 Functional Correctness

No change needed. numan use 0.114 parses and normalizes the minor-only argument, and the subsequent minor-key reconciliation uses that same parsed value.

src/cmd/mod.rs (1)

2-2: LGTM!

src/cmd/use_cmd.rs (4)

7-19: LGTM!


31-98: LGTM!


122-144: LGTM!


515-645: LGTM!

Also applies to: 652-657

Comment thread AGENTS.md
Comment thread README.md
Comment thread README.md
Comment thread src/cmd/activate.rs Outdated
Comment thread src/cmd/activation_switch.rs Outdated
Comment thread src/core/resolve.rs
Comment thread src/core/resolve.rs Outdated
Comment thread src/core/resolve.rs Outdated
Comment thread src/state/activation_profile.rs
Comment thread src/state/activation_profile.rs
@tonythethompson

Copy link
Copy Markdown
Collaborator Author

All cargo test --lib failures from the initial push are now fixed:

  • cmd::activation_switch::tests::teardown_order_modules_then_plugins
  • cmd::use_cmd::tests::execute_with_hooks_and_refresh_integration
  • nu::bootstrap::tests::register_existing_nu_refuses_non_tty_without_yes_before_path_mutation

cargo test --lib now passes the full suite (646 passed, 1 ignored), and cargo clippy -- -D warnings and cargo fmt --check are clean.

Comment thread src/cmd/try_cmd.rs Outdated

@coderabbitai coderabbitai 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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/cmd/try_cmd.rs (1)

700-704: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Add a regression test for the lock handoff.

The activation callback only sets activated. The test passes even if Line 333 is removed. Add a timeout-controlled test seam that attempts to acquire the same root mutation lock during activation.

As per coding guidelines: “Tests must cover failure modes, not only successful execution.”

🤖 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/cmd/try_cmd.rs` around lines 700 - 704, Add a regression test around the
activation callback in the try command test to verify lock handoff: during
activation, attempt to acquire the same root mutation lock using a
timeout-controlled test seam, and assert the acquisition succeeds. Keep the
existing package assertion and activated tracking, while ensuring the test would
fail if the lock remains held through activation.

Source: Coding guidelines

🤖 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.

Outside diff comments:
In `@src/cmd/try_cmd.rs`:
- Around line 700-704: Add a regression test around the activation callback in
the try command test to verify lock handoff: during activation, attempt to
acquire the same root mutation lock using a timeout-controlled test seam, and
assert the acquisition succeeds. Keep the existing package assertion and
activated tracking, while ensuring the test would fail if the lock remains held
through activation.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 9d6d0249-586d-4af7-96f9-be5a9f52fd2b

📥 Commits

Reviewing files that changed from the base of the PR and between 21bdc2e and 5d3c126.

📒 Files selected for processing (1)
  • src/cmd/try_cmd.rs
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • tonythethompson/QuickShell (manual)
  • tonythethompson/numan (manual)
  • tonythethompson/dependency-chain-substrate (manual)
📜 Review details
⏰ Context from checks skipped due to timeout. (1)
  • GitHub Check: Greptile Review
🧰 Additional context used
📓 Path-based instructions (10)
**/*

📄 CodeRabbit inference engine (CLAUDE.md)

**/*: Use Serena's semantic, symbol-aware tools as the primary tools for reading and editing code; use built-in Read, Glob, Grep, and Edit only under the stated exceptions.
Before editing a code file, inspect its symbol overview, read the specific symbols being changed, and edit them with Serena's symbol-aware tools.
Understand the existing code before changing it and make the smallest change that satisfies the request; avoid unrelated cleanup, premature abstractions, unnecessary error handling, feature flags, and compatibility shims.
Prefer editing existing files over creating new ones, and never create Markdown or README files unless explicitly requested.
For exploratory questions, provide a 2–3 sentence recommendation with the main tradeoff and do not implement until the user agrees.
For UI or frontend changes that cannot be tested in a browser, explicitly state that browser testing was not performed rather than claiming success.
Address security issues when discovered, including injection, XSS, SQL injection, path traversal, and secret leaks.
Pause and obtain confirmation before destructive, hard-to-reverse, externally visible, or third-party-upload actions, including deleting files or branches, dropping tables, force-pushing, modifying CI/CD, posting externally, or uploading content.
When blocked, investigate the root cause instead of bypassing it with --no-verify, --force, or deletion; investigate unfamiliar files, branches, and configuration before deleting them.
Only commit when explicitly asked; do not proactively update git configuration or push changes.
Do not skip Git hooks unless explicitly asked; if a pre-commit hook fails, fix the issue, re-stage, and create a new commit rather than amending.
Stage files by name rather than using git add -A or git add ., to avoid accidentally including secrets or large binaries.
Use a HEREDOC for commit messages, and add co-author attribution only when the user explicitly requests the exact trailer.
Do not force-pus...

Files:

  • src/cmd/try_cmd.rs
**/*.{js,jsx,ts,tsx,py,java,go,rs,rb,php,c,cpp,h,hpp,cs,swift,kt,kts}

📄 CodeRabbit inference engine (CLAUDE.md)

Add comments only when the WHY is non-obvious; do not narrate what the code does, reference the current task, or reference the PR in comments.

Files:

  • src/cmd/try_cmd.rs
!**/.env,!**/credentials.json,!**/*.pem

📄 CodeRabbit inference engine (CLAUDE.md)

Do not commit files that appear to contain secrets, including .env, credentials.json, and PEM files; warn before doing so even if explicitly requested.

Files:

  • src/cmd/try_cmd.rs
**/*.rs

📄 CodeRabbit inference engine (CONTRIBUTING.md)

**/*.rs: Use the Rust 2021 edition.
Use anyhow::Result with .context(...) in application code; use thiserror for library error types that callers match on.
Use clap derive macros for CLI definitions.
Use serde with serde_json or toml for serialization.
Function parameters must use &Path, not &PathBuf.
Library code must not panic; error paths should return anyhow::Result with context where appropriate.
Add or update tests for behavior changes, including relevant failure paths.
New mutating code paths must acquire the mutation lock via acquire_mutation_lock(root) and snapshot the lockfile before writes.
Lockfile, journal, and state-file JSON writes must use write_json_atomic.
numan install must write only to $NUMAN_ROOT; it must not invoke Nu or register plugins/autoloads.
Only activate and deactivate may modify Nu integration state.
Treat the lockfile as the authoritative source of truth; derived projections such as autoload state must not be authoritative.
Install payloads under versioned, content-addressed paths and never overwrite them in place.
Never overwrite foreign autoload files; respect OWNERSHIP_MARKER.
Pass plugin paths through environment variables only; do not use runtime interpolation in Nu program strings.

**/*.rs: All CI gates must pass: cargo test, cargo clippy -- -D warnings, and cargo fmt --check.
Every mutating command—including install, remove, update, gc, and future nupm import—must call acquire_mutation_lock(root).
Lockfiles, journals, and state files must use write_json_atomic; partial writes are not allowed.
Pending activation, autoload, and lifecycle journals must be stored under $NUMAN_ROOT/state/.
Module autoload identity must match all four fields: Nu executable hash, Nu version, vendor autoload directory, and managed file path; the lockfile module_activation value is authoritative.
Never overwrite foreign autoload files; respect OWNERSHIP_MARKER.
Pass paths to Nu only throu...

Files:

  • src/cmd/try_cmd.rs
**/*.{rs,toml}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Run and keep cargo fmt/rustfmt clean, and ensure cargo clippy -- -D warnings passes.

Files:

  • src/cmd/try_cmd.rs
**/*.{rs,nu}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

**/*.{rs,nu}: Real-Nu acceptance tests must be marked #[ignore] and should be run when changes affect activation or nupm import; unit tests must not spawn real nu and should use injectable seams such as FakeCandidateRunner or registrars.
The nupm integration must be read-only toward NUPM_HOME, must not execute build.nu, and must not perform bidirectional synchronization.

Unit tests must use FakeCandidateRunner or injectable registrars and must not spawn a real nu process.

Files:

  • src/cmd/try_cmd.rs
**/*.{rs,md}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Match existing naming, module layout, and documentation level in the file being edited; update AGENTS.md, docs/, or command help when structure, conventions, or user-visible behavior changes.

Tests must cover failure modes, not only successful execution.

Files:

  • src/cmd/try_cmd.rs
**/*.{rs,md,toml}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Use the repository's established serialization and module conventions rather than introducing unrelated refactors.

Files:

  • src/cmd/try_cmd.rs
src/{cmd,state,config,nu}/**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

Create a snapshot before mutations performed by install, update, remove, activate, deactivate, nupm import, or init --refresh.

Files:

  • src/cmd/try_cmd.rs
**/*.{md,rs,toml,yml,yaml}

📄 CodeRabbit inference engine (AGENTS.md)

Keep user-facing fix hints aligned with docs/numan-doctor.md, and keep review conventions aligned with REVIEW.md and the GitHub review instructions.

Files:

  • src/cmd/try_cmd.rs
🧠 Learnings (1)
📓 Common learnings
Learnt from: CR
Repo: tonythethompson/numan

Timestamp: 2026-08-07T23:17:09.897Z
Learning: Do not silently auto-switch the user's Nushell version; use compatibility-aware UX such as `numan try`, honest search/install results, and offer-based managed Nu pinning.
Learnt from: CR
Repo: tonythethompson/numan

Timestamp: 2026-08-07T23:17:09.897Z
Learning: Use imperative commit messages shorter than 72 characters, feature/fix branch naming, no force-pushes to `master`, and squash merges for features.
🔍 Remote MCP DeepWiki, GitHub Copilot

Relevant review context

  • Confirmed critical issue: leave_current_nu treats every Lockfile::load error as “no lockfile.” Since missing lockfiles already load as empty, this swallows malformed/unreadable lockfiles and allows version switching without tearing down active packages. DeepWiki confirms malformed lockfiles must block automated operations.

  • Confirmed numan try lock behavior: the PR explicitly drops the install lock before invoking activate, addressing the non-reentrant lock failure identified in review.

  • Unresolved pinned-version correctness issue: incompatible owner/name@version requests pass the unversioned package ID into compatibility reporting. Recommendations are computed across all releases and the retry hint omits @version, potentially switching to or installing a different release.

  • Unresolved activation-profile integrity issue: explicit activation requests are synchronized into the profile without checking that activation records were successfully written; failed activations may become desired restore state.

  • Unresolved same-target path issue: numan use latest can repair a dangling marker path, then enter the same-target reconciliation path without refreshing paths.json, leaving cached Nu identity potentially stale.

  • Unresolved restore fail-open issue: restore classification treats missing/unavailable registry information as compatible, allowing restoration without validating Nu compatibility.

  • Test gap: the ordering assertion compares the unregister position with order.len(), so it cannot prove teardown occurred before marker/path switching.

  • CI observations: CodeQL, CodeFactor, and language analysis checks reported success; Greptile review and Rust analysis were still in progress, while the CodeRabbit status was pending.

🔇 Additional comments (5)
src/cmd/try_cmd.rs (5)

287-289: Preserve explicit-version context in incompatibility reporting.

At Line 289, target_entry is already classified, but report_incompatible receives only package_id. For owner/name@version, the report can use compatibility data from another release and print a retry command without @version. Pass the original package_spec and scope compatibility reporting to the selected version. This repeats the previous review finding.


673-709: Cover explicit-version failure paths.

The supplied try_package tests pass None for version. They do not cover invalid, unavailable, or incompatible explicit versions. Add these cases and verify that installation and activation callbacks are not called. This repeats the previous review finding.

As per coding guidelines: “Tests must cover failure modes, not only successful execution.”

Source: Coding guidelines


292-349: LGTM!


399-451: LGTM!


513-541: LGTM!

tonythethompson added a commit that referenced this pull request Aug 8, 2026
- Move activation-profile.json from nu_state/ to state/ so snapshots
  and rollback capture it alongside other state files. Added
  activation_profile sidecar to Snapshot/SidecarDigests, capture in
  create_snapshot, restore in rollback_to_snapshot, new
  ActivationProfileCommitted lifecycle stage.
- Extract duplicated nearest-version comparator in resolve.rs into
  nearest_comparator helper using u64::abs_diff.
- Remove unused verified parameter from plugin_with_verified test
  fixture (renamed to windows_plugin).
- Preserve explicit-version context in try_cmd incompatibility
  reporting: report_incompatible now accepts package_spec and optional
  target_entry so pinned owner/name@version scopes compatibility to
  that release and the retry hint includes @Version.
- Add compatible_nu_versions_for_entry to resolve.rs for scoped
  compatibility checks against a single VersionEntry.
- Add tests: invalid version format, unavailable version, incompatible
  pinned version with scoped compat, lock handoff regression.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
tonythethompson added a commit that referenced this pull request Aug 8, 2026
- Critical: propagate Lockfile::load errors in leave_current_nu instead
  of swallowing them. A missing lockfile already returns Ok(empty), so
  the Err arm only fires on corrupt state -- switching must stop there.
- Major: filter args.packages by post-activation liveness in
  sync_user_activate_profile so failed activation lanes are not recorded
  as desired state for numan use restore.
- Major: fix tautological ordering assertion in use_cmd test to assert
  against the observable path_refresh boundary (unreg < refresh < reg).
- Minor: add .context() to active_nu_binary and latest_installed_version
  in resolve_managed_nu_binary for actionable doctor diagnostics.
- Minor: remove behavior-narrating doc comments from registry.rs helpers.
- Minor: fix incorrect doc comment on candidate_nu_versions_from_constraint
  (it does not include verified-with versions; caller adds those).
- Trivial: add rationale comment for plugin-only fallback in
  classify_restore_target (plugins need target match; modules are scripts).

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>

@coderabbitai coderabbitai 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.

Actionable comments posted: 7

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/cmd/use_cmd.rs (1)

532-541: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Both fake Nu versions hash to the same value, so the identity dimension is inert.

Line 534 hashes b"fake". Line 539 hashes "fake".as_bytes(). Those are the same bytes, so hash_113 == hash_114.

The lockfile activation at Line 583 records nu_executable_sha256: hash_113. After path_refresh runs, nu_paths.nu_executable_hash is hash_114, which equals hash_113. Any switch-path check that compares the recorded executable hash against the live one therefore cannot distinguish the two Nu installations in this test. The test name claims a cross-minor switch, but the executable-identity dimension is degenerate.

Write distinct bytes per version, and hash the same bytes the test writes to disk.

💚 Proposed fix — give each version a distinct hash
     fn create_fake_version(root: &Path, version: &str) {
         let binary_name = if cfg!(windows) { "nu.exe" } else { "nu" };
         let dir = version_manager::version_install_dir(root, version);
         std::fs::create_dir_all(&dir).unwrap();
-        std::fs::write(dir.join(binary_name), "fake").unwrap();
+        std::fs::write(dir.join(binary_name), format!("fake-{version}")).unwrap();
     }
         let (nu_exe_113, hash_113) = {
             let binary = version_manager::version_binary(root, "0.113.1");
-            let hash = integrity::compute_sha256(b"fake");
+            let hash = integrity::compute_sha256(b"fake-0.113.1");
             (binary.to_string_lossy().into_owned(), hash)
         };
         let (nu_exe_114, hash_114) = {
             let binary = version_manager::version_binary(root, "0.114.0");
-            let hash = integrity::compute_sha256("fake".as_bytes());
+            let hash = integrity::compute_sha256(b"fake-0.114.0");
             (binary.to_string_lossy().into_owned(), hash)
         };
+        assert_ne!(hash_113, hash_114, "fake Nu binaries must have distinct hashes");

Check the other tests in this module that rely on create_fake_version; test_use_switch_clears_stale_paths_cache_when_probe_fails uses a literal "deadbeef" hash and is unaffected.

As per coding guidelines: "Module autoload identity must match all four fields: Nu executable hash, Nu version, vendor autoload directory, and managed file path."

🤖 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/cmd/use_cmd.rs` around lines 532 - 541, Update the fake Nu version setup
in the test around nu_exe_113 and nu_exe_114 to write distinct per-version bytes
to disk and compute each hash from the exact bytes written. Keep the resulting
hash_113 and hash_114 values different so the cross-minor switch validates
executable identity along with the other autoload fields; do not change
unrelated tests such as
test_use_switch_clears_stale_paths_cache_when_probe_fails.

Source: Coding guidelines

README.md (1)

262-262: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Qualify numan try activation by package type.

The documentation treats compatibility as sufficient for activation. Scripts and completion packages remain install-only, so the documentation must distinguish installation from activation.

  • README.md#L262-L262: state that numan try activates only activatable package types.
  • README.md#L214-L214: qualify the compatible-package activation statement.
  • CHANGELOG.md#L18-L18: describe activation as conditional on the package type.
🤖 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 `@README.md` at line 262, Update the `numan try` documentation to distinguish
installation from activation: in README.md lines 262-262 and 214-214, state that
activation occurs only for compatible, activatable package types while scripts
and completion packages remain install-only; update CHANGELOG.md lines 18-18
with the same conditional activation wording.
🤖 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 `@AGENTS.md`:
- Line 91: Document that activation-profile.json is captured, digested, and
restored only for new snapshots; legacy snapshots omit it and leave the live
activation profile unchanged during rollback. Update AGENTS.md lines 91 and 156
to qualify the project-structure summary and activation-profile convention, and
update CHANGELOG.md line 14 to state that the capture and rollback behavior
applies only to new snapshots.

In `@CHANGELOG.md`:
- Line 14: Update the changelog entry describing activation-profile snapshot
capture and restoration to qualify that only new snapshots include and digest
activation-profile.json; specify that legacy snapshots omit it and leave the
live profile unchanged during rollback, while preserving the existing behavior
descriptions for new snapshots.

In `@src/cmd/deactivate.rs`:
- Around line 393-417: Keep the runner validation in the terminal deactivation
flow, but avoid calling run_partial_deactivation when remaining_ids is empty;
route that case through the existing journaled run_full_deactivation path so
deletion of the managed file and AutoloadState is journaled and the journal is
cleared last. Preserve the non-terminal partial-deactivation path, and add
coverage verifying runner-driven final deactivation leaves no managed autoload
file, no autoload-state.json, and no journal.

In `@src/core/resolve.rs`:
- Around line 526-551: Extract the shared candidate iteration, version
deduplication, and sorting logic from compatible_nu_versions and
compatible_nu_versions_for_entry into a private helper that accepts the
compatibility predicate. Update both public functions to call this helper with
their respective predicates, preserving the existing deduplication key,
ascending sort order, and compatibility behavior.

In `@src/nu/bootstrap.rs`:
- Around line 1462-1468: Move PathRestoreGuard::new() to before the PATH
inspection/source scan so the process-global environment is protected throughout
the test. Update every PATH-mutating test, including
prepend_process_path_adds_canonical_dir, to acquire and retain the same guard
before reading or modifying PATH.
- Line 1459: Update the set_permissions call in the bootstrap
permission-handling code to pass perms by value instead of borrowing it.
Preserve the existing existing path and permission-setting behavior.

In `@src/state/snapshot.rs`:
- Around line 692-708: Update src/state/snapshot.rs:692-708 in
capture_activation_profile_sidecar to return SnapshotSidecar::Absent or Present
rather than Option, always compute activation_profile_sha256 with ?, and always
write the sidecar so missing profiles are represented. Ensure the documentation
at src/state/snapshot.rs:163-175 states that new snapshots record Absent or
Present. In src/state/rollback.rs:269-275, retain the SnapshotSidecar::Absent
handling, verify it is reachable, and add a test confirming rollback removes
state/activation-profile.json when the snapshot recorded no profile.

---

Outside diff comments:
In `@README.md`:
- Line 262: Update the `numan try` documentation to distinguish installation
from activation: in README.md lines 262-262 and 214-214, state that activation
occurs only for compatible, activatable package types while scripts and
completion packages remain install-only; update CHANGELOG.md lines 18-18 with
the same conditional activation wording.

In `@src/cmd/use_cmd.rs`:
- Around line 532-541: Update the fake Nu version setup in the test around
nu_exe_113 and nu_exe_114 to write distinct per-version bytes to disk and
compute each hash from the exact bytes written. Keep the resulting hash_113 and
hash_114 values different so the cross-minor switch validates executable
identity along with the other autoload fields; do not change unrelated tests
such as test_use_switch_clears_stale_paths_cache_when_probe_fails.
🪄 Autofix

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: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: d22b821b-5008-4a4b-bb62-9cd9b942d25f

📥 Commits

Reviewing files that changed from the base of the PR and between 5d3c126 and b136255.

📒 Files selected for processing (13)
  • .markdownlint.json
  • AGENTS.md
  • CHANGELOG.md
  • README.md
  • src/cmd/deactivate.rs
  • src/cmd/try_cmd.rs
  • src/cmd/use_cmd.rs
  • src/core/resolve.rs
  • src/nu/bootstrap.rs
  • src/state/activation_profile.rs
  • src/state/lifecycle_journal.rs
  • src/state/rollback.rs
  • src/state/snapshot.rs
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • tonythethompson/QuickShell (manual)
  • tonythethompson/numan (manual)
  • tonythethompson/dependency-chain-substrate (manual)
📜 Review details
⏰ Context from checks skipped due to timeout. (2)
  • GitHub Check: Greptile Review
  • GitHub Check: Analyze (rust)
🧰 Additional context used
📓 Path-based instructions (15)
!**/.env,!**/credentials.json,!**/*.pem

📄 CodeRabbit inference engine (CLAUDE.md)

Do not commit files that appear to contain secrets, including .env, credentials.json, and PEM files; warn before doing so even if explicitly requested.

Files:

  • .markdownlint.json
  • src/state/lifecycle_journal.rs
  • CHANGELOG.md
  • src/nu/bootstrap.rs
  • src/state/rollback.rs
  • src/cmd/use_cmd.rs
  • src/cmd/deactivate.rs
  • AGENTS.md
  • src/core/resolve.rs
  • src/state/activation_profile.rs
  • src/state/snapshot.rs
  • README.md
  • src/cmd/try_cmd.rs
**/*

📄 CodeRabbit inference engine (CLAUDE.md)

**/*: Use Serena's semantic, symbol-aware tools as the primary tools for reading and editing code; use built-in Read, Glob, Grep, and Edit only under the stated exceptions.
Before editing a code file, inspect its symbol overview, read the specific symbols being changed, and edit them with Serena's symbol-aware tools.
Understand the existing code before changing it and make the smallest change that satisfies the request; avoid unrelated cleanup, premature abstractions, unnecessary error handling, feature flags, and compatibility shims.
Prefer editing existing files over creating new ones, and never create Markdown or README files unless explicitly requested.
For exploratory questions, provide a 2–3 sentence recommendation with the main tradeoff and do not implement until the user agrees.
For UI or frontend changes that cannot be tested in a browser, explicitly state that browser testing was not performed rather than claiming success.
Address security issues when discovered, including injection, XSS, SQL injection, path traversal, and secret leaks.
Pause and obtain confirmation before destructive, hard-to-reverse, externally visible, or third-party-upload actions, including deleting files or branches, dropping tables, force-pushing, modifying CI/CD, posting externally, or uploading content.
When blocked, investigate the root cause instead of bypassing it with --no-verify, --force, or deletion; investigate unfamiliar files, branches, and configuration before deleting them.
Only commit when explicitly asked; do not proactively update git configuration or push changes.
Do not skip Git hooks unless explicitly asked; if a pre-commit hook fails, fix the issue, re-stage, and create a new commit rather than amending.
Stage files by name rather than using git add -A or git add ., to avoid accidentally including secrets or large binaries.
Use a HEREDOC for commit messages, and add co-author attribution only when the user explicitly requests the exact trailer.
Do not force-pus...

Files:

  • src/state/lifecycle_journal.rs
  • CHANGELOG.md
  • src/nu/bootstrap.rs
  • src/state/rollback.rs
  • src/cmd/use_cmd.rs
  • src/cmd/deactivate.rs
  • AGENTS.md
  • src/core/resolve.rs
  • src/state/activation_profile.rs
  • src/state/snapshot.rs
  • README.md
  • src/cmd/try_cmd.rs
**/*.{js,jsx,ts,tsx,py,java,go,rs,rb,php,c,cpp,h,hpp,cs,swift,kt,kts}

📄 CodeRabbit inference engine (CLAUDE.md)

Add comments only when the WHY is non-obvious; do not narrate what the code does, reference the current task, or reference the PR in comments.

Files:

  • src/state/lifecycle_journal.rs
  • src/nu/bootstrap.rs
  • src/state/rollback.rs
  • src/cmd/use_cmd.rs
  • src/cmd/deactivate.rs
  • src/core/resolve.rs
  • src/state/activation_profile.rs
  • src/state/snapshot.rs
  • src/cmd/try_cmd.rs
**/*.rs

📄 CodeRabbit inference engine (CONTRIBUTING.md)

**/*.rs: Use the Rust 2021 edition.
Use anyhow::Result with .context(...) in application code; use thiserror for library error types that callers match on.
Use clap derive macros for CLI definitions.
Use serde with serde_json or toml for serialization.
Function parameters must use &Path, not &PathBuf.
Library code must not panic; error paths should return anyhow::Result with context where appropriate.
Add or update tests for behavior changes, including relevant failure paths.
New mutating code paths must acquire the mutation lock via acquire_mutation_lock(root) and snapshot the lockfile before writes.
Lockfile, journal, and state-file JSON writes must use write_json_atomic.
numan install must write only to $NUMAN_ROOT; it must not invoke Nu or register plugins/autoloads.
Only activate and deactivate may modify Nu integration state.
Treat the lockfile as the authoritative source of truth; derived projections such as autoload state must not be authoritative.
Install payloads under versioned, content-addressed paths and never overwrite them in place.
Never overwrite foreign autoload files; respect OWNERSHIP_MARKER.
Pass plugin paths through environment variables only; do not use runtime interpolation in Nu program strings.

**/*.rs: All CI gates must pass: cargo test, cargo clippy -- -D warnings, and cargo fmt --check.
Every mutating command—including install, remove, update, gc, and future nupm import—must call acquire_mutation_lock(root).
Lockfiles, journals, and state files must use write_json_atomic; partial writes are not allowed.
Pending activation, autoload, and lifecycle journals must be stored under $NUMAN_ROOT/state/.
Module autoload identity must match all four fields: Nu executable hash, Nu version, vendor autoload directory, and managed file path; the lockfile module_activation value is authoritative.
Never overwrite foreign autoload files; respect OWNERSHIP_MARKER.
Pass paths to Nu only throu...

Files:

  • src/state/lifecycle_journal.rs
  • src/nu/bootstrap.rs
  • src/state/rollback.rs
  • src/cmd/use_cmd.rs
  • src/cmd/deactivate.rs
  • src/core/resolve.rs
  • src/state/activation_profile.rs
  • src/state/snapshot.rs
  • src/cmd/try_cmd.rs
**/*.{rs,toml}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Run and keep cargo fmt/rustfmt clean, and ensure cargo clippy -- -D warnings passes.

Files:

  • src/state/lifecycle_journal.rs
  • src/nu/bootstrap.rs
  • src/state/rollback.rs
  • src/cmd/use_cmd.rs
  • src/cmd/deactivate.rs
  • src/core/resolve.rs
  • src/state/activation_profile.rs
  • src/state/snapshot.rs
  • src/cmd/try_cmd.rs
**/*.{rs,nu}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

**/*.{rs,nu}: Real-Nu acceptance tests must be marked #[ignore] and should be run when changes affect activation or nupm import; unit tests must not spawn real nu and should use injectable seams such as FakeCandidateRunner or registrars.
The nupm integration must be read-only toward NUPM_HOME, must not execute build.nu, and must not perform bidirectional synchronization.

Unit tests must use FakeCandidateRunner or injectable registrars and must not spawn a real nu process.

Files:

  • src/state/lifecycle_journal.rs
  • src/nu/bootstrap.rs
  • src/state/rollback.rs
  • src/cmd/use_cmd.rs
  • src/cmd/deactivate.rs
  • src/core/resolve.rs
  • src/state/activation_profile.rs
  • src/state/snapshot.rs
  • src/cmd/try_cmd.rs
**/*.{rs,md}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Match existing naming, module layout, and documentation level in the file being edited; update AGENTS.md, docs/, or command help when structure, conventions, or user-visible behavior changes.

Tests must cover failure modes, not only successful execution.

Files:

  • src/state/lifecycle_journal.rs
  • CHANGELOG.md
  • src/nu/bootstrap.rs
  • src/state/rollback.rs
  • src/cmd/use_cmd.rs
  • src/cmd/deactivate.rs
  • AGENTS.md
  • src/core/resolve.rs
  • src/state/activation_profile.rs
  • src/state/snapshot.rs
  • README.md
  • src/cmd/try_cmd.rs
**/*.{rs,md,toml}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Use the repository's established serialization and module conventions rather than introducing unrelated refactors.

Files:

  • src/state/lifecycle_journal.rs
  • CHANGELOG.md
  • src/nu/bootstrap.rs
  • src/state/rollback.rs
  • src/cmd/use_cmd.rs
  • src/cmd/deactivate.rs
  • AGENTS.md
  • src/core/resolve.rs
  • src/state/activation_profile.rs
  • src/state/snapshot.rs
  • README.md
  • src/cmd/try_cmd.rs
src/state/{lockfile,journal,plugin_deactivate_journal,migration_journal,autoload_journal,lifecycle_journal}.rs

📄 CodeRabbit inference engine (AGENTS.md)

src/state/{lockfile,journal,plugin_deactivate_journal,migration_journal,autoload_journal,lifecycle_journal}.rs: Write journal state atomically and reconcile pending journals on the next relevant operation; journal transitions must not leave inconsistent lockfile state.
Use write_json_atomic for JSON state writes to prevent partial-write corruption.

Files:

  • src/state/lifecycle_journal.rs
src/**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

Use serde/serde_json for JSON serialization, toml for configuration, and clap derive macros for CLI definitions.

Files:

  • src/state/lifecycle_journal.rs
  • src/nu/bootstrap.rs
  • src/state/rollback.rs
  • src/cmd/use_cmd.rs
  • src/cmd/deactivate.rs
  • src/core/resolve.rs
  • src/state/activation_profile.rs
  • src/state/snapshot.rs
  • src/cmd/try_cmd.rs
**/*.md

📄 CodeRabbit inference engine (REVIEW.md)

Update documentation and AGENTS.md when project structure or conventions change.

Files:

  • CHANGELOG.md
  • AGENTS.md
  • README.md
src/cmd/{activate,deactivate,plugin_lifecycle,update}.rs

📄 CodeRabbit inference engine (AGENTS.md)

Nu plugin registration and unregistration belong exclusively to the activate/deactivate lifecycle boundary; opted-in update orchestration may coordinate that boundary but must not invoke Nu callbacks directly.

Files:

  • src/cmd/deactivate.rs
src/cmd/{activate,deactivate}.rs

📄 CodeRabbit inference engine (AGENTS.md)

Expose dependency-injection seams such as execute_with_registrar, execute_with_unregistrar, and candidate-runner variants; unit tests must use fakes rather than spawning real Nu.

Files:

  • src/cmd/deactivate.rs
src/state/activation_profile.rs

📄 CodeRabbit inference engine (AGENTS.md)

Maintain desired activation sets per Nu minor; cross-minor switching tears down modules before plugins and restores plugins before modules, while same-target switching only restores missing desired activations.

Files:

  • src/state/activation_profile.rs
src/state/snapshot.rs

📄 CodeRabbit inference engine (AGENTS.md)

Create a snapshot before install, update, remove, activate, deactivate, nupm import, and init --refresh mutations; snapshots must capture nu_state/paths.json and keep referenced payloads live for GC.

Files:

  • src/state/snapshot.rs
🧠 Learnings (1)
📓 Common learnings
Learnt from: CR
Repo: tonythethompson/numan

Timestamp: 2026-08-08T01:02:39.785Z
Learning: Run `cargo test`, `cargo clippy -- -D warnings`, and `cargo fmt --check`; CI also runs ignored real-Nu acceptance tests across Ubuntu, Windows, and macOS.
Learnt from: CR
Repo: tonythethompson/numan

Timestamp: 2026-08-08T01:02:39.785Z
Learning: Source builds require explicit user consent before cloning or building, with separate consent scopes.
Learnt from: CR
Repo: tonythethompson/numan

Timestamp: 2026-08-08T01:02:39.785Z
Learning: Create a feature branch, implement with tests, update AGENTS.md when conventions change, and submit a descriptive PR.
🪛 LanguageTool
AGENTS.md

[grammar] ~5-~5: Ensure spelling is correct
Context: ...es, rollback, and interoperability with nupm. ## Build & Test ```bash # Build cargo buil...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)

🔍 Remote MCP DeepWiki, GitHub Copilot

Additional review context

  • leave_current_nu treats all Lockfile::load errors as “no lockfile” and proceeds. This can allow switching past malformed/unreadable lockfiles instead of failing closed. The repository’s lockfile contains authoritative activation records, and lifecycle operations depend on those records matching the current Nu identity.

  • Teardown ordering is implemented as modules first, then plugins; restoration is plugins first, then modules. The test verifies lifecycle callback ordering, but the use_cmd integration test’s marker-order assertion compares unregister position against order.len(), so it does not actually establish that teardown preceded marker mutation.

  • Restore compatibility classification is fail-open when registry lookup fails or the installed version is absent from the registry: classify_restore_target only returns Incompatible for explicit incompatible entries (or missing compatible plugin versions), otherwise it returns Ok. This may restore packages without verified compatibility.

  • Activation-profile persistence is now part of snapshot/rollback state. New snapshots record and digest activation-profile.json; legacy snapshots omit it and leave the live profile unchanged during rollback. Rollback records a dedicated ActivationProfileCommitted lifecycle stage.

  • numan try correctly scopes compatibility recommendations to the pinned VersionEntry when owner/name@version is supplied, and explicitly drops the install lock before invoking activation so activation can reacquire the mutation lock.

🔇 Additional comments (16)
src/cmd/use_cmd.rs (1)

663-668: 🎯 Functional Correctness | ⚡ Quick win

The ordering assertion still cannot fail.

version_changed_pos is order.len(). unreg_pos is an index into order, and Line 657 already asserted that "unregister" is present. Any valid index is less than the length, so the comparison at Line 665-668 is always true.

The message claims the assertion verifies that the unregistrar runs before the active-version marker changes. The marker write is never pushed into order, so its position is not observable from this vector. This is fake readiness for the ordering invariant the cross-minor switch depends on.

path_refresh runs immediately after the marker write, so use it as the observable boundary.

💚 Proposed fix — assert against an observable boundary
         let unreg_pos = order.iter().position(|&x| x == "unregister").unwrap();
-        let version_changed_pos = order.len();
-        assert!(
-            unreg_pos < version_changed_pos,
-            "unregistrar must execute before active-version marker changes"
-        );
+        // `path_refresh` runs immediately after the active-version marker
+        // write, so it marks the switch boundary observably.
+        let refresh_pos = order.iter().position(|&x| x == "path_refresh").unwrap();
+        let reg_pos = order.iter().position(|&x| x == "register").unwrap();
+        assert!(
+            unreg_pos < refresh_pos,
+            "unregistrar must execute before the active-version marker changes: {order:?}"
+        );
+        assert!(
+            refresh_pos < reg_pos,
+            "restore must run after the marker write and paths refresh: {order:?}"
+        );
src/state/activation_profile.rs (1)

1-1: LGTM!

Also applies to: 85-130, 132-169

src/cmd/deactivate.rs (1)

1572-1589: LGTM!

src/state/lifecycle_journal.rs (1)

62-63: LGTM!

src/state/snapshot.rs (2)

102-105: LGTM!


359-395: LGTM!

src/core/resolve.rs (1)

621-644: LGTM!

Also applies to: 963-963, 991-991, 1016-1016, 1036-1036

src/cmd/try_cmd.rs (1)

3-3: LGTM!

Also applies to: 96-105, 184-184, 285-302, 843-843, 934-1078

AGENTS.md (3)

156-156: Document that restoration can fail after the marker write.

numan use switches the active marker before restoring activations. The restore phase can fail or remain partial, so this convention should describe an attempted restore and its failure behavior.

Source: MCP tools


247-247: Preserve the explicit package version in retry guidance.

When the user supplies owner/name@version, the retry must repeat that full specification. Dropping @version can select a different package version after numan use <version>.

Also applies to: 263-263

Source: MCP tools


4-8: LGTM!

Also applies to: 38-39, 71-73, 132-132, 172-172, 184-190, 213-227, 245-246, 248-251, 252-262, 264-265

README.md (2)

356-357: Document restore failure after the marker write.

Cross-minor numan use can switch the marker successfully and then fail during plugin or module restoration. Document successful restoration and the possibility of a non-zero, partial restore result.

Source: MCP tools


7-8: LGTM!

Also applies to: 26-26, 61-61, 94-108, 170-188, 201-201, 245-245, 308-308, 334-336, 370-370, 457-457, 468-468, 479-479, 489-489

CHANGELOG.md (1)

19-20: LGTM!

Also applies to: 24-24

.markdownlint.json (1)

1-5: LGTM!

src/nu/bootstrap.rs (1)

1436-1437: 🎯 Functional Correctness

No change needed. validate_nushell_binary() only checks the executable bit before probing, and register_existing_nu() returns before PATH mutation when TTY is false without --yes; probe_nu_config_path() is not called in this code path.

Comment thread AGENTS.md
Comment thread CHANGELOG.md
Comment thread src/cmd/deactivate.rs
Comment thread src/core/resolve.rs
Comment thread src/nu/bootstrap.rs Outdated
Comment thread src/nu/bootstrap.rs Outdated
Comment thread src/state/snapshot.rs
tonythethompson and others added 13 commits August 7, 2026 19:02
Doctor still looked for the legacy tools/nushell/nu path, so versioned setup nu installs were reported as missing.

Co-authored-by: Cursor <cursoragent@cursor.com>
Style package ids, soft-wrap dim descriptions, and separate entries with blank lines.

Co-authored-by: Cursor <cursoragent@cursor.com>
Remember per-Nu-minor activation desire so cross-minor switches leave and restore plugins/modules without shrinking leave profiles.

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Fixed 7 file(s) based on 9 unresolved review comments.

Co-authored-by: CodeRabbit <noreply@coderabbit.ai>
- `numan try <owner/name[@Version]>` now attempts the specified package for the current Nu and platform.

- If incompatible, it lists compatible managed Nu versions, recommends the nearest, and suggests `numan use <version>` followed by `numan try <package>` without auto-switching Nu or installing alternatives.

- Removed the curated-starter logic and the obsolete `try --yes` flow.

- Reuses existing Resolver, transaction, and activate machinery.

- Added resolve helpers for candidate Nu version discovery and recommendation.

- Updated README, CHANGELOG, AGENTS, and CLI docs; added 16 unit tests.

- Also fixed compile/test blockers in activation_switch and use_cmd.

Generated with [Devin](https://devin.ai)
- activation_switch: use partial module deactivation when a runner is provided so teardown-order test can observe the module lane.

- use_cmd: seed 0.114 activation profile and refresh fake Nu paths in the path_refresh hook so the integration test exercises plugin restore.

- nu/bootstrap: isolate PATH with PathRestoreGuard in register_existing_nu_refuses_non_tty_without_yes_before_path_mutation so concurrent tests cannot race on the process-global PATH.
- Move activation-profile.json from nu_state/ to state/ so snapshots
  and rollback capture it alongside other state files. Added
  activation_profile sidecar to Snapshot/SidecarDigests, capture in
  create_snapshot, restore in rollback_to_snapshot, new
  ActivationProfileCommitted lifecycle stage.
- Extract duplicated nearest-version comparator in resolve.rs into
  nearest_comparator helper using u64::abs_diff.
- Remove unused verified parameter from plugin_with_verified test
  fixture (renamed to windows_plugin).
- Preserve explicit-version context in try_cmd incompatibility
  reporting: report_incompatible now accepts package_spec and optional
  target_entry so pinned owner/name@version scopes compatibility to
  that release and the retry hint includes @Version.
- Add compatible_nu_versions_for_entry to resolve.rs for scoped
  compatibility checks against a single VersionEntry.
- Add tests: invalid version format, unavailable version, incompatible
  pinned version with scoped compat, lock handoff regression.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Forward the use PreMutation snapshot into unlocked activate/deactivate
module helpers, print leave summary before restore, prove restore order
with TrackingRunner, and harden HOME/PATH test isolation around register.

Co-authored-by: Cursor <cursoragent@cursor.com>
greptile-apps[bot]
greptile-apps Bot previously approved these changes Aug 8, 2026

@coderabbitai coderabbitai 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.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (4)
src/cmd/activation_switch.rs (1)

340-368: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Preserve committed module results when journal cleanup fails.

activate_modules_unlocked can return Err after it writes module activation records and autoload-state.json. For example, PendingAutoload::delete(root)? runs after those commits.

The Err branch marks every module_id as failed without reloading actual activation state. numan use can then report successful module activations as failures and return an incorrect lifecycle failure.

Reload and classify module activation state in the Err branch, as the Ok(true) branch already does. Record the journal-cleanup error as a separate lifecycle error. Add a failure-path test that injects an error after module state commits.

As per coding guidelines: “Tests must cover failure modes, not only successful execution.”

🤖 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/cmd/activation_switch.rs` around lines 340 - 368, Update the Err branch
handling the result of activate_modules_unlocked to reload the lockfile and
classify each module using collect_currently_active, matching the Ok(true)
branch instead of marking every module failed. Preserve successfully committed
modules in report.restored_modules, record only inactive modules as failed, and
retain the journal-cleanup error as a separate lifecycle error. Add a
failure-path test that injects an error after activation records and
autoload-state.json are committed.

Sources: Coding guidelines, MCP tools

src/cmd/try_cmd.rs (3)

1063-1116: 📐 Maintainability & Code Quality | 🔵 Trivial

Confirm that all Rust CI gates are green at the current head.

The observed CI state reports an Ubuntu Test failure while other jobs passed or were still running. Confirm that the failure is resolved before merge.

As per coding guidelines: “All CI gates must pass: cargo test, cargo clippy -- -D warnings, and cargo fmt --check.”

🤖 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/cmd/try_cmd.rs` around lines 1063 - 1116, Confirm the current head passes
all required Rust CI gates: cargo test, cargo clippy -- -D warnings, and cargo
fmt --check. Resolve any failures, including the Ubuntu test failure, before
considering the change complete.

Sources: Coding guidelines, MCP tools


1110-1116: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Make the malformed-lockfile test corrupt the file that production reads.

The test writes {not-json to lockfile, but the authoritative state file is lockfile.json. The assertion also accepts Failed to load lockfile, so the test can pass because the file is missing and never reach JSON parsing.

Write malformed content to the exact path used by Lockfile::load. Assert a parse-specific error.

The repository contract uses lockfile.json as the authoritative lockfile. As per coding guidelines: “Tests must cover failure modes, not only successful execution.”

🤖 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/cmd/try_cmd.rs` around lines 1110 - 1116, Update the malformed-lockfile
test around print_install_only_hint to write invalid JSON to the authoritative
lockfile.json path consumed by Lockfile::load. Replace the broad error assertion
with one requiring a JSON parse-specific error, ensuring the test exercises
malformed-content handling rather than a missing-file path.

Sources: Coding guidelines, MCP tools


200-210: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Remove the duplicate error prefix and show the complete package syntax.

This error returns through the standard anyhow::Result path. Do not embed error: in the message. The CLI renderer can add that prefix already.

Use numan try owner/name[@Version] in the usage text. Add assertions for both missing and empty package arguments.

As per coding guidelines: update command help when user-visible behavior changes, and use lowercase numan for the CLI.

🤖 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/cmd/try_cmd.rs` around lines 200 - 210, Update execute’s missing-package
validation to remove any embedded “error:” prefix, use the complete lowercase
syntax “numan try owner/name[`@version`]” in the message, and retain the example.
Add assertions covering both absent and empty package arguments, and update the
command help to match the revised user-facing syntax.

Sources: Coding guidelines, MCP tools

🤖 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/nu/bootstrap.rs`:
- Around line 559-568: Update the temporary-directory validation around path
registration to run unconditionally, before the consent check and any PATH
mutation. Remove the !options.skip_path guard from
path_is_under_temp_dir(&parent), while retaining skip_path solely to suppress
the durable/user PATH update.

In `@src/util/test_paths.rs`:
- Around line 194-207: Update home_restore_guard_restores_previous_value so the
baseline HOME value is captured only after HomeRestoreGuard::new() acquires
HOME_MUTEX, and reacquire HOME_MUTEX before the post-guard restoration
assertion. Match the locking pattern used by the existing PATH restoration test
while preserving the current HOME mutation and expected-value checks.

---

Outside diff comments:
In `@src/cmd/activation_switch.rs`:
- Around line 340-368: Update the Err branch handling the result of
activate_modules_unlocked to reload the lockfile and classify each module using
collect_currently_active, matching the Ok(true) branch instead of marking every
module failed. Preserve successfully committed modules in
report.restored_modules, record only inactive modules as failed, and retain the
journal-cleanup error as a separate lifecycle error. Add a failure-path test
that injects an error after activation records and autoload-state.json are
committed.

In `@src/cmd/try_cmd.rs`:
- Around line 1063-1116: Confirm the current head passes all required Rust CI
gates: cargo test, cargo clippy -- -D warnings, and cargo fmt --check. Resolve
any failures, including the Ubuntu test failure, before considering the change
complete.
- Around line 1110-1116: Update the malformed-lockfile test around
print_install_only_hint to write invalid JSON to the authoritative lockfile.json
path consumed by Lockfile::load. Replace the broad error assertion with one
requiring a JSON parse-specific error, ensuring the test exercises
malformed-content handling rather than a missing-file path.
- Around line 200-210: Update execute’s missing-package validation to remove any
embedded “error:” prefix, use the complete lowercase syntax “numan try
owner/name[`@version`]” in the message, and retain the example. Add assertions
covering both absent and empty package arguments, and update the command help to
match the revised user-facing syntax.
🪄 Autofix

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: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: e1890613-f688-464e-bfae-276cab67a9f3

📥 Commits

Reviewing files that changed from the base of the PR and between ed655b7 and d9d37d7.

📒 Files selected for processing (8)
  • src/cmd/activate.rs
  • src/cmd/activation_switch.rs
  • src/cmd/deactivate.rs
  • src/cmd/try_cmd.rs
  • src/cmd/use_cmd.rs
  • src/nu/bootstrap.rs
  • src/state/activation_profile.rs
  • src/util/test_paths.rs
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • tonythethompson/QuickShell (manual)
  • tonythethompson/numan (manual)
  • tonythethompson/dependency-chain-substrate (manual)
📜 Review details
⏰ Context from checks skipped due to timeout. (3)
  • GitHub Check: Greptile Review
  • GitHub Check: Analyze (rust)
  • GitHub Check: Analyze (rust)
⚠️ CI failures not shown inline (17)

GitHub Actions: CI / Real-Nu acceptance (windows-latest): feat/try compat

Conclusion: failure

View job details

##[group]Run cargo test --verbose -- --ignored --skip acceptance_process_helper --skip stage1_official_registry --skip real_nu_active_update_
 �[36;1mcargo test --verbose -- --ignored --skip acceptance_process_helper --skip stage1_official_registry --skip real_nu_active_update_�[0m
 shell: C:\Program Files\PowerShell\7\pwsh.EXE -command ". '{0}'"
 env:
   CARGO_TERM_COLOR: always
   CARGO_HOME: C:\Users\runneradmin\.cargo
   CARGO_INCREMENTAL: 0
   CACHE_ON_FAILURE: false
 ##[endgroup]
 ##[error]The operation was canceled.

GitHub Actions: CI / Test (windows-latest): feat/try compat

Conclusion: failure

View job details

##[group]Cache Configuration
 Cache Provider:
     github
 Workspaces:
     D:\a\numan\numan
 Cache Paths:
     C:\Users\runneradmin\.cargo\bin
     C:\Users\runneradmin\.cargo\.crates.toml
     C:\Users\runneradmin\.cargo\.crates2.json
     C:\Users\runneradmin\.cargo\registry
     C:\Users\runneradmin\.cargo\git
     D:\a\numan\numan\target
 Restore Key:
     v0-rust-test-Windows_NT-x64-8af1e26a
 Cache Key:
     v0-rust-test-Windows_NT-x64-8af1e26a-2799deb7
 .. Prefix:
   - v0-rust-test-Windows_NT-x64
 .. Environment considered:
   - Rust Versions:
     - 1.97.1 x86_64-pc-windows-msvc 8bab26f4f68e0e26f0bb7960be334d5b520ea452
     - 1.97.1 x86_64-pc-windows-msvc 8bab26f4f68e0e26f0bb7960be334d5b520ea452
   - CARGO_HOME
   - CARGO_INCREMENTAL
   - CARGO_TERM_COLOR
 .. Lockfiles considered:
   - D:\a\numan\numan\Cargo.lock
   - D:\a\numan\numan\Cargo.toml
 ##[endgroup]
 ... Restoring cache ...
 Cache hit for: v0-rust-test-Windows_NT-x64-8af1e26a-2799deb7
 Received 176160768 of 231634064 (76.1%), 167.0 MBs/sec
 Received 231634064 of 231634064 (100.0%), 170.6 MBs/sec
 Cache Size: ~221 MB (231634064 B)
 [command]"C:\Program Files\Git\usr\bin\tar.exe" -xf D:/a/_temp/703466e8-814b-4022-a618-6ac5707e54d0/cache.tzst -P -C D:/a/numan/numan --force-local --use-compress-program "zstd -d"
 ##[error]The operation was canceled.

GitHub Actions: CI / Roadmap drift: feat/try compat

Conclusion: failure

View job details

##[group]Run curl --fail-with-body --silent --show-error --location \
 �[36;1mcurl --fail-with-body --silent --show-error --location \�[0m
 �[36;1m  https://raw.githubusercontent.com/tonythethompson/numan/$CONTRACT_SHA/scripts/check-roadmap-drift.py \�[0m
 �[36;1m  -o /tmp/check-roadmap-drift.py�[0m
 �[36;1mdiff -u scripts/check-roadmap-drift.py /tmp/check-roadmap-drift.py \�[0m
 �[36;1m  || (echo "::error::Local drift script diverges from $CONTRACT_SHA."; \�[0m

GitHub Actions: CI / Roadmap drift: feat/try compat

Conclusion: failure

View job details

##[group]Run curl --fail-with-body --silent --show-error --location \
 �[36;1mcurl --fail-with-body --silent --show-error --location \�[0m
 �[36;1m  https://raw.githubusercontent.com/tonythethompson/numan/$CONTRACT_SHA/docs/contracts/roadmap-v1.md \�[0m
 �[36;1m  -o /tmp/roadmap-v1.md�[0m
 �[36;1mdiff -u docs/contracts/roadmap-v1.md /tmp/roadmap-v1.md \�[0m
 �[36;1m  || (echo "::error::Local contract doc diverges from $CONTRACT_SHA."; \�[0m

GitHub Actions: CI / 5_Real-Nu acceptance (windows-latest).txt: feat/try compat

Conclusion: failure

View job details

##[group]Run cargo test --verbose -- --ignored --skip acceptance_process_helper --skip stage1_official_registry --skip real_nu_active_update_
 �[36;1mcargo test --verbose -- --ignored --skip acceptance_process_helper --skip stage1_official_registry --skip real_nu_active_update_�[0m
 shell: C:\Program Files\PowerShell\7\pwsh.EXE -command ". '{0}'"
 env:
   CARGO_TERM_COLOR: always
   CARGO_HOME: C:\Users\runneradmin\.cargo
   CARGO_INCREMENTAL: 0
   CACHE_ON_FAILURE: false
 ##[endgroup]
 ##[error]The operation was canceled.

GitHub Actions: CI / 7_Test (windows-latest).txt: feat/try compat

Conclusion: failure

View job details

##[group]Cache Configuration
 Cache Provider:
     github
 Workspaces:
     D:\a\numan\numan
 Cache Paths:
     C:\Users\runneradmin\.cargo\bin
     C:\Users\runneradmin\.cargo\.crates.toml
     C:\Users\runneradmin\.cargo\.crates2.json
     C:\Users\runneradmin\.cargo\registry
     C:\Users\runneradmin\.cargo\git
     D:\a\numan\numan\target
 Restore Key:
     v0-rust-test-Windows_NT-x64-8af1e26a
 Cache Key:
     v0-rust-test-Windows_NT-x64-8af1e26a-2799deb7
 .. Prefix:
   - v0-rust-test-Windows_NT-x64
 .. Environment considered:
   - Rust Versions:
     - 1.97.1 x86_64-pc-windows-msvc 8bab26f4f68e0e26f0bb7960be334d5b520ea452
     - 1.97.1 x86_64-pc-windows-msvc 8bab26f4f68e0e26f0bb7960be334d5b520ea452
   - CARGO_HOME
   - CARGO_INCREMENTAL
   - CARGO_TERM_COLOR
 .. Lockfiles considered:
   - D:\a\numan\numan\Cargo.lock
   - D:\a\numan\numan\Cargo.toml
 ##[endgroup]
 ... Restoring cache ...
 Cache hit for: v0-rust-test-Windows_NT-x64-8af1e26a-2799deb7
 Received 176160768 of 231634064 (76.1%), 167.0 MBs/sec
 Received 231634064 of 231634064 (100.0%), 170.6 MBs/sec
 Cache Size: ~221 MB (231634064 B)
 [command]"C:\Program Files\Git\usr\bin\tar.exe" -xf D:/a/_temp/703466e8-814b-4022-a618-6ac5707e54d0/cache.tzst -P -C D:/a/numan/numan --force-local --use-compress-program "zstd -d"
 ##[error]The operation was canceled.

GitHub Actions: CI / 8_Roadmap drift.txt: feat/try compat

Conclusion: failure

View job details

##[group]Run ref_file=$(mktemp)
 �[36;1mref_file=$(mktemp)�[0m
 �[36;1mstatus=$(curl --silent --show-error --output "$ref_file" --write-out "%{http_code}" \�[0m
 �[36;1m  -H "Authorization: ***" \�[0m
 �[36;1m  -H "Accept: application/vnd.github+json" \�[0m
 �[36;1m  -H "User-Agent: numan-ci" \�[0m
 �[36;1m  "https://api.github.com/repos/tonythethompson/numan/git/refs/tags/${CONTRACT_TAG}")�[0m
 �[36;1mif [ "$status" = "404" ]; then�[0m
 �[36;1m  echo "::warning::Tag $CONTRACT_TAG does not exist yet; skipping SHA resolution check."�[0m
 �[36;1m  exit 0�[0m
 �[36;1mfi�[0m
 �[36;1mif [ "$status" != "200" ]; then�[0m
 �[36;1m  echo "::error::GitHub API returned HTTP $status for tag $CONTRACT_TAG."�[0m

GitHub Actions: CI / Roadmap drift: feat/try compat

Conclusion: failure

View job details

##[group]Run curl --fail-with-body --silent --show-error --location \
 �[36;1mcurl --fail-with-body --silent --show-error --location \�[0m
 �[36;1m  https://raw.githubusercontent.com/tonythethompson/numan/$CONTRACT_SHA/docs/plans/consolidated-multi-repo-roadmap.md \�[0m
 �[36;1m  -o /tmp/consolidated-roadmap.md�[0m
 �[36;1mdiff -u docs/plans/consolidated-multi-repo-roadmap.md /tmp/consolidated-roadmap.md \�[0m
 �[36;1m  || (echo "::error::Local consolidated roadmap diverges from $CONTRACT_SHA."; \�[0m

GitHub Actions: CI / Roadmap drift: feat/try compat

Conclusion: failure

View job details

##[group]Run ref_file=$(mktemp)
 �[36;1mref_file=$(mktemp)�[0m
 �[36;1mstatus=$(curl --silent --show-error --output "$ref_file" --write-out "%{http_code}" \�[0m
 �[36;1m  -H "Authorization: ***" \�[0m
 �[36;1m  -H "Accept: application/vnd.github+json" \�[0m
 �[36;1m  -H "User-Agent: numan-ci" \�[0m
 �[36;1m  "https://api.github.com/repos/tonythethompson/numan/git/refs/tags/${CONTRACT_TAG}")�[0m
 �[36;1mif [ "$status" = "404" ]; then�[0m
 �[36;1m  echo "::warning::Tag $CONTRACT_TAG does not exist yet; skipping SHA resolution check."�[0m
 �[36;1m  exit 0�[0m
 �[36;1mfi�[0m
 �[36;1mif [ "$status" != "200" ]; then�[0m
 �[36;1m  echo "::error::GitHub API returned HTTP $status for tag $CONTRACT_TAG."�[0m

GitHub Actions: CI / Real-Nu acceptance (macos-latest): feat/try compat

Conclusion: failure

View job details

emver=/Users/runner/work/numan/numan/target/debug/deps/libsemver-8e618bac00eed7e7.rlib --extern serde=/Users/runner/work/numan/numan/target/debug/deps/libserde-b685fc42c5c8fcbf.rlib --extern serde_json=/Users/runner/work/numan/numan/target/debug/deps/libserde_json-f87702b5f448b39c.rlib --extern sha2=/Users/runner/work/numan/numan/target/debug/deps/libsha2-2b174ae6d50727fb.rlib --extern tar=/Users/runner/work/numan/numan/target/debug/deps/libtar-48850b7ab1cdb196.rlib --extern tempfile=/Users/runner/work/numan/numan/target/debug/deps/libtempfile-a5e5a50385bf5ed2.rlib --extern thiserror=/Users/runner/work/numan/numan/target/debug/deps/libthiserror-90085ed5d82d1fba.rlib --extern toml=/Users/runner/work/numan/numan/target/debug/deps/libtoml-b3944a01ff08379e.rlib --extern uuid=/Users/runner/work/numan/numan/target/debug/deps/libuuid-57fb4db30512c65c.rlib --extern wait_timeout=/Users/runner/work/numan/numan/target/debug/deps/libwait_timeout-e98bd672c49c60a0.rlib --extern xz2=/Users/runner/work/numan/numan/target/debug/deps/libxz2-8e0ead227871d7a8.rlib --extern zip=/Users/runner/work/numan/numan/target/debug/deps/libzip-9778315c125c94c2.rlib -L native=/Users/runner/work/numan/numan/target/debug/build/libgit2-sys-b5e1493a1ae1720e/out/build -L native=/Users/runner/work/numan/numan/target/debug/build/zstd-sys-5b52c2a9924f88fa/out -L native=/opt/homebrew/Cellar/xz/5.8.3/lib -L native=/usr/lib`
 �[1m�[92m     Running�[0m `/Users/runner/.rustup/toolchains/stable-aarch64-apple-darwin/bin/rustc --crate-name plugin_lifecycle_real_nu --edition=2021 tests/plugin_lifecycle_real_nu.rs --error-format=json --json=diagnostic-rendered-ansi,artifacts,future-incompat --emit=dep-info,link -C embed-bitcode=no -C debuginfo=2 -C split-debuginfo=unpacked --test --check-cfg 'cfg(docsrs,test)' --check-cfg 'cfg(feature, values())' -C metadata=43756f88bb3caab8 -C extra-filename=-c8ff62241e125e61 --out-dir /Users/runner/work/numan/numan/target/debug/deps -L dependency=/Users/runner/work/numan/numan/...

GitHub Actions: CI / 0_Real-Nu acceptance (macos-latest).txt: feat/try compat

Conclusion: failure

View job details

emver=/Users/runner/work/numan/numan/target/debug/deps/libsemver-8e618bac00eed7e7.rlib --extern serde=/Users/runner/work/numan/numan/target/debug/deps/libserde-b685fc42c5c8fcbf.rlib --extern serde_json=/Users/runner/work/numan/numan/target/debug/deps/libserde_json-f87702b5f448b39c.rlib --extern sha2=/Users/runner/work/numan/numan/target/debug/deps/libsha2-2b174ae6d50727fb.rlib --extern tar=/Users/runner/work/numan/numan/target/debug/deps/libtar-48850b7ab1cdb196.rlib --extern tempfile=/Users/runner/work/numan/numan/target/debug/deps/libtempfile-a5e5a50385bf5ed2.rlib --extern thiserror=/Users/runner/work/numan/numan/target/debug/deps/libthiserror-90085ed5d82d1fba.rlib --extern toml=/Users/runner/work/numan/numan/target/debug/deps/libtoml-b3944a01ff08379e.rlib --extern uuid=/Users/runner/work/numan/numan/target/debug/deps/libuuid-57fb4db30512c65c.rlib --extern wait_timeout=/Users/runner/work/numan/numan/target/debug/deps/libwait_timeout-e98bd672c49c60a0.rlib --extern xz2=/Users/runner/work/numan/numan/target/debug/deps/libxz2-8e0ead227871d7a8.rlib --extern zip=/Users/runner/work/numan/numan/target/debug/deps/libzip-9778315c125c94c2.rlib -L native=/Users/runner/work/numan/numan/target/debug/build/libgit2-sys-b5e1493a1ae1720e/out/build -L native=/Users/runner/work/numan/numan/target/debug/build/zstd-sys-5b52c2a9924f88fa/out -L native=/opt/homebrew/Cellar/xz/5.8.3/lib -L native=/usr/lib`
 �[1m�[92m     Running�[0m `/Users/runner/.rustup/toolchains/stable-aarch64-apple-darwin/bin/rustc --crate-name plugin_lifecycle_real_nu --edition=2021 tests/plugin_lifecycle_real_nu.rs --error-format=json --json=diagnostic-rendered-ansi,artifacts,future-incompat --emit=dep-info,link -C embed-bitcode=no -C debuginfo=2 -C split-debuginfo=unpacked --test --check-cfg 'cfg(docsrs,test)' --check-cfg 'cfg(feature, values())' -C metadata=43756f88bb3caab8 -C extra-filename=-c8ff62241e125e61 --out-dir /Users/runner/work/numan/numan/target/debug/deps -L dependency=/Users/runner/work/numan/numan/...

GitHub Actions: CI / Real-Nu acceptance (ubuntu-latest): feat/try compat

Conclusion: failure

View job details

nner/work/numan/numan/target/debug/deps/libthiserror-586dfbc5650686d0.rlib --extern toml=/home/runner/work/numan/numan/target/debug/deps/libtoml-3a01d174782f9120.rlib --extern uuid=/home/runner/work/numan/numan/target/debug/deps/libuuid-1068b4ee51a57a2f.rlib --extern wait_timeout=/home/runner/work/numan/numan/target/debug/deps/libwait_timeout-fa4fc4237a4e496f.rlib --extern xz2=/home/runner/work/numan/numan/target/debug/deps/libxz2-24b073cd3f366c2c.rlib --extern zip=/home/runner/work/numan/numan/target/debug/deps/libzip-7d9f25bc64201460.rlib -L native=/home/runner/work/numan/numan/target/debug/build/libgit2-sys-8489ee2672c70f74/out/build -L native=/home/runner/work/numan/numan/target/debug/build/lzma-sys-49b2a8bf09b7cbbd/out -L native=/home/runner/work/numan/numan/target/debug/build/bzip2-sys-387644da4e3ca1ec/out/lib -L native=/home/runner/work/numan/numan/target/debug/build/zstd-sys-84e663e874f8a180/out`
 �[1m�[92m     Running�[0m `/home/runner/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/bin/rustc --crate-name plugin_active_update_real_nu --edition=2021 tests/plugin_active_update_real_nu.rs --error-format=json --json=diagnostic-rendered-ansi,artifacts,future-incompat --emit=dep-info,link -C embed-bitcode=no -C debuginfo=2 --test --check-cfg 'cfg(docsrs,test)' --check-cfg 'cfg(feature, values())' -C metadata=17687d9e7a3811a8 -C extra-filename=-0883b0d2f61c1de5 --out-dir /home/runner/work/numan/numan/target/debug/deps -L dependency=/home/runner/work/numan/numan/target/debug/deps --extern anyhow=/home/runner/work/numan/numan/target/debug/deps/libanyhow-a5ec7606a567b1e8.rlib --extern base64=/home/runner/work/numan/numan/target/debug/deps/libbase64-ef7c71042959ea5a.rlib --extern clap=/home/runner/work/numan/numan/target/debug/deps/libclap-ac5abf46c593b52c.rlib --extern clap_complete=/home/runner/work/numan/numan/target/debug/deps/libclap_complete-73c9ebc1ee885a35.rlib --extern clap_complete_nushell=/home/runner/work/numan/numan/target/debug/deps/libclap_complet...

GitHub Actions: CI / 2_Real-Nu acceptance (ubuntu-latest).txt: feat/try compat

Conclusion: failure

View job details

nner/work/numan/numan/target/debug/deps/libthiserror-586dfbc5650686d0.rlib --extern toml=/home/runner/work/numan/numan/target/debug/deps/libtoml-3a01d174782f9120.rlib --extern uuid=/home/runner/work/numan/numan/target/debug/deps/libuuid-1068b4ee51a57a2f.rlib --extern wait_timeout=/home/runner/work/numan/numan/target/debug/deps/libwait_timeout-fa4fc4237a4e496f.rlib --extern xz2=/home/runner/work/numan/numan/target/debug/deps/libxz2-24b073cd3f366c2c.rlib --extern zip=/home/runner/work/numan/numan/target/debug/deps/libzip-7d9f25bc64201460.rlib -L native=/home/runner/work/numan/numan/target/debug/build/libgit2-sys-8489ee2672c70f74/out/build -L native=/home/runner/work/numan/numan/target/debug/build/lzma-sys-49b2a8bf09b7cbbd/out -L native=/home/runner/work/numan/numan/target/debug/build/bzip2-sys-387644da4e3ca1ec/out/lib -L native=/home/runner/work/numan/numan/target/debug/build/zstd-sys-84e663e874f8a180/out`
 �[1m�[92m     Running�[0m `/home/runner/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/bin/rustc --crate-name plugin_active_update_real_nu --edition=2021 tests/plugin_active_update_real_nu.rs --error-format=json --json=diagnostic-rendered-ansi,artifacts,future-incompat --emit=dep-info,link -C embed-bitcode=no -C debuginfo=2 --test --check-cfg 'cfg(docsrs,test)' --check-cfg 'cfg(feature, values())' -C metadata=17687d9e7a3811a8 -C extra-filename=-0883b0d2f61c1de5 --out-dir /home/runner/work/numan/numan/target/debug/deps -L dependency=/home/runner/work/numan/numan/target/debug/deps --extern anyhow=/home/runner/work/numan/numan/target/debug/deps/libanyhow-a5ec7606a567b1e8.rlib --extern base64=/home/runner/work/numan/numan/target/debug/deps/libbase64-ef7c71042959ea5a.rlib --extern clap=/home/runner/work/numan/numan/target/debug/deps/libclap-ac5abf46c593b52c.rlib --extern clap_complete=/home/runner/work/numan/numan/target/debug/deps/libclap_complete-73c9ebc1ee885a35.rlib --extern clap_complete_nushell=/home/runner/work/numan/numan/target/debug/deps/libclap_complet...

GitHub Actions: CI / 4_Test (ubuntu-latest).txt: feat/try compat

Conclusion: failure

View job details

rlib --extern thiserror=/home/runner/work/numan/numan/target/debug/deps/libthiserror-586dfbc5650686d0.rlib --extern toml=/home/runner/work/numan/numan/target/debug/deps/libtoml-3a01d174782f9120.rlib --extern uuid=/home/runner/work/numan/numan/target/debug/deps/libuuid-1068b4ee51a57a2f.rlib --extern wait_timeout=/home/runner/work/numan/numan/target/debug/deps/libwait_timeout-fa4fc4237a4e496f.rlib --extern xz2=/home/runner/work/numan/numan/target/debug/deps/libxz2-24b073cd3f366c2c.rlib --extern zip=/home/runner/work/numan/numan/target/debug/deps/libzip-7d9f25bc64201460.rlib -L native=/home/runner/work/numan/numan/target/debug/build/libgit2-sys-8489ee2672c70f74/out/build -L native=/home/runner/work/numan/numan/target/debug/build/lzma-sys-49b2a8bf09b7cbbd/out -L native=/home/runner/work/numan/numan/target/debug/build/bzip2-sys-387644da4e3ca1ec/out/lib -L native=/home/runner/work/numan/numan/target/debug/build/zstd-sys-84e663e874f8a180/out`
 �[1m�[92m     Running�[0m `/home/runner/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/bin/rustc --crate-name plugin_deactivate_real_nu --edition=2021 tests/plugin_deactivate_real_nu.rs --error-format=json --json=diagnostic-rendered-ansi,artifacts,future-incompat --emit=dep-info,link -C embed-bitcode=no -C debuginfo=2 --test --check-cfg 'cfg(docsrs,test)' --check-cfg 'cfg(feature, values())' -C metadata=5f18f17a8368e0b5 -C extra-filename=-f27447e092ad8230 --out-dir /home/runner/work/numan/numan/target/debug/deps -L dependency=/home/runner/work/numan/numan/target/debug/deps --extern anyhow=/home/runner/work/numan/numan/target/debug/deps/libanyhow-a5ec7606a567b1e8.rlib --extern base64=/home/runner/work/numan/numan/target/debug/deps/libbase64-ef7c71042959ea5a.rlib --extern clap=/home/runner/work/numan/numan/target/debug/deps/libclap-ac5abf46c593b52c.rlib --extern clap_complete=/home/runner/work/numan/numan/target/debug/deps/libclap_complete-73c9ebc1ee885a35.rlib --extern clap_complete_nushell=/home/runner/work/numan/numan/target/...

GitHub Actions: CI / Test (ubuntu-latest): feat/try compat

Conclusion: failure

View job details

rlib --extern thiserror=/home/runner/work/numan/numan/target/debug/deps/libthiserror-586dfbc5650686d0.rlib --extern toml=/home/runner/work/numan/numan/target/debug/deps/libtoml-3a01d174782f9120.rlib --extern uuid=/home/runner/work/numan/numan/target/debug/deps/libuuid-1068b4ee51a57a2f.rlib --extern wait_timeout=/home/runner/work/numan/numan/target/debug/deps/libwait_timeout-fa4fc4237a4e496f.rlib --extern xz2=/home/runner/work/numan/numan/target/debug/deps/libxz2-24b073cd3f366c2c.rlib --extern zip=/home/runner/work/numan/numan/target/debug/deps/libzip-7d9f25bc64201460.rlib -L native=/home/runner/work/numan/numan/target/debug/build/libgit2-sys-8489ee2672c70f74/out/build -L native=/home/runner/work/numan/numan/target/debug/build/lzma-sys-49b2a8bf09b7cbbd/out -L native=/home/runner/work/numan/numan/target/debug/build/bzip2-sys-387644da4e3ca1ec/out/lib -L native=/home/runner/work/numan/numan/target/debug/build/zstd-sys-84e663e874f8a180/out`
 �[1m�[92m     Running�[0m `/home/runner/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/bin/rustc --crate-name plugin_deactivate_real_nu --edition=2021 tests/plugin_deactivate_real_nu.rs --error-format=json --json=diagnostic-rendered-ansi,artifacts,future-incompat --emit=dep-info,link -C embed-bitcode=no -C debuginfo=2 --test --check-cfg 'cfg(docsrs,test)' --check-cfg 'cfg(feature, values())' -C metadata=5f18f17a8368e0b5 -C extra-filename=-f27447e092ad8230 --out-dir /home/runner/work/numan/numan/target/debug/deps -L dependency=/home/runner/work/numan/numan/target/debug/deps --extern anyhow=/home/runner/work/numan/numan/target/debug/deps/libanyhow-a5ec7606a567b1e8.rlib --extern base64=/home/runner/work/numan/numan/target/debug/deps/libbase64-ef7c71042959ea5a.rlib --extern clap=/home/runner/work/numan/numan/target/debug/deps/libclap-ac5abf46c593b52c.rlib --extern clap_complete=/home/runner/work/numan/numan/target/debug/deps/libclap_complete-73c9ebc1ee885a35.rlib --extern clap_complete_nushell=/home/runner/work/numan/numan/target/...

GitHub Actions: CI / 10_Test (macos-latest).txt: feat/try compat

Conclusion: failure

View job details

n/numan/target/debug/deps/libxz2-8e0ead227871d7a8.rlib --extern zip=/Users/runner/work/numan/numan/target/debug/deps/libzip-9778315c125c94c2.rlib -L native=/Users/runner/work/numan/numan/target/debug/build/libgit2-sys-b5e1493a1ae1720e/out/build -L native=/Users/runner/work/numan/numan/target/debug/build/zstd-sys-5b52c2a9924f88fa/out -L native=/opt/homebrew/Cellar/xz/5.8.3/lib -L native=/usr/lib`
 �[1m�[92m     Running�[0m `/Users/runner/.rustup/toolchains/stable-aarch64-apple-darwin/bin/rustc --crate-name module_autoload_test --edition=2021 tests/module_autoload_test.rs --error-format=json --json=diagnostic-rendered-ansi,artifacts,future-incompat --emit=dep-info,link -C embed-bitcode=no -C debuginfo=2 -C split-debuginfo=unpacked --test --check-cfg 'cfg(docsrs,test)' --check-cfg 'cfg(feature, values())' -C metadata=a4ad8e058f525c6a -C extra-filename=-81871ac1746f3cc1 --out-dir /Users/runner/work/numan/numan/target/debug/deps -L dependency=/Users/runner/work/numan/numan/target/debug/deps --extern anyhow=/Users/runner/work/numan/numan/target/debug/deps/libanyhow-a7c2b97cced6d62c.rlib --extern base64=/Users/runner/work/numan/numan/target/debug/deps/libbase64-35589c29a679fc09.rlib --extern clap=/Users/runner/work/numan/numan/target/debug/deps/libclap-91a01e217dc65eca.rlib --extern clap_complete=/Users/runner/work/numan/numan/target/debug/deps/libclap_complete-4bbb4721d590a39c.rlib --extern clap_complete_nushell=/Users/runner/work/numan/numan/target/debug/deps/libclap_complete_nushell-4c7ee6de86e61196.rlib --extern console=/Users/runner/work/numan/numan/target/debug/deps/libconsole-8e2f795b55b9c710.rlib --extern dirs=/Users/runner/work/numan/numan/target/debug/deps/libdirs-98b40dc56d3c28d7.rlib --extern ed25519_dalek=/Users/runner/work/numan/numan/target/debug/deps/libed25519_dalek-89cc653197a6cb66.rlib --extern fd_lock=/Users/runner/work/numan/numan/target/debug/deps/libfd_lock-019c225f1e06d1e9.rlib --extern flate2=/Users/runner/work/numan/numan/target/debug/deps/libf...

GitHub Actions: CI / Test (macos-latest): feat/try compat

Conclusion: failure

View job details

n/numan/target/debug/deps/libxz2-8e0ead227871d7a8.rlib --extern zip=/Users/runner/work/numan/numan/target/debug/deps/libzip-9778315c125c94c2.rlib -L native=/Users/runner/work/numan/numan/target/debug/build/libgit2-sys-b5e1493a1ae1720e/out/build -L native=/Users/runner/work/numan/numan/target/debug/build/zstd-sys-5b52c2a9924f88fa/out -L native=/opt/homebrew/Cellar/xz/5.8.3/lib -L native=/usr/lib`
 �[1m�[92m     Running�[0m `/Users/runner/.rustup/toolchains/stable-aarch64-apple-darwin/bin/rustc --crate-name module_autoload_test --edition=2021 tests/module_autoload_test.rs --error-format=json --json=diagnostic-rendered-ansi,artifacts,future-incompat --emit=dep-info,link -C embed-bitcode=no -C debuginfo=2 -C split-debuginfo=unpacked --test --check-cfg 'cfg(docsrs,test)' --check-cfg 'cfg(feature, values())' -C metadata=a4ad8e058f525c6a -C extra-filename=-81871ac1746f3cc1 --out-dir /Users/runner/work/numan/numan/target/debug/deps -L dependency=/Users/runner/work/numan/numan/target/debug/deps --extern anyhow=/Users/runner/work/numan/numan/target/debug/deps/libanyhow-a7c2b97cced6d62c.rlib --extern base64=/Users/runner/work/numan/numan/target/debug/deps/libbase64-35589c29a679fc09.rlib --extern clap=/Users/runner/work/numan/numan/target/debug/deps/libclap-91a01e217dc65eca.rlib --extern clap_complete=/Users/runner/work/numan/numan/target/debug/deps/libclap_complete-4bbb4721d590a39c.rlib --extern clap_complete_nushell=/Users/runner/work/numan/numan/target/debug/deps/libclap_complete_nushell-4c7ee6de86e61196.rlib --extern console=/Users/runner/work/numan/numan/target/debug/deps/libconsole-8e2f795b55b9c710.rlib --extern dirs=/Users/runner/work/numan/numan/target/debug/deps/libdirs-98b40dc56d3c28d7.rlib --extern ed25519_dalek=/Users/runner/work/numan/numan/target/debug/deps/libed25519_dalek-89cc653197a6cb66.rlib --extern fd_lock=/Users/runner/work/numan/numan/target/debug/deps/libfd_lock-019c225f1e06d1e9.rlib --extern flate2=/Users/runner/work/numan/numan/target/debug/deps/libf...
🧰 Additional context used
📓 Path-based instructions (13)
**/*

📄 CodeRabbit inference engine (CLAUDE.md)

**/*: Use Serena's semantic, symbol-aware tools as the primary tools for reading and editing code; use built-in Read, Glob, Grep, and Edit only under the stated exceptions.
Before editing a code file, inspect its symbol overview, read the specific symbols being changed, and edit them with Serena's symbol-aware tools.
Understand the existing code before changing it and make the smallest change that satisfies the request; avoid unrelated cleanup, premature abstractions, unnecessary error handling, feature flags, and compatibility shims.
Prefer editing existing files over creating new ones, and never create Markdown or README files unless explicitly requested.
For exploratory questions, provide a 2–3 sentence recommendation with the main tradeoff and do not implement until the user agrees.
For UI or frontend changes that cannot be tested in a browser, explicitly state that browser testing was not performed rather than claiming success.
Address security issues when discovered, including injection, XSS, SQL injection, path traversal, and secret leaks.
Pause and obtain confirmation before destructive, hard-to-reverse, externally visible, or third-party-upload actions, including deleting files or branches, dropping tables, force-pushing, modifying CI/CD, posting externally, or uploading content.
When blocked, investigate the root cause instead of bypassing it with --no-verify, --force, or deletion; investigate unfamiliar files, branches, and configuration before deleting them.
Only commit when explicitly asked; do not proactively update git configuration or push changes.
Do not skip Git hooks unless explicitly asked; if a pre-commit hook fails, fix the issue, re-stage, and create a new commit rather than amending.
Stage files by name rather than using git add -A or git add ., to avoid accidentally including secrets or large binaries.
Use a HEREDOC for commit messages, and add co-author attribution only when the user explicitly requests the exact trailer.
Do not force-pus...

Files:

  • src/util/test_paths.rs
  • src/nu/bootstrap.rs
  • src/cmd/use_cmd.rs
  • src/cmd/deactivate.rs
  • src/cmd/activation_switch.rs
  • src/cmd/activate.rs
  • src/cmd/try_cmd.rs
  • src/state/activation_profile.rs
**/*.{js,jsx,ts,tsx,py,java,go,rs,rb,php,c,cpp,h,hpp,cs,swift,kt,kts}

📄 CodeRabbit inference engine (CLAUDE.md)

Add comments only when the WHY is non-obvious; do not narrate what the code does, reference the current task, or reference the PR in comments.

Files:

  • src/util/test_paths.rs
  • src/nu/bootstrap.rs
  • src/cmd/use_cmd.rs
  • src/cmd/deactivate.rs
  • src/cmd/activation_switch.rs
  • src/cmd/activate.rs
  • src/cmd/try_cmd.rs
  • src/state/activation_profile.rs
!**/.env,!**/credentials.json,!**/*.pem

📄 CodeRabbit inference engine (CLAUDE.md)

Do not commit files that appear to contain secrets, including .env, credentials.json, and PEM files; warn before doing so even if explicitly requested.

Files:

  • src/util/test_paths.rs
  • src/nu/bootstrap.rs
  • src/cmd/use_cmd.rs
  • src/cmd/deactivate.rs
  • src/cmd/activation_switch.rs
  • src/cmd/activate.rs
  • src/cmd/try_cmd.rs
  • src/state/activation_profile.rs
**/*.rs

📄 CodeRabbit inference engine (CONTRIBUTING.md)

**/*.rs: Use the Rust 2021 edition.
Use anyhow::Result with .context(...) in application code; use thiserror for library error types that callers match on.
Use clap derive macros for CLI definitions.
Use serde with serde_json or toml for serialization.
Function parameters must use &Path, not &PathBuf.
Library code must not panic; error paths should return anyhow::Result with context where appropriate.
Add or update tests for behavior changes, including relevant failure paths.
New mutating code paths must acquire the mutation lock via acquire_mutation_lock(root) and snapshot the lockfile before writes.
Lockfile, journal, and state-file JSON writes must use write_json_atomic.
numan install must write only to $NUMAN_ROOT; it must not invoke Nu or register plugins/autoloads.
Only activate and deactivate may modify Nu integration state.
Treat the lockfile as the authoritative source of truth; derived projections such as autoload state must not be authoritative.
Install payloads under versioned, content-addressed paths and never overwrite them in place.
Never overwrite foreign autoload files; respect OWNERSHIP_MARKER.
Pass plugin paths through environment variables only; do not use runtime interpolation in Nu program strings.

**/*.rs: All CI gates must pass: cargo test, cargo clippy -- -D warnings, and cargo fmt --check.
Every mutating command—including install, remove, update, gc, and future nupm import—must call acquire_mutation_lock(root).
Lockfiles, journals, and state files must use write_json_atomic; partial writes are not allowed.
Pending activation, autoload, and lifecycle journals must be stored under $NUMAN_ROOT/state/.
Module autoload identity must match all four fields: Nu executable hash, Nu version, vendor autoload directory, and managed file path; the lockfile module_activation value is authoritative.
Never overwrite foreign autoload files; respect OWNERSHIP_MARKER.
Pass paths to Nu only throu...

Files:

  • src/util/test_paths.rs
  • src/nu/bootstrap.rs
  • src/cmd/use_cmd.rs
  • src/cmd/deactivate.rs
  • src/cmd/activation_switch.rs
  • src/cmd/activate.rs
  • src/cmd/try_cmd.rs
  • src/state/activation_profile.rs
**/*.{rs,toml}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Run and keep cargo fmt/rustfmt clean, and ensure cargo clippy -- -D warnings passes.

Files:

  • src/util/test_paths.rs
  • src/nu/bootstrap.rs
  • src/cmd/use_cmd.rs
  • src/cmd/deactivate.rs
  • src/cmd/activation_switch.rs
  • src/cmd/activate.rs
  • src/cmd/try_cmd.rs
  • src/state/activation_profile.rs
**/*.{rs,nu}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

**/*.{rs,nu}: Real-Nu acceptance tests must be marked #[ignore] and should be run when changes affect activation or nupm import; unit tests must not spawn real nu and should use injectable seams such as FakeCandidateRunner or registrars.
The nupm integration must be read-only toward NUPM_HOME, must not execute build.nu, and must not perform bidirectional synchronization.

Unit tests must use FakeCandidateRunner or injectable registrars and must not spawn a real nu process.

Files:

  • src/util/test_paths.rs
  • src/nu/bootstrap.rs
  • src/cmd/use_cmd.rs
  • src/cmd/deactivate.rs
  • src/cmd/activation_switch.rs
  • src/cmd/activate.rs
  • src/cmd/try_cmd.rs
  • src/state/activation_profile.rs
**/*.{rs,md}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Match existing naming, module layout, and documentation level in the file being edited; update AGENTS.md, docs/, or command help when structure, conventions, or user-visible behavior changes.

Tests must cover failure modes, not only successful execution.

Files:

  • src/util/test_paths.rs
  • src/nu/bootstrap.rs
  • src/cmd/use_cmd.rs
  • src/cmd/deactivate.rs
  • src/cmd/activation_switch.rs
  • src/cmd/activate.rs
  • src/cmd/try_cmd.rs
  • src/state/activation_profile.rs
**/*.{rs,md,toml}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Use the repository's established serialization and module conventions rather than introducing unrelated refactors.

Files:

  • src/util/test_paths.rs
  • src/nu/bootstrap.rs
  • src/cmd/use_cmd.rs
  • src/cmd/deactivate.rs
  • src/cmd/activation_switch.rs
  • src/cmd/activate.rs
  • src/cmd/try_cmd.rs
  • src/state/activation_profile.rs
src/**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

src/**/*.rs: Serialize mutations per root with acquire_mutation_lock(root); the second acquisition must fail immediately rather than block.
Pass Nu paths and names through NUMAN_PLUGIN_BINARY, NUMAN_PLUGIN_CONFIG, and NUMAN_PLUGIN_NAME; the Nu program string must be a compile-time constant with no runtime interpolation.

Files:

  • src/util/test_paths.rs
  • src/nu/bootstrap.rs
  • src/cmd/use_cmd.rs
  • src/cmd/deactivate.rs
  • src/cmd/activation_switch.rs
  • src/cmd/activate.rs
  • src/cmd/try_cmd.rs
  • src/state/activation_profile.rs
src/cmd/{activate,deactivate,plugin_lifecycle,update}.rs

📄 CodeRabbit inference engine (AGENTS.md)

Nu plugin register/unregister callbacks belong exclusively to the activate/deactivate lifecycle boundary; opted-in update orchestration may coordinate that boundary but must not invoke callbacks directly.

Files:

  • src/cmd/deactivate.rs
  • src/cmd/activate.rs
src/cmd/deactivate.rs

📄 CodeRabbit inference engine (AGENTS.md)

Use execute_with_unregistrar for plugin tests and execute_with_candidate_runner_and_unregistrar when both module and plugin lanes require fakes.

Files:

  • src/cmd/deactivate.rs
src/cmd/activate.rs

📄 CodeRabbit inference engine (AGENTS.md)

Use execute_with_registrar for plugin tests and execute_with_candidate_runner for module tests; inject fakes instead of spawning a real Nu binary in unit tests.

Files:

  • src/cmd/activate.rs
src/state/**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

src/state/**/*.rs: Write JSON state files, including lockfiles, journals, and nu_state/paths.json, with write_json_atomic using a same-directory temporary file and persist operation.
Create a snapshot before mutating install, update, remove, activate, deactivate, nupm-import, or init --refresh state; snapshots must preserve referenced payloads as GC live roots.

Files:

  • src/state/activation_profile.rs
🧠 Learnings (1)
📓 Common learnings
Learnt from: CR
Repo: tonythethompson/numan

Timestamp: 2026-08-08T10:55:43.714Z
Learning: Source builds require explicit user consent before cloning or building, with separate consent scopes.
Learnt from: CR
Repo: tonythethompson/numan

Timestamp: 2026-08-08T10:55:43.714Z
Learning: Create a feature branch from `master`, implement with tests, run the full test suite, update AGENTS.md when conventions change, and open a described PR.
Learnt from: CR
Repo: tonythethompson/numan

Timestamp: 2026-08-08T10:55:43.714Z
Learning: Commits must use imperative mood and be under 72 characters; use `feature/description` or `fix/description` branches; never force-push `master`; squash feature merges.
🔍 Remote MCP DeepWiki, GitHub Copilot

Relevant review context

  • The repository treats lockfile.json as authoritative activation state; autoload state is derived, and activation records are tied to Nu executable identity/version. Cross-minor switching must preserve lifecycle ordering and journal/snapshot consistency.
  • At the current PR head (d9d37d7), three fresh review concerns remain:
    1. capture_activation_profile_sidecar reads the profile twice—once for content/digest and again for parsed value—so concurrent modification can produce an internally inconsistent snapshot.
    2. restore_desired can classify every module as failed when activate_modules_unlocked returns Ok(true), even if some modules were committed successfully; this may incorrectly fail numan use and misreport restored state.
    3. The missing-package error in numan try includes an error: prefix despite being returned through anyhow::Result, potentially producing duplicated error text; its usage text also omits the documented owner/name[@Version] shape.
  • Earlier major findings were addressed: the install-to-activation lock is now intentionally held through activate::execute_under_lock; pinned compatibility recommendations preserve the requested version; snapshot absence is represented explicitly; and module restore ordering is now tested with a tracking runner.
  • CI is not fully green at the observed state: Ubuntu Test failed, while Format, MSRV, CodeFactor, Package, Deny, and several analysis checks passed; other jobs were still running.
🔇 Additional comments (14)
src/state/activation_profile.rs (1)

376-387: LGTM!

src/cmd/deactivate.rs (1)

474-525: LGTM!

Also applies to: 1625-1641

src/cmd/activation_switch.rs (1)

124-153: LGTM!

Also applies to: 158-229, 233-270, 458-539, 632-655, 832-859, 918-919, 1003-1003, 1072-1094, 1152-1152, 1291-1314

src/cmd/use_cmd.rs (2)

81-100: 🩺 Stability & Availability

Resolve the failing Ubuntu Test job before merge.

Review context reports that the Ubuntu Test job failed at PR head d9d37d7. Identify the failing test and rerun the complete Rust gate set on the final head before merge.

As per coding guidelines: “All CI gates must pass: cargo test, cargo clippy -- -D warnings, and cargo fmt --check.”

Sources: Coding guidelines, MCP tools


127-152: LGTM!

src/cmd/activate.rs (1)

73-74: LGTM!

Also applies to: 734-767

src/cmd/try_cmd.rs (2)

316-316: LGTM!

Also applies to: 353-365


328-328: 🗄️ Data Integrity & Integration

No change needed for unpinned installs.

transaction::install_package treats None as Resolver::resolve, which returns the same latest compatible entry used by try_package, so passing None does not install a different release.

			> Likely an incorrect or invalid review comment.
src/nu/bootstrap.rs (4)

526-526: LGTM!


1195-1197: LGTM!


1595-1601: LGTM!


1626-1630: LGTM!

src/util/test_paths.rs (2)

6-7: LGTM!


93-133: 🩺 Stability & Availability

No lock-order issue found in current test call sites.

No combined HomeRestoreGuard/PathRestoreGuard call site acquires Home before Path.

Comment thread src/nu/bootstrap.rs
Comment thread src/util/test_paths.rs
tonythethompson and others added 2 commits August 8, 2026 04:04
The early temp-directory refusal in register_existing_nu fired regardless
of NUMAN_TEST_NO_PERSIST_USER_PATH, so ignored acceptance tests and the
#[cfg(unix)] unit tests in cmd::setup that stage binaries under tempfile
roots with PathRestoreGuard hit the guard and bailed. persist_path_dir
already short-circuits under that flag (no durable write, no refusal), so
the half-update risk the guard prevents does not apply in test mode. Gate
the early refusal on the flag being absent to align with persist_path_dir.

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
coderabbitai[bot]
coderabbitai Bot previously approved these changes Aug 8, 2026
coderabbitai[bot]
coderabbitai Bot previously approved these changes Aug 8, 2026
Per CodeRabbit security review, drop the `!options.skip_path` gate so a
session-only registration can never put a temp dir on the process PATH.
In production skip_path is always false here, so this is defense-in-depth
for future callers; the test harness bypass via NUMAN_TEST_NO_PERSIST_USER_PATH
is preserved.

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@tonythethompson

Copy link
Copy Markdown
Collaborator Author

Applied in 28c04e3: removed the !options.skip_path\ gate so the temp-dir refusal is unconditional. The \NUMAN_TEST_NO_PERSIST_USER_PATH\ bypass (mirroring \persist_path_dir_*) is preserved so acceptance tests can stage binaries in TempDir under PathRestoreGuard. Verified locally:
egister_existing_nu_refuses_non_tty_without_yes_before_path_mutation\ (uses \skip_path: true) and the temp-dir unit tests still pass.

coderabbitai[bot]
coderabbitai Bot previously approved these changes Aug 8, 2026
greptile-apps[bot]
greptile-apps Bot previously approved these changes Aug 8, 2026
…rrors

restore_desired's Err branch marked every requested module failed even when
activate_modules_unlocked committed activation records and autoload-state.json
before bailing (e.g. a journal-cleanup failure in run_module_lane step 12).
Reload the lockfile and classify each module via collect_currently_active,
matching the Ok(failed) branch: committed modules go to restored_modules,
only inactive ones to failed, and the journal-cleanup error is retained as
a separate lifecycle_errors warning rather than a per-module failure.

Also address try_cmd review feedback: drop the angle-bracket placeholder and
embedded "error:" prefix from the missing-package message, use the lowercase
"numan try owner/name[@Version]" syntax, add an empty-package test, and
tighten the malformed-lockfile test to assert a serde_json parse error
against the authoritative lockfile path.

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@tonythethompson
tonythethompson merged commit 0f2ae80 into master Aug 8, 2026
35 checks passed
@tonythethompson
tonythethompson deleted the feat/try-compat branch August 8, 2026 11:37
@linear-code

linear-code Bot commented Aug 8, 2026

Copy link
Copy Markdown

TS-169

tonythethompson added a commit that referenced this pull request Aug 8, 2026
P1 (use_cmd.rs): refresh cached paths.json after the dangling off-tree
binary_path repair in execute_latest. Without this, the same-target
reconcile loads the stale cache and validate_drift fails after the marker
has already been rewritten. Added regression test
test_use_latest_self_heal_clears_stale_paths_cache.

P2 (remove.rs): move activation-profile cleanup to a preflight before
lockfile/payload removal so a profile-write failure aborts the remove
while state is still intact and retryable. Removed the duplicate dead
warning-only call.

P1 (activation_profile snapshots/rollback): already addressed by #108;
snapshot capture and rollback restore are in place. No code change.

Also applies cargo fmt to doctor.rs (Format CI was failing).
tonythethompson added a commit that referenced this pull request Aug 8, 2026
…#106)

* Report versioned managed Nu installs in doctor.

Doctor still looked for the legacy tools/nushell/nu path, so versioned setup nu installs were reported as missing.

Co-authored-by: Cursor <cursoragent@cursor.com>

* Improve registry packages listing readability.

Style package ids, soft-wrap dim descriptions, and separate entries with blank lines.

Co-authored-by: Cursor <cursoragent@cursor.com>

* Auto-deactivate and restore packages on numan use.

Remember per-Nu-minor activation desire so cross-minor switches leave and restore plugins/modules without shrinking leave profiles.

Co-authored-by: Cursor <cursoragent@cursor.com>

* Update src/cmd/activation_switch.rs

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* Update src/cmd/activation_switch.rs

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* Update src/state/activation_profile.rs

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* Update src/cmd/remove.rs

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* fix: apply CodeRabbit auto-fixes

Fixed 7 file(s) based on 9 unresolved review comments.

Co-authored-by: CodeRabbit <noreply@coderabbit.ai>

* fix: address review feedback and rebase onto master

- Rebased onto latest master to resolve merge conflicts
- Cleaned up activation_switch.rs per review (simplified logic)
- Fixed use_cmd.rs per review comments
- Cleaned up activation_profile.rs per review

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* fix: address remaining valid PR 106 review findings

Filter activate profile sync to packages that are active, retain profile
desire when deactivate fails, tighten use switch ordering assertions, and
document ensure_absent_for_paths error behavior.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix: map managed Nu doctor errors by VersionManagerError

Reserve the numan use hint for dangling active markers; filesystem and
marker parse failures get a permissions/reinstall message instead.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix: address Codex review findings on PR #106

P1 (use_cmd.rs): refresh cached paths.json after the dangling off-tree
binary_path repair in execute_latest. Without this, the same-target
reconcile loads the stale cache and validate_drift fails after the marker
has already been rewritten. Added regression test
test_use_latest_self_heal_clears_stale_paths_cache.

P2 (remove.rs): move activation-profile cleanup to a preflight before
lockfile/payload removal so a profile-write failure aborts the remove
while state is still intact and retryable. Removed the duplicate dead
warning-only call.

P1 (activation_profile snapshots/rollback): already addressed by #108;
snapshot capture and rollback restore are in place. No code change.

Also applies cargo fmt to doctor.rs (Format CI was failing).

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: CodeRabbit <noreply@coderabbit.ai>
Co-authored-by: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
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