feat: add TypeScript declaration files for all core libraries

Add .d.ts type definitions for all four library modules:
- utils.d.ts: Platform detection, file ops, hook I/O, git helpers
- package-manager.d.ts: PM detection with PackageManagerName union type,
  DetectionSource union, and typed config interfaces
- session-manager.d.ts: Session CRUD with Session, SessionMetadata,
  SessionStats, and SessionListResult interfaces
- session-aliases.d.ts: Alias management with typed result interfaces
  for set, delete, rename, and cleanup operations

These provide IDE autocomplete and type-checking for TypeScript
consumers of the npm package without converting the source to TS.
This commit is contained in:
Affaan Mustafa
2026-02-12 13:56:48 -08:00
parent b7519cb545
commit be0ba0cabc
4 changed files with 554 additions and 0 deletions

119
scripts/lib/package-manager.d.ts vendored Normal file
View File

@@ -0,0 +1,119 @@
/**
* Package Manager Detection and Selection.
* Supports: npm, pnpm, yarn, bun.
*/
/** Supported package manager names */
export type PackageManagerName = 'npm' | 'pnpm' | 'yarn' | 'bun';
/** Configuration for a single package manager */
export interface PackageManagerConfig {
name: PackageManagerName;
/** Lock file name (e.g., "package-lock.json", "pnpm-lock.yaml") */
lockFile: string;
/** Install command (e.g., "npm install") */
installCmd: string;
/** Run script command prefix (e.g., "npm run", "pnpm") */
runCmd: string;
/** Execute binary command (e.g., "npx", "pnpm dlx") */
execCmd: string;
/** Test command (e.g., "npm test") */
testCmd: string;
/** Build command (e.g., "npm run build") */
buildCmd: string;
/** Dev server command (e.g., "npm run dev") */
devCmd: string;
}
/** How the package manager was detected */
export type DetectionSource =
| 'environment'
| 'project-config'
| 'package.json'
| 'lock-file'
| 'global-config'
| 'default';
/** Result from getPackageManager() */
export interface PackageManagerResult {
name: PackageManagerName;
config: PackageManagerConfig;
source: DetectionSource;
}
/** Map of all supported package managers keyed by name */
export const PACKAGE_MANAGERS: Record<PackageManagerName, PackageManagerConfig>;
/** Priority order for lock file detection */
export const DETECTION_PRIORITY: PackageManagerName[];
export interface GetPackageManagerOptions {
/** Project directory to detect from (default: process.cwd()) */
projectDir?: string;
}
/**
* Get the package manager to use for the current project.
*
* Detection priority:
* 1. CLAUDE_PACKAGE_MANAGER environment variable
* 2. Project-specific config (.claude/package-manager.json)
* 3. package.json `packageManager` field
* 4. Lock file detection
* 5. Global user preference (~/.claude/package-manager.json)
* 6. Default to npm (no child processes spawned)
*/
export function getPackageManager(options?: GetPackageManagerOptions): PackageManagerResult;
/**
* Set the user's globally preferred package manager.
* Saves to ~/.claude/package-manager.json.
* @throws If pmName is not a known package manager
*/
export function setPreferredPackageManager(pmName: PackageManagerName): { packageManager: string; setAt: string };
/**
* Set a project-specific preferred package manager.
* Saves to <projectDir>/.claude/package-manager.json.
* @throws If pmName is not a known package manager
*/
export function setProjectPackageManager(pmName: PackageManagerName, projectDir?: string): { packageManager: string; setAt: string };
/**
* Get package managers installed on the system.
* WARNING: Spawns child processes for each PM check.
* Do NOT call during session startup hooks.
*/
export function getAvailablePackageManagers(): PackageManagerName[];
/** Detect package manager from lock file in the given directory */
export function detectFromLockFile(projectDir?: string): PackageManagerName | null;
/** Detect package manager from package.json `packageManager` field */
export function detectFromPackageJson(projectDir?: string): PackageManagerName | null;
/**
* Get the full command string to run a script.
* @param script - Script name: "install", "test", "build", "dev", or custom
*/
export function getRunCommand(script: string, options?: GetPackageManagerOptions): string;
/**
* Get the full command string to execute a package binary.
* @param binary - Binary name (e.g., "prettier", "eslint")
* @param args - Arguments to pass to the binary
*/
export function getExecCommand(binary: string, args?: string, options?: GetPackageManagerOptions): string;
/**
* Get a message prompting the user to configure their package manager.
* Does NOT spawn child processes.
*/
export function getSelectionPrompt(): string;
/**
* Generate a regex pattern string that matches commands for all package managers.
* @param action - Action like "dev", "install", "test", "build", or custom
* @returns Parenthesized alternation regex string, e.g., "(npm run dev|pnpm( run)? dev|...)"
*/
export function getCommandPattern(action: string): string;

136
scripts/lib/session-aliases.d.ts vendored Normal file
View File

@@ -0,0 +1,136 @@
/**
* Session Aliases Library for Claude Code.
* Manages named aliases for session files, stored in ~/.claude/session-aliases.json.
*/
/** Internal alias storage entry */
export interface AliasEntry {
sessionPath: string;
createdAt: string;
updatedAt?: string;
title: string | null;
}
/** Alias data structure stored on disk */
export interface AliasStore {
version: string;
aliases: Record<string, AliasEntry>;
metadata: {
totalCount: number;
lastUpdated: string;
};
}
/** Resolved alias information returned by resolveAlias */
export interface ResolvedAlias {
alias: string;
sessionPath: string;
createdAt: string;
title: string | null;
}
/** Alias entry returned by listAliases */
export interface AliasListItem {
name: string;
sessionPath: string;
createdAt: string;
updatedAt?: string;
title: string | null;
}
/** Result from mutation operations (set, delete, rename, update, cleanup) */
export interface AliasResult {
success: boolean;
error?: string;
[key: string]: unknown;
}
export interface SetAliasResult extends AliasResult {
isNew?: boolean;
alias?: string;
sessionPath?: string;
title?: string | null;
}
export interface DeleteAliasResult extends AliasResult {
alias?: string;
deletedSessionPath?: string;
}
export interface RenameAliasResult extends AliasResult {
oldAlias?: string;
newAlias?: string;
sessionPath?: string;
}
export interface CleanupResult {
totalChecked: number;
removed: number;
removedAliases: Array<{ name: string; sessionPath: string }>;
error?: string;
}
export interface ListAliasesOptions {
/** Filter aliases by name or title (partial match, case-insensitive) */
search?: string | null;
/** Maximum number of aliases to return */
limit?: number | null;
}
/** Get the path to the aliases JSON file */
export function getAliasesPath(): string;
/** Load all aliases from disk. Returns default structure if file doesn't exist. */
export function loadAliases(): AliasStore;
/**
* Save aliases to disk with atomic write (temp file + rename).
* Creates backup before writing; restores on failure.
*/
export function saveAliases(aliases: AliasStore): boolean;
/**
* Resolve an alias name to its session data.
* @returns Alias data, or null if not found or invalid name
*/
export function resolveAlias(alias: string): ResolvedAlias | null;
/**
* Create or update an alias for a session.
* Alias names must be alphanumeric with dashes/underscores.
* Reserved names (list, help, remove, delete, create, set) are rejected.
*/
export function setAlias(alias: string, sessionPath: string, title?: string | null): SetAliasResult;
/**
* List all aliases, optionally filtered and limited.
* Results are sorted by updated time (newest first).
*/
export function listAliases(options?: ListAliasesOptions): AliasListItem[];
/** Delete an alias by name */
export function deleteAlias(alias: string): DeleteAliasResult;
/**
* Rename an alias. Fails if old alias doesn't exist or new alias already exists.
* New alias name must be alphanumeric with dashes/underscores.
*/
export function renameAlias(oldAlias: string, newAlias: string): RenameAliasResult;
/**
* Resolve an alias or pass through a session path.
* First tries to resolve as alias; if not found, returns the input as-is.
*/
export function resolveSessionAlias(aliasOrId: string): string;
/** Update the title of an existing alias */
export function updateAliasTitle(alias: string, title: string): AliasResult;
/** Get all aliases that point to a specific session path */
export function getAliasesForSession(sessionPath: string): Array<{ name: string; createdAt: string; title: string | null }>;
/**
* Remove aliases whose sessions no longer exist.
* @param sessionExists - Function that returns true if a session path is valid
*/
export function cleanupAliases(sessionExists: (sessionPath: string) => boolean): CleanupResult;

130
scripts/lib/session-manager.d.ts vendored Normal file
View File

@@ -0,0 +1,130 @@
/**
* Session Manager Library for Claude Code.
* Provides CRUD operations for session files stored as markdown in ~/.claude/sessions/.
*/
/** Parsed metadata from a session filename */
export interface SessionFilenameMeta {
/** Original filename */
filename: string;
/** Short ID extracted from filename, or "no-id" for old format */
shortId: string;
/** Date string in YYYY-MM-DD format */
date: string;
/** Parsed Date object from the date string */
datetime: Date;
}
/** Metadata parsed from session markdown content */
export interface SessionMetadata {
title: string | null;
date: string | null;
started: string | null;
lastUpdated: string | null;
completed: string[];
inProgress: string[];
notes: string;
context: string;
}
/** Statistics computed from session content */
export interface SessionStats {
totalItems: number;
completedItems: number;
inProgressItems: number;
lineCount: number;
hasNotes: boolean;
hasContext: boolean;
}
/** A session object returned by getAllSessions and getSessionById */
export interface Session extends SessionFilenameMeta {
/** Full filesystem path to the session file */
sessionPath: string;
/** Whether the file has any content */
hasContent?: boolean;
/** File size in bytes */
size: number;
/** Last modification time */
modifiedTime: Date;
/** File creation time (falls back to ctime on Linux) */
createdTime: Date;
/** Session markdown content (only when includeContent=true) */
content?: string | null;
/** Parsed metadata (only when includeContent=true) */
metadata?: SessionMetadata;
/** Session statistics (only when includeContent=true) */
stats?: SessionStats;
}
/** Pagination result from getAllSessions */
export interface SessionListResult {
sessions: Session[];
total: number;
offset: number;
limit: number;
hasMore: boolean;
}
export interface GetAllSessionsOptions {
/** Maximum number of sessions to return (default: 50) */
limit?: number;
/** Number of sessions to skip (default: 0) */
offset?: number;
/** Filter by date in YYYY-MM-DD format */
date?: string | null;
/** Search in short ID */
search?: string | null;
}
/**
* Parse a session filename to extract date and short ID.
* @returns Parsed metadata, or null if the filename doesn't match the expected pattern
*/
export function parseSessionFilename(filename: string): SessionFilenameMeta | null;
/** Get the full filesystem path for a session filename */
export function getSessionPath(filename: string): string;
/**
* Read session markdown content from disk.
* @returns Content string, or null if the file doesn't exist
*/
export function getSessionContent(sessionPath: string): string | null;
/** Parse session metadata from markdown content */
export function parseSessionMetadata(content: string | null): SessionMetadata;
/**
* Calculate statistics for a session.
* Accepts either a file path (ending in .tmp) or pre-read content string.
*/
export function getSessionStats(sessionPathOrContent: string): SessionStats;
/** Get the title from a session file, or "Untitled Session" if none */
export function getSessionTitle(sessionPath: string): string;
/** Get human-readable file size (e.g., "1.2 KB") */
export function getSessionSize(sessionPath: string): string;
/** Get all sessions with optional filtering and pagination */
export function getAllSessions(options?: GetAllSessionsOptions): SessionListResult;
/**
* Find a session by short ID or filename.
* @param sessionId - Short ID prefix, full filename, or filename without .tmp
* @param includeContent - Whether to read and parse the session content
*/
export function getSessionById(sessionId: string, includeContent?: boolean): Session | null;
/** Write markdown content to a session file */
export function writeSessionContent(sessionPath: string, content: string): boolean;
/** Append content to an existing session file */
export function appendSessionContent(sessionPath: string, content: string): boolean;
/** Delete a session file */
export function deleteSession(sessionPath: string): boolean;
/** Check if a session file exists and is a regular file */
export function sessionExists(sessionPath: string): boolean;

169
scripts/lib/utils.d.ts vendored Normal file
View File

@@ -0,0 +1,169 @@
/**
* 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;
}
/**
* 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[];