mirror of
https://github.com/affaan-m/everything-claude-code.git
synced 2026-02-16 03:13:08 +08:00
Bug fixes: - utils.js: prevent duplicate 'g' flag in countInFile regex construction - validate-agents.js: handle CRLF line endings in frontmatter parsing - validate-hooks.js: handle \t and \\ escape sequences in inline JS validation - session-aliases.js: prevent NaN in date sort when timestamps are missing - session-aliases.js: persist rollback on rename failure instead of silent loss - session-manager.js: require absolute paths in getSessionStats to prevent content strings ending with .tmp from being treated as file paths New tests (164 total, up from 97): - session-manager.test.js: 27 tests covering parseSessionFilename, parseSessionMetadata, getSessionStats, CRUD operations, getSessionSize, getSessionTitle, edge cases (null input, non-existent files, directories) - session-aliases.test.js: 40 tests covering loadAliases (corrupted JSON, invalid structure), setAlias (validation, reserved names), resolveAlias, listAliases (sort, search, limit), deleteAlias, renameAlias, updateAliasTitle, resolveSessionAlias, getAliasesForSession, cleanupAliases, atomic write Also includes hook-generated improvements: - utils.d.ts: document that readStdinJson never rejects - session-aliases.d.ts: fix updateAliasTitle type to accept null - package-manager.js: add try-catch to setProjectPackageManager writeFile
176 lines
5.5 KiB
TypeScript
176 lines
5.5 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, times out, or contains invalid JSON.
|
|
* Never rejects — safe to use without try-catch in hooks.
|
|
*/
|
|
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[];
|