claude-flow-tbowman01
Version:
Enterprise-grade AI agent orchestration with ruv-swarm integration (Alpha Release)
447 lines • 12 kB
JavaScript
/**
* Utility helper functions for Claude-Flow
*/
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, b) {
return a + b;
}
/**
* Simple hello world function
*/
export function helloWorld() {
return "Hello, World!";
}
/**
* Generates a unique identifier
*/
export function generateId(prefix) {
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(promise, ms, message) {
let timeoutId;
let completed = false;
const timeoutPromise = new Promise((_, 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) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
/**
* Retries a function with exponential backoff
*/
export async function retry(fn, options = {}) {
const { maxAttempts = 3, initialDelay = 1000, maxDelay = 30000, factor = 2, onRetry, } = options;
let lastError;
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(fn, delayMs) {
let timeoutId;
return (...args) => {
if (timeoutId !== undefined) {
clearTimeout(timeoutId);
}
timeoutId = setTimeout(() => {
fn(...args);
timeoutId = undefined;
}, delayMs);
};
}
/**
* Throttles a function
*/
export function throttle(fn, limitMs) {
let inThrottle = false;
let lastArgs = null;
return (...args) => {
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(obj) {
if (obj === null || typeof obj !== 'object') {
return obj;
}
if (obj instanceof Date) {
return new Date(obj.getTime());
}
if (obj instanceof Array) {
return obj.map((item) => deepClone(item));
}
if (obj instanceof Map) {
const map = new Map();
obj.forEach((value, key) => {
map.set(key, deepClone(value));
});
return map;
}
if (obj instanceof Set) {
const set = new Set();
obj.forEach((value) => {
set.add(deepClone(value));
});
return set;
}
const cloned = {};
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(target, ...sources) {
// 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, sourceValue);
}
else {
result[key] = sourceValue;
}
}
}
return deepMerge(result, ...sources);
}
/**
* Checks if a value is a plain object
*/
function isObject(value) {
return value !== null && typeof value === 'object' && !Array.isArray(value);
}
/**
* Creates a typed event emitter
*/
export class TypedEventEmitter {
listeners = new Map();
on(event, handler) {
if (!this.listeners.has(event)) {
this.listeners.set(event, new Set());
}
this.listeners.get(event).add(handler);
}
off(event, handler) {
const handlers = this.listeners.get(event);
if (handlers) {
handlers.delete(handler);
}
}
emit(event, data) {
const handlers = this.listeners.get(event);
if (handlers) {
handlers.forEach((handler) => handler(data));
}
}
once(event, handler) {
const onceHandler = (data) => {
handler(data);
this.off(event, onceHandler);
};
this.on(event, onceHandler);
}
removeAllListeners(event) {
if (event) {
this.listeners.delete(event);
}
else {
this.listeners.clear();
}
}
}
/**
* Formats bytes to human-readable string
*/
export function formatBytes(bytes, decimals = 2) {
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) {
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(value) {
return Array.isArray(value) ? value : [value];
}
/**
* Groups an array by a key function
*/
export function groupBy(items, keyFn) {
return items.reduce((groups, item) => {
const key = keyFn(item);
if (!groups[key]) {
groups[key] = [];
}
groups[key].push(item);
return groups;
}, {});
}
/**
* Creates a promise that can be resolved/rejected externally
*/
export function createDeferred() {
let resolve;
let reject;
const promise = new Promise((res, rej) => {
resolve = res;
reject = rej;
});
return { promise, resolve: resolve, reject: reject };
}
/**
* Safely parses JSON with error handling
*/
export function safeParseJSON(json, fallback) {
try {
return JSON.parse(json);
}
catch {
return fallback;
}
}
/**
* Simple calculator function with basic operations
*/
export function calculator(a, b, operation) {
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, options) {
const state = {
failureCount: 0,
lastFailureTime: 0,
state: 'closed',
};
const isOpen = () => {
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 = () => {
state.failureCount = 0;
state.state = 'closed';
};
const recordFailure = () => {
state.failureCount++;
state.lastFailureTime = Date.now();
if (state.failureCount >= options.threshold) {
state.state = 'open';
}
};
return {
async execute(fn) {
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() {
return { ...state };
},
reset() {
state.failureCount = 0;
state.lastFailureTime = 0;
state.state = 'closed';
},
};
}
/**
* Greeting function that returns a personalized greeting
*/
export function greeting(name, options) {
const opts = {
timeOfDay: false,
formal: false,
locale: 'en',
...options
};
// Determine time-based greeting
const getTimeGreeting = () => {
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 = () => {
const greetings = {
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;
}
//# sourceMappingURL=helpers.js.map