@fromsvenwithlove/devops-issues-cli
Version:
AI-powered CLI tool and library for Azure DevOps work item management with Claude agents
109 lines (94 loc) • 2.56 kB
JavaScript
import keypress from 'keypress';
import { stdinStateManager } from './stdin-state-manager.js';
/**
* Global keypress manager to prevent double event registration
* This ensures keypress(process.stdin) is only called once per process
*/
class KeypressManager {
constructor() {
this.initialized = false;
this.handlers = new Map();
this.activeHandlers = 0;
}
/**
* Initialize keypress on stdin if not already done
*/
init() {
if (!this.initialized) {
// Check if we're in an interactive terminal
if (!process.stdin.isTTY) {
return false;
}
// Save stdin state before modifying
stdinStateManager.saveState();
keypress(process.stdin);
process.stdin.setRawMode(true);
process.stdin.resume();
// Global keypress handler that delegates to registered handlers
process.stdin.on('keypress', (ch, key) => {
this.handlers.forEach(handler => {
try {
handler(ch, key);
} catch (error) {
console.error('Keypress handler error:', error);
}
});
});
this.initialized = true;
}
return true;
}
/**
* Add a keypress handler with unique ID
* @param {string} id - Unique identifier for this handler
* @param {Function} handler - Function to handle keypress events
* @returns {boolean} - True if successfully added
*/
addHandler(id, handler) {
if (!this.init()) {
return false;
}
this.handlers.set(id, handler);
this.activeHandlers++;
return true;
}
/**
* Remove a specific keypress handler
* @param {string} id - Handler ID to remove
*/
removeHandler(id) {
if (this.handlers.has(id)) {
this.handlers.delete(id);
this.activeHandlers--;
// If no handlers left, cleanup
if (this.activeHandlers <= 0) {
this.cleanup();
}
}
}
/**
* Force cleanup of all keypress handling
*/
cleanup() {
if (this.initialized) {
// Clear our handlers first
this.handlers.clear();
this.activeHandlers = 0;
// Reset stdin for inquirer compatibility
stdinStateManager.resetForInquirer();
this.initialized = false;
}
}
/**
* Get current status
*/
getStatus() {
return {
initialized: this.initialized,
activeHandlers: this.activeHandlers,
handlerIds: Array.from(this.handlers.keys())
};
}
}
// Export singleton instance
export const keypressManager = new KeypressManager();