#!/usr/bin/env node /** * Context Monitor Hook - UserPromptSubmit hook * Monitors context usage and triggers backups when needed */ const fs = require('fs-extra'); const path = require('path'); // Add lib directory to require path const libPath = path.join(__dirname, '..', 'lib'); const { ContextMonitor } = require(path.join(libPath, 'context-monitor')); const { BackupManager } = require(path.join(libPath, 'backup-manager')); const { SessionStateManager } = require(path.join(libPath, 'session-state')); async function main() { try { // Read input from Claude Code let inputData = ''; // Handle stdin input if (process.stdin.isTTY) { // If called directly for testing inputData = JSON.stringify({ prompt: 'test prompt', context_size: 1000 }); } else { // Read from stdin process.stdin.setEncoding('utf8'); for await (const chunk of process.stdin) { inputData += chunk; } } const input = JSON.parse(inputData); // Initialize components const contextMonitor = new ContextMonitor(); const backupManager = new BackupManager(); const sessionManager = new SessionStateManager(); // Update context estimates from prompt contextMonitor.updateFromPrompt(input); // Check if backup should be triggered const backupDecision = contextMonitor.checkBackupTriggers('UserPromptSubmit', input); let message; if (backupDecision.shouldBackup) { // Execute backup const sessionState = await sessionManager.getSessionSummary(); const backupResult = await backupManager.executeBackup(backupDecision, sessionState); // Record backup in session await sessionManager.addBackup(backupResult.backupId, { reason: backupDecision.reason, success: backupResult.success }); // Add context snapshot await sessionManager.addContextSnapshot({ usageRatio: contextMonitor.getContextUsageRatio(), promptCount: contextMonitor.promptCount, toolExecutions: contextMonitor.toolExecutions }); // Notify about backup if (backupResult.success) { message = `Auto-backup created: ${backupDecision.reason} (usage: ${(contextMonitor.getContextUsageRatio() * 100).toFixed(1)}%)`; } else { message = `Backup attempted but failed: ${backupResult.error}`; } } else { message = `Context usage: ${(contextMonitor.getContextUsageRatio() * 100).toFixed(1)}%`; } // Always allow operation (this is a monitoring hook) const response = { allow: true, message }; console.log(JSON.stringify(response)); process.exit(0); } catch (error) { // Never block on errors - always allow operation const response = { allow: true, message: `Context monitor error: ${error.message}` }; console.log(JSON.stringify(response)); process.exit(0); } } // Handle unhandled promise rejections process.on('unhandledRejection', (error) => { const response = { allow: true, message: `Context monitor error: ${error.message}` }; console.log(JSON.stringify(response)); process.exit(0); }); main();