See what a lockfile change actually did to your dependencies. A PR touches
package-lock.json and the diff is 4,000 unreadable lines — you can't tell which
packages were added (the supply-chain surface you actually need to eyeball),
which got a major bump, which were quietly downgraded. locksift turns that
noise into a short, reviewable changelog. Zero dependencies, no account, no
network.
# What did my uncommitted changes do to the tree?
npx locksift package-lock.json --git
Added (2) — new in tree, review these
+ ansi-styles@6.2.1
+ picocolors@1.0.1
Removed (1)
- request@2.88.2
Changed (2)
↑ chalk 4.1.2 → 5.3.0 [major]
↓ semver 7.5.4 → 7.3.8 [downgrade]
+2 -1 ~2 (1 major, 1 downgrade)The big supply-chain incidents all enter the same way: a new (often transitive)
package lands in your lockfile and nobody looks, because the lockfile diff is
unreadable by design. git shows you thousands of churned hash/resolved lines;
what you want is the dependency-level answer — what's new, what's gone, what
jumped a major. locksift computes exactly that from the lockfile itself. It
runs locally, talks to nothing, and needs no registry token.
# Diff two lockfiles
locksift old/package-lock.json new/package-lock.json
# Diff your working tree against a git ref (default HEAD) — the PR-review case
locksift package-lock.json --git
locksift package-lock.json --git main
# Just the new packages, one per line — pipe into review tooling
locksift package-lock.json --git --added-only
# Machine-readable
locksift a.json b.json --json
# CI gate: fail the job if the lockfile changed at all
locksift package-lock.json --git --exit-code| Flag | Effect |
|---|---|
--git [ref] |
Compare the working-tree lockfile against ref (default HEAD) |
--json |
Emit { added, removed, changed, summary } as JSON |
--added-only |
Print only newly added packages as name@version, one per line |
--exit-code |
Exit 1 when there are any changes (for CI gates) |
-v, --version |
Print version |
-h, --help |
Show help |
| File | Notes |
|---|---|
package-lock.json |
lockfileVersion 1, 2, and 3. v2/v3 read the authoritative packages map; v1 walks the nested dependencies tree; workspace source dirs are skipped. When a package resolves to several versions in one tree, the diff compares a single representative (the last seen in traversal). |
Pipfile.lock |
pipenv — both default and develop sections. Entries without a pinned version (git/VCS/editable/local-path installs) are not surfaced. |
Both are plain JSON, which is what keeps locksift dependency-free.
A changed package is tagged by comparing the numeric major.minor.patch core
(range prefixes like ^, ~, v and prerelease/build suffixes are tolerated):
[major]/[minor]/[patch]— the first component that moved up[downgrade]— the new version is lower than the old (worth a second look)[other]— same numeric core, different string (e.g. prerelease tag changed)
--json carries the same bump value per changed entry, plus a summary with
majors and downgrades counts.
| Code | Meaning |
|---|---|
0 |
success (default — even when changes are found) |
1 |
changes found and --exit-code was passed |
2 |
error (bad args, unreadable/invalid lockfile, git failure) |
By default locksift is a viewer and exits 0; add --exit-code to make it a
gate (the git diff --exit-code convention).
MIT