Skip to content

ideascoldigital/fnpm

Repository files navigation

FNPM

Release Downloads License codecov

Use your favorite package manager in any project without breaking the team's lockfile β€” and block shady install scripts and malicious code before they run on your machine.

How? The project uses npm, but you prefer pnpm. You keep typing pnpm commands as always β€” FNPM intercepts them, runs the install with pnpm on your machine, and keeps the project's original package-lock.json in sync for the team:

# One-time setup: tell FNPM you want to work with pnpm
fnpm setup pnpm
source .fnpm/setup.sh

# Type pnpm commands like you always do
pnpm add express

# FNPM intercepts the command:
#   β†’ installs with pnpm (your local workflow)
#   β†’ πŸ”„ Syncing target lockfile: package-lock.json
#   β†’ βœ“ Target lockfile updated: package-lock.json  (the team's lockfile)

Works with npm, yarn, pnpm, bun, and deno β€” everyone on the team uses whatever they like, and the project's lockfile never breaks.

And because every install goes through FNPM, it audits packages before they touch your disk: it flags suspicious preinstall/postinstall scripts and detects malicious patterns in the code you're about to download.

⭐ Like FNPM? Give us a star on GitHub! ⭐

πŸ“¦ Installation

curl -fsSL https://raw.githubusercontent.com/ideascoldigital/fnpm/main/install.sh | bash

Or download a binary from GitHub Releases, or build from source:

git clone https://github.com/ideascoldigital/fnpm.git
cd fnpm
make install

🎯 Quick Start

# Interactive setup (or: fnpm setup pnpm, fnpm setup yarn, etc.)
fnpm

# Then use the same commands regardless of package manager
fnpm install            # Install dependencies
fnpm add lodash         # Add a package
fnpm add -D typescript  # Add a dev dependency
fnpm remove lodash      # Remove a package
fnpm run build          # Run scripts
fnpm dlx create-react-app my-app  # Execute commands (like npx)

# Check your environment
fnpm doctor

πŸ”„ How Lockfile Sync Works

FNPM detects the project's existing lockfile during setup and keeps it as the source of truth for the team:

  1. You install with your preferred package manager (its own lockfile is created locally).
  2. After every install, add, or remove, FNPM updates the project's original lockfile.
  3. The team's lockfile stays consistent; you keep your workflow.

🎭 Drama Detection

How messy is your project's package manager situation? fnpm doctor calculates a drama score (0–100%) by checking for conflicting signals:

  • Multiple lockfiles living together (package-lock.json + yarn.lock + ...)
  • Dockerfile using a different package manager than your lockfiles
  • CI/CD pipelines demanding yet another one
fnpm doctor

😰 Three's a crowd! Multiple lockfiles detected!
⚠️  Docker wants pnpm! +20 drama points
⚠️  CI demands yarn! +20 drama points

πŸ”΄ 75% - DRAMA ALERT! 🚨
This is fine. Everything is fine. (It's not fine.)

Fix it automatically β€” pick one lockfile to keep and remove the rest:

fnpm doctor --fix              # interactive: choose which lockfile survives
fnpm doctor --fix --keep pnpm  # keep pnpm's lockfile, remove the others

πŸͺ Hooks: Keep Using Your Muscle Memory

Don't want to type fnpm? Hooks intercept direct package manager commands and redirect them:

fnpm setup pnpm
source .fnpm/setup.sh   # add to your shell profile for permanent activation

pnpm add express   # β†’ fnpm add express (lockfile sync + security audit included)
yarn add lodash    # β†’ fnpm add lodash

Manage hooks with fnpm hooks status|create|remove, or skip them entirely with fnpm setup --no-hooks npm (useful for CI/CD). Details in HOOKS.md.

🧱 Anti-Corruption Layer

Stop letting a package's API leak all over your codebase. fnpm adapt scans how your project actually uses a package (AST-based) and generates a port (interface with only the members you use) plus an adapter (implementation backed by the package):

fnpm adapt axios

πŸ” Scanning project for usage of 'axios'
   Default export members: get, post
   Named exports: isAxiosError

🧱 Anti-corruption layer created:
   src/adapters/axios/axios.port.ts      # interface β€” reshape it toward your domain
   src/adapters/axios/axios.adapter.ts   # implementation backed by axios
   src/adapters/axios/index.ts

Your code then depends on the port instead of the package β€” swapping axios later means writing a new adapter, not touching every call site. TypeScript projects get a typed port; JavaScript projects get the adapter object. There's also a lighter option: fnpm add <pkg> --adapter generates a simple re-export barrel at install time.

Optional: AI Review with Ollama

Want a second opinion on the generated layer? With Ollama running locally, add --ai and a local model suggests domain-oriented names and cohesion improvements β€” advisory only, it never blocks anything, and nothing leaves your machine:

fnpm adapt axios --ai

πŸ€– Asking qwen2.5-coder (http://localhost:11434) for an advisory review...

AI suggestions (advisory only):
   - Rename AxiosPort to UserApiPort β€” it's only used to fetch/save users
   - Replace axios config types with your own request options type

Configure in .fnpm/config.json (all optional; set enabled: true to review on every adapt without --ai):

{
  "ai": {
    "enabled": false,
    "provider": "ollama",
    "url": "http://localhost:11434",
    "model": "qwen2.5-coder",
    "timeout_seconds": 120
  }
}

πŸ›‘οΈ Security Auditing

Every package (and its dependency tree) is scanned before installation:

  1. Install scripts β€” flags suspicious preinstall/install/postinstall commands (curl, rm -rf, credential access like ~/.ssh or ~/.aws)
  2. Source code β€” deep JavaScript analysis for eval(), Function(), base64 obfuscation, exec()/spawn(), with precise file:line reporting
  3. Transitive dependencies β€” recursive scan of the whole tree with configurable depth
fnpm add malicious-package

⚠️  HIGH RISK PACKAGES:
  β€’ evil-dependency - ☠ CRITICAL
    β†’ eval: Executes arbitrary code
    β†’ ~/.ssh: Accesses SSH keys

? Found 1 high-risk package(s) in dependency tree. Continue anyway? (y/N)

Configure in .fnpm/config.json:

{
  "security_audit": true,
  "transitive_scan_depth": 2
}

transitive_scan_depth: 0 disables transitive scanning, 1 scans direct dependencies, 2 (default) goes one level deeper, up to 5. Skip the audit for a trusted package with --no-audit (not recommended).

Full security documentation β†’ Β· Transitive scanning guide β†’

πŸ“‹ Available Commands

Command Description
fnpm Interactive setup wizard
fnpm setup <pm> Setup with specific package manager (npm/yarn/pnpm/bun/deno)
fnpm install Install dependencies
fnpm add <pkg> Add package (-D for dev dependency)
fnpm remove <pkg> Remove package
fnpm adapt <pkg> [--ai] Generate anti-corruption layer (port + adapter); --ai adds local Ollama review
fnpm run <script> Run package script
fnpm dlx <cmd> Execute command (like npx)
fnpm doctor Run diagnostics + drama score detection
fnpm doctor --fix [--keep <pm>] Remove conflicting lockfiles, keep one
fnpm hooks status|create|remove Manage hooks
fnpm --version / fnpm --help Version / help

πŸ› οΈ Development

Requires Rust 1.70.0+ and Git.

git clone https://github.com/ideascoldigital/fnpm.git
cd fnpm
make setup
make dev    # format, lint, test

Other targets: make build, make test, make fmt, make clippy, make install.

Project Structure

src/
β”œβ”€β”€ main.rs              # CLI entry point
β”œβ”€β”€ lib.rs               # Main library
β”œβ”€β”€ config.rs            # Configuration management
β”œβ”€β”€ detector.rs          # Package manager detection
β”œβ”€β”€ doctor.rs            # System diagnostics
β”œβ”€β”€ hooks.rs             # Hook system
β”œβ”€β”€ security.rs          # Security scanner
β”œβ”€β”€ package_manager.rs   # Package manager trait
└── package_managers/    # npm, yarn, pnpm, bun, deno implementations

🀝 Contributing

Contributions welcome! See CONTRIBUTING.md. Standard flow: fork, branch, make dev, open a PR.

More docs: llms.txt Β· Hooks Β· Testing Β· CI/CD Β· Cross-Platform Β· Windows

πŸ€” About the Name

FNPM originally stood for "F*ck NPM" β€” born from the frustration of lockfile conflicts and package manager wars inside teams. If that's not your style, feel free to read it as "Friendly NPM" or "Flexible NPM": the tool exists precisely so nobody has to fight about package managers anymore.

πŸ“„ License

MIT β€” see LICENSE.


If FNPM helps you or your team: ⭐ star the repo, πŸ› report issues, or πŸ”€ contribute.

About

Resources

License

Contributing

Security policy

Stars

17 stars

Watchers

1 watching

Forks

Packages

 
 
 

Contributors