Skip to main content
One of Better PM’s most convenient features is paste-friendly command parsing. You can copy installation commands from documentation and paste them directly into pm add, regardless of which package manager the docs assume you’re using.

The Problem

You’re reading a library’s README and see:
npm install some-package
But your project uses pnpm. You have to mentally translate:
  • npm installpnpm add
  • Extract the package name
  • Remember to add -D if it was --save-dev
With Better PM, just paste the whole command:
pm add "npm install some-package"
Better PM automatically detects it’s a pasted command and does the right thing.

How It Works

The paste detection logic is in src/lib/parse-pm-command.ts and handles the pm add command in src/commands/add.ts.
1

Detect pasted commands

When you pass a string to pm add, it checks if:
  1. The argument contains spaces (indicating a full command)
  2. The first token is a package manager name (npm, pnpm, or bun)
  3. The second token is an install subcommand (install, add, or i)
From parse-pm-command.ts
const isPmCommand =
  tokens.length >= 2 && isPmName(tokens[0]) && isSubcommand(tokens[1]);
2

Extract packages and flags

If it’s a pasted command, Better PM:
  • Splits the command by whitespace: "npm install -D foo bar"['npm', 'install', '-D', 'foo', 'bar']
  • Extracts package names (tokens without - prefix): ['foo', 'bar']
  • Detects dev flag (-D or --save-dev): true
From parse-pm-command.ts
const rest = tokens.slice(2);  // Skip 'npm install'
const packages = rest.filter((t) => !t.startsWith('-'));
const dev = rest.some((t) => t === '-D' || t === '--save-dev');
3

Build the correct command

Better PM then builds the installation command using your project’s package manager:
From add.ts
const resolved = resolveAddArgs(Array.from(args.packages), args.dev);
const cmd = pm.buildAddCommand(resolved.packages, resolved.dev);
If your project uses pnpm and you pasted npm install -D foo, Better PM runs:
pnpm add -D foo

Supported Formats

Better PM recognizes these package manager commands:

npm

npm install pkg
npm install -D pkg
npm i pkg
npm i --save-dev pkg

pnpm

pnpm install pkg
pnpm add pkg
pnpm add -D pkg
pnpm i pkg

bun

bun install pkg
bun add pkg  
bun add -D pkg
bun i pkg

Valid Package Manager Names

From parse-pm-command.ts:1
const PM_NAMES = ['npm', 'pnpm', 'bun'] as const;

Valid Subcommands

From parse-pm-command.ts:2
const SUBCOMMANDS = ['install', 'add', 'i'] as const;

Examples

Copy from README:
npm install react
Paste into Better PM:
pm add "npm install react"
Better PM runs (assuming your project uses pnpm):
pnpm add react

Real-World Workflows

Copying from GitHub READMEs

1

Find the installation section

Navigate to a library’s README on GitHub:
From a typical README
## Installation

```bash
npm install framer-motion
</Step>

<Step title="Copy the command">
Select and copy the entire command:
npm install framer-motion
</Step>

<Step title="Paste into pm add">
In your terminal:
```bash
pm add "npm install framer-motion"
Output:
Running: pnpm add framer-motion

Copying from Documentation Sites

Many docs show multiple package manager options:
Example from docs
## Installation

npm:
```bash
npm install next
pnpm:
pnpm add next

**With Better PM:** Doesn't matter which one you copy. Both will work:

```bash
pm add "npm install next"  # ✅ Works
pm add "pnpm add next"     # ✅ Also works

Copying from Stack Overflow

Stack Overflow answers often include full commands:
To fix this, install the missing peer dependency:
npm install --save-dev @babel/core
Just paste it:
pm add "npm install --save-dev @babel/core"

Edge Cases

Empty Package List

If you paste a command without package names:
pm add "npm install"
Better PM throws an error:
From parse-pm-command.ts:40-43
if (extracted.packages.length === 0) {
  throw new Error(
    'No packages specified in pasted command. To install dependencies, use: pm i',
  );
}
This prevents accidentally running pm add without packages, which would fail.

Mixed Flags

If the pasted command has both -D from the paste AND you pass -D explicitly:
pm add -D "npm install -D typescript"
Both flags are recognized:
From parse-pm-command.ts:46
return { packages: extracted.packages, dev: devFlag || extracted.dev };
Result: dev = true || true = true (no duplication, just ensures dev mode).

Non-Pasted Commands

If you pass arguments without spaces (normal usage), Better PM skips parsing:
pm add typescript  # No parsing, direct pass-through
From parse-pm-command.ts:26-32
const tokens =
  rawPackages.length === 1 && rawPackages[0].includes(' ')
    ? rawPackages[0].split(/\s+/)
    : rawPackages;

const isPmCommand =
  tokens.length >= 2 && isPmName(tokens[0]) && isSubcommand(tokens[1]);

if (!isPmCommand) {
  return { packages: rawPackages, dev: devFlag };
}

Limitations

Not supported:
  • yarn commands: yarn add pkg is not detected (yarn not in PM_NAMES)
  • npm shorthands with flags: npm i -g pkg (global installs not supported by Better PM)
  • Complex flags: --legacy-peer-deps, --force, etc. are ignored
  • Version specifiers in paste: npm install [email protected] (the @1.2.3 becomes part of package name, which may fail)
For these cases, extract the package name manually:
pm add pkg        # Instead of pasting the full command
pm add [email protected]  # Explicit version works fine

Why This Feature Exists

From the README:
Copied a command from a README? Just paste it:
pm add "npm install -D something"    # automatically extracts -D and the package
pm add "pnpm add foo bar"            # works with any package manager command  
pm add "bun add -D @scope/pkg"       # scoped packages too
pm detects pasted npm install, pnpm add, bun add (and their shorthands like npm i) and extracts the packages and -D flag automatically.
This feature eliminates the mental overhead of translating between package managers when reading documentation, making Better PM truly package manager agnostic from the developer’s perspective.

Source Code Deep Dive

The implementation is remarkably concise:
src/lib/parse-pm-command.ts (complete file)
const PM_NAMES = ['npm', 'pnpm', 'bun'] as const;
const SUBCOMMANDS = ['install', 'add', 'i'] as const;

function isPmName(token: string): boolean {
  return (PM_NAMES as ReadonlyArray<string>).includes(token);
}

function isSubcommand(token: string): boolean {
  return (SUBCOMMANDS as ReadonlyArray<string>).includes(token);
}

function extractFromTokens(tokens: Array<string>): {
  packages: Array<string>;
  dev: boolean;
} {
  const rest = tokens.slice(2);
  const packages = rest.filter((t) => !t.startsWith('-'));
  const dev = rest.some((t) => t === '-D' || t === '--save-dev');
  return { packages, dev };
}

export function resolveAddArgs(
  rawPackages: Array<string>,
  devFlag: boolean,
): { packages: Array<string>; dev: boolean } {
  const tokens =
    rawPackages.length === 1 && rawPackages[0].includes(' ')
      ? rawPackages[0].split(/\s+/)
      : rawPackages;

  const isPmCommand =
    tokens.length >= 2 && isPmName(tokens[0]) && isSubcommand(tokens[1]);

  if (!isPmCommand) {
    return { packages: rawPackages, dev: devFlag };
  }

  const extracted = extractFromTokens(tokens);

  if (extracted.packages.length === 0) {
    throw new Error(
      'No packages specified in pasted command. To install dependencies, use: pm i',
    );
  }

  return { packages: extracted.packages, dev: devFlag || extracted.dev };
}
Key insights:
  • Simple string splitting: Uses split(/\s+/) to tokenize
  • Negative filter: Packages are tokens that don’t start with -
  • Boolean flags: Checks for -D or --save-dev explicitly
  • Fall-through: If not a pasted command, returns args unchanged

Testing

You can test the parsing logic directly:
# These should all work:
pm add "npm install react"
pm add "pnpm add -D typescript" 
pm add "bun i zod @tanstack/react-query"

# These bypass parsing (normal usage):
pm add react
pm add -D typescript
pm add zod @tanstack/react-query
Check the output to see which command Better PM actually runs.