Metadata-Version: 2.4
Name: locksift
Version: 0.1.0
Summary: See which dependencies a lockfile change adds, removes, or bumps — review the supply-chain surface of a PR. Zero dependencies, no account.
Author: yyfjj
License: MIT
Project-URL: Homepage, https://github.com/jjdoor/locksift-py
Project-URL: Repository, https://github.com/jjdoor/locksift-py
Project-URL: Issues, https://github.com/jjdoor/locksift-py/issues
Keywords: lockfile,package-lock,dependencies,diff,supply-chain,security,npm,audit,cli,ci
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Software Development :: Quality Assurance
Classifier: Topic :: Security
Classifier: Topic :: Utilities
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE
Dynamic: license-file

# locksift

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

```bash
pip install locksift

# What did my uncommitted changes do to the tree?
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)
```

> This is the Python build. A byte-for-byte-equivalent Node build is on npm:
> `npx locksift` (<https://github.com/jjdoor/locksift>).

## Why

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.

## Usage

```bash
# 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
```

## Options

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

## Supported lockfiles

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

## Bump classification

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.

## Exit codes

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

## License

MIT
