claude-hooks/hooks/context-monitor.js

109 lines
3.2 KiB
JavaScript
Executable File

#!/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();