npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@radleta/just-one

v1.4.2

Published

A CLI tool that ensures only one instance of a command runs at a time

Readme

just-one

npm version CI license node

A CLI tool that ensures only one instance of a command runs at a time. Tracks processes by name using PID files, kills the previous instance before starting a new one, and verifies process identity to prevent PID reuse accidents.

Quick start:

npx @radleta/just-one -n dev -- npm run dev

The -- separator tells just-one where its own options end and your command begins.

Table of Contents

Motivation

When developing with dev servers (Storybook, Vite, webpack-dev-server, etc.), you often get:

Error: Port 6006 is already in use

Existing solutions have drawbacks:

  • kill-port — Kills ANY process on that port (imprecise, might kill unrelated processes)
  • Manual — Find PID, kill it, restart (tedious)
  • pm2 — Overkill for dev servers

just-one tracks processes by name using PID files. When you run a command, it kills the previous instance (if any) and starts fresh — precisely targeting only the process it started.

Features

  • Named process tracking — Each process gets a unique name for precise targeting
  • Automatic cleanup — Previous instance killed before starting new one
  • PID reuse protection — Verifies process identity before killing to prevent accidents
  • Log capture — stdout/stderr captured to log file in both foreground and daemon modes
  • Daemon mode — Run processes in the background (detached)
  • Log viewing — View captured logs, follow in real-time (like tail -f)
  • Log rotation — Automatic rotation at 10MB (keeps 1 backup)
  • Cross-platform — Works on Windows, macOS, and Linux
  • Minimal dependencies — Only pidusage for process verification

Installation

npm install -g @radleta/just-one

Or use with npx (no install required):

npx @radleta/just-one -n myapp -- npm run dev

Usage

Basic Usage

# Run storybook, killing any previous instance named "storybook"
just-one -n storybook -- npx storybook dev -p 6006

# Run vite dev server
just-one -n vite -- npm run dev

# Run any command
just-one -n myapp -- node server.js

Ensure a Process Is Running (Idempotent)

# Only starts if not already running — safe to call repeatedly
just-one -n vite -e -- npm run dev

Log Capture

Output is automatically captured to .just-one/<name>.log in both foreground and daemon modes:

# Foreground — output appears in terminal AND is saved to log file
just-one -n myapp -- npm start

# Disable log capture if you don't need it
just-one -n myapp --no-log -- npm start

Daemon Mode (Background)

# Run in background — parent exits immediately, output captured to log file
just-one -n myapp -D -- npm start

Viewing Logs

# View all captured logs (works for both foreground and daemon processes)
just-one -L myapp

# View last 50 lines
just-one -L myapp --lines 50

# Follow logs in real-time (like tail -f) — auto-exits when process dies
just-one -L myapp -f

# Show last 20 lines then follow
just-one -L myapp -f --lines 20

Check If a Process Is Running

just-one -s storybook        # exit 0 if running, exit 1 if stopped
just-one --status myapp

Get the PID for Scripting

pid=$(just-one -p myapp -q)  # prints just the PID number

Kill a Named Process

just-one -k storybook
just-one --kill myapp

Kill All Tracked Processes

just-one -K
just-one --kill-all

Wait for a Process to Exit

just-one -w myapp             # wait indefinitely
just-one -w myapp -t 30       # wait up to 30 seconds

List Tracked Processes

just-one -l
just-one --list

Clean Up Stale PID Files and Logs

just-one --clean              # removes stale PID files and their associated log files

Specify Custom PID Directory

# Default: ./.just-one/<name>.pid
just-one -n storybook -- npx storybook dev

# Custom directory
just-one -n storybook -d /tmp -- npx storybook dev

CLI Options

| Option | Alias | Description | | ------------------ | ----- | -------------------------------------------------- | | --name <name> | -n | Required for run. Name to identify this process | | --daemon | -D | Run in background (detached) | | --no-log | | Disable log file capture in foreground mode | | --logs <name> | -L | View captured logs for a named process | | --tail | -f | Follow log output in real-time (use with --logs) | | --lines <n> | | Number of lines to show (use with --logs) | | --kill <name> | -k | Kill the named process and exit | | --kill-all | -K | Kill all tracked processes | | --status <name> | -s | Check if a named process is running (exit 0/1) | | --ensure | -e | Only start if not already running (use with -n) | | --pid <name> | -p | Print the PID of a named process | | --wait <name> | -w | Wait for a named process to exit | | --timeout <secs> | -t | Timeout in seconds (use with --wait) | | --grace <secs> | -g | Grace period before force kill (default: 5s) | | --clean | | Remove stale PID files and orphaned log files | | --list | -l | List all tracked processes and their status | | --pid-dir <dir> | -d | Directory for PID files (default: .just-one/) | | --quiet | -q | Suppress output | | --help | -h | Show help | | --version | -v | Show version |

package.json Scripts

{
  "scripts": {
    "storybook": "just-one -n storybook -- storybook dev -p 6006",
    "dev": "just-one -n vite -e -- vite",
    "dev:api": "just-one -n api -D -- node server.js",
    "dev:logs": "just-one -L api -f",
    "dev:quick": "just-one -n quick --no-log -- node scripts/check.js",
    "stop": "just-one -K"
  }
}

How It Works

.just-one/
  storybook.pid    # Contains: 12345
  storybook.log    # Captured output (both foreground and daemon)
  storybook.log.1  # Rotated backup (auto-managed)
  vite.pid         # Contains: 67890
  1. Check if a PID file exists for that name
  2. If yes, verify it's the same process we started (by comparing start times)
  3. If verified, send SIGTERM and wait up to 5 seconds (configurable with --grace)
  4. If still alive, escalate to SIGKILL (force kill)
  5. Start the new process
  6. Save its PID for next time

PID Reuse Protection

Operating systems can reuse PIDs after a process terminates. To prevent accidentally killing an unrelated process that received the same PID, just-one compares:

  • The PID file's modification time (when we recorded the PID)
  • The process's actual start time (from the OS)

If these don't match within 5 seconds, the PID file is considered stale and the process is not killed.

| Platform | Kill Method | Signal Handling | | -------- | ------------------------------------------------ | --------------------------------------------------------------------------------------------------- | | Windows | taskkill /PID <pid> /T /F (kills process tree) | On Ctrl+C, relies on OS-delivered CTRL_C_EVENT for graceful shutdown with a force-kill safety net | | Unix/Mac | kill -SIGTERM -<pid> (process group) | Forwards SIGTERM to child process |

Windows graceful shutdown: In foreground mode with log capture, stdout/stderr are piped so CTRL_C_EVENT may not reach the child automatically. just-one sends an explicit SIGTERM as a defensive fallback, with a force-kill safety net after 2 seconds. With --no-log, the child shares the console directly and receives CTRL_C_EVENT from the OS.

Use Cases

  • Dev servers — Storybook, Vite, webpack-dev-server, Next.js
  • Background processes — API servers, database seeders, watchers
  • CI/CD — Ensure clean state before running tests
  • Multiple instances — Run named instances on different ports
# Run two storybooks on different ports
just-one -n storybook-main -- storybook dev -p 6006
just-one -n storybook-docs -- storybook dev -p 6007

Comparison

| Feature | just-one | kill-port | pm2 | | ---------------------- | --------------- | ------------ | ------------ | | Kills by PID (precise) | Yes | No (by port) | Yes | | PID reuse protection | Yes | No | No | | Status check | Yes | No | Yes | | Cross-platform | Yes | Yes | Yes | | Zero config | Yes | Yes | No | | Remembers processes | Yes (PID file) | No | Yes (daemon) | | Lightweight | Yes (1 dep) | Yes | Heavy | | Daemon mode | Yes | No | Yes | | Log capture & tailing | Yes | No | Yes |

Programmatic Usage

The package exports a main() function that mirrors the CLI interface:

import { main } from '@radleta/just-one';

// main() reads from process.argv and returns an exit code
const exitCode = await main();

This is primarily designed for embedding just-one in custom CLI tooling. For most use cases, the CLI is the recommended interface.

Requirements

  • Node.js >= 20.0.0

Development

# Install dependencies
npm install

# Build
npm run build

# Run tests
npm test

# Lint + typecheck + test
npm run validate

Contributing

Contributions are welcome! Please open an issue to discuss what you'd like to change, or submit a pull request directly.

Changelog

See CHANGELOG.md for a history of changes to this project.

License

MIT