claude-flow-multilang
Version:
Revolutionary multilingual AI orchestration framework with cultural awareness and DDD architecture
349 lines (296 loc) • 10.6 kB
text/typescript
import { spawn } from 'child_process';
import { Logger } from '../../core/logger.js';
import type {
PreTaskOptions,
PostTaskOptions,
PreEditOptions,
PostEditOptions,
PreCommandOptions,
PostCommandOptions,
SessionStartOptions,
SessionEndOptions,
SessionRestoreOptions,
PreSearchOptions,
NotificationOptions,
HookCommandOptions,
PerformanceOptions,
MemorySyncOptions,
TelemetryOptions,
} from './hook-types.js';
const logger = new Logger(
{
level: 'info',
format: 'text',
destination: 'console',
},
{ prefix: 'Hook' },
);
// Helper function to build command arguments
function buildArgs(hookType: string, options: Record<string, any>): string[] {
const args = [hookType];
Object.entries(options).forEach(([key, value]) => {
if (value !== undefined && value !== null) {
const flagName = key.replace(/([A-Z])/g, '-$1').toLowerCase();
if (typeof value === 'boolean') {
if (value) {
args.push(`--${flagName}`);
} else {
args.push(`--no-${flagName}`);
}
} else {
args.push(`--${flagName}`, String(value));
}
}
});
return args;
}
// Hook subcommand handlers
const hookHandlers: Record<string, (args: string[]) => Promise<void>> = {
'pre-task': async (args: string[]) => {
const options = parseArgs<PreTaskOptions>(args);
await executeHook('pre-task', options);
},
'post-task': async (args: string[]) => {
const options = parseArgs<PostTaskOptions>(args);
if (!options.taskId) {
throw new Error('--task-id is required for post-task hook');
}
await executeHook('post-task', options);
},
'pre-edit': async (args: string[]) => {
const options = parseArgs<PreEditOptions>(args);
if (!options.file) {
throw new Error('--file is required for pre-edit hook');
}
await executeHook('pre-edit', options);
},
'post-edit': async (args: string[]) => {
const options = parseArgs<PostEditOptions>(args);
if (!options.file) {
throw new Error('--file is required for post-edit hook');
}
await executeHook('post-edit', options);
},
'pre-command': async (args: string[]) => {
const options = parseArgs<PreCommandOptions>(args);
if (!options.command) {
throw new Error('--command is required for pre-command hook');
}
await executeHook('pre-command', options);
},
'post-command': async (args: string[]) => {
const options = parseArgs<PostCommandOptions>(args);
if (!options.command) {
throw new Error('--command is required for post-command hook');
}
await executeHook('post-command', options);
},
'session-start': async (args: string[]) => {
const options = parseArgs<SessionStartOptions>(args);
await executeHook('session-start', options);
},
'session-end': async (args: string[]) => {
const options = parseArgs<SessionEndOptions>(args);
await executeHook('session-end', options);
},
'session-restore': async (args: string[]) => {
const options = parseArgs<SessionRestoreOptions>(args);
if (!options.sessionId) {
throw new Error('--session-id is required for session-restore hook');
}
await executeHook('session-restore', options);
},
'pre-search': async (args: string[]) => {
const options = parseArgs<PreSearchOptions>(args);
if (!options.query) {
throw new Error('--query is required for pre-search hook');
}
await executeHook('pre-search', options);
},
notification: async (args: string[]) => {
const options = parseArgs<NotificationOptions>(args);
if (!options.message) {
throw new Error('--message is required for notification hook');
}
await executeHook('notification', options);
},
performance: async (args: string[]) => {
const options = parseArgs<PerformanceOptions>(args);
await executeHook('performance', options);
},
'memory-sync': async (args: string[]) => {
const options = parseArgs<MemorySyncOptions>(args);
await executeHook('memory-sync', options);
},
telemetry: async (args: string[]) => {
const options = parseArgs<TelemetryOptions>(args);
if (!options.event) {
throw new Error('--event is required for telemetry hook');
}
await executeHook('telemetry', options);
},
};
// Parse command line arguments
function parseArgs<T extends Record<string, any>>(args: string[]): T {
const options: Record<string, any> = {};
for (let i = 0; i < args.length; i++) {
const arg = args[i];
if (arg.startsWith('--')) {
const key = arg.slice(2).replace(/-([a-z])/g, (_, letter) => letter.toUpperCase());
const nextArg = args[i + 1];
if (!nextArg || nextArg.startsWith('--')) {
// Boolean flag
options[key] = !arg.startsWith('--no-');
} else {
// Value flag
options[key] = nextArg;
i++; // Skip next arg
}
}
}
return options as T;
}
// Execute hook with ruv-swarm
async function executeHook(hookType: string, options: Record<string, any>): Promise<void> {
const args = buildArgs(hookType, options);
logger.debug(`Executing hook: ruv-swarm hook ${args.join(' ')}`);
const child = spawn('npx', ['ruv-swarm', 'hook', ...args], {
stdio: 'inherit',
shell: true,
});
await new Promise<void>((resolve, reject) => {
child.on('exit', (code) => {
if (code === 0) {
resolve();
} else {
reject(new Error(`Hook ${hookType} failed with exit code ${code}`));
}
});
child.on('error', (error) => {
logger.error(`Failed to execute hook ${hookType}:`, error);
reject(error);
});
});
}
// Main hook command handler
export const hookCommand = {
name: 'hook',
description: 'Execute ruv-swarm hooks for agent coordination',
action: async ({ args }: HookCommandOptions): Promise<void> => {
try {
if (args.length === 0) {
showHookHelp();
return;
}
const subcommand = args[0];
const handler = hookHandlers[subcommand];
if (!handler) {
logger.error(`Unknown hook subcommand: ${subcommand}`);
showHookHelp();
throw new Error(`Unknown hook subcommand: ${subcommand}`);
}
await handler(args.slice(1));
} catch (error) {
logger.error('Hook command error:', error);
throw error;
}
},
};
// Show help for hook commands
function showHookHelp(): void {
console.log(`
Claude Flow Hook Commands
========================
Available hooks:
pre-task - Run before starting a task
--description <desc> Task description
--auto-spawn-agents Auto-spawn agents (default: true)
--complexity <level> Task complexity: low|medium|high
--estimated-minutes <n> Estimated duration
--requires-research Task requires research
--requires-testing Task requires testing
post-task - Run after completing a task
--task-id <id> Task ID (required)
--analyze-performance Analyze performance metrics
--generate-report Generate completion report
pre-edit - Run before editing a file
--file <path> File path (required)
--operation <op> Operation type: read|write|edit|delete
--validate Validate file before edit
post-edit - Run after editing a file
--file <path> File path (required)
--memory-key <key> Store in memory with key
--format Auto-format code
--analyze Analyze changes
pre-command - Run before executing a command
--command <cmd> Command to execute (required)
--validate Validate command safety
--sandbox Run in sandbox mode
post-command - Run after executing a command
--command <cmd> Command executed (required)
--exit-code <code> Command exit code
--duration <ms> Execution duration
session-start - Run at session start
--session-id <id> Session identifier
--load-previous Load previous session data
--auto-restore Auto-restore context
session-end - Run at session end
--session-id <id> Session identifier
--export-metrics Export performance metrics
--generate-summary Generate session summary
--save-to <path> Save session data to path
session-restore - Restore a previous session
--session-id <id> Session ID to restore (required)
--load-memory Load memory state
--load-agents Load agent configuration
--load-tasks Load task list
pre-search - Run before searching
--query <text> Search query (required)
--cache-results Cache search results
--max-results <n> Maximum results to return
notification - Send a notification
--message <text> Notification message (required)
--level <level> Message level: info|warning|error
--telemetry Include in telemetry
--persist Persist notification
performance - Track performance metrics
--operation <name> Operation name
--duration <ms> Operation duration
--metrics <json> Performance metrics as JSON
memory-sync - Synchronize memory state
--namespace <name> Memory namespace
--direction <dir> Sync direction: push|pull|sync
--target <location> Target location for sync
telemetry - Send telemetry data
--event <name> Event name (required)
--data <json> Event data as JSON
--tags <list> Comma-separated tags
Common options:
--verbose Show detailed output
--metadata <json> Additional metadata as JSON
Examples:
claude hook pre-task --description "Build REST API" --complexity high
claude hook post-edit --file src/index.js --memory-key "api/implementation"
claude hook session-end --export-metrics --generate-summary
claude hook performance --operation "api-build" --duration 1234
claude hook memory-sync --namespace "project" --direction push
claude hook telemetry --event "task-completed" --data '{"taskId":"123"}'
`);
}
// Export hook subcommands for better CLI integration
export const hookSubcommands = [
'pre-task',
'post-task',
'pre-edit',
'post-edit',
'pre-command',
'post-command',
'session-start',
'session-end',
'session-restore',
'pre-search',
'notification',
'performance',
'memory-sync',
'telemetry',
];