A slime mold reads your dependency graph and stages an upgrade ritual: the few direct dependencies to act on, in order, and exactly how much of your vulnerable surface each one closes.
Vulnerable packages are food. Your project is the heart. The organism lays a tube along every chain that can carry a vulnerability home, thickens the tubes that carry current, and starves the rest, the way Physarum polycephalum rebuilt the Tokyo rail network in Tero et al.'s experiment (Science, 2010). The entrances it keeps are where you act.
Every package and every dependency edge, lit. Before it has learned anything, the organism reaches everywhere.
Current flows home from each vulnerable package, weighted by severity. Unfed tubes starve. Rival routes compete until one wins. On the fixture, 7% of the terrain survives.
Act by act, gold lacquer runs out from the heart along each claimed vein and seals it. Closed packages turn teal. The coverage figure is the exact cut, not an estimate.
What can't be fixed yet stays coral and on the record. The script, a package.json patch, waits in the playbill with a copy button.
$ git clone https://github.com/mazze93/theatre-of-dependencies $ cd theatre-of-dependencies $ node bin/theatre.mjs demo # the fixture above, fully offline $ node bin/theatre.mjs stage ~/code/your-app # your graph → growth in the terminal → this stage $ node bin/theatre.mjs scan . --gate open # CI: exit 3 if the ritual leaves you OPEN
Node ≥ 20. Reads an npm v2/v3 package-lock.json or a CycloneDX JSON SBOM. --json for machines, --write to save the script, --prod to skip devDependencies.
The organism routes each advisory through one entrance, but some come in through two. In the fixture, minimist enters through both handlebars and mkdirp. An advisory only counts as closed once every entrance it can use is in the ritual, and the playbill names the ones that aren't.
Advisories with no published fix are listed in coral and stay listed. The state reads CLOSED, HALF-OPEN or OPEN from what the ritual actually closes, not from how many things were looked at.
Nothing else. Cache filenames are hashed, never built from package names. The stage escapes hostile names against </script> breakout and renders text only. Use --offline on a private project you don't want disclosed.
npm audit exactly. npm audit's five extra entries reach an advisory only through a child.npm audit agrees on both.