Core functions for package manager detection, command parsing, and programmatic execution. Perfect for build tools and development scripts that need package manager abstraction.
Detect the appropriate package manager based on lock files and project configuration.
/**
* Detect package manager from lock files and package.json
* @param options - Detection configuration options
* @returns Promise resolving to detected agent or undefined
*/
function detect(options?: DetectOptions): Promise<Agent | undefined>;
interface DetectOptions {
/** Automatically install missing package manager */
autoInstall?: boolean;
/** Running in programmatic mode (affects prompts and error handling) */
programmatic?: boolean;
/** Working directory to search for lock files */
cwd?: string;
/** Enable Volta wrapper detection (default: true) */
detectVolta?: boolean;
}Usage Examples:
import { detect } from "@antfu/ni";
// Basic detection
const agent = await detect();
console.log(agent); // 'npm' | 'yarn' | 'pnpm' | 'bun' | undefined
// Detection with options
const agent = await detect({
cwd: '/path/to/project',
programmatic: true,
autoInstall: false
});
// Auto-install missing package manager
const agent = await detect({
autoInstall: true,
programmatic: false
});Parse ni commands into package manager-specific commands.
/**
* Parse ni install command into agent-specific command
* @param agent - Target package manager
* @param args - Command arguments
* @param ctx - Execution context
* @returns Resolved command or undefined
*/
function parseNi(
agent: Agent,
args: string[],
ctx?: RunnerContext
): ResolvedCommand | undefined;
/**
* Parse nr run command into agent-specific command
* @param agent - Target package manager
* @param args - Command arguments
* @returns Resolved command or undefined
*/
function parseNr(agent: Agent, args: string[]): ResolvedCommand | undefined;
/**
* Parse nup upgrade command into agent-specific command
* @param agent - Target package manager
* @param args - Command arguments
* @returns Resolved command or undefined
*/
function parseNup(agent: Agent, args: string[]): ResolvedCommand | undefined;
/**
* Parse nun uninstall command into agent-specific command
* @param agent - Target package manager
* @param args - Command arguments
* @returns Resolved command or undefined
*/
function parseNun(agent: Agent, args: string[]): ResolvedCommand | undefined;
/**
* Parse nlx execute command into agent-specific command
* @param agent - Target package manager
* @param args - Command arguments
* @returns Resolved command or undefined
*/
function parseNlx(agent: Agent, args: string[]): ResolvedCommand | undefined;
/**
* Parse na agent command into agent-specific command
* @param agent - Target package manager
* @param args - Command arguments
* @returns Resolved command or undefined
*/
function parseNa(agent: Agent, args: string[]): ResolvedCommand | undefined;
interface RunnerContext {
/** Running in programmatic mode */
programmatic?: boolean;
/** Lock file is present */
hasLock?: boolean;
/** Working directory */
cwd?: string;
}
interface ResolvedCommand {
/** Command to execute */
command: string;
/** Command arguments */
args: string[];
}Usage Examples:
import { parseNi, parseNr, parseNup } from "@antfu/ni";
// Parse install commands
const installCmd = parseNi('npm', ['react', 'vue']);
console.log(installCmd); // { command: 'npm', args: ['install', 'react', 'vue'] }
const devInstallCmd = parseNi('pnpm', ['@types/node', '-D']);
console.log(devInstallCmd); // { command: 'pnpm', args: ['add', '-D', '@types/node'] }
// Parse run commands
const runCmd = parseNr('yarn', ['dev', '--port=3000']);
console.log(runCmd); // { command: 'yarn', args: ['run', 'dev', '--port=3000'] }
// Parse upgrade commands
const upgradeCmd = parseNup('bun', ['-i']);
console.log(upgradeCmd); // { command: 'bun', args: ['update'] } (interactive not supported for bun)Execute commands with full package manager detection and error handling.
/**
* Run CLI command with automatic agent detection
* @param fn - Runner function to execute
* @param options - Detection and execution options
*/
function runCli(
fn: Runner,
options?: DetectOptions & { args?: string[] }
): Promise<void>;
/**
* Get CLI command without executing
* @param fn - Runner function to process
* @param args - Command arguments
* @param options - Detection options
* @param cwd - Working directory
* @returns Promise resolving to resolved command
*/
function getCliCommand(
fn: Runner,
args: string[],
options?: DetectOptions,
cwd?: string
): Promise<ResolvedCommand | undefined>;
/**
* Execute command with package manager detection
* @param fn - Runner function to execute
* @param args - Command arguments
* @param options - Detection options
*/
function run(
fn: Runner,
args: string[],
options?: DetectOptions
): Promise<void>;
type Runner = (
agent: Agent,
args: string[],
ctx?: RunnerContext
) => Promise<ResolvedCommand | undefined> | ResolvedCommand | undefined;Usage Examples:
import { runCli, getCliCommand, parseNi, parseNr } from "@antfu/ni";
// Run install command programmatically
await runCli(parseNi, {
args: ['react', 'vue'],
programmatic: true,
cwd: '/path/to/project'
});
// Get command without executing
const command = await getCliCommand(parseNr, ['dev'], {
programmatic: true
});
console.log(command); // { command: 'npm', args: ['run', 'dev'] }
// Custom runner function
const customRunner = (agent, args) => {
if (args.includes('--custom')) {
return { command: agent, args: ['custom-command'] };
}
return parseNi(agent, args);
};
await runCli(customRunner, { args: ['--custom'] });Direct access to command construction and serialization.
/**
* Get resolved command for specific agent and command type
* @param agent - Target package manager
* @param command - Command type
* @param args - Command arguments
* @returns Resolved command
* @throws UnsupportedCommand if command not supported by agent
*/
function getCommand(
agent: Agent,
command: Command,
args?: string[]
): ResolvedCommand;
/**
* Serialize resolved command to string
* @param command - Command to serialize
* @returns Command string or undefined
*/
function serializeCommand(command?: ResolvedCommand): string | undefined;
class UnsupportedCommand extends Error {
constructor({ agent, command }: { agent: Agent; command: Command });
}Usage Examples:
import { getCommand, serializeCommand, UnsupportedCommand } from "@antfu/ni";
try {
// Get specific command
const cmd = getCommand('npm', 'install', ['react']);
console.log(cmd); // { command: 'npm', args: ['install', 'react'] }
// Serialize to string
const cmdStr = serializeCommand(cmd);
console.log(cmdStr); // "npm install react"
// Handle unsupported commands
const unsupportedCmd = getCommand('npm', 'upgrade-interactive', []);
} catch (error) {
if (error instanceof UnsupportedCommand) {
console.log('Command not supported by this agent');
}
}Helper functions for array manipulation, system checks, and formatting.
/**
* Remove element from array in-place
* @param arr - Array to modify
* @param v - Value to remove
* @returns Modified array
*/
function remove<T>(arr: T[], v: T): T[];
/**
* Create new array excluding specified values
* @param arr - Source array
* @param v - Values to exclude
* @returns New array without excluded values
*/
function exclude<T>(arr: T[], ...v: T[]): T[];
/**
* Check if command exists in system PATH
* @param cmd - Command name to check
* @returns True if command exists
*/
function cmdExists(cmd: string): boolean;
/**
* Write file safely with atomic operations
* @param path - File path
* @param data - File content
* @returns Promise resolving to success status
*/
function writeFileSafe(path: string, data?: string | Buffer): Promise<boolean>;
/**
* Limit text to maximum width with ellipsis
* @param text - Text to limit
* @param maxWidth - Maximum character width
* @returns Truncated text with ellipsis if needed
*/
function limitText(text: string, maxWidth: number): string;
/**
* Format package name with URL for terminal display
* @param pkg - Package name to format
* @param url - Optional URL to link to
* @param limits - Character limit for combined display
* @returns Formatted package string with terminal link
*/
function formatPackageWithUrl(pkg: string, url?: string, limits?: number): string;
/** Temporary directory path used by ni CLI operations */
const CLI_TEMP_DIR: string;Usage Examples:
import { remove, exclude, cmdExists, limitText } from "@antfu/ni";
// Array manipulation
const args = ['install', 'react', '-D', 'vue'];
remove(args, '-D'); // ['install', 'react', 'vue']
const filtered = exclude(args, 'install', '-D'); // ['react', 'vue']
// System checks
const hasYarn = cmdExists('yarn'); // true/false
const hasPnpm = cmdExists('pnpm'); // true/false
// Text utilities
const shortText = limitText('very long package description', 20); // "very long package..."Functions for interacting with the NPM registry for package search.
/**
* NPM package metadata structure
*/
interface NpmPackage {
name: string;
description: string;
version: string;
keywords: string[];
date: string;
links: {
npm: string;
homepage: string;
repository: string;
};
}
/**
* Fetch packages from NPM registry by search pattern
* @param pattern - Search pattern or package name
* @returns Promise resolving to choices for interactive selection
*/
function fetchNpmPackages(pattern: string): Promise<Choice[]>;Usage Examples:
import { fetchNpmPackages } from "@antfu/ni";
// Search for packages
const packages = await fetchNpmPackages('react');
console.log(packages.length); // ~35 packages
// Get package metadata
const firstPackage = packages[0].value as NpmPackage;
console.log(firstPackage.name); // Package name
console.log(firstPackage.description); // Package description
console.log(firstPackage.links.repository); // Repository URLFunctions for reading and parsing project files.
/**
* Read and parse package.json from project directory
* @param ctx - Optional runner context for directory and error handling
* @returns Parsed package.json object or undefined if not found
*/
function getPackageJSON(ctx?: RunnerContext): any;Usage Examples:
import { getPackageJSON } from "@antfu/ni";
// Read package.json from current directory
const pkg = getPackageJSON();
console.log(pkg?.name); // Package name
console.log(pkg?.scripts); // Available scripts
// Read from specific directory
const pkg = getPackageJSON({ cwd: '/path/to/project' });
console.log(pkg?.dependencies); // DependenciesFunctions for reading environment-based configuration options.
/**
* Environment configuration options
*/
interface EnvironmentOptions {
autoInstall: boolean;
}
/**
* Get environment-based configuration options
* @returns Environment options based on process.env
*/
function getEnvironmentOptions(): EnvironmentOptions;Usage Examples:
import { getEnvironmentOptions } from "@antfu/ni";
// Get current environment options
const envOptions = getEnvironmentOptions();
console.log(envOptions.autoInstall); // true if NI_AUTO_INSTALL=true
// Use in detection
const agent = await detect({
autoInstall: envOptions.autoInstall
});The programmatic API uses different error handling patterns:
import { UnsupportedCommand, runCli } from "@antfu/ni";
try {
await runCli(parseNi, {
args: ['invalid-package'],
programmatic: true // Throws errors instead of process.exit()
});
} catch (error) {
if (error instanceof UnsupportedCommand) {
console.error('Command not supported by detected package manager');
} else {
console.error('Execution failed:', error.message);
}
}When programmatic: true is set:
process.exit()