jay-code
Version:
Streamlined AI CLI orchestration engine with mathematical rigor and enterprise-grade reliability
580 lines (500 loc) • 13.3 kB
text/typescript
/**
* Utility helper functions for Jay-Code
*/
import { promisify } from 'util';
import { exec } from 'child_process';
// Utility helper functions
/**
* Executes a command asynchronously and returns the result
*/
export const execAsync = promisify(exec);
/**
* Simple calculator function that adds two numbers
*/
export function add(a: number, b: number): number {
return a + b;
}
/**
* Simple hello world function
*/
export function helloWorld(): string {
return 'Hello, World!';
}
/**
* Generates a unique identifier
*/
export function generateId(prefix?: string): string {
const timestamp = Date.now().toString(36);
const random = Math.random().toString(36).substr(2, 9);
return prefix ? `${prefix}_${timestamp}_${random}` : `${timestamp}_${random}`;
}
/**
* Creates a timeout promise that rejects after the specified time
*/
export function timeout<T>(promise: Promise<T>, ms: number, message?: string): Promise<T> {
let timeoutId: ReturnType<typeof setTimeout> | undefined;
let completed = false;
const timeoutPromise = new Promise<never>((_, reject) => {
timeoutId = setTimeout(() => {
if (!completed) {
completed = true;
reject(new Error(message || 'Operation timed out'));
}
}, ms);
});
const wrappedPromise = promise.then(
(result) => {
completed = true;
if (timeoutId !== undefined) {
clearTimeout(timeoutId);
}
return result;
},
(error) => {
completed = true;
if (timeoutId !== undefined) {
clearTimeout(timeoutId);
}
throw error;
},
);
return Promise.race([wrappedPromise, timeoutPromise]);
}
/**
* Delays execution for specified milliseconds
*/
export function delay(ms: number): Promise<void> {
return new Promise((resolve) => setTimeout(resolve, ms));
}
/**
* Retries a function with exponential backoff
*/
export async function retry<T>(
fn: () => Promise<T>,
options: {
maxAttempts?: number;
initialDelay?: number;
maxDelay?: number;
factor?: number;
onRetry?: (attempt: number, error: Error) => void;
} = {},
): Promise<T> {
const { maxAttempts = 3, initialDelay = 1000, maxDelay = 30000, factor = 2, onRetry } = options;
let lastError: Error;
let delayMs = initialDelay;
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
try {
return await fn();
} catch (error) {
lastError = error instanceof Error ? error : new Error(String(error));
if (attempt === maxAttempts) {
throw lastError;
}
if (onRetry) {
onRetry(attempt, lastError);
}
await delay(Math.min(delayMs, maxDelay));
delayMs *= factor;
}
}
throw lastError!;
}
/**
* Debounces a function
*/
export function debounce<T extends (...args: unknown[]) => unknown>(
fn: T,
delayMs: number,
): (...args: Parameters<T>) => void {
let timeoutId: ReturnType<typeof setTimeout> | undefined;
return (...args: Parameters<T>) => {
if (timeoutId !== undefined) {
clearTimeout(timeoutId);
}
timeoutId = setTimeout(() => {
fn(...args);
timeoutId = undefined;
}, delayMs);
};
}
/**
* Throttles a function
*/
export function throttle<T extends (...args: unknown[]) => unknown>(
fn: T,
limitMs: number,
): (...args: Parameters<T>) => void {
let inThrottle = false;
let lastArgs: Parameters<T> | null = null;
return (...args: Parameters<T>) => {
if (!inThrottle) {
fn(...args);
inThrottle = true;
setTimeout(() => {
inThrottle = false;
if (lastArgs !== null) {
fn(...lastArgs);
lastArgs = null;
}
}, limitMs);
} else {
lastArgs = args;
}
};
}
/**
* Deep clones an object
*/
export function deepClone<T>(obj: T): T {
if (obj === null || typeof obj !== 'object') {
return obj;
}
if (obj instanceof Date) {
return new Date(obj.getTime()) as T;
}
if (obj instanceof Array) {
return obj.map((item) => deepClone(item)) as T;
}
if (obj instanceof Map) {
const map = new Map();
obj.forEach((value, key) => {
map.set(key, deepClone(value));
});
return map as T;
}
if (obj instanceof Set) {
const set = new Set();
obj.forEach((value) => {
set.add(deepClone(value));
});
return set as T;
}
const cloned = {} as T;
for (const key in obj) {
if (Object.prototype.hasOwnProperty.call(obj, key)) {
cloned[key] = deepClone(obj[key]);
}
}
return cloned;
}
/**
* Merges multiple objects deeply
*/
export function deepMerge<T extends Record<string, unknown>>(
target: T,
...sources: Partial<T>[]
): T {
// Create a deep clone of the target to avoid mutation
const result = deepClone(target);
if (!sources.length) return result;
const source = sources.shift();
if (!source) return result;
for (const key in source) {
if (Object.prototype.hasOwnProperty.call(source, key)) {
const sourceValue = source[key];
const resultValue = result[key];
if (isObject(resultValue) && isObject(sourceValue)) {
result[key] = deepMerge(
resultValue as Record<string, unknown>,
sourceValue as Record<string, unknown>,
) as T[Extract<keyof T, string>];
} else {
result[key] = sourceValue as T[Extract<keyof T, string>];
}
}
}
return deepMerge(result, ...sources);
}
/**
* Checks if a value is a plain object
*/
function isObject(value: unknown): value is Record<string, unknown> {
return value !== null && typeof value === 'object' && !Array.isArray(value);
}
/**
* Creates a typed event emitter
*/
export class TypedEventEmitter<T extends Record<string, unknown>> {
private listeners = new Map<keyof T, Set<(data: unknown) => void>>();
on<K extends keyof T>(event: K, handler: (data: T[K]) => void): void {
if (!this.listeners.has(event)) {
this.listeners.set(event, new Set());
}
this.listeners.get(event)!.add(handler as (data: unknown) => void);
}
off<K extends keyof T>(event: K, handler: (data: T[K]) => void): void {
const handlers = this.listeners.get(event);
if (handlers) {
handlers.delete(handler as (data: unknown) => void);
}
}
emit<K extends keyof T>(event: K, data: T[K]): void {
const handlers = this.listeners.get(event);
if (handlers) {
handlers.forEach((handler) => handler(data));
}
}
once<K extends keyof T>(event: K, handler: (data: T[K]) => void): void {
const onceHandler = (data: T[K]) => {
handler(data);
this.off(event, onceHandler);
};
this.on(event, onceHandler);
}
removeAllListeners(event?: keyof T): void {
if (event) {
this.listeners.delete(event);
} else {
this.listeners.clear();
}
}
}
/**
* Formats bytes to human-readable string
*/
export function formatBytes(bytes: number, decimals = 2): string {
if (bytes === 0) return '0 Bytes';
const k = 1024;
const dm = decimals < 0 ? 0 : decimals;
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
// Handle negative numbers
const absBytes = Math.abs(bytes);
const i = Math.floor(Math.log(absBytes) / Math.log(k));
const value = parseFloat((absBytes / Math.pow(k, i)).toFixed(dm));
const sign = bytes < 0 ? '-' : '';
return sign + value + ' ' + sizes[i];
}
/**
* Parses duration string to milliseconds
*/
export function parseDuration(duration: string): number {
const match = duration.match(/^(\d+)(ms|s|m|h|d)$/);
if (!match) {
throw new Error(`Invalid duration format: ${duration}`);
}
const value = parseInt(match[1], 10);
const unit = match[2];
switch (unit) {
case 'ms':
return value;
case 's':
return value * 1000;
case 'm':
return value * 60 * 1000;
case 'h':
return value * 60 * 60 * 1000;
case 'd':
return value * 24 * 60 * 60 * 1000;
default:
throw new Error(`Unknown duration unit: ${unit}`);
}
}
/**
* Ensures a value is an array
*/
export function ensureArray<T>(value: T | T[]): T[] {
return Array.isArray(value) ? value : [value];
}
/**
* Groups an array by a key function
*/
export function groupBy<T, K extends string | number | symbol>(
items: T[],
keyFn: (item: T) => K,
): Record<K, T[]> {
return items.reduce(
(groups, item) => {
const key = keyFn(item);
if (!groups[key]) {
groups[key] = [];
}
groups[key].push(item);
return groups;
},
{} as Record<K, T[]>,
);
}
/**
* Creates a promise that can be resolved/rejected externally
*/
export function createDeferred<T>(): {
promise: Promise<T>;
resolve: (value: T) => void;
reject: (reason?: unknown) => void;
} {
let resolve: (value: T) => void;
let reject: (reason?: unknown) => void;
const promise = new Promise<T>((res, rej) => {
resolve = res;
reject = rej;
});
return { promise, resolve: resolve!, reject: reject! };
}
/**
* Safely parses JSON with error handling
*/
export function safeParseJSON<T>(json: string, fallback?: T): T | undefined {
try {
return JSON.parse(json) as T;
} catch {
return fallback;
}
}
/**
* Circuit breaker state
*/
export interface CircuitBreakerState {
failureCount: number;
lastFailureTime: number;
state: 'closed' | 'open' | 'half-open';
}
/**
* Circuit breaker options
*/
export interface CircuitBreakerOptions {
threshold: number;
timeout: number;
resetTimeout: number;
}
/**
* Circuit breaker interface
*/
export interface CircuitBreaker {
execute<T>(fn: () => Promise<T>): Promise<T>;
getState(): CircuitBreakerState;
reset(): void;
}
/**
* Simple calculator function with basic operations
*/
export function calculator(
a: number,
b: number,
operation: '+' | '-' | '*' | '/' | '^' | '%',
): number {
switch (operation) {
case '+':
return a + b;
case '-':
return a - b;
case '*':
return a * b;
case '/':
if (b === 0) {
throw new Error('Division by zero');
}
return a / b;
case '^':
return Math.pow(a, b);
case '%':
if (b === 0) {
throw new Error('Modulo by zero');
}
return a % b;
default:
throw new Error(`Invalid operation: ${operation}`);
}
}
/**
* Creates a circuit breaker
*/
export function circuitBreaker(name: string, options: CircuitBreakerOptions): CircuitBreaker {
const state: CircuitBreakerState = {
failureCount: 0,
lastFailureTime: 0,
state: 'closed',
};
const isOpen = (): boolean => {
if (state.state === 'open') {
const now = Date.now();
if (now - state.lastFailureTime >= options.resetTimeout) {
state.state = 'half-open';
return false;
}
return true;
}
return false;
};
const recordSuccess = (): void => {
state.failureCount = 0;
state.state = 'closed';
};
const recordFailure = (): void => {
state.failureCount++;
state.lastFailureTime = Date.now();
if (state.failureCount >= options.threshold) {
state.state = 'open';
}
};
return {
async execute<T>(fn: () => Promise<T>): Promise<T> {
if (isOpen()) {
throw new Error(`Circuit breaker ${name} is open`);
}
try {
const result = await timeout(fn(), options.timeout);
recordSuccess();
return result;
} catch (error) {
recordFailure();
throw error;
}
},
getState(): CircuitBreakerState {
return { ...state };
},
reset(): void {
state.failureCount = 0;
state.lastFailureTime = 0;
state.state = 'closed';
},
};
}
/**
* Greeting function that returns a personalized greeting
*/
export function greeting(
name?: string,
options?: {
timeOfDay?: boolean;
formal?: boolean;
locale?: 'en' | 'es' | 'fr' | 'de' | 'it' | 'pt' | 'ja' | 'zh';
},
): string {
const opts = {
timeOfDay: false,
formal: false,
locale: 'en' as const,
...options,
};
// Determine time-based greeting
const getTimeGreeting = (): string => {
const hour = new Date().getHours();
if (hour < 12) return 'Good morning';
if (hour < 17) return 'Good afternoon';
if (hour < 21) return 'Good evening';
return 'Good night';
};
// Get greeting by locale
const getLocaleGreeting = (): string => {
const greetings: Record<string, { informal: string; formal: string }> = {
en: { informal: 'Hello', formal: 'Greetings' },
es: { informal: 'Hola', formal: 'Saludos' },
fr: { informal: 'Salut', formal: 'Bonjour' },
de: { informal: 'Hallo', formal: 'Guten Tag' },
it: { informal: 'Ciao', formal: 'Salve' },
pt: { informal: 'Olá', formal: 'Saudações' },
ja: { informal: 'こんにちは', formal: 'ご挨拶' },
zh: { informal: '你好', formal: '您好' },
};
const localeGreeting = greetings[opts.locale] || greetings.en;
return opts.formal ? localeGreeting.formal : localeGreeting.informal;
};
// Build the greeting
let greetingText = opts.timeOfDay ? getTimeGreeting() : getLocaleGreeting();
if (name) {
greetingText += `, ${name}`;
}
greetingText += '!';
return greetingText;
}