Files
everything-claude-code/scripts/lib/utils.d.ts
Affaan Mustafa 9e791ed305 fix: harden utils.js edge cases and add input validation
- Guard findFiles() against null/undefined dir and pattern parameters
  (previously crashed with TypeError on .replace() or fs.existsSync())
- Wrap countInFile() and grepFile() regex construction in try-catch to
  handle invalid regex strings like '(unclosed' (previously crashed with
  SyntaxError: Invalid regular expression)
- Add try-catch to replaceInFile() with descriptive error logging
- Add 1MB size limit to readStdinJson() matching the PostToolUse hooks
  (previously had unbounded stdin accumulation)
- Improve ensureDir() error message to include the directory path
- Add 128-char length limit to setAlias() to prevent oversized alias
  names from inflating the JSON store
- Update utils.d.ts with new maxSize option on ReadStdinJsonOptions
2026-02-12 14:49:11 -08:00

175 lines
5.4 KiB
TypeScript

/**
* Cross-platform utility functions for Claude Code hooks and scripts.
* Works on Windows, macOS, and Linux.
*/
import type { ExecSyncOptions } from 'child_process';
// Platform detection
export const isWindows: boolean;
export const isMacOS: boolean;
export const isLinux: boolean;
// --- Directories ---
/** Get the user's home directory (cross-platform) */
export function getHomeDir(): string;
/** Get the Claude config directory (~/.claude) */
export function getClaudeDir(): string;
/** Get the sessions directory (~/.claude/sessions) */
export function getSessionsDir(): string;
/** Get the learned skills directory (~/.claude/skills/learned) */
export function getLearnedSkillsDir(): string;
/** Get the temp directory (cross-platform) */
export function getTempDir(): string;
/**
* Ensure a directory exists, creating it recursively if needed.
* Handles EEXIST race conditions from concurrent creation.
* @throws If directory cannot be created (e.g., permission denied)
*/
export function ensureDir(dirPath: string): string;
// --- Date/Time ---
/** Get current date in YYYY-MM-DD format */
export function getDateString(): string;
/** Get current time in HH:MM format */
export function getTimeString(): string;
/** Get current datetime in YYYY-MM-DD HH:MM:SS format */
export function getDateTimeString(): string;
// --- Session/Project ---
/**
* Get short session ID from CLAUDE_SESSION_ID environment variable.
* Returns last 8 characters, falls back to project name then the provided fallback.
*/
export function getSessionIdShort(fallback?: string): string;
/** Get the git repository name from the current working directory */
export function getGitRepoName(): string | null;
/** Get project name from git repo or current directory basename */
export function getProjectName(): string | null;
// --- File operations ---
export interface FileMatch {
/** Absolute path to the matching file */
path: string;
/** Modification time in milliseconds since epoch */
mtime: number;
}
export interface FindFilesOptions {
/** Maximum age in days. Only files modified within this many days are returned. */
maxAge?: number | null;
/** Whether to search subdirectories recursively */
recursive?: boolean;
}
/**
* Find files matching a glob-like pattern in a directory.
* Supports `*` (any chars), `?` (single char), and `.` (literal dot).
* Results are sorted by modification time (newest first).
*/
export function findFiles(dir: string, pattern: string, options?: FindFilesOptions): FileMatch[];
/**
* Read a text file safely. Returns null if the file doesn't exist or can't be read.
*/
export function readFile(filePath: string): string | null;
/** Write a text file, creating parent directories if needed */
export function writeFile(filePath: string, content: string): void;
/** Append to a text file, creating parent directories if needed */
export function appendFile(filePath: string, content: string): void;
/**
* Replace text in a file (cross-platform sed alternative).
* @returns true if the file was found and updated, false if file not found
*/
export function replaceInFile(filePath: string, search: string | RegExp, replace: string): boolean;
/**
* Count occurrences of a pattern in a file.
* The global flag is enforced automatically for correct counting.
*/
export function countInFile(filePath: string, pattern: string | RegExp): number;
export interface GrepMatch {
/** 1-based line number */
lineNumber: number;
/** Full content of the matching line */
content: string;
}
/** Search for a pattern in a file and return matching lines with line numbers */
export function grepFile(filePath: string, pattern: string | RegExp): GrepMatch[];
// --- Hook I/O ---
export interface ReadStdinJsonOptions {
/**
* Timeout in milliseconds. Prevents hooks from hanging indefinitely
* if stdin never closes. Default: 5000
*/
timeoutMs?: number;
/**
* Maximum stdin data size in bytes. Prevents unbounded memory growth.
* Default: 1048576 (1MB)
*/
maxSize?: number;
}
/**
* Read JSON from stdin (for hook input).
* Returns an empty object if stdin is empty or times out.
*/
export function readStdinJson(options?: ReadStdinJsonOptions): Promise<Record<string, unknown>>;
/** Log a message to stderr (visible to user in Claude Code terminal) */
export function log(message: string): void;
/** Output data to stdout (returned to Claude's context) */
export function output(data: string | Record<string, unknown>): void;
// --- System ---
/**
* Check if a command exists in PATH.
* Only allows alphanumeric, dash, underscore, and dot characters.
* WARNING: Spawns a child process (where.exe on Windows, which on Unix).
*/
export function commandExists(cmd: string): boolean;
export interface CommandResult {
success: boolean;
/** Trimmed stdout on success, stderr or error message on failure */
output: string;
}
/**
* Run a shell command and return the output.
* SECURITY: Only use with trusted, hardcoded commands.
* Never pass user-controlled input directly.
*/
export function runCommand(cmd: string, options?: ExecSyncOptions): CommandResult;
/** Check if the current directory is inside a git repository */
export function isGitRepo(): boolean;
/**
* Get git modified files (staged + unstaged), optionally filtered by regex patterns.
* Invalid regex patterns are silently skipped.
*/
export function getGitModifiedFiles(patterns?: string[]): string[];