Skip to content

feat(pacquet): implement the outdated command#12112

Merged
zkochan merged 1 commit into
mainfrom
pq-outdated
Jun 1, 2026
Merged

feat(pacquet): implement the outdated command#12112
zkochan merged 1 commit into
mainfrom
pq-outdated

Conversation

@zkochan

@zkochan zkochan commented Jun 1, 2026

Copy link
Copy Markdown
Member

What

Ports pnpm's outdated command to pacquet. It reports the direct dependencies whose newest published version (or highest in-range version under --compatible) is newer than the lockfile-pinned version, and exits with code 1 when any outdated dependency is found.

This widens pacquet's command surface beyond install/add/update/remove.

How

  • Detection corecollect_outdated / OutdatedQuery / TargetVersion in pacquet/crates/cli/src/cli_args/outdated.rs. This is shared with update --interactive, which already computed the same "what has a newer version" list inline; that code now calls the shared collector. The two callers differ only in the TargetVersion they compare against (outdatedlatest tag / highest in-range under --compatible; update → the version a bump moves to). Packument fetches fan out concurrently via futures::join_all, mirroring pnpm's Promise.all (bounded by the HTTP client's per-registry concurrency limit).
  • Flags--compatible, --long, --format table|list|json (plus --no-table / --json shorthands), -P/--prod (--production), -D/--dev, --no-optional (following pnpm's only-normalization include-set), --sort-by name (default sort is by semver-change size then name), and positional name patterns (@pnpm/config.matcher).
  • Exit codeOutdatedArgs::run returns an OutdatedOutcome; the single process::exit(1) lives in the top-level CLI dispatch, keeping the command composable.
  • --global and --recursive are rejected with a "not supported yet" message, matching pacquet update (single-project scope).
  • Empty-manifest short-circuit — a dependency-free manifest reports empty (exit 0) before the no-lockfile check, matching pnpm's packageHasNoDeps behavior so an empty, never-installed project doesn't error.
  • Rendering — adds tabled (Style::modern() reproduces pnpm's @zkochan/table full-grid borders) and owo-colors (auto-disables on non-TTY, like chalk, so piped/JSON output is escape-free). Both are MIT (allowed by deny.toml). JSON output is keyed by package name with current / latest / wanted / isDeprecated / dependencyType (+ latestManifest under --long), matching pnpm's renderOutdatedJSON.
  • Adds an optional homepage field to the registry Package for the --long details column.

Parity notes / scope

pacquet loads a single (wanted) lockfile, so current == wanted and pnpm's "missing (wanted X)" state does not arise. OUTDATED_NO_LOCKFILE is raised when a manifest declares dependencies but no lockfile exists. Deprecated-but-current packages are still reported.

Deferred with their surrounding features (not yet ported to pacquet), each tracked by an upstream test that does not yet translate:

  • --long homepage needs full registry metadata; the abbreviated fetch omits it, so it appears only when the registry serves it (deprecation details work fully).
  • minimumReleaseAge / minimumReleaseAgeExclude, pnpm.updateConfig.ignoreDependencies, catalog: protocol replacement, -g/global packages, recursive workspace listing, and runtime: (node/deno/bun) dependencies.

Tests

Ported the translatable pnpm outdated tests (deps/inspection/outdated/test/* and deps/inspection/commands/test/outdated/*):

  • 10 unit tests — semver-change classification, include-set normalization (default / --prod / --dev / --no-optional), default sort order, renderLatest (deprecated / not), and JSON shape (with/without --long).
  • 14 integration tests against the mocked registry — newer-version report, --compatible discrimination, JSON, JSON-empty {}, list (--no-table) format, up-to-date → exit 0, name-pattern filter, prod/dev filtering, npm-alias real-name reporting, deprecated package, --long deprecation details, no-deps/no-lockfile → empty exit 0, no-lockfile-with-deps error, and --recursive rejection.

No changeset (pacquet-only change).


Written by an agent (Claude Code, claude-opus-4-8).

Summary by CodeRabbit

  • New Features
    • Added pacquet outdated (table, list, or JSON) with semver-diff colorization and deprecation/homepage details in long mode.
    • pacquet update --interactive can source outdated candidates for selection; supports name filtering and prod/dev scopes.
  • Behavior Changes / Bug Fixes
    • Command exits non‑zero when outdated packages exist; rejects unsupported flags and errors when a lockfile is required; disables ANSI styling when stdout is not a TTY.
  • Tests
    • Integration and unit tests added for reporting, formatting, filtering, and deprecated-package handling.

@coderabbitai

coderabbitai Bot commented Jun 1, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 9941a423-9236-4ac6-b672-719778156662

📥 Commits

Reviewing files that changed from the base of the PR and between e0f3e3c and 4cdec16.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (12)
  • Cargo.toml
  • pacquet/crates/cli/Cargo.toml
  • pacquet/crates/cli/src/cli_args.rs
  • pacquet/crates/cli/src/cli_args/outdated.rs
  • pacquet/crates/cli/src/cli_args/outdated/tests.rs
  • pacquet/crates/cli/src/cli_args/update_interactive.rs
  • pacquet/crates/cli/tests/outdated.rs
  • pacquet/crates/registry/src/package.rs
  • pacquet/crates/registry/src/package/tests.rs
  • pacquet/crates/resolving-npm-resolver/src/create_npm_resolution_verifier.rs
  • pacquet/crates/resolving-npm-resolver/src/pick_package_from_meta.rs
  • pacquet/crates/resolving-npm-resolver/src/pick_package_from_meta/tests.rs
✅ Files skipped from review due to trivial changes (2)
  • pacquet/crates/registry/src/package/tests.rs
  • pacquet/crates/resolving-npm-resolver/src/pick_package_from_meta/tests.rs
🚧 Files skipped from review as they are similar to previous changes (9)
  • pacquet/crates/resolving-npm-resolver/src/pick_package_from_meta.rs
  • pacquet/crates/cli/src/cli_args/outdated/tests.rs
  • pacquet/crates/cli/src/cli_args.rs
  • pacquet/crates/registry/src/package.rs
  • pacquet/crates/resolving-npm-resolver/src/create_npm_resolution_verifier.rs
  • Cargo.toml
  • pacquet/crates/cli/src/cli_args/update_interactive.rs
  • pacquet/crates/cli/tests/outdated.rs
  • pacquet/crates/cli/src/cli_args/outdated.rs
📜 Recent review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
  • GitHub Check: Run benchmark on ubuntu-latest
  • GitHub Check: Code Coverage
  • GitHub Check: Lint and Test (windows-latest)
  • GitHub Check: Lint and Test (macos-latest)
  • GitHub Check: Spell Check
  • GitHub Check: Compile & Lint
🧰 Additional context used
📓 Path-based instructions (1)
pacquet/**/Cargo.toml

📄 CodeRabbit inference engine (pacquet/AGENTS.md)

pacquet/**/Cargo.toml: Check whether the workspace already depends on something suitable in [workspace.dependencies] in the root Cargo.toml before adding a new dependency
Keep dependencies at the right level — add a new dependency to the specific crate that needs it, not to the workspace root or shared crate unless multiple crates depend on it

Files:

  • pacquet/crates/cli/Cargo.toml
🔇 Additional comments (1)
pacquet/crates/cli/Cargo.toml (1)

34-49: LGTM!


📝 Walkthrough

Walkthrough

Implements pacquet outdated: collection, concurrent registry resolution, sorting, table/list/JSON rendering with deprecation/homepage details, interactive reuse, adds homepage to registry Package, and adds workspace/CLI deps for colors and tables.

Changes

Outdated subcommand and homepage metadata

Layer / File(s) Summary
Workspace and CLI dependencies
Cargo.toml, pacquet/crates/cli/Cargo.toml
Add owo-colors (with supports-colors) and tabled v0.17 to workspace; wire owo-colors into CLI crate.
CLI wiring and dispatcher integration
pacquet/crates/cli/src/cli_args.rs
Export outdated module, import OutdatedArgs/OutdatedOutcome, add CliCommand::Outdated variant and dispatcher arm that runs the command and exits non-zero when outdated packages are found.
Outdated types and query interface
pacquet/crates/cli/src/cli_args/outdated.rs (types/args)
Define TargetVersion, OutdatedPackage, OutdatedQuery, OutdatedFormat, dependency option normalization, OutdatedArgs, SortBy, and OutdatedOutcome.
Collect and resolve outdated packages
pacquet/crates/cli/src/cli_args/outdated.rs (collection/resolve)
Implement collect_outdated with concurrent registry resolution, resolve_target, and current_versions_from_lockfile; skip unresolvable registry packages.
Orchestration and validation
pacquet/crates/cli/src/cli_args/outdated.rs (run)
Implement OutdatedArgs::run: CLI validation, lockfile requirement, build query, invoke collection, sort, render, and return outcome.
Sorting, rendering, and color helpers
pacquet/crates/cli/src/cli_args/outdated.rs (render/sort/helpers)
Add semver classification, priority/name sorting, render_table/render_list/render_json, package-name/version rendering, detail lines (deprecation/homepage), and terminal-aware color/styling helpers.
Unit tests for outdated logic
pacquet/crates/cli/src/cli_args/outdated/tests.rs
Unit tests for classification, dependency-group includes, sorting, JSON shape, latest rendering, deprecation markers, and long-mode fields including homepage.
Refactor update --interactive to reuse collection
pacquet/crates/cli/src/cli_args/update_interactive.rs
Replace local outdated candidate computation with shared OutdatedQuery + collect_outdated; adapt prompt labels/selection to use alias.
Integration tests for outdated subcommand
pacquet/crates/cli/tests/outdated.rs
End-to-end tests: detection, --compatible, format variants, filtering, deprecation reporting, lockfile and flag error cases, npm alias handling, and group filters.
Add homepage to Package metadata and propagate
pacquet/crates/registry/src/package.rs, pacquet/crates/registry/src/package/tests.rs, pacquet/crates/resolving-npm-resolver/src/pick_package_from_meta.rs, pacquet/crates/resolving-npm-resolver/src/pick_package_from_meta/tests.rs
Add optional homepage: Option<String> to Package, update test helpers, and preserve homepage through packument filtering and related projections.

Sequence Diagram

sequenceDiagram
  participant CLI
  participant OutdatedArgs
  participant collect_outdated
  participant ThrottledClient
  participant Registry
  participant Lockfile
  CLI->>OutdatedArgs: run()
  OutdatedArgs->>Lockfile: read root importer versions
  OutdatedArgs->>collect_outdated: collect_outdated(...)
  collect_outdated->>ThrottledClient: fetch packuments concurrently
  ThrottledClient->>Registry: HTTP requests
  Registry-->>ThrottledClient: packuments
  collect_outdated->>collect_outdated: resolve_target, filter newer/deprecated
  collect_outdated-->>OutdatedArgs: Vec<OutdatedPackage>
  OutdatedArgs->>CLI: render (table/list/json)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

🐰 A new command hops into pacquet's burrow,
Outdated friends are flagged with color and flow,
Tables and JSON show what's newer or old,
Interactive picks reuse the shared code,
And each package now keeps a homepage to show. 🏠✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: implementing the 'outdated' command as a new feature for the pacquet package manager.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.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.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch pq-outdated

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 and usage tips.

@codecov-commenter

codecov-commenter commented Jun 1, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 87.80488% with 40 lines in your changes missing coverage. Please review.
✅ Project coverage is 87.34%. Comparing base (12b7201) to head (4cdec16).

Files with missing lines Patch % Lines
pacquet/crates/cli/src/cli_args/outdated.rs 90.29% 30 Missing ⚠️
...quet/crates/cli/src/cli_args/update_interactive.rs 0.00% 10 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main   #12112      +/-   ##
==========================================
+ Coverage   87.17%   87.34%   +0.17%     
==========================================
  Files         254      255       +1     
  Lines       28426    28703     +277     
==========================================
+ Hits        24779    25072     +293     
+ Misses       3647     3631      -16     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@github-actions

github-actions Bot commented Jun 1, 2026

Copy link
Copy Markdown
Contributor

Micro-Benchmark Results

Linux

group                          main                                   pr
-----                          ----                                   --
tarball/download_dependency    1.01      8.1±0.24ms   535.6 KB/sec    1.00      8.0±0.25ms   540.7 KB/sec

@github-actions

github-actions Bot commented Jun 1, 2026

Copy link
Copy Markdown
Contributor

Integrated-Benchmark Report (Linux)

Scenario: Isolated linker: fresh restore, cold cache + cold store

Command Mean [s] Min [s] Max [s] Relative
pacquet@HEAD 2.150 ± 0.090 2.059 2.318 1.01 ± 0.05
pacquet@main 2.137 ± 0.045 2.076 2.209 1.00
BENCHMARK_REPORT.json
{
  "results": [
    {
      "command": "pacquet@HEAD",
      "mean": 2.15008847214,
      "stddev": 0.09040705335963342,
      "median": 2.11027879504,
      "user": 2.7342133599999996,
      "system": 3.514403599999999,
      "min": 2.05918090504,
      "max": 2.31761110304,
      "times": [
        2.06240476704,
        2.05918090504,
        2.09331690904,
        2.23930631204,
        2.0733968520399997,
        2.10018102904,
        2.12037656104,
        2.31761110304,
        2.21633520504,
        2.2187750780399997
      ]
    },
    {
      "command": "pacquet@main",
      "mean": 2.1368505555399997,
      "stddev": 0.04478877259710517,
      "median": 2.1313691225399998,
      "user": 2.71175406,
      "system": 3.454026999999999,
      "min": 2.0762586060399997,
      "max": 2.20873432504,
      "times": [
        2.13711503704,
        2.14241051004,
        2.09858343204,
        2.0934390280399997,
        2.0762586060399997,
        2.11181626204,
        2.12562320804,
        2.20873432504,
        2.18693250604,
        2.1875926410399997
      ]
    }
  ]
}

Scenario: Isolated linker: fresh restore, hot cache + hot store

Command Mean [ms] Min [ms] Max [ms] Relative
pacquet@HEAD 671.7 ± 31.1 652.7 758.8 1.00
pacquet@main 674.3 ± 21.0 649.6 719.4 1.00 ± 0.06
BENCHMARK_REPORT.json
{
  "results": [
    {
      "command": "pacquet@HEAD",
      "mean": 0.67174581224,
      "stddev": 0.031071914836157382,
      "median": 0.6646347167400001,
      "user": 0.38101576000000004,
      "system": 1.3454966999999998,
      "min": 0.65273868574,
      "max": 0.7587942067400001,
      "times": [
        0.7587942067400001,
        0.6649183997400001,
        0.66435103374,
        0.66886856374,
        0.6666676367400001,
        0.6594999907400001,
        0.6550479047400001,
        0.65273868574,
        0.65863847074,
        0.66793322974
      ]
    },
    {
      "command": "pacquet@main",
      "mean": 0.6742771764400001,
      "stddev": 0.021003273281374232,
      "median": 0.66868507574,
      "user": 0.37657295999999996,
      "system": 1.3561182999999999,
      "min": 0.6496446427400001,
      "max": 0.7194066517400001,
      "times": [
        0.7194066517400001,
        0.6709285797400001,
        0.66504513174,
        0.6496446427400001,
        0.6571770797400001,
        0.67672867274,
        0.6622909357400001,
        0.6664415717400001,
        0.67387376574,
        0.70123473274
      ]
    }
  ]
}

Scenario: Isolated linker: fresh install, cold cache + cold store

Command Mean [s] Min [s] Max [s] Relative
pacquet@HEAD 2.436 ± 0.046 2.354 2.506 1.01 ± 0.02
pacquet@main 2.411 ± 0.036 2.345 2.450 1.00
BENCHMARK_REPORT.json
{
  "results": [
    {
      "command": "pacquet@HEAD",
      "mean": 2.4358166167800004,
      "stddev": 0.046332862088036254,
      "median": 2.4415221765800004,
      "user": 3.9207568000000004,
      "system": 3.2140056800000005,
      "min": 2.35404357708,
      "max": 2.50605716608,
      "times": [
        2.37570119508,
        2.46220603208,
        2.35404357708,
        2.4124185020800004,
        2.48111095008,
        2.45334300408,
        2.45548056308,
        2.42970134908,
        2.4281038290800003,
        2.50605716608
      ]
    },
    {
      "command": "pacquet@main",
      "mean": 2.41144689688,
      "stddev": 0.03594347547777449,
      "median": 2.4135026600800003,
      "user": 3.9371422000000003,
      "system": 3.20774598,
      "min": 2.34533075108,
      "max": 2.4499523460800003,
      "times": [
        2.41079253508,
        2.44698909808,
        2.43099233608,
        2.4162127850800004,
        2.36195213408,
        2.4499523460800003,
        2.39451714108,
        2.4093476330800003,
        2.44838220908,
        2.34533075108
      ]
    }
  ]
}

Scenario: Isolated linker: fresh install, hot cache + hot store

Command Mean [s] Min [s] Max [s] Relative
pacquet@HEAD 1.590 ± 0.028 1.541 1.643 1.00 ± 0.03
pacquet@main 1.588 ± 0.046 1.544 1.664 1.00
BENCHMARK_REPORT.json
{
  "results": [
    {
      "command": "pacquet@HEAD",
      "mean": 1.5903830150199998,
      "stddev": 0.027810369503833768,
      "median": 1.58875919172,
      "user": 1.8060878799999998,
      "system": 1.8789392999999996,
      "min": 1.54081222472,
      "max": 1.6434831527199998,
      "times": [
        1.5786715537199998,
        1.59302600772,
        1.5844923757199998,
        1.6434831527199998,
        1.6080762097199999,
        1.56745628372,
        1.60956232772,
        1.60127661772,
        1.54081222472,
        1.57697339672
      ]
    },
    {
      "command": "pacquet@main",
      "mean": 1.58798941722,
      "stddev": 0.045686957887831676,
      "median": 1.5685175122200001,
      "user": 1.78369818,
      "system": 1.8914244,
      "min": 1.5443661337199999,
      "max": 1.6638713007200001,
      "times": [
        1.60645459772,
        1.6618572807199998,
        1.55019348472,
        1.6638713007200001,
        1.61074582772,
        1.5443661337199999,
        1.5466340427199998,
        1.56320198872,
        1.55873647972,
        1.57383303572
      ]
    }
  ]
}

@github-actions

github-actions Bot commented Jun 1, 2026

Copy link
Copy Markdown
Contributor

🐰 Bencher Report

Branchpr/12112
Testbedpacquet
Click to view all benchmark results
BenchmarkLatencyBenchmark Result
milliseconds (ms)
(Result Δ%)
Upper Boundary
milliseconds (ms)
(Limit %)
isolated-linker.fresh-install.cold-cache.cold-store📈 view plot
🚷 view threshold
2,435.82 ms
(+3.23%)Baseline: 2,359.56 ms
2,831.47 ms
(86.03%)
isolated-linker.fresh-install.hot-cache.hot-store📈 view plot
🚷 view threshold
1,590.38 ms
(+4.38%)Baseline: 1,523.71 ms
1,828.45 ms
(86.98%)
isolated-linker.fresh-restore.cold-cache.cold-store📈 view plot
🚷 view threshold
2,150.09 ms
(+2.86%)Baseline: 2,090.30 ms
2,508.35 ms
(85.72%)
isolated-linker.fresh-restore.hot-cache.hot-store📈 view plot
🚷 view threshold
671.75 ms
(+0.65%)Baseline: 667.43 ms
800.91 ms
(83.87%)
🐰 View full continuous benchmarking report in Bencher

@zkochan zkochan force-pushed the pq-outdated branch 2 times, most recently from 8ed9ace to 7d40fe7 Compare June 1, 2026 16:13
@zkochan zkochan marked this pull request as ready for review June 1, 2026 16:38
Copilot AI review requested due to automatic review settings June 1, 2026 16:38
@qodo-free-for-open-source-projects

Copy link
Copy Markdown

Review Summary by Qodo

Implement pacquet outdated command with shared detection core

✨ Enhancement

Grey Divider

Walkthroughs

Description
• Implement pacquet outdated command to report direct dependencies with newer versions available
• Share outdated detection core with update --interactive via collect_outdated and
  TargetVersion enum
• Support --compatible, --long, --format table|list|json, -P/--prod, -D/--dev,
  --no-optional, --sort-by name flags
• Add table/list/JSON rendering with color support; exit code 1 when outdated dependencies found
• Port 10 unit tests and 14 integration tests from pnpm's outdated command
Diagram
flowchart LR
  manifest["Package Manifest"]
  lockfile["Lockfile"]
  registry["Registry"]
  
  manifest -- "dependencies" --> collect["collect_outdated"]
  lockfile -- "current versions" --> collect
  registry -- "target versions" --> collect
  
  collect -- "OutdatedPackage list" --> render["Render Output"]
  render -- "table|list|json" --> stdout["stdout"]
  
  update_interactive["update --interactive"] -.->|reuses| collect
  outdated_cmd["outdated command"] -.->|uses| collect

Loading

Grey Divider

File Changes

1. pacquet/crates/cli/src/cli_args.rs ✨ Enhancement +8/-0

Add outdated subcommand to CLI dispatcher

pacquet/crates/cli/src/cli_args.rs


2. pacquet/crates/cli/src/cli_args/outdated.rs ✨ Enhancement +604/-0

Implement outdated command with detection and rendering

pacquet/crates/cli/src/cli_args/outdated.rs


3. pacquet/crates/cli/src/cli_args/outdated/tests.rs 🧪 Tests +118/-0

Add unit tests for outdated detection and rendering

pacquet/crates/cli/src/cli_args/outdated/tests.rs


View more (9)
4. pacquet/crates/cli/src/cli_args/update_interactive.rs ✨ Enhancement +19/-93

Refactor to use shared collect_outdated function

pacquet/crates/cli/src/cli_args/update_interactive.rs


5. pacquet/crates/cli/tests/outdated.rs 🧪 Tests +308/-0

Add integration tests for outdated command

pacquet/crates/cli/tests/outdated.rs


6. pacquet/crates/registry/src/package.rs ✨ Enhancement +11/-0

Add optional homepage field to Package struct

pacquet/crates/registry/src/package.rs


7. pacquet/crates/registry/src/package/tests.rs 🧪 Tests +1/-0

Update package test helper with homepage field

pacquet/crates/registry/src/package/tests.rs


8. pacquet/crates/resolving-npm-resolver/src/create_npm_resolution_verifier.rs ✨ Enhancement +1/-0

Preserve homepage field in package metadata

pacquet/crates/resolving-npm-resolver/src/create_npm_resolution_verifier.rs


9. pacquet/crates/resolving-npm-resolver/src/pick_package_from_meta.rs ✨ Enhancement +1/-0

Preserve homepage field in filtered package metadata

pacquet/crates/resolving-npm-resolver/src/pick_package_from_meta.rs


10. pacquet/crates/resolving-npm-resolver/src/pick_package_from_meta/tests.rs 🧪 Tests +1/-0

Update package test helper with homepage field

pacquet/crates/resolving-npm-resolver/src/pick_package_from_meta/tests.rs


11. Cargo.toml Dependencies +2/-0

Add tabled and owo-colors dependencies

Cargo.toml


12. pacquet/crates/cli/Cargo.toml Dependencies +2/-0

Add tabled and owo-colors to CLI crate

pacquet/crates/cli/Cargo.toml


Grey Divider

Qodo Logo

Copilot AI 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.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Implements pacquet outdated, porting pnpm’s behavior to report direct dependencies that have newer (or deprecated) registry versions and exit with code 1 when any are found.

Changes:

  • Adds outdated subcommand with shared collection logic reused by update --interactive.
  • Introduces rendering in table/list/json formats plus dependency-group filtering and pattern matching.
  • Extends registry Package metadata with optional homepage for --long details and adds integration/unit tests.

Reviewed changes

Copilot reviewed 12 out of 13 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
pacquet/crates/registry/src/package.rs Adds optional homepage field to Package for outdated --long details.
pacquet/crates/resolving-npm-resolver/src/pick_package_from_meta.rs Propagates homepage when filtering/cloning package metadata.
pacquet/crates/resolving-npm-resolver/src/create_npm_resolution_verifier.rs Preserves homepage when projecting trusted Package metadata.
pacquet/crates/resolving-npm-resolver/src/pick_package_from_meta/tests.rs Updates test package constructor to include homepage: None.
pacquet/crates/registry/src/package/tests.rs Updates test package constructor to include homepage: None.
pacquet/crates/cli/src/cli_args/outdated.rs Adds outdated command implementation, formatting, sorting, and shared collector.
pacquet/crates/cli/src/cli_args/outdated/tests.rs Adds unit tests for sorting/classification/rendering/JSON shape.
pacquet/crates/cli/src/cli_args/update_interactive.rs Refactors interactive update to reuse shared collect_outdated logic.
pacquet/crates/cli/src/cli_args.rs Wires new Outdated subcommand into CLI dispatch.
pacquet/crates/cli/tests/outdated.rs Adds integration tests for pacquet outdated against mocked registry.
pacquet/crates/cli/Cargo.toml Adds owo-colors and tabled dependencies for output rendering.
Cargo.toml Adds workspace dependencies for owo-colors and tabled.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread pacquet/crates/cli/src/cli_args/outdated.rs
Comment thread pacquet/crates/cli/src/cli_args/outdated.rs Outdated
Comment thread pacquet/crates/cli/src/cli_args/outdated.rs Outdated
Comment thread pacquet/crates/cli/src/cli_args/outdated.rs

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
pacquet/crates/cli/src/cli_args/outdated.rs (1)

429-442: 💤 Low value

Consider semantic version comparison for the tertiary sort key.

Line 439 compares versions as strings, which gives lexicographic ordering ("1.9.0" > "1.10.0"). While this tiebreaker rarely triggers in practice (same name + same change priority would require duplicate manifest entries), using Version's Ord impl would be semantically correct.

♻️ Suggested fix
         None => outdated.sort_by(|left, right| {
             let by_change = change_priority(classify(&left.current, &left.target))
                 .cmp(&change_priority(classify(&right.current, &right.target)));
             by_change
                 .then_with(|| left.package_name.cmp(&right.package_name))
-                .then_with(|| left.current.to_string().cmp(&right.current.to_string()))
+                .then_with(|| left.current.cmp(&right.current))
         }),
🤖 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 `@pacquet/crates/cli/src/cli_args/outdated.rs` around lines 429 - 442, The
tertiary sort currently compares versions as strings in sort_outdated (function)
which yields lexicographic ordering; change the tertiary comparator to use the
Version Ord impl by comparing left.current and right.current directly (e.g.,
replace the left.current.to_string().cmp(&right.current.to_string()) comparison
with left.current.cmp(&right.current)) so semantic version ordering is used;
keep the rest of the chain (change_priority/classify and package_name)
unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@pacquet/crates/resolving-npm-resolver/src/create_npm_resolution_verifier.rs`:
- Line 866: The project_trust_meta projection currently includes the homepage
field (the line homepage: meta.homepage.clone()), which is unnecessary for trust
verification and increases memory usage; remove that field from the projection
in the project_trust_meta function so the returned trust-meta only contains the
fields used by fail_if_trust_downgraded (name, per-version time map, and trust
evidence), then run tests/compile to ensure no other code depends on
meta.homepage in that projection.

---

Nitpick comments:
In `@pacquet/crates/cli/src/cli_args/outdated.rs`:
- Around line 429-442: The tertiary sort currently compares versions as strings
in sort_outdated (function) which yields lexicographic ordering; change the
tertiary comparator to use the Version Ord impl by comparing left.current and
right.current directly (e.g., replace the
left.current.to_string().cmp(&right.current.to_string()) comparison with
left.current.cmp(&right.current)) so semantic version ordering is used; keep the
rest of the chain (change_priority/classify and package_name) unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 5a7744c8-76fb-4f47-88eb-919209d72296

📥 Commits

Reviewing files that changed from the base of the PR and between 7d40fe7 and 11da003.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (12)
  • Cargo.toml
  • pacquet/crates/cli/Cargo.toml
  • pacquet/crates/cli/src/cli_args.rs
  • pacquet/crates/cli/src/cli_args/outdated.rs
  • pacquet/crates/cli/src/cli_args/outdated/tests.rs
  • pacquet/crates/cli/src/cli_args/update_interactive.rs
  • pacquet/crates/cli/tests/outdated.rs
  • pacquet/crates/registry/src/package.rs
  • pacquet/crates/registry/src/package/tests.rs
  • pacquet/crates/resolving-npm-resolver/src/create_npm_resolution_verifier.rs
  • pacquet/crates/resolving-npm-resolver/src/pick_package_from_meta.rs
  • pacquet/crates/resolving-npm-resolver/src/pick_package_from_meta/tests.rs
✅ Files skipped from review due to trivial changes (1)
  • pacquet/crates/resolving-npm-resolver/src/pick_package_from_meta/tests.rs
🚧 Files skipped from review as they are similar to previous changes (9)
  • pacquet/crates/registry/src/package/tests.rs
  • pacquet/crates/resolving-npm-resolver/src/pick_package_from_meta.rs
  • pacquet/crates/registry/src/package.rs
  • pacquet/crates/cli/src/cli_args.rs
  • Cargo.toml
  • pacquet/crates/cli/src/cli_args/update_interactive.rs
  • pacquet/crates/cli/src/cli_args/outdated/tests.rs
  • pacquet/crates/cli/Cargo.toml
  • pacquet/crates/cli/tests/outdated.rs
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (9)
  • GitHub Check: Lint and Test (macos-latest)
  • GitHub Check: Lint and Test (ubuntu-latest)
  • GitHub Check: Lint and Test (windows-latest)
  • GitHub Check: Dylint
  • GitHub Check: Run benchmark on ubuntu-latest
  • GitHub Check: Analyze (javascript)
  • GitHub Check: Code Coverage
  • GitHub Check: Run benchmark on ubuntu-latest
  • GitHub Check: Compile & Lint
🧰 Additional context used
📓 Path-based instructions (1)
pacquet/**/*.rs

📄 CodeRabbit inference engine (pacquet/AGENTS.md)

pacquet/**/*.rs: Log emissions are part of matching pnpm — when porting a function that fires pnpm:<channel> events through globalLogger, logger.debug(...), or streamParser.write(...), mirror the call site, payload, and ordering so @pnpm/cli.default-reporter parses pacquet's NDJSON the same way
Declare a newtype wrapper for branded string types instead of collapsing the brand into a plain String or &str in Rust
If upstream TypeScript always validates before construction of a branded string, validate in the Rust wrapper too via TryFrom<String> and/or FromStr and do not provide an infallible public constructor
If upstream TypeScript never validates a branded string, just brand for type-safety in Rust by exposing an infallible From<String> constructor
If upstream TypeScript occasionally constructs a branded string without validation, expose from_str_unchecked in Rust as an escape hatch alongside the validating constructor
Match upstream serde behavior for branded strings crossing JSON, YAML, or INI boundaries by using #[serde(try_from = "String")] for deserialization and #[serde(into = "String")] for serialization
Derive simple conversions for branded strings using #[derive(derive_more::From)] and #[derive(derive_more::Into)] instead of handwriting impl blocks; use manual impl only when conversion needs custom logic
Model TypeScript string literal unions (like 'auto' | 'always' | 'never') as Rust enums instead of newtype wrappers, since the set of valid values is closed
Treat TypeScript string template literal types (like `${string}@${string}`) the same as branded string types in Rust, using a newtype wrapper with validation
Follow the code style guide in CODE_STYLE_GUIDE.md — imports, modules, naming, ownership and borrowing, parameter type selection, trait bounds, pattern matching, pipe-trait, error handling, test layout, and cloning of Arc and Rc
Choose owned vs. borrowed parameters to minimize copies; widen to t...

Files:

  • pacquet/crates/resolving-npm-resolver/src/create_npm_resolution_verifier.rs
  • pacquet/crates/cli/src/cli_args/outdated.rs
🧠 Learnings (3)
📚 Learning: 2026-05-20T19:40:55.051Z
Learnt from: zkochan
Repo: pnpm/pnpm PR: 11774
File: pacquet/crates/resolving-deps-resolver/src/resolve_peers.rs:0-0
Timestamp: 2026-05-20T19:40:55.051Z
Learning: In the pacquet Rust code, ensure the semver implementation uses the `node-semver` crate (not `nodejs-semver`). `node-semver`’s public API does not include a `satisfies_with_prerelease`-style method; prerelease-tolerant matching should be implemented inline by first calling `Range::satisfies`, and when it rejects a prerelease version, retry matching against a stripped `MAJOR.MINOR.PATCH` base of the prerelease version.

Applied to files:

  • pacquet/crates/resolving-npm-resolver/src/create_npm_resolution_verifier.rs
  • pacquet/crates/cli/src/cli_args/outdated.rs
📚 Learning: 2026-05-22T00:08:44.646Z
Learnt from: zkochan
Repo: pnpm/pnpm PR: 11837
File: pacquet/crates/resolving-npm-resolver/src/pick_package.rs:33-51
Timestamp: 2026-05-22T00:08:44.646Z
Learning: In the pnpm/pnpm repo’s pacquet Rust crates, do not flag Unicode ellipsis characters (U+2026, `…`) in Rust doc comments (`///` / `/** */`) as a lint violation. The pacquet crate’s `dylint.toml` only enables `perfectionist::derive_ordering`, and the Dylint `unicode-ellipsis` rule is not enabled for this project—so `…` in doc comments is an intentional, repo-consistent style.

Applied to files:

  • pacquet/crates/resolving-npm-resolver/src/create_npm_resolution_verifier.rs
  • pacquet/crates/cli/src/cli_args/outdated.rs
📚 Learning: 2026-05-20T23:07:58.444Z
Learnt from: zkochan
Repo: pnpm/pnpm PR: 11784
File: pacquet/crates/resolving-deps-resolver/src/hoist_peers.rs:120-133
Timestamp: 2026-05-20T23:07:58.444Z
Learning: When reviewing code in this pacquet Rust port, follow the upstream pnpm compatibility rule: only match pnpm’s behavior exactly. Do not propose review changes that intentionally deviate from pnpm’s documented/observed behavior, even if pnpm appears buggy. If you identify a real bug in pnpm behavior, the review should prioritize fixing it upstream in pnpm first, and avoid implementing a pnpm-behavior workaround here unless the same fix has already landed upstream.

Applied to files:

  • pacquet/crates/resolving-npm-resolver/src/create_npm_resolution_verifier.rs
  • pacquet/crates/cli/src/cli_args/outdated.rs
🔇 Additional comments (8)
pacquet/crates/cli/src/cli_args/outdated.rs (8)

1-36: LGTM!


38-89: LGTM!


97-154: LGTM!


156-196: LGTM!


198-305: LGTM!


307-389: LGTM!


444-575: LGTM!


577-619: LGTM!

Comment thread pacquet/crates/resolving-npm-resolver/src/create_npm_resolution_verifier.rs Outdated
Copilot AI review requested due to automatic review settings June 1, 2026 19:13

Copilot AI 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.

Pull request overview

Copilot reviewed 12 out of 13 changed files in this pull request and generated 3 comments.

Comment thread pacquet/crates/cli/src/cli_args/outdated.rs
Comment thread pacquet/crates/cli/src/cli_args/outdated.rs
Comment thread pacquet/crates/cli/src/cli_args/outdated.rs
Port pnpm's `outdated` command to pacquet. It reports direct
dependencies whose latest published version (or highest in-range
version under `--compatible`) is newer than the lockfile-pinned
version, and exits non-zero when any is found.

The detection core is shared with `update --interactive` via
`collect_outdated` / `OutdatedQuery` / `TargetVersion`; the two
callers differ only in which registry version they compare against.
Packuments are fetched concurrently (`futures::join_all`), mirroring
pnpm's `Promise.all`, bounded by the HTTP client's concurrency limit.

Supports `--compatible`, `--long`, `--format table|list|json` (with
`--no-table` / `--json` shorthands), `-P/--prod`, `-D/--dev`,
`--no-optional`, `--sort-by name`, and name-pattern arguments.
`--global` and `--recursive` are rejected, matching `pacquet update`.
A dependency-free manifest reports empty (exit 0) before the
no-lockfile check, matching pnpm's `packageHasNoDeps` short-circuit.
`OutdatedArgs::run` returns an outcome; the single process exit lives
in the top-level CLI dispatch.

The semver-change classifier matches `@pnpm/semver-diff`: equal
versions are `None`, a prerelease-only difference is `unknown` (sorts
last), and major/minor/patch differences are breaking/feature/fix.

Table output uses `tabled` (Style::modern matches pnpm's full-grid
borders) and `owo-colors` (auto-disables on non-TTY like chalk).

Ports the translatable pnpm outdated tests (detection, render-latest,
format/list/json, prod-dev filtering, npm alias, deprecation,
no-deps/no-lockfile). minimumReleaseAge, ignoreDependencies, catalog
protocol, global, recursive listing, and runtime deps are deferred
with the surrounding features.
@zkochan zkochan merged commit ae6e077 into main Jun 1, 2026
28 checks passed
@zkochan zkochan deleted the pq-outdated branch June 1, 2026 21:04
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.

3 participants