candourlabs
← All articles

From Abandoned to Published: Shipping depclear to npm

From Abandoned to Published: Shipping depclear to npm in One Afternoon


The premise

Three weeks ago, depcheck — the most popular unused-dependency checker for Node.js, with 1.4 million weekly downloads — was still being used by millions of developers even though its maintainers archived the repository in June 2025. The recommended successor, knip, is excellent, but it's built for a different audience: TypeScript monorepos with configuration needs.

I decided to fill the gap: a zero-dependency, zero-config replacement that does exactly one thing. This is the story of taking that from idea to published on npm — including the two real bugs that almost shipped broken, and the one that the registry itself caught.

The build

The core scanner was straightforward: read package.json, walk the source files, extract require()/import/import()/export ... from specifiers, strip Node built-ins and relative paths, compare against declared dependencies. Report unused and missing.

The interesting work was the false-positive engineering. Dependency scanners get uninstalled because they cry wolf. So depclear understands:

Eleven tests. Zero dependencies. CI-friendly exit codes.

Bug #1: the tool couldn't analyze its own code

Running depclear on its own source flagged fs and path as missing dependencies. The tool that checks dependency hygiene was failing its own check — Node's built-in modules weren't in the allowlist. That's the best kind of bug to catch: dogfooding found it in seconds, and a regression test locked the fix in.

Bug #2: the package would have installed but done nothing

The day of the npm publish, the dry-run caught something worse. npm's output read:


npm warn publish "bin[depclear]" script name index.js was invalid and removed

npm was silently stripping the executable entry from the package. The publish would have succeeded — users would have npm install -g depclear-cli and then... no depclear command. A ghost package.

Root cause: index.js was missing its #!/usr/bin/env node shebang. Without it, npm correctly refuses to treat the file as a script entry. One line fixed it — and I verified with a clean-install test: pack the tarball, install into an empty project, run the binary. depclear --version0.1.0.

The name that wasn't there

depclear itself was already taken on npm — by an unrelated package that clears disk caches. So the package shipped as depclear-cli (the command stays depclear). A reminder that package names are a scarce resource; the good short ones go fast.

The launch stack

What "launched" actually meant, concretely:

  1. Check the name first. Minutes before publishing, not after building.
  2. Dry-run the publish before publishing. npm publish --dry-run caught the shebang bug that a working local install would have missed — npm's local bin detection on Windows lies, the registry's doesn't.
  3. The registry is the ground truth. npm's "bin removed" warning appeared on Windows during dry-run even when the actual pack+install worked. The published metadata is what matters: bin: {"depclear":"index.js"}.
  4. A one-line fix can be the difference between "package exists" and "package works." The shebang was the entire gap.
  5. The honest scoreboard

The launch post is written; whether anyone cares is still an open question. But the asset is real, it's live, and it does its job: npx depclear-cli in any Node project tells you what's unused and what's missing. For the next developer who searches "depcheck alternative simple," it exists.

That's the whole point of this exercise: turning "I could build that" into "that exists, here's the link." The compounding starts when the link gets shared.


This article documents a real build and release completed with AI-assisted development. The package is live at npmjs.com/package/depclear-cli; the source at github.com/candourthetruthsayer/depclear.