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 🙏

© 2025 – Pkg Stats / Ryan Hefner

@vibe-validate/utils

v0.18.1

Published

Common utilities for vibe-validate packages (command execution, path normalization)

Readme

@vibe-validate/utils

Common utilities for vibe-validate packages - the foundational package with NO dependencies on other vibe-validate packages.

Purpose

@vibe-validate/utils provides generic, non-domain-specific utilities used across multiple vibe-validate packages. It serves as the foundation layer that other packages can depend on without creating circular dependencies.

When to Use

Use @vibe-validate/utils for:

  • Security-critical command execution (safeExec*) - When you need to spawn processes safely without shell injection vulnerabilities
  • Cross-platform path normalization - When working with Windows 8.3 short names that cause path mismatches
  • Generic utilities - Functionality needed by multiple packages that doesn't belong to a specific domain

When NOT to Use

DO NOT use @vibe-validate/utils for:

  • Domain-specific utilities - Use the appropriate domain package instead:

    • Git utilities → @vibe-validate/git
    • Config utilities → @vibe-validate/config
    • Extractor utilities → @vibe-validate/extractors
    • Validation utilities → @vibe-validate/core
  • Test utilities - Keep test-specific mocks/helpers in each package's test/helpers/ directory

Installation

# Production dependency
pnpm add @vibe-validate/utils

# Development dependency (for tests)
pnpm add -D @vibe-validate/utils

API Reference

Safe Command Execution

Secure command execution using spawnSync + which pattern. Prevents command injection by:

  • Resolving PATH once using pure Node.js (which package)
  • Executing with absolute path and shell: false (except Windows-specific cases)
  • No shell interpreter = no command injection risk

safeExecSync(command, args?, options?): Buffer | string

Execute a command synchronously and return output (throws on error).

Parameters:

  • command (string) - Command name (e.g., 'git', 'node', 'pnpm')
  • args (string[]) - Array of arguments
  • options (SafeExecOptions) - Execution options

Returns: Buffer (default) or string (if encoding specified)

Example:

import { safeExecSync } from '@vibe-validate/utils';

// Get output as Buffer
const versionBuffer = safeExecSync('node', ['--version']);

// Get output as string
const version = safeExecSync('node', ['--version'], { encoding: 'utf8' });

// Custom environment variables
safeExecSync('git', ['add', '--all'], {
  env: { ...process.env, GIT_INDEX_FILE: tempFile }
});

safeExecResult(command, args?, options?): SafeExecResult

Execute a command and return detailed result (doesn't throw on error).

Use this when you need to handle errors programmatically.

Returns:

{
  status: number;        // Exit code (0 = success)
  stdout: Buffer | string;
  stderr: Buffer | string;
  error?: Error;         // If command failed to spawn
}

Example:

import { safeExecResult } from '@vibe-validate/utils';

const result = safeExecResult('git', ['status']);
if (result.status === 0) {
  console.log(result.stdout.toString());
} else {
  console.error(`Failed: ${result.stderr.toString()}`);
}

safeExecFromString(commandString, options?): Buffer | string

Execute a command from a command string (convenience wrapper).

WARNING: This function parses command strings using simple whitespace splitting. It does NOT handle shell quoting, escaping, or complex command syntax. Use only for simple commands.

Example:

import { safeExecFromString } from '@vibe-validate/utils';

// ✅ Simple command
safeExecFromString('git status --short');

// ❌ Complex shell features won't work
// Use safeExecSync() with explicit args array instead

isToolAvailable(toolName): boolean

Check if a command-line tool is available.

Example:

import { isToolAvailable } from '@vibe-validate/utils';

if (isToolAvailable('gh')) {
  console.log('GitHub CLI is installed');
}

getToolVersion(toolName, versionArg?): string | null

Get tool version if available.

Parameters:

  • toolName (string) - Tool name (e.g., 'node', 'pnpm')
  • versionArg (string) - Version argument (default: '--version')

Returns: Version string or null if not available

Example:

import { getToolVersion } from '@vibe-validate/utils';

const nodeVersion = getToolVersion('node');
console.log(nodeVersion); // "v20.11.0"

const gitVersion = getToolVersion('git', 'version');
console.log(gitVersion); // "git version 2.39.2"

CommandExecutionError

Error thrown when command execution fails (extends Error).

Properties:

  • status (number) - Exit code
  • stdout (Buffer | string) - Standard output
  • stderr (Buffer | string) - Standard error

Cross-Platform Path Helpers

Windows-safe path utilities that handle 8.3 short names (e.g., RUNNER~1). These prevent "works on Mac, fails on Windows CI" bugs.

normalizedTmpdir(): string

Get normalized temp directory path.

On Windows, tmpdir() may return 8.3 short names like C:\Users\RUNNER~1\AppData\Local\Temp. This function returns the real (long) path.

Why this matters:

  • Node.js operations create directories with LONG names
  • Tests using SHORT paths from tmpdir() will fail existsSync() checks

Example:

import { normalizedTmpdir } from '@vibe-validate/utils';
import { join } from 'node:path';

// ❌ WRONG - May return short path on Windows
const testDir = join(tmpdir(), 'test-dir');

// ✅ RIGHT - Always returns real path
const testDir = join(normalizedTmpdir(), 'test-dir');

mkdirSyncReal(path, options?): string

Create directory and return normalized path.

Combines mkdirSync + realpathSync to ensure the returned path matches the actual filesystem path (resolves Windows short names).

Example:

import { mkdirSyncReal, normalizedTmpdir } from '@vibe-validate/utils';
import { join } from 'node:path';

// ✅ RIGHT - Normalized path guaranteed
const testDir = mkdirSyncReal(
  join(normalizedTmpdir(), 'test-dir'),
  { recursive: true }
);
// testDir is now: C:\Users\runneradmin\...\test-dir (real path)

normalizePath(path): string

Normalize any path (resolve short names on Windows).

Utility to normalize paths without creating directories. Useful when you have an existing path that might contain short names.

Example:

import { normalizePath } from '@vibe-validate/utils';

const shortPath = 'C:\\PROGRA~1\\nodejs';
const longPath = normalizePath(shortPath);
// Result: 'C:\\Program Files\\nodejs'

Security

Command Injection Prevention

All safeExec* functions prevent command injection by:

  1. No shell interpreter - Uses spawnSync with shell: false (except Windows-specific cases)
  2. Arguments as array - Never string interpolation
  3. PATH resolution via which - Resolved before execution, not during

This is more secure than execSync() which uses shell by default.

Example of safe execution:

import { safeExecSync } from '@vibe-validate/utils';

// Malicious input is treated as literal argument, not executed
const maliciousArg = '; rm -rf / #';
const result = safeExecSync('echo', [maliciousArg], { encoding: 'utf8' });
// Output: "; rm -rf / #" (literal string, not executed)

Development

# Build
pnpm build

# Test
pnpm test

# Watch mode
pnpm test:watch

License

MIT