DeadWeight

mcp
Security Audit
Fail
Health Warn
  • License — License: MIT
  • Description — Repository has a description
  • Active repo — Last push 0 days ago
  • Low visibility — Only 9 GitHub stars
Code Fail
  • exec() — Shell command execution in dist/action/index.js
  • process.env — Environment variable access in dist/action/index.js
  • fs module — File system access in dist/action/index.js
  • network request — Outbound network request in dist/action/index.js
Permissions Pass
  • Permissions — No dangerous permissions requested

No AI report is available for this listing yet.

SUMMARY

VS Code extension: find and remove unused npm packages and dead code, and catch malicious dependencies. Verified removal with auto-undo.

README.md

💀 Deadweight

Find and remove unused npm packages and dead code, and catch malicious dependencies, right inside VS Code.

VS Code Marketplace
Installs
Rating
License: MIT
GitHub stars

Deadweight demo: a scan flags malicious and unused packages, then one-click removal frees 14 MB and is verified by the tests

Install from the Marketplace · or run ext install kalyanmanna.deadweight from Ctrl+P

  • 📦 Unused packages: dependencies nothing imports, with the MB each one frees from node_modules
  • 🗂️ Dead files and unused exports: code no entry point can reach, marked right in the editor
  • ☣️ Malicious dependencies: every installed package checked against the npm advisory database and OSV.dev malware records
  • 🎯 Safe-to-delete score: every finding rated 0–99 with the reason, so you know what's safe before you touch it
  • ✅ Verified one-click removal: your own type check, build and tests run after removal, and it's undone automatically if anything breaks
  • 🔓 Deletes vulnerabilities too: see the known CVEs you remove, e.g. "frees 84 MB and 3 known vulnerabilities"
  • 🕸️ Connection graph, blast radius, MCP server for AI agents and a PR guard GitHub Action

Works with npm, yarn and pnpm, in JavaScript and TypeScript projects, including folders with several projects.


📑 Contents


🚨 The Problem

Modern projects accumulate technical clutter surprisingly fast.

You install a package for a feature that gets removed.
You create a utility file that stops being used.
You leave behind dependencies from an old implementation.

Over time, these become deadweight: unnecessary dependencies, unused files, larger projects, harder navigation, more maintenance and more technical debt.

Tools that detect dead code already exist — but they print a list of 40 paths in a terminal and leave you to double-check every one before daring to delete anything. Most people never act on it.

Deadweight closes that loop: detect → understand → remove safely → undo if needed.


⚡ Quick start (1 minute)

  1. Install — in VS Code open Extensions (Ctrl+Shift+X / Cmd+Shift+X), search Deadweight, click Install.
  2. Open your project — File → Open Folder… and pick the folder that contains your package.json.
  3. Click the Deadweight icon (🗑️) in the left activity bar → Scan Workspace.
  4. Read the results — every item has a score like high · 98. Hover it to see why.
  5. Click the trash icon at the top of the panel → check the preview → Remove.
  6. Changed your mind? Click Undo.

That's it. The rest of this page explains each step in detail.


🧭 The complete workflow

 Install ─► Open project ─► Scan ─► Read scores ─► Investigate ─► Review & Remove ─► (Undo) ─► Scan again
                              │                        ▲
                              └──► Connection Graph ───┘   (optional: see how everything connects)

Step 1 — Install

  • VS Code: Extensions view → search Deadweight → Install, or press Ctrl+P and run ext install kalyanmanna.deadweight.
  • From a file: download the .vsix from the GitHub releases, then Extensions view → ⋯ → Install from VSIX…

Installing does nothing on its own — Deadweight never runs in the background or on startup. It only works when you ask.

Step 2 — Open your project

Open the folder that directly contains package.json (File → Open Folder…).

💡 If your project lives in a subfolder — e.g. you opened my-projects/ but the app is in my-projects/my-app/ — open my-app itself. Otherwise Deadweight will tell you it can't find a package.json.

Tip: commit your work to git before cleaning up. Then the cleanup shows up as its own, easy-to-review diff.

Step 3 — Scan

Click the Deadweight icon in the activity bar, then Scan Workspace (or run Deadweight: Scan for unused code from the Command Palette).

  • A progress notification appears; you can keep working, or Cancel at any time.
  • The first scan downloads the analysis engines and can take 30–60 seconds; later scans take a few seconds.
  • When it finishes, the panel fills with three groups:
Group What it lists Can Deadweight remove it?
📦 Unused Packages Dependencies in package.json that nothing imports, runs or configures ✅ Yes (uninstalls with your package manager)
🗂️ Unused Files Files no entry point can reach ✅ Yes (moves them to a trash folder)
🧩 Unused Exports Exported functions, classes, constants and types that no file imports ✋ No — you delete the code yourself

If nothing is found you'll see "No deadweight found" — that's a clean project. 🎉

Step 4 — Read the scores

Every finding shows a band and a safe-to-delete score from 0 to 99:

Score Band Meaning Pre-checked?
80–99 🟢 high Independent checks all agree it's unused ✅ Yes
50–79 🟡 medium Probably unused, but something is worth a look No
< 50 🔴 low Could be used in a way that can't be proven (dynamic imports, config, plugins…) No

Hover any finding to read exactly why it got its score — for example "No import found across 5 scanned files; depcheck agrees. Deadweight's graph agrees: nothing imports it." See Understanding the score for all the rules.

Step 5 — Investigate

  • Click a finding to open it: a file opens directly, a package jumps to its line in package.json, an export jumps to the exact function.
  • In the editor, dead files and unused exports are marked with a ⊘ in the gutter and a note like "Deadweight: unused export · high 98" at the end of the line. Unused files are also dimmed in the Explorer.

Unused exports marked in the editor

  • Right-click a finding → Show in Connection Graph to see what it is (or isn't) connected to.

Step 6 — Review & Remove

  1. Tick or untick the checkboxes. High-score packages and files start ticked; medium and low never do.
  2. Click the trash icon at the top of the Deadweight panel (Review & Remove).
  3. A preview opens — nothing has changed yet. It shows:
    • the exact uninstall command (e.g. npm uninstall chalk left-pad lodash),
    • a View package.json diff button,
    • which files will move to .deadweight-trash/<timestamp>/,
    • the checks that will verify the removal (your type check, build and test scripts),
    • a warning if you have uncommitted changes.
  4. Click Remove & verify to go ahead, or Cancel to leave everything as it is.

Review & Remove preview

What actually happens:

  • Packages are uninstalled in one command with your package manager (npm, yarn, pnpm or bun — detected automatically). package.json and your lockfile are backed up first.
  • Files are moved, never deleted, into .deadweight-trash/<timestamp>/ with their folder structure preserved. The trash folder is added to your .gitignore automatically.
  • Unused exports are never touched — open them and delete the code by hand if you agree.

🛡️ Delete a vulnerability

Every unused package shows what removing it really gains: the space it and the dependencies nothing else needs take up in node_modules, and the known vulnerabilities among them (from the npm advisory database, the one npm audit uses):

lodash     high · 98 · 1.3 MB · ⚠ 5 vulns
minimist   high · 98 · 32 KB  · ⚠ 1 vuln

Hover a package for the list of advisories with links. The scan summary and the Review & Remove panel add it up: "Frees 1.4 MB and removes 6 known vulnerabilities (1 critical, 2 high, 3 moderate)." Unused code you never run can still be installed, audited against and exploited in your supply chain; removing it is the cheapest fix there is.

The lookup sends the names and versions of the unused packages (and their exclusive dependencies) to registry.npmjs.org, like npm audit does. Turn it off with deadweight.checkVulnerabilities; sizes are measured locally either way.

☠️ Malicious packages

Every scan also checks everything installed in node_modules, used or not, for known malware: hijacked releases of real packages (like [email protected]) and packages published only to steal tokens. The exact installed versions are matched against the npm advisory database and OSV.dev (the OpenSSF malicious-packages records), so a clean version of the same package is never flagged.

⚠ Malicious Packages (2)        known malware · remove by hand
   [email protected]                  declared in package.json
   [email protected]         installed by event-stream

Each one shows its version, whether you declared it or which of your dependencies installs it, and links to the reports on hover. You also get an error notification, with the details in the Deadweight output channel.

Deadweight doesn't remove malware for you: remove or replace the package (or the dependency that installs it), delete node_modules and reinstall. Its code may already have run on install, so treat tokens, keys and .env secrets on that machine as leaked and rotate them.

The check needs dependencies installed, and sends the names and versions of the installed packages to registry.npmjs.org and api.osv.dev. Turn it off with deadweight.checkMalware.

🤖 AI Security Scan (bring your own key)

The databases only know malware that has already been reported. AI Security Scan asks an AI to look for what they can't know yet, using your own API key for Claude, OpenAI, Gemini, or any OpenAI-compatible API (OpenRouter, Groq, Mistral, DeepSeek, a local Ollama server…). Click it in the Deadweight view, or run Deadweight: AI Security Scan. The first time, it asks for the provider, the key and the model.

It reviews:

  • Install scripts (preinstall / install / postinstall) of every installed package, with the files they run. Most npm malware runs this way.
  • Your dependencies, looking for typosquats and packages pulled from unexpected sources.
  • Your own code, configs and CI: lines matching backdoor and exfiltration patterns (eval, shell commands, base64 payloads, environment dumps, credential-file reads, webhook hosts, reverse shells, hard-coded master passwords, disabled TLS checks), with the code around them.
  • .npmrc, .yarnrc and CI files, where registries and tokens get redirected.

You get a report with a verdict and each finding's severity, location, evidence and fix.

Before anything is sent, Deadweight shows how much evidence will go and to which host, and you can Preview exactly what goes. Tokens, keys and passwords are replaced with <redacted>, and .env and key files are never read. The key is kept in your OS keychain through VS Code's SecretStorage, never in settings or the workspace. Change or remove it with Deadweight: Set AI Provider & API Key.

An AI review is a second opinion, not a guarantee: it sees the evidence Deadweight collected, not every line of every package.

✅ Verified removal

Static analysis can only guess. Deadweight checks its work with your project's own checks:

  1. Before removing, it runs the ticked checks: your type check (typecheck / check-types script, or tsc --noEmit), build and test. Checks that already fail are left out, since they can't prove anything.
  2. After removing, it runs the passing ones again.
  3. If one that passed before now fails, the removal is undone automatically. Deadweight reads the error output, names the likely cause (e.g. "Cannot find module 'lodash'" → lodash) and marks it in use, so it stays at the bottom of the score in future scans.

When everything still passes you get "Verified: type check, build and tests passed after the removal", plus the usual Undo. Untick any check in the panel to skip it (your choice is remembered), or turn verification off with deadweight.verifyRemovals.

Step 7 — Undo (if you need to)

  • Right after removing: click Undo in the notification. Files go back to where they were and packages are reinstalled at their exact previous versions.
  • Any time later: click the clock icon at the top of the panel (Restore from Trash) and pick the removal to restore. Every removal is kept until you delete it.

When you're happy with a cleanup, you can delete the .deadweight-trash folder yourself.

Step 8 — Scan again

Click the refresh icon at the top of the panel. The list should be shorter — or show "No deadweight found".


🎯 Understanding the safe-to-delete score

Deadweight never guesses and never uses AI. Every score comes from evidence it can show you, and your code never leaves your machine.

What raises the score — independent engines agreeing:

  • knip found no import of it,
  • depcheck agrees (packages),
  • Deadweight's own connection graph agrees nothing reachable uses it,
  • for exports: the name appears in no other file at all.

What lowers the score — anything that could mean it's still used:

Situation Effect
Loaded by a computed import like import(`./plugins/${name}.js`) or require(x) → low
Referenced by path or name in a config file (webpack, next.config, …) → low / medium
Run by an npm script or CI → medium
Type definitions (@types/*), a peer dependency of another package → low
Plugins and presets loaded by name (ESLint, Babel, PostCSS, …) → medium
Barrel files (index.ts), packages inside a monorepo workspace → medium
An entry file's exports (may be public API) → medium

Agreement can raise a score only within the band its risks allow — a risky item can never climb to high. The score never reaches 100, because nothing is ever certain.


🕸️ The Connection Graph

An interactive map of how every file and package in your project connects — built in milliseconds, fully offline, no scan needed.

Open it with the graph icon at the top of the Deadweight panel, or Deadweight: Show Connection Graph from the Command Palette.

Connection Graph

Reading it

Shape / line Meaning
🟦 square Entry point — where the app starts (main/bin, framework pages, configs, tests, npm scripts)
🟢 circle Used file — reachable from an entry point
🟡 dashed circle Maybe — only reachable through a computed import, can't be proven
🔴 glowing circle Unused — nothing reachable uses it
◆ diamond Package (purple = used, red = unused)
solid line import · dashed: type-only import · dotted: path in a config · yellow dashed: computed import

Using it

To… Do this
See why a file is used or unused Click it — the details panel shows the reason, Imported by and Imports
Open a file Double-click it, or Open file in the details panel
Find a file Type in the search box (press /), Enter jumps to each match in turn
Show only the problems Click the Entry points and Used chips to hide them (their neighbours stay faintly visible for context)
Hide packages Click the Packages chip
See the flow from the entry points Switch the layout to Tree
Zoom Mouse wheel, the + / − buttons, or F to fit everything
Update after editing code Click Rebuild (⟳)

Graph details panel

Your filters and layout are remembered. Very large projects open on the problems only; click a chip to show everything.


💥 Blast radius: what breaks if I change this?

Right-click any JavaScript/TypeScript file (in the Explorer, its editor tab or the editor) → Show Blast Radius. You get every file that depends on it, directly or through other files, and the entry points it reaches (pages, commands, tests):

Blast radius of format.ts: 14 files (5 direct, 9 indirect) · 3 entry points

Pick a file to open it, or Show in Connection Graph to see the whole chain highlighted in orange. In the graph, every file's details panel shows its blast radius with a Highlight what it can break button.


🤖 AI agents (MCP)

Deadweight ships an MCP server, so coding agents can ask how your project connects instead of opening file after file to find out. That's fewer tokens and fewer wrong guesses.

Tool What the agent gets
project_map The compact project map (every file, its imports, entry points, unused code), optionally for one folder
file_info What a file imports, what imports it, whether it's used, and its blast radius
blast_radius Everything a change to a file or package can break, and the entry points affected
import_path The import chain from one file to another file or package
find_unused Unused and maybe-unused files and packages, with reasons

Connect an agent: run Deadweight: Connect AI Agents (MCP) and pick yours.

  • GitHub Copilot (VS Code 1.101+): nothing to do. Deadweight appears in Copilot Chat's Agent mode tools list.
  • Claude Code: registers it with claude mcp add in a terminal.
  • Cursor: adds it to the project's .cursor/mcp.json.
  • Anything else (Windsurf, Claude Desktop, Cline, Zed…): copies an mcpServers config to paste.

The server runs offline on your machine and only reads source files. Agents other than Copilot need Node.js on your PATH.


🛡️ PR guard (GitHub Action)

Stop dead code at the door. The Deadweight action scans every pull request and its base branch, and comments with only what the PR adds: new unused files, packages and exports, with their safe-to-delete score and any known vulnerabilities. Old dead code on the base branch never makes a PR noisy.

Add .github/workflows/deadweight.yml:

name: Deadweight
on: pull_request

permissions:
  contents: read
  pull-requests: write   # to comment

jobs:
  deadweight:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v5
      - uses: actions/setup-node@v5
        with:
          node-version: 24
      - run: npm ci                       # optional: enables sizes and vulnerability checks
      - uses: Kalyan-github-4/DeadWeight@v1
        with:
          fail-on: none                   # or "new" / "new-high" to fail the check

What you get on each pull request:

  • One comment, updated on every push (never a new one each time): "This pull request adds 1 unused package and 2 unused files", a table with scores and reasons, a warning when the new unused packages carry vulnerabilities, and a 🎉 when the PR removes dead code.
  • Inline warnings on the changed lines of the diff.
  • A caution block and a failed check when a known-malicious package is installed, on any PR, with the version and the dependency that installs it.
  • A job summary, and outputs added, removed, existing, vulnerabilities, malware for later steps.
Input Default
path . Folder to scan; may hold one project or several
fail-on none new: fail when the PR adds unused code · new-high: only for high-confidence findings
comment true Set false to only write the job summary
check-vulnerabilities true Look up known vulnerabilities (run npm ci first)
check-malware true Check every installed package for known malware (run npm ci first). Malware fails the check, whatever fail-on says
exclude .gitignore-style patterns, one per line
entry-points Extra entry-point globs, one per line

Pull requests from forks get a read-only token, so they get the job summary and annotations but no comment.


⚙️ Commands & settings

Commands

Command What it does
Deadweight: Scan for unused code Find unused packages, files and exports
Deadweight: Show Connection Graph Open the interactive file & package graph
Deadweight: Review & Remove Preview and remove the checked findings
Deadweight: Restore from Trash Undo any earlier removal
Deadweight: Show Blast Radius See every file a change to this file can break (also on right-click)
Deadweight: Connect AI Agents (MCP) Give Copilot, Claude Code, Cursor and others Deadweight's graph tools
Deadweight: Export Project Map for AI Agents Save or copy a compact map of the project for any AI chat
Deadweight: AI Security Scan (Malware & Backdoors) Have Claude, OpenAI, Gemini or another AI review install scripts, dependencies and your code, with your own API key
Deadweight: Set AI Provider & API Key Choose the AI provider and model, and save or remove the API key

Settings

Open Settings (Ctrl+,) and search Deadweight.

Setting Default Use it when
deadweight.exclude [] You want to hide some files or packages from the results, as .gitignore-style patterns: legacy/, **/*.stories.tsx, @types/*
deadweight.entryPoints [] A file is run in a way Deadweight can't see (a cron job, a custom loader). Globs like scripts/*.js — they and everything they import count as used
deadweight.minimumConfidence low You only want to see medium+ or high results
deadweight.packageManager auto You want to force npm, yarn, pnpm or bun
deadweight.verifyRemovals true Turn off if your checks are too slow to run twice per removal
deadweight.verifyTimeoutMinutes 10 A check needs longer than 10 minutes (it counts as failed after this)
deadweight.checkVulnerabilities true Turn off to keep package names from being sent to the npm advisory database
deadweight.checkMalware true Turn off to skip the malware check, which sends installed package names to the npm advisory database and OSV.dev
deadweight.ai.provider / deadweight.ai.model / deadweight.ai.baseUrl — You want to change the AI security scan's provider, model or OpenAI-compatible URL (application-wide only; the key itself is in the keychain)

Example .vscode/settings.json:

{
  "deadweight.exclude": ["legacy/", "@types/*"],
  "deadweight.entryPoints": ["scripts/*.js"],
  "deadweight.minimumConfidence": "medium"
}

🩺 Troubleshooting & FAQ

"No package.json found in …"
You opened a folder above your project. Open the folder that directly contains package.json (File → Open Folder…).

The scan failed.
Click Show Details on the error (or View → Output → Deadweight). The scan needs Node.js and npm on your PATH, and an internet connection the first time, because it runs knip and depcheck through npx. The Connection Graph works without either.

The first scan is slow.
The first run downloads the analysis engines. Later scans take a few seconds.

Deadweight flagged something I actually use.
It's probably loaded in a way no static analysis can see. Add it to deadweight.entryPoints (for files) or deadweight.exclude, and please open an issue — false positives are the thing we care about most.

Does it upload my code anywhere?
No. Everything runs locally. No AI, no API key, no telemetry.

Does it delete my files?
No. Files are moved to .deadweight-trash/, and every removal can be undone.

Why can't it remove unused exports for me?
Deleting code inside a file is a change a human should make and review. Deadweight shows you exactly where each one is.

Does it work in Cursor / Windsurf / VSCodium?
Yes — it needs VS Code 1.90 or newer (or a compatible editor). Install it from the .vsix file if the editor can't reach the VS Code Marketplace.

Which projects are supported?
JavaScript and TypeScript projects with a package.json — React, Next.js, Vue/Nuxt, Svelte/SvelteKit, Remix, Astro, Gatsby, Angular, Expo/React Native, Node CLIs and servers. Monorepos work, with findings inside workspace packages capped at medium confidence for now.

Requirements

  • VS Code 1.90 or newer
  • Node.js and npm on your PATH (for the scan)
  • Internet access for the first scan

🧠 How it works

                        ┌─────────────┐
                        │   Project   │
                        └──────┬──────┘
          ┌────────────────────┼────────────────────┐
          ▼                    ▼                    ▼
        knip               depcheck          Deadweight graph
  (files, packages,     (second opinion     (its own import graph:
      exports)            on packages)       entry points → reachability)
          └────────────────────┼────────────────────┘
                               ▼
                 Safe-to-delete score + reasons
                               │
                    ┌──────────┴──────────┐
                    ▼                     ▼
               ✅ Required          💀 Deadweight
                                         │
                            Review → Remove → Undo

Deadweight's own graph finds your entry points (main/bin/exports in package.json, framework conventions for Next.js, Nuxt, SvelteKit, Remix, Astro, Gatsby, Angular and Expo, npm scripts, CI workflows, config files and tests), resolves every import (relative paths, index files, .js→.ts, tsconfig/jsconfig path aliases, monorepo packages, file paths in configs and build scripts) and walks from the entry points to see what's reachable. When independent engines agree, confidence goes up; anything they can't prove lowers it.


🔐 Safety Philosophy

Deadweight should never encourage developers to blindly delete code.

A file or dependency can appear unused while still being required through:

  • Dynamic imports
  • Configuration
  • Build tooling
  • Runtime behavior
  • Framework conventions
  • External consumers

That's why Deadweight is an analysis and decision tool, not an auto-deleter:

  • every finding explains itself,
  • uncertain items are never pre-checked,
  • nothing is removed without a preview,
  • files go to a trash folder instead of being deleted,
  • and every removal can be undone.

🧪 Development

git clone https://github.com/Kalyan-github-4/DeadWeight.git
cd DeadWeight
npm install
npm run compile

Press F5 in VS Code to launch an Extension Development Host with Deadweight loaded.

Script What it does
npm run compile Type-check, lint and build
npm run watch Rebuild on every change
npm run test:unit Unit tests, including the zero-false-positive release gate on the fixture projects
npm run vsix Build deadweight-<version>.vsix

Tech stack: VS Code Extension API · TypeScript · Node.js · knip & depcheck · Cytoscape.js


🗺️ Roadmap

  • Unused dependency detection
  • Dead-file analysis
  • Unused export detection
  • Safe-to-delete score with explanations
  • Connection graph visualization
  • One-click cleanup with undo
  • Configurable safety rules
  • Framework-specific analysis
  • Automatically find projects in subfolders
  • Full monorepo support (cross-workspace verification)
  • Bundled engines for faster, fully offline scans
  • CI/CD integration (PR guard GitHub Action)
  • Malicious package detection

📄 License

MIT © Kalyan Manna

Reviews (0)

No results found